Print this page
NEX-1785 Add IPMP related subcommands to ipadm(1M) man page
Reviewed by: Dan Fields <dan.fields@nexenta.com>
OS-161: Integrate IPMP changes
        
*** 36,45 ****
--- 36,47 ----
  #include <libdladm.h>
  #include <libdliptun.h>
  #include <libdllink.h>
  #include <libinetutil.h>
  #include <libipadm.h>
+ #include <ipmp.h>
+ #include <ipmp_admin.h>
  #include <locale.h>
  #include <netdb.h>
  #include <netinet/in.h>
  #include <ofmt.h>
  #include <stdarg.h>
*** 49,72 ****
  #include <string.h>
  #include <strings.h>
  #include <sys/stat.h>
  #include <sys/types.h>
  #include <zone.h>
  
  #define STR_UNKNOWN_VAL "?"
  #define LIFC_DEFAULT    (LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES |\
                          LIFC_UNDER_IPMP)
  
  typedef void cmdfunc_t(int, char **, const char *);
! static cmdfunc_t do_create_if, do_delete_if, do_enable_if, do_disable_if;
! static cmdfunc_t do_show_if;
! static cmdfunc_t do_set_prop, do_show_prop, do_set_ifprop;
! static cmdfunc_t do_show_ifprop, do_reset_ifprop, do_reset_prop;
! static cmdfunc_t do_show_addrprop, do_set_addrprop, do_reset_addrprop;
! static cmdfunc_t do_create_addr, do_delete_addr, do_show_addr;
! static cmdfunc_t do_enable_addr, do_disable_addr;
! static cmdfunc_t do_up_addr, do_down_addr, do_refresh_addr;
  
  static void warn(const char *, ...);
  static void die(const char *, ...);
  
  typedef struct  cmd {
--- 51,78 ----
  #include <string.h>
  #include <strings.h>
  #include <sys/stat.h>
  #include <sys/types.h>
  #include <zone.h>
+ #include <sys/list.h>
+ #include <stddef.h>
  
  #define STR_UNKNOWN_VAL "?"
  #define LIFC_DEFAULT    (LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES |\
                          LIFC_UNDER_IPMP)
  
+ static void do_create_ip_common(int, char **, const char *, uint32_t);
+ 
  typedef void cmdfunc_t(int, char **, const char *);
! static cmdfunc_t do_create_ip, do_delete_ip;
! static cmdfunc_t do_create_ipmp, do_add_ipmp, do_remove_ipmp;
! static cmdfunc_t do_disable_if, do_enable_if, do_show_if;
! static cmdfunc_t do_set_ifprop, do_reset_ifprop, do_show_ifprop;
! static cmdfunc_t do_create_addr, do_delete_addr, do_show_addr, do_refresh_addr;
! static cmdfunc_t do_disable_addr, do_enable_addr, do_down_addr, do_up_addr;
! static cmdfunc_t do_set_addrprop, do_reset_addrprop, do_show_addrprop;
! static cmdfunc_t do_set_prop, do_reset_prop, do_show_prop;
  
  static void warn(const char *, ...);
  static void die(const char *, ...);
  
  typedef struct  cmd {
*** 75,90 ****
          const char      *c_usage;
  } cmd_t;
  
  static cmd_t    cmds[] = {
          /* interface management related sub-commands */
!         { "create-if",  do_create_if,   "\tcreate-if\t[-t] <interface>" },
          { "disable-if", do_disable_if,  "\tdisable-if\t-t <interface>"  },
          { "enable-if",  do_enable_if,   "\tenable-if\t-t <interface>"   },
-         { "delete-if",  do_delete_if,   "\tdelete-if\t<interface>"      },
          { "show-if",    do_show_if,
              "\tshow-if\t\t[[-p] -o <field>,...] [<interface>]\n"        },
          { "set-ifprop", do_set_ifprop,
              "\tset-ifprop\t[-t] -p <prop>=<value[,...]> -m <protocol> "
              "<interface>"                                               },
          { "reset-ifprop", do_reset_ifprop,
              "\treset-ifprop\t[-t] -p <prop> -m <protocol> <interface>"  },
--- 81,111 ----
          const char      *c_usage;
  } cmd_t;
  
  static cmd_t    cmds[] = {
          /* interface management related sub-commands */
!         { "create-ip", do_create_ip, "\tcreate-ip\t[-t] <interface>"    },
!         { "create-if", do_create_ip, NULL                               },
!         { "delete-ip", do_delete_ip, "\tdelete-ip\t<interface>\n"       },
!         { "delete-if", do_delete_ip, NULL                               },
! 
!         { "create-ipmp", do_create_ipmp,
!             "\tcreate-ipmp\t[-t] <ipmp-interface>"                      },
!         { "delete-ipmp", do_delete_ip,
!             "\tdelete-ipmp\t<ipmp-interface>"                           },
!         { "add-ipmp", do_add_ipmp,
!             "\tadd-ipmp\t[-t] -i <interface> ... "
!             "<ipmp-interface>"                                          },
!         { "remove-ipmp", do_remove_ipmp,
!             "\tremove-ipmp\t[-t] -i <interface> ... "
!             "<ipmp-interface>\n"                                        },
! 
          { "disable-if", do_disable_if, "\tdisable-if\t-t <interface>"   },
          { "enable-if", do_enable_if, "\tenable-if\t-t <interface>"      },
          { "show-if", do_show_if,
              "\tshow-if\t\t[[-p] -o <field>,...] [<interface>]\n"        },
+ 
          { "set-ifprop", do_set_ifprop,
              "\tset-ifprop\t[-t] -p <prop>=<value[,...]> -m <protocol> "
              "<interface>"                                               },
          { "reset-ifprop", do_reset_ifprop,
              "\treset-ifprop\t[-t] -p <prop> -m <protocol> <interface>"  },
*** 98,115 ****
              "-a{local|remote}=addr[/prefixlen]\n\t\t\t<addrobj>\n"
              "\tcreate-addr\t[-t] -T dhcp [-w <seconds> | forever]\n"
              "\t\t\t[-1] [-h <hostname>] <addrobj>\n"
              "\tcreate-addr\t[-t] -T addrconf [-i interface-id]\n"
              "\t\t\t[-p {stateful|stateless}={yes|no}] <addrobj>" },
          { "down-addr",  do_down_addr,   "\tdown-addr\t[-t] <addrobj>"   },
          { "up-addr",    do_up_addr,     "\tup-addr\t\t[-t] <addrobj>"   },
          { "disable-addr", do_disable_addr, "\tdisable-addr\t-t <addrobj>" },
!         { "enable-addr", do_enable_addr, "\tenable-addr\t-t <addrobj>"  },
!         { "refresh-addr", do_refresh_addr, "\trefresh-addr\t[-i] <addrobj>" },
!         { "delete-addr", do_delete_addr, "\tdelete-addr\t[-r] <addrobj>" },
!         { "show-addr",  do_show_addr,
!             "\tshow-addr\t[[-p] -o <field>,...] [<addrobj>]\n"          },
          { "set-addrprop", do_set_addrprop,
              "\tset-addrprop\t[-t] -p <prop>=<value[,...]> <addrobj>"    },
          { "reset-addrprop", do_reset_addrprop,
              "\treset-addrprop\t[-t] -p <prop> <addrobj>"                },
          { "show-addrprop", do_show_addrprop,
--- 119,137 ----
              "-a{local|remote}=addr[/prefixlen]\n\t\t\t<addrobj>\n"
              "\tcreate-addr\t[-t] -T dhcp [-w <seconds> | forever]\n"
              "\t\t\t[-1] [-h <hostname>] <addrobj>\n"
              "\tcreate-addr\t[-t] -T addrconf [-i interface-id]\n"
              "\t\t\t[-p {stateful|stateless}={yes|no}] <addrobj>" },
+         { "delete-addr", do_delete_addr, "\tdelete-addr\t[-r] <addrobj>" },
+         { "show-addr", do_show_addr,
+             "\tshow-addr\t[[-p] -o <field>,...] [<addrobj>]"            },
+         { "refresh-addr", do_refresh_addr, "\trefresh-addr\t[-i] <addrobj>" },
          { "down-addr", do_down_addr, "\tdown-addr\t[-t] <addrobj>"      },
          { "up-addr", do_up_addr, "\tup-addr\t\t[-t] <addrobj>"  },
          { "disable-addr", do_disable_addr, "\tdisable-addr\t-t <addrobj>" },
!         { "enable-addr", do_enable_addr, "\tenable-addr\t-t <addrobj>\n" },
! 
          { "set-addrprop", do_set_addrprop,
              "\tset-addrprop\t[-t] -p <prop>=<value[,...]> <addrobj>"    },
          { "reset-addrprop", do_reset_addrprop,
              "\treset-addrprop\t[-t] -p <prop> <addrobj>"                },
          { "show-addrprop", do_show_addrprop,
*** 293,302 ****
--- 315,325 ----
          SA_ADDR
  } sa_field_index_t;
  
  typedef enum {
          SI_IFNAME,
+         SI_IFCLASS,
          SI_STATE,
          SI_CURRENT,
          SI_PERSISTENT
  } si_field_index_t;
  
*** 312,321 ****
--- 335,345 ----
  };
  
  static ofmt_field_t show_if_fields[] = {
  /* name,        field width,    id,             callback */
  { "IFNAME",     11,             SI_IFNAME,      print_si_cb},
+ { "CLASS",      10,             SI_IFCLASS,     print_si_cb},
  { "STATE",      9,              SI_STATE,       print_si_cb},
  { "CURRENT",    13,             SI_CURRENT,     print_si_cb},
  { "PERSISTENT", 11,             SI_PERSISTENT,  print_si_cb},
  { NULL,         0,              0,              NULL}
  };
*** 325,334 ****
--- 349,363 ----
          char            *name;
          uint64_t        bits;
          uint64_t        mask;
  } fmask_t;
  
+ typedef enum {
+     IPMP_ADD_MEMBER,
+     IPMP_REMOVE_MEMBER
+ } ipmp_action_t;
+ 
  /*
   * Handle to libipadm. Opened in main() before the sub-command specific
   * function is called and is closed before the program exits.
   */
  ipadm_handle_t  iph = NULL;
*** 344,353 ****
--- 373,383 ----
  static void     die_opterr(int, int, const char *);
  static void     warn_ipadmerr(ipadm_status_t, const char *, ...);
  static void     ipadm_check_propstr(const char *, boolean_t, const char *);
  static void     process_misc_addrargs(int, char **, const char *, int *,
                      uint32_t *);
+ static void     do_action_ipmp(int, char **, const char *, ipmp_action_t);
  
  static void
  usage(void)
  {
          int     i;
*** 406,428 ****
  
          return (0);
  }
  
  /*
!  * Create an IP interface for which no saved configuration exists in the
!  * persistent store.
   */
  static void
! do_create_if(int argc, char *argv[], const char *use)
  {
          ipadm_status_t  status;
          int             option;
-         uint32_t        flags = IPADM_OPT_PERSIST|IPADM_OPT_ACTIVE;
  
          opterr = 0;
!         while ((option = getopt_long(argc, argv, ":t", if_longopts,
!             NULL)) != -1) {
                  switch (option) {
                  case 't':
                          /*
                           * "ifconfig" mode - plumb interface, but do not
                           * restore settings that may exist in db.
--- 436,456 ----
  
          return (0);
  }
  
  /*
!  * Create regular IP interface or IPMP group interface
   */
  static void
! do_create_ip_common(int argc, char *argv[], const char *use, uint32_t flags)
  {
          ipadm_status_t  status;
          int             option;
  
          opterr = 0;
!         while ((option = getopt_long(argc, argv,
!             ":t", if_longopts, NULL)) != -1) {
                  switch (option) {
                  case 't':
                          /*
                           * "ifconfig" mode - plumb interface, but do not
                           * restore settings that may exist in db.
*** 431,450 ****
                          break;
                  default:
                          die_opterr(optopt, option, use);
                  }
          }
!         if (optind != (argc - 1))
!                 die("Usage: %s", use);
          status = ipadm_create_if(iph, argv[optind], AF_UNSPEC, flags);
          if (status != IPADM_SUCCESS) {
                  die("Could not create %s : %s",
                      argv[optind], ipadm_status2str(status));
          }
  }
  
  /*
   * Enable an IP interface based on the persistent configuration for
   * that interface.
   */
  static void
  do_enable_if(int argc, char *argv[], const char *use)
--- 459,600 ----
                          break;
                  default:
                          die_opterr(optopt, option, use);
                  }
          }
!         if (optind != (argc - 1)) {
!                 if (use != NULL)
!                         die("usage: %s", use);
!                 else
!                         die(NULL);
!         }
          status = ipadm_create_if(iph, argv[optind], AF_UNSPEC, flags);
          if (status != IPADM_SUCCESS) {
                  die("Could not create %s : %s",
                      argv[optind], ipadm_status2str(status));
          }
  }
  
  /*
+  * Create an IPMP group interface for which no saved configuration
+  * exists in the persistent store.
+  */
+ static void
+ do_create_ipmp(int argc, char *argv[], const char *use)
+ {
+         ipmp_handle_t ipmp_handle;
+         int retval;
+         uint32_t flags = IPADM_OPT_PERSIST | IPADM_OPT_ACTIVE | IPADM_OPT_IPMP;
+ 
+         retval = ipmp_open(&ipmp_handle);
+         if (retval != IPMP_SUCCESS) {
+                 die("Could not create IPMP handle: %s",
+                     ipadm_status2str(retval));
+         }
+ 
+         retval = ipmp_ping_daemon(ipmp_handle);
+         ipmp_close(ipmp_handle);
+ 
+         if (retval != IPMP_SUCCESS) {
+                 die("Cannot ping in.mpathd: %s", ipmp_errmsg(retval));
+         }
+ 
+         do_create_ip_common(argc, argv, use, flags);
+ }
+ 
+ static void
+ do_add_ipmp(int argc, char *argv[], const char *use)
+ {
+         do_action_ipmp(argc, argv, use, IPMP_ADD_MEMBER);
+ }
+ 
+ static void
+ do_remove_ipmp(int argc, char *argv[], const char *use)
+ {
+         do_action_ipmp(argc, argv, use, IPMP_REMOVE_MEMBER);
+ }
+ 
+ static void
+ do_action_ipmp(int argc, char *argv[], const char *use,
+     ipmp_action_t action)
+ {
+         int     option;
+         ipadm_status_t  status;
+         ipadm_ipmp_members_t members;
+         ipadm_ipmp_member_t *ipmp_member;
+         uint32_t flags = IPADM_OPT_PERSIST | IPADM_OPT_ACTIVE;
+ 
+         list_create(&members, sizeof (ipadm_ipmp_member_t),
+             offsetof(ipadm_ipmp_member_t, node));
+ 
+         opterr = 0;
+         while ((option = getopt_long(argc, argv,
+             ":ti:", if_longopts, NULL)) != -1) {
+                 switch (option) {
+                 case 't':
+                         flags &= ~IPADM_OPT_PERSIST;
+                         break;
+                 case 'i':
+                         if ((ipmp_member = calloc(1,
+                             sizeof (ipadm_ipmp_member_t))) == NULL)
+                                 die("insufficient memory");
+ 
+                         if (strlcpy(ipmp_member->if_name,
+                             optarg, sizeof (ipmp_member->if_name)) >= LIFNAMSIZ)
+                                 die("Incorrect length of interface"
+                                     "name: %s", optarg);
+ 
+                         list_insert_tail(&members, ipmp_member);
+                         break;
+                 default:
+                         die_opterr(optopt, option, use);
+                 }
+         }
+ 
+         if (optind != (argc - 1))
+                 die("Usage: %s", use);
+ 
+         while ((ipmp_member = list_remove_head(&members)) != NULL) {
+                 switch (action) {
+                         case IPMP_ADD_MEMBER:
+                                 if ((status = ipadm_add_ipmp_member(iph,
+                                     argv[optind], ipmp_member->if_name, flags))
+                                     != IPADM_SUCCESS)
+                                         die("Cannot add interface '%s' to "
+                                             "IPMP interface '%s': %s",
+                                             ipmp_member->if_name, argv[optind],
+                                             ipadm_status2str(status));
+                                 break;
+                         case IPMP_REMOVE_MEMBER:
+                                 if ((status = ipadm_remove_ipmp_member(iph,
+                                     argv[optind], ipmp_member->if_name, flags))
+                                     != IPADM_SUCCESS)
+                                         die("Cannot remove interface '%s' from "
+                                             "IPMP interface '%s': %s",
+                                             ipmp_member->if_name, argv[optind],
+                                             ipadm_status2str(status));
+                                 break;
+                 }
+ 
+                 free(ipmp_member);
+         }
+ 
+         list_destroy(&members);
+ }
+ 
+ /*
+  * Create an IP interface for which no saved configuration exists in the
+  * persistent store.
+  */
+ static void
+ do_create_ip(int argc, char *argv[], const char *use)
+ {
+         do_create_ip_common(argc, argv, use,
+             IPADM_OPT_PERSIST | IPADM_OPT_ACTIVE);
+ }
+ 
+ /*
   * Enable an IP interface based on the persistent configuration for
   * that interface.
   */
  static void
  do_enable_if(int argc, char *argv[], const char *use)
*** 467,477 ****
  
  /*
   * Remove an IP interface from both active and persistent configuration.
   */
  static void
! do_delete_if(int argc, char *argv[], const char *use)
  {
          ipadm_status_t  status;
          uint32_t        flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
  
          if (argc != 2)
--- 617,627 ----
  
  /*
   * Remove an IP interface from both active and persistent configuration.
   */
  static void
! do_delete_ip(int argc, char *argv[], const char *use)
  {
          ipadm_status_t  status;
          uint32_t        flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
  
          if (argc != 2)
*** 1042,1059 ****
--- 1192,1211 ----
  static void
  die(const char *format, ...)
  {
          va_list alist;
  
+         if (format != NULL) {
                  format = gettext(format);
                  (void) fprintf(stderr, "%s: ", progname);
  
                  va_start(alist, format);
                  (void) vfprintf(stderr, format, alist);
                  va_end(alist);
  
                  (void) putchar('\n');
+         }
  
          ipadm_destroy_addrobj(ipaddr);
          ipadm_close(iph);
          exit(EXIT_FAILURE);
  }
*** 1919,1934 ****
--- 2071,2097 ----
                  { "Z",  IFIF_L3PROTECT,         IFIF_L3PROTECT  },
                  { "4",  IFIF_IPV4,              IFIF_IPV4       },
                  { "6",  IFIF_IPV6,              IFIF_IPV6       },
                  { NULL, 0,                      0               }
          };
+         fmask_t intf_class[] = {
+                 { "IP",         IPADM_IF_CLASS_REGULAR, IPADM_ALL_BITS},
+                 { "IPMP",       IPADM_IF_CLASS_IPMP,    IPADM_ALL_BITS},
+                 { "VIRTUAL",    IPADM_IF_CLASS_VIRTUAL, IPADM_ALL_BITS},
+                 { "UNKNOWN",    IPADM_IF_CLASS_UNKNOWN, IPADM_ALL_BITS},
+                 { NULL, 0,      0}
+         };
  
          buf[0] = '\0';
          switch (ofarg->ofmt_id) {
          case SI_IFNAME:
                  (void) snprintf(buf, bufsize, "%s", ifname);
                  break;
+         case SI_IFCLASS:
+                 flags2str(ifinfo->ifi_class, intf_class, _B_FALSE,
+                     buf, bufsize);
+                 break;
          case SI_STATE:
                  flags2str(ifinfo->ifi_state, intf_state, _B_FALSE,
                      buf, bufsize);
                  break;
          case SI_CURRENT: