Print this page
Commit IPMP changes

@@ -19,10 +19,11 @@
  * CDDL HEADER END
  */
 
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
  */
 
 /*
  * Main door handler functions used by ipmgmtd to process the different door
  * call requests, issued by the library libipadm.so.

@@ -39,10 +40,13 @@
 #include <errno.h>
 #include <assert.h>
 #include <libnvpair.h>
 #include "ipmgmt_impl.h"
 
+
+static void ipmgmt_common_handler(char *, char *, db_wfunc_t *);
+
 /* Handler declaration for each door command */
 typedef void ipmgmt_door_handler_t(void *argp);
 
 static ipmgmt_door_handler_t    ipmgmt_getaddr_handler,
                                 ipmgmt_getprop_handler,

@@ -52,11 +56,12 @@
                                 ipmgmt_resetaddr_handler,
                                 ipmgmt_setif_handler,
                                 ipmgmt_resetif_handler,
                                 ipmgmt_resetprop_handler,
                                 ipmgmt_setaddr_handler,
-                                ipmgmt_setprop_handler;
+                                ipmgmt_setprop_handler,
+                                ipmgmt_ipmp_update_handler;
 
 typedef struct ipmgmt_door_info_s {
         uint_t                  idi_cmd;
         boolean_t               idi_set;
         ipmgmt_door_handler_t   *idi_handler;

@@ -77,10 +82,11 @@
         { IPMGMT_CMD_ADDROBJ_LOOKUPADD, B_TRUE,  ipmgmt_aobjop_handler },
         { IPMGMT_CMD_ADDROBJ_SETLIFNUM, B_TRUE,  ipmgmt_aobjop_handler },
         { IPMGMT_CMD_ADDROBJ_ADD,       B_TRUE,  ipmgmt_aobjop_handler },
         { IPMGMT_CMD_AOBJNAME2ADDROBJ,  B_FALSE, ipmgmt_aobjop_handler },
         { IPMGMT_CMD_LIF2ADDROBJ,       B_FALSE, ipmgmt_aobjop_handler },
+        { IPMGMT_CMD_IPMP_UPDATE,       B_FALSE, ipmgmt_ipmp_update_handler},
         { 0, 0, NULL },
 };
 
 /*
  * The main server procedure function that gets invoked for any of the incoming

@@ -574,10 +580,14 @@
         uint32_t                flags = rargp->ia_flags;
         int                     err = 0;
 
         cbarg.cb_family = rargp->ia_family;
         cbarg.cb_ifname = rargp->ia_ifname;
+
+        cbarg.cb_ipv4exists = B_TRUE;
+        cbarg.cb_ipv6exists = B_TRUE;
+
         if (flags & IPMGMT_PERSIST)
                 err = ipmgmt_db_walk(ipmgmt_db_resetif, &cbarg,
                     IPADM_DB_DELETE);
 
         if (flags & IPMGMT_ACTIVE)

@@ -635,59 +645,14 @@
  * handler through library.
  */
 static void
 ipmgmt_getaddr_handler(void *argp)
 {
-        size_t                  buflen, onvlsize;
-        char                    *buf, *onvlbuf;
         ipmgmt_getaddr_arg_t    *gargp = argp;
-        ipmgmt_getaddr_cbarg_t  cbarg;
-        ipmgmt_get_rval_t       rval, *rvalp = &rval;
-        int                     err = 0;
 
-        cbarg.cb_ifname = gargp->ia_ifname;
-        cbarg.cb_aobjname = gargp->ia_aobjname;
-        cbarg.cb_ocnt = 0;
-        if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
-                goto fail;
-        err = ipmgmt_db_walk(ipmgmt_db_getaddr, &cbarg, IPADM_DB_READ);
-        if (err == ENOENT && cbarg.cb_ocnt > 0) {
-                /*
-                 * If there is atleast one entry in the nvlist,
-                 * do not return error.
-                 */
-                err = 0;
-        }
-        if (err != 0)
-                goto fail;
-
-        if ((err = nvlist_size(cbarg.cb_onvl, &onvlsize,
-            NV_ENCODE_NATIVE)) != 0) {
-                goto fail;
-        }
-        buflen = onvlsize + sizeof (ipmgmt_get_rval_t);
-        /*
-         * We cannot use malloc() here because door_return never returns, and
-         * memory allocated by malloc() would get leaked. Use alloca() instead.
-         */
-        buf = alloca(buflen);
-        onvlbuf = buf + sizeof (ipmgmt_get_rval_t);
-        if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, &onvlsize,
-            NV_ENCODE_NATIVE, 0)) != 0) {
-                goto fail;
-        }
-        nvlist_free(cbarg.cb_onvl);
-        rvalp = (ipmgmt_get_rval_t *)(void *)buf;
-        rvalp->ir_err = 0;
-        rvalp->ir_nvlsize = onvlsize;
-
-        (void) door_return(buf, buflen, NULL, 0);
-        return;
-fail:
-        nvlist_free(cbarg.cb_onvl);
-        rvalp->ir_err = err;
-        (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
+        ipmgmt_common_handler(gargp->ia_ifname, gargp->ia_aobjname,
+            ipmgmt_db_getaddr);
 }
 
 /*
  * Handles the door command IPMGMT_CMD_RESETPROP. It deletes the property line
  * from the DB.

@@ -705,67 +670,22 @@
         (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
 }
 
 /*
  * Handles the door command IPMGMT_CMD_GETIF. It retrieves the name of all the
- * persisted interfaces and the IP protocols (IPv4 or IPv6) they support.
+ * persisted interfaces and the IP protocols (IPv4 or IPv6) they support and
+ * returns the info as a nvlist
  */
 static void
 ipmgmt_getif_handler(void *argp)
 {
         ipmgmt_getif_arg_t      *getif = argp;
-        ipmgmt_getif_rval_t     *rvalp;
-        ipmgmt_retval_t         rval;
-        ipmgmt_getif_cbarg_t    cbarg;
-        ipadm_if_info_t         *ifp, *rifp, *curifp;
-        int                     i, err = 0, count = 0;
-        size_t                  rbufsize;
 
         assert(getif->ia_cmd == IPMGMT_CMD_GETIF);
 
-        bzero(&cbarg, sizeof (cbarg));
-        cbarg.cb_ifname = getif->ia_ifname;
-        err = ipmgmt_db_walk(ipmgmt_db_getif, &cbarg, IPADM_DB_READ);
-        if (err == ENOENT && cbarg.cb_ifinfo) {
-                /*
-                 * If there is atleast one entry in the nvlist,
-                 * do not return error.
-                 */
-                err = 0;
-        }
-        if (err != 0) {
-                rval.ir_err = err;
-                (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
-                return;
-        }
-
-        /* allocate sufficient buffer to return the interface info */
-        for (ifp = cbarg.cb_ifinfo; ifp != NULL; ifp = ifp->ifi_next)
-                ++count;
-        rbufsize = sizeof (*rvalp) + count * sizeof (*ifp);
-        rvalp = alloca(rbufsize);
-        bzero(rvalp, rbufsize);
-
-        rvalp->ir_ifcnt = count;
-        rifp = rvalp->ir_ifinfo;
-        ifp = cbarg.cb_ifinfo;
-
-        /*
-         * copy the interface info to buffer allocated on stack. The reason
-         * we do this is to avoid memory leak, as door_return() would never
-         * return
-         */
-        for (i = 0; i < count; i++) {
-                rifp = rvalp->ir_ifinfo + i;
-                (void) bcopy(ifp, rifp, sizeof (*rifp));
-                rifp->ifi_next = NULL;
-                curifp = ifp->ifi_next;
-                free(ifp);
-                ifp = curifp;
-        }
-        rvalp->ir_err = err;
-        (void) door_return((char *)rvalp, rbufsize, NULL, 0);
+        ipmgmt_common_handler(getif->ia_ifname, NULL,
+            ipmgmt_db_getif);
 }
 
 /*
  * Handles the door command IPMGMT_CMD_INITIF. It retrieves all the persisted
  * interface configuration (interface properties and addresses), for all those

@@ -795,11 +715,11 @@
                 goto fail;
 
         err = ipmgmt_db_walk(ipmgmt_db_initif, &cbarg, IPADM_DB_READ);
         if (err == ENOENT && cbarg.cb_ocnt > 0) {
                 /*
-                 * If there is atleast one entry in the nvlist,
+                 * If there is at least one entry in the nvlist,
                  * do not return error.
                  */
                 err = 0;
         }
         if (err != 0)

