Print this page
    
NEX-4233 remove unnecessary libdladm header includes
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Steve Peng <steve.peng@nexenta.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/dladm/dladm.c
          +++ new/usr/src/cmd/dladm/dladm.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   * Copyright 2016 Nexenta Systems, Inc.
  25   25   */
  26   26  
  27   27  #include <stdio.h>
  28   28  #include <ctype.h>
  29   29  #include <dlfcn.h>
  30   30  #include <locale.h>
  31   31  #include <signal.h>
  32   32  #include <stdarg.h>
  33   33  #include <stdlib.h>
  34   34  #include <fcntl.h>
  35   35  #include <string.h>
  36   36  #include <stropts.h>
  37   37  #include <sys/stat.h>
  38   38  #include <errno.h>
  39   39  #include <kstat.h>
  40   40  #include <strings.h>
  41   41  #include <getopt.h>
  42   42  #include <unistd.h>
  43   43  #include <priv.h>
  44   44  #include <limits.h>
  45   45  #include <termios.h>
  46   46  #include <pwd.h>
  47   47  #include <auth_attr.h>
  48   48  #include <auth_list.h>
  49   49  #include <libintl.h>
  50   50  #include <libdevinfo.h>
  51   51  #include <libdlpi.h>
  52   52  #include <libdladm.h>
  53   53  #include <libdllink.h>
  54   54  #include <libdlstat.h>
  55   55  #include <libdlaggr.h>
  56   56  #include <libdlwlan.h>
  57   57  #include <libdlvlan.h>
  58   58  #include <libdlvnic.h>
  59   59  #include <libdlib.h>
  60   60  #include <libdlether.h>
  61   61  #include <libdliptun.h>
  62   62  #include <libdlsim.h>
  63   63  #include <libdlbridge.h>
  64   64  #include <libinetutil.h>
  65   65  #include <libvrrpadm.h>
  66   66  #include <bsm/adt.h>
  67   67  #include <bsm/adt_event.h>
  68   68  #include <libdlvnic.h>
  69   69  #include <sys/types.h>
  70   70  #include <sys/socket.h>
  71   71  #include <sys/ib/ib_types.h>
  72   72  #include <sys/processor.h>
  73   73  #include <netinet/in.h>
  74   74  #include <arpa/inet.h>
  75   75  #include <net/if_types.h>
  76   76  #include <stddef.h>
  77   77  #include <stp_in.h>
  
    | 
      ↓ open down ↓ | 
    77 lines elided | 
    
      ↑ open up ↑ | 
  
  78   78  #include <ofmt.h>
  79   79  
  80   80  #define MAXPORT                 256
  81   81  #define MAXVNIC                 256
  82   82  #define BUFLEN(lim, ptr)        (((lim) > (ptr)) ? ((lim) - (ptr)) : 0)
  83   83  #define MAXLINELEN              1024
  84   84  #define SMF_UPGRADE_FILE                "/var/svc/profile/upgrade"
  85   85  #define SMF_UPGRADEDATALINK_FILE        "/var/svc/profile/upgrade_datalink"
  86   86  #define SMF_DLADM_UPGRADE_MSG           " # added by dladm(1M)"
  87   87  #define DLADM_DEFAULT_COL       80
       88 +#define FFORCE                  "force" /* boolean_t */
  88   89  
  89   90  /*
  90   91   * used by the wifi show-* commands to set up ofmt_field_t structures.
  91   92   */
  92   93  #define WIFI_CMD_SCAN           0x00000001
  93   94  #define WIFI_CMD_SHOW           0x00000002
  94   95  #define WIFI_CMD_ALL            (WIFI_CMD_SCAN | WIFI_CMD_SHOW)
  95   96  
  96   97  /* No larger than pktsum_t */
  97   98  typedef struct brsum_s {
  98   99          uint64_t        drops;
  99  100          uint64_t        forward_dir;
 100  101          uint64_t        forward_mb;
 101  102          uint64_t        forward_unk;
 102  103          uint64_t        recv;
 103  104          uint64_t        sent;
 104  105  } brsum_t;
 105  106  
 106  107  /* No larger than pktsum_t */
 107  108  typedef struct brlsum_s {
 108  109          uint32_t        cfgbpdu;
 109  110          uint32_t        tcnbpdu;
 110  111          uint32_t        rstpbpdu;
 111  112          uint32_t        txbpdu;
 112  113          uint64_t        drops;
 113  114          uint64_t        recv;
 114  115          uint64_t        xmit;
 115  116  } brlsum_t;
 116  117  
 117  118  typedef struct show_state {
 118  119          boolean_t       ls_firstonly;
 119  120          boolean_t       ls_donefirst;
 120  121          pktsum_t        ls_prevstats;
 121  122          uint32_t        ls_flags;
 122  123          dladm_status_t  ls_status;
 123  124          ofmt_handle_t   ls_ofmt;
 124  125          boolean_t       ls_parsable;
 125  126          boolean_t       ls_mac;
 126  127          boolean_t       ls_hwgrp;
 127  128  } show_state_t;
 128  129  
 129  130  typedef struct show_grp_state {
 130  131          pktsum_t        gs_prevstats[MAXPORT];
 131  132          uint32_t        gs_flags;
 132  133          dladm_status_t  gs_status;
 133  134          boolean_t       gs_parsable;
 134  135          boolean_t       gs_lacp;
 135  136          boolean_t       gs_extended;
 136  137          boolean_t       gs_stats;
 137  138          boolean_t       gs_firstonly;
 138  139          boolean_t       gs_donefirst;
 139  140          ofmt_handle_t   gs_ofmt;
 140  141  } show_grp_state_t;
 141  142  
 142  143  typedef struct show_vnic_state {
 143  144          datalink_id_t   vs_vnic_id;
 144  145          datalink_id_t   vs_link_id;
 145  146          char            vs_vnic[MAXLINKNAMELEN];
 146  147          char            vs_link[MAXLINKNAMELEN];
 147  148          boolean_t       vs_parsable;
 148  149          boolean_t       vs_found;
 149  150          boolean_t       vs_firstonly;
 150  151          boolean_t       vs_donefirst;
 151  152          boolean_t       vs_stats;
 152  153          boolean_t       vs_printstats;
 153  154          pktsum_t        vs_totalstats;
 154  155          pktsum_t        vs_prevstats[MAXVNIC];
 155  156          boolean_t       vs_etherstub;
 156  157          dladm_status_t  vs_status;
 157  158          uint32_t        vs_flags;
 158  159          ofmt_handle_t   vs_ofmt;
 159  160  } show_vnic_state_t;
 160  161  
 161  162  typedef struct show_part_state {
 162  163          datalink_id_t   ps_over_id;
 163  164          char            ps_part[MAXLINKNAMELEN];
 164  165          boolean_t       ps_parsable;
 165  166          boolean_t       ps_found;
 166  167          dladm_status_t  ps_status;
 167  168          uint32_t        ps_flags;
 168  169          ofmt_handle_t   ps_ofmt;
 169  170  } show_part_state_t;
 170  171  
 171  172  typedef struct show_ib_state {
 172  173          datalink_id_t   is_link_id;
 173  174          char            is_link[MAXLINKNAMELEN];
 174  175          boolean_t       is_parsable;
 175  176          dladm_status_t  is_status;
 176  177          uint32_t        is_flags;
 177  178          ofmt_handle_t   is_ofmt;
 178  179  } show_ib_state_t;
 179  180  
 180  181  typedef struct show_usage_state_s {
 181  182          boolean_t       us_plot;
 182  183          boolean_t       us_parsable;
 183  184          boolean_t       us_printheader;
 184  185          boolean_t       us_first;
 185  186          boolean_t       us_showall;
 186  187          ofmt_handle_t   us_ofmt;
 187  188  } show_usage_state_t;
 188  189  
 189  190  /*
 190  191   * callback functions for printing output and error diagnostics.
 191  192   */
 192  193  static ofmt_cb_t print_default_cb, print_link_stats_cb, print_linkprop_cb;
 193  194  static ofmt_cb_t print_lacp_cb, print_phys_one_mac_cb;
 194  195  static ofmt_cb_t print_xaggr_cb, print_aggr_stats_cb;
 195  196  static ofmt_cb_t print_phys_one_hwgrp_cb, print_wlan_attr_cb;
 196  197  static ofmt_cb_t print_wifi_status_cb, print_link_attr_cb;
 197  198  
 198  199  typedef void cmdfunc_t(int, char **, const char *);
 199  200  
 200  201  static cmdfunc_t do_show_link, do_show_wifi, do_show_phys;
 201  202  static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr;
 202  203  static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr;
 203  204  static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi;
 204  205  static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop;
 205  206  static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj;
 206  207  static cmdfunc_t do_init_linkprop, do_init_secobj;
 207  208  static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan;
 208  209  static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys;
 209  210  static cmdfunc_t do_show_linkmap;
 210  211  static cmdfunc_t do_show_ether;
 211  212  static cmdfunc_t do_create_vnic, do_delete_vnic, do_show_vnic;
 212  213  static cmdfunc_t do_up_vnic;
 213  214  static cmdfunc_t do_create_part, do_delete_part, do_show_part, do_show_ib;
 214  215  static cmdfunc_t do_up_part;
 215  216  static cmdfunc_t do_create_etherstub, do_delete_etherstub, do_show_etherstub;
 216  217  static cmdfunc_t do_create_simnet, do_modify_simnet;
 217  218  static cmdfunc_t do_delete_simnet, do_show_simnet, do_up_simnet;
 218  219  static cmdfunc_t do_show_usage;
 219  220  static cmdfunc_t do_create_bridge, do_modify_bridge, do_delete_bridge;
 220  221  static cmdfunc_t do_add_bridge, do_remove_bridge, do_show_bridge;
 221  222  static cmdfunc_t do_create_iptun, do_modify_iptun, do_delete_iptun;
 222  223  static cmdfunc_t do_show_iptun, do_up_iptun, do_down_iptun;
 223  224  
 224  225  static void     do_up_vnic_common(int, char **, const char *, boolean_t);
 225  226  
 226  227  static int show_part(dladm_handle_t, datalink_id_t, void *);
 227  228  
 228  229  static void     altroot_cmd(char *, int, char **);
 229  230  static int      show_linkprop_onelink(dladm_handle_t, datalink_id_t, void *);
 230  231  
 231  232  static void     link_stats(datalink_id_t, uint_t, char *, show_state_t *);
 232  233  static void     aggr_stats(datalink_id_t, show_grp_state_t *, uint_t);
 233  234  static void     vnic_stats(show_vnic_state_t *, uint32_t);
 234  235  
 235  236  static int      get_one_kstat(const char *, const char *, uint8_t,
 236  237                      void *, boolean_t);
 237  238  static void     get_mac_stats(const char *, pktsum_t *);
 238  239  static void     get_link_stats(const char *, pktsum_t *);
 239  240  static uint64_t get_ifspeed(const char *, boolean_t);
 240  241  static const char       *get_linkstate(const char *, boolean_t, char *);
 241  242  static const char       *get_linkduplex(const char *, boolean_t, char *);
 242  243  
 243  244  static iptun_type_t     iptun_gettypebyname(char *);
 244  245  static const char       *iptun_gettypebyvalue(iptun_type_t);
 245  246  static dladm_status_t   print_iptun(dladm_handle_t, datalink_id_t,
 246  247                              show_state_t *);
 247  248  static int      print_iptun_walker(dladm_handle_t, datalink_id_t, void *);
 248  249  
 249  250  static int      show_etherprop(dladm_handle_t, datalink_id_t, void *);
 250  251  static void     show_ether_xprop(void *, dladm_ether_info_t *);
 251  252  static boolean_t        link_is_ether(const char *, datalink_id_t *);
 252  253  
 253  254  static boolean_t str2int(const char *, int *);
 254  255  static void     die(const char *, ...);
 255  256  static void     die_optdup(int);
 256  257  static void     die_opterr(int, int, const char *);
 257  258  static void     die_dlerr(dladm_status_t, const char *, ...);
 258  259  static void     warn(const char *, ...);
 259  260  static void     warn_dlerr(dladm_status_t, const char *, ...);
 260  261  
 261  262  typedef struct  cmd {
 262  263          char            *c_name;
 263  264          cmdfunc_t       *c_fn;
 264  265          const char      *c_usage;
 265  266  } cmd_t;
 266  267  
 267  268  static cmd_t    cmds[] = {
 268  269          { "rename-link",        do_rename_link,
 269  270              "    rename-link      <oldlink> <newlink>"                  },
 270  271          { "show-link",          do_show_link,
 271  272              "    show-link        [-pP] [-o <field>,..] [-s [-i <interval>]] "
 272  273              "[<link>]\n"                                                },
 273  274          { "create-aggr",        do_create_aggr,
 274  275              "    create-aggr      [-t] [-P <policy>] [-L <mode>] [-T <time>] "
 275  276              "[-u <address>]\n"
 276  277              "\t\t     -l <link> [-l <link>...] <link>"                  },
 277  278          { "delete-aggr",        do_delete_aggr,
 278  279              "    delete-aggr      [-t] <link>"                          },
 279  280          { "add-aggr",           do_add_aggr,
 280  281              "    add-aggr         [-t] -l <link> [-l <link>...] <link>" },
 281  282          { "remove-aggr",        do_remove_aggr,
 282  283              "    remove-aggr      [-t] -l <link> [-l <link>...] <link>" },
 283  284          { "modify-aggr",        do_modify_aggr,
 284  285              "    modify-aggr      [-t] [-P <policy>] [-L <mode>] [-T <time>] "
 285  286              "[-u <address>]\n"
 286  287              "\t\t     <link>"                                           },
 287  288          { "show-aggr",          do_show_aggr,
 288  289              "    show-aggr        [-pPLx] [-o <field>,..] [-s [-i <interval>]] "
 289  290              "[<link>]\n"                                                },
 290  291          { "up-aggr",            do_up_aggr,     NULL                    },
 291  292          { "scan-wifi",          do_scan_wifi,
 292  293              "    scan-wifi        [-p] [-o <field>,...] [<link>]"       },
 293  294          { "connect-wifi",       do_connect_wifi,
 294  295              "    connect-wifi     [-e <essid>] [-i <bssid>] [-k <key>,...] "
 295  296              "[-s wep|wpa]\n"
 296  297              "\t\t     [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g] "
 297  298              "[-T <time>]\n"
 298  299              "\t\t     [<link>]"                                         },
 299  300          { "disconnect-wifi",    do_disconnect_wifi,
 300  301              "    disconnect-wifi  [-a] [<link>]"                        },
 301  302          { "show-wifi",          do_show_wifi,
 302  303              "    show-wifi        [-p] [-o <field>,...] [<link>]\n"     },
 303  304          { "set-linkprop",       do_set_linkprop,
 304  305              "    set-linkprop     [-t] -p <prop>=<value>[,...] <name>"  },
 305  306          { "reset-linkprop",     do_reset_linkprop,
 306  307              "    reset-linkprop   [-t] [-p <prop>,...] <name>"          },
 307  308          { "show-linkprop",      do_show_linkprop,
 308  309              "    show-linkprop    [-cP] [-o <field>,...] [-p <prop>,...] "
 309  310              "<name>\n"                                                  },
 310  311          { "show-ether",         do_show_ether,
 311  312              "    show-ether       [-px][-o <field>,...] <link>\n"       },
 312  313          { "create-secobj",      do_create_secobj,
 313  314              "    create-secobj    [-t] [-f <file>] -c <class> <secobj>" },
 314  315          { "delete-secobj",      do_delete_secobj,
 315  316              "    delete-secobj    [-t] <secobj>[,...]"                  },
 316  317          { "show-secobj",        do_show_secobj,
 317  318              "    show-secobj      [-pP] [-o <field>,...] [<secobj>,...]\n" },
 318  319          { "init-linkprop",      do_init_linkprop,       NULL            },
 319  320          { "init-secobj",        do_init_secobj,         NULL            },
 320  321          { "create-vlan",        do_create_vlan,
 321  322              "    create-vlan      [-ft] -l <link> -v <vid> [link]"      },
 322  323          { "delete-vlan",        do_delete_vlan,
 323  324              "    delete-vlan      [-t] <link>"                          },
 324  325          { "show-vlan",          do_show_vlan,
 325  326              "    show-vlan        [-pP] [-o <field>,..] [<link>]\n"     },
 326  327          { "up-vlan",            do_up_vlan,             NULL            },
 327  328          { "create-iptun",       do_create_iptun,
 328  329              "    create-iptun     [-t] -T <type> "
 329  330              "[-a {local|remote}=<addr>,...] <link>]" },
 330  331          { "delete-iptun",       do_delete_iptun,
 331  332              "    delete-iptun     [-t] <link>"                          },
 332  333          { "modify-iptun",       do_modify_iptun,
 333  334              "    modify-iptun     [-t] -a {local|remote}=<addr>,... <link>" },
 334  335          { "show-iptun",         do_show_iptun,
 335  336              "    show-iptun       [-pP] [-o <field>,..] [<link>]\n"     },
 336  337          { "up-iptun",           do_up_iptun,            NULL            },
 337  338          { "down-iptun",         do_down_iptun,          NULL            },
 338  339          { "delete-phys",        do_delete_phys,
 339  340              "    delete-phys      <link>"                               },
 340  341          { "show-phys",          do_show_phys,
 341  342              "    show-phys        [-m | -H | -P] [[-p] [-o <field>[,...]] "
 342  343              "[<link>]\n"                                                },
 343  344          { "init-phys",          do_init_phys,           NULL            },
 344  345          { "show-linkmap",       do_show_linkmap,        NULL            },
 345  346          { "create-vnic",        do_create_vnic,
 346  347              "    create-vnic      [-t] -l <link> [-m <value> | auto |\n"
 347  348              "\t\t     {factory [-n <slot-id>]} | {random [-r <prefix>]} |\n"
 348  349              "\t\t     {vrrp -V <vrid> -A {inet | inet6}} [-v <vid> [-f]]\n"
 349  350              "\t\t     [-p <prop>=<value>[,...]] <vnic-link>"    },
 350  351          { "delete-vnic",        do_delete_vnic,
 351  352              "    delete-vnic      [-t] <vnic-link>"                     },
 352  353          { "show-vnic",          do_show_vnic,
 353  354              "    show-vnic        [-pP] [-l <link>] [-s [-i <interval>]] "
 354  355              "[<link>]\n"                                                },
 355  356          { "up-vnic",            do_up_vnic,             NULL            },
 356  357          { "create-part",        do_create_part,
 357  358              "    create-part      [-t] [-f] -l <link> [-P <pkey>]\n"
 358  359              "\t\t     [-R <root-dir>] <part-link>"                      },
 359  360          { "delete-part",        do_delete_part,
 360  361              "    delete-part      [-t] [-R <root-dir>] <part-link>"},
 361  362          { "show-part",          do_show_part,
 362  363              "    show-part        [-pP] [-o <field>,...][-l <linkover>]\n"
 363  364              "\t\t     [<part-link>]"            },
 364  365          { "show-ib",            do_show_ib,
 365  366              "    show-ib          [-p] [-o <field>,...] [<link>]\n"     },
 366  367          { "up-part",            do_up_part,             NULL            },
 367  368          { "create-etherstub",   do_create_etherstub,
 368  369              "    create-etherstub [-t] <link>"                          },
 369  370          { "delete-etherstub",   do_delete_etherstub,
 370  371              "    delete-etherstub [-t] <link>"                          },
 371  372          { "show-etherstub",     do_show_etherstub,
 372  373              "    show-etherstub   [-t] [<link>]\n"                      },
 373  374          { "create-simnet",      do_create_simnet,       NULL            },
 374  375          { "modify-simnet",      do_modify_simnet,       NULL            },
 375  376          { "delete-simnet",      do_delete_simnet,       NULL            },
 376  377          { "show-simnet",        do_show_simnet,         NULL            },
 377  378          { "up-simnet",          do_up_simnet,           NULL            },
 378  379          { "create-bridge",      do_create_bridge,
 379  380              "    create-bridge    [-R <root-dir>] [-P <protect>] "
 380  381              "[-p <priority>]\n"
 381  382              "\t\t     [-m <max-age>] [-h <hello-time>] [-d <forward-delay>]\n"
 382  383              "\t\t     [-f <force-protocol>] [-l <link>]... <bridge>"    },
 383  384          { "modify-bridge",      do_modify_bridge,
 384  385              "    modify-bridge    [-R <root-dir>] [-P <protect>] "
 385  386              "[-p <priority>]\n"
 386  387              "\t\t     [-m <max-age>] [-h <hello-time>] [-d <forward-delay>]\n"
 387  388              "\t\t     [-f <force-protocol>] <bridge>"                   },
 388  389          { "delete-bridge",      do_delete_bridge,
 389  390              "    delete-bridge    [-R <root-dir>] <bridge>"             },
 390  391          { "add-bridge",         do_add_bridge,
 391  392              "    add-bridge       [-R <root-dir>] -l <link> [-l <link>]... "
 392  393              "<bridge>"                                                  },
 393  394          { "remove-bridge",      do_remove_bridge,
 394  395              "    remove-bridge    [-R <root-dir>] -l <link> [-l <link>]... "
 395  396              "<bridge>"                                                  },
 396  397          { "show-bridge",        do_show_bridge,
 397  398              "    show-bridge      [-p] [-o <field>,...] [-s [-i <interval>]] "
 398  399              "[<bridge>]\n"
 399  400              "    show-bridge      -l [-p] [-o <field>,...] [-s [-i <interval>]]"
 400  401              " <bridge>\n"
 401  402              "    show-bridge      -f [-p] [-o <field>,...] [-s [-i <interval>]]"
 402  403              " <bridge>\n"
 403  404              "    show-bridge      -t [-p] [-o <field>,...] [-s [-i <interval>]]"
 404  405              " <bridge>\n"                                               },
 405  406          { "show-usage",         do_show_usage,
 406  407              "    show-usage       [-a] [-d | -F <format>] "
 407  408              "[-s <DD/MM/YYYY,HH:MM:SS>]\n"
 408  409              "\t\t     [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> [<link>]" }
 409  410  };
 410  411  
 411  412  static const struct option lopts[] = {
 412  413          {"vlan-id",     required_argument,      0, 'v'},
 413  414          {"output",      required_argument,      0, 'o'},
 414  415          {"dev",         required_argument,      0, 'd'},
 415  416          {"policy",      required_argument,      0, 'P'},
 416  417          {"lacp-mode",   required_argument,      0, 'L'},
 417  418          {"lacp-timer",  required_argument,      0, 'T'},
 418  419          {"unicast",     required_argument,      0, 'u'},
 419  420          {"temporary",   no_argument,            0, 't'},
 420  421          {"root-dir",    required_argument,      0, 'R'},
 421  422          {"link",        required_argument,      0, 'l'},
 422  423          {"forcible",    no_argument,            0, 'f'},
 423  424          {"bw-limit",    required_argument,      0, 'b'},
 424  425          {"mac-address", required_argument,      0, 'm'},
 425  426          {"slot",        required_argument,      0, 'n'},
 426  427          { 0, 0, 0, 0 }
 427  428  };
 428  429  
 429  430  static const struct option show_lopts[] = {
 430  431          {"statistics",  no_argument,            0, 's'},
 431  432          {"continuous",  no_argument,            0, 'S'},
 432  433          {"interval",    required_argument,      0, 'i'},
 433  434          {"parsable",    no_argument,            0, 'p'},
 434  435          {"parseable",   no_argument,            0, 'p'},
 435  436          {"extended",    no_argument,            0, 'x'},
 436  437          {"output",      required_argument,      0, 'o'},
 437  438          {"persistent",  no_argument,            0, 'P'},
 438  439          {"lacp",        no_argument,            0, 'L'},
 439  440          { 0, 0, 0, 0 }
 440  441  };
 441  442  
 442  443  static const struct option iptun_lopts[] = {
 443  444          {"output",      required_argument,      0, 'o'},
 444  445          {"tunnel-type", required_argument,      0, 'T'},
 445  446          {"address",     required_argument,      0, 'a'},
 446  447          {"root-dir",    required_argument,      0, 'R'},
 447  448          {"parsable",    no_argument,            0, 'p'},
 448  449          {"parseable",   no_argument,            0, 'p'},
 449  450          {"persistent",  no_argument,            0, 'P'},
 450  451          { 0, 0, 0, 0 }
 451  452  };
 452  453  
 453  454  static char * const iptun_addropts[] = {
 454  455  #define IPTUN_LOCAL     0
 455  456          "local",
 456  457  #define IPTUN_REMOTE    1
 457  458          "remote",
 458  459          NULL};
 459  460  
 460  461  static const struct {
 461  462          const char      *type_name;
 462  463          iptun_type_t    type_value;
 463  464  } iptun_types[] = {
 464  465          {"ipv4",        IPTUN_TYPE_IPV4},
 465  466          {"ipv6",        IPTUN_TYPE_IPV6},
 466  467          {"6to4",        IPTUN_TYPE_6TO4},
 467  468          {NULL,          0}
 468  469  };
 469  470  
 470  471  static const struct option prop_longopts[] = {
 471  472          {"temporary",   no_argument,            0, 't'  },
 472  473          {"output",      required_argument,      0, 'o'  },
 473  474          {"root-dir",    required_argument,      0, 'R'  },
 474  475          {"prop",        required_argument,      0, 'p'  },
 475  476          {"parsable",    no_argument,            0, 'c'  },
 476  477          {"parseable",   no_argument,            0, 'c'  },
 477  478          {"persistent",  no_argument,            0, 'P'  },
 478  479          { 0, 0, 0, 0 }
 479  480  };
 480  481  
 481  482  static const struct option wifi_longopts[] = {
 482  483          {"parsable",    no_argument,            0, 'p'  },
 483  484          {"parseable",   no_argument,            0, 'p'  },
 484  485          {"output",      required_argument,      0, 'o'  },
 485  486          {"essid",       required_argument,      0, 'e'  },
 486  487          {"bsstype",     required_argument,      0, 'b'  },
 487  488          {"mode",        required_argument,      0, 'm'  },
 488  489          {"key",         required_argument,      0, 'k'  },
 489  490          {"sec",         required_argument,      0, 's'  },
 490  491          {"auth",        required_argument,      0, 'a'  },
 491  492          {"create-ibss", required_argument,      0, 'c'  },
 492  493          {"timeout",     required_argument,      0, 'T'  },
 493  494          {"all-links",   no_argument,            0, 'a'  },
 494  495          {"temporary",   no_argument,            0, 't'  },
 495  496          {"root-dir",    required_argument,      0, 'R'  },
 496  497          {"persistent",  no_argument,            0, 'P'  },
 497  498          {"file",        required_argument,      0, 'f'  },
 498  499          { 0, 0, 0, 0 }
 499  500  };
 500  501  
 501  502  static const struct option showeth_lopts[] = {
 502  503          {"parsable",    no_argument,            0, 'p'  },
 503  504          {"parseable",   no_argument,            0, 'p'  },
 504  505          {"extended",    no_argument,            0, 'x'  },
 505  506          {"output",      required_argument,      0, 'o'  },
 506  507          { 0, 0, 0, 0 }
 507  508  };
 508  509  
 509  510  static const struct option vnic_lopts[] = {
 510  511          {"temporary",   no_argument,            0, 't'  },
 511  512          {"root-dir",    required_argument,      0, 'R'  },
 512  513          {"dev",         required_argument,      0, 'd'  },
 513  514          {"mac-address", required_argument,      0, 'm'  },
 514  515          {"cpus",        required_argument,      0, 'c'  },
 515  516          {"bw-limit",    required_argument,      0, 'b'  },
 516  517          {"slot",        required_argument,      0, 'n'  },
 517  518          {"mac-prefix",  required_argument,      0, 'r'  },
 518  519          {"vrid",        required_argument,      0, 'V'  },
 519  520          {"address-family",      required_argument,      0, 'A'  },
 520  521          { 0, 0, 0, 0 }
 521  522  };
 522  523  
 523  524  static const struct option part_lopts[] = {
 524  525          {"temporary",   no_argument,            0, 't'  },
 525  526          {"pkey",        required_argument,      0, 'P'  },
 526  527          {"link",        required_argument,      0, 'l'  },
 527  528          {"force",       no_argument,            0, 'f'  },
 528  529          {"root-dir",    required_argument,      0, 'R'  },
 529  530          {"prop",        required_argument,      0, 'p'  },
 530  531          { 0, 0, 0, 0 }
 531  532  };
 532  533  
 533  534  static const struct option show_part_lopts[] = {
 534  535          {"parsable",    no_argument,            0, 'p'  },
 535  536          {"parseable",   no_argument,            0, 'p'  },
 536  537          {"link",        required_argument,      0, 'l'  },
 537  538          {"persistent",  no_argument,            0, 'P'  },
 538  539          {"output",      required_argument,      0, 'o'  },
 539  540          { 0, 0, 0, 0 }
 540  541  };
 541  542  
 542  543  static const struct option etherstub_lopts[] = {
 543  544          {"temporary",   no_argument,            0, 't'  },
 544  545          {"root-dir",    required_argument,      0, 'R'  },
 545  546          { 0, 0, 0, 0 }
 546  547  };
 547  548  
 548  549  static const struct option usage_opts[] = {
 549  550          {"file",        required_argument,      0, 'f'  },
 550  551          {"format",      required_argument,      0, 'F'  },
 551  552          {"start",       required_argument,      0, 's'  },
 552  553          {"stop",        required_argument,      0, 'e'  },
 553  554          { 0, 0, 0, 0 }
 554  555  };
 555  556  
 556  557  static const struct option simnet_lopts[] = {
 557  558          {"temporary",   no_argument,            0, 't'  },
 558  559          {"root-dir",    required_argument,      0, 'R'  },
 559  560          {"media",       required_argument,      0, 'm'  },
 560  561          {"peer",        required_argument,      0, 'p'  },
 561  562          { 0, 0, 0, 0 }
 562  563  };
 563  564  
 564  565  static const struct option bridge_lopts[] = {
 565  566          { "protect",            required_argument,      0, 'P' },
 566  567          { "root-dir",           required_argument,      0, 'R'  },
 567  568          { "forward-delay",      required_argument,      0, 'd'  },
 568  569          { "force-protocol",     required_argument,      0, 'f'  },
 569  570          { "hello-time",         required_argument,      0, 'h'  },
 570  571          { "link",               required_argument,      0, 'l'  },
 571  572          { "max-age",            required_argument,      0, 'm'  },
 572  573          { "priority",           required_argument,      0, 'p'  },
 573  574          { NULL, NULL, 0, 0 }
 574  575  };
 575  576  
 576  577  static const struct option bridge_show_lopts[] = {
 577  578          { "forwarding", no_argument,            0, 'f' },
 578  579          { "interval",   required_argument,      0, 'i' },
 579  580          { "link",       no_argument,            0, 'l' },
 580  581          { "output",     required_argument,      0, 'o' },
 581  582          { "parsable",   no_argument,            0, 'p' },
 582  583          { "parseable",  no_argument,            0, 'p' },
 583  584          { "statistics", no_argument,            0, 's' },
 584  585          { "trill",      no_argument,            0, 't' },
 585  586          { 0, 0, 0, 0 }
 586  587  };
 587  588  
 588  589  /*
 589  590   * structures for 'dladm show-ether'
 590  591   */
 591  592  static const char *ptype[] = {LEI_ATTR_NAMES};
 592  593  
 593  594  typedef struct ether_fields_buf_s
 594  595  {
 595  596          char    eth_link[15];
 596  597          char    eth_ptype[8];
 597  598          char    eth_state[8];
 598  599          char    eth_autoneg[5];
 599  600          char    eth_spdx[31];
 600  601          char    eth_pause[6];
 601  602          char    eth_rem_fault[16];
 602  603  } ether_fields_buf_t;
 603  604  
 604  605  static const ofmt_field_t ether_fields[] = {
 605  606  /* name,        field width,    offset      callback */
 606  607  { "LINK",       16,
 607  608          offsetof(ether_fields_buf_t, eth_link), print_default_cb},
 608  609  { "PTYPE",      9,
 609  610          offsetof(ether_fields_buf_t, eth_ptype), print_default_cb},
 610  611  { "STATE",      9,
 611  612          offsetof(ether_fields_buf_t, eth_state),
 612  613          print_default_cb},
 613  614  { "AUTO",       6,
 614  615          offsetof(ether_fields_buf_t, eth_autoneg), print_default_cb},
 615  616  { "SPEED-DUPLEX", 32,
 616  617          offsetof(ether_fields_buf_t, eth_spdx), print_default_cb},
 617  618  { "PAUSE",      7,
 618  619          offsetof(ether_fields_buf_t, eth_pause), print_default_cb},
 619  620  { "REM_FAULT",  17,
 620  621          offsetof(ether_fields_buf_t, eth_rem_fault), print_default_cb},
 621  622  {NULL,          0,
 622  623          0,      NULL}}
 623  624  ;
 624  625  
 625  626  typedef struct print_ether_state {
 626  627          const char      *es_link;
 627  628          boolean_t       es_parsable;
 628  629          boolean_t       es_header;
 629  630          boolean_t       es_extended;
 630  631          ofmt_handle_t   es_ofmt;
 631  632  } print_ether_state_t;
 632  633  
 633  634  /*
 634  635   * structures for 'dladm show-link -s' (print statistics)
 635  636   */
 636  637  typedef enum {
 637  638          LINK_S_LINK,
 638  639          LINK_S_IPKTS,
 639  640          LINK_S_RBYTES,
 640  641          LINK_S_IERRORS,
 641  642          LINK_S_OPKTS,
 642  643          LINK_S_OBYTES,
 643  644          LINK_S_OERRORS
 644  645  } link_s_field_index_t;
 645  646  
 646  647  static const ofmt_field_t link_s_fields[] = {
 647  648  /* name,        field width,    index,          callback        */
 648  649  { "LINK",       15,             LINK_S_LINK,    print_link_stats_cb},
 649  650  { "IPACKETS",   10,             LINK_S_IPKTS,   print_link_stats_cb},
 650  651  { "RBYTES",     8,              LINK_S_RBYTES,  print_link_stats_cb},
 651  652  { "IERRORS",    10,             LINK_S_IERRORS, print_link_stats_cb},
 652  653  { "OPACKETS",   12,             LINK_S_OPKTS,   print_link_stats_cb},
 653  654  { "OBYTES",     12,             LINK_S_OBYTES,  print_link_stats_cb},
 654  655  { "OERRORS",    8,              LINK_S_OERRORS, print_link_stats_cb}}
 655  656  ;
 656  657  
 657  658  typedef struct link_args_s {
 658  659          char            *link_s_link;
 659  660          pktsum_t        *link_s_psum;
 660  661  } link_args_t;
 661  662  
 662  663  /*
 663  664   * buffer used by print functions for show-{link,phys,vlan} commands.
 664  665   */
 665  666  typedef struct link_fields_buf_s {
 666  667          char link_name[MAXLINKNAMELEN];
 667  668          char link_class[DLADM_STRSIZE];
 668  669          char link_mtu[11];
 669  670          char link_state[DLADM_STRSIZE];
 670  671          char link_bridge[MAXLINKNAMELEN * MAXPORT];
 671  672          char link_over[MAXLINKNAMELEN * MAXPORT];
 672  673          char link_phys_state[DLADM_STRSIZE];
 673  674          char link_phys_media[DLADM_STRSIZE];
 674  675          char link_phys_speed[DLADM_STRSIZE];
 675  676          char link_phys_duplex[DLPI_LINKNAME_MAX];
 676  677          char link_phys_device[DLPI_LINKNAME_MAX];
 677  678          char link_flags[6];
 678  679          char link_vlan_vid[6];
 679  680  } link_fields_buf_t;
 680  681  
 681  682  /*
 682  683   * structures for 'dladm show-link'
 683  684   */
 684  685  static const ofmt_field_t link_fields[] = {
 685  686  /* name,        field width,    index,  callback */
 686  687  { "LINK",       12,
 687  688          offsetof(link_fields_buf_t, link_name), print_default_cb},
 688  689  { "CLASS",      10,
 689  690          offsetof(link_fields_buf_t, link_class), print_default_cb},
 690  691  { "MTU",        7,
 691  692          offsetof(link_fields_buf_t, link_mtu), print_default_cb},
 692  693  { "STATE",      9,
 693  694          offsetof(link_fields_buf_t, link_state), print_default_cb},
 694  695  { "BRIDGE",     11,
 695  696      offsetof(link_fields_buf_t, link_bridge), print_default_cb},
 696  697  { "OVER",       30,
 697  698          offsetof(link_fields_buf_t, link_over), print_default_cb},
 698  699  { NULL,         0, 0, NULL}}
 699  700  ;
 700  701  
 701  702  /*
 702  703   * structures for 'dladm show-aggr'
 703  704   */
 704  705  typedef struct laggr_fields_buf_s {
 705  706          char laggr_name[DLPI_LINKNAME_MAX];
 706  707          char laggr_policy[9];
 707  708          char laggr_addrpolicy[ETHERADDRL * 3 + 3];
 708  709          char laggr_lacpactivity[14];
 709  710          char laggr_lacptimer[DLADM_STRSIZE];
 710  711          char laggr_flags[7];
 711  712  } laggr_fields_buf_t;
 712  713  
 713  714  typedef struct laggr_args_s {
 714  715          int                     laggr_lport; /* -1 indicates the aggr itself */
 715  716          const char              *laggr_link;
 716  717          dladm_aggr_grp_attr_t   *laggr_ginfop;
 717  718          dladm_status_t          *laggr_status;
 718  719          pktsum_t                *laggr_pktsumtot; /* -s only */
 719  720          pktsum_t                *laggr_diffstats; /* -s only */
 720  721          boolean_t               laggr_parsable;
 721  722  } laggr_args_t;
 722  723  
 723  724  static const ofmt_field_t laggr_fields[] = {
 724  725  /* name,        field width,    offset, callback */
 725  726  { "LINK",       16,
 726  727          offsetof(laggr_fields_buf_t, laggr_name), print_default_cb},
 727  728  { "POLICY",     9,
 728  729          offsetof(laggr_fields_buf_t, laggr_policy), print_default_cb},
 729  730  { "ADDRPOLICY", ETHERADDRL * 3 + 3,
 730  731          offsetof(laggr_fields_buf_t, laggr_addrpolicy), print_default_cb},
 731  732  { "LACPACTIVITY", 14,
 732  733          offsetof(laggr_fields_buf_t, laggr_lacpactivity), print_default_cb},
 733  734  { "LACPTIMER",  12,
 734  735          offsetof(laggr_fields_buf_t, laggr_lacptimer), print_default_cb},
 735  736  { "FLAGS",      8,
 736  737          offsetof(laggr_fields_buf_t, laggr_flags), print_default_cb},
 737  738  { NULL,         0, 0, NULL}}
 738  739  ;
 739  740  
 740  741  /*
 741  742   * structures for 'dladm show-aggr -x'.
 742  743   */
 743  744  typedef enum {
 744  745          AGGR_X_LINK,
 745  746          AGGR_X_PORT,
 746  747          AGGR_X_SPEED,
 747  748          AGGR_X_DUPLEX,
 748  749          AGGR_X_STATE,
 749  750          AGGR_X_ADDRESS,
 750  751          AGGR_X_PORTSTATE
 751  752  } aggr_x_field_index_t;
 752  753  
 753  754  static const ofmt_field_t aggr_x_fields[] = {
 754  755  /* name,        field width,    index           callback */
 755  756  { "LINK",       12,     AGGR_X_LINK,            print_xaggr_cb},
 756  757  { "PORT",       15,     AGGR_X_PORT,            print_xaggr_cb},
 757  758  { "SPEED",      5,      AGGR_X_SPEED,           print_xaggr_cb},
 758  759  { "DUPLEX",     10,     AGGR_X_DUPLEX,          print_xaggr_cb},
 759  760  { "STATE",      10,     AGGR_X_STATE,           print_xaggr_cb},
 760  761  { "ADDRESS",    19,     AGGR_X_ADDRESS,         print_xaggr_cb},
 761  762  { "PORTSTATE",  16,     AGGR_X_PORTSTATE,       print_xaggr_cb},
 762  763  { NULL,         0,      0,                      NULL}}
 763  764  ;
 764  765  
 765  766  /*
 766  767   * structures for 'dladm show-aggr -s'.
 767  768   */
 768  769  typedef enum {
 769  770          AGGR_S_LINK,
 770  771          AGGR_S_PORT,
 771  772          AGGR_S_IPKTS,
 772  773          AGGR_S_RBYTES,
 773  774          AGGR_S_OPKTS,
 774  775          AGGR_S_OBYTES,
 775  776          AGGR_S_IPKTDIST,
 776  777          AGGR_S_OPKTDIST
 777  778  } aggr_s_field_index_t;
 778  779  
 779  780  static const ofmt_field_t aggr_s_fields[] = {
 780  781  { "LINK",               12,     AGGR_S_LINK, print_aggr_stats_cb},
 781  782  { "PORT",               10,     AGGR_S_PORT, print_aggr_stats_cb},
 782  783  { "IPACKETS",           8,      AGGR_S_IPKTS, print_aggr_stats_cb},
 783  784  { "RBYTES",             8,      AGGR_S_RBYTES, print_aggr_stats_cb},
 784  785  { "OPACKETS",           8,      AGGR_S_OPKTS, print_aggr_stats_cb},
 785  786  { "OBYTES",             8,      AGGR_S_OBYTES, print_aggr_stats_cb},
 786  787  { "IPKTDIST",           9,      AGGR_S_IPKTDIST, print_aggr_stats_cb},
 787  788  { "OPKTDIST",           15,     AGGR_S_OPKTDIST, print_aggr_stats_cb},
 788  789  { NULL,                 0,      0,              NULL}}
 789  790  ;
 790  791  
 791  792  /*
 792  793   * structures for 'dladm show-aggr -L'.
 793  794   */
 794  795  typedef enum {
 795  796          AGGR_L_LINK,
 796  797          AGGR_L_PORT,
 797  798          AGGR_L_AGGREGATABLE,
 798  799          AGGR_L_SYNC,
 799  800          AGGR_L_COLL,
 800  801          AGGR_L_DIST,
 801  802          AGGR_L_DEFAULTED,
 802  803          AGGR_L_EXPIRED
 803  804  } aggr_l_field_index_t;
 804  805  
 805  806  static const ofmt_field_t aggr_l_fields[] = {
 806  807  /* name,                field width,    index */
 807  808  { "LINK",               12,     AGGR_L_LINK,            print_lacp_cb},
 808  809  { "PORT",               13,     AGGR_L_PORT,            print_lacp_cb},
 809  810  { "AGGREGATABLE",       13,     AGGR_L_AGGREGATABLE,    print_lacp_cb},
 810  811  { "SYNC",               5,      AGGR_L_SYNC,            print_lacp_cb},
 811  812  { "COLL",               5,      AGGR_L_COLL,            print_lacp_cb},
 812  813  { "DIST",               5,      AGGR_L_DIST,            print_lacp_cb},
 813  814  { "DEFAULTED",          10,     AGGR_L_DEFAULTED,       print_lacp_cb},
 814  815  { "EXPIRED",            15,     AGGR_L_EXPIRED,         print_lacp_cb},
 815  816  { NULL,                 0,      0,                      NULL}}
 816  817  ;
 817  818  
 818  819  /*
 819  820   * structures for 'dladm show-phys'
 820  821   */
 821  822  
 822  823  static const ofmt_field_t phys_fields[] = {
 823  824  /* name,        field width,    offset */
 824  825  { "LINK",       13,
 825  826          offsetof(link_fields_buf_t, link_name), print_default_cb},
 826  827  { "MEDIA",      21,
 827  828          offsetof(link_fields_buf_t, link_phys_media), print_default_cb},
 828  829  { "STATE",      11,
 829  830          offsetof(link_fields_buf_t, link_phys_state), print_default_cb},
 830  831  { "SPEED",      7,
 831  832          offsetof(link_fields_buf_t, link_phys_speed), print_default_cb},
 832  833  { "DUPLEX",     10,
 833  834          offsetof(link_fields_buf_t, link_phys_duplex), print_default_cb},
 834  835  { "DEVICE",     13,
 835  836          offsetof(link_fields_buf_t, link_phys_device), print_default_cb},
 836  837  { "FLAGS",      7,
 837  838          offsetof(link_fields_buf_t, link_flags), print_default_cb},
 838  839  { NULL,         0, NULL, 0}}
 839  840  ;
 840  841  
 841  842  /*
 842  843   * structures for 'dladm show-phys -m'
 843  844   */
 844  845  
 845  846  typedef enum {
 846  847          PHYS_M_LINK,
 847  848          PHYS_M_SLOT,
 848  849          PHYS_M_ADDRESS,
 849  850          PHYS_M_INUSE,
 850  851          PHYS_M_CLIENT
 851  852  } phys_m_field_index_t;
 852  853  
 853  854  static const ofmt_field_t phys_m_fields[] = {
 854  855  /* name,        field width,    offset */
 855  856  { "LINK",       13,     PHYS_M_LINK,    print_phys_one_mac_cb},
 856  857  { "SLOT",       9,      PHYS_M_SLOT,    print_phys_one_mac_cb},
 857  858  { "ADDRESS",    19,     PHYS_M_ADDRESS, print_phys_one_mac_cb},
 858  859  { "INUSE",      5,      PHYS_M_INUSE,   print_phys_one_mac_cb},
 859  860  { "CLIENT",     13,     PHYS_M_CLIENT,  print_phys_one_mac_cb},
 860  861  { NULL,         0,      0,              NULL}}
 861  862  ;
 862  863  
 863  864  /*
 864  865   * structures for 'dladm show-phys -H'
 865  866   */
 866  867  
 867  868  typedef enum {
 868  869          PHYS_H_LINK,
 869  870          PHYS_H_RINGTYPE,
 870  871          PHYS_H_RINGS,
 871  872          PHYS_H_CLIENTS
 872  873  } phys_h_field_index_t;
 873  874  
 874  875  #define RINGSTRLEN      21
 875  876  
 876  877  static const ofmt_field_t phys_h_fields[] = {
 877  878  { "LINK",       13,     PHYS_H_LINK,    print_phys_one_hwgrp_cb},
 878  879  { "RINGTYPE",   9,      PHYS_H_RINGTYPE,        print_phys_one_hwgrp_cb},
 879  880  { "RINGS",      RINGSTRLEN,     PHYS_H_RINGS,   print_phys_one_hwgrp_cb},
 880  881  { "CLIENTS",    24,     PHYS_H_CLIENTS, print_phys_one_hwgrp_cb},
 881  882  { NULL,         0,      0,              NULL}}
 882  883  ;
 883  884  
 884  885  /*
 885  886   * structures for 'dladm show-vlan'
 886  887   */
 887  888  static const ofmt_field_t vlan_fields[] = {
 888  889  { "LINK",       16,
 889  890          offsetof(link_fields_buf_t, link_name), print_default_cb},
 890  891  { "VID",        9,
 891  892          offsetof(link_fields_buf_t, link_vlan_vid), print_default_cb},
 892  893  { "OVER",       13,
 893  894          offsetof(link_fields_buf_t, link_over), print_default_cb},
 894  895  { "FLAGS",      7,
 895  896          offsetof(link_fields_buf_t, link_flags), print_default_cb},
 896  897  { NULL,         0, 0, NULL}}
 897  898  ;
 898  899  
 899  900  /*
 900  901   * structures common to 'dladm scan-wifi' and 'dladm show-wifi'
 901  902   * callback will be determined in parse_wifi_fields.
 902  903   */
 903  904  static ofmt_field_t wifi_common_fields[] = {
 904  905  { "LINK",       11, 0,                          NULL},
 905  906  { "ESSID",      20, DLADM_WLAN_ATTR_ESSID,      NULL},
 906  907  { "BSSID",      18, DLADM_WLAN_ATTR_BSSID,      NULL},
 907  908  { "IBSSID",     18, DLADM_WLAN_ATTR_BSSID,      NULL},
 908  909  { "MODE",       7,  DLADM_WLAN_ATTR_MODE,       NULL},
 909  910  { "SPEED",      7,  DLADM_WLAN_ATTR_SPEED,      NULL},
 910  911  { "BSSTYPE",    9,  DLADM_WLAN_ATTR_BSSTYPE,    NULL},
 911  912  { "SEC",        7,  DLADM_WLAN_ATTR_SECMODE,    NULL},
 912  913  { "STRENGTH",   11, DLADM_WLAN_ATTR_STRENGTH,   NULL},
 913  914  { NULL,         0,  0,                          NULL}};
 914  915  
 915  916  /*
 916  917   * the 'show-wifi' command supports all the fields in wifi_common_fields
 917  918   * plus the AUTH and STATUS fields.
 918  919   */
 919  920  static ofmt_field_t wifi_show_fields[A_CNT(wifi_common_fields) + 2] = {
 920  921  { "AUTH",       9,  DLADM_WLAN_ATTR_AUTH,       NULL},
 921  922  { "STATUS",     18, DLADM_WLAN_LINKATTR_STATUS, print_wifi_status_cb},
 922  923  /* copy wifi_common_fields here */
 923  924  };
 924  925  
 925  926  static char *all_scan_wifi_fields =
 926  927          "link,essid,bssid,sec,strength,mode,speed,bsstype";
 927  928  static char *all_show_wifi_fields =
 928  929          "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype";
 929  930  static char *def_scan_wifi_fields =
 930  931          "link,essid,bssid,sec,strength,mode,speed";
 931  932  static char *def_show_wifi_fields =
 932  933          "link,status,essid,sec,strength,mode,speed";
 933  934  
 934  935  /*
 935  936   * structures for 'dladm show-linkprop'
 936  937   */
 937  938  typedef enum {
 938  939          LINKPROP_LINK,
 939  940          LINKPROP_PROPERTY,
 940  941          LINKPROP_PERM,
 941  942          LINKPROP_VALUE,
 942  943          LINKPROP_DEFAULT,
 943  944          LINKPROP_POSSIBLE
 944  945  } linkprop_field_index_t;
 945  946  
 946  947  static const ofmt_field_t linkprop_fields[] = {
 947  948  /* name,        field width,  index */
 948  949  { "LINK",       13,     LINKPROP_LINK,          print_linkprop_cb},
 949  950  { "PROPERTY",   16,     LINKPROP_PROPERTY,      print_linkprop_cb},
 950  951  { "PERM",       5,      LINKPROP_PERM,          print_linkprop_cb},
 951  952  { "VALUE",      15,     LINKPROP_VALUE,         print_linkprop_cb},
 952  953  { "DEFAULT",    15,     LINKPROP_DEFAULT,       print_linkprop_cb},
 953  954  { "POSSIBLE",   20,     LINKPROP_POSSIBLE,      print_linkprop_cb},
 954  955  { NULL,         0,      0,                      NULL}}
 955  956  ;
 956  957  
 957  958  #define MAX_PROP_LINE           512
 958  959  
 959  960  typedef struct show_linkprop_state {
 960  961          char                    ls_link[MAXLINKNAMELEN];
 961  962          char                    *ls_line;
 962  963          char                    **ls_propvals;
 963  964          dladm_arg_list_t        *ls_proplist;
 964  965          boolean_t               ls_parsable;
 965  966          boolean_t               ls_persist;
 966  967          boolean_t               ls_header;
 967  968          dladm_status_t          ls_status;
 968  969          dladm_status_t          ls_retstatus;
 969  970          ofmt_handle_t           ls_ofmt;
 970  971  } show_linkprop_state_t;
 971  972  
 972  973  typedef struct set_linkprop_state {
 973  974          const char              *ls_name;
 974  975          boolean_t               ls_reset;
 975  976          boolean_t               ls_temp;
 976  977          dladm_status_t          ls_status;
 977  978  } set_linkprop_state_t;
 978  979  
 979  980  typedef struct linkprop_args_s {
 980  981          show_linkprop_state_t   *ls_state;
 981  982          char                    *ls_propname;
 982  983          datalink_id_t           ls_linkid;
 983  984  } linkprop_args_t;
 984  985  
 985  986  /*
 986  987   * structures for 'dladm show-secobj'
 987  988   */
 988  989  typedef struct secobj_fields_buf_s {
 989  990          char                    ss_obj_name[DLADM_SECOBJ_VAL_MAX];
 990  991          char                    ss_class[20];
 991  992          char                    ss_val[30];
 992  993  } secobj_fields_buf_t;
 993  994  
 994  995  static const ofmt_field_t secobj_fields[] = {
 995  996  { "OBJECT",     21,
 996  997          offsetof(secobj_fields_buf_t, ss_obj_name), print_default_cb},
 997  998  { "CLASS",      21,
 998  999          offsetof(secobj_fields_buf_t, ss_class), print_default_cb},
 999 1000  { "VALUE",      31,
1000 1001          offsetof(secobj_fields_buf_t, ss_val), print_default_cb},
1001 1002  { NULL,         0, 0, NULL}}
1002 1003  ;
1003 1004  
1004 1005  /*
1005 1006   * structures for 'dladm show-vnic'
1006 1007   */
1007 1008  typedef struct vnic_fields_buf_s
1008 1009  {
1009 1010          char vnic_link[DLPI_LINKNAME_MAX];
1010 1011          char vnic_over[DLPI_LINKNAME_MAX];
1011 1012          char vnic_speed[6];
1012 1013          char vnic_macaddr[18];
1013 1014          char vnic_macaddrtype[19];
1014 1015          char vnic_vid[6];
1015 1016  } vnic_fields_buf_t;
1016 1017  
1017 1018  static const ofmt_field_t vnic_fields[] = {
1018 1019  { "LINK",               13,
1019 1020          offsetof(vnic_fields_buf_t, vnic_link), print_default_cb},
1020 1021  { "OVER",               13,
1021 1022          offsetof(vnic_fields_buf_t, vnic_over), print_default_cb},
1022 1023  { "SPEED",              7,
1023 1024          offsetof(vnic_fields_buf_t, vnic_speed), print_default_cb},
1024 1025  { "MACADDRESS",         18,
1025 1026          offsetof(vnic_fields_buf_t, vnic_macaddr), print_default_cb},
1026 1027  { "MACADDRTYPE",        20,
1027 1028          offsetof(vnic_fields_buf_t, vnic_macaddrtype), print_default_cb},
1028 1029  { "VID",                7,
1029 1030          offsetof(vnic_fields_buf_t, vnic_vid), print_default_cb},
1030 1031  { NULL,                 0, 0, NULL}}
1031 1032  ;
1032 1033  
1033 1034  /*
1034 1035   * structures for 'dladm show-ib'
1035 1036   */
1036 1037  typedef struct ib_fields_buf_s
1037 1038  {
1038 1039          char ib_link[DLPI_LINKNAME_MAX];
1039 1040          char ib_hcaguid[17];
1040 1041          char ib_portguid[17];
1041 1042          char ib_portnum[4];
1042 1043          char ib_state[6];
1043 1044          char ib_pkeys[MAXPKEYSTRSZ];
1044 1045  } ib_fields_buf_t;
1045 1046  
1046 1047  static const ofmt_field_t ib_fields[] = {
1047 1048  { "LINK",               13,
1048 1049          offsetof(ib_fields_buf_t, ib_link),     print_default_cb},
1049 1050  { "HCAGUID",            IBGUIDSTRLEN,
1050 1051          offsetof(ib_fields_buf_t, ib_hcaguid),  print_default_cb},
1051 1052  { "PORTGUID",           IBGUIDSTRLEN,
1052 1053          offsetof(ib_fields_buf_t, ib_portguid), print_default_cb},
1053 1054  { "PORT",               IBPORTSTRLEN,
1054 1055          offsetof(ib_fields_buf_t, ib_portnum), print_default_cb},
1055 1056  { "STATE",              7,
1056 1057          offsetof(ib_fields_buf_t, ib_state), print_default_cb},
1057 1058  { "PKEYS",      18,
1058 1059          offsetof(ib_fields_buf_t, ib_pkeys), print_default_cb},
1059 1060  { NULL,                 0, 0, NULL}};
1060 1061  
1061 1062  /*
1062 1063   * structures for 'dladm show-part'
1063 1064   */
1064 1065  typedef struct part_fields_buf_s
1065 1066  {
1066 1067          char part_link[DLPI_LINKNAME_MAX];
1067 1068          char part_pkey[5];
1068 1069          char part_over[DLPI_LINKNAME_MAX];
1069 1070          char part_state[8];
1070 1071          char part_flags[5];
1071 1072  } part_fields_buf_t;
1072 1073  
1073 1074  static const ofmt_field_t part_fields[] = {
1074 1075  { "LINK",               13,
1075 1076          offsetof(part_fields_buf_t, part_link), print_default_cb},
1076 1077  { "PKEY",               MAXPKEYLEN,
1077 1078          offsetof(part_fields_buf_t, part_pkey), print_default_cb},
1078 1079  { "OVER",               13,
1079 1080          offsetof(part_fields_buf_t, part_over), print_default_cb},
1080 1081  { "STATE",              9,
1081 1082          offsetof(part_fields_buf_t, part_state), print_default_cb},
1082 1083  { "FLAGS",      5,
1083 1084          offsetof(part_fields_buf_t, part_flags), print_default_cb},
1084 1085  { NULL,                 0, 0, NULL}};
1085 1086  
1086 1087  /*
1087 1088   * structures for 'dladm show-simnet'
1088 1089   */
1089 1090  typedef struct simnet_fields_buf_s
1090 1091  {
1091 1092          char simnet_name[DLPI_LINKNAME_MAX];
1092 1093          char simnet_media[DLADM_STRSIZE];
1093 1094          char simnet_macaddr[18];
1094 1095          char simnet_otherlink[DLPI_LINKNAME_MAX];
1095 1096  } simnet_fields_buf_t;
1096 1097  
1097 1098  static const ofmt_field_t simnet_fields[] = {
1098 1099  { "LINK",               12,
1099 1100          offsetof(simnet_fields_buf_t, simnet_name), print_default_cb},
1100 1101  { "MEDIA",              20,
1101 1102          offsetof(simnet_fields_buf_t, simnet_media), print_default_cb},
1102 1103  { "MACADDRESS",         18,
1103 1104          offsetof(simnet_fields_buf_t, simnet_macaddr), print_default_cb},
1104 1105  { "OTHERLINK",          12,
1105 1106          offsetof(simnet_fields_buf_t, simnet_otherlink), print_default_cb},
1106 1107  { NULL,                 0, 0, NULL}}
1107 1108  ;
1108 1109  
1109 1110  /*
1110 1111   * structures for 'dladm show-usage'
1111 1112   */
1112 1113  
1113 1114  typedef struct  usage_fields_buf_s {
1114 1115          char    usage_link[12];
1115 1116          char    usage_duration[10];
1116 1117          char    usage_ipackets[9];
1117 1118          char    usage_rbytes[10];
1118 1119          char    usage_opackets[9];
1119 1120          char    usage_obytes[10];
1120 1121          char    usage_bandwidth[14];
1121 1122  } usage_fields_buf_t;
1122 1123  
1123 1124  static const ofmt_field_t usage_fields[] = {
1124 1125  { "LINK",       13,
1125 1126          offsetof(usage_fields_buf_t, usage_link), print_default_cb},
1126 1127  { "DURATION",   11,
1127 1128          offsetof(usage_fields_buf_t, usage_duration), print_default_cb},
1128 1129  { "IPACKETS",   10,
1129 1130          offsetof(usage_fields_buf_t, usage_ipackets), print_default_cb},
1130 1131  { "RBYTES",     11,
1131 1132          offsetof(usage_fields_buf_t, usage_rbytes), print_default_cb},
1132 1133  { "OPACKETS",   10,
1133 1134          offsetof(usage_fields_buf_t, usage_opackets), print_default_cb},
1134 1135  { "OBYTES",     11,
1135 1136          offsetof(usage_fields_buf_t, usage_obytes), print_default_cb},
1136 1137  { "BANDWIDTH",  15,
1137 1138          offsetof(usage_fields_buf_t, usage_bandwidth), print_default_cb},
1138 1139  { NULL,         0, 0, NULL}}
1139 1140  ;
1140 1141  
1141 1142  
1142 1143  /*
1143 1144   * structures for 'dladm show-usage link'
1144 1145   */
1145 1146  
1146 1147  typedef struct  usage_l_fields_buf_s {
1147 1148          char    usage_l_link[12];
1148 1149          char    usage_l_stime[13];
1149 1150          char    usage_l_etime[13];
1150 1151          char    usage_l_rbytes[8];
1151 1152          char    usage_l_obytes[8];
1152 1153          char    usage_l_bandwidth[14];
1153 1154  } usage_l_fields_buf_t;
1154 1155  
1155 1156  static const ofmt_field_t usage_l_fields[] = {
1156 1157  /* name,        field width,    offset */
1157 1158  { "LINK",       13,
1158 1159          offsetof(usage_l_fields_buf_t, usage_l_link), print_default_cb},
1159 1160  { "START",      14,
1160 1161          offsetof(usage_l_fields_buf_t, usage_l_stime), print_default_cb},
1161 1162  { "END",        14,
1162 1163          offsetof(usage_l_fields_buf_t, usage_l_etime), print_default_cb},
1163 1164  { "RBYTES",     9,
1164 1165          offsetof(usage_l_fields_buf_t, usage_l_rbytes), print_default_cb},
1165 1166  { "OBYTES",     9,
1166 1167          offsetof(usage_l_fields_buf_t, usage_l_obytes), print_default_cb},
1167 1168  { "BANDWIDTH",  15,
1168 1169          offsetof(usage_l_fields_buf_t, usage_l_bandwidth), print_default_cb},
1169 1170  { NULL,         0, 0, NULL}}
1170 1171  ;
1171 1172  
1172 1173  /* IPTUN_*FLAG_INDEX values are indices into iptun_flags below. */
1173 1174  enum { IPTUN_SFLAG_INDEX, IPTUN_IFLAG_INDEX, IPTUN_NUM_FLAGS };
1174 1175  
1175 1176  /*
1176 1177   * structures for 'dladm show-iptun'
1177 1178   */
1178 1179  typedef struct iptun_fields_buf_s {
1179 1180          char    iptun_name[MAXLINKNAMELEN];
1180 1181          char    iptun_type[5];
1181 1182          char    iptun_laddr[NI_MAXHOST];
1182 1183          char    iptun_raddr[NI_MAXHOST];
1183 1184          char    iptun_flags[IPTUN_NUM_FLAGS + 1];
1184 1185  } iptun_fields_buf_t;
1185 1186  
1186 1187  static const ofmt_field_t iptun_fields[] = {
1187 1188  { "LINK",       16,
1188 1189          offsetof(iptun_fields_buf_t, iptun_name), print_default_cb },
1189 1190  { "TYPE",       6,
1190 1191          offsetof(iptun_fields_buf_t, iptun_type), print_default_cb },
1191 1192  { "FLAGS",      7,
1192 1193          offsetof(iptun_fields_buf_t, iptun_flags), print_default_cb },
1193 1194  { "LOCAL",      20,
1194 1195          offsetof(iptun_fields_buf_t, iptun_laddr), print_default_cb },
1195 1196  { "REMOTE",     20,
1196 1197          offsetof(iptun_fields_buf_t, iptun_raddr), print_default_cb },
1197 1198  { NULL, 0, 0, NULL}
1198 1199  };
1199 1200  
1200 1201  /*
1201 1202   * structures for 'dladm show-bridge'.  These are based on sections 14.8.1.1.3
1202 1203   * and 14.8.1.2.2 of IEEE 802.1D-2004.
1203 1204   */
1204 1205  typedef struct bridge_fields_buf_s {
1205 1206          char bridge_name[MAXLINKNAMELEN]; /* 14.4.1.2.3(b) */
1206 1207          char bridge_protect[7];         /* stp or trill */
1207 1208          char bridge_address[24];        /* 17.18.3, 7.12.5, 14.4.1.2.3(a) */
1208 1209          char bridge_priority[7];        /* 17.18.3 9.2.5 - only upper 4 bits */
1209 1210          char bridge_bmaxage[7];         /* 17.18.4 configured */
1210 1211          char bridge_bhellotime[7];      /* 17.18.4 configured */
1211 1212          char bridge_bfwddelay[7];       /* 17.18.4 configured */
1212 1213          char bridge_forceproto[3];      /* 17.13.4 configured */
1213 1214          char bridge_tctime[12];         /* 14.8.1.1.3(b) */
1214 1215          char bridge_tccount[12];        /* 17.17.8 */
1215 1216          char bridge_tchange[12];        /* 17.17.8 */
1216 1217          char bridge_desroot[24];        /* 17.18.6 priority "/" MAC */
1217 1218          char bridge_rootcost[12];       /* 17.18.6 */
1218 1219          char bridge_rootport[12];       /* 17.18.6 */
1219 1220          char bridge_maxage[7];          /* 17.18.7 for root */
1220 1221          char bridge_hellotime[7];       /* 17.13.6 for root */
1221 1222          char bridge_fwddelay[7];        /* 17.13.5 for root */
1222 1223          char bridge_holdtime[12];       /* 17.13.12 for root */
1223 1224  } bridge_fields_buf_t;
1224 1225  
1225 1226  static ofmt_field_t bridge_fields[] = {
1226 1227  /* name,        field width,    offset, callback        */
1227 1228  { "BRIDGE",     12,
1228 1229      offsetof(bridge_fields_buf_t, bridge_name), print_default_cb },
1229 1230  { "PROTECT",    8,
1230 1231      offsetof(bridge_fields_buf_t, bridge_protect), print_default_cb },
1231 1232  { "ADDRESS",    19,
1232 1233      offsetof(bridge_fields_buf_t, bridge_address), print_default_cb },
1233 1234  { "PRIORITY",   9,
1234 1235      offsetof(bridge_fields_buf_t, bridge_priority), print_default_cb },
1235 1236  { "BMAXAGE",    8,
1236 1237      offsetof(bridge_fields_buf_t, bridge_bmaxage), print_default_cb },
1237 1238  { "BHELLOTIME", 11,
1238 1239      offsetof(bridge_fields_buf_t, bridge_bhellotime), print_default_cb },
1239 1240  { "BFWDDELAY",  10,
1240 1241      offsetof(bridge_fields_buf_t, bridge_bfwddelay), print_default_cb },
1241 1242  { "FORCEPROTO", 11,
1242 1243      offsetof(bridge_fields_buf_t, bridge_forceproto), print_default_cb },
1243 1244  { "TCTIME",     10,
1244 1245      offsetof(bridge_fields_buf_t, bridge_tctime), print_default_cb },
1245 1246  { "TCCOUNT",    10,
1246 1247      offsetof(bridge_fields_buf_t, bridge_tccount), print_default_cb },
1247 1248  { "TCHANGE",    10,
1248 1249      offsetof(bridge_fields_buf_t, bridge_tchange), print_default_cb },
1249 1250  { "DESROOT",    23,
1250 1251      offsetof(bridge_fields_buf_t, bridge_desroot), print_default_cb },
1251 1252  { "ROOTCOST",   11,
1252 1253      offsetof(bridge_fields_buf_t, bridge_rootcost), print_default_cb },
1253 1254  { "ROOTPORT",   11,
1254 1255      offsetof(bridge_fields_buf_t, bridge_rootport), print_default_cb },
1255 1256  { "MAXAGE",     8,
1256 1257      offsetof(bridge_fields_buf_t, bridge_maxage), print_default_cb },
1257 1258  { "HELLOTIME",  10,
1258 1259      offsetof(bridge_fields_buf_t, bridge_hellotime), print_default_cb },
1259 1260  { "FWDDELAY",   9,
1260 1261      offsetof(bridge_fields_buf_t, bridge_fwddelay), print_default_cb },
1261 1262  { "HOLDTIME",   9,
1262 1263      offsetof(bridge_fields_buf_t, bridge_holdtime), print_default_cb },
1263 1264  { NULL,         0, 0, NULL}};
1264 1265  
1265 1266  /*
1266 1267   * structures for 'dladm show-bridge -l'.  These are based on 14.4.1.2.3 and
1267 1268   * 14.8.2.1.3 of IEEE 802.1D-2004.
1268 1269   */
1269 1270  typedef struct bridge_link_fields_buf_s {
1270 1271          char bridgel_link[MAXLINKNAMELEN];
1271 1272          char bridgel_index[7];                  /* 14.4.1.2.3(d1) */
1272 1273          char bridgel_state[11];                 /* 14.8.2.1.3(b) */
1273 1274          char bridgel_uptime[7];                 /* 14.8.2.1.3(a) */
1274 1275          char bridgel_opercost[7]                /* 14.8.2.1.3(d) */;
1275 1276          char bridgel_operp2p[4];                /* 14.8.2.1.3(p) */
1276 1277          char bridgel_operedge[4];               /* 14.8.2.1.3(k) */
1277 1278          char bridgel_desroot[23];               /* 14.8.2.1.3(e) */
1278 1279          char bridgel_descost[12];               /* 14.8.2.1.3(f) */
1279 1280          char bridgel_desbridge[23];             /* 14.8.2.1.3(g) */
1280 1281          char bridgel_desport[7];                /* 14.8.2.1.3(h) */
1281 1282          char bridgel_tcack[4];                  /* 14.8.2.1.3(i) */
1282 1283  } bridge_link_fields_buf_t;
1283 1284  
1284 1285  static ofmt_field_t bridge_link_fields[] = {
1285 1286  /* name,        field width,    offset, callback        */
1286 1287  { "LINK",               12,
1287 1288      offsetof(bridge_link_fields_buf_t, bridgel_link), print_default_cb },
1288 1289  { "INDEX",      8,
1289 1290      offsetof(bridge_link_fields_buf_t, bridgel_index), print_default_cb },
1290 1291  { "STATE",      12,
1291 1292      offsetof(bridge_link_fields_buf_t, bridgel_state), print_default_cb },
1292 1293  { "UPTIME",     8,
1293 1294      offsetof(bridge_link_fields_buf_t, bridgel_uptime), print_default_cb },
1294 1295  { "OPERCOST",   9,
1295 1296      offsetof(bridge_link_fields_buf_t, bridgel_opercost), print_default_cb },
1296 1297  { "OPERP2P",    8,
1297 1298      offsetof(bridge_link_fields_buf_t, bridgel_operp2p), print_default_cb },
1298 1299  { "OPEREDGE",   9,
1299 1300      offsetof(bridge_link_fields_buf_t, bridgel_operedge), print_default_cb },
1300 1301  { "DESROOT",    22,
1301 1302      offsetof(bridge_link_fields_buf_t, bridgel_desroot), print_default_cb },
1302 1303  { "DESCOST",    11,
1303 1304      offsetof(bridge_link_fields_buf_t, bridgel_descost), print_default_cb },
1304 1305  { "DESBRIDGE",  22,
1305 1306      offsetof(bridge_link_fields_buf_t, bridgel_desbridge), print_default_cb },
1306 1307  { "DESPORT",    8,
1307 1308      offsetof(bridge_link_fields_buf_t, bridgel_desport), print_default_cb },
1308 1309  { "TCACK",      6,
1309 1310      offsetof(bridge_link_fields_buf_t, bridgel_tcack), print_default_cb },
1310 1311  { NULL,         0, 0, NULL}};
1311 1312  
1312 1313  /*
1313 1314   * structures for 'dladm show-bridge -s'.  These are not based on IEEE
1314 1315   * 802.1D-2004.
1315 1316   */
1316 1317  #define ULONG_DIG       (((sizeof (ulong_t) * NBBY) * 3 / 10) + 1)
1317 1318  #define UINT64_DIG      (((sizeof (uint64_t) * NBBY) * 3 / 10) + 1)
1318 1319  typedef struct bridge_statfields_buf_s {
1319 1320          char bridges_name[MAXLINKNAMELEN];
1320 1321          char bridges_drops[UINT64_DIG];
1321 1322          char bridges_forwards[UINT64_DIG];
1322 1323          char bridges_mbcast[UINT64_DIG];
1323 1324          char bridges_unknown[UINT64_DIG];
1324 1325          char bridges_recv[UINT64_DIG];
1325 1326          char bridges_sent[UINT64_DIG];
1326 1327  } bridge_statfields_buf_t;
1327 1328  
1328 1329  static ofmt_field_t bridge_statfields[] = {
1329 1330  /* name,        field width,    offset, callback        */
1330 1331  { "BRIDGE",     12,
1331 1332      offsetof(bridge_statfields_buf_t, bridges_name), print_default_cb },
1332 1333  { "DROPS",      12,
1333 1334      offsetof(bridge_statfields_buf_t, bridges_drops), print_default_cb },
1334 1335  { "FORWARDS",   12,
1335 1336      offsetof(bridge_statfields_buf_t, bridges_forwards), print_default_cb },
1336 1337  { "MBCAST",     12,
1337 1338      offsetof(bridge_statfields_buf_t, bridges_mbcast), print_default_cb },
1338 1339  { "UNKNOWN",    12,
1339 1340      offsetof(bridge_statfields_buf_t, bridges_unknown), print_default_cb },
1340 1341  { "RECV",       12,
1341 1342      offsetof(bridge_statfields_buf_t, bridges_recv), print_default_cb },
1342 1343  { "SENT",       12,
1343 1344      offsetof(bridge_statfields_buf_t, bridges_sent), print_default_cb },
1344 1345  { NULL,         0, 0, NULL}};
1345 1346  
1346 1347  /*
1347 1348   * structures for 'dladm show-bridge -s -l'.  These are based in part on
1348 1349   * section 14.6.1.1.3 of IEEE 802.1D-2004.
1349 1350   */
1350 1351  typedef struct bridge_link_statfields_buf_s {
1351 1352          char bridgels_link[MAXLINKNAMELEN];
1352 1353          char bridgels_cfgbpdu[ULONG_DIG];
1353 1354          char bridgels_tcnbpdu[ULONG_DIG];
1354 1355          char bridgels_rstpbpdu[ULONG_DIG];
1355 1356          char bridgels_txbpdu[ULONG_DIG];
1356 1357          char bridgels_drops[UINT64_DIG];        /* 14.6.1.1.3(d) */
1357 1358          char bridgels_recv[UINT64_DIG];         /* 14.6.1.1.3(a) */
1358 1359          char bridgels_xmit[UINT64_DIG];         /* 14.6.1.1.3(c) */
1359 1360  } bridge_link_statfields_buf_t;
1360 1361  
1361 1362  static ofmt_field_t bridge_link_statfields[] = {
1362 1363  /* name,        field width,    offset, callback        */
1363 1364  { "LINK",       12,
1364 1365      offsetof(bridge_link_statfields_buf_t, bridgels_link), print_default_cb },
1365 1366  { "CFGBPDU",    9,
1366 1367      offsetof(bridge_link_statfields_buf_t, bridgels_cfgbpdu),
1367 1368      print_default_cb },
1368 1369  { "TCNBPDU",    9,
1369 1370      offsetof(bridge_link_statfields_buf_t, bridgels_tcnbpdu),
1370 1371      print_default_cb },
1371 1372  { "RSTPBPDU",   9,
1372 1373      offsetof(bridge_link_statfields_buf_t, bridgels_rstpbpdu),
1373 1374      print_default_cb },
1374 1375  { "TXBPDU",     9,
1375 1376      offsetof(bridge_link_statfields_buf_t, bridgels_txbpdu), print_default_cb },
1376 1377  { "DROPS",      9,
1377 1378      offsetof(bridge_link_statfields_buf_t, bridgels_drops), print_default_cb },
1378 1379  { "RECV",       9,
1379 1380      offsetof(bridge_link_statfields_buf_t, bridgels_recv), print_default_cb },
1380 1381  { "XMIT",       9,
1381 1382      offsetof(bridge_link_statfields_buf_t, bridgels_xmit), print_default_cb },
1382 1383  { NULL,         0, 0, NULL}};
1383 1384  
1384 1385  /*
1385 1386   * structures for 'dladm show-bridge -f'.  These are based in part on
1386 1387   * section  14.7.6.3.3 of IEEE 802.1D-2004.
1387 1388   */
1388 1389  typedef struct bridge_fwd_fields_buf_s {
1389 1390          char bridgef_dest[18];                  /* 14.7.6.3.3(a) */
1390 1391          char bridgef_age[8];
1391 1392          char bridgef_flags[6];
1392 1393          char bridgef_output[MAXLINKNAMELEN];    /* 14.7.6.3.3(c) */
1393 1394  } bridge_fwd_fields_buf_t;
1394 1395  
1395 1396  static ofmt_field_t bridge_fwd_fields[] = {
1396 1397  /* name,        field width,    offset, callback        */
1397 1398  { "DEST",       17,
1398 1399      offsetof(bridge_fwd_fields_buf_t, bridgef_dest), print_default_cb },
1399 1400  { "AGE",        7,
1400 1401      offsetof(bridge_fwd_fields_buf_t, bridgef_age), print_default_cb },
1401 1402  { "FLAGS",      6,
1402 1403      offsetof(bridge_fwd_fields_buf_t, bridgef_flags), print_default_cb },
1403 1404  { "OUTPUT",     12,
1404 1405      offsetof(bridge_fwd_fields_buf_t, bridgef_output), print_default_cb },
1405 1406  { NULL,         0, 0, NULL}};
1406 1407  
1407 1408  /*
1408 1409   * structures for 'dladm show-bridge -t'.
1409 1410   */
1410 1411  typedef struct bridge_trill_fields_buf_s {
1411 1412          char bridget_nick[6];
1412 1413          char bridget_flags[6];
1413 1414          char bridget_link[MAXLINKNAMELEN];
1414 1415          char bridget_nexthop[18];
1415 1416  } bridge_trill_fields_buf_t;
1416 1417  
1417 1418  static ofmt_field_t bridge_trill_fields[] = {
1418 1419  /* name,        field width,    offset, callback        */
1419 1420  { "NICK",       5,
1420 1421      offsetof(bridge_trill_fields_buf_t, bridget_nick), print_default_cb },
1421 1422  { "FLAGS",      6,
1422 1423      offsetof(bridge_trill_fields_buf_t, bridget_flags), print_default_cb },
1423 1424  { "LINK",       12,
1424 1425      offsetof(bridge_trill_fields_buf_t, bridget_link), print_default_cb },
1425 1426  { "NEXTHOP",    17,
1426 1427      offsetof(bridge_trill_fields_buf_t, bridget_nexthop), print_default_cb },
1427 1428  { NULL,         0, 0, NULL}};
1428 1429  
1429 1430  static char *progname;
1430 1431  static sig_atomic_t signalled;
1431 1432  
1432 1433  /*
1433 1434   * Handle to libdladm.  Opened in main() before the sub-command
1434 1435   * specific function is called.
1435 1436   */
1436 1437  static dladm_handle_t handle = NULL;
1437 1438  
1438 1439  #define DLADM_ETHERSTUB_NAME    "etherstub"
1439 1440  #define DLADM_IS_ETHERSTUB(id)  (id == DATALINK_INVALID_LINKID)
1440 1441  
1441 1442  static void
1442 1443  usage(void)
1443 1444  {
1444 1445          int     i;
1445 1446          cmd_t   *cmdp;
1446 1447          (void) fprintf(stderr, gettext("usage:  dladm <subcommand> <args> ..."
1447 1448              "\n"));
1448 1449          for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
1449 1450                  cmdp = &cmds[i];
1450 1451                  if (cmdp->c_usage != NULL)
1451 1452                          (void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage));
1452 1453          }
1453 1454  
1454 1455          /* close dladm handle if it was opened */
1455 1456          if (handle != NULL)
1456 1457                  dladm_close(handle);
1457 1458  
1458 1459          exit(EXIT_FAILURE);
1459 1460  }
1460 1461  
1461 1462  int
1462 1463  main(int argc, char *argv[])
1463 1464  {
1464 1465          int     i;
1465 1466          cmd_t   *cmdp;
1466 1467          dladm_status_t status;
1467 1468  
1468 1469          (void) setlocale(LC_ALL, "");
1469 1470  #if !defined(TEXT_DOMAIN)
1470 1471  #define TEXT_DOMAIN "SYS_TEST"
1471 1472  #endif
1472 1473          (void) textdomain(TEXT_DOMAIN);
1473 1474  
1474 1475          progname = argv[0];
1475 1476  
1476 1477          if (argc < 2)
1477 1478                  usage();
1478 1479  
1479 1480          for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
1480 1481                  cmdp = &cmds[i];
1481 1482                  if (strcmp(argv[1], cmdp->c_name) == 0) {
1482 1483                          /* Open the libdladm handle */
1483 1484                          if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) {
1484 1485                                  die_dlerr(status,
1485 1486                                      "could not open /dev/dld");
1486 1487                          }
1487 1488  
1488 1489                          cmdp->c_fn(argc - 1, &argv[1], cmdp->c_usage);
1489 1490  
1490 1491                          dladm_close(handle);
1491 1492                          return (EXIT_SUCCESS);
1492 1493                  }
1493 1494          }
1494 1495  
1495 1496          (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
1496 1497              progname, argv[1]);
1497 1498          usage();
1498 1499          return (EXIT_FAILURE);
1499 1500  }
1500 1501  
1501 1502  /*ARGSUSED*/
1502 1503  static int
1503 1504  show_usage_date(dladm_usage_t *usage, void *arg)
1504 1505  {
1505 1506          show_usage_state_t      *state = (show_usage_state_t *)arg;
1506 1507          time_t                  stime;
1507 1508          char                    timebuf[20];
1508 1509          dladm_status_t          status;
1509 1510          uint32_t                flags;
1510 1511  
1511 1512          /*
1512 1513           * Only show usage information for existing links unless '-a'
1513 1514           * is specified.
1514 1515           */
1515 1516          if (!state->us_showall) {
1516 1517                  if ((status = dladm_name2info(handle, usage->du_name,
1517 1518                      NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) {
1518 1519                          return (status);
1519 1520                  }
1520 1521                  if ((flags & DLADM_OPT_ACTIVE) == 0)
1521 1522                          return (DLADM_STATUS_LINKINVAL);
1522 1523          }
1523 1524  
1524 1525          stime = usage->du_stime;
1525 1526          (void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y",
1526 1527              localtime(&stime));
1527 1528          (void) printf("%s\n", timebuf);
1528 1529  
1529 1530          return (DLADM_STATUS_OK);
1530 1531  }
1531 1532  
1532 1533  static int
1533 1534  show_usage_time(dladm_usage_t *usage, void *arg)
1534 1535  {
1535 1536          show_usage_state_t      *state = (show_usage_state_t *)arg;
1536 1537          char                    buf[DLADM_STRSIZE];
1537 1538          usage_l_fields_buf_t    ubuf;
1538 1539          time_t                  time;
1539 1540          double                  bw;
1540 1541          dladm_status_t          status;
1541 1542          uint32_t                flags;
1542 1543  
1543 1544          /*
1544 1545           * Only show usage information for existing links unless '-a'
1545 1546           * is specified.
1546 1547           */
1547 1548          if (!state->us_showall) {
1548 1549                  if ((status = dladm_name2info(handle, usage->du_name,
1549 1550                      NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) {
1550 1551                          return (status);
1551 1552                  }
1552 1553                  if ((flags & DLADM_OPT_ACTIVE) == 0)
1553 1554                          return (DLADM_STATUS_LINKINVAL);
1554 1555          }
1555 1556  
1556 1557          if (state->us_plot) {
1557 1558                  if (!state->us_printheader) {
1558 1559                          if (state->us_first) {
1559 1560                                  (void) printf("# Time");
1560 1561                                  state->us_first = B_FALSE;
1561 1562                          }
1562 1563                          (void) printf(" %s", usage->du_name);
1563 1564                          if (usage->du_last) {
1564 1565                                  (void) printf("\n");
1565 1566                                  state->us_first = B_TRUE;
1566 1567                                  state->us_printheader = B_TRUE;
1567 1568                          }
1568 1569                  } else {
1569 1570                          if (state->us_first) {
1570 1571                                  time = usage->du_etime;
1571 1572                                  (void) strftime(buf, sizeof (buf), "%T",
1572 1573                                      localtime(&time));
1573 1574                                  state->us_first = B_FALSE;
1574 1575                                  (void) printf("%s", buf);
1575 1576                          }
1576 1577                          bw = (double)usage->du_bandwidth/1000;
1577 1578                          (void) printf(" %.2f", bw);
1578 1579                          if (usage->du_last) {
1579 1580                                  (void) printf("\n");
1580 1581                                  state->us_first = B_TRUE;
1581 1582                          }
1582 1583                  }
1583 1584                  return (DLADM_STATUS_OK);
1584 1585          }
1585 1586  
1586 1587          bzero(&ubuf, sizeof (ubuf));
1587 1588  
1588 1589          (void) snprintf(ubuf.usage_l_link, sizeof (ubuf.usage_l_link), "%s",
1589 1590              usage->du_name);
1590 1591          time = usage->du_stime;
1591 1592          (void) strftime(buf, sizeof (buf), "%T", localtime(&time));
1592 1593          (void) snprintf(ubuf.usage_l_stime, sizeof (ubuf.usage_l_stime), "%s",
1593 1594              buf);
1594 1595          time = usage->du_etime;
1595 1596          (void) strftime(buf, sizeof (buf), "%T", localtime(&time));
1596 1597          (void) snprintf(ubuf.usage_l_etime, sizeof (ubuf.usage_l_etime), "%s",
1597 1598              buf);
1598 1599          (void) snprintf(ubuf.usage_l_rbytes, sizeof (ubuf.usage_l_rbytes),
1599 1600              "%llu", usage->du_rbytes);
1600 1601          (void) snprintf(ubuf.usage_l_obytes, sizeof (ubuf.usage_l_obytes),
1601 1602              "%llu", usage->du_obytes);
1602 1603          (void) snprintf(ubuf.usage_l_bandwidth, sizeof (ubuf.usage_l_bandwidth),
1603 1604              "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf));
1604 1605  
1605 1606          ofmt_print(state->us_ofmt, &ubuf);
1606 1607          return (DLADM_STATUS_OK);
1607 1608  }
1608 1609  
1609 1610  static int
1610 1611  show_usage_res(dladm_usage_t *usage, void *arg)
1611 1612  {
1612 1613          show_usage_state_t      *state = (show_usage_state_t *)arg;
1613 1614          char                    buf[DLADM_STRSIZE];
1614 1615          usage_fields_buf_t      ubuf;
1615 1616          dladm_status_t          status;
1616 1617          uint32_t                flags;
1617 1618  
1618 1619          /*
1619 1620           * Only show usage information for existing links unless '-a'
1620 1621           * is specified.
1621 1622           */
1622 1623          if (!state->us_showall) {
1623 1624                  if ((status = dladm_name2info(handle, usage->du_name,
1624 1625                      NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) {
1625 1626                          return (status);
1626 1627                  }
1627 1628                  if ((flags & DLADM_OPT_ACTIVE) == 0)
1628 1629                          return (DLADM_STATUS_LINKINVAL);
1629 1630          }
1630 1631  
1631 1632          bzero(&ubuf, sizeof (ubuf));
1632 1633  
1633 1634          (void) snprintf(ubuf.usage_link, sizeof (ubuf.usage_link), "%s",
1634 1635              usage->du_name);
1635 1636          (void) snprintf(ubuf.usage_duration, sizeof (ubuf.usage_duration),
1636 1637              "%llu", usage->du_duration);
1637 1638          (void) snprintf(ubuf.usage_ipackets, sizeof (ubuf.usage_ipackets),
1638 1639              "%llu", usage->du_ipackets);
1639 1640          (void) snprintf(ubuf.usage_rbytes, sizeof (ubuf.usage_rbytes),
1640 1641              "%llu", usage->du_rbytes);
1641 1642          (void) snprintf(ubuf.usage_opackets, sizeof (ubuf.usage_opackets),
1642 1643              "%llu", usage->du_opackets);
1643 1644          (void) snprintf(ubuf.usage_obytes, sizeof (ubuf.usage_obytes),
1644 1645              "%llu", usage->du_obytes);
1645 1646          (void) snprintf(ubuf.usage_bandwidth, sizeof (ubuf.usage_bandwidth),
1646 1647              "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf));
1647 1648  
1648 1649          ofmt_print(state->us_ofmt, &ubuf);
1649 1650  
1650 1651          return (DLADM_STATUS_OK);
1651 1652  }
1652 1653  
1653 1654  static boolean_t
1654 1655  valid_formatspec(char *formatspec_str)
1655 1656  {
1656 1657          if (strcmp(formatspec_str, "gnuplot") == 0)
1657 1658                  return (B_TRUE);
1658 1659          return (B_FALSE);
1659 1660  
1660 1661  }
1661 1662  
1662 1663  /*ARGSUSED*/
1663 1664  static void
1664 1665  do_show_usage(int argc, char *argv[], const char *use)
1665 1666  {
1666 1667          char                    *file = NULL;
1667 1668          int                     opt;
1668 1669          dladm_status_t          status;
1669 1670          boolean_t               d_arg = B_FALSE;
1670 1671          char                    *stime = NULL;
1671 1672          char                    *etime = NULL;
1672 1673          char                    *resource = NULL;
1673 1674          show_usage_state_t      state;
1674 1675          boolean_t               o_arg = B_FALSE;
1675 1676          boolean_t               F_arg = B_FALSE;
1676 1677          char                    *fields_str = NULL;
1677 1678          char                    *formatspec_str = NULL;
1678 1679          char                    *all_l_fields =
1679 1680              "link,start,end,rbytes,obytes,bandwidth";
1680 1681          ofmt_handle_t           ofmt;
1681 1682          ofmt_status_t           oferr;
1682 1683          uint_t                  ofmtflags = 0;
1683 1684  
1684 1685          bzero(&state, sizeof (show_usage_state_t));
1685 1686          state.us_parsable = B_FALSE;
1686 1687          state.us_printheader = B_FALSE;
1687 1688          state.us_plot = B_FALSE;
1688 1689          state.us_first = B_TRUE;
1689 1690  
1690 1691          while ((opt = getopt_long(argc, argv, "das:e:o:f:F:",
1691 1692              usage_opts, NULL)) != -1) {
1692 1693                  switch (opt) {
1693 1694                  case 'd':
1694 1695                          d_arg = B_TRUE;
1695 1696                          break;
1696 1697                  case 'a':
1697 1698                          state.us_showall = B_TRUE;
1698 1699                          break;
1699 1700                  case 'f':
1700 1701                          file = optarg;
1701 1702                          break;
1702 1703                  case 's':
1703 1704                          stime = optarg;
1704 1705                          break;
1705 1706                  case 'e':
1706 1707                          etime = optarg;
1707 1708                          break;
1708 1709                  case 'o':
1709 1710                          o_arg = B_TRUE;
1710 1711                          fields_str = optarg;
1711 1712                          break;
1712 1713                  case 'F':
1713 1714                          state.us_plot = F_arg = B_TRUE;
1714 1715                          formatspec_str = optarg;
1715 1716                          break;
1716 1717                  default:
1717 1718                          die_opterr(optopt, opt, use);
1718 1719                          break;
1719 1720                  }
1720 1721          }
1721 1722  
1722 1723          if (file == NULL)
1723 1724                  die("show-usage requires a file");
1724 1725  
1725 1726          if (optind == (argc-1)) {
1726 1727                  uint32_t        flags;
1727 1728  
1728 1729                  resource = argv[optind];
1729 1730                  if (!state.us_showall &&
1730 1731                      (((status = dladm_name2info(handle, resource, NULL, &flags,
1731 1732                      NULL, NULL)) != DLADM_STATUS_OK) ||
1732 1733                      ((flags & DLADM_OPT_ACTIVE) == 0))) {
1733 1734                          die("invalid link: '%s'", resource);
1734 1735                  }
1735 1736          }
1736 1737  
1737 1738          if (F_arg && d_arg)
1738 1739                  die("incompatible -d and -F options");
1739 1740  
1740 1741          if (F_arg && valid_formatspec(formatspec_str) == B_FALSE)
1741 1742                  die("Format specifier %s not supported", formatspec_str);
1742 1743  
1743 1744          if (state.us_parsable)
1744 1745                  ofmtflags |= OFMT_PARSABLE;
1745 1746  
1746 1747          if (resource == NULL && stime == NULL && etime == NULL) {
1747 1748                  oferr = ofmt_open(fields_str, usage_fields, ofmtflags, 0,
1748 1749                      &ofmt);
1749 1750          } else {
1750 1751                  if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
1751 1752                          fields_str = all_l_fields;
1752 1753                  oferr = ofmt_open(fields_str, usage_l_fields, ofmtflags, 0,
1753 1754                      &ofmt);
1754 1755  
1755 1756          }
1756 1757          ofmt_check(oferr, state.us_parsable, ofmt, die, warn);
1757 1758          state.us_ofmt = ofmt;
1758 1759  
1759 1760          if (d_arg) {
1760 1761                  /* Print log dates */
1761 1762                  status = dladm_usage_dates(show_usage_date,
1762 1763                      DLADM_LOGTYPE_LINK, file, resource, &state);
1763 1764          } else if (resource == NULL && stime == NULL && etime == NULL &&
1764 1765              !F_arg) {
1765 1766                  /* Print summary */
1766 1767                  status = dladm_usage_summary(show_usage_res,
1767 1768                      DLADM_LOGTYPE_LINK, file, &state);
1768 1769          } else if (resource != NULL) {
1769 1770                  /* Print log entries for named resource */
1770 1771                  status = dladm_walk_usage_res(show_usage_time,
1771 1772                      DLADM_LOGTYPE_LINK, file, resource, stime, etime, &state);
1772 1773          } else {
1773 1774                  /* Print time and information for each link */
1774 1775                  status = dladm_walk_usage_time(show_usage_time,
1775 1776                      DLADM_LOGTYPE_LINK, file, stime, etime, &state);
1776 1777          }
1777 1778  
1778 1779          if (status != DLADM_STATUS_OK)
1779 1780                  die_dlerr(status, "show-usage");
1780 1781          ofmt_close(ofmt);
1781 1782  }
1782 1783  
1783 1784  static void
1784 1785  do_create_aggr(int argc, char *argv[], const char *use)
1785 1786  {
1786 1787          int                     option;
1787 1788          int                     key = 0;
1788 1789          uint32_t                policy = AGGR_POLICY_L4;
1789 1790          aggr_lacp_mode_t        lacp_mode = AGGR_LACP_OFF;
1790 1791          aggr_lacp_timer_t       lacp_timer = AGGR_LACP_TIMER_SHORT;
1791 1792          dladm_aggr_port_attr_db_t       port[MAXPORT];
1792 1793          uint_t                  n, ndev, nlink;
1793 1794          uint8_t                 mac_addr[ETHERADDRL];
1794 1795          boolean_t               mac_addr_fixed = B_FALSE;
1795 1796          boolean_t               P_arg = B_FALSE;
1796 1797          boolean_t               l_arg = B_FALSE;
1797 1798          boolean_t               u_arg = B_FALSE;
1798 1799          boolean_t               T_arg = B_FALSE;
1799 1800          uint32_t                flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1800 1801          char                    *altroot = NULL;
1801 1802          char                    name[MAXLINKNAMELEN];
1802 1803          char                    *devs[MAXPORT];
1803 1804          char                    *links[MAXPORT];
1804 1805          dladm_status_t          status;
1805 1806          dladm_status_t          pstatus;
1806 1807          char                    propstr[DLADM_STRSIZE];
1807 1808          dladm_arg_list_t        *proplist = NULL;
1808 1809          int                     i;
1809 1810          datalink_id_t           linkid;
1810 1811  
1811 1812          ndev = nlink = opterr = 0;
1812 1813          bzero(propstr, DLADM_STRSIZE);
1813 1814  
1814 1815          while ((option = getopt_long(argc, argv, ":d:l:L:P:R:tfu:T:p:",
1815 1816              lopts, NULL)) != -1) {
1816 1817                  switch (option) {
1817 1818                  case 'd':
1818 1819                          if (ndev + nlink >= MAXPORT)
1819 1820                                  die("too many ports specified");
1820 1821  
1821 1822                          devs[ndev++] = optarg;
1822 1823                          break;
1823 1824                  case 'P':
1824 1825                          if (P_arg)
1825 1826                                  die_optdup(option);
1826 1827  
1827 1828                          P_arg = B_TRUE;
1828 1829                          if (!dladm_aggr_str2policy(optarg, &policy))
1829 1830                                  die("invalid policy '%s'", optarg);
1830 1831                          break;
1831 1832                  case 'u':
1832 1833                          if (u_arg)
1833 1834                                  die_optdup(option);
1834 1835  
1835 1836                          u_arg = B_TRUE;
1836 1837                          if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed,
1837 1838                              mac_addr))
1838 1839                                  die("invalid MAC address '%s'", optarg);
1839 1840                          break;
1840 1841                  case 'l':
1841 1842                          if (isdigit(optarg[strlen(optarg) - 1])) {
1842 1843  
1843 1844                                  /*
1844 1845                                   * Ended with digit, possibly a link name.
1845 1846                                   */
1846 1847                                  if (ndev + nlink >= MAXPORT)
1847 1848                                          die("too many ports specified");
1848 1849  
1849 1850                                  links[nlink++] = optarg;
1850 1851                                  break;
1851 1852                          }
1852 1853                          /* FALLTHROUGH */
1853 1854                  case 'L':
1854 1855                          if (l_arg)
1855 1856                                  die_optdup(option);
1856 1857  
1857 1858                          l_arg = B_TRUE;
1858 1859                          if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode))
1859 1860                                  die("invalid LACP mode '%s'", optarg);
1860 1861                          break;
1861 1862                  case 'T':
1862 1863                          if (T_arg)
1863 1864                                  die_optdup(option);
1864 1865  
1865 1866                          T_arg = B_TRUE;
1866 1867                          if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer))
1867 1868                                  die("invalid LACP timer value '%s'", optarg);
1868 1869                          break;
1869 1870                  case 't':
1870 1871                          flags &= ~DLADM_OPT_PERSIST;
1871 1872                          break;
1872 1873                  case 'f':
1873 1874                          flags |= DLADM_OPT_FORCE;
1874 1875                          break;
1875 1876                  case 'R':
1876 1877                          altroot = optarg;
1877 1878                          break;
1878 1879                  case 'p':
1879 1880                          (void) strlcat(propstr, optarg, DLADM_STRSIZE);
1880 1881                          if (strlcat(propstr, ",", DLADM_STRSIZE) >=
1881 1882                              DLADM_STRSIZE)
1882 1883                                  die("property list too long '%s'", propstr);
1883 1884                          break;
1884 1885  
1885 1886                  default:
1886 1887                          die_opterr(optopt, option, use);
1887 1888                          break;
1888 1889                  }
1889 1890          }
1890 1891  
1891 1892          if (ndev + nlink == 0)
1892 1893                  usage();
1893 1894  
1894 1895          /* get key value or the aggregation name (required last argument) */
1895 1896          if (optind != (argc-1))
1896 1897                  usage();
1897 1898  
1898 1899          if (!str2int(argv[optind], &key)) {
1899 1900                  if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >=
1900 1901                      MAXLINKNAMELEN) {
1901 1902                          die("link name too long '%s'", argv[optind]);
1902 1903                  }
1903 1904  
1904 1905                  if (!dladm_valid_linkname(name))
1905 1906                          die("invalid link name '%s'", argv[optind]);
1906 1907          } else {
1907 1908                  (void) snprintf(name, MAXLINKNAMELEN, "aggr%d", key);
1908 1909          }
1909 1910  
1910 1911          if (altroot != NULL)
1911 1912                  altroot_cmd(altroot, argc, argv);
1912 1913  
1913 1914          for (n = 0; n < ndev; n++) {
1914 1915                  if ((status = dladm_dev2linkid(handle, devs[n],
1915 1916                      &port[n].lp_linkid)) != DLADM_STATUS_OK) {
1916 1917                          die_dlerr(status, "invalid dev name '%s'", devs[n]);
1917 1918                  }
1918 1919          }
1919 1920  
1920 1921          for (n = 0; n < nlink; n++) {
1921 1922                  if ((status = dladm_name2info(handle, links[n],
1922 1923                      &port[ndev + n].lp_linkid, NULL, NULL, NULL)) !=
1923 1924                      DLADM_STATUS_OK) {
1924 1925                          die_dlerr(status, "invalid link name '%s'", links[n]);
1925 1926                  }
1926 1927          }
1927 1928  
1928 1929          status = dladm_aggr_create(handle, name, key, ndev + nlink, port,
1929 1930              policy, mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode,
1930 1931              lacp_timer, flags);
1931 1932          if (status != DLADM_STATUS_OK)
1932 1933                  goto done;
1933 1934  
1934 1935          if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
1935 1936              != DLADM_STATUS_OK)
1936 1937                  die("invalid aggregation property");
1937 1938  
1938 1939          if (proplist == NULL)
1939 1940                  return;
1940 1941  
1941 1942          status = dladm_name2info(handle, name, &linkid, NULL, NULL, NULL);
1942 1943          if (status != DLADM_STATUS_OK)
1943 1944                  goto done;
1944 1945  
1945 1946          for (i = 0; i < proplist->al_count; i++) {
1946 1947                  dladm_arg_info_t        *aip = &proplist->al_info[i];
1947 1948  
1948 1949                  pstatus = dladm_set_linkprop(handle, linkid, aip->ai_name,
1949 1950                      aip->ai_val, aip->ai_count, flags);
1950 1951  
1951 1952                  if (pstatus != DLADM_STATUS_OK) {
1952 1953                          die_dlerr(pstatus,
1953 1954                              "aggr creation succeeded but "
1954 1955                              "could not set property '%s'", aip->ai_name);
1955 1956                  }
1956 1957          }
1957 1958  done:
1958 1959          dladm_free_props(proplist);
1959 1960          if (status != DLADM_STATUS_OK) {
1960 1961                  if (status == DLADM_STATUS_NONOTIF) {
1961 1962                          die("not all links have link up/down detection; must "
1962 1963                              "use -f (see dladm(1M))");
1963 1964                  } else {
1964 1965                          die_dlerr(status, "create operation failed");
1965 1966                  }
1966 1967          }
1967 1968  }
1968 1969  
1969 1970  /*
1970 1971   * arg is either the key or the aggr name. Validate it and convert it to
1971 1972   * the linkid if altroot is NULL.
1972 1973   */
1973 1974  static dladm_status_t
1974 1975  i_dladm_aggr_get_linkid(const char *altroot, const char *arg,
1975 1976      datalink_id_t *linkidp, uint32_t flags)
1976 1977  {
1977 1978          int             key = 0;
1978 1979          char            *aggr = NULL;
1979 1980          dladm_status_t  status;
1980 1981  
1981 1982          if (!str2int(arg, &key))
1982 1983                  aggr = (char *)arg;
1983 1984  
1984 1985          if (aggr == NULL && key == 0)
1985 1986                  return (DLADM_STATUS_LINKINVAL);
1986 1987  
1987 1988          if (altroot != NULL)
1988 1989                  return (DLADM_STATUS_OK);
1989 1990  
1990 1991          if (aggr != NULL) {
1991 1992                  status = dladm_name2info(handle, aggr, linkidp, NULL, NULL,
1992 1993                      NULL);
1993 1994          } else {
1994 1995                  status = dladm_key2linkid(handle, key, linkidp, flags);
1995 1996          }
1996 1997  
1997 1998          return (status);
1998 1999  }
1999 2000  
2000 2001  static void
2001 2002  do_delete_aggr(int argc, char *argv[], const char *use)
2002 2003  {
2003 2004          int                     option;
2004 2005          char                    *altroot = NULL;
2005 2006          uint32_t                flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
2006 2007          dladm_status_t          status;
2007 2008          datalink_id_t           linkid;
2008 2009  
2009 2010          opterr = 0;
2010 2011          while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) {
2011 2012                  switch (option) {
2012 2013                  case 't':
2013 2014                          flags &= ~DLADM_OPT_PERSIST;
2014 2015                          break;
2015 2016                  case 'R':
2016 2017                          altroot = optarg;
2017 2018                          break;
2018 2019                  default:
2019 2020                          die_opterr(optopt, option, use);
2020 2021                          break;
2021 2022                  }
2022 2023          }
2023 2024  
2024 2025          /* get key value or the aggregation name (required last argument) */
2025 2026          if (optind != (argc-1))
2026 2027                  usage();
2027 2028  
2028 2029          status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
2029 2030          if (status != DLADM_STATUS_OK)
2030 2031                  goto done;
2031 2032  
2032 2033          if (altroot != NULL)
2033 2034                  altroot_cmd(altroot, argc, argv);
2034 2035  
2035 2036          status = dladm_aggr_delete(handle, linkid, flags);
2036 2037  done:
2037 2038          if (status != DLADM_STATUS_OK)
2038 2039                  die_dlerr(status, "delete operation failed");
2039 2040  }
2040 2041  
2041 2042  static void
2042 2043  do_add_aggr(int argc, char *argv[], const char *use)
2043 2044  {
2044 2045          int                     option;
2045 2046          uint_t                  n, ndev, nlink;
2046 2047          char                    *altroot = NULL;
2047 2048          uint32_t                flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
2048 2049          datalink_id_t           linkid;
2049 2050          dladm_status_t          status;
2050 2051          dladm_aggr_port_attr_db_t       port[MAXPORT];
2051 2052          char                    *devs[MAXPORT];
2052 2053          char                    *links[MAXPORT];
2053 2054  
2054 2055          ndev = nlink = opterr = 0;
2055 2056          while ((option = getopt_long(argc, argv, ":d:l:R:tf", lopts,
2056 2057              NULL)) != -1) {
2057 2058                  switch (option) {
2058 2059                  case 'd':
2059 2060                          if (ndev + nlink >= MAXPORT)
2060 2061                                  die("too many ports specified");
2061 2062  
2062 2063                          devs[ndev++] = optarg;
2063 2064                          break;
2064 2065                  case 'l':
2065 2066                          if (ndev + nlink >= MAXPORT)
2066 2067                                  die("too many ports specified");
2067 2068  
2068 2069                          links[nlink++] = optarg;
2069 2070                          break;
2070 2071                  case 't':
2071 2072                          flags &= ~DLADM_OPT_PERSIST;
2072 2073                          break;
2073 2074                  case 'f':
2074 2075                          flags |= DLADM_OPT_FORCE;
2075 2076                          break;
2076 2077                  case 'R':
2077 2078                          altroot = optarg;
2078 2079                          break;
2079 2080                  default:
2080 2081                          die_opterr(optopt, option, use);
2081 2082                          break;
2082 2083                  }
2083 2084          }
2084 2085  
2085 2086          if (ndev + nlink == 0)
2086 2087                  usage();
2087 2088  
2088 2089          /* get key value or the aggregation name (required last argument) */
2089 2090          if (optind != (argc-1))
2090 2091                  usage();
2091 2092  
2092 2093          if ((status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid,
2093 2094              flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST))) !=
2094 2095              DLADM_STATUS_OK) {
2095 2096                  goto done;
2096 2097          }
2097 2098  
2098 2099          if (altroot != NULL)
2099 2100                  altroot_cmd(altroot, argc, argv);
2100 2101  
2101 2102          for (n = 0; n < ndev; n++) {
2102 2103                  if ((status = dladm_dev2linkid(handle, devs[n],
2103 2104                      &(port[n].lp_linkid))) != DLADM_STATUS_OK) {
2104 2105                          die_dlerr(status, "invalid <dev> '%s'", devs[n]);
2105 2106                  }
2106 2107          }
2107 2108  
2108 2109          for (n = 0; n < nlink; n++) {
2109 2110                  if ((status = dladm_name2info(handle, links[n],
2110 2111                      &port[n + ndev].lp_linkid, NULL, NULL, NULL)) !=
2111 2112                      DLADM_STATUS_OK) {
2112 2113                          die_dlerr(status, "invalid <link> '%s'", links[n]);
2113 2114                  }
2114 2115          }
2115 2116  
2116 2117          status = dladm_aggr_add(handle, linkid, ndev + nlink, port, flags);
2117 2118  done:
2118 2119          if (status != DLADM_STATUS_OK) {
2119 2120                  /*
2120 2121                   * checking DLADM_STATUS_NOTSUP is a temporary workaround
2121 2122                   * and should be removed once 6399681 is fixed.
2122 2123                   */
2123 2124                  if (status == DLADM_STATUS_NOTSUP) {
2124 2125                          die("add operation failed: link capabilities don't "
2125 2126                              "match");
2126 2127                  } else if (status == DLADM_STATUS_NONOTIF) {
2127 2128                          die("not all links have link up/down detection; must "
2128 2129                              "use -f (see dladm(1M))");
2129 2130                  } else {
2130 2131                          die_dlerr(status, "add operation failed");
2131 2132                  }
2132 2133          }
2133 2134  }
2134 2135  
2135 2136  static void
2136 2137  do_remove_aggr(int argc, char *argv[], const char *use)
2137 2138  {
2138 2139          int                             option;
2139 2140          dladm_aggr_port_attr_db_t       port[MAXPORT];
2140 2141          uint_t                          n, ndev, nlink;
2141 2142          char                            *devs[MAXPORT];
2142 2143          char                            *links[MAXPORT];
2143 2144          char                            *altroot = NULL;
2144 2145          uint32_t                        flags;
2145 2146          datalink_id_t                   linkid;
2146 2147          dladm_status_t                  status;
2147 2148  
2148 2149          flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
2149 2150          ndev = nlink = opterr = 0;
2150 2151          while ((option = getopt_long(argc, argv, ":d:l:R:t",
2151 2152              lopts, NULL)) != -1) {
2152 2153                  switch (option) {
2153 2154                  case 'd':
2154 2155                          if (ndev + nlink >= MAXPORT)
2155 2156                                  die("too many ports specified");
2156 2157  
2157 2158                          devs[ndev++] = optarg;
2158 2159                          break;
2159 2160                  case 'l':
2160 2161                          if (ndev + nlink >= MAXPORT)
2161 2162                                  die("too many ports specified");
2162 2163  
2163 2164                          links[nlink++] = optarg;
2164 2165                          break;
2165 2166                  case 't':
2166 2167                          flags &= ~DLADM_OPT_PERSIST;
2167 2168                          break;
2168 2169                  case 'R':
2169 2170                          altroot = optarg;
2170 2171                          break;
2171 2172                  default:
2172 2173                          die_opterr(optopt, option, use);
2173 2174                          break;
2174 2175                  }
2175 2176          }
2176 2177  
2177 2178          if (ndev + nlink == 0)
2178 2179                  usage();
2179 2180  
2180 2181          /* get key value or the aggregation name (required last argument) */
2181 2182          if (optind != (argc-1))
2182 2183                  usage();
2183 2184  
2184 2185          status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
2185 2186          if (status != DLADM_STATUS_OK)
2186 2187                  goto done;
2187 2188  
2188 2189          if (altroot != NULL)
2189 2190                  altroot_cmd(altroot, argc, argv);
2190 2191  
2191 2192          for (n = 0; n < ndev; n++) {
2192 2193                  if ((status = dladm_dev2linkid(handle, devs[n],
2193 2194                      &(port[n].lp_linkid))) != DLADM_STATUS_OK) {
2194 2195                          die_dlerr(status, "invalid <dev> '%s'", devs[n]);
2195 2196                  }
2196 2197          }
2197 2198  
2198 2199          for (n = 0; n < nlink; n++) {
2199 2200                  if ((status = dladm_name2info(handle, links[n],
2200 2201                      &port[n + ndev].lp_linkid, NULL, NULL, NULL)) !=
2201 2202                      DLADM_STATUS_OK) {
2202 2203                          die_dlerr(status, "invalid <link> '%s'", links[n]);
2203 2204                  }
2204 2205          }
2205 2206  
2206 2207          status = dladm_aggr_remove(handle, linkid, ndev + nlink, port, flags);
2207 2208  done:
2208 2209          if (status != DLADM_STATUS_OK)
2209 2210                  die_dlerr(status, "remove operation failed");
2210 2211  }
2211 2212  
2212 2213  static void
2213 2214  do_modify_aggr(int argc, char *argv[], const char *use)
2214 2215  {
2215 2216          int                     option;
2216 2217          uint32_t                policy = AGGR_POLICY_L4;
2217 2218          aggr_lacp_mode_t        lacp_mode = AGGR_LACP_OFF;
2218 2219          aggr_lacp_timer_t       lacp_timer = AGGR_LACP_TIMER_SHORT;
2219 2220          uint8_t                 mac_addr[ETHERADDRL];
2220 2221          boolean_t               mac_addr_fixed = B_FALSE;
2221 2222          uint8_t                 modify_mask = 0;
2222 2223          char                    *altroot = NULL;
2223 2224          uint32_t                flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
2224 2225          datalink_id_t           linkid;
2225 2226          dladm_status_t          status;
2226 2227  
2227 2228          opterr = 0;
2228 2229          while ((option = getopt_long(argc, argv, ":L:l:P:R:tu:T:", lopts,
2229 2230              NULL)) != -1) {
2230 2231                  switch (option) {
2231 2232                  case 'P':
2232 2233                          if (modify_mask & DLADM_AGGR_MODIFY_POLICY)
2233 2234                                  die_optdup(option);
2234 2235  
2235 2236                          modify_mask |= DLADM_AGGR_MODIFY_POLICY;
2236 2237  
2237 2238                          if (!dladm_aggr_str2policy(optarg, &policy))
2238 2239                                  die("invalid policy '%s'", optarg);
2239 2240                          break;
2240 2241                  case 'u':
2241 2242                          if (modify_mask & DLADM_AGGR_MODIFY_MAC)
2242 2243                                  die_optdup(option);
2243 2244  
2244 2245                          modify_mask |= DLADM_AGGR_MODIFY_MAC;
2245 2246  
2246 2247                          if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed,
2247 2248                              mac_addr))
2248 2249                                  die("invalid MAC address '%s'", optarg);
2249 2250                          break;
2250 2251                  case 'l':
2251 2252                  case 'L':
2252 2253                          if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE)
2253 2254                                  die_optdup(option);
2254 2255  
2255 2256                          modify_mask |= DLADM_AGGR_MODIFY_LACP_MODE;
2256 2257  
2257 2258                          if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode))
2258 2259                                  die("invalid LACP mode '%s'", optarg);
2259 2260                          break;
2260 2261                  case 'T':
2261 2262                          if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER)
2262 2263                                  die_optdup(option);
2263 2264  
2264 2265                          modify_mask |= DLADM_AGGR_MODIFY_LACP_TIMER;
2265 2266  
2266 2267                          if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer))
2267 2268                                  die("invalid LACP timer value '%s'", optarg);
2268 2269                          break;
2269 2270                  case 't':
2270 2271                          flags &= ~DLADM_OPT_PERSIST;
2271 2272                          break;
2272 2273                  case 'R':
2273 2274                          altroot = optarg;
2274 2275                          break;
2275 2276                  default:
2276 2277                          die_opterr(optopt, option, use);
2277 2278                          break;
2278 2279                  }
2279 2280          }
2280 2281  
2281 2282          if (modify_mask == 0)
2282 2283                  die("at least one of the -PulT options must be specified");
2283 2284  
2284 2285          /* get key value or the aggregation name (required last argument) */
2285 2286          if (optind != (argc-1))
2286 2287                  usage();
2287 2288  
2288 2289          status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
2289 2290          if (status != DLADM_STATUS_OK)
2290 2291                  goto done;
2291 2292  
2292 2293          if (altroot != NULL)
2293 2294                  altroot_cmd(altroot, argc, argv);
2294 2295  
2295 2296          status = dladm_aggr_modify(handle, linkid, modify_mask, policy,
2296 2297              mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, lacp_timer,
2297 2298              flags);
2298 2299  
2299 2300  done:
2300 2301          if (status != DLADM_STATUS_OK)
2301 2302                  die_dlerr(status, "modify operation failed");
2302 2303  }
2303 2304  
2304 2305  /*ARGSUSED*/
2305 2306  static void
2306 2307  do_up_aggr(int argc, char *argv[], const char *use)
2307 2308  {
2308 2309          datalink_id_t   linkid = DATALINK_ALL_LINKID;
2309 2310          dladm_status_t  status;
2310 2311  
2311 2312          /*
2312 2313           * get the key or the name of the aggregation (optional last argument)
2313 2314           */
2314 2315          if (argc == 2) {
2315 2316                  if ((status = i_dladm_aggr_get_linkid(NULL, argv[1], &linkid,
2316 2317                      DLADM_OPT_PERSIST)) != DLADM_STATUS_OK)
2317 2318                          goto done;
2318 2319          } else if (argc > 2) {
2319 2320                  usage();
2320 2321          }
2321 2322  
2322 2323          status = dladm_aggr_up(handle, linkid);
2323 2324  done:
2324 2325          if (status != DLADM_STATUS_OK) {
2325 2326                  if (argc == 2) {
2326 2327                          die_dlerr(status,
2327 2328                              "could not bring up aggregation '%s'", argv[1]);
2328 2329                  } else {
2329 2330                          die_dlerr(status, "could not bring aggregations up");
2330 2331                  }
2331 2332          }
2332 2333  }
2333 2334  
2334 2335  static void
2335 2336  do_create_vlan(int argc, char *argv[], const char *use)
2336 2337  {
2337 2338          char                    *link = NULL;
2338 2339          char                    drv[DLPI_LINKNAME_MAX];
2339 2340          uint_t                  ppa;
2340 2341          datalink_id_t           linkid;
2341 2342          datalink_id_t           dev_linkid;
2342 2343          int                     vid = 0;
2343 2344          int                     option;
2344 2345          uint32_t                flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
2345 2346          char                    *altroot = NULL;
2346 2347          char                    vlan[MAXLINKNAMELEN];
2347 2348          char                    propstr[DLADM_STRSIZE];
2348 2349          dladm_arg_list_t        *proplist = NULL;
2349 2350          dladm_status_t          status;
2350 2351  
2351 2352          opterr = 0;
2352 2353          bzero(propstr, DLADM_STRSIZE);
2353 2354  
2354 2355          while ((option = getopt_long(argc, argv, ":tfR:l:v:p:",
2355 2356              lopts, NULL)) != -1) {
2356 2357                  switch (option) {
2357 2358                  case 'v':
2358 2359                          if (vid != 0)
2359 2360                                  die_optdup(option);
2360 2361  
2361 2362                          if (!str2int(optarg, &vid) || vid < 1 || vid > 4094)
2362 2363                                  die("invalid VLAN identifier '%s'", optarg);
2363 2364  
2364 2365                          break;
2365 2366                  case 'l':
2366 2367                          if (link != NULL)
2367 2368                                  die_optdup(option);
2368 2369  
2369 2370                          link = optarg;
2370 2371                          break;
2371 2372                  case 't':
2372 2373                          flags &= ~DLADM_OPT_PERSIST;
2373 2374                          break;
2374 2375                  case 'R':
2375 2376                          altroot = optarg;
2376 2377                          break;
2377 2378                  case 'p':
2378 2379                          (void) strlcat(propstr, optarg, DLADM_STRSIZE);
2379 2380                          if (strlcat(propstr, ",", DLADM_STRSIZE) >=
2380 2381                              DLADM_STRSIZE)
2381 2382                                  die("property list too long '%s'", propstr);
2382 2383                          break;
2383 2384                  case 'f':
2384 2385                          flags |= DLADM_OPT_FORCE;
2385 2386                          break;
2386 2387                  default:
2387 2388                          die_opterr(optopt, option, use);
2388 2389                          break;
2389 2390                  }
2390 2391          }
2391 2392  
2392 2393          /* get vlan name if there is any */
2393 2394          if ((vid == 0) || (link == NULL) || (argc - optind > 1))
2394 2395                  usage();
2395 2396  
2396 2397          if (optind == (argc - 1)) {
2397 2398                  if (strlcpy(vlan, argv[optind], MAXLINKNAMELEN) >=
2398 2399                      MAXLINKNAMELEN) {
2399 2400                          die("vlan name too long '%s'", argv[optind]);
2400 2401                  }
2401 2402          } else {
2402 2403                  if ((dlpi_parselink(link, drv, &ppa) != DLPI_SUCCESS) ||
2403 2404                      (ppa >= 1000) ||
2404 2405                      (dlpi_makelink(vlan, drv, vid * 1000 + ppa) !=
2405 2406                      DLPI_SUCCESS)) {
2406 2407                          die("invalid link name '%s'", link);
2407 2408                  }
2408 2409          }
2409 2410  
2410 2411          if (altroot != NULL)
2411 2412                  altroot_cmd(altroot, argc, argv);
2412 2413  
2413 2414          if (dladm_name2info(handle, link, &dev_linkid, NULL, NULL, NULL) !=
2414 2415              DLADM_STATUS_OK) {
2415 2416                  die("invalid link name '%s'", link);
2416 2417          }
2417 2418  
2418 2419          if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
2419 2420              != DLADM_STATUS_OK)
2420 2421                  die("invalid vlan property");
2421 2422  
2422 2423          status = dladm_vlan_create(handle, vlan, dev_linkid, vid, proplist,
2423 2424              flags, &linkid);
2424 2425          switch (status) {
2425 2426          case DLADM_STATUS_OK:
2426 2427                  break;
2427 2428  
2428 2429          case DLADM_STATUS_NOTSUP:
2429 2430                  die("VLAN over '%s' may require lowered MTU; must use -f (see "
2430 2431                      "dladm(1M))", link);
2431 2432                  break;
2432 2433  
2433 2434          case DLADM_STATUS_LINKBUSY:
2434 2435                  die("VLAN over '%s' may not use default_tag ID "
2435 2436                      "(see dladm(1M))", link);
2436 2437                  break;
2437 2438  
2438 2439          default:
2439 2440                  die_dlerr(status, "create operation failed");
2440 2441          }
2441 2442  }
2442 2443  
2443 2444  static void
2444 2445  do_delete_vlan(int argc, char *argv[], const char *use)
2445 2446  {
2446 2447          int             option;
2447 2448          uint32_t        flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
2448 2449          char            *altroot = NULL;
2449 2450          datalink_id_t   linkid;
2450 2451          dladm_status_t  status;
2451 2452  
2452 2453          opterr = 0;
2453 2454          while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) {
2454 2455                  switch (option) {
2455 2456                  case 't':
2456 2457                          flags &= ~DLADM_OPT_PERSIST;
2457 2458                          break;
2458 2459                  case 'R':
2459 2460                          altroot = optarg;
2460 2461                          break;
2461 2462                  default:
2462 2463                          die_opterr(optopt, option, use);
2463 2464                          break;
2464 2465                  }
2465 2466          }
2466 2467  
2467 2468          /* get VLAN link name (required last argument) */
2468 2469          if (optind != (argc - 1))
2469 2470                  usage();
2470 2471  
2471 2472          if (altroot != NULL)
2472 2473                  altroot_cmd(altroot, argc, argv);
2473 2474  
2474 2475          status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
2475 2476              NULL);
2476 2477          if (status != DLADM_STATUS_OK)
2477 2478                  goto done;
2478 2479  
2479 2480          status = dladm_vlan_delete(handle, linkid, flags);
2480 2481  done:
2481 2482          if (status != DLADM_STATUS_OK)
2482 2483                  die_dlerr(status, "delete operation failed");
2483 2484  }
2484 2485  
2485 2486  /*ARGSUSED*/
2486 2487  static void
2487 2488  do_up_vlan(int argc, char *argv[], const char *use)
2488 2489  {
2489 2490          do_up_vnic_common(argc, argv, use, B_TRUE);
2490 2491  }
2491 2492  
2492 2493  static void
2493 2494  do_rename_link(int argc, char *argv[], const char *use)
2494 2495  {
2495 2496          int             option;
2496 2497          char            *link1, *link2;
2497 2498          char            *altroot = NULL;
2498 2499          dladm_status_t  status;
2499 2500  
2500 2501          opterr = 0;
2501 2502          while ((option = getopt_long(argc, argv, ":R:", lopts, NULL)) != -1) {
2502 2503                  switch (option) {
2503 2504                  case 'R':
2504 2505                          altroot = optarg;
2505 2506                          break;
2506 2507                  default:
2507 2508                          die_opterr(optopt, option, use);
2508 2509                          break;
2509 2510                  }
2510 2511          }
2511 2512  
2512 2513          /* get link1 and link2 name (required the last 2 arguments) */
2513 2514          if (optind != (argc - 2))
2514 2515                  usage();
2515 2516  
2516 2517          if (altroot != NULL)
2517 2518                  altroot_cmd(altroot, argc, argv);
2518 2519  
2519 2520          link1 = argv[optind++];
2520 2521          link2 = argv[optind];
2521 2522          if ((status = dladm_rename_link(handle, link1, link2)) !=
2522 2523              DLADM_STATUS_OK)
2523 2524                  die_dlerr(status, "rename operation failed");
2524 2525  }
2525 2526  
2526 2527  /*ARGSUSED*/
2527 2528  static void
2528 2529  do_delete_phys(int argc, char *argv[], const char *use)
2529 2530  {
2530 2531          datalink_id_t   linkid = DATALINK_ALL_LINKID;
2531 2532          dladm_status_t  status;
2532 2533  
2533 2534          /* get link name (required the last argument) */
2534 2535          if (argc > 2)
2535 2536                  usage();
2536 2537  
2537 2538          if (argc == 2) {
2538 2539                  if ((status = dladm_name2info(handle, argv[1], &linkid, NULL,
2539 2540                      NULL, NULL)) != DLADM_STATUS_OK)
2540 2541                          die_dlerr(status, "cannot delete '%s'", argv[1]);
2541 2542          }
2542 2543  
2543 2544          if ((status = dladm_phys_delete(handle, linkid)) != DLADM_STATUS_OK) {
2544 2545                  if (argc == 2)
2545 2546                          die_dlerr(status, "cannot delete '%s'", argv[1]);
2546 2547                  else
2547 2548                          die_dlerr(status, "delete operation failed");
2548 2549          }
2549 2550  }
2550 2551  
2551 2552  /*ARGSUSED*/
2552 2553  static int
2553 2554  i_dladm_walk_linkmap(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2554 2555  {
2555 2556          char                    name[MAXLINKNAMELEN];
2556 2557          char                    mediabuf[DLADM_STRSIZE];
2557 2558          char                    classbuf[DLADM_STRSIZE];
2558 2559          datalink_class_t        class;
2559 2560          uint32_t                media;
2560 2561          uint32_t                flags;
2561 2562  
2562 2563          if (dladm_datalink_id2info(dh, linkid, &flags, &class, &media, name,
2563 2564              MAXLINKNAMELEN) == DLADM_STATUS_OK) {
2564 2565                  (void) dladm_class2str(class, classbuf);
2565 2566                  (void) dladm_media2str(media, mediabuf);
2566 2567                  (void) printf("%-12s%8d  %-12s%-20s %6d\n", name,
2567 2568                      linkid, classbuf, mediabuf, flags);
2568 2569          }
2569 2570          return (DLADM_WALK_CONTINUE);
2570 2571  }
2571 2572  
2572 2573  /*ARGSUSED*/
2573 2574  static void
2574 2575  do_show_linkmap(int argc, char *argv[], const char *use)
2575 2576  {
2576 2577          if (argc != 1)
2577 2578                  die("invalid arguments");
2578 2579  
2579 2580          (void) printf("%-12s%8s  %-12s%-20s %6s\n", "NAME", "LINKID",
2580 2581              "CLASS", "MEDIA", "FLAGS");
2581 2582  
2582 2583          (void) dladm_walk_datalink_id(i_dladm_walk_linkmap, handle, NULL,
2583 2584              DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
2584 2585              DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
2585 2586  }
2586 2587  
2587 2588  /*
2588 2589   * Delete inactive physical links.
2589 2590   */
2590 2591  /*ARGSUSED*/
2591 2592  static int
2592 2593  purge_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2593 2594  {
2594 2595          datalink_class_t        class;
2595 2596          uint32_t                flags;
2596 2597  
2597 2598          if (dladm_datalink_id2info(dh, linkid, &flags, &class, NULL, NULL, 0)
2598 2599              != DLADM_STATUS_OK) {
2599 2600                  return (DLADM_WALK_CONTINUE);
2600 2601          }
2601 2602  
2602 2603          if (class == DATALINK_CLASS_PHYS && !(flags & DLADM_OPT_ACTIVE))
2603 2604                  (void) dladm_phys_delete(dh, linkid);
2604 2605  
2605 2606          return (DLADM_WALK_CONTINUE);
2606 2607  }
2607 2608  
2608 2609  /*ARGSUSED*/
2609 2610  static void
2610 2611  do_init_phys(int argc, char *argv[], const char *use)
2611 2612  {
2612 2613          di_node_t       devtree;
2613 2614  
2614 2615          if (argc > 1)
2615 2616                  usage();
2616 2617  
2617 2618          /*
2618 2619           * Force all the devices to attach, therefore all the network physical
2619 2620           * devices can be known to the dlmgmtd daemon.
2620 2621           */
2621 2622          if ((devtree = di_init("/", DINFOFORCE | DINFOSUBTREE)) != DI_NODE_NIL)
2622 2623                  di_fini(devtree);
2623 2624  
2624 2625          (void) dladm_walk_datalink_id(purge_phys, handle, NULL,
2625 2626              DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
2626 2627  }
2627 2628  
2628 2629  /*
2629 2630   * Print the active topology information.
2630 2631   */
2631 2632  void
2632 2633  print_link_topology(show_state_t *state, datalink_id_t linkid,
2633 2634      datalink_class_t class, link_fields_buf_t *lbuf)
2634 2635  {
2635 2636          uint32_t        flags = state->ls_flags;
2636 2637          dladm_status_t  status;
2637 2638          char            tmpbuf[MAXLINKNAMELEN];
2638 2639  
2639 2640          lbuf->link_over[0] = '\0';
2640 2641          lbuf->link_bridge[0] = '\0';
2641 2642  
2642 2643          switch (class) {
2643 2644          case DATALINK_CLASS_AGGR:
2644 2645          case DATALINK_CLASS_PHYS:
2645 2646          case DATALINK_CLASS_ETHERSTUB:
2646 2647                  status = dladm_bridge_getlink(handle, linkid, lbuf->link_bridge,
2647 2648                      sizeof (lbuf->link_bridge));
2648 2649                  if (status != DLADM_STATUS_OK &&
2649 2650                      status != DLADM_STATUS_NOTFOUND)
2650 2651                          (void) strcpy(lbuf->link_bridge, "?");
2651 2652                  break;
2652 2653          }
2653 2654  
2654 2655          switch (class) {
2655 2656          case DATALINK_CLASS_VLAN: {
2656 2657                  dladm_vlan_attr_t       vinfo;
2657 2658  
2658 2659                  if (dladm_vlan_info(handle, linkid, &vinfo, flags) !=
2659 2660                      DLADM_STATUS_OK) {
2660 2661                          (void) strcpy(lbuf->link_over, "?");
2661 2662                          break;
2662 2663                  }
2663 2664                  if (dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL, NULL,
2664 2665                      NULL, lbuf->link_over, sizeof (lbuf->link_over)) !=
2665 2666                      DLADM_STATUS_OK)
2666 2667                          (void) strcpy(lbuf->link_over, "?");
2667 2668                  break;
2668 2669          }
2669 2670          case DATALINK_CLASS_AGGR: {
2670 2671                  dladm_aggr_grp_attr_t   ginfo;
2671 2672                  int                     i;
2672 2673  
2673 2674                  if (dladm_aggr_info(handle, linkid, &ginfo, flags) !=
2674 2675                      DLADM_STATUS_OK || ginfo.lg_nports == 0) {
2675 2676                          (void) strcpy(lbuf->link_over, "?");
2676 2677                          break;
2677 2678                  }
2678 2679                  for (i = 0; i < ginfo.lg_nports; i++) {
2679 2680                          if (dladm_datalink_id2info(handle,
2680 2681                              ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL,
2681 2682                              tmpbuf, sizeof (tmpbuf)) != DLADM_STATUS_OK) {
2682 2683                                  (void) strcpy(lbuf->link_over, "?");
2683 2684                                  break;
2684 2685                          }
2685 2686                          (void) strlcat(lbuf->link_over, tmpbuf,
2686 2687                              sizeof (lbuf->link_over));
2687 2688                          if (i != (ginfo.lg_nports - 1)) {
2688 2689                                  (void) strlcat(lbuf->link_over, ",",
2689 2690                                      sizeof (lbuf->link_over));
2690 2691                          }
2691 2692                  }
2692 2693                  free(ginfo.lg_ports);
2693 2694                  break;
2694 2695          }
2695 2696          case DATALINK_CLASS_VNIC: {
2696 2697                  dladm_vnic_attr_t       vinfo;
2697 2698  
2698 2699                  if (dladm_vnic_info(handle, linkid, &vinfo, flags) !=
2699 2700                      DLADM_STATUS_OK) {
2700 2701                          (void) strcpy(lbuf->link_over, "?");
2701 2702                          break;
2702 2703                  }
2703 2704                  if (dladm_datalink_id2info(handle, vinfo.va_link_id, NULL, NULL,
2704 2705                      NULL, lbuf->link_over, sizeof (lbuf->link_over)) !=
2705 2706                      DLADM_STATUS_OK)
2706 2707                          (void) strcpy(lbuf->link_over, "?");
2707 2708                  break;
2708 2709          }
2709 2710  
2710 2711          case DATALINK_CLASS_PART: {
2711 2712                  dladm_part_attr_t       pinfo;
2712 2713  
2713 2714                  if (dladm_part_info(handle, linkid, &pinfo, flags) !=
2714 2715                      DLADM_STATUS_OK) {
2715 2716                          (void) strcpy(lbuf->link_over, "?");
2716 2717                          break;
2717 2718                  }
2718 2719                  if (dladm_datalink_id2info(handle, pinfo.dia_physlinkid, NULL,
2719 2720                      NULL, NULL, lbuf->link_over, sizeof (lbuf->link_over)) !=
2720 2721                      DLADM_STATUS_OK)
2721 2722                          (void) strcpy(lbuf->link_over, "?");
2722 2723                  break;
2723 2724          }
2724 2725  
2725 2726          case DATALINK_CLASS_BRIDGE: {
2726 2727                  datalink_id_t *dlp;
2727 2728                  uint_t i, nports;
2728 2729  
2729 2730                  if (dladm_datalink_id2info(handle, linkid, NULL, NULL,
2730 2731                      NULL, tmpbuf, sizeof (tmpbuf)) != DLADM_STATUS_OK) {
2731 2732                          (void) strcpy(lbuf->link_over, "?");
2732 2733                          break;
2733 2734                  }
2734 2735                  if (tmpbuf[0] != '\0')
2735 2736                          tmpbuf[strlen(tmpbuf) - 1] = '\0';
2736 2737                  dlp = dladm_bridge_get_portlist(tmpbuf, &nports);
2737 2738                  if (dlp == NULL) {
2738 2739                          (void) strcpy(lbuf->link_over, "?");
2739 2740                          break;
2740 2741                  }
2741 2742                  for (i = 0; i < nports; i++) {
2742 2743                          if (dladm_datalink_id2info(handle, dlp[i], NULL,
2743 2744                              NULL, NULL, tmpbuf, sizeof (tmpbuf)) !=
2744 2745                              DLADM_STATUS_OK) {
2745 2746                                  (void) strcpy(lbuf->link_over, "?");
2746 2747                                  break;
2747 2748                          }
2748 2749                          (void) strlcat(lbuf->link_over, tmpbuf,
2749 2750                              sizeof (lbuf->link_over));
2750 2751                          if (i != nports - 1) {
2751 2752                                  (void) strlcat(lbuf->link_over, ",",
2752 2753                                      sizeof (lbuf->link_over));
2753 2754                          }
2754 2755                  }
2755 2756                  dladm_bridge_free_portlist(dlp);
2756 2757                  break;
2757 2758          }
2758 2759  
2759 2760          case DATALINK_CLASS_SIMNET: {
2760 2761                  dladm_simnet_attr_t     slinfo;
2761 2762  
2762 2763                  if (dladm_simnet_info(handle, linkid, &slinfo, flags) !=
2763 2764                      DLADM_STATUS_OK) {
2764 2765                          (void) strcpy(lbuf->link_over, "?");
2765 2766                          break;
2766 2767                  }
2767 2768                  if (slinfo.sna_peer_link_id != DATALINK_INVALID_LINKID) {
2768 2769                          if (dladm_datalink_id2info(handle,
2769 2770                              slinfo.sna_peer_link_id, NULL, NULL, NULL,
2770 2771                              lbuf->link_over, sizeof (lbuf->link_over)) !=
2771 2772                              DLADM_STATUS_OK)
2772 2773                                  (void) strcpy(lbuf->link_over, "?");
2773 2774                  }
2774 2775                  break;
2775 2776          }
2776 2777          }
2777 2778  }
2778 2779  
2779 2780  static dladm_status_t
2780 2781  print_link(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *lbuf)
2781 2782  {
2782 2783          char                    link[MAXLINKNAMELEN];
2783 2784          datalink_class_t        class;
2784 2785          uint_t                  mtu;
2785 2786          uint32_t                flags;
2786 2787          dladm_status_t          status;
2787 2788  
2788 2789          if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class,
2789 2790              NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
2790 2791                  goto done;
2791 2792          }
2792 2793  
2793 2794          if (!(state->ls_flags & flags)) {
2794 2795                  status = DLADM_STATUS_NOTFOUND;
2795 2796                  goto done;
2796 2797          }
2797 2798  
2798 2799          if (state->ls_flags == DLADM_OPT_ACTIVE) {
2799 2800                  dladm_attr_t    dlattr;
2800 2801  
2801 2802                  if (class == DATALINK_CLASS_PHYS) {
2802 2803                          dladm_phys_attr_t       dpa;
2803 2804                          dlpi_handle_t           dh;
2804 2805                          dlpi_info_t             dlinfo;
2805 2806  
2806 2807                          if ((status = dladm_phys_info(handle, linkid, &dpa,
2807 2808                              DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2808 2809                                  goto done;
2809 2810                          }
2810 2811  
2811 2812                          if (!dpa.dp_novanity)
2812 2813                                  goto link_mtu;
2813 2814  
2814 2815                          /*
2815 2816                           * This is a physical link that does not have
2816 2817                           * vanity naming support.
2817 2818                           */
2818 2819                          if (dlpi_open(dpa.dp_dev, &dh, DLPI_DEVONLY) !=
2819 2820                              DLPI_SUCCESS) {
2820 2821                                  status = DLADM_STATUS_NOTFOUND;
2821 2822                                  goto done;
2822 2823                          }
2823 2824  
2824 2825                          if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) {
2825 2826                                  dlpi_close(dh);
2826 2827                                  status = DLADM_STATUS_BADARG;
2827 2828                                  goto done;
2828 2829                          }
2829 2830  
2830 2831                          dlpi_close(dh);
2831 2832                          mtu = dlinfo.di_max_sdu;
2832 2833                  } else {
2833 2834  link_mtu:
2834 2835                          status = dladm_info(handle, linkid, &dlattr);
2835 2836                          if (status != DLADM_STATUS_OK)
2836 2837                                  goto done;
2837 2838                          mtu = dlattr.da_max_sdu;
2838 2839                  }
2839 2840          }
2840 2841  
2841 2842          (void) snprintf(lbuf->link_name, sizeof (lbuf->link_name),
2842 2843              "%s", link);
2843 2844          (void) dladm_class2str(class, lbuf->link_class);
2844 2845          if (state->ls_flags == DLADM_OPT_ACTIVE) {
2845 2846                  (void) snprintf(lbuf->link_mtu, sizeof (lbuf->link_mtu),
2846 2847                      "%u", mtu);
2847 2848                  (void) get_linkstate(link, B_TRUE, lbuf->link_state);
2848 2849          }
2849 2850  
2850 2851          print_link_topology(state, linkid, class, lbuf);
2851 2852  done:
2852 2853          return (status);
2853 2854  }
2854 2855  
2855 2856  /* ARGSUSED */
2856 2857  static int
2857 2858  show_link(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2858 2859  {
2859 2860          show_state_t            *state = (show_state_t *)arg;
2860 2861          dladm_status_t          status;
2861 2862          link_fields_buf_t       lbuf;
2862 2863  
2863 2864          /*
2864 2865           * first get all the link attributes into lbuf;
2865 2866           */
2866 2867          bzero(&lbuf, sizeof (link_fields_buf_t));
2867 2868          if ((status = print_link(state, linkid, &lbuf)) == DLADM_STATUS_OK)
2868 2869                  ofmt_print(state->ls_ofmt, &lbuf);
2869 2870          state->ls_status = status;
2870 2871          return (DLADM_WALK_CONTINUE);
2871 2872  }
2872 2873  
2873 2874  static boolean_t
2874 2875  print_link_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
2875 2876  {
2876 2877          link_args_t *largs = ofarg->ofmt_cbarg;
2877 2878          pktsum_t *diff_stats = largs->link_s_psum;
2878 2879  
2879 2880          switch (ofarg->ofmt_id) {
2880 2881          case LINK_S_LINK:
2881 2882                  (void) snprintf(buf, bufsize, "%s", largs->link_s_link);
2882 2883                  break;
2883 2884          case LINK_S_IPKTS:
2884 2885                  (void) snprintf(buf, bufsize, "%llu", diff_stats->ipackets);
2885 2886                  break;
2886 2887          case LINK_S_RBYTES:
2887 2888                  (void) snprintf(buf, bufsize, "%llu", diff_stats->rbytes);
2888 2889                  break;
2889 2890          case LINK_S_IERRORS:
2890 2891                  (void) snprintf(buf, bufsize, "%u", diff_stats->ierrors);
2891 2892                  break;
2892 2893          case LINK_S_OPKTS:
2893 2894                  (void) snprintf(buf, bufsize, "%llu", diff_stats->opackets);
2894 2895                  break;
2895 2896          case LINK_S_OBYTES:
2896 2897                  (void) snprintf(buf, bufsize, "%llu", diff_stats->obytes);
2897 2898                  break;
2898 2899          case LINK_S_OERRORS:
2899 2900                  (void) snprintf(buf, bufsize, "%u", diff_stats->oerrors);
2900 2901                  break;
2901 2902          default:
2902 2903                  die("invalid input");
2903 2904                  break;
2904 2905          }
2905 2906          return (B_TRUE);
2906 2907  }
2907 2908  
2908 2909  static int
2909 2910  show_link_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2910 2911  {
2911 2912          char                    link[DLPI_LINKNAME_MAX];
2912 2913          datalink_class_t        class;
2913 2914          show_state_t            *state = arg;
2914 2915          pktsum_t                stats, diff_stats;
2915 2916          dladm_phys_attr_t       dpa;
2916 2917          link_args_t             largs;
2917 2918  
2918 2919          if (state->ls_firstonly) {
2919 2920                  if (state->ls_donefirst)
2920 2921                          return (DLADM_WALK_CONTINUE);
2921 2922                  state->ls_donefirst = B_TRUE;
2922 2923          } else {
2923 2924                  bzero(&state->ls_prevstats, sizeof (state->ls_prevstats));
2924 2925          }
2925 2926  
2926 2927          if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, link,
2927 2928              DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
2928 2929                  return (DLADM_WALK_CONTINUE);
2929 2930          }
2930 2931  
2931 2932          if (class == DATALINK_CLASS_PHYS) {
2932 2933                  if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
2933 2934                      DLADM_STATUS_OK) {
2934 2935                          return (DLADM_WALK_CONTINUE);
2935 2936                  }
2936 2937                  if (dpa.dp_novanity)
2937 2938                          get_mac_stats(dpa.dp_dev, &stats);
2938 2939                  else
2939 2940                          get_link_stats(link, &stats);
2940 2941          } else {
2941 2942                  get_link_stats(link, &stats);
2942 2943          }
2943 2944          dladm_stats_diff(&diff_stats, &stats, &state->ls_prevstats);
2944 2945  
2945 2946          largs.link_s_link = link;
2946 2947          largs.link_s_psum = &diff_stats;
2947 2948          ofmt_print(state->ls_ofmt, &largs);
2948 2949  
2949 2950          state->ls_prevstats = stats;
2950 2951          return (DLADM_WALK_CONTINUE);
2951 2952  }
2952 2953  
2953 2954  
2954 2955  static dladm_status_t
2955 2956  print_aggr_info(show_grp_state_t *state, const char *link,
2956 2957      dladm_aggr_grp_attr_t *ginfop)
2957 2958  {
2958 2959          char                    addr_str[ETHERADDRL * 3];
2959 2960          laggr_fields_buf_t      lbuf;
2960 2961  
2961 2962          (void) snprintf(lbuf.laggr_name, sizeof (lbuf.laggr_name),
2962 2963              "%s", link);
2963 2964  
2964 2965          (void) dladm_aggr_policy2str(ginfop->lg_policy,
2965 2966              lbuf.laggr_policy);
2966 2967  
2967 2968          if (ginfop->lg_mac_fixed) {
2968 2969                  (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str);
2969 2970                  (void) snprintf(lbuf.laggr_addrpolicy,
2970 2971                      sizeof (lbuf.laggr_addrpolicy), "fixed (%s)", addr_str);
2971 2972          } else {
2972 2973                  (void) snprintf(lbuf.laggr_addrpolicy,
2973 2974                      sizeof (lbuf.laggr_addrpolicy), "auto");
2974 2975          }
2975 2976  
2976 2977          (void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode,
2977 2978              lbuf.laggr_lacpactivity);
2978 2979          (void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer,
2979 2980              lbuf.laggr_lacptimer);
2980 2981          (void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----",
2981 2982              ginfop->lg_force ? 'f' : '-');
2982 2983  
2983 2984          ofmt_print(state->gs_ofmt, &lbuf);
2984 2985  
2985 2986          return (DLADM_STATUS_OK);
2986 2987  }
2987 2988  
2988 2989  static boolean_t
2989 2990  print_xaggr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
2990 2991  {
2991 2992          const laggr_args_t      *l = ofarg->ofmt_cbarg;
2992 2993          boolean_t               is_port = (l->laggr_lport >= 0);
2993 2994          char                    tmpbuf[DLADM_STRSIZE];
2994 2995          const char              *objname;
2995 2996          dladm_aggr_port_attr_t  *portp;
2996 2997          dladm_phys_attr_t       dpa;
2997 2998  
2998 2999          if (is_port) {
2999 3000                  portp = &(l->laggr_ginfop->lg_ports[l->laggr_lport]);
3000 3001                  if (dladm_phys_info(handle, portp->lp_linkid, &dpa,
3001 3002                      DLADM_OPT_ACTIVE) != DLADM_STATUS_OK)
3002 3003                          objname = "?";
3003 3004                  else
3004 3005                          objname = dpa.dp_dev;
3005 3006          } else {
3006 3007                  objname = l->laggr_link;
3007 3008          }
3008 3009  
3009 3010          switch (ofarg->ofmt_id) {
3010 3011          case AGGR_X_LINK:
3011 3012                  (void) snprintf(buf, bufsize, "%s",
3012 3013                      (is_port && !l->laggr_parsable ? " " : l->laggr_link));
3013 3014                  break;
3014 3015          case AGGR_X_PORT:
3015 3016                  if (is_port) {
3016 3017                          if (dladm_datalink_id2info(handle, portp->lp_linkid,
3017 3018                              NULL, NULL, NULL, buf, bufsize) != DLADM_STATUS_OK)
3018 3019                                  (void) sprintf(buf, "?");
3019 3020                  }
3020 3021                  break;
3021 3022  
3022 3023          case AGGR_X_SPEED:
3023 3024                  (void) snprintf(buf, bufsize, "%uMb",
3024 3025                      (uint_t)((get_ifspeed(objname, !is_port)) / 1000000ull));
3025 3026                  break;
3026 3027  
3027 3028          case AGGR_X_DUPLEX:
3028 3029                  (void) get_linkduplex(objname, !is_port, tmpbuf);
3029 3030                  (void) strlcpy(buf, tmpbuf, bufsize);
3030 3031                  break;
3031 3032  
3032 3033          case AGGR_X_STATE:
3033 3034                  (void) get_linkstate(objname, !is_port, tmpbuf);
3034 3035                  (void) strlcpy(buf, tmpbuf, bufsize);
3035 3036                  break;
3036 3037          case AGGR_X_ADDRESS:
3037 3038                  (void) dladm_aggr_macaddr2str(
3038 3039                      (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac),
3039 3040                      tmpbuf);
3040 3041                  (void) strlcpy(buf, tmpbuf, bufsize);
3041 3042                  break;
3042 3043          case AGGR_X_PORTSTATE:
3043 3044                  if (is_port) {
3044 3045                          (void) dladm_aggr_portstate2str(portp->lp_state,
3045 3046                              tmpbuf);
3046 3047                          (void) strlcpy(buf, tmpbuf, bufsize);
3047 3048                  }
3048 3049                  break;
3049 3050          }
3050 3051  err:
3051 3052          *(l->laggr_status) = DLADM_STATUS_OK;
3052 3053          return (B_TRUE);
3053 3054  }
3054 3055  
3055 3056  static dladm_status_t
3056 3057  print_aggr_extended(show_grp_state_t *state, const char *link,
3057 3058      dladm_aggr_grp_attr_t *ginfop)
3058 3059  {
3059 3060          int                     i;
3060 3061          dladm_status_t          status;
3061 3062          laggr_args_t            largs;
3062 3063  
3063 3064          largs.laggr_lport = -1;
3064 3065          largs.laggr_link = link;
3065 3066          largs.laggr_ginfop = ginfop;
3066 3067          largs.laggr_status = &status;
3067 3068          largs.laggr_parsable = state->gs_parsable;
3068 3069  
3069 3070          ofmt_print(state->gs_ofmt, &largs);
3070 3071  
3071 3072          if (status != DLADM_STATUS_OK)
3072 3073                  goto done;
3073 3074  
3074 3075          for (i = 0; i < ginfop->lg_nports; i++) {
3075 3076                  largs.laggr_lport = i;
3076 3077                  ofmt_print(state->gs_ofmt, &largs);
3077 3078                  if (status != DLADM_STATUS_OK)
3078 3079                          goto done;
3079 3080          }
3080 3081  
3081 3082          status = DLADM_STATUS_OK;
3082 3083  done:
3083 3084          return (status);
3084 3085  }
3085 3086  
3086 3087  static boolean_t
3087 3088  print_lacp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
3088 3089  {
3089 3090          const laggr_args_t      *l = ofarg->ofmt_cbarg;
3090 3091          int                     portnum;
3091 3092          boolean_t               is_port = (l->laggr_lport >= 0);
3092 3093          dladm_aggr_port_attr_t  *portp;
3093 3094          aggr_lacp_state_t       *lstate;
3094 3095  
3095 3096          if (!is_port)
3096 3097                  return (B_FALSE); /* cannot happen! */
3097 3098  
3098 3099          portnum = l->laggr_lport;
3099 3100          portp = &(l->laggr_ginfop->lg_ports[portnum]);
3100 3101          lstate = &(portp->lp_lacp_state);
3101 3102  
3102 3103          switch (ofarg->ofmt_id) {
3103 3104          case AGGR_L_LINK:
3104 3105                  (void) snprintf(buf, bufsize, "%s",
3105 3106                      (portnum > 0 ? "" : l->laggr_link));
3106 3107                  break;
3107 3108  
3108 3109          case AGGR_L_PORT:
3109 3110                  if (dladm_datalink_id2info(handle, portp->lp_linkid, NULL, NULL,
3110 3111                      NULL, buf, bufsize) != DLADM_STATUS_OK)
3111 3112                          (void) sprintf(buf, "?");
3112 3113                  break;
3113 3114  
3114 3115          case AGGR_L_AGGREGATABLE:
3115 3116                  (void) snprintf(buf, bufsize, "%s",
3116 3117                      (lstate->bit.aggregation ? "yes" : "no"));
3117 3118                  break;
3118 3119  
3119 3120          case AGGR_L_SYNC:
3120 3121                  (void) snprintf(buf, bufsize, "%s",
3121 3122                      (lstate->bit.sync ? "yes" : "no"));
3122 3123                  break;
3123 3124  
3124 3125          case AGGR_L_COLL:
3125 3126                  (void) snprintf(buf, bufsize, "%s",
3126 3127                      (lstate->bit.collecting ? "yes" : "no"));
3127 3128                  break;
3128 3129  
3129 3130          case AGGR_L_DIST:
3130 3131                  (void) snprintf(buf, bufsize, "%s",
3131 3132                      (lstate->bit.distributing ? "yes" : "no"));
3132 3133                  break;
3133 3134  
3134 3135          case AGGR_L_DEFAULTED:
3135 3136                  (void) snprintf(buf, bufsize, "%s",
3136 3137                      (lstate->bit.defaulted ? "yes" : "no"));
3137 3138                  break;
3138 3139  
3139 3140          case AGGR_L_EXPIRED:
3140 3141                  (void) snprintf(buf, bufsize, "%s",
3141 3142                      (lstate->bit.expired ? "yes" : "no"));
3142 3143                  break;
3143 3144          }
3144 3145  
3145 3146          *(l->laggr_status) = DLADM_STATUS_OK;
3146 3147          return (B_TRUE);
3147 3148  }
3148 3149  
3149 3150  static dladm_status_t
3150 3151  print_aggr_lacp(show_grp_state_t *state, const char *link,
3151 3152      dladm_aggr_grp_attr_t *ginfop)
3152 3153  {
3153 3154          int             i;
3154 3155          dladm_status_t  status;
3155 3156          laggr_args_t    largs;
3156 3157  
3157 3158          largs.laggr_link = link;
3158 3159          largs.laggr_ginfop = ginfop;
3159 3160          largs.laggr_status = &status;
3160 3161  
3161 3162          for (i = 0; i < ginfop->lg_nports; i++) {
3162 3163                  largs.laggr_lport = i;
3163 3164                  ofmt_print(state->gs_ofmt, &largs);
3164 3165                  if (status != DLADM_STATUS_OK)
3165 3166                          goto done;
3166 3167          }
3167 3168  
3168 3169          status = DLADM_STATUS_OK;
3169 3170  done:
3170 3171          return (status);
3171 3172  }
3172 3173  
3173 3174  static boolean_t
3174 3175  print_aggr_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
3175 3176  {
3176 3177          const laggr_args_t      *l = ofarg->ofmt_cbarg;
3177 3178          int                     portnum;
3178 3179          boolean_t               is_port = (l->laggr_lport >= 0);
3179 3180          dladm_aggr_port_attr_t  *portp;
3180 3181          dladm_status_t          *stat, status;
3181 3182          pktsum_t                *diff_stats;
3182 3183  
3183 3184          stat = l->laggr_status;
3184 3185          *stat = DLADM_STATUS_OK;
3185 3186  
3186 3187          if (is_port) {
3187 3188                  portnum = l->laggr_lport;
3188 3189                  portp = &(l->laggr_ginfop->lg_ports[portnum]);
3189 3190  
3190 3191                  if ((status = dladm_datalink_id2info(handle,
3191 3192                      portp->lp_linkid, NULL, NULL, NULL, buf, bufsize)) !=
3192 3193                      DLADM_STATUS_OK) {
3193 3194                          goto err;
3194 3195                  }
3195 3196                  diff_stats = l->laggr_diffstats;
3196 3197          }
3197 3198  
3198 3199          switch (ofarg->ofmt_id) {
3199 3200          case AGGR_S_LINK:
3200 3201                  (void) snprintf(buf, bufsize, "%s",
3201 3202                      (is_port ? "" : l->laggr_link));
3202 3203                  break;
3203 3204          case AGGR_S_PORT:
3204 3205                  /*
3205 3206                   * if (is_port), buf has port name. Otherwise we print
3206 3207                   * STR_UNDEF_VAL
3207 3208                   */
3208 3209                  break;
3209 3210  
3210 3211          case AGGR_S_IPKTS:
3211 3212                  if (is_port) {
3212 3213                          (void) snprintf(buf, bufsize, "%llu",
3213 3214                              diff_stats->ipackets);
3214 3215                  } else {
3215 3216                          (void) snprintf(buf, bufsize, "%llu",
3216 3217                              l->laggr_pktsumtot->ipackets);
3217 3218                  }
3218 3219                  break;
3219 3220  
3220 3221          case AGGR_S_RBYTES:
3221 3222                  if (is_port) {
3222 3223                          (void) snprintf(buf, bufsize, "%llu",
3223 3224                              diff_stats->rbytes);
3224 3225                  } else {
3225 3226                          (void) snprintf(buf, bufsize, "%llu",
3226 3227                              l->laggr_pktsumtot->rbytes);
3227 3228                  }
3228 3229                  break;
3229 3230  
3230 3231          case AGGR_S_OPKTS:
3231 3232                  if (is_port) {
3232 3233                          (void) snprintf(buf, bufsize, "%llu",
3233 3234                              diff_stats->opackets);
3234 3235                  } else {
3235 3236                          (void) snprintf(buf, bufsize, "%llu",
3236 3237                              l->laggr_pktsumtot->opackets);
3237 3238                  }
3238 3239                  break;
3239 3240          case AGGR_S_OBYTES:
3240 3241                  if (is_port) {
3241 3242                          (void) snprintf(buf, bufsize, "%llu",
3242 3243                              diff_stats->obytes);
3243 3244                  } else {
3244 3245                          (void) snprintf(buf, bufsize, "%llu",
3245 3246                              l->laggr_pktsumtot->obytes);
3246 3247                  }
3247 3248                  break;
3248 3249  
3249 3250          case AGGR_S_IPKTDIST:
3250 3251                  if (is_port) {
3251 3252                          (void) snprintf(buf, bufsize, "%-6.1f",
3252 3253                              (double)diff_stats->ipackets/
3253 3254                              (double)l->laggr_pktsumtot->ipackets * 100);
3254 3255                  }
3255 3256                  break;
3256 3257          case AGGR_S_OPKTDIST:
3257 3258                  if (is_port) {
3258 3259                          (void) snprintf(buf, bufsize, "%-6.1f",
3259 3260                              (double)diff_stats->opackets/
3260 3261                              (double)l->laggr_pktsumtot->opackets * 100);
3261 3262                  }
3262 3263                  break;
3263 3264          }
3264 3265          return (B_TRUE);
3265 3266  
3266 3267  err:
3267 3268          *stat = status;
3268 3269          return (B_TRUE);
3269 3270  }
3270 3271  
3271 3272  static dladm_status_t
3272 3273  print_aggr_stats(show_grp_state_t *state, const char *link,
3273 3274      dladm_aggr_grp_attr_t *ginfop)
3274 3275  {
3275 3276          dladm_phys_attr_t       dpa;
3276 3277          dladm_aggr_port_attr_t  *portp;
3277 3278          pktsum_t                pktsumtot, *port_stat;
3278 3279          dladm_status_t          status;
3279 3280          int                     i;
3280 3281          laggr_args_t            largs;
3281 3282  
3282 3283          /* sum the ports statistics */
3283 3284          bzero(&pktsumtot, sizeof (pktsumtot));
3284 3285  
3285 3286          /* Allocate memory to keep stats of each port */
3286 3287          port_stat = malloc(ginfop->lg_nports * sizeof (pktsum_t));
3287 3288          if (port_stat == NULL) {
3288 3289                  /* Bail out; no memory */
3289 3290                  return (DLADM_STATUS_NOMEM);
3290 3291          }
3291 3292  
3292 3293  
3293 3294          for (i = 0; i < ginfop->lg_nports; i++) {
3294 3295  
3295 3296                  portp = &(ginfop->lg_ports[i]);
3296 3297                  if ((status = dladm_phys_info(handle, portp->lp_linkid, &dpa,
3297 3298                      DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
3298 3299                          goto done;
3299 3300                  }
3300 3301  
3301 3302                  get_mac_stats(dpa.dp_dev, &port_stat[i]);
3302 3303  
3303 3304                  /*
3304 3305                   * Let's re-use gs_prevstats[] to store the difference of the
3305 3306                   * counters since last use. We will store the new stats from
3306 3307                   * port_stat[] once we have the stats displayed.
3307 3308                   */
3308 3309  
3309 3310                  dladm_stats_diff(&state->gs_prevstats[i], &port_stat[i],
3310 3311                      &state->gs_prevstats[i]);
3311 3312                  dladm_stats_total(&pktsumtot, &pktsumtot,
3312 3313                      &state->gs_prevstats[i]);
3313 3314          }
3314 3315  
3315 3316          largs.laggr_lport = -1;
3316 3317          largs.laggr_link = link;
3317 3318          largs.laggr_ginfop = ginfop;
3318 3319          largs.laggr_status = &status;
3319 3320          largs.laggr_pktsumtot = &pktsumtot;
3320 3321  
3321 3322          ofmt_print(state->gs_ofmt, &largs);
3322 3323  
3323 3324          if (status != DLADM_STATUS_OK)
3324 3325                  goto done;
3325 3326  
3326 3327          for (i = 0; i < ginfop->lg_nports; i++) {
3327 3328                  largs.laggr_lport = i;
3328 3329                  largs.laggr_diffstats = &state->gs_prevstats[i];
3329 3330                  ofmt_print(state->gs_ofmt, &largs);
3330 3331                  if (status != DLADM_STATUS_OK)
3331 3332                          goto done;
3332 3333          }
3333 3334  
3334 3335          status = DLADM_STATUS_OK;
3335 3336          for (i = 0; i < ginfop->lg_nports; i++)
3336 3337                  state->gs_prevstats[i] = port_stat[i];
3337 3338  
3338 3339  done:
3339 3340          free(port_stat);
3340 3341          return (status);
3341 3342  }
3342 3343  
3343 3344  static dladm_status_t
3344 3345  print_aggr(show_grp_state_t *state, datalink_id_t linkid)
3345 3346  {
3346 3347          char                    link[MAXLINKNAMELEN];
3347 3348          dladm_aggr_grp_attr_t   ginfo;
3348 3349          uint32_t                flags;
3349 3350          dladm_status_t          status;
3350 3351  
3351 3352          bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t));
3352 3353          if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
3353 3354              NULL, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
3354 3355                  return (status);
3355 3356          }
3356 3357  
3357 3358          if (!(state->gs_flags & flags))
3358 3359                  return (DLADM_STATUS_NOTFOUND);
3359 3360  
3360 3361          status = dladm_aggr_info(handle, linkid, &ginfo, state->gs_flags);
3361 3362          if (status != DLADM_STATUS_OK)
3362 3363                  return (status);
3363 3364  
3364 3365          if (state->gs_lacp)
3365 3366                  status = print_aggr_lacp(state, link, &ginfo);
3366 3367          else if (state->gs_extended)
3367 3368                  status = print_aggr_extended(state, link, &ginfo);
3368 3369          else if (state->gs_stats)
3369 3370                  status = print_aggr_stats(state, link, &ginfo);
3370 3371          else
3371 3372                  status = print_aggr_info(state, link, &ginfo);
3372 3373  
3373 3374  done:
3374 3375          free(ginfo.lg_ports);
3375 3376          return (status);
3376 3377  }
3377 3378  
3378 3379  /* ARGSUSED */
3379 3380  static int
3380 3381  show_aggr(dladm_handle_t dh, datalink_id_t linkid, void *arg)
3381 3382  {
3382 3383          show_grp_state_t        *state = arg;
3383 3384  
3384 3385          state->gs_status = print_aggr(state, linkid);
3385 3386          return (DLADM_WALK_CONTINUE);
3386 3387  }
3387 3388  
3388 3389  static void
3389 3390  do_show_link(int argc, char *argv[], const char *use)
3390 3391  {
3391 3392          int             option;
3392 3393          boolean_t       s_arg = B_FALSE;
3393 3394          boolean_t       i_arg = B_FALSE;
3394 3395          uint32_t        flags = DLADM_OPT_ACTIVE;
3395 3396          boolean_t       p_arg = B_FALSE;
3396 3397          datalink_id_t   linkid = DATALINK_ALL_LINKID;
3397 3398          char            linkname[MAXLINKNAMELEN];
3398 3399          uint32_t        interval = 0;
3399 3400          show_state_t    state;
3400 3401          dladm_status_t  status;
3401 3402          boolean_t       o_arg = B_FALSE;
3402 3403          char            *fields_str = NULL;
3403 3404          char            *all_active_fields = "link,class,mtu,state,bridge,over";
3404 3405          char            *all_inactive_fields = "link,class,bridge,over";
3405 3406          char            *allstat_fields =
3406 3407              "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors";
3407 3408          ofmt_handle_t   ofmt;
3408 3409          ofmt_status_t   oferr;
3409 3410          uint_t          ofmtflags = 0;
3410 3411  
3411 3412          bzero(&state, sizeof (state));
3412 3413  
3413 3414          opterr = 0;
3414 3415          while ((option = getopt_long(argc, argv, ":pPsi:o:",
3415 3416              show_lopts, NULL)) != -1) {
3416 3417                  switch (option) {
3417 3418                  case 'p':
3418 3419                          if (p_arg)
3419 3420                                  die_optdup(option);
3420 3421  
3421 3422                          p_arg = B_TRUE;
3422 3423                          break;
3423 3424                  case 's':
3424 3425                          if (s_arg)
3425 3426                                  die_optdup(option);
3426 3427  
3427 3428                          s_arg = B_TRUE;
3428 3429                          break;
3429 3430                  case 'P':
3430 3431                          if (flags != DLADM_OPT_ACTIVE)
3431 3432                                  die_optdup(option);
3432 3433  
3433 3434                          flags = DLADM_OPT_PERSIST;
3434 3435                          break;
3435 3436                  case 'o':
3436 3437                          o_arg = B_TRUE;
3437 3438                          fields_str = optarg;
3438 3439                          break;
3439 3440                  case 'i':
3440 3441                          if (i_arg)
3441 3442                                  die_optdup(option);
3442 3443  
3443 3444                          i_arg = B_TRUE;
3444 3445                          if (!dladm_str2interval(optarg, &interval))
3445 3446                                  die("invalid interval value '%s'", optarg);
3446 3447                          break;
3447 3448                  default:
3448 3449                          die_opterr(optopt, option, use);
3449 3450                          break;
3450 3451                  }
3451 3452          }
3452 3453  
3453 3454          if (i_arg && !s_arg)
3454 3455                  die("the option -i can be used only with -s");
3455 3456  
3456 3457          if (s_arg && flags != DLADM_OPT_ACTIVE)
3457 3458                  die("the option -P cannot be used with -s");
3458 3459  
3459 3460          /* get link name (optional last argument) */
3460 3461          if (optind == (argc-1)) {
3461 3462                  uint32_t        f;
3462 3463  
3463 3464                  if (strlcpy(linkname, argv[optind], MAXLINKNAMELEN) >=
3464 3465                      MAXLINKNAMELEN)
3465 3466                          die("link name too long");
3466 3467                  if ((status = dladm_name2info(handle, linkname, &linkid, &f,
3467 3468                      NULL, NULL)) != DLADM_STATUS_OK) {
3468 3469                          die_dlerr(status, "link %s is not valid", linkname);
3469 3470                  }
3470 3471  
3471 3472                  if (!(f & flags)) {
3472 3473                          die_dlerr(DLADM_STATUS_BADARG, "link %s is %s",
3473 3474                              argv[optind], flags == DLADM_OPT_PERSIST ?
3474 3475                              "a temporary link" : "temporarily removed");
3475 3476                  }
3476 3477          } else if (optind != argc) {
3477 3478                  usage();
3478 3479          }
3479 3480  
3480 3481          if (p_arg && !o_arg)
3481 3482                  die("-p requires -o");
3482 3483  
3483 3484          if (p_arg && strcasecmp(fields_str, "all") == 0)
3484 3485                  die("\"-o all\" is invalid with -p");
3485 3486  
3486 3487          if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
3487 3488                  if (s_arg)
3488 3489                          fields_str = allstat_fields;
3489 3490                  else if (flags & DLADM_OPT_ACTIVE)
3490 3491                          fields_str = all_active_fields;
3491 3492                  else
3492 3493                          fields_str = all_inactive_fields;
3493 3494          }
3494 3495  
3495 3496          state.ls_parsable = p_arg;
3496 3497          state.ls_flags = flags;
3497 3498          state.ls_donefirst = B_FALSE;
3498 3499  
3499 3500          if (s_arg) {
3500 3501                  link_stats(linkid, interval, fields_str, &state);
3501 3502                  return;
3502 3503          }
3503 3504          if (state.ls_parsable)
3504 3505                  ofmtflags |= OFMT_PARSABLE;
3505 3506          else
3506 3507                  ofmtflags |= OFMT_WRAP;
3507 3508  
3508 3509          oferr = ofmt_open(fields_str, link_fields, ofmtflags, 0, &ofmt);
3509 3510          ofmt_check(oferr, state.ls_parsable, ofmt, die, warn);
3510 3511          state.ls_ofmt = ofmt;
3511 3512  
3512 3513          if (linkid == DATALINK_ALL_LINKID) {
3513 3514                  (void) dladm_walk_datalink_id(show_link, handle, &state,
3514 3515                      DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags);
3515 3516          } else {
3516 3517                  (void) show_link(handle, linkid, &state);
3517 3518                  if (state.ls_status != DLADM_STATUS_OK) {
3518 3519                          die_dlerr(state.ls_status, "failed to show link %s",
3519 3520                              argv[optind]);
3520 3521                  }
3521 3522          }
3522 3523          ofmt_close(ofmt);
3523 3524  }
3524 3525  
3525 3526  static void
3526 3527  do_show_aggr(int argc, char *argv[], const char *use)
3527 3528  {
3528 3529          boolean_t               L_arg = B_FALSE;
3529 3530          boolean_t               s_arg = B_FALSE;
3530 3531          boolean_t               i_arg = B_FALSE;
3531 3532          boolean_t               p_arg = B_FALSE;
3532 3533          boolean_t               x_arg = B_FALSE;
3533 3534          show_grp_state_t        state;
3534 3535          uint32_t                flags = DLADM_OPT_ACTIVE;
3535 3536          datalink_id_t           linkid = DATALINK_ALL_LINKID;
3536 3537          int                     option;
3537 3538          uint32_t                interval = 0;
3538 3539          int                     key;
3539 3540          dladm_status_t          status;
3540 3541          boolean_t               o_arg = B_FALSE;
3541 3542          char                    *fields_str = NULL;
3542 3543          char                    *all_fields =
3543 3544              "link,policy,addrpolicy,lacpactivity,lacptimer,flags";
3544 3545          char                    *all_lacp_fields =
3545 3546              "link,port,aggregatable,sync,coll,dist,defaulted,expired";
3546 3547          char                    *all_stats_fields =
3547 3548              "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist";
3548 3549          char                    *all_extended_fields =
3549 3550              "link,port,speed,duplex,state,address,portstate";
3550 3551          const ofmt_field_t      *pf;
3551 3552          ofmt_handle_t           ofmt;
3552 3553          ofmt_status_t           oferr;
3553 3554          uint_t                  ofmtflags = 0;
3554 3555  
3555 3556          opterr = 0;
3556 3557          while ((option = getopt_long(argc, argv, ":LpPxsi:o:",
3557 3558              show_lopts, NULL)) != -1) {
3558 3559                  switch (option) {
3559 3560                  case 'L':
3560 3561                          if (L_arg)
3561 3562                                  die_optdup(option);
3562 3563  
3563 3564                          L_arg = B_TRUE;
3564 3565                          break;
3565 3566                  case 'p':
3566 3567                          if (p_arg)
3567 3568                                  die_optdup(option);
3568 3569  
3569 3570                          p_arg = B_TRUE;
3570 3571                          break;
3571 3572                  case 'x':
3572 3573                          if (x_arg)
3573 3574                                  die_optdup(option);
3574 3575  
3575 3576                          x_arg = B_TRUE;
3576 3577                          break;
3577 3578                  case 'P':
3578 3579                          if (flags != DLADM_OPT_ACTIVE)
3579 3580                                  die_optdup(option);
3580 3581  
3581 3582                          flags = DLADM_OPT_PERSIST;
3582 3583                          break;
3583 3584                  case 's':
3584 3585                          if (s_arg)
3585 3586                                  die_optdup(option);
3586 3587  
3587 3588                          s_arg = B_TRUE;
3588 3589                          break;
3589 3590                  case 'o':
3590 3591                          o_arg = B_TRUE;
3591 3592                          fields_str = optarg;
3592 3593                          break;
3593 3594                  case 'i':
3594 3595                          if (i_arg)
3595 3596                                  die_optdup(option);
3596 3597  
3597 3598                          i_arg = B_TRUE;
3598 3599                          if (!dladm_str2interval(optarg, &interval))
3599 3600                                  die("invalid interval value '%s'", optarg);
3600 3601                          break;
3601 3602                  default:
3602 3603                          die_opterr(optopt, option, use);
3603 3604                          break;
3604 3605                  }
3605 3606          }
3606 3607  
3607 3608          if (p_arg && !o_arg)
3608 3609                  die("-p requires -o");
3609 3610  
3610 3611          if (p_arg && strcasecmp(fields_str, "all") == 0)
3611 3612                  die("\"-o all\" is invalid with -p");
3612 3613  
3613 3614          if (i_arg && !s_arg)
3614 3615                  die("the option -i can be used only with -s");
3615 3616  
3616 3617          if (s_arg && (L_arg || p_arg || x_arg || flags != DLADM_OPT_ACTIVE)) {
3617 3618                  die("the option -%c cannot be used with -s",
3618 3619                      L_arg ? 'L' : (p_arg ? 'p' : (x_arg ? 'x' : 'P')));
3619 3620          }
3620 3621  
3621 3622          if (L_arg && flags != DLADM_OPT_ACTIVE)
3622 3623                  die("the option -P cannot be used with -L");
3623 3624  
3624 3625          if (x_arg && (L_arg || flags != DLADM_OPT_ACTIVE))
3625 3626                  die("the option -%c cannot be used with -x", L_arg ? 'L' : 'P');
3626 3627  
3627 3628          /* get aggregation key or aggrname (optional last argument) */
3628 3629          if (optind == (argc-1)) {
3629 3630                  if (!str2int(argv[optind], &key)) {
3630 3631                          status = dladm_name2info(handle, argv[optind],
3631 3632                              &linkid, NULL, NULL, NULL);
3632 3633                  } else {
3633 3634                          status = dladm_key2linkid(handle, (uint16_t)key,
3634 3635                              &linkid, DLADM_OPT_ACTIVE);
3635 3636                  }
3636 3637  
3637 3638                  if (status != DLADM_STATUS_OK)
3638 3639                          die("non-existent aggregation '%s'", argv[optind]);
3639 3640  
3640 3641          } else if (optind != argc) {
3641 3642                  usage();
3642 3643          }
3643 3644  
3644 3645          bzero(&state, sizeof (state));
3645 3646          state.gs_lacp = L_arg;
3646 3647          state.gs_stats = s_arg;
3647 3648          state.gs_flags = flags;
3648 3649          state.gs_parsable = p_arg;
3649 3650          state.gs_extended = x_arg;
3650 3651  
3651 3652          if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
3652 3653                  if (state.gs_lacp)
3653 3654                          fields_str = all_lacp_fields;
3654 3655                  else if (state.gs_stats)
3655 3656                          fields_str = all_stats_fields;
3656 3657                  else if (state.gs_extended)
3657 3658                          fields_str = all_extended_fields;
3658 3659                  else
3659 3660                          fields_str = all_fields;
3660 3661          }
3661 3662  
3662 3663          if (state.gs_lacp) {
3663 3664                  pf = aggr_l_fields;
3664 3665          } else if (state.gs_stats) {
3665 3666                  pf = aggr_s_fields;
3666 3667          } else if (state.gs_extended) {
3667 3668                  pf = aggr_x_fields;
3668 3669          } else {
3669 3670                  pf = laggr_fields;
3670 3671          }
3671 3672  
3672 3673          if (state.gs_parsable)
3673 3674                  ofmtflags |= OFMT_PARSABLE;
3674 3675          oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt);
3675 3676          ofmt_check(oferr, state.gs_parsable, ofmt, die, warn);
3676 3677          state.gs_ofmt = ofmt;
3677 3678  
3678 3679          if (s_arg) {
3679 3680                  aggr_stats(linkid, &state, interval);
3680 3681                  ofmt_close(ofmt);
3681 3682                  return;
3682 3683          }
3683 3684  
3684 3685          if (linkid == DATALINK_ALL_LINKID) {
3685 3686                  (void) dladm_walk_datalink_id(show_aggr, handle, &state,
3686 3687                      DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags);
3687 3688          } else {
3688 3689                  (void) show_aggr(handle, linkid, &state);
3689 3690                  if (state.gs_status != DLADM_STATUS_OK) {
3690 3691                          die_dlerr(state.gs_status, "failed to show aggr %s",
3691 3692                              argv[optind]);
3692 3693                  }
3693 3694          }
3694 3695          ofmt_close(ofmt);
3695 3696  }
3696 3697  
3697 3698  static dladm_status_t
3698 3699  print_phys_default(show_state_t *state, datalink_id_t linkid,
3699 3700      const char *link, uint32_t flags, uint32_t media)
3700 3701  {
3701 3702          dladm_phys_attr_t dpa;
3702 3703          dladm_status_t status;
3703 3704          link_fields_buf_t pattr;
3704 3705  
3705 3706          status = dladm_phys_info(handle, linkid, &dpa, state->ls_flags);
3706 3707          if (status != DLADM_STATUS_OK)
3707 3708                  goto done;
3708 3709  
3709 3710          bzero(&pattr, sizeof (pattr));
3710 3711          (void) snprintf(pattr.link_phys_device,
3711 3712              sizeof (pattr.link_phys_device), "%s", dpa.dp_dev);
3712 3713          (void) dladm_media2str(media, pattr.link_phys_media);
3713 3714          if (state->ls_flags == DLADM_OPT_ACTIVE) {
3714 3715                  boolean_t       islink;
3715 3716  
3716 3717                  if (!dpa.dp_novanity) {
3717 3718                          (void) strlcpy(pattr.link_name, link,
3718 3719                              sizeof (pattr.link_name));
3719 3720                          islink = B_TRUE;
3720 3721                  } else {
3721 3722                          /*
3722 3723                           * This is a physical link that does not have
3723 3724                           * vanity naming support.
3724 3725                           */
3725 3726                          (void) strlcpy(pattr.link_name, dpa.dp_dev,
3726 3727                              sizeof (pattr.link_name));
3727 3728                          islink = B_FALSE;
3728 3729                  }
3729 3730  
3730 3731                  (void) get_linkstate(pattr.link_name, islink,
3731 3732                      pattr.link_phys_state);
3732 3733                  (void) snprintf(pattr.link_phys_speed,
3733 3734                      sizeof (pattr.link_phys_speed), "%u",
3734 3735                      (uint_t)((get_ifspeed(pattr.link_name,
3735 3736                      islink)) / 1000000ull));
3736 3737                  (void) get_linkduplex(pattr.link_name, islink,
3737 3738                      pattr.link_phys_duplex);
3738 3739          } else {
3739 3740                  (void) snprintf(pattr.link_name, sizeof (pattr.link_name),
3740 3741                      "%s", link);
3741 3742                  (void) snprintf(pattr.link_flags, sizeof (pattr.link_flags),
3742 3743                      "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r');
3743 3744          }
3744 3745  
3745 3746          ofmt_print(state->ls_ofmt, &pattr);
3746 3747  
3747 3748  done:
3748 3749          return (status);
3749 3750  }
3750 3751  
3751 3752  typedef struct {
3752 3753          show_state_t    *ms_state;
3753 3754          char            *ms_link;
3754 3755          dladm_macaddr_attr_t *ms_mac_attr;
3755 3756  } print_phys_mac_state_t;
3756 3757  
3757 3758  /*
3758 3759   *  callback for ofmt_print()
3759 3760   */
3760 3761  static boolean_t
3761 3762  print_phys_one_mac_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
3762 3763  {
3763 3764          print_phys_mac_state_t *mac_state = ofarg->ofmt_cbarg;
3764 3765          dladm_macaddr_attr_t *attr = mac_state->ms_mac_attr;
3765 3766          boolean_t is_primary = (attr->ma_slot == 0);
3766 3767          boolean_t is_parsable = mac_state->ms_state->ls_parsable;
3767 3768  
3768 3769          switch (ofarg->ofmt_id) {
3769 3770          case PHYS_M_LINK:
3770 3771                  (void) snprintf(buf, bufsize, "%s",
3771 3772                      (is_primary || is_parsable) ? mac_state->ms_link : " ");
3772 3773                  break;
3773 3774          case PHYS_M_SLOT:
3774 3775                  if (is_primary)
3775 3776                          (void) snprintf(buf, bufsize, gettext("primary"));
3776 3777                  else
3777 3778                          (void) snprintf(buf, bufsize, "%d", attr->ma_slot);
3778 3779                  break;
3779 3780          case PHYS_M_ADDRESS:
3780 3781                  (void) dladm_aggr_macaddr2str(attr->ma_addr, buf);
3781 3782                  break;
3782 3783          case PHYS_M_INUSE:
3783 3784                  (void) snprintf(buf, bufsize, "%s",
3784 3785                      attr->ma_flags & DLADM_MACADDR_USED ? gettext("yes") :
3785 3786                      gettext("no"));
3786 3787                  break;
3787 3788          case PHYS_M_CLIENT:
3788 3789                  /*
3789 3790                   * CR 6678526: resolve link id to actual link name if
3790 3791                   * it is valid.
3791 3792                   */
3792 3793                  (void) snprintf(buf, bufsize, "%s", attr->ma_client_name);
3793 3794                  break;
3794 3795          }
3795 3796  
3796 3797          return (B_TRUE);
3797 3798  }
3798 3799  
3799 3800  typedef struct {
3800 3801          show_state_t    *hs_state;
3801 3802          char            *hs_link;
3802 3803          dladm_hwgrp_attr_t *hs_grp_attr;
3803 3804  } print_phys_hwgrp_state_t;
3804 3805  
3805 3806  static boolean_t
3806 3807  print_phys_one_hwgrp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
3807 3808  {
3808 3809          int             i;
3809 3810          boolean_t       first = B_TRUE;
3810 3811          int             start = -1;
3811 3812          int             end = -1;
3812 3813          char            ringstr[RINGSTRLEN];
3813 3814          char            ringsubstr[RINGSTRLEN];
3814 3815  
3815 3816          print_phys_hwgrp_state_t *hg_state = ofarg->ofmt_cbarg;
3816 3817          dladm_hwgrp_attr_t *attr = hg_state->hs_grp_attr;
3817 3818  
3818 3819          switch (ofarg->ofmt_id) {
3819 3820          case PHYS_H_LINK:
3820 3821                  (void) snprintf(buf, bufsize, "%s", attr->hg_link_name);
3821 3822                  break;
3822 3823          case PHYS_H_RINGTYPE:
3823 3824                  (void) snprintf(buf, bufsize, "%s",
3824 3825                      attr->hg_grp_type == DLADM_HWGRP_TYPE_RX ? "RX" : "TX");
3825 3826                  break;
3826 3827          case PHYS_H_RINGS:
3827 3828                  ringstr[0] = '\0';
3828 3829                  for (i = 0; i < attr->hg_n_rings; i++) {
3829 3830                          uint_t  index = attr->hg_rings[i];
3830 3831  
3831 3832                          if (start == -1) {
3832 3833                                  start = index;
3833 3834                                  end = index;
3834 3835                          } else if (index == end + 1) {
3835 3836                                  end = index;
3836 3837                          } else {
3837 3838                                  if (start == end) {
3838 3839                                          if (first) {
3839 3840                                                  (void) snprintf(
3840 3841                                                      ringsubstr,
3841 3842                                                      RINGSTRLEN, "%d",
3842 3843                                                      start);
3843 3844                                                  first = B_FALSE;
3844 3845                                          } else {
3845 3846                                                  (void) snprintf(
3846 3847                                                      ringsubstr,
3847 3848                                                      RINGSTRLEN, ",%d",
3848 3849                                                      start);
3849 3850                                          }
3850 3851                                  } else {
3851 3852                                          if (first) {
3852 3853                                                  (void) snprintf(
3853 3854                                                      ringsubstr,
3854 3855                                                      RINGSTRLEN,
3855 3856                                                      "%d-%d",
3856 3857                                                      start, end);
3857 3858                                                  first = B_FALSE;
3858 3859                                          } else {
3859 3860                                                  (void) snprintf(
3860 3861                                                      ringsubstr,
3861 3862                                                      RINGSTRLEN,
3862 3863                                                      ",%d-%d",
3863 3864                                                      start, end);
3864 3865                                          }
3865 3866                                  }
3866 3867                                  (void) strlcat(ringstr, ringsubstr,
3867 3868                                      RINGSTRLEN);
3868 3869                                  start = index;
3869 3870                                  end = index;
3870 3871                          }
3871 3872                  }
3872 3873                  /* The last one */
3873 3874                  if (start != -1) {
3874 3875                          if (first) {
3875 3876                                  if (start == end) {
3876 3877                                          (void) snprintf(buf, bufsize, "%d",
3877 3878                                              start);
3878 3879                                  } else {
3879 3880                                          (void) snprintf(buf, bufsize, "%d-%d",
3880 3881                                              start, end);
3881 3882                                  }
3882 3883                          } else {
3883 3884                                  if (start == end) {
3884 3885                                          (void) snprintf(ringsubstr, RINGSTRLEN,
3885 3886                                              ",%d", start);
3886 3887                                  } else {
3887 3888                                          (void) snprintf(ringsubstr, RINGSTRLEN,
3888 3889                                              ",%d-%d", start, end);
3889 3890                                  }
3890 3891                                  (void) strlcat(ringstr, ringsubstr, RINGSTRLEN);
3891 3892                                  (void) snprintf(buf, bufsize, "%s", ringstr);
3892 3893                          }
3893 3894                  }
3894 3895                  break;
3895 3896          case PHYS_H_CLIENTS:
3896 3897                  if (attr->hg_client_names[0] == '\0') {
3897 3898                          (void) snprintf(buf, bufsize, "--");
3898 3899                  } else {
3899 3900                          (void) snprintf(buf, bufsize, "%s ",
3900 3901                              attr->hg_client_names);
3901 3902                  }
3902 3903                  break;
3903 3904          }
3904 3905  
3905 3906          return (B_TRUE);
3906 3907  }
3907 3908  
3908 3909  /*
3909 3910   * callback for dladm_walk_macaddr, invoked for each MAC address slot
3910 3911   */
3911 3912  static boolean_t
3912 3913  print_phys_mac_callback(void *arg, dladm_macaddr_attr_t *attr)
3913 3914  {
3914 3915          print_phys_mac_state_t *mac_state = arg;
3915 3916          show_state_t *state = mac_state->ms_state;
3916 3917  
3917 3918          mac_state->ms_mac_attr = attr;
3918 3919          ofmt_print(state->ls_ofmt, mac_state);
3919 3920  
3920 3921          return (B_TRUE);
3921 3922  }
3922 3923  
3923 3924  /*
3924 3925   * invoked by show-phys -m for each physical data-link
3925 3926   */
3926 3927  static dladm_status_t
3927 3928  print_phys_mac(show_state_t *state, datalink_id_t linkid, char *link)
3928 3929  {
3929 3930          print_phys_mac_state_t mac_state;
3930 3931  
3931 3932          mac_state.ms_state = state;
3932 3933          mac_state.ms_link = link;
3933 3934  
3934 3935          return (dladm_walk_macaddr(handle, linkid, &mac_state,
3935 3936              print_phys_mac_callback));
3936 3937  }
3937 3938  
3938 3939  /*
3939 3940   * callback for dladm_walk_hwgrp, invoked for each MAC hwgrp
3940 3941   */
3941 3942  static boolean_t
3942 3943  print_phys_hwgrp_callback(void *arg, dladm_hwgrp_attr_t *attr)
3943 3944  {
3944 3945          print_phys_hwgrp_state_t *hwgrp_state = arg;
3945 3946          show_state_t *state = hwgrp_state->hs_state;
3946 3947  
3947 3948          hwgrp_state->hs_grp_attr = attr;
3948 3949          ofmt_print(state->ls_ofmt, hwgrp_state);
3949 3950  
3950 3951          return (B_TRUE);
3951 3952  }
3952 3953  
3953 3954  /* invoked by show-phys -H for each physical data-link */
3954 3955  static dladm_status_t
3955 3956  print_phys_hwgrp(show_state_t *state, datalink_id_t linkid, char *link)
3956 3957  {
3957 3958          print_phys_hwgrp_state_t hwgrp_state;
3958 3959  
3959 3960          hwgrp_state.hs_state = state;
3960 3961          hwgrp_state.hs_link = link;
3961 3962          return (dladm_walk_hwgrp(handle, linkid, &hwgrp_state,
3962 3963              print_phys_hwgrp_callback));
3963 3964  }
3964 3965  
3965 3966  /*
3966 3967   * Parse the "local=<laddr>,remote=<raddr>" sub-options for the -a option of
3967 3968   * *-iptun subcommands.
3968 3969   */
3969 3970  static void
3970 3971  iptun_process_addrarg(char *addrarg, iptun_params_t *params)
3971 3972  {
3972 3973          char *addrval;
3973 3974  
3974 3975          while (*addrarg != '\0') {
3975 3976                  switch (getsubopt(&addrarg, iptun_addropts, &addrval)) {
3976 3977                  case IPTUN_LOCAL:
3977 3978                          params->iptun_param_flags |= IPTUN_PARAM_LADDR;
3978 3979                          if (strlcpy(params->iptun_param_laddr, addrval,
3979 3980                              sizeof (params->iptun_param_laddr)) >=
3980 3981                              sizeof (params->iptun_param_laddr))
3981 3982                                  die("tunnel source address is too long");
3982 3983                          break;
3983 3984                  case IPTUN_REMOTE:
3984 3985                          params->iptun_param_flags |= IPTUN_PARAM_RADDR;
3985 3986                          if (strlcpy(params->iptun_param_raddr, addrval,
3986 3987                              sizeof (params->iptun_param_raddr)) >=
3987 3988                              sizeof (params->iptun_param_raddr))
3988 3989                                  die("tunnel destination address is too long");
3989 3990                          break;
3990 3991                  default:
3991 3992                          die("invalid address type: %s", addrval);
3992 3993                          break;
3993 3994                  }
3994 3995          }
3995 3996  }
3996 3997  
3997 3998  /*
3998 3999   * Convenience routine to process iptun-create/modify/delete subcommand
3999 4000   * arguments.
4000 4001   */
4001 4002  static void
4002 4003  iptun_process_args(int argc, char *argv[], const char *opts,
4003 4004      iptun_params_t *params, uint32_t *flags, char *name, const char *use)
4004 4005  {
4005 4006          int     option;
4006 4007          char    *altroot = NULL;
4007 4008  
4008 4009          if (params != NULL)
4009 4010                  bzero(params, sizeof (*params));
4010 4011          *flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
4011 4012  
4012 4013          opterr = 0;
4013 4014          while ((option = getopt_long(argc, argv, opts, iptun_lopts, NULL)) !=
4014 4015              -1) {
4015 4016                  switch (option) {
4016 4017                  case 'a':
4017 4018                          iptun_process_addrarg(optarg, params);
4018 4019                          break;
4019 4020                  case 'R':
4020 4021                          altroot = optarg;
4021 4022                          break;
4022 4023                  case 't':
4023 4024                          *flags &= ~DLADM_OPT_PERSIST;
4024 4025                          break;
4025 4026                  case 'T':
4026 4027                          params->iptun_param_type = iptun_gettypebyname(optarg);
4027 4028                          if (params->iptun_param_type == IPTUN_TYPE_UNKNOWN)
4028 4029                                  die("unknown tunnel type: %s", optarg);
4029 4030                          params->iptun_param_flags |= IPTUN_PARAM_TYPE;
4030 4031                          break;
4031 4032                  default:
4032 4033                          die_opterr(optopt, option, use);
4033 4034                          break;
4034 4035                  }
4035 4036          }
4036 4037  
4037 4038          /* Get the required tunnel name argument. */
4038 4039          if (argc - optind != 1)
4039 4040                  usage();
4040 4041  
4041 4042          if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
4042 4043                  die("tunnel name is too long");
4043 4044  
4044 4045          if (altroot != NULL)
4045 4046                  altroot_cmd(altroot, argc, argv);
4046 4047  }
4047 4048  
4048 4049  static void
4049 4050  do_create_iptun(int argc, char *argv[], const char *use)
4050 4051  {
4051 4052          iptun_params_t  params;
4052 4053          dladm_status_t  status;
4053 4054          uint32_t        flags;
4054 4055          char            name[MAXLINKNAMELEN];
4055 4056  
4056 4057          iptun_process_args(argc, argv, ":a:R:tT:", ¶ms, &flags, name,
4057 4058              use);
4058 4059  
4059 4060          status = dladm_iptun_create(handle, name, ¶ms, flags);
4060 4061          if (status != DLADM_STATUS_OK)
4061 4062                  die_dlerr(status, "could not create tunnel");
4062 4063  }
4063 4064  
4064 4065  static void
4065 4066  do_delete_iptun(int argc, char *argv[], const char *use)
4066 4067  {
4067 4068          uint32_t        flags;
4068 4069          datalink_id_t   linkid;
4069 4070          dladm_status_t  status;
4070 4071          char            name[MAXLINKNAMELEN];
4071 4072  
4072 4073          iptun_process_args(argc, argv, ":R:t", NULL, &flags, name, use);
4073 4074  
4074 4075          status = dladm_name2info(handle, name, &linkid, NULL, NULL, NULL);
4075 4076          if (status != DLADM_STATUS_OK)
4076 4077                  die_dlerr(status, "could not delete tunnel");
4077 4078          status = dladm_iptun_delete(handle, linkid, flags);
4078 4079          if (status != DLADM_STATUS_OK)
4079 4080                  die_dlerr(status, "could not delete tunnel");
4080 4081  }
4081 4082  
4082 4083  static void
4083 4084  do_modify_iptun(int argc, char *argv[], const char *use)
4084 4085  {
4085 4086          iptun_params_t  params;
4086 4087          uint32_t        flags;
4087 4088          dladm_status_t  status;
4088 4089          char            name[MAXLINKNAMELEN];
4089 4090  
4090 4091          iptun_process_args(argc, argv, ":a:R:t", ¶ms, &flags, name, use);
4091 4092  
4092 4093          if ((status = dladm_name2info(handle, name, ¶ms.iptun_param_linkid,
4093 4094              NULL, NULL, NULL)) != DLADM_STATUS_OK)
4094 4095                  die_dlerr(status, "could not modify tunnel");
4095 4096          status = dladm_iptun_modify(handle, ¶ms, flags);
4096 4097          if (status != DLADM_STATUS_OK)
4097 4098                  die_dlerr(status, "could not modify tunnel");
4098 4099  }
4099 4100  
4100 4101  static void
4101 4102  do_show_iptun(int argc, char *argv[], const char *use)
4102 4103  {
4103 4104          char            option;
4104 4105          datalink_id_t   linkid;
4105 4106          uint32_t        flags = DLADM_OPT_ACTIVE;
4106 4107          char            *name = NULL;
4107 4108          dladm_status_t  status;
4108 4109          const char      *fields_str = NULL;
4109 4110          show_state_t    state;
4110 4111          ofmt_handle_t   ofmt;
4111 4112          ofmt_status_t   oferr;
4112 4113          uint_t          ofmtflags = 0;
4113 4114  
4114 4115          bzero(&state, sizeof (state));
4115 4116          opterr = 0;
4116 4117          while ((option = getopt_long(argc, argv, ":pPo:",
4117 4118              iptun_lopts, NULL)) != -1) {
4118 4119                  switch (option) {
4119 4120                  case 'o':
4120 4121                          fields_str = optarg;
4121 4122                          break;
4122 4123                  case 'p':
4123 4124                          state.ls_parsable = B_TRUE;
4124 4125                          ofmtflags = OFMT_PARSABLE;
4125 4126                          break;
4126 4127                  case 'P':
4127 4128                          flags = DLADM_OPT_PERSIST;
4128 4129                          break;
4129 4130                  default:
4130 4131                          die_opterr(optopt, option, use);
4131 4132                          break;
4132 4133                  }
4133 4134          }
4134 4135  
4135 4136          /*
4136 4137           * Get the optional tunnel name argument.  If there is one, it must
4137 4138           * be the last thing remaining on the command-line.
4138 4139           */
4139 4140          if (argc - optind > 1)
4140 4141                  die(gettext(use));
4141 4142          if (argc - optind == 1)
4142 4143                  name = argv[optind];
4143 4144  
4144 4145          oferr = ofmt_open(fields_str, iptun_fields, ofmtflags,
4145 4146              DLADM_DEFAULT_COL, &ofmt);
4146 4147          ofmt_check(oferr, state.ls_parsable, ofmt, die, warn);
4147 4148  
4148 4149          state.ls_ofmt = ofmt;
4149 4150          state.ls_flags = flags;
4150 4151  
4151 4152          if (name == NULL) {
4152 4153                  (void) dladm_walk_datalink_id(print_iptun_walker, handle,
4153 4154                      &state, DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE,
4154 4155                      flags);
4155 4156                  status = state.ls_status;
4156 4157          } else {
4157 4158                  if ((status = dladm_name2info(handle, name, &linkid, NULL, NULL,
4158 4159                      NULL)) == DLADM_STATUS_OK)
4159 4160                          status = print_iptun(handle, linkid, &state);
4160 4161          }
4161 4162  
4162 4163          if (status != DLADM_STATUS_OK)
4163 4164                  die_dlerr(status, "unable to obtain tunnel status");
4164 4165  }
4165 4166  
4166 4167  /* ARGSUSED */
4167 4168  static void
4168 4169  do_up_iptun(int argc, char *argv[], const char *use)
4169 4170  {
4170 4171          datalink_id_t   linkid = DATALINK_ALL_LINKID;
4171 4172          dladm_status_t  status = DLADM_STATUS_OK;
4172 4173  
4173 4174          /*
4174 4175           * Get the optional tunnel name argument.  If there is one, it must
4175 4176           * be the last thing remaining on the command-line.
4176 4177           */
4177 4178          if (argc - optind > 1)
4178 4179                  usage();
4179 4180          if (argc - optind == 1) {
4180 4181                  status = dladm_name2info(handle, argv[optind], &linkid, NULL,
4181 4182                      NULL, NULL);
4182 4183          }
4183 4184          if (status == DLADM_STATUS_OK)
4184 4185                  status = dladm_iptun_up(handle, linkid);
4185 4186          if (status != DLADM_STATUS_OK)
4186 4187                  die_dlerr(status, "unable to configure IP tunnel links");
4187 4188  }
4188 4189  
4189 4190  /* ARGSUSED */
4190 4191  static void
4191 4192  do_down_iptun(int argc, char *argv[], const char *use)
4192 4193  {
4193 4194          datalink_id_t   linkid = DATALINK_ALL_LINKID;
4194 4195          dladm_status_t  status = DLADM_STATUS_OK;
4195 4196  
4196 4197          /*
4197 4198           * Get the optional tunnel name argument.  If there is one, it must
4198 4199           * be the last thing remaining on the command-line.
4199 4200           */
4200 4201          if (argc - optind > 1)
4201 4202                  usage();
4202 4203          if (argc - optind == 1) {
4203 4204                  status = dladm_name2info(handle, argv[optind], &linkid, NULL,
4204 4205                      NULL, NULL);
4205 4206          }
4206 4207          if (status == DLADM_STATUS_OK)
4207 4208                  status = dladm_iptun_down(handle, linkid);
4208 4209          if (status != DLADM_STATUS_OK)
4209 4210                  die_dlerr(status, "unable to bring down IP tunnel links");
4210 4211  }
4211 4212  
4212 4213  static iptun_type_t
4213 4214  iptun_gettypebyname(char *typestr)
4214 4215  {
4215 4216          int i;
4216 4217  
4217 4218          for (i = 0; iptun_types[i].type_name != NULL; i++) {
4218 4219                  if (strncmp(iptun_types[i].type_name, typestr,
4219 4220                      strlen(iptun_types[i].type_name)) == 0) {
4220 4221                          return (iptun_types[i].type_value);
4221 4222                  }
4222 4223          }
4223 4224          return (IPTUN_TYPE_UNKNOWN);
4224 4225  }
4225 4226  
4226 4227  static const char *
4227 4228  iptun_gettypebyvalue(iptun_type_t type)
4228 4229  {
4229 4230          int i;
4230 4231  
4231 4232          for (i = 0; iptun_types[i].type_name != NULL; i++) {
4232 4233                  if (iptun_types[i].type_value == type)
4233 4234                          return (iptun_types[i].type_name);
4234 4235          }
4235 4236          return (NULL);
4236 4237  }
4237 4238  
4238 4239  static dladm_status_t
4239 4240  print_iptun(dladm_handle_t dh, datalink_id_t linkid, show_state_t *state)
4240 4241  {
4241 4242          dladm_status_t          status;
4242 4243          iptun_params_t          params;
4243 4244          iptun_fields_buf_t      lbuf;
4244 4245          const char              *laddr;
4245 4246          const char              *raddr;
4246 4247  
4247 4248          params.iptun_param_linkid = linkid;
4248 4249          status = dladm_iptun_getparams(dh, ¶ms, state->ls_flags);
4249 4250          if (status != DLADM_STATUS_OK)
4250 4251                  return (status);
4251 4252  
4252 4253          /* LINK */
4253 4254          status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL,
4254 4255              lbuf.iptun_name, sizeof (lbuf.iptun_name));
4255 4256          if (status != DLADM_STATUS_OK)
4256 4257                  return (status);
4257 4258  
4258 4259          /* TYPE */
4259 4260          (void) strlcpy(lbuf.iptun_type,
4260 4261              iptun_gettypebyvalue(params.iptun_param_type),
4261 4262              sizeof (lbuf.iptun_type));
4262 4263  
4263 4264          /* FLAGS */
4264 4265          (void) memset(lbuf.iptun_flags, '-', IPTUN_NUM_FLAGS);
4265 4266          lbuf.iptun_flags[IPTUN_NUM_FLAGS] = '\0';
4266 4267          if (params.iptun_param_flags & IPTUN_PARAM_IPSECPOL)
4267 4268                  lbuf.iptun_flags[IPTUN_SFLAG_INDEX] = 's';
4268 4269          if (params.iptun_param_flags & IPTUN_PARAM_IMPLICIT)
4269 4270                  lbuf.iptun_flags[IPTUN_IFLAG_INDEX] = 'i';
4270 4271  
4271 4272          /* LOCAL */
4272 4273          if (params.iptun_param_flags & IPTUN_PARAM_LADDR)
4273 4274                  laddr = params.iptun_param_laddr;
4274 4275          else
4275 4276                  laddr = (state->ls_parsable) ? "" : "--";
4276 4277          (void) strlcpy(lbuf.iptun_laddr, laddr, sizeof (lbuf.iptun_laddr));
4277 4278  
4278 4279          /* REMOTE */
4279 4280          if (params.iptun_param_flags & IPTUN_PARAM_RADDR)
4280 4281                  raddr = params.iptun_param_raddr;
4281 4282          else
4282 4283                  raddr = (state->ls_parsable) ? "" : "--";
4283 4284          (void) strlcpy(lbuf.iptun_raddr, raddr, sizeof (lbuf.iptun_raddr));
4284 4285  
4285 4286          ofmt_print(state->ls_ofmt, &lbuf);
4286 4287  
4287 4288          return (DLADM_STATUS_OK);
4288 4289  }
4289 4290  
4290 4291  static int
4291 4292  print_iptun_walker(dladm_handle_t dh, datalink_id_t linkid, void *arg)
4292 4293  {
4293 4294          ((show_state_t *)arg)->ls_status = print_iptun(dh, linkid, arg);
4294 4295          return (DLADM_WALK_CONTINUE);
4295 4296  }
4296 4297  
4297 4298  static dladm_status_t
4298 4299  print_phys(show_state_t *state, datalink_id_t linkid)
4299 4300  {
4300 4301          char                    link[MAXLINKNAMELEN];
4301 4302          uint32_t                flags;
4302 4303          dladm_status_t          status;
4303 4304          datalink_class_t        class;
4304 4305          uint32_t                media;
4305 4306  
4306 4307          if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class,
4307 4308              &media, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
4308 4309                  goto done;
4309 4310          }
4310 4311  
4311 4312          if (class != DATALINK_CLASS_PHYS) {
4312 4313                  status = DLADM_STATUS_BADARG;
4313 4314                  goto done;
4314 4315          }
4315 4316  
4316 4317          if (!(state->ls_flags & flags)) {
4317 4318                  status = DLADM_STATUS_NOTFOUND;
4318 4319                  goto done;
4319 4320          }
4320 4321  
4321 4322          if (state->ls_mac)
4322 4323                  status = print_phys_mac(state, linkid, link);
4323 4324          else if (state->ls_hwgrp)
4324 4325                  status = print_phys_hwgrp(state, linkid, link);
4325 4326          else
4326 4327                  status = print_phys_default(state, linkid, link, flags, media);
4327 4328  
4328 4329  done:
4329 4330          return (status);
4330 4331  }
4331 4332  
4332 4333  /* ARGSUSED */
4333 4334  static int
4334 4335  show_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg)
4335 4336  {
4336 4337          show_state_t    *state = arg;
4337 4338  
4338 4339          state->ls_status = print_phys(state, linkid);
4339 4340          return (DLADM_WALK_CONTINUE);
4340 4341  }
4341 4342  
4342 4343  /*
4343 4344   * Print the active topology information.
4344 4345   */
4345 4346  static dladm_status_t
4346 4347  print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l)
4347 4348  {
4348 4349          dladm_vlan_attr_t       vinfo;
4349 4350          uint32_t                flags;
4350 4351          dladm_status_t          status;
4351 4352  
4352 4353          if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL,
4353 4354              l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) {
4354 4355                  goto done;
4355 4356          }
4356 4357  
4357 4358          if (!(state->ls_flags & flags)) {
4358 4359                  status = DLADM_STATUS_NOTFOUND;
4359 4360                  goto done;
4360 4361          }
4361 4362  
4362 4363          if ((status = dladm_vlan_info(handle, linkid, &vinfo,
4363 4364              state->ls_flags)) != DLADM_STATUS_OK ||
4364 4365              (status = dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL,
4365 4366              NULL, NULL, l->link_over, sizeof (l->link_over))) !=
4366 4367              DLADM_STATUS_OK) {
4367 4368                  goto done;
4368 4369          }
4369 4370  
4370 4371          (void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d",
4371 4372              vinfo.dv_vid);
4372 4373          (void) snprintf(l->link_flags, sizeof (l->link_flags), "%c----",
4373 4374              vinfo.dv_force ? 'f' : '-');
4374 4375  
4375 4376  done:
4376 4377          return (status);
4377 4378  }
4378 4379  
4379 4380  /* ARGSUSED */
4380 4381  static int
4381 4382  show_vlan(dladm_handle_t dh, datalink_id_t linkid, void *arg)
4382 4383  {
4383 4384          show_state_t            *state = arg;
4384 4385          dladm_status_t          status;
4385 4386          link_fields_buf_t       lbuf;
4386 4387  
4387 4388          bzero(&lbuf, sizeof (link_fields_buf_t));
4388 4389          status = print_vlan(state, linkid, &lbuf);
4389 4390          if (status != DLADM_STATUS_OK)
4390 4391                  goto done;
4391 4392  
4392 4393          ofmt_print(state->ls_ofmt, &lbuf);
4393 4394  
4394 4395  done:
4395 4396          state->ls_status = status;
4396 4397          return (DLADM_WALK_CONTINUE);
4397 4398  }
4398 4399  
4399 4400  static void
4400 4401  do_show_phys(int argc, char *argv[], const char *use)
4401 4402  {
4402 4403          int             option;
4403 4404          uint32_t        flags = DLADM_OPT_ACTIVE;
4404 4405          boolean_t       p_arg = B_FALSE;
4405 4406          boolean_t       o_arg = B_FALSE;
4406 4407          boolean_t       m_arg = B_FALSE;
4407 4408          boolean_t       H_arg = B_FALSE;
4408 4409          datalink_id_t   linkid = DATALINK_ALL_LINKID;
4409 4410          show_state_t    state;
4410 4411          dladm_status_t  status;
4411 4412          char            *fields_str = NULL;
4412 4413          char            *all_active_fields =
4413 4414              "link,media,state,speed,duplex,device";
4414 4415          char            *all_inactive_fields = "link,device,media,flags";
4415 4416          char            *all_mac_fields = "link,slot,address,inuse,client";
4416 4417          char            *all_hwgrp_fields = "link,ringtype,rings,clients";
4417 4418          const ofmt_field_t *pf;
4418 4419          ofmt_handle_t   ofmt;
4419 4420          ofmt_status_t   oferr;
4420 4421          uint_t          ofmtflags = 0;
4421 4422  
4422 4423          bzero(&state, sizeof (state));
4423 4424          opterr = 0;
4424 4425          while ((option = getopt_long(argc, argv, ":pPo:mH",
4425 4426              show_lopts, NULL)) != -1) {
4426 4427                  switch (option) {
4427 4428                  case 'p':
4428 4429                          if (p_arg)
4429 4430                                  die_optdup(option);
4430 4431  
4431 4432                          p_arg = B_TRUE;
4432 4433                          break;
4433 4434                  case 'P':
4434 4435                          if (flags != DLADM_OPT_ACTIVE)
4435 4436                                  die_optdup(option);
4436 4437  
4437 4438                          flags = DLADM_OPT_PERSIST;
4438 4439                          break;
4439 4440                  case 'o':
4440 4441                          o_arg = B_TRUE;
4441 4442                          fields_str = optarg;
4442 4443                          break;
4443 4444                  case 'm':
4444 4445                          m_arg = B_TRUE;
4445 4446                          break;
4446 4447                  case 'H':
4447 4448                          H_arg = B_TRUE;
4448 4449                          break;
4449 4450                  default:
4450 4451                          die_opterr(optopt, option, use);
4451 4452                          break;
4452 4453                  }
4453 4454          }
4454 4455  
4455 4456          if (p_arg && !o_arg)
4456 4457                  die("-p requires -o");
4457 4458  
4458 4459          if (m_arg && H_arg)
4459 4460                  die("-m cannot combine with -H");
4460 4461  
4461 4462          if (p_arg && strcasecmp(fields_str, "all") == 0)
4462 4463                  die("\"-o all\" is invalid with -p");
4463 4464  
4464 4465          /* get link name (optional last argument) */
4465 4466          if (optind == (argc-1)) {
4466 4467                  if ((status = dladm_name2info(handle, argv[optind], &linkid,
4467 4468                      NULL, NULL, NULL)) != DLADM_STATUS_OK) {
4468 4469                          die_dlerr(status, "link %s is not valid", argv[optind]);
4469 4470                  }
4470 4471          } else if (optind != argc) {
4471 4472                  usage();
4472 4473          }
4473 4474  
4474 4475          state.ls_parsable = p_arg;
4475 4476          state.ls_flags = flags;
4476 4477          state.ls_donefirst = B_FALSE;
4477 4478          state.ls_mac = m_arg;
4478 4479          state.ls_hwgrp = H_arg;
4479 4480  
4480 4481          if (m_arg && !(flags & DLADM_OPT_ACTIVE)) {
4481 4482                  /*
4482 4483                   * We can only display the factory MAC addresses of
4483 4484                   * active data-links.
4484 4485                   */
4485 4486                  die("-m not compatible with -P");
4486 4487          }
4487 4488  
4488 4489          if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
4489 4490                  if (state.ls_mac)
4490 4491                          fields_str = all_mac_fields;
4491 4492                  else if (state.ls_hwgrp)
4492 4493                          fields_str = all_hwgrp_fields;
4493 4494                  else if (state.ls_flags & DLADM_OPT_ACTIVE) {
4494 4495                          fields_str = all_active_fields;
4495 4496                  } else {
4496 4497                          fields_str = all_inactive_fields;
4497 4498                  }
4498 4499          }
4499 4500  
4500 4501          if (state.ls_mac) {
4501 4502                  pf = phys_m_fields;
4502 4503          } else if (state.ls_hwgrp) {
4503 4504                  pf = phys_h_fields;
4504 4505          } else {
4505 4506                  pf = phys_fields;
4506 4507          }
4507 4508  
4508 4509          if (state.ls_parsable)
4509 4510                  ofmtflags |= OFMT_PARSABLE;
4510 4511          oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt);
4511 4512          ofmt_check(oferr, state.ls_parsable, ofmt, die, warn);
4512 4513          state.ls_ofmt = ofmt;
4513 4514  
4514 4515          if (linkid == DATALINK_ALL_LINKID) {
4515 4516                  (void) dladm_walk_datalink_id(show_phys, handle, &state,
4516 4517                      DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags);
4517 4518          } else {
4518 4519                  (void) show_phys(handle, linkid, &state);
4519 4520                  if (state.ls_status != DLADM_STATUS_OK) {
4520 4521                          die_dlerr(state.ls_status,
4521 4522                              "failed to show physical link %s", argv[optind]);
4522 4523                  }
4523 4524          }
4524 4525          ofmt_close(ofmt);
4525 4526  }
4526 4527  
4527 4528  static void
4528 4529  do_show_vlan(int argc, char *argv[], const char *use)
4529 4530  {
4530 4531          int             option;
4531 4532          uint32_t        flags = DLADM_OPT_ACTIVE;
4532 4533          boolean_t       p_arg = B_FALSE;
4533 4534          datalink_id_t   linkid = DATALINK_ALL_LINKID;
4534 4535          show_state_t    state;
4535 4536          dladm_status_t  status;
4536 4537          boolean_t       o_arg = B_FALSE;
4537 4538          char            *fields_str = NULL;
4538 4539          ofmt_handle_t   ofmt;
4539 4540          ofmt_status_t   oferr;
4540 4541          uint_t          ofmtflags = 0;
4541 4542  
4542 4543          bzero(&state, sizeof (state));
4543 4544  
4544 4545          opterr = 0;
4545 4546          while ((option = getopt_long(argc, argv, ":pPo:",
4546 4547              show_lopts, NULL)) != -1) {
4547 4548                  switch (option) {
4548 4549                  case 'p':
4549 4550                          if (p_arg)
4550 4551                                  die_optdup(option);
4551 4552  
4552 4553                          p_arg = B_TRUE;
4553 4554                          break;
4554 4555                  case 'P':
4555 4556                          if (flags != DLADM_OPT_ACTIVE)
4556 4557                                  die_optdup(option);
4557 4558  
4558 4559                          flags = DLADM_OPT_PERSIST;
4559 4560                          break;
4560 4561                  case 'o':
4561 4562                          o_arg = B_TRUE;
4562 4563                          fields_str = optarg;
4563 4564                          break;
4564 4565                  default:
4565 4566                          die_opterr(optopt, option, use);
4566 4567                          break;
4567 4568                  }
4568 4569          }
4569 4570  
4570 4571          /* get link name (optional last argument) */
4571 4572          if (optind == (argc-1)) {
4572 4573                  if ((status = dladm_name2info(handle, argv[optind], &linkid,
4573 4574                      NULL, NULL, NULL)) != DLADM_STATUS_OK) {
4574 4575                          die_dlerr(status, "link %s is not valid", argv[optind]);
4575 4576                  }
4576 4577          } else if (optind != argc) {
4577 4578                  usage();
4578 4579          }
4579 4580  
4580 4581          state.ls_parsable = p_arg;
4581 4582          state.ls_flags = flags;
4582 4583          state.ls_donefirst = B_FALSE;
4583 4584  
4584 4585          if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
4585 4586                  fields_str = NULL;
4586 4587  
4587 4588          if (state.ls_parsable)
4588 4589                  ofmtflags |= OFMT_PARSABLE;
4589 4590          oferr = ofmt_open(fields_str, vlan_fields, ofmtflags, 0, &ofmt);
4590 4591          ofmt_check(oferr, state.ls_parsable, ofmt, die, warn);
4591 4592          state.ls_ofmt = ofmt;
4592 4593  
4593 4594          if (linkid == DATALINK_ALL_LINKID) {
4594 4595                  (void) dladm_walk_datalink_id(show_vlan, handle, &state,
4595 4596                      DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags);
4596 4597          } else {
4597 4598                  (void) show_vlan(handle, linkid, &state);
4598 4599                  if (state.ls_status != DLADM_STATUS_OK) {
4599 4600                          die_dlerr(state.ls_status, "failed to show vlan %s",
4600 4601                              argv[optind]);
4601 4602                  }
4602 4603          }
4603 4604          ofmt_close(ofmt);
4604 4605  }
4605 4606  
4606 4607  static void
4607 4608  do_create_vnic(int argc, char *argv[], const char *use)
4608 4609  {
4609 4610          datalink_id_t           linkid, dev_linkid;
4610 4611          char                    devname[MAXLINKNAMELEN];
4611 4612          char                    name[MAXLINKNAMELEN];
4612 4613          boolean_t               l_arg = B_FALSE;
4613 4614          uint32_t                flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
4614 4615          char                    *altroot = NULL;
4615 4616          int                     option;
4616 4617          char                    *endp = NULL;
4617 4618          dladm_status_t          status;
4618 4619          vnic_mac_addr_type_t    mac_addr_type = VNIC_MAC_ADDR_TYPE_UNKNOWN;
4619 4620          uchar_t                 *mac_addr = NULL;
4620 4621          int                     mac_slot = -1;
4621 4622          uint_t                  maclen = 0, mac_prefix_len = 0;
4622 4623          char                    propstr[DLADM_STRSIZE];
4623 4624          dladm_arg_list_t        *proplist = NULL;
4624 4625          int                     vid = 0;
4625 4626          int                     af = AF_UNSPEC;
4626 4627          vrid_t                  vrid = VRRP_VRID_NONE;
4627 4628  
4628 4629          opterr = 0;
4629 4630          bzero(propstr, DLADM_STRSIZE);
4630 4631  
4631 4632          while ((option = getopt_long(argc, argv, ":tfR:l:m:n:p:r:v:V:A:H",
4632 4633              vnic_lopts, NULL)) != -1) {
4633 4634                  switch (option) {
4634 4635                  case 't':
4635 4636                          flags &= ~DLADM_OPT_PERSIST;
4636 4637                          break;
4637 4638                  case 'R':
4638 4639                          altroot = optarg;
4639 4640                          break;
4640 4641                  case 'l':
4641 4642                          if (strlcpy(devname, optarg, MAXLINKNAMELEN) >=
4642 4643                              MAXLINKNAMELEN)
4643 4644                                  die("link name too long");
4644 4645                          l_arg = B_TRUE;
4645 4646                          break;
4646 4647                  case 'm':
4647 4648                          if (mac_addr_type != VNIC_MAC_ADDR_TYPE_UNKNOWN)
4648 4649                                  die("cannot specify -m option twice");
4649 4650  
4650 4651                          if (strcmp(optarg, "fixed") == 0) {
4651 4652                                  /*
4652 4653                                   * A fixed MAC address must be specified
4653 4654                                   * by its value, not by the keyword 'fixed'.
4654 4655                                   */
4655 4656                                  die("'fixed' is not a valid MAC address");
4656 4657                          }
4657 4658                          if (dladm_vnic_str2macaddrtype(optarg,
4658 4659                              &mac_addr_type) != DLADM_STATUS_OK) {
4659 4660                                  mac_addr_type = VNIC_MAC_ADDR_TYPE_FIXED;
4660 4661                                  /* MAC address specified by value */
4661 4662                                  mac_addr = _link_aton(optarg, (int *)&maclen);
4662 4663                                  if (mac_addr == NULL) {
4663 4664                                          if (maclen == (uint_t)-1)
4664 4665                                                  die("invalid MAC address");
4665 4666                                          else
4666 4667                                                  die("out of memory");
4667 4668                                  }
4668 4669                          }
4669 4670                          break;
4670 4671                  case 'n':
4671 4672                          errno = 0;
4672 4673                          mac_slot = (int)strtol(optarg, &endp, 10);
4673 4674                          if (errno != 0 || *endp != '\0')
4674 4675                                  die("invalid slot number");
4675 4676                          break;
4676 4677                  case 'p':
4677 4678                          (void) strlcat(propstr, optarg, DLADM_STRSIZE);
4678 4679                          if (strlcat(propstr, ",", DLADM_STRSIZE) >=
4679 4680                              DLADM_STRSIZE)
4680 4681                                  die("property list too long '%s'", propstr);
4681 4682                          break;
4682 4683                  case 'r':
4683 4684                          mac_addr = _link_aton(optarg, (int *)&mac_prefix_len);
4684 4685                          if (mac_addr == NULL) {
4685 4686                                  if (mac_prefix_len == (uint_t)-1)
4686 4687                                          die("invalid MAC address");
4687 4688                                  else
4688 4689                                          die("out of memory");
4689 4690                          }
4690 4691                          break;
4691 4692                  case 'V':
4692 4693                          if (!str2int(optarg, (int *)&vrid) ||
4693 4694                              vrid < VRRP_VRID_MIN || vrid > VRRP_VRID_MAX) {
4694 4695                                  die("invalid VRRP identifier '%s'", optarg);
4695 4696                          }
4696 4697  
4697 4698                          break;
4698 4699                  case 'A':
4699 4700                          if (strcmp(optarg, "inet") == 0)
4700 4701                                  af = AF_INET;
4701 4702                          else if (strcmp(optarg, "inet6") == 0)
4702 4703                                  af = AF_INET6;
4703 4704                          else
4704 4705                                  die("invalid address family '%s'", optarg);
4705 4706                          break;
4706 4707                  case 'v':
4707 4708                          if (vid != 0)
4708 4709                                  die_optdup(option);
4709 4710  
4710 4711                          if (!str2int(optarg, &vid) || vid < 1 || vid > 4094)
4711 4712                                  die("invalid VLAN identifier '%s'", optarg);
4712 4713  
4713 4714                          break;
4714 4715                  case 'f':
4715 4716                          flags |= DLADM_OPT_FORCE;
4716 4717                          break;
4717 4718                  default:
4718 4719                          die_opterr(optopt, option, use);
4719 4720                  }
4720 4721          }
4721 4722  
4722 4723          if (mac_addr_type == VNIC_MAC_ADDR_TYPE_UNKNOWN)
4723 4724                  mac_addr_type = VNIC_MAC_ADDR_TYPE_AUTO;
4724 4725  
4725 4726          /*
4726 4727           * 'f' - force, flag can be specified only with 'v' - vlan.
4727 4728           */
4728 4729          if ((flags & DLADM_OPT_FORCE) != 0 && vid == 0)
4729 4730                  die("-f option can only be used with -v");
4730 4731  
4731 4732          if (mac_prefix_len != 0 && mac_addr_type != VNIC_MAC_ADDR_TYPE_RANDOM &&
4732 4733              mac_addr_type != VNIC_MAC_ADDR_TYPE_FIXED)
4733 4734                  usage();
4734 4735  
4735 4736          if (mac_addr_type == VNIC_MAC_ADDR_TYPE_VRID) {
4736 4737                  if (vrid == VRRP_VRID_NONE || af == AF_UNSPEC ||
4737 4738                      mac_addr != NULL || maclen != 0 || mac_slot != -1 ||
4738 4739                      mac_prefix_len != 0) {
4739 4740                          usage();
4740 4741                  }
4741 4742          } else if ((af != AF_UNSPEC || vrid != VRRP_VRID_NONE)) {
4742 4743                  usage();
4743 4744          }
4744 4745  
4745 4746          /* check required options */
4746 4747          if (!l_arg)
4747 4748                  usage();
4748 4749  
4749 4750          if (mac_slot != -1 && mac_addr_type != VNIC_MAC_ADDR_TYPE_FACTORY)
4750 4751                  usage();
4751 4752  
4752 4753          /* the VNIC id is the required operand */
4753 4754          if (optind != (argc - 1))
4754 4755                  usage();
4755 4756  
4756 4757          if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
4757 4758                  die("link name too long '%s'", argv[optind]);
4758 4759  
4759 4760          if (!dladm_valid_linkname(name))
4760 4761                  die("invalid link name '%s'", argv[optind]);
4761 4762  
4762 4763          if (altroot != NULL)
4763 4764                  altroot_cmd(altroot, argc, argv);
4764 4765  
4765 4766          if (dladm_name2info(handle, devname, &dev_linkid, NULL, NULL, NULL) !=
4766 4767              DLADM_STATUS_OK)
4767 4768                  die("invalid link name '%s'", devname);
4768 4769  
4769 4770          if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
4770 4771              != DLADM_STATUS_OK)
4771 4772                  die("invalid vnic property");
4772 4773  
4773 4774          status = dladm_vnic_create(handle, name, dev_linkid, mac_addr_type,
4774 4775              mac_addr, maclen, &mac_slot, mac_prefix_len, vid, vrid, af,
4775 4776              &linkid, proplist, flags);
4776 4777          switch (status) {
4777 4778          case DLADM_STATUS_OK:
4778 4779                  break;
4779 4780  
4780 4781          case DLADM_STATUS_LINKBUSY:
4781 4782                  die("VLAN over '%s' may not use default_tag ID "
4782 4783                      "(see dladm(1M))", devname);
4783 4784                  break;
4784 4785  
4785 4786          default:
4786 4787                  die_dlerr(status, "vnic creation over %s failed", devname);
4787 4788          }
4788 4789  
4789 4790          dladm_free_props(proplist);
4790 4791          free(mac_addr);
4791 4792  }
4792 4793  
4793 4794  static void
4794 4795  do_etherstub_check(const char *name, datalink_id_t linkid, boolean_t etherstub,
4795 4796      uint32_t flags)
4796 4797  {
4797 4798          boolean_t is_etherstub;
4798 4799          dladm_vnic_attr_t attr;
4799 4800  
4800 4801          if (dladm_vnic_info(handle, linkid, &attr, flags) != DLADM_STATUS_OK) {
4801 4802                  /*
4802 4803                   * Let the delete continue anyway.
4803 4804                   */
4804 4805                  return;
4805 4806          }
4806 4807          is_etherstub = (attr.va_link_id == DATALINK_INVALID_LINKID);
4807 4808          if (is_etherstub != etherstub) {
4808 4809                  die("'%s' is not %s", name,
4809 4810                      (is_etherstub ? "a vnic" : "an etherstub"));
4810 4811          }
4811 4812  }
4812 4813  
4813 4814  static void
4814 4815  do_delete_vnic_common(int argc, char *argv[], const char *use,
4815 4816      boolean_t etherstub)
4816 4817  {
4817 4818          int option;
4818 4819          uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
4819 4820          datalink_id_t linkid;
4820 4821          char *altroot = NULL;
4821 4822          dladm_status_t status;
4822 4823  
4823 4824          opterr = 0;
4824 4825          while ((option = getopt_long(argc, argv, ":R:t", lopts,
4825 4826              NULL)) != -1) {
4826 4827                  switch (option) {
4827 4828                  case 't':
4828 4829                          flags &= ~DLADM_OPT_PERSIST;
4829 4830                          break;
4830 4831                  case 'R':
4831 4832                          altroot = optarg;
4832 4833                          break;
4833 4834                  default:
4834 4835                          die_opterr(optopt, option, use);
4835 4836                  }
4836 4837          }
4837 4838  
4838 4839          /* get vnic name (required last argument) */
4839 4840          if (optind != (argc - 1))
4840 4841                  usage();
4841 4842  
4842 4843          if (altroot != NULL)
4843 4844                  altroot_cmd(altroot, argc, argv);
4844 4845  
4845 4846          status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
4846 4847              NULL);
4847 4848          if (status != DLADM_STATUS_OK)
4848 4849                  die("invalid link name '%s'", argv[optind]);
4849 4850  
4850 4851          if ((flags & DLADM_OPT_ACTIVE) != 0) {
4851 4852                  do_etherstub_check(argv[optind], linkid, etherstub,
4852 4853                      DLADM_OPT_ACTIVE);
4853 4854          }
4854 4855          if ((flags & DLADM_OPT_PERSIST) != 0) {
4855 4856                  do_etherstub_check(argv[optind], linkid, etherstub,
4856 4857                      DLADM_OPT_PERSIST);
4857 4858          }
4858 4859  
4859 4860          status = dladm_vnic_delete(handle, linkid, flags);
4860 4861          if (status != DLADM_STATUS_OK)
4861 4862                  die_dlerr(status, "vnic deletion failed");
4862 4863  }
4863 4864  
4864 4865  static void
4865 4866  do_delete_vnic(int argc, char *argv[], const char *use)
4866 4867  {
4867 4868          do_delete_vnic_common(argc, argv, use, B_FALSE);
4868 4869  }
4869 4870  
4870 4871  /* ARGSUSED */
4871 4872  static void
4872 4873  do_up_vnic_common(int argc, char *argv[], const char *use, boolean_t vlan)
4873 4874  {
4874 4875          datalink_id_t   linkid = DATALINK_ALL_LINKID;
4875 4876          dladm_status_t  status;
4876 4877          char            *type;
4877 4878  
4878 4879          type = vlan ? "vlan" : "vnic";
4879 4880  
4880 4881          /*
4881 4882           * get the id or the name of the vnic/vlan (optional last argument)
4882 4883           */
4883 4884          if (argc == 2) {
4884 4885                  status = dladm_name2info(handle, argv[1], &linkid, NULL, NULL,
4885 4886                      NULL);
4886 4887                  if (status != DLADM_STATUS_OK)
4887 4888                          goto done;
4888 4889  
4889 4890          } else if (argc > 2) {
4890 4891                  usage();
4891 4892          }
4892 4893  
4893 4894          if (vlan)
4894 4895                  status = dladm_vlan_up(handle, linkid);
4895 4896          else
4896 4897                  status = dladm_vnic_up(handle, linkid, 0);
4897 4898  
4898 4899  done:
4899 4900          if (status != DLADM_STATUS_OK) {
4900 4901                  if (argc == 2) {
4901 4902                          die_dlerr(status,
4902 4903                              "could not bring up %s '%s'", type, argv[1]);
4903 4904                  } else {
4904 4905                          die_dlerr(status, "could not bring %ss up", type);
4905 4906                  }
4906 4907          }
4907 4908  }
4908 4909  
4909 4910  static void
4910 4911  do_up_vnic(int argc, char *argv[], const char *use)
4911 4912  {
4912 4913          do_up_vnic_common(argc, argv, use, B_FALSE);
4913 4914  }
4914 4915  
4915 4916  static void
4916 4917  dump_vnics_head(const char *dev)
4917 4918  {
4918 4919          if (strlen(dev))
4919 4920                  (void) printf("%s", dev);
4920 4921  
4921 4922          (void) printf("\tipackets  rbytes      opackets  obytes          ");
4922 4923  
4923 4924          if (strlen(dev))
4924 4925                  (void) printf("%%ipkts  %%opkts\n");
4925 4926          else
4926 4927                  (void) printf("\n");
4927 4928  }
4928 4929  
4929 4930  static void
4930 4931  dump_vnic_stat(const char *name, datalink_id_t vnic_id,
4931 4932      show_vnic_state_t *state, pktsum_t *vnic_stats, pktsum_t *tot_stats)
4932 4933  {
4933 4934          pktsum_t        diff_stats;
4934 4935          pktsum_t        *old_stats = &state->vs_prevstats[vnic_id];
4935 4936  
4936 4937          dladm_stats_diff(&diff_stats, vnic_stats, old_stats);
4937 4938  
4938 4939          (void) printf("%s", name);
4939 4940  
4940 4941          (void) printf("\t%-10llu", diff_stats.ipackets);
4941 4942          (void) printf("%-12llu", diff_stats.rbytes);
4942 4943          (void) printf("%-10llu", diff_stats.opackets);
4943 4944          (void) printf("%-12llu", diff_stats.obytes);
4944 4945  
4945 4946          if (tot_stats) {
4946 4947                  if (tot_stats->ipackets == 0) {
4947 4948                          (void) printf("\t-");
4948 4949                  } else {
4949 4950                          (void) printf("\t%-6.1f", (double)diff_stats.ipackets/
4950 4951                              (double)tot_stats->ipackets * 100);
4951 4952                  }
4952 4953                  if (tot_stats->opackets == 0) {
4953 4954                          (void) printf("\t-");
4954 4955                  } else {
4955 4956                          (void) printf("\t%-6.1f", (double)diff_stats.opackets/
4956 4957                              (double)tot_stats->opackets * 100);
4957 4958                  }
4958 4959          }
4959 4960          (void) printf("\n");
4960 4961  
4961 4962          *old_stats = *vnic_stats;
4962 4963  }
4963 4964  
4964 4965  /*
4965 4966   * Called from the walker dladm_vnic_walk_sys() for each vnic to display
4966 4967   * vnic information or statistics.
4967 4968   */
4968 4969  static dladm_status_t
4969 4970  print_vnic(show_vnic_state_t *state, datalink_id_t linkid)
4970 4971  {
4971 4972          dladm_vnic_attr_t       attr, *vnic = &attr;
4972 4973          dladm_status_t          status;
4973 4974          boolean_t               is_etherstub;
4974 4975          char                    devname[MAXLINKNAMELEN];
4975 4976          char                    vnic_name[MAXLINKNAMELEN];
4976 4977          char                    mstr[MAXMACADDRLEN * 3];
4977 4978          vnic_fields_buf_t       vbuf;
4978 4979  
4979 4980          if ((status = dladm_vnic_info(handle, linkid, vnic, state->vs_flags)) !=
4980 4981              DLADM_STATUS_OK)
4981 4982                  return (status);
4982 4983  
4983 4984          is_etherstub = (vnic->va_link_id == DATALINK_INVALID_LINKID);
4984 4985          if (state->vs_etherstub != is_etherstub) {
4985 4986                  /*
4986 4987                   * Want all etherstub but it's not one, or want
4987 4988                   * non-etherstub and it's one.
4988 4989                   */
4989 4990                  return (DLADM_STATUS_OK);
4990 4991          }
4991 4992  
4992 4993          if (state->vs_link_id != DATALINK_ALL_LINKID) {
4993 4994                  if (state->vs_link_id != vnic->va_link_id)
4994 4995                          return (DLADM_STATUS_OK);
4995 4996          }
4996 4997  
4997 4998          if (dladm_datalink_id2info(handle, linkid, NULL, NULL,
4998 4999              NULL, vnic_name, sizeof (vnic_name)) != DLADM_STATUS_OK)
4999 5000                  return (DLADM_STATUS_BADARG);
5000 5001  
5001 5002          bzero(devname, sizeof (devname));
5002 5003          if (!is_etherstub &&
5003 5004              dladm_datalink_id2info(handle, vnic->va_link_id, NULL, NULL,
5004 5005              NULL, devname, sizeof (devname)) != DLADM_STATUS_OK)
5005 5006                  (void) sprintf(devname, "?");
5006 5007  
5007 5008          state->vs_found = B_TRUE;
5008 5009          if (state->vs_stats) {
5009 5010                  /* print vnic statistics */
5010 5011                  pktsum_t vnic_stats;
5011 5012  
5012 5013                  if (state->vs_firstonly) {
5013 5014                          if (state->vs_donefirst)
5014 5015                                  return (0);
5015 5016                          state->vs_donefirst = B_TRUE;
5016 5017                  }
5017 5018  
5018 5019                  if (!state->vs_printstats) {
5019 5020                          /*
5020 5021                           * get vnic statistics and add to the sum for the
5021 5022                           * named device.
5022 5023                           */
5023 5024                          get_link_stats(vnic_name, &vnic_stats);
5024 5025                          dladm_stats_total(&state->vs_totalstats, &vnic_stats,
5025 5026                              &state->vs_prevstats[vnic->va_vnic_id]);
5026 5027                  } else {
5027 5028                          /* get and print vnic statistics */
5028 5029                          get_link_stats(vnic_name, &vnic_stats);
5029 5030                          dump_vnic_stat(vnic_name, linkid, state, &vnic_stats,
5030 5031                              &state->vs_totalstats);
5031 5032                  }
5032 5033                  return (DLADM_STATUS_OK);
5033 5034          } else {
5034 5035                  (void) snprintf(vbuf.vnic_link, sizeof (vbuf.vnic_link),
5035 5036                      "%s", vnic_name);
5036 5037  
5037 5038                  if (!is_etherstub) {
5038 5039  
5039 5040                          (void) snprintf(vbuf.vnic_over, sizeof (vbuf.vnic_over),
5040 5041                              "%s", devname);
5041 5042                          (void) snprintf(vbuf.vnic_speed,
5042 5043                              sizeof (vbuf.vnic_speed), "%u",
5043 5044                              (uint_t)((get_ifspeed(vnic_name, B_TRUE))
5044 5045                              / 1000000ull));
5045 5046  
5046 5047                          switch (vnic->va_mac_addr_type) {
5047 5048                          case VNIC_MAC_ADDR_TYPE_FIXED:
5048 5049                          case VNIC_MAC_ADDR_TYPE_PRIMARY:
5049 5050                                  (void) snprintf(vbuf.vnic_macaddrtype,
5050 5051                                      sizeof (vbuf.vnic_macaddrtype),
5051 5052                                      gettext("fixed"));
5052 5053                                  break;
5053 5054                          case VNIC_MAC_ADDR_TYPE_RANDOM:
5054 5055                                  (void) snprintf(vbuf.vnic_macaddrtype,
5055 5056                                      sizeof (vbuf.vnic_macaddrtype),
5056 5057                                      gettext("random"));
5057 5058                                  break;
5058 5059                          case VNIC_MAC_ADDR_TYPE_FACTORY:
5059 5060                                  (void) snprintf(vbuf.vnic_macaddrtype,
5060 5061                                      sizeof (vbuf.vnic_macaddrtype),
5061 5062                                      gettext("factory, slot %d"),
5062 5063                                      vnic->va_mac_slot);
5063 5064                                  break;
5064 5065                          case VNIC_MAC_ADDR_TYPE_VRID:
5065 5066                                  (void) snprintf(vbuf.vnic_macaddrtype,
5066 5067                                      sizeof (vbuf.vnic_macaddrtype),
5067 5068                                      gettext("vrrp, %d/%s"),
5068 5069                                      vnic->va_vrid, vnic->va_af == AF_INET ?
5069 5070                                      "inet" : "inet6");
5070 5071                                  break;
5071 5072                          }
5072 5073  
5073 5074                          if (strlen(vbuf.vnic_macaddrtype) > 0) {
5074 5075                                  (void) snprintf(vbuf.vnic_macaddr,
5075 5076                                      sizeof (vbuf.vnic_macaddr), "%s",
5076 5077                                      dladm_aggr_macaddr2str(vnic->va_mac_addr,
5077 5078                                      mstr));
5078 5079                          }
5079 5080  
5080 5081                          (void) snprintf(vbuf.vnic_vid, sizeof (vbuf.vnic_vid),
5081 5082                              "%d", vnic->va_vid);
5082 5083                  }
5083 5084  
5084 5085                  ofmt_print(state->vs_ofmt, &vbuf);
5085 5086  
5086 5087                  return (DLADM_STATUS_OK);
5087 5088          }
5088 5089  }
5089 5090  
5090 5091  /* ARGSUSED */
5091 5092  static int
5092 5093  show_vnic(dladm_handle_t dh, datalink_id_t linkid, void *arg)
5093 5094  {
5094 5095          show_vnic_state_t       *state = arg;
5095 5096  
5096 5097          state->vs_status = print_vnic(state, linkid);
5097 5098          return (DLADM_WALK_CONTINUE);
5098 5099  }
5099 5100  
5100 5101  static void
5101 5102  do_show_vnic_common(int argc, char *argv[], const char *use,
5102 5103      boolean_t etherstub)
5103 5104  {
5104 5105          int                     option;
5105 5106          boolean_t               s_arg = B_FALSE;
5106 5107          boolean_t               i_arg = B_FALSE;
5107 5108          boolean_t               l_arg = B_FALSE;
5108 5109          uint32_t                interval = 0, flags = DLADM_OPT_ACTIVE;
5109 5110          datalink_id_t           linkid = DATALINK_ALL_LINKID;
5110 5111          datalink_id_t           dev_linkid = DATALINK_ALL_LINKID;
5111 5112          show_vnic_state_t       state;
5112 5113          dladm_status_t          status;
5113 5114          boolean_t               o_arg = B_FALSE;
5114 5115          char                    *fields_str = NULL;
5115 5116          const ofmt_field_t      *pf;
5116 5117          char                    *all_e_fields = "link";
5117 5118          ofmt_handle_t           ofmt;
5118 5119          ofmt_status_t           oferr;
5119 5120          uint_t                  ofmtflags = 0;
5120 5121  
5121 5122          bzero(&state, sizeof (state));
5122 5123          opterr = 0;
5123 5124          while ((option = getopt_long(argc, argv, ":pPl:si:o:", lopts,
5124 5125              NULL)) != -1) {
5125 5126                  switch (option) {
5126 5127                  case 'p':
5127 5128                          state.vs_parsable = B_TRUE;
5128 5129                          break;
5129 5130                  case 'P':
5130 5131                          flags = DLADM_OPT_PERSIST;
5131 5132                          break;
5132 5133                  case 'l':
5133 5134                          if (etherstub)
5134 5135                                  die("option not supported for this command");
5135 5136  
5136 5137                          if (strlcpy(state.vs_link, optarg, MAXLINKNAMELEN) >=
5137 5138                              MAXLINKNAMELEN)
5138 5139                                  die("link name too long");
5139 5140  
5140 5141                          l_arg = B_TRUE;
5141 5142                          break;
5142 5143                  case 's':
5143 5144                          if (s_arg) {
5144 5145                                  die("the option -s cannot be specified "
5145 5146                                      "more than once");
5146 5147                          }
5147 5148                          s_arg = B_TRUE;
5148 5149                          break;
5149 5150                  case 'i':
5150 5151                          if (i_arg) {
5151 5152                                  die("the option -i cannot be specified "
5152 5153                                      "more than once");
5153 5154                          }
5154 5155                          i_arg = B_TRUE;
5155 5156                          if (!dladm_str2interval(optarg, &interval))
5156 5157                                  die("invalid interval value '%s'", optarg);
5157 5158                          break;
5158 5159                  case 'o':
5159 5160                          o_arg = B_TRUE;
5160 5161                          fields_str = optarg;
5161 5162                          break;
5162 5163                  default:
5163 5164                          die_opterr(optopt, option, use);
5164 5165                  }
5165 5166          }
5166 5167  
5167 5168          if (i_arg && !s_arg)
5168 5169                  die("the option -i can be used only with -s");
5169 5170  
5170 5171          /* get vnic ID (optional last argument) */
5171 5172          if (optind == (argc - 1)) {
5172 5173                  status = dladm_name2info(handle, argv[optind], &linkid, NULL,
5173 5174                      NULL, NULL);
5174 5175                  if (status != DLADM_STATUS_OK) {
5175 5176                          die_dlerr(status, "invalid vnic name '%s'",
5176 5177                              argv[optind]);
5177 5178                  }
5178 5179                  (void) strlcpy(state.vs_vnic, argv[optind], MAXLINKNAMELEN);
5179 5180          } else if (optind != argc) {
5180 5181                  usage();
5181 5182          }
5182 5183  
5183 5184          if (l_arg) {
5184 5185                  status = dladm_name2info(handle, state.vs_link, &dev_linkid,
5185 5186                      NULL, NULL, NULL);
5186 5187                  if (status != DLADM_STATUS_OK) {
5187 5188                          die_dlerr(status, "invalid link name '%s'",
5188 5189                              state.vs_link);
5189 5190                  }
5190 5191          }
5191 5192  
5192 5193          state.vs_vnic_id = linkid;
5193 5194          state.vs_link_id = dev_linkid;
5194 5195          state.vs_etherstub = etherstub;
5195 5196          state.vs_found = B_FALSE;
5196 5197          state.vs_flags = flags;
5197 5198  
5198 5199          if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
5199 5200                  if (etherstub)
5200 5201                          fields_str = all_e_fields;
5201 5202          }
5202 5203          pf = vnic_fields;
5203 5204  
5204 5205          if (state.vs_parsable)
5205 5206                  ofmtflags |= OFMT_PARSABLE;
5206 5207          oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt);
5207 5208          ofmt_check(oferr, state.vs_parsable, ofmt, die, warn);
5208 5209          state.vs_ofmt = ofmt;
5209 5210  
5210 5211          if (s_arg) {
5211 5212                  /* Display vnic statistics */
5212 5213                  vnic_stats(&state, interval);
5213 5214                  ofmt_close(ofmt);
5214 5215                  return;
5215 5216          }
5216 5217  
5217 5218          /* Display vnic information */
5218 5219          state.vs_donefirst = B_FALSE;
5219 5220  
5220 5221          if (linkid == DATALINK_ALL_LINKID) {
5221 5222                  (void) dladm_walk_datalink_id(show_vnic, handle, &state,
5222 5223                      DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB,
5223 5224                      DATALINK_ANY_MEDIATYPE, flags);
5224 5225          } else {
5225 5226                  (void) show_vnic(handle, linkid, &state);
5226 5227                  if (state.vs_status != DLADM_STATUS_OK) {
5227 5228                          ofmt_close(ofmt);
5228 5229                          die_dlerr(state.vs_status, "failed to show vnic '%s'",
5229 5230                              state.vs_vnic);
5230 5231                  }
5231 5232          }
5232 5233          ofmt_close(ofmt);
5233 5234  }
5234 5235  
5235 5236  static void
5236 5237  do_show_vnic(int argc, char *argv[], const char *use)
5237 5238  {
5238 5239          do_show_vnic_common(argc, argv, use, B_FALSE);
5239 5240  }
5240 5241  
5241 5242  static void
5242 5243  do_create_etherstub(int argc, char *argv[], const char *use)
5243 5244  {
5244 5245          uint32_t flags;
5245 5246          char *altroot = NULL;
5246 5247          int option;
5247 5248          dladm_status_t status;
5248 5249          char name[MAXLINKNAMELEN];
5249 5250          uchar_t mac_addr[ETHERADDRL];
5250 5251  
5251 5252          name[0] = '\0';
5252 5253          bzero(mac_addr, sizeof (mac_addr));
5253 5254          flags = DLADM_OPT_ANCHOR | DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
5254 5255  
5255 5256          opterr = 0;
5256 5257          while ((option = getopt_long(argc, argv, "tR:",
5257 5258              etherstub_lopts, NULL)) != -1) {
5258 5259                  switch (option) {
5259 5260                  case 't':
5260 5261                          flags &= ~DLADM_OPT_PERSIST;
5261 5262                          break;
5262 5263                  case 'R':
5263 5264                          altroot = optarg;
5264 5265                          break;
5265 5266                  default:
5266 5267                          die_opterr(optopt, option, use);
5267 5268                  }
5268 5269          }
5269 5270  
5270 5271          /* the etherstub id is the required operand */
5271 5272          if (optind != (argc - 1))
5272 5273                  usage();
5273 5274  
5274 5275          if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
5275 5276                  die("link name too long '%s'", argv[optind]);
5276 5277  
5277 5278          if (!dladm_valid_linkname(name))
5278 5279                  die("invalid link name '%s'", argv[optind]);
5279 5280  
5280 5281          if (altroot != NULL)
5281 5282                  altroot_cmd(altroot, argc, argv);
5282 5283  
5283 5284          status = dladm_vnic_create(handle, name, DATALINK_INVALID_LINKID,
5284 5285              VNIC_MAC_ADDR_TYPE_AUTO, mac_addr, ETHERADDRL, NULL, 0, 0,
5285 5286              VRRP_VRID_NONE, AF_UNSPEC, NULL, NULL, flags);
5286 5287          if (status != DLADM_STATUS_OK)
5287 5288                  die_dlerr(status, "etherstub creation failed");
5288 5289  }
5289 5290  
5290 5291  static void
5291 5292  do_delete_etherstub(int argc, char *argv[], const char *use)
5292 5293  {
5293 5294          do_delete_vnic_common(argc, argv, use, B_TRUE);
5294 5295  }
5295 5296  
5296 5297  /* ARGSUSED */
5297 5298  static void
5298 5299  do_show_etherstub(int argc, char *argv[], const char *use)
5299 5300  {
5300 5301          do_show_vnic_common(argc, argv, use, B_TRUE);
5301 5302  }
5302 5303  
5303 5304  /* ARGSUSED */
5304 5305  static void
5305 5306  do_up_simnet(int argc, char *argv[], const char *use)
5306 5307  {
5307 5308          (void) dladm_simnet_up(handle, DATALINK_ALL_LINKID, 0);
5308 5309  }
5309 5310  
5310 5311  static void
5311 5312  do_create_simnet(int argc, char *argv[], const char *use)
5312 5313  {
5313 5314          uint32_t flags;
5314 5315          char *altroot = NULL;
5315 5316          char *media = NULL;
5316 5317          uint32_t mtype = DL_ETHER;
5317 5318          int option;
5318 5319          dladm_status_t status;
5319 5320          char name[MAXLINKNAMELEN];
5320 5321  
5321 5322          name[0] = '\0';
5322 5323          flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
5323 5324  
5324 5325          opterr = 0;
5325 5326          while ((option = getopt_long(argc, argv, ":tR:m:",
5326 5327              simnet_lopts, NULL)) != -1) {
5327 5328                  switch (option) {
5328 5329                  case 't':
5329 5330                          flags &= ~DLADM_OPT_PERSIST;
5330 5331                          break;
5331 5332                  case 'R':
5332 5333                          altroot = optarg;
5333 5334                          break;
5334 5335                  case 'm':
5335 5336                          media = optarg;
5336 5337                          break;
5337 5338                  default:
5338 5339                          die_opterr(optopt, option, use);
5339 5340                  }
5340 5341          }
5341 5342  
5342 5343          /* the simnet id is the required operand */
5343 5344          if (optind != (argc - 1))
5344 5345                  usage();
5345 5346  
5346 5347          if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
5347 5348                  die("link name too long '%s'", argv[optind]);
5348 5349  
5349 5350          if (!dladm_valid_linkname(name))
5350 5351                  die("invalid link name '%s'", name);
5351 5352  
5352 5353          if (media != NULL) {
5353 5354                  mtype = dladm_str2media(media);
5354 5355                  if (mtype != DL_ETHER && mtype != DL_WIFI)
5355 5356                          die("media type '%s' is not supported", media);
5356 5357          }
5357 5358  
5358 5359          if (altroot != NULL)
5359 5360                  altroot_cmd(altroot, argc, argv);
5360 5361  
5361 5362          status = dladm_simnet_create(handle, name, mtype, flags);
5362 5363          if (status != DLADM_STATUS_OK)
5363 5364                  die_dlerr(status, "simnet creation failed");
5364 5365  }
5365 5366  
5366 5367  static void
5367 5368  do_delete_simnet(int argc, char *argv[], const char *use)
5368 5369  {
5369 5370          int option;
5370 5371          uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
5371 5372          datalink_id_t linkid;
5372 5373          char *altroot = NULL;
5373 5374          dladm_status_t status;
5374 5375          dladm_simnet_attr_t slinfo;
5375 5376  
5376 5377          opterr = 0;
5377 5378          while ((option = getopt_long(argc, argv, ":tR:", simnet_lopts,
5378 5379              NULL)) != -1) {
5379 5380                  switch (option) {
5380 5381                  case 't':
5381 5382                          flags &= ~DLADM_OPT_PERSIST;
5382 5383                          break;
5383 5384                  case 'R':
5384 5385                          altroot = optarg;
5385 5386                          break;
5386 5387                  default:
5387 5388                          die_opterr(optopt, option, use);
5388 5389                  }
5389 5390          }
5390 5391  
5391 5392          /* get simnet name (required last argument) */
5392 5393          if (optind != (argc - 1))
5393 5394                  usage();
5394 5395  
5395 5396          if (!dladm_valid_linkname(argv[optind]))
5396 5397                  die("invalid link name '%s'", argv[optind]);
5397 5398  
5398 5399          if (altroot != NULL)
5399 5400                  altroot_cmd(altroot, argc, argv);
5400 5401  
5401 5402          status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
5402 5403              NULL);
5403 5404          if (status != DLADM_STATUS_OK)
5404 5405                  die("simnet '%s' not found", argv[optind]);
5405 5406  
5406 5407          if ((status = dladm_simnet_info(handle, linkid, &slinfo,
5407 5408              flags)) != DLADM_STATUS_OK)
5408 5409                  die_dlerr(status, "failed to retrieve simnet information");
5409 5410  
5410 5411          status = dladm_simnet_delete(handle, linkid, flags);
5411 5412          if (status != DLADM_STATUS_OK)
5412 5413                  die_dlerr(status, "simnet deletion failed");
5413 5414  }
5414 5415  
5415 5416  static void
5416 5417  do_modify_simnet(int argc, char *argv[], const char *use)
5417 5418  {
5418 5419          int option;
5419 5420          uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
5420 5421          datalink_id_t linkid;
5421 5422          datalink_id_t peer_linkid;
5422 5423          char *altroot = NULL;
5423 5424          dladm_status_t status;
5424 5425          boolean_t p_arg = B_FALSE;
5425 5426  
5426 5427          opterr = 0;
5427 5428          while ((option = getopt_long(argc, argv, ":tR:p:", simnet_lopts,
5428 5429              NULL)) != -1) {
5429 5430                  switch (option) {
5430 5431                  case 't':
5431 5432                          flags &= ~DLADM_OPT_PERSIST;
5432 5433                          break;
5433 5434                  case 'R':
5434 5435                          altroot = optarg;
5435 5436                          break;
5436 5437                  case 'p':
5437 5438                          if (p_arg)
5438 5439                                  die_optdup(option);
5439 5440                          p_arg = B_TRUE;
5440 5441                          if (strcasecmp(optarg, "none") == 0)
5441 5442                                  peer_linkid = DATALINK_INVALID_LINKID;
5442 5443                          else if (dladm_name2info(handle, optarg, &peer_linkid,
5443 5444                              NULL, NULL, NULL) != DLADM_STATUS_OK)
5444 5445                                  die("invalid peer link name '%s'", optarg);
5445 5446                          break;
5446 5447                  default:
5447 5448                          die_opterr(optopt, option, use);
5448 5449                  }
5449 5450          }
5450 5451  
5451 5452          /* get simnet name (required last argument) */
5452 5453          if (optind != (argc - 1))
5453 5454                  usage();
5454 5455  
5455 5456          /* Nothing to do if no peer link argument */
5456 5457          if (!p_arg)
5457 5458                  return;
5458 5459  
5459 5460          if (altroot != NULL)
5460 5461                  altroot_cmd(altroot, argc, argv);
5461 5462  
5462 5463          status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
5463 5464              NULL);
5464 5465          if (status != DLADM_STATUS_OK)
5465 5466                  die("invalid link name '%s'", argv[optind]);
5466 5467  
5467 5468          status = dladm_simnet_modify(handle, linkid, peer_linkid, flags);
5468 5469          if (status != DLADM_STATUS_OK)
5469 5470                  die_dlerr(status, "simnet modification failed");
5470 5471  }
5471 5472  
5472 5473  static dladm_status_t
5473 5474  print_simnet(show_state_t *state, datalink_id_t linkid)
5474 5475  {
5475 5476          dladm_simnet_attr_t     slinfo;
5476 5477          uint32_t                flags;
5477 5478          dladm_status_t          status;
5478 5479          simnet_fields_buf_t     slbuf;
5479 5480          char                    mstr[ETHERADDRL * 3];
5480 5481  
5481 5482          bzero(&slbuf, sizeof (slbuf));
5482 5483          if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL,
5483 5484              slbuf.simnet_name, sizeof (slbuf.simnet_name)))
5484 5485              != DLADM_STATUS_OK)
5485 5486                  return (status);
5486 5487  
5487 5488          if (!(state->ls_flags & flags))
5488 5489                  return (DLADM_STATUS_NOTFOUND);
5489 5490  
5490 5491          if ((status = dladm_simnet_info(handle, linkid, &slinfo,
5491 5492              state->ls_flags)) != DLADM_STATUS_OK)
5492 5493                  return (status);
5493 5494  
5494 5495          if (slinfo.sna_peer_link_id != DATALINK_INVALID_LINKID &&
5495 5496              (status = dladm_datalink_id2info(handle, slinfo.sna_peer_link_id,
5496 5497              NULL, NULL, NULL, slbuf.simnet_otherlink,
5497 5498              sizeof (slbuf.simnet_otherlink))) !=
5498 5499              DLADM_STATUS_OK)
5499 5500                  return (status);
5500 5501  
5501 5502          if (slinfo.sna_mac_len > sizeof (slbuf.simnet_macaddr))
5502 5503                  return (DLADM_STATUS_BADVAL);
5503 5504  
5504 5505          (void) strlcpy(slbuf.simnet_macaddr,
5505 5506              dladm_aggr_macaddr2str(slinfo.sna_mac_addr, mstr),
5506 5507              sizeof (slbuf.simnet_macaddr));
5507 5508          (void) dladm_media2str(slinfo.sna_type, slbuf.simnet_media);
5508 5509  
5509 5510          ofmt_print(state->ls_ofmt, &slbuf);
5510 5511          return (status);
5511 5512  }
5512 5513  
5513 5514  /* ARGSUSED */
5514 5515  static int
5515 5516  show_simnet(dladm_handle_t dh, datalink_id_t linkid, void *arg)
5516 5517  {
5517 5518          show_state_t            *state = arg;
5518 5519  
5519 5520          state->ls_status = print_simnet(state, linkid);
5520 5521          return (DLADM_WALK_CONTINUE);
5521 5522  }
5522 5523  
5523 5524  static void
5524 5525  do_show_simnet(int argc, char *argv[], const char *use)
5525 5526  {
5526 5527          int             option;
5527 5528          uint32_t        flags = DLADM_OPT_ACTIVE;
5528 5529          boolean_t       p_arg = B_FALSE;
5529 5530          datalink_id_t   linkid = DATALINK_ALL_LINKID;
5530 5531          show_state_t    state;
5531 5532          dladm_status_t  status;
5532 5533          boolean_t       o_arg = B_FALSE;
5533 5534          ofmt_handle_t   ofmt;
5534 5535          ofmt_status_t   oferr;
5535 5536          char            *all_fields = "link,media,macaddress,otherlink";
5536 5537          char            *fields_str = all_fields;
5537 5538          uint_t          ofmtflags = 0;
5538 5539  
5539 5540          bzero(&state, sizeof (state));
5540 5541  
5541 5542          opterr = 0;
5542 5543          while ((option = getopt_long(argc, argv, ":pPo:",
5543 5544              show_lopts, NULL)) != -1) {
5544 5545                  switch (option) {
5545 5546                  case 'p':
5546 5547                          if (p_arg)
5547 5548                                  die_optdup(option);
5548 5549  
5549 5550                          p_arg = B_TRUE;
5550 5551                          state.ls_parsable = p_arg;
5551 5552                          break;
5552 5553                  case 'P':
5553 5554                          if (flags != DLADM_OPT_ACTIVE)
5554 5555                                  die_optdup(option);
5555 5556  
5556 5557                          flags = DLADM_OPT_PERSIST;
5557 5558                          break;
5558 5559                  case 'o':
5559 5560                          o_arg = B_TRUE;
5560 5561                          fields_str = optarg;
5561 5562                          break;
5562 5563                  default:
5563 5564                          die_opterr(optopt, option, use);
5564 5565                          break;
5565 5566                  }
5566 5567          }
5567 5568  
5568 5569          if (p_arg && !o_arg)
5569 5570                  die("-p requires -o");
5570 5571  
5571 5572          if (strcasecmp(fields_str, "all") == 0) {
5572 5573                  if (p_arg)
5573 5574                          die("\"-o all\" is invalid with -p");
5574 5575                  fields_str = all_fields;
5575 5576          }
5576 5577  
5577 5578          /* get link name (optional last argument) */
5578 5579          if (optind == (argc-1)) {
5579 5580                  if ((status = dladm_name2info(handle, argv[optind], &linkid,
5580 5581                      NULL, NULL, NULL)) != DLADM_STATUS_OK) {
5581 5582                          die_dlerr(status, "link %s is not valid", argv[optind]);
5582 5583                  }
5583 5584          } else if (optind != argc) {
5584 5585                  usage();
5585 5586          }
5586 5587  
5587 5588          state.ls_flags = flags;
5588 5589          state.ls_donefirst = B_FALSE;
5589 5590          if (state.ls_parsable)
5590 5591                  ofmtflags |= OFMT_PARSABLE;
5591 5592          oferr = ofmt_open(fields_str, simnet_fields, ofmtflags, 0, &ofmt);
5592 5593          ofmt_check(oferr, state.ls_parsable, ofmt, die, warn);
5593 5594          state.ls_ofmt = ofmt;
5594 5595  
5595 5596          if (linkid == DATALINK_ALL_LINKID) {
5596 5597                  (void) dladm_walk_datalink_id(show_simnet, handle, &state,
5597 5598                      DATALINK_CLASS_SIMNET, DATALINK_ANY_MEDIATYPE, flags);
5598 5599          } else {
5599 5600                  (void) show_simnet(handle, linkid, &state);
5600 5601                  if (state.ls_status != DLADM_STATUS_OK) {
5601 5602                          ofmt_close(ofmt);
5602 5603                          die_dlerr(state.ls_status, "failed to show simnet %s",
5603 5604                              argv[optind]);
5604 5605                  }
5605 5606          }
5606 5607          ofmt_close(ofmt);
5607 5608  }
5608 5609  
5609 5610  static void
5610 5611  link_stats(datalink_id_t linkid, uint_t interval, char *fields_str,
5611 5612      show_state_t *state)
5612 5613  {
5613 5614          ofmt_handle_t   ofmt;
5614 5615          ofmt_status_t   oferr;
5615 5616          uint_t          ofmtflags = 0;
5616 5617  
5617 5618          if (state->ls_parsable)
5618 5619                  ofmtflags |= OFMT_PARSABLE;
5619 5620          oferr = ofmt_open(fields_str, link_s_fields, ofmtflags, 0, &ofmt);
5620 5621          ofmt_check(oferr, state->ls_parsable, ofmt, die, warn);
5621 5622          state->ls_ofmt = ofmt;
5622 5623  
5623 5624          /*
5624 5625           * If an interval is specified, continuously show the stats
5625 5626           * only for the first MAC port.
5626 5627           */
5627 5628          state->ls_firstonly = (interval != 0);
5628 5629  
5629 5630          for (;;) {
5630 5631                  state->ls_donefirst = B_FALSE;
5631 5632                  if (linkid == DATALINK_ALL_LINKID) {
5632 5633                          (void) dladm_walk_datalink_id(show_link_stats, handle,
5633 5634                              state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
5634 5635                              DLADM_OPT_ACTIVE);
5635 5636                  } else {
5636 5637                          (void) show_link_stats(handle, linkid, state);
5637 5638                  }
5638 5639  
5639 5640                  if (interval == 0)
5640 5641                          break;
5641 5642  
5642 5643                  (void) fflush(stdout);
5643 5644                  (void) sleep(interval);
5644 5645          }
5645 5646          ofmt_close(ofmt);
5646 5647  }
5647 5648  
5648 5649  static void
5649 5650  aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval)
5650 5651  {
5651 5652          /*
5652 5653           * If an interval is specified, continuously show the stats
5653 5654           * only for the first group.
5654 5655           */
5655 5656          state->gs_firstonly = (interval != 0);
5656 5657  
5657 5658          for (;;) {
5658 5659                  state->gs_donefirst = B_FALSE;
5659 5660                  if (linkid == DATALINK_ALL_LINKID)
5660 5661                          (void) dladm_walk_datalink_id(show_aggr, handle, state,
5661 5662                              DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE,
5662 5663                              DLADM_OPT_ACTIVE);
5663 5664                  else
5664 5665                          (void) show_aggr(handle, linkid, state);
5665 5666  
5666 5667                  if (interval == 0)
5667 5668                          break;
5668 5669  
5669 5670                  (void) fflush(stdout);
5670 5671                  (void) sleep(interval);
5671 5672          }
5672 5673  }
5673 5674  
5674 5675  /* ARGSUSED */
5675 5676  static void
5676 5677  vnic_stats(show_vnic_state_t *sp, uint32_t interval)
5677 5678  {
5678 5679          show_vnic_state_t       state;
5679 5680          boolean_t               specific_link, specific_dev;
5680 5681  
5681 5682          /* Display vnic statistics */
5682 5683          dump_vnics_head(sp->vs_link);
5683 5684  
5684 5685          bzero(&state, sizeof (state));
5685 5686          state.vs_stats = B_TRUE;
5686 5687          state.vs_vnic_id = sp->vs_vnic_id;
5687 5688          state.vs_link_id = sp->vs_link_id;
5688 5689  
5689 5690          /*
5690 5691           * If an interval is specified, and a vnic ID is not specified,
5691 5692           * continuously show the stats only for the first vnic.
5692 5693           */
5693 5694          specific_link = (sp->vs_vnic_id != DATALINK_ALL_LINKID);
5694 5695          specific_dev = (sp->vs_link_id != DATALINK_ALL_LINKID);
5695 5696  
5696 5697          for (;;) {
5697 5698                  /* Get stats for each vnic */
5698 5699                  state.vs_found = B_FALSE;
5699 5700                  state.vs_donefirst = B_FALSE;
5700 5701                  state.vs_printstats = B_FALSE;
5701 5702                  state.vs_flags = DLADM_OPT_ACTIVE;
5702 5703  
5703 5704                  if (!specific_link) {
5704 5705                          (void) dladm_walk_datalink_id(show_vnic, handle, &state,
5705 5706                              DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE,
5706 5707                              DLADM_OPT_ACTIVE);
5707 5708                  } else {
5708 5709                          (void) show_vnic(handle, sp->vs_vnic_id, &state);
5709 5710                          if (state.vs_status != DLADM_STATUS_OK) {
5710 5711                                  die_dlerr(state.vs_status,
5711 5712                                      "failed to show vnic '%s'", sp->vs_vnic);
5712 5713                          }
5713 5714                  }
5714 5715  
5715 5716                  if (specific_link && !state.vs_found)
5716 5717                          die("non-existent vnic '%s'", sp->vs_vnic);
5717 5718                  if (specific_dev && !state.vs_found)
5718 5719                          die("device %s has no vnics", sp->vs_link);
5719 5720  
5720 5721                  /* Show totals */
5721 5722                  if ((specific_link | specific_dev) && !interval) {
5722 5723                          (void) printf("Total");
5723 5724                          (void) printf("\t%-10llu",
5724 5725                              state.vs_totalstats.ipackets);
5725 5726                          (void) printf("%-12llu",
5726 5727                              state.vs_totalstats.rbytes);
5727 5728                          (void) printf("%-10llu",
5728 5729                              state.vs_totalstats.opackets);
5729 5730                          (void) printf("%-12llu\n",
5730 5731                              state.vs_totalstats.obytes);
5731 5732                  }
5732 5733  
5733 5734                  /* Show stats for each vnic */
5734 5735                  state.vs_donefirst = B_FALSE;
5735 5736                  state.vs_printstats = B_TRUE;
5736 5737  
5737 5738                  if (!specific_link) {
5738 5739                          (void) dladm_walk_datalink_id(show_vnic, handle, &state,
5739 5740                              DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE,
5740 5741                              DLADM_OPT_ACTIVE);
5741 5742                  } else {
5742 5743                          (void) show_vnic(handle, sp->vs_vnic_id, &state);
5743 5744                          if (state.vs_status != DLADM_STATUS_OK) {
5744 5745                                  die_dlerr(state.vs_status,
5745 5746                                      "failed to show vnic '%s'", sp->vs_vnic);
5746 5747                          }
5747 5748                  }
5748 5749  
5749 5750                  if (interval == 0)
5750 5751                          break;
5751 5752  
5752 5753                  (void) fflush(stdout);
5753 5754                  (void) sleep(interval);
5754 5755          }
5755 5756  }
5756 5757  
5757 5758  static void
5758 5759  get_mac_stats(const char *dev, pktsum_t *stats)
5759 5760  {
5760 5761          kstat_ctl_t     *kcp;
5761 5762          kstat_t         *ksp;
5762 5763          char module[DLPI_LINKNAME_MAX];
5763 5764          uint_t instance;
5764 5765  
5765 5766  
5766 5767          bzero(stats, sizeof (*stats));
5767 5768  
5768 5769          if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS)
5769 5770                  return;
5770 5771  
5771 5772          if ((kcp = kstat_open()) == NULL) {
5772 5773                  warn("kstat open operation failed");
5773 5774                  return;
5774 5775          }
5775 5776  
5776 5777          ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL);
5777 5778          if (ksp != NULL)
5778 5779                  dladm_get_stats(kcp, ksp, stats);
5779 5780  
5780 5781          (void) kstat_close(kcp);
5781 5782  
5782 5783  }
5783 5784  
5784 5785  static void
5785 5786  get_link_stats(const char *link, pktsum_t *stats)
5786 5787  {
5787 5788          kstat_ctl_t     *kcp;
5788 5789          kstat_t         *ksp;
5789 5790  
5790 5791          bzero(stats, sizeof (*stats));
5791 5792  
5792 5793          if ((kcp = kstat_open()) == NULL) {
5793 5794                  warn("kstat_open operation failed");
5794 5795                  return;
5795 5796          }
5796 5797  
5797 5798          ksp = dladm_kstat_lookup(kcp, "link", 0, link, NULL);
5798 5799  
5799 5800          if (ksp != NULL)
5800 5801                  dladm_get_stats(kcp, ksp, stats);
5801 5802  
5802 5803          (void) kstat_close(kcp);
5803 5804  }
5804 5805  
5805 5806  static int
5806 5807  query_kstat(char *module, int instance, const char *name, const char *stat,
5807 5808      uint8_t type, void *val)
5808 5809  {
5809 5810          kstat_ctl_t     *kcp;
5810 5811          kstat_t         *ksp;
5811 5812  
5812 5813          if ((kcp = kstat_open()) == NULL) {
5813 5814                  warn("kstat open operation failed");
5814 5815                  return (-1);
5815 5816          }
5816 5817  
5817 5818          if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) {
5818 5819                  /*
5819 5820                   * The kstat query could fail if the underlying MAC
5820 5821                   * driver was already detached.
5821 5822                   */
5822 5823                  goto bail;
5823 5824          }
5824 5825  
5825 5826          if (kstat_read(kcp, ksp, NULL) == -1) {
5826 5827                  warn("kstat read failed");
5827 5828                  goto bail;
5828 5829          }
5829 5830  
5830 5831          if (dladm_kstat_value(ksp, stat, type, val) < 0)
5831 5832                  goto bail;
5832 5833  
5833 5834          (void) kstat_close(kcp);
5834 5835          return (0);
5835 5836  
5836 5837  bail:
5837 5838          (void) kstat_close(kcp);
5838 5839          return (-1);
5839 5840  }
5840 5841  
5841 5842  static int
5842 5843  get_one_kstat(const char *name, const char *stat, uint8_t type,
5843 5844      void *val, boolean_t islink)
5844 5845  {
5845 5846          char            module[DLPI_LINKNAME_MAX];
5846 5847          uint_t          instance;
5847 5848  
5848 5849          if (islink) {
5849 5850                  return (query_kstat("link", 0, name, stat, type, val));
5850 5851          } else {
5851 5852                  if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS)
5852 5853                          return (-1);
5853 5854  
5854 5855                  return (query_kstat(module, instance, "mac", stat, type, val));
5855 5856          }
5856 5857  }
5857 5858  
5858 5859  static uint64_t
5859 5860  get_ifspeed(const char *name, boolean_t islink)
5860 5861  {
5861 5862          uint64_t ifspeed = 0;
5862 5863  
5863 5864          (void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64,
5864 5865              &ifspeed, islink);
5865 5866  
5866 5867          return (ifspeed);
5867 5868  }
5868 5869  
5869 5870  static const char *
5870 5871  get_linkstate(const char *name, boolean_t islink, char *buf)
5871 5872  {
5872 5873          link_state_t    linkstate;
5873 5874  
5874 5875          if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32,
5875 5876              &linkstate, islink) != 0) {
5876 5877                  (void) strlcpy(buf, "?", DLADM_STRSIZE);
5877 5878                  return (buf);
5878 5879          }
5879 5880          return (dladm_linkstate2str(linkstate, buf));
5880 5881  }
5881 5882  
5882 5883  static const char *
5883 5884  get_linkduplex(const char *name, boolean_t islink, char *buf)
5884 5885  {
5885 5886          link_duplex_t   linkduplex;
5886 5887  
5887 5888          if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32,
5888 5889              &linkduplex, islink) != 0) {
5889 5890                  (void) strlcpy(buf, "unknown", DLADM_STRSIZE);
5890 5891                  return (buf);
5891 5892          }
5892 5893  
5893 5894          return (dladm_linkduplex2str(linkduplex, buf));
5894 5895  }
5895 5896  
5896 5897  static int
5897 5898  parse_wifi_fields(char *str, ofmt_handle_t *ofmt, uint_t cmdtype,
5898 5899      boolean_t parsable)
5899 5900  {
5900 5901          ofmt_field_t    *template, *of;
5901 5902          ofmt_cb_t       *fn;
5902 5903          ofmt_status_t   oferr;
5903 5904  
5904 5905          if (cmdtype == WIFI_CMD_SCAN) {
5905 5906                  template = wifi_common_fields;
5906 5907                  if (str == NULL)
5907 5908                          str = def_scan_wifi_fields;
5908 5909                  if (strcasecmp(str, "all") == 0)
5909 5910                          str = all_scan_wifi_fields;
5910 5911                  fn = print_wlan_attr_cb;
5911 5912          } else if (cmdtype == WIFI_CMD_SHOW) {
5912 5913                  bcopy(wifi_common_fields, &wifi_show_fields[2],
5913 5914                      sizeof (wifi_common_fields));
5914 5915                  template = wifi_show_fields;
5915 5916                  if (str == NULL)
5916 5917                          str = def_show_wifi_fields;
5917 5918                  if (strcasecmp(str, "all") == 0)
5918 5919                          str = all_show_wifi_fields;
5919 5920                  fn = print_link_attr_cb;
5920 5921          } else {
5921 5922                  return (-1);
5922 5923          }
5923 5924  
5924 5925          for (of = template; of->of_name != NULL; of++) {
5925 5926                  if (of->of_cb == NULL)
5926 5927                          of->of_cb = fn;
5927 5928          }
5928 5929  
5929 5930          oferr = ofmt_open(str, template, (parsable ? OFMT_PARSABLE : 0),
5930 5931              0, ofmt);
5931 5932          ofmt_check(oferr, parsable, *ofmt, die, warn);
5932 5933          return (0);
5933 5934  }
5934 5935  
5935 5936  typedef struct print_wifi_state {
5936 5937          char            *ws_link;
5937 5938          boolean_t       ws_parsable;
5938 5939          boolean_t       ws_header;
5939 5940          ofmt_handle_t   ws_ofmt;
5940 5941  } print_wifi_state_t;
5941 5942  
5942 5943  typedef struct  wlan_scan_args_s {
5943 5944          print_wifi_state_t      *ws_state;
5944 5945          void                    *ws_attr;
5945 5946  } wlan_scan_args_t;
5946 5947  
5947 5948  static boolean_t
5948 5949  print_wlan_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
5949 5950  {
5950 5951          wlan_scan_args_t        *w = ofarg->ofmt_cbarg;
5951 5952          print_wifi_state_t      *statep = w->ws_state;
5952 5953          dladm_wlan_attr_t       *attrp = w->ws_attr;
5953 5954          char                    tmpbuf[DLADM_STRSIZE];
5954 5955  
5955 5956          if (ofarg->ofmt_id == 0) {
5956 5957                  (void) strlcpy(buf, (char *)statep->ws_link, bufsize);
5957 5958                  return (B_TRUE);
5958 5959          }
5959 5960  
5960 5961          if ((ofarg->ofmt_id & attrp->wa_valid) == 0)
5961 5962                  return (B_TRUE);
5962 5963  
5963 5964          switch (ofarg->ofmt_id) {
5964 5965          case DLADM_WLAN_ATTR_ESSID:
5965 5966                  (void) dladm_wlan_essid2str(&attrp->wa_essid, tmpbuf);
5966 5967                  break;
5967 5968          case DLADM_WLAN_ATTR_BSSID:
5968 5969                  (void) dladm_wlan_bssid2str(&attrp->wa_bssid, tmpbuf);
5969 5970                  break;
5970 5971          case DLADM_WLAN_ATTR_SECMODE:
5971 5972                  (void) dladm_wlan_secmode2str(&attrp->wa_secmode, tmpbuf);
5972 5973                  break;
5973 5974          case DLADM_WLAN_ATTR_STRENGTH:
5974 5975                  (void) dladm_wlan_strength2str(&attrp->wa_strength, tmpbuf);
5975 5976                  break;
5976 5977          case DLADM_WLAN_ATTR_MODE:
5977 5978                  (void) dladm_wlan_mode2str(&attrp->wa_mode, tmpbuf);
5978 5979                  break;
5979 5980          case DLADM_WLAN_ATTR_SPEED:
5980 5981                  (void) dladm_wlan_speed2str(&attrp->wa_speed, tmpbuf);
5981 5982                  (void) strlcat(tmpbuf, "Mb", sizeof (tmpbuf));
5982 5983                  break;
5983 5984          case DLADM_WLAN_ATTR_AUTH:
5984 5985                  (void) dladm_wlan_auth2str(&attrp->wa_auth, tmpbuf);
5985 5986                  break;
5986 5987          case DLADM_WLAN_ATTR_BSSTYPE:
5987 5988                  (void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, tmpbuf);
5988 5989                  break;
5989 5990          }
5990 5991          (void) strlcpy(buf, tmpbuf, bufsize);
5991 5992  
5992 5993          return (B_TRUE);
5993 5994  }
5994 5995  
5995 5996  static boolean_t
5996 5997  print_scan_results(void *arg, dladm_wlan_attr_t *attrp)
5997 5998  {
5998 5999          print_wifi_state_t      *statep = arg;
5999 6000          wlan_scan_args_t        warg;
6000 6001  
6001 6002          bzero(&warg, sizeof (warg));
6002 6003          warg.ws_state = statep;
6003 6004          warg.ws_attr = attrp;
6004 6005          ofmt_print(statep->ws_ofmt, &warg);
6005 6006          return (B_TRUE);
6006 6007  }
6007 6008  
6008 6009  static int
6009 6010  scan_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg)
6010 6011  {
6011 6012          print_wifi_state_t      *statep = arg;
6012 6013          dladm_status_t          status;
6013 6014          char                    link[MAXLINKNAMELEN];
6014 6015  
6015 6016          if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link,
6016 6017              sizeof (link))) != DLADM_STATUS_OK) {
6017 6018                  return (DLADM_WALK_CONTINUE);
6018 6019          }
6019 6020  
6020 6021          statep->ws_link = link;
6021 6022          status = dladm_wlan_scan(dh, linkid, statep, print_scan_results);
6022 6023          if (status != DLADM_STATUS_OK)
6023 6024                  die_dlerr(status, "cannot scan link '%s'", statep->ws_link);
6024 6025  
6025 6026          return (DLADM_WALK_CONTINUE);
6026 6027  }
6027 6028  
6028 6029  static boolean_t
6029 6030  print_wifi_status_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
6030 6031  {
6031 6032          static char             tmpbuf[DLADM_STRSIZE];
6032 6033          wlan_scan_args_t        *w = ofarg->ofmt_cbarg;
6033 6034          dladm_wlan_linkattr_t   *attrp = w->ws_attr;
6034 6035  
6035 6036          if ((ofarg->ofmt_id & attrp->la_valid) != 0) {
6036 6037                  (void) dladm_wlan_linkstatus2str(&attrp->la_status, tmpbuf);
6037 6038                  (void) strlcpy(buf, tmpbuf, bufsize);
6038 6039          }
6039 6040          return (B_TRUE);
6040 6041  }
6041 6042  
6042 6043  static boolean_t
6043 6044  print_link_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
6044 6045  {
6045 6046          wlan_scan_args_t        *w = ofarg->ofmt_cbarg, w1;
6046 6047          print_wifi_state_t      *statep = w->ws_state;
6047 6048          dladm_wlan_linkattr_t   *attrp = w->ws_attr;
6048 6049  
6049 6050          bzero(&w1, sizeof (w1));
6050 6051          w1.ws_state = statep;
6051 6052          w1.ws_attr = &attrp->la_wlan_attr;
6052 6053          ofarg->ofmt_cbarg = &w1;
6053 6054          return (print_wlan_attr_cb(ofarg, buf, bufsize));
6054 6055  }
6055 6056  
6056 6057  static int
6057 6058  show_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg)
6058 6059  {
6059 6060          print_wifi_state_t      *statep = arg;
6060 6061          dladm_wlan_linkattr_t   attr;
6061 6062          dladm_status_t          status;
6062 6063          char                    link[MAXLINKNAMELEN];
6063 6064          wlan_scan_args_t        warg;
6064 6065  
6065 6066          if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link,
6066 6067              sizeof (link))) != DLADM_STATUS_OK) {
6067 6068                  return (DLADM_WALK_CONTINUE);
6068 6069          }
6069 6070  
6070 6071          /* dladm_wlan_get_linkattr() memsets attr with 0 */
6071 6072          status = dladm_wlan_get_linkattr(dh, linkid, &attr);
6072 6073          if (status != DLADM_STATUS_OK)
6073 6074                  die_dlerr(status, "cannot get link attributes for %s", link);
6074 6075  
6075 6076          statep->ws_link = link;
6076 6077  
6077 6078          bzero(&warg, sizeof (warg));
6078 6079          warg.ws_state = statep;
6079 6080          warg.ws_attr = &attr;
6080 6081          ofmt_print(statep->ws_ofmt, &warg);
6081 6082          return (DLADM_WALK_CONTINUE);
6082 6083  }
6083 6084  
6084 6085  static void
6085 6086  do_display_wifi(int argc, char **argv, int cmd, const char *use)
6086 6087  {
6087 6088          int                     option;
6088 6089          char                    *fields_str = NULL;
6089 6090          int             (*callback)(dladm_handle_t, datalink_id_t, void *);
6090 6091          print_wifi_state_t      state;
6091 6092          datalink_id_t           linkid = DATALINK_ALL_LINKID;
6092 6093          dladm_status_t          status;
6093 6094  
6094 6095          if (cmd == WIFI_CMD_SCAN)
6095 6096                  callback = scan_wifi;
6096 6097          else if (cmd == WIFI_CMD_SHOW)
6097 6098                  callback = show_wifi;
6098 6099          else
6099 6100                  return;
6100 6101  
6101 6102          state.ws_parsable = B_FALSE;
6102 6103          state.ws_header = B_TRUE;
6103 6104          opterr = 0;
6104 6105          while ((option = getopt_long(argc, argv, ":o:p",
6105 6106              wifi_longopts, NULL)) != -1) {
6106 6107                  switch (option) {
6107 6108                  case 'o':
6108 6109                          fields_str = optarg;
6109 6110                          break;
6110 6111                  case 'p':
6111 6112                          state.ws_parsable = B_TRUE;
6112 6113                          break;
6113 6114                  default:
6114 6115                          die_opterr(optopt, option, use);
6115 6116                  }
6116 6117          }
6117 6118  
6118 6119          if (state.ws_parsable && fields_str == NULL)
6119 6120                  die("-p requires -o");
6120 6121  
6121 6122          if (state.ws_parsable && strcasecmp(fields_str, "all") == 0)
6122 6123                  die("\"-o all\" is invalid with -p");
6123 6124  
6124 6125          if (optind == (argc - 1)) {
6125 6126                  if ((status = dladm_name2info(handle, argv[optind], &linkid,
6126 6127                      NULL, NULL, NULL)) != DLADM_STATUS_OK) {
6127 6128                          die_dlerr(status, "link %s is not valid", argv[optind]);
6128 6129                  }
6129 6130          } else if (optind != argc) {
6130 6131                  usage();
6131 6132          }
6132 6133  
6133 6134          if (parse_wifi_fields(fields_str, &state.ws_ofmt, cmd,
6134 6135              state.ws_parsable) < 0)
6135 6136                  die("invalid field(s) specified");
6136 6137  
6137 6138          if (linkid == DATALINK_ALL_LINKID) {
6138 6139                  (void) dladm_walk_datalink_id(callback, handle, &state,
6139 6140                      DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET,
6140 6141                      DL_WIFI, DLADM_OPT_ACTIVE);
6141 6142          } else {
6142 6143                  (void) (*callback)(handle, linkid, &state);
6143 6144          }
6144 6145          ofmt_close(state.ws_ofmt);
6145 6146  }
6146 6147  
6147 6148  static void
6148 6149  do_scan_wifi(int argc, char **argv, const char *use)
6149 6150  {
6150 6151          do_display_wifi(argc, argv, WIFI_CMD_SCAN, use);
6151 6152  }
6152 6153  
6153 6154  static void
6154 6155  do_show_wifi(int argc, char **argv, const char *use)
6155 6156  {
6156 6157          do_display_wifi(argc, argv, WIFI_CMD_SHOW, use);
6157 6158  }
6158 6159  
6159 6160  typedef struct wlan_count_attr {
6160 6161          uint_t          wc_count;
6161 6162          datalink_id_t   wc_linkid;
6162 6163  } wlan_count_attr_t;
6163 6164  
6164 6165  /* ARGSUSED */
6165 6166  static int
6166 6167  do_count_wlan(dladm_handle_t dh, datalink_id_t linkid, void *arg)
6167 6168  {
6168 6169          wlan_count_attr_t *cp = arg;
6169 6170  
6170 6171          if (cp->wc_count == 0)
6171 6172                  cp->wc_linkid = linkid;
6172 6173          cp->wc_count++;
6173 6174          return (DLADM_WALK_CONTINUE);
6174 6175  }
6175 6176  
6176 6177  static int
6177 6178  parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp)
6178 6179  {
6179 6180          uint_t                  i;
6180 6181          dladm_wlan_key_t        *wk;
6181 6182          int                     nfields = 1;
6182 6183          char                    *field, *token, *lasts = NULL, c;
6183 6184  
6184 6185          token = str;
6185 6186          while ((c = *token++) != NULL) {
6186 6187                  if (c == ',')
6187 6188                          nfields++;
6188 6189          }
6189 6190          token = strdup(str);
6190 6191          if (token == NULL)
6191 6192                  return (-1);
6192 6193  
6193 6194          wk = malloc(nfields * sizeof (dladm_wlan_key_t));
6194 6195          if (wk == NULL)
6195 6196                  goto fail;
6196 6197  
6197 6198          token = str;
6198 6199          for (i = 0; i < nfields; i++) {
6199 6200                  char                    *s;
6200 6201                  dladm_secobj_class_t    class;
6201 6202                  dladm_status_t          status;
6202 6203  
6203 6204                  field = strtok_r(token, ",", &lasts);
6204 6205                  token = NULL;
6205 6206  
6206 6207                  (void) strlcpy(wk[i].wk_name, field,
6207 6208                      DLADM_WLAN_MAX_KEYNAME_LEN);
6208 6209  
6209 6210                  wk[i].wk_idx = 1;
6210 6211                  if ((s = strrchr(wk[i].wk_name, ':')) != NULL) {
6211 6212                          if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1]))
6212 6213                                  goto fail;
6213 6214  
6214 6215                          wk[i].wk_idx = (uint_t)(s[1] - '0');
6215 6216                          *s = '\0';
6216 6217                  }
6217 6218                  wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN;
6218 6219  
6219 6220                  status = dladm_get_secobj(handle, wk[i].wk_name, &class,
6220 6221                      wk[i].wk_val, &wk[i].wk_len, 0);
6221 6222                  if (status != DLADM_STATUS_OK) {
6222 6223                          if (status == DLADM_STATUS_NOTFOUND) {
6223 6224                                  status = dladm_get_secobj(handle, wk[i].wk_name,
6224 6225                                      &class, wk[i].wk_val, &wk[i].wk_len,
6225 6226                                      DLADM_OPT_PERSIST);
6226 6227                          }
6227 6228                          if (status != DLADM_STATUS_OK)
6228 6229                                  goto fail;
6229 6230                  }
6230 6231                  wk[i].wk_class = class;
6231 6232          }
6232 6233          *keys = wk;
6233 6234          *key_countp = i;
6234 6235          free(token);
6235 6236          return (0);
6236 6237  fail:
6237 6238          free(wk);
6238 6239          free(token);
6239 6240          return (-1);
6240 6241  }
6241 6242  
6242 6243  static void
6243 6244  do_connect_wifi(int argc, char **argv, const char *use)
6244 6245  {
6245 6246          int                     option;
6246 6247          dladm_wlan_attr_t       attr, *attrp;
6247 6248          dladm_status_t          status = DLADM_STATUS_OK;
6248 6249          int                     timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT;
6249 6250          datalink_id_t           linkid = DATALINK_ALL_LINKID;
6250 6251          dladm_wlan_key_t        *keys = NULL;
6251 6252          uint_t                  key_count = 0;
6252 6253          uint_t                  flags = 0;
6253 6254          dladm_wlan_secmode_t    keysecmode = DLADM_WLAN_SECMODE_NONE;
6254 6255          char                    buf[DLADM_STRSIZE];
6255 6256  
6256 6257          opterr = 0;
6257 6258          (void) memset(&attr, 0, sizeof (attr));
6258 6259          while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c",
6259 6260              wifi_longopts, NULL)) != -1) {
6260 6261                  switch (option) {
6261 6262                  case 'e':
6262 6263                          status = dladm_wlan_str2essid(optarg, &attr.wa_essid);
6263 6264                          if (status != DLADM_STATUS_OK)
6264 6265                                  die("invalid ESSID '%s'", optarg);
6265 6266  
6266 6267                          attr.wa_valid |= DLADM_WLAN_ATTR_ESSID;
6267 6268                          /*
6268 6269                           * Try to connect without doing a scan.
6269 6270                           */
6270 6271                          flags |= DLADM_WLAN_CONNECT_NOSCAN;
6271 6272                          break;
6272 6273                  case 'i':
6273 6274                          status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid);
6274 6275                          if (status != DLADM_STATUS_OK)
6275 6276                                  die("invalid BSSID %s", optarg);
6276 6277  
6277 6278                          attr.wa_valid |= DLADM_WLAN_ATTR_BSSID;
6278 6279                          break;
6279 6280                  case 'a':
6280 6281                          status = dladm_wlan_str2auth(optarg, &attr.wa_auth);
6281 6282                          if (status != DLADM_STATUS_OK)
6282 6283                                  die("invalid authentication mode '%s'", optarg);
6283 6284  
6284 6285                          attr.wa_valid |= DLADM_WLAN_ATTR_AUTH;
6285 6286                          break;
6286 6287                  case 'm':
6287 6288                          status = dladm_wlan_str2mode(optarg, &attr.wa_mode);
6288 6289                          if (status != DLADM_STATUS_OK)
6289 6290                                  die("invalid mode '%s'", optarg);
6290 6291  
6291 6292                          attr.wa_valid |= DLADM_WLAN_ATTR_MODE;
6292 6293                          break;
6293 6294                  case 'b':
6294 6295                          if ((status = dladm_wlan_str2bsstype(optarg,
6295 6296                              &attr.wa_bsstype)) != DLADM_STATUS_OK) {
6296 6297                                  die("invalid bsstype '%s'", optarg);
6297 6298                          }
6298 6299  
6299 6300                          attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
6300 6301                          break;
6301 6302                  case 's':
6302 6303                          if ((status = dladm_wlan_str2secmode(optarg,
6303 6304                              &attr.wa_secmode)) != DLADM_STATUS_OK) {
6304 6305                                  die("invalid security mode '%s'", optarg);
6305 6306                          }
6306 6307  
6307 6308                          attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
6308 6309                          break;
6309 6310                  case 'k':
6310 6311                          if (parse_wlan_keys(optarg, &keys, &key_count) < 0)
6311 6312                                  die("invalid key(s) '%s'", optarg);
6312 6313  
6313 6314                          if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP)
6314 6315                                  keysecmode = DLADM_WLAN_SECMODE_WEP;
6315 6316                          else
6316 6317                                  keysecmode = DLADM_WLAN_SECMODE_WPA;
6317 6318                          break;
6318 6319                  case 'T':
6319 6320                          if (strcasecmp(optarg, "forever") == 0) {
6320 6321                                  timeout = -1;
6321 6322                                  break;
6322 6323                          }
6323 6324                          if (!str2int(optarg, &timeout) || timeout < 0)
6324 6325                                  die("invalid timeout value '%s'", optarg);
6325 6326                          break;
6326 6327                  case 'c':
6327 6328                          flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
6328 6329                          flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
6329 6330                          break;
6330 6331                  default:
6331 6332                          die_opterr(optopt, option, use);
6332 6333                          break;
6333 6334                  }
6334 6335          }
6335 6336  
6336 6337          if (keysecmode == DLADM_WLAN_SECMODE_NONE) {
6337 6338                  if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) {
6338 6339                          die("key required for security mode '%s'",
6339 6340                              dladm_wlan_secmode2str(&attr.wa_secmode, buf));
6340 6341                  }
6341 6342          } else {
6342 6343                  if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 &&
6343 6344                      attr.wa_secmode != keysecmode)
6344 6345                          die("incompatible -s and -k options");
6345 6346                  attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
6346 6347                  attr.wa_secmode = keysecmode;
6347 6348          }
6348 6349  
6349 6350          if (optind == (argc - 1)) {
6350 6351                  if ((status = dladm_name2info(handle, argv[optind], &linkid,
6351 6352                      NULL, NULL, NULL)) != DLADM_STATUS_OK) {
6352 6353                          die_dlerr(status, "link %s is not valid", argv[optind]);
6353 6354                  }
6354 6355          } else if (optind != argc) {
6355 6356                  usage();
6356 6357          }
6357 6358  
6358 6359          if (linkid == DATALINK_ALL_LINKID) {
6359 6360                  wlan_count_attr_t wcattr;
6360 6361  
6361 6362                  wcattr.wc_linkid = DATALINK_INVALID_LINKID;
6362 6363                  wcattr.wc_count = 0;
6363 6364                  (void) dladm_walk_datalink_id(do_count_wlan, handle, &wcattr,
6364 6365                      DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET,
6365 6366                      DL_WIFI, DLADM_OPT_ACTIVE);
6366 6367                  if (wcattr.wc_count == 0) {
6367 6368                          die("no wifi links are available");
6368 6369                  } else if (wcattr.wc_count > 1) {
6369 6370                          die("link name is required when more than one wifi "
6370 6371                              "link is available");
6371 6372                  }
6372 6373                  linkid = wcattr.wc_linkid;
6373 6374          }
6374 6375          attrp = (attr.wa_valid == 0) ? NULL : &attr;
6375 6376  again:
6376 6377          if ((status = dladm_wlan_connect(handle, linkid, attrp, timeout, keys,
6377 6378              key_count, flags)) != DLADM_STATUS_OK) {
6378 6379                  if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) {
6379 6380                          /*
6380 6381                           * Try again with scanning and filtering.
6381 6382                           */
6382 6383                          flags &= ~DLADM_WLAN_CONNECT_NOSCAN;
6383 6384                          goto again;
6384 6385                  }
6385 6386  
6386 6387                  if (status == DLADM_STATUS_NOTFOUND) {
6387 6388                          if (attr.wa_valid == 0) {
6388 6389                                  die("no wifi networks are available");
6389 6390                          } else {
6390 6391                                  die("no wifi networks with the specified "
6391 6392                                      "criteria are available");
6392 6393                          }
6393 6394                  }
6394 6395                  die_dlerr(status, "cannot connect");
6395 6396          }
6396 6397          free(keys);
6397 6398  }
6398 6399  
6399 6400  /* ARGSUSED */
6400 6401  static int
6401 6402  do_all_disconnect_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg)
6402 6403  {
6403 6404          dladm_status_t  status;
6404 6405  
6405 6406          status = dladm_wlan_disconnect(dh, linkid);
6406 6407          if (status != DLADM_STATUS_OK)
6407 6408                  warn_dlerr(status, "cannot disconnect link");
6408 6409  
6409 6410          return (DLADM_WALK_CONTINUE);
6410 6411  }
6411 6412  
6412 6413  static void
6413 6414  do_disconnect_wifi(int argc, char **argv, const char *use)
6414 6415  {
6415 6416          int                     option;
6416 6417          datalink_id_t           linkid = DATALINK_ALL_LINKID;
6417 6418          boolean_t               all_links = B_FALSE;
6418 6419          dladm_status_t          status;
6419 6420          wlan_count_attr_t       wcattr;
6420 6421  
6421 6422          opterr = 0;
6422 6423          while ((option = getopt_long(argc, argv, ":a",
6423 6424              wifi_longopts, NULL)) != -1) {
6424 6425                  switch (option) {
6425 6426                  case 'a':
6426 6427                          all_links = B_TRUE;
6427 6428                          break;
6428 6429                  default:
6429 6430                          die_opterr(optopt, option, use);
6430 6431                          break;
6431 6432                  }
6432 6433          }
6433 6434  
6434 6435          if (optind == (argc - 1)) {
6435 6436                  if ((status = dladm_name2info(handle, argv[optind], &linkid,
6436 6437                      NULL, NULL, NULL)) != DLADM_STATUS_OK) {
6437 6438                          die_dlerr(status, "link %s is not valid", argv[optind]);
6438 6439                  }
6439 6440          } else if (optind != argc) {
6440 6441                  usage();
6441 6442          }
6442 6443  
6443 6444          if (linkid == DATALINK_ALL_LINKID) {
6444 6445                  if (!all_links) {
6445 6446                          wcattr.wc_linkid = linkid;
6446 6447                          wcattr.wc_count = 0;
6447 6448                          (void) dladm_walk_datalink_id(do_count_wlan, handle,
6448 6449                              &wcattr,
6449 6450                              DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET,
6450 6451                              DL_WIFI, DLADM_OPT_ACTIVE);
6451 6452                          if (wcattr.wc_count == 0) {
6452 6453                                  die("no wifi links are available");
6453 6454                          } else if (wcattr.wc_count > 1) {
6454 6455                                  die("link name is required when more than "
6455 6456                                      "one wifi link is available");
6456 6457                          }
6457 6458                          linkid = wcattr.wc_linkid;
6458 6459                  } else {
6459 6460                          (void) dladm_walk_datalink_id(do_all_disconnect_wifi,
6460 6461                              handle, NULL,
6461 6462                              DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET,
6462 6463                              DL_WIFI, DLADM_OPT_ACTIVE);
6463 6464                          return;
6464 6465                  }
6465 6466          }
6466 6467          status = dladm_wlan_disconnect(handle, linkid);
6467 6468          if (status != DLADM_STATUS_OK)
6468 6469                  die_dlerr(status, "cannot disconnect");
6469 6470  }
6470 6471  
6471 6472  static void
6472 6473  print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep,
6473 6474      const char *propname, dladm_prop_type_t type, const char *format,
6474 6475      char **pptr)
6475 6476  {
6476 6477          int             i;
6477 6478          char            *ptr, *lim;
6478 6479          char            buf[DLADM_STRSIZE];
6479 6480          char            *unknown = "--", *notsup = "";
6480 6481          char            **propvals = statep->ls_propvals;
6481 6482          uint_t          valcnt = DLADM_MAX_PROP_VALCNT;
6482 6483          dladm_status_t  status;
6483 6484  
6484 6485          status = dladm_get_linkprop(handle, linkid, type, propname, propvals,
6485 6486              &valcnt);
6486 6487          if (status != DLADM_STATUS_OK) {
6487 6488                  if (status == DLADM_STATUS_TEMPONLY) {
6488 6489                          if (type == DLADM_PROP_VAL_MODIFIABLE &&
6489 6490                              statep->ls_persist) {
6490 6491                                  valcnt = 1;
6491 6492                                  propvals = &unknown;
6492 6493                          } else {
6493 6494                                  statep->ls_status = status;
6494 6495                                  statep->ls_retstatus = status;
6495 6496                                  return;
6496 6497                          }
6497 6498                  } else if (status == DLADM_STATUS_NOTSUP ||
6498 6499                      statep->ls_persist) {
6499 6500                          valcnt = 1;
6500 6501                          if (type == DLADM_PROP_VAL_CURRENT ||
6501 6502                              type == DLADM_PROP_VAL_PERM)
6502 6503                                  propvals = &unknown;
6503 6504                          else
6504 6505                                  propvals = ¬sup;
6505 6506                  } else if (status == DLADM_STATUS_NOTDEFINED) {
6506 6507                          propvals = ¬sup; /* STR_UNDEF_VAL */
6507 6508                  } else {
6508 6509                          if (statep->ls_proplist &&
6509 6510                              statep->ls_status == DLADM_STATUS_OK) {
6510 6511                                  warn_dlerr(status,
6511 6512                                      "cannot get link property '%s' for %s",
6512 6513                                      propname, statep->ls_link);
6513 6514                          }
6514 6515                          statep->ls_status = status;
6515 6516                          statep->ls_retstatus = status;
6516 6517                          return;
6517 6518                  }
6518 6519          }
6519 6520  
6520 6521          statep->ls_status = DLADM_STATUS_OK;
6521 6522  
6522 6523          buf[0] = '\0';
6523 6524          ptr = buf;
6524 6525          lim = buf + DLADM_STRSIZE;
6525 6526          for (i = 0; i < valcnt; i++) {
6526 6527                  if (propvals[i][0] == '\0' && !statep->ls_parsable)
6527 6528                          ptr += snprintf(ptr, lim - ptr, "--,");
6528 6529                  else
6529 6530                          ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]);
6530 6531                  if (ptr >= lim)
6531 6532                          break;
6532 6533          }
6533 6534          if (valcnt > 0)
6534 6535                  buf[strlen(buf) - 1] = '\0';
6535 6536  
6536 6537          lim = statep->ls_line + MAX_PROP_LINE;
6537 6538          if (statep->ls_parsable) {
6538 6539                  *pptr += snprintf(*pptr, lim - *pptr,
6539 6540                      "%s", buf);
6540 6541          } else {
6541 6542                  *pptr += snprintf(*pptr, lim - *pptr, format, buf);
6542 6543          }
6543 6544  }
6544 6545  
6545 6546  static boolean_t
6546 6547  print_linkprop_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
6547 6548  {
6548 6549          linkprop_args_t         *arg = ofarg->ofmt_cbarg;
6549 6550          char                    *propname = arg->ls_propname;
6550 6551          show_linkprop_state_t   *statep = arg->ls_state;
6551 6552          char                    *ptr = statep->ls_line;
6552 6553          char                    *lim = ptr + MAX_PROP_LINE;
6553 6554          datalink_id_t           linkid = arg->ls_linkid;
6554 6555  
6555 6556          switch (ofarg->ofmt_id) {
6556 6557          case LINKPROP_LINK:
6557 6558                  (void) snprintf(ptr, lim - ptr, "%s", statep->ls_link);
6558 6559                  break;
6559 6560          case LINKPROP_PROPERTY:
6560 6561                  (void) snprintf(ptr, lim - ptr, "%s", propname);
6561 6562                  break;
6562 6563          case LINKPROP_VALUE:
6563 6564                  print_linkprop(linkid, statep, propname,
6564 6565                      statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT :
6565 6566                      DLADM_PROP_VAL_CURRENT, "%s", &ptr);
6566 6567                  /*
6567 6568                   * If we failed to query the link property, for example, query
6568 6569                   * the persistent value of a non-persistable link property,
6569 6570                   * simply skip the output.
6570 6571                   */
6571 6572                  if (statep->ls_status != DLADM_STATUS_OK) {
6572 6573                          /*
6573 6574                           * Ignore the temponly error when we skip printing
6574 6575                           * link properties to avoid returning failure on exit.
6575 6576                           */
6576 6577                          if (statep->ls_retstatus == DLADM_STATUS_TEMPONLY)
6577 6578                                  statep->ls_retstatus = DLADM_STATUS_OK;
6578 6579                          goto skip;
6579 6580                  }
6580 6581                  ptr = statep->ls_line;
6581 6582                  break;
6582 6583          case LINKPROP_PERM:
6583 6584                  print_linkprop(linkid, statep, propname,
6584 6585                      DLADM_PROP_VAL_PERM, "%s", &ptr);
6585 6586                  if (statep->ls_status != DLADM_STATUS_OK)
6586 6587                          goto skip;
6587 6588                  ptr = statep->ls_line;
6588 6589                  break;
6589 6590          case LINKPROP_DEFAULT:
6590 6591                  print_linkprop(linkid, statep, propname,
6591 6592                      DLADM_PROP_VAL_DEFAULT, "%s", &ptr);
6592 6593                  if (statep->ls_status != DLADM_STATUS_OK)
6593 6594                          goto skip;
6594 6595                  ptr = statep->ls_line;
6595 6596                  break;
6596 6597          case LINKPROP_POSSIBLE:
6597 6598                  print_linkprop(linkid, statep, propname,
6598 6599                      DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr);
6599 6600                  if (statep->ls_status != DLADM_STATUS_OK)
6600 6601                          goto skip;
6601 6602                  ptr = statep->ls_line;
6602 6603                  break;
6603 6604          default:
6604 6605                  die("invalid input");
6605 6606                  break;
6606 6607          }
6607 6608          (void) strlcpy(buf, ptr, bufsize);
6608 6609          return (B_TRUE);
6609 6610  skip:
6610 6611          return ((statep->ls_status == DLADM_STATUS_OK) ?
6611 6612              B_TRUE : B_FALSE);
6612 6613  }
6613 6614  
6614 6615  static boolean_t
6615 6616  linkprop_is_supported(datalink_id_t  linkid, const char *propname,
6616 6617      show_linkprop_state_t *statep)
6617 6618  {
6618 6619          dladm_status_t  status;
6619 6620          uint_t          valcnt = DLADM_MAX_PROP_VALCNT;
6620 6621  
6621 6622          /* if used with -p flag, always print output */
6622 6623          if (statep->ls_proplist != NULL)
6623 6624                  return (B_TRUE);
6624 6625  
6625 6626          status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_DEFAULT,
6626 6627              propname, statep->ls_propvals, &valcnt);
6627 6628  
6628 6629          if (status == DLADM_STATUS_OK)
6629 6630                  return (B_TRUE);
6630 6631  
6631 6632          /*
6632 6633           * A system wide default value is not available for the
6633 6634           * property. Check if current value can be retrieved.
6634 6635           */
6635 6636          status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_CURRENT,
6636 6637              propname, statep->ls_propvals, &valcnt);
6637 6638  
6638 6639          return (status == DLADM_STATUS_OK);
6639 6640  }
6640 6641  
6641 6642  /* ARGSUSED */
6642 6643  static int
6643 6644  show_linkprop(dladm_handle_t dh, datalink_id_t linkid, const char *propname,
6644 6645      void *arg)
6645 6646  {
6646 6647          show_linkprop_state_t   *statep = arg;
6647 6648          linkprop_args_t         ls_arg;
6648 6649  
6649 6650          bzero(&ls_arg, sizeof (ls_arg));
6650 6651          ls_arg.ls_state = statep;
6651 6652          ls_arg.ls_propname = (char *)propname;
6652 6653          ls_arg.ls_linkid = linkid;
6653 6654  
6654 6655          /*
6655 6656           * This will need to be fixed when kernel interfaces are added
6656 6657           * to enable walking of all known private properties. For now,
6657 6658           * we are limited to walking persistent private properties only.
6658 6659           */
6659 6660          if ((propname[0] == '_') && !statep->ls_persist &&
6660 6661              (statep->ls_proplist == NULL))
6661 6662                  return (DLADM_WALK_CONTINUE);
6662 6663          if (!statep->ls_parsable &&
6663 6664              !linkprop_is_supported(linkid, propname, statep))
6664 6665                  return (DLADM_WALK_CONTINUE);
6665 6666  
6666 6667          ofmt_print(statep->ls_ofmt, &ls_arg);
6667 6668  
6668 6669          return (DLADM_WALK_CONTINUE);
6669 6670  }
6670 6671  
6671 6672  static void
6672 6673  do_show_linkprop(int argc, char **argv, const char *use)
6673 6674  {
6674 6675          int                     option;
6675 6676          char                    propstr[DLADM_STRSIZE];
6676 6677          dladm_arg_list_t        *proplist = NULL;
6677 6678          datalink_id_t           linkid = DATALINK_ALL_LINKID;
6678 6679          show_linkprop_state_t   state;
6679 6680          uint32_t                flags = DLADM_OPT_ACTIVE;
6680 6681          dladm_status_t          status;
6681 6682          char                    *fields_str = NULL;
6682 6683          ofmt_handle_t           ofmt;
6683 6684          ofmt_status_t           oferr;
6684 6685          uint_t                  ofmtflags = 0;
6685 6686  
6686 6687          bzero(propstr, DLADM_STRSIZE);
6687 6688          opterr = 0;
6688 6689          state.ls_propvals = NULL;
6689 6690          state.ls_line = NULL;
6690 6691          state.ls_parsable = B_FALSE;
6691 6692          state.ls_persist = B_FALSE;
6692 6693          state.ls_header = B_TRUE;
6693 6694          state.ls_retstatus = DLADM_STATUS_OK;
6694 6695  
6695 6696          while ((option = getopt_long(argc, argv, ":p:cPo:",
6696 6697              prop_longopts, NULL)) != -1) {
6697 6698                  switch (option) {
6698 6699                  case 'p':
6699 6700                          (void) strlcat(propstr, optarg, DLADM_STRSIZE);
6700 6701                          if (strlcat(propstr, ",", DLADM_STRSIZE) >=
6701 6702                              DLADM_STRSIZE)
6702 6703                                  die("property list too long '%s'", propstr);
6703 6704                          break;
6704 6705                  case 'c':
6705 6706                          state.ls_parsable = B_TRUE;
6706 6707                          break;
6707 6708                  case 'P':
6708 6709                          state.ls_persist = B_TRUE;
6709 6710                          flags = DLADM_OPT_PERSIST;
6710 6711                          break;
6711 6712                  case 'o':
6712 6713                          fields_str = optarg;
6713 6714                          break;
6714 6715                  default:
6715 6716                          die_opterr(optopt, option, use);
6716 6717                          break;
6717 6718                  }
6718 6719          }
6719 6720  
6720 6721          if (optind == (argc - 1)) {
6721 6722                  if ((status = dladm_name2info(handle, argv[optind], &linkid,
6722 6723                      NULL, NULL, NULL)) != DLADM_STATUS_OK) {
6723 6724                          die_dlerr(status, "link %s is not valid", argv[optind]);
6724 6725                  }
6725 6726          } else if (optind != argc) {
6726 6727                  usage();
6727 6728          }
6728 6729  
6729 6730          if (dladm_parse_link_props(propstr, &proplist, B_TRUE)
6730 6731              != DLADM_STATUS_OK)
6731 6732                  die("invalid link properties specified");
6732 6733          state.ls_proplist = proplist;
6733 6734          state.ls_status = DLADM_STATUS_OK;
6734 6735  
6735 6736          if (state.ls_parsable)
6736 6737                  ofmtflags |= OFMT_PARSABLE;
6737 6738          else
6738 6739                  ofmtflags |= OFMT_WRAP;
6739 6740  
6740 6741          oferr = ofmt_open(fields_str, linkprop_fields, ofmtflags, 0, &ofmt);
6741 6742          ofmt_check(oferr, state.ls_parsable, ofmt, die, warn);
6742 6743          state.ls_ofmt = ofmt;
6743 6744  
6744 6745          if (linkid == DATALINK_ALL_LINKID) {
6745 6746                  (void) dladm_walk_datalink_id(show_linkprop_onelink, handle,
6746 6747                      &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags);
6747 6748          } else {
6748 6749                  (void) show_linkprop_onelink(handle, linkid, &state);
6749 6750          }
6750 6751          ofmt_close(ofmt);
6751 6752          dladm_free_props(proplist);
6752 6753  
6753 6754          if (state.ls_retstatus != DLADM_STATUS_OK) {
6754 6755                  dladm_close(handle);
6755 6756                  exit(EXIT_FAILURE);
6756 6757          }
6757 6758  }
6758 6759  
6759 6760  static int
6760 6761  show_linkprop_onelink(dladm_handle_t hdl, datalink_id_t linkid, void *arg)
6761 6762  {
6762 6763          int                     i;
6763 6764          char                    *buf;
6764 6765          uint32_t                flags;
6765 6766          dladm_arg_list_t        *proplist = NULL;
6766 6767          show_linkprop_state_t   *statep = arg;
6767 6768          dlpi_handle_t           dh = NULL;
6768 6769  
6769 6770          statep->ls_status = DLADM_STATUS_OK;
6770 6771  
6771 6772          if (dladm_datalink_id2info(hdl, linkid, &flags, NULL, NULL,
6772 6773              statep->ls_link, MAXLINKNAMELEN) != DLADM_STATUS_OK) {
6773 6774                  statep->ls_status = DLADM_STATUS_NOTFOUND;
6774 6775                  return (DLADM_WALK_CONTINUE);
6775 6776          }
6776 6777  
6777 6778          if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) ||
6778 6779              (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) {
6779 6780                  statep->ls_status = DLADM_STATUS_BADARG;
6780 6781                  return (DLADM_WALK_CONTINUE);
6781 6782          }
6782 6783  
6783 6784          proplist = statep->ls_proplist;
6784 6785  
6785 6786          /*
6786 6787           * When some WiFi links are opened for the first time, their hardware
6787 6788           * automatically scans for APs and does other slow operations.  Thus,
6788 6789           * if there are no open links, the retrieval of link properties
6789 6790           * (below) will proceed slowly unless we hold the link open.
6790 6791           *
6791 6792           * Note that failure of dlpi_open() does not necessarily mean invalid
6792 6793           * link properties, because dlpi_open() may fail because of incorrect
6793 6794           * autopush configuration. Therefore, we ingore the return value of
6794 6795           * dlpi_open().
6795 6796           */
6796 6797          if (!statep->ls_persist)
6797 6798                  (void) dlpi_open(statep->ls_link, &dh, 0);
6798 6799  
6799 6800          buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
6800 6801              DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE);
6801 6802          if (buf == NULL)
6802 6803                  die("insufficient memory");
6803 6804  
6804 6805          statep->ls_propvals = (char **)(void *)buf;
6805 6806          for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
6806 6807                  statep->ls_propvals[i] = buf +
6807 6808                      sizeof (char *) * DLADM_MAX_PROP_VALCNT +
6808 6809                      i * DLADM_PROP_VAL_MAX;
6809 6810          }
6810 6811          statep->ls_line = buf +
6811 6812              (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
6812 6813  
6813 6814          if (proplist != NULL) {
6814 6815                  for (i = 0; i < proplist->al_count; i++) {
6815 6816                          (void) show_linkprop(hdl, linkid,
6816 6817                              proplist->al_info[i].ai_name, statep);
6817 6818                  }
6818 6819          } else {
6819 6820                  (void) dladm_walk_linkprop(hdl, linkid, statep,
6820 6821                      show_linkprop);
6821 6822          }
6822 6823          if (dh != NULL)
6823 6824                  dlpi_close(dh);
6824 6825          free(buf);
6825 6826          return (DLADM_WALK_CONTINUE);
6826 6827  }
6827 6828  
6828 6829  static int
6829 6830  reset_one_linkprop(dladm_handle_t dh, datalink_id_t linkid,
6830 6831      const char *propname, void *arg)
6831 6832  {
6832 6833          set_linkprop_state_t    *statep = arg;
6833 6834          dladm_status_t          status;
6834 6835  
6835 6836          status = dladm_set_linkprop(dh, linkid, propname, NULL, 0,
6836 6837              DLADM_OPT_ACTIVE | (statep->ls_temp ? 0 : DLADM_OPT_PERSIST));
6837 6838          if (status != DLADM_STATUS_OK &&
6838 6839              status != DLADM_STATUS_PROPRDONLY &&
6839 6840              status != DLADM_STATUS_NOTSUP) {
6840 6841                  warn_dlerr(status, "cannot reset link property '%s' on '%s'",
6841 6842                      propname, statep->ls_name);
6842 6843                  statep->ls_status = status;
6843 6844          }
6844 6845  
6845 6846          return (DLADM_WALK_CONTINUE);
6846 6847  }
6847 6848  
6848 6849  static void
6849 6850  set_linkprop(int argc, char **argv, boolean_t reset, const char *use)
6850 6851  {
6851 6852          int                     i, option;
6852 6853          char                    errmsg[DLADM_STRSIZE];
6853 6854          char                    *altroot = NULL;
6854 6855          datalink_id_t           linkid;
6855 6856          boolean_t               temp = B_FALSE;
6856 6857          dladm_status_t          status = DLADM_STATUS_OK;
6857 6858          char                    propstr[DLADM_STRSIZE];
6858 6859          dladm_arg_list_t        *proplist = NULL;
6859 6860  
6860 6861          opterr = 0;
6861 6862          bzero(propstr, DLADM_STRSIZE);
6862 6863  
6863 6864          while ((option = getopt_long(argc, argv, ":p:R:t",
6864 6865              prop_longopts, NULL)) != -1) {
6865 6866                  switch (option) {
6866 6867                  case 'p':
6867 6868                          (void) strlcat(propstr, optarg, DLADM_STRSIZE);
6868 6869                          if (strlcat(propstr, ",", DLADM_STRSIZE) >=
6869 6870                              DLADM_STRSIZE)
6870 6871                                  die("property list too long '%s'", propstr);
6871 6872                          break;
6872 6873                  case 't':
6873 6874                          temp = B_TRUE;
6874 6875                          break;
6875 6876                  case 'R':
6876 6877                          altroot = optarg;
6877 6878                          break;
6878 6879                  default:
6879 6880                          die_opterr(optopt, option, use);
6880 6881  
6881 6882                  }
6882 6883          }
6883 6884  
6884 6885          /* get link name (required last argument) */
6885 6886          if (optind != (argc - 1))
6886 6887                  usage();
6887 6888  
6888 6889          if (dladm_parse_link_props(propstr, &proplist, reset) !=
6889 6890              DLADM_STATUS_OK)
6890 6891                  die("invalid link properties specified");
6891 6892  
6892 6893          if (proplist == NULL && !reset)
6893 6894                  die("link property must be specified");
6894 6895  
6895 6896          if (altroot != NULL) {
6896 6897                  dladm_free_props(proplist);
6897 6898                  altroot_cmd(altroot, argc, argv);
6898 6899          }
6899 6900  
6900 6901          status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
6901 6902              NULL);
6902 6903          if (status != DLADM_STATUS_OK)
6903 6904                  die_dlerr(status, "link %s is not valid", argv[optind]);
6904 6905  
6905 6906          if (proplist == NULL) {
6906 6907                  set_linkprop_state_t    state;
6907 6908  
6908 6909                  state.ls_name = argv[optind];
6909 6910                  state.ls_reset = reset;
6910 6911                  state.ls_temp = temp;
6911 6912                  state.ls_status = DLADM_STATUS_OK;
6912 6913  
6913 6914                  (void) dladm_walk_linkprop(handle, linkid, &state,
6914 6915                      reset_one_linkprop);
6915 6916  
6916 6917                  status = state.ls_status;
6917 6918                  goto done;
6918 6919          }
6919 6920  
6920 6921          for (i = 0; i < proplist->al_count; i++) {
6921 6922                  dladm_arg_info_t        *aip = &proplist->al_info[i];
6922 6923                  char            **val;
6923 6924                  uint_t          count;
6924 6925  
6925 6926                  if (reset) {
6926 6927                          val = NULL;
6927 6928                          count = 0;
6928 6929                  } else {
6929 6930                          val = aip->ai_val;
6930 6931                          count = aip->ai_count;
6931 6932                          if (count == 0) {
6932 6933                                  warn("no value specified for '%s'",
6933 6934                                      aip->ai_name);
6934 6935                                  status = DLADM_STATUS_BADARG;
6935 6936                                  continue;
6936 6937                          }
6937 6938                  }
6938 6939                  status = dladm_set_linkprop(handle, linkid, aip->ai_name, val,
6939 6940                      count, DLADM_OPT_ACTIVE | (temp ? 0 : DLADM_OPT_PERSIST));
6940 6941                  switch (status) {
6941 6942                  case DLADM_STATUS_OK:
6942 6943                          break;
6943 6944                  case DLADM_STATUS_NOTFOUND:
6944 6945                          warn("invalid link property '%s'", aip->ai_name);
6945 6946                          break;
6946 6947                  case DLADM_STATUS_BADVAL: {
6947 6948                          int             j;
6948 6949                          char            *ptr, *lim;
6949 6950                          char            **propvals = NULL;
6950 6951                          uint_t          valcnt = DLADM_MAX_PROP_VALCNT;
6951 6952                          dladm_status_t  s;
6952 6953  
6953 6954                          ptr = malloc((sizeof (char *) +
6954 6955                              DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT +
6955 6956                              MAX_PROP_LINE);
6956 6957  
6957 6958                          propvals = (char **)(void *)ptr;
6958 6959                          if (propvals == NULL)
6959 6960                                  die("insufficient memory");
6960 6961  
6961 6962                          for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) {
6962 6963                                  propvals[j] = ptr + sizeof (char *) *
6963 6964                                      DLADM_MAX_PROP_VALCNT +
6964 6965                                      j * DLADM_PROP_VAL_MAX;
6965 6966                          }
6966 6967                          s = dladm_get_linkprop(handle, linkid,
6967 6968                              DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals,
6968 6969                              &valcnt);
6969 6970  
6970 6971                          if (s != DLADM_STATUS_OK) {
6971 6972                                  warn_dlerr(status, "cannot set link property "
6972 6973                                      "'%s' on '%s'", aip->ai_name, argv[optind]);
6973 6974                                  free(propvals);
6974 6975                                  break;
6975 6976                          }
6976 6977  
6977 6978                          ptr = errmsg;
6978 6979                          lim = ptr + DLADM_STRSIZE;
6979 6980                          *ptr = '\0';
6980 6981                          for (j = 0; j < valcnt; j++) {
6981 6982                                  ptr += snprintf(ptr, lim - ptr, "%s,",
6982 6983                                      propvals[j]);
6983 6984                                  if (ptr >= lim)
6984 6985                                          break;
6985 6986                          }
6986 6987                          if (ptr > errmsg) {
6987 6988                                  *(ptr - 1) = '\0';
6988 6989                                  warn("link property '%s' must be one of: %s",
6989 6990                                      aip->ai_name, errmsg);
6990 6991                          } else
6991 6992                                  warn("invalid link property '%s'", *val);
6992 6993                          free(propvals);
6993 6994                          break;
6994 6995                  }
6995 6996                  default:
6996 6997                          if (reset) {
6997 6998                                  warn_dlerr(status, "cannot reset link property "
6998 6999                                      "'%s' on '%s'", aip->ai_name, argv[optind]);
6999 7000                          } else {
7000 7001                                  warn_dlerr(status, "cannot set link property "
7001 7002                                      "'%s' on '%s'", aip->ai_name, argv[optind]);
7002 7003                          }
7003 7004                          break;
7004 7005                  }
7005 7006          }
7006 7007  done:
7007 7008          dladm_free_props(proplist);
7008 7009          if (status != DLADM_STATUS_OK) {
7009 7010                  dladm_close(handle);
7010 7011                  exit(EXIT_FAILURE);
7011 7012          }
7012 7013  }
7013 7014  
7014 7015  static void
7015 7016  do_set_linkprop(int argc, char **argv, const char *use)
7016 7017  {
7017 7018          set_linkprop(argc, argv, B_FALSE, use);
7018 7019  }
7019 7020  
7020 7021  static void
7021 7022  do_reset_linkprop(int argc, char **argv, const char *use)
7022 7023  {
7023 7024          set_linkprop(argc, argv, B_TRUE, use);
7024 7025  }
7025 7026  
7026 7027  static int
7027 7028  convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp,
7028 7029      dladm_secobj_class_t class)
7029 7030  {
7030 7031          int error = 0;
7031 7032  
7032 7033          if (class == DLADM_SECOBJ_CLASS_WPA) {
7033 7034                  if (len < 8 || len > 63)
7034 7035                          return (EINVAL);
7035 7036                  (void) memcpy(obj_val, buf, len);
7036 7037                  *obj_lenp = len;
7037 7038                  return (error);
7038 7039          }
7039 7040  
7040 7041          if (class == DLADM_SECOBJ_CLASS_WEP) {
7041 7042                  switch (len) {
7042 7043                  case 5:                 /* ASCII key sizes */
7043 7044                  case 13:
7044 7045                          (void) memcpy(obj_val, buf, len);
7045 7046                          *obj_lenp = len;
7046 7047                          break;
7047 7048                  case 10:                /* Hex key sizes, not preceded by 0x */
7048 7049                  case 26:
7049 7050                          error = hexascii_to_octet(buf, len, obj_val, obj_lenp);
7050 7051                          break;
7051 7052                  case 12:                /* Hex key sizes, preceded by 0x */
7052 7053                  case 28:
7053 7054                          if (strncmp(buf, "0x", 2) != 0)
7054 7055                                  return (EINVAL);
7055 7056                          error = hexascii_to_octet(buf + 2, len - 2,
7056 7057                              obj_val, obj_lenp);
7057 7058                          break;
7058 7059                  default:
7059 7060                          return (EINVAL);
7060 7061                  }
7061 7062                  return (error);
7062 7063          }
7063 7064  
7064 7065          return (ENOENT);
7065 7066  }
7066 7067  
7067 7068  static void
7068 7069  defersig(int sig)
7069 7070  {
7070 7071          signalled = sig;
7071 7072  }
7072 7073  
7073 7074  static int
7074 7075  get_secobj_from_tty(uint_t try, const char *objname, char *buf)
7075 7076  {
7076 7077          uint_t          len = 0;
7077 7078          int             c;
7078 7079          struct termios  stored, current;
7079 7080          void            (*sigfunc)(int);
7080 7081  
7081 7082          /*
7082 7083           * Turn off echo -- but before we do so, defer SIGINT handling
7083 7084           * so that a ^C doesn't leave the terminal corrupted.
7084 7085           */
7085 7086          sigfunc = signal(SIGINT, defersig);
7086 7087          (void) fflush(stdin);
7087 7088          (void) tcgetattr(0, &stored);
7088 7089          current = stored;
7089 7090          current.c_lflag &= ~(ICANON|ECHO);
7090 7091          current.c_cc[VTIME] = 0;
7091 7092          current.c_cc[VMIN] = 1;
7092 7093          (void) tcsetattr(0, TCSANOW, ¤t);
7093 7094  again:
7094 7095          if (try == 1)
7095 7096                  (void) printf(gettext("provide value for '%s': "), objname);
7096 7097          else
7097 7098                  (void) printf(gettext("confirm value for '%s': "), objname);
7098 7099  
7099 7100          (void) fflush(stdout);
7100 7101          while (signalled == 0) {
7101 7102                  c = getchar();
7102 7103                  if (c == '\n' || c == '\r') {
7103 7104                          if (len != 0)
7104 7105                                  break;
7105 7106                          (void) putchar('\n');
7106 7107                          goto again;
7107 7108                  }
7108 7109  
7109 7110                  buf[len++] = c;
7110 7111                  if (len >= DLADM_SECOBJ_VAL_MAX - 1)
7111 7112                          break;
7112 7113                  (void) putchar('*');
7113 7114          }
7114 7115  
7115 7116          (void) putchar('\n');
7116 7117          (void) fflush(stdin);
7117 7118  
7118 7119          /*
7119 7120           * Restore terminal setting and handle deferred signals.
7120 7121           */
7121 7122          (void) tcsetattr(0, TCSANOW, &stored);
7122 7123  
7123 7124          (void) signal(SIGINT, sigfunc);
7124 7125          if (signalled != 0)
7125 7126                  (void) kill(getpid(), signalled);
7126 7127  
7127 7128          return (len);
7128 7129  }
7129 7130  
7130 7131  static int
7131 7132  get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp,
7132 7133      dladm_secobj_class_t class, FILE *filep)
7133 7134  {
7134 7135          int             rval;
7135 7136          uint_t          len, len2;
7136 7137          char            buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX];
7137 7138  
7138 7139          if (filep == NULL) {
7139 7140                  len = get_secobj_from_tty(1, obj_name, buf);
7140 7141                  rval = convert_secobj(buf, len, obj_val, obj_lenp, class);
7141 7142                  if (rval == 0) {
7142 7143                          len2 = get_secobj_from_tty(2, obj_name, buf2);
7143 7144                          if (len != len2 || memcmp(buf, buf2, len) != 0)
7144 7145                                  rval = ENOTSUP;
7145 7146                  }
7146 7147                  return (rval);
7147 7148          } else {
7148 7149                  for (;;) {
7149 7150                          if (fgets(buf, sizeof (buf), filep) == NULL)
7150 7151                                  break;
7151 7152                          if (isspace(buf[0]))
7152 7153                                  continue;
7153 7154  
7154 7155                          len = strlen(buf);
7155 7156                          if (buf[len - 1] == '\n') {
7156 7157                                  buf[len - 1] = '\0';
7157 7158                                  len--;
7158 7159                          }
7159 7160                          break;
7160 7161                  }
7161 7162                  (void) fclose(filep);
7162 7163          }
7163 7164          return (convert_secobj(buf, len, obj_val, obj_lenp, class));
7164 7165  }
7165 7166  
7166 7167  static boolean_t
7167 7168  check_auth(const char *auth)
7168 7169  {
7169 7170          struct passwd   *pw;
7170 7171  
7171 7172          if ((pw = getpwuid(getuid())) == NULL)
7172 7173                  return (B_FALSE);
7173 7174  
7174 7175          return (chkauthattr(auth, pw->pw_name) != 0);
7175 7176  }
7176 7177  
7177 7178  static void
7178 7179  audit_secobj(char *auth, char *class, char *obj,
7179 7180      boolean_t success, boolean_t create)
7180 7181  {
7181 7182          adt_session_data_t      *ah;
7182 7183          adt_event_data_t        *event;
7183 7184          au_event_t              flag;
7184 7185          char                    *errstr;
7185 7186  
7186 7187          if (create) {
7187 7188                  flag = ADT_dladm_create_secobj;
7188 7189                  errstr = "ADT_dladm_create_secobj";
7189 7190          } else {
7190 7191                  flag = ADT_dladm_delete_secobj;
7191 7192                  errstr = "ADT_dladm_delete_secobj";
7192 7193          }
7193 7194  
7194 7195          if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0)
7195 7196                  die("adt_start_session: %s", strerror(errno));
7196 7197  
7197 7198          if ((event = adt_alloc_event(ah, flag)) == NULL)
7198 7199                  die("adt_alloc_event (%s): %s", errstr, strerror(errno));
7199 7200  
7200 7201          /* fill in audit info */
7201 7202          if (create) {
7202 7203                  event->adt_dladm_create_secobj.auth_used = auth;
7203 7204                  event->adt_dladm_create_secobj.obj_class = class;
7204 7205                  event->adt_dladm_create_secobj.obj_name = obj;
7205 7206          } else {
7206 7207                  event->adt_dladm_delete_secobj.auth_used = auth;
7207 7208                  event->adt_dladm_delete_secobj.obj_class = class;
7208 7209                  event->adt_dladm_delete_secobj.obj_name = obj;
7209 7210          }
7210 7211  
7211 7212          if (success) {
7212 7213                  if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
7213 7214                          die("adt_put_event (%s, success): %s", errstr,
7214 7215                              strerror(errno));
7215 7216                  }
7216 7217          } else {
7217 7218                  if (adt_put_event(event, ADT_FAILURE,
7218 7219                      ADT_FAIL_VALUE_AUTH) != 0) {
7219 7220                          die("adt_put_event: (%s, failure): %s", errstr,
7220 7221                              strerror(errno));
7221 7222                  }
7222 7223          }
7223 7224  
7224 7225          adt_free_event(event);
7225 7226          (void) adt_end_session(ah);
7226 7227  }
7227 7228  
7228 7229  static void
7229 7230  do_create_secobj(int argc, char **argv, const char *use)
7230 7231  {
7231 7232          int                     option, rval;
7232 7233          FILE                    *filep = NULL;
7233 7234          char                    *obj_name = NULL;
7234 7235          char                    *class_name = NULL;
7235 7236          uint8_t                 obj_val[DLADM_SECOBJ_VAL_MAX];
7236 7237          uint_t                  obj_len;
7237 7238          boolean_t               success, temp = B_FALSE;
7238 7239          dladm_status_t          status;
7239 7240          dladm_secobj_class_t    class = -1;
7240 7241          uid_t                   euid;
7241 7242  
7242 7243          opterr = 0;
7243 7244          (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX);
7244 7245          while ((option = getopt_long(argc, argv, ":f:c:R:t",
7245 7246              wifi_longopts, NULL)) != -1) {
7246 7247                  switch (option) {
7247 7248                  case 'f':
7248 7249                          euid = geteuid();
7249 7250                          (void) seteuid(getuid());
7250 7251                          filep = fopen(optarg, "r");
7251 7252                          if (filep == NULL) {
7252 7253                                  die("cannot open %s: %s", optarg,
7253 7254                                      strerror(errno));
7254 7255                          }
7255 7256                          (void) seteuid(euid);
7256 7257                          break;
7257 7258                  case 'c':
7258 7259                          class_name = optarg;
7259 7260                          status = dladm_str2secobjclass(optarg, &class);
7260 7261                          if (status != DLADM_STATUS_OK) {
7261 7262                                  die("invalid secure object class '%s', "
7262 7263                                      "valid values are: wep, wpa", optarg);
7263 7264                          }
7264 7265                          break;
7265 7266                  case 't':
7266 7267                          temp = B_TRUE;
7267 7268                          break;
7268 7269                  case 'R':
7269 7270                          status = dladm_set_rootdir(optarg);
7270 7271                          if (status != DLADM_STATUS_OK) {
7271 7272                                  die_dlerr(status, "invalid directory "
7272 7273                                      "specified");
7273 7274                          }
7274 7275                          break;
7275 7276                  default:
7276 7277                          die_opterr(optopt, option, use);
7277 7278                          break;
7278 7279                  }
7279 7280          }
7280 7281  
7281 7282          if (optind == (argc - 1))
7282 7283                  obj_name = argv[optind];
7283 7284          else if (optind != argc)
7284 7285                  usage();
7285 7286  
7286 7287          if (class == -1)
7287 7288                  die("secure object class required");
7288 7289  
7289 7290          if (obj_name == NULL)
7290 7291                  die("secure object name required");
7291 7292  
7292 7293          if (!dladm_valid_secobj_name(obj_name))
7293 7294                  die("invalid secure object name '%s'", obj_name);
7294 7295  
7295 7296          success = check_auth(LINK_SEC_AUTH);
7296 7297          audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE);
7297 7298          if (!success)
7298 7299                  die("authorization '%s' is required", LINK_SEC_AUTH);
7299 7300  
7300 7301          rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep);
7301 7302          if (rval != 0) {
7302 7303                  switch (rval) {
7303 7304                  case ENOENT:
7304 7305                          die("invalid secure object class");
7305 7306                          break;
7306 7307                  case EINVAL:
7307 7308                          die("invalid secure object value");
7308 7309                          break;
7309 7310                  case ENOTSUP:
7310 7311                          die("verification failed");
7311 7312                          break;
7312 7313                  default:
7313 7314                          die("invalid secure object: %s", strerror(rval));
7314 7315                          break;
7315 7316                  }
7316 7317          }
7317 7318  
7318 7319          status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len,
7319 7320              DLADM_OPT_CREATE | DLADM_OPT_ACTIVE);
7320 7321          if (status != DLADM_STATUS_OK) {
7321 7322                  die_dlerr(status, "could not create secure object '%s'",
7322 7323                      obj_name);
7323 7324          }
7324 7325          if (temp)
7325 7326                  return;
7326 7327  
7327 7328          status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len,
7328 7329              DLADM_OPT_PERSIST);
7329 7330          if (status != DLADM_STATUS_OK) {
7330 7331                  warn_dlerr(status, "could not persistently create secure "
7331 7332                      "object '%s'", obj_name);
7332 7333          }
7333 7334  }
7334 7335  
7335 7336  static void
7336 7337  do_delete_secobj(int argc, char **argv, const char *use)
7337 7338  {
7338 7339          int             i, option;
7339 7340          boolean_t       temp = B_FALSE;
7340 7341          boolean_t       success;
7341 7342          dladm_status_t  status, pstatus;
7342 7343          int             nfields = 1;
7343 7344          char            *field, *token, *lasts = NULL, c;
7344 7345  
7345 7346          opterr = 0;
7346 7347          status = pstatus = DLADM_STATUS_OK;
7347 7348          while ((option = getopt_long(argc, argv, ":R:t",
7348 7349              wifi_longopts, NULL)) != -1) {
7349 7350                  switch (option) {
7350 7351                  case 't':
7351 7352                          temp = B_TRUE;
7352 7353                          break;
7353 7354                  case 'R':
7354 7355                          status = dladm_set_rootdir(optarg);
7355 7356                          if (status != DLADM_STATUS_OK) {
7356 7357                                  die_dlerr(status, "invalid directory "
7357 7358                                      "specified");
7358 7359                          }
7359 7360                          break;
7360 7361                  default:
7361 7362                          die_opterr(optopt, option, use);
7362 7363                          break;
7363 7364                  }
7364 7365          }
7365 7366  
7366 7367          if (optind != (argc - 1))
7367 7368                  die("secure object name required");
7368 7369  
7369 7370          token = argv[optind];
7370 7371          while ((c = *token++) != NULL) {
7371 7372                  if (c == ',')
7372 7373                          nfields++;
7373 7374          }
7374 7375          token = strdup(argv[optind]);
7375 7376          if (token == NULL)
7376 7377                  die("no memory");
7377 7378  
7378 7379          success = check_auth(LINK_SEC_AUTH);
7379 7380          audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE);
7380 7381          if (!success)
7381 7382                  die("authorization '%s' is required", LINK_SEC_AUTH);
7382 7383  
7383 7384          for (i = 0; i < nfields; i++) {
7384 7385  
7385 7386                  field = strtok_r(token, ",", &lasts);
7386 7387                  token = NULL;
7387 7388                  status = dladm_unset_secobj(handle, field, DLADM_OPT_ACTIVE);
7388 7389                  if (!temp) {
7389 7390                          pstatus = dladm_unset_secobj(handle, field,
7390 7391                              DLADM_OPT_PERSIST);
7391 7392                  } else {
7392 7393                          pstatus = DLADM_STATUS_OK;
7393 7394                  }
7394 7395  
7395 7396                  if (status != DLADM_STATUS_OK) {
7396 7397                          warn_dlerr(status, "could not delete secure object "
7397 7398                              "'%s'", field);
7398 7399                  }
7399 7400                  if (pstatus != DLADM_STATUS_OK) {
7400 7401                          warn_dlerr(pstatus, "could not persistently delete "
7401 7402                              "secure object '%s'", field);
7402 7403                  }
7403 7404          }
7404 7405          free(token);
7405 7406  
7406 7407          if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) {
7407 7408                  dladm_close(handle);
7408 7409                  exit(EXIT_FAILURE);
7409 7410          }
7410 7411  }
7411 7412  
7412 7413  typedef struct show_secobj_state {
7413 7414          boolean_t       ss_persist;
7414 7415          boolean_t       ss_parsable;
7415 7416          boolean_t       ss_header;
7416 7417          ofmt_handle_t   ss_ofmt;
7417 7418  } show_secobj_state_t;
7418 7419  
7419 7420  
7420 7421  static boolean_t
7421 7422  show_secobj(dladm_handle_t dh, void *arg, const char *obj_name)
7422 7423  {
7423 7424          uint_t                  obj_len = DLADM_SECOBJ_VAL_MAX;
7424 7425          uint8_t                 obj_val[DLADM_SECOBJ_VAL_MAX];
7425 7426          char                    buf[DLADM_STRSIZE];
7426 7427          uint_t                  flags = 0;
7427 7428          dladm_secobj_class_t    class;
7428 7429          show_secobj_state_t     *statep = arg;
7429 7430          dladm_status_t          status;
7430 7431          secobj_fields_buf_t     sbuf;
7431 7432  
7432 7433          bzero(&sbuf, sizeof (secobj_fields_buf_t));
7433 7434          if (statep->ss_persist)
7434 7435                  flags |= DLADM_OPT_PERSIST;
7435 7436  
7436 7437          status = dladm_get_secobj(dh, obj_name, &class, obj_val, &obj_len,
7437 7438              flags);
7438 7439          if (status != DLADM_STATUS_OK)
7439 7440                  die_dlerr(status, "cannot get secure object '%s'", obj_name);
7440 7441  
7441 7442          (void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name),
7442 7443              obj_name);
7443 7444          (void) dladm_secobjclass2str(class, buf);
7444 7445          (void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf);
7445 7446          if (getuid() == 0) {
7446 7447                  char    val[DLADM_SECOBJ_VAL_MAX * 2];
7447 7448                  uint_t  len = sizeof (val);
7448 7449  
7449 7450                  if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0)
7450 7451                          (void) snprintf(sbuf.ss_val,
7451 7452                              sizeof (sbuf.ss_val), "%s", val);
7452 7453          }
7453 7454          ofmt_print(statep->ss_ofmt, &sbuf);
7454 7455          return (B_TRUE);
7455 7456  }
7456 7457  
7457 7458  static void
7458 7459  do_show_secobj(int argc, char **argv, const char *use)
7459 7460  {
7460 7461          int                     option;
7461 7462          show_secobj_state_t     state;
7462 7463          dladm_status_t          status;
7463 7464          boolean_t               o_arg = B_FALSE;
7464 7465          uint_t                  i;
7465 7466          uint_t                  flags;
7466 7467          char                    *fields_str = NULL;
7467 7468          char                    *def_fields = "object,class";
7468 7469          char                    *all_fields = "object,class,value";
7469 7470          char                    *field, *token, *lasts = NULL, c;
7470 7471          ofmt_handle_t           ofmt;
7471 7472          ofmt_status_t           oferr;
7472 7473          uint_t                  ofmtflags = 0;
7473 7474  
7474 7475          opterr = 0;
7475 7476          bzero(&state, sizeof (state));
7476 7477          state.ss_parsable = B_FALSE;
7477 7478          fields_str = def_fields;
7478 7479          state.ss_persist = B_FALSE;
7479 7480          state.ss_parsable = B_FALSE;
7480 7481          state.ss_header = B_TRUE;
7481 7482          while ((option = getopt_long(argc, argv, ":pPo:",
7482 7483              wifi_longopts, NULL)) != -1) {
7483 7484                  switch (option) {
7484 7485                  case 'p':
7485 7486                          state.ss_parsable = B_TRUE;
7486 7487                          break;
7487 7488                  case 'P':
7488 7489                          state.ss_persist = B_TRUE;
7489 7490                          break;
7490 7491                  case 'o':
7491 7492                          o_arg = B_TRUE;
7492 7493                          if (strcasecmp(optarg, "all") == 0)
7493 7494                                  fields_str = all_fields;
7494 7495                          else
7495 7496                                  fields_str = optarg;
7496 7497                          break;
7497 7498                  default:
7498 7499                          die_opterr(optopt, option, use);
7499 7500                          break;
7500 7501                  }
7501 7502          }
7502 7503  
7503 7504          if (state.ss_parsable && !o_arg)
7504 7505                  die("option -c requires -o");
7505 7506  
7506 7507          if (state.ss_parsable && fields_str == all_fields)
7507 7508                  die("\"-o all\" is invalid with -p");
7508 7509  
7509 7510          if (state.ss_parsable)
7510 7511                  ofmtflags |= OFMT_PARSABLE;
7511 7512          oferr = ofmt_open(fields_str, secobj_fields, ofmtflags, 0, &ofmt);
7512 7513          ofmt_check(oferr, state.ss_parsable, ofmt, die, warn);
7513 7514          state.ss_ofmt = ofmt;
7514 7515  
7515 7516          flags = state.ss_persist ? DLADM_OPT_PERSIST : 0;
7516 7517  
7517 7518          if (optind == (argc - 1)) {
7518 7519                  uint_t obj_fields = 1;
7519 7520  
7520 7521                  token = argv[optind];
7521 7522                  if (token == NULL)
7522 7523                          die("secure object name required");
7523 7524                  while ((c = *token++) != NULL) {
7524 7525                          if (c == ',')
7525 7526                                  obj_fields++;
7526 7527                  }
7527 7528                  token = strdup(argv[optind]);
7528 7529                  if (token == NULL)
7529 7530                          die("no memory");
7530 7531                  for (i = 0; i < obj_fields; i++) {
7531 7532                          field = strtok_r(token, ",", &lasts);
7532 7533                          token = NULL;
7533 7534                          if (!show_secobj(handle, &state, field))
7534 7535                                  break;
7535 7536                  }
7536 7537                  free(token);
7537 7538                  ofmt_close(ofmt);
7538 7539                  return;
7539 7540          } else if (optind != argc)
7540 7541                  usage();
7541 7542  
7542 7543          status = dladm_walk_secobj(handle, &state, show_secobj, flags);
7543 7544  
7544 7545          if (status != DLADM_STATUS_OK)
7545 7546                  die_dlerr(status, "show-secobj");
7546 7547          ofmt_close(ofmt);
7547 7548  }
7548 7549  
7549 7550  /*ARGSUSED*/
7550 7551  static int
7551 7552  i_dladm_init_linkprop(dladm_handle_t dh, datalink_id_t linkid, void *arg)
7552 7553  {
7553 7554          (void) dladm_init_linkprop(dh, linkid, B_TRUE);
7554 7555          return (DLADM_WALK_CONTINUE);
7555 7556  }
7556 7557  
7557 7558  /*ARGSUSED*/
7558 7559  void
7559 7560  do_init_linkprop(int argc, char **argv, const char *use)
7560 7561  {
7561 7562          int                     option;
7562 7563          dladm_status_t          status;
7563 7564          datalink_id_t           linkid = DATALINK_ALL_LINKID;
7564 7565          datalink_media_t        media = DATALINK_ANY_MEDIATYPE;
7565 7566          uint_t                  any_media = B_TRUE;
7566 7567  
7567 7568          opterr = 0;
7568 7569          while ((option = getopt(argc, argv, ":w")) != -1) {
7569 7570                  switch (option) {
7570 7571                  case 'w':
7571 7572                          media = DL_WIFI;
7572 7573                          any_media = B_FALSE;
7573 7574                          break;
7574 7575                  default:
7575 7576                          /*
7576 7577                           * Because init-linkprop is not a public command,
7577 7578                           * print the usage instead.
7578 7579                           */
7579 7580                          usage();
7580 7581                          break;
7581 7582                  }
7582 7583          }
7583 7584  
7584 7585          if (optind == (argc - 1)) {
7585 7586                  if ((status = dladm_name2info(handle, argv[optind], &linkid,
7586 7587                      NULL, NULL, NULL)) != DLADM_STATUS_OK)
7587 7588                          die_dlerr(status, "link %s is not valid", argv[optind]);
7588 7589          } else if (optind != argc) {
7589 7590                  usage();
7590 7591          }
7591 7592  
7592 7593          if (linkid == DATALINK_ALL_LINKID) {
7593 7594                  /*
7594 7595                   * linkprops of links of other classes have been initialized as
7595 7596                   * part of the dladm up-xxx operation.
7596 7597                   */
7597 7598                  (void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle,
7598 7599                      NULL, DATALINK_CLASS_PHYS, media, DLADM_OPT_PERSIST);
7599 7600          } else {
7600 7601                  (void) dladm_init_linkprop(handle, linkid, any_media);
7601 7602          }
7602 7603  }
7603 7604  
7604 7605  static void
7605 7606  do_show_ether(int argc, char **argv, const char *use)
7606 7607  {
7607 7608          int                     option;
7608 7609          datalink_id_t           linkid;
7609 7610          print_ether_state_t     state;
7610 7611          char                    *fields_str = NULL;
7611 7612          ofmt_handle_t           ofmt;
7612 7613          ofmt_status_t           oferr;
7613 7614          uint_t                  ofmtflags = 0;
7614 7615  
7615 7616          bzero(&state, sizeof (state));
7616 7617          state.es_link = NULL;
7617 7618          state.es_parsable = B_FALSE;
7618 7619  
7619 7620          while ((option = getopt_long(argc, argv, "o:px",
7620 7621              showeth_lopts, NULL)) != -1) {
7621 7622                  switch (option) {
7622 7623                          case 'x':
7623 7624                                  state.es_extended = B_TRUE;
7624 7625                                  break;
7625 7626                          case 'p':
7626 7627                                  state.es_parsable = B_TRUE;
7627 7628                                  break;
7628 7629                          case 'o':
7629 7630                                  fields_str = optarg;
7630 7631                                  break;
7631 7632                          default:
7632 7633                                  die_opterr(optopt, option, use);
7633 7634                                  break;
7634 7635                  }
7635 7636          }
7636 7637  
7637 7638          if (optind == (argc - 1))
7638 7639                  state.es_link = argv[optind];
7639 7640  
7640 7641          if (state.es_parsable)
7641 7642                  ofmtflags |= OFMT_PARSABLE;
7642 7643          oferr = ofmt_open(fields_str, ether_fields, ofmtflags,
7643 7644              DLADM_DEFAULT_COL, &ofmt);
7644 7645          ofmt_check(oferr, state.es_parsable, ofmt, die, warn);
7645 7646          state.es_ofmt = ofmt;
7646 7647  
7647 7648          if (state.es_link == NULL) {
7648 7649                  (void) dladm_walk_datalink_id(show_etherprop, handle, &state,
7649 7650                      DATALINK_CLASS_PHYS, DL_ETHER, DLADM_OPT_ACTIVE);
7650 7651          } else {
7651 7652                  if (!link_is_ether(state.es_link, &linkid))
7652 7653                          die("invalid link specified");
7653 7654                  (void) show_etherprop(handle, linkid, &state);
7654 7655          }
7655 7656          ofmt_close(ofmt);
7656 7657  }
7657 7658  
7658 7659  static int
7659 7660  show_etherprop(dladm_handle_t dh, datalink_id_t linkid, void *arg)
7660 7661  {
7661 7662          print_ether_state_t     *statep = arg;
7662 7663          ether_fields_buf_t      ebuf;
7663 7664          dladm_ether_info_t      eattr;
7664 7665          dladm_status_t          status;
7665 7666  
7666 7667          bzero(&ebuf, sizeof (ether_fields_buf_t));
7667 7668          if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL,
7668 7669              ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) {
7669 7670                  return (DLADM_WALK_CONTINUE);
7670 7671          }
7671 7672  
7672 7673          status = dladm_ether_info(dh, linkid, &eattr);
7673 7674          if (status != DLADM_STATUS_OK)
7674 7675                  goto cleanup;
7675 7676  
7676 7677          (void) strlcpy(ebuf.eth_ptype, "current", sizeof (ebuf.eth_ptype));
7677 7678  
7678 7679          (void) dladm_ether_autoneg2str(ebuf.eth_autoneg,
7679 7680              sizeof (ebuf.eth_autoneg), &eattr, CURRENT);
7680 7681          (void) dladm_ether_pause2str(ebuf.eth_pause,
7681 7682              sizeof (ebuf.eth_pause), &eattr, CURRENT);
7682 7683          (void) dladm_ether_spdx2str(ebuf.eth_spdx,
7683 7684              sizeof (ebuf.eth_spdx), &eattr, CURRENT);
7684 7685          (void) strlcpy(ebuf.eth_state,
7685 7686              dladm_linkstate2str(eattr.lei_state, ebuf.eth_state),
7686 7687              sizeof (ebuf.eth_state));
7687 7688          (void) strlcpy(ebuf.eth_rem_fault,
7688 7689              (eattr.lei_attr[CURRENT].le_fault ? "fault" : "none"),
7689 7690              sizeof (ebuf.eth_rem_fault));
7690 7691  
7691 7692          ofmt_print(statep->es_ofmt, &ebuf);
7692 7693  
7693 7694          if (statep->es_extended)
7694 7695                  show_ether_xprop(arg, &eattr);
7695 7696  
7696 7697  cleanup:
7697 7698          dladm_ether_info_done(&eattr);
7698 7699          return (DLADM_WALK_CONTINUE);
7699 7700  }
7700 7701  
7701 7702  /* ARGSUSED */
7702 7703  static void
7703 7704  do_init_secobj(int argc, char **argv, const char *use)
7704 7705  {
7705 7706          dladm_status_t  status;
7706 7707  
7707 7708          status = dladm_init_secobj(handle);
7708 7709          if (status != DLADM_STATUS_OK)
7709 7710                  die_dlerr(status, "secure object initialization failed");
7710 7711  }
7711 7712  
7712 7713  enum bridge_func {
7713 7714          brCreate, brAdd, brModify
7714 7715  };
7715 7716  
7716 7717  static void
7717 7718  create_modify_add_bridge(int argc, char **argv, const char *use,
7718 7719      enum bridge_func func)
7719 7720  {
7720 7721          int                     option;
7721 7722          uint_t                  n, i, nlink;
7722 7723          uint32_t                flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
7723 7724          char                    *altroot = NULL;
7724 7725          char                    *links[MAXPORT];
7725 7726          datalink_id_t           linkids[MAXPORT];
7726 7727          dladm_status_t          status;
7727 7728          const char              *bridge;
7728 7729          UID_STP_CFG_T           cfg, cfg_old;
7729 7730          dladm_bridge_prot_t     brprot = DLADM_BRIDGE_PROT_UNKNOWN;
7730 7731          dladm_bridge_prot_t     brprot_old;
7731 7732  
7732 7733          /* Set up the default configuration values */
7733 7734          cfg.field_mask = 0;
7734 7735          cfg.bridge_priority = DEF_BR_PRIO;
7735 7736          cfg.max_age = DEF_BR_MAXAGE;
7736 7737          cfg.hello_time = DEF_BR_HELLOT;
7737 7738          cfg.forward_delay = DEF_BR_FWDELAY;
7738 7739          cfg.force_version = DEF_FORCE_VERS;
7739 7740  
7740 7741          nlink = opterr = 0;
7741 7742          while ((option = getopt_long(argc, argv, ":P:R:d:f:h:l:m:p:",
7742 7743              bridge_lopts, NULL)) != -1) {
7743 7744                  switch (option) {
7744 7745                  case 'P':
7745 7746                          if (func == brAdd)
7746 7747                                  die_opterr(optopt, option, use);
7747 7748                          status = dladm_bridge_str2prot(optarg, &brprot);
7748 7749                          if (status != DLADM_STATUS_OK)
7749 7750                                  die_dlerr(status, "protection %s", optarg);
7750 7751                          break;
7751 7752                  case 'R':
7752 7753                          altroot = optarg;
7753 7754                          break;
7754 7755                  case 'd':
7755 7756                          if (func == brAdd)
7756 7757                                  die_opterr(optopt, option, use);
7757 7758                          if (cfg.field_mask & BR_CFG_DELAY)
7758 7759                                  die("forwarding delay set more than once");
7759 7760                          if (!str2int(optarg, &cfg.forward_delay) ||
7760 7761                              cfg.forward_delay < MIN_BR_FWDELAY ||
7761 7762                              cfg.forward_delay > MAX_BR_FWDELAY)
7762 7763                                  die("incorrect forwarding delay");
7763 7764                          cfg.field_mask |= BR_CFG_DELAY;
7764 7765                          break;
7765 7766                  case 'f':
7766 7767                          if (func == brAdd)
7767 7768                                  die_opterr(optopt, option, use);
7768 7769                          if (cfg.field_mask & BR_CFG_FORCE_VER)
7769 7770                                  die("force protocol set more than once");
7770 7771                          if (!str2int(optarg, &cfg.force_version) ||
7771 7772                              cfg.force_version < 0)
7772 7773                                  die("incorrect force protocol");
7773 7774                          cfg.field_mask |= BR_CFG_FORCE_VER;
7774 7775                          break;
7775 7776                  case 'h':
7776 7777                          if (func == brAdd)
7777 7778                                  die_opterr(optopt, option, use);
7778 7779                          if (cfg.field_mask & BR_CFG_HELLO)
7779 7780                                  die("hello time set more than once");
7780 7781                          if (!str2int(optarg, &cfg.hello_time) ||
7781 7782                              cfg.hello_time < MIN_BR_HELLOT ||
7782 7783                              cfg.hello_time > MAX_BR_HELLOT)
7783 7784                                  die("incorrect hello time");
7784 7785                          cfg.field_mask |= BR_CFG_HELLO;
7785 7786                          break;
7786 7787                  case 'l':
7787 7788                          if (func == brModify)
7788 7789                                  die_opterr(optopt, option, use);
7789 7790                          if (nlink >= MAXPORT)
7790 7791                                  die("too many links specified");
7791 7792                          links[nlink++] = optarg;
7792 7793                          break;
7793 7794                  case 'm':
7794 7795                          if (func == brAdd)
7795 7796                                  die_opterr(optopt, option, use);
7796 7797                          if (cfg.field_mask & BR_CFG_AGE)
7797 7798                                  die("max age set more than once");
7798 7799                          if (!str2int(optarg, &cfg.max_age) ||
7799 7800                              cfg.max_age < MIN_BR_MAXAGE ||
7800 7801                              cfg.max_age > MAX_BR_MAXAGE)
7801 7802                                  die("incorrect max age");
7802 7803                          cfg.field_mask |= BR_CFG_AGE;
7803 7804                          break;
7804 7805                  case 'p':
7805 7806                          if (func == brAdd)
7806 7807                                  die_opterr(optopt, option, use);
7807 7808                          if (cfg.field_mask & BR_CFG_PRIO)
7808 7809                                  die("priority set more than once");
7809 7810                          if (!str2int(optarg, &cfg.bridge_priority) ||
7810 7811                              cfg.bridge_priority < MIN_BR_PRIO ||
7811 7812                              cfg.bridge_priority > MAX_BR_PRIO)
7812 7813                                  die("incorrect priority");
7813 7814                          cfg.bridge_priority &= 0xF000;
7814 7815                          cfg.field_mask |= BR_CFG_PRIO;
7815 7816                          break;
7816 7817                  default:
7817 7818                          die_opterr(optopt, option, use);
7818 7819                          break;
7819 7820                  }
7820 7821          }
7821 7822  
7822 7823          /* get the bridge name (required last argument) */
7823 7824          if (optind != (argc-1))
7824 7825                  usage();
7825 7826  
7826 7827          bridge = argv[optind];
7827 7828          if (!dladm_valid_bridgename(bridge))
7828 7829                  die("invalid bridge name '%s'", bridge);
7829 7830  
7830 7831          /*
7831 7832           * Get the current properties, if any, and merge in with changes.  This
7832 7833           * is necessary (even with the field_mask feature) so that the
7833 7834           * value-checking macros will produce the right results with proposed
7834 7835           * changes to existing configuration.  We only need it for those
7835 7836           * parameters, though.
7836 7837           */
7837 7838          (void) dladm_bridge_get_properties(bridge, &cfg_old, &brprot_old);
7838 7839          if (brprot == DLADM_BRIDGE_PROT_UNKNOWN)
7839 7840                  brprot = brprot_old;
7840 7841          if (!(cfg.field_mask & BR_CFG_AGE))
7841 7842                  cfg.max_age = cfg_old.max_age;
7842 7843          if (!(cfg.field_mask & BR_CFG_HELLO))
7843 7844                  cfg.hello_time = cfg_old.hello_time;
7844 7845          if (!(cfg.field_mask & BR_CFG_DELAY))
7845 7846                  cfg.forward_delay = cfg_old.forward_delay;
7846 7847  
7847 7848          if (!CHECK_BRIDGE_CONFIG(cfg)) {
7848 7849                  warn("illegal forward delay / max age / hello time "
7849 7850                      "combination");
7850 7851                  if (NO_MAXAGE(cfg)) {
7851 7852                          die("no max age possible: need forward delay >= %d or "
7852 7853                              "hello time <= %d", MIN_FWDELAY_NOM(cfg),
7853 7854                              MAX_HELLOTIME_NOM(cfg));
7854 7855                  } else if (SMALL_MAXAGE(cfg)) {
7855 7856                          if (CAPPED_MAXAGE(cfg))
7856 7857                                  die("max age too small: need age >= %d and "
7857 7858                                      "<= %d or hello time <= %d",
7858 7859                                      MIN_MAXAGE(cfg), MAX_MAXAGE(cfg),
7859 7860                                      MAX_HELLOTIME(cfg));
7860 7861                          else
7861 7862                                  die("max age too small: need age >= %d or "
7862 7863                                      "hello time <= %d",
7863 7864                                      MIN_MAXAGE(cfg), MAX_HELLOTIME(cfg));
7864 7865                  } else if (FLOORED_MAXAGE(cfg)) {
7865 7866                          die("max age too large: need age >= %d and <= %d or "
7866 7867                              "forward delay >= %d",
7867 7868                              MIN_MAXAGE(cfg), MAX_MAXAGE(cfg),
7868 7869                              MIN_FWDELAY(cfg));
7869 7870                  } else {
7870 7871                          die("max age too large: need age <= %d or forward "
7871 7872                              "delay >= %d",
7872 7873                              MAX_MAXAGE(cfg), MIN_FWDELAY(cfg));
7873 7874                  }
7874 7875          }
7875 7876  
7876 7877          if (altroot != NULL)
7877 7878                  altroot_cmd(altroot, argc, argv);
7878 7879  
7879 7880          for (n = 0; n < nlink; n++) {
7880 7881                  datalink_class_t class;
7881 7882                  uint32_t media;
7882 7883                  char pointless[DLADM_STRSIZE];
7883 7884  
7884 7885                  if (dladm_name2info(handle, links[n], &linkids[n], NULL, &class,
7885 7886                      &media) != DLADM_STATUS_OK)
7886 7887                          die("invalid link name '%s'", links[n]);
7887 7888                  if (class & ~(DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR |
7888 7889                      DATALINK_CLASS_ETHERSTUB | DATALINK_CLASS_SIMNET))
7889 7890                          die("%s %s cannot be bridged",
7890 7891                              dladm_class2str(class, pointless), links[n]);
7891 7892                  if (media != DL_ETHER && media != DL_100VG &&
7892 7893                      media != DL_ETH_CSMA && media != DL_100BT)
7893 7894                          die("%s interface %s cannot be bridged",
7894 7895                              dladm_media2str(media, pointless), links[n]);
7895 7896          }
7896 7897  
7897 7898          if (func == brCreate)
7898 7899                  flags |= DLADM_OPT_CREATE;
7899 7900  
7900 7901          if (func != brAdd) {
7901 7902                  status = dladm_bridge_configure(handle, bridge, &cfg, brprot,
7902 7903                      flags);
7903 7904                  if (status != DLADM_STATUS_OK)
7904 7905                          die_dlerr(status, "create operation failed");
7905 7906          }
7906 7907  
7907 7908          status = DLADM_STATUS_OK;
7908 7909          for (n = 0; n < nlink; n++) {
7909 7910                  status = dladm_bridge_setlink(handle, linkids[n], bridge);
7910 7911                  if (status != DLADM_STATUS_OK)
7911 7912                          break;
7912 7913          }
7913 7914  
7914 7915          if (n >= nlink) {
7915 7916                  /*
7916 7917                   * We were successful.  If we're creating a new bridge, then
7917 7918                   * there's just one more step: enabling.  If we're modifying or
7918 7919                   * just adding links, then we're done.
7919 7920                   */
7920 7921                  if (func != brCreate ||
7921 7922                      (status = dladm_bridge_enable(bridge)) == DLADM_STATUS_OK)
7922 7923                          return;
7923 7924          }
7924 7925  
7925 7926          /* clean up the partial configuration */
7926 7927          for (i = 0; i < n; i++)
7927 7928                  (void) dladm_bridge_setlink(handle, linkids[i], "");
7928 7929  
7929 7930          /* if failure for brCreate, then delete the bridge */
7930 7931          if (func == brCreate)
7931 7932                  (void) dladm_bridge_delete(handle, bridge, flags);
7932 7933  
7933 7934          if (n < nlink)
7934 7935                  die_dlerr(status, "unable to add link %s to bridge %s",
7935 7936                      links[n], bridge);
7936 7937          else
7937 7938                  die_dlerr(status, "unable to enable bridge %s", bridge);
7938 7939  }
7939 7940  
7940 7941  static void
7941 7942  do_create_bridge(int argc, char **argv, const char *use)
7942 7943  {
7943 7944          create_modify_add_bridge(argc, argv, use, brCreate);
7944 7945  }
7945 7946  
7946 7947  static void
7947 7948  do_modify_bridge(int argc, char **argv, const char *use)
7948 7949  {
7949 7950          create_modify_add_bridge(argc, argv, use, brModify);
7950 7951  }
7951 7952  
7952 7953  static void
7953 7954  do_add_bridge(int argc, char **argv, const char *use)
7954 7955  {
7955 7956          create_modify_add_bridge(argc, argv, use, brAdd);
7956 7957  }
7957 7958  
7958 7959  static void
7959 7960  do_delete_bridge(int argc, char **argv, const char *use)
7960 7961  {
7961 7962          char                    option;
7962 7963          char                    *altroot = NULL;
7963 7964          uint32_t                flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
7964 7965          dladm_status_t          status;
7965 7966  
7966 7967          opterr = 0;
7967 7968          while ((option = getopt_long(argc, argv, ":R:", bridge_lopts, NULL)) !=
7968 7969              -1) {
7969 7970                  switch (option) {
7970 7971                  case 'R':
7971 7972                          altroot = optarg;
7972 7973                          break;
7973 7974                  default:
7974 7975                          die_opterr(optopt, option, use);
7975 7976                          break;
7976 7977                  }
7977 7978          }
7978 7979  
7979 7980          /* get the bridge name (required last argument) */
7980 7981          if (optind != (argc-1))
7981 7982                  usage();
7982 7983  
7983 7984          if (altroot != NULL)
7984 7985                  altroot_cmd(altroot, argc, argv);
7985 7986  
7986 7987          status = dladm_bridge_delete(handle, argv[optind], flags);
7987 7988          if (status != DLADM_STATUS_OK)
7988 7989                  die_dlerr(status, "delete operation failed");
7989 7990  }
7990 7991  
7991 7992  static void
7992 7993  do_remove_bridge(int argc, char **argv, const char *use)
7993 7994  {
7994 7995          char            option;
7995 7996          uint_t          n, nlink;
7996 7997          char            *links[MAXPORT];
7997 7998          datalink_id_t   linkids[MAXPORT];
7998 7999          char            *altroot = NULL;
7999 8000          dladm_status_t  status;
8000 8001          boolean_t       removed_one;
8001 8002  
8002 8003          nlink = opterr = 0;
8003 8004          while ((option = getopt_long(argc, argv, ":R:l:", bridge_lopts,
8004 8005              NULL)) != -1) {
8005 8006                  switch (option) {
8006 8007                  case 'R':
8007 8008                          altroot = optarg;
8008 8009                          break;
8009 8010                  case 'l':
8010 8011                          if (nlink >= MAXPORT)
8011 8012                                  die("too many links specified");
8012 8013                          links[nlink++] = optarg;
8013 8014                          break;
8014 8015                  default:
8015 8016                          die_opterr(optopt, option, use);
8016 8017                          break;
8017 8018                  }
8018 8019          }
8019 8020  
8020 8021          if (nlink == 0)
8021 8022                  usage();
8022 8023  
8023 8024          /* get the bridge name (required last argument) */
8024 8025          if (optind != (argc-1))
8025 8026                  usage();
8026 8027  
8027 8028          if (altroot != NULL)
8028 8029                  altroot_cmd(altroot, argc, argv);
8029 8030  
8030 8031          for (n = 0; n < nlink; n++) {
8031 8032                  char bridge[MAXLINKNAMELEN];
8032 8033  
8033 8034                  if (dladm_name2info(handle, links[n], &linkids[n], NULL, NULL,
8034 8035                      NULL) != DLADM_STATUS_OK)
8035 8036                          die("invalid link name '%s'", links[n]);
8036 8037                  status = dladm_bridge_getlink(handle, linkids[n], bridge,
8037 8038                      sizeof (bridge));
8038 8039                  if (status != DLADM_STATUS_OK &&
8039 8040                      status != DLADM_STATUS_NOTFOUND) {
8040 8041                          die_dlerr(status, "cannot get bridge status on %s",
8041 8042                              links[n]);
8042 8043                  }
8043 8044                  if (status == DLADM_STATUS_NOTFOUND ||
8044 8045                      strcmp(bridge, argv[optind]) != 0)
8045 8046                          die("link %s is not on bridge %s", links[n],
8046 8047                              argv[optind]);
8047 8048          }
8048 8049  
8049 8050          removed_one = B_FALSE;
8050 8051          for (n = 0; n < nlink; n++) {
8051 8052                  status = dladm_bridge_setlink(handle, linkids[n], "");
8052 8053                  if (status == DLADM_STATUS_OK) {
8053 8054                          removed_one = B_TRUE;
8054 8055                  } else {
8055 8056                          warn_dlerr(status,
8056 8057                              "cannot remove link %s from bridge %s",
8057 8058                              links[n], argv[optind]);
8058 8059                  }
8059 8060          }
8060 8061          if (!removed_one)
8061 8062                  die("unable to remove any links from bridge %s", argv[optind]);
8062 8063  }
8063 8064  
8064 8065  static void
8065 8066  fmt_int(char *buf, size_t buflen, int value, int runvalue,
8066 8067      boolean_t printstar)
8067 8068  {
8068 8069          (void) snprintf(buf, buflen, "%d", value);
8069 8070          if (value != runvalue && printstar)
8070 8071                  (void) strlcat(buf, "*", buflen);
8071 8072  }
8072 8073  
8073 8074  static void
8074 8075  fmt_bridge_id(char *buf, size_t buflen, UID_BRIDGE_ID_T *bid)
8075 8076  {
8076 8077          (void) snprintf(buf, buflen, "%u/%x:%x:%x:%x:%x:%x", bid->prio,
8077 8078              bid->addr[0], bid->addr[1], bid->addr[2], bid->addr[3],
8078 8079              bid->addr[4], bid->addr[5]);
8079 8080  }
8080 8081  
8081 8082  static dladm_status_t
8082 8083  print_bridge(show_state_t *state, datalink_id_t linkid,
8083 8084      bridge_fields_buf_t *bbuf)
8084 8085  {
8085 8086          char                    link[MAXLINKNAMELEN];
8086 8087          datalink_class_t        class;
8087 8088          uint32_t                flags;
8088 8089          dladm_status_t          status;
8089 8090          UID_STP_CFG_T           smfcfg, runcfg;
8090 8091          UID_STP_STATE_T         stpstate;
8091 8092          dladm_bridge_prot_t     smfprot, runprot;
8092 8093  
8093 8094          if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class,
8094 8095              NULL, link, sizeof (link))) != DLADM_STATUS_OK)
8095 8096                  return (status);
8096 8097  
8097 8098          if (!(state->ls_flags & flags))
8098 8099                  return (DLADM_STATUS_NOTFOUND);
8099 8100  
8100 8101          /* Convert observability node name back to bridge name */
8101 8102          if (!dladm_observe_to_bridge(link))
8102 8103                  return (DLADM_STATUS_NOTFOUND);
8103 8104          (void) strlcpy(bbuf->bridge_name, link, sizeof (bbuf->bridge_name));
8104 8105  
8105 8106          /*
8106 8107           * If the running value differs from the one in SMF, and parsable
8107 8108           * output is not requested, then we show the running value with an
8108 8109           * asterisk.
8109 8110           */
8110 8111          (void) dladm_bridge_get_properties(bbuf->bridge_name, &smfcfg,
8111 8112              &smfprot);
8112 8113          (void) dladm_bridge_run_properties(bbuf->bridge_name, &runcfg,
8113 8114              &runprot);
8114 8115          (void) snprintf(bbuf->bridge_protect, sizeof (bbuf->bridge_protect),
8115 8116              "%s%s", state->ls_parsable || smfprot == runprot ? "" : "*",
8116 8117              dladm_bridge_prot2str(runprot));
8117 8118          fmt_int(bbuf->bridge_priority, sizeof (bbuf->bridge_priority),
8118 8119              smfcfg.bridge_priority, runcfg.bridge_priority,
8119 8120              !state->ls_parsable && (runcfg.field_mask & BR_CFG_AGE));
8120 8121          fmt_int(bbuf->bridge_bmaxage, sizeof (bbuf->bridge_bmaxage),
8121 8122              smfcfg.max_age, runcfg.max_age,
8122 8123              !state->ls_parsable && (runcfg.field_mask & BR_CFG_AGE));
8123 8124          fmt_int(bbuf->bridge_bhellotime,
8124 8125              sizeof (bbuf->bridge_bhellotime), smfcfg.hello_time,
8125 8126              runcfg.hello_time,
8126 8127              !state->ls_parsable && (runcfg.field_mask & BR_CFG_HELLO));
8127 8128          fmt_int(bbuf->bridge_bfwddelay, sizeof (bbuf->bridge_bfwddelay),
8128 8129              smfcfg.forward_delay, runcfg.forward_delay,
8129 8130              !state->ls_parsable && (runcfg.field_mask & BR_CFG_DELAY));
8130 8131          fmt_int(bbuf->bridge_forceproto, sizeof (bbuf->bridge_forceproto),
8131 8132              smfcfg.force_version, runcfg.force_version,
8132 8133              !state->ls_parsable && (runcfg.field_mask & BR_CFG_FORCE_VER));
8133 8134          fmt_int(bbuf->bridge_holdtime, sizeof (bbuf->bridge_holdtime),
8134 8135              smfcfg.hold_time, runcfg.hold_time,
8135 8136              !state->ls_parsable && (runcfg.field_mask & BR_CFG_HOLD_TIME));
8136 8137  
8137 8138          if (dladm_bridge_state(bbuf->bridge_name, &stpstate) ==
8138 8139              DLADM_STATUS_OK) {
8139 8140                  fmt_bridge_id(bbuf->bridge_address,
8140 8141                      sizeof (bbuf->bridge_address), &stpstate.bridge_id);
8141 8142                  (void) snprintf(bbuf->bridge_tctime,
8142 8143                      sizeof (bbuf->bridge_tctime), "%lu",
8143 8144                      stpstate.timeSince_Topo_Change);
8144 8145                  (void) snprintf(bbuf->bridge_tccount,
8145 8146                      sizeof (bbuf->bridge_tccount), "%lu",
8146 8147                      stpstate.Topo_Change_Count);
8147 8148                  (void) snprintf(bbuf->bridge_tchange,
8148 8149                      sizeof (bbuf->bridge_tchange), "%u", stpstate.Topo_Change);
8149 8150                  fmt_bridge_id(bbuf->bridge_desroot,
8150 8151                      sizeof (bbuf->bridge_desroot), &stpstate.designated_root);
8151 8152                  (void) snprintf(bbuf->bridge_rootcost,
8152 8153                      sizeof (bbuf->bridge_rootcost), "%lu",
8153 8154                      stpstate.root_path_cost);
8154 8155                  (void) snprintf(bbuf->bridge_rootport,
8155 8156                      sizeof (bbuf->bridge_rootport), "%u", stpstate.root_port);
8156 8157                  (void) snprintf(bbuf->bridge_maxage,
8157 8158                      sizeof (bbuf->bridge_maxage), "%d", stpstate.max_age);
8158 8159                  (void) snprintf(bbuf->bridge_hellotime,
8159 8160                      sizeof (bbuf->bridge_hellotime), "%d", stpstate.hello_time);
8160 8161                  (void) snprintf(bbuf->bridge_fwddelay,
8161 8162                      sizeof (bbuf->bridge_fwddelay), "%d",
8162 8163                      stpstate.forward_delay);
8163 8164          }
8164 8165          return (DLADM_STATUS_OK);
8165 8166  }
8166 8167  
8167 8168  static dladm_status_t
8168 8169  print_bridge_stats(show_state_t *state, datalink_id_t linkid,
8169 8170      bridge_statfields_buf_t *bbuf)
8170 8171  {
8171 8172          char                    link[MAXLINKNAMELEN];
8172 8173          datalink_class_t        class;
8173 8174          uint32_t                flags;
8174 8175          dladm_status_t          status;
8175 8176          kstat_ctl_t             *kcp;
8176 8177          kstat_t                 *ksp;
8177 8178          brsum_t                 *brsum = (brsum_t *)&state->ls_prevstats;
8178 8179          brsum_t                 newval;
8179 8180  
8180 8181  #ifndef lint
8181 8182          /* This is a compile-time assertion; optimizer normally fixes this */
8182 8183          extern void brsum_t_is_too_large(void);
8183 8184  
8184 8185          if (sizeof (*brsum) > sizeof (state->ls_prevstats))
8185 8186                  brsum_t_is_too_large();
8186 8187  #endif
8187 8188  
8188 8189          if (state->ls_firstonly) {
8189 8190                  if (state->ls_donefirst)
8190 8191                          return (DLADM_WALK_CONTINUE);
8191 8192                  state->ls_donefirst = B_TRUE;
8192 8193          } else {
8193 8194                  bzero(brsum, sizeof (*brsum));
8194 8195          }
8195 8196          bzero(&newval, sizeof (newval));
8196 8197  
8197 8198          if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class,
8198 8199              NULL, link, sizeof (link))) != DLADM_STATUS_OK)
8199 8200                  return (status);
8200 8201  
8201 8202          if (!(state->ls_flags & flags))
8202 8203                  return (DLADM_STATUS_NOTFOUND);
8203 8204  
8204 8205          if ((kcp = kstat_open()) == NULL) {
8205 8206                  warn("kstat open operation failed");
8206 8207                  return (DLADM_STATUS_OK);
8207 8208          }
8208 8209          if ((ksp = kstat_lookup(kcp, "bridge", 0, link)) != NULL &&
8209 8210              kstat_read(kcp, ksp, NULL) != -1) {
8210 8211                  if (dladm_kstat_value(ksp, "drops", KSTAT_DATA_UINT64,
8211 8212                      &newval.drops) == DLADM_STATUS_OK) {
8212 8213                          (void) snprintf(bbuf->bridges_drops,
8213 8214                              sizeof (bbuf->bridges_drops), "%llu",
8214 8215                              newval.drops - brsum->drops);
8215 8216                  }
8216 8217                  if (dladm_kstat_value(ksp, "forward_direct", KSTAT_DATA_UINT64,
8217 8218                      &newval.forward_dir) == DLADM_STATUS_OK) {
8218 8219                          (void) snprintf(bbuf->bridges_forwards,
8219 8220                              sizeof (bbuf->bridges_forwards), "%llu",
8220 8221                              newval.forward_dir - brsum->forward_dir);
8221 8222                  }
8222 8223                  if (dladm_kstat_value(ksp, "forward_mbcast", KSTAT_DATA_UINT64,
8223 8224                      &newval.forward_mb) == DLADM_STATUS_OK) {
8224 8225                          (void) snprintf(bbuf->bridges_mbcast,
8225 8226                              sizeof (bbuf->bridges_mbcast), "%llu",
8226 8227                              newval.forward_mb - brsum->forward_mb);
8227 8228                  }
8228 8229                  if (dladm_kstat_value(ksp, "forward_unknown", KSTAT_DATA_UINT64,
8229 8230                      &newval.forward_unk) == DLADM_STATUS_OK) {
8230 8231                          (void) snprintf(bbuf->bridges_unknown,
8231 8232                              sizeof (bbuf->bridges_unknown), "%llu",
8232 8233                              newval.forward_unk - brsum->forward_unk);
8233 8234                  }
8234 8235                  if (dladm_kstat_value(ksp, "recv", KSTAT_DATA_UINT64,
8235 8236                      &newval.recv) == DLADM_STATUS_OK) {
8236 8237                          (void) snprintf(bbuf->bridges_recv,
8237 8238                              sizeof (bbuf->bridges_recv), "%llu",
8238 8239                              newval.recv - brsum->recv);
8239 8240                  }
8240 8241                  if (dladm_kstat_value(ksp, "sent", KSTAT_DATA_UINT64,
8241 8242                      &newval.sent) == DLADM_STATUS_OK) {
8242 8243                          (void) snprintf(bbuf->bridges_sent,
8243 8244                              sizeof (bbuf->bridges_sent), "%llu",
8244 8245                              newval.sent - brsum->sent);
8245 8246                  }
8246 8247          }
8247 8248          (void) kstat_close(kcp);
8248 8249  
8249 8250          /* Convert observability node name back to bridge name */
8250 8251          if (!dladm_observe_to_bridge(link))
8251 8252                  return (DLADM_STATUS_NOTFOUND);
8252 8253          (void) strlcpy(bbuf->bridges_name, link, sizeof (bbuf->bridges_name));
8253 8254  
8254 8255          *brsum = newval;
8255 8256  
8256 8257          return (DLADM_STATUS_OK);
8257 8258  }
8258 8259  
8259 8260  /*
8260 8261   * This structure carries around extra state information for the show-bridge
8261 8262   * command and allows us to use common support functions.
8262 8263   */
8263 8264  typedef struct {
8264 8265          show_state_t    state;
8265 8266          boolean_t       show_stats;
8266 8267          const char      *bridge;
8267 8268  } show_brstate_t;
8268 8269  
8269 8270  /* ARGSUSED */
8270 8271  static int
8271 8272  show_bridge(dladm_handle_t handle, datalink_id_t linkid, void *arg)
8272 8273  {
8273 8274          show_brstate_t  *brstate = arg;
8274 8275          void *buf;
8275 8276  
8276 8277          if (brstate->show_stats) {
8277 8278                  bridge_statfields_buf_t bbuf;
8278 8279  
8279 8280                  bzero(&bbuf, sizeof (bbuf));
8280 8281                  brstate->state.ls_status = print_bridge_stats(&brstate->state,
8281 8282                      linkid, &bbuf);
8282 8283                  buf = &bbuf;
8283 8284          } else {
8284 8285                  bridge_fields_buf_t bbuf;
8285 8286  
8286 8287                  bzero(&bbuf, sizeof (bbuf));
8287 8288                  brstate->state.ls_status = print_bridge(&brstate->state, linkid,
8288 8289                      &bbuf);
8289 8290                  buf = &bbuf;
8290 8291          }
8291 8292          if (brstate->state.ls_status == DLADM_STATUS_OK)
8292 8293                  ofmt_print(brstate->state.ls_ofmt, buf);
8293 8294          return (DLADM_WALK_CONTINUE);
8294 8295  }
8295 8296  
8296 8297  static void
8297 8298  fmt_bool(char *buf, size_t buflen, int val)
8298 8299  {
8299 8300          (void) strlcpy(buf, val ? "yes" : "no", buflen);
8300 8301  }
8301 8302  
8302 8303  static dladm_status_t
8303 8304  print_bridge_link(show_state_t *state, datalink_id_t linkid,
8304 8305      bridge_link_fields_buf_t *bbuf)
8305 8306  {
8306 8307          datalink_class_t        class;
8307 8308          uint32_t                flags;
8308 8309          dladm_status_t          status;
8309 8310          UID_STP_PORT_STATE_T    stpstate;
8310 8311  
8311 8312          status = dladm_datalink_id2info(handle, linkid, &flags, &class, NULL,
8312 8313              bbuf->bridgel_link, sizeof (bbuf->bridgel_link));
8313 8314          if (status != DLADM_STATUS_OK)
8314 8315                  return (status);
8315 8316  
8316 8317          if (!(state->ls_flags & flags))
8317 8318                  return (DLADM_STATUS_NOTFOUND);
8318 8319  
8319 8320          if (dladm_bridge_link_state(handle, linkid, &stpstate) ==
8320 8321              DLADM_STATUS_OK) {
8321 8322                  (void) snprintf(bbuf->bridgel_index,
8322 8323                      sizeof (bbuf->bridgel_index), "%u", stpstate.port_no);
8323 8324                  if (dlsym(RTLD_PROBE, "STP_IN_state2str")) {
8324 8325                          (void) strlcpy(bbuf->bridgel_state,
8325 8326                              STP_IN_state2str(stpstate.state),
8326 8327                              sizeof (bbuf->bridgel_state));
8327 8328                  } else {
8328 8329                          (void) snprintf(bbuf->bridgel_state,
8329 8330                              sizeof (bbuf->bridgel_state), "%u",
8330 8331                              stpstate.state);
8331 8332                  }
8332 8333                  (void) snprintf(bbuf->bridgel_uptime,
8333 8334                      sizeof (bbuf->bridgel_uptime), "%lu", stpstate.uptime);
8334 8335                  (void) snprintf(bbuf->bridgel_opercost,
8335 8336                      sizeof (bbuf->bridgel_opercost), "%lu",
8336 8337                      stpstate.oper_port_path_cost);
8337 8338                  fmt_bool(bbuf->bridgel_operp2p, sizeof (bbuf->bridgel_operp2p),
8338 8339                      stpstate.oper_point2point);
8339 8340                  fmt_bool(bbuf->bridgel_operedge,
8340 8341                      sizeof (bbuf->bridgel_operedge), stpstate.oper_edge);
8341 8342                  fmt_bridge_id(bbuf->bridgel_desroot,
8342 8343                      sizeof (bbuf->bridgel_desroot), &stpstate.designated_root);
8343 8344                  (void) snprintf(bbuf->bridgel_descost,
8344 8345                      sizeof (bbuf->bridgel_descost), "%lu",
8345 8346                      stpstate.designated_cost);
8346 8347                  fmt_bridge_id(bbuf->bridgel_desbridge,
8347 8348                      sizeof (bbuf->bridgel_desbridge),
8348 8349                      &stpstate.designated_bridge);
8349 8350                  (void) snprintf(bbuf->bridgel_desport,
8350 8351                      sizeof (bbuf->bridgel_desport), "%u",
8351 8352                      stpstate.designated_port);
8352 8353                  fmt_bool(bbuf->bridgel_tcack, sizeof (bbuf->bridgel_tcack),
8353 8354                      stpstate.top_change_ack);
8354 8355          }
8355 8356          return (DLADM_STATUS_OK);
8356 8357  }
8357 8358  
8358 8359  static dladm_status_t
8359 8360  print_bridge_link_stats(show_state_t *state, datalink_id_t linkid,
8360 8361      bridge_link_statfields_buf_t *bbuf)
8361 8362  {
8362 8363          datalink_class_t        class;
8363 8364          uint32_t                flags;
8364 8365          dladm_status_t          status;
8365 8366          UID_STP_PORT_STATE_T    stpstate;
8366 8367          kstat_ctl_t             *kcp;
8367 8368          kstat_t                 *ksp;
8368 8369          char                    bridge[MAXLINKNAMELEN];
8369 8370          char                    kstatname[MAXLINKNAMELEN*2 + 1];
8370 8371          brlsum_t                *brlsum = (brlsum_t *)&state->ls_prevstats;
8371 8372          brlsum_t                newval;
8372 8373  
8373 8374  #ifndef lint
8374 8375          /* This is a compile-time assertion; optimizer normally fixes this */
8375 8376          extern void brlsum_t_is_too_large(void);
8376 8377  
8377 8378          if (sizeof (*brlsum) > sizeof (state->ls_prevstats))
8378 8379                  brlsum_t_is_too_large();
8379 8380  #endif
8380 8381  
8381 8382          if (state->ls_firstonly) {
8382 8383                  if (state->ls_donefirst)
8383 8384                          return (DLADM_WALK_CONTINUE);
8384 8385                  state->ls_donefirst = B_TRUE;
8385 8386          } else {
8386 8387                  bzero(brlsum, sizeof (*brlsum));
8387 8388          }
8388 8389          bzero(&newval, sizeof (newval));
8389 8390  
8390 8391          status = dladm_datalink_id2info(handle, linkid, &flags, &class, NULL,
8391 8392              bbuf->bridgels_link, sizeof (bbuf->bridgels_link));
8392 8393          if (status != DLADM_STATUS_OK)
8393 8394                  return (status);
8394 8395  
8395 8396          if (!(state->ls_flags & flags))
8396 8397                  return (DLADM_STATUS_NOTFOUND);
8397 8398  
8398 8399          if (dladm_bridge_link_state(handle, linkid, &stpstate) ==
8399 8400              DLADM_STATUS_OK) {
8400 8401                  newval.cfgbpdu = stpstate.rx_cfg_bpdu_cnt;
8401 8402                  newval.tcnbpdu = stpstate.rx_tcn_bpdu_cnt;
8402 8403                  newval.rstpbpdu = stpstate.rx_rstp_bpdu_cnt;
8403 8404                  newval.txbpdu = stpstate.txCount;
8404 8405  
8405 8406                  (void) snprintf(bbuf->bridgels_cfgbpdu,
8406 8407                      sizeof (bbuf->bridgels_cfgbpdu), "%lu",
8407 8408                      newval.cfgbpdu - brlsum->cfgbpdu);
8408 8409                  (void) snprintf(bbuf->bridgels_tcnbpdu,
8409 8410                      sizeof (bbuf->bridgels_tcnbpdu), "%lu",
8410 8411                      newval.tcnbpdu - brlsum->tcnbpdu);
8411 8412                  (void) snprintf(bbuf->bridgels_rstpbpdu,
8412 8413                      sizeof (bbuf->bridgels_rstpbpdu), "%lu",
8413 8414                      newval.rstpbpdu - brlsum->rstpbpdu);
8414 8415                  (void) snprintf(bbuf->bridgels_txbpdu,
8415 8416                      sizeof (bbuf->bridgels_txbpdu), "%lu",
8416 8417                      newval.txbpdu - brlsum->txbpdu);
8417 8418          }
8418 8419  
8419 8420          if ((status = dladm_bridge_getlink(handle, linkid, bridge,
8420 8421              sizeof (bridge))) != DLADM_STATUS_OK)
8421 8422                  goto bls_out;
8422 8423          (void) snprintf(kstatname, sizeof (kstatname), "%s0-%s", bridge,
8423 8424              bbuf->bridgels_link);
8424 8425          if ((kcp = kstat_open()) == NULL) {
8425 8426                  warn("kstat open operation failed");
8426 8427                  goto bls_out;
8427 8428          }
8428 8429          if ((ksp = kstat_lookup(kcp, "bridge", 0, kstatname)) != NULL &&
8429 8430              kstat_read(kcp, ksp, NULL) != -1) {
8430 8431                  if (dladm_kstat_value(ksp, "drops", KSTAT_DATA_UINT64,
8431 8432                      &newval.drops) != -1) {
8432 8433                          (void) snprintf(bbuf->bridgels_drops,
8433 8434                              sizeof (bbuf->bridgels_drops), "%llu",
8434 8435                              newval.drops - brlsum->drops);
8435 8436                  }
8436 8437                  if (dladm_kstat_value(ksp, "recv", KSTAT_DATA_UINT64,
8437 8438                      &newval.recv) != -1) {
8438 8439                          (void) snprintf(bbuf->bridgels_recv,
8439 8440                              sizeof (bbuf->bridgels_recv), "%llu",
8440 8441                              newval.recv - brlsum->recv);
8441 8442                  }
8442 8443                  if (dladm_kstat_value(ksp, "xmit", KSTAT_DATA_UINT64,
8443 8444                      &newval.xmit) != -1) {
8444 8445                          (void) snprintf(bbuf->bridgels_xmit,
8445 8446                              sizeof (bbuf->bridgels_xmit), "%llu",
8446 8447                              newval.xmit - brlsum->xmit);
8447 8448                  }
8448 8449          }
8449 8450          (void) kstat_close(kcp);
8450 8451  bls_out:
8451 8452          *brlsum = newval;
8452 8453  
8453 8454          return (status);
8454 8455  }
8455 8456  
8456 8457  static void
8457 8458  show_bridge_link(datalink_id_t linkid, show_brstate_t *brstate)
8458 8459  {
8459 8460          void *buf;
8460 8461  
8461 8462          if (brstate->show_stats) {
8462 8463                  bridge_link_statfields_buf_t bbuf;
8463 8464  
8464 8465                  bzero(&bbuf, sizeof (bbuf));
8465 8466                  brstate->state.ls_status = print_bridge_link_stats(
8466 8467                      &brstate->state, linkid, &bbuf);
8467 8468                  buf = &bbuf;
8468 8469          } else {
8469 8470                  bridge_link_fields_buf_t bbuf;
8470 8471  
8471 8472                  bzero(&bbuf, sizeof (bbuf));
8472 8473                  brstate->state.ls_status = print_bridge_link(&brstate->state,
8473 8474                      linkid, &bbuf);
8474 8475                  buf = &bbuf;
8475 8476          }
8476 8477          if (brstate->state.ls_status == DLADM_STATUS_OK)
8477 8478                  ofmt_print(brstate->state.ls_ofmt, buf);
8478 8479  }
8479 8480  
8480 8481  /* ARGSUSED */
8481 8482  static int
8482 8483  show_bridge_link_walk(dladm_handle_t handle, datalink_id_t linkid, void *arg)
8483 8484  {
8484 8485          show_brstate_t  *brstate = arg;
8485 8486          char bridge[MAXLINKNAMELEN];
8486 8487  
8487 8488          if (dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge)) ==
8488 8489              DLADM_STATUS_OK && strcmp(bridge, brstate->bridge) == 0) {
8489 8490                  show_bridge_link(linkid, brstate);
8490 8491          }
8491 8492          return (DLADM_WALK_CONTINUE);
8492 8493  }
8493 8494  
8494 8495  static void
8495 8496  show_bridge_fwd(dladm_handle_t handle, bridge_listfwd_t *blf,
8496 8497      show_state_t *state)
8497 8498  {
8498 8499          bridge_fwd_fields_buf_t bbuf;
8499 8500  
8500 8501          bzero(&bbuf, sizeof (bbuf));
8501 8502          (void) snprintf(bbuf.bridgef_dest, sizeof (bbuf.bridgef_dest),
8502 8503              "%s", ether_ntoa((struct ether_addr *)blf->blf_dest));
8503 8504          if (blf->blf_is_local) {
8504 8505                  (void) strlcpy(bbuf.bridgef_flags, "L",
8505 8506                      sizeof (bbuf.bridgef_flags));
8506 8507          } else {
8507 8508                  (void) snprintf(bbuf.bridgef_age, sizeof (bbuf.bridgef_age),
8508 8509                      "%2d.%03d", blf->blf_ms_age / 1000, blf->blf_ms_age % 1000);
8509 8510                  if (blf->blf_trill_nick != 0) {
8510 8511                          (void) snprintf(bbuf.bridgef_output,
8511 8512                              sizeof (bbuf.bridgef_output), "%u",
8512 8513                              blf->blf_trill_nick);
8513 8514                  }
8514 8515          }
8515 8516          if (blf->blf_linkid != DATALINK_INVALID_LINKID &&
8516 8517              blf->blf_trill_nick == 0) {
8517 8518                  state->ls_status = dladm_datalink_id2info(handle,
8518 8519                      blf->blf_linkid, NULL, NULL, NULL, bbuf.bridgef_output,
8519 8520                      sizeof (bbuf.bridgef_output));
8520 8521          }
8521 8522          if (state->ls_status == DLADM_STATUS_OK)
8522 8523                  ofmt_print(state->ls_ofmt, &bbuf);
8523 8524  }
8524 8525  
8525 8526  static void
8526 8527  show_bridge_trillnick(trill_listnick_t *tln, show_state_t *state)
8527 8528  {
8528 8529          bridge_trill_fields_buf_t bbuf;
8529 8530  
8530 8531          bzero(&bbuf, sizeof (bbuf));
8531 8532          (void) snprintf(bbuf.bridget_nick, sizeof (bbuf.bridget_nick),
8532 8533              "%u", tln->tln_nick);
8533 8534          if (tln->tln_ours) {
8534 8535                  (void) strlcpy(bbuf.bridget_flags, "L",
8535 8536                      sizeof (bbuf.bridget_flags));
8536 8537          } else {
8537 8538                  state->ls_status = dladm_datalink_id2info(handle,
8538 8539                      tln->tln_linkid, NULL, NULL, NULL, bbuf.bridget_link,
8539 8540                      sizeof (bbuf.bridget_link));
8540 8541                  (void) snprintf(bbuf.bridget_nexthop,
8541 8542                      sizeof (bbuf.bridget_nexthop), "%s",
8542 8543                      ether_ntoa((struct ether_addr *)tln->tln_nexthop));
8543 8544          }
8544 8545          if (state->ls_status == DLADM_STATUS_OK)
8545 8546                  ofmt_print(state->ls_ofmt, &bbuf);
8546 8547  }
8547 8548  
8548 8549  static void
8549 8550  do_show_bridge(int argc, char **argv, const char *use)
8550 8551  {
8551 8552          int             option;
8552 8553          enum {
8553 8554                  bridgeMode, linkMode, fwdMode, trillMode
8554 8555          }               op_mode = bridgeMode;
8555 8556          uint32_t        flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
8556 8557          boolean_t       parsable = B_FALSE;
8557 8558          datalink_id_t   linkid = DATALINK_ALL_LINKID;
8558 8559          int             interval = 0;
8559 8560          show_brstate_t  brstate;
8560 8561          dladm_status_t  status;
8561 8562          char            *fields_str = NULL;
8562 8563          /* default: bridge-related data */
8563 8564          char            *all_fields = "bridge,protect,address,priority,bmaxage,"
8564 8565              "bhellotime,bfwddelay,forceproto,tctime,tccount,tchange,"
8565 8566              "desroot,rootcost,rootport,maxage,hellotime,fwddelay,holdtime";
8566 8567          char            *default_fields = "bridge,protect,address,priority,"
8567 8568              "desroot";
8568 8569          char            *all_statfields = "bridge,drops,forwards,mbcast,"
8569 8570              "unknown,recv,sent";
8570 8571          char            *default_statfields = "bridge,drops,forwards,mbcast,"
8571 8572              "unknown";
8572 8573          /* -l: link-related data */
8573 8574          char            *all_link_fields = "link,index,state,uptime,opercost,"
8574 8575              "operp2p,operedge,desroot,descost,desbridge,desport,tcack";
8575 8576          char            *default_link_fields = "link,state,uptime,desroot";
8576 8577          char            *all_link_statfields = "link,cfgbpdu,tcnbpdu,rstpbpdu,"
8577 8578              "txbpdu,drops,recv,xmit";
8578 8579          char            *default_link_statfields = "link,drops,recv,xmit";
8579 8580          /* -f: bridge forwarding table related data */
8580 8581          char            *default_fwd_fields = "dest,age,flags,output";
8581 8582          /* -t: TRILL nickname table related data */
8582 8583          char            *default_trill_fields = "nick,flags,link,nexthop";
8583 8584          char            *default_str;
8584 8585          char            *all_str;
8585 8586          ofmt_field_t    *field_arr;
8586 8587          ofmt_handle_t   ofmt;
8587 8588          ofmt_status_t   oferr;
8588 8589          uint_t          ofmtflags = 0;
8589 8590  
8590 8591          bzero(&brstate, sizeof (brstate));
8591 8592  
8592 8593          opterr = 0;
8593 8594          while ((option = getopt_long(argc, argv, ":fi:lo:pst",
8594 8595              bridge_show_lopts, NULL)) != -1) {
8595 8596                  switch (option) {
8596 8597                  case 'f':
8597 8598                          if (op_mode != bridgeMode && op_mode != fwdMode)
8598 8599                                  die("-f is incompatible with -l or -t");
8599 8600                          op_mode = fwdMode;
8600 8601                          break;
8601 8602                  case 'i':
8602 8603                          if (interval != 0)
8603 8604                                  die_optdup(option);
8604 8605                          if (!str2int(optarg, &interval) || interval == 0)
8605 8606                                  die("invalid interval value '%s'", optarg);
8606 8607                          break;
8607 8608                  case 'l':
8608 8609                          if (op_mode != bridgeMode && op_mode != linkMode)
8609 8610                                  die("-l is incompatible with -f or -t");
8610 8611                          op_mode = linkMode;
8611 8612                          break;
8612 8613                  case 'o':
8613 8614                          fields_str = optarg;
8614 8615                          break;
8615 8616                  case 'p':
8616 8617                          if (parsable)
8617 8618                                  die_optdup(option);
8618 8619                          parsable = B_TRUE;
8619 8620                          break;
8620 8621                  case 's':
8621 8622                          if (brstate.show_stats)
8622 8623                                  die_optdup(option);
8623 8624                          brstate.show_stats = B_TRUE;
8624 8625                          break;
8625 8626                  case 't':
8626 8627                          if (op_mode != bridgeMode && op_mode != trillMode)
8627 8628                                  die("-t is incompatible with -f or -l");
8628 8629                          op_mode = trillMode;
8629 8630                          break;
8630 8631                  default:
8631 8632                          die_opterr(optopt, option, use);
8632 8633                          break;
8633 8634                  }
8634 8635          }
8635 8636  
8636 8637          if (interval != 0 && !brstate.show_stats)
8637 8638                  die("the -i option can be used only with -s");
8638 8639  
8639 8640          if ((op_mode == fwdMode || op_mode == trillMode) && brstate.show_stats)
8640 8641                  die("the -f/-t and -s options cannot be used together");
8641 8642  
8642 8643          /* get the bridge name (optional last argument) */
8643 8644          if (optind == (argc-1)) {
8644 8645                  char lname[MAXLINKNAMELEN];
8645 8646                  uint32_t lnkflg;
8646 8647                  datalink_class_t class;
8647 8648  
8648 8649                  brstate.bridge = argv[optind];
8649 8650                  (void) snprintf(lname, sizeof (lname), "%s0", brstate.bridge);
8650 8651                  if ((status = dladm_name2info(handle, lname, &linkid, &lnkflg,
8651 8652                      &class, NULL)) != DLADM_STATUS_OK) {
8652 8653                          die_dlerr(status, "bridge %s is not valid",
8653 8654                              brstate.bridge);
8654 8655                  }
8655 8656  
8656 8657                  if (class != DATALINK_CLASS_BRIDGE)
8657 8658                          die("%s is not a bridge", brstate.bridge);
8658 8659  
8659 8660                  if (!(lnkflg & flags)) {
8660 8661                          die_dlerr(DLADM_STATUS_BADARG,
8661 8662                              "bridge %s is temporarily removed", brstate.bridge);
8662 8663                  }
8663 8664          } else if (optind != argc) {
8664 8665                  usage();
8665 8666          } else if (op_mode != bridgeMode) {
8666 8667                  die("bridge name required for -l, -f, or -t");
8667 8668                  return;
8668 8669          }
8669 8670  
8670 8671          brstate.state.ls_parsable = parsable;
8671 8672          brstate.state.ls_flags = flags;
8672 8673          brstate.state.ls_firstonly = (interval != 0);
8673 8674  
8674 8675          switch (op_mode) {
8675 8676          case bridgeMode:
8676 8677                  if (brstate.show_stats) {
8677 8678                          default_str = default_statfields;
8678 8679                          all_str = all_statfields;
8679 8680                          field_arr = bridge_statfields;
8680 8681                  } else {
8681 8682                          default_str = default_fields;
8682 8683                          all_str = all_fields;
8683 8684                          field_arr = bridge_fields;
8684 8685                  }
8685 8686                  break;
8686 8687  
8687 8688          case linkMode:
8688 8689                  if (brstate.show_stats) {
8689 8690                          default_str = default_link_statfields;
8690 8691                          all_str = all_link_statfields;
8691 8692                          field_arr = bridge_link_statfields;
8692 8693                  } else {
8693 8694                          default_str = default_link_fields;
8694 8695                          all_str = all_link_fields;
8695 8696                          field_arr = bridge_link_fields;
8696 8697                  }
8697 8698                  break;
8698 8699  
8699 8700          case fwdMode:
8700 8701                  default_str = all_str = default_fwd_fields;
8701 8702                  field_arr = bridge_fwd_fields;
8702 8703                  break;
8703 8704  
8704 8705          case trillMode:
8705 8706                  default_str = all_str = default_trill_fields;
8706 8707                  field_arr = bridge_trill_fields;
8707 8708                  break;
8708 8709          }
8709 8710  
8710 8711          if (fields_str == NULL)
8711 8712                  fields_str = default_str;
8712 8713          else if (strcasecmp(fields_str, "all") == 0)
8713 8714                  fields_str = all_str;
8714 8715  
8715 8716          if (parsable)
8716 8717                  ofmtflags |= OFMT_PARSABLE;
8717 8718          oferr = ofmt_open(fields_str, field_arr, ofmtflags, 0, &ofmt);
8718 8719          ofmt_check(oferr, brstate.state.ls_parsable, ofmt, die, warn);
8719 8720          brstate.state.ls_ofmt = ofmt;
8720 8721  
8721 8722          for (;;) {
8722 8723                  brstate.state.ls_donefirst = B_FALSE;
8723 8724                  switch (op_mode) {
8724 8725                  case bridgeMode:
8725 8726                          if (linkid == DATALINK_ALL_LINKID) {
8726 8727                                  (void) dladm_walk_datalink_id(show_bridge,
8727 8728                                      handle, &brstate, DATALINK_CLASS_BRIDGE,
8728 8729                                      DATALINK_ANY_MEDIATYPE, flags);
8729 8730                          } else {
8730 8731                                  (void) show_bridge(handle, linkid, &brstate);
8731 8732                                  if (brstate.state.ls_status !=
8732 8733                                      DLADM_STATUS_OK) {
8733 8734                                          die_dlerr(brstate.state.ls_status,
8734 8735                                              "failed to show bridge %s",
8735 8736                                              brstate.bridge);
8736 8737                                  }
8737 8738                          }
8738 8739                          break;
8739 8740  
8740 8741                  case linkMode: {
8741 8742                          datalink_id_t *dlp;
8742 8743                          uint_t i, nlinks;
8743 8744  
8744 8745                          dlp = dladm_bridge_get_portlist(brstate.bridge,
8745 8746                              &nlinks);
8746 8747                          if (dlp != NULL) {
8747 8748                                  for (i = 0; i < nlinks; i++)
8748 8749                                          show_bridge_link(dlp[i], &brstate);
8749 8750                                  dladm_bridge_free_portlist(dlp);
8750 8751                          } else if (errno == ENOENT) {
8751 8752                                  /* bridge not running; iterate on libdladm */
8752 8753                                  (void) dladm_walk_datalink_id(
8753 8754                                      show_bridge_link_walk, handle,
8754 8755                                      &brstate, DATALINK_CLASS_PHYS |
8755 8756                                      DATALINK_CLASS_AGGR |
8756 8757                                      DATALINK_CLASS_ETHERSTUB,
8757 8758                                      DATALINK_ANY_MEDIATYPE, flags);
8758 8759                          } else {
8759 8760                                  die("unable to get port list for bridge %s: %s",
8760 8761                                      brstate.bridge, strerror(errno));
8761 8762                          }
8762 8763                          break;
8763 8764                  }
8764 8765  
8765 8766                  case fwdMode: {
8766 8767                          bridge_listfwd_t *blf;
8767 8768                          uint_t i, nfwd;
8768 8769  
8769 8770                          blf = dladm_bridge_get_fwdtable(handle, brstate.bridge,
8770 8771                              &nfwd);
8771 8772                          if (blf == NULL) {
8772 8773                                  die("unable to get forwarding entries for "
8773 8774                                      "bridge %s", brstate.bridge);
8774 8775                          } else {
8775 8776                                  for (i = 0; i < nfwd; i++)
8776 8777                                          show_bridge_fwd(handle, blf + i,
8777 8778                                              &brstate.state);
8778 8779                                  dladm_bridge_free_fwdtable(blf);
8779 8780                          }
8780 8781                          break;
8781 8782                  }
8782 8783  
8783 8784                  case trillMode: {
8784 8785                          trill_listnick_t *tln;
8785 8786                          uint_t i, nnick;
8786 8787  
8787 8788                          tln = dladm_bridge_get_trillnick(brstate.bridge,
8788 8789                              &nnick);
8789 8790                          if (tln == NULL) {
8790 8791                                  if (errno == ENOENT)
8791 8792                                          die("bridge %s is not running TRILL",
8792 8793                                              brstate.bridge);
8793 8794                                  else
8794 8795                                          die("unable to get TRILL nickname "
8795 8796                                              "entries for bridge %s",
8796 8797                                              brstate.bridge);
8797 8798                          } else {
8798 8799                                  for (i = 0; i < nnick; i++)
8799 8800                                          show_bridge_trillnick(tln + i,
8800 8801                                              &brstate.state);
8801 8802                                  dladm_bridge_free_trillnick(tln);
8802 8803                          }
8803 8804                          break;
8804 8805                  }
8805 8806                  }
8806 8807                  if (interval == 0)
8807 8808                          break;
8808 8809                  (void) sleep(interval);
8809 8810          }
8810 8811  }
8811 8812  
8812 8813  /*
8813 8814   * "-R" option support. It is used for live upgrading. Append dladm commands
8814 8815   * to a upgrade script which will be run when the alternative root boots up:
8815 8816   *
8816 8817   * - If the /etc/dladm/datalink.conf file exists on the alternative root,
8817 8818   * append dladm commands to the <altroot>/var/svc/profile/upgrade_datalink
8818 8819   * script. This script will be run as part of the network/physical service.
8819 8820   * We cannot defer this to /var/svc/profile/upgrade because then the
8820 8821   * configuration will not be able to take effect before network/physical
8821 8822   * plumbs various interfaces.
8822 8823   *
8823 8824   * - If the /etc/dladm/datalink.conf file does not exist on the alternative
8824 8825   * root, append dladm commands to the <altroot>/var/svc/profile/upgrade script,
8825 8826   * which will be run in the manifest-import service.
8826 8827   *
8827 8828   * Note that the SMF team is considering to move the manifest-import service
8828 8829   * to be run at the very begining of boot. Once that is done, the need for
8829 8830   * the /var/svc/profile/upgrade_datalink script will not exist any more.
8830 8831   */
8831 8832  static void
8832 8833  altroot_cmd(char *altroot, int argc, char *argv[])
8833 8834  {
8834 8835          char            path[MAXPATHLEN];
8835 8836          struct stat     stbuf;
8836 8837          FILE            *fp;
8837 8838          int             i;
8838 8839  
8839 8840          /*
8840 8841           * Check for the existence of the /etc/dladm/datalink.conf
8841 8842           * configuration file, and determine the name of script file.
8842 8843           */
8843 8844          (void) snprintf(path, MAXPATHLEN, "/%s/etc/dladm/datalink.conf",
8844 8845              altroot);
8845 8846          if (stat(path, &stbuf) < 0) {
8846 8847                  (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot,
8847 8848                      SMF_UPGRADE_FILE);
8848 8849          } else {
8849 8850                  (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot,
8850 8851                      SMF_UPGRADEDATALINK_FILE);
8851 8852          }
8852 8853  
8853 8854          if ((fp = fopen(path, "a+")) == NULL)
8854 8855                  die("operation not supported on %s", altroot);
8855 8856  
8856 8857          (void) fprintf(fp, "/sbin/dladm ");
8857 8858          for (i = 0; i < argc; i++) {
8858 8859                  /*
8859 8860                   * Directly write to the file if it is not the "-R <altroot>"
8860 8861                   * option. In which case, skip it.
8861 8862                   */
8862 8863                  if (strcmp(argv[i], "-R") != 0)
8863 8864                          (void) fprintf(fp, "%s ", argv[i]);
8864 8865                  else
8865 8866                          i ++;
8866 8867          }
8867 8868          (void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG);
8868 8869          (void) fclose(fp);
8869 8870          dladm_close(handle);
8870 8871          exit(EXIT_SUCCESS);
8871 8872  }
8872 8873  
8873 8874  /*
8874 8875   * Convert the string to an integer. Note that the string must not have any
8875 8876   * trailing non-integer characters.
8876 8877   */
8877 8878  static boolean_t
8878 8879  str2int(const char *str, int *valp)
8879 8880  {
8880 8881          int     val;
8881 8882          char    *endp = NULL;
8882 8883  
8883 8884          errno = 0;
8884 8885          val = strtol(str, &endp, 10);
8885 8886          if (errno != 0 || *endp != '\0')
8886 8887                  return (B_FALSE);
8887 8888  
8888 8889          *valp = val;
8889 8890          return (B_TRUE);
8890 8891  }
8891 8892  
8892 8893  /* PRINTFLIKE1 */
8893 8894  static void
8894 8895  warn(const char *format, ...)
8895 8896  {
8896 8897          va_list alist;
8897 8898  
8898 8899          format = gettext(format);
8899 8900          (void) fprintf(stderr, "%s: warning: ", progname);
8900 8901  
8901 8902          va_start(alist, format);
8902 8903          (void) vfprintf(stderr, format, alist);
8903 8904          va_end(alist);
8904 8905  
8905 8906          (void) putc('\n', stderr);
8906 8907  }
8907 8908  
8908 8909  /* PRINTFLIKE2 */
8909 8910  static void
8910 8911  warn_dlerr(dladm_status_t err, const char *format, ...)
8911 8912  {
8912 8913          va_list alist;
8913 8914          char    errmsg[DLADM_STRSIZE];
8914 8915  
8915 8916          format = gettext(format);
8916 8917          (void) fprintf(stderr, gettext("%s: warning: "), progname);
8917 8918  
8918 8919          va_start(alist, format);
8919 8920          (void) vfprintf(stderr, format, alist);
8920 8921          va_end(alist);
8921 8922          (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
8922 8923  }
8923 8924  
8924 8925  /*
8925 8926   * Also closes the dladm handle if it is not NULL.
8926 8927   */
8927 8928  /* PRINTFLIKE2 */
8928 8929  static void
8929 8930  die_dlerr(dladm_status_t err, const char *format, ...)
8930 8931  {
8931 8932          va_list alist;
8932 8933          char    errmsg[DLADM_STRSIZE];
8933 8934  
8934 8935          format = gettext(format);
8935 8936          (void) fprintf(stderr, "%s: ", progname);
8936 8937  
8937 8938          va_start(alist, format);
8938 8939          (void) vfprintf(stderr, format, alist);
8939 8940          va_end(alist);
8940 8941          (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
8941 8942  
8942 8943          /* close dladm handle if it was opened */
8943 8944          if (handle != NULL)
8944 8945                  dladm_close(handle);
8945 8946  
8946 8947          exit(EXIT_FAILURE);
8947 8948  }
8948 8949  
8949 8950  /* PRINTFLIKE1 */
8950 8951  static void
8951 8952  die(const char *format, ...)
8952 8953  {
8953 8954          va_list alist;
8954 8955  
8955 8956          format = gettext(format);
8956 8957          (void) fprintf(stderr, "%s: ", progname);
8957 8958  
8958 8959          va_start(alist, format);
8959 8960          (void) vfprintf(stderr, format, alist);
8960 8961          va_end(alist);
8961 8962  
8962 8963          (void) putc('\n', stderr);
8963 8964  
8964 8965          /* close dladm handle if it was opened */
8965 8966          if (handle != NULL)
8966 8967                  dladm_close(handle);
8967 8968  
8968 8969          exit(EXIT_FAILURE);
8969 8970  }
8970 8971  
8971 8972  static void
8972 8973  die_optdup(int opt)
8973 8974  {
8974 8975          die("the option -%c cannot be specified more than once", opt);
8975 8976  }
8976 8977  
8977 8978  static void
8978 8979  die_opterr(int opt, int opterr, const char *usage)
8979 8980  {
8980 8981          switch (opterr) {
8981 8982          case ':':
8982 8983                  die("option '-%c' requires a value\nusage: %s", opt,
8983 8984                      gettext(usage));
8984 8985                  break;
8985 8986          case '?':
8986 8987          default:
8987 8988                  die("unrecognized option '-%c'\nusage: %s", opt,
8988 8989                      gettext(usage));
8989 8990                  break;
8990 8991          }
8991 8992  }
8992 8993  
8993 8994  static void
8994 8995  show_ether_xprop(void *arg, dladm_ether_info_t *eattr)
8995 8996  {
8996 8997          print_ether_state_t     *statep = arg;
8997 8998          ether_fields_buf_t      ebuf;
8998 8999          int                     i;
8999 9000  
9000 9001          for (i = CAPABLE; i <= PEERADV; i++)  {
9001 9002                  bzero(&ebuf, sizeof (ebuf));
9002 9003                  (void) strlcpy(ebuf.eth_ptype, ptype[i],
9003 9004                      sizeof (ebuf.eth_ptype));
9004 9005                  (void) dladm_ether_autoneg2str(ebuf.eth_autoneg,
9005 9006                      sizeof (ebuf.eth_autoneg), eattr, i);
9006 9007                  (void) dladm_ether_spdx2str(ebuf.eth_spdx,
9007 9008                      sizeof (ebuf.eth_spdx), eattr, i);
9008 9009                  (void) dladm_ether_pause2str(ebuf.eth_pause,
9009 9010                      sizeof (ebuf.eth_pause), eattr, i);
9010 9011                  (void) strlcpy(ebuf.eth_rem_fault,
9011 9012                      (eattr->lei_attr[i].le_fault ? "fault" : "none"),
9012 9013                      sizeof (ebuf.eth_rem_fault));
9013 9014                  ofmt_print(statep->es_ofmt, &ebuf);
9014 9015          }
9015 9016  
9016 9017  }
9017 9018  
9018 9019  static boolean_t
9019 9020  link_is_ether(const char *link, datalink_id_t *linkid)
9020 9021  {
9021 9022          uint32_t media;
9022 9023          datalink_class_t class;
9023 9024  
9024 9025          if (dladm_name2info(handle, link, linkid, NULL, &class, &media) ==
9025 9026              DLADM_STATUS_OK) {
9026 9027                  if (class == DATALINK_CLASS_PHYS && media == DL_ETHER)
9027 9028                          return (B_TRUE);
9028 9029          }
9029 9030          return (B_FALSE);
9030 9031  }
9031 9032  
9032 9033  /*
9033 9034   * default output callback function that, when invoked,
9034 9035   * prints string which is offset by ofmt_arg->ofmt_id within buf.
9035 9036   */
9036 9037  static boolean_t
9037 9038  print_default_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
9038 9039  {
9039 9040          char *value;
9040 9041  
9041 9042          value = (char *)ofarg->ofmt_cbarg + ofarg->ofmt_id;
9042 9043          (void) strlcpy(buf, value, bufsize);
9043 9044          return (B_TRUE);
9044 9045  }
9045 9046  
9046 9047  /*
9047 9048   * Called from the walker dladm_walk_datalink_id() for each IB partition to
9048 9049   * display IB partition specific information.
9049 9050   */
9050 9051  static dladm_status_t
9051 9052  print_part(show_part_state_t *state, datalink_id_t linkid)
9052 9053  {
9053 9054          dladm_part_attr_t       attr;
9054 9055          dladm_status_t          status;
9055 9056          dladm_conf_t            conf;
9056 9057          char                    part_over[MAXLINKNAMELEN];
9057 9058          char                    part_name[MAXLINKNAMELEN];
9058 9059          part_fields_buf_t       pbuf;
9059 9060          boolean_t               force_in_conf = B_FALSE;
9060 9061  
9061 9062          /*
9062 9063           * Get the information about the IB partition from the partition
9063 9064           * datlink ID 'linkid'.
9064 9065           */
9065 9066          if ((status = dladm_part_info(handle, linkid, &attr, state->ps_flags))
9066 9067              != DLADM_STATUS_OK)
9067 9068                  return (status);
9068 9069  
9069 9070          /*
9070 9071           * If an IB Phys link name was provided on the command line we have
9071 9072           * the Phys link's datalink ID in the ps_over_id field of the state
9072 9073           * structure. Proceed only if the IB partition represented by 'linkid'
9073 9074           * was created over Phys link denoted by ps_over_id. The
9074 9075           * 'dia_physlinkid' field of dladm_part_attr_t represents the IB Phys
9075 9076           * link over which the partition was created.
9076 9077           */
9077 9078          if (state->ps_over_id != DATALINK_ALL_LINKID)
9078 9079                  if (state->ps_over_id != attr.dia_physlinkid)
9079 9080                          return (DLADM_STATUS_OK);
9080 9081  
9081 9082          /*
9082 9083           * The linkid argument passed to this function is the datalink ID
9083 9084           * of the IB Partition. Get the partitions name from this linkid.
9084 9085           */
9085 9086          if (dladm_datalink_id2info(handle, linkid, NULL, NULL,
9086 9087              NULL, part_name, sizeof (part_name)) != DLADM_STATUS_OK)
9087 9088                  return (DLADM_STATUS_BADARG);
9088 9089  
9089 9090          bzero(part_over, sizeof (part_over));
9090 9091  
9091 9092          /*
9092 9093           * The 'dia_physlinkid' field contains the datalink ID of the IB Phys
9093 9094           * link over which the partition was created. Use this linkid to get the
9094 9095           * linkover field.
9095 9096           */
9096 9097          if (dladm_datalink_id2info(handle, attr.dia_physlinkid, NULL, NULL,
9097 9098              NULL, part_over, sizeof (part_over)) != DLADM_STATUS_OK)
9098 9099                  (void) sprintf(part_over, "?");
9099 9100          state->ps_found = B_TRUE;
9100 9101  
9101 9102          /*
9102 9103           * Read the FFORCE field from this datalink's persistent configuration
9103 9104           * database line to determine if this datalink was created forcibly.
9104 9105           * If this datalink is a temporary datalink, then it will not have an
9105 9106           * entry in the persistent configuration, so check if force create flag
9106 9107           * is set in the partition attributes.
9107 9108           *
9108 9109           * We need this two level check since persistent partitions brought up
9109 9110           * by up-part during boot will have force create flag always set, since
9110 9111           * we want up-part to always succeed even if the port is currently down
9111 9112           * or P_Key is not yet available in the subnet.
9112 9113           */
9113 9114          if ((status = dladm_getsnap_conf(handle, linkid, &conf)) ==
9114 9115              DLADM_STATUS_OK) {
9115 9116                  (void) dladm_get_conf_field(handle, conf, FFORCE,
9116 9117                      &force_in_conf, sizeof (boolean_t));
9117 9118                  dladm_destroy_conf(handle, conf);
9118 9119          } else if (status == DLADM_STATUS_NOTFOUND) {
9119 9120                  /*
9120 9121                   * for a temp link the force create flag will determine
9121 9122                   * whether it was created with force flag.
9122 9123                   */
9123 9124                  force_in_conf = ((attr.dia_flags & DLADM_PART_FORCE_CREATE)
9124 9125                      != 0);
9125 9126          }
9126 9127  
9127 9128          (void) snprintf(pbuf.part_link, sizeof (pbuf.part_link),
9128 9129              "%s", part_name);
9129 9130  
9130 9131          (void) snprintf(pbuf.part_over, sizeof (pbuf.part_over),
9131 9132              "%s", part_over);
9132 9133  
9133 9134          (void) snprintf(pbuf.part_pkey, sizeof (pbuf.part_pkey),
9134 9135              "%X", attr.dia_pkey);
9135 9136  
9136 9137          (void) get_linkstate(pbuf.part_link, B_TRUE, pbuf.part_state);
9137 9138  
9138 9139          (void) snprintf(pbuf.part_flags, sizeof (pbuf.part_flags),
9139 9140              "%c----", force_in_conf ? 'f' : '-');
9140 9141  
9141 9142          ofmt_print(state->ps_ofmt, &pbuf);
9142 9143  
9143 9144          return (DLADM_STATUS_OK);
9144 9145  }
9145 9146  
9146 9147  /* ARGSUSED */
9147 9148  static int
9148 9149  show_part(dladm_handle_t dh, datalink_id_t linkid, void *arg)
9149 9150  {
9150 9151          ((show_part_state_t *)arg)->ps_status = print_part(arg, linkid);
9151 9152          return (DLADM_WALK_CONTINUE);
9152 9153  }
9153 9154  
9154 9155  /*
9155 9156   * Show the information about the IB partition objects.
9156 9157   */
9157 9158  static void
9158 9159  do_show_part(int argc, char *argv[], const char *use)
9159 9160  {
9160 9161          int                     option;
9161 9162          boolean_t               l_arg = B_FALSE;
9162 9163          uint32_t                flags = DLADM_OPT_ACTIVE;
9163 9164          datalink_id_t           linkid = DATALINK_ALL_LINKID;
9164 9165          datalink_id_t           over_linkid = DATALINK_ALL_LINKID;
9165 9166          char                    over_link[MAXLINKNAMELEN];
9166 9167          show_part_state_t       state;
9167 9168          dladm_status_t          status;
9168 9169          boolean_t               o_arg = B_FALSE;
9169 9170          char                    *fields_str = NULL;
9170 9171          ofmt_handle_t           ofmt;
9171 9172          ofmt_status_t           oferr;
9172 9173          uint_t                  ofmtflags = 0;
9173 9174  
9174 9175          bzero(&state, sizeof (state));
9175 9176          opterr = 0;
9176 9177          while ((option = getopt_long(argc, argv, ":pPl:o:", show_part_lopts,
9177 9178              NULL)) != -1) {
9178 9179                  switch (option) {
9179 9180                  case 'p':
9180 9181                          state.ps_parsable = B_TRUE;
9181 9182                          break;
9182 9183                  case 'P':
9183 9184                          flags = DLADM_OPT_PERSIST;
9184 9185                          break;
9185 9186                  case 'l':
9186 9187                          /*
9187 9188                           * The data link ID of the IB Phys link. When this
9188 9189                           * argument is provided we list only the partition
9189 9190                           * objects created over this IB Phys link.
9190 9191                           */
9191 9192                          if (strlcpy(over_link, optarg, MAXLINKNAMELEN) >=
9192 9193                              MAXLINKNAMELEN)
9193 9194                                  die("link name too long");
9194 9195  
9195 9196                          l_arg = B_TRUE;
9196 9197                          break;
9197 9198                  case 'o':
9198 9199                          o_arg = B_TRUE;
9199 9200                          fields_str = optarg;
9200 9201                          break;
9201 9202                  default:
9202 9203                          die_opterr(optopt, option, use);
9203 9204                  }
9204 9205          }
9205 9206  
9206 9207          /*
9207 9208           * Get the partition ID (optional last argument).
9208 9209           */
9209 9210          if (optind == (argc - 1)) {
9210 9211                  status = dladm_name2info(handle, argv[optind], &linkid, NULL,
9211 9212                      NULL, NULL);
9212 9213                  if (status != DLADM_STATUS_OK) {
9213 9214                          die_dlerr(status, "invalid partition link name '%s'",
9214 9215                              argv[optind]);
9215 9216                  }
9216 9217                  (void) strlcpy(state.ps_part, argv[optind], MAXLINKNAMELEN);
9217 9218          } else if (optind != argc) {
9218 9219                  usage();
9219 9220          }
9220 9221  
9221 9222          if (state.ps_parsable && !o_arg)
9222 9223                  die("-p requires -o");
9223 9224  
9224 9225          /*
9225 9226           * If an IB Phys link name was provided as an argument, then get its
9226 9227           * datalink ID.
9227 9228           */
9228 9229          if (l_arg) {
9229 9230                  status = dladm_name2info(handle, over_link, &over_linkid, NULL,
9230 9231                      NULL, NULL);
9231 9232                  if (status != DLADM_STATUS_OK) {
9232 9233                          die_dlerr(status, "invalid link name '%s'", over_link);
9233 9234                  }
9234 9235          }
9235 9236  
9236 9237          state.ps_over_id = over_linkid; /* IB Phys link ID */
9237 9238          state.ps_found = B_FALSE;
9238 9239          state.ps_flags = flags;
9239 9240  
9240 9241          if (state.ps_parsable)
9241 9242                  ofmtflags |= OFMT_PARSABLE;
9242 9243          oferr = ofmt_open(fields_str, part_fields, ofmtflags, 0, &ofmt);
9243 9244          ofmt_check(oferr, state.ps_parsable, ofmt, die, warn);
9244 9245          state.ps_ofmt = ofmt;
9245 9246  
9246 9247          /*
9247 9248           * If a specific IB partition name was not provided as an argument,
9248 9249           * walk all the datalinks and display the information for all
9249 9250           * IB partitions. If IB Phys link was provided limit it to only
9250 9251           * IB partitions created over that IB Phys link.
9251 9252           */
9252 9253          if (linkid == DATALINK_ALL_LINKID) {
9253 9254                  (void) dladm_walk_datalink_id(show_part, handle, &state,
9254 9255                      DATALINK_CLASS_PART, DATALINK_ANY_MEDIATYPE, flags);
9255 9256          } else {
9256 9257                  (void) show_part(handle, linkid, &state);
9257 9258                  if (state.ps_status != DLADM_STATUS_OK) {
9258 9259                          ofmt_close(ofmt);
9259 9260                          die_dlerr(state.ps_status, "failed to show IB partition"
9260 9261                              " '%s'", state.ps_part);
9261 9262                  }
9262 9263          }
9263 9264          ofmt_close(ofmt);
9264 9265  }
9265 9266  
9266 9267  
9267 9268  /*
9268 9269   * Called from the walker dladm_walk_datalink_id() for each IB Phys link to
9269 9270   * display IB specific information for these Phys links.
9270 9271   */
9271 9272  static dladm_status_t
9272 9273  print_ib(show_ib_state_t *state, datalink_id_t phys_linkid)
9273 9274  {
9274 9275          dladm_ib_attr_t         attr;
9275 9276          dladm_status_t          status;
9276 9277          char                    linkname[MAXLINKNAMELEN];
9277 9278          char                    pkeystr[MAXPKEYLEN];
9278 9279          int                     i;
9279 9280          ib_fields_buf_t         ibuf;
9280 9281  
9281 9282          bzero(&attr, sizeof (attr));
9282 9283  
9283 9284          /*
9284 9285           * Get the attributes of the IB Phys link from active/Persistent config
9285 9286           * based on the flag passed.
9286 9287           */
9287 9288          if ((status = dladm_ib_info(handle, phys_linkid, &attr,
9288 9289              state->is_flags)) != DLADM_STATUS_OK)
9289 9290                  return (status);
9290 9291  
9291 9292          if ((state->is_link_id != DATALINK_ALL_LINKID) && (state->is_link_id
9292 9293              != attr.dia_physlinkid)) {
9293 9294                  dladm_free_ib_info(&attr);
9294 9295                  return (DLADM_STATUS_OK);
9295 9296          }
9296 9297  
9297 9298          /*
9298 9299           * Get the data link name for the phys_linkid. If we are doing show-ib
9299 9300           * for all IB Phys links, we have only the datalink IDs not the
9300 9301           * datalink name.
9301 9302           */
9302 9303          if (dladm_datalink_id2info(handle, phys_linkid, NULL, NULL, NULL,
9303 9304              linkname, MAXLINKNAMELEN) != DLADM_STATUS_OK)
9304 9305                  return (status);
9305 9306  
9306 9307          (void) snprintf(ibuf.ib_link, sizeof (ibuf.ib_link),
9307 9308              "%s", linkname);
9308 9309  
9309 9310          (void) snprintf(ibuf.ib_portnum, sizeof (ibuf.ib_portnum),
9310 9311              "%d", attr.dia_portnum);
9311 9312  
9312 9313          (void) snprintf(ibuf.ib_hcaguid, sizeof (ibuf.ib_hcaguid),
9313 9314              "%llX", attr.dia_hca_guid);
9314 9315  
9315 9316          (void) snprintf(ibuf.ib_portguid, sizeof (ibuf.ib_portguid),
9316 9317              "%llX", attr.dia_port_guid);
9317 9318  
9318 9319          (void) get_linkstate(linkname, B_TRUE, ibuf.ib_state);
9319 9320  
9320 9321          /*
9321 9322           * Create a comma separated list of pkeys from the pkey table returned
9322 9323           * by the IP over IB driver instance.
9323 9324           */
9324 9325          bzero(ibuf.ib_pkeys, attr.dia_port_pkey_tbl_sz * sizeof (ib_pkey_t));
9325 9326          for (i = 0; i < attr.dia_port_pkey_tbl_sz; i++) {
9326 9327                  if (attr.dia_port_pkeys[i] != IB_PKEY_INVALID_FULL &&
9327 9328                      attr.dia_port_pkeys[i] != IB_PKEY_INVALID_LIMITED) {
9328 9329                          if (i == 0)
9329 9330                                  (void) snprintf(pkeystr, MAXPKEYLEN, "%X",
9330 9331                                      attr.dia_port_pkeys[i]);
9331 9332                          else
9332 9333                                  (void) snprintf(pkeystr, MAXPKEYLEN, ",%X",
9333 9334                                      attr.dia_port_pkeys[i]);
9334 9335                          (void) strlcat(ibuf.ib_pkeys, pkeystr, MAXPKEYSTRSZ);
9335 9336                  }
9336 9337          }
9337 9338  
9338 9339          dladm_free_ib_info(&attr);
9339 9340  
9340 9341          ofmt_print(state->is_ofmt, &ibuf);
9341 9342  
9342 9343          return (DLADM_STATUS_OK);
9343 9344  }
9344 9345  
9345 9346  /* ARGSUSED */
9346 9347  static int
9347 9348  show_ib(dladm_handle_t dh, datalink_id_t linkid, void *arg)
9348 9349  {
9349 9350          ((show_ib_state_t *)arg)->is_status = print_ib(arg, linkid);
9350 9351          return (DLADM_WALK_CONTINUE);
9351 9352  }
9352 9353  
9353 9354  /*
9354 9355   * Show the properties of one/all IB Phys links. This is different from
9355 9356   * show-phys command since this will display IB specific information about the
9356 9357   * Phys link like, HCA GUID, PORT GUID, PKEYS active for this port etc.
9357 9358   */
9358 9359  static void
9359 9360  do_show_ib(int argc, char *argv[], const char *use)
9360 9361  {
9361 9362          int                     option;
9362 9363          uint32_t                flags = DLADM_OPT_ACTIVE;
9363 9364          datalink_id_t           linkid = DATALINK_ALL_LINKID;
9364 9365          show_ib_state_t         state;
9365 9366          dladm_status_t          status;
9366 9367          boolean_t               o_arg = B_FALSE;
9367 9368          char                    *fields_str = NULL;
9368 9369          ofmt_handle_t           ofmt;
9369 9370          ofmt_status_t           oferr;
9370 9371          uint_t                  ofmtflags = 0;
9371 9372  
9372 9373          bzero(&state, sizeof (state));
9373 9374          opterr = 0;
9374 9375          while ((option = getopt_long(argc, argv, ":po:", show_lopts,
9375 9376              NULL)) != -1) {
9376 9377                  switch (option) {
9377 9378                  case 'p':
9378 9379                          state.is_parsable = B_TRUE;
9379 9380                          break;
9380 9381                  case 'o':
9381 9382                          o_arg = B_TRUE;
9382 9383                          fields_str = optarg;
9383 9384                          break;
9384 9385                  default:
9385 9386                          die_opterr(optopt, option, use);
9386 9387                  }
9387 9388          }
9388 9389  
9389 9390          /* get IB Phys link ID (optional last argument) */
9390 9391          if (optind == (argc - 1)) {
9391 9392                  status = dladm_name2info(handle, argv[optind], &linkid, NULL,
9392 9393                      NULL, NULL);
9393 9394                  if (status != DLADM_STATUS_OK) {
9394 9395                          die_dlerr(status, "invalid IB port name '%s'",
9395 9396                              argv[optind]);
9396 9397                  }
9397 9398                  (void) strlcpy(state.is_link, argv[optind], MAXLINKNAMELEN);
9398 9399          } else if (optind != argc) {
9399 9400                  usage();
9400 9401          }
9401 9402  
9402 9403          if (state.is_parsable && !o_arg)
9403 9404                  die("-p requires -o");
9404 9405  
9405 9406          /*
9406 9407           * linkid is the data link ID of the IB Phys link. By default it will
9407 9408           * be DATALINK_ALL_LINKID.
9408 9409           */
9409 9410          state.is_link_id = linkid;
9410 9411          state.is_flags = flags;
9411 9412  
9412 9413          if (state.is_parsable)
9413 9414                  ofmtflags |= OFMT_PARSABLE;
9414 9415          oferr = ofmt_open(fields_str, ib_fields, ofmtflags, 0, &ofmt);
9415 9416          ofmt_check(oferr, state.is_parsable, ofmt, die, warn);
9416 9417          state.is_ofmt = ofmt;
9417 9418  
9418 9419          /*
9419 9420           * If we are going to display the information for all IB Phys links
9420 9421           * then we'll walk through all the datalinks for datalinks of Phys
9421 9422           * class and media type IB.
9422 9423           */
9423 9424          if (linkid == DATALINK_ALL_LINKID) {
9424 9425                  (void) dladm_walk_datalink_id(show_ib, handle, &state,
9425 9426                      DATALINK_CLASS_PHYS, DL_IB, flags);
9426 9427          } else {
9427 9428                  /*
9428 9429                   * We need to display the information only for the IB phys link
9429 9430                   * linkid. Call show_ib for this link.
9430 9431                   */
9431 9432                  (void) show_ib(handle, linkid, &state);
9432 9433                  if (state.is_status != DLADM_STATUS_OK) {
9433 9434                          ofmt_close(ofmt);
9434 9435                          die_dlerr(state.is_status, "failed to show IB Phys link"
9435 9436                              " '%s'", state.is_link);
9436 9437                  }
9437 9438          }
9438 9439          ofmt_close(ofmt);
9439 9440  }
9440 9441  
9441 9442  /*
9442 9443   * Create an IP over Infiniband partition object over an IB Phys link. The IB
9443 9444   * Phys link is associated with an Infiniband HCA port. The IB partition object
9444 9445   * is created over a port, pkey combination. This partition object represents
9445 9446   * an instance of IP over IB interface.
9446 9447   */
9447 9448  /* ARGSUSED */
9448 9449  static void
9449 9450  do_create_part(int argc, char *argv[], const char *use)
9450 9451  {
9451 9452          int             status, option;
9452 9453          int             flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
9453 9454          char            *pname;
9454 9455          char            *l_arg = NULL;
9455 9456          char            *altroot = NULL;
9456 9457          datalink_id_t   physlinkid = 0;
9457 9458          datalink_id_t   partlinkid = 0;
9458 9459          unsigned long   opt_pkey;
9459 9460          ib_pkey_t       pkey = 0;
9460 9461          char            *endp = NULL;
9461 9462          char            propstr[DLADM_STRSIZE];
9462 9463          dladm_arg_list_t        *proplist = NULL;
9463 9464  
9464 9465          propstr[0] = '\0';
9465 9466          while ((option = getopt_long(argc, argv, ":tfl:P:R:p:",
9466 9467              part_lopts, NULL)) != -1) {
9467 9468                  switch (option) {
9468 9469                  case 't':
9469 9470                          /*
9470 9471                           * Create a temporary IB partition object. This
9471 9472                           * instance is not entered into the persistent database
9472 9473                           * so it will not be recreated automatically on a
9473 9474                           * reboot.
9474 9475                           */
9475 9476                          flags &= ~DLADM_OPT_PERSIST;
9476 9477                          break;
9477 9478                  case 'l':
9478 9479                          /*
9479 9480                           * The IB phys link over which the partition object will
9480 9481                           * be created.
9481 9482                           */
9482 9483                          l_arg = optarg;
9483 9484                          break;
9484 9485                  case 'R':
9485 9486                          altroot = optarg;
9486 9487                          break;
9487 9488                  case 'p':
9488 9489                          (void) strlcat(propstr, optarg, DLADM_STRSIZE);
9489 9490                          if (strlcat(propstr, ",", DLADM_STRSIZE) >=
9490 9491                              DLADM_STRSIZE)
9491 9492                                  die("property list too long '%s'", propstr);
9492 9493                          break;
9493 9494                  case 'P':
9494 9495                          /*
9495 9496                           * The P_Key for the port, pkey tuple of the partition
9496 9497                           * object. This P_Key should exist in the IB subnet.
9497 9498                           * The partition creation for a non-existent P_Key will
9498 9499                           * fail unless the -f option is used.
9499 9500                           *
9500 9501                           * The P_Key is expected to be a hexadecimal number.
9501 9502                           */
9502 9503                          opt_pkey = strtoul(optarg, &endp, 16);
9503 9504                          if (errno == ERANGE || opt_pkey > USHRT_MAX ||
9504 9505                              *endp != '\0')
9505 9506                                  die("Invalid pkey");
9506 9507  
9507 9508                          pkey = (ib_pkey_t)opt_pkey;
9508 9509                          break;
9509 9510                  case 'f':
9510 9511                          flags |= DLADM_OPT_FORCE;
9511 9512                          break;
9512 9513                  default:
9513 9514                          die_opterr(optopt, option, use);
9514 9515                          break;
9515 9516                  }
9516 9517          }
9517 9518  
9518 9519          /* check required options */
9519 9520          if (!l_arg)
9520 9521                  usage();
9521 9522  
9522 9523          /* the partition name is a required operand */
9523 9524          if (optind != (argc - 1))
9524 9525                  usage();
9525 9526  
9526 9527          pname = argv[argc - 1];
9527 9528  
9528 9529          /*
9529 9530           * Verify that the partition object's name is in the valid link name
9530 9531           * format.
9531 9532           */
9532 9533          if (!dladm_valid_linkname(pname))
9533 9534                  die("Invalid link name '%s'", pname);
9534 9535  
9535 9536          /* pkey is a mandatory argument */
9536 9537          if (pkey == 0)
9537 9538                  usage();
9538 9539  
9539 9540          if (altroot != NULL)
9540 9541                  altroot_cmd(altroot, argc, argv);
9541 9542  
9542 9543          /*
9543 9544           * Get the data link id of the IB Phys link over which we will be
9544 9545           * creating partition object.
9545 9546           */
9546 9547          if (dladm_name2info(handle, l_arg,
9547 9548              &physlinkid, NULL, NULL, NULL) != DLADM_STATUS_OK)
9548 9549                  die("invalid link name '%s'", l_arg);
9549 9550  
9550 9551          /*
9551 9552           * parse the property list provided with -p option.
9552 9553           */
9553 9554          if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
9554 9555              != DLADM_STATUS_OK)
9555 9556                  die("invalid IB partition property");
9556 9557  
9557 9558          /*
9558 9559           * Call the library routine to create the partition object.
9559 9560           */
9560 9561          status = dladm_part_create(handle, physlinkid, pkey, flags, pname,
9561 9562              &partlinkid, proplist);
9562 9563          if (status != DLADM_STATUS_OK)
9563 9564                  die_dlerr(status,
9564 9565                      "partition %x creation over %s failed", pkey, l_arg);
9565 9566  }
9566 9567  
9567 9568  /*
9568 9569   * Delete an IP over Infiniband partition object. The partition object should
9569 9570   * be unplumbed before attempting the delete.
9570 9571   */
9571 9572  static void
9572 9573  do_delete_part(int argc, char *argv[], const char *use)
9573 9574  {
9574 9575          int option, flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
9575 9576          int status;
9576 9577          char *altroot = NULL;
9577 9578          datalink_id_t   partid;
9578 9579  
9579 9580          opterr = 0;
9580 9581          while ((option = getopt_long(argc, argv, "R:t", part_lopts,
9581 9582              NULL)) != -1) {
9582 9583                  switch (option) {
9583 9584                  case 't':
9584 9585                          flags &= ~DLADM_OPT_PERSIST;
9585 9586                          break;
9586 9587                  case 'R':
9587 9588                          altroot = optarg;
9588 9589                          break;
9589 9590                  default:
9590 9591                          die_opterr(optopt, option, use);
9591 9592                  }
9592 9593          }
9593 9594  
9594 9595          /* get partition name (required last argument) */
9595 9596          if (optind != (argc - 1))
9596 9597                  usage();
9597 9598  
9598 9599          if (altroot != NULL)
9599 9600                  altroot_cmd(altroot, argc, argv);
9600 9601  
9601 9602          /*
9602 9603           * Get the data link id of the partition object given the partition
9603 9604           * name.
9604 9605           */
9605 9606          status = dladm_name2info(handle, argv[optind], &partid, NULL, NULL,
9606 9607              NULL);
9607 9608          if (status != DLADM_STATUS_OK)
9608 9609                  die("invalid link name '%s'", argv[optind]);
9609 9610  
9610 9611          /*
9611 9612           * Call the library routine to delete the IB partition. This will
9612 9613           * result in the IB partition object and all its resources getting
9613 9614           * deleted.
9614 9615           */
9615 9616          status = dladm_part_delete(handle, partid, flags);
9616 9617          if (status != DLADM_STATUS_OK)
9617 9618                  die_dlerr(status, "%s: partition deletion failed",
9618 9619                      argv[optind]);
9619 9620  }
9620 9621  
9621 9622  /*
9622 9623   * Bring up all or one IB partition already present in the persistent database
9623 9624   * but not active yet.
9624 9625   *
9625 9626   * This sub-command is used during the system boot up to bring up all IB
9626 9627   * partitions present in the persistent database. This is similar to a
9627 9628   * create partition except that, the partitions are always created even if the
9628 9629   * HCA port is down or P_Key is not present in the IB subnet. This is similar
9629 9630   * to using the 'force' option while creating the partition except that the 'f'
9630 9631   * flag will be set in the flags field only if the create-part for this command
9631 9632   * was called with '-f' option.
9632 9633   */
9633 9634  /* ARGSUSED */
9634 9635  static void
9635 9636  do_up_part(int argc, char *argv[], const char *use)
9636 9637  {
9637 9638          datalink_id_t   partid = DATALINK_ALL_LINKID;
9638 9639          dladm_status_t status;
9639 9640  
9640 9641          /*
9641 9642           * If a partition name was passed as an argument, get its data link
9642 9643           * id. By default we'll attempt to bring up all IB partition data
9643 9644           * links.
9644 9645           */
9645 9646          if (argc == 2) {
9646 9647                  status = dladm_name2info(handle, argv[argc - 1], &partid, NULL,
9647 9648                      NULL, NULL);
9648 9649                  if (status != DLADM_STATUS_OK)
9649 9650                          return;
9650 9651          } else if (argc > 2) {
9651 9652                  usage();
9652 9653          }
9653 9654  
9654 9655          (void) dladm_part_up(handle, partid, 0);
9655 9656  }
  
    | 
      ↓ open down ↓ | 
    9558 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX