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 done:
293 if ((err = vrrp_create(vrrp_vh, &conf)) == VRRP_SUCCESS)
294 return;
295
296 err_exit("create-router failed: %s", vrrp_err2str(err));
297 }
298
299 static void
do_delete(int argc,char * argv[],const char * use)300 do_delete(int argc, char *argv[], const char *use)
301 {
302 vrrp_err_t err;
303
304 if (argc != 2)
305 err_exit("usage: %s", gettext(use));
306
307 if ((err = vrrp_delete(vrrp_vh, argv[1])) != VRRP_SUCCESS)
308 err_exit("delete-router failed: %s", vrrp_err2str(err));
309 }
310
311 static void
do_enable(int argc,char * argv[],const char * use)312 do_enable(int argc, char *argv[], const char *use)
313 {
314 vrrp_err_t err;
315
316 if (argc != 2)
317 err_exit("usage: %s", gettext(use));
318
319 if ((err = vrrp_enable(vrrp_vh, argv[1])) != VRRP_SUCCESS)
320 err_exit("enable-router failed: %s", vrrp_err2str(err));
321 }
322
323 static void
do_disable(int argc,char * argv[],const char * use)324 do_disable(int argc, char *argv[], const char *use)
325 {
326 vrrp_err_t err;
327
328 if (argc != 2)
329 err_exit("usage: %s", gettext(use));
330
331 if ((err = vrrp_disable(vrrp_vh, argv[1])) != VRRP_SUCCESS)
332 err_exit("disable-router failed: %s", vrrp_err2str(err));
333 }
334
335 static void
do_modify(int argc,char * argv[],const char * use)336 do_modify(int argc, char *argv[], const char *use)
337 {
338 vrrp_vr_conf_t conf;
339 vrrp_err_t err;
340 uint32_t modify_mask = 0, mask;
341 char *endp;
342 int c;
343
344 while ((c = getopt_long(argc, argv, ":i:p:o:", lopts, NULL)) != EOF) {
345 switch (c) {
346 case 'i':
347 if (modify_mask & VRRP_CONF_INTERVAL)
348 err_exit("duplicate '-i' option");
349
350 modify_mask |= VRRP_CONF_INTERVAL;
351 conf.vvc_adver_int = (uint32_t)strtol(optarg, &endp, 0);
352 if ((*endp) != '\0' ||
353 conf.vvc_adver_int < VRRP_MAX_ADVER_INT_MIN ||
354 conf.vvc_adver_int > VRRP_MAX_ADVER_INT_MAX ||
355 (conf.vvc_adver_int == 0 && errno != 0)) {
356 err_exit("invalid advertisement interval");
357 }
358 break;
359 case 'o':
360 mask = 0;
361 if (str2opt(optarg, &mask, &conf.vvc_preempt,
362 &conf.vvc_accept) != 0) {
363 err_exit("Invalid options");
364 }
365 if (mask & modify_mask & VRRP_CONF_PREEMPT)
366 err_exit("duplicate '-o preempt' option");
367 else if (mask & modify_mask & VRRP_CONF_ACCEPT)
368 err_exit("duplicate '-o accept' option");
369 modify_mask |= mask;
370 break;
371 case 'p':
372 if (modify_mask & VRRP_CONF_PRIORITY)
373 err_exit("duplicate '-p' option");
374
375 modify_mask |= VRRP_CONF_PRIORITY;
376 conf.vvc_pri = strtol(optarg, &endp, 0);
377 if ((*endp) != '\0' || conf.vvc_pri < VRRP_PRI_MIN ||
378 conf.vvc_pri > VRRP_PRI_OWNER ||
379 (conf.vvc_pri == 0 && errno != 0)) {
380 err_exit("invalid priority");
381 }
382 break;
383 default:
384 opterr_exit(optopt, c, use);
385 }
386 }
387
388 if (argc - optind > 1)
389 err_exit("usage: %s", gettext(use));
390
391 if (optind != argc - 1)
392 err_exit("VRRP name not specified.");
393
394 if (strlcpy(conf.vvc_name, argv[optind], sizeof (conf.vvc_name)) >=
395 sizeof (conf.vvc_name)) {
396 err_exit("invalid router name %s", argv[optind]);
397 }
398
399 if ((modify_mask & VRRP_CONF_ACCEPT) && !conf.vvc_accept &&
400 (modify_mask & VRRP_CONF_PRIORITY) &&
401 conf.vvc_pri == VRRP_PRI_OWNER) {
402 err_exit("accept_mode must be true for virtual IP owner");
403 }
404
405 if (modify_mask == 0)
406 usage();
407
408 err = vrrp_modify(vrrp_vh, &conf, modify_mask);
409 if (err != VRRP_SUCCESS)
410 err_exit("modify-router failed: %s", vrrp_err2str(err));
411 }
412
413 /*
414 * 'show-router' one VRRP router.
415 */
416 static vrrp_err_t
do_show_router(const char * vn,ofmt_handle_t ofmt)417 do_show_router(const char *vn, ofmt_handle_t ofmt)
418 {
419 vrrp_queryinfo_t *vq;
420 vrrp_err_t err;
421
422 if ((err = vrrp_query(vrrp_vh, vn, &vq)) != VRRP_SUCCESS)
423 return (err);
424
425 ofmt_print(ofmt, vq);
426 free(vq);
427 return (VRRP_SUCCESS);
428 }
429
430 static void
do_show(int argc,char * argv[],const char * use)431 do_show(int argc, char *argv[], const char *use)
432 {
433 int c;
434 char *fields_str = NULL;
435 char *names = NULL, *router;
436 uint32_t i, in_cnt = 0, out_cnt;
437 ofmt_status_t oferr;
438 ofmt_handle_t ofmt;
439 uint_t ofmt_flags = 0;
440 vrrp_err_t err = VRRP_SUCCESS;
441 boolean_t P_opt, x_opt;
442
443 static char *dft_fields_str =
444 "NAME,VRID,LINK,AF,PRIO,ADV_INTV,MODE,STATE,VNIC";
445 static char *ext_fields_str =
446 "NAME,STATE,PRV_STAT,STAT_LAST,VNIC,PRIMARY_IP,VIRTUAL_IPS";
447 static char *peer_fields_str =
448 "NAME,PEER,P_PRIO,P_INTV,P_ADV_LAST,M_DOWN_INTV";
449 /*
450 * If parsable output is requested, add VIP_CNT into the output
451 * for extended output. It is not needed for human-readable
452 * output as it is obvious from the VIRTUAL_IPS list.
453 */
454 static char *ext_parsable_fields_str =
455 "NAME,STATE,PRV_STAT,STAT_LAST,VNIC,PRIMARY_IP,VIP_CNT,"
456 "VIRTUAL_IPS";
457
458 P_opt = x_opt = B_FALSE;
459 fields_str = dft_fields_str;
460 while ((c = getopt_long(argc, argv, ":Pxpo:", l_show_opts,
461 NULL)) != EOF) {
462 switch (c) {
463 case 'o':
464 fields_str = optarg;
465 break;
466 case 'p':
467 ofmt_flags |= OFMT_PARSABLE;
468 break;
469 case 'P':
470 P_opt = B_TRUE;
471 fields_str = peer_fields_str;
472 break;
473 case 'x':
474 x_opt = B_TRUE;
475 fields_str = ext_fields_str;
476 break;
477 default:
478 opterr_exit(optopt, c, use);
479 }
480 }
481
482 if (x_opt && P_opt)
483 err_exit("incompatible -P and -x options");
484
485 /*
486 * If parsable output is requested, add VIP_CNT into the output
487 * for extended output.
488 */
489 if ((ofmt_flags & OFMT_PARSABLE) && (fields_str == ext_fields_str))
490 fields_str = ext_parsable_fields_str;
491
492 if ((oferr = ofmt_open(fields_str, show_print_fields, ofmt_flags,
493 0, &ofmt)) != OFMT_SUCCESS) {
494 char buf[OFMT_BUFSIZE];
495
496 /*
497 * If some fields were badly formed in human-friendly mode, we
498 * emit a warning and continue. Otherwise exit immediately.
499 */
500 (void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf));
501 if (oferr != OFMT_EBADFIELDS || (ofmt_flags & OFMT_PARSABLE)) {
502 ofmt_close(ofmt);
503 err_exit(buf);
504 } else {
505 warn(buf);
506 }
507 }
508
509 /* Show one router */
510 if (optind == argc - 1) {
511 err = do_show_router(argv[optind], ofmt);
512 goto done;
513 }
514
515 /*
516 * Show all routers. First set in_cnt to 0 to find out the number
517 * of vrrp routers.
518 */
519 again:
520 if ((in_cnt != 0) && (names = malloc(in_cnt * VRRP_NAME_MAX)) == NULL) {
521 err = VRRP_ENOMEM;
522 goto done;
523 }
524
525 out_cnt = in_cnt;
526 if ((err = vrrp_list(vrrp_vh, VRRP_VRID_NONE, NULL, AF_UNSPEC,
527 &out_cnt, names)) != VRRP_SUCCESS) {
528 free(names);
529 goto done;
530 }
531
532 /*
533 * The VRRP routers has been changed between two vrrp_list()
534 * calls, try again.
535 */
536 if (out_cnt > in_cnt) {
537 in_cnt = out_cnt;
538 free(names);
539 goto again;
540 }
541
542 /*
543 * Each VRRP router name is separated by '\0`
544 */
545 router = names;
546 for (i = 0; i < in_cnt; i++) {
547 (void) do_show_router(router, ofmt);
548 router += strlen(router) + 1;
549 }
550
551 free(names);
552
553 done:
554 ofmt_close(ofmt);
555
556 if (err != VRRP_SUCCESS)
557 err_exit(vrrp_err2str(err));
558 }
559
560 /*
561 * Callback function to print fields of the configuration information.
562 */
563 static boolean_t
sfunc_vrrp_conf(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)564 sfunc_vrrp_conf(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
565 {
566 vrrp_queryinfo_t *qinfo = ofmtarg->ofmt_cbarg;
567 uint_t ofmtid = ofmtarg->ofmt_id;
568 vrrp_vr_conf_t *conf = &qinfo->show_vi;
569 vrrp_stateinfo_t *sinfo = &qinfo->show_vs;
570 vrrp_peer_t *peer = &qinfo->show_vp;
571 vrrp_timerinfo_t *tinfo = &qinfo->show_vt;
572 vrrp_addrinfo_t *ainfo = &qinfo->show_va;
573
574 switch (ofmtid) {
575 case ROUTER_NAME:
576 (void) snprintf(buf, bufsize, "%s", conf->vvc_name);
577 break;
578 case ROUTER_VRID:
579 (void) snprintf(buf, bufsize, "%d", conf->vvc_vrid);
580 break;
581 case ROUTER_LINK:
582 (void) snprintf(buf, bufsize, "%s", conf->vvc_link);
583 break;
584 case ROUTER_AF:
585 (void) snprintf(buf, bufsize, "IPv%d",
586 conf->vvc_af == AF_INET ? 4 : 6);
587 break;
588 case ROUTER_PRIO:
589 (void) snprintf(buf, bufsize, "%d", conf->vvc_pri);
590 break;
591 case ROUTER_ADV_INTV:
592 (void) snprintf(buf, bufsize, "%d", conf->vvc_adver_int);
593 break;
594 case ROUTER_MODE:
595 (void) strlcpy(buf, "-----", bufsize);
596 if (conf->vvc_enabled)
597 buf[0] = 'e';
598 if (conf->vvc_pri == VRRP_PRI_OWNER)
599 buf[1] = 'o';
600 if (conf->vvc_preempt)
601 buf[2] = 'p';
602 if (conf->vvc_accept)
603 buf[3] = 'a';
604 break;
605 case ROUTER_STATE:
606 (void) snprintf(buf, bufsize, "%s",
607 vrrp_state2str(sinfo->vs_state));
608 break;
609 case ROUTER_PRV_STAT:
610 (void) snprintf(buf, bufsize, "%s",
611 vrrp_state2str(sinfo->vs_prev_state));
612 break;
613 case ROUTER_STAT_LAST:
614 (void) timeval_since_str(tinfo->vt_since_last_tran, buf,
615 bufsize);
616 break;
617 case ROUTER_PEER:
618 /* LINTED E_CONSTANT_CONDITION */
619 VRRPADDR2STR(conf->vvc_af, &peer->vp_addr,
620 buf, bufsize, B_FALSE);
621 break;
622 case ROUTER_P_PRIO:
623 (void) snprintf(buf, bufsize, "%d", peer->vp_prio);
624 break;
625 case ROUTER_P_INTV:
626 (void) snprintf(buf, bufsize, "%d", peer->vp_adver_int);
627 break;
628 case ROUTER_P_ADV_LAST:
629 (void) timeval_since_str(tinfo->vt_since_last_adv, buf,
630 bufsize);
631 break;
632 case ROUTER_M_DOWN_INTV:
633 (void) snprintf(buf, bufsize, "%d", tinfo->vt_master_down_intv);
634 break;
635 case ROUTER_VNIC:
636 (void) snprintf(buf, bufsize, "%s",
637 strlen(ainfo->va_vnic) == 0 ? "--" : ainfo->va_vnic);
638 break;
639 case ROUTER_PRIMARY_IP:
640 /* LINTED E_CONSTANT_CONDITION */
641 VRRPADDR2STR(conf->vvc_af, &ainfo->va_primary,
642 buf, bufsize, B_FALSE);
643 break;
644 case ROUTER_VIRTUAL_IPS: {
645 uint32_t i;
646
647 for (i = 0; i < ainfo->va_vipcnt; i++) {
648 /* LINTED E_CONSTANT_CONDITION */
649 VRRPADDR2STR(conf->vvc_af, &(ainfo->va_vips[i]),
650 buf, bufsize, B_TRUE);
651 if (i != ainfo->va_vipcnt - 1)
652 (void) strlcat(buf, ",", bufsize);
653 }
654 break;
655 }
656 case ROUTER_VIP_CNT:
657 (void) snprintf(buf, bufsize, "%d", ainfo->va_vipcnt);
658 break;
659 default:
660 return (B_FALSE);
661 }
662
663 return (B_TRUE);
664 }
665
666 static void
usage()667 usage()
668 {
669 int i;
670 cmd_t *cp;
671
672 (void) fprintf(stderr, "%s",
673 gettext("usage: vrrpadm <sub-command> <args> ...\n"));
674
675 for (i = 0; i < sizeof (cmds) / sizeof (cmd_t); i++) {
676 cp = &cmds[i];
677 if (cp->c_usage != NULL)
678 (void) fprintf(stderr, " %-10s %s\n",
679 gettext(cp->c_name), gettext(cp->c_usage));
680 }
681
682 vrrp_close(vrrp_vh);
683 exit(EXIT_FAILURE);
684 }
685
686 static void
warn(const char * format,...)687 warn(const char *format, ...)
688 {
689 va_list alist;
690
691 format = gettext(format);
692 (void) fprintf(stderr, gettext("warning: "));
693
694 va_start(alist, format);
695 (void) vfprintf(stderr, format, alist);
696 va_end(alist);
697 (void) putc('\n', stderr);
698 }
699
700 static void
err_exit(const char * format,...)701 err_exit(const char *format, ...)
702 {
703 va_list alist;
704
705 format = gettext(format);
706 va_start(alist, format);
707 (void) vfprintf(stderr, format, alist);
708 va_end(alist);
709 (void) putc('\n', stderr);
710 vrrp_close(vrrp_vh);
711 exit(EXIT_FAILURE);
712 }
713
714 static void
opterr_exit(int opt,int opterr,const char * use)715 opterr_exit(int opt, int opterr, const char *use)
716 {
717 switch (opterr) {
718 case ':':
719 err_exit("option '-%c' requires a value\nusage: %s", opt,
720 gettext(use));
721 break;
722 case '?':
723 default:
724 err_exit("unrecognized option '-%c'\nusage: %s", opt,
725 gettext(use));
726 break;
727 }
728 }
729
730 static char *
timeval_since_str(int mill,char * str,size_t len)731 timeval_since_str(int mill, char *str, size_t len)
732 {
733 int sec, msec, min;
734
735 msec = mill % 1000;
736 sec = mill / 1000;
737 min = sec > 60 ? sec / 60 : 0;
738 sec %= 60;
739
740 if (min > 0)
741 (void) snprintf(str, len, "%4dm%2ds", min, sec);
742 else
743 (void) snprintf(str, len, "%4d.%03ds", sec, msec);
744
745 return (str);
746 }
747
748 /*
749 * Parses options string. The values of the two options will be returned
750 * by 'preempt' and 'accept', and the mask 'modify_mask' will be updated
751 * accordingly.
752 *
753 * Returns 0 on success, errno on failures.
754 *
755 * Used by do_create() and do_modify().
756 *
757 * Note that "opts" could be modified internally in this function.
758 */
759 static int
str2opt(char * opts,uint32_t * modify_mask,boolean_t * preempt,boolean_t * accept)760 str2opt(char *opts, uint32_t *modify_mask, boolean_t *preempt,
761 boolean_t *accept)
762 {
763 char *value;
764 int opt;
765 uint32_t mask = 0;
766 enum { o_preempt = 0, o_un_preempt, o_accept, o_no_accept };
767 static char *myopts[] = {
768 "preempt",
769 "un_preempt",
770 "accept",
771 "no_accept",
772 NULL
773 };
774
775 while (*opts != '\0') {
776 switch ((opt = getsubopt(&opts, myopts, &value))) {
777 case o_preempt:
778 case o_un_preempt:
779 if (mask & VRRP_CONF_PREEMPT)
780 return (EINVAL);
781
782 mask |= VRRP_CONF_PREEMPT;
783 *preempt = (opt == o_preempt);
784 break;
785 case o_accept:
786 case o_no_accept:
787 if (mask & VRRP_CONF_ACCEPT)
788 return (EINVAL);
789
790 mask |= VRRP_CONF_ACCEPT;
791 *accept = (opt == o_accept);
792 break;
793 default:
794 return (EINVAL);
795 }
796 }
797
798 *modify_mask |= mask;
799 return (0);
800 }
801