@@ -837,28 +757,171 @@
 ipmgmt_persist_if(ipmgmt_if_arg_t *sargp)
 {
         ipadm_dbwrite_cbarg_t   cb;
         uint32_t                flags = sargp->ia_flags;
         nvlist_t                *nvl = NULL;
-        int                     err = 0;
         char                    strval[IPMGMT_STRSIZE];
+        int     err = 0;
 
         if (!(flags & IPMGMT_PERSIST) || sargp->ia_family == AF_UNSPEC ||
             sargp->ia_ifname[0] == '\0') {
                 err = EINVAL;
                 goto ret;
         }
         if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
                 goto ret;
+
         if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
             sargp->ia_ifname)) != 0)
                 goto ret;
-        (void) snprintf(strval, IPMGMT_STRSIZE, "%d", sargp->ia_family);
-        if ((err = nvlist_add_string(nvl, IPADM_NVP_FAMILY, strval)) != 0)
+
+        if ((err = ipmgmt_update_family_nvp(nvl, sargp->ia_family,
+            IPMGMT_APPEND)) != 0)
                 goto ret;
+
+        (void) snprintf(strval, IPMGMT_STRSIZE, "%d", sargp->ia_ifclass);
+        if ((err = nvlist_add_string(nvl, IPADM_NVP_IFCLASS, strval)) != 0)
+                goto ret;
+
         cb.dbw_nvl = nvl;
-        cb.dbw_flags = 0;
-        err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
+        cb.dbw_flags = IPMGMT_APPEND | IPMGMT_UPDATE_IF;
+        err = ipmgmt_db_walk(ipmgmt_db_update_if, &cb, IPADM_DB_WRITE);
 ret:
         nvlist_free(nvl);
         return (err);
+}
+
+/*
+ * The helper for ipmgmt_getif_handler and ipmgmt_getaddr_handler
+ */
+static void
+ipmgmt_common_handler(char *if_name, char *aobj_name, db_wfunc_t worker)
+{
+        ipmgmt_get_rval_t   rval, *rvalp = &rval;
+        ipmgmt_get_cbarg_t    cbarg;
+        int     err = 0;
+        size_t  buflen, onvlsize;
+        char    *buf, *onvlbuf;
+
+        cbarg.cb_ifname = if_name;
+        cbarg.cb_aobjname = aobj_name;
+        cbarg.cb_ocnt = 0;
+
+        if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
+                goto fail;
+
+        err = ipmgmt_db_walk(worker, &cbarg, IPADM_DB_READ);
+        if (err == ENOENT && cbarg.cb_ocnt > 0) {
+                /*
+                 * If there is atleast one entry in the nvlist,
+                 * do not return error.
+                 */
+                err = 0;
+        }
+        if (err != 0)
+                goto fail;
+
+        if ((err = nvlist_size(cbarg.cb_onvl, &onvlsize,
+            NV_ENCODE_NATIVE)) != 0)
+                goto fail;
+
+        buflen = onvlsize + sizeof (ipmgmt_get_rval_t);
+        /* We cannot use malloc() here because door_return never returns */
+        buf = alloca(buflen);
+        onvlbuf = buf + sizeof (ipmgmt_get_rval_t);
+        if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf,
+            &onvlsize, NV_ENCODE_NATIVE, 0)) != 0)
+                goto fail;
+
+        nvlist_free(cbarg.cb_onvl);
+        rvalp = (ipmgmt_get_rval_t *)(void *)buf;
+        rvalp->ir_err = 0;
+        rvalp->ir_nvlsize = onvlsize;
+
+        (void) door_return(buf, buflen, NULL, 0);
+        return;
+
+fail:
+        nvlist_free(cbarg.cb_onvl);
+        rvalp->ir_err = err;
+        (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
+}
+
+/*
+ * Handles the door command IPMGMT_CMD_IPMP_UPDATE
+ */
+static void
+ipmgmt_ipmp_update_handler(void *argp)
+{
+        ipmgmt_ipmp_update_arg_t *uargp = argp;
+        ipmgmt_retval_t rval;
+        ipadm_dbwrite_cbarg_t   cb;
+
+        boolean_t       gif_exists;
+        char            gifname[LIFNAMSIZ];
+        nvlist_t        *nvl = NULL;
+        uint32_t        flags = uargp->ia_flags;
+        int             err = 0;
+
+        assert(uargp->ia_cmd == IPMGMT_CMD_IPMP_UPDATE);
+
+        gif_exists = ipmgmt_persist_if_exists(uargp->ia_gifname,
+            AF_UNSPEC);
+
+        if (!ipmgmt_persist_if_exists(uargp->ia_mifname, AF_UNSPEC)) {
+                err = EINVAL;
+                goto ret;
+        }
+
+        ipmgmt_get_group_interface(uargp->ia_mifname, gifname, LIFNAMSIZ);
+
+        if (flags & IPMGMT_APPEND) {
+                /* group interface should be available in the DB */
+                if (!gif_exists) {
+                        err = ENOENT;
+                        goto ret;
+                }
+
+                if (gifname[0] != '\0') {
+                        err = EEXIST;
+                        goto ret;
+                }
+        }
+
+        if (flags & IPMGMT_REMOVE) {
+                /* We cannot remove something that does not exist */
+                if (!gif_exists || gifname[0] == '\0') {
+                        err = ENOENT;
+                        goto ret;
+                }
+                if (strcmp(uargp->ia_gifname, gifname) != 0) {
+                        err = EINVAL;
+                        goto ret;
+                }
+        }
+
+        if (flags & IPMGMT_PERSIST) {
+
+                if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
+                        goto ret;
+
+                if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
+                    uargp->ia_gifname)) != 0)
+                        goto ret;
+
+                if ((err = nvlist_add_string(nvl, IPADM_NVP_MIFNAMES,
+                    uargp->ia_mifname)) != 0)
+                        goto ret;
+
+                if ((err = nvlist_add_string(nvl, IPADM_NVP_GIFNAME,
+                    uargp->ia_gifname)) != 0)
+                        goto ret;
+
+                cb.dbw_nvl = nvl;
+                cb.dbw_flags = flags | IPMGMT_UPDATE_IF | IPMGMT_UPDATE_IPMP;
+                err = ipmgmt_db_walk(ipmgmt_db_update_if, &cb, IPADM_DB_WRITE);
+        }
+ret:
+        nvlist_free(nvl);
+        rval.ir_err = err;
+        (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
 }