xref: /titanic_53/usr/src/cmd/vrrpadm/vrrpadm.c (revision 1cb875ae88fb9463b368e725c2444776595895cb)
1*1cb875aeSCathy Zhou /*
2*1cb875aeSCathy Zhou  * CDDL HEADER START
3*1cb875aeSCathy Zhou  *
4*1cb875aeSCathy Zhou  * The contents of this file are subject to the terms of the
5*1cb875aeSCathy Zhou  * Common Development and Distribution License (the "License").
6*1cb875aeSCathy Zhou  * You may not use this file except in compliance with the License.
7*1cb875aeSCathy Zhou  *
8*1cb875aeSCathy Zhou  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1cb875aeSCathy Zhou  * or http://www.opensolaris.org/os/licensing.
10*1cb875aeSCathy Zhou  * See the License for the specific language governing permissions
11*1cb875aeSCathy Zhou  * and limitations under the License.
12*1cb875aeSCathy Zhou  *
13*1cb875aeSCathy Zhou  * When distributing Covered Code, include this CDDL HEADER in each
14*1cb875aeSCathy Zhou  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1cb875aeSCathy Zhou  * If applicable, add the following below this CDDL HEADER, with the
16*1cb875aeSCathy Zhou  * fields enclosed by brackets "[]" replaced with your own identifying
17*1cb875aeSCathy Zhou  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1cb875aeSCathy Zhou  *
19*1cb875aeSCathy Zhou  * CDDL HEADER END
20*1cb875aeSCathy Zhou  */
21*1cb875aeSCathy Zhou 
22*1cb875aeSCathy Zhou /*
23*1cb875aeSCathy Zhou  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*1cb875aeSCathy Zhou  * Use is subject to license terms.
25*1cb875aeSCathy Zhou  */
26*1cb875aeSCathy Zhou 
27*1cb875aeSCathy Zhou #include <sys/types.h>
28*1cb875aeSCathy Zhou #include <sys/varargs.h>
29*1cb875aeSCathy Zhou #include <getopt.h>
30*1cb875aeSCathy Zhou #include <stdio.h>
31*1cb875aeSCathy Zhou #include <stdlib.h>
32*1cb875aeSCathy Zhou #include <strings.h>
33*1cb875aeSCathy Zhou #include <errno.h>
34*1cb875aeSCathy Zhou #include <locale.h>
35*1cb875aeSCathy Zhou #include <libintl.h>
36*1cb875aeSCathy Zhou #include <libvrrpadm.h>
37*1cb875aeSCathy Zhou #include <ofmt.h>
38*1cb875aeSCathy Zhou 
39*1cb875aeSCathy Zhou static vrrp_handle_t	vrrp_vh = NULL;
40*1cb875aeSCathy Zhou typedef void cmd_func_t(int, char *[], const char *);
41*1cb875aeSCathy Zhou 
42*1cb875aeSCathy Zhou static cmd_func_t do_create, do_delete, do_enable, do_disable,
43*1cb875aeSCathy Zhou     do_modify, do_show;
44*1cb875aeSCathy Zhou 
45*1cb875aeSCathy Zhou typedef struct {
46*1cb875aeSCathy Zhou 	char		*c_name;
47*1cb875aeSCathy Zhou 	cmd_func_t	*c_fn;
48*1cb875aeSCathy Zhou 	const char	*c_usage;
49*1cb875aeSCathy Zhou } cmd_t;
50*1cb875aeSCathy Zhou 
51*1cb875aeSCathy Zhou static cmd_t cmds[] = {
52*1cb875aeSCathy Zhou 	{ "create-router",	do_create,
53*1cb875aeSCathy Zhou 	    "-V <vrid> -l <link> -A {inet | inet6} [-p <priority>] "
54*1cb875aeSCathy Zhou 	    "[-i <adv_interval>] [-o <flags>] <router_name>" },
55*1cb875aeSCathy Zhou 	{ "delete-router",	do_delete,	"<router_name>"		},
56*1cb875aeSCathy Zhou 	{ "enable-router",	do_enable,	"<router_name>"		},
57*1cb875aeSCathy Zhou 	{ "disable-router",	do_disable,	"<router_name>"		},
58*1cb875aeSCathy Zhou 	{ "modify-router",	do_modify,
59*1cb875aeSCathy Zhou 	    "[-p <priority>] [-i <adv_interval>] [-o <flags>] <router_name>" },
60*1cb875aeSCathy Zhou 	{ "show-router",	do_show,
61*1cb875aeSCathy Zhou 	    "[-P | -x] [-o field[,...]] [-p] [<router_name>]"	}
62*1cb875aeSCathy Zhou };
63*1cb875aeSCathy Zhou 
64*1cb875aeSCathy Zhou static const struct option lopts[] = {
65*1cb875aeSCathy Zhou 	{"vrid",		required_argument,	0, 'V'},
66*1cb875aeSCathy Zhou 	{"link",		required_argument,	0, 'l'},
67*1cb875aeSCathy Zhou 	{"address_family",	required_argument,	0, 'A'},
68*1cb875aeSCathy Zhou 	{"priority",		required_argument,	0, 'p'},
69*1cb875aeSCathy Zhou 	{"adv_interval",	required_argument,	0, 'i'},
70*1cb875aeSCathy Zhou 	{"flags",		required_argument,	0, 'o'},
71*1cb875aeSCathy Zhou 	{ 0, 0, 0, 0 }
72*1cb875aeSCathy Zhou };
73*1cb875aeSCathy Zhou 
74*1cb875aeSCathy Zhou static const struct option l_show_opts[] = {
75*1cb875aeSCathy Zhou 	{"peer",	no_argument,		0, 'P'},
76*1cb875aeSCathy Zhou 	{"parsable",	no_argument,		0, 'p'},
77*1cb875aeSCathy Zhou 	{"extended",	no_argument,		0, 'x'},
78*1cb875aeSCathy Zhou 	{"output",	required_argument,	0, 'o'},
79*1cb875aeSCathy Zhou 	{ 0, 0, 0, 0 }
80*1cb875aeSCathy Zhou };
81*1cb875aeSCathy Zhou 
82*1cb875aeSCathy Zhou static ofmt_cb_t sfunc_vrrp_conf;
83*1cb875aeSCathy Zhou 
84*1cb875aeSCathy Zhou /*
85*1cb875aeSCathy Zhou  * structures for 'dladm show-link -s' (print statistics)
86*1cb875aeSCathy Zhou  */
87*1cb875aeSCathy Zhou enum {
88*1cb875aeSCathy Zhou 	ROUTER_NAME,
89*1cb875aeSCathy Zhou 	ROUTER_VRID,
90*1cb875aeSCathy Zhou 	ROUTER_LINK,
91*1cb875aeSCathy Zhou 	ROUTER_VNIC,
92*1cb875aeSCathy Zhou 	ROUTER_AF,
93*1cb875aeSCathy Zhou 	ROUTER_PRIO,
94*1cb875aeSCathy Zhou 	ROUTER_ADV_INTV,
95*1cb875aeSCathy Zhou 	ROUTER_MODE,
96*1cb875aeSCathy Zhou 	ROUTER_STATE,
97*1cb875aeSCathy Zhou 	ROUTER_PRV_STAT,
98*1cb875aeSCathy Zhou 	ROUTER_STAT_LAST,
99*1cb875aeSCathy Zhou 	ROUTER_PEER,
100*1cb875aeSCathy Zhou 	ROUTER_P_PRIO,
101*1cb875aeSCathy Zhou 	ROUTER_P_INTV,
102*1cb875aeSCathy Zhou 	ROUTER_P_ADV_LAST,
103*1cb875aeSCathy Zhou 	ROUTER_M_DOWN_INTV,
104*1cb875aeSCathy Zhou 	ROUTER_PRIMARY_IP,
105*1cb875aeSCathy Zhou 	ROUTER_VIRTUAL_IPS,
106*1cb875aeSCathy Zhou 	ROUTER_VIP_CNT
107*1cb875aeSCathy Zhou };
108*1cb875aeSCathy Zhou 
109*1cb875aeSCathy Zhou /*
110*1cb875aeSCathy Zhou  * structures for 'vrrpadm show-router'
111*1cb875aeSCathy Zhou  */
112*1cb875aeSCathy Zhou static const ofmt_field_t show_print_fields[] = {
113*1cb875aeSCathy Zhou /* name,	field width,	index,			callback */
114*1cb875aeSCathy Zhou { "NAME",		8,	ROUTER_NAME,		sfunc_vrrp_conf	},
115*1cb875aeSCathy Zhou { "VRID",		5,	ROUTER_VRID,		sfunc_vrrp_conf	},
116*1cb875aeSCathy Zhou { "LINK",		8,	ROUTER_LINK,		sfunc_vrrp_conf },
117*1cb875aeSCathy Zhou { "VNIC",		8,	ROUTER_VNIC,		sfunc_vrrp_conf },
118*1cb875aeSCathy Zhou { "AF",			5,	ROUTER_AF,		sfunc_vrrp_conf },
119*1cb875aeSCathy Zhou { "PRIO",		5,	ROUTER_PRIO,		sfunc_vrrp_conf },
120*1cb875aeSCathy Zhou { "ADV_INTV",		9,	ROUTER_ADV_INTV,	sfunc_vrrp_conf },
121*1cb875aeSCathy Zhou { "MODE",		6,	ROUTER_MODE,		sfunc_vrrp_conf	},
122*1cb875aeSCathy Zhou { "STATE",		6,	ROUTER_STATE,		sfunc_vrrp_conf },
123*1cb875aeSCathy Zhou { "PRV_STAT",		9, 	ROUTER_PRV_STAT,	sfunc_vrrp_conf	},
124*1cb875aeSCathy Zhou { "STAT_LAST",		10,	ROUTER_STAT_LAST,	sfunc_vrrp_conf },
125*1cb875aeSCathy Zhou { "PEER",		20,	ROUTER_PEER,		sfunc_vrrp_conf	},
126*1cb875aeSCathy Zhou { "P_PRIO",		7,	ROUTER_P_PRIO,		sfunc_vrrp_conf	},
127*1cb875aeSCathy Zhou { "P_INTV",		9,	ROUTER_P_INTV,		sfunc_vrrp_conf	},
128*1cb875aeSCathy Zhou { "P_ADV_LAST",		11,	ROUTER_P_ADV_LAST,	sfunc_vrrp_conf	},
129*1cb875aeSCathy Zhou { "M_DOWN_INTV",	12,	ROUTER_M_DOWN_INTV,	sfunc_vrrp_conf	},
130*1cb875aeSCathy Zhou { "PRIMARY_IP",		20,	ROUTER_PRIMARY_IP,	sfunc_vrrp_conf	},
131*1cb875aeSCathy Zhou { "VIRTUAL_IPS",	40,	ROUTER_VIRTUAL_IPS,	sfunc_vrrp_conf	},
132*1cb875aeSCathy Zhou { "VIP_CNT",		7,	ROUTER_VIP_CNT,		sfunc_vrrp_conf	},
133*1cb875aeSCathy Zhou { NULL,			0, 	0,			NULL}}
134*1cb875aeSCathy Zhou ;
135*1cb875aeSCathy Zhou 
136*1cb875aeSCathy Zhou static vrrp_err_t do_show_router(const char *, ofmt_handle_t);
137*1cb875aeSCathy Zhou static int str2opt(char *opts, uint32_t *, boolean_t *, boolean_t *);
138*1cb875aeSCathy Zhou static char *timeval_since_str(int, char *, size_t);
139*1cb875aeSCathy Zhou 
140*1cb875aeSCathy Zhou static void usage();
141*1cb875aeSCathy Zhou static void warn(const char *, ...);
142*1cb875aeSCathy Zhou static void err_exit(const char *, ...);
143*1cb875aeSCathy Zhou static void opterr_exit(int, int, const char *);
144*1cb875aeSCathy Zhou 
145*1cb875aeSCathy Zhou int
146*1cb875aeSCathy Zhou main(int argc, char *argv[])
147*1cb875aeSCathy Zhou {
148*1cb875aeSCathy Zhou 	vrrp_err_t	err;
149*1cb875aeSCathy Zhou 	int		i;
150*1cb875aeSCathy Zhou 	cmd_t		*cp;
151*1cb875aeSCathy Zhou 
152*1cb875aeSCathy Zhou 	(void) setlocale(LC_ALL, "");
153*1cb875aeSCathy Zhou 	(void) textdomain(TEXT_DOMAIN);
154*1cb875aeSCathy Zhou 
155*1cb875aeSCathy Zhou 	if (argv[1] == NULL)
156*1cb875aeSCathy Zhou 		usage();
157*1cb875aeSCathy Zhou 
158*1cb875aeSCathy Zhou 	if ((err = vrrp_open(&vrrp_vh)) != VRRP_SUCCESS)
159*1cb875aeSCathy Zhou 		err_exit("operation failed: %s", vrrp_err2str(err));
160*1cb875aeSCathy Zhou 
161*1cb875aeSCathy Zhou 	for (i = 0; i < sizeof (cmds) / sizeof (cmd_t); i++) {
162*1cb875aeSCathy Zhou 		cp = &cmds[i];
163*1cb875aeSCathy Zhou 		if (strcmp(argv[1], cp->c_name) == 0) {
164*1cb875aeSCathy Zhou 			cp->c_fn(argc - 1, &argv[1], cp->c_usage);
165*1cb875aeSCathy Zhou 			vrrp_close(vrrp_vh);
166*1cb875aeSCathy Zhou 			return (EXIT_SUCCESS);
167*1cb875aeSCathy Zhou 		}
168*1cb875aeSCathy Zhou 	}
169*1cb875aeSCathy Zhou 
170*1cb875aeSCathy Zhou 	usage();
171*1cb875aeSCathy Zhou 	return (EXIT_FAILURE);
172*1cb875aeSCathy Zhou }
173*1cb875aeSCathy Zhou 
174*1cb875aeSCathy Zhou static void
175*1cb875aeSCathy Zhou do_create(int argc, char *argv[], const char *usage)
176*1cb875aeSCathy Zhou {
177*1cb875aeSCathy Zhou 	vrrp_vr_conf_t		conf;
178*1cb875aeSCathy Zhou 	int			c;
179*1cb875aeSCathy Zhou 	uint32_t		create_mask = 0, mask;
180*1cb875aeSCathy Zhou 	char			*endp;
181*1cb875aeSCathy Zhou 	vrrp_err_t		err;
182*1cb875aeSCathy Zhou 
183*1cb875aeSCathy Zhou 	/*
184*1cb875aeSCathy Zhou 	 * default value
185*1cb875aeSCathy Zhou 	 */
186*1cb875aeSCathy Zhou 	bzero(&conf, sizeof (vrrp_vr_conf_t));
187*1cb875aeSCathy Zhou 	conf.vvc_vrid = VRRP_VRID_NONE;
188*1cb875aeSCathy Zhou 	conf.vvc_af = AF_UNSPEC;
189*1cb875aeSCathy Zhou 	conf.vvc_pri = VRRP_PRI_DEFAULT;
190*1cb875aeSCathy Zhou 	conf.vvc_adver_int = VRRP_MAX_ADVER_INT_DFLT;
191*1cb875aeSCathy Zhou 	conf.vvc_preempt = B_TRUE;
192*1cb875aeSCathy Zhou 	conf.vvc_accept = B_TRUE;
193*1cb875aeSCathy Zhou 	conf.vvc_enabled = B_TRUE;
194*1cb875aeSCathy Zhou 
195*1cb875aeSCathy Zhou 	while ((c = getopt_long(argc, argv, ":V:l:p:i:o:A:f", lopts,
196*1cb875aeSCathy Zhou 	    NULL)) != EOF) {
197*1cb875aeSCathy Zhou 		switch (c) {
198*1cb875aeSCathy Zhou 		case 'l':
199*1cb875aeSCathy Zhou 			if (strlcpy(conf.vvc_link, optarg,
200*1cb875aeSCathy Zhou 			    sizeof (conf.vvc_link)) >=
201*1cb875aeSCathy Zhou 			    sizeof (conf.vvc_link)) {
202*1cb875aeSCathy Zhou 				err_exit("invalid data-link name %s", optarg);
203*1cb875aeSCathy Zhou 			}
204*1cb875aeSCathy Zhou 			break;
205*1cb875aeSCathy Zhou 		case 'i':
206*1cb875aeSCathy Zhou 			if (create_mask & VRRP_CONF_INTERVAL)
207*1cb875aeSCathy Zhou 				err_exit("duplicate '-i' option");
208*1cb875aeSCathy Zhou 
209*1cb875aeSCathy Zhou 			create_mask |= VRRP_CONF_INTERVAL;
210*1cb875aeSCathy Zhou 			conf.vvc_adver_int = (uint32_t)strtol(optarg, &endp, 0);
211*1cb875aeSCathy Zhou 			if ((*endp) != '\0' ||
212*1cb875aeSCathy Zhou 			    conf.vvc_adver_int < VRRP_MAX_ADVER_INT_MIN ||
213*1cb875aeSCathy Zhou 			    conf.vvc_adver_int > VRRP_MAX_ADVER_INT_MAX ||
214*1cb875aeSCathy Zhou 			    (conf.vvc_adver_int == 0 && errno != 0)) {
215*1cb875aeSCathy Zhou 				err_exit("invalid advertisement interval");
216*1cb875aeSCathy Zhou 			}
217*1cb875aeSCathy Zhou 			break;
218*1cb875aeSCathy Zhou 		case 'p':
219*1cb875aeSCathy Zhou 			if (create_mask & VRRP_CONF_PRIORITY)
220*1cb875aeSCathy Zhou 				err_exit("duplicate '-p' option");
221*1cb875aeSCathy Zhou 
222*1cb875aeSCathy Zhou 			create_mask |= VRRP_CONF_PRIORITY;
223*1cb875aeSCathy Zhou 			conf.vvc_pri = strtol(optarg, &endp, 0);
224*1cb875aeSCathy Zhou 			if ((*endp) != '\0' || conf.vvc_pri < VRRP_PRI_MIN ||
225*1cb875aeSCathy Zhou 			    conf.vvc_pri > VRRP_PRI_OWNER ||
226*1cb875aeSCathy Zhou 			    (conf.vvc_pri == 0 && errno != 0)) {
227*1cb875aeSCathy Zhou 				err_exit("invalid priority");
228*1cb875aeSCathy Zhou 			}
229*1cb875aeSCathy Zhou 			break;
230*1cb875aeSCathy Zhou 		case 'o':
231*1cb875aeSCathy Zhou 			mask = 0;
232*1cb875aeSCathy Zhou 			if (str2opt(optarg, &mask,
233*1cb875aeSCathy Zhou 			    &conf.vvc_preempt, &conf.vvc_accept) != 0) {
234*1cb875aeSCathy Zhou 				err_exit("invalid options: %s", optarg);
235*1cb875aeSCathy Zhou 			}
236*1cb875aeSCathy Zhou 			if (mask & create_mask & VRRP_CONF_PREEMPT)
237*1cb875aeSCathy Zhou 				err_exit("duplicate '-o preempt' option");
238*1cb875aeSCathy Zhou 			else if (mask & create_mask & VRRP_CONF_ACCEPT)
239*1cb875aeSCathy Zhou 				err_exit("duplicate '-o accept' option");
240*1cb875aeSCathy Zhou 			create_mask |= mask;
241*1cb875aeSCathy Zhou 			break;
242*1cb875aeSCathy Zhou 		case 'V':
243*1cb875aeSCathy Zhou 			if (conf.vvc_vrid != VRRP_VRID_NONE)
244*1cb875aeSCathy Zhou 				err_exit("duplicate '-V' option");
245*1cb875aeSCathy Zhou 
246*1cb875aeSCathy Zhou 			conf.vvc_vrid = strtol(optarg, &endp, 0);
247*1cb875aeSCathy Zhou 			if ((*endp) != '\0' || conf.vvc_vrid < VRRP_VRID_MIN ||
248*1cb875aeSCathy Zhou 			    conf.vvc_vrid > VRRP_VRID_MAX ||
249*1cb875aeSCathy Zhou 			    (conf.vvc_vrid == 0 && errno != 0)) {
250*1cb875aeSCathy Zhou 				err_exit("invalid VRID");
251*1cb875aeSCathy Zhou 			}
252*1cb875aeSCathy Zhou 			break;
253*1cb875aeSCathy Zhou 		case 'A':
254*1cb875aeSCathy Zhou 			if (conf.vvc_af != AF_UNSPEC)
255*1cb875aeSCathy Zhou 				err_exit("duplicate '-A' option");
256*1cb875aeSCathy Zhou 
257*1cb875aeSCathy Zhou 			if (strcmp(optarg, "inet") == 0)
258*1cb875aeSCathy Zhou 				conf.vvc_af = AF_INET;
259*1cb875aeSCathy Zhou 			else if (strcmp(optarg, "inet6") == 0)
260*1cb875aeSCathy Zhou 				conf.vvc_af = AF_INET6;
261*1cb875aeSCathy Zhou 			else
262*1cb875aeSCathy Zhou 				err_exit("invalid address family");
263*1cb875aeSCathy Zhou 			break;
264*1cb875aeSCathy Zhou 		default:
265*1cb875aeSCathy Zhou 			opterr_exit(optopt, c, usage);
266*1cb875aeSCathy Zhou 		}
267*1cb875aeSCathy Zhou 	}
268*1cb875aeSCathy Zhou 
269*1cb875aeSCathy Zhou 	if (argc - optind > 1)
270*1cb875aeSCathy Zhou 		err_exit("usage: %s", gettext(usage));
271*1cb875aeSCathy Zhou 
272*1cb875aeSCathy Zhou 	if (optind != argc - 1)
273*1cb875aeSCathy Zhou 		err_exit("VRRP name not specified");
274*1cb875aeSCathy Zhou 
275*1cb875aeSCathy Zhou 	if (strlcpy(conf.vvc_name, argv[optind],
276*1cb875aeSCathy Zhou 	    sizeof (conf.vvc_name)) >= sizeof (conf.vvc_name)) {
277*1cb875aeSCathy Zhou 		err_exit("Invalid router name %s", argv[optind]);
278*1cb875aeSCathy Zhou 	}
279*1cb875aeSCathy Zhou 
280*1cb875aeSCathy Zhou 	if (conf.vvc_vrid == VRRP_VRID_NONE)
281*1cb875aeSCathy Zhou 		err_exit("VRID not specified");
282*1cb875aeSCathy Zhou 
283*1cb875aeSCathy Zhou 	if (conf.vvc_af == AF_UNSPEC)
284*1cb875aeSCathy Zhou 		err_exit("address family not specified");
285*1cb875aeSCathy Zhou 
286*1cb875aeSCathy Zhou 	if (strlen(conf.vvc_link) == 0)
287*1cb875aeSCathy Zhou 		err_exit("link name not specified");
288*1cb875aeSCathy Zhou 
289*1cb875aeSCathy Zhou 	if (!conf.vvc_accept && conf.vvc_pri == VRRP_PRI_OWNER)
290*1cb875aeSCathy Zhou 		err_exit("accept_mode must be true for virtual IP owner");
291*1cb875aeSCathy Zhou 
292*1cb875aeSCathy Zhou done:
293*1cb875aeSCathy Zhou 	if ((err = vrrp_create(vrrp_vh, &conf)) == VRRP_SUCCESS)
294*1cb875aeSCathy Zhou 		return;
295*1cb875aeSCathy Zhou 
296*1cb875aeSCathy Zhou 	err_exit("create-router failed: %s", vrrp_err2str(err));
297*1cb875aeSCathy Zhou }
298*1cb875aeSCathy Zhou 
299*1cb875aeSCathy Zhou static void
300*1cb875aeSCathy Zhou do_delete(int argc, char *argv[], const char *use)
301*1cb875aeSCathy Zhou {
302*1cb875aeSCathy Zhou 	vrrp_err_t	err;
303*1cb875aeSCathy Zhou 
304*1cb875aeSCathy Zhou 	if (argc != 2)
305*1cb875aeSCathy Zhou 		err_exit("usage: %s", gettext(use));
306*1cb875aeSCathy Zhou 
307*1cb875aeSCathy Zhou 	if ((err = vrrp_delete(vrrp_vh, argv[1])) != VRRP_SUCCESS)
308*1cb875aeSCathy Zhou 		err_exit("delete-router failed: %s", vrrp_err2str(err));
309*1cb875aeSCathy Zhou }
310*1cb875aeSCathy Zhou 
311*1cb875aeSCathy Zhou static void
312*1cb875aeSCathy Zhou do_enable(int argc, char *argv[], const char *use)
313*1cb875aeSCathy Zhou {
314*1cb875aeSCathy Zhou 	vrrp_err_t	err;
315*1cb875aeSCathy Zhou 
316*1cb875aeSCathy Zhou 	if (argc != 2)
317*1cb875aeSCathy Zhou 		err_exit("usage: %s", gettext(use));
318*1cb875aeSCathy Zhou 
319*1cb875aeSCathy Zhou 	if ((err = vrrp_enable(vrrp_vh, argv[1])) != VRRP_SUCCESS)
320*1cb875aeSCathy Zhou 		err_exit("enable-router failed: %s", vrrp_err2str(err));
321*1cb875aeSCathy Zhou }
322*1cb875aeSCathy Zhou 
323*1cb875aeSCathy Zhou static void
324*1cb875aeSCathy Zhou do_disable(int argc, char *argv[], const char *use)
325*1cb875aeSCathy Zhou {
326*1cb875aeSCathy Zhou 	vrrp_err_t	err;
327*1cb875aeSCathy Zhou 
328*1cb875aeSCathy Zhou 	if (argc != 2)
329*1cb875aeSCathy Zhou 		err_exit("usage: %s", gettext(use));
330*1cb875aeSCathy Zhou 
331*1cb875aeSCathy Zhou 	if ((err = vrrp_disable(vrrp_vh, argv[1])) != VRRP_SUCCESS)
332*1cb875aeSCathy Zhou 		err_exit("disable-router failed: %s", vrrp_err2str(err));
333*1cb875aeSCathy Zhou }
334*1cb875aeSCathy Zhou 
335*1cb875aeSCathy Zhou static void
336*1cb875aeSCathy Zhou do_modify(int argc, char *argv[], const char *use)
337*1cb875aeSCathy Zhou {
338*1cb875aeSCathy Zhou 	vrrp_vr_conf_t	conf;
339*1cb875aeSCathy Zhou 	vrrp_err_t	err;
340*1cb875aeSCathy Zhou 	uint32_t	modify_mask = 0, mask;
341*1cb875aeSCathy Zhou 	char		*endp;
342*1cb875aeSCathy Zhou 	int		c;
343*1cb875aeSCathy Zhou 
344*1cb875aeSCathy Zhou 	while ((c = getopt_long(argc, argv, ":i:p:o:", lopts, NULL)) != EOF) {
345*1cb875aeSCathy Zhou 		switch (c) {
346*1cb875aeSCathy Zhou 		case 'i':
347*1cb875aeSCathy Zhou 			if (modify_mask & VRRP_CONF_INTERVAL)
348*1cb875aeSCathy Zhou 				err_exit("duplicate '-i' option");
349*1cb875aeSCathy Zhou 
350*1cb875aeSCathy Zhou 			modify_mask |= VRRP_CONF_INTERVAL;
351*1cb875aeSCathy Zhou 			conf.vvc_adver_int = (uint32_t)strtol(optarg, &endp, 0);
352*1cb875aeSCathy Zhou 			if ((*endp) != '\0' ||
353*1cb875aeSCathy Zhou 			    conf.vvc_adver_int < VRRP_MAX_ADVER_INT_MIN ||
354*1cb875aeSCathy Zhou 			    conf.vvc_adver_int > VRRP_MAX_ADVER_INT_MAX ||
355*1cb875aeSCathy Zhou 			    (conf.vvc_adver_int == 0 && errno != 0)) {
356*1cb875aeSCathy Zhou 				err_exit("invalid advertisement interval");
357*1cb875aeSCathy Zhou 			}
358*1cb875aeSCathy Zhou 			break;
359*1cb875aeSCathy Zhou 		case 'o':
360*1cb875aeSCathy Zhou 			mask = 0;
361*1cb875aeSCathy Zhou 			if (str2opt(optarg, &mask, &conf.vvc_preempt,
362*1cb875aeSCathy Zhou 			    &conf.vvc_accept) != 0) {
363*1cb875aeSCathy Zhou 				err_exit("Invalid options");
364*1cb875aeSCathy Zhou 			}
365*1cb875aeSCathy Zhou 			if (mask & modify_mask & VRRP_CONF_PREEMPT)
366*1cb875aeSCathy Zhou 				err_exit("duplicate '-o preempt' option");
367*1cb875aeSCathy Zhou 			else if (mask & modify_mask & VRRP_CONF_ACCEPT)
368*1cb875aeSCathy Zhou 				err_exit("duplicate '-o accept' option");
369*1cb875aeSCathy Zhou 			modify_mask |= mask;
370*1cb875aeSCathy Zhou 			break;
371*1cb875aeSCathy Zhou 		case 'p':
372*1cb875aeSCathy Zhou 			if (modify_mask & VRRP_CONF_PRIORITY)
373*1cb875aeSCathy Zhou 				err_exit("duplicate '-p' option");
374*1cb875aeSCathy Zhou 
375*1cb875aeSCathy Zhou 			modify_mask |= VRRP_CONF_PRIORITY;
376*1cb875aeSCathy Zhou 			conf.vvc_pri = strtol(optarg, &endp, 0);
377*1cb875aeSCathy Zhou 			if ((*endp) != '\0' || conf.vvc_pri < VRRP_PRI_MIN ||
378*1cb875aeSCathy Zhou 			    conf.vvc_pri > VRRP_PRI_OWNER ||
379*1cb875aeSCathy Zhou 			    (conf.vvc_pri == 0 && errno != 0)) {
380*1cb875aeSCathy Zhou 				err_exit("invalid priority");
381*1cb875aeSCathy Zhou 			}
382*1cb875aeSCathy Zhou 			break;
383*1cb875aeSCathy Zhou 		default:
384*1cb875aeSCathy Zhou 			opterr_exit(optopt, c, use);
385*1cb875aeSCathy Zhou 		}
386*1cb875aeSCathy Zhou 	}
387*1cb875aeSCathy Zhou 
388*1cb875aeSCathy Zhou 	if (argc - optind > 1)
389*1cb875aeSCathy Zhou 		err_exit("usage: %s", gettext(use));
390*1cb875aeSCathy Zhou 
391*1cb875aeSCathy Zhou 	if (optind != argc - 1)
392*1cb875aeSCathy Zhou 		err_exit("VRRP name not specified.");
393*1cb875aeSCathy Zhou 
394*1cb875aeSCathy Zhou 	if (strlcpy(conf.vvc_name, argv[optind], sizeof (conf.vvc_name)) >=
395*1cb875aeSCathy Zhou 	    sizeof (conf.vvc_name)) {
396*1cb875aeSCathy Zhou 		err_exit("invalid router name %s", argv[optind]);
397*1cb875aeSCathy Zhou 	}
398*1cb875aeSCathy Zhou 
399*1cb875aeSCathy Zhou 	if ((modify_mask & VRRP_CONF_ACCEPT) && !conf.vvc_accept &&
400*1cb875aeSCathy Zhou 	    (modify_mask & VRRP_CONF_PRIORITY) &&
401*1cb875aeSCathy Zhou 	    conf.vvc_pri == VRRP_PRI_OWNER) {
402*1cb875aeSCathy Zhou 		err_exit("accept_mode must be true for virtual IP owner");
403*1cb875aeSCathy Zhou 	}
404*1cb875aeSCathy Zhou 
405*1cb875aeSCathy Zhou 	if (modify_mask == 0)
406*1cb875aeSCathy Zhou 		usage();
407*1cb875aeSCathy Zhou 
408*1cb875aeSCathy Zhou 	err = vrrp_modify(vrrp_vh, &conf, modify_mask);
409*1cb875aeSCathy Zhou 	if (err != VRRP_SUCCESS)
410*1cb875aeSCathy Zhou 		err_exit("modify-router failed: %s", vrrp_err2str(err));
411*1cb875aeSCathy Zhou }
412*1cb875aeSCathy Zhou 
413*1cb875aeSCathy Zhou /*
414*1cb875aeSCathy Zhou  * 'show-router' one VRRP router.
415*1cb875aeSCathy Zhou  */
416*1cb875aeSCathy Zhou static vrrp_err_t
417*1cb875aeSCathy Zhou do_show_router(const char *vn, ofmt_handle_t ofmt)
418*1cb875aeSCathy Zhou {
419*1cb875aeSCathy Zhou 	vrrp_queryinfo_t	*vq;
420*1cb875aeSCathy Zhou 	vrrp_err_t		err;
421*1cb875aeSCathy Zhou 
422*1cb875aeSCathy Zhou 	if ((err = vrrp_query(vrrp_vh, vn, &vq)) != VRRP_SUCCESS)
423*1cb875aeSCathy Zhou 		return (err);
424*1cb875aeSCathy Zhou 
425*1cb875aeSCathy Zhou 	ofmt_print(ofmt, vq);
426*1cb875aeSCathy Zhou 	free(vq);
427*1cb875aeSCathy Zhou 	return (VRRP_SUCCESS);
428*1cb875aeSCathy Zhou }
429*1cb875aeSCathy Zhou 
430*1cb875aeSCathy Zhou static void
431*1cb875aeSCathy Zhou do_show(int argc, char *argv[], const char *use)
432*1cb875aeSCathy Zhou {
433*1cb875aeSCathy Zhou 	int			c;
434*1cb875aeSCathy Zhou 	char			*fields_str = NULL;
435*1cb875aeSCathy Zhou 	char			*names = NULL, *router;
436*1cb875aeSCathy Zhou 	uint32_t		i, in_cnt = 0, out_cnt;
437*1cb875aeSCathy Zhou 	ofmt_status_t		oferr;
438*1cb875aeSCathy Zhou 	ofmt_handle_t		ofmt;
439*1cb875aeSCathy Zhou 	uint_t			ofmt_flags = 0;
440*1cb875aeSCathy Zhou 	vrrp_err_t		err = VRRP_SUCCESS;
441*1cb875aeSCathy Zhou 	boolean_t		P_opt, x_opt;
442*1cb875aeSCathy Zhou 
443*1cb875aeSCathy Zhou 	static char		*dft_fields_str =
444*1cb875aeSCathy Zhou 	    "NAME,VRID,LINK,AF,PRIO,ADV_INTV,MODE,STATE,VNIC";
445*1cb875aeSCathy Zhou 	static char		*ext_fields_str =
446*1cb875aeSCathy Zhou 	    "NAME,STATE,PRV_STAT,STAT_LAST,VNIC,PRIMARY_IP,VIRTUAL_IPS";
447*1cb875aeSCathy Zhou 	static char		*peer_fields_str =
448*1cb875aeSCathy Zhou 	    "NAME,PEER,P_PRIO,P_INTV,P_ADV_LAST,M_DOWN_INTV";
449*1cb875aeSCathy Zhou 	/*
450*1cb875aeSCathy Zhou 	 * If parsable output is requested, add VIP_CNT into the output
451*1cb875aeSCathy Zhou 	 * for extended output. It is not needed for human-readable
452*1cb875aeSCathy Zhou 	 * output as it is obvious from the VIRTUAL_IPS list.
453*1cb875aeSCathy Zhou 	 */
454*1cb875aeSCathy Zhou 	static char		*ext_parsable_fields_str =
455*1cb875aeSCathy Zhou 	    "NAME,STATE,PRV_STAT,STAT_LAST,VNIC,PRIMARY_IP,VIP_CNT,"
456*1cb875aeSCathy Zhou 	    "VIRTUAL_IPS";
457*1cb875aeSCathy Zhou 
458*1cb875aeSCathy Zhou 	P_opt = x_opt = B_FALSE;
459*1cb875aeSCathy Zhou 	fields_str = dft_fields_str;
460*1cb875aeSCathy Zhou 	while ((c = getopt_long(argc, argv, ":Pxpo:", l_show_opts,
461*1cb875aeSCathy Zhou 	    NULL)) != EOF) {
462*1cb875aeSCathy Zhou 		switch (c) {
463*1cb875aeSCathy Zhou 		case 'o':
464*1cb875aeSCathy Zhou 			fields_str = optarg;
465*1cb875aeSCathy Zhou 			break;
466*1cb875aeSCathy Zhou 		case 'p':
467*1cb875aeSCathy Zhou 			ofmt_flags |= OFMT_PARSABLE;
468*1cb875aeSCathy Zhou 			break;
469*1cb875aeSCathy Zhou 		case 'P':
470*1cb875aeSCathy Zhou 			P_opt = B_TRUE;
471*1cb875aeSCathy Zhou 			fields_str = peer_fields_str;
472*1cb875aeSCathy Zhou 			break;
473*1cb875aeSCathy Zhou 		case 'x':
474*1cb875aeSCathy Zhou 			x_opt = B_TRUE;
475*1cb875aeSCathy Zhou 			fields_str = ext_fields_str;
476*1cb875aeSCathy Zhou 			break;
477*1cb875aeSCathy Zhou 		default:
478*1cb875aeSCathy Zhou 			opterr_exit(optopt, c, use);
479*1cb875aeSCathy Zhou 		}
480*1cb875aeSCathy Zhou 	}
481*1cb875aeSCathy Zhou 
482*1cb875aeSCathy Zhou 	if (x_opt && P_opt)
483*1cb875aeSCathy Zhou 		err_exit("incompatible -P and -x options");
484*1cb875aeSCathy Zhou 
485*1cb875aeSCathy Zhou 	/*
486*1cb875aeSCathy Zhou 	 * If parsable output is requested, add VIP_CNT into the output
487*1cb875aeSCathy Zhou 	 * for extended output.
488*1cb875aeSCathy Zhou 	 */
489*1cb875aeSCathy Zhou 	if ((ofmt_flags & OFMT_PARSABLE) && (fields_str == ext_fields_str))
490*1cb875aeSCathy Zhou 		fields_str = ext_parsable_fields_str;
491*1cb875aeSCathy Zhou 
492*1cb875aeSCathy Zhou 	if ((oferr = ofmt_open(fields_str, show_print_fields, ofmt_flags,
493*1cb875aeSCathy Zhou 	    0, &ofmt)) != OFMT_SUCCESS) {
494*1cb875aeSCathy Zhou 		char buf[OFMT_BUFSIZE];
495*1cb875aeSCathy Zhou 
496*1cb875aeSCathy Zhou 		/*
497*1cb875aeSCathy Zhou 		 * If some fields were badly formed in human-friendly mode, we
498*1cb875aeSCathy Zhou 		 * emit a warning and continue.  Otherwise exit immediately.
499*1cb875aeSCathy Zhou 		 */
500*1cb875aeSCathy Zhou 		(void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf));
501*1cb875aeSCathy Zhou 		if (oferr != OFMT_EBADFIELDS || (ofmt_flags & OFMT_PARSABLE)) {
502*1cb875aeSCathy Zhou 			ofmt_close(ofmt);
503*1cb875aeSCathy Zhou 			err_exit(buf);
504*1cb875aeSCathy Zhou 		} else {
505*1cb875aeSCathy Zhou 			warn(buf);
506*1cb875aeSCathy Zhou 		}
507*1cb875aeSCathy Zhou 	}
508*1cb875aeSCathy Zhou 
509*1cb875aeSCathy Zhou 	/* Show one router */
510*1cb875aeSCathy Zhou 	if (optind == argc - 1) {
511*1cb875aeSCathy Zhou 		err = do_show_router(argv[optind], ofmt);
512*1cb875aeSCathy Zhou 		goto done;
513*1cb875aeSCathy Zhou 	}
514*1cb875aeSCathy Zhou 
515*1cb875aeSCathy Zhou 	/*
516*1cb875aeSCathy Zhou 	 * Show all routers. First set in_cnt to 0 to find out the number
517*1cb875aeSCathy Zhou 	 * of vrrp routers.
518*1cb875aeSCathy Zhou 	 */
519*1cb875aeSCathy Zhou again:
520*1cb875aeSCathy Zhou 	if ((in_cnt != 0) && (names = malloc(in_cnt * VRRP_NAME_MAX)) == NULL) {
521*1cb875aeSCathy Zhou 		err = VRRP_ENOMEM;
522*1cb875aeSCathy Zhou 		goto done;
523*1cb875aeSCathy Zhou 	}
524*1cb875aeSCathy Zhou 
525*1cb875aeSCathy Zhou 	out_cnt = in_cnt;
526*1cb875aeSCathy Zhou 	if ((err = vrrp_list(vrrp_vh, VRRP_VRID_NONE, NULL, AF_UNSPEC,
527*1cb875aeSCathy Zhou 	    &out_cnt, names)) != VRRP_SUCCESS) {
528*1cb875aeSCathy Zhou 		free(names);
529*1cb875aeSCathy Zhou 		goto done;
530*1cb875aeSCathy Zhou 	}
531*1cb875aeSCathy Zhou 
532*1cb875aeSCathy Zhou 	/*
533*1cb875aeSCathy Zhou 	 * The VRRP routers has been changed between two vrrp_list()
534*1cb875aeSCathy Zhou 	 * calls, try again.
535*1cb875aeSCathy Zhou 	 */
536*1cb875aeSCathy Zhou 	if (out_cnt > in_cnt) {
537*1cb875aeSCathy Zhou 		in_cnt = out_cnt;
538*1cb875aeSCathy Zhou 		free(names);
539*1cb875aeSCathy Zhou 		goto again;
540*1cb875aeSCathy Zhou 	}
541*1cb875aeSCathy Zhou 
542*1cb875aeSCathy Zhou 	/*
543*1cb875aeSCathy Zhou 	 * Each VRRP router name is separated by '\0`
544*1cb875aeSCathy Zhou 	 */
545*1cb875aeSCathy Zhou 	router = names;
546*1cb875aeSCathy Zhou 	for (i = 0; i < in_cnt; i++) {
547*1cb875aeSCathy Zhou 		(void) do_show_router(router, ofmt);
548*1cb875aeSCathy Zhou 		router += strlen(router) + 1;
549*1cb875aeSCathy Zhou 	}
550*1cb875aeSCathy Zhou 
551*1cb875aeSCathy Zhou 	free(names);
552*1cb875aeSCathy Zhou 
553*1cb875aeSCathy Zhou done:
554*1cb875aeSCathy Zhou 	ofmt_close(ofmt);
555*1cb875aeSCathy Zhou 
556*1cb875aeSCathy Zhou 	if (err != VRRP_SUCCESS)
557*1cb875aeSCathy Zhou 		err_exit(vrrp_err2str(err));
558*1cb875aeSCathy Zhou }
559*1cb875aeSCathy Zhou 
560*1cb875aeSCathy Zhou /*
561*1cb875aeSCathy Zhou  * Callback function to print fields of the configuration information.
562*1cb875aeSCathy Zhou  */
563*1cb875aeSCathy Zhou static boolean_t
564*1cb875aeSCathy Zhou sfunc_vrrp_conf(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
565*1cb875aeSCathy Zhou {
566*1cb875aeSCathy Zhou 	vrrp_queryinfo_t	*qinfo = ofmtarg->ofmt_cbarg;
567*1cb875aeSCathy Zhou 	uint_t			ofmtid = ofmtarg->ofmt_id;
568*1cb875aeSCathy Zhou 	vrrp_vr_conf_t		*conf = &qinfo->show_vi;
569*1cb875aeSCathy Zhou 	vrrp_stateinfo_t	*sinfo = &qinfo->show_vs;
570*1cb875aeSCathy Zhou 	vrrp_peer_t		*peer = &qinfo->show_vp;
571*1cb875aeSCathy Zhou 	vrrp_timerinfo_t	*tinfo = &qinfo->show_vt;
572*1cb875aeSCathy Zhou 	vrrp_addrinfo_t		*ainfo = &qinfo->show_va;
573*1cb875aeSCathy Zhou 
574*1cb875aeSCathy Zhou 	switch (ofmtid) {
575*1cb875aeSCathy Zhou 	case ROUTER_NAME:
576*1cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%s", conf->vvc_name);
577*1cb875aeSCathy Zhou 		break;
578*1cb875aeSCathy Zhou 	case ROUTER_VRID:
579*1cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%d", conf->vvc_vrid);
580*1cb875aeSCathy Zhou 		break;
581*1cb875aeSCathy Zhou 	case ROUTER_LINK:
582*1cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%s", conf->vvc_link);
583*1cb875aeSCathy Zhou 		break;
584*1cb875aeSCathy Zhou 	case ROUTER_AF:
585*1cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "IPv%d",
586*1cb875aeSCathy Zhou 		    conf->vvc_af == AF_INET ? 4 : 6);
587*1cb875aeSCathy Zhou 		break;
588*1cb875aeSCathy Zhou 	case ROUTER_PRIO:
589*1cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%d", conf->vvc_pri);
590*1cb875aeSCathy Zhou 		break;
591*1cb875aeSCathy Zhou 	case ROUTER_ADV_INTV:
592*1cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%d", conf->vvc_adver_int);
593*1cb875aeSCathy Zhou 		break;
594*1cb875aeSCathy Zhou 	case ROUTER_MODE:
595*1cb875aeSCathy Zhou 		(void) strlcpy(buf, "-----", bufsize);
596*1cb875aeSCathy Zhou 		if (conf->vvc_enabled)
597*1cb875aeSCathy Zhou 			buf[0] = 'e';
598*1cb875aeSCathy Zhou 		if (conf->vvc_pri == VRRP_PRI_OWNER)
599*1cb875aeSCathy Zhou 			buf[1] = 'o';
600*1cb875aeSCathy Zhou 		if (conf->vvc_preempt)
601*1cb875aeSCathy Zhou 			buf[2] = 'p';
602*1cb875aeSCathy Zhou 		if (conf->vvc_accept)
603*1cb875aeSCathy Zhou 			buf[3] = 'a';
604*1cb875aeSCathy Zhou 		break;
605*1cb875aeSCathy Zhou 	case ROUTER_STATE:
606*1cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%s",
607*1cb875aeSCathy Zhou 		    vrrp_state2str(sinfo->vs_state));
608*1cb875aeSCathy Zhou 		break;
609*1cb875aeSCathy Zhou 	case ROUTER_PRV_STAT:
610*1cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%s",
611*1cb875aeSCathy Zhou 		    vrrp_state2str(sinfo->vs_prev_state));
612*1cb875aeSCathy Zhou 		break;
613*1cb875aeSCathy Zhou 	case ROUTER_STAT_LAST:
614*1cb875aeSCathy Zhou 		(void) timeval_since_str(tinfo->vt_since_last_tran, buf,
615*1cb875aeSCathy Zhou 		    bufsize);
616*1cb875aeSCathy Zhou 		break;
617*1cb875aeSCathy Zhou 	case ROUTER_PEER:
618*1cb875aeSCathy Zhou 		/* LINTED E_CONSTANT_CONDITION */
619*1cb875aeSCathy Zhou 		VRRPADDR2STR(conf->vvc_af, &peer->vp_addr,
620*1cb875aeSCathy Zhou 		    buf, bufsize, B_FALSE);
621*1cb875aeSCathy Zhou 		break;
622*1cb875aeSCathy Zhou 	case ROUTER_P_PRIO:
623*1cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%d", peer->vp_prio);
624*1cb875aeSCathy Zhou 		break;
625*1cb875aeSCathy Zhou 	case ROUTER_P_INTV:
626*1cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%d", peer->vp_adver_int);
627*1cb875aeSCathy Zhou 		break;
628*1cb875aeSCathy Zhou 	case ROUTER_P_ADV_LAST:
629*1cb875aeSCathy Zhou 		(void) timeval_since_str(tinfo->vt_since_last_adv, buf,
630*1cb875aeSCathy Zhou 		    bufsize);
631*1cb875aeSCathy Zhou 		break;
632*1cb875aeSCathy Zhou 	case ROUTER_M_DOWN_INTV:
633*1cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%d", tinfo->vt_master_down_intv);
634*1cb875aeSCathy Zhou 		break;
635*1cb875aeSCathy Zhou 	case ROUTER_VNIC:
636*1cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%s",
637*1cb875aeSCathy Zhou 		    strlen(ainfo->va_vnic) == 0 ? "--" : ainfo->va_vnic);
638*1cb875aeSCathy Zhou 		break;
639*1cb875aeSCathy Zhou 	case ROUTER_PRIMARY_IP:
640*1cb875aeSCathy Zhou 		/* LINTED E_CONSTANT_CONDITION */
641*1cb875aeSCathy Zhou 		VRRPADDR2STR(conf->vvc_af, &ainfo->va_primary,
642*1cb875aeSCathy Zhou 		    buf, bufsize, B_FALSE);
643*1cb875aeSCathy Zhou 		break;
644*1cb875aeSCathy Zhou 	case ROUTER_VIRTUAL_IPS: {
645*1cb875aeSCathy Zhou 		uint32_t i;
646*1cb875aeSCathy Zhou 
647*1cb875aeSCathy Zhou 		for (i = 0; i < ainfo->va_vipcnt; i++) {
648*1cb875aeSCathy Zhou 			/* LINTED E_CONSTANT_CONDITION */
649*1cb875aeSCathy Zhou 			VRRPADDR2STR(conf->vvc_af, &(ainfo->va_vips[i]),
650*1cb875aeSCathy Zhou 			    buf, bufsize, B_TRUE);
651*1cb875aeSCathy Zhou 			if (i != ainfo->va_vipcnt - 1)
652*1cb875aeSCathy Zhou 				(void) strlcat(buf, ",", bufsize);
653*1cb875aeSCathy Zhou 		}
654*1cb875aeSCathy Zhou 		break;
655*1cb875aeSCathy Zhou 	}
656*1cb875aeSCathy Zhou 	case ROUTER_VIP_CNT:
657*1cb875aeSCathy Zhou 		(void) snprintf(buf, bufsize, "%d", ainfo->va_vipcnt);
658*1cb875aeSCathy Zhou 		break;
659*1cb875aeSCathy Zhou 	default:
660*1cb875aeSCathy Zhou 		return (B_FALSE);
661*1cb875aeSCathy Zhou 	}
662*1cb875aeSCathy Zhou 
663*1cb875aeSCathy Zhou 	return (B_TRUE);
664*1cb875aeSCathy Zhou }
665*1cb875aeSCathy Zhou 
666*1cb875aeSCathy Zhou static void
667*1cb875aeSCathy Zhou usage()
668*1cb875aeSCathy Zhou {
669*1cb875aeSCathy Zhou 	int	i;
670*1cb875aeSCathy Zhou 	cmd_t	*cp;
671*1cb875aeSCathy Zhou 
672*1cb875aeSCathy Zhou 	(void) fprintf(stderr, "%s",
673*1cb875aeSCathy Zhou 	    gettext("usage:  vrrpadm <sub-command> <args> ...\n"));
674*1cb875aeSCathy Zhou 
675*1cb875aeSCathy Zhou 	for (i = 0; i < sizeof (cmds) / sizeof (cmd_t); i++) {
676*1cb875aeSCathy Zhou 		cp = &cmds[i];
677*1cb875aeSCathy Zhou 		if (cp->c_usage != NULL)
678*1cb875aeSCathy Zhou 			(void) fprintf(stderr, "          %-10s %s\n",
679*1cb875aeSCathy Zhou 			    gettext(cp->c_name), gettext(cp->c_usage));
680*1cb875aeSCathy Zhou 	}
681*1cb875aeSCathy Zhou 
682*1cb875aeSCathy Zhou 	vrrp_close(vrrp_vh);
683*1cb875aeSCathy Zhou 	exit(EXIT_FAILURE);
684*1cb875aeSCathy Zhou }
685*1cb875aeSCathy Zhou 
686*1cb875aeSCathy Zhou static void
687*1cb875aeSCathy Zhou warn(const char *format, ...)
688*1cb875aeSCathy Zhou {
689*1cb875aeSCathy Zhou 	va_list alist;
690*1cb875aeSCathy Zhou 
691*1cb875aeSCathy Zhou 	format = gettext(format);
692*1cb875aeSCathy Zhou 	(void) fprintf(stderr, gettext("warning: "));
693*1cb875aeSCathy Zhou 
694*1cb875aeSCathy Zhou 	va_start(alist, format);
695*1cb875aeSCathy Zhou 	(void) vfprintf(stderr, format, alist);
696*1cb875aeSCathy Zhou 	va_end(alist);
697*1cb875aeSCathy Zhou 	(void) putc('\n', stderr);
698*1cb875aeSCathy Zhou }
699*1cb875aeSCathy Zhou 
700*1cb875aeSCathy Zhou static void
701*1cb875aeSCathy Zhou err_exit(const char *format, ...)
702*1cb875aeSCathy Zhou {
703*1cb875aeSCathy Zhou 	va_list alist;
704*1cb875aeSCathy Zhou 
705*1cb875aeSCathy Zhou 	format = gettext(format);
706*1cb875aeSCathy Zhou 	va_start(alist, format);
707*1cb875aeSCathy Zhou 	(void) vfprintf(stderr, format, alist);
708*1cb875aeSCathy Zhou 	va_end(alist);
709*1cb875aeSCathy Zhou 	(void) putc('\n', stderr);
710*1cb875aeSCathy Zhou 	vrrp_close(vrrp_vh);
711*1cb875aeSCathy Zhou 	exit(EXIT_FAILURE);
712*1cb875aeSCathy Zhou }
713*1cb875aeSCathy Zhou 
714*1cb875aeSCathy Zhou static void
715*1cb875aeSCathy Zhou opterr_exit(int opt, int opterr, const char *use)
716*1cb875aeSCathy Zhou {
717*1cb875aeSCathy Zhou 	switch (opterr) {
718*1cb875aeSCathy Zhou 	case ':':
719*1cb875aeSCathy Zhou 		err_exit("option '-%c' requires a value\nusage: %s", opt,
720*1cb875aeSCathy Zhou 		    gettext(use));
721*1cb875aeSCathy Zhou 		break;
722*1cb875aeSCathy Zhou 	case '?':
723*1cb875aeSCathy Zhou 	default:
724*1cb875aeSCathy Zhou 		err_exit("unrecognized option '-%c'\nusage: %s", opt,
725*1cb875aeSCathy Zhou 		    gettext(use));
726*1cb875aeSCathy Zhou 		break;
727*1cb875aeSCathy Zhou 	}
728*1cb875aeSCathy Zhou }
729*1cb875aeSCathy Zhou 
730*1cb875aeSCathy Zhou static char *
731*1cb875aeSCathy Zhou timeval_since_str(int mill, char *str, size_t len)
732*1cb875aeSCathy Zhou {
733*1cb875aeSCathy Zhou 	int	sec, msec, min;
734*1cb875aeSCathy Zhou 
735*1cb875aeSCathy Zhou 	msec = mill % 1000;
736*1cb875aeSCathy Zhou 	sec = mill / 1000;
737*1cb875aeSCathy Zhou 	min = sec > 60 ? sec / 60 : 0;
738*1cb875aeSCathy Zhou 	sec %= 60;
739*1cb875aeSCathy Zhou 
740*1cb875aeSCathy Zhou 	if (min > 0)
741*1cb875aeSCathy Zhou 		(void) snprintf(str, len, "%4dm%2ds", min, sec);
742*1cb875aeSCathy Zhou 	else
743*1cb875aeSCathy Zhou 		(void) snprintf(str, len, "%4d.%03ds", sec, msec);
744*1cb875aeSCathy Zhou 
745*1cb875aeSCathy Zhou 	return (str);
746*1cb875aeSCathy Zhou }
747*1cb875aeSCathy Zhou 
748*1cb875aeSCathy Zhou /*
749*1cb875aeSCathy Zhou  * Parses options string. The values of the two options will be returned
750*1cb875aeSCathy Zhou  * by 'preempt' and 'accept', and the mask 'modify_mask' will be updated
751*1cb875aeSCathy Zhou  * accordingly.
752*1cb875aeSCathy Zhou  *
753*1cb875aeSCathy Zhou  * Returns 0 on success, errno on failures.
754*1cb875aeSCathy Zhou  *
755*1cb875aeSCathy Zhou  * Used by do_create() and do_modify().
756*1cb875aeSCathy Zhou  *
757*1cb875aeSCathy Zhou  * Note that "opts" could be modified internally in this function.
758*1cb875aeSCathy Zhou  */
759*1cb875aeSCathy Zhou static int
760*1cb875aeSCathy Zhou str2opt(char *opts, uint32_t *modify_mask, boolean_t *preempt,
761*1cb875aeSCathy Zhou     boolean_t *accept)
762*1cb875aeSCathy Zhou {
763*1cb875aeSCathy Zhou 	char		*value;
764*1cb875aeSCathy Zhou 	int		opt;
765*1cb875aeSCathy Zhou 	uint32_t	mask = 0;
766*1cb875aeSCathy Zhou 	static enum { o_preempt = 0, o_un_preempt, o_accept, o_no_accept };
767*1cb875aeSCathy Zhou 	static char	*myopts[] = {
768*1cb875aeSCathy Zhou 		"preempt",
769*1cb875aeSCathy Zhou 		"un_preempt",
770*1cb875aeSCathy Zhou 		"accept",
771*1cb875aeSCathy Zhou 		"no_accept",
772*1cb875aeSCathy Zhou 		NULL
773*1cb875aeSCathy Zhou 	};
774*1cb875aeSCathy Zhou 
775*1cb875aeSCathy Zhou 	while (*opts != '\0') {
776*1cb875aeSCathy Zhou 		switch ((opt = getsubopt(&opts, myopts, &value))) {
777*1cb875aeSCathy Zhou 		case o_preempt:
778*1cb875aeSCathy Zhou 		case o_un_preempt:
779*1cb875aeSCathy Zhou 			if (mask & VRRP_CONF_PREEMPT)
780*1cb875aeSCathy Zhou 				return (EINVAL);
781*1cb875aeSCathy Zhou 
782*1cb875aeSCathy Zhou 			mask |= VRRP_CONF_PREEMPT;
783*1cb875aeSCathy Zhou 			*preempt = (opt == o_preempt);
784*1cb875aeSCathy Zhou 			break;
785*1cb875aeSCathy Zhou 		case o_accept:
786*1cb875aeSCathy Zhou 		case o_no_accept:
787*1cb875aeSCathy Zhou 			if (mask & VRRP_CONF_ACCEPT)
788*1cb875aeSCathy Zhou 				return (EINVAL);
789*1cb875aeSCathy Zhou 
790*1cb875aeSCathy Zhou 			mask |= VRRP_CONF_ACCEPT;
791*1cb875aeSCathy Zhou 			*accept = (opt == o_accept);
792*1cb875aeSCathy Zhou 			break;
793*1cb875aeSCathy Zhou 		default:
794*1cb875aeSCathy Zhou 			return (EINVAL);
795*1cb875aeSCathy Zhou 		}
796*1cb875aeSCathy Zhou 	}
797*1cb875aeSCathy Zhou 
798*1cb875aeSCathy Zhou 	*modify_mask |= mask;
799*1cb875aeSCathy Zhou 	return (0);
800*1cb875aeSCathy Zhou }
801