--- old/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c	Mon Aug  5 17:14:36 2019
+++ new/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c	Mon Aug  5 17:14:36 2019
@@ -38,6 +38,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>
@@ -51,20 +53,24 @@
 #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_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;
 
 static void warn(const char *, ...);
 static void die(const char *, ...);
@@ -77,12 +83,27 @@
 
 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,
+	{ "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>" 						},
@@ -90,7 +111,7 @@
 	    "\treset-ifprop\t[-t] -p <prop> -m <protocol> <interface>"	},
 	{ "show-ifprop", do_show_ifprop,
 	    "\tshow-ifprop\t[[-c] -o <field>,...] [-p <prop>,...]\n"
-	    "\t\t\t[-m <protocol>] [interface]\n" 			},
+	    "\t\t\t[-m <protocol>] [interface]\n"			},
 
 	/* address management related sub-commands */
 	{ "create-addr", do_create_addr,
@@ -100,14 +121,15 @@
 	    "\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,
@@ -117,11 +139,11 @@
 	    "<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]"						}
 };
@@ -295,6 +317,7 @@
 
 typedef enum {
 	SI_IFNAME,
+	SI_IFCLASS,
 	SI_STATE,
 	SI_CURRENT,
 	SI_PERSISTENT
@@ -314,6 +337,7 @@
 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},
@@ -327,6 +351,11 @@
 	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.
@@ -346,6 +375,7 @@
 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)
@@ -408,19 +438,17 @@
 }
 
 /*
- * 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':
 			/*
@@ -433,8 +461,12 @@
 			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",
@@ -443,6 +475,124 @@
 }
 
 /*
+ * 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.
  */
@@ -469,7 +619,7 @@
  * 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;
@@ -1044,14 +1194,16 @@
 {
 	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);
@@ -1921,6 +2073,13 @@
 		{ "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) {
@@ -1927,6 +2086,10 @@
 	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);
