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