1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 #include <sys/aoe.h>
  17 
  18 #include <libaoe.h>
  19 #include <libdllink.h>
  20 #include <libintl.h>
  21 #include <libscf.h>
  22 #include <locale.h>
  23 #include <stddef.h>
  24 #include <stdlib.h>
  25 #include <string.h>
  26 #include <strings.h>
  27 #include <syslog.h>
  28 #include <wchar.h>
  29 
  30 /* Define an abbreviation for gettext to save typing */
  31 #define _(s)    gettext(s)
  32 
  33 static int      aoeadm_create_port(int, char **);
  34 static int      aoeadm_delete_port(int, char **);
  35 static int      aoeadm_list_ports(int, char **);
  36 static void     print_port_info(aoe_port_instance_t *, char *, int);
  37 static void     usage(void);
  38 
  39 typedef struct aoeadm_command {
  40         const char      *name;
  41         int             (*func)(int argc, char **argv);
  42 } aoeadm_command_t;
  43 
  44 static aoeadm_command_t cmdtable[] = {
  45         { "create-initiator",   aoeadm_create_port      },
  46         { "create-target",      aoeadm_create_port      },
  47         { "delete-initiator",   aoeadm_delete_port      },
  48         { "delete-target",      aoeadm_delete_port      },
  49         { "list-initiator",     aoeadm_list_ports       },
  50         { "list-target",        aoeadm_list_ports       }
  51 };
  52 /* Note: Update this value if necessary when cmdtable is updated */
  53 #define MAX_AOEADM_CMDLEN       16
  54 
  55 static const char       *cmdname;
  56 
  57 extern const char       *__progname;
  58 
  59 
  60 int
  61 main(int argc, char **argv)
  62 {
  63         int     i;
  64 
  65         (void) setlocale(LC_ALL, "");
  66 #if !defined(TEXT_DOMAIN)
  67 #define TEXT_DOMAIN "SYS_TEST"
  68 #endif
  69         (void) textdomain(TEXT_DOMAIN);
  70 
  71         if (argc < 2)
  72                 usage();
  73 
  74         if (strnlen(argv[1], MAX_AOEADM_CMDLEN+1) > MAX_AOEADM_CMDLEN) {
  75                 (void) fprintf(stderr, _("Invalid argument.\n"));
  76                 usage();
  77                 return (1);
  78         }
  79         for (i = 0; i < sizeof (cmdtable) / sizeof (cmdtable[0]); i++) {
  80                 /*
  81                  * The following strcmp is safe because we've
  82                  * already validated the size of argv[1].
  83                  */
  84                 if (strcmp(argv[1], cmdtable[i].name) == 0) {
  85                         cmdname = argv[1];
  86                         return (cmdtable[i].func(argc - 1, argv + 1));
  87                 }
  88         };
  89 
  90         usage();
  91         /* NOTREACHED */
  92         return (0);
  93 }
  94 
  95 static int
  96 aoeadm_create_port(int argc, char **argv)
  97 {
  98         AOE_STATUS      ret;
  99         aoe_cli_policy_t policy = AOE_POLICY_NONE;
 100         char            c;
 101         char            *linknames;
 102         char            *module = NULL;
 103         int             portid;
 104         int             promisc = 0;
 105 
 106         while ((c = getopt(argc, argv, "fm:p:")) != -1) {
 107                 switch (c) {
 108                 case 'f':
 109                         promisc = 1;
 110                         break;
 111                 case 'm':
 112                         module = optarg;
 113                         break;
 114                 case 'p':
 115                         if (strcmp(optarg, "failover") == 0)
 116                                 policy = AOE_POLICY_FAILOVER;
 117                         else if (strcmp(optarg, "loadbalance") == 0)
 118                                 policy = AOE_POLICY_LOADBALANCE;
 119                         else if (strcmp(optarg, "roundrobin") == 0)
 120                                 policy = AOE_POLICY_ROUNDROBIN;
 121                         else
 122                                 usage();
 123                         break;
 124                 default:
 125                         usage();
 126                 }
 127         }
 128 
 129         argc -= optind;
 130         argv += optind;
 131 
 132         if (argc < 2)
 133                 usage();
 134 
 135         errno = 0;
 136         portid = strtol(argv[0], (char **)NULL, 10);
 137         if (errno != 0 || portid < 0)
 138                 usage();
 139         linknames = argv[1];
 140 
 141         if (strcmp(cmdname, "create-initiator") == 0)
 142                 ret = aoe_create_port(portid, linknames, promisc,
 143                     AOE_CLIENT_INITIATOR, policy, module);
 144         else
 145                 ret = aoe_create_port(portid, linknames, promisc,
 146                     AOE_CLIENT_TARGET, policy, module);
 147 
 148         if (ret != AOE_STATUS_OK) {
 149                 (void) fprintf(stderr, _("Failed to create port: %s\n"),
 150                     aoe_strerror(ret));
 151         }
 152 
 153         return (ret);
 154 }
 155 
 156 static int
 157 aoeadm_delete_port(int argc, char **argv)
 158 {
 159         AOE_STATUS      ret;
 160         int             portid;
 161 
 162         if (argc < 2)
 163                 usage();
 164 
 165         errno = 0;
 166         portid = strtol(argv[1], (char **)NULL, 10);
 167         if (errno != 0 || portid < 0)
 168                 usage();
 169 
 170         ret = aoe_delete_port(portid);
 171 
 172         if (ret != AOE_STATUS_OK) {
 173                 (void) fprintf(stderr, _("Failed to delete port: %s\n"),
 174                     aoe_strerror(ret));
 175         }
 176 
 177         return (ret);
 178 }
 179 
 180 static int
 181 aoeadm_list_ports(int argc, char **argv)
 182 {
 183         AOE_STATUS      ret;
 184         aoe_port_list_t *portlist = NULL;
 185         char            c;
 186         dladm_handle_t  handle;
 187         int             i;
 188         int             portid = -1;
 189         int             verbose = 0;
 190         uint32_t        nports;
 191 
 192         while ((c = getopt(argc, argv, "v")) != -1) {
 193                 switch (c) {
 194                 case 'v':
 195                         verbose = 1;
 196                         break;
 197                 default:
 198                         usage();
 199                 }
 200         }
 201 
 202         argc -= optind;
 203         argv += optind;
 204 
 205         if (argc == 1) {
 206                 errno = 0;
 207                 portid = strtol(argv[0], (char **)NULL, 10);
 208                 if (errno != 0 || portid < 0)
 209                         usage();
 210         }
 211 
 212         ret = aoe_get_port_list(&nports, &portlist);
 213 
 214         if (ret != AOE_STATUS_OK) {
 215                 (void) fprintf(stderr, _("Failed to list ports: %s\n"),
 216                     aoe_strerror(ret));
 217                 return (ret);
 218         }
 219 
 220         if (nports == 0) {
 221                 free(portlist);
 222                 return (0);
 223         }
 224 
 225         if (dladm_open(&handle) != DLADM_STATUS_OK)
 226                 handle = NULL;
 227 
 228         for (i = 0; i < nports; i++) {
 229                 aoe_port_instance_t *pi = &portlist->ports[i];
 230                 char            linknames[AOE_MAX_MACOBJ * MAXLINKNAMELEN];
 231                 int             j;
 232 
 233                 if (portid >= 0 && pi->api_port_id != portid)
 234                         continue;
 235 
 236                 if ((pi->api_port_type == AOE_CLIENT_INITIATOR &&
 237                     strcmp(cmdname, "list-target") == 0) ||
 238                     (pi->api_port_type == AOE_CLIENT_TARGET &&
 239                     strcmp(cmdname, "list-initiator") == 0))
 240                         continue;
 241 
 242                 /* Convert linkid to interface name */
 243                 for (j = 0; j < pi->api_mac_cnt; j++) {
 244                         aoe_mac_instance_t *mi = &pi->api_mac[j];
 245                         char    *linkname = linknames + j * MAXLINKNAMELEN;
 246 
 247                         if (handle == NULL ||
 248                             dladm_datalink_id2info(handle, mi->ami_mac_linkid,
 249                             NULL, NULL, NULL, linkname, MAXLINKNAMELEN - 1) !=
 250                             DLADM_STATUS_OK)
 251                                 (void) strcpy(linkname, "<unknown>");
 252                 }
 253 
 254                 print_port_info(pi, linknames, verbose);
 255 
 256                 if (portid >= 0) {
 257                         if (handle != NULL)
 258                                 dladm_close(handle);
 259                         free(portlist);
 260                         return (0);
 261                 }
 262         }
 263 
 264         if (handle != NULL)
 265                 dladm_close(handle);
 266         free(portlist);
 267 
 268         return (portid >= 0 ? 1 : 0);
 269 }
 270 
 271 static void
 272 print_port_info(aoe_port_instance_t *pi, char *linknames, int verbose)
 273 {
 274         int     i;
 275 
 276         if (pi == NULL)
 277                 return;
 278 
 279         if (pi->api_port_type == AOE_CLIENT_INITIATOR)
 280                 (void) printf(_("Initiator: aoe.port"));
 281         else
 282                 (void) printf(_("Target: aoe.shelf"));
 283         (void) printf("%d\n", pi->api_port_id);
 284 
 285         if (!verbose)
 286                 return;
 287 
 288         (void) printf(_("    State\t\t: %s\n"),
 289             (pi->api_port_state == AOE_PORT_STATE_ONLINE) ?
 290             _("Online") : _("Offline"));
 291         (void) printf(_("    Multipath Policy\t: %s\n"),
 292             (pi->api_port_policy == AOE_POLICY_NONE) ? _("Disabled") :
 293             (pi->api_port_policy == AOE_POLICY_FAILOVER ?  _("Fail-Over") :
 294             (pi->api_port_policy == AOE_POLICY_ROUNDROBIN ?
 295             _("Round-Robin") : _("Load-Balance"))));
 296         (void) printf(_("    Maxxfer\t\t: %d bytes\n"), pi->api_maxxfer);
 297         (void) printf(_("    Interfaces\t\t: %d\n"), pi->api_mac_cnt);
 298 
 299         for (i = 0; i < pi->api_mac_cnt; i++) {
 300                 aoe_mac_instance_t *mi = &pi->api_mac[i];
 301                 int             j;
 302 
 303                 (void) printf(_("\tInterface: %s\n"),
 304                     linknames + i * MAXLINKNAMELEN);
 305                 (void) printf(_("\t    Link Id\t\t: %d\n"), mi->ami_mac_linkid);
 306                 (void) printf(_("\t    Link State\t\t: %s\n"),
 307                     mi->ami_mac_link_state == AOE_MAC_LINK_STATE_UP ?
 308                     _("Up") : _("Down"));
 309                 (void) printf(_("\t    Link MTU\t\t: %d\n"), mi->ami_mtu_size);
 310                 (void) printf(_("\t    Primary MAC Address\t: "));
 311                 for (j = 0; j < 6; j++)
 312                         (void) printf("%02x", mi->ami_mac_factory_addr[j]);
 313                 (void) printf(_("\n\t    Current MAC Address\t: "));
 314                 for (j = 0; j < 6; j++)
 315                         (void) printf("%02x", mi->ami_mac_current_addr[j]);
 316                 (void) printf(_("\n\t    Promiscuous Mode\t: %s\n"),
 317                     mi->ami_mac_promisc == 1 ? _("On") : _("Off"));
 318                 (void) printf(_("\t    TX frames\t\t: %ld\n"),
 319                     mi->ami_mac_tx_frames);
 320                 (void) printf(_("\t    RX frames\t\t: %ld\n"),
 321                     mi->ami_mac_rx_frames);
 322         }
 323 }
 324 
 325 static void
 326 usage(void)
 327 {
 328 
 329         (void) fprintf(stderr, _(
 330 "Usage:\n"
 331 "\t%s create-initiator [-f] [-p policy] port link[,link,...]\n"
 332 "\t%s create-target [-f] [-m module] [-p policy] shelf link[,link,...]\n"
 333 "\t%s delete-initiator port\n"
 334 "\t%s delete-target shelf\n"
 335 "\t%s list-initiator [-v]\n"
 336 "\t%s list-target [-v]\n"),
 337             __progname, __progname, __progname,
 338             __progname, __progname, __progname);
 339 
 340         exit(1);
 341 }