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 /* 23f6da83d4SAnurag S. Maskey * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 241cb875aeSCathy Zhou */ 251cb875aeSCathy Zhou 26*2954adb0SRob Gulewich /* 27*2954adb0SRob Gulewich * Copyright (c) 2012, Joyent, Inc. All rights reserved. 28*2954adb0SRob Gulewich */ 29*2954adb0SRob Gulewich 301cb875aeSCathy Zhou #include <sys/types.h> 311cb875aeSCathy Zhou #include <sys/socket.h> 321cb875aeSCathy Zhou #include <sys/sockio.h> 331cb875aeSCathy Zhou #include <sys/sysevent/vrrp.h> 341cb875aeSCathy Zhou #include <sys/sysevent/eventdefs.h> 351cb875aeSCathy Zhou #include <sys/varargs.h> 361cb875aeSCathy Zhou #include <auth_attr.h> 371cb875aeSCathy Zhou #include <ctype.h> 381cb875aeSCathy Zhou #include <fcntl.h> 391cb875aeSCathy Zhou #include <stdlib.h> 401cb875aeSCathy Zhou #include <strings.h> 411cb875aeSCathy Zhou #include <errno.h> 421cb875aeSCathy Zhou #include <unistd.h> 431cb875aeSCathy Zhou #include <zone.h> 441cb875aeSCathy Zhou #include <libsysevent.h> 451cb875aeSCathy Zhou #include <limits.h> 461cb875aeSCathy Zhou #include <locale.h> 471cb875aeSCathy Zhou #include <arpa/inet.h> 481cb875aeSCathy Zhou #include <signal.h> 491cb875aeSCathy Zhou #include <assert.h> 501cb875aeSCathy Zhou #include <ucred.h> 511cb875aeSCathy Zhou #include <bsm/adt.h> 521cb875aeSCathy Zhou #include <bsm/adt_event.h> 531cb875aeSCathy Zhou #include <priv_utils.h> 541cb875aeSCathy Zhou #include <libdllink.h> 551cb875aeSCathy Zhou #include <libdlvnic.h> 56f6da83d4SAnurag S. Maskey #include <libipadm.h> 571cb875aeSCathy Zhou #include <pwd.h> 581cb875aeSCathy Zhou #include <libvrrpadm.h> 591cb875aeSCathy Zhou #include <net/route.h> 601cb875aeSCathy Zhou #include "vrrpd_impl.h" 611cb875aeSCathy Zhou 621cb875aeSCathy Zhou /* 631cb875aeSCathy Zhou * A VRRP router can be only start participating the VRRP protocol of a virtual 641cb875aeSCathy Zhou * router when all the following conditions are met: 651cb875aeSCathy Zhou * 661cb875aeSCathy Zhou * - The VRRP router is enabled (vr->vvr_conf.vvc_enabled is _B_TRUE) 671cb875aeSCathy Zhou * - The RX socket is successfully created over the physical interface to 681cb875aeSCathy Zhou * receive the VRRP multicast advertisement. Note that one RX socket can 691cb875aeSCathy Zhou * be shared by several VRRP routers configured over the same physical 701cb875aeSCathy Zhou * interface. (See vrrpd_init_rxsock()) 711cb875aeSCathy Zhou * - The TX socket is successfully created over the VNIC interface to send 721cb875aeSCathy Zhou * the VRRP advertisment. (See vrrpd_init_txsock()) 731cb875aeSCathy Zhou * - The primary IP address has been successfully selected over the physical 741cb875aeSCathy Zhou * interface. (See vrrpd_select_primary()) 751cb875aeSCathy Zhou * 761cb875aeSCathy Zhou * If a VRRP router is enabled but the other conditions haven't be satisfied, 771cb875aeSCathy Zhou * the router will be stay at the VRRP_STATE_INIT state. If all the above 781cb875aeSCathy Zhou * conditions are met, the VRRP router will be transit to either 791cb875aeSCathy Zhou * the VRRP_STATE_MASTER or the VRRP_STATE_BACKUP state, depends on the VRRP 801cb875aeSCathy Zhou * protocol. 811cb875aeSCathy Zhou */ 821cb875aeSCathy Zhou 831cb875aeSCathy Zhou #define skip_whitespace(p) while (isspace(*(p))) ++(p) 841cb875aeSCathy Zhou 851cb875aeSCathy Zhou #define BUFFSIZE 65536 861cb875aeSCathy Zhou 871cb875aeSCathy Zhou #define VRRPCONF "/etc/inet/vrrp.conf" 881cb875aeSCathy Zhou 891cb875aeSCathy Zhou typedef struct vrrpd_rtsock_s { 901cb875aeSCathy Zhou int vrt_af; /* address family */ 911cb875aeSCathy Zhou int vrt_fd; /* socket for the PF_ROUTE msg */ 921cb875aeSCathy Zhou iu_event_id_t vrt_eid; /* event ID */ 931cb875aeSCathy Zhou } vrrpd_rtsock_t; 941cb875aeSCathy Zhou 95f6da83d4SAnurag S. Maskey static ipadm_handle_t vrrp_ipadm_handle = NULL; /* libipadm handle */ 961cb875aeSCathy Zhou static int vrrp_logflag = 0; 971cb875aeSCathy Zhou boolean_t vrrp_debug_level = 0; 981cb875aeSCathy Zhou iu_eh_t *vrrpd_eh = NULL; 991cb875aeSCathy Zhou iu_tq_t *vrrpd_timerq = NULL; 1001cb875aeSCathy Zhou static vrrp_handle_t vrrpd_vh = NULL; 1011cb875aeSCathy Zhou static int vrrpd_cmdsock_fd = -1; /* socket to communicate */ 1021cb875aeSCathy Zhou /* between vrrpd/libvrrpadm */ 1031cb875aeSCathy Zhou static iu_event_id_t vrrpd_cmdsock_eid = -1; 1041cb875aeSCathy Zhou static int vrrpd_ctlsock_fd = -1; /* socket to bring up/down */ 1051cb875aeSCathy Zhou /* the virtual IP addresses */ 1061cb875aeSCathy Zhou static int vrrpd_ctlsock6_fd = -1; 1071cb875aeSCathy Zhou static vrrpd_rtsock_t vrrpd_rtsocks[2] = { 1081cb875aeSCathy Zhou {AF_INET, -1, -1}, 1091cb875aeSCathy Zhou {AF_INET6, -1, -1} 1101cb875aeSCathy Zhou }; 1111cb875aeSCathy Zhou static iu_timer_id_t vrrp_scan_timer_id = -1; 1121cb875aeSCathy Zhou 1131cb875aeSCathy Zhou TAILQ_HEAD(vrrp_vr_list_s, vrrp_vr_s); 1141cb875aeSCathy Zhou TAILQ_HEAD(vrrp_intf_list_s, vrrp_intf_s); 1151cb875aeSCathy Zhou static struct vrrp_vr_list_s vrrp_vr_list; 1161cb875aeSCathy Zhou static struct vrrp_intf_list_s vrrp_intf_list; 1171cb875aeSCathy Zhou static char vrrpd_conffile[MAXPATHLEN]; 1181cb875aeSCathy Zhou 1191cb875aeSCathy Zhou /* 1201cb875aeSCathy Zhou * Multicast address of VRRP advertisement in network byte order 1211cb875aeSCathy Zhou */ 1221cb875aeSCathy Zhou static vrrp_addr_t vrrp_muladdr4; 1231cb875aeSCathy Zhou static vrrp_addr_t vrrp_muladdr6; 1241cb875aeSCathy Zhou 1251cb875aeSCathy Zhou static int vrrpd_scan_interval = 20000; /* ms */ 126c5e0ece0SCathy Zhou static int pfds[2]; 1271cb875aeSCathy Zhou 1281cb875aeSCathy Zhou /* 1291cb875aeSCathy Zhou * macros to calculate skew_time and master_down_timer 1301cb875aeSCathy Zhou * 1311cb875aeSCathy Zhou * Note that the input is in centisecs and output are in msecs 1321cb875aeSCathy Zhou */ 1331cb875aeSCathy Zhou #define SKEW_TIME(pri, intv) ((intv) * (256 - (pri)) / 256) 1341cb875aeSCathy Zhou #define MASTER_DOWN_INTERVAL(pri, intv) (3 * (intv) + SKEW_TIME((pri), (intv))) 1351cb875aeSCathy Zhou 1361cb875aeSCathy Zhou #define SKEW_TIME_VR(vr) \ 1371cb875aeSCathy Zhou SKEW_TIME((vr)->vvr_conf.vvc_pri, (vr)->vvr_master_adver_int) 1381cb875aeSCathy Zhou #define MASTER_DOWN_INTERVAL_VR(vr) \ 1391cb875aeSCathy Zhou MASTER_DOWN_INTERVAL((vr)->vvr_conf.vvc_pri, (vr)->vvr_master_adver_int) 1401cb875aeSCathy Zhou 1411cb875aeSCathy Zhou #define VRRP_CONF_UPDATE 0x01 1421cb875aeSCathy Zhou #define VRRP_CONF_DELETE 0x02 1431cb875aeSCathy Zhou 1441cb875aeSCathy Zhou static char *af_str(int); 1451cb875aeSCathy Zhou 1461cb875aeSCathy Zhou static iu_tq_callback_t vrrp_adv_timeout; 1471cb875aeSCathy Zhou static iu_tq_callback_t vrrp_b2m_timeout; 1481cb875aeSCathy Zhou static iu_eh_callback_t vrrpd_sock_handler; 1491cb875aeSCathy Zhou static iu_eh_callback_t vrrpd_rtsock_handler; 1501cb875aeSCathy Zhou static iu_eh_callback_t vrrpd_cmdsock_handler; 1511cb875aeSCathy Zhou 1521cb875aeSCathy Zhou static int daemon_init(); 1531cb875aeSCathy Zhou 1541cb875aeSCathy Zhou static vrrp_err_t vrrpd_init(); 1551cb875aeSCathy Zhou static void vrrpd_fini(); 1561cb875aeSCathy Zhou static vrrp_err_t vrrpd_cmdsock_create(); 1571cb875aeSCathy Zhou static void vrrpd_cmdsock_destroy(); 1581cb875aeSCathy Zhou static vrrp_err_t vrrpd_rtsock_create(); 1591cb875aeSCathy Zhou static void vrrpd_rtsock_destroy(); 1601cb875aeSCathy Zhou static vrrp_err_t vrrpd_ctlsock_create(); 1611cb875aeSCathy Zhou static void vrrpd_ctlsock_destroy(); 1621cb875aeSCathy Zhou 1631cb875aeSCathy Zhou static void vrrpd_scan_timer(iu_tq_t *, void *); 1641cb875aeSCathy Zhou static void vrrpd_scan(int); 1651cb875aeSCathy Zhou static vrrp_err_t vrrpd_init_rxsock(vrrp_vr_t *); 1661cb875aeSCathy Zhou static void vrrpd_fini_rxsock(vrrp_vr_t *); 1671cb875aeSCathy Zhou static vrrp_err_t vrrpd_init_txsock(vrrp_vr_t *); 1681cb875aeSCathy Zhou static vrrp_err_t vrrpd_init_txsock_v4(vrrp_vr_t *); 1691cb875aeSCathy Zhou static vrrp_err_t vrrpd_init_txsock_v6(vrrp_vr_t *); 1701cb875aeSCathy Zhou static void vrrpd_fini_txsock(vrrp_vr_t *); 1711cb875aeSCathy Zhou 1721cb875aeSCathy Zhou static vrrp_err_t vrrpd_create_vr(vrrp_vr_conf_t *); 1731cb875aeSCathy Zhou static vrrp_err_t vrrpd_enable_vr(vrrp_vr_t *); 1741cb875aeSCathy Zhou static void vrrpd_disable_vr(vrrp_vr_t *, vrrp_intf_t *, boolean_t); 1751cb875aeSCathy Zhou static void vrrpd_delete_vr(vrrp_vr_t *); 1761cb875aeSCathy Zhou 1771cb875aeSCathy Zhou static vrrp_err_t vrrpd_create(vrrp_vr_conf_t *, boolean_t); 1781cb875aeSCathy Zhou static vrrp_err_t vrrpd_delete(const char *); 1791cb875aeSCathy Zhou static vrrp_err_t vrrpd_enable(const char *, boolean_t); 1801cb875aeSCathy Zhou static vrrp_err_t vrrpd_disable(const char *); 1811cb875aeSCathy Zhou static vrrp_err_t vrrpd_modify(vrrp_vr_conf_t *, uint32_t); 1821cb875aeSCathy Zhou static void vrrpd_list(vrid_t, char *, int, vrrp_ret_list_t *, size_t *); 1831cb875aeSCathy Zhou static void vrrpd_query(const char *, vrrp_ret_query_t *, size_t *); 1841cb875aeSCathy Zhou 1851cb875aeSCathy Zhou static boolean_t vrrp_rd_prop_name(vrrp_vr_conf_t *, const char *); 1861cb875aeSCathy Zhou static boolean_t vrrp_rd_prop_vrid(vrrp_vr_conf_t *, const char *); 1871cb875aeSCathy Zhou static boolean_t vrrp_rd_prop_af(vrrp_vr_conf_t *, const char *); 1881cb875aeSCathy Zhou static boolean_t vrrp_rd_prop_pri(vrrp_vr_conf_t *, const char *); 1891cb875aeSCathy Zhou static boolean_t vrrp_rd_prop_adver_int(vrrp_vr_conf_t *, const char *); 1901cb875aeSCathy Zhou static boolean_t vrrp_rd_prop_preempt(vrrp_vr_conf_t *, const char *); 1911cb875aeSCathy Zhou static boolean_t vrrp_rd_prop_accept(vrrp_vr_conf_t *, const char *); 1921cb875aeSCathy Zhou static boolean_t vrrp_rd_prop_ifname(vrrp_vr_conf_t *, const char *); 1931cb875aeSCathy Zhou static boolean_t vrrp_rd_prop_enabled(vrrp_vr_conf_t *, const char *); 1941cb875aeSCathy Zhou static int vrrp_wt_prop_name(vrrp_vr_conf_t *, char *, size_t); 1951cb875aeSCathy Zhou static int vrrp_wt_prop_vrid(vrrp_vr_conf_t *, char *, size_t); 1961cb875aeSCathy Zhou static int vrrp_wt_prop_af(vrrp_vr_conf_t *, char *, size_t); 1971cb875aeSCathy Zhou static int vrrp_wt_prop_pri(vrrp_vr_conf_t *, char *, size_t); 1981cb875aeSCathy Zhou static int vrrp_wt_prop_adver_int(vrrp_vr_conf_t *, char *, size_t); 1991cb875aeSCathy Zhou static int vrrp_wt_prop_preempt(vrrp_vr_conf_t *, char *, size_t); 2001cb875aeSCathy Zhou static int vrrp_wt_prop_accept(vrrp_vr_conf_t *, char *, size_t); 2011cb875aeSCathy Zhou static int vrrp_wt_prop_ifname(vrrp_vr_conf_t *, char *, size_t); 2021cb875aeSCathy Zhou static int vrrp_wt_prop_enabled(vrrp_vr_conf_t *, char *, size_t); 2031cb875aeSCathy Zhou 2041cb875aeSCathy Zhou static void vrrpd_cmd_create(void *, void *, size_t *); 2051cb875aeSCathy Zhou static void vrrpd_cmd_delete(void *, void *, size_t *); 2061cb875aeSCathy Zhou static void vrrpd_cmd_enable(void *, void *, size_t *); 2071cb875aeSCathy Zhou static void vrrpd_cmd_disable(void *, void *, size_t *); 2081cb875aeSCathy Zhou static void vrrpd_cmd_modify(void *, void *, size_t *); 2091cb875aeSCathy Zhou static void vrrpd_cmd_list(void *, void *, size_t *); 2101cb875aeSCathy Zhou static void vrrpd_cmd_query(void *, void *, size_t *); 2111cb875aeSCathy Zhou 2121cb875aeSCathy Zhou static vrrp_vr_t *vrrpd_lookup_vr_by_vrid(char *, vrid_t vrid_t, int); 2131cb875aeSCathy Zhou static vrrp_vr_t *vrrpd_lookup_vr_by_name(const char *); 2141cb875aeSCathy Zhou static vrrp_intf_t *vrrpd_lookup_if(const char *, int); 2151cb875aeSCathy Zhou static vrrp_err_t vrrpd_create_if(const char *, int, uint32_t, vrrp_intf_t **); 2161cb875aeSCathy Zhou static void vrrpd_delete_if(vrrp_intf_t *, boolean_t); 2171cb875aeSCathy Zhou static vrrp_err_t vrrpd_create_ip(vrrp_intf_t *, const char *, vrrp_addr_t *, 2181cb875aeSCathy Zhou uint64_t flags); 2191cb875aeSCathy Zhou static void vrrpd_delete_ip(vrrp_intf_t *, vrrp_ip_t *); 2201cb875aeSCathy Zhou 2211cb875aeSCathy Zhou static void vrrpd_init_ipcache(int); 2221cb875aeSCathy Zhou static void vrrpd_update_ipcache(int); 223f6da83d4SAnurag S. Maskey static ipadm_status_t vrrpd_walk_addr_info(int); 2241cb875aeSCathy Zhou static vrrp_err_t vrrpd_add_ipaddr(char *, int, vrrp_addr_t *, 2251cb875aeSCathy Zhou int, uint64_t); 2261cb875aeSCathy Zhou static vrrp_ip_t *vrrpd_select_primary(vrrp_intf_t *); 2271cb875aeSCathy Zhou static void vrrpd_reselect_primary(vrrp_intf_t *); 2281cb875aeSCathy Zhou static void vrrpd_reenable_all_vr(); 2291cb875aeSCathy Zhou static void vrrpd_remove_if(vrrp_intf_t *, boolean_t); 2301cb875aeSCathy Zhou 2311cb875aeSCathy Zhou static uint16_t in_cksum(int, uint16_t, void *); 2321cb875aeSCathy Zhou static uint16_t vrrp_cksum4(struct in_addr *, struct in_addr *, 2331cb875aeSCathy Zhou uint16_t, vrrp_pkt_t *); 2341cb875aeSCathy Zhou static uint16_t vrrp_cksum6(struct in6_addr *, struct in6_addr *, 2351cb875aeSCathy Zhou uint16_t, vrrp_pkt_t *); 2361cb875aeSCathy Zhou static size_t vrrpd_build_vrrp(vrrp_vr_t *, uchar_t *, int, boolean_t); 2371cb875aeSCathy Zhou 2381cb875aeSCathy Zhou static void vrrpd_process_adv(vrrp_vr_t *, vrrp_addr_t *, vrrp_pkt_t *); 2391cb875aeSCathy Zhou static vrrp_err_t vrrpd_send_adv(vrrp_vr_t *, boolean_t); 2401cb875aeSCathy Zhou 2411cb875aeSCathy Zhou /* state transition functions */ 2421cb875aeSCathy Zhou static vrrp_err_t vrrpd_state_i2m(vrrp_vr_t *); 2431cb875aeSCathy Zhou static vrrp_err_t vrrpd_state_i2b(vrrp_vr_t *); 2441cb875aeSCathy Zhou static void vrrpd_state_m2i(vrrp_vr_t *); 2451cb875aeSCathy Zhou static void vrrpd_state_b2i(vrrp_vr_t *); 2461cb875aeSCathy Zhou static vrrp_err_t vrrpd_state_b2m(vrrp_vr_t *); 2471cb875aeSCathy Zhou static vrrp_err_t vrrpd_state_m2b(vrrp_vr_t *); 2481cb875aeSCathy Zhou static void vrrpd_state_trans(vrrp_state_t, vrrp_state_t, vrrp_vr_t *); 2491cb875aeSCathy Zhou 2501cb875aeSCathy Zhou static vrrp_err_t vrrpd_set_noaccept(vrrp_vr_t *, boolean_t); 2511cb875aeSCathy Zhou static vrrp_err_t vrrpd_virtualip_update(vrrp_vr_t *, boolean_t); 2521cb875aeSCathy Zhou static vrrp_err_t vrrpd_virtualip_updateone(vrrp_intf_t *, vrrp_ip_t *, 2531cb875aeSCathy Zhou boolean_t); 2541cb875aeSCathy Zhou static int vrrpd_post_event(const char *, vrrp_state_t, vrrp_state_t); 2551cb875aeSCathy Zhou 2561cb875aeSCathy Zhou static void vrrpd_initconf(); 2571cb875aeSCathy Zhou static vrrp_err_t vrrpd_updateconf(vrrp_vr_conf_t *, uint_t); 2581cb875aeSCathy Zhou static vrrp_err_t vrrpd_write_vrconf(char *, size_t, vrrp_vr_conf_t *); 2591cb875aeSCathy Zhou static vrrp_err_t vrrpd_read_vrconf(char *, vrrp_vr_conf_t *); 2601cb875aeSCathy Zhou static vrrp_err_t vrrpd_readprop(const char *, vrrp_vr_conf_t *); 2611cb875aeSCathy Zhou static void vrrpd_cleanup(); 2621cb875aeSCathy Zhou 2631cb875aeSCathy Zhou static void vrrp_log(int, char *, ...); 2641cb875aeSCathy Zhou static int timeval_to_milli(struct timeval); 2651cb875aeSCathy Zhou static struct timeval timeval_delta(struct timeval, struct timeval); 2661cb875aeSCathy Zhou 2671cb875aeSCathy Zhou typedef struct vrrpd_prop_s { 2681cb875aeSCathy Zhou char *vs_propname; 2691cb875aeSCathy Zhou boolean_t (*vs_propread)(vrrp_vr_conf_t *, const char *); 2701cb875aeSCathy Zhou int (*vs_propwrite)(vrrp_vr_conf_t *, char *, size_t); 2711cb875aeSCathy Zhou } vrrp_prop_t; 2721cb875aeSCathy Zhou 2731cb875aeSCathy Zhou /* 2741cb875aeSCathy Zhou * persistent VRRP properties array 2751cb875aeSCathy Zhou */ 2761cb875aeSCathy Zhou static vrrp_prop_t vrrp_prop_info_tbl[] = { 2771cb875aeSCathy Zhou {"name", vrrp_rd_prop_name, vrrp_wt_prop_name}, 2781cb875aeSCathy Zhou {"vrid", vrrp_rd_prop_vrid, vrrp_wt_prop_vrid}, 2791cb875aeSCathy Zhou {"priority", vrrp_rd_prop_pri, vrrp_wt_prop_pri}, 2801cb875aeSCathy Zhou {"adv_intval", vrrp_rd_prop_adver_int, vrrp_wt_prop_adver_int}, 2811cb875aeSCathy Zhou {"preempt_mode", vrrp_rd_prop_preempt, vrrp_wt_prop_preempt}, 2821cb875aeSCathy Zhou {"accept_mode", vrrp_rd_prop_accept, vrrp_wt_prop_accept}, 2831cb875aeSCathy Zhou {"interface", vrrp_rd_prop_ifname, vrrp_wt_prop_ifname}, 2841cb875aeSCathy Zhou {"af", vrrp_rd_prop_af, vrrp_wt_prop_af}, 2851cb875aeSCathy Zhou {"enabled", vrrp_rd_prop_enabled, vrrp_wt_prop_enabled} 2861cb875aeSCathy Zhou }; 2871cb875aeSCathy Zhou 2881cb875aeSCathy Zhou #define VRRP_PROP_INFO_TABSIZE \ 2891cb875aeSCathy Zhou (sizeof (vrrp_prop_info_tbl) / sizeof (vrrp_prop_t)) 2901cb875aeSCathy Zhou 2911cb875aeSCathy Zhou typedef void vrrp_cmd_func_t(void *, void *, size_t *); 2921cb875aeSCathy Zhou 2931cb875aeSCathy Zhou typedef struct vrrp_cmd_info_s { 2941cb875aeSCathy Zhou vrrp_cmd_type_t vi_cmd; 2951cb875aeSCathy Zhou size_t vi_reqsize; 2961cb875aeSCathy Zhou size_t vi_acksize; /* 0 if the size is variable */ 2971cb875aeSCathy Zhou boolean_t vi_setop; /* Set operation? Check credentials */ 2981cb875aeSCathy Zhou vrrp_cmd_func_t *vi_cmdfunc; 2991cb875aeSCathy Zhou } vrrp_cmd_info_t; 3001cb875aeSCathy Zhou 3011cb875aeSCathy Zhou static vrrp_cmd_info_t vrrp_cmd_info_tbl[] = { 3021cb875aeSCathy Zhou {VRRP_CMD_CREATE, sizeof (vrrp_cmd_create_t), 3031cb875aeSCathy Zhou sizeof (vrrp_ret_create_t), _B_TRUE, vrrpd_cmd_create}, 3041cb875aeSCathy Zhou {VRRP_CMD_DELETE, sizeof (vrrp_cmd_delete_t), 3051cb875aeSCathy Zhou sizeof (vrrp_ret_delete_t), _B_TRUE, vrrpd_cmd_delete}, 3061cb875aeSCathy Zhou {VRRP_CMD_ENABLE, sizeof (vrrp_cmd_enable_t), 3071cb875aeSCathy Zhou sizeof (vrrp_ret_enable_t), _B_TRUE, vrrpd_cmd_enable}, 3081cb875aeSCathy Zhou {VRRP_CMD_DISABLE, sizeof (vrrp_cmd_disable_t), 3091cb875aeSCathy Zhou sizeof (vrrp_ret_disable_t), _B_TRUE, vrrpd_cmd_disable}, 3101cb875aeSCathy Zhou {VRRP_CMD_MODIFY, sizeof (vrrp_cmd_modify_t), 3111cb875aeSCathy Zhou sizeof (vrrp_ret_modify_t), _B_TRUE, vrrpd_cmd_modify}, 3121cb875aeSCathy Zhou {VRRP_CMD_QUERY, sizeof (vrrp_cmd_query_t), 0, 3131cb875aeSCathy Zhou _B_FALSE, vrrpd_cmd_query}, 3141cb875aeSCathy Zhou {VRRP_CMD_LIST, sizeof (vrrp_cmd_list_t), 0, 3151cb875aeSCathy Zhou _B_FALSE, vrrpd_cmd_list} 3161cb875aeSCathy Zhou }; 3171cb875aeSCathy Zhou 3181cb875aeSCathy Zhou #define VRRP_DOOR_INFO_TABLE_SIZE \ 3191cb875aeSCathy Zhou (sizeof (vrrp_cmd_info_tbl) / sizeof (vrrp_cmd_info_t)) 3201cb875aeSCathy Zhou 3211cb875aeSCathy Zhou static int 3221cb875aeSCathy Zhou ipaddr_cmp(int af, vrrp_addr_t *addr1, vrrp_addr_t *addr2) 3231cb875aeSCathy Zhou { 3241cb875aeSCathy Zhou if (af == AF_INET) { 3251cb875aeSCathy Zhou return (memcmp(&addr1->in4.sin_addr, 3261cb875aeSCathy Zhou &addr2->in4.sin_addr, sizeof (struct in_addr))); 3271cb875aeSCathy Zhou } else { 3281cb875aeSCathy Zhou return (memcmp(&addr1->in6.sin6_addr, 3291cb875aeSCathy Zhou &addr2->in6.sin6_addr, sizeof (struct in6_addr))); 3301cb875aeSCathy Zhou } 3311cb875aeSCathy Zhou } 3321cb875aeSCathy Zhou 3331cb875aeSCathy Zhou static vrrp_vr_t * 3341cb875aeSCathy Zhou vrrpd_lookup_vr_by_vrid(char *ifname, vrid_t vrid, int af) 3351cb875aeSCathy Zhou { 3361cb875aeSCathy Zhou vrrp_vr_t *vr; 3371cb875aeSCathy Zhou 3381cb875aeSCathy Zhou TAILQ_FOREACH(vr, &vrrp_vr_list, vvr_next) { 3391cb875aeSCathy Zhou if (strcmp(vr->vvr_conf.vvc_link, ifname) == 0 && 3401cb875aeSCathy Zhou vr->vvr_conf.vvc_vrid == vrid && 3411cb875aeSCathy Zhou vr->vvr_conf.vvc_af == af) { 3421cb875aeSCathy Zhou break; 3431cb875aeSCathy Zhou } 3441cb875aeSCathy Zhou } 3451cb875aeSCathy Zhou return (vr); 3461cb875aeSCathy Zhou } 3471cb875aeSCathy Zhou 3481cb875aeSCathy Zhou static vrrp_vr_t * 3491cb875aeSCathy Zhou vrrpd_lookup_vr_by_name(const char *name) 3501cb875aeSCathy Zhou { 3511cb875aeSCathy Zhou vrrp_vr_t *vr; 3521cb875aeSCathy Zhou 3531cb875aeSCathy Zhou TAILQ_FOREACH(vr, &vrrp_vr_list, vvr_next) { 3541cb875aeSCathy Zhou if (strcmp(vr->vvr_conf.vvc_name, name) == 0) 3551cb875aeSCathy Zhou break; 3561cb875aeSCathy Zhou } 3571cb875aeSCathy Zhou return (vr); 3581cb875aeSCathy Zhou } 3591cb875aeSCathy Zhou 3601cb875aeSCathy Zhou static vrrp_intf_t * 3611cb875aeSCathy Zhou vrrpd_lookup_if(const char *ifname, int af) 3621cb875aeSCathy Zhou { 3631cb875aeSCathy Zhou vrrp_intf_t *intf; 3641cb875aeSCathy Zhou 3651cb875aeSCathy Zhou TAILQ_FOREACH(intf, &vrrp_intf_list, vvi_next) { 3661cb875aeSCathy Zhou if (strcmp(ifname, intf->vvi_ifname) == 0 && 3671cb875aeSCathy Zhou af == intf->vvi_af) { 3681cb875aeSCathy Zhou break; 3691cb875aeSCathy Zhou } 3701cb875aeSCathy Zhou } 3711cb875aeSCathy Zhou return (intf); 3721cb875aeSCathy Zhou } 3731cb875aeSCathy Zhou 3741cb875aeSCathy Zhou static vrrp_err_t 3751cb875aeSCathy Zhou vrrpd_create_if(const char *ifname, int af, uint32_t ifindex, 3761cb875aeSCathy Zhou vrrp_intf_t **intfp) 3771cb875aeSCathy Zhou { 3781cb875aeSCathy Zhou vrrp_intf_t *intf; 3791cb875aeSCathy Zhou 3801cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_create_if(%s, %s, %d)", 3811cb875aeSCathy Zhou ifname, af_str(af), ifindex); 3821cb875aeSCathy Zhou 3831cb875aeSCathy Zhou if (((*intfp) = malloc(sizeof (vrrp_intf_t))) == NULL) { 3841cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_create_if(): failed to " 3851cb875aeSCathy Zhou "allocate %s/%s interface", ifname, af_str(af)); 3861cb875aeSCathy Zhou return (VRRP_ENOMEM); 3871cb875aeSCathy Zhou } 3881cb875aeSCathy Zhou 3891cb875aeSCathy Zhou intf = *intfp; 3901cb875aeSCathy Zhou TAILQ_INIT(&intf->vvi_iplist); 3911cb875aeSCathy Zhou (void) strlcpy(intf->vvi_ifname, ifname, sizeof (intf->vvi_ifname)); 3921cb875aeSCathy Zhou intf->vvi_af = af; 3931cb875aeSCathy Zhou intf->vvi_sockfd = -1; 3941cb875aeSCathy Zhou intf->vvi_nvr = 0; 3951cb875aeSCathy Zhou intf->vvi_eid = -1; 3961cb875aeSCathy Zhou intf->vvi_pip = NULL; 3971cb875aeSCathy Zhou intf->vvi_ifindex = ifindex; 3981cb875aeSCathy Zhou intf->vvi_state = NODE_STATE_NEW; 3991cb875aeSCathy Zhou intf->vvi_vr_state = VRRP_STATE_INIT; 4001cb875aeSCathy Zhou TAILQ_INSERT_TAIL(&vrrp_intf_list, intf, vvi_next); 4011cb875aeSCathy Zhou return (VRRP_SUCCESS); 4021cb875aeSCathy Zhou } 4031cb875aeSCathy Zhou 4041cb875aeSCathy Zhou /* 4051cb875aeSCathy Zhou * An interface is deleted. If update_vr is true, the deletion of the interface 4061cb875aeSCathy Zhou * may cause the state transition of assoicated VRRP router (if this interface 4071cb875aeSCathy Zhou * is either the primary or the VNIC interface of the VRRP router); otherwise, 4081cb875aeSCathy Zhou * simply delete the interface without updating the VRRP router. 4091cb875aeSCathy Zhou */ 4101cb875aeSCathy Zhou static void 4111cb875aeSCathy Zhou vrrpd_delete_if(vrrp_intf_t *intf, boolean_t update_vr) 4121cb875aeSCathy Zhou { 4131cb875aeSCathy Zhou vrrp_ip_t *ip; 4141cb875aeSCathy Zhou 4151cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_delete_if(%s, %s, %supdate_vr)", 4161cb875aeSCathy Zhou intf->vvi_ifname, af_str(intf->vvi_af), update_vr ? "" : "no_"); 4171cb875aeSCathy Zhou 4181cb875aeSCathy Zhou if (update_vr) { 4191cb875aeSCathy Zhou /* 4201cb875aeSCathy Zhou * If a this interface is the physical interface or the VNIC 4211cb875aeSCathy Zhou * of a VRRP router, the deletion of the interface (no IP 4221cb875aeSCathy Zhou * address exists on this interface) may cause the state 4231cb875aeSCathy Zhou * transition of the VRRP router. call vrrpd_remove_if() 4241cb875aeSCathy Zhou * to find all corresponding VRRP router and update their 4251cb875aeSCathy Zhou * states. 4261cb875aeSCathy Zhou */ 4271cb875aeSCathy Zhou vrrpd_remove_if(intf, _B_FALSE); 4281cb875aeSCathy Zhou } 4291cb875aeSCathy Zhou 4301cb875aeSCathy Zhou /* 4311cb875aeSCathy Zhou * First remove and delete all the IP addresses on the interface 4321cb875aeSCathy Zhou */ 4331cb875aeSCathy Zhou while (!TAILQ_EMPTY(&intf->vvi_iplist)) { 4341cb875aeSCathy Zhou ip = TAILQ_FIRST(&intf->vvi_iplist); 4351cb875aeSCathy Zhou vrrpd_delete_ip(intf, ip); 4361cb875aeSCathy Zhou } 4371cb875aeSCathy Zhou 4381cb875aeSCathy Zhou /* 4391cb875aeSCathy Zhou * Then remove and delete the interface 4401cb875aeSCathy Zhou */ 4411cb875aeSCathy Zhou TAILQ_REMOVE(&vrrp_intf_list, intf, vvi_next); 4421cb875aeSCathy Zhou (void) free(intf); 4431cb875aeSCathy Zhou } 4441cb875aeSCathy Zhou 4451cb875aeSCathy Zhou static vrrp_err_t 4461cb875aeSCathy Zhou vrrpd_create_ip(vrrp_intf_t *intf, const char *lifname, vrrp_addr_t *addr, 4471cb875aeSCathy Zhou uint64_t flags) 4481cb875aeSCathy Zhou { 4491cb875aeSCathy Zhou vrrp_ip_t *ip; 4501cb875aeSCathy Zhou char abuf[INET6_ADDRSTRLEN]; 4511cb875aeSCathy Zhou 4521cb875aeSCathy Zhou /* LINTED E_CONSTANT_CONDITION */ 4531cb875aeSCathy Zhou VRRPADDR2STR(intf->vvi_af, addr, abuf, INET6_ADDRSTRLEN, _B_FALSE); 4541cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_create_ip(%s, %s, %s, 0x%x)", 4551cb875aeSCathy Zhou intf->vvi_ifname, lifname, abuf, flags); 4561cb875aeSCathy Zhou 4571cb875aeSCathy Zhou if ((ip = malloc(sizeof (vrrp_ip_t))) == NULL) { 4581cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_create_ip(%s, %s):" 4591cb875aeSCathy Zhou "failed to allocate IP", lifname, abuf); 4601cb875aeSCathy Zhou return (VRRP_ENOMEM); 4611cb875aeSCathy Zhou } 4621cb875aeSCathy Zhou 4631cb875aeSCathy Zhou (void) strncpy(ip->vip_lifname, lifname, sizeof (ip->vip_lifname)); 4641cb875aeSCathy Zhou ip->vip_state = NODE_STATE_NEW; 4651cb875aeSCathy Zhou ip->vip_flags = flags; 4661cb875aeSCathy Zhou (void) memcpy(&ip->vip_addr, addr, sizeof (ip->vip_addr)); 4671cb875aeSCathy Zhou 4681cb875aeSCathy Zhou /* 4691cb875aeSCathy Zhou * Make sure link-local IPv6 IP addresses are at the head of the list 4701cb875aeSCathy Zhou */ 4711cb875aeSCathy Zhou if (intf->vvi_af == AF_INET6 && 4721cb875aeSCathy Zhou IN6_IS_ADDR_LINKLOCAL(&addr->in6.sin6_addr)) { 4731cb875aeSCathy Zhou TAILQ_INSERT_HEAD(&intf->vvi_iplist, ip, vip_next); 4741cb875aeSCathy Zhou } else { 4751cb875aeSCathy Zhou TAILQ_INSERT_TAIL(&intf->vvi_iplist, ip, vip_next); 4761cb875aeSCathy Zhou } 4771cb875aeSCathy Zhou return (VRRP_SUCCESS); 4781cb875aeSCathy Zhou } 4791cb875aeSCathy Zhou 4801cb875aeSCathy Zhou static void 4811cb875aeSCathy Zhou vrrpd_delete_ip(vrrp_intf_t *intf, vrrp_ip_t *ip) 4821cb875aeSCathy Zhou { 4831cb875aeSCathy Zhou char abuf[INET6_ADDRSTRLEN]; 4841cb875aeSCathy Zhou int af = intf->vvi_af; 4851cb875aeSCathy Zhou 4861cb875aeSCathy Zhou /* LINTED E_CONSTANT_CONDITION */ 4871cb875aeSCathy Zhou VRRPADDR2STR(af, &ip->vip_addr, abuf, sizeof (abuf), _B_FALSE); 4881cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_delete_ip(%s, %s, %s) is %sprimary", 4891cb875aeSCathy Zhou intf->vvi_ifname, ip->vip_lifname, abuf, 4901cb875aeSCathy Zhou intf->vvi_pip == ip ? "" : "not "); 4911cb875aeSCathy Zhou 4921cb875aeSCathy Zhou if (intf->vvi_pip == ip) 4931cb875aeSCathy Zhou intf->vvi_pip = NULL; 4941cb875aeSCathy Zhou 4951cb875aeSCathy Zhou TAILQ_REMOVE(&intf->vvi_iplist, ip, vip_next); 4961cb875aeSCathy Zhou (void) free(ip); 4971cb875aeSCathy Zhou } 4981cb875aeSCathy Zhou 4991cb875aeSCathy Zhou static char * 5001cb875aeSCathy Zhou rtm_event2str(uchar_t event) 5011cb875aeSCathy Zhou { 5021cb875aeSCathy Zhou switch (event) { 5031cb875aeSCathy Zhou case RTM_NEWADDR: 5041cb875aeSCathy Zhou return ("RTM_NEWADDR"); 5051cb875aeSCathy Zhou case RTM_DELADDR: 5061cb875aeSCathy Zhou return ("RTM_DELADDR"); 5071cb875aeSCathy Zhou case RTM_IFINFO: 5081cb875aeSCathy Zhou return ("RTM_IFINFO"); 5091cb875aeSCathy Zhou case RTM_ADD: 5101cb875aeSCathy Zhou return ("RTM_ADD"); 5111cb875aeSCathy Zhou case RTM_DELETE: 5121cb875aeSCathy Zhou return ("RTM_DELETE"); 5131cb875aeSCathy Zhou case RTM_CHANGE: 5141cb875aeSCathy Zhou return ("RTM_CHANGE"); 5151cb875aeSCathy Zhou case RTM_OLDADD: 5161cb875aeSCathy Zhou return ("RTM_OLDADD"); 5171cb875aeSCathy Zhou case RTM_OLDDEL: 5181cb875aeSCathy Zhou return ("RTM_OLDDEL"); 5191cb875aeSCathy Zhou case RTM_CHGADDR: 5201cb875aeSCathy Zhou return ("RTM_CHGADDR"); 5211cb875aeSCathy Zhou case RTM_FREEADDR: 5221cb875aeSCathy Zhou return ("RTM_FREEADDR"); 5231cb875aeSCathy Zhou default: 5241cb875aeSCathy Zhou return ("RTM_OTHER"); 5251cb875aeSCathy Zhou } 5261cb875aeSCathy Zhou } 5271cb875aeSCathy Zhou 528c5e0ece0SCathy Zhou /* 529c5e0ece0SCathy Zhou * This is called by the child process to inform the parent process to 530c5e0ece0SCathy Zhou * exit with the given return value. Note that the child process 531c5e0ece0SCathy Zhou * (the daemon process) informs the parent process to exit when anything 532c5e0ece0SCathy Zhou * goes wrong or when all the intialization is done. 533c5e0ece0SCathy Zhou */ 534c5e0ece0SCathy Zhou static int 535c5e0ece0SCathy Zhou vrrpd_inform_parent_exit(int rv) 536c5e0ece0SCathy Zhou { 537c5e0ece0SCathy Zhou int err = 0; 538c5e0ece0SCathy Zhou 539c5e0ece0SCathy Zhou /* 540c5e0ece0SCathy Zhou * If vrrp_debug_level is none-zero, vrrpd is not running as 541c5e0ece0SCathy Zhou * a daemon. Return directly. 542c5e0ece0SCathy Zhou */ 543c5e0ece0SCathy Zhou if (vrrp_debug_level != 0) 544c5e0ece0SCathy Zhou return (0); 545c5e0ece0SCathy Zhou 546c5e0ece0SCathy Zhou if (write(pfds[1], &rv, sizeof (int)) != sizeof (int)) { 547c5e0ece0SCathy Zhou err = errno; 548c5e0ece0SCathy Zhou (void) close(pfds[1]); 549c5e0ece0SCathy Zhou return (err); 550c5e0ece0SCathy Zhou } 551c5e0ece0SCathy Zhou (void) close(pfds[1]); 552c5e0ece0SCathy Zhou return (0); 553c5e0ece0SCathy Zhou } 554c5e0ece0SCathy Zhou 5551cb875aeSCathy Zhou int 5561cb875aeSCathy Zhou main(int argc, char *argv[]) 5571cb875aeSCathy Zhou { 5581cb875aeSCathy Zhou int c, err; 5591cb875aeSCathy Zhou struct sigaction sa; 5601cb875aeSCathy Zhou sigset_t mask; 5611cb875aeSCathy Zhou struct rlimit rl; 5621cb875aeSCathy Zhou 5631cb875aeSCathy Zhou (void) setlocale(LC_ALL, ""); 5641cb875aeSCathy Zhou (void) textdomain(TEXT_DOMAIN); 5651cb875aeSCathy Zhou 5661cb875aeSCathy Zhou /* 5671cb875aeSCathy Zhou * We need PRIV_SYS_CONFIG to post VRRP sysevent, PRIV_NET_RAWACESS 5681cb875aeSCathy Zhou * and PRIV_NET_ICMPACCESS to open the raw socket, PRIV_SYS_IP_CONFIG 5691cb875aeSCathy Zhou * to bring up/down the virtual IP addresses, and PRIV_SYS_RESOURCE to 5701cb875aeSCathy Zhou * setrlimit(). 5711cb875aeSCathy Zhou * 5721cb875aeSCathy Zhou * Note that sysevent is not supported in non-global zones. 5731cb875aeSCathy Zhou */ 5741cb875aeSCathy Zhou if (getzoneid() == GLOBAL_ZONEID) { 5751cb875aeSCathy Zhou err = __init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, 0, 0, 5761cb875aeSCathy Zhou PRIV_SYS_CONFIG, PRIV_NET_RAWACCESS, PRIV_NET_ICMPACCESS, 5771cb875aeSCathy Zhou PRIV_SYS_IP_CONFIG, PRIV_SYS_RESOURCE, NULL); 5781cb875aeSCathy Zhou } else { 5791cb875aeSCathy Zhou err = __init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, 0, 0, 5801cb875aeSCathy Zhou PRIV_NET_RAWACCESS, PRIV_NET_ICMPACCESS, 5811cb875aeSCathy Zhou PRIV_SYS_IP_CONFIG, PRIV_SYS_RESOURCE, NULL); 5821cb875aeSCathy Zhou } 5831cb875aeSCathy Zhou 5841cb875aeSCathy Zhou if (err == -1) { 5851cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "main(): init_daemon_priv() failed"); 5861cb875aeSCathy Zhou return (EXIT_FAILURE); 5871cb875aeSCathy Zhou } 5881cb875aeSCathy Zhou 5891cb875aeSCathy Zhou /* 5901cb875aeSCathy Zhou * If vrrpd is started by other process, it will inherit the 5911cb875aeSCathy Zhou * signal block mask. We unblock all signals to make sure the 5921cb875aeSCathy Zhou * signal handling will work normally. 5931cb875aeSCathy Zhou */ 5941cb875aeSCathy Zhou (void) sigfillset(&mask); 5951cb875aeSCathy Zhou (void) thr_sigsetmask(SIG_UNBLOCK, &mask, NULL); 5961cb875aeSCathy Zhou sa.sa_handler = vrrpd_cleanup; 5971cb875aeSCathy Zhou sa.sa_flags = 0; 5981cb875aeSCathy Zhou (void) sigemptyset(&sa.sa_mask); 5991cb875aeSCathy Zhou (void) sigaction(SIGINT, &sa, NULL); 6001cb875aeSCathy Zhou (void) sigaction(SIGQUIT, &sa, NULL); 6011cb875aeSCathy Zhou (void) sigaction(SIGTERM, &sa, NULL); 6021cb875aeSCathy Zhou 6031cb875aeSCathy Zhou vrrp_debug_level = 0; 6041cb875aeSCathy Zhou (void) strlcpy(vrrpd_conffile, VRRPCONF, sizeof (vrrpd_conffile)); 6051cb875aeSCathy Zhou while ((c = getopt(argc, argv, "d:f:")) != EOF) { 6061cb875aeSCathy Zhou switch (c) { 6071cb875aeSCathy Zhou case 'd': 6081cb875aeSCathy Zhou vrrp_debug_level = atoi(optarg); 6091cb875aeSCathy Zhou break; 6101cb875aeSCathy Zhou case 'f': 6111cb875aeSCathy Zhou (void) strlcpy(vrrpd_conffile, optarg, 6121cb875aeSCathy Zhou sizeof (vrrpd_conffile)); 6131cb875aeSCathy Zhou break; 6141cb875aeSCathy Zhou default: 6151cb875aeSCathy Zhou break; 6161cb875aeSCathy Zhou } 6171cb875aeSCathy Zhou } 6181cb875aeSCathy Zhou 6191cb875aeSCathy Zhou closefrom(3); 6201cb875aeSCathy Zhou if (vrrp_debug_level == 0 && (daemon_init() != 0)) { 6211cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "main(): daemon_init() failed"); 6221cb875aeSCathy Zhou return (EXIT_FAILURE); 6231cb875aeSCathy Zhou } 6241cb875aeSCathy Zhou 6251cb875aeSCathy Zhou rl.rlim_cur = RLIM_INFINITY; 6261cb875aeSCathy Zhou rl.rlim_max = RLIM_INFINITY; 6271cb875aeSCathy Zhou if (setrlimit(RLIMIT_NOFILE, &rl) == -1) { 6281cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "main(): setrlimit() failed"); 629c5e0ece0SCathy Zhou goto child_out; 6301cb875aeSCathy Zhou } 6311cb875aeSCathy Zhou 6321cb875aeSCathy Zhou if (vrrpd_init() != VRRP_SUCCESS) { 6331cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "main(): vrrpd_init() failed"); 634c5e0ece0SCathy Zhou goto child_out; 6351cb875aeSCathy Zhou } 6361cb875aeSCathy Zhou 6371cb875aeSCathy Zhou /* 6381cb875aeSCathy Zhou * Get rid of unneeded privileges. 6391cb875aeSCathy Zhou */ 6401cb875aeSCathy Zhou __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION, 6411cb875aeSCathy Zhou PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, PRIV_SYS_RESOURCE, NULL); 6421cb875aeSCathy Zhou 6431cb875aeSCathy Zhou /* 6441cb875aeSCathy Zhou * Read the configuration and initialize the existing VRRP 6451cb875aeSCathy Zhou * configuration 6461cb875aeSCathy Zhou */ 6471cb875aeSCathy Zhou vrrpd_initconf(); 6481cb875aeSCathy Zhou 6491cb875aeSCathy Zhou /* 650c5e0ece0SCathy Zhou * Inform the parent process that it can successfully exit. 651c5e0ece0SCathy Zhou */ 652c5e0ece0SCathy Zhou if ((err = vrrpd_inform_parent_exit(EXIT_SUCCESS)) != 0) { 653c5e0ece0SCathy Zhou vrrpd_cleanup(); 654c5e0ece0SCathy Zhou vrrp_log(VRRP_WARNING, "vrrpd_inform_parent_exit() failed: %s", 655c5e0ece0SCathy Zhou strerror(err)); 656c5e0ece0SCathy Zhou return (EXIT_FAILURE); 657c5e0ece0SCathy Zhou } 658c5e0ece0SCathy Zhou 659c5e0ece0SCathy Zhou /* 6601cb875aeSCathy Zhou * Start the loop to handle the timer and the IO events. 6611cb875aeSCathy Zhou */ 6621cb875aeSCathy Zhou switch (iu_handle_events(vrrpd_eh, vrrpd_timerq)) { 6631cb875aeSCathy Zhou case -1: 6641cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "main(): iu_handle_events() failed " 6651cb875aeSCathy Zhou "abnormally"); 6661cb875aeSCathy Zhou break; 6671cb875aeSCathy Zhou default: 6681cb875aeSCathy Zhou break; 6691cb875aeSCathy Zhou } 6701cb875aeSCathy Zhou 6711cb875aeSCathy Zhou vrrpd_cleanup(); 6721cb875aeSCathy Zhou return (EXIT_SUCCESS); 673c5e0ece0SCathy Zhou 674c5e0ece0SCathy Zhou child_out: 675c5e0ece0SCathy Zhou (void) vrrpd_inform_parent_exit(EXIT_FAILURE); 676c5e0ece0SCathy Zhou return (EXIT_FAILURE); 6771cb875aeSCathy Zhou } 6781cb875aeSCathy Zhou 6791cb875aeSCathy Zhou static int 6801cb875aeSCathy Zhou daemon_init() 6811cb875aeSCathy Zhou { 6821cb875aeSCathy Zhou pid_t pid; 683c5e0ece0SCathy Zhou int rv; 6841cb875aeSCathy Zhou 6851cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "daemon_init()"); 6861cb875aeSCathy Zhou 6871cb875aeSCathy Zhou if (getenv("SMF_FMRI") == NULL) { 688c5e0ece0SCathy Zhou vrrp_log(VRRP_ERR, "daemon_init(): vrrpd is an smf(5) managed " 689c5e0ece0SCathy Zhou "service and should not be run from the command line."); 6901cb875aeSCathy Zhou return (-1); 6911cb875aeSCathy Zhou } 6921cb875aeSCathy Zhou 693c5e0ece0SCathy Zhou /* 694c5e0ece0SCathy Zhou * Create the pipe used for the child process to inform the parent 695c5e0ece0SCathy Zhou * process to exit after all initialization is done. 696c5e0ece0SCathy Zhou */ 697c5e0ece0SCathy Zhou if (pipe(pfds) < 0) { 698c5e0ece0SCathy Zhou vrrp_log(VRRP_ERR, "daemon_init(): pipe() failed: %s", 699c5e0ece0SCathy Zhou strerror(errno)); 7001cb875aeSCathy Zhou return (-1); 701c5e0ece0SCathy Zhou } 7021cb875aeSCathy Zhou 703c5e0ece0SCathy Zhou if ((pid = fork()) < 0) { 704c5e0ece0SCathy Zhou vrrp_log(VRRP_ERR, "daemon_init(): fork() failed: %s", 705c5e0ece0SCathy Zhou strerror(errno)); 706c5e0ece0SCathy Zhou (void) close(pfds[0]); 707c5e0ece0SCathy Zhou (void) close(pfds[1]); 708c5e0ece0SCathy Zhou return (-1); 709c5e0ece0SCathy Zhou } 710c5e0ece0SCathy Zhou 711c5e0ece0SCathy Zhou if (pid != 0) { /* Parent */ 712c5e0ece0SCathy Zhou (void) close(pfds[1]); 713c5e0ece0SCathy Zhou 714c5e0ece0SCathy Zhou /* 715c5e0ece0SCathy Zhou * Read the child process's return value from the pfds. 716c5e0ece0SCathy Zhou * If the child process exits unexpectedly, read() returns -1. 717c5e0ece0SCathy Zhou */ 718c5e0ece0SCathy Zhou if (read(pfds[0], &rv, sizeof (int)) != sizeof (int)) { 719c5e0ece0SCathy Zhou vrrp_log(VRRP_ERR, "daemon_init(): child process " 720c5e0ece0SCathy Zhou "exited unexpectedly %s", strerror(errno)); 721c5e0ece0SCathy Zhou (void) kill(pid, SIGTERM); 722c5e0ece0SCathy Zhou rv = EXIT_FAILURE; 723c5e0ece0SCathy Zhou } 724c5e0ece0SCathy Zhou (void) close(pfds[0]); 725c5e0ece0SCathy Zhou exit(rv); 7261cb875aeSCathy Zhou } 7271cb875aeSCathy Zhou 7281cb875aeSCathy Zhou /* 7291cb875aeSCathy Zhou * in child process, became a daemon, and return to main() to continue. 7301cb875aeSCathy Zhou */ 731c5e0ece0SCathy Zhou (void) close(pfds[0]); 7321cb875aeSCathy Zhou (void) chdir("/"); 7331cb875aeSCathy Zhou (void) setsid(); 7341cb875aeSCathy Zhou (void) close(0); 7351cb875aeSCathy Zhou (void) close(1); 7361cb875aeSCathy Zhou (void) close(2); 7371cb875aeSCathy Zhou (void) open("/dev/null", O_RDWR, 0); 7381cb875aeSCathy Zhou (void) dup2(0, 1); 7391cb875aeSCathy Zhou (void) dup2(0, 2); 7401cb875aeSCathy Zhou openlog("vrrpd", LOG_PID, LOG_DAEMON); 7411cb875aeSCathy Zhou vrrp_logflag = 1; 7421cb875aeSCathy Zhou return (0); 7431cb875aeSCathy Zhou } 7441cb875aeSCathy Zhou 7451cb875aeSCathy Zhou static vrrp_err_t 7461cb875aeSCathy Zhou vrrpd_init() 7471cb875aeSCathy Zhou { 7481cb875aeSCathy Zhou vrrp_err_t err = VRRP_ESYS; 7491cb875aeSCathy Zhou 7501cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_init()"); 7511cb875aeSCathy Zhou 7521cb875aeSCathy Zhou TAILQ_INIT(&vrrp_vr_list); 7531cb875aeSCathy Zhou TAILQ_INIT(&vrrp_intf_list); 7541cb875aeSCathy Zhou 7551cb875aeSCathy Zhou if (vrrp_open(&vrrpd_vh) != VRRP_SUCCESS) { 7561cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_init(): vrrp_open() failed"); 7571cb875aeSCathy Zhou goto fail; 7581cb875aeSCathy Zhou } 7591cb875aeSCathy Zhou 7601cb875aeSCathy Zhou if ((vrrpd_timerq = iu_tq_create()) == NULL) { 7611cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_init(): iu_tq_create() failed"); 7621cb875aeSCathy Zhou goto fail; 7631cb875aeSCathy Zhou } 7641cb875aeSCathy Zhou 7651cb875aeSCathy Zhou if ((vrrpd_eh = iu_eh_create()) == NULL) { 7661cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_init(): iu_eh_create() failed"); 7671cb875aeSCathy Zhou goto fail; 7681cb875aeSCathy Zhou } 7691cb875aeSCathy Zhou 7701cb875aeSCathy Zhou /* 7711cb875aeSCathy Zhou * Create the AF_UNIX socket used to communicate with libvrrpadm. 7721cb875aeSCathy Zhou * 7731cb875aeSCathy Zhou * This socket is used to receive the administrative requests and 7741cb875aeSCathy Zhou * send back the results. 7751cb875aeSCathy Zhou */ 7761cb875aeSCathy Zhou if (vrrpd_cmdsock_create() != VRRP_SUCCESS) { 7771cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_init(): vrrpd_cmdsock_create() " 7781cb875aeSCathy Zhou "failed"); 7791cb875aeSCathy Zhou goto fail; 7801cb875aeSCathy Zhou } 7811cb875aeSCathy Zhou 7821cb875aeSCathy Zhou /* 7831cb875aeSCathy Zhou * Create the VRRP control socket used to bring up/down the virtual 7841cb875aeSCathy Zhou * IP addresses. It is also used to set the IFF_NOACCEPT flag of 7851cb875aeSCathy Zhou * the virtual IP addresses. 7861cb875aeSCathy Zhou */ 7871cb875aeSCathy Zhou if (vrrpd_ctlsock_create() != VRRP_SUCCESS) { 7881cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_init(): vrrpd_ctlsock_create() " 7891cb875aeSCathy Zhou "failed"); 7901cb875aeSCathy Zhou goto fail; 7911cb875aeSCathy Zhou } 7921cb875aeSCathy Zhou 7931cb875aeSCathy Zhou /* 7941cb875aeSCathy Zhou * Create the PF_ROUTER socket used to listen to the routing socket 7951cb875aeSCathy Zhou * messages and build the interface/IP address list. 7961cb875aeSCathy Zhou */ 7971cb875aeSCathy Zhou if (vrrpd_rtsock_create() != VRRP_SUCCESS) { 7981cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_init(): vrrpd_rtsock_create() " 7991cb875aeSCathy Zhou "failed"); 8001cb875aeSCathy Zhou goto fail; 8011cb875aeSCathy Zhou } 8021cb875aeSCathy Zhou 803f6da83d4SAnurag S. Maskey /* Open the libipadm handle */ 804f6da83d4SAnurag S. Maskey if (ipadm_open(&vrrp_ipadm_handle, 0) != IPADM_SUCCESS) { 805f6da83d4SAnurag S. Maskey vrrp_log(VRRP_ERR, "vrrpd_init(): ipadm_open() failed"); 806f6da83d4SAnurag S. Maskey goto fail; 807f6da83d4SAnurag S. Maskey } 808f6da83d4SAnurag S. Maskey 8091cb875aeSCathy Zhou /* 8101cb875aeSCathy Zhou * Build the list of interfaces and IP addresses. Also, start the time 8111cb875aeSCathy Zhou * to scan the interfaces/IP addresses periodically. 8121cb875aeSCathy Zhou */ 8131cb875aeSCathy Zhou vrrpd_scan(AF_INET); 8141cb875aeSCathy Zhou vrrpd_scan(AF_INET6); 8151cb875aeSCathy Zhou if ((vrrp_scan_timer_id = iu_schedule_timer_ms(vrrpd_timerq, 8161cb875aeSCathy Zhou vrrpd_scan_interval, vrrpd_scan_timer, NULL)) == -1) { 8171cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_init(): start scan_timer failed"); 8181cb875aeSCathy Zhou goto fail; 8191cb875aeSCathy Zhou } 8201cb875aeSCathy Zhou 8211cb875aeSCathy Zhou /* 8221cb875aeSCathy Zhou * Initialize the VRRP multicast address. 8231cb875aeSCathy Zhou */ 8241cb875aeSCathy Zhou bzero(&vrrp_muladdr4, sizeof (vrrp_addr_t)); 8251cb875aeSCathy Zhou vrrp_muladdr4.in4.sin_family = AF_INET; 8261cb875aeSCathy Zhou (void) inet_pton(AF_INET, "224.0.0.18", &vrrp_muladdr4.in4.sin_addr); 8271cb875aeSCathy Zhou 8281cb875aeSCathy Zhou bzero(&vrrp_muladdr6, sizeof (vrrp_addr_t)); 8291cb875aeSCathy Zhou vrrp_muladdr6.in6.sin6_family = AF_INET6; 8301cb875aeSCathy Zhou (void) inet_pton(AF_INET6, "ff02::12", &vrrp_muladdr6.in6.sin6_addr); 8311cb875aeSCathy Zhou 8321cb875aeSCathy Zhou return (VRRP_SUCCESS); 8331cb875aeSCathy Zhou 8341cb875aeSCathy Zhou fail: 8351cb875aeSCathy Zhou vrrpd_fini(); 8361cb875aeSCathy Zhou return (err); 8371cb875aeSCathy Zhou } 8381cb875aeSCathy Zhou 8391cb875aeSCathy Zhou static void 8401cb875aeSCathy Zhou vrrpd_fini() 8411cb875aeSCathy Zhou { 8421cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_fini()"); 8431cb875aeSCathy Zhou 8441cb875aeSCathy Zhou (void) iu_cancel_timer(vrrpd_timerq, vrrp_scan_timer_id, NULL); 8451cb875aeSCathy Zhou vrrp_scan_timer_id = -1; 8461cb875aeSCathy Zhou 8471cb875aeSCathy Zhou vrrpd_rtsock_destroy(); 8481cb875aeSCathy Zhou vrrpd_ctlsock_destroy(); 8491cb875aeSCathy Zhou vrrpd_cmdsock_destroy(); 8501cb875aeSCathy Zhou 8511cb875aeSCathy Zhou if (vrrpd_eh != NULL) { 8521cb875aeSCathy Zhou iu_eh_destroy(vrrpd_eh); 8531cb875aeSCathy Zhou vrrpd_eh = NULL; 8541cb875aeSCathy Zhou } 8551cb875aeSCathy Zhou 8561cb875aeSCathy Zhou if (vrrpd_timerq != NULL) { 8571cb875aeSCathy Zhou iu_tq_destroy(vrrpd_timerq); 8581cb875aeSCathy Zhou vrrpd_timerq = NULL; 8591cb875aeSCathy Zhou } 8601cb875aeSCathy Zhou 8611cb875aeSCathy Zhou vrrp_close(vrrpd_vh); 8621cb875aeSCathy Zhou vrrpd_vh = NULL; 8631cb875aeSCathy Zhou assert(TAILQ_EMPTY(&vrrp_vr_list)); 8641cb875aeSCathy Zhou assert(TAILQ_EMPTY(&vrrp_intf_list)); 865f6da83d4SAnurag S. Maskey 866f6da83d4SAnurag S. Maskey ipadm_close(vrrp_ipadm_handle); 8671cb875aeSCathy Zhou } 8681cb875aeSCathy Zhou 8691cb875aeSCathy Zhou static void 8701cb875aeSCathy Zhou vrrpd_cleanup(void) 8711cb875aeSCathy Zhou { 8721cb875aeSCathy Zhou vrrp_vr_t *vr; 8731cb875aeSCathy Zhou vrrp_intf_t *intf; 8741cb875aeSCathy Zhou 8751cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_cleanup()"); 8761cb875aeSCathy Zhou 8771cb875aeSCathy Zhou while (!TAILQ_EMPTY(&vrrp_vr_list)) { 8781cb875aeSCathy Zhou vr = TAILQ_FIRST(&vrrp_vr_list); 8791cb875aeSCathy Zhou vrrpd_delete_vr(vr); 8801cb875aeSCathy Zhou } 8811cb875aeSCathy Zhou 8821cb875aeSCathy Zhou while (!TAILQ_EMPTY(&vrrp_intf_list)) { 8831cb875aeSCathy Zhou intf = TAILQ_FIRST(&vrrp_intf_list); 8841cb875aeSCathy Zhou vrrpd_delete_if(intf, _B_FALSE); 8851cb875aeSCathy Zhou } 8861cb875aeSCathy Zhou 8871cb875aeSCathy Zhou vrrpd_fini(); 8881cb875aeSCathy Zhou closelog(); 8891cb875aeSCathy Zhou exit(1); 8901cb875aeSCathy Zhou } 8911cb875aeSCathy Zhou 8921cb875aeSCathy Zhou /* 8931cb875aeSCathy Zhou * Read the configuration file and initialize all the existing VRRP routers. 8941cb875aeSCathy Zhou */ 8951cb875aeSCathy Zhou static void 8961cb875aeSCathy Zhou vrrpd_initconf() 8971cb875aeSCathy Zhou { 8981cb875aeSCathy Zhou FILE *fp; 8991cb875aeSCathy Zhou char line[LINE_MAX]; 9001cb875aeSCathy Zhou int linenum = 0; 9011cb875aeSCathy Zhou vrrp_vr_conf_t conf; 9021cb875aeSCathy Zhou vrrp_err_t err; 9031cb875aeSCathy Zhou 9041cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_initconf()"); 9051cb875aeSCathy Zhou 9061cb875aeSCathy Zhou if ((fp = fopen(vrrpd_conffile, "rF")) == NULL) { 9071cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "failed to open the configuration file %s", 9081cb875aeSCathy Zhou vrrpd_conffile); 9091cb875aeSCathy Zhou return; 9101cb875aeSCathy Zhou } 9111cb875aeSCathy Zhou 9121cb875aeSCathy Zhou while (fgets(line, sizeof (line), fp) != NULL) { 9131cb875aeSCathy Zhou linenum++; 9141cb875aeSCathy Zhou conf.vvc_vrid = VRRP_VRID_NONE; 9151cb875aeSCathy Zhou if ((err = vrrpd_read_vrconf(line, &conf)) != VRRP_SUCCESS) { 9161cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "failed to parse %d line %s", 9171cb875aeSCathy Zhou linenum, line); 9181cb875aeSCathy Zhou continue; 9191cb875aeSCathy Zhou } 9201cb875aeSCathy Zhou 9211cb875aeSCathy Zhou /* 9221cb875aeSCathy Zhou * Blank or comment line 9231cb875aeSCathy Zhou */ 9241cb875aeSCathy Zhou if (conf.vvc_vrid == VRRP_VRID_NONE) 9251cb875aeSCathy Zhou continue; 9261cb875aeSCathy Zhou 9271cb875aeSCathy Zhou /* 9281cb875aeSCathy Zhou * No need to update the configuration since the VRRP router 9291cb875aeSCathy Zhou * created/enabled based on the existing configuration. 9301cb875aeSCathy Zhou */ 9311cb875aeSCathy Zhou if ((err = vrrpd_create(&conf, _B_FALSE)) != VRRP_SUCCESS) { 9321cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "VRRP router %s creation failed: " 9331cb875aeSCathy Zhou "%s", conf.vvc_name, vrrp_err2str(err)); 9341cb875aeSCathy Zhou continue; 9351cb875aeSCathy Zhou } 9361cb875aeSCathy Zhou 9371cb875aeSCathy Zhou if (conf.vvc_enabled && 9381cb875aeSCathy Zhou ((err = vrrpd_enable(conf.vvc_name, _B_FALSE)) != 9391cb875aeSCathy Zhou VRRP_SUCCESS)) { 9401cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "VRRP router %s enable failed: %s", 9411cb875aeSCathy Zhou conf.vvc_name, vrrp_err2str(err)); 9421cb875aeSCathy Zhou } 9431cb875aeSCathy Zhou } 9441cb875aeSCathy Zhou 9451cb875aeSCathy Zhou (void) fclose(fp); 9461cb875aeSCathy Zhou } 9471cb875aeSCathy Zhou 9481cb875aeSCathy Zhou /* 9491cb875aeSCathy Zhou * Create the AF_UNIX socket used to communicate with libvrrpadm. 9501cb875aeSCathy Zhou * 9511cb875aeSCathy Zhou * This socket is used to receive the administrative request and 9521cb875aeSCathy Zhou * send back the results. 9531cb875aeSCathy Zhou */ 9541cb875aeSCathy Zhou static vrrp_err_t 9551cb875aeSCathy Zhou vrrpd_cmdsock_create() 9561cb875aeSCathy Zhou { 9571cb875aeSCathy Zhou iu_event_id_t eid; 9581cb875aeSCathy Zhou struct sockaddr_un laddr; 9591cb875aeSCathy Zhou int sock, flags; 9601cb875aeSCathy Zhou 9611cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_cmdsock_create()"); 9621cb875aeSCathy Zhou 9631cb875aeSCathy Zhou if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { 9641cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_cmdsock_create(): socket(AF_UNIX) " 9651cb875aeSCathy Zhou "failed: %s", strerror(errno)); 9661cb875aeSCathy Zhou return (VRRP_ESYS); 9671cb875aeSCathy Zhou } 9681cb875aeSCathy Zhou 9691cb875aeSCathy Zhou /* 9701cb875aeSCathy Zhou * Set it to be non-blocking. 9711cb875aeSCathy Zhou */ 9721cb875aeSCathy Zhou flags = fcntl(sock, F_GETFL, 0); 9731cb875aeSCathy Zhou (void) fcntl(sock, F_SETFL, (flags | O_NONBLOCK)); 9741cb875aeSCathy Zhou 9751cb875aeSCathy Zhou /* 9761cb875aeSCathy Zhou * Unlink first in case a previous daemon instance exited ungracefully. 9771cb875aeSCathy Zhou */ 9781cb875aeSCathy Zhou (void) unlink(VRRPD_SOCKET); 9791cb875aeSCathy Zhou 9801cb875aeSCathy Zhou bzero(&laddr, sizeof (laddr)); 9811cb875aeSCathy Zhou laddr.sun_family = AF_UNIX; 9821cb875aeSCathy Zhou (void) strlcpy(laddr.sun_path, VRRPD_SOCKET, sizeof (laddr.sun_path)); 9831cb875aeSCathy Zhou if (bind(sock, (struct sockaddr *)&laddr, sizeof (laddr)) < 0) { 9841cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_cmdsock_create(): bind() failed: %s", 9851cb875aeSCathy Zhou strerror(errno)); 9861cb875aeSCathy Zhou (void) close(sock); 9871cb875aeSCathy Zhou return (VRRP_ESYS); 9881cb875aeSCathy Zhou } 9891cb875aeSCathy Zhou 9901cb875aeSCathy Zhou if (listen(sock, 30) < 0) { 9911cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_cmdsock_create(): listen() " 9921cb875aeSCathy Zhou "failed: %s", strerror(errno)); 9931cb875aeSCathy Zhou (void) close(sock); 9941cb875aeSCathy Zhou return (VRRP_ESYS); 9951cb875aeSCathy Zhou } 9961cb875aeSCathy Zhou 9971cb875aeSCathy Zhou if ((eid = iu_register_event(vrrpd_eh, sock, POLLIN, 9981cb875aeSCathy Zhou vrrpd_cmdsock_handler, NULL)) == -1) { 9991cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_cmdsock_create(): iu_register_event()" 10001cb875aeSCathy Zhou " failed"); 10011cb875aeSCathy Zhou (void) close(sock); 10021cb875aeSCathy Zhou return (VRRP_ESYS); 10031cb875aeSCathy Zhou } 10041cb875aeSCathy Zhou 10051cb875aeSCathy Zhou vrrpd_cmdsock_fd = sock; 10061cb875aeSCathy Zhou vrrpd_cmdsock_eid = eid; 10071cb875aeSCathy Zhou return (VRRP_SUCCESS); 10081cb875aeSCathy Zhou } 10091cb875aeSCathy Zhou 10101cb875aeSCathy Zhou static void 10111cb875aeSCathy Zhou vrrpd_cmdsock_destroy() 10121cb875aeSCathy Zhou { 10131cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_cmdsock_destroy()"); 10141cb875aeSCathy Zhou 10151cb875aeSCathy Zhou (void) iu_unregister_event(vrrpd_eh, vrrpd_cmdsock_eid, NULL); 10161cb875aeSCathy Zhou (void) close(vrrpd_cmdsock_fd); 10171cb875aeSCathy Zhou vrrpd_cmdsock_fd = -1; 10181cb875aeSCathy Zhou vrrpd_cmdsock_eid = -1; 10191cb875aeSCathy Zhou } 10201cb875aeSCathy Zhou 10211cb875aeSCathy Zhou /* 10221cb875aeSCathy Zhou * Create the PF_ROUTER sockets used to listen to the routing socket 10231cb875aeSCathy Zhou * messages and build the interface/IP address list. Create one for 10241cb875aeSCathy Zhou * each address family (IPv4 and IPv6). 10251cb875aeSCathy Zhou */ 10261cb875aeSCathy Zhou static vrrp_err_t 10271cb875aeSCathy Zhou vrrpd_rtsock_create() 10281cb875aeSCathy Zhou { 10291cb875aeSCathy Zhou int i, flags, sock; 10301cb875aeSCathy Zhou iu_event_id_t eid; 10311cb875aeSCathy Zhou 10321cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_rtsock_create()"); 10331cb875aeSCathy Zhou 10341cb875aeSCathy Zhou for (i = 0; i < 2; i++) { 10351cb875aeSCathy Zhou sock = socket(PF_ROUTE, SOCK_RAW, vrrpd_rtsocks[i].vrt_af); 10361cb875aeSCathy Zhou if (sock == -1) { 10371cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_rtsock_create(): socket() " 10381cb875aeSCathy Zhou "failed: %s", strerror(errno)); 10391cb875aeSCathy Zhou break; 10401cb875aeSCathy Zhou } 10411cb875aeSCathy Zhou 10421cb875aeSCathy Zhou /* 10431cb875aeSCathy Zhou * Set it to be non-blocking. 10441cb875aeSCathy Zhou */ 10451cb875aeSCathy Zhou if ((flags = fcntl(sock, F_GETFL, 0)) < 0) { 10461cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_rtsock_create(): " 10471cb875aeSCathy Zhou "fcntl(F_GETFL) failed: %s", strerror(errno)); 10481cb875aeSCathy Zhou break; 10491cb875aeSCathy Zhou } 10501cb875aeSCathy Zhou 10511cb875aeSCathy Zhou if ((fcntl(sock, F_SETFL, flags | O_NONBLOCK)) < 0) { 10521cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_rtsock_create(): " 10531cb875aeSCathy Zhou "fcntl(F_SETFL) failed: %s", strerror(errno)); 10541cb875aeSCathy Zhou break; 10551cb875aeSCathy Zhou } 10561cb875aeSCathy Zhou 10571cb875aeSCathy Zhou if ((eid = iu_register_event(vrrpd_eh, sock, POLLIN, 10581cb875aeSCathy Zhou vrrpd_rtsock_handler, &(vrrpd_rtsocks[i].vrt_af))) == -1) { 10591cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_rtsock_create(): register " 10601cb875aeSCathy Zhou "rtsock %d(%s) failed", sock, 10611cb875aeSCathy Zhou af_str(vrrpd_rtsocks[i].vrt_af)); 10621cb875aeSCathy Zhou break; 10631cb875aeSCathy Zhou } 10641cb875aeSCathy Zhou 10651cb875aeSCathy Zhou vrrpd_rtsocks[i].vrt_fd = sock; 10661cb875aeSCathy Zhou vrrpd_rtsocks[i].vrt_eid = eid; 10671cb875aeSCathy Zhou } 10681cb875aeSCathy Zhou 10691cb875aeSCathy Zhou if (i != 2) { 10701cb875aeSCathy Zhou (void) close(sock); 10711cb875aeSCathy Zhou vrrpd_rtsock_destroy(); 10721cb875aeSCathy Zhou return (VRRP_ESYS); 10731cb875aeSCathy Zhou } 10741cb875aeSCathy Zhou 10751cb875aeSCathy Zhou return (VRRP_SUCCESS); 10761cb875aeSCathy Zhou } 10771cb875aeSCathy Zhou 10781cb875aeSCathy Zhou static void 10791cb875aeSCathy Zhou vrrpd_rtsock_destroy() 10801cb875aeSCathy Zhou { 10811cb875aeSCathy Zhou int i; 10821cb875aeSCathy Zhou 10831cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_rtsock_destroy()"); 10841cb875aeSCathy Zhou for (i = 0; i < 2; i++) { 10851cb875aeSCathy Zhou (void) iu_unregister_event(vrrpd_eh, vrrpd_rtsocks[i].vrt_eid, 10861cb875aeSCathy Zhou NULL); 10871cb875aeSCathy Zhou (void) close(vrrpd_rtsocks[i].vrt_fd); 10881cb875aeSCathy Zhou vrrpd_rtsocks[i].vrt_eid = -1; 10891cb875aeSCathy Zhou vrrpd_rtsocks[i].vrt_fd = -1; 10901cb875aeSCathy Zhou } 10911cb875aeSCathy Zhou } 10921cb875aeSCathy Zhou 10931cb875aeSCathy Zhou /* 10941cb875aeSCathy Zhou * Create the VRRP control socket used to bring up/down the virtual 10951cb875aeSCathy Zhou * IP addresses. It is also used to set the IFF_NOACCEPT flag of 10961cb875aeSCathy Zhou * the virtual IP addresses. 10971cb875aeSCathy Zhou */ 10981cb875aeSCathy Zhou static vrrp_err_t 10991cb875aeSCathy Zhou vrrpd_ctlsock_create() 11001cb875aeSCathy Zhou { 11011cb875aeSCathy Zhou int s, s6; 11021cb875aeSCathy Zhou int on = _B_TRUE; 11031cb875aeSCathy Zhou 11041cb875aeSCathy Zhou if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 11051cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_ctlsock_create(): socket(INET) " 11061cb875aeSCathy Zhou "failed: %s", strerror(errno)); 11071cb875aeSCathy Zhou return (VRRP_ESYS); 11081cb875aeSCathy Zhou } 11091cb875aeSCathy Zhou if (setsockopt(s, SOL_SOCKET, SO_VRRP, &on, sizeof (on)) < 0) { 11101cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_ctlsock_create(): " 11111cb875aeSCathy Zhou "setsockopt(INET, SO_VRRP) failed: %s", strerror(errno)); 11121cb875aeSCathy Zhou (void) close(s); 11131cb875aeSCathy Zhou return (VRRP_ESYS); 11141cb875aeSCathy Zhou } 11151cb875aeSCathy Zhou 11161cb875aeSCathy Zhou if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 11171cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_ctlsock_create(): socket(INET6) " 11181cb875aeSCathy Zhou "failed: %s", strerror(errno)); 11191cb875aeSCathy Zhou (void) close(s); 11201cb875aeSCathy Zhou return (VRRP_ESYS); 11211cb875aeSCathy Zhou } 11221cb875aeSCathy Zhou if (setsockopt(s6, SOL_SOCKET, SO_VRRP, &on, sizeof (on)) < 0) { 11231cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_ctlsock_create(): " 11241cb875aeSCathy Zhou "setsockopt(INET6, SO_VRRP) failed: %s", strerror(errno)); 11251cb875aeSCathy Zhou (void) close(s); 11261cb875aeSCathy Zhou (void) close(s6); 11271cb875aeSCathy Zhou return (VRRP_ESYS); 11281cb875aeSCathy Zhou } 11291cb875aeSCathy Zhou 11301cb875aeSCathy Zhou vrrpd_ctlsock_fd = s; 11311cb875aeSCathy Zhou vrrpd_ctlsock6_fd = s6; 11321cb875aeSCathy Zhou return (VRRP_SUCCESS); 11331cb875aeSCathy Zhou } 11341cb875aeSCathy Zhou 11351cb875aeSCathy Zhou static void 11361cb875aeSCathy Zhou vrrpd_ctlsock_destroy() 11371cb875aeSCathy Zhou { 11381cb875aeSCathy Zhou (void) close(vrrpd_ctlsock_fd); 11391cb875aeSCathy Zhou vrrpd_ctlsock_fd = -1; 11401cb875aeSCathy Zhou (void) close(vrrpd_ctlsock6_fd); 11411cb875aeSCathy Zhou vrrpd_ctlsock6_fd = -1; 11421cb875aeSCathy Zhou } 11431cb875aeSCathy Zhou 11441cb875aeSCathy Zhou /*ARGSUSED*/ 11451cb875aeSCathy Zhou static void 11461cb875aeSCathy Zhou vrrpd_cmd_create(void *arg1, void *arg2, size_t *arg2_sz) 11471cb875aeSCathy Zhou { 11481cb875aeSCathy Zhou vrrp_cmd_create_t *cmd = (vrrp_cmd_create_t *)arg1; 11491cb875aeSCathy Zhou vrrp_ret_create_t *ret = (vrrp_ret_create_t *)arg2; 11501cb875aeSCathy Zhou vrrp_err_t err; 11511cb875aeSCathy Zhou 11521cb875aeSCathy Zhou err = vrrpd_create(&cmd->vcc_conf, _B_TRUE); 11531cb875aeSCathy Zhou if (err == VRRP_SUCCESS && cmd->vcc_conf.vvc_enabled) { 11541cb875aeSCathy Zhou /* 11551cb875aeSCathy Zhou * No need to update the configuration since it is already 11561cb875aeSCathy Zhou * done in the above vrrpd_create() call 11571cb875aeSCathy Zhou */ 11581cb875aeSCathy Zhou err = vrrpd_enable(cmd->vcc_conf.vvc_name, _B_FALSE); 11591cb875aeSCathy Zhou if (err != VRRP_SUCCESS) 11601cb875aeSCathy Zhou (void) vrrpd_delete(cmd->vcc_conf.vvc_name); 11611cb875aeSCathy Zhou } 11621cb875aeSCathy Zhou ret->vrc_err = err; 11631cb875aeSCathy Zhou } 11641cb875aeSCathy Zhou 11651cb875aeSCathy Zhou /*ARGSUSED*/ 11661cb875aeSCathy Zhou static void 11671cb875aeSCathy Zhou vrrpd_cmd_delete(void *arg1, void *arg2, size_t *arg2_sz) 11681cb875aeSCathy Zhou { 11691cb875aeSCathy Zhou vrrp_cmd_delete_t *cmd = (vrrp_cmd_delete_t *)arg1; 11701cb875aeSCathy Zhou vrrp_ret_delete_t *ret = (vrrp_ret_delete_t *)arg2; 11711cb875aeSCathy Zhou 11721cb875aeSCathy Zhou ret->vrd_err = vrrpd_delete(cmd->vcd_name); 11731cb875aeSCathy Zhou } 11741cb875aeSCathy Zhou 11751cb875aeSCathy Zhou /*ARGSUSED*/ 11761cb875aeSCathy Zhou static void 11771cb875aeSCathy Zhou vrrpd_cmd_enable(void *arg1, void *arg2, size_t *arg2_sz) 11781cb875aeSCathy Zhou { 11791cb875aeSCathy Zhou vrrp_cmd_enable_t *cmd = (vrrp_cmd_enable_t *)arg1; 11801cb875aeSCathy Zhou vrrp_ret_enable_t *ret = (vrrp_ret_enable_t *)arg2; 11811cb875aeSCathy Zhou 11821cb875aeSCathy Zhou ret->vrs_err = vrrpd_enable(cmd->vcs_name, _B_TRUE); 11831cb875aeSCathy Zhou } 11841cb875aeSCathy Zhou 11851cb875aeSCathy Zhou /*ARGSUSED*/ 11861cb875aeSCathy Zhou static void 11871cb875aeSCathy Zhou vrrpd_cmd_disable(void *arg1, void *arg2, size_t *arg2_sz) 11881cb875aeSCathy Zhou { 11891cb875aeSCathy Zhou vrrp_cmd_disable_t *cmd = (vrrp_cmd_disable_t *)arg1; 11901cb875aeSCathy Zhou vrrp_ret_disable_t *ret = (vrrp_ret_disable_t *)arg2; 11911cb875aeSCathy Zhou 11921cb875aeSCathy Zhou ret->vrx_err = vrrpd_disable(cmd->vcx_name); 11931cb875aeSCathy Zhou } 11941cb875aeSCathy Zhou 11951cb875aeSCathy Zhou /*ARGSUSED*/ 11961cb875aeSCathy Zhou static void 11971cb875aeSCathy Zhou vrrpd_cmd_modify(void *arg1, void *arg2, size_t *arg2_sz) 11981cb875aeSCathy Zhou { 11991cb875aeSCathy Zhou vrrp_cmd_modify_t *cmd = (vrrp_cmd_modify_t *)arg1; 12001cb875aeSCathy Zhou vrrp_ret_modify_t *ret = (vrrp_ret_modify_t *)arg2; 12011cb875aeSCathy Zhou 12021cb875aeSCathy Zhou ret->vrm_err = vrrpd_modify(&cmd->vcm_conf, cmd->vcm_mask); 12031cb875aeSCathy Zhou } 12041cb875aeSCathy Zhou 12051cb875aeSCathy Zhou static void 12061cb875aeSCathy Zhou vrrpd_cmd_query(void *arg1, void *arg2, size_t *arg2_sz) 12071cb875aeSCathy Zhou { 12081cb875aeSCathy Zhou vrrp_cmd_query_t *cmd = (vrrp_cmd_query_t *)arg1; 12091cb875aeSCathy Zhou 12101cb875aeSCathy Zhou vrrpd_query(cmd->vcq_name, arg2, arg2_sz); 12111cb875aeSCathy Zhou } 12121cb875aeSCathy Zhou 12131cb875aeSCathy Zhou static void 12141cb875aeSCathy Zhou vrrpd_cmd_list(void *arg1, void *arg2, size_t *arg2_sz) 12151cb875aeSCathy Zhou { 12161cb875aeSCathy Zhou vrrp_cmd_list_t *cmd = (vrrp_cmd_list_t *)arg1; 12171cb875aeSCathy Zhou 12181cb875aeSCathy Zhou vrrpd_list(cmd->vcl_vrid, cmd->vcl_ifname, cmd->vcl_af, arg2, arg2_sz); 12191cb875aeSCathy Zhou } 12201cb875aeSCathy Zhou 12211cb875aeSCathy Zhou /* 12221cb875aeSCathy Zhou * Write-type requeset must have the solaris.network.vrrp authorization. 12231cb875aeSCathy Zhou */ 12241cb875aeSCathy Zhou static boolean_t 12251cb875aeSCathy Zhou vrrp_auth_check(int connfd, vrrp_cmd_info_t *cinfo) 12261cb875aeSCathy Zhou { 12271cb875aeSCathy Zhou ucred_t *cred = NULL; 12281cb875aeSCathy Zhou uid_t uid; 12291cb875aeSCathy Zhou struct passwd *pw; 12301cb875aeSCathy Zhou boolean_t success = _B_FALSE; 12311cb875aeSCathy Zhou 12321cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrp_auth_check()"); 12331cb875aeSCathy Zhou 12341cb875aeSCathy Zhou if (!cinfo->vi_setop) 12351cb875aeSCathy Zhou return (_B_TRUE); 12361cb875aeSCathy Zhou 12371cb875aeSCathy Zhou /* 12381cb875aeSCathy Zhou * Validate the credential 12391cb875aeSCathy Zhou */ 12401cb875aeSCathy Zhou if (getpeerucred(connfd, &cred) == (uid_t)-1) { 12411cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrp_auth_check(): getpeerucred() " 12421cb875aeSCathy Zhou "failed: %s", strerror(errno)); 12431cb875aeSCathy Zhou return (_B_FALSE); 12441cb875aeSCathy Zhou } 12451cb875aeSCathy Zhou 12461cb875aeSCathy Zhou if ((uid = ucred_getruid((const ucred_t *)cred)) == (uid_t)-1) { 12471cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrp_auth_check(): ucred_getruid() " 12481cb875aeSCathy Zhou "failed: %s", strerror(errno)); 12491cb875aeSCathy Zhou goto done; 12501cb875aeSCathy Zhou } 12511cb875aeSCathy Zhou 12521cb875aeSCathy Zhou if ((pw = getpwuid(uid)) == NULL) { 12531cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrp_auth_check(): getpwuid() failed"); 12541cb875aeSCathy Zhou goto done; 12551cb875aeSCathy Zhou } 12561cb875aeSCathy Zhou 12571cb875aeSCathy Zhou success = (chkauthattr("solaris.network.vrrp", pw->pw_name) == 1); 12581cb875aeSCathy Zhou 12591cb875aeSCathy Zhou done: 12601cb875aeSCathy Zhou ucred_free(cred); 12611cb875aeSCathy Zhou return (success); 12621cb875aeSCathy Zhou } 12631cb875aeSCathy Zhou 12641cb875aeSCathy Zhou /* 12651cb875aeSCathy Zhou * Process the administrative request from libvrrpadm 12661cb875aeSCathy Zhou */ 12671cb875aeSCathy Zhou /* ARGSUSED */ 12681cb875aeSCathy Zhou static void 12691cb875aeSCathy Zhou vrrpd_cmdsock_handler(iu_eh_t *eh, int s, short events, iu_event_id_t id, 12701cb875aeSCathy Zhou void *arg) 12711cb875aeSCathy Zhou { 12721cb875aeSCathy Zhou vrrp_cmd_info_t *cinfo = NULL; 12731cb875aeSCathy Zhou vrrp_err_t err = VRRP_SUCCESS; 12741cb875aeSCathy Zhou uchar_t buf[BUFFSIZE], ackbuf[BUFFSIZE]; 12751cb875aeSCathy Zhou size_t cursize, acksize, len; 12761cb875aeSCathy Zhou uint32_t cmd; 12771cb875aeSCathy Zhou int connfd, i; 12781cb875aeSCathy Zhou struct sockaddr_in from; 12791cb875aeSCathy Zhou socklen_t fromlen; 12801cb875aeSCathy Zhou 12811cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_cmdsock_handler()"); 12821cb875aeSCathy Zhou 12831cb875aeSCathy Zhou fromlen = (socklen_t)sizeof (from); 12841cb875aeSCathy Zhou if ((connfd = accept(s, (struct sockaddr *)&from, &fromlen)) < 0) { 12851cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_cmdsock_handler() accept(): %s", 12861cb875aeSCathy Zhou strerror(errno)); 12871cb875aeSCathy Zhou return; 12881cb875aeSCathy Zhou } 12891cb875aeSCathy Zhou 12901cb875aeSCathy Zhou /* 12911cb875aeSCathy Zhou * First get the type of the request 12921cb875aeSCathy Zhou */ 12931cb875aeSCathy Zhou cursize = 0; 12941cb875aeSCathy Zhou while (cursize < sizeof (uint32_t)) { 12951cb875aeSCathy Zhou len = read(connfd, buf + cursize, 12961cb875aeSCathy Zhou sizeof (uint32_t) - cursize); 12971cb875aeSCathy Zhou if (len == (size_t)-1 && (errno == EAGAIN || errno == EINTR)) { 12981cb875aeSCathy Zhou continue; 12991cb875aeSCathy Zhou } else if (len > 0) { 13001cb875aeSCathy Zhou cursize += len; 13011cb875aeSCathy Zhou continue; 13021cb875aeSCathy Zhou } 13031cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_cmdsock_handler(): invalid message " 13041cb875aeSCathy Zhou "length"); 13051cb875aeSCathy Zhou (void) close(connfd); 13061cb875aeSCathy Zhou return; 13071cb875aeSCathy Zhou } 13081cb875aeSCathy Zhou 13091cb875aeSCathy Zhou /* LINTED E_BAD_PTR_CAST_ALIGN */ 13101cb875aeSCathy Zhou cmd = ((vrrp_cmd_t *)buf)->vc_cmd; 13111cb875aeSCathy Zhou for (i = 0; i < VRRP_DOOR_INFO_TABLE_SIZE; i++) { 13121cb875aeSCathy Zhou if (vrrp_cmd_info_tbl[i].vi_cmd == cmd) { 13131cb875aeSCathy Zhou cinfo = vrrp_cmd_info_tbl + i; 13141cb875aeSCathy Zhou break; 13151cb875aeSCathy Zhou } 13161cb875aeSCathy Zhou } 13171cb875aeSCathy Zhou 13181cb875aeSCathy Zhou if (cinfo == NULL) { 13191cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_cmdsock_handler(): invalid request " 13201cb875aeSCathy Zhou "type %d", cmd); 13211cb875aeSCathy Zhou err = VRRP_EINVAL; 13221cb875aeSCathy Zhou goto done; 13231cb875aeSCathy Zhou } 13241cb875aeSCathy Zhou 13251cb875aeSCathy Zhou /* 13261cb875aeSCathy Zhou * Get the rest of the request. 13271cb875aeSCathy Zhou */ 13281cb875aeSCathy Zhou assert(cursize == sizeof (uint32_t)); 13291cb875aeSCathy Zhou while (cursize < cinfo->vi_reqsize) { 13301cb875aeSCathy Zhou len = read(connfd, buf + cursize, 13311cb875aeSCathy Zhou cinfo->vi_reqsize - cursize); 13321cb875aeSCathy Zhou if (len == (size_t)-1 && (errno == EAGAIN || errno == EINTR)) { 13331cb875aeSCathy Zhou continue; 13341cb875aeSCathy Zhou } else if (len > 0) { 13351cb875aeSCathy Zhou cursize += len; 13361cb875aeSCathy Zhou continue; 13371cb875aeSCathy Zhou } 13381cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_cmdsock_handler(): invalid message " 13391cb875aeSCathy Zhou "length"); 13401cb875aeSCathy Zhou err = VRRP_EINVAL; 13411cb875aeSCathy Zhou goto done; 13421cb875aeSCathy Zhou } 13431cb875aeSCathy Zhou 13441cb875aeSCathy Zhou /* 13451cb875aeSCathy Zhou * Validate the authorization 13461cb875aeSCathy Zhou */ 13471cb875aeSCathy Zhou if (!vrrp_auth_check(connfd, cinfo)) { 13481cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_cmdsock_handler(): " 13491cb875aeSCathy Zhou "not sufficient authorization"); 13501cb875aeSCathy Zhou err = VRRP_EPERM; 13511cb875aeSCathy Zhou } 13521cb875aeSCathy Zhou 13531cb875aeSCathy Zhou done: 13541cb875aeSCathy Zhou /* 13551cb875aeSCathy Zhou * Ack the request 13561cb875aeSCathy Zhou */ 13571cb875aeSCathy Zhou if (err != 0) { 13581cb875aeSCathy Zhou /* LINTED E_BAD_PTR_CAST_ALIGN */ 13591cb875aeSCathy Zhou ((vrrp_ret_t *)ackbuf)->vr_err = err; 13601cb875aeSCathy Zhou acksize = sizeof (vrrp_ret_t); 13611cb875aeSCathy Zhou } else { 13621cb875aeSCathy Zhou /* 13631cb875aeSCathy Zhou * If the size of ack is varied, the cmdfunc callback 13641cb875aeSCathy Zhou * will set the right size. 13651cb875aeSCathy Zhou */ 13661cb875aeSCathy Zhou if ((acksize = cinfo->vi_acksize) == 0) 13671cb875aeSCathy Zhou acksize = sizeof (ackbuf); 13681cb875aeSCathy Zhou 13691cb875aeSCathy Zhou /* LINTED E_BAD_PTR_CAST_ALIGN */ 13701cb875aeSCathy Zhou cinfo->vi_cmdfunc((vrrp_cmd_t *)buf, ackbuf, &acksize); 13711cb875aeSCathy Zhou } 13721cb875aeSCathy Zhou 13731cb875aeSCathy Zhou /* 13741cb875aeSCathy Zhou * Send the ack back. 13751cb875aeSCathy Zhou */ 13761cb875aeSCathy Zhou cursize = 0; 13771cb875aeSCathy Zhou while (cursize < acksize) { 13781cb875aeSCathy Zhou len = sendto(connfd, ackbuf + cursize, acksize - cursize, 13791cb875aeSCathy Zhou 0, (struct sockaddr *)&from, fromlen); 13801cb875aeSCathy Zhou if (len == (size_t)-1 && errno == EAGAIN) { 13811cb875aeSCathy Zhou continue; 13821cb875aeSCathy Zhou } else if (len > 0) { 13831cb875aeSCathy Zhou cursize += len; 13841cb875aeSCathy Zhou continue; 13851cb875aeSCathy Zhou } else { 13861cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_cmdsock_handler() failed to " 13871cb875aeSCathy Zhou "ack: %s", strerror(errno)); 13881cb875aeSCathy Zhou break; 13891cb875aeSCathy Zhou } 13901cb875aeSCathy Zhou } 13911cb875aeSCathy Zhou 13921cb875aeSCathy Zhou (void) shutdown(connfd, SHUT_RDWR); 13931cb875aeSCathy Zhou (void) close(connfd); 13941cb875aeSCathy Zhou } 13951cb875aeSCathy Zhou 13961cb875aeSCathy Zhou /* 13971cb875aeSCathy Zhou * Process the routing socket messages and update the interfaces/IP addresses 13981cb875aeSCathy Zhou * list 13991cb875aeSCathy Zhou */ 14001cb875aeSCathy Zhou /* ARGSUSED */ 14011cb875aeSCathy Zhou static void 14021cb875aeSCathy Zhou vrrpd_rtsock_handler(iu_eh_t *eh, int s, short events, 14031cb875aeSCathy Zhou iu_event_id_t id, void *arg) 14041cb875aeSCathy Zhou { 14051cb875aeSCathy Zhou char buf[BUFFSIZE]; 14061cb875aeSCathy Zhou struct ifa_msghdr *ifam; 14071cb875aeSCathy Zhou int nbytes; 14081cb875aeSCathy Zhou int af = *(int *)arg; 14091cb875aeSCathy Zhou boolean_t scanif = _B_FALSE; 14101cb875aeSCathy Zhou 14111cb875aeSCathy Zhou for (;;) { 14121cb875aeSCathy Zhou nbytes = read(s, buf, sizeof (buf)); 14131cb875aeSCathy Zhou if (nbytes <= 0) { 14141cb875aeSCathy Zhou /* No more messages */ 14151cb875aeSCathy Zhou break; 14161cb875aeSCathy Zhou } 14171cb875aeSCathy Zhou 14181cb875aeSCathy Zhou /* LINTED E_BAD_PTR_CAST_ALIGN */ 14191cb875aeSCathy Zhou ifam = (struct ifa_msghdr *)buf; 14201cb875aeSCathy Zhou if (ifam->ifam_version != RTM_VERSION) { 14211cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_rtsock_handler(): version %d " 14221cb875aeSCathy Zhou "not understood", ifam->ifam_version); 14231cb875aeSCathy Zhou break; 14241cb875aeSCathy Zhou } 14251cb875aeSCathy Zhou 14261cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_rtsock_handler(): recv %s event", 14271cb875aeSCathy Zhou rtm_event2str(ifam->ifam_type)); 14281cb875aeSCathy Zhou 14291cb875aeSCathy Zhou switch (ifam->ifam_type) { 14301cb875aeSCathy Zhou case RTM_FREEADDR: 14311cb875aeSCathy Zhou case RTM_CHGADDR: 14321cb875aeSCathy Zhou case RTM_NEWADDR: 14331cb875aeSCathy Zhou case RTM_DELADDR: 14341cb875aeSCathy Zhou /* 14351cb875aeSCathy Zhou * An IP address has been created/updated/deleted or 14361cb875aeSCathy Zhou * brought up/down, re-initilialize the interface/IP 14371cb875aeSCathy Zhou * address list. 14381cb875aeSCathy Zhou */ 14391cb875aeSCathy Zhou scanif = _B_TRUE; 14401cb875aeSCathy Zhou break; 14411cb875aeSCathy Zhou default: 14421cb875aeSCathy Zhou /* Not interesting */ 14431cb875aeSCathy Zhou break; 14441cb875aeSCathy Zhou } 14451cb875aeSCathy Zhou } 14461cb875aeSCathy Zhou 14471cb875aeSCathy Zhou if (scanif) 14481cb875aeSCathy Zhou vrrpd_scan(af); 14491cb875aeSCathy Zhou } 14501cb875aeSCathy Zhou 14511cb875aeSCathy Zhou /* 14521cb875aeSCathy Zhou * Periodically scan the interface/IP addresses on the system. 14531cb875aeSCathy Zhou */ 14541cb875aeSCathy Zhou /* ARGSUSED */ 14551cb875aeSCathy Zhou static void 14561cb875aeSCathy Zhou vrrpd_scan_timer(iu_tq_t *tq, void *arg) 14571cb875aeSCathy Zhou { 14581cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_scan_timer()"); 14591cb875aeSCathy Zhou vrrpd_scan(AF_INET); 14601cb875aeSCathy Zhou vrrpd_scan(AF_INET6); 14611cb875aeSCathy Zhou } 14621cb875aeSCathy Zhou 14631cb875aeSCathy Zhou /* 14641cb875aeSCathy Zhou * Get the list of the interface/IP addresses of the specified address 14651cb875aeSCathy Zhou * family. 14661cb875aeSCathy Zhou */ 14671cb875aeSCathy Zhou static void 14681cb875aeSCathy Zhou vrrpd_scan(int af) 14691cb875aeSCathy Zhou { 14701cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_scan(%s)", af_str(af)); 14711cb875aeSCathy Zhou 14721cb875aeSCathy Zhou again: 14731cb875aeSCathy Zhou vrrpd_init_ipcache(af); 14741cb875aeSCathy Zhou 1475f6da83d4SAnurag S. Maskey /* If interface index changes, walk again. */ 1476f6da83d4SAnurag S. Maskey if (vrrpd_walk_addr_info(af) != IPADM_SUCCESS) 14771cb875aeSCathy Zhou goto again; 14781cb875aeSCathy Zhou 14791cb875aeSCathy Zhou vrrpd_update_ipcache(af); 14801cb875aeSCathy Zhou } 14811cb875aeSCathy Zhou 14821cb875aeSCathy Zhou /* 14831cb875aeSCathy Zhou * First mark all IP addresses of the specific address family to be removed. 14841cb875aeSCathy Zhou * This flag will then be cleared when we walk up all the IP addresses. 14851cb875aeSCathy Zhou */ 14861cb875aeSCathy Zhou static void 14871cb875aeSCathy Zhou vrrpd_init_ipcache(int af) 14881cb875aeSCathy Zhou { 14891cb875aeSCathy Zhou vrrp_intf_t *intf, *next_intf; 14901cb875aeSCathy Zhou vrrp_ip_t *ip, *nextip; 14911cb875aeSCathy Zhou char abuf[INET6_ADDRSTRLEN]; 14921cb875aeSCathy Zhou 14931cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_init_ipcache(%s)", af_str(af)); 14941cb875aeSCathy Zhou 14951cb875aeSCathy Zhou next_intf = TAILQ_FIRST(&vrrp_intf_list); 14961cb875aeSCathy Zhou while ((intf = next_intf) != NULL) { 14971cb875aeSCathy Zhou next_intf = TAILQ_NEXT(intf, vvi_next); 14981cb875aeSCathy Zhou if (intf->vvi_af != af) 14991cb875aeSCathy Zhou continue; 15001cb875aeSCathy Zhou 15011cb875aeSCathy Zhou /* 15021cb875aeSCathy Zhou * If the interface is still marked as new, it means that this 15031cb875aeSCathy Zhou * vrrpd_init_ipcache() call is a result of ifindex change, 15041cb875aeSCathy Zhou * which causes the re-walk of all the interfaces (see 15051cb875aeSCathy Zhou * vrrpd_add_ipaddr()), and some interfaces are still marked 15061cb875aeSCathy Zhou * as new during the last walk. In this case, delete this 15071cb875aeSCathy Zhou * interface with the "update_vr" argument to be _B_FALSE, 15081cb875aeSCathy Zhou * since no VRRP router has been assoicated with this 15091cb875aeSCathy Zhou * interface yet (the association is done in 15101cb875aeSCathy Zhou * vrrpd_update_ipcache()). 15111cb875aeSCathy Zhou * 15121cb875aeSCathy Zhou * This interface will be re-added later if it still exists. 15131cb875aeSCathy Zhou */ 15141cb875aeSCathy Zhou if (intf->vvi_state == NODE_STATE_NEW) { 15151cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_init_ipcache(): remove %s " 15161cb875aeSCathy Zhou "(%d), may be added later", intf->vvi_ifname, 15171cb875aeSCathy Zhou intf->vvi_ifindex); 15181cb875aeSCathy Zhou vrrpd_delete_if(intf, _B_FALSE); 15191cb875aeSCathy Zhou continue; 15201cb875aeSCathy Zhou } 15211cb875aeSCathy Zhou 15221cb875aeSCathy Zhou for (ip = TAILQ_FIRST(&intf->vvi_iplist); ip != NULL; 15231cb875aeSCathy Zhou ip = nextip) { 15241cb875aeSCathy Zhou nextip = TAILQ_NEXT(ip, vip_next); 15251cb875aeSCathy Zhou /* LINTED E_CONSTANT_CONDITION */ 15261cb875aeSCathy Zhou VRRPADDR2STR(af, &ip->vip_addr, abuf, 15271cb875aeSCathy Zhou INET6_ADDRSTRLEN, _B_FALSE); 15281cb875aeSCathy Zhou 15291cb875aeSCathy Zhou if (ip->vip_state != NODE_STATE_NEW) { 15301cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_init_ipcache(%s/%d, " 15311cb875aeSCathy Zhou "%s(%s/0x%x))", intf->vvi_ifname, 15321cb875aeSCathy Zhou intf->vvi_ifindex, ip->vip_lifname, 15331cb875aeSCathy Zhou abuf, ip->vip_flags); 15341cb875aeSCathy Zhou ip->vip_state = NODE_STATE_STALE; 15351cb875aeSCathy Zhou continue; 15361cb875aeSCathy Zhou } 15371cb875aeSCathy Zhou 15381cb875aeSCathy Zhou /* 15391cb875aeSCathy Zhou * If the IP is still marked as new, it means that 15401cb875aeSCathy Zhou * this vrrpd_init_ipcache() call is a result of 15411cb875aeSCathy Zhou * ifindex change, which causes the re-walk of all 15421cb875aeSCathy Zhou * the IP addresses (see vrrpd_add_ipaddr()). 15431cb875aeSCathy Zhou * Delete this IP. 15441cb875aeSCathy Zhou * 15451cb875aeSCathy Zhou * This IP will be readded later if it still exists. 15461cb875aeSCathy Zhou */ 15471cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_init_ipcache(): remove " 15481cb875aeSCathy Zhou "%s/%d , %s(%s)", intf->vvi_ifname, 15491cb875aeSCathy Zhou intf->vvi_ifindex, ip->vip_lifname, abuf); 15501cb875aeSCathy Zhou vrrpd_delete_ip(intf, ip); 15511cb875aeSCathy Zhou } 15521cb875aeSCathy Zhou } 15531cb875aeSCathy Zhou } 15541cb875aeSCathy Zhou 15551cb875aeSCathy Zhou /* 1556f6da83d4SAnurag S. Maskey * Walk all the IP addresses of the given family and update its 1557f6da83d4SAnurag S. Maskey * addresses list. Return IPADM_FAILURE if it is required to walk 15581cb875aeSCathy Zhou * all the interfaces again (one of the interface index changes in between). 15591cb875aeSCathy Zhou */ 1560f6da83d4SAnurag S. Maskey static ipadm_status_t 1561f6da83d4SAnurag S. Maskey vrrpd_walk_addr_info(int af) 15621cb875aeSCathy Zhou { 1563f6da83d4SAnurag S. Maskey ipadm_addr_info_t *ainfo, *ainfop; 1564f6da83d4SAnurag S. Maskey ipadm_status_t ipstatus; 1565f6da83d4SAnurag S. Maskey char *lifname; 156664639aafSDarren Reed struct sockaddr_storage stor; 1567f6da83d4SAnurag S. Maskey vrrp_addr_t *addr; 15681cb875aeSCathy Zhou int ifindex; 15691cb875aeSCathy Zhou uint64_t flags; 15701cb875aeSCathy Zhou 1571f6da83d4SAnurag S. Maskey vrrp_log(VRRP_DBG0, "vrrpd_walk_addr_info(%s)", af_str(af)); 15721cb875aeSCathy Zhou 1573f6da83d4SAnurag S. Maskey ipstatus = ipadm_addr_info(vrrp_ipadm_handle, NULL, &ainfo, 0, 0); 1574f6da83d4SAnurag S. Maskey if (ipstatus != IPADM_SUCCESS) { 1575f6da83d4SAnurag S. Maskey vrrp_log(VRRP_ERR, "vrrpd_walk_addr_info(%s): " 1576f6da83d4SAnurag S. Maskey "ipadm_addr_info() failed: %s", 1577f6da83d4SAnurag S. Maskey af_str(af), ipadm_status2str(ipstatus)); 1578f6da83d4SAnurag S. Maskey return (IPADM_SUCCESS); 15791cb875aeSCathy Zhou } 15801cb875aeSCathy Zhou 1581f6da83d4SAnurag S. Maskey for (ainfop = ainfo; ainfop != NULL; ainfop = IA_NEXT(ainfop)) { 158264639aafSDarren Reed if (ainfop->ia_ifa.ifa_addr->sa_family != af) 1583f6da83d4SAnurag S. Maskey continue; 1584f6da83d4SAnurag S. Maskey 1585f6da83d4SAnurag S. Maskey lifname = ainfop->ia_ifa.ifa_name; 1586f6da83d4SAnurag S. Maskey flags = ainfop->ia_ifa.ifa_flags; 158764639aafSDarren Reed (void) memcpy(&stor, ainfop->ia_ifa.ifa_addr, sizeof (stor)); 158864639aafSDarren Reed addr = (vrrp_addr_t *)&stor; 1589f6da83d4SAnurag S. Maskey 1590f6da83d4SAnurag S. Maskey vrrp_log(VRRP_DBG0, "vrrpd_walk_addr_info(%s): %s", 1591f6da83d4SAnurag S. Maskey af_str(af), lifname); 1592f6da83d4SAnurag S. Maskey 1593f6da83d4SAnurag S. Maskey /* Skip virtual/IPMP/P2P interfaces */ 1594f6da83d4SAnurag S. Maskey if (flags & (IFF_VIRTUAL|IFF_IPMP|IFF_POINTOPOINT)) { 1595f6da83d4SAnurag S. Maskey vrrp_log(VRRP_DBG0, "vrrpd_walk_addr_info(%s): " 1596f6da83d4SAnurag S. Maskey "skipped %s", af_str(af), lifname); 1597f6da83d4SAnurag S. Maskey continue; 1598f6da83d4SAnurag S. Maskey } 1599f6da83d4SAnurag S. Maskey 1600f6da83d4SAnurag S. Maskey /* Filter out the all-zero IP address */ 1601f6da83d4SAnurag S. Maskey if (VRRPADDR_UNSPECIFIED(af, addr)) 1602f6da83d4SAnurag S. Maskey continue; 1603f6da83d4SAnurag S. Maskey 1604f6da83d4SAnurag S. Maskey if ((ifindex = if_nametoindex(lifname)) == 0) { 16051cb875aeSCathy Zhou if (errno != ENXIO && errno != ENOENT) { 1606f6da83d4SAnurag S. Maskey vrrp_log(VRRP_ERR, "vrrpd_walk_addr_info(%s): " 1607f6da83d4SAnurag S. Maskey "if_nametoindex() failed for %s: %s", 1608f6da83d4SAnurag S. Maskey af_str(af), lifname, strerror(errno)); 16091cb875aeSCathy Zhou } 1610f6da83d4SAnurag S. Maskey break; 16111cb875aeSCathy Zhou } 16121cb875aeSCathy Zhou 16131cb875aeSCathy Zhou /* 1614f6da83d4SAnurag S. Maskey * The interface is unplumbed/replumbed during the walk. Try 1615f6da83d4SAnurag S. Maskey * to walk the IP addresses one more time. 16161cb875aeSCathy Zhou */ 1617f6da83d4SAnurag S. Maskey if (vrrpd_add_ipaddr(lifname, af, addr, ifindex, flags) 1618f6da83d4SAnurag S. Maskey == VRRP_EAGAIN) { 1619f6da83d4SAnurag S. Maskey ipstatus = IPADM_FAILURE; 1620f6da83d4SAnurag S. Maskey break; 1621f6da83d4SAnurag S. Maskey } 16221cb875aeSCathy Zhou } 16231cb875aeSCathy Zhou 1624f6da83d4SAnurag S. Maskey ipadm_free_addr_info(ainfo); 1625f6da83d4SAnurag S. Maskey return (ipstatus); 16261cb875aeSCathy Zhou } 16271cb875aeSCathy Zhou 16281cb875aeSCathy Zhou /* 16291cb875aeSCathy Zhou * Given the information of each IP address, update the interface and 16301cb875aeSCathy Zhou * IP addresses list 16311cb875aeSCathy Zhou */ 16321cb875aeSCathy Zhou static vrrp_err_t 16331cb875aeSCathy Zhou vrrpd_add_ipaddr(char *lifname, int af, vrrp_addr_t *addr, int ifindex, 16341cb875aeSCathy Zhou uint64_t flags) 16351cb875aeSCathy Zhou { 16361cb875aeSCathy Zhou char ifname[LIFNAMSIZ], *c; 16371cb875aeSCathy Zhou vrrp_intf_t *intf; 16381cb875aeSCathy Zhou vrrp_ip_t *ip; 16391cb875aeSCathy Zhou char abuf[INET6_ADDRSTRLEN]; 16401cb875aeSCathy Zhou vrrp_err_t err; 16411cb875aeSCathy Zhou 16421cb875aeSCathy Zhou /* LINTED E_CONSTANT_CONDITION */ 16431cb875aeSCathy Zhou VRRPADDR2STR(af, addr, abuf, INET6_ADDRSTRLEN, _B_FALSE); 16441cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_add_ipaddr(%s, %s, %d, 0x%x)", lifname, 16451cb875aeSCathy Zhou abuf, ifindex, flags); 16461cb875aeSCathy Zhou 16471cb875aeSCathy Zhou /* 16481cb875aeSCathy Zhou * Get the physical interface name from the logical interface name. 16491cb875aeSCathy Zhou */ 16501cb875aeSCathy Zhou (void) strlcpy(ifname, lifname, sizeof (ifname)); 16511cb875aeSCathy Zhou if ((c = strchr(ifname, ':')) != NULL) 16521cb875aeSCathy Zhou *c = '\0'; 16531cb875aeSCathy Zhou 16541cb875aeSCathy Zhou if ((intf = vrrpd_lookup_if(ifname, af)) == NULL) { 16551cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_add_ipaddr(): %s is new", ifname); 16561cb875aeSCathy Zhou err = vrrpd_create_if(ifname, af, ifindex, &intf); 16571cb875aeSCathy Zhou if (err != VRRP_SUCCESS) 16581cb875aeSCathy Zhou return (err); 16591cb875aeSCathy Zhou } else if (intf->vvi_ifindex != ifindex) { 16601cb875aeSCathy Zhou /* 16611cb875aeSCathy Zhou * If index changes, it means that this interface is 16621cb875aeSCathy Zhou * unplumbed/replumbed since we last checked. If this 16631cb875aeSCathy Zhou * interface is not used by any VRRP router, just 16641cb875aeSCathy Zhou * update its ifindex, and the IP addresses list will 16651cb875aeSCathy Zhou * be updated later. Otherwise, return EAGAIN to rewalk 16661cb875aeSCathy Zhou * all the IP addresses from the beginning. 16671cb875aeSCathy Zhou */ 16681cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_add_ipaddr(%s) ifindex changed ", 16691cb875aeSCathy Zhou "from %d to %d", ifname, intf->vvi_ifindex, ifindex); 16701cb875aeSCathy Zhou if (!IS_PRIMARY_INTF(intf) && !IS_VIRTUAL_INTF(intf)) { 16711cb875aeSCathy Zhou intf->vvi_ifindex = ifindex; 16721cb875aeSCathy Zhou } else { 16731cb875aeSCathy Zhou /* 16741cb875aeSCathy Zhou * delete this interface from the list if this 16751cb875aeSCathy Zhou * interface has already been assoicated with 16761cb875aeSCathy Zhou * any VRRP routers. 16771cb875aeSCathy Zhou */ 16781cb875aeSCathy Zhou vrrpd_delete_if(intf, _B_TRUE); 16791cb875aeSCathy Zhou return (VRRP_EAGAIN); 16801cb875aeSCathy Zhou } 16811cb875aeSCathy Zhou } 16821cb875aeSCathy Zhou 16831cb875aeSCathy Zhou /* 16841cb875aeSCathy Zhou * Does this IP address already exist? 16851cb875aeSCathy Zhou */ 16861cb875aeSCathy Zhou TAILQ_FOREACH(ip, &intf->vvi_iplist, vip_next) { 16871cb875aeSCathy Zhou if (strcmp(ip->vip_lifname, lifname) == 0) 16881cb875aeSCathy Zhou break; 16891cb875aeSCathy Zhou } 16901cb875aeSCathy Zhou 16911cb875aeSCathy Zhou if (ip != NULL) { 16921cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_add_ipaddr(%s, %s) IP exists", 16931cb875aeSCathy Zhou lifname, abuf); 16941cb875aeSCathy Zhou ip->vip_state = NODE_STATE_NONE; 16951cb875aeSCathy Zhou ip->vip_flags = flags; 16961cb875aeSCathy Zhou if (ipaddr_cmp(af, addr, &ip->vip_addr) != 0) { 16971cb875aeSCathy Zhou /* 16981cb875aeSCathy Zhou * Address has been changed, mark it as new 16991cb875aeSCathy Zhou * If this address is already selected as the 17001cb875aeSCathy Zhou * primary IP address, the new IP will be checked 17011cb875aeSCathy Zhou * to see whether it is still qualified as the 17021cb875aeSCathy Zhou * primary IP address. If not, the primary IP 17031cb875aeSCathy Zhou * address will be reselected. 17041cb875aeSCathy Zhou */ 17051cb875aeSCathy Zhou (void) memcpy(&ip->vip_addr, addr, 17061cb875aeSCathy Zhou sizeof (vrrp_addr_t)); 17071cb875aeSCathy Zhou 17081cb875aeSCathy Zhou ip->vip_state = NODE_STATE_NEW; 17091cb875aeSCathy Zhou } 17101cb875aeSCathy Zhou } else { 17111cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_add_ipaddr(%s, %s) IP is new", 17121cb875aeSCathy Zhou lifname, abuf); 17131cb875aeSCathy Zhou 17141cb875aeSCathy Zhou err = vrrpd_create_ip(intf, lifname, addr, flags); 17151cb875aeSCathy Zhou if (err != VRRP_SUCCESS) 17161cb875aeSCathy Zhou return (err); 17171cb875aeSCathy Zhou } 17181cb875aeSCathy Zhou return (VRRP_SUCCESS); 17191cb875aeSCathy Zhou } 17201cb875aeSCathy Zhou 17211cb875aeSCathy Zhou /* 17221cb875aeSCathy Zhou * Update the interface and IP addresses list. Remove the ones that have been 17231cb875aeSCathy Zhou * staled since last time we walk the IP addresses and updated the ones that 17241cb875aeSCathy Zhou * have been changed. 17251cb875aeSCathy Zhou */ 17261cb875aeSCathy Zhou static void 17271cb875aeSCathy Zhou vrrpd_update_ipcache(int af) 17281cb875aeSCathy Zhou { 17291cb875aeSCathy Zhou vrrp_intf_t *intf, *nextif; 17301cb875aeSCathy Zhou vrrp_ip_t *ip, *nextip; 17311cb875aeSCathy Zhou char abuf[INET6_ADDRSTRLEN]; 17321cb875aeSCathy Zhou boolean_t primary_selected; 17331cb875aeSCathy Zhou boolean_t primary_now_selected; 17341cb875aeSCathy Zhou boolean_t need_reenable = _B_FALSE; 17351cb875aeSCathy Zhou 17361cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_update_ipcache(%s)", af_str(af)); 17371cb875aeSCathy Zhou 17381cb875aeSCathy Zhou nextif = TAILQ_FIRST(&vrrp_intf_list); 17391cb875aeSCathy Zhou while ((intf = nextif) != NULL) { 17401cb875aeSCathy Zhou nextif = TAILQ_NEXT(intf, vvi_next); 17411cb875aeSCathy Zhou if (intf->vvi_af != af) 17421cb875aeSCathy Zhou continue; 17431cb875aeSCathy Zhou 17441cb875aeSCathy Zhou /* 17451cb875aeSCathy Zhou * Does the interface already select its primary IP address? 17461cb875aeSCathy Zhou */ 17471cb875aeSCathy Zhou primary_selected = (intf->vvi_pip != NULL); 17481cb875aeSCathy Zhou assert(!primary_selected || IS_PRIMARY_INTF(intf)); 17491cb875aeSCathy Zhou 17501cb875aeSCathy Zhou /* 17511cb875aeSCathy Zhou * Removed the IP addresses that have been unconfigured. 17521cb875aeSCathy Zhou */ 17531cb875aeSCathy Zhou for (ip = TAILQ_FIRST(&intf->vvi_iplist); ip != NULL; 17541cb875aeSCathy Zhou ip = nextip) { 17551cb875aeSCathy Zhou nextip = TAILQ_NEXT(ip, vip_next); 17561cb875aeSCathy Zhou if (ip->vip_state != NODE_STATE_STALE) 17571cb875aeSCathy Zhou continue; 17581cb875aeSCathy Zhou 17591cb875aeSCathy Zhou /* LINTED E_CONSTANT_CONDITION */ 17601cb875aeSCathy Zhou VRRPADDR2STR(af, &ip->vip_addr, abuf, INET6_ADDRSTRLEN, 17611cb875aeSCathy Zhou _B_FALSE); 17621cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_update_ipcache(): IP %s " 17631cb875aeSCathy Zhou "is removed over %s", abuf, intf->vvi_ifname); 17641cb875aeSCathy Zhou vrrpd_delete_ip(intf, ip); 17651cb875aeSCathy Zhou } 17661cb875aeSCathy Zhou 17671cb875aeSCathy Zhou /* 17681cb875aeSCathy Zhou * No IP addresses left, delete this interface. 17691cb875aeSCathy Zhou */ 17701cb875aeSCathy Zhou if (TAILQ_EMPTY(&intf->vvi_iplist)) { 17711cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_update_ipcache(): " 17721cb875aeSCathy Zhou "no IP left over %s", intf->vvi_ifname); 17731cb875aeSCathy Zhou vrrpd_delete_if(intf, _B_TRUE); 17741cb875aeSCathy Zhou continue; 17751cb875aeSCathy Zhou } 17761cb875aeSCathy Zhou 17771cb875aeSCathy Zhou /* 17781cb875aeSCathy Zhou * If this is selected ss the physical interface for any 17791cb875aeSCathy Zhou * VRRP router, reselect the primary address if needed. 17801cb875aeSCathy Zhou */ 17811cb875aeSCathy Zhou if (IS_PRIMARY_INTF(intf)) { 17821cb875aeSCathy Zhou vrrpd_reselect_primary(intf); 17831cb875aeSCathy Zhou primary_now_selected = (intf->vvi_pip != NULL); 17841cb875aeSCathy Zhou 17851cb875aeSCathy Zhou /* 17861cb875aeSCathy Zhou * Cannot find the new primary IP address. 17871cb875aeSCathy Zhou */ 17881cb875aeSCathy Zhou if (primary_selected && !primary_now_selected) { 17891cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_update_ipcache() " 17901cb875aeSCathy Zhou "reselect primary IP on %s failed", 17911cb875aeSCathy Zhou intf->vvi_ifname); 17921cb875aeSCathy Zhou vrrpd_remove_if(intf, _B_TRUE); 17931cb875aeSCathy Zhou } else if (!primary_selected && primary_now_selected) { 17941cb875aeSCathy Zhou /* 17951cb875aeSCathy Zhou * The primary IP address is successfully 17961cb875aeSCathy Zhou * selected on the physical interfacew we 17971cb875aeSCathy Zhou * need to walk through all the VRRP routers 17981cb875aeSCathy Zhou * that is created on this physical interface 17991cb875aeSCathy Zhou * and see whether they can now be enabled. 18001cb875aeSCathy Zhou */ 18011cb875aeSCathy Zhou need_reenable = _B_TRUE; 18021cb875aeSCathy Zhou } 18031cb875aeSCathy Zhou } 18041cb875aeSCathy Zhou 18051cb875aeSCathy Zhou /* 18061cb875aeSCathy Zhou * For every new virtual IP address, bring up/down it based 18071cb875aeSCathy Zhou * on the state of VRRP router. 18081cb875aeSCathy Zhou * 18091cb875aeSCathy Zhou * Note that it is fine to not update the IP's vip_flags field 18101cb875aeSCathy Zhou * even if vrrpd_virtualip_updateone() changed the address's 18111cb875aeSCathy Zhou * up/down state, since the vip_flags field is only used for 18121cb875aeSCathy Zhou * select primary IP address over a physical interface, and 18131cb875aeSCathy Zhou * vrrpd_virtualip_updateone() only affects the virtual IP 18141cb875aeSCathy Zhou * address's status. 18151cb875aeSCathy Zhou */ 18161cb875aeSCathy Zhou for (ip = TAILQ_FIRST(&intf->vvi_iplist); ip != NULL; 18171cb875aeSCathy Zhou ip = nextip) { 18181cb875aeSCathy Zhou nextip = TAILQ_NEXT(ip, vip_next); 18191cb875aeSCathy Zhou /* LINTED E_CONSTANT_CONDITION */ 18201cb875aeSCathy Zhou VRRPADDR2STR(af, &ip->vip_addr, abuf, INET6_ADDRSTRLEN, 18211cb875aeSCathy Zhou _B_FALSE); 18221cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_update_ipcache(): " 18231cb875aeSCathy Zhou "IP %s over %s%s", abuf, intf->vvi_ifname, 18241cb875aeSCathy Zhou ip->vip_state == NODE_STATE_NEW ? " is new" : ""); 18251cb875aeSCathy Zhou 18261cb875aeSCathy Zhou if (IS_VIRTUAL_INTF(intf)) { 18271cb875aeSCathy Zhou /* 18281cb875aeSCathy Zhou * If this IP is new, update its up/down state 18291cb875aeSCathy Zhou * based on the virtual interface's state 18301cb875aeSCathy Zhou * (which is determined by the VRRP router's 18311cb875aeSCathy Zhou * state). Otherwise, check only and prompt 18321cb875aeSCathy Zhou * warnings if its up/down state has been 18331cb875aeSCathy Zhou * changed. 18341cb875aeSCathy Zhou */ 18351cb875aeSCathy Zhou if (vrrpd_virtualip_updateone(intf, ip, 18361cb875aeSCathy Zhou ip->vip_state == NODE_STATE_NONE) != 18371cb875aeSCathy Zhou VRRP_SUCCESS) { 18381cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, 18391cb875aeSCathy Zhou "vrrpd_update_ipcache(): " 18401cb875aeSCathy Zhou "IP %s over %s update failed", abuf, 18411cb875aeSCathy Zhou intf->vvi_ifname); 18421cb875aeSCathy Zhou vrrpd_delete_ip(intf, ip); 18431cb875aeSCathy Zhou continue; 18441cb875aeSCathy Zhou } 18451cb875aeSCathy Zhou } 18461cb875aeSCathy Zhou ip->vip_state = NODE_STATE_NONE; 18471cb875aeSCathy Zhou } 18481cb875aeSCathy Zhou 18491cb875aeSCathy Zhou /* 18501cb875aeSCathy Zhou * The IP address is deleted when it is failed to be brought 18511cb875aeSCathy Zhou * up. If no IP addresses are left, delete this interface. 18521cb875aeSCathy Zhou */ 18531cb875aeSCathy Zhou if (TAILQ_EMPTY(&intf->vvi_iplist)) { 18541cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_update_ipcache(): " 18551cb875aeSCathy Zhou "no IP left over %s", intf->vvi_ifname); 18561cb875aeSCathy Zhou vrrpd_delete_if(intf, _B_TRUE); 18571cb875aeSCathy Zhou continue; 18581cb875aeSCathy Zhou } 18591cb875aeSCathy Zhou 18601cb875aeSCathy Zhou if (intf->vvi_state == NODE_STATE_NEW) { 18611cb875aeSCathy Zhou /* 18621cb875aeSCathy Zhou * A new interface is found. This interface can be 18631cb875aeSCathy Zhou * the primary interface or the virtual VNIC 18641cb875aeSCathy Zhou * interface. Again, we need to walk throught all 18651cb875aeSCathy Zhou * the VRRP routers to see whether some of them can 18661cb875aeSCathy Zhou * now be enabled because of the new primary IP 18671cb875aeSCathy Zhou * address or the new virtual IP addresses. 18681cb875aeSCathy Zhou */ 18691cb875aeSCathy Zhou intf->vvi_state = NODE_STATE_NONE; 18701cb875aeSCathy Zhou need_reenable = _B_TRUE; 18711cb875aeSCathy Zhou } 18721cb875aeSCathy Zhou } 18731cb875aeSCathy Zhou 18741cb875aeSCathy Zhou if (need_reenable) 18751cb875aeSCathy Zhou vrrpd_reenable_all_vr(); 18761cb875aeSCathy Zhou } 18771cb875aeSCathy Zhou 18781cb875aeSCathy Zhou /* 18791cb875aeSCathy Zhou * Reselect primary IP if: 18801cb875aeSCathy Zhou * - The existing primary IP is no longer qualified (removed or it is down or 18811cb875aeSCathy Zhou * not a link-local IP for IPv6 VRRP router); 18821cb875aeSCathy Zhou * - This is a physical interface but no primary IP is chosen; 18831cb875aeSCathy Zhou */ 18841cb875aeSCathy Zhou static void 18851cb875aeSCathy Zhou vrrpd_reselect_primary(vrrp_intf_t *intf) 18861cb875aeSCathy Zhou { 18871cb875aeSCathy Zhou vrrp_ip_t *ip; 18881cb875aeSCathy Zhou char abuf[INET6_ADDRSTRLEN]; 18891cb875aeSCathy Zhou 18901cb875aeSCathy Zhou assert(IS_PRIMARY_INTF(intf)); 18911cb875aeSCathy Zhou 18921cb875aeSCathy Zhou /* 18931cb875aeSCathy Zhou * If the interface's old primary IP address is still valid, return 18941cb875aeSCathy Zhou */ 18951cb875aeSCathy Zhou if (((ip = intf->vvi_pip) != NULL) && (QUALIFY_PRIMARY_ADDR(intf, ip))) 18961cb875aeSCathy Zhou return; 18971cb875aeSCathy Zhou 18981cb875aeSCathy Zhou if (ip != NULL) { 18991cb875aeSCathy Zhou /* LINTED E_CONSTANT_CONDITION */ 19001cb875aeSCathy Zhou VRRPADDR2STR(intf->vvi_af, &ip->vip_addr, abuf, 19011cb875aeSCathy Zhou sizeof (abuf), _B_FALSE); 19021cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_reselect_primary(%s): primary IP %s " 19031cb875aeSCathy Zhou "is no longer qualified", intf->vvi_ifname, abuf); 19041cb875aeSCathy Zhou } 19051cb875aeSCathy Zhou 19061cb875aeSCathy Zhou ip = vrrpd_select_primary(intf); 19071cb875aeSCathy Zhou intf->vvi_pip = ip; 19081cb875aeSCathy Zhou 19091cb875aeSCathy Zhou if (ip != NULL) { 19101cb875aeSCathy Zhou /* LINTED E_CONSTANT_CONDITION */ 19111cb875aeSCathy Zhou VRRPADDR2STR(intf->vvi_af, &ip->vip_addr, abuf, 19121cb875aeSCathy Zhou sizeof (abuf), _B_FALSE); 19131cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_reselect_primary(%s): primary IP %s " 19141cb875aeSCathy Zhou "is selected", intf->vvi_ifname, abuf); 19151cb875aeSCathy Zhou } 19161cb875aeSCathy Zhou } 19171cb875aeSCathy Zhou 19181cb875aeSCathy Zhou /* 19191cb875aeSCathy Zhou * Select the primary IP address. Since the link-local IP address is always 19201cb875aeSCathy Zhou * at the head of the IP address list, try to find the first UP IP address 19211cb875aeSCathy Zhou * and see whether it qualify. 19221cb875aeSCathy Zhou */ 19231cb875aeSCathy Zhou static vrrp_ip_t * 19241cb875aeSCathy Zhou vrrpd_select_primary(vrrp_intf_t *pif) 19251cb875aeSCathy Zhou { 19261cb875aeSCathy Zhou vrrp_ip_t *pip; 19271cb875aeSCathy Zhou char abuf[INET6_ADDRSTRLEN]; 19281cb875aeSCathy Zhou 19291cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_select_primary(%s)", pif->vvi_ifname); 19301cb875aeSCathy Zhou 19311cb875aeSCathy Zhou TAILQ_FOREACH(pip, &pif->vvi_iplist, vip_next) { 19321cb875aeSCathy Zhou assert(pip->vip_state != NODE_STATE_STALE); 19331cb875aeSCathy Zhou 19341cb875aeSCathy Zhou /* LINTED E_CONSTANT_CONDITION */ 19351cb875aeSCathy Zhou VRRPADDR2STR(pif->vvi_af, &pip->vip_addr, abuf, 19361cb875aeSCathy Zhou INET6_ADDRSTRLEN, _B_FALSE); 19371cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_select_primary(%s): %s is %s", 19381cb875aeSCathy Zhou pif->vvi_ifname, abuf, 19391cb875aeSCathy Zhou (pip->vip_flags & IFF_UP) ? "up" : "down"); 19401cb875aeSCathy Zhou 19411cb875aeSCathy Zhou if (pip->vip_flags & IFF_UP) 19421cb875aeSCathy Zhou break; 19431cb875aeSCathy Zhou } 19441cb875aeSCathy Zhou 19451cb875aeSCathy Zhou /* 19461cb875aeSCathy Zhou * Is this valid primary IP address? 19471cb875aeSCathy Zhou */ 19481cb875aeSCathy Zhou if (pip == NULL || !QUALIFY_PRIMARY_ADDR(pif, pip)) { 19491cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_select_primary(%s/%s) failed", 19501cb875aeSCathy Zhou pif->vvi_ifname, af_str(pif->vvi_af)); 19511cb875aeSCathy Zhou return (NULL); 19521cb875aeSCathy Zhou } 19531cb875aeSCathy Zhou return (pip); 19541cb875aeSCathy Zhou } 19551cb875aeSCathy Zhou 19561cb875aeSCathy Zhou /* 19571cb875aeSCathy Zhou * This is a new interface. Check whether any VRRP router is waiting for it 19581cb875aeSCathy Zhou */ 19591cb875aeSCathy Zhou static void 19601cb875aeSCathy Zhou vrrpd_reenable_all_vr() 19611cb875aeSCathy Zhou { 19621cb875aeSCathy Zhou vrrp_vr_t *vr; 19631cb875aeSCathy Zhou 19641cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_reenable_all_vr()"); 19651cb875aeSCathy Zhou 19661cb875aeSCathy Zhou TAILQ_FOREACH(vr, &vrrp_vr_list, vvr_next) { 19671cb875aeSCathy Zhou if (vr->vvr_conf.vvc_enabled) 19681cb875aeSCathy Zhou (void) vrrpd_enable_vr(vr); 19691cb875aeSCathy Zhou } 19701cb875aeSCathy Zhou } 19711cb875aeSCathy Zhou 19721cb875aeSCathy Zhou /* 19731cb875aeSCathy Zhou * If primary_addr_gone is _B_TRUE, it means that we failed to select 19741cb875aeSCathy Zhou * the primary IP address on this (physical) interface; otherwise, 19751cb875aeSCathy Zhou * it means the interface is no longer available. 19761cb875aeSCathy Zhou */ 19771cb875aeSCathy Zhou static void 19781cb875aeSCathy Zhou vrrpd_remove_if(vrrp_intf_t *intf, boolean_t primary_addr_gone) 19791cb875aeSCathy Zhou { 19801cb875aeSCathy Zhou vrrp_vr_t *vr; 19811cb875aeSCathy Zhou 19821cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_remove_if(%s): %s", intf->vvi_ifname, 19831cb875aeSCathy Zhou primary_addr_gone ? "primary address gone" : "interface deleted"); 19841cb875aeSCathy Zhou 19851cb875aeSCathy Zhou TAILQ_FOREACH(vr, &vrrp_vr_list, vvr_next) { 19861cb875aeSCathy Zhou if (vr->vvr_conf.vvc_enabled) 19871cb875aeSCathy Zhou vrrpd_disable_vr(vr, intf, primary_addr_gone); 19881cb875aeSCathy Zhou } 19891cb875aeSCathy Zhou } 19901cb875aeSCathy Zhou 19911cb875aeSCathy Zhou /* 19921cb875aeSCathy Zhou * Update the VRRP configuration file based on the given configuration. 19931cb875aeSCathy Zhou * op is either VRRP_CONF_UPDATE or VRRP_CONF_DELETE 19941cb875aeSCathy Zhou */ 19951cb875aeSCathy Zhou static vrrp_err_t 19961cb875aeSCathy Zhou vrrpd_updateconf(vrrp_vr_conf_t *newconf, uint_t op) 19971cb875aeSCathy Zhou { 19981cb875aeSCathy Zhou vrrp_vr_conf_t conf; 19991cb875aeSCathy Zhou FILE *fp, *nfp; 20001cb875aeSCathy Zhou int nfd; 20011cb875aeSCathy Zhou char line[LINE_MAX]; 20021cb875aeSCathy Zhou char newfile[MAXPATHLEN]; 20031cb875aeSCathy Zhou boolean_t found = _B_FALSE; 20041cb875aeSCathy Zhou vrrp_err_t err = VRRP_SUCCESS; 20051cb875aeSCathy Zhou 20061cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_updateconf(%s, %s)", newconf->vvc_name, 20071cb875aeSCathy Zhou op == VRRP_CONF_UPDATE ? "update" : "delete"); 20081cb875aeSCathy Zhou 20091cb875aeSCathy Zhou if ((fp = fopen(vrrpd_conffile, "r+F")) == NULL) { 2010*2954adb0SRob Gulewich if (errno != ENOENT) { 2011*2954adb0SRob Gulewich vrrp_log(VRRP_ERR, "vrrpd_updateconf(): open %s for " 2012*2954adb0SRob Gulewich "update failed: %s", vrrpd_conffile, 2013*2954adb0SRob Gulewich strerror(errno)); 20141cb875aeSCathy Zhou return (VRRP_EDB); 20151cb875aeSCathy Zhou } 20161cb875aeSCathy Zhou 2017*2954adb0SRob Gulewich if ((fp = fopen(vrrpd_conffile, "w+F")) == NULL) { 2018*2954adb0SRob Gulewich vrrp_log(VRRP_ERR, "vrrpd_updateconf(): open %s for " 2019*2954adb0SRob Gulewich "write failed: %s", vrrpd_conffile, 2020*2954adb0SRob Gulewich strerror(errno)); 2021*2954adb0SRob Gulewich return (VRRP_EDB); 2022*2954adb0SRob Gulewich } 2023*2954adb0SRob Gulewich } 2024*2954adb0SRob Gulewich 20251cb875aeSCathy Zhou (void) snprintf(newfile, MAXPATHLEN, "%s.new", vrrpd_conffile); 20261cb875aeSCathy Zhou if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC, 20271cb875aeSCathy Zhou S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) { 20281cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_updateconf(): open %s failed: %s", 20291cb875aeSCathy Zhou newfile, strerror(errno)); 20301cb875aeSCathy Zhou (void) fclose(fp); 20311cb875aeSCathy Zhou return (VRRP_EDB); 20321cb875aeSCathy Zhou } 20331cb875aeSCathy Zhou 20341cb875aeSCathy Zhou if ((nfp = fdopen(nfd, "wF")) == NULL) { 20351cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_updateconf(): fdopen(%s) failed: %s", 20361cb875aeSCathy Zhou newfile, strerror(errno)); 20371cb875aeSCathy Zhou goto done; 20381cb875aeSCathy Zhou } 20391cb875aeSCathy Zhou 20401cb875aeSCathy Zhou while (fgets(line, sizeof (line), fp) != NULL) { 20411cb875aeSCathy Zhou conf.vvc_vrid = VRRP_VRID_NONE; 20421cb875aeSCathy Zhou if (!found && (err = vrrpd_read_vrconf(line, &conf)) != 20431cb875aeSCathy Zhou VRRP_SUCCESS) { 20441cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_updateconf(): invalid " 20451cb875aeSCathy Zhou "configuration format: %s", line); 20461cb875aeSCathy Zhou goto done; 20471cb875aeSCathy Zhou } 20481cb875aeSCathy Zhou 20491cb875aeSCathy Zhou /* 20501cb875aeSCathy Zhou * Write this line out if: 20511cb875aeSCathy Zhou * - this is a comment line; or 20521cb875aeSCathy Zhou * - we've done updating/deleting the the given VR; or 20531cb875aeSCathy Zhou * - if the name of the VR read from this line does not match 20541cb875aeSCathy Zhou * the VR name that we are about to update/delete; 20551cb875aeSCathy Zhou */ 20561cb875aeSCathy Zhou if (found || conf.vvc_vrid == VRRP_VRID_NONE || 20571cb875aeSCathy Zhou strcmp(conf.vvc_name, newconf->vvc_name) != 0) { 20581cb875aeSCathy Zhou if (fputs(line, nfp) != EOF) 20591cb875aeSCathy Zhou continue; 20601cb875aeSCathy Zhou 20611cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_updateconf(): failed to " 20621cb875aeSCathy Zhou "write line %s", line); 20631cb875aeSCathy Zhou err = VRRP_EDB; 20641cb875aeSCathy Zhou goto done; 20651cb875aeSCathy Zhou } 20661cb875aeSCathy Zhou 20671cb875aeSCathy Zhou /* 20681cb875aeSCathy Zhou * Otherwise, update/skip the line. 20691cb875aeSCathy Zhou */ 20701cb875aeSCathy Zhou found = _B_TRUE; 20711cb875aeSCathy Zhou if (op == VRRP_CONF_DELETE) 20721cb875aeSCathy Zhou continue; 20731cb875aeSCathy Zhou 20741cb875aeSCathy Zhou assert(op == VRRP_CONF_UPDATE); 20751cb875aeSCathy Zhou if ((err = vrrpd_write_vrconf(line, sizeof (line), 20761cb875aeSCathy Zhou newconf)) != VRRP_SUCCESS) { 20771cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_updateconf(): failed to " 20781cb875aeSCathy Zhou "update configuration for %s", newconf->vvc_name); 20791cb875aeSCathy Zhou goto done; 20801cb875aeSCathy Zhou } 20811cb875aeSCathy Zhou if (fputs(line, nfp) == EOF) { 20821cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_updateconf(): failed to " 20831cb875aeSCathy Zhou "write line %s", line); 20841cb875aeSCathy Zhou err = VRRP_EDB; 20851cb875aeSCathy Zhou goto done; 20861cb875aeSCathy Zhou } 20871cb875aeSCathy Zhou } 20881cb875aeSCathy Zhou 20891cb875aeSCathy Zhou /* 20901cb875aeSCathy Zhou * If we get to the end of the file and have not seen the router that 20911cb875aeSCathy Zhou * we are about to update, write it out. 20921cb875aeSCathy Zhou */ 20931cb875aeSCathy Zhou if (!found && op == VRRP_CONF_UPDATE) { 20941cb875aeSCathy Zhou if ((err = vrrpd_write_vrconf(line, sizeof (line), 20951cb875aeSCathy Zhou newconf)) == VRRP_SUCCESS && fputs(line, nfp) == EOF) { 20961cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_updateconf(): failed to " 20971cb875aeSCathy Zhou "write line %s", line); 20981cb875aeSCathy Zhou err = VRRP_EDB; 20991cb875aeSCathy Zhou } 21001cb875aeSCathy Zhou } else if (!found && op == VRRP_CONF_DELETE) { 21011cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_updateconf(): failed to find " 21021cb875aeSCathy Zhou "configuation for %s", newconf->vvc_name); 21031cb875aeSCathy Zhou err = VRRP_ENOTFOUND; 21041cb875aeSCathy Zhou } 21051cb875aeSCathy Zhou 21061cb875aeSCathy Zhou if (err != VRRP_SUCCESS) 21071cb875aeSCathy Zhou goto done; 21081cb875aeSCathy Zhou 21091cb875aeSCathy Zhou if (fflush(nfp) == EOF || rename(newfile, vrrpd_conffile) < 0) { 21101cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_updateconf(): failed to " 21111cb875aeSCathy Zhou "rename file %s", newfile); 21121cb875aeSCathy Zhou err = VRRP_EDB; 21131cb875aeSCathy Zhou } 21141cb875aeSCathy Zhou 21151cb875aeSCathy Zhou done: 21161cb875aeSCathy Zhou (void) fclose(fp); 21171cb875aeSCathy Zhou (void) fclose(nfp); 21181cb875aeSCathy Zhou (void) unlink(newfile); 21191cb875aeSCathy Zhou return (err); 21201cb875aeSCathy Zhou } 21211cb875aeSCathy Zhou 21221cb875aeSCathy Zhou static vrrp_err_t 21231cb875aeSCathy Zhou vrrpd_write_vrconf(char *line, size_t len, vrrp_vr_conf_t *conf) 21241cb875aeSCathy Zhou { 21251cb875aeSCathy Zhou vrrp_prop_t *prop; 21261cb875aeSCathy Zhou int n, i; 21271cb875aeSCathy Zhou 21281cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_write_vrconf(%s)", conf->vvc_name); 21291cb875aeSCathy Zhou 21301cb875aeSCathy Zhou for (i = 0; i < VRRP_PROP_INFO_TABSIZE; i++) { 21311cb875aeSCathy Zhou prop = &vrrp_prop_info_tbl[i]; 21321cb875aeSCathy Zhou n = snprintf(line, len, i == 0 ? "%s=" : " %s=", 21331cb875aeSCathy Zhou prop->vs_propname); 21341cb875aeSCathy Zhou if (n < 0 || n >= len) 21351cb875aeSCathy Zhou break; 21361cb875aeSCathy Zhou len -= n; 21371cb875aeSCathy Zhou line += n; 21381cb875aeSCathy Zhou n = prop->vs_propwrite(conf, line, len); 21391cb875aeSCathy Zhou if (n < 0 || n >= len) 21401cb875aeSCathy Zhou break; 21411cb875aeSCathy Zhou len -= n; 21421cb875aeSCathy Zhou line += n; 21431cb875aeSCathy Zhou } 21441cb875aeSCathy Zhou if (i != VRRP_PROP_INFO_TABSIZE) { 21451cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_write_vrconf(%s): buffer size too" 21461cb875aeSCathy Zhou "small", conf->vvc_name); 21471cb875aeSCathy Zhou return (VRRP_EDB); 21481cb875aeSCathy Zhou } 21491cb875aeSCathy Zhou n = snprintf(line, len, "\n"); 21501cb875aeSCathy Zhou if (n < 0 || n >= len) { 21511cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_write_vrconf(%s): buffer size too" 21521cb875aeSCathy Zhou "small", conf->vvc_name); 21531cb875aeSCathy Zhou return (VRRP_EDB); 21541cb875aeSCathy Zhou } 21551cb875aeSCathy Zhou return (VRRP_SUCCESS); 21561cb875aeSCathy Zhou } 21571cb875aeSCathy Zhou 21581cb875aeSCathy Zhou static vrrp_err_t 21591cb875aeSCathy Zhou vrrpd_read_vrconf(char *line, vrrp_vr_conf_t *conf) 21601cb875aeSCathy Zhou { 21611cb875aeSCathy Zhou char *str, *token; 21621cb875aeSCathy Zhou char *next; 21631cb875aeSCathy Zhou vrrp_err_t err = VRRP_SUCCESS; 21641cb875aeSCathy Zhou char tmpbuf[MAXLINELEN]; 21651cb875aeSCathy Zhou 21661cb875aeSCathy Zhou str = tmpbuf; 21671cb875aeSCathy Zhou (void) strlcpy(tmpbuf, line, MAXLINELEN); 21681cb875aeSCathy Zhou 21691cb875aeSCathy Zhou /* 21701cb875aeSCathy Zhou * Skip leading spaces, blank lines, and comments. 21711cb875aeSCathy Zhou */ 21721cb875aeSCathy Zhou skip_whitespace(str); 21731cb875aeSCathy Zhou if ((str - tmpbuf == strlen(tmpbuf)) || (*str == '#')) { 21741cb875aeSCathy Zhou conf->vvc_vrid = VRRP_VRID_NONE; 21751cb875aeSCathy Zhou return (VRRP_SUCCESS); 21761cb875aeSCathy Zhou } 21771cb875aeSCathy Zhou 21781cb875aeSCathy Zhou /* 21791cb875aeSCathy Zhou * Read each VR properties. 21801cb875aeSCathy Zhou */ 21811cb875aeSCathy Zhou for (token = strtok_r(str, " \n\t", &next); token != NULL; 21821cb875aeSCathy Zhou token = strtok_r(NULL, " \n\t", &next)) { 21831cb875aeSCathy Zhou if ((err = vrrpd_readprop(token, conf)) != VRRP_SUCCESS) 21841cb875aeSCathy Zhou break; 21851cb875aeSCathy Zhou } 21861cb875aeSCathy Zhou 21871cb875aeSCathy Zhou /* All properties read but no VRID defined */ 21881cb875aeSCathy Zhou if (err == VRRP_SUCCESS && conf->vvc_vrid == VRRP_VRID_NONE) 21891cb875aeSCathy Zhou err = VRRP_EINVAL; 21901cb875aeSCathy Zhou 21911cb875aeSCathy Zhou return (err); 21921cb875aeSCathy Zhou } 21931cb875aeSCathy Zhou 21941cb875aeSCathy Zhou static vrrp_err_t 21951cb875aeSCathy Zhou vrrpd_readprop(const char *str, vrrp_vr_conf_t *conf) 21961cb875aeSCathy Zhou { 21971cb875aeSCathy Zhou vrrp_prop_t *prop; 21981cb875aeSCathy Zhou char *pstr; 21991cb875aeSCathy Zhou int i; 22001cb875aeSCathy Zhou 22011cb875aeSCathy Zhou if ((pstr = strchr(str, '=')) == NULL) { 22021cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_readprop(%s): invalid property", str); 22031cb875aeSCathy Zhou return (VRRP_EINVAL); 22041cb875aeSCathy Zhou } 22051cb875aeSCathy Zhou 22061cb875aeSCathy Zhou *pstr++ = '\0'; 22071cb875aeSCathy Zhou for (i = 0; i < VRRP_PROP_INFO_TABSIZE; i++) { 22081cb875aeSCathy Zhou prop = &vrrp_prop_info_tbl[i]; 22091cb875aeSCathy Zhou if (strcasecmp(str, prop->vs_propname) == 0) { 22101cb875aeSCathy Zhou if (prop->vs_propread(conf, pstr)) 22111cb875aeSCathy Zhou break; 22121cb875aeSCathy Zhou } 22131cb875aeSCathy Zhou } 22141cb875aeSCathy Zhou 22151cb875aeSCathy Zhou if (i == VRRP_PROP_INFO_TABSIZE) { 22161cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_readprop(%s): invalid property", str); 22171cb875aeSCathy Zhou return (VRRP_EINVAL); 22181cb875aeSCathy Zhou } 22191cb875aeSCathy Zhou 22201cb875aeSCathy Zhou return (VRRP_SUCCESS); 22211cb875aeSCathy Zhou } 22221cb875aeSCathy Zhou 22231cb875aeSCathy Zhou static boolean_t 22241cb875aeSCathy Zhou vrrp_rd_prop_name(vrrp_vr_conf_t *conf, const char *str) 22251cb875aeSCathy Zhou { 22261cb875aeSCathy Zhou size_t size = sizeof (conf->vvc_name); 22271cb875aeSCathy Zhou return (strlcpy(conf->vvc_name, str, size) < size); 22281cb875aeSCathy Zhou } 22291cb875aeSCathy Zhou 22301cb875aeSCathy Zhou static boolean_t 22311cb875aeSCathy Zhou vrrp_rd_prop_vrid(vrrp_vr_conf_t *conf, const char *str) 22321cb875aeSCathy Zhou { 22331cb875aeSCathy Zhou conf->vvc_vrid = strtol(str, NULL, 0); 22341cb875aeSCathy Zhou return (!(conf->vvc_vrid < VRRP_VRID_MIN || 22351cb875aeSCathy Zhou conf->vvc_vrid > VRRP_VRID_MAX || 22361cb875aeSCathy Zhou (conf->vvc_vrid == 0 && errno != 0))); 22371cb875aeSCathy Zhou } 22381cb875aeSCathy Zhou 22391cb875aeSCathy Zhou static boolean_t 22401cb875aeSCathy Zhou vrrp_rd_prop_af(vrrp_vr_conf_t *conf, const char *str) 22411cb875aeSCathy Zhou { 22421cb875aeSCathy Zhou if (strcasecmp(str, "AF_INET") == 0) 22431cb875aeSCathy Zhou conf->vvc_af = AF_INET; 22441cb875aeSCathy Zhou else if (strcasecmp(str, "AF_INET6") == 0) 22451cb875aeSCathy Zhou conf->vvc_af = AF_INET6; 22461cb875aeSCathy Zhou else 22471cb875aeSCathy Zhou return (_B_FALSE); 22481cb875aeSCathy Zhou return (_B_TRUE); 22491cb875aeSCathy Zhou } 22501cb875aeSCathy Zhou 22511cb875aeSCathy Zhou static boolean_t 22521cb875aeSCathy Zhou vrrp_rd_prop_pri(vrrp_vr_conf_t *conf, const char *str) 22531cb875aeSCathy Zhou { 22541cb875aeSCathy Zhou conf->vvc_pri = strtol(str, NULL, 0); 22551cb875aeSCathy Zhou return (!(conf->vvc_pri < VRRP_PRI_MIN || 22561cb875aeSCathy Zhou conf->vvc_pri > VRRP_PRI_OWNER || 22571cb875aeSCathy Zhou (conf->vvc_pri == 0 && errno != 0))); 22581cb875aeSCathy Zhou } 22591cb875aeSCathy Zhou 22601cb875aeSCathy Zhou static boolean_t 22611cb875aeSCathy Zhou vrrp_rd_prop_adver_int(vrrp_vr_conf_t *conf, const char *str) 22621cb875aeSCathy Zhou { 22631cb875aeSCathy Zhou conf->vvc_adver_int = strtol(str, NULL, 0); 22641cb875aeSCathy Zhou return (!(conf->vvc_adver_int < VRRP_MAX_ADVER_INT_MIN || 22651cb875aeSCathy Zhou conf->vvc_adver_int > VRRP_MAX_ADVER_INT_MAX || 22661cb875aeSCathy Zhou (conf->vvc_adver_int == 0 && errno != 0))); 22671cb875aeSCathy Zhou } 22681cb875aeSCathy Zhou 22691cb875aeSCathy Zhou static boolean_t 22701cb875aeSCathy Zhou vrrp_rd_prop_preempt(vrrp_vr_conf_t *conf, const char *str) 22711cb875aeSCathy Zhou { 22721cb875aeSCathy Zhou if (strcasecmp(str, "true") == 0) 22731cb875aeSCathy Zhou conf->vvc_preempt = _B_TRUE; 22741cb875aeSCathy Zhou else if (strcasecmp(str, "false") == 0) 22751cb875aeSCathy Zhou conf->vvc_preempt = _B_FALSE; 22761cb875aeSCathy Zhou else 22771cb875aeSCathy Zhou return (_B_FALSE); 22781cb875aeSCathy Zhou return (_B_TRUE); 22791cb875aeSCathy Zhou } 22801cb875aeSCathy Zhou 22811cb875aeSCathy Zhou static boolean_t 22821cb875aeSCathy Zhou vrrp_rd_prop_accept(vrrp_vr_conf_t *conf, const char *str) 22831cb875aeSCathy Zhou { 22841cb875aeSCathy Zhou if (strcasecmp(str, "true") == 0) 22851cb875aeSCathy Zhou conf->vvc_accept = _B_TRUE; 22861cb875aeSCathy Zhou else if (strcasecmp(str, "false") == 0) 22871cb875aeSCathy Zhou conf->vvc_accept = _B_FALSE; 22881cb875aeSCathy Zhou else 22891cb875aeSCathy Zhou return (_B_FALSE); 22901cb875aeSCathy Zhou return (_B_TRUE); 22911cb875aeSCathy Zhou } 22921cb875aeSCathy Zhou 22931cb875aeSCathy Zhou static boolean_t 22941cb875aeSCathy Zhou vrrp_rd_prop_enabled(vrrp_vr_conf_t *conf, const char *str) 22951cb875aeSCathy Zhou { 22961cb875aeSCathy Zhou if (strcasecmp(str, "enabled") == 0) 22971cb875aeSCathy Zhou conf->vvc_enabled = _B_TRUE; 22981cb875aeSCathy Zhou else if (strcasecmp(str, "disabled") == 0) 22991cb875aeSCathy Zhou conf->vvc_enabled = _B_FALSE; 23001cb875aeSCathy Zhou else 23011cb875aeSCathy Zhou return (_B_FALSE); 23021cb875aeSCathy Zhou return (_B_TRUE); 23031cb875aeSCathy Zhou } 23041cb875aeSCathy Zhou 23051cb875aeSCathy Zhou static boolean_t 23061cb875aeSCathy Zhou vrrp_rd_prop_ifname(vrrp_vr_conf_t *conf, const char *str) 23071cb875aeSCathy Zhou { 23081cb875aeSCathy Zhou size_t size = sizeof (conf->vvc_link); 23091cb875aeSCathy Zhou return (strlcpy(conf->vvc_link, str, size) < size); 23101cb875aeSCathy Zhou } 23111cb875aeSCathy Zhou 23121cb875aeSCathy Zhou static int 23131cb875aeSCathy Zhou vrrp_wt_prop_name(vrrp_vr_conf_t *conf, char *str, size_t size) 23141cb875aeSCathy Zhou { 23151cb875aeSCathy Zhou return (snprintf(str, size, "%s", conf->vvc_name)); 23161cb875aeSCathy Zhou } 23171cb875aeSCathy Zhou 23181cb875aeSCathy Zhou static int 23191cb875aeSCathy Zhou vrrp_wt_prop_pri(vrrp_vr_conf_t *conf, char *str, size_t size) 23201cb875aeSCathy Zhou { 23211cb875aeSCathy Zhou return (snprintf(str, size, "%d", conf->vvc_pri)); 23221cb875aeSCathy Zhou } 23231cb875aeSCathy Zhou 23241cb875aeSCathy Zhou static int 23251cb875aeSCathy Zhou vrrp_wt_prop_adver_int(vrrp_vr_conf_t *conf, char *str, size_t size) 23261cb875aeSCathy Zhou { 23271cb875aeSCathy Zhou return (snprintf(str, size, "%d", conf->vvc_adver_int)); 23281cb875aeSCathy Zhou } 23291cb875aeSCathy Zhou 23301cb875aeSCathy Zhou static int 23311cb875aeSCathy Zhou vrrp_wt_prop_preempt(vrrp_vr_conf_t *conf, char *str, size_t size) 23321cb875aeSCathy Zhou { 23331cb875aeSCathy Zhou return (snprintf(str, size, "%s", 23341cb875aeSCathy Zhou conf->vvc_preempt ? "true" : "false")); 23351cb875aeSCathy Zhou } 23361cb875aeSCathy Zhou 23371cb875aeSCathy Zhou static int 23381cb875aeSCathy Zhou vrrp_wt_prop_accept(vrrp_vr_conf_t *conf, char *str, size_t size) 23391cb875aeSCathy Zhou { 23401cb875aeSCathy Zhou return (snprintf(str, size, "%s", 23411cb875aeSCathy Zhou conf->vvc_accept ? "true" : "false")); 23421cb875aeSCathy Zhou } 23431cb875aeSCathy Zhou 23441cb875aeSCathy Zhou static int 23451cb875aeSCathy Zhou vrrp_wt_prop_enabled(vrrp_vr_conf_t *conf, char *str, size_t size) 23461cb875aeSCathy Zhou { 23471cb875aeSCathy Zhou return (snprintf(str, size, "%s", 23481cb875aeSCathy Zhou conf->vvc_enabled ? "enabled" : "disabled")); 23491cb875aeSCathy Zhou } 23501cb875aeSCathy Zhou 23511cb875aeSCathy Zhou static int 23521cb875aeSCathy Zhou vrrp_wt_prop_vrid(vrrp_vr_conf_t *conf, char *str, size_t size) 23531cb875aeSCathy Zhou { 23541cb875aeSCathy Zhou return (snprintf(str, size, "%d", conf->vvc_vrid)); 23551cb875aeSCathy Zhou } 23561cb875aeSCathy Zhou 23571cb875aeSCathy Zhou static int 23581cb875aeSCathy Zhou vrrp_wt_prop_af(vrrp_vr_conf_t *conf, char *str, size_t size) 23591cb875aeSCathy Zhou { 23601cb875aeSCathy Zhou return (snprintf(str, size, "%s", 23611cb875aeSCathy Zhou conf->vvc_af == AF_INET ? "AF_INET" : "AF_INET6")); 23621cb875aeSCathy Zhou } 23631cb875aeSCathy Zhou 23641cb875aeSCathy Zhou static int 23651cb875aeSCathy Zhou vrrp_wt_prop_ifname(vrrp_vr_conf_t *conf, char *str, size_t size) 23661cb875aeSCathy Zhou { 23671cb875aeSCathy Zhou return (snprintf(str, size, "%s", conf->vvc_link)); 23681cb875aeSCathy Zhou } 23691cb875aeSCathy Zhou 23701cb875aeSCathy Zhou static char * 23711cb875aeSCathy Zhou af_str(int af) 23721cb875aeSCathy Zhou { 23731cb875aeSCathy Zhou if (af == 4 || af == AF_INET) 23741cb875aeSCathy Zhou return ("AF_INET"); 23751cb875aeSCathy Zhou else if (af == 6 || af == AF_INET6) 23761cb875aeSCathy Zhou return ("AF_INET6"); 23771cb875aeSCathy Zhou else if (af == AF_UNSPEC) 23781cb875aeSCathy Zhou return ("AF_UNSPEC"); 23791cb875aeSCathy Zhou else 23801cb875aeSCathy Zhou return ("AF_error"); 23811cb875aeSCathy Zhou } 23821cb875aeSCathy Zhou 23831cb875aeSCathy Zhou static vrrp_err_t 23841cb875aeSCathy Zhou vrrpd_create_vr(vrrp_vr_conf_t *conf) 23851cb875aeSCathy Zhou { 23861cb875aeSCathy Zhou vrrp_vr_t *vr; 23871cb875aeSCathy Zhou 23881cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_create_vr(%s)", conf->vvc_name); 23891cb875aeSCathy Zhou 23901cb875aeSCathy Zhou if ((vr = malloc(sizeof (vrrp_vr_t))) == NULL) { 23911cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_create_vr(): memory allocation for %s" 23921cb875aeSCathy Zhou " failed", conf->vvc_name); 23931cb875aeSCathy Zhou return (VRRP_ENOMEM); 23941cb875aeSCathy Zhou } 23951cb875aeSCathy Zhou 23961cb875aeSCathy Zhou bzero(vr, sizeof (vrrp_vr_t)); 23971cb875aeSCathy Zhou vr->vvr_state = VRRP_STATE_NONE; 23981cb875aeSCathy Zhou vr->vvr_timer_id = -1; 23991cb875aeSCathy Zhou vrrpd_state_trans(VRRP_STATE_NONE, VRRP_STATE_INIT, vr); 24001cb875aeSCathy Zhou (void) memcpy(&vr->vvr_conf, conf, sizeof (vrrp_vr_conf_t)); 24011cb875aeSCathy Zhou vr->vvr_conf.vvc_enabled = _B_FALSE; 24021cb875aeSCathy Zhou TAILQ_INSERT_HEAD(&vrrp_vr_list, vr, vvr_next); 24031cb875aeSCathy Zhou return (VRRP_SUCCESS); 24041cb875aeSCathy Zhou } 24051cb875aeSCathy Zhou 24061cb875aeSCathy Zhou static void 24071cb875aeSCathy Zhou vrrpd_delete_vr(vrrp_vr_t *vr) 24081cb875aeSCathy Zhou { 24091cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_delete_vr(%s)", vr->vvr_conf.vvc_name); 24101cb875aeSCathy Zhou if (vr->vvr_conf.vvc_enabled) 24111cb875aeSCathy Zhou vrrpd_disable_vr(vr, NULL, _B_FALSE); 24121cb875aeSCathy Zhou assert(vr->vvr_state == VRRP_STATE_INIT); 24131cb875aeSCathy Zhou vrrpd_state_trans(VRRP_STATE_INIT, VRRP_STATE_NONE, vr); 24141cb875aeSCathy Zhou TAILQ_REMOVE(&vrrp_vr_list, vr, vvr_next); 24151cb875aeSCathy Zhou (void) free(vr); 24161cb875aeSCathy Zhou } 24171cb875aeSCathy Zhou 24181cb875aeSCathy Zhou static vrrp_err_t 24191cb875aeSCathy Zhou vrrpd_enable_vr(vrrp_vr_t *vr) 24201cb875aeSCathy Zhou { 24211cb875aeSCathy Zhou vrrp_err_t rx_err, tx_err, err = VRRP_EINVAL; 24221cb875aeSCathy Zhou 24231cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_enable_vr(%s)", vr->vvr_conf.vvc_name); 24241cb875aeSCathy Zhou 24251cb875aeSCathy Zhou assert(vr->vvr_conf.vvc_enabled); 24261cb875aeSCathy Zhou 24271cb875aeSCathy Zhou /* 24281cb875aeSCathy Zhou * This VRRP router has been successfully enabled and start 24291cb875aeSCathy Zhou * participating. 24301cb875aeSCathy Zhou */ 24311cb875aeSCathy Zhou if (vr->vvr_state != VRRP_STATE_INIT) 24321cb875aeSCathy Zhou return (VRRP_SUCCESS); 24331cb875aeSCathy Zhou 24341cb875aeSCathy Zhou if ((rx_err = vrrpd_init_rxsock(vr)) == VRRP_SUCCESS) { 24351cb875aeSCathy Zhou /* 24361cb875aeSCathy Zhou * Select the primary IP address. Even if this time 24371cb875aeSCathy Zhou * primary IP selection failed, we will reselect the 24381cb875aeSCathy Zhou * primary IP address when new IP address comes up. 24391cb875aeSCathy Zhou */ 24401cb875aeSCathy Zhou vrrpd_reselect_primary(vr->vvr_pif); 24411cb875aeSCathy Zhou if (vr->vvr_pif->vvi_pip == NULL) { 24421cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_enable_vr(%s): " 24431cb875aeSCathy Zhou "select_primary over %s failed", 24441cb875aeSCathy Zhou vr->vvr_conf.vvc_name, vr->vvr_pif->vvi_ifname); 24451cb875aeSCathy Zhou rx_err = VRRP_ENOPRIM; 24461cb875aeSCathy Zhou } 24471cb875aeSCathy Zhou } 24481cb875aeSCathy Zhou 24491cb875aeSCathy Zhou /* 24501cb875aeSCathy Zhou * Initialize the TX socket used for this vrrp_vr_t to send the 24511cb875aeSCathy Zhou * multicast packets. 24521cb875aeSCathy Zhou */ 24531cb875aeSCathy Zhou tx_err = vrrpd_init_txsock(vr); 24541cb875aeSCathy Zhou 24551cb875aeSCathy Zhou /* 24561cb875aeSCathy Zhou * Only start the state transition if sockets for both RX and TX are 24571cb875aeSCathy Zhou * initialized correctly. 24581cb875aeSCathy Zhou */ 24591cb875aeSCathy Zhou if (rx_err != VRRP_SUCCESS || tx_err != VRRP_SUCCESS) { 24601cb875aeSCathy Zhou /* 24611cb875aeSCathy Zhou * Record the error information for diagnose purpose. 24621cb875aeSCathy Zhou */ 24631cb875aeSCathy Zhou vr->vvr_err = (rx_err == VRRP_SUCCESS) ? tx_err : rx_err; 24641cb875aeSCathy Zhou return (err); 24651cb875aeSCathy Zhou } 24661cb875aeSCathy Zhou 24671cb875aeSCathy Zhou if (vr->vvr_conf.vvc_pri == 255) 24681cb875aeSCathy Zhou err = vrrpd_state_i2m(vr); 24691cb875aeSCathy Zhou else 24701cb875aeSCathy Zhou err = vrrpd_state_i2b(vr); 24711cb875aeSCathy Zhou 24721cb875aeSCathy Zhou if (err != VRRP_SUCCESS) { 24731cb875aeSCathy Zhou vr->vvr_err = err; 24741cb875aeSCathy Zhou vr->vvr_pif->vvi_pip = NULL; 24751cb875aeSCathy Zhou vrrpd_fini_txsock(vr); 24761cb875aeSCathy Zhou vrrpd_fini_rxsock(vr); 24771cb875aeSCathy Zhou } 24781cb875aeSCathy Zhou return (err); 24791cb875aeSCathy Zhou } 24801cb875aeSCathy Zhou 24811cb875aeSCathy Zhou /* 24821cb875aeSCathy Zhou * Given the removed interface, see whether the given VRRP router would 24831cb875aeSCathy Zhou * be affected and stop participating the VRRP protocol. 24841cb875aeSCathy Zhou * 24851cb875aeSCathy Zhou * If intf is NULL, VR disabling request is coming from the admin. 24861cb875aeSCathy Zhou */ 24871cb875aeSCathy Zhou static void 24881cb875aeSCathy Zhou vrrpd_disable_vr(vrrp_vr_t *vr, vrrp_intf_t *intf, boolean_t primary_addr_gone) 24891cb875aeSCathy Zhou { 24901cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_disable_vr(%s): %s%s", vr->vvr_conf.vvc_name, 24911cb875aeSCathy Zhou intf == NULL ? "requested by admin" : intf->vvi_ifname, 24921cb875aeSCathy Zhou intf == NULL ? "" : (primary_addr_gone ? "primary address gone" : 24931cb875aeSCathy Zhou "interface deleted")); 24941cb875aeSCathy Zhou 24951cb875aeSCathy Zhou /* 24961cb875aeSCathy Zhou * An interface is deleted, see whether this interface is the 24971cb875aeSCathy Zhou * physical interface or the VNIC of the given VRRP router. 24981cb875aeSCathy Zhou * If so, continue to disable the VRRP router. 24991cb875aeSCathy Zhou */ 25001cb875aeSCathy Zhou if (!primary_addr_gone && (intf != NULL) && (intf != vr->vvr_pif) && 25011cb875aeSCathy Zhou (intf != vr->vvr_vif)) { 25021cb875aeSCathy Zhou return; 25031cb875aeSCathy Zhou } 25041cb875aeSCathy Zhou 25051cb875aeSCathy Zhou /* 25061cb875aeSCathy Zhou * If this is the case that the primary IP address is gone, 25071cb875aeSCathy Zhou * and we failed to reselect another primary IP address, 25081cb875aeSCathy Zhou * continue to disable the VRRP router. 25091cb875aeSCathy Zhou */ 25101cb875aeSCathy Zhou if (primary_addr_gone && intf != vr->vvr_pif) 25111cb875aeSCathy Zhou return; 25121cb875aeSCathy Zhou 25131cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_disable_vr(%s): disabling", 25141cb875aeSCathy Zhou vr->vvr_conf.vvc_name); 25151cb875aeSCathy Zhou 25161cb875aeSCathy Zhou if (vr->vvr_state == VRRP_STATE_MASTER) { 25171cb875aeSCathy Zhou /* 25181cb875aeSCathy Zhou * If this router is disabled by the administrator, send 25191cb875aeSCathy Zhou * the zero-priority advertisement to indicate the Master 25201cb875aeSCathy Zhou * stops participating VRRP. 25211cb875aeSCathy Zhou */ 25221cb875aeSCathy Zhou if (intf == NULL) 25231cb875aeSCathy Zhou (void) vrrpd_send_adv(vr, _B_TRUE); 25241cb875aeSCathy Zhou 25251cb875aeSCathy Zhou vrrpd_state_m2i(vr); 25261cb875aeSCathy Zhou } else if (vr->vvr_state == VRRP_STATE_BACKUP) { 25271cb875aeSCathy Zhou vrrpd_state_b2i(vr); 25281cb875aeSCathy Zhou } 25291cb875aeSCathy Zhou 25301cb875aeSCathy Zhou /* 25311cb875aeSCathy Zhou * If no primary IP address can be selected, the VRRP router 25321cb875aeSCathy Zhou * stays at the INIT state and will become BACKUP and MASTER when 25331cb875aeSCathy Zhou * a primary IP address is reselected. 25341cb875aeSCathy Zhou */ 25351cb875aeSCathy Zhou if (primary_addr_gone) { 25361cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_disable_vr(%s): primary IP " 25371cb875aeSCathy Zhou "is removed", vr->vvr_conf.vvc_name); 25381cb875aeSCathy Zhou vr->vvr_err = VRRP_ENOPRIM; 25391cb875aeSCathy Zhou } else if (intf == NULL) { 25401cb875aeSCathy Zhou /* 25411cb875aeSCathy Zhou * The VRRP router is disable by the administrator 25421cb875aeSCathy Zhou */ 25431cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_disable_vr(%s): disabled by admin", 25441cb875aeSCathy Zhou vr->vvr_conf.vvc_name); 25451cb875aeSCathy Zhou vr->vvr_err = VRRP_SUCCESS; 25461cb875aeSCathy Zhou vrrpd_fini_txsock(vr); 25471cb875aeSCathy Zhou vrrpd_fini_rxsock(vr); 25481cb875aeSCathy Zhou } else if (intf == vr->vvr_pif) { 25491cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_disable_vr(%s): physical interface " 25501cb875aeSCathy Zhou "%s removed", vr->vvr_conf.vvc_name, intf->vvi_ifname); 25511cb875aeSCathy Zhou vr->vvr_err = VRRP_ENOPRIM; 25521cb875aeSCathy Zhou vrrpd_fini_rxsock(vr); 25531cb875aeSCathy Zhou } else if (intf == vr->vvr_vif) { 25541cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_disable_vr(%s): VNIC interface %s" 25551cb875aeSCathy Zhou " removed", vr->vvr_conf.vvc_name, intf->vvi_ifname); 25561cb875aeSCathy Zhou vr->vvr_err = VRRP_ENOVIRT; 25571cb875aeSCathy Zhou vrrpd_fini_txsock(vr); 25581cb875aeSCathy Zhou } 25591cb875aeSCathy Zhou } 25601cb875aeSCathy Zhou 25611cb875aeSCathy Zhou vrrp_err_t 25621cb875aeSCathy Zhou vrrpd_create(vrrp_vr_conf_t *conf, boolean_t updateconf) 25631cb875aeSCathy Zhou { 25641cb875aeSCathy Zhou vrrp_err_t err = VRRP_SUCCESS; 25651cb875aeSCathy Zhou 25661cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_create(%s, %s, %d)", conf->vvc_name, 25671cb875aeSCathy Zhou conf->vvc_link, conf->vvc_vrid); 25681cb875aeSCathy Zhou 25691cb875aeSCathy Zhou assert(conf != NULL); 25701cb875aeSCathy Zhou 25711cb875aeSCathy Zhou /* 25721cb875aeSCathy Zhou * Sanity check 25731cb875aeSCathy Zhou */ 25741cb875aeSCathy Zhou if ((strlen(conf->vvc_name) == 0) || 25751cb875aeSCathy Zhou (strlen(conf->vvc_link) == 0) || 25761cb875aeSCathy Zhou (conf->vvc_vrid < VRRP_VRID_MIN || 25771cb875aeSCathy Zhou conf->vvc_vrid > VRRP_VRID_MAX) || 25781cb875aeSCathy Zhou (conf->vvc_pri < VRRP_PRI_MIN || 25791cb875aeSCathy Zhou conf->vvc_pri > VRRP_PRI_OWNER) || 25801cb875aeSCathy Zhou (conf->vvc_adver_int < VRRP_MAX_ADVER_INT_MIN || 25811cb875aeSCathy Zhou conf->vvc_adver_int > VRRP_MAX_ADVER_INT_MAX) || 25821cb875aeSCathy Zhou (conf->vvc_af != AF_INET && conf->vvc_af != AF_INET6) || 25831cb875aeSCathy Zhou (conf->vvc_pri == VRRP_PRI_OWNER && !conf->vvc_accept)) { 25841cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_create(%s): invalid argument", 25851cb875aeSCathy Zhou conf->vvc_name); 25861cb875aeSCathy Zhou return (VRRP_EINVAL); 25871cb875aeSCathy Zhou } 25881cb875aeSCathy Zhou 25891cb875aeSCathy Zhou if (!vrrp_valid_name(conf->vvc_name)) { 25901cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_create(): %s is not a valid router " 25911cb875aeSCathy Zhou "name", conf->vvc_name); 25921cb875aeSCathy Zhou return (VRRP_EINVALVRNAME); 25931cb875aeSCathy Zhou } 25941cb875aeSCathy Zhou 25951cb875aeSCathy Zhou if (vrrpd_lookup_vr_by_name(conf->vvc_name) != NULL) { 25961cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_create(): %s already exists", 25971cb875aeSCathy Zhou conf->vvc_name); 25981cb875aeSCathy Zhou return (VRRP_EINSTEXIST); 25991cb875aeSCathy Zhou } 26001cb875aeSCathy Zhou 26011cb875aeSCathy Zhou if (vrrpd_lookup_vr_by_vrid(conf->vvc_link, conf->vvc_vrid, 26021cb875aeSCathy Zhou conf->vvc_af) != NULL) { 26031cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_create(): VRID %d/%s over %s " 26041cb875aeSCathy Zhou "already exists", conf->vvc_vrid, af_str(conf->vvc_af), 26051cb875aeSCathy Zhou conf->vvc_link); 26061cb875aeSCathy Zhou return (VRRP_EVREXIST); 26071cb875aeSCathy Zhou } 26081cb875aeSCathy Zhou 26091cb875aeSCathy Zhou if (updateconf && (err = vrrpd_updateconf(conf, 26101cb875aeSCathy Zhou VRRP_CONF_UPDATE)) != VRRP_SUCCESS) { 26111cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_create(): failed to update " 26121cb875aeSCathy Zhou "configuration for %s", conf->vvc_name); 26131cb875aeSCathy Zhou return (err); 26141cb875aeSCathy Zhou } 26151cb875aeSCathy Zhou 26161cb875aeSCathy Zhou err = vrrpd_create_vr(conf); 26171cb875aeSCathy Zhou if (err != VRRP_SUCCESS && updateconf) 26181cb875aeSCathy Zhou (void) vrrpd_updateconf(conf, VRRP_CONF_DELETE); 26191cb875aeSCathy Zhou 26201cb875aeSCathy Zhou return (err); 26211cb875aeSCathy Zhou } 26221cb875aeSCathy Zhou 26231cb875aeSCathy Zhou static vrrp_err_t 26241cb875aeSCathy Zhou vrrpd_delete(const char *vn) 26251cb875aeSCathy Zhou { 26261cb875aeSCathy Zhou vrrp_vr_t *vr; 26271cb875aeSCathy Zhou vrrp_err_t err; 26281cb875aeSCathy Zhou 26291cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_delete(%s)", vn); 26301cb875aeSCathy Zhou 26311cb875aeSCathy Zhou if ((vr = vrrpd_lookup_vr_by_name(vn)) == NULL) { 26321cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_delete(): %s not exists", vn); 26331cb875aeSCathy Zhou return (VRRP_ENOTFOUND); 26341cb875aeSCathy Zhou } 26351cb875aeSCathy Zhou 26361cb875aeSCathy Zhou err = vrrpd_updateconf(&vr->vvr_conf, VRRP_CONF_DELETE); 26371cb875aeSCathy Zhou if (err != VRRP_SUCCESS) { 26381cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_delete(): failed to delete " 26391cb875aeSCathy Zhou "configuration for %s", vr->vvr_conf.vvc_name); 26401cb875aeSCathy Zhou return (err); 26411cb875aeSCathy Zhou } 26421cb875aeSCathy Zhou 26431cb875aeSCathy Zhou vrrpd_delete_vr(vr); 26441cb875aeSCathy Zhou return (VRRP_SUCCESS); 26451cb875aeSCathy Zhou } 26461cb875aeSCathy Zhou 26471cb875aeSCathy Zhou static vrrp_err_t 26481cb875aeSCathy Zhou vrrpd_enable(const char *vn, boolean_t updateconf) 26491cb875aeSCathy Zhou { 26501cb875aeSCathy Zhou vrrp_vr_t *vr; 26511cb875aeSCathy Zhou vrrp_vr_conf_t *conf; 26521cb875aeSCathy Zhou uint32_t flags; 26531cb875aeSCathy Zhou datalink_class_t class; 26541cb875aeSCathy Zhou vrrp_err_t err = VRRP_SUCCESS; 26551cb875aeSCathy Zhou 26561cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_enable(%s)", vn); 26571cb875aeSCathy Zhou 26581cb875aeSCathy Zhou if ((vr = vrrpd_lookup_vr_by_name(vn)) == NULL) { 26591cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_enable(): %s does not exist", vn); 26601cb875aeSCathy Zhou return (VRRP_ENOTFOUND); 26611cb875aeSCathy Zhou } 26621cb875aeSCathy Zhou 26631cb875aeSCathy Zhou /* 26641cb875aeSCathy Zhou * The VR is already enabled. 26651cb875aeSCathy Zhou */ 26661cb875aeSCathy Zhou conf = &vr->vvr_conf; 26671cb875aeSCathy Zhou if (conf->vvc_enabled) { 26681cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_enable(): %s is already " 26691cb875aeSCathy Zhou "enabled", vn); 26701cb875aeSCathy Zhou return (VRRP_EALREADY); 26711cb875aeSCathy Zhou } 26721cb875aeSCathy Zhou 26731cb875aeSCathy Zhou /* 26741cb875aeSCathy Zhou * Check whether the link exists. 26751cb875aeSCathy Zhou */ 26761cb875aeSCathy Zhou if ((strlen(conf->vvc_link) == 0) || dladm_name2info(vrrpd_vh->vh_dh, 26771cb875aeSCathy Zhou conf->vvc_link, NULL, &flags, &class, NULL) != DLADM_STATUS_OK || 26781cb875aeSCathy Zhou !(flags & DLADM_OPT_ACTIVE) || ((class != DATALINK_CLASS_PHYS) && 2679*2954adb0SRob Gulewich (class != DATALINK_CLASS_VLAN) && (class != DATALINK_CLASS_AGGR) && 2680*2954adb0SRob Gulewich (class != DATALINK_CLASS_VNIC))) { 26811cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_enable(%s): invalid link %s", 26821cb875aeSCathy Zhou vn, conf->vvc_link); 26831cb875aeSCathy Zhou return (VRRP_EINVALLINK); 26841cb875aeSCathy Zhou } 26851cb875aeSCathy Zhou 26861cb875aeSCathy Zhou /* 26871cb875aeSCathy Zhou * Get the associated VNIC name by the given interface/vrid/ 26881cb875aeSCathy Zhou * address famitly. 26891cb875aeSCathy Zhou */ 26901cb875aeSCathy Zhou err = vrrp_get_vnicname(vrrpd_vh, conf->vvc_vrid, 26911cb875aeSCathy Zhou conf->vvc_af, conf->vvc_link, NULL, NULL, vr->vvr_vnic, 26921cb875aeSCathy Zhou sizeof (vr->vvr_vnic)); 26931cb875aeSCathy Zhou if (err != VRRP_SUCCESS) { 26941cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_enable(%s): no VNIC for VRID %d/%s " 26951cb875aeSCathy Zhou "over %s", vn, conf->vvc_vrid, af_str(conf->vvc_af), 26961cb875aeSCathy Zhou conf->vvc_link); 26971cb875aeSCathy Zhou err = VRRP_ENOVNIC; 26981cb875aeSCathy Zhou goto fail; 26991cb875aeSCathy Zhou } 27001cb875aeSCathy Zhou 27011cb875aeSCathy Zhou /* 27021cb875aeSCathy Zhou * Find the right VNIC, primary interface and get the list of the 27031cb875aeSCathy Zhou * protected IP adressses and primary IP address. Note that if 27041cb875aeSCathy Zhou * either interface is NULL (no IP addresses configured over the 27051cb875aeSCathy Zhou * interface), we will still continue and mark this VRRP router 27061cb875aeSCathy Zhou * as "enabled". 27071cb875aeSCathy Zhou */ 27081cb875aeSCathy Zhou vr->vvr_conf.vvc_enabled = _B_TRUE; 27091cb875aeSCathy Zhou if (updateconf && (err = vrrpd_updateconf(&vr->vvr_conf, 27101cb875aeSCathy Zhou VRRP_CONF_UPDATE)) != VRRP_SUCCESS) { 27111cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_enable(): failed to update " 27121cb875aeSCathy Zhou "configuration for %s", vr->vvr_conf.vvc_name); 27131cb875aeSCathy Zhou goto fail; 27141cb875aeSCathy Zhou } 27151cb875aeSCathy Zhou 27161cb875aeSCathy Zhou /* 27171cb875aeSCathy Zhou * If vrrpd_setup_vr() fails, it is possible that there is no IP 27181cb875aeSCathy Zhou * addresses over ether the primary interface or the VNIC yet, 27191cb875aeSCathy Zhou * return success in this case, the VRRP router will stay in 27201cb875aeSCathy Zhou * the initialized state and start to work when the IP address is 27211cb875aeSCathy Zhou * configured. 27221cb875aeSCathy Zhou */ 27231cb875aeSCathy Zhou (void) vrrpd_enable_vr(vr); 27241cb875aeSCathy Zhou return (VRRP_SUCCESS); 27251cb875aeSCathy Zhou 27261cb875aeSCathy Zhou fail: 27271cb875aeSCathy Zhou vr->vvr_conf.vvc_enabled = _B_FALSE; 27281cb875aeSCathy Zhou vr->vvr_vnic[0] = '\0'; 27291cb875aeSCathy Zhou return (err); 27301cb875aeSCathy Zhou } 27311cb875aeSCathy Zhou 27321cb875aeSCathy Zhou static vrrp_err_t 27331cb875aeSCathy Zhou vrrpd_disable(const char *vn) 27341cb875aeSCathy Zhou { 27351cb875aeSCathy Zhou vrrp_vr_t *vr; 27361cb875aeSCathy Zhou vrrp_err_t err; 27371cb875aeSCathy Zhou 27381cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_disable(%s)", vn); 27391cb875aeSCathy Zhou 27401cb875aeSCathy Zhou if ((vr = vrrpd_lookup_vr_by_name(vn)) == NULL) { 27411cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_disable(): %s does not exist", vn); 27421cb875aeSCathy Zhou return (VRRP_ENOTFOUND); 27431cb875aeSCathy Zhou } 27441cb875aeSCathy Zhou 27451cb875aeSCathy Zhou /* 27461cb875aeSCathy Zhou * The VR is already disable. 27471cb875aeSCathy Zhou */ 27481cb875aeSCathy Zhou if (!vr->vvr_conf.vvc_enabled) { 27491cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_disable(): %s was not enabled", vn); 27501cb875aeSCathy Zhou return (VRRP_EALREADY); 27511cb875aeSCathy Zhou } 27521cb875aeSCathy Zhou 27531cb875aeSCathy Zhou vr->vvr_conf.vvc_enabled = _B_FALSE; 27541cb875aeSCathy Zhou err = vrrpd_updateconf(&vr->vvr_conf, VRRP_CONF_UPDATE); 27551cb875aeSCathy Zhou if (err != VRRP_SUCCESS) { 27561cb875aeSCathy Zhou vr->vvr_conf.vvc_enabled = _B_TRUE; 27571cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_disable(): failed to update " 27581cb875aeSCathy Zhou "configuration for %s", vr->vvr_conf.vvc_name); 27591cb875aeSCathy Zhou return (err); 27601cb875aeSCathy Zhou } 27611cb875aeSCathy Zhou 27621cb875aeSCathy Zhou vrrpd_disable_vr(vr, NULL, _B_FALSE); 27631cb875aeSCathy Zhou vr->vvr_vnic[0] = '\0'; 27641cb875aeSCathy Zhou return (VRRP_SUCCESS); 27651cb875aeSCathy Zhou } 27661cb875aeSCathy Zhou 27671cb875aeSCathy Zhou static vrrp_err_t 27681cb875aeSCathy Zhou vrrpd_modify(vrrp_vr_conf_t *conf, uint32_t mask) 27691cb875aeSCathy Zhou { 27701cb875aeSCathy Zhou vrrp_vr_t *vr; 27711cb875aeSCathy Zhou vrrp_vr_conf_t savconf; 27721cb875aeSCathy Zhou int pri; 27731cb875aeSCathy Zhou boolean_t accept, set_accept = _B_FALSE; 27741cb875aeSCathy Zhou vrrp_err_t err; 27751cb875aeSCathy Zhou 27761cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_modify(%s)", conf->vvc_name); 27771cb875aeSCathy Zhou 27781cb875aeSCathy Zhou if (mask == 0) 27791cb875aeSCathy Zhou return (VRRP_SUCCESS); 27801cb875aeSCathy Zhou 27811cb875aeSCathy Zhou if ((vr = vrrpd_lookup_vr_by_name(conf->vvc_name)) == NULL) { 27821cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_modify(): cannot find the given " 27831cb875aeSCathy Zhou "VR instance: %s", conf->vvc_name); 27841cb875aeSCathy Zhou return (VRRP_ENOTFOUND); 27851cb875aeSCathy Zhou } 27861cb875aeSCathy Zhou 27871cb875aeSCathy Zhou if (mask & VRRP_CONF_INTERVAL) { 27881cb875aeSCathy Zhou if (conf->vvc_adver_int < VRRP_MAX_ADVER_INT_MIN || 27891cb875aeSCathy Zhou conf->vvc_adver_int > VRRP_MAX_ADVER_INT_MAX) { 27901cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_modify(%s): invalid " 27911cb875aeSCathy Zhou "adver_interval %d", conf->vvc_name, 27921cb875aeSCathy Zhou conf->vvc_adver_int); 27931cb875aeSCathy Zhou return (VRRP_EINVAL); 27941cb875aeSCathy Zhou } 27951cb875aeSCathy Zhou } 27961cb875aeSCathy Zhou 27971cb875aeSCathy Zhou pri = vr->vvr_conf.vvc_pri; 27981cb875aeSCathy Zhou if (mask & VRRP_CONF_PRIORITY) { 27991cb875aeSCathy Zhou if (conf->vvc_pri < VRRP_PRI_MIN || 28001cb875aeSCathy Zhou conf->vvc_pri > VRRP_PRI_OWNER) { 28011cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_modify(%s): invalid " 28021cb875aeSCathy Zhou "priority %d", conf->vvc_name, conf->vvc_pri); 28031cb875aeSCathy Zhou return (VRRP_EINVAL); 28041cb875aeSCathy Zhou } 28051cb875aeSCathy Zhou pri = conf->vvc_pri; 28061cb875aeSCathy Zhou } 28071cb875aeSCathy Zhou 28081cb875aeSCathy Zhou accept = vr->vvr_conf.vvc_accept; 28091cb875aeSCathy Zhou if (mask & VRRP_CONF_ACCEPT) 28101cb875aeSCathy Zhou accept = conf->vvc_accept; 28111cb875aeSCathy Zhou 28121cb875aeSCathy Zhou if (pri == VRRP_PRI_OWNER && !accept) { 28131cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_modify(%s): accept mode must be " 28141cb875aeSCathy Zhou "true for VRRP address owner", conf->vvc_name); 28151cb875aeSCathy Zhou return (VRRP_EINVAL); 28161cb875aeSCathy Zhou } 28171cb875aeSCathy Zhou 28181cb875aeSCathy Zhou if ((mask & VRRP_CONF_ACCEPT) && (vr->vvr_conf.vvc_accept != accept)) { 28191cb875aeSCathy Zhou err = vrrpd_set_noaccept(vr, !accept); 28201cb875aeSCathy Zhou if (err != VRRP_SUCCESS) { 28211cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_modify(%s): access mode " 28221cb875aeSCathy Zhou "updating failed: %s", conf->vvc_name, 28231cb875aeSCathy Zhou vrrp_err2str(err)); 28241cb875aeSCathy Zhou return (err); 28251cb875aeSCathy Zhou } 28261cb875aeSCathy Zhou set_accept = _B_TRUE; 28271cb875aeSCathy Zhou } 28281cb875aeSCathy Zhou 28291cb875aeSCathy Zhou /* 28301cb875aeSCathy Zhou * Save the current configuration, so it can be restored if the 28311cb875aeSCathy Zhou * following fails. 28321cb875aeSCathy Zhou */ 28331cb875aeSCathy Zhou (void) memcpy(&savconf, &vr->vvr_conf, sizeof (vrrp_vr_conf_t)); 28341cb875aeSCathy Zhou if (mask & VRRP_CONF_PREEMPT) 28351cb875aeSCathy Zhou vr->vvr_conf.vvc_preempt = conf->vvc_preempt; 28361cb875aeSCathy Zhou 28371cb875aeSCathy Zhou if (mask & VRRP_CONF_ACCEPT) 28381cb875aeSCathy Zhou vr->vvr_conf.vvc_accept = accept; 28391cb875aeSCathy Zhou 28401cb875aeSCathy Zhou if (mask & VRRP_CONF_PRIORITY) 28411cb875aeSCathy Zhou vr->vvr_conf.vvc_pri = pri; 28421cb875aeSCathy Zhou 28431cb875aeSCathy Zhou if (mask & VRRP_CONF_INTERVAL) 28441cb875aeSCathy Zhou vr->vvr_conf.vvc_adver_int = conf->vvc_adver_int; 28451cb875aeSCathy Zhou 28461cb875aeSCathy Zhou err = vrrpd_updateconf(&vr->vvr_conf, VRRP_CONF_UPDATE); 28471cb875aeSCathy Zhou if (err != VRRP_SUCCESS) { 28481cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_modify(%s): configuration update " 28491cb875aeSCathy Zhou "failed: %s", conf->vvc_name, vrrp_err2str(err)); 28501cb875aeSCathy Zhou if (set_accept) 28511cb875aeSCathy Zhou (void) vrrpd_set_noaccept(vr, accept); 28521cb875aeSCathy Zhou (void) memcpy(&vr->vvr_conf, &savconf, sizeof (vrrp_vr_conf_t)); 28531cb875aeSCathy Zhou return (err); 28541cb875aeSCathy Zhou } 28551cb875aeSCathy Zhou 28561cb875aeSCathy Zhou if ((mask & VRRP_CONF_PRIORITY) && (vr->vvr_state == VRRP_STATE_BACKUP)) 28571cb875aeSCathy Zhou vr->vvr_timeout = MASTER_DOWN_INTERVAL_VR(vr); 28581cb875aeSCathy Zhou 28591cb875aeSCathy Zhou if ((mask & VRRP_CONF_INTERVAL) && (vr->vvr_state == VRRP_STATE_MASTER)) 28601cb875aeSCathy Zhou vr->vvr_timeout = conf->vvc_adver_int; 28611cb875aeSCathy Zhou 28621cb875aeSCathy Zhou return (VRRP_SUCCESS); 28631cb875aeSCathy Zhou } 28641cb875aeSCathy Zhou 28651cb875aeSCathy Zhou static void 28661cb875aeSCathy Zhou vrrpd_list(vrid_t vrid, char *ifname, int af, vrrp_ret_list_t *ret, 28671cb875aeSCathy Zhou size_t *sizep) 28681cb875aeSCathy Zhou { 28691cb875aeSCathy Zhou vrrp_vr_t *vr; 28701cb875aeSCathy Zhou char *p = (char *)ret + sizeof (vrrp_ret_list_t); 28711cb875aeSCathy Zhou size_t size = (*sizep) - sizeof (vrrp_ret_list_t); 28721cb875aeSCathy Zhou 28731cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_list(%d_%s_%s)", vrid, ifname, af_str(af)); 28741cb875aeSCathy Zhou 28751cb875aeSCathy Zhou ret->vrl_cnt = 0; 28761cb875aeSCathy Zhou TAILQ_FOREACH(vr, &vrrp_vr_list, vvr_next) { 28771cb875aeSCathy Zhou if (vrid != VRRP_VRID_NONE && vr->vvr_conf.vvc_vrid != vrid) 28781cb875aeSCathy Zhou continue; 28791cb875aeSCathy Zhou 28801cb875aeSCathy Zhou if (strlen(ifname) != 0 && strcmp(ifname, 28811cb875aeSCathy Zhou vr->vvr_conf.vvc_link) == 0) { 28821cb875aeSCathy Zhou continue; 28831cb875aeSCathy Zhou } 28841cb875aeSCathy Zhou 28851cb875aeSCathy Zhou if ((af == AF_INET || af == AF_INET6) && 28861cb875aeSCathy Zhou vr->vvr_conf.vvc_af != af) 28871cb875aeSCathy Zhou continue; 28881cb875aeSCathy Zhou 28891cb875aeSCathy Zhou if (size < VRRP_NAME_MAX) { 28901cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_list(): buffer size too " 28911cb875aeSCathy Zhou "small to hold %d router names", ret->vrl_cnt); 28921cb875aeSCathy Zhou *sizep = sizeof (vrrp_ret_list_t); 28931cb875aeSCathy Zhou ret->vrl_err = VRRP_ETOOSMALL; 28941cb875aeSCathy Zhou return; 28951cb875aeSCathy Zhou } 28961cb875aeSCathy Zhou (void) strlcpy(p, vr->vvr_conf.vvc_name, VRRP_NAME_MAX); 28971cb875aeSCathy Zhou p += (strlen(vr->vvr_conf.vvc_name) + 1); 28981cb875aeSCathy Zhou ret->vrl_cnt++; 28991cb875aeSCathy Zhou size -= VRRP_NAME_MAX; 29001cb875aeSCathy Zhou } 29011cb875aeSCathy Zhou 29021cb875aeSCathy Zhou *sizep = sizeof (vrrp_ret_list_t) + ret->vrl_cnt * VRRP_NAME_MAX; 29031cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_list() return %d", ret->vrl_cnt); 29041cb875aeSCathy Zhou ret->vrl_err = VRRP_SUCCESS; 29051cb875aeSCathy Zhou } 29061cb875aeSCathy Zhou 29071cb875aeSCathy Zhou static void 29081cb875aeSCathy Zhou vrrpd_query(const char *vn, vrrp_ret_query_t *ret, size_t *sizep) 29091cb875aeSCathy Zhou { 29101cb875aeSCathy Zhou vrrp_queryinfo_t *infop; 29111cb875aeSCathy Zhou vrrp_vr_t *vr; 29121cb875aeSCathy Zhou vrrp_intf_t *vif; 29131cb875aeSCathy Zhou vrrp_ip_t *ip; 29141cb875aeSCathy Zhou struct timeval now; 29151cb875aeSCathy Zhou uint32_t vipcnt = 0; 29161cb875aeSCathy Zhou size_t size = *sizep; 29171cb875aeSCathy Zhou 29181cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_query(%s)", vn); 29191cb875aeSCathy Zhou 29201cb875aeSCathy Zhou if ((vr = vrrpd_lookup_vr_by_name(vn)) == NULL) { 29211cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_query(): %s does not exist", vn); 29221cb875aeSCathy Zhou *sizep = sizeof (vrrp_ret_query_t); 29231cb875aeSCathy Zhou ret->vrq_err = VRRP_ENOTFOUND; 29241cb875aeSCathy Zhou return; 29251cb875aeSCathy Zhou } 29261cb875aeSCathy Zhou 29271cb875aeSCathy Zhou /* 29281cb875aeSCathy Zhou * Get the virtual IP list if the router is not in the INIT state. 29291cb875aeSCathy Zhou */ 29301cb875aeSCathy Zhou if (vr->vvr_state != VRRP_STATE_INIT) { 29311cb875aeSCathy Zhou vif = vr->vvr_vif; 29321cb875aeSCathy Zhou TAILQ_FOREACH(ip, &vif->vvi_iplist, vip_next) { 29331cb875aeSCathy Zhou vipcnt++; 29341cb875aeSCathy Zhou } 29351cb875aeSCathy Zhou } 29361cb875aeSCathy Zhou 29371cb875aeSCathy Zhou *sizep = sizeof (vrrp_ret_query_t); 29381cb875aeSCathy Zhou *sizep += (vipcnt == 0) ? 0 : (vipcnt - 1) * sizeof (vrrp_addr_t); 29391cb875aeSCathy Zhou if (*sizep > size) { 29401cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_query(): not enough space to hold " 29411cb875aeSCathy Zhou "%d virtual IPs", vipcnt); 29421cb875aeSCathy Zhou *sizep = sizeof (vrrp_ret_query_t); 29431cb875aeSCathy Zhou ret->vrq_err = VRRP_ETOOSMALL; 29441cb875aeSCathy Zhou return; 29451cb875aeSCathy Zhou } 29461cb875aeSCathy Zhou 29471cb875aeSCathy Zhou (void) gettimeofday(&now, NULL); 29481cb875aeSCathy Zhou 29491cb875aeSCathy Zhou bzero(ret, *sizep); 29501cb875aeSCathy Zhou infop = &ret->vrq_qinfo; 29511cb875aeSCathy Zhou (void) memcpy(&infop->show_vi, 29521cb875aeSCathy Zhou &(vr->vvr_conf), sizeof (vrrp_vr_conf_t)); 29531cb875aeSCathy Zhou (void) memcpy(&infop->show_vs, 29541cb875aeSCathy Zhou &(vr->vvr_sinfo), sizeof (vrrp_stateinfo_t)); 29551cb875aeSCathy Zhou (void) strlcpy(infop->show_va.va_vnic, vr->vvr_vnic, MAXLINKNAMELEN); 29561cb875aeSCathy Zhou infop->show_vt.vt_since_last_tran = timeval_to_milli( 29571cb875aeSCathy Zhou timeval_delta(now, vr->vvr_sinfo.vs_st_time)); 29581cb875aeSCathy Zhou 29591cb875aeSCathy Zhou if (vr->vvr_state == VRRP_STATE_INIT) { 29601cb875aeSCathy Zhou ret->vrq_err = VRRP_SUCCESS; 29611cb875aeSCathy Zhou return; 29621cb875aeSCathy Zhou } 29631cb875aeSCathy Zhou 29641cb875aeSCathy Zhou vipcnt = 0; 29651cb875aeSCathy Zhou TAILQ_FOREACH(ip, &vif->vvi_iplist, vip_next) { 29661cb875aeSCathy Zhou (void) memcpy(&infop->show_va.va_vips[vipcnt++], 29671cb875aeSCathy Zhou &ip->vip_addr, sizeof (vrrp_addr_t)); 29681cb875aeSCathy Zhou } 29691cb875aeSCathy Zhou infop->show_va.va_vipcnt = vipcnt; 29701cb875aeSCathy Zhou 29711cb875aeSCathy Zhou (void) memcpy(&infop->show_va.va_primary, 29721cb875aeSCathy Zhou &vr->vvr_pif->vvi_pip->vip_addr, sizeof (vrrp_addr_t)); 29731cb875aeSCathy Zhou 29741cb875aeSCathy Zhou (void) memcpy(&infop->show_vp, &(vr->vvr_peer), sizeof (vrrp_peer_t)); 29751cb875aeSCathy Zhou 29761cb875aeSCathy Zhou /* 29771cb875aeSCathy Zhou * Check whether there is a peer. 29781cb875aeSCathy Zhou */ 29791cb875aeSCathy Zhou if (!VRRPADDR_UNSPECIFIED(vr->vvr_conf.vvc_af, 29801cb875aeSCathy Zhou &(vr->vvr_peer.vp_addr))) { 29811cb875aeSCathy Zhou infop->show_vt.vt_since_last_adv = timeval_to_milli( 29821cb875aeSCathy Zhou timeval_delta(now, vr->vvr_peer.vp_time)); 29831cb875aeSCathy Zhou } 29841cb875aeSCathy Zhou 29851cb875aeSCathy Zhou if (vr->vvr_state == VRRP_STATE_BACKUP) { 29861cb875aeSCathy Zhou infop->show_vt.vt_master_down_intv = 29871cb875aeSCathy Zhou MASTER_DOWN_INTERVAL_VR(vr); 29881cb875aeSCathy Zhou } 29891cb875aeSCathy Zhou 29901cb875aeSCathy Zhou ret->vrq_err = VRRP_SUCCESS; 29911cb875aeSCathy Zhou } 29921cb875aeSCathy Zhou 29931cb875aeSCathy Zhou /* 29941cb875aeSCathy Zhou * Build the VRRP packet (not including the IP header). Return the 29951cb875aeSCathy Zhou * payload length. 29961cb875aeSCathy Zhou * 29971cb875aeSCathy Zhou * If zero_pri is set to be B_TRUE, then this is the specical zero-priority 29981cb875aeSCathy Zhou * advertisement which is sent by the Master to indicate that it has been 29991cb875aeSCathy Zhou * stopped participating in VRRP. 30001cb875aeSCathy Zhou */ 30011cb875aeSCathy Zhou static size_t 30021cb875aeSCathy Zhou vrrpd_build_vrrp(vrrp_vr_t *vr, uchar_t *buf, int buflen, boolean_t zero_pri) 30031cb875aeSCathy Zhou { 30041cb875aeSCathy Zhou /* LINTED E_BAD_PTR_CAST_ALIGN */ 30051cb875aeSCathy Zhou vrrp_pkt_t *vp = (vrrp_pkt_t *)buf; 30061cb875aeSCathy Zhou /* LINTED E_BAD_PTR_CAST_ALIGN */ 30071cb875aeSCathy Zhou struct in_addr *a4 = (struct in_addr *)(vp + 1); 30081cb875aeSCathy Zhou /* LINTED E_BAD_PTR_CAST_ALIGN */ 30091cb875aeSCathy Zhou struct in6_addr *a6 = (struct in6_addr *)(vp + 1); 30101cb875aeSCathy Zhou vrrp_intf_t *vif = vr->vvr_vif; 30111cb875aeSCathy Zhou vrrp_ip_t *vip; 30121cb875aeSCathy Zhou int af = vif->vvi_af; 30131cb875aeSCathy Zhou size_t size = sizeof (vrrp_pkt_t); 30141cb875aeSCathy Zhou uint16_t rsvd_adver_int; 30151cb875aeSCathy Zhou int nip = 0; 30161cb875aeSCathy Zhou 30171cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_build_vrrp(%s, %s_priority): intv %d", 30181cb875aeSCathy Zhou vr->vvr_conf.vvc_name, zero_pri ? "zero" : "non-zero", 30191cb875aeSCathy Zhou vr->vvr_conf.vvc_adver_int); 30201cb875aeSCathy Zhou 30211cb875aeSCathy Zhou TAILQ_FOREACH(vip, &vif->vvi_iplist, vip_next) { 30221cb875aeSCathy Zhou if ((size += ((af == AF_INET) ? sizeof (struct in_addr) : 30231cb875aeSCathy Zhou sizeof (struct in6_addr))) > buflen) { 30241cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_build_vrrp(%s): buffer size " 30251cb875aeSCathy Zhou "not big enough %d", vr->vvr_conf.vvc_name, size); 30261cb875aeSCathy Zhou return (0); 30271cb875aeSCathy Zhou } 30281cb875aeSCathy Zhou 30291cb875aeSCathy Zhou if (af == AF_INET) 30301cb875aeSCathy Zhou a4[nip++] = vip->vip_addr.in4.sin_addr; 30311cb875aeSCathy Zhou else 30321cb875aeSCathy Zhou a6[nip++] = vip->vip_addr.in6.sin6_addr; 30331cb875aeSCathy Zhou } 30341cb875aeSCathy Zhou 30351cb875aeSCathy Zhou if (nip == 0) { 30361cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_build_vrrp(%s): no virtual IP " 30371cb875aeSCathy Zhou "address", vr->vvr_conf.vvc_name); 30381cb875aeSCathy Zhou return (0); 30391cb875aeSCathy Zhou } 30401cb875aeSCathy Zhou 30411cb875aeSCathy Zhou vp->vp_vers_type = (VRRP_VERSION << 4) | VRRP_PKT_ADVERT; 30421cb875aeSCathy Zhou vp->vp_vrid = vr->vvr_conf.vvc_vrid; 30431cb875aeSCathy Zhou vp->vp_prio = zero_pri ? VRRP_PRIO_ZERO : vr->vvr_conf.vvc_pri; 30441cb875aeSCathy Zhou 30451cb875aeSCathy Zhou rsvd_adver_int = MSEC2CENTISEC(vr->vvr_conf.vvc_adver_int) & 0x0fff; 30461cb875aeSCathy Zhou vp->vp_rsvd_adver_int = htons(rsvd_adver_int); 30471cb875aeSCathy Zhou vp->vp_ipnum = nip; 30481cb875aeSCathy Zhou 30491cb875aeSCathy Zhou /* 30501cb875aeSCathy Zhou * Set the checksum to 0 first, then caculate it. 30511cb875aeSCathy Zhou */ 30521cb875aeSCathy Zhou vp->vp_chksum = 0; 30531cb875aeSCathy Zhou if (af == AF_INET) { 30541cb875aeSCathy Zhou vp->vp_chksum = vrrp_cksum4( 30551cb875aeSCathy Zhou &vr->vvr_pif->vvi_pip->vip_addr.in4.sin_addr, 30561cb875aeSCathy Zhou &vrrp_muladdr4.in4.sin_addr, size, vp); 30571cb875aeSCathy Zhou } else { 30581cb875aeSCathy Zhou vp->vp_chksum = vrrp_cksum6( 30591cb875aeSCathy Zhou &vr->vvr_pif->vvi_pip->vip_addr.in6.sin6_addr, 30601cb875aeSCathy Zhou &vrrp_muladdr6.in6.sin6_addr, size, vp); 30611cb875aeSCathy Zhou } 30621cb875aeSCathy Zhou 30631cb875aeSCathy Zhou return (size); 30641cb875aeSCathy Zhou } 30651cb875aeSCathy Zhou 30661cb875aeSCathy Zhou /* 30671cb875aeSCathy Zhou * We need to build the IPv4 header on our own. 30681cb875aeSCathy Zhou */ 30691cb875aeSCathy Zhou static vrrp_err_t 30701cb875aeSCathy Zhou vrrpd_send_adv_v4(vrrp_vr_t *vr, uchar_t *buf, size_t len, boolean_t zero_pri) 30711cb875aeSCathy Zhou { 30721cb875aeSCathy Zhou /* LINTED E_BAD_PTR_CAST_ALIGN */ 30731cb875aeSCathy Zhou struct ip *ip = (struct ip *)buf; 30741cb875aeSCathy Zhou size_t plen; 30751cb875aeSCathy Zhou 30761cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_send_adv_v4(%s)", vr->vvr_conf.vvc_name); 30771cb875aeSCathy Zhou 30781cb875aeSCathy Zhou if ((plen = vrrpd_build_vrrp(vr, buf + sizeof (struct ip), 30791cb875aeSCathy Zhou len - sizeof (struct ip), zero_pri)) == 0) { 30801cb875aeSCathy Zhou return (VRRP_ETOOSMALL); 30811cb875aeSCathy Zhou } 30821cb875aeSCathy Zhou 30831cb875aeSCathy Zhou ip->ip_hl = sizeof (struct ip) >> 2; 30841cb875aeSCathy Zhou ip->ip_v = IPV4_VERSION; 30851cb875aeSCathy Zhou ip->ip_tos = 0; 30861cb875aeSCathy Zhou plen += sizeof (struct ip); 30871cb875aeSCathy Zhou ip->ip_len = htons(plen); 30881cb875aeSCathy Zhou ip->ip_off = 0; 30891cb875aeSCathy Zhou ip->ip_ttl = VRRP_IP_TTL; 30901cb875aeSCathy Zhou ip->ip_p = IPPROTO_VRRP; 30911cb875aeSCathy Zhou ip->ip_src = vr->vvr_pif->vvi_pip->vip_addr.in4.sin_addr; 30921cb875aeSCathy Zhou ip->ip_dst = vrrp_muladdr4.in4.sin_addr; 30931cb875aeSCathy Zhou 30941cb875aeSCathy Zhou /* 30951cb875aeSCathy Zhou * The kernel will set the IP cksum and the IPv4 identification. 30961cb875aeSCathy Zhou */ 30971cb875aeSCathy Zhou ip->ip_id = 0; 30981cb875aeSCathy Zhou ip->ip_sum = 0; 30991cb875aeSCathy Zhou 31001cb875aeSCathy Zhou if ((len = sendto(vr->vvr_vif->vvi_sockfd, buf, plen, 0, 31011cb875aeSCathy Zhou (const struct sockaddr *)&vrrp_muladdr4, 31021cb875aeSCathy Zhou sizeof (struct sockaddr_in))) != plen) { 31031cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_send_adv_v4(): sendto() on " 31041cb875aeSCathy Zhou "(vrid:%d, %s, %s) failed: %s sent:%d expect:%d", 31051cb875aeSCathy Zhou vr->vvr_conf.vvc_vrid, vr->vvr_vif->vvi_ifname, 31061cb875aeSCathy Zhou af_str(vr->vvr_conf.vvc_af), strerror(errno), len, plen); 31071cb875aeSCathy Zhou return (VRRP_ESYS); 31081cb875aeSCathy Zhou } 31091cb875aeSCathy Zhou 31101cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_send_adv_v4(%s) succeed", 31111cb875aeSCathy Zhou vr->vvr_conf.vvc_name); 31121cb875aeSCathy Zhou return (VRRP_SUCCESS); 31131cb875aeSCathy Zhou } 31141cb875aeSCathy Zhou 31151cb875aeSCathy Zhou static vrrp_err_t 31161cb875aeSCathy Zhou vrrpd_send_adv_v6(vrrp_vr_t *vr, uchar_t *buf, size_t len, boolean_t zero_pri) 31171cb875aeSCathy Zhou { 31181cb875aeSCathy Zhou struct msghdr msg6; 31191cb875aeSCathy Zhou size_t hoplimit_space = 0; 31201cb875aeSCathy Zhou size_t pktinfo_space = 0; 31211cb875aeSCathy Zhou size_t bufspace = 0; 31221cb875aeSCathy Zhou struct in6_pktinfo *pktinfop; 31231cb875aeSCathy Zhou struct cmsghdr *cmsgp; 31241cb875aeSCathy Zhou uchar_t *cmsg_datap; 31251cb875aeSCathy Zhou struct iovec iov; 31261cb875aeSCathy Zhou size_t plen; 31271cb875aeSCathy Zhou 31281cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_send_adv_v6(%s)", vr->vvr_conf.vvc_name); 31291cb875aeSCathy Zhou 31301cb875aeSCathy Zhou if ((plen = vrrpd_build_vrrp(vr, buf, len, zero_pri)) == 0) 31311cb875aeSCathy Zhou return (VRRP_ETOOSMALL); 31321cb875aeSCathy Zhou 31331cb875aeSCathy Zhou msg6.msg_control = NULL; 31341cb875aeSCathy Zhou msg6.msg_controllen = 0; 31351cb875aeSCathy Zhou 31361cb875aeSCathy Zhou hoplimit_space = sizeof (int); 31371cb875aeSCathy Zhou bufspace += sizeof (struct cmsghdr) + _MAX_ALIGNMENT + 31381cb875aeSCathy Zhou hoplimit_space + _MAX_ALIGNMENT; 31391cb875aeSCathy Zhou 31401cb875aeSCathy Zhou pktinfo_space = sizeof (struct in6_pktinfo); 31411cb875aeSCathy Zhou bufspace += sizeof (struct cmsghdr) + _MAX_ALIGNMENT + 31421cb875aeSCathy Zhou pktinfo_space + _MAX_ALIGNMENT; 31431cb875aeSCathy Zhou 31441cb875aeSCathy Zhou /* 31451cb875aeSCathy Zhou * We need to temporarily set the msg6.msg_controllen to bufspace 31461cb875aeSCathy Zhou * (we will later trim it to actual length used). This is needed because 31471cb875aeSCathy Zhou * CMSG_NXTHDR() uses it to check we have not exceeded the bounds. 31481cb875aeSCathy Zhou */ 31491cb875aeSCathy Zhou bufspace += sizeof (struct cmsghdr); 31501cb875aeSCathy Zhou msg6.msg_controllen = bufspace; 31511cb875aeSCathy Zhou 31521cb875aeSCathy Zhou msg6.msg_control = (struct cmsghdr *)malloc(bufspace); 31531cb875aeSCathy Zhou if (msg6.msg_control == NULL) { 31541cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_send_adv_v6(%s): memory allocation " 31551cb875aeSCathy Zhou "failed: %s", vr->vvr_conf.vvc_name, strerror(errno)); 31561cb875aeSCathy Zhou return (VRRP_ENOMEM); 31571cb875aeSCathy Zhou } 31581cb875aeSCathy Zhou 31591cb875aeSCathy Zhou cmsgp = CMSG_FIRSTHDR(&msg6); 31601cb875aeSCathy Zhou 31611cb875aeSCathy Zhou cmsgp->cmsg_level = IPPROTO_IPV6; 31621cb875aeSCathy Zhou cmsgp->cmsg_type = IPV6_HOPLIMIT; 31631cb875aeSCathy Zhou cmsg_datap = CMSG_DATA(cmsgp); 31641cb875aeSCathy Zhou /* LINTED */ 31651cb875aeSCathy Zhou *(int *)cmsg_datap = VRRP_IP_TTL; 31661cb875aeSCathy Zhou cmsgp->cmsg_len = cmsg_datap + hoplimit_space - (uchar_t *)cmsgp; 31671cb875aeSCathy Zhou cmsgp = CMSG_NXTHDR(&msg6, cmsgp); 31681cb875aeSCathy Zhou 31691cb875aeSCathy Zhou cmsgp->cmsg_level = IPPROTO_IPV6; 31701cb875aeSCathy Zhou cmsgp->cmsg_type = IPV6_PKTINFO; 31711cb875aeSCathy Zhou cmsg_datap = CMSG_DATA(cmsgp); 31721cb875aeSCathy Zhou 31731cb875aeSCathy Zhou /* LINTED */ 31741cb875aeSCathy Zhou pktinfop = (struct in6_pktinfo *)cmsg_datap; 31751cb875aeSCathy Zhou /* 31761cb875aeSCathy Zhou * We don't know if pktinfop->ipi6_addr is aligned properly, 31771cb875aeSCathy Zhou * therefore let's use bcopy, instead of assignment. 31781cb875aeSCathy Zhou */ 31791cb875aeSCathy Zhou (void) bcopy(&vr->vvr_pif->vvi_pip->vip_addr.in6.sin6_addr, 31801cb875aeSCathy Zhou &pktinfop->ipi6_addr, sizeof (struct in6_addr)); 31811cb875aeSCathy Zhou 31821cb875aeSCathy Zhou /* 31831cb875aeSCathy Zhou * We can assume pktinfop->ipi6_ifindex is 32 bit aligned. 31841cb875aeSCathy Zhou */ 31851cb875aeSCathy Zhou pktinfop->ipi6_ifindex = vr->vvr_vif->vvi_ifindex; 31861cb875aeSCathy Zhou cmsgp->cmsg_len = cmsg_datap + pktinfo_space - (uchar_t *)cmsgp; 31871cb875aeSCathy Zhou cmsgp = CMSG_NXTHDR(&msg6, cmsgp); 31881cb875aeSCathy Zhou msg6.msg_controllen = (char *)cmsgp - (char *)msg6.msg_control; 31891cb875aeSCathy Zhou 31901cb875aeSCathy Zhou msg6.msg_name = &vrrp_muladdr6; 31911cb875aeSCathy Zhou msg6.msg_namelen = sizeof (struct sockaddr_in6); 31921cb875aeSCathy Zhou 31931cb875aeSCathy Zhou iov.iov_base = buf; 31941cb875aeSCathy Zhou iov.iov_len = plen; 31951cb875aeSCathy Zhou msg6.msg_iov = &iov; 31961cb875aeSCathy Zhou msg6.msg_iovlen = 1; 31971cb875aeSCathy Zhou 31981cb875aeSCathy Zhou if ((len = sendmsg(vr->vvr_vif->vvi_sockfd, 31991cb875aeSCathy Zhou (const struct msghdr *)&msg6, 0)) != plen) { 32001cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_send_adv_v6(%s): sendmsg() failed: " 32011cb875aeSCathy Zhou "%s expect %d sent %d", vr->vvr_conf.vvc_name, 32021cb875aeSCathy Zhou strerror(errno), plen, len); 32031cb875aeSCathy Zhou (void) free(msg6.msg_control); 32041cb875aeSCathy Zhou return (VRRP_ESYS); 32051cb875aeSCathy Zhou } 32061cb875aeSCathy Zhou 32071cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_send_adv_v6(%s) succeed", 32081cb875aeSCathy Zhou vr->vvr_conf.vvc_name); 32091cb875aeSCathy Zhou (void) free(msg6.msg_control); 32101cb875aeSCathy Zhou return (VRRP_SUCCESS); 32111cb875aeSCathy Zhou } 32121cb875aeSCathy Zhou 32131cb875aeSCathy Zhou /* 32141cb875aeSCathy Zhou * Send the VRRP advertisement packets. 32151cb875aeSCathy Zhou */ 32161cb875aeSCathy Zhou static vrrp_err_t 32171cb875aeSCathy Zhou vrrpd_send_adv(vrrp_vr_t *vr, boolean_t zero_pri) 32181cb875aeSCathy Zhou { 32191cb875aeSCathy Zhou uint64_t buf[(IP_MAXPACKET + 1)/8]; 32201cb875aeSCathy Zhou 32211cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_send_adv(%s, %s_priority)", 32221cb875aeSCathy Zhou vr->vvr_conf.vvc_name, zero_pri ? "zero" : "non_zero"); 32231cb875aeSCathy Zhou 32241cb875aeSCathy Zhou assert(vr->vvr_pif->vvi_pip != NULL); 32251cb875aeSCathy Zhou 32261cb875aeSCathy Zhou if (vr->vvr_pif->vvi_pip == NULL) { 32271cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_send_adv(%s): no primary IP " 32281cb875aeSCathy Zhou "address", vr->vvr_conf.vvc_name); 32291cb875aeSCathy Zhou return (VRRP_EINVAL); 32301cb875aeSCathy Zhou } 32311cb875aeSCathy Zhou 32321cb875aeSCathy Zhou if (vr->vvr_conf.vvc_af == AF_INET) { 32331cb875aeSCathy Zhou return (vrrpd_send_adv_v4(vr, (uchar_t *)buf, 32341cb875aeSCathy Zhou sizeof (buf), zero_pri)); 32351cb875aeSCathy Zhou } else { 32361cb875aeSCathy Zhou return (vrrpd_send_adv_v6(vr, (uchar_t *)buf, 32371cb875aeSCathy Zhou sizeof (buf), zero_pri)); 32381cb875aeSCathy Zhou } 32391cb875aeSCathy Zhou } 32401cb875aeSCathy Zhou 32411cb875aeSCathy Zhou static void 32421cb875aeSCathy Zhou vrrpd_process_adv(vrrp_vr_t *vr, vrrp_addr_t *from, vrrp_pkt_t *vp) 32431cb875aeSCathy Zhou { 32441cb875aeSCathy Zhou vrrp_vr_conf_t *conf = &vr->vvr_conf; 32451cb875aeSCathy Zhou char peer[INET6_ADDRSTRLEN]; 32461cb875aeSCathy Zhou char local[INET6_ADDRSTRLEN]; 32471cb875aeSCathy Zhou int addr_cmp; 32481cb875aeSCathy Zhou uint16_t peer_adver_int; 32491cb875aeSCathy Zhou 32501cb875aeSCathy Zhou /* LINTED E_CONSTANT_CONDITION */ 32511cb875aeSCathy Zhou VRRPADDR2STR(vr->vvr_conf.vvc_af, from, peer, INET6_ADDRSTRLEN, 32521cb875aeSCathy Zhou _B_FALSE); 32531cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_process_adv(%s) from %s", conf->vvc_name, 32541cb875aeSCathy Zhou peer); 32551cb875aeSCathy Zhou 32561cb875aeSCathy Zhou if (vr->vvr_state <= VRRP_STATE_INIT) { 32571cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_process_adv(%s): state: %s, not " 32581cb875aeSCathy Zhou "ready", conf->vvc_name, vrrp_state2str(vr->vvr_state)); 32591cb875aeSCathy Zhou return; 32601cb875aeSCathy Zhou } 32611cb875aeSCathy Zhou 32621cb875aeSCathy Zhou peer_adver_int = CENTISEC2MSEC(ntohs(vp->vp_rsvd_adver_int) & 0x0fff); 32631cb875aeSCathy Zhou 32641cb875aeSCathy Zhou /* LINTED E_CONSTANT_CONDITION */ 32651cb875aeSCathy Zhou VRRPADDR2STR(vr->vvr_pif->vvi_af, &vr->vvr_pif->vvi_pip->vip_addr, 32661cb875aeSCathy Zhou local, INET6_ADDRSTRLEN, _B_FALSE); 32671cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_process_adv(%s): local/state/pri" 32681cb875aeSCathy Zhou "(%s/%s/%d) peer/pri/intv(%s/%d/%d)", conf->vvc_name, local, 32691cb875aeSCathy Zhou vrrp_state2str(vr->vvr_state), conf->vvc_pri, peer, 32701cb875aeSCathy Zhou vp->vp_prio, peer_adver_int); 32711cb875aeSCathy Zhou 32721cb875aeSCathy Zhou addr_cmp = ipaddr_cmp(vr->vvr_pif->vvi_af, from, 32731cb875aeSCathy Zhou &vr->vvr_pif->vvi_pip->vip_addr); 32741cb875aeSCathy Zhou if (addr_cmp == 0) { 32751cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_process_adv(%s): local message", 32761cb875aeSCathy Zhou conf->vvc_name); 32771cb875aeSCathy Zhou return; 32781cb875aeSCathy Zhou } else if (conf->vvc_pri == vp->vp_prio) { 32791cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_process_adv(%s): peer IP %s is %s" 32801cb875aeSCathy Zhou " than the local IP %s", conf->vvc_name, peer, 32811cb875aeSCathy Zhou addr_cmp > 0 ? "greater" : "less", local); 32821cb875aeSCathy Zhou } 32831cb875aeSCathy Zhou 32841cb875aeSCathy Zhou if (conf->vvc_pri == 255) { 32851cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_process_adv(%s): virtual address " 32861cb875aeSCathy Zhou "owner received advertisement from %s", conf->vvc_name, 32871cb875aeSCathy Zhou peer); 32881cb875aeSCathy Zhou return; 32891cb875aeSCathy Zhou } 32901cb875aeSCathy Zhou 32911cb875aeSCathy Zhou (void) gettimeofday(&vr->vvr_peer_time, NULL); 32921cb875aeSCathy Zhou (void) memcpy(&vr->vvr_peer_addr, from, sizeof (vrrp_addr_t)); 32931cb875aeSCathy Zhou vr->vvr_peer_prio = vp->vp_prio; 32941cb875aeSCathy Zhou vr->vvr_peer_adver_int = peer_adver_int; 32951cb875aeSCathy Zhou 32961cb875aeSCathy Zhou if (vr->vvr_state == VRRP_STATE_BACKUP) { 32971cb875aeSCathy Zhou vr->vvr_master_adver_int = vr->vvr_peer_adver_int; 32981cb875aeSCathy Zhou if ((vp->vp_prio == VRRP_PRIO_ZERO) || 32991cb875aeSCathy Zhou (conf->vvc_preempt == _B_FALSE || 33001cb875aeSCathy Zhou vp->vp_prio >= conf->vvc_pri)) { 33011cb875aeSCathy Zhou (void) iu_cancel_timer(vrrpd_timerq, 33021cb875aeSCathy Zhou vr->vvr_timer_id, NULL); 33031cb875aeSCathy Zhou if (vp->vp_prio == VRRP_PRIO_ZERO) { 33041cb875aeSCathy Zhou /* the master stops participating in VRRP */ 33051cb875aeSCathy Zhou vr->vvr_timeout = SKEW_TIME_VR(vr); 33061cb875aeSCathy Zhou } else { 33071cb875aeSCathy Zhou vr->vvr_timeout = MASTER_DOWN_INTERVAL_VR(vr); 33081cb875aeSCathy Zhou } 33091cb875aeSCathy Zhou if ((vr->vvr_timer_id = iu_schedule_timer_ms( 33101cb875aeSCathy Zhou vrrpd_timerq, vr->vvr_timeout, vrrp_b2m_timeout, 33111cb875aeSCathy Zhou vr)) == -1) { 33121cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_process_adv(%s): " 33131cb875aeSCathy Zhou "start vrrp_b2m_timeout(%d) failed", 33141cb875aeSCathy Zhou conf->vvc_name, vr->vvr_timeout); 33151cb875aeSCathy Zhou } else { 33161cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_process_adv(%s): " 33171cb875aeSCathy Zhou "start vrrp_b2m_timeout(%d)", 33181cb875aeSCathy Zhou conf->vvc_name, vr->vvr_timeout); 33191cb875aeSCathy Zhou } 33201cb875aeSCathy Zhou } 33211cb875aeSCathy Zhou } else if (vr->vvr_state == VRRP_STATE_MASTER) { 33221cb875aeSCathy Zhou if (vp->vp_prio == VRRP_PRIO_ZERO) { 33231cb875aeSCathy Zhou (void) vrrpd_send_adv(vr, _B_FALSE); 33241cb875aeSCathy Zhou (void) iu_cancel_timer(vrrpd_timerq, 33251cb875aeSCathy Zhou vr->vvr_timer_id, NULL); 33261cb875aeSCathy Zhou if ((vr->vvr_timer_id = iu_schedule_timer_ms( 33271cb875aeSCathy Zhou vrrpd_timerq, vr->vvr_timeout, vrrp_adv_timeout, 33281cb875aeSCathy Zhou vr)) == -1) { 33291cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_process_adv(%s): " 33301cb875aeSCathy Zhou "start vrrp_adv_timeout(%d) failed", 33311cb875aeSCathy Zhou conf->vvc_name, vr->vvr_timeout); 33321cb875aeSCathy Zhou } else { 33331cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_process_adv(%s): " 33341cb875aeSCathy Zhou "start vrrp_adv_timeout(%d)", 33351cb875aeSCathy Zhou conf->vvc_name, vr->vvr_timeout); 33361cb875aeSCathy Zhou } 33371cb875aeSCathy Zhou } else if (vp->vp_prio > conf->vvc_pri || 33381cb875aeSCathy Zhou (vp->vp_prio == conf->vvc_pri && addr_cmp > 0)) { 33391cb875aeSCathy Zhou (void) vrrpd_state_m2b(vr); 33401cb875aeSCathy Zhou } 33411cb875aeSCathy Zhou } else { 33421cb875aeSCathy Zhou assert(_B_FALSE); 33431cb875aeSCathy Zhou } 33441cb875aeSCathy Zhou } 33451cb875aeSCathy Zhou 33461cb875aeSCathy Zhou static vrrp_err_t 33471cb875aeSCathy Zhou vrrpd_process_vrrp(vrrp_intf_t *pif, vrrp_pkt_t *vp, size_t len, 33481cb875aeSCathy Zhou vrrp_addr_t *from) 33491cb875aeSCathy Zhou { 33501cb875aeSCathy Zhou vrrp_vr_t *vr; 33511cb875aeSCathy Zhou uint8_t vers_type; 33521cb875aeSCathy Zhou uint16_t saved_cksum, cksum; 33531cb875aeSCathy Zhou char peer[INET6_ADDRSTRLEN]; 33541cb875aeSCathy Zhou 33551cb875aeSCathy Zhou /* LINTED E_CONSTANT_CONDITION */ 33561cb875aeSCathy Zhou VRRPADDR2STR(pif->vvi_af, from, peer, INET6_ADDRSTRLEN, _B_FALSE); 33571cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_process_vrrp(%s) from %s", pif->vvi_ifname, 33581cb875aeSCathy Zhou peer); 33591cb875aeSCathy Zhou 33601cb875aeSCathy Zhou if (len < sizeof (vrrp_pkt_t)) { 33611cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_process_vrrp(%s): invalid message " 33621cb875aeSCathy Zhou "length %d", len); 33631cb875aeSCathy Zhou return (VRRP_EINVAL); 33641cb875aeSCathy Zhou } 33651cb875aeSCathy Zhou 33661cb875aeSCathy Zhou /* 33671cb875aeSCathy Zhou * Verify: VRRP version number and packet type. 33681cb875aeSCathy Zhou */ 33691cb875aeSCathy Zhou vers_type = ((vp->vp_vers_type & VRRP_VER_MASK) >> 4); 33701cb875aeSCathy Zhou if (vers_type != VRRP_VERSION) { 33711cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_process_vrrp(%s) unsupported " 33721cb875aeSCathy Zhou "version %d", pif->vvi_ifname, vers_type); 33731cb875aeSCathy Zhou return (VRRP_EINVAL); 33741cb875aeSCathy Zhou } 33751cb875aeSCathy Zhou 33761cb875aeSCathy Zhou if (vp->vp_ipnum == 0) { 33771cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_process_vrrp(%s): zero IPvX count", 33781cb875aeSCathy Zhou pif->vvi_ifname); 33791cb875aeSCathy Zhou return (VRRP_EINVAL); 33801cb875aeSCathy Zhou } 33811cb875aeSCathy Zhou 33821cb875aeSCathy Zhou if (len - sizeof (vrrp_pkt_t) != 33831cb875aeSCathy Zhou vp->vp_ipnum * (pif->vvi_af == AF_INET ? sizeof (struct in_addr) : 33841cb875aeSCathy Zhou sizeof (struct in6_addr))) { 33851cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_process_vrrp(%s): invalid IPvX count" 33861cb875aeSCathy Zhou " %d", pif->vvi_ifname, vp->vp_ipnum); 33871cb875aeSCathy Zhou return (VRRP_EINVAL); 33881cb875aeSCathy Zhou } 33891cb875aeSCathy Zhou 33901cb875aeSCathy Zhou vers_type = (vp->vp_vers_type & VRRP_TYPE_MASK); 33911cb875aeSCathy Zhou 33921cb875aeSCathy Zhou /* 33931cb875aeSCathy Zhou * verify: VRRP checksum. Note that vrrp_cksum returns network byte 33941cb875aeSCathy Zhou * order checksum value; 33951cb875aeSCathy Zhou */ 33961cb875aeSCathy Zhou saved_cksum = vp->vp_chksum; 33971cb875aeSCathy Zhou vp->vp_chksum = 0; 33981cb875aeSCathy Zhou if (pif->vvi_af == AF_INET) { 33991cb875aeSCathy Zhou cksum = vrrp_cksum4(&from->in4.sin_addr, 34001cb875aeSCathy Zhou &vrrp_muladdr4.in4.sin_addr, len, vp); 34011cb875aeSCathy Zhou } else { 34021cb875aeSCathy Zhou cksum = vrrp_cksum6(&from->in6.sin6_addr, 34031cb875aeSCathy Zhou &vrrp_muladdr6.in6.sin6_addr, len, vp); 34041cb875aeSCathy Zhou } 34051cb875aeSCathy Zhou 34061cb875aeSCathy Zhou if (cksum != saved_cksum) { 34071cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_process_vrrp(%s) invalid " 34081cb875aeSCathy Zhou "checksum: expected/real(0x%x/0x%x)", pif->vvi_ifname, 34091cb875aeSCathy Zhou cksum, saved_cksum); 34101cb875aeSCathy Zhou return (VRRP_EINVAL); 34111cb875aeSCathy Zhou } 34121cb875aeSCathy Zhou 34131cb875aeSCathy Zhou if ((vr = vrrpd_lookup_vr_by_vrid(pif->vvi_ifname, vp->vp_vrid, 34141cb875aeSCathy Zhou pif->vvi_af)) != NULL && vers_type == VRRP_PKT_ADVERT) { 34151cb875aeSCathy Zhou vrrpd_process_adv(vr, from, vp); 34161cb875aeSCathy Zhou } else { 34171cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_process_vrrp(%s) VRID(%d/%s) " 34181cb875aeSCathy Zhou "not configured", pif->vvi_ifname, vp->vp_vrid, 34191cb875aeSCathy Zhou af_str(pif->vvi_af)); 34201cb875aeSCathy Zhou } 34211cb875aeSCathy Zhou return (VRRP_SUCCESS); 34221cb875aeSCathy Zhou } 34231cb875aeSCathy Zhou 34241cb875aeSCathy Zhou /* 34251cb875aeSCathy Zhou * IPv4 socket, the IPv4 header is included. 34261cb875aeSCathy Zhou */ 34271cb875aeSCathy Zhou static vrrp_err_t 34281cb875aeSCathy Zhou vrrpd_process_adv_v4(vrrp_intf_t *pif, struct msghdr *msgp, size_t len) 34291cb875aeSCathy Zhou { 34301cb875aeSCathy Zhou char abuf[INET6_ADDRSTRLEN]; 34311cb875aeSCathy Zhou struct ip *ip; 34321cb875aeSCathy Zhou 34331cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_process_adv_v4(%s, %d)", 34341cb875aeSCathy Zhou pif->vvi_ifname, len); 34351cb875aeSCathy Zhou 34361cb875aeSCathy Zhou ip = (struct ip *)msgp->msg_iov->iov_base; 34371cb875aeSCathy Zhou 34381cb875aeSCathy Zhou /* Sanity check */ 34391cb875aeSCathy Zhou if (len < sizeof (struct ip) || len < ntohs(ip->ip_len)) { 34401cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_process_adv_v4(%s): invalid length " 34411cb875aeSCathy Zhou "%d", pif->vvi_ifname, len); 34421cb875aeSCathy Zhou return (VRRP_EINVAL); 34431cb875aeSCathy Zhou } 34441cb875aeSCathy Zhou 34451cb875aeSCathy Zhou assert(ip->ip_v == IPV4_VERSION); 34461cb875aeSCathy Zhou assert(ip->ip_p == IPPROTO_VRRP); 34471cb875aeSCathy Zhou assert(msgp->msg_namelen == sizeof (struct sockaddr_in)); 34481cb875aeSCathy Zhou 34491cb875aeSCathy Zhou if (vrrp_muladdr4.in4.sin_addr.s_addr != ip->ip_dst.s_addr) { 34501cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_process_adv_v4(%s): invalid " 34511cb875aeSCathy Zhou "destination %s", pif->vvi_ifname, 34521cb875aeSCathy Zhou inet_ntop(pif->vvi_af, &(ip->ip_dst), abuf, sizeof (abuf))); 34531cb875aeSCathy Zhou return (VRRP_EINVAL); 34541cb875aeSCathy Zhou } 34551cb875aeSCathy Zhou 34561cb875aeSCathy Zhou if (ip->ip_ttl != VRRP_IP_TTL) { 34571cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_process_adv_v4(%s): invalid " 34581cb875aeSCathy Zhou "ttl %d", pif->vvi_ifname, ip->ip_ttl); 34591cb875aeSCathy Zhou return (VRRP_EINVAL); 34601cb875aeSCathy Zhou } 34611cb875aeSCathy Zhou 34621cb875aeSCathy Zhou /* 34631cb875aeSCathy Zhou * Note that the ip_len contains only the IP payload length. 34641cb875aeSCathy Zhou */ 34651cb875aeSCathy Zhou return (vrrpd_process_vrrp(pif, 34661cb875aeSCathy Zhou /* LINTED E_BAD_PTR_CAST_ALIGN */ 34671cb875aeSCathy Zhou (vrrp_pkt_t *)((char *)ip + ip->ip_hl * 4), ntohs(ip->ip_len), 34681cb875aeSCathy Zhou (vrrp_addr_t *)msgp->msg_name)); 34691cb875aeSCathy Zhou } 34701cb875aeSCathy Zhou 34711cb875aeSCathy Zhou /* 34721cb875aeSCathy Zhou * IPv6 socket, check the ancillary_data. 34731cb875aeSCathy Zhou */ 34741cb875aeSCathy Zhou static vrrp_err_t 34751cb875aeSCathy Zhou vrrpd_process_adv_v6(vrrp_intf_t *pif, struct msghdr *msgp, size_t len) 34761cb875aeSCathy Zhou { 34771cb875aeSCathy Zhou struct cmsghdr *cmsgp; 34781cb875aeSCathy Zhou uchar_t *cmsg_datap; 34791cb875aeSCathy Zhou struct in6_pktinfo *pktinfop; 34801cb875aeSCathy Zhou char abuf[INET6_ADDRSTRLEN]; 34811cb875aeSCathy Zhou int ttl; 34821cb875aeSCathy Zhou 34831cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_process_adv_v6(%s, %d)", 34841cb875aeSCathy Zhou pif->vvi_ifname, len); 34851cb875aeSCathy Zhou 34861cb875aeSCathy Zhou /* Sanity check */ 34871cb875aeSCathy Zhou if (len < sizeof (vrrp_pkt_t)) { 34881cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_process_adv_v6(%s): invalid length " 34891cb875aeSCathy Zhou "%d", pif->vvi_ifname, len); 34901cb875aeSCathy Zhou return (VRRP_EINVAL); 34911cb875aeSCathy Zhou } 34921cb875aeSCathy Zhou 34931cb875aeSCathy Zhou assert(msgp->msg_namelen == sizeof (struct sockaddr_in6)); 34941cb875aeSCathy Zhou 34951cb875aeSCathy Zhou for (cmsgp = CMSG_FIRSTHDR(msgp); cmsgp != NULL; 34961cb875aeSCathy Zhou cmsgp = CMSG_NXTHDR(msgp, cmsgp)) { 34971cb875aeSCathy Zhou assert(cmsgp->cmsg_level == IPPROTO_IPV6); 34981cb875aeSCathy Zhou cmsg_datap = CMSG_DATA(cmsgp); 34991cb875aeSCathy Zhou 35001cb875aeSCathy Zhou switch (cmsgp->cmsg_type) { 35011cb875aeSCathy Zhou case IPV6_HOPLIMIT: 35021cb875aeSCathy Zhou /* LINTED E_BAD_PTR_CAST_ALIGN */ 35031cb875aeSCathy Zhou if ((ttl = *(int *)cmsg_datap) == VRRP_IP_TTL) 35041cb875aeSCathy Zhou break; 35051cb875aeSCathy Zhou 35061cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_process_adv_v4(%s): invalid " 35071cb875aeSCathy Zhou "ttl %d", pif->vvi_ifname, ttl); 35081cb875aeSCathy Zhou return (VRRP_EINVAL); 35091cb875aeSCathy Zhou case IPV6_PKTINFO: 35101cb875aeSCathy Zhou /* LINTED E_BAD_PTR_CAST_ALIGN */ 35111cb875aeSCathy Zhou pktinfop = (struct in6_pktinfo *)cmsg_datap; 35121cb875aeSCathy Zhou if (IN6_ARE_ADDR_EQUAL(&pktinfop->ipi6_addr, 35131cb875aeSCathy Zhou &vrrp_muladdr6.in6.sin6_addr)) { 35141cb875aeSCathy Zhou break; 35151cb875aeSCathy Zhou } 35161cb875aeSCathy Zhou 35171cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_process_adv_v4(%s): invalid " 35181cb875aeSCathy Zhou "destination %s", pif->vvi_ifname, 35191cb875aeSCathy Zhou inet_ntop(pif->vvi_af, &pktinfop->ipi6_addr, abuf, 35201cb875aeSCathy Zhou sizeof (abuf))); 35211cb875aeSCathy Zhou return (VRRP_EINVAL); 35221cb875aeSCathy Zhou } 35231cb875aeSCathy Zhou } 35241cb875aeSCathy Zhou 35251cb875aeSCathy Zhou return (vrrpd_process_vrrp(pif, msgp->msg_iov->iov_base, len, 35261cb875aeSCathy Zhou msgp->msg_name)); 35271cb875aeSCathy Zhou } 35281cb875aeSCathy Zhou 35291cb875aeSCathy Zhou /* ARGSUSED */ 35301cb875aeSCathy Zhou static void 35311cb875aeSCathy Zhou vrrpd_sock_handler(iu_eh_t *eh, int s, short events, iu_event_id_t id, 35321cb875aeSCathy Zhou void *arg) 35331cb875aeSCathy Zhou { 35341cb875aeSCathy Zhou struct msghdr msg; 35351cb875aeSCathy Zhou vrrp_addr_t from; 35361cb875aeSCathy Zhou uint64_t buf[(IP_MAXPACKET + 1)/8]; 35371cb875aeSCathy Zhou uint64_t ancillary_data[(IP_MAXPACKET + 1)/8]; 35381cb875aeSCathy Zhou vrrp_intf_t *pif = arg; 35391cb875aeSCathy Zhou int af = pif->vvi_af; 35401cb875aeSCathy Zhou int len; 35411cb875aeSCathy Zhou struct iovec iov; 35421cb875aeSCathy Zhou 35431cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_sock_handler(%s)", pif->vvi_ifname); 35441cb875aeSCathy Zhou 35451cb875aeSCathy Zhou msg.msg_name = (struct sockaddr *)&from; 35461cb875aeSCathy Zhou msg.msg_namelen = (af == AF_INET) ? sizeof (struct sockaddr_in) : 35471cb875aeSCathy Zhou sizeof (struct sockaddr_in6); 35481cb875aeSCathy Zhou iov.iov_base = (char *)buf; 35491cb875aeSCathy Zhou iov.iov_len = sizeof (buf); 35501cb875aeSCathy Zhou msg.msg_iov = &iov; 35511cb875aeSCathy Zhou msg.msg_iovlen = 1; 35521cb875aeSCathy Zhou msg.msg_control = ancillary_data; 35531cb875aeSCathy Zhou msg.msg_controllen = sizeof (ancillary_data); 35541cb875aeSCathy Zhou 35551cb875aeSCathy Zhou if ((len = recvmsg(s, &msg, 0)) == -1) { 35561cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_sock_handler() recvmsg(%s) " 35571cb875aeSCathy Zhou "failed: %s", pif->vvi_ifname, strerror(errno)); 35581cb875aeSCathy Zhou return; 35591cb875aeSCathy Zhou } 35601cb875aeSCathy Zhou 35611cb875aeSCathy Zhou /* 35621cb875aeSCathy Zhou * Ignore packets whose control buffers that don't fit 35631cb875aeSCathy Zhou */ 35641cb875aeSCathy Zhou if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { 35651cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_sock_handler() %s buffer not " 35661cb875aeSCathy Zhou "big enough", pif->vvi_ifname); 35671cb875aeSCathy Zhou return; 35681cb875aeSCathy Zhou } 35691cb875aeSCathy Zhou 35701cb875aeSCathy Zhou if (af == AF_INET) 35711cb875aeSCathy Zhou (void) vrrpd_process_adv_v4(pif, &msg, len); 35721cb875aeSCathy Zhou else 35731cb875aeSCathy Zhou (void) vrrpd_process_adv_v6(pif, &msg, len); 35741cb875aeSCathy Zhou } 35751cb875aeSCathy Zhou 35761cb875aeSCathy Zhou /* 35771cb875aeSCathy Zhou * Create the socket which is used to receive VRRP packets. Virtual routers 35781cb875aeSCathy Zhou * that configured on the same physical interface share the same socket. 35791cb875aeSCathy Zhou */ 35801cb875aeSCathy Zhou static vrrp_err_t 35811cb875aeSCathy Zhou vrrpd_init_rxsock(vrrp_vr_t *vr) 35821cb875aeSCathy Zhou { 35831cb875aeSCathy Zhou vrrp_intf_t *pif; /* Physical interface used to recv packets */ 35841cb875aeSCathy Zhou struct group_req greq; 35851cb875aeSCathy Zhou struct sockaddr_storage *muladdr; 35861cb875aeSCathy Zhou int af, proto; 35871cb875aeSCathy Zhou int on = 1; 35881cb875aeSCathy Zhou vrrp_err_t err = VRRP_SUCCESS; 35891cb875aeSCathy Zhou 35901cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_init_rxsock(%s)", vr->vvr_conf.vvc_name); 35911cb875aeSCathy Zhou 35921cb875aeSCathy Zhou /* 35931cb875aeSCathy Zhou * The RX sockets may already been initialized. 35941cb875aeSCathy Zhou */ 35951cb875aeSCathy Zhou if ((pif = vr->vvr_pif) != NULL) { 35961cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_init_rxsock(%s) already done on %s", 35971cb875aeSCathy Zhou vr->vvr_conf.vvc_name, pif->vvi_ifname); 35981cb875aeSCathy Zhou assert(pif->vvi_sockfd != -1); 35991cb875aeSCathy Zhou return (VRRP_SUCCESS); 36001cb875aeSCathy Zhou } 36011cb875aeSCathy Zhou 36021cb875aeSCathy Zhou /* 36031cb875aeSCathy Zhou * If no IP addresses configured on the primary interface, 36041cb875aeSCathy Zhou * return failure. 36051cb875aeSCathy Zhou */ 36061cb875aeSCathy Zhou af = vr->vvr_conf.vvc_af; 36071cb875aeSCathy Zhou pif = vrrpd_lookup_if(vr->vvr_conf.vvc_link, af); 36081cb875aeSCathy Zhou if (pif == NULL) { 36091cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_init_rxsock(%s): no IP address " 36101cb875aeSCathy Zhou "over %s/%s", vr->vvr_conf.vvc_name, 36111cb875aeSCathy Zhou vr->vvr_conf.vvc_link, af_str(af)); 36121cb875aeSCathy Zhou return (VRRP_ENOPRIM); 36131cb875aeSCathy Zhou } 36141cb875aeSCathy Zhou 36151cb875aeSCathy Zhou proto = (af == AF_INET ? IPPROTO_IP : IPPROTO_IPV6); 36161cb875aeSCathy Zhou if (pif->vvi_nvr++ == 0) { 36171cb875aeSCathy Zhou assert(pif->vvi_sockfd < 0); 36181cb875aeSCathy Zhou pif->vvi_sockfd = socket(af, SOCK_RAW, IPPROTO_VRRP); 36191cb875aeSCathy Zhou if (pif->vvi_sockfd < 0) { 36201cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_init_rxsock(%s): socket() " 36211cb875aeSCathy Zhou "failed %s", vr->vvr_conf.vvc_name, 36221cb875aeSCathy Zhou strerror(errno)); 36231cb875aeSCathy Zhou err = VRRP_ESYS; 36241cb875aeSCathy Zhou goto done; 36251cb875aeSCathy Zhou } 36261cb875aeSCathy Zhou 36271cb875aeSCathy Zhou /* 36281cb875aeSCathy Zhou * Join the multicast group to receive VRRP packets. 36291cb875aeSCathy Zhou */ 36301cb875aeSCathy Zhou if (af == AF_INET) { 36311cb875aeSCathy Zhou muladdr = (struct sockaddr_storage *) 36321cb875aeSCathy Zhou (void *)&vrrp_muladdr4; 36331cb875aeSCathy Zhou } else { 36341cb875aeSCathy Zhou muladdr = (struct sockaddr_storage *) 36351cb875aeSCathy Zhou (void *)&vrrp_muladdr6; 36361cb875aeSCathy Zhou } 36371cb875aeSCathy Zhou 36381cb875aeSCathy Zhou greq.gr_interface = pif->vvi_ifindex; 36391cb875aeSCathy Zhou (void) memcpy(&greq.gr_group, muladdr, 36401cb875aeSCathy Zhou sizeof (struct sockaddr_storage)); 36411cb875aeSCathy Zhou if (setsockopt(pif->vvi_sockfd, proto, MCAST_JOIN_GROUP, &greq, 36421cb875aeSCathy Zhou sizeof (struct group_req)) < 0) { 36431cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_init_rxsock(%s): " 36441cb875aeSCathy Zhou "join_group(%d) failed: %s", vr->vvr_conf.vvc_name, 36451cb875aeSCathy Zhou pif->vvi_ifindex, strerror(errno)); 36461cb875aeSCathy Zhou err = VRRP_ESYS; 36471cb875aeSCathy Zhou goto done; 36481cb875aeSCathy Zhou } else { 36491cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_init_rxsock(%s): " 36501cb875aeSCathy Zhou "join_group(%d) succeeded", vr->vvr_conf.vvc_name, 36511cb875aeSCathy Zhou pif->vvi_ifindex); 36521cb875aeSCathy Zhou } 36531cb875aeSCathy Zhou 36541cb875aeSCathy Zhou /* 36551cb875aeSCathy Zhou * Unlike IPv4, the IPv6 raw socket does not pass the IP header 36561cb875aeSCathy Zhou * when a packet is received. Call setsockopt() to receive such 36571cb875aeSCathy Zhou * information. 36581cb875aeSCathy Zhou */ 36591cb875aeSCathy Zhou if (af == AF_INET6) { 36601cb875aeSCathy Zhou /* 36611cb875aeSCathy Zhou * Enable receipt of destination address info 36621cb875aeSCathy Zhou */ 36631cb875aeSCathy Zhou if (setsockopt(pif->vvi_sockfd, proto, IPV6_RECVPKTINFO, 36641cb875aeSCathy Zhou (char *)&on, sizeof (on)) < 0) { 36651cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_init_rxsock(%s): " 36661cb875aeSCathy Zhou "enable recvpktinfo failed: %s", 36671cb875aeSCathy Zhou vr->vvr_conf.vvc_name, strerror(errno)); 36681cb875aeSCathy Zhou err = VRRP_ESYS; 36691cb875aeSCathy Zhou goto done; 36701cb875aeSCathy Zhou } 36711cb875aeSCathy Zhou 36721cb875aeSCathy Zhou /* 36731cb875aeSCathy Zhou * Enable receipt of hoplimit info 36741cb875aeSCathy Zhou */ 36751cb875aeSCathy Zhou if (setsockopt(pif->vvi_sockfd, proto, 36761cb875aeSCathy Zhou IPV6_RECVHOPLIMIT, (char *)&on, sizeof (on)) < 0) { 36771cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_init_rxsock(%s): " 36781cb875aeSCathy Zhou "enable recvhoplimit failed: %s", 36791cb875aeSCathy Zhou vr->vvr_conf.vvc_name, strerror(errno)); 36801cb875aeSCathy Zhou err = VRRP_ESYS; 36811cb875aeSCathy Zhou goto done; 36821cb875aeSCathy Zhou } 36831cb875aeSCathy Zhou } 36841cb875aeSCathy Zhou 36851cb875aeSCathy Zhou if ((pif->vvi_eid = iu_register_event(vrrpd_eh, 36861cb875aeSCathy Zhou pif->vvi_sockfd, POLLIN, vrrpd_sock_handler, pif)) == -1) { 36871cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_init_rxsock(%s): " 36881cb875aeSCathy Zhou "iu_register_event() failed", 36891cb875aeSCathy Zhou vr->vvr_conf.vvc_name); 36901cb875aeSCathy Zhou err = VRRP_ESYS; 36911cb875aeSCathy Zhou goto done; 36921cb875aeSCathy Zhou } 36931cb875aeSCathy Zhou } else { 36941cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_init_rxsock(%s) over %s already " 36951cb875aeSCathy Zhou "done %d", vr->vvr_conf.vvc_name, pif->vvi_ifname, 36961cb875aeSCathy Zhou pif->vvi_nvr); 36971cb875aeSCathy Zhou assert(IS_PRIMARY_INTF(pif)); 36981cb875aeSCathy Zhou } 36991cb875aeSCathy Zhou 37001cb875aeSCathy Zhou done: 37011cb875aeSCathy Zhou vr->vvr_pif = pif; 37021cb875aeSCathy Zhou if (err != VRRP_SUCCESS) 37031cb875aeSCathy Zhou vrrpd_fini_rxsock(vr); 37041cb875aeSCathy Zhou 37051cb875aeSCathy Zhou return (err); 37061cb875aeSCathy Zhou } 37071cb875aeSCathy Zhou 37081cb875aeSCathy Zhou /* 37091cb875aeSCathy Zhou * Delete the socket which is used to receive VRRP packets for the given 37101cb875aeSCathy Zhou * VRRP router. Since all virtual routers that configured on the same 37111cb875aeSCathy Zhou * physical interface share the same socket, the socket is only closed 37121cb875aeSCathy Zhou * when the last VRRP router share this socket is deleted. 37131cb875aeSCathy Zhou */ 37141cb875aeSCathy Zhou static void 37151cb875aeSCathy Zhou vrrpd_fini_rxsock(vrrp_vr_t *vr) 37161cb875aeSCathy Zhou { 37171cb875aeSCathy Zhou vrrp_intf_t *pif = vr->vvr_pif; 37181cb875aeSCathy Zhou 37191cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_fini_rxsock(%s)", vr->vvr_conf.vvc_name); 37201cb875aeSCathy Zhou 37211cb875aeSCathy Zhou if (pif == NULL) 37221cb875aeSCathy Zhou return; 37231cb875aeSCathy Zhou 37241cb875aeSCathy Zhou if (--pif->vvi_nvr == 0) { 37251cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_fini_rxsock(%s) over %s", 37261cb875aeSCathy Zhou vr->vvr_conf.vvc_name, pif->vvi_ifname); 37271cb875aeSCathy Zhou (void) iu_unregister_event(vrrpd_eh, pif->vvi_eid, NULL); 37281cb875aeSCathy Zhou (void) close(pif->vvi_sockfd); 37291cb875aeSCathy Zhou pif->vvi_pip = NULL; 37301cb875aeSCathy Zhou pif->vvi_sockfd = -1; 37311cb875aeSCathy Zhou pif->vvi_eid = -1; 37321cb875aeSCathy Zhou } else { 37331cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_fini_rxsock(%s) over %s %d", 37341cb875aeSCathy Zhou vr->vvr_conf.vvc_name, pif->vvi_ifname, pif->vvi_nvr); 37351cb875aeSCathy Zhou } 37361cb875aeSCathy Zhou vr->vvr_pif = NULL; 37371cb875aeSCathy Zhou } 37381cb875aeSCathy Zhou 37391cb875aeSCathy Zhou /* 37401cb875aeSCathy Zhou * Create the socket which is used to send VRRP packets. Further, set 37411cb875aeSCathy Zhou * the IFF_NOACCEPT flag based on the VRRP router's accept mode. 37421cb875aeSCathy Zhou */ 37431cb875aeSCathy Zhou static vrrp_err_t 37441cb875aeSCathy Zhou vrrpd_init_txsock(vrrp_vr_t *vr) 37451cb875aeSCathy Zhou { 37461cb875aeSCathy Zhou int af; 37471cb875aeSCathy Zhou vrrp_intf_t *vif; 37481cb875aeSCathy Zhou vrrp_err_t err; 37491cb875aeSCathy Zhou 37501cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_init_txsock(%s)", vr->vvr_conf.vvc_name); 37511cb875aeSCathy Zhou 37521cb875aeSCathy Zhou if (vr->vvr_vif != NULL) { 37531cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_init_txsock(%s) already done on %s", 37541cb875aeSCathy Zhou vr->vvr_conf.vvc_name, vr->vvr_vif->vvi_ifname); 37551cb875aeSCathy Zhou return (VRRP_SUCCESS); 37561cb875aeSCathy Zhou } 37571cb875aeSCathy Zhou 37581cb875aeSCathy Zhou af = vr->vvr_conf.vvc_af; 37591cb875aeSCathy Zhou if ((vif = vrrpd_lookup_if(vr->vvr_vnic, af)) == NULL) { 37601cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_init_txsock(%s) no IP address over " 37611cb875aeSCathy Zhou "%s/%s", vr->vvr_conf.vvc_name, vr->vvr_vnic, af_str(af)); 37621cb875aeSCathy Zhou return (VRRP_ENOVIRT); 37631cb875aeSCathy Zhou } 37641cb875aeSCathy Zhou 37651cb875aeSCathy Zhou vr->vvr_vif = vif; 37661cb875aeSCathy Zhou if (vr->vvr_conf.vvc_af == AF_INET) 37671cb875aeSCathy Zhou err = vrrpd_init_txsock_v4(vr); 37681cb875aeSCathy Zhou else 37691cb875aeSCathy Zhou err = vrrpd_init_txsock_v6(vr); 37701cb875aeSCathy Zhou 37711cb875aeSCathy Zhou if (err != VRRP_SUCCESS) 37721cb875aeSCathy Zhou goto done; 37731cb875aeSCathy Zhou 37741cb875aeSCathy Zhou /* 37751cb875aeSCathy Zhou * The interface should start with IFF_NOACCEPT flag not set, only 37761cb875aeSCathy Zhou * call this function when the VRRP router requires IFF_NOACCEPT. 37771cb875aeSCathy Zhou */ 37781cb875aeSCathy Zhou if (!vr->vvr_conf.vvc_accept) 37791cb875aeSCathy Zhou err = vrrpd_set_noaccept(vr, _B_TRUE); 37801cb875aeSCathy Zhou 37811cb875aeSCathy Zhou done: 37821cb875aeSCathy Zhou if (err != VRRP_SUCCESS) { 37831cb875aeSCathy Zhou (void) close(vif->vvi_sockfd); 37841cb875aeSCathy Zhou vif->vvi_sockfd = -1; 37851cb875aeSCathy Zhou vr->vvr_vif = NULL; 37861cb875aeSCathy Zhou } 37871cb875aeSCathy Zhou 37881cb875aeSCathy Zhou return (err); 37891cb875aeSCathy Zhou } 37901cb875aeSCathy Zhou 37911cb875aeSCathy Zhou /* 37921cb875aeSCathy Zhou * Create the IPv4 socket which is used to send VRRP packets. Note that 37931cb875aeSCathy Zhou * the destination MAC address of VRRP advertisement must be the virtual 37941cb875aeSCathy Zhou * MAC address, so we specify the output interface to be the specific VNIC. 37951cb875aeSCathy Zhou */ 37961cb875aeSCathy Zhou static vrrp_err_t 37971cb875aeSCathy Zhou vrrpd_init_txsock_v4(vrrp_vr_t *vr) 37981cb875aeSCathy Zhou { 37991cb875aeSCathy Zhou vrrp_intf_t *vif; /* VNIC interface used to send packets */ 38001cb875aeSCathy Zhou vrrp_ip_t *vip; /* The first IP over the VNIC */ 38011cb875aeSCathy Zhou int on = 1; 38021cb875aeSCathy Zhou char off = 0; 38031cb875aeSCathy Zhou vrrp_err_t err = VRRP_SUCCESS; 38041cb875aeSCathy Zhou char abuf[INET6_ADDRSTRLEN]; 38051cb875aeSCathy Zhou 38061cb875aeSCathy Zhou vif = vr->vvr_vif; 38071cb875aeSCathy Zhou assert(vr->vvr_conf.vvc_af == AF_INET); 38081cb875aeSCathy Zhou assert(vif != NULL); 38091cb875aeSCathy Zhou 38101cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_init_txsock_v4(%s) over %s", 38111cb875aeSCathy Zhou vr->vvr_conf.vvc_name, vif->vvi_ifname); 38121cb875aeSCathy Zhou 38131cb875aeSCathy Zhou if (vif->vvi_sockfd != -1) { 38141cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_init_txsock_v4(%s) already done " 38151cb875aeSCathy Zhou "over %s", vr->vvr_conf.vvc_name, vif->vvi_ifname); 38161cb875aeSCathy Zhou return (VRRP_SUCCESS); 38171cb875aeSCathy Zhou } 38181cb875aeSCathy Zhou 38191cb875aeSCathy Zhou vif->vvi_sockfd = socket(vif->vvi_af, SOCK_RAW, IPPROTO_VRRP); 38201cb875aeSCathy Zhou if (vif->vvi_sockfd < 0) { 38211cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_init_txsock_v4(%s): socket() " 38221cb875aeSCathy Zhou "failed: %s", vr->vvr_conf.vvc_name, strerror(errno)); 38231cb875aeSCathy Zhou err = VRRP_ESYS; 38241cb875aeSCathy Zhou goto done; 38251cb875aeSCathy Zhou } 38261cb875aeSCathy Zhou 38271cb875aeSCathy Zhou /* 38281cb875aeSCathy Zhou * Include the IP header, so that we can specify the IP address/ttl. 38291cb875aeSCathy Zhou */ 38301cb875aeSCathy Zhou if (setsockopt(vif->vvi_sockfd, IPPROTO_IP, IP_HDRINCL, (char *)&on, 38311cb875aeSCathy Zhou sizeof (on)) < 0) { 38321cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_init_txsock_v4(%s): ip_hdrincl " 38331cb875aeSCathy Zhou "failed: %s", vr->vvr_conf.vvc_name, strerror(errno)); 38341cb875aeSCathy Zhou err = VRRP_ESYS; 38351cb875aeSCathy Zhou goto done; 38361cb875aeSCathy Zhou } 38371cb875aeSCathy Zhou 38381cb875aeSCathy Zhou /* 38391cb875aeSCathy Zhou * Disable multicast loopback. 38401cb875aeSCathy Zhou */ 38411cb875aeSCathy Zhou if (setsockopt(vif->vvi_sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &off, 38421cb875aeSCathy Zhou sizeof (char)) == -1) { 38431cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_init_txsock_v4(%s): disable " 38441cb875aeSCathy Zhou "multicast_loop failed: %s", vr->vvr_conf.vvc_name, 38451cb875aeSCathy Zhou strerror(errno)); 38461cb875aeSCathy Zhou err = VRRP_ESYS; 38471cb875aeSCathy Zhou goto done; 38481cb875aeSCathy Zhou } 38491cb875aeSCathy Zhou 38501cb875aeSCathy Zhou vip = TAILQ_FIRST(&vif->vvi_iplist); 38511cb875aeSCathy Zhou /* LINTED E_CONSTANT_CONDITION */ 38521cb875aeSCathy Zhou VRRPADDR2STR(vif->vvi_af, &vip->vip_addr, abuf, INET6_ADDRSTRLEN, 38531cb875aeSCathy Zhou _B_FALSE); 38541cb875aeSCathy Zhou 38551cb875aeSCathy Zhou /* 38561cb875aeSCathy Zhou * Set the output interface to send the VRRP packet. 38571cb875aeSCathy Zhou */ 38581cb875aeSCathy Zhou if (setsockopt(vif->vvi_sockfd, IPPROTO_IP, IP_MULTICAST_IF, 38591cb875aeSCathy Zhou &vip->vip_addr.in4.sin_addr, sizeof (struct in_addr)) < 0) { 38601cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_init_txsock_v4(%s): multcast_if(%s) " 38611cb875aeSCathy Zhou "failed: %s", vr->vvr_conf.vvc_name, abuf, strerror(errno)); 38621cb875aeSCathy Zhou err = VRRP_ESYS; 38631cb875aeSCathy Zhou } else { 38641cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_init_txsock_v4(%s): multcast_if(%s) " 38651cb875aeSCathy Zhou "succeed", vr->vvr_conf.vvc_name, abuf); 38661cb875aeSCathy Zhou } 38671cb875aeSCathy Zhou 38681cb875aeSCathy Zhou done: 38691cb875aeSCathy Zhou if (err != VRRP_SUCCESS) { 38701cb875aeSCathy Zhou (void) close(vif->vvi_sockfd); 38711cb875aeSCathy Zhou vif->vvi_sockfd = -1; 38721cb875aeSCathy Zhou } 38731cb875aeSCathy Zhou 38741cb875aeSCathy Zhou return (err); 38751cb875aeSCathy Zhou } 38761cb875aeSCathy Zhou 38771cb875aeSCathy Zhou /* 38781cb875aeSCathy Zhou * Create the IPv6 socket which is used to send VRRP packets. Note that 38791cb875aeSCathy Zhou * the destination must be the virtual MAC address, so we specify the output 38801cb875aeSCathy Zhou * interface to be the specific VNIC. 38811cb875aeSCathy Zhou */ 38821cb875aeSCathy Zhou static vrrp_err_t 38831cb875aeSCathy Zhou vrrpd_init_txsock_v6(vrrp_vr_t *vr) 38841cb875aeSCathy Zhou { 38851cb875aeSCathy Zhou vrrp_intf_t *vif; /* VNIC interface used to send packets */ 38861cb875aeSCathy Zhou int off = 0, ttl = VRRP_IP_TTL; 38871cb875aeSCathy Zhou vrrp_err_t err = VRRP_SUCCESS; 38881cb875aeSCathy Zhou 38891cb875aeSCathy Zhou vif = vr->vvr_vif; 38901cb875aeSCathy Zhou assert(vr->vvr_conf.vvc_af == AF_INET6); 38911cb875aeSCathy Zhou assert(vif != NULL); 38921cb875aeSCathy Zhou 38931cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_init_txsock_v6(%s) over %s", 38941cb875aeSCathy Zhou vr->vvr_conf.vvc_name, vif->vvi_ifname); 38951cb875aeSCathy Zhou 38961cb875aeSCathy Zhou if (vif->vvi_sockfd != -1) { 38971cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_init_txsock_v6(%s) already done " 38981cb875aeSCathy Zhou "over %s", vr->vvr_conf.vvc_name, vif->vvi_ifname); 38991cb875aeSCathy Zhou return (VRRP_SUCCESS); 39001cb875aeSCathy Zhou } 39011cb875aeSCathy Zhou 39021cb875aeSCathy Zhou vif->vvi_sockfd = socket(vif->vvi_af, SOCK_RAW, IPPROTO_VRRP); 39031cb875aeSCathy Zhou if (vif->vvi_sockfd < 0) { 39041cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_init_txsock_v6(%s): socket() " 39051cb875aeSCathy Zhou "failed: %s", vr->vvr_conf.vvc_name, strerror(errno)); 39061cb875aeSCathy Zhou err = VRRP_ESYS; 39071cb875aeSCathy Zhou goto done; 39081cb875aeSCathy Zhou } 39091cb875aeSCathy Zhou 39101cb875aeSCathy Zhou /* 39111cb875aeSCathy Zhou * Disable multicast loopback. 39121cb875aeSCathy Zhou */ 39131cb875aeSCathy Zhou if (setsockopt(vif->vvi_sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 39141cb875aeSCathy Zhou &off, sizeof (int)) == -1) { 39151cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_init_txsock_v6(%s): disable " 39161cb875aeSCathy Zhou "multicast_loop failed: %s", vr->vvr_conf.vvc_name, 39171cb875aeSCathy Zhou strerror(errno)); 39181cb875aeSCathy Zhou err = VRRP_ESYS; 39191cb875aeSCathy Zhou goto done; 39201cb875aeSCathy Zhou } 39211cb875aeSCathy Zhou 39221cb875aeSCathy Zhou /* 39231cb875aeSCathy Zhou * Set the multicast TTL. 39241cb875aeSCathy Zhou */ 39251cb875aeSCathy Zhou if (setsockopt(vif->vvi_sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 39261cb875aeSCathy Zhou &ttl, sizeof (int)) == -1) { 39271cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_init_txsock_v6(%s): enable " 39281cb875aeSCathy Zhou "multicast_hops %d failed: %s", vr->vvr_conf.vvc_name, 39291cb875aeSCathy Zhou ttl, strerror(errno)); 39301cb875aeSCathy Zhou err = VRRP_ESYS; 39311cb875aeSCathy Zhou goto done; 39321cb875aeSCathy Zhou } 39331cb875aeSCathy Zhou 39341cb875aeSCathy Zhou /* 39351cb875aeSCathy Zhou * Set the output interface to send the VRRP packet. 39361cb875aeSCathy Zhou */ 39371cb875aeSCathy Zhou if (setsockopt(vif->vvi_sockfd, IPPROTO_IPV6, IPV6_MULTICAST_IF, 39381cb875aeSCathy Zhou &vif->vvi_ifindex, sizeof (uint32_t)) < 0) { 39391cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_init_txsock_v6(%s): multicast_if(%d) " 39401cb875aeSCathy Zhou "failed: %s", vr->vvr_conf.vvc_name, vif->vvi_ifindex, 39411cb875aeSCathy Zhou strerror(errno)); 39421cb875aeSCathy Zhou err = VRRP_ESYS; 39431cb875aeSCathy Zhou } else { 39441cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_init_txsock_v6(%s): multicast_if(%d)" 39451cb875aeSCathy Zhou " succeed", vr->vvr_conf.vvc_name, vif->vvi_ifindex); 39461cb875aeSCathy Zhou } 39471cb875aeSCathy Zhou 39481cb875aeSCathy Zhou done: 39491cb875aeSCathy Zhou if (err != VRRP_SUCCESS) { 39501cb875aeSCathy Zhou (void) close(vif->vvi_sockfd); 39511cb875aeSCathy Zhou vif->vvi_sockfd = -1; 39521cb875aeSCathy Zhou } 39531cb875aeSCathy Zhou 39541cb875aeSCathy Zhou return (err); 39551cb875aeSCathy Zhou } 39561cb875aeSCathy Zhou 39571cb875aeSCathy Zhou /* 39581cb875aeSCathy Zhou * Delete the socket which is used to send VRRP packets. Further, clear 39591cb875aeSCathy Zhou * the IFF_NOACCEPT flag based on the VRRP router's accept mode. 39601cb875aeSCathy Zhou */ 39611cb875aeSCathy Zhou static void 39621cb875aeSCathy Zhou vrrpd_fini_txsock(vrrp_vr_t *vr) 39631cb875aeSCathy Zhou { 39641cb875aeSCathy Zhou vrrp_intf_t *vif = vr->vvr_vif; 39651cb875aeSCathy Zhou 39661cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_fini_txsock(%s)", vr->vvr_conf.vvc_name); 39671cb875aeSCathy Zhou 39681cb875aeSCathy Zhou if (vif != NULL) { 39691cb875aeSCathy Zhou if (!vr->vvr_conf.vvc_accept) 39701cb875aeSCathy Zhou (void) vrrpd_set_noaccept(vr, _B_FALSE); 39711cb875aeSCathy Zhou (void) close(vif->vvi_sockfd); 39721cb875aeSCathy Zhou vif->vvi_sockfd = -1; 39731cb875aeSCathy Zhou vr->vvr_vif = NULL; 39741cb875aeSCathy Zhou } 39751cb875aeSCathy Zhou } 39761cb875aeSCathy Zhou 39771cb875aeSCathy Zhou /* 39781cb875aeSCathy Zhou * Given the the pseudo header cksum value (sum), caculate the cksum with 39791cb875aeSCathy Zhou * the rest of VRRP packet. 39801cb875aeSCathy Zhou */ 39811cb875aeSCathy Zhou static uint16_t 39821cb875aeSCathy Zhou in_cksum(int sum, uint16_t plen, void *p) 39831cb875aeSCathy Zhou { 39841cb875aeSCathy Zhou int nleft; 39851cb875aeSCathy Zhou uint16_t *w; 39861cb875aeSCathy Zhou uint16_t answer; 39871cb875aeSCathy Zhou uint16_t odd_byte = 0; 39881cb875aeSCathy Zhou 39891cb875aeSCathy Zhou nleft = plen; 39901cb875aeSCathy Zhou w = (uint16_t *)p; 39911cb875aeSCathy Zhou while (nleft > 1) { 39921cb875aeSCathy Zhou sum += *w++; 39931cb875aeSCathy Zhou nleft -= 2; 39941cb875aeSCathy Zhou } 39951cb875aeSCathy Zhou 39961cb875aeSCathy Zhou /* mop up an odd byte, if necessary */ 39971cb875aeSCathy Zhou if (nleft == 1) { 39981cb875aeSCathy Zhou *(uchar_t *)(&odd_byte) = *(uchar_t *)w; 39991cb875aeSCathy Zhou sum += odd_byte; 40001cb875aeSCathy Zhou } 40011cb875aeSCathy Zhou 40021cb875aeSCathy Zhou /* 40031cb875aeSCathy Zhou * add back carry outs from top 16 bits to low 16 bits 40041cb875aeSCathy Zhou */ 40051cb875aeSCathy Zhou sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 40061cb875aeSCathy Zhou sum += (sum >> 16); /* add carry */ 40071cb875aeSCathy Zhou answer = ~sum; /* truncate to 16 bits */ 40081cb875aeSCathy Zhou return (answer == 0 ? ~0 : answer); 40091cb875aeSCathy Zhou } 40101cb875aeSCathy Zhou 40111cb875aeSCathy Zhou /* Pseudo header for v4 */ 40121cb875aeSCathy Zhou struct pshv4 { 40131cb875aeSCathy Zhou struct in_addr ph4_src; 40141cb875aeSCathy Zhou struct in_addr ph4_dst; 40151cb875aeSCathy Zhou uint8_t ph4_zero; /* always zero */ 40161cb875aeSCathy Zhou uint8_t ph4_protocol; /* protocol used, IPPROTO_VRRP */ 40171cb875aeSCathy Zhou uint16_t ph4_len; /* VRRP payload len */ 40181cb875aeSCathy Zhou }; 40191cb875aeSCathy Zhou 40201cb875aeSCathy Zhou /* 40211cb875aeSCathy Zhou * Checksum routine for VRRP checksum. Note that plen is the upper-layer 40221cb875aeSCathy Zhou * packet length (in the host byte order), and both IP source and destination 40231cb875aeSCathy Zhou * addresses are in the network byte order. 40241cb875aeSCathy Zhou */ 40251cb875aeSCathy Zhou static uint16_t 40261cb875aeSCathy Zhou vrrp_cksum4(struct in_addr *src, struct in_addr *dst, uint16_t plen, 40271cb875aeSCathy Zhou vrrp_pkt_t *vp) 40281cb875aeSCathy Zhou { 40291cb875aeSCathy Zhou struct pshv4 ph4; 40301cb875aeSCathy Zhou int nleft; 40311cb875aeSCathy Zhou uint16_t *w; 40321cb875aeSCathy Zhou int sum = 0; 40331cb875aeSCathy Zhou 40341cb875aeSCathy Zhou ph4.ph4_src = *src; 40351cb875aeSCathy Zhou ph4.ph4_dst = *dst; 40361cb875aeSCathy Zhou ph4.ph4_zero = 0; 40371cb875aeSCathy Zhou ph4.ph4_protocol = IPPROTO_VRRP; 40381cb875aeSCathy Zhou ph4.ph4_len = htons(plen); 40391cb875aeSCathy Zhou 40401cb875aeSCathy Zhou /* 40411cb875aeSCathy Zhou * Our algorithm is simple, using a 32 bit accumulator (sum), 40421cb875aeSCathy Zhou * we add sequential 16 bit words to it, and at the end, fold 40431cb875aeSCathy Zhou * back all the carry bits from the top 16 bits into the lower 40441cb875aeSCathy Zhou * 16 bits. 40451cb875aeSCathy Zhou */ 40461cb875aeSCathy Zhou nleft = sizeof (struct pshv4); 40471cb875aeSCathy Zhou w = (uint16_t *)&ph4; 40481cb875aeSCathy Zhou while (nleft > 0) { 40491cb875aeSCathy Zhou sum += *w++; 40501cb875aeSCathy Zhou nleft -= 2; 40511cb875aeSCathy Zhou } 40521cb875aeSCathy Zhou 40531cb875aeSCathy Zhou return (in_cksum(sum, plen, vp)); 40541cb875aeSCathy Zhou } 40551cb875aeSCathy Zhou 40561cb875aeSCathy Zhou /* Pseudo header for v6 */ 40571cb875aeSCathy Zhou struct pshv6 { 40581cb875aeSCathy Zhou struct in6_addr ph6_src; 40591cb875aeSCathy Zhou struct in6_addr ph6_dst; 40601cb875aeSCathy Zhou uint32_t ph6_len; /* VRRP payload len */ 40611cb875aeSCathy Zhou uint32_t ph6_zero : 24, 40621cb875aeSCathy Zhou ph6_protocol : 8; /* protocol used, IPPROTO_VRRP */ 40631cb875aeSCathy Zhou }; 40641cb875aeSCathy Zhou 40651cb875aeSCathy Zhou /* 40661cb875aeSCathy Zhou * Checksum routine for VRRP checksum. Note that plen is the upper-layer 40671cb875aeSCathy Zhou * packet length (in the host byte order), and both IP source and destination 40681cb875aeSCathy Zhou * addresses are in the network byte order. 40691cb875aeSCathy Zhou */ 40701cb875aeSCathy Zhou static uint16_t 40711cb875aeSCathy Zhou vrrp_cksum6(struct in6_addr *src, struct in6_addr *dst, uint16_t plen, 40721cb875aeSCathy Zhou vrrp_pkt_t *vp) 40731cb875aeSCathy Zhou { 40741cb875aeSCathy Zhou struct pshv6 ph6; 40751cb875aeSCathy Zhou int nleft; 40761cb875aeSCathy Zhou uint16_t *w; 40771cb875aeSCathy Zhou int sum = 0; 40781cb875aeSCathy Zhou 40791cb875aeSCathy Zhou ph6.ph6_src = *src; 40801cb875aeSCathy Zhou ph6.ph6_dst = *dst; 40811cb875aeSCathy Zhou ph6.ph6_zero = 0; 40821cb875aeSCathy Zhou ph6.ph6_protocol = IPPROTO_VRRP; 40831cb875aeSCathy Zhou ph6.ph6_len = htonl((uint32_t)plen); 40841cb875aeSCathy Zhou 40851cb875aeSCathy Zhou /* 40861cb875aeSCathy Zhou * Our algorithm is simple, using a 32 bit accumulator (sum), 40871cb875aeSCathy Zhou * we add sequential 16 bit words to it, and at the end, fold 40881cb875aeSCathy Zhou * back all the carry bits from the top 16 bits into the lower 40891cb875aeSCathy Zhou * 16 bits. 40901cb875aeSCathy Zhou */ 40911cb875aeSCathy Zhou nleft = sizeof (struct pshv6); 40921cb875aeSCathy Zhou w = (uint16_t *)&ph6; 40931cb875aeSCathy Zhou while (nleft > 0) { 40941cb875aeSCathy Zhou sum += *w++; 40951cb875aeSCathy Zhou nleft -= 2; 40961cb875aeSCathy Zhou } 40971cb875aeSCathy Zhou 40981cb875aeSCathy Zhou return (in_cksum(sum, plen, vp)); 40991cb875aeSCathy Zhou } 41001cb875aeSCathy Zhou 41011cb875aeSCathy Zhou vrrp_err_t 41021cb875aeSCathy Zhou vrrpd_state_i2m(vrrp_vr_t *vr) 41031cb875aeSCathy Zhou { 41041cb875aeSCathy Zhou vrrp_err_t err; 41051cb875aeSCathy Zhou 41061cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_state_i2m(%s)", vr->vvr_conf.vvc_name); 41071cb875aeSCathy Zhou 41081cb875aeSCathy Zhou vrrpd_state_trans(VRRP_STATE_INIT, VRRP_STATE_MASTER, vr); 41091cb875aeSCathy Zhou if ((err = vrrpd_virtualip_update(vr, _B_FALSE)) != VRRP_SUCCESS) 41101cb875aeSCathy Zhou return (err); 41111cb875aeSCathy Zhou 41121cb875aeSCathy Zhou (void) vrrpd_send_adv(vr, _B_FALSE); 41131cb875aeSCathy Zhou 41141cb875aeSCathy Zhou vr->vvr_err = VRRP_SUCCESS; 41151cb875aeSCathy Zhou vr->vvr_timeout = vr->vvr_conf.vvc_adver_int; 41161cb875aeSCathy Zhou if ((vr->vvr_timer_id = iu_schedule_timer_ms(vrrpd_timerq, 41171cb875aeSCathy Zhou vr->vvr_timeout, vrrp_adv_timeout, vr)) == -1) { 41181cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_state_i2m(): unable to start timer"); 41191cb875aeSCathy Zhou return (VRRP_ESYS); 41201cb875aeSCathy Zhou } else { 41211cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_state_i2m(%s): start " 41221cb875aeSCathy Zhou "vrrp_adv_timeout(%d)", vr->vvr_conf.vvc_name, 41231cb875aeSCathy Zhou vr->vvr_timeout); 41241cb875aeSCathy Zhou } 41251cb875aeSCathy Zhou return (VRRP_SUCCESS); 41261cb875aeSCathy Zhou } 41271cb875aeSCathy Zhou 41281cb875aeSCathy Zhou vrrp_err_t 41291cb875aeSCathy Zhou vrrpd_state_i2b(vrrp_vr_t *vr) 41301cb875aeSCathy Zhou { 41311cb875aeSCathy Zhou vrrp_err_t err; 41321cb875aeSCathy Zhou 41331cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_state_i2b(%s)", vr->vvr_conf.vvc_name); 41341cb875aeSCathy Zhou 41351cb875aeSCathy Zhou vrrpd_state_trans(VRRP_STATE_INIT, VRRP_STATE_BACKUP, vr); 41361cb875aeSCathy Zhou if ((err = vrrpd_virtualip_update(vr, _B_FALSE)) != VRRP_SUCCESS) 41371cb875aeSCathy Zhou return (err); 41381cb875aeSCathy Zhou 41391cb875aeSCathy Zhou /* 41401cb875aeSCathy Zhou * Reinitialize the Master advertisement interval to be the configured 41411cb875aeSCathy Zhou * value. 41421cb875aeSCathy Zhou */ 41431cb875aeSCathy Zhou vr->vvr_err = VRRP_SUCCESS; 41441cb875aeSCathy Zhou vr->vvr_master_adver_int = vr->vvr_conf.vvc_adver_int; 41451cb875aeSCathy Zhou vr->vvr_timeout = MASTER_DOWN_INTERVAL_VR(vr); 41461cb875aeSCathy Zhou if ((vr->vvr_timer_id = iu_schedule_timer_ms(vrrpd_timerq, 41471cb875aeSCathy Zhou vr->vvr_timeout, vrrp_b2m_timeout, vr)) == -1) { 41481cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_state_i2b(): unable to set timer"); 41491cb875aeSCathy Zhou return (VRRP_ESYS); 41501cb875aeSCathy Zhou } else { 41511cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_state_i2b(%s): start " 41521cb875aeSCathy Zhou "vrrp_b2m_timeout(%d)", vr->vvr_conf.vvc_name, 41531cb875aeSCathy Zhou vr->vvr_timeout); 41541cb875aeSCathy Zhou } 41551cb875aeSCathy Zhou return (VRRP_SUCCESS); 41561cb875aeSCathy Zhou } 41571cb875aeSCathy Zhou 41581cb875aeSCathy Zhou void 41591cb875aeSCathy Zhou vrrpd_state_m2i(vrrp_vr_t *vr) 41601cb875aeSCathy Zhou { 41611cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_state_m2i(%s)", vr->vvr_conf.vvc_name); 41621cb875aeSCathy Zhou 41631cb875aeSCathy Zhou vrrpd_state_trans(VRRP_STATE_MASTER, VRRP_STATE_INIT, vr); 41641cb875aeSCathy Zhou (void) vrrpd_virtualip_update(vr, _B_TRUE); 41651cb875aeSCathy Zhou bzero(&vr->vvr_peer, sizeof (vrrp_peer_t)); 41661cb875aeSCathy Zhou (void) iu_cancel_timer(vrrpd_timerq, vr->vvr_timer_id, NULL); 41671cb875aeSCathy Zhou } 41681cb875aeSCathy Zhou 41691cb875aeSCathy Zhou void 41701cb875aeSCathy Zhou vrrpd_state_b2i(vrrp_vr_t *vr) 41711cb875aeSCathy Zhou { 41721cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_state_b2i(%s)", vr->vvr_conf.vvc_name); 41731cb875aeSCathy Zhou 41741cb875aeSCathy Zhou bzero(&vr->vvr_peer, sizeof (vrrp_peer_t)); 41751cb875aeSCathy Zhou (void) iu_cancel_timer(vrrpd_timerq, vr->vvr_timer_id, NULL); 41761cb875aeSCathy Zhou vrrpd_state_trans(VRRP_STATE_BACKUP, VRRP_STATE_INIT, vr); 41771cb875aeSCathy Zhou (void) vrrpd_virtualip_update(vr, _B_TRUE); 41781cb875aeSCathy Zhou } 41791cb875aeSCathy Zhou 41801cb875aeSCathy Zhou /* ARGSUSED */ 41811cb875aeSCathy Zhou static void 41821cb875aeSCathy Zhou vrrp_b2m_timeout(iu_tq_t *tq, void *arg) 41831cb875aeSCathy Zhou { 41841cb875aeSCathy Zhou vrrp_vr_t *vr = (vrrp_vr_t *)arg; 41851cb875aeSCathy Zhou 41861cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrp_b2m_timeout(%s)", vr->vvr_conf.vvc_name); 41871cb875aeSCathy Zhou (void) vrrpd_state_b2m(vr); 41881cb875aeSCathy Zhou } 41891cb875aeSCathy Zhou 41901cb875aeSCathy Zhou /* ARGSUSED */ 41911cb875aeSCathy Zhou static void 41921cb875aeSCathy Zhou vrrp_adv_timeout(iu_tq_t *tq, void *arg) 41931cb875aeSCathy Zhou { 41941cb875aeSCathy Zhou vrrp_vr_t *vr = (vrrp_vr_t *)arg; 41951cb875aeSCathy Zhou 41961cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrp_adv_timeout(%s)", vr->vvr_conf.vvc_name); 41971cb875aeSCathy Zhou 41981cb875aeSCathy Zhou (void) vrrpd_send_adv(vr, _B_FALSE); 41991cb875aeSCathy Zhou if ((vr->vvr_timer_id = iu_schedule_timer_ms(vrrpd_timerq, 42001cb875aeSCathy Zhou vr->vvr_timeout, vrrp_adv_timeout, vr)) == -1) { 42011cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrp_adv_timeout(%s): start timer failed", 42021cb875aeSCathy Zhou vr->vvr_conf.vvc_name); 42031cb875aeSCathy Zhou } else { 42041cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrp_adv_timeout(%s): start " 42051cb875aeSCathy Zhou "vrrp_adv_timeout(%d)", vr->vvr_conf.vvc_name, 42061cb875aeSCathy Zhou vr->vvr_timeout); 42071cb875aeSCathy Zhou } 42081cb875aeSCathy Zhou } 42091cb875aeSCathy Zhou 42101cb875aeSCathy Zhou vrrp_err_t 42111cb875aeSCathy Zhou vrrpd_state_b2m(vrrp_vr_t *vr) 42121cb875aeSCathy Zhou { 42131cb875aeSCathy Zhou vrrp_err_t err; 42141cb875aeSCathy Zhou 42151cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_state_b2m(%s)", vr->vvr_conf.vvc_name); 42161cb875aeSCathy Zhou 42171cb875aeSCathy Zhou vrrpd_state_trans(VRRP_STATE_BACKUP, VRRP_STATE_MASTER, vr); 42181cb875aeSCathy Zhou if ((err = vrrpd_virtualip_update(vr, _B_FALSE)) != VRRP_SUCCESS) 42191cb875aeSCathy Zhou return (err); 42201cb875aeSCathy Zhou (void) vrrpd_send_adv(vr, _B_FALSE); 42211cb875aeSCathy Zhou 42221cb875aeSCathy Zhou vr->vvr_timeout = vr->vvr_conf.vvc_adver_int; 42231cb875aeSCathy Zhou if ((vr->vvr_timer_id = iu_schedule_timer_ms(vrrpd_timerq, 42241cb875aeSCathy Zhou vr->vvr_timeout, vrrp_adv_timeout, vr)) == -1) { 42251cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_state_b2m(%s): start timer failed", 42261cb875aeSCathy Zhou vr->vvr_conf.vvc_name); 42271cb875aeSCathy Zhou return (VRRP_ESYS); 42281cb875aeSCathy Zhou } else { 42291cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_state_b2m(%s): start " 42301cb875aeSCathy Zhou "vrrp_adv_timeout(%d)", vr->vvr_conf.vvc_name, 42311cb875aeSCathy Zhou vr->vvr_timeout); 42321cb875aeSCathy Zhou } 42331cb875aeSCathy Zhou return (VRRP_SUCCESS); 42341cb875aeSCathy Zhou } 42351cb875aeSCathy Zhou 42361cb875aeSCathy Zhou vrrp_err_t 42371cb875aeSCathy Zhou vrrpd_state_m2b(vrrp_vr_t *vr) 42381cb875aeSCathy Zhou { 42391cb875aeSCathy Zhou vrrp_err_t err; 42401cb875aeSCathy Zhou 42411cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_state_m2b(%s)", vr->vvr_conf.vvc_name); 42421cb875aeSCathy Zhou 42431cb875aeSCathy Zhou vrrpd_state_trans(VRRP_STATE_MASTER, VRRP_STATE_BACKUP, vr); 42441cb875aeSCathy Zhou if ((err = vrrpd_virtualip_update(vr, _B_FALSE)) != VRRP_SUCCESS) 42451cb875aeSCathy Zhou return (err); 42461cb875aeSCathy Zhou 42471cb875aeSCathy Zhou /* 42481cb875aeSCathy Zhou * Cancel the adver_timer. 42491cb875aeSCathy Zhou */ 42501cb875aeSCathy Zhou vr->vvr_master_adver_int = vr->vvr_peer_adver_int; 42511cb875aeSCathy Zhou (void) iu_cancel_timer(vrrpd_timerq, vr->vvr_timer_id, NULL); 42521cb875aeSCathy Zhou vr->vvr_timeout = MASTER_DOWN_INTERVAL_VR(vr); 42531cb875aeSCathy Zhou if ((vr->vvr_timer_id = iu_schedule_timer_ms(vrrpd_timerq, 42541cb875aeSCathy Zhou vr->vvr_timeout, vrrp_b2m_timeout, vr)) == -1) { 42551cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_state_m2b(%s): start timer failed", 42561cb875aeSCathy Zhou vr->vvr_conf.vvc_name); 42571cb875aeSCathy Zhou } else { 42581cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_state_m2b(%s) start " 42591cb875aeSCathy Zhou "vrrp_b2m_timeout(%d)", vr->vvr_conf.vvc_name, 42601cb875aeSCathy Zhou vr->vvr_timeout); 42611cb875aeSCathy Zhou } 42621cb875aeSCathy Zhou return (VRRP_SUCCESS); 42631cb875aeSCathy Zhou } 42641cb875aeSCathy Zhou 42651cb875aeSCathy Zhou /* 42661cb875aeSCathy Zhou * Set the IFF_NOACCESS flag on the VNIC interface of the VRRP router 42671cb875aeSCathy Zhou * based on its access mode. 42681cb875aeSCathy Zhou */ 42691cb875aeSCathy Zhou static vrrp_err_t 42701cb875aeSCathy Zhou vrrpd_set_noaccept(vrrp_vr_t *vr, boolean_t on) 42711cb875aeSCathy Zhou { 42721cb875aeSCathy Zhou vrrp_intf_t *vif = vr->vvr_vif; 42731cb875aeSCathy Zhou uint64_t curr_flags; 42741cb875aeSCathy Zhou struct lifreq lifr; 42751cb875aeSCathy Zhou int s; 42761cb875aeSCathy Zhou 42771cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_set_noaccept(%s, %s)", 42781cb875aeSCathy Zhou vr->vvr_conf.vvc_name, on ? "on" : "off"); 42791cb875aeSCathy Zhou 42801cb875aeSCathy Zhou /* 42811cb875aeSCathy Zhou * Possibly no virtual address exists on this VRRP router yet. 42821cb875aeSCathy Zhou */ 42831cb875aeSCathy Zhou if (vif == NULL) 42841cb875aeSCathy Zhou return (VRRP_SUCCESS); 42851cb875aeSCathy Zhou 42861cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_set_noaccept(%s, %s)", 42871cb875aeSCathy Zhou vif->vvi_ifname, vrrp_state2str(vr->vvr_state)); 42881cb875aeSCathy Zhou 42891cb875aeSCathy Zhou s = (vif->vvi_af == AF_INET) ? vrrpd_ctlsock_fd : vrrpd_ctlsock6_fd; 42901cb875aeSCathy Zhou (void) strncpy(lifr.lifr_name, vif->vvi_ifname, 42911cb875aeSCathy Zhou sizeof (lifr.lifr_name)); 42921cb875aeSCathy Zhou if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 42931cb875aeSCathy Zhou if (errno != ENXIO && errno != ENOENT) { 42941cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_set_noaccept(): " 42951cb875aeSCathy Zhou "SIOCGLIFFLAGS on %s failed: %s", 42961cb875aeSCathy Zhou vif->vvi_ifname, strerror(errno)); 42971cb875aeSCathy Zhou } 42981cb875aeSCathy Zhou return (VRRP_ESYS); 42991cb875aeSCathy Zhou } 43001cb875aeSCathy Zhou 43011cb875aeSCathy Zhou curr_flags = lifr.lifr_flags; 43021cb875aeSCathy Zhou if (on) 43031cb875aeSCathy Zhou lifr.lifr_flags |= IFF_NOACCEPT; 43041cb875aeSCathy Zhou else 43051cb875aeSCathy Zhou lifr.lifr_flags &= ~IFF_NOACCEPT; 43061cb875aeSCathy Zhou 43071cb875aeSCathy Zhou if (lifr.lifr_flags != curr_flags) { 43081cb875aeSCathy Zhou if (ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) { 43091cb875aeSCathy Zhou if (errno != ENXIO && errno != ENOENT) { 43101cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_set_noaccept(%s): " 43111cb875aeSCathy Zhou "SIOCSLIFFLAGS 0x%llx on %s failed: %s", 43121cb875aeSCathy Zhou on ? "no_accept" : "accept", 43131cb875aeSCathy Zhou lifr.lifr_flags, vif->vvi_ifname, 43141cb875aeSCathy Zhou strerror(errno)); 43151cb875aeSCathy Zhou } 43161cb875aeSCathy Zhou return (VRRP_ESYS); 43171cb875aeSCathy Zhou } 43181cb875aeSCathy Zhou } 43191cb875aeSCathy Zhou return (VRRP_SUCCESS); 43201cb875aeSCathy Zhou } 43211cb875aeSCathy Zhou 43221cb875aeSCathy Zhou static vrrp_err_t 43231cb875aeSCathy Zhou vrrpd_virtualip_updateone(vrrp_intf_t *vif, vrrp_ip_t *ip, boolean_t checkonly) 43241cb875aeSCathy Zhou { 43251cb875aeSCathy Zhou vrrp_state_t state = vif->vvi_vr_state; 43261cb875aeSCathy Zhou struct lifreq lifr; 43271cb875aeSCathy Zhou char abuf[INET6_ADDRSTRLEN]; 43281cb875aeSCathy Zhou int af = vif->vvi_af; 43291cb875aeSCathy Zhou uint64_t curr_flags; 43301cb875aeSCathy Zhou int s; 43311cb875aeSCathy Zhou 43321cb875aeSCathy Zhou assert(IS_VIRTUAL_INTF(vif)); 43331cb875aeSCathy Zhou 43341cb875aeSCathy Zhou /* LINTED E_CONSTANT_CONDITION */ 43351cb875aeSCathy Zhou VRRPADDR2STR(af, &ip->vip_addr, abuf, INET6_ADDRSTRLEN, _B_FALSE); 43361cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_virtualip_updateone(%s, %s%s)", 43371cb875aeSCathy Zhou vif->vvi_ifname, abuf, checkonly ? ", checkonly" : ""); 43381cb875aeSCathy Zhou 43391cb875aeSCathy Zhou s = (af == AF_INET) ? vrrpd_ctlsock_fd : vrrpd_ctlsock6_fd; 43401cb875aeSCathy Zhou (void) strncpy(lifr.lifr_name, ip->vip_lifname, 43411cb875aeSCathy Zhou sizeof (lifr.lifr_name)); 43421cb875aeSCathy Zhou if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 43431cb875aeSCathy Zhou if (errno != ENXIO && errno != ENOENT) { 43441cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_virtualip_updateone(%s): " 43451cb875aeSCathy Zhou "SIOCGLIFFLAGS on %s/%s failed: %s", 43461cb875aeSCathy Zhou vif->vvi_ifname, lifr.lifr_name, abuf, 43471cb875aeSCathy Zhou strerror(errno)); 43481cb875aeSCathy Zhou } 43491cb875aeSCathy Zhou return (VRRP_ESYS); 43501cb875aeSCathy Zhou } 43511cb875aeSCathy Zhou 43521cb875aeSCathy Zhou curr_flags = lifr.lifr_flags; 43531cb875aeSCathy Zhou if (state == VRRP_STATE_MASTER) 43541cb875aeSCathy Zhou lifr.lifr_flags |= IFF_UP; 43551cb875aeSCathy Zhou else 43561cb875aeSCathy Zhou lifr.lifr_flags &= ~IFF_UP; 43571cb875aeSCathy Zhou 43581cb875aeSCathy Zhou if (lifr.lifr_flags == curr_flags) 43591cb875aeSCathy Zhou return (VRRP_SUCCESS); 43601cb875aeSCathy Zhou 43611cb875aeSCathy Zhou if (checkonly) { 43621cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "VRRP virtual IP %s/%s was brought %s", 43631cb875aeSCathy Zhou ip->vip_lifname, abuf, 43641cb875aeSCathy Zhou state == VRRP_STATE_MASTER ? "down" : "up"); 43651cb875aeSCathy Zhou return (VRRP_ESYS); 43661cb875aeSCathy Zhou } else if (ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) { 43671cb875aeSCathy Zhou if (errno != ENXIO && errno != ENOENT) { 43681cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_virtualip_updateone(%s, %s): " 43691cb875aeSCathy Zhou "bring %s %s/%s failed: %s", 43701cb875aeSCathy Zhou vif->vvi_ifname, vrrp_state2str(state), 43711cb875aeSCathy Zhou state == VRRP_STATE_MASTER ? "up" : "down", 43721cb875aeSCathy Zhou ip->vip_lifname, abuf, strerror(errno)); 43731cb875aeSCathy Zhou } 43741cb875aeSCathy Zhou return (VRRP_ESYS); 43751cb875aeSCathy Zhou } 43761cb875aeSCathy Zhou return (VRRP_SUCCESS); 43771cb875aeSCathy Zhou } 43781cb875aeSCathy Zhou 43791cb875aeSCathy Zhou static vrrp_err_t 43801cb875aeSCathy Zhou vrrpd_virtualip_update(vrrp_vr_t *vr, boolean_t checkonly) 43811cb875aeSCathy Zhou { 43821cb875aeSCathy Zhou vrrp_state_t state; 43831cb875aeSCathy Zhou vrrp_intf_t *vif = vr->vvr_vif; 43841cb875aeSCathy Zhou vrrp_ip_t *ip, *nextip; 43851cb875aeSCathy Zhou char abuf[INET6_ADDRSTRLEN]; 43861cb875aeSCathy Zhou vrrp_err_t err; 43871cb875aeSCathy Zhou 43881cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_virtualip_update(%s, %s, %s)%s", 43891cb875aeSCathy Zhou vr->vvr_conf.vvc_name, vrrp_state2str(vr->vvr_state), 43901cb875aeSCathy Zhou vif->vvi_ifname, checkonly ? " checkonly" : ""); 43911cb875aeSCathy Zhou 43921cb875aeSCathy Zhou state = vr->vvr_state; 43931cb875aeSCathy Zhou assert(vif != NULL); 43941cb875aeSCathy Zhou assert(IS_VIRTUAL_INTF(vif)); 43951cb875aeSCathy Zhou assert(vif->vvi_vr_state != state); 43961cb875aeSCathy Zhou vif->vvi_vr_state = state; 43971cb875aeSCathy Zhou for (ip = TAILQ_FIRST(&vif->vvi_iplist); ip != NULL; ip = nextip) { 43981cb875aeSCathy Zhou nextip = TAILQ_NEXT(ip, vip_next); 43991cb875aeSCathy Zhou err = vrrpd_virtualip_updateone(vif, ip, _B_FALSE); 44001cb875aeSCathy Zhou if (!checkonly && err != VRRP_SUCCESS) { 44011cb875aeSCathy Zhou /* LINTED E_CONSTANT_CONDITION */ 44021cb875aeSCathy Zhou VRRPADDR2STR(vif->vvi_af, &ip->vip_addr, abuf, 44031cb875aeSCathy Zhou INET6_ADDRSTRLEN, _B_FALSE); 44041cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_virtualip_update() update " 44051cb875aeSCathy Zhou "%s over %s failed", abuf, vif->vvi_ifname); 44061cb875aeSCathy Zhou vrrpd_delete_ip(vif, ip); 44071cb875aeSCathy Zhou } 44081cb875aeSCathy Zhou } 44091cb875aeSCathy Zhou 44101cb875aeSCathy Zhou /* 44111cb875aeSCathy Zhou * The IP address is deleted when it is failed to be brought 44121cb875aeSCathy Zhou * up. If no IP addresses are left, delete this interface. 44131cb875aeSCathy Zhou */ 44141cb875aeSCathy Zhou if (!checkonly && TAILQ_EMPTY(&vif->vvi_iplist)) { 44151cb875aeSCathy Zhou vrrp_log(VRRP_DBG0, "vrrpd_virtualip_update(): " 44161cb875aeSCathy Zhou "no IP left over %s", vif->vvi_ifname); 44171cb875aeSCathy Zhou vrrpd_delete_if(vif, _B_TRUE); 44181cb875aeSCathy Zhou return (VRRP_ENOVIRT); 44191cb875aeSCathy Zhou } 44201cb875aeSCathy Zhou return (VRRP_SUCCESS); 44211cb875aeSCathy Zhou } 44221cb875aeSCathy Zhou 44231cb875aeSCathy Zhou void 44241cb875aeSCathy Zhou vrrpd_state_trans(vrrp_state_t prev_s, vrrp_state_t s, vrrp_vr_t *vr) 44251cb875aeSCathy Zhou { 44261cb875aeSCathy Zhou vrrp_log(VRRP_DBG1, "vrrpd_state_trans(%s): %s --> %s", 44271cb875aeSCathy Zhou vr->vvr_conf.vvc_name, vrrp_state2str(prev_s), vrrp_state2str(s)); 44281cb875aeSCathy Zhou 44291cb875aeSCathy Zhou assert(vr->vvr_state == prev_s); 44301cb875aeSCathy Zhou vr->vvr_state = s; 44311cb875aeSCathy Zhou vr->vvr_prev_state = prev_s; 44321cb875aeSCathy Zhou (void) gettimeofday(&vr->vvr_st_time, NULL); 44331cb875aeSCathy Zhou (void) vrrpd_post_event(vr->vvr_conf.vvc_name, prev_s, s); 44341cb875aeSCathy Zhou } 44351cb875aeSCathy Zhou 44361cb875aeSCathy Zhou static int 44371cb875aeSCathy Zhou vrrpd_post_event(const char *name, vrrp_state_t prev_st, vrrp_state_t st) 44381cb875aeSCathy Zhou { 44391cb875aeSCathy Zhou sysevent_id_t eid; 44401cb875aeSCathy Zhou nvlist_t *nvl = NULL; 44411cb875aeSCathy Zhou 44421cb875aeSCathy Zhou /* 44431cb875aeSCathy Zhou * sysevent is not supported in the non-global zone 44441cb875aeSCathy Zhou */ 44451cb875aeSCathy Zhou if (getzoneid() != GLOBAL_ZONEID) 44461cb875aeSCathy Zhou return (0); 44471cb875aeSCathy Zhou 44481cb875aeSCathy Zhou if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 44491cb875aeSCathy Zhou goto failed; 44501cb875aeSCathy Zhou 44511cb875aeSCathy Zhou if (nvlist_add_uint8(nvl, VRRP_EVENT_VERSION, 44521cb875aeSCathy Zhou VRRP_EVENT_CUR_VERSION) != 0) 44531cb875aeSCathy Zhou goto failed; 44541cb875aeSCathy Zhou 44551cb875aeSCathy Zhou if (nvlist_add_string(nvl, VRRP_EVENT_ROUTER_NAME, name) != 0) 44561cb875aeSCathy Zhou goto failed; 44571cb875aeSCathy Zhou 44581cb875aeSCathy Zhou if (nvlist_add_uint8(nvl, VRRP_EVENT_STATE, st) != 0) 44591cb875aeSCathy Zhou goto failed; 44601cb875aeSCathy Zhou 44611cb875aeSCathy Zhou if (nvlist_add_uint8(nvl, VRRP_EVENT_PREV_STATE, prev_st) != 0) 44621cb875aeSCathy Zhou goto failed; 44631cb875aeSCathy Zhou 44641cb875aeSCathy Zhou if (sysevent_post_event(EC_VRRP, ESC_VRRP_STATE_CHANGE, 44651cb875aeSCathy Zhou SUNW_VENDOR, VRRP_EVENT_PUBLISHER, nvl, &eid) == 0) { 44661cb875aeSCathy Zhou nvlist_free(nvl); 44671cb875aeSCathy Zhou return (0); 44681cb875aeSCathy Zhou } 44691cb875aeSCathy Zhou 44701cb875aeSCathy Zhou failed: 44711cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "vrrpd_post_event(): `state change (%s --> %s)' " 44721cb875aeSCathy Zhou "sysevent posting failed: %s", vrrp_state2str(prev_st), 44731cb875aeSCathy Zhou vrrp_state2str(st), strerror(errno)); 44741cb875aeSCathy Zhou 44751cb875aeSCathy Zhou nvlist_free(nvl); 44761cb875aeSCathy Zhou return (-1); 44771cb875aeSCathy Zhou } 44781cb875aeSCathy Zhou 44791cb875aeSCathy Zhou /* 44801cb875aeSCathy Zhou * timeval processing functions 44811cb875aeSCathy Zhou */ 44821cb875aeSCathy Zhou static int 44831cb875aeSCathy Zhou timeval_to_milli(struct timeval tv) 44841cb875aeSCathy Zhou { 44851cb875aeSCathy Zhou return ((int)(tv.tv_sec * 1000 + tv.tv_usec / 1000 + 0.5)); 44861cb875aeSCathy Zhou } 44871cb875aeSCathy Zhou 44881cb875aeSCathy Zhou static struct timeval 44891cb875aeSCathy Zhou timeval_delta(struct timeval t1, struct timeval t2) 44901cb875aeSCathy Zhou { 44911cb875aeSCathy Zhou struct timeval t; 44921cb875aeSCathy Zhou t.tv_sec = t1.tv_sec - t2.tv_sec; 44931cb875aeSCathy Zhou t.tv_usec = t1.tv_usec - t2.tv_usec; 44941cb875aeSCathy Zhou 44951cb875aeSCathy Zhou if (t.tv_usec < 0) { 44961cb875aeSCathy Zhou t.tv_usec += 1000000; 44971cb875aeSCathy Zhou t.tv_sec--; 44981cb875aeSCathy Zhou } 44991cb875aeSCathy Zhou return (t); 45001cb875aeSCathy Zhou } 45011cb875aeSCathy Zhou 45021cb875aeSCathy Zhou /* 45031cb875aeSCathy Zhou * print error messages to the terminal or to syslog 45041cb875aeSCathy Zhou */ 45051cb875aeSCathy Zhou static void 45061cb875aeSCathy Zhou vrrp_log(int level, char *message, ...) 45071cb875aeSCathy Zhou { 45081cb875aeSCathy Zhou va_list ap; 45091cb875aeSCathy Zhou int log_level = -1; 45101cb875aeSCathy Zhou 45111cb875aeSCathy Zhou va_start(ap, message); 45121cb875aeSCathy Zhou 45131cb875aeSCathy Zhou if (vrrp_logflag == 0) { 45141cb875aeSCathy Zhou if (level <= vrrp_debug_level) { 45151cb875aeSCathy Zhou /* 45161cb875aeSCathy Zhou * VRRP_ERR goes to stderr, others go to stdout 45171cb875aeSCathy Zhou */ 45181cb875aeSCathy Zhou FILE *out = (level <= VRRP_ERR) ? stderr : stdout; 4519c5e0ece0SCathy Zhou (void) fprintf(out, "vrrpd: "); 45201cb875aeSCathy Zhou /* LINTED: E_SEC_PRINTF_VAR_FMT */ 45211cb875aeSCathy Zhou (void) vfprintf(out, message, ap); 45221cb875aeSCathy Zhou (void) fprintf(out, "\n"); 45231cb875aeSCathy Zhou (void) fflush(out); 45241cb875aeSCathy Zhou } 45251cb875aeSCathy Zhou va_end(ap); 45261cb875aeSCathy Zhou return; 45271cb875aeSCathy Zhou } 45281cb875aeSCathy Zhou 45291cb875aeSCathy Zhou /* 45301cb875aeSCathy Zhou * translate VRRP_* to LOG_* 45311cb875aeSCathy Zhou */ 45321cb875aeSCathy Zhou switch (level) { 45331cb875aeSCathy Zhou case VRRP_ERR: 45341cb875aeSCathy Zhou log_level = LOG_ERR; 45351cb875aeSCathy Zhou break; 45361cb875aeSCathy Zhou case VRRP_WARNING: 45371cb875aeSCathy Zhou log_level = LOG_WARNING; 45381cb875aeSCathy Zhou break; 45391cb875aeSCathy Zhou case VRRP_NOTICE: 45401cb875aeSCathy Zhou log_level = LOG_NOTICE; 45411cb875aeSCathy Zhou break; 45421cb875aeSCathy Zhou case VRRP_DBG0: 45431cb875aeSCathy Zhou log_level = LOG_INFO; 45441cb875aeSCathy Zhou break; 45451cb875aeSCathy Zhou default: 45461cb875aeSCathy Zhou log_level = LOG_DEBUG; 45471cb875aeSCathy Zhou break; 45481cb875aeSCathy Zhou } 45491cb875aeSCathy Zhou 45501cb875aeSCathy Zhou /* LINTED: E_SEC_PRINTF_VAR_FMT */ 45511cb875aeSCathy Zhou (void) vsyslog(log_level, message, ap); 45521cb875aeSCathy Zhou va_end(ap); 45531cb875aeSCathy Zhou } 4554