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