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