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