Print this page
Commit IPMP changes

@@ -18,11 +18,11 @@
  *
  * CDDL HEADER END
  */
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
  */
 #include <arpa/inet.h>
 #include <errno.h>
 #include <getopt.h>
 #include <inet/ip.h>

@@ -31,10 +31,12 @@
 #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>

@@ -44,16 +46,21 @@
 #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_if_common(int, char **, const char *, uint32_t);
+
 typedef void cmdfunc_t(int, char **, const char *);
+static cmdfunc_t do_create_ipmp, do_add_ipmp, do_remove_ipmp;
 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;

@@ -67,10 +74,18 @@
         const char      *c_usage;
 } cmd_t;
 
 static cmd_t    cmds[] = {
         /* interface management related sub-commands */
+        { "create-ipmp", do_create_ipmp, "\tcreate-ipmp\t[-t] <ipmp-group>"},
+        { "delete-ipmp", do_delete_if, "\tdelete-ipmp\t[-t] <ipmp-group>"},
+        { "add-ipmp", do_add_ipmp, "\tadd-ipmp\t[-t] -i"
+            " <ipmp-member-interface> "
+            "[-i <ipmp-member-interface>] <ipmp-group-interface>"},
+        { "remove-ipmp", do_remove_ipmp, "\tremove-ipmp\t[-t] -i"
+            " <ipmp-member-interface> "
+            "[-i <ipmp-member-interface>] <ipmp-group-interface>"},
         { "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,

@@ -282,10 +297,11 @@
         SA_ADDR
 } sa_field_index_t;
 
 typedef enum {
         SI_IFNAME,
+        SI_IFCLASS,
         SI_STATE,
         SI_CURRENT,
         SI_PERSISTENT
 } si_field_index_t;
 

@@ -301,10 +317,11 @@
 };
 
 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}
 };

@@ -314,10 +331,15 @@
         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;

@@ -334,10 +356,11 @@
 static void     warn_ipadmerr(ipadm_status_t, const char *, ...);
 static void     ipadm_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t);
 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;

@@ -396,23 +419,21 @@
 
         return (0);
 }
 
 /*
- * Create an IP interface for which no saved configuration exists in the
- * persistent store.
+ * Create regular IP interface or IPMP group interface
  */
 static void
-do_create_if(int argc, char *argv[], const char *use)
+do_create_if_common(int argc, char *argv[], const char *use, uint32_t flags)
 {
         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) {
+        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,10 +452,128 @@
                     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_if_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 '%s' interface to"
+                                            "'%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 '%s' interface from "
+                                            "'%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_if(int argc, char *argv[], const char *use)
+{
+        do_create_if_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)

@@ -1906,16 +2045,27 @@
                 { "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: