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);
}