summaryrefslogtreecommitdiff
path: root/usr/src/cmd/cmd-inet
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/cmd-inet')
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile8
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c290
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h25
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c27
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c451
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/in.mpathd/Makefile17
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/in.mpathd/net-ipmp31
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/in.mpathd/network-ipmp.xml78
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ipadm/Makefile5
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c333
10 files changed, 998 insertions, 267 deletions
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile b/usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile
index f9ae4eacdc..1c32ce2ff1 100644
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile
@@ -18,7 +18,10 @@
#
# CDDL HEADER END
#
+
+#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2021 Tintri by DDN, Inc. All rights reserved.
#
# Needed for ROOTFS_LIBDIR definition
@@ -38,9 +41,6 @@ ROOTCFGDIR= $(ROOTETC)/ipadm
ROOTCFGFILES= $(CFGFILES:%=$(ROOTCFGDIR)/%)
ROOTMANIFESTDIR= $(ROOTSVCNETWORK)
-CERRWARN += -_gcc=-Wno-switch
-CERRWARN += $(CNOWARN_UNINIT)
-
$(ROOTCFGFILES) := OWNER= ipadm
$(ROOTCFGFILES) := GROUP= sys
$(ROOTCFGFILES) := FILEMODE= 644
@@ -85,4 +85,4 @@ $(ROOTCFGDIR):
$(ROOTCFGDIR)/%: $(ROOTCFGDIR) %
$(INS.file)
-include ../../../Makefile.targ
+include ../../../Makefile.targ
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c
index 92e3f73f55..b446b2ffa4 100644
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c
@@ -43,6 +43,9 @@
#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);
@@ -56,7 +59,8 @@ static ipmgmt_door_handler_t ipmgmt_getaddr_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;
@@ -81,6 +85,7 @@ static ipmgmt_door_info_t i_ipmgmt_door_info_tbl[] = {
{ 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 },
};
@@ -593,6 +598,10 @@ ipmgmt_resetif_handler(void *argp)
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);
@@ -654,59 +663,10 @@ ipmgmt_resetaddr_handler(void *argp)
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;
- }
-
- if (onvlsize > (UINT32_MAX - sizeof (ipmgmt_get_rval_t)))
- 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;
+ ipmgmt_getaddr_arg_t *gargp = argp;
- (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);
}
/*
@@ -727,65 +687,20 @@ ipmgmt_resetprop_handler(void *argp)
}
/*
- * 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.
+ * Handles the door command IPMGMT_CMD_GETIF. It retrieves the names of all
+ * persisted interfaces and the IP protocol families (IPv4 or IPv6) they
+ * support. Returns the info as a nvlist using door_return() from
+ * ipmgmt_common_handler().
*/
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_list_t *ifl, *curifl;
- ipadm_if_info_t *ifp, *rifp;
- int i, err = 0, count = 0;
- size_t rbufsize;
+ ipmgmt_getif_arg_t *getif = argp;
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 (ifl = cbarg.cb_ifinfo; ifl != NULL; ifl = ifl->ifil_next)
- ++count;
- rbufsize = sizeof (*rvalp) + count * sizeof (*ifp);
- rvalp = alloca(rbufsize);
- bzero(rvalp, rbufsize);
-
- rvalp->ir_ifcnt = count;
- rifp = rvalp->ir_ifinfo;
- ifl = 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++) {
- ifp = &ifl->ifil_ifi;
- rifp = rvalp->ir_ifinfo + i;
- (void) bcopy(ifp, rifp, sizeof (*rifp));
- curifl = ifl->ifil_next;
- free(ifl);
- ifl = curifl;
- }
- rvalp->ir_err = err;
- (void) door_return((char *)rvalp, rbufsize, NULL, 0);
+ ipmgmt_common_handler(getif->ia_ifname, NULL,
+ ipmgmt_db_getif);
}
/*
@@ -819,7 +734,7 @@ ipmgmt_initif_handler(void *argp)
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;
@@ -863,10 +778,10 @@ int
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];
+ uint32_t flags = sargp->ia_flags;
+ nvlist_t *nvl = NULL;
+ char strval[IPMGMT_STRSIZE];
+ int err = 0;
if (!(flags & IPMGMT_PERSIST) || sargp->ia_family == AF_UNSPEC ||
sargp->ia_ifname[0] == '\0') {
@@ -875,16 +790,163 @@ ipmgmt_persist_if(ipmgmt_if_arg_t *sargp)
}
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)
+{
+ size_t buflen, onvlsize;
+ char *buf, *onvlbuf;
+ ipmgmt_get_cbarg_t cbarg;
+ ipmgmt_get_rval_t rval, *rvalp = &rval;
+ int err = 0;
+
+ 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 at least 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;
+
+ if (onvlsize > (UINT32_MAX - sizeof (ipmgmt_get_rval_t)))
+ 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);
+
+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);
+}
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h
index 968fa77923..fe7e95a87e 100644
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h
@@ -22,7 +22,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
- * Copyright 2021, Tintri by DDN. All rights reserved.
+ * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
*/
#ifndef _IPMGMT_IMPL_H
@@ -51,6 +51,8 @@ extern void ipmgmt_log(int, const char *, ...);
extern int ipmgmt_cpfile(const char *, const char *, boolean_t);
/* ipmgmt_persist.c */
+extern boolean_t ipmgmt_persist_if_exists(const char *, sa_family_t);
+extern void ipmgmt_get_group_interface(const char *, char *, size_t);
/*
* following are the list of DB walker callback functions and the callback
@@ -60,25 +62,22 @@ extern int ipmgmt_cpfile(const char *, const char *, boolean_t);
extern db_wfunc_t ipmgmt_db_getprop, ipmgmt_db_resetprop;
/* following functions take ipadm_dbwrite_cbarg_t as callback argument */
-extern db_wfunc_t ipmgmt_db_add, ipmgmt_db_update;
+extern db_wfunc_t ipmgmt_db_add, ipmgmt_db_update, ipmgmt_db_update_if;
typedef struct {
- char *cb_ifname;
- ipadm_if_info_list_t *cb_ifinfo;
-} ipmgmt_getif_cbarg_t;
-extern db_wfunc_t ipmgmt_db_getif;
-
-typedef struct {
- char *cb_aobjname;
- char *cb_ifname;
+ char *cb_ifname;
+ char *cb_aobjname;
nvlist_t *cb_onvl;
- int cb_ocnt;
-} ipmgmt_getaddr_cbarg_t;
+ int cb_ocnt;
+} ipmgmt_get_cbarg_t;
+extern db_wfunc_t ipmgmt_db_getif;
extern db_wfunc_t ipmgmt_db_getaddr;
typedef struct {
sa_family_t cb_family;
char *cb_ifname;
+ boolean_t cb_ipv4exists;
+ boolean_t cb_ipv6exists;
} ipmgmt_if_cbarg_t;
extern db_wfunc_t ipmgmt_db_setif, ipmgmt_db_resetif;
@@ -182,6 +181,8 @@ typedef struct scf_resources {
scf_transaction_entry_t *sr_ent;
} scf_resources_t;
+extern int ipmgmt_update_family_nvp(nvlist_t *,
+ sa_family_t, uint_t);
extern int ipmgmt_db_walk(db_wfunc_t *, void *, ipadm_db_op_t);
extern int ipmgmt_aobjmap_op(ipmgmt_aobjmap_t *, uint32_t);
extern boolean_t ipmgmt_aobjmap_init(void *, nvlist_t *, char *,
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c
index e3a8d3e817..3573ca40ca 100644
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2021, Tintri by DDN. All rights reserved.
+ * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
*/
/*
@@ -522,31 +522,6 @@ child_out:
}
/*
- * Return TRUE if `ifname' has persistent configuration for the `af' address
- * family in the datastore
- */
-static boolean_t
-ipmgmt_persist_if_exists(char *ifname, sa_family_t af)
-{
- ipmgmt_getif_cbarg_t cbarg;
- boolean_t exists = B_FALSE;
- ipadm_if_info_t *ifp;
-
- bzero(&cbarg, sizeof (cbarg));
- cbarg.cb_ifname = ifname;
- (void) ipmgmt_db_walk(ipmgmt_db_getif, &cbarg, IPADM_DB_READ);
- if (cbarg.cb_ifinfo != NULL) {
- ifp = &cbarg.cb_ifinfo->ifil_ifi;
- if ((af == AF_INET && (ifp->ifi_pflags & IFIF_IPV4)) ||
- (af == AF_INET6 && (ifp->ifi_pflags & IFIF_IPV6))) {
- exists = B_TRUE;
- }
- }
- free(cbarg.cb_ifinfo);
- return (exists);
-}
-
-/*
* Persist any NGZ interfaces assigned to us from the global zone if they do
* not already exist in the persistent db. We need to
* do this before any calls to ipadm_enable_if() can succeed (i.e.,
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c
index 5f9d24df7a..cf9e30e819 100644
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c
@@ -24,7 +24,7 @@
* Copyright 2018 Joyent, Inc.
* Copyright 2016 Argo Technologie SA.
* Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
- * Copyright 2021, Tintri by DDN. All rights reserved.
+ * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
*/
/*
@@ -81,6 +81,161 @@ extern pthread_rwlock_t ipmgmt_dbconf_lock;
/* signifies whether volatile copy of data store is in use */
static boolean_t ipmgmt_rdonly_root = B_FALSE;
+typedef int ipmgmt_if_updater_func_t(nvlist_t *, nvpair_t *, uint_t);
+
+static ipmgmt_if_updater_func_t ipmgmt_if_family_updater;
+static ipmgmt_if_updater_func_t ipmgmt_if_groupmembers_updater;
+
+static int ipmgmt_get_ifinfo_nvl(const char *ifname, nvlist_t **if_info_nvl);
+
+typedef struct {
+ const char *name;
+ ipmgmt_if_updater_func_t *func;
+} ipmgmt_if_updater_ent_t;
+
+static ipmgmt_if_updater_ent_t ipmgmt_if_updater_ent[] = {
+ {IPADM_NVP_FAMILIES, ipmgmt_if_family_updater},
+ {IPADM_NVP_MIFNAMES, ipmgmt_if_groupmembers_updater},
+ {NULL, NULL}
+};
+
+static ipmgmt_if_updater_ent_t *
+ipmgmt_find_if_field_updater(const char *field_name)
+{
+ int i;
+
+ for (i = 0; ipmgmt_if_updater_ent[i].name != NULL; i++) {
+ if (strcmp(field_name, ipmgmt_if_updater_ent[i].name) == 0) {
+ break;
+ }
+ }
+
+ return (&ipmgmt_if_updater_ent[i]);
+}
+
+static int
+ipmgmt_if_groupmembers_updater(nvlist_t *db_nvl, nvpair_t *member_nvp,
+ uint_t flags)
+{
+ char **members;
+ char *member;
+ char **out_members;
+ uint_t nelem = 0, cnt = 0;
+ int err;
+
+ if ((err = nvpair_value_string(member_nvp, &member)) != 0)
+ return (err);
+
+ err = nvlist_lookup_string_array(db_nvl, IPADM_NVP_MIFNAMES,
+ &members, &nelem);
+
+ if (err != 0 && (flags & IPMGMT_REMOVE))
+ return (ENOENT);
+
+ /*
+ * Reserve one extra slot for IPMGMT_APPEND.
+ * Probably not worth conditionalizing.
+ */
+ out_members = calloc(nelem + 1, sizeof (char *));
+ if (out_members == NULL)
+ return (ENOMEM);
+
+ while (nelem-- > 0) {
+ if ((flags & IPMGMT_REMOVE) &&
+ (strcmp(member, members[nelem]) == 0))
+ continue;
+
+ if ((out_members[cnt] = strdup(members[nelem])) == NULL) {
+ err = ENOMEM;
+ goto fail;
+ }
+
+ cnt++;
+ }
+
+ if (flags & IPMGMT_APPEND) {
+ if ((out_members[cnt] = strdup(member)) == NULL) {
+ err = ENOMEM;
+ goto fail;
+ }
+ cnt++;
+ }
+
+ if (cnt == 0) {
+ err = nvlist_remove(db_nvl, IPADM_NVP_MIFNAMES,
+ DATA_TYPE_STRING_ARRAY);
+ } else {
+ err = nvlist_add_string_array(db_nvl, IPADM_NVP_MIFNAMES,
+ out_members, cnt);
+ }
+
+fail:
+ while (cnt--)
+ free(out_members[cnt]);
+
+ free(out_members);
+
+ return (err);
+}
+
+static int
+ipmgmt_if_family_updater(nvlist_t *db_nvl, nvpair_t *families_nvp, uint_t flags)
+{
+ uint16_t *families;
+ uint_t nelem = 0;
+ int err;
+
+ if ((err = nvpair_value_uint16_array(families_nvp, &families,
+ &nelem)) != 0)
+ return (err);
+
+ return (ipmgmt_update_family_nvp(db_nvl, families[0], flags));
+}
+
+int
+ipmgmt_update_family_nvp(nvlist_t *nvl, sa_family_t af, uint_t flags)
+{
+ uint16_t *families = NULL;
+ uint16_t out_families[2];
+ uint_t nelem = 0, cnt;
+ int err;
+
+ err = nvlist_lookup_uint16_array(nvl, IPADM_NVP_FAMILIES,
+ &families, &nelem);
+ if (err != 0 && (flags & IPMGMT_REMOVE)) {
+ return (ENOENT);
+ }
+
+ if (flags & IPMGMT_APPEND) {
+ if (families != NULL) {
+ if (nelem == 2 || families[0] == af) {
+ return (EEXIST);
+ }
+ out_families[0] = families[0];
+ out_families[1] = af;
+ cnt = 2;
+ } else {
+ out_families[0] = af;
+ cnt = 1;
+ }
+ } else {
+ assert(nelem == 1 || nelem == 2);
+ cnt = 0;
+ while (nelem-- > 0) {
+ if (families[nelem] != af) {
+ out_families[cnt] = families[nelem];
+ cnt++;
+ }
+ }
+ }
+
+ if (cnt != 0) {
+ return (nvlist_add_uint16_array(nvl, IPADM_NVP_FAMILIES,
+ out_families, cnt));
+ }
+ return (nvlist_remove(nvl, IPADM_NVP_FAMILIES, DATA_TYPE_UINT16_ARRAY));
+}
+
/*
* Checks if the database nvl, `db_nvl' contains and matches ALL of the passed
* in private nvpairs `proto', `ifname' & `aobjname'.
@@ -329,7 +484,7 @@ boolean_t
ipmgmt_db_getaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
int *errp)
{
- ipmgmt_getaddr_cbarg_t *cbarg = arg;
+ ipmgmt_get_cbarg_t *cbarg = arg;
char *db_aobjname = NULL;
char *db_ifname = NULL;
nvlist_t *db_addr = NULL;
@@ -556,57 +711,130 @@ ipmgmt_db_update(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
}
/*
- * For the given `cbarg->cb_ifname' interface, retrieves any persistent
- * interface information (used in 'ipadm show-if')
+ * This function is used to update a DB line that describes
+ * an interface, its family and group interface
+ *
*/
-/* ARGSUSED */
boolean_t
-ipmgmt_db_getif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
+ipmgmt_db_update_if(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
int *errp)
{
- ipmgmt_getif_cbarg_t *cbarg = arg;
- char *ifname = cbarg->cb_ifname;
- char *intf = NULL;
- ipadm_if_info_list_t *ifl = NULL;
- ipadm_if_info_t *ifp;
- sa_family_t af;
- char *afstr;
+ ipadm_dbwrite_cbarg_t *cb = arg;
+ ipmgmt_if_updater_ent_t *updater;
+ nvlist_t *in_nvl = cb->dbw_nvl;
+ uint_t flags = cb->dbw_flags;
+ nvpair_t *nvp;
+ char *name;
+ char *db_ifname;
+ char *gifname = NULL;
+ char *mifname = NULL;
*errp = 0;
- if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) != 0 ||
- nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &intf) != 0 ||
- (ifname[0] != '\0' && strcmp(ifname, intf) != 0)) {
+
+ /* Only one flag */
+ if ((flags & (IPMGMT_APPEND | IPMGMT_REMOVE)) == 0 ||
+ ((flags & IPMGMT_APPEND) && (flags & IPMGMT_REMOVE))) {
+ *errp = EINVAL;
+ return (B_FALSE);
+ }
+
+ if (!nvlist_exists(db_nvl, IPADM_NVP_FAMILIES))
return (B_TRUE);
+
+ if (nvlist_exists(db_nvl, IPADM_NVP_IFCLASS) &&
+ nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &db_ifname) == 0 &&
+ nvlist_lookup_string(in_nvl, IPADM_NVP_GIFNAME, &gifname) == 0 &&
+ nvlist_lookup_string(in_nvl, IPADM_NVP_MIFNAMES, &mifname) == 0 &&
+ strcmp(db_ifname, mifname) == 0) {
+ if (flags & IPMGMT_APPEND) {
+ if ((*errp = nvlist_add_string(db_nvl,
+ IPADM_NVP_GIFNAME, gifname)) != 0)
+ return (B_FALSE);
+ } else {
+ if ((*errp = nvlist_remove(db_nvl, IPADM_NVP_GIFNAME,
+ DATA_TYPE_STRING)) != 0)
+ return (B_FALSE);
+ }
+ cb->dbw_flags &= ~IPMGMT_UPDATE_IPMP;
+ goto done;
}
- af = atoi(afstr);
- for (ifl = cbarg->cb_ifinfo; ifl != NULL; ifl = ifl->ifil_next) {
- ifp = &ifl->ifil_ifi;
- if (strcmp(ifp->ifi_name, intf) == 0)
- break;
+
+ if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
+ return (B_TRUE);
+
+ for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
+ nvp = nvlist_next_nvpair(in_nvl, nvp)) {
+ name = nvpair_name(nvp);
+ if (strcmp(name, IPADM_NVP_FAMILIES) != 0 &&
+ strcmp(name, IPADM_NVP_MIFNAMES) != 0)
+ continue;
+
+ updater = ipmgmt_find_if_field_updater(name);
+ assert(updater != NULL);
+ *errp = (*updater->func)(db_nvl, nvp, flags);
+ if (*errp != 0)
+ return (B_FALSE);
}
- if (ifl == NULL) {
- ipadm_if_info_list_t *new;
- if ((new = calloc(1, sizeof (*new))) == NULL) {
- *errp = ENOMEM;
- return (B_FALSE); /* don't continue the walk */
- }
- new->ifil_next = cbarg->cb_ifinfo;
- cbarg->cb_ifinfo = new;
- ifp = &new->ifil_ifi;
- (void) strlcpy(ifp->ifi_name, intf, sizeof (ifp->ifi_name));
+ cb->dbw_flags &= ~IPMGMT_UPDATE_IF;
+
+done:
+ (void) memset(buf, 0, buflen);
+ if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
+ *errp = EOVERFLOW;
+ return (B_FALSE);
}
- if (af == AF_INET) {
- ifp->ifi_pflags |= IFIF_IPV4;
- } else {
- assert(af == AF_INET6);
- ifp->ifi_pflags |= IFIF_IPV6;
+ /* we finished all operations, so do not continue */
+ if ((cb->dbw_flags & (IPMGMT_UPDATE_IF | IPMGMT_UPDATE_IPMP)) == 0)
+ return (B_FALSE);
+
+ return (B_TRUE);
+}
+
+/*
+ * For the given `cbarg->cb_ifname' interface, retrieve the nvlist that
+ * represents the persistent interface information.
+ * The nvlist contains:
+ * IPADM_NVP_IFNAME
+ * IPADM_NVP_FAMILIES
+ * IPADM_NVP_IF_CLASS
+ *
+ * (used in 'ipadm show-if')
+ */
+/* ARGSUSED */
+boolean_t
+ipmgmt_db_getif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
+ int *errp)
+{
+ ipmgmt_get_cbarg_t *cbarg = arg;
+ char *ifname = cbarg->cb_ifname;
+ nvpair_t *nvp;
+ char *db_ifname = NULL;
+ boolean_t families = B_FALSE;
+
+ /* Parse db nvlist */
+ for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
+ nvp = nvlist_next_nvpair(db_nvl, nvp)) {
+ if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0) {
+ (void) nvpair_value_string(nvp, &db_ifname);
+ } else if (strcmp(nvpair_name(nvp), IPADM_NVP_FAMILIES) == 0) {
+ families = B_TRUE;
+ }
}
- /* Terminate the walk if we found both v4 and v6 interfaces. */
- if (ifname[0] != '\0' && (ifp->ifi_pflags & IFIF_IPV4) &&
- (ifp->ifi_pflags & IFIF_IPV6))
+ if (db_ifname == NULL || !families)
+ return (B_TRUE);
+
+ if (ifname != NULL && ifname[0] != '\0' &&
+ strcmp(ifname, db_ifname) != 0)
+ return (B_TRUE);
+
+ *errp = nvlist_add_nvlist(cbarg->cb_onvl, db_ifname, db_nvl);
+ if (*errp == 0)
+ cbarg->cb_ocnt++;
+
+ if (ifname != NULL && ifname[0] != '\0')
return (B_FALSE);
return (B_TRUE);
@@ -625,7 +853,6 @@ ipmgmt_db_resetif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
boolean_t isv6 = (cbarg->cb_family == AF_INET6);
char *ifname = cbarg->cb_ifname;
char *modstr = NULL;
- char *afstr;
char *aobjname;
uint_t proto;
ipmgmt_aobjmap_t *head;
@@ -636,9 +863,31 @@ ipmgmt_db_resetif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
if (!ipmgmt_nvlist_contains(db_nvl, NULL, ifname, NULL))
return (B_TRUE);
- if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) == 0) {
- if (atoi(afstr) == cbarg->cb_family)
+ if (nvlist_exists(db_nvl, IPADM_NVP_FAMILIES)) {
+
+ if ((*errp = ipmgmt_update_family_nvp(db_nvl, cbarg->cb_family,
+ IPMGMT_REMOVE)) != 0) {
+ return (B_FALSE);
+ }
+
+ if (cbarg->cb_family == AF_INET) {
+ cbarg->cb_ipv4exists = B_FALSE;
+ } else {
+ assert(cbarg->cb_family == AF_INET6);
+ cbarg->cb_ipv6exists = B_FALSE;
+ }
+ if (!nvlist_exists(db_nvl, IPADM_NVP_FAMILIES)) {
+ cbarg->cb_ipv4exists = B_FALSE;
+ cbarg->cb_ipv6exists = B_FALSE;
goto delete;
+ }
+ /* Otherwise need to reconstruct this string */
+ (void) memset(buf, 0, buflen);
+ if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
+ /* buffer overflow */
+ *errp = EOVERFLOW;
+ return (B_FALSE);
+ }
return (B_TRUE);
}
@@ -694,8 +943,8 @@ ipmgmt_db_resetif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
goto delete;
break;
case MOD_PROTO_IP:
- /* this should never be the case, today */
- assert(0);
+ if (!cbarg->cb_ipv4exists && !cbarg->cb_ipv6exists)
+ goto delete;
break;
}
}
@@ -895,7 +1144,7 @@ ipmgmt_aobjmap_op(ipmgmt_aobjmap_t *nodep, uint32_t op)
ipmgmt_aobjmap_t *head, *prev, *matched = NULL;
boolean_t update = B_TRUE;
int err = 0;
- ipadm_db_op_t db_op;
+ ipadm_db_op_t db_op = IPADM_DB_READ;
(void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock);
@@ -1371,7 +1620,7 @@ ipmgmt_db_init(void *cbarg, nvlist_t *db_nvl, char *buf, size_t buflen,
int *errp)
{
ipadm_handle_t iph = cbarg;
- nvpair_t *nvp, *pnvp;
+ nvpair_t *nvp, *pnvp = NULL;
char *strval = NULL, *name, *mod = NULL, *pname;
char tmpstr[IPMGMT_STRSIZE];
uint_t proto;
@@ -1398,7 +1647,7 @@ ipmgmt_db_init(void *cbarg, nvlist_t *db_nvl, char *buf, size_t buflen,
}
}
- /* if we are here than we found a global property */
+ /* If we are here then we have found a global property */
assert(mod != NULL);
assert(nvpair_type(pnvp) == DATA_TYPE_STRING);
@@ -1587,6 +1836,8 @@ ipmgmt_get_scfprop(scf_resources_t *res, const char *pgname, const char *pname,
case SCF_TYPE_ASTRING:
*(char **)pval = scf_simple_prop_next_astring(prop);
break;
+ default:
+ break;
}
ret:
scf_simple_prop_free(prop);
@@ -1710,3 +1961,109 @@ ipmgmt_update_dbver(scf_resources_t *res)
(void) ipmgmt_set_scfprop(res, IPMGMTD_APP_PG,
IPMGMTD_PROP_DBVER, &version, SCF_TYPE_INTEGER);
}
+
+/*
+ * Return TRUE if `ifname' has persistent configuration for the `af' address
+ * family in the datastore.
+ * It is possible to call the function with af == AF_UNSPEC, so in this case
+ * the function returns TRUE if either AF_INET or AF_INET6 interface exists
+ */
+boolean_t
+ipmgmt_persist_if_exists(const char *ifname, sa_family_t af)
+{
+ boolean_t exists = B_FALSE;
+ nvlist_t *if_info_nvl;
+ uint16_t *families = NULL;
+ sa_family_t af_db;
+ uint_t nelem = 0;
+
+ if (ipmgmt_get_ifinfo_nvl(ifname, &if_info_nvl) != 0)
+ goto done;
+
+ if (nvlist_lookup_uint16_array(if_info_nvl, IPADM_NVP_FAMILIES,
+ &families, &nelem) != 0)
+ goto done;
+
+ while (nelem-- > 0) {
+ af_db = families[nelem];
+ if (af_db == af || (af == AF_UNSPEC &&
+ (af_db == AF_INET || af_db == AF_INET6))) {
+ exists = B_TRUE;
+ break;
+ }
+ }
+
+done:
+ if (if_info_nvl != NULL)
+ nvlist_free(if_info_nvl);
+
+ return (exists);
+}
+
+/*
+ * Retrieves the membership information for the requested mif_name
+ * if mif_name is a member of a IPMP group, then gif_name will contain
+ * the name of IPMP group interface, otherwise the variable will be empty
+ */
+void
+ipmgmt_get_group_interface(const char *mif_name, char *gif_name, size_t size)
+{
+ char *gif_name_from_nvl;
+ nvlist_t *if_info_nvl;
+
+ gif_name[0] = '\0';
+
+ if (ipmgmt_get_ifinfo_nvl(mif_name, &if_info_nvl) != 0)
+ goto done;
+
+ if (nvlist_lookup_string(if_info_nvl, IPADM_NVP_GIFNAME,
+ &gif_name_from_nvl) != 0)
+ goto done;
+
+ (void) strlcpy(gif_name, gif_name_from_nvl, size);
+
+done:
+ if (if_info_nvl != NULL)
+ nvlist_free(if_info_nvl);
+}
+
+static int
+ipmgmt_get_ifinfo_nvl(const char *ifname, nvlist_t **if_info_nvl)
+{
+ ipmgmt_get_cbarg_t cbarg;
+ nvpair_t *nvp;
+ nvlist_t *nvl;
+ int err;
+
+ cbarg.cb_ifname = NULL;
+ cbarg.cb_aobjname = NULL;
+ cbarg.cb_ocnt = 0;
+
+ if ((err = nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0)) != 0)
+ goto done;
+
+ err = ipmgmt_db_walk(ipmgmt_db_getif, &cbarg, IPADM_DB_READ);
+ if (err == ENOENT && cbarg.cb_ocnt > 0)
+ err = 0;
+
+ if (err != 0)
+ goto done;
+
+ for (nvp = nvlist_next_nvpair(cbarg.cb_onvl, NULL); nvp != NULL;
+ nvp = nvlist_next_nvpair(cbarg.cb_onvl, nvp)) {
+
+ if (strcmp(nvpair_name(nvp), ifname) != 0)
+ continue;
+
+ if ((err = nvpair_value_nvlist(nvp, &nvl)) != 0 ||
+ (err = nvlist_dup(nvl, if_info_nvl, NV_UNIQUE_NAME)) != 0)
+ *if_info_nvl = NULL;
+
+ break;
+ }
+
+done:
+ nvlist_free(cbarg.cb_onvl);
+
+ return (err);
+}
diff --git a/usr/src/cmd/cmd-inet/usr.lib/in.mpathd/Makefile b/usr/src/cmd/cmd-inet/usr.lib/in.mpathd/Makefile
index 3668af100b..d63134dae8 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/in.mpathd/Makefile
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.mpathd/Makefile
@@ -22,16 +22,21 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright 2021 Tintri by DDN, Inc. All rights reserved.
+#
PROG = in.mpathd
ROOTFS_PROG = $(PROG)
OBJS = mpd_tables.o mpd_main.o mpd_probe.o
SRCS = $(OBJS:%.o=%.c)
DEFAULTFILES = mpathd.dfl
+SVCMETHOD = net-ipmp
+MANIFEST = network-ipmp.xml
include ../../../Makefile.cmd
ROOTCMDDIR = $(ROOT)/lib/inet
+ROOTMANIFESTDIR = $(ROOTSVCNETWORK)
POFILE = $(PROG).po
POFILES = $(SRCS:%.c=%.po)
@@ -63,15 +68,9 @@ $(PROG): $(OBJS)
$(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(CTFMERGE_HOOK)
$(POST_PROCESS)
-include ../Makefile.lib
-
-$(ROOTLIBINETPROG):
- $(RM) $@; $(SYMLINK) ../../../lib/inet/$(PROG) $@
-
-$(ROOTSBINPROG):
- $(RM) $@; $(SYMLINK) ../lib/inet/$(PROG) $@
+check: $(CHKMANIFEST)
-install: all $(ROOTLIBINETPROG) $(ROOTSBINPROG) $(ROOTCMD) \
+install: all $(ROOTCMD) $(ROOTMANIFEST) $(ROOTSVCMETHOD) \
$(ROOTETCDEFAULTFILES)
clean:
@@ -79,7 +78,7 @@ clean:
lint: lint_SRCS
-$(POFILE): $(POFILES)
+$(POFILE): $(POFILES)
$(RM) $@
$(CAT) $(POFILES) > $@
diff --git a/usr/src/cmd/cmd-inet/usr.lib/in.mpathd/net-ipmp b/usr/src/cmd/cmd-inet/usr.lib/in.mpathd/net-ipmp
new file mode 100644
index 0000000000..be4263a74b
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.mpathd/net-ipmp
@@ -0,0 +1,31 @@
+#!/sbin/sh
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2021 Tintri by DDN, Inc. All rights reserved.
+#
+
+. /lib/svc/share/smf_include.sh
+
+if [ -z "$SMF_FMRI" ]; then
+ echo "this script can only be invoked by smf(5)"
+ exit $SMF_EXIT_ERR_NOSMF
+fi
+
+smf_configure_ip || exit $SMF_EXIT_ERR_FATAL
+
+if /lib/inet/in.mpathd; then
+ exit $SMF_EXIT_OK
+else
+ exit $SMF_EXIT_ERR_FATAL
+fi
diff --git a/usr/src/cmd/cmd-inet/usr.lib/in.mpathd/network-ipmp.xml b/usr/src/cmd/cmd-inet/usr.lib/in.mpathd/network-ipmp.xml
new file mode 100644
index 0000000000..282bf5b4df
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.mpathd/network-ipmp.xml
@@ -0,0 +1,78 @@
+<?xml version='1.0'?>
+<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
+
+<!--
+ Copyright 2021 Tintri by DDN, Inc. All rights reserved.
+
+ This file and its contents are supplied under the terms of the
+ Common Development and Distribution License ("CDDL"), version 1.0.
+ You may only use this file in accordance with the terms of version
+ 1.0 of the CDDL.
+
+ A full copy of the text of the CDDL should have accompanied this
+ source. A copy of the CDDL is also available via the Internet at
+ http://www.illumos.org/license/CDDL.
+
+ NOTE: This service manifest is not editable; its contents will
+ be overwritten by package or patch operations, including
+ operating system upgrade. Make customizations in a different
+ file.
+-->
+
+<service_bundle type='manifest' name='SUNWcsr:ipmp'>
+
+<service
+ name='network/ipmp'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='true' />
+
+ <dependency name='loopback' grouping='require_all' restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/network/loopback' />
+ </dependency>
+
+ <dependent name='network-physical' grouping='optional_all'
+ restart_on='none'>
+ <service_fmri value='svc:/network/physical:default' />
+ </dependent>
+
+ <exec_method type='method' name='start' exec='/lib/svc/method/net-ipmp'
+ timeout_seconds='60'>
+ </exec_method>
+
+ <exec_method type='method' name='stop' exec=':kill'
+ timeout_seconds='60'>
+ </exec_method>
+
+ <exec_method type='method' name='refresh' exec=':kill -HUP'
+ timeout_seconds='60'>
+ </exec_method>
+
+ <property_group name='config' type='application'>
+ <propval name='action_authorization' type='astring'
+ value='solaris.smf.manage.ipmp' />
+ </property_group>
+
+ <property_group name='general' type='framework'>
+ <propval name='action_authorization' type='astring'
+ value='solaris.smf.manage.ipmp' />
+ <propval name='value_authorization' type='astring'
+ value='solaris.smf.manage.ipmp' />
+ </property_group>
+
+ <stability value='Unstable' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ IP MultiPathing
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='in.mpathd' section='1M' />
+ </documentation>
+ </template>
+</service>
+</service_bundle>
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ipadm/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/Makefile
index 801fb40158..c9337fb75b 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ipadm/Makefile
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/Makefile
@@ -23,6 +23,9 @@
# Use is subject to license terms.
#
# Copyright 2020 Joyent, Inc.
+# Copyright 2021 Tintri by DDN, Inc. All rights reserved.
+#
+#
PROG = ipadm
ROOTFS_PROG = $(PROG)
@@ -39,7 +42,7 @@ COMMONSRCS= $(CMDINETCOMMONDIR)/$(COMMONOBJS:%.o=%.c)
SRCS= $(LOCALSRCS) $(COMMONSRCS)
CPPFLAGS += -I$(CMDINETCOMMONDIR)
-LDLIBS += -lofmt -linetutil -lipadm -lnvpair
+LDLIBS += -lofmt -linetutil -lipadm -lnvpair -lipmp -lcmdutils
LINTFLAGS += -m
ROOTUSRSBINLINKS = $(PROG:%=$(ROOTUSRSBIN)/%)
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c
index e48b32733f..1a1aa5e5ac 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c
@@ -21,11 +21,10 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2017 Nexenta Systems, Inc.
* Copyright (c) 2018, Joyent, Inc.
* Copyright 2017 Gary Mills
* Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
- * Copyright 2021, Tintri by DDN. All rights reserved.
+ * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
* Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
*/
@@ -40,6 +39,8 @@
#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>
@@ -53,21 +54,25 @@
#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_help;
-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 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;
typedef struct cmd {
char *c_name;
@@ -78,12 +83,28 @@ typedef struct cmd {
static cmd_t cmds[] = {
{ "help", do_help, NULL },
/* 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,
+ { "create-if", do_create_ip, "\tcreate-if\t[-t] <interface>" },
+ { "create-ip", do_create_ip, "\tcreate-ip\t[-t] <interface>" },
+ { "delete-if", do_delete_ip, "\tdelete-if\t<interface>\n" },
+ { "delete-ip", do_delete_ip, "\tdelete-ip\t<interface>\n" },
+
+ { "create-ipmp", do_create_ipmp,
+ "\tcreate-ipmp\t[-t] [-i <interface>[,<interface>]...] "
+ "<ipmp-interface>" },
+ { "delete-ipmp", do_delete_ip,
+ "\tdelete-ipmp\t<ipmp-interface>" },
+ { "add-ipmp", do_add_ipmp,
+ "\tadd-ipmp\t[-t] -i <interface>[,<interface>]... "
+ "<ipmp-interface>" },
+ { "remove-ipmp", do_remove_ipmp,
+ "\tremove-ipmp\t[-t] -i <interface>[,<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>" },
@@ -101,14 +122,15 @@ static cmd_t cmds[] = {
"\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" },
+ { "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,
@@ -118,11 +140,11 @@ static cmd_t cmds[] = {
"<addrobj>\n" },
/* protocol properties related sub-commands */
- { "set-prop", do_set_prop,
+ { "set-prop", do_set_prop,
"\tset-prop\t[-t] -p <prop>[+|-]=<value[,...]> <protocol>" },
- { "reset-prop", do_reset_prop,
+ { "reset-prop", do_reset_prop,
"\treset-prop\t[-t] -p <prop> <protocol>" },
- { "show-prop", do_show_prop,
+ { "show-prop", do_show_prop,
"\tshow-prop\t[[-c] -o <field>,...] [-p <prop>,...]"
" [protocol]" }
};
@@ -282,7 +304,7 @@ typedef struct show_addr_args_s {
typedef struct show_if_args_s {
show_if_state_t *si_state;
- ipadm_if_info_list_t *si_info;
+ ipadm_if_info_t *si_info;
} show_if_args_t;
typedef enum {
@@ -296,6 +318,7 @@ typedef enum {
typedef enum {
SI_IFNAME,
+ SI_IFCLASS,
SI_STATE,
SI_CURRENT,
SI_PERSISTENT
@@ -315,6 +338,7 @@ static ofmt_field_t show_addr_fields[] = {
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},
@@ -328,6 +352,11 @@ typedef struct intf_mask {
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.
@@ -349,6 +378,9 @@ 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(char *, ipadm_ipmp_members_t *, ipmp_action_t,
+ uint32_t);
+
static void
usage(int ret)
@@ -419,19 +451,17 @@ main(int argc, char *argv[])
}
/*
- * 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_ip_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':
/*
@@ -444,8 +474,12 @@ do_create_if(int argc, char *argv[], const char *use)
die_opterr(optopt, option, use);
}
}
- if (optind != (argc - 1))
- die("Usage: %s", 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",
@@ -454,6 +488,185 @@ do_create_if(int argc, char *argv[], const char *use)
}
/*
+ * Helpers to parse options into ipadm_ipmp_members_t list, and to free it.
+ */
+static ipadm_ipmp_members_t *
+get_ipmp_members(int argc, char *argv[], const char *use, uint32_t *flags)
+{
+ ipadm_ipmp_members_t *members = NULL;
+ ipadm_ipmp_member_t *member;
+ char *ifname;
+ int option;
+
+
+ opterr = 0;
+ while ((option = getopt_long(argc, argv, ":i:", if_longopts, NULL)) !=
+ -1) {
+ switch (option) {
+ case 't':
+ *flags &= ~IPADM_OPT_PERSIST;
+ break;
+ case 'i':
+ if (members == NULL) {
+ members = calloc(1,
+ sizeof (ipadm_ipmp_members_t));
+ if (members == NULL)
+ die("insufficient memory");
+ list_create(members,
+ sizeof (ipadm_ipmp_member_t),
+ offsetof(ipadm_ipmp_member_t, node));
+ }
+
+ for (ifname = strtok(optarg, ",");
+ ifname != NULL;
+ ifname = strtok(NULL, ",")) {
+ if ((member = calloc(1,
+ sizeof (ipadm_ipmp_member_t))) == NULL)
+ die("insufficient memory");
+
+ if (strlcpy(member->if_name, ifname,
+ sizeof (member->if_name)) >= LIFNAMSIZ)
+ die("Incorrect length of interface "
+ "name: %s", ifname);
+
+ list_insert_tail(members, member);
+ }
+ break;
+ default:
+ die_opterr(optopt, option, use);
+ }
+ }
+
+ if (optind != (argc - 1))
+ die("Usage: %s", use);
+
+ if (members != NULL && list_is_empty(members)) {
+ free(members);
+ members = NULL;
+ }
+
+ return (members);
+}
+
+static void
+free_ipmp_members(ipadm_ipmp_members_t *members)
+{
+ ipadm_ipmp_member_t *member;
+
+ while ((member = list_remove_head(members)) != NULL)
+ free(member);
+
+ list_destroy(members);
+
+ free(members);
+}
+
+/*
+ * 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)
+{
+ uint32_t flags = IPADM_OPT_PERSIST | IPADM_OPT_ACTIVE | IPADM_OPT_IPMP;
+ ipadm_ipmp_members_t *members = NULL;
+ ipmp_handle_t ipmp_handle;
+ int retval;
+
+ 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));
+ }
+
+ members = get_ipmp_members(argc, argv, use, &flags);
+
+ do_create_ip_common(argc, argv, use, flags);
+
+ if (members != NULL) {
+ do_action_ipmp(argv[optind], members, IPMP_ADD_MEMBER, flags);
+ free_ipmp_members(members);
+ }
+}
+
+static void
+do_add_ipmp(int argc, char *argv[], const char *use)
+{
+ uint32_t flags = IPADM_OPT_PERSIST | IPADM_OPT_ACTIVE;
+ ipadm_ipmp_members_t *members;
+
+ members = get_ipmp_members(argc, argv, use, &flags);
+
+ if (members == NULL)
+ die_opterr(optopt, ':', use);
+
+ do_action_ipmp(argv[optind], members, IPMP_ADD_MEMBER, flags);
+ free_ipmp_members(members);
+}
+
+static void
+do_remove_ipmp(int argc, char *argv[], const char *use)
+{
+ uint32_t flags = IPADM_OPT_PERSIST | IPADM_OPT_ACTIVE;
+ ipadm_ipmp_members_t *members;
+
+ members = get_ipmp_members(argc, argv, use, &flags);
+
+ if (members == NULL)
+ die_opterr(optopt, ':', use);
+
+ do_action_ipmp(argv[optind], members, IPMP_REMOVE_MEMBER, flags);
+ free_ipmp_members(members);
+}
+
+static void
+do_action_ipmp(char *ipmp, ipadm_ipmp_members_t *members, ipmp_action_t action,
+ uint32_t flags)
+{
+ ipadm_status_t (*func)(ipadm_handle_t, const char *, const char *,
+ uint32_t);
+ ipadm_status_t status;
+ ipadm_ipmp_member_t *member;
+ char *ifname;
+ const char *msg;
+
+ if (action == IPMP_ADD_MEMBER) {
+ func = ipadm_add_ipmp_member;
+ msg = "Cannot add interface '%s' to IPMP interface '%s': %s";
+ } else {
+ func = ipadm_remove_ipmp_member;
+ msg = "Cannot remove interface '%s' from IPMP interface '%s': "
+ "%s";
+ }
+
+ while ((member = list_remove_head(members)) != NULL) {
+ ifname = member->if_name;
+
+ status = func(iph, ipmp, ifname, flags);
+ if (status != IPADM_SUCCESS)
+ die(msg, ifname, ipmp, ipadm_status2str(status));
+ }
+}
+
+/*
+ * 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.
*/
@@ -480,7 +693,7 @@ do_enable_if(int argc, char *argv[], const char *use)
* Remove an IP interface from both active and persistent configuration.
*/
static void
-do_delete_if(int argc, char *argv[], const char *use)
+do_delete_ip(int argc, char *argv[], const char *use)
{
ipadm_status_t status;
uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
@@ -687,7 +900,7 @@ do_show_ifprop(int argc, char **argv, const char *use)
uint_t proto;
boolean_t m_arg = _B_FALSE;
char *protostr;
- ipadm_if_info_list_t *ifinfo, *ifl;
+ ipadm_if_info_t *ifinfo, *ifp;
ipadm_status_t status;
show_prop_state_t state;
@@ -751,9 +964,8 @@ do_show_ifprop(int argc, char **argv, const char *use)
if (status != IPADM_SUCCESS)
die("Error retrieving interface(s): %s",
ipadm_status2str(status));
- for (ifl = ifinfo; ifl != NULL; ifl = ifl->ifil_next) {
- (void) strlcpy(state.sps_ifname, ifl->ifil_ifi.ifi_name,
- LIFNAMSIZ);
+ for (ifp = ifinfo; ifp != NULL; ifp = ifp->ifi_next) {
+ (void) strlcpy(state.sps_ifname, ifp->ifi_name, LIFNAMSIZ);
state.sps_proto = proto;
show_properties(&state, IPADMPROP_CLASS_IF);
}
@@ -1057,14 +1269,16 @@ die(const char *format, ...)
{
va_list alist;
- format = gettext(format);
- (void) fprintf(stderr, "%s: ", progname);
+ if (format != NULL) {
+ format = gettext(format);
+ (void) fprintf(stderr, "%s: ", progname);
- va_start(alist, format);
- (void) vfprintf(stderr, format, alist);
- va_end(alist);
+ va_start(alist, format);
+ (void) vfprintf(stderr, format, alist);
+ va_end(alist);
- (void) putchar('\n');
+ (void) putchar('\n');
+ }
ipadm_destroy_addrobj(ipaddr);
ipadm_close(iph);
@@ -1624,7 +1838,7 @@ flags2str(uint64_t flags, fmask_t *tbl, boolean_t is_bits,
static boolean_t
is_from_gz(const char *lifname)
{
- ipadm_if_info_list_t *if_info;
+ ipadm_if_info_t *if_info;
char phyname[LIFNAMSIZ], *cp;
boolean_t ret = _B_FALSE;
ipadm_status_t status;
@@ -1647,7 +1861,7 @@ is_from_gz(const char *lifname)
if (status != IPADM_SUCCESS)
return (ret);
- if (if_info->ifil_ifi.ifi_cflags & IFIF_L3PROTECT)
+ if (if_info->ifi_cflags & IFIF_L3PROTECT)
ret = _B_TRUE;
ipadm_free_if_info(if_info);
return (ret);
@@ -1902,8 +2116,8 @@ static boolean_t
print_si_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
{
show_if_args_t *arg = ofarg->ofmt_cbarg;
- ipadm_if_info_list_t *ifinfo = arg->si_info;
- char *ifname = ifinfo->ifil_ifi.ifi_name;
+ ipadm_if_info_t *ifinfo = arg->si_info;
+ char *ifname = ifinfo->ifi_name;
fmask_t intf_state[] = {
{ "ok", IFIS_OK, IPADM_ALL_BITS},
{ "down", IFIS_DOWN, IPADM_ALL_BITS},
@@ -1933,22 +2147,33 @@ print_si_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
{ "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->ifil_ifi.ifi_state, intf_state, _B_FALSE,
+ flags2str(ifinfo->ifi_state, intf_state, _B_FALSE,
buf, bufsize);
break;
case SI_CURRENT:
- flags2str(ifinfo->ifil_ifi.ifi_cflags, intf_cflags, _B_TRUE,
+ flags2str(ifinfo->ifi_cflags, intf_cflags, _B_TRUE,
buf, bufsize);
break;
case SI_PERSISTENT:
- flags2str(ifinfo->ifil_ifi.ifi_pflags, intf_pflags, _B_TRUE,
+ flags2str(ifinfo->ifi_pflags, intf_pflags, _B_TRUE,
buf, bufsize);
break;
default:
@@ -1969,7 +2194,7 @@ do_show_if(int argc, char *argv[], const char *use)
ipadm_status_t status;
show_if_state_t state;
char *fields_str = NULL;
- ipadm_if_info_list_t *if_info, *ptr;
+ ipadm_if_info_t *if_info, *ptr;
show_if_args_t sargs;
int option;
ofmt_handle_t ofmt;
@@ -2014,7 +2239,7 @@ do_show_if(int argc, char *argv[], const char *use)
ipadm_status2str(status));
}
- for (ptr = if_info; ptr != NULL; ptr = ptr->ifil_next) {
+ for (ptr = if_info; ptr != NULL; ptr = ptr->ifi_next) {
sargs.si_info = ptr;
ofmt_print(state.si_ofmt, &sargs);
}