xref: /titanic_51/usr/src/cmd/vrrpadm/vrrpadm.c (revision df53e1a116c70dde0788e9b6aff5f893ac34473e)
11cb875aeSCathy Zhou /*
21cb875aeSCathy Zhou  * CDDL HEADER START
31cb875aeSCathy Zhou  *
41cb875aeSCathy Zhou  * The contents of this file are subject to the terms of the
51cb875aeSCathy Zhou  * Common Development and Distribution License (the "License").
61cb875aeSCathy Zhou  * You may not use this file except in compliance with the License.
71cb875aeSCathy Zhou  *
81cb875aeSCathy Zhou  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91cb875aeSCathy Zhou  * or http://www.opensolaris.org/os/licensing.
101cb875aeSCathy Zhou  * See the License for the specific language governing permissions
111cb875aeSCathy Zhou  * and limitations under the License.
121cb875aeSCathy Zhou  *
131cb875aeSCathy Zhou  * When distributing Covered Code, include this CDDL HEADER in each
141cb875aeSCathy Zhou  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151cb875aeSCathy Zhou  * If applicable, add the following below this CDDL HEADER, with the
161cb875aeSCathy Zhou  * fields enclosed by brackets "[]" replaced with your own identifying
171cb875aeSCathy Zhou  * information: Portions Copyright [yyyy] [name of copyright owner]
181cb875aeSCathy Zhou  *
191cb875aeSCathy Zhou  * CDDL HEADER END
201cb875aeSCathy Zhou  */
211cb875aeSCathy Zhou 
221cb875aeSCathy Zhou /*
231cb875aeSCathy Zhou  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
241cb875aeSCathy Zhou  * Use is subject to license terms.
251cb875aeSCathy Zhou  */
261cb875aeSCathy Zhou 
271cb875aeSCathy Zhou #include <sys/types.h>
281cb875aeSCathy Zhou #include <sys/varargs.h>
291cb875aeSCathy Zhou #include <getopt.h>
301cb875aeSCathy Zhou #include <stdio.h>
311cb875aeSCathy Zhou #include <stdlib.h>
321cb875aeSCathy Zhou #include <strings.h>
331cb875aeSCathy Zhou #include <errno.h>
341cb875aeSCathy Zhou #include <locale.h>
351cb875aeSCathy Zhou #include <libintl.h>
361cb875aeSCathy Zhou #include <libvrrpadm.h>
371cb875aeSCathy Zhou #include <ofmt.h>
381cb875aeSCathy Zhou 
391cb875aeSCathy Zhou static vrrp_handle_t	vrrp_vh = NULL;
401cb875aeSCathy Zhou typedef void cmd_func_t(int, char *[], const char *);
411cb875aeSCathy Zhou 
421cb875aeSCathy Zhou static cmd_func_t do_create, do_delete, do_enable, do_disable,
431cb875aeSCathy Zhou     do_modify, do_show;
441cb875aeSCathy Zhou 
451cb875aeSCathy Zhou typedef struct {
461cb875aeSCathy Zhou 	char		*c_name;
471cb875aeSCathy Zhou 	cmd_func_t	*c_fn;
481cb875aeSCathy Zhou 	const char	*c_usage;
491cb875aeSCathy Zhou } cmd_t;
501cb875aeSCathy Zhou 
511cb875aeSCathy Zhou static cmd_t cmds[] = {
521cb875aeSCathy Zhou 	{ "create-router",	do_create,
531cb875aeSCathy Zhou 	    "-V <vrid> -l <link> -A {inet | inet6} [-p <priority>] "
541cb875aeSCathy Zhou 	    "[-i <adv_interval>] [-o <flags>] <router_name>" },
551cb875aeSCathy Zhou 	{ "delete-router",	do_delete,	"<router_name>"		},
561cb875aeSCathy Zhou 	{ "enable-router",	do_enable,	"<router_name>"		},
571cb875aeSCathy Zhou 	{ "disable-router",	do_disable,	"<router_name>"		},
581cb875aeSCathy Zhou 	{ "modify-router",	do_modify,
591cb875aeSCathy Zhou 	    "[-p <priority>] [-i <adv_interval>] [-o <flags>] <router_name>" },
601cb875aeSCathy Zhou 	{ "show-router",	do_show,
611cb875aeSCathy Zhou 	    "[-P | -x] [-o field[,...]] [-p] [<router_name>]"	}
621cb875aeSCathy Zhou };
631cb875aeSCathy Zhou 
641cb875aeSCathy Zhou static const struct option lopts[] = {
651cb875aeSCathy Zhou 	{"vrid",		required_argument,	0, 'V'},
661cb875aeSCathy Zhou 	{"link",		required_argument,	0, 'l'},
671cb875aeSCathy Zhou 	{"address_family",	required_argument,	0, 'A'},
681cb875aeSCathy Zhou 	{"priority",		required_argument,	0, 'p'},
691cb875aeSCathy Zhou 	{"adv_interval",	required_argument,	0, 'i'},
701cb875aeSCathy Zhou 	{"flags",		required_argument,	0, 'o'},
711cb875aeSCathy Zhou 	{ 0, 0, 0, 0 }
721cb875aeSCathy Zhou };
731cb875aeSCathy Zhou 
741cb875aeSCathy Zhou static const struct option l_show_opts[] = {
751cb875aeSCathy Zhou 	{"peer",	no_argument,		0, 'P'},
761cb875aeSCathy Zhou 	{"parsable",	no_argument,		0, 'p'},
771cb875aeSCathy Zhou 	{"extended",	no_argument,		0, 'x'},
781cb875aeSCathy Zhou 	{"output",	required_argument,	0, 'o'},
791cb875aeSCathy Zhou 	{ 0, 0, 0, 0 }
801cb875aeSCathy Zhou };
811cb875aeSCathy Zhou 
821cb875aeSCathy Zhou static ofmt_cb_t sfunc_vrrp_conf;
831cb875aeSCathy Zhou 
841cb875aeSCathy Zhou /*
851cb875aeSCathy Zhou  * structures for 'dladm show-link -s' (print statistics)
861cb875aeSCathy Zhou  */
871cb875aeSCathy Zhou enum {
881cb875aeSCathy Zhou 	ROUTER_NAME,
891cb875aeSCathy Zhou 	ROUTER_VRID,
901cb875aeSCathy Zhou 	ROUTER_LINK,
911cb875aeSCathy Zhou 	ROUTER_VNIC,
921cb875aeSCathy Zhou 	ROUTER_AF,
931cb875aeSCathy Zhou 	ROUTER_PRIO,
941cb875aeSCathy Zhou 	ROUTER_ADV_INTV,
951cb875aeSCathy Zhou 	ROUTER_MODE,
961cb875aeSCathy Zhou 	ROUTER_STATE,
971cb875aeSCathy Zhou 	ROUTER_PRV_STAT,
981cb875aeSCathy Zhou 	ROUTER_STAT_LAST,
991cb875aeSCathy Zhou 	ROUTER_PEER,
1001cb875aeSCathy Zhou 	ROUTER_P_PRIO,
1011cb875aeSCathy Zhou 	ROUTER_P_INTV,
1021cb875aeSCathy Zhou 	ROUTER_P_ADV_LAST,
1031cb875aeSCathy Zhou 	ROUTER_M_DOWN_INTV,
1041cb875aeSCathy Zhou 	ROUTER_PRIMARY_IP,
1051cb875aeSCathy Zhou 	ROUTER_VIRTUAL_IPS,
1061cb875aeSCathy Zhou 	ROUTER_VIP_CNT
1071cb875aeSCathy Zhou };
1081cb875aeSCathy Zhou 
1091cb875aeSCathy Zhou /*
1101cb875aeSCathy Zhou  * structures for 'vrrpadm show-router'
1111cb875aeSCathy Zhou  */
1121cb875aeSCathy Zhou static const ofmt_field_t show_print_fields[] = {
1131cb875aeSCathy Zhou /* name,	field width,	index,			callback */
1141cb875aeSCathy Zhou { "NAME",		8,	ROUTER_NAME,		sfunc_vrrp_conf	},
1151cb875aeSCathy Zhou { "VRID",		5,	ROUTER_VRID,		sfunc_vrrp_conf	},
1161cb875aeSCathy Zhou { "LINK",		8,	ROUTER_LINK,		sfunc_vrrp_conf },
1171cb875aeSCathy Zhou { "VNIC",		8,	ROUTER_VNIC,		sfunc_vrrp_conf },
1181cb875aeSCathy Zhou { "AF",			5,	ROUTER_AF,		sfunc_vrrp_conf },
1191cb875aeSCathy Zhou { "PRIO",		5,	ROUTER_PRIO,		sfunc_vrrp_conf },
1201cb875aeSCathy Zhou { "ADV_INTV",		9,	ROUTER_ADV_INTV,	sfunc_vrrp_conf },
1211cb875aeSCathy Zhou { "MODE",		6,	ROUTER_MODE,		sfunc_vrrp_conf	},
1221cb875aeSCathy Zhou { "STATE",		6,	ROUTER_STATE,		sfunc_vrrp_conf },
1231cb875aeSCathy Zhou { "PRV_STAT",		9, 	ROUTER_PRV_STAT,	sfunc_vrrp_conf	},
1241cb875aeSCathy Zhou { "STAT_LAST",		10,	ROUTER_STAT_LAST,	sfunc_vrrp_conf },
1251cb875aeSCathy Zhou { "PEER",		20,	ROUTER_PEER,		sfunc_vrrp_conf	},
1261cb875aeSCathy Zhou { "P_PRIO",		7,	ROUTER_P_PRIO,		sfunc_vrrp_conf	},
1271cb875aeSCathy Zhou { "P_INTV",		9,	ROUTER_P_INTV,		sfunc_vrrp_conf	},
1281cb875aeSCathy Zhou { "P_ADV_LAST",		11,	ROUTER_P_ADV_LAST,	sfunc_vrrp_conf	},
1291cb875aeSCathy Zhou { "M_DOWN_INTV",	12,	ROUTER_M_DOWN_INTV,	sfunc_vrrp_conf	},
1301cb875aeSCathy Zhou { "PRIMARY_IP",		20,	ROUTER_PRIMARY_IP,	sfunc_vrrp_conf	},
1311cb875aeSCathy Zhou { "VIRTUAL_IPS",	40,	ROUTER_VIRTUAL_IPS,	sfunc_vrrp_conf	},
1321cb875aeSCathy Zhou { "VIP_CNT",		7,	ROUTER_VIP_CNT,		sfunc_vrrp_conf	},
1331cb875aeSCathy Zhou { NULL,			0, 	0,			NULL}}
1341cb875aeSCathy Zhou ;
1351cb875aeSCathy Zhou 
1361cb875aeSCathy Zhou static vrrp_err_t do_show_router(const char *, ofmt_handle_t);
1371cb875aeSCathy Zhou static int str2opt(char *opts, uint32_t *, boolean_t *, boolean_t *);
1381cb875aeSCathy Zhou static char *timeval_since_str(int, char *, size_t);
1391cb875aeSCathy Zhou 
1401cb875aeSCathy Zhou static void usage();
1411cb875aeSCathy Zhou static void warn(const char *, ...);
1421cb875aeSCathy Zhou static void err_exit(const char *, ...);
1431cb875aeSCathy Zhou static void opterr_exit(int, int, const char *);
1441cb875aeSCathy Zhou 
1451cb875aeSCathy Zhou int
1461cb875aeSCathy Zhou main(int argc, char *argv[])
1471cb875aeSCathy Zhou {
1481cb875aeSCathy Zhou 	vrrp_err_t	err;
1491cb875aeSCathy Zhou 	int		i;
1501cb875aeSCathy Zhou 	cmd_t		*cp;
1511cb875aeSCathy Zhou 
1521cb875aeSCathy Zhou 	(void) setlocale(LC_ALL, "");
1531cb875aeSCathy Zhou 	(void) textdomain(TEXT_DOMAIN);
1541cb875aeSCathy Zhou 
1551cb875aeSCathy Zhou 	if (argv[1] == NULL)
1561cb875aeSCathy Zhou 		usage();
1571cb875aeSCathy Zhou 
1581cb875aeSCathy Zhou 	if ((err = vrrp_open(&vrrp_vh)) != VRRP_SUCCESS)
1591cb875aeSCathy Zhou 		err_exit("operation failed: %s", vrrp_err2str(err));
1601cb875aeSCathy Zhou 
1611cb875aeSCathy Zhou 	for (i = 0; i < sizeof (cmds) / sizeof (cmd_t); i++) {
1621cb875aeSCathy Zhou 		cp = &cmds[i];
1631cb875aeSCathy Zhou 		if (strcmp(argv[1], cp->c_name) == 0) {
1641cb875aeSCathy Zhou 			cp->c_fn(argc - 1, &argv[1], cp->c_usage);
1651cb875aeSCathy Zhou 			vrrp_close(vrrp_vh);
1661cb875aeSCathy Zhou 			return (EXIT_SUCCESS);
1671cb875aeSCathy Zhou 		}
1681cb875aeSCathy Zhou 	}
1691cb875aeSCathy Zhou 
1701cb875aeSCathy Zhou 	usage();
1711cb875aeSCathy Zhou 	return (EXIT_FAILURE);
1721cb875aeSCathy Zhou }
1731cb875aeSCathy Zhou 
1741cb875aeSCathy Zhou static void
1751cb875aeSCathy Zhou do_create(int argc, char *argv[], const char *usage)
1761cb875aeSCathy Zhou {
1771cb875aeSCathy Zhou 	vrrp_vr_conf_t		conf;
1781cb875aeSCathy Zhou 	int			c;
1791cb875aeSCathy Zhou 	uint32_t		create_mask = 0, mask;
1801cb875aeSCathy Zhou 	char			*endp;
1811cb875aeSCathy Zhou 	vrrp_err_t		err;
1821cb875aeSCathy Zhou 
1831cb875aeSCathy Zhou 	/*
1841cb875aeSCathy Zhou 	 * default value
1851cb875aeSCathy Zhou 	 */
1861cb875aeSCathy Zhou 	bzero(&conf, sizeof (vrrp_vr_conf_t));
1871cb875aeSCathy Zhou 	conf.vvc_vrid = VRRP_VRID_NONE;
1881cb875aeSCathy Zhou 	conf.vvc_af = AF_UNSPEC;
1891cb875aeSCathy Zhou 	conf.vvc_pri = VRRP_PRI_DEFAULT;
1901cb875aeSCathy Zhou 	conf.vvc_adver_int = VRRP_MAX_ADVER_INT_DFLT;
1911cb875aeSCathy Zhou 	conf.vvc_preempt = B_TRUE;
1921cb875aeSCathy Zhou 	conf.vvc_accept = B_TRUE;
1931cb875aeSCathy Zhou 	conf.vvc_enabled = B_TRUE;
1941cb875aeSCathy Zhou 
1951cb875aeSCathy Zhou 	while ((c = getopt_long(argc, argv, ":V:l:p:i:o:A:f", lopts,
1961cb875aeSCathy Zhou 	    NULL)) != EOF) {
1971cb875aeSCathy Zhou 		switch (c) {
1981cb875aeSCathy Zhou 		case 'l':
1991cb875aeSCathy Zhou 			if (strlcpy(conf.vvc_link, optarg,
2001cb875aeSCathy Zhou 			    sizeof (conf.vvc_link)) >=
2011cb875aeSCathy Zhou 			    sizeof (conf.vvc_link)) {
2021cb875aeSCathy Zhou 				err_exit("invalid data-link name %s", optarg);
2031cb875aeSCathy Zhou 			}
2041cb875aeSCathy Zhou 			break;
2051cb875aeSCathy Zhou 		case 'i':
2061cb875aeSCathy Zhou 			if (create_mask & VRRP_CONF_INTERVAL)
2071cb875aeSCathy Zhou 				err_exit("duplicate '-i' option");
2081cb875aeSCathy Zhou 
2091cb875aeSCathy Zhou 			create_mask |= VRRP_CONF_INTERVAL;
2101cb875aeSCathy Zhou 			conf.vvc_adver_int = (uint32_t)strtol(optarg, &endp, 0);
2111cb875aeSCathy Zhou 			if ((*endp) != '\0' ||
2121cb875aeSCathy Zhou 			    conf.vvc_adver_int < VRRP_MAX_ADVER_INT_MIN ||
2131cb875aeSCathy Zhou 			    conf.vvc_adver_int > VRRP_MAX_ADVER_INT_MAX ||
2141cb875aeSCathy Zhou 			    (conf.vvc_adver_int == 0 && errno != 0)) {
2151cb875aeSCathy Zhou 				err_exit("invalid advertisement interval");
2161cb875aeSCathy Zhou 			}
2171cb875aeSCathy Zhou 			break;
2181cb875aeSCathy Zhou 		case 'p':
2191cb875aeSCathy Zhou 			if (create_mask & VRRP_CONF_PRIORITY)
2201cb875aeSCathy Zhou 				err_exit("duplicate '-p' option");
2211cb875aeSCathy Zhou 
2221cb875aeSCathy Zhou 			create_mask |= VRRP_CONF_PRIORITY;
2231cb875aeSCathy Zhou 			conf.vvc_pri = strtol(optarg, &endp, 0);
2241cb875aeSCathy Zhou 			if ((*endp) != '\0' || conf.vvc_pri < VRRP_PRI_MIN ||
2251cb875aeSCathy Zhou 			    conf.vvc_pri > VRRP_PRI_OWNER ||
2261cb875aeSCathy Zhou 			    (conf.vvc_pri == 0 && errno != 0)) {
2271cb875aeSCathy Zhou 				err_exit("invalid priority");
2281cb875aeSCathy Zhou 			}
2291cb875aeSCathy Zhou 			break;
2301cb875aeSCathy Zhou 		case 'o':
2311cb875aeSCathy Zhou 			mask = 0;
2321cb875aeSCathy Zhou 			if (str2opt(optarg, &mask,
2331cb875aeSCathy Zhou 			    &conf.vvc_preempt, &conf.vvc_accept) != 0) {
2341cb875aeSCathy Zhou 				err_exit("invalid options: %s", optarg);
2351cb875aeSCathy Zhou 			}
2361cb875aeSCathy Zhou 			if (mask & create_mask & VRRP_CONF_PREEMPT)
2371cb875aeSCathy Zhou 				err_exit("duplicate '-o preempt' option");
2381cb875aeSCathy Zhou 			else if (mask & create_mask & VRRP_CONF_ACCEPT)
2391cb875aeSCathy Zhou 				err_exit("duplicate '-o accept' option");
2401cb875aeSCathy Zhou 			create_mask |= mask;
2411cb875aeSCathy Zhou 			break;
2421cb875aeSCathy Zhou 		case 'V':
2431cb875aeSCathy Zhou 			if (conf.vvc_vrid != VRRP_VRID_NONE)
2441cb875aeSCathy Zhou 				err_exit("duplicate '-V' option");
2451cb875aeSCathy Zhou 
2461cb875aeSCathy Zhou 			conf.vvc_vrid = strtol(optarg, &endp, 0);
2471cb875aeSCathy Zhou 			if ((*endp) != '\0' || conf.vvc_vrid < VRRP_VRID_MIN ||
2481cb875aeSCathy Zhou 			    conf.vvc_vrid > VRRP_VRID_MAX ||
2491cb875aeSCathy Zhou 			    (conf.vvc_vrid == 0 && errno != 0)) {
2501cb875aeSCathy Zhou 				err_exit("invalid VRID");
2511cb875aeSCathy Zhou 			}
2521cb875aeSCathy Zhou 			break;
2531cb875aeSCathy Zhou 		case 'A':
2541cb875aeSCathy Zhou 			if (conf.vvc_af != AF_UNSPEC)
2551cb875aeSCathy Zhou 				err_exit("duplicate '-A' option");
2561cb875aeSCathy Zhou 
2571cb875aeSCathy Zhou 			if (strcmp(optarg, "inet") == 0)
2581cb875aeSCathy Zhou 				conf.vvc_af = AF_INET;
2591cb875aeSCathy Zhou 			else if (strcmp(optarg, "inet6") == 0)
2601cb875aeSCathy Zhou 				conf.vvc_af = AF_INET6;
2611cb875aeSCathy Zhou 			else
2621cb875aeSCathy Zhou 				err_exit("invalid address family");
2631cb875aeSCathy Zhou 			break;
2641cb875aeSCathy Zhou 		default:
2651cb875aeSCathy Zhou 			opterr_exit(optopt, c, usage);
2661cb875aeSCathy Zhou 		}
2671cb875aeSCathy Zhou 	}
2681cb875aeSCathy Zhou 
2691cb875aeSCathy Zhou 	if (argc - optind > 1)
2701cb875aeSCathy Zhou 		err_exit("usage: %s", gettext(usage));
2711cb875aeSCathy Zhou 
2721cb875aeSCathy Zhou 	if (optind != argc - 1)
2731cb875aeSCathy Zhou 		err_exit("VRRP name not specified");
2741cb875aeSCathy Zhou 
2751cb875aeSCathy Zhou 	if (strlcpy(conf.vvc_name, argv[optind],
2761cb875aeSCathy Zhou 	    sizeof (conf.vvc_name)) >= sizeof (conf.vvc_name)) {
2771cb875aeSCathy Zhou 		err_exit("Invalid router name %s", argv[optind]);
2781cb875aeSCathy Zhou 	}
2791cb875aeSCathy Zhou 
2801cb875aeSCathy Zhou 	if (conf.vvc_vrid == VRRP_VRID_NONE)
2811cb875aeSCathy Zhou 		err_exit("VRID not specified");
2821cb875aeSCathy Zhou 
2831cb875aeSCathy Zhou 	if (conf.vvc_af == AF_UNSPEC)
2841cb875aeSCathy Zhou 		err_exit("address family not specified");
2851cb875aeSCathy Zhou 
2861cb875aeSCathy Zhou 	if (strlen(conf.vvc_link) == 0)
2871cb875aeSCathy Zhou 		err_exit("link name not specified");
2881cb875aeSCathy Zhou 
2891cb875aeSCathy Zhou 	if (!conf.vvc_accept && conf.vvc_pri == VRRP_PRI_OWNER)
2901cb875aeSCathy Zhou 		err_exit("accept_mode must be true for virtual IP owner");
2911cb875aeSCathy Zhou 
2921cb875aeSCathy Zhou done:
2931cb875aeSCathy Zhou 	if ((err = vrrp_create(vrrp_vh, &conf)) == VRRP_SUCCESS)
2941cb875aeSCathy Zhou 		return;
2951cb875aeSCathy Zhou 
2961cb875aeSCathy Zhou 	err_exit("create-router failed: %s", vrrp_err2str(err));
2971cb875aeSCathy Zhou }
2981cb875aeSCathy Zhou 
2991cb875aeSCathy Zhou static void
3001cb875aeSCathy Zhou do_delete(int argc, char *argv[], const char *use)
3011cb875aeSCathy Zhou {
3021cb875aeSCathy Zhou 	vrrp_err_t	err;
3031cb875aeSCathy Zhou 
3041cb875aeSCathy Zhou 	if (argc != 2)
3051cb875aeSCathy Zhou 		err_exit("usage: %s", gettext(use));
3061cb875aeSCathy Zhou 
3071cb875aeSCathy Zhou 	if ((err = vrrp_delete(vrrp_vh, argv[1])) != VRRP_SUCCESS)
3081cb875aeSCathy Zhou 		err_exit("delete-router failed: %s", vrrp_err2str(err));
3091cb875aeSCathy Zhou }
3101cb875aeSCathy Zhou 
3111cb875aeSCathy Zhou static void
3121cb875aeSCathy Zhou do_enable(int argc, char *argv[], const char *use)
3131cb875aeSCathy Zhou {
3141cb875aeSCathy Zhou 	vrrp_err_t	err;
3151cb875aeSCathy Zhou 
3161cb875aeSCathy Zhou 	if (argc != 2)
3171cb875aeSCathy Zhou 		err_exit("usage: %s", gettext(use));
3181cb875aeSCathy Zhou 
3191cb875aeSCathy Zhou 	if ((err = vrrp_enable(vrrp_vh, argv[1])) != VRRP_SUCCESS)
3201cb875aeSCathy Zhou 		err_exit("enable-router failed: %s", vrrp_err2str(err));
3211cb875aeSCathy Zhou }
3221cb875aeSCathy Zhou 
3231cb875aeSCathy Zhou static void
3241cb875aeSCathy Zhou do_disable(int argc, char *argv[], const char *use)
3251cb875aeSCathy Zhou {
3261cb875aeSCathy Zhou 	vrrp_err_t	err;
3271cb875aeSCathy Zhou 
3281cb875aeSCathy Zhou 	if (argc != 2)
3291cb875aeSCathy Zhou 		err_exit("usage: %s", gettext(use));
3301cb875aeSCathy Zhou 
3311cb875aeSCathy Zhou 	if ((err = vrrp_disable(vrrp_vh, argv[1])) != VRRP_SUCCESS)
3321cb875aeSCathy Zhou 		err_exit("disable-router failed: %s", vrrp_err2str(err));
3331cb875aeSCathy Zhou }
3341cb875aeSCathy Zhou 
3351cb875aeSCathy Zhou static void
3361cb875aeSCathy Zhou do_modify(int argc, char *argv[], const char *use)
3371cb875aeSCathy Zhou {
3381cb875aeSCathy Zhou 	vrrp_vr_conf_t	conf;
3391cb875aeSCathy Zhou 	vrrp_err_t	err;
3401cb875aeSCathy Zhou 	uint32_t	modify_mask = 0, mask;
3411cb875aeSCathy Zhou 	char		*endp;
3421cb875aeSCathy Zhou 	int		c;
3431cb875aeSCathy Zhou 
3441cb875aeSCathy Zhou 	while ((c = getopt_long(argc, argv, ":i:p:o:", lopts, NULL)) != EOF) {
3451cb875aeSCathy Zhou 		switch (c) {
3461cb875aeSCathy Zhou 		case 'i':
3471cb875aeSCathy Zhou 			if (modify_mask & VRRP_CONF_INTERVAL)
3481cb875aeSCathy Zhou 				err_exit("duplicate '-i' option");
3491cb875aeSCathy Zhou 
3501cb875aeSCathy Zhou 			modify_mask |= VRRP_CONF_INTERVAL;
3511cb875aeSCathy Zhou 			conf.vvc_adver_int = (uint32_t)strtol(optarg, &endp, 0);
3521cb875aeSCathy Zhou 			if ((*endp) != '\0' ||
3531cb875aeSCathy Zhou 			    conf.vvc_adver_int < VRRP_MAX_ADVER_INT_MIN ||
3541cb875aeSCathy Zhou 			    conf.vvc_adver_int > VRRP_MAX_ADVER_INT_MAX ||
3551cb875aeSCathy Zhou 			    (conf.vvc_adver_int == 0 && errno != 0)) {
3561cb875aeSCathy Zhou 				err_exit("invalid advertisement interval");
3571cb875aeSCathy Zhou 			}
3581cb875aeSCathy Zhou 			break;
3591cb875aeSCathy Zhou 		case 'o':
3601cb875aeSCathy Zhou 			mask = 0;
3611cb875aeSCathy Zhou 			if (str2opt(optarg, &mask, &conf.vvc_preempt,
3621cb875aeSCathy Zhou 			    &conf.vvc_accept) != 0) {
3631cb875aeSCathy Zhou 				err_exit("Invalid options");
3641cb875aeSCathy Zhou 			}
3651cb875aeSCathy Zhou 			if (mask & modify_mask & VRRP_CONF_PREEMPT)
3661cb875aeSCathy Zhou 				err_exit("duplicate '-o preempt' option");
3671cb875aeSCathy Zhou 			else if (mask & modify_mask & VRRP_CONF_ACCEPT)
3681cb875aeSCathy Zhou 				err_exit("duplicate '-o accept' option");
3691cb875aeSCathy Zhou 			modify_mask |= mask;
3701cb875aeSCathy Zhou 			break;
3711cb875aeSCathy Zhou 		case 'p':
3721cb875aeSCathy Zhou 			if (modify_mask & VRRP_CONF_PRIORITY)
3731cb875aeSCathy Zhou 				err_exit("duplicate '-p' option");
3741cb875aeSCathy Zhou 
3751cb875aeSCathy Zhou 			modify_mask |= VRRP_CONF_PRIORITY;
3761cb875aeSCathy Zhou 			conf.vvc_pri = strtol(optarg, &endp, 0);
3771cb875aeSCathy Zhou 			if ((*endp) != '\0' || conf.vvc_pri < VRRP_PRI_MIN ||
3781cb875aeSCathy Zhou 			    conf.vvc_pri > VRRP_PRI_OWNER ||
3791cb875aeSCathy Zhou 			    (conf.vvc_pri == 0 && errno != 0)) {
3801cb875aeSCathy Zhou 				err_exit("invalid priority");
3811cb875aeSCathy Zhou 			}
3821cb875aeSCathy Zhou 			break;
3831cb875aeSCathy Zhou 		default:
3841cb875aeSCathy Zhou 			opterr_exit(optopt, c, use);
3851cb875aeSCathy Zhou 		}
3861cb875aeSCathy Zhou 	}
3871cb875aeSCathy Zhou 
3881cb875aeSCathy Zhou 	if (argc - optind > 1)
3891cb875aeSCathy Zhou 		err_exit("usage: %s", gettext(use));
3901cb875aeSCathy Zhou 
3911cb875aeSCathy Zhou 	if (optind != argc - 1)
3921cb875aeSCathy Zhou 		err_exit("VRRP name not specified.");
3931cb875aeSCathy Zhou 
3941cb875aeSCathy Zhou 	if (strlcpy(conf.vvc_name, argv[optind], sizeof (conf.vvc_name)) >=
3951cb875aeSCathy Zhou 	    sizeof (conf.vvc_name)) {
3961cb875aeSCathy Zhou 		err_exit("invalid router name %s", argv[optind]);
3971cb875aeSCathy Zhou 	}
3981cb875aeSCathy Zhou 
3991cb875aeSCathy Zhou 	if ((modify_mask & VRRP_CONF_ACCEPT) && !conf.vvc_accept &&
4001cb875aeSCathy Zhou 	    (modify_mask & VRRP_CONF_PRIORITY) &&
4011cb875aeSCathy Zhou 	    conf.vvc_pri == VRRP_PRI_OWNER) {
4021cb875aeSCathy Zhou 		err_exit("accept_mode must be true for virtual IP owner");
4031cb875aeSCathy Zhou 	}
4041cb875aeSCathy Zhou 
4051cb875aeSCathy Zhou 	if (modify_mask == 0)
4061cb875aeSCathy Zhou 		usage();
4071cb875aeSCathy Zhou 
4081cb875aeSCathy Zhou 	err = vrrp_modify(vrrp_vh, &conf, modify_mask);
4091cb875aeSCathy Zhou 	if (err != VRRP_SUCCESS)
4101cb875aeSCathy Zhou 		err_exit("modify-router failed: %s", vrrp_err2str(err));
4111cb875aeSCathy Zhou }
4121cb875aeSCathy Zhou 
4131cb875aeSCathy Zhou /*
4141cb875aeSCathy Zhou  * 'show-router' one VRRP router.
4151cb875aeSCathy Zhou  */
4161cb875aeSCathy Zhou static vrrp_err_t
4171cb875aeSCathy Zhou do_show_router(const char *vn, ofmt_handle_t ofmt)
4181cb875aeSCathy Zhou {
4191cb875aeSCathy Zhou 	vrrp_queryinfo_t	*vq;
4201cb875aeSCathy Zhou 	vrrp_err_t		err;
4211cb875aeSCathy Zhou 
4221cb875aeSCathy Zhou 	if ((err = vrrp_query(vrrp_vh, vn, &vq)) != VRRP_SUCCESS)
4231cb875aeSCathy Zhou 		return (err);
4241cb875aeSCathy Zhou 
4251cb875aeSCathy Zhou 	ofmt_print(ofmt, vq);
4261cb875aeSCathy Zhou 	free(vq);
4271cb875aeSCathy Zhou 	return (VRRP_SUCCESS);
4281cb875aeSCathy Zhou }
4291cb875aeSCathy Zhou 
4301cb875aeSCathy Zhou static void
4311cb875aeSCathy Zhou do_show(int argc, char *argv[], const char *use)
4321cb875aeSCathy Zhou {
4331cb875aeSCathy Zhou 	int			c;
4341cb875aeSCathy Zhou 	char			*fields_str = NULL;
4351cb875aeSCathy Zhou 	char			*names = NULL, *router;
4361cb875aeSCathy Zhou 	uint32_t		i, in_cnt = 0, out_cnt;
4371cb875aeSCathy Zhou 	ofmt_status_t		oferr;
4381cb875aeSCathy Zhou 	ofmt_handle_t		ofmt;
4391cb875aeSCathy Zhou 	uint_t			ofmt_flags = 0;
4401cb875aeSCathy Zhou 	vrrp_err_t		err = VRRP_SUCCESS;
4411cb875aeSCathy Zhou 	boolean_t		P_opt, x_opt;
4421cb875aeSCathy Zhou 
4431cb875aeSCathy Zhou 	static char		*dft_fields_str =
4441cb875aeSCathy Zhou 	    "NAME,VRID,LINK,AF,PRIO,ADV_INTV,MODE,STATE,VNIC";
4451cb875aeSCathy Zhou 	static char		*ext_fields_str =
4461cb875aeSCathy Zhou 	    "NAME,STATE,PRV_STAT,STAT_LAST,VNIC,PRIMARY_IP,VIRTUAL_IPS";
4471cb875aeSCathy Zhou 	static char		*peer_fields_str =
4481cb875aeSCathy Zhou 	    "NAME,PEER,P_PRIO,P_INTV,P_ADV_LAST,M_DOWN_INTV";
4491cb875aeSCathy Zhou 	/*
4501cb875aeSCathy Zhou 	 * If parsable output is requested, add VIP_CNT into the output
4511cb875aeSCathy Zhou 	 * for extended output. It is not needed for human-readable
4521cb875aeSCathy Zhou 	 * output as it is obvious from the VIRTUAL_IPS list.
4531cb875aeSCathy Zhou 	 */
4541cb875aeSCathy Zhou 	static char		*ext_parsable_fields_str =
4551cb875aeSCathy Zhou 	    "NAME,STATE,PRV_STAT,STAT_LAST,VNIC,PRIMARY_IP,VIP_CNT,"
4561cb875aeSCathy Zhou 	    "VIRTUAL_IPS";
4571cb875aeSCathy Zhou 
4581cb875aeSCathy Zhou 	P_opt = x_opt = B_FALSE;
4591cb875aeSCathy Zhou 	fields_str = dft_fields_str;
4601cb875aeSCathy Zhou 	while ((c = getopt_long(argc, argv, ":Pxpo:", l_show_opts,
4611cb875aeSCathy Zhou 	    NULL)) != EOF) {
4621cb875aeSCathy Zhou 		switch (c) {
4631cb875aeSCathy Zhou 		case 'o':
4641cb875aeSCathy Zhou 			fields_str = optarg;
4651cb875aeSCathy Zhou 			break;
4661cb875aeSCathy Zhou 		case 'p':
4671cb875aeSCathy Zhou 			ofmt_flags |= OFMT_PARSABLE;
4681cb875aeSCathy Zhou 			break;
4691cb875aeSCathy Zhou 		case 'P':
4701cb875aeSCathy Zhou 			P_opt = B_TRUE;
4711cb875aeSCathy Zhou 			fields_str = peer_fields_str;
4721cb875aeSCathy Zhou 			break;
4731cb875aeSCathy Zhou 		case 'x':
4741cb875aeSCathy Zhou 			x_opt = B_TRUE;
4751cb875aeSCathy Zhou 			fields_str = ext_fields_str;
4761cb875aeSCathy Zhou 			break;
4771cb875aeSCathy Zhou 		default:
4781cb875aeSCathy Zhou 			opterr_exit(optopt, c, use);
4791cb875aeSCathy Zhou 		}
4801cb875aeSCathy Zhou 	}
4811cb875aeSCathy Zhou 
4821cb875aeSCathy Zhou 	if (x_opt && P_opt)
4831cb875aeSCathy Zhou 		err_exit("incompatible -P and -x options");
4841cb875aeSCathy Zhou 
4851cb875aeSCathy Zhou 	/*
4861cb875aeSCathy Zhou 	 * If parsable output is requested, add VIP_CNT into the output
4871cb875aeSCathy Zhou 	 * for extended output.
4881cb875aeSCathy Zhou 	 */
4891cb875aeSCathy Zhou 	if ((ofmt_flags & OFMT_PARSABLE) && (fields_str == ext_fields_str))
4901cb875aeSCathy Zhou 		fields_str = ext_parsable_fields_str;
4911cb875aeSCathy Zhou 
4921cb875aeSCathy Zhou 	if ((oferr = ofmt_open(fields_str, show_print_fields, ofmt_flags,
4931cb875aeSCathy Zhou 	    0, &ofmt)) != OFMT_SUCCESS) {
4941cb875aeSCathy Zhou 		char buf[OFMT_BUFSIZE];
4951cb875aeSCathy Zhou 
4961cb875aeSCathy Zhou 		/*
4971cb875aeSCathy Zhou 		 * If some fields were badly formed in human-friendly mode, we
4981cb875aeSCathy Zhou 		 * emit a warning and continue.  Otherwise exit immediately.
4991cb875aeSCathy Zhou 		 */
5001cb875aeSCathy Zhou 		(void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf));
5011cb875aeSCathy Zhou 		if (oferr != OFMT_EBADFIELDS || (ofmt_flags & OFMT_PARSABLE)) {
5021cb875aeSCathy Zhou 			ofmt_close(ofmt);
5031cb875aeSCathy Zhou 			err_exit(buf);
5041cb875aeSCathy Zhou 		} else {
5051cb875aeSCathy Zhou 			warn(buf);
5061cb875aeSCathy Zhou 		}
5071cb875aeSCathy Zhou 	}
5081cb875aeSCathy Zhou 
5091cb875aeSCathy Zhou 	/* Show one router */
5101cb875aeSCathy Zhou 	if (optind == argc - 1) {
5111cb875aeSCathy Zhou 		err = do_show_router(argv[optind], ofmt);
5121cb875aeSCathy Zhou 		goto done;
5131cb875aeSCathy Zhou 	}
5141cb875aeSCathy Zhou 
5151cb875aeSCathy Zhou 	/*
5161cb875aeSCathy Zhou 	 * Show all routers. First set in_cnt to 0 to find out the number
5171cb875aeSCathy Zhou 	 * of vrrp routers.
5181cb875aeSCathy Zhou 	 */
5191cb875aeSCathy Zhou again:
5201cb875aeSCathy Zhou 	if ((in_cnt != 0) && (names = malloc(in_cnt * VRRP_NAME_MAX)) == NULL) {
5211cb875aeSCathy Zhou 		err = VRRP_ENOMEM;
5221cb875aeSCathy Zhou 		goto done;
5231cb875aeSCathy Zhou 	}
5241cb875aeSCathy Zhou 
5251cb875aeSCathy Zhou 	out_cnt = in_cnt;
5261cb875aeSCathy Zhou 	if ((err = vrrp_list(vrrp_vh, VRRP_VRID_NONE, NULL, AF_UNSPEC,
5271cb875aeSCathy Zhou 	    &out_cnt, names)) != VRRP_SUCCESS) {
5281cb875aeSCathy Zhou 		free(names);
5291cb875aeSCathy Zhou 		goto done;
5301cb875aeSCathy Zhou 	}
5311cb875aeSCathy Zhou 
5321cb875aeSCathy Zhou 	/*
5331cb875aeSCathy Zhou 	 * The VRRP routers has been changed between two vrrp_list()
5341cb875aeSCathy Zhou 	 * calls, try again.
5351cb875aeSCathy Zhou 	 */
5361cb875aeSCathy Zhou 	if (out_cnt > in_cnt) {
5371cb875aeSCathy Zhou 		in_cnt = out_cnt;
5381cb875aeSCathy Zhou 		free(names);
5391cb875aeSCathy Zhou 		goto again;
5401cb875aeSCathy Zhou 	}
5411cb875aeSCathy Zhou 
5421cb875aeSCathy Zhou 	/*
5431cb875aeSCathy Zhou 	 * Each VRRP router name is separated by '\0`
5441cb875aeSCathy Zhou 	 */
5451cb875aeSCathy Zhou 	router = names;
5461cb875aeSCathy Zhou 	for (i = 0; i < in_cnt; i++) {
5471cb875aeSCathy Zhou 		(void) do_show_router(router, ofmt);
5481cb875aeSCathy Zhou 		router += strlen(router) + 1;
5491cb875aeSCathy Zhou 	}
5501cb875aeSCathy Zhou 
5511cb875aeSCathy Zhou 	free(names);
5521cb875aeSCathy Zhou 
5531cb875aeSCathy Zhou done:
5541cb875aeSCathy Zhou 	ofmt_close(ofmt);
5551cb875aeSCathy Zhou 
5561cb875aeSCathy Zhou 	if (err != VRRP_SUCCESS)
5571cb875aeSCathy Zhou 		err_exit(vrrp_err2str(err));
5581cb875aeSCathy Zhou }
5591cb875aeSCathy Zhou 
5601cb875aeSCathy Zhou /*
5611cb875aeSCathy Zhou  * Callback function to print fields of the configuration information.
5621cb875aeSCathy Zhou  */
5631cb875aeSCathy Zhou static boolean_t
5641cb875aeSCathy Zhou sfunc_vrrp_conf(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
5651cb875aeSCathy Zhou {
5661cb875aeSCathy Zhou 	vrrp_queryinfo_t	*qinfo = ofmtarg->ofmt_cbarg;
5671cb875aeSCathy Zhou 	uint_t			ofmtid = ofmtarg->ofmt_id;
5681cb875aeSCathy Zhou 	vrrp_vr_conf_t		*conf = &qinfo->show_vi;
5691cb875aeSCathy Zhou 	vrrp_stateinfo_t	*sinfo = &qinfo->show_vs;
5701cb875aeSCathy Zhou 	vrrp_peer_t		*peer = &qinfo->show_vp;
5711cb875aeSCathy Zhou 	vrrp_timerinfo_t	*tinfo = &qinfo->show_vt;
5721cb875aeSCathy Zhou 	vrrp_addrinfo_t		*ainfo = &qinfo->show_va;
5731cb875aeSCathy Zhou 
5741cb875aeSCathy Zhou 	switch (ofmtid) {
5751cb875aeSCathy Zhou 	case ROUTER_NAME:
5761cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%s", conf->vvc_name);
5771cb875aeSCathy Zhou 		break;
5781cb875aeSCathy Zhou 	case ROUTER_VRID:
5791cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%d", conf->vvc_vrid);
5801cb875aeSCathy Zhou 		break;
5811cb875aeSCathy Zhou 	case ROUTER_LINK:
5821cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%s", conf->vvc_link);
5831cb875aeSCathy Zhou 		break;
5841cb875aeSCathy Zhou 	case ROUTER_AF:
5851cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "IPv%d",
5861cb875aeSCathy Zhou 		    conf->vvc_af == AF_INET ? 4 : 6);
5871cb875aeSCathy Zhou 		break;
5881cb875aeSCathy Zhou 	case ROUTER_PRIO:
5891cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%d", conf->vvc_pri);
5901cb875aeSCathy Zhou 		break;
5911cb875aeSCathy Zhou 	case ROUTER_ADV_INTV:
5921cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%d", conf->vvc_adver_int);
5931cb875aeSCathy Zhou 		break;
5941cb875aeSCathy Zhou 	case ROUTER_MODE:
5951cb875aeSCathy Zhou 		(void) strlcpy(buf, "-----", bufsize);
5961cb875aeSCathy Zhou 		if (conf->vvc_enabled)
5971cb875aeSCathy Zhou 			buf[0] = 'e';
5981cb875aeSCathy Zhou 		if (conf->vvc_pri == VRRP_PRI_OWNER)
5991cb875aeSCathy Zhou 			buf[1] = 'o';
6001cb875aeSCathy Zhou 		if (conf->vvc_preempt)
6011cb875aeSCathy Zhou 			buf[2] = 'p';
6021cb875aeSCathy Zhou 		if (conf->vvc_accept)
6031cb875aeSCathy Zhou 			buf[3] = 'a';
6041cb875aeSCathy Zhou 		break;
6051cb875aeSCathy Zhou 	case ROUTER_STATE:
6061cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%s",
6071cb875aeSCathy Zhou 		    vrrp_state2str(sinfo->vs_state));
6081cb875aeSCathy Zhou 		break;
6091cb875aeSCathy Zhou 	case ROUTER_PRV_STAT:
6101cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%s",
6111cb875aeSCathy Zhou 		    vrrp_state2str(sinfo->vs_prev_state));
6121cb875aeSCathy Zhou 		break;
6131cb875aeSCathy Zhou 	case ROUTER_STAT_LAST:
6141cb875aeSCathy Zhou 		(void) timeval_since_str(tinfo->vt_since_last_tran, buf,
6151cb875aeSCathy Zhou 		    bufsize);
6161cb875aeSCathy Zhou 		break;
6171cb875aeSCathy Zhou 	case ROUTER_PEER:
6181cb875aeSCathy Zhou 		/* LINTED E_CONSTANT_CONDITION */
6191cb875aeSCathy Zhou 		VRRPADDR2STR(conf->vvc_af, &peer->vp_addr,
6201cb875aeSCathy Zhou 		    buf, bufsize, B_FALSE);
6211cb875aeSCathy Zhou 		break;
6221cb875aeSCathy Zhou 	case ROUTER_P_PRIO:
6231cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%d", peer->vp_prio);
6241cb875aeSCathy Zhou 		break;
6251cb875aeSCathy Zhou 	case ROUTER_P_INTV:
6261cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%d", peer->vp_adver_int);
6271cb875aeSCathy Zhou 		break;
6281cb875aeSCathy Zhou 	case ROUTER_P_ADV_LAST:
6291cb875aeSCathy Zhou 		(void) timeval_since_str(tinfo->vt_since_last_adv, buf,
6301cb875aeSCathy Zhou 		    bufsize);
6311cb875aeSCathy Zhou 		break;
6321cb875aeSCathy Zhou 	case ROUTER_M_DOWN_INTV:
6331cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%d", tinfo->vt_master_down_intv);
6341cb875aeSCathy Zhou 		break;
6351cb875aeSCathy Zhou 	case ROUTER_VNIC:
6361cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%s",
6371cb875aeSCathy Zhou 		    strlen(ainfo->va_vnic) == 0 ? "--" : ainfo->va_vnic);
6381cb875aeSCathy Zhou 		break;
6391cb875aeSCathy Zhou 	case ROUTER_PRIMARY_IP:
6401cb875aeSCathy Zhou 		/* LINTED E_CONSTANT_CONDITION */
6411cb875aeSCathy Zhou 		VRRPADDR2STR(conf->vvc_af, &ainfo->va_primary,
6421cb875aeSCathy Zhou 		    buf, bufsize, B_FALSE);
6431cb875aeSCathy Zhou 		break;
6441cb875aeSCathy Zhou 	case ROUTER_VIRTUAL_IPS: {
6451cb875aeSCathy Zhou 		uint32_t i;
6461cb875aeSCathy Zhou 
6471cb875aeSCathy Zhou 		for (i = 0; i < ainfo->va_vipcnt; i++) {
6481cb875aeSCathy Zhou 			/* LINTED E_CONSTANT_CONDITION */
6491cb875aeSCathy Zhou 			VRRPADDR2STR(conf->vvc_af, &(ainfo->va_vips[i]),
6501cb875aeSCathy Zhou 			    buf, bufsize, B_TRUE);
6511cb875aeSCathy Zhou 			if (i != ainfo->va_vipcnt - 1)
6521cb875aeSCathy Zhou 				(void) strlcat(buf, ",", bufsize);
6531cb875aeSCathy Zhou 		}
6541cb875aeSCathy Zhou 		break;
6551cb875aeSCathy Zhou 	}
6561cb875aeSCathy Zhou 	case ROUTER_VIP_CNT:
6571cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%d", ainfo->va_vipcnt);
6581cb875aeSCathy Zhou 		break;
6591cb875aeSCathy Zhou 	default:
6601cb875aeSCathy Zhou 		return (B_FALSE);
6611cb875aeSCathy Zhou 	}
6621cb875aeSCathy Zhou 
6631cb875aeSCathy Zhou 	return (B_TRUE);
6641cb875aeSCathy Zhou }
6651cb875aeSCathy Zhou 
6661cb875aeSCathy Zhou static void
6671cb875aeSCathy Zhou usage()
6681cb875aeSCathy Zhou {
6691cb875aeSCathy Zhou 	int	i;
6701cb875aeSCathy Zhou 	cmd_t	*cp;
6711cb875aeSCathy Zhou 
6721cb875aeSCathy Zhou 	(void) fprintf(stderr, "%s",
6731cb875aeSCathy Zhou 	    gettext("usage:  vrrpadm <sub-command> <args> ...\n"));
6741cb875aeSCathy Zhou 
6751cb875aeSCathy Zhou 	for (i = 0; i < sizeof (cmds) / sizeof (cmd_t); i++) {
6761cb875aeSCathy Zhou 		cp = &cmds[i];
6771cb875aeSCathy Zhou 		if (cp->c_usage != NULL)
6781cb875aeSCathy Zhou 			(void) fprintf(stderr, "          %-10s %s\n",
6791cb875aeSCathy Zhou 			    gettext(cp->c_name), gettext(cp->c_usage));
6801cb875aeSCathy Zhou 	}
6811cb875aeSCathy Zhou 
6821cb875aeSCathy Zhou 	vrrp_close(vrrp_vh);
6831cb875aeSCathy Zhou 	exit(EXIT_FAILURE);
6841cb875aeSCathy Zhou }
6851cb875aeSCathy Zhou 
6861cb875aeSCathy Zhou static void
6871cb875aeSCathy Zhou warn(const char *format, ...)
6881cb875aeSCathy Zhou {
6891cb875aeSCathy Zhou 	va_list alist;
6901cb875aeSCathy Zhou 
6911cb875aeSCathy Zhou 	format = gettext(format);
6921cb875aeSCathy Zhou 	(void) fprintf(stderr, gettext("warning: "));
6931cb875aeSCathy Zhou 
6941cb875aeSCathy Zhou 	va_start(alist, format);
6951cb875aeSCathy Zhou 	(void) vfprintf(stderr, format, alist);
6961cb875aeSCathy Zhou 	va_end(alist);
6971cb875aeSCathy Zhou 	(void) putc('\n', stderr);
6981cb875aeSCathy Zhou }
6991cb875aeSCathy Zhou 
7001cb875aeSCathy Zhou static void
7011cb875aeSCathy Zhou err_exit(const char *format, ...)
7021cb875aeSCathy Zhou {
7031cb875aeSCathy Zhou 	va_list alist;
7041cb875aeSCathy Zhou 
7051cb875aeSCathy Zhou 	format = gettext(format);
7061cb875aeSCathy Zhou 	va_start(alist, format);
7071cb875aeSCathy Zhou 	(void) vfprintf(stderr, format, alist);
7081cb875aeSCathy Zhou 	va_end(alist);
7091cb875aeSCathy Zhou 	(void) putc('\n', stderr);
7101cb875aeSCathy Zhou 	vrrp_close(vrrp_vh);
7111cb875aeSCathy Zhou 	exit(EXIT_FAILURE);
7121cb875aeSCathy Zhou }
7131cb875aeSCathy Zhou 
7141cb875aeSCathy Zhou static void
7151cb875aeSCathy Zhou opterr_exit(int opt, int opterr, const char *use)
7161cb875aeSCathy Zhou {
7171cb875aeSCathy Zhou 	switch (opterr) {
7181cb875aeSCathy Zhou 	case ':':
7191cb875aeSCathy Zhou 		err_exit("option '-%c' requires a value\nusage: %s", opt,
7201cb875aeSCathy Zhou 		    gettext(use));
7211cb875aeSCathy Zhou 		break;
7221cb875aeSCathy Zhou 	case '?':
7231cb875aeSCathy Zhou 	default:
7241cb875aeSCathy Zhou 		err_exit("unrecognized option '-%c'\nusage: %s", opt,
7251cb875aeSCathy Zhou 		    gettext(use));
7261cb875aeSCathy Zhou 		break;
7271cb875aeSCathy Zhou 	}
7281cb875aeSCathy Zhou }
7291cb875aeSCathy Zhou 
7301cb875aeSCathy Zhou static char *
7311cb875aeSCathy Zhou timeval_since_str(int mill, char *str, size_t len)
7321cb875aeSCathy Zhou {
7331cb875aeSCathy Zhou 	int	sec, msec, min;
7341cb875aeSCathy Zhou 
7351cb875aeSCathy Zhou 	msec = mill % 1000;
7361cb875aeSCathy Zhou 	sec = mill / 1000;
7371cb875aeSCathy Zhou 	min = sec > 60 ? sec / 60 : 0;
7381cb875aeSCathy Zhou 	sec %= 60;
7391cb875aeSCathy Zhou 
7401cb875aeSCathy Zhou 	if (min > 0)
7411cb875aeSCathy Zhou 		(void) snprintf(str, len, "%4dm%2ds", min, sec);
7421cb875aeSCathy Zhou 	else
7431cb875aeSCathy Zhou 		(void) snprintf(str, len, "%4d.%03ds", sec, msec);
7441cb875aeSCathy Zhou 
7451cb875aeSCathy Zhou 	return (str);
7461cb875aeSCathy Zhou }
7471cb875aeSCathy Zhou 
7481cb875aeSCathy Zhou /*
7491cb875aeSCathy Zhou  * Parses options string. The values of the two options will be returned
7501cb875aeSCathy Zhou  * by 'preempt' and 'accept', and the mask 'modify_mask' will be updated
7511cb875aeSCathy Zhou  * accordingly.
7521cb875aeSCathy Zhou  *
7531cb875aeSCathy Zhou  * Returns 0 on success, errno on failures.
7541cb875aeSCathy Zhou  *
7551cb875aeSCathy Zhou  * Used by do_create() and do_modify().
7561cb875aeSCathy Zhou  *
7571cb875aeSCathy Zhou  * Note that "opts" could be modified internally in this function.
7581cb875aeSCathy Zhou  */
7591cb875aeSCathy Zhou static int
7601cb875aeSCathy Zhou str2opt(char *opts, uint32_t *modify_mask, boolean_t *preempt,
7611cb875aeSCathy Zhou     boolean_t *accept)
7621cb875aeSCathy Zhou {
7631cb875aeSCathy Zhou 	char		*value;
7641cb875aeSCathy Zhou 	int		opt;
7651cb875aeSCathy Zhou 	uint32_t	mask = 0;
766*df53e1a1SCathy Zhou 	enum { o_preempt = 0, o_un_preempt, o_accept, o_no_accept };
7671cb875aeSCathy Zhou 	static char	*myopts[] = {
7681cb875aeSCathy Zhou 		"preempt",
7691cb875aeSCathy Zhou 		"un_preempt",
7701cb875aeSCathy Zhou 		"accept",
7711cb875aeSCathy Zhou 		"no_accept",
7721cb875aeSCathy Zhou 		NULL
7731cb875aeSCathy Zhou 	};
7741cb875aeSCathy Zhou 
7751cb875aeSCathy Zhou 	while (*opts != '\0') {
7761cb875aeSCathy Zhou 		switch ((opt = getsubopt(&opts, myopts, &value))) {
7771cb875aeSCathy Zhou 		case o_preempt:
7781cb875aeSCathy Zhou 		case o_un_preempt:
7791cb875aeSCathy Zhou 			if (mask & VRRP_CONF_PREEMPT)
7801cb875aeSCathy Zhou 				return (EINVAL);
7811cb875aeSCathy Zhou 
7821cb875aeSCathy Zhou 			mask |= VRRP_CONF_PREEMPT;
7831cb875aeSCathy Zhou 			*preempt = (opt == o_preempt);
7841cb875aeSCathy Zhou 			break;
7851cb875aeSCathy Zhou 		case o_accept:
7861cb875aeSCathy Zhou 		case o_no_accept:
7871cb875aeSCathy Zhou 			if (mask & VRRP_CONF_ACCEPT)
7881cb875aeSCathy Zhou 				return (EINVAL);
7891cb875aeSCathy Zhou 
7901cb875aeSCathy Zhou 			mask |= VRRP_CONF_ACCEPT;
7911cb875aeSCathy Zhou 			*accept = (opt == o_accept);
7921cb875aeSCathy Zhou 			break;
7931cb875aeSCathy Zhou 		default:
7941cb875aeSCathy Zhou 			return (EINVAL);
7951cb875aeSCathy Zhou 		}
7961cb875aeSCathy Zhou 	}
7971cb875aeSCathy Zhou 
7981cb875aeSCathy Zhou 	*modify_mask |= mask;
7991cb875aeSCathy Zhou 	return (0);
8001cb875aeSCathy Zhou }
801