11cb875aeSCathy Zhou /*
21cb875aeSCathy Zhou  * CDDL HEADER START
31cb875aeSCathy Zhou  *
41cb875aeSCathy Zhou  * The contents of this file are subject to the terms of the
51cb875aeSCathy Zhou  * Common Development and Distribution License (the "License").
61cb875aeSCathy Zhou  * You may not use this file except in compliance with the License.
71cb875aeSCathy Zhou  *
81cb875aeSCathy Zhou  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91cb875aeSCathy Zhou  * or http://www.opensolaris.org/os/licensing.
101cb875aeSCathy Zhou  * See the License for the specific language governing permissions
111cb875aeSCathy Zhou  * and limitations under the License.
121cb875aeSCathy Zhou  *
131cb875aeSCathy Zhou  * When distributing Covered Code, include this CDDL HEADER in each
141cb875aeSCathy Zhou  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151cb875aeSCathy Zhou  * If applicable, add the following below this CDDL HEADER, with the
161cb875aeSCathy Zhou  * fields enclosed by brackets "[]" replaced with your own identifying
171cb875aeSCathy Zhou  * information: Portions Copyright [yyyy] [name of copyright owner]
181cb875aeSCathy Zhou  *
191cb875aeSCathy Zhou  * CDDL HEADER END
201cb875aeSCathy Zhou  */
211cb875aeSCathy Zhou 
221cb875aeSCathy Zhou /*
23f6da83d4SAnurag S. Maskey  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
241cb875aeSCathy Zhou  */
251cb875aeSCathy Zhou 
262954adb0SRob Gulewich /*
272954adb0SRob Gulewich  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
282954adb0SRob Gulewich  */
292954adb0SRob Gulewich 
301cb875aeSCathy Zhou #include <sys/types.h>
311cb875aeSCathy Zhou #include <sys/socket.h>
321cb875aeSCathy Zhou #include <sys/sockio.h>
331cb875aeSCathy Zhou #include <sys/sysevent/vrrp.h>
341cb875aeSCathy Zhou #include <sys/sysevent/eventdefs.h>
351cb875aeSCathy Zhou #include <sys/varargs.h>
361cb875aeSCathy Zhou #include <auth_attr.h>
371cb875aeSCathy Zhou #include <ctype.h>
381cb875aeSCathy Zhou #include <fcntl.h>
391cb875aeSCathy Zhou #include <stdlib.h>
401cb875aeSCathy Zhou #include <strings.h>
411cb875aeSCathy Zhou #include <errno.h>
421cb875aeSCathy Zhou #include <unistd.h>
431cb875aeSCathy Zhou #include <zone.h>
441cb875aeSCathy Zhou #include <libsysevent.h>
451cb875aeSCathy Zhou #include <limits.h>
461cb875aeSCathy Zhou #include <locale.h>
471cb875aeSCathy Zhou #include <arpa/inet.h>
481cb875aeSCathy Zhou #include <signal.h>
491cb875aeSCathy Zhou #include <assert.h>
501cb875aeSCathy Zhou #include <ucred.h>
511cb875aeSCathy Zhou #include <bsm/adt.h>
521cb875aeSCathy Zhou #include <bsm/adt_event.h>
531cb875aeSCathy Zhou #include <priv_utils.h>
541cb875aeSCathy Zhou #include <libdllink.h>
551cb875aeSCathy Zhou #include <libdlvnic.h>
56f6da83d4SAnurag S. Maskey #include <libipadm.h>
571cb875aeSCathy Zhou #include <pwd.h>
581cb875aeSCathy Zhou #include <libvrrpadm.h>
591cb875aeSCathy Zhou #include <net/route.h>
601cb875aeSCathy Zhou #include "vrrpd_impl.h"
611cb875aeSCathy Zhou 
621cb875aeSCathy Zhou /*
631cb875aeSCathy Zhou  * A VRRP router can be only start participating the VRRP protocol of a virtual
641cb875aeSCathy Zhou  * router when all the following conditions are met:
651cb875aeSCathy Zhou  *
661cb875aeSCathy Zhou  * - The VRRP router is enabled (vr->vvr_conf.vvc_enabled is _B_TRUE)
671cb875aeSCathy Zhou  * - The RX socket is successfully created over the physical interface to
681cb875aeSCathy Zhou  *   receive the VRRP multicast advertisement. Note that one RX socket can
691cb875aeSCathy Zhou  *   be shared by several VRRP routers configured over the same physical
701cb875aeSCathy Zhou  *   interface. (See vrrpd_init_rxsock())
711cb875aeSCathy Zhou  * - The TX socket is successfully created over the VNIC interface to send
721cb875aeSCathy Zhou  *   the VRRP advertisment. (See vrrpd_init_txsock())
731cb875aeSCathy Zhou  * - The primary IP address has been successfully selected over the physical
741cb875aeSCathy Zhou  *   interface. (See vrrpd_select_primary())
751cb875aeSCathy Zhou  *
761cb875aeSCathy Zhou  * If a VRRP router is enabled but the other conditions haven't be satisfied,
771cb875aeSCathy Zhou  * the router will be stay at the VRRP_STATE_INIT state. If all the above
781cb875aeSCathy Zhou  * conditions are met, the VRRP router will be transit to either
791cb875aeSCathy Zhou  * the VRRP_STATE_MASTER or the VRRP_STATE_BACKUP state, depends on the VRRP
801cb875aeSCathy Zhou  * protocol.
811cb875aeSCathy Zhou  */
821cb875aeSCathy Zhou 
831cb875aeSCathy Zhou #define	skip_whitespace(p)	while (isspace(*(p))) ++(p)
841cb875aeSCathy Zhou 
851cb875aeSCathy Zhou #define	BUFFSIZE	65536
861cb875aeSCathy Zhou 
871cb875aeSCathy Zhou #define	VRRPCONF	"/etc/inet/vrrp.conf"
881cb875aeSCathy Zhou 
891cb875aeSCathy Zhou typedef struct vrrpd_rtsock_s {
901cb875aeSCathy Zhou 	int		vrt_af;		/* address family */
911cb875aeSCathy Zhou 	int		vrt_fd;		/* socket for the PF_ROUTE msg */
921cb875aeSCathy Zhou 	iu_event_id_t	vrt_eid;	/* event ID */
931cb875aeSCathy Zhou } vrrpd_rtsock_t;
941cb875aeSCathy Zhou 
95f6da83d4SAnurag S. Maskey static ipadm_handle_t	vrrp_ipadm_handle = NULL;	/* libipadm handle */
961cb875aeSCathy Zhou static int		vrrp_logflag = 0;
971cb875aeSCathy Zhou boolean_t		vrrp_debug_level = 0;
981cb875aeSCathy Zhou iu_eh_t			*vrrpd_eh = NULL;
991cb875aeSCathy Zhou iu_tq_t			*vrrpd_timerq = NULL;
1001cb875aeSCathy Zhou static vrrp_handle_t	vrrpd_vh = NULL;
1011cb875aeSCathy Zhou static int		vrrpd_cmdsock_fd = -1;	/* socket to communicate */
1021cb875aeSCathy Zhou 						/* between vrrpd/libvrrpadm */
1031cb875aeSCathy Zhou static iu_event_id_t	vrrpd_cmdsock_eid = -1;
1041cb875aeSCathy Zhou static int		vrrpd_ctlsock_fd = -1;	/* socket to bring up/down */
1051cb875aeSCathy Zhou 						/* the virtual IP addresses */
1061cb875aeSCathy Zhou static int		vrrpd_ctlsock6_fd = -1;
1071cb875aeSCathy Zhou static vrrpd_rtsock_t	vrrpd_rtsocks[2] = {
1081cb875aeSCathy Zhou 	{AF_INET, -1, -1},
1091cb875aeSCathy Zhou 	{AF_INET6, -1, -1}
1101cb875aeSCathy Zhou };
1111cb875aeSCathy Zhou static iu_timer_id_t	vrrp_scan_timer_id = -1;
1121cb875aeSCathy Zhou 
1131cb875aeSCathy Zhou TAILQ_HEAD(vrrp_vr_list_s, vrrp_vr_s);
1141cb875aeSCathy Zhou TAILQ_HEAD(vrrp_intf_list_s, vrrp_intf_s);
1151cb875aeSCathy Zhou static struct vrrp_vr_list_s	vrrp_vr_list;
1161cb875aeSCathy Zhou static struct vrrp_intf_list_s	vrrp_intf_list;
1171cb875aeSCathy Zhou static char		vrrpd_conffile[MAXPATHLEN];
1181cb875aeSCathy Zhou 
1191cb875aeSCathy Zhou /*
1201cb875aeSCathy Zhou  * Multicast address of VRRP advertisement in network byte order
1211cb875aeSCathy Zhou  */
1221cb875aeSCathy Zhou static vrrp_addr_t	vrrp_muladdr4;
1231cb875aeSCathy Zhou static vrrp_addr_t	vrrp_muladdr6;
1241cb875aeSCathy Zhou 
1251cb875aeSCathy Zhou static int		vrrpd_scan_interval = 20000;	/* ms */
126c5e0ece0SCathy Zhou static int		pfds[2];
1271cb875aeSCathy Zhou 
1281cb875aeSCathy Zhou /*
1291cb875aeSCathy Zhou  * macros to calculate skew_time and master_down_timer
1301cb875aeSCathy Zhou  *
1311cb875aeSCathy Zhou  * Note that the input is in centisecs and output are in msecs
1321cb875aeSCathy Zhou  */
1331cb875aeSCathy Zhou #define	SKEW_TIME(pri, intv)	((intv) * (256 - (pri)) / 256)
1341cb875aeSCathy Zhou #define	MASTER_DOWN_INTERVAL(pri, intv)	(3 * (intv) + SKEW_TIME((pri), (intv)))
1351cb875aeSCathy Zhou 
1361cb875aeSCathy Zhou #define	SKEW_TIME_VR(vr)	\
1371cb875aeSCathy Zhou 	SKEW_TIME((vr)->vvr_conf.vvc_pri, (vr)->vvr_master_adver_int)
1381cb875aeSCathy Zhou #define	MASTER_DOWN_INTERVAL_VR(vr)	\
1391cb875aeSCathy Zhou 	MASTER_DOWN_INTERVAL((vr)->vvr_conf.vvc_pri, (vr)->vvr_master_adver_int)
1401cb875aeSCathy Zhou 
1411cb875aeSCathy Zhou #define	VRRP_CONF_UPDATE	0x01
1421cb875aeSCathy Zhou #define	VRRP_CONF_DELETE	0x02
1431cb875aeSCathy Zhou 
1441cb875aeSCathy Zhou static char *af_str(int);
1451cb875aeSCathy Zhou 
1461cb875aeSCathy Zhou static iu_tq_callback_t vrrp_adv_timeout;
1471cb875aeSCathy Zhou static iu_tq_callback_t vrrp_b2m_timeout;
1481cb875aeSCathy Zhou static iu_eh_callback_t vrrpd_sock_handler;
1491cb875aeSCathy Zhou static iu_eh_callback_t vrrpd_rtsock_handler;
1501cb875aeSCathy Zhou static iu_eh_callback_t vrrpd_cmdsock_handler;
1511cb875aeSCathy Zhou 
1521cb875aeSCathy Zhou static int daemon_init();
1531cb875aeSCathy Zhou 
1541cb875aeSCathy Zhou static vrrp_err_t vrrpd_init();
1551cb875aeSCathy Zhou static void vrrpd_fini();
1561cb875aeSCathy Zhou static vrrp_err_t vrrpd_cmdsock_create();
1571cb875aeSCathy Zhou static void vrrpd_cmdsock_destroy();
1581cb875aeSCathy Zhou static vrrp_err_t vrrpd_rtsock_create();
1591cb875aeSCathy Zhou static void vrrpd_rtsock_destroy();
1601cb875aeSCathy Zhou static vrrp_err_t vrrpd_ctlsock_create();
1611cb875aeSCathy Zhou static void vrrpd_ctlsock_destroy();
1621cb875aeSCathy Zhou 
1631cb875aeSCathy Zhou static void vrrpd_scan_timer(iu_tq_t *, void *);
1641cb875aeSCathy Zhou static void vrrpd_scan(int);
1651cb875aeSCathy Zhou static vrrp_err_t vrrpd_init_rxsock(vrrp_vr_t *);
1661cb875aeSCathy Zhou static void vrrpd_fini_rxsock(vrrp_vr_t *);
1671cb875aeSCathy Zhou static vrrp_err_t vrrpd_init_txsock(vrrp_vr_t *);
1681cb875aeSCathy Zhou static vrrp_err_t vrrpd_init_txsock_v4(vrrp_vr_t *);
1691cb875aeSCathy Zhou static vrrp_err_t vrrpd_init_txsock_v6(vrrp_vr_t *);
1701cb875aeSCathy Zhou static void vrrpd_fini_txsock(vrrp_vr_t *);
1711cb875aeSCathy Zhou 
1721cb875aeSCathy Zhou static vrrp_err_t vrrpd_create_vr(vrrp_vr_conf_t *);
1731cb875aeSCathy Zhou static vrrp_err_t vrrpd_enable_vr(vrrp_vr_t *);
1741cb875aeSCathy Zhou static void vrrpd_disable_vr(vrrp_vr_t *, vrrp_intf_t *, boolean_t);
1751cb875aeSCathy Zhou static void vrrpd_delete_vr(vrrp_vr_t *);
1761cb875aeSCathy Zhou 
1771cb875aeSCathy Zhou static vrrp_err_t vrrpd_create(vrrp_vr_conf_t *, boolean_t);
1781cb875aeSCathy Zhou static vrrp_err_t vrrpd_delete(const char *);
1791cb875aeSCathy Zhou static vrrp_err_t vrrpd_enable(const char *, boolean_t);
1801cb875aeSCathy Zhou static vrrp_err_t vrrpd_disable(const char *);
1811cb875aeSCathy Zhou static vrrp_err_t vrrpd_modify(vrrp_vr_conf_t *, uint32_t);
1821cb875aeSCathy Zhou static void vrrpd_list(vrid_t, char *, int, vrrp_ret_list_t *, size_t *);
1831cb875aeSCathy Zhou static void vrrpd_query(const char *, vrrp_ret_query_t *, size_t *);
1841cb875aeSCathy Zhou 
1851cb875aeSCathy Zhou static boolean_t vrrp_rd_prop_name(vrrp_vr_conf_t *, const char *);
1861cb875aeSCathy Zhou static boolean_t vrrp_rd_prop_vrid(vrrp_vr_conf_t *, const char *);
1871cb875aeSCathy Zhou static boolean_t vrrp_rd_prop_af(vrrp_vr_conf_t *, const char *);
1881cb875aeSCathy Zhou static boolean_t vrrp_rd_prop_pri(vrrp_vr_conf_t *, const char *);
1891cb875aeSCathy Zhou static boolean_t vrrp_rd_prop_adver_int(vrrp_vr_conf_t *, const char *);
1901cb875aeSCathy Zhou static boolean_t vrrp_rd_prop_preempt(vrrp_vr_conf_t *, const char *);
1911cb875aeSCathy Zhou static boolean_t vrrp_rd_prop_accept(vrrp_vr_conf_t *, const char *);
1921cb875aeSCathy Zhou static boolean_t vrrp_rd_prop_ifname(vrrp_vr_conf_t *, const char *);
1931cb875aeSCathy Zhou static boolean_t vrrp_rd_prop_enabled(vrrp_vr_conf_t *, const char *);
1941cb875aeSCathy Zhou static int vrrp_wt_prop_name(vrrp_vr_conf_t *, char *, size_t);
1951cb875aeSCathy Zhou static int vrrp_wt_prop_vrid(vrrp_vr_conf_t *, char *, size_t);
1961cb875aeSCathy Zhou static int vrrp_wt_prop_af(vrrp_vr_conf_t *, char *, size_t);
1971cb875aeSCathy Zhou static int vrrp_wt_prop_pri(vrrp_vr_conf_t *, char *, size_t);
1981cb875aeSCathy Zhou static int vrrp_wt_prop_adver_int(vrrp_vr_conf_t *, char *, size_t);
1991cb875aeSCathy Zhou static int vrrp_wt_prop_preempt(vrrp_vr_conf_t *, char *, size_t);
2001cb875aeSCathy Zhou static int vrrp_wt_prop_accept(vrrp_vr_conf_t *, char *, size_t);
2011cb875aeSCathy Zhou static int vrrp_wt_prop_ifname(vrrp_vr_conf_t *, char *, size_t);
2021cb875aeSCathy Zhou static int vrrp_wt_prop_enabled(vrrp_vr_conf_t *, char *, size_t);
2031cb875aeSCathy Zhou 
2041cb875aeSCathy Zhou static void vrrpd_cmd_create(void *, void *, size_t *);
2051cb875aeSCathy Zhou static void vrrpd_cmd_delete(void *, void *, size_t *);
2061cb875aeSCathy Zhou static void vrrpd_cmd_enable(void *, void *, size_t *);
2071cb875aeSCathy Zhou static void vrrpd_cmd_disable(void *, void *, size_t *);
2081cb875aeSCathy Zhou static void vrrpd_cmd_modify(void *, void *, size_t *);
2091cb875aeSCathy Zhou static void vrrpd_cmd_list(void *, void *, size_t *);
2101cb875aeSCathy Zhou static void vrrpd_cmd_query(void *, void *, size_t *);
2111cb875aeSCathy Zhou 
2121cb875aeSCathy Zhou static vrrp_vr_t *vrrpd_lookup_vr_by_vrid(char *, vrid_t vrid_t, int);
2131cb875aeSCathy Zhou static vrrp_vr_t *vrrpd_lookup_vr_by_name(const char *);
2141cb875aeSCathy Zhou static vrrp_intf_t *vrrpd_lookup_if(const char *, int);
2151cb875aeSCathy Zhou static vrrp_err_t vrrpd_create_if(const char *, int, uint32_t, vrrp_intf_t **);
2161cb875aeSCathy Zhou static void vrrpd_delete_if(vrrp_intf_t *, boolean_t);
2171cb875aeSCathy Zhou static vrrp_err_t vrrpd_create_ip(vrrp_intf_t *, const char *, vrrp_addr_t *,
2181cb875aeSCathy Zhou     uint64_t flags);
2191cb875aeSCathy Zhou static void vrrpd_delete_ip(vrrp_intf_t *, vrrp_ip_t *);
2201cb875aeSCathy Zhou 
2211cb875aeSCathy Zhou static void vrrpd_init_ipcache(int);
2221cb875aeSCathy Zhou static void vrrpd_update_ipcache(int);
223f6da83d4SAnurag S. Maskey static ipadm_status_t vrrpd_walk_addr_info(int);
2241cb875aeSCathy Zhou static vrrp_err_t vrrpd_add_ipaddr(char *, int, vrrp_addr_t *,
2251cb875aeSCathy Zhou     int, uint64_t);
2261cb875aeSCathy Zhou static vrrp_ip_t *vrrpd_select_primary(vrrp_intf_t *);
2271cb875aeSCathy Zhou static void vrrpd_reselect_primary(vrrp_intf_t *);
2281cb875aeSCathy Zhou static void vrrpd_reenable_all_vr();
2291cb875aeSCathy Zhou static void vrrpd_remove_if(vrrp_intf_t *, boolean_t);
2301cb875aeSCathy Zhou 
2311cb875aeSCathy Zhou static uint16_t in_cksum(int, uint16_t, void *);
2321cb875aeSCathy Zhou static uint16_t vrrp_cksum4(struct in_addr *, struct in_addr *,
2331cb875aeSCathy Zhou     uint16_t, vrrp_pkt_t *);
2341cb875aeSCathy Zhou static uint16_t vrrp_cksum6(struct in6_addr *, struct in6_addr *,
2351cb875aeSCathy Zhou     uint16_t, vrrp_pkt_t *);
2361cb875aeSCathy Zhou static size_t vrrpd_build_vrrp(vrrp_vr_t *, uchar_t *, int, boolean_t);
2371cb875aeSCathy Zhou 
2381cb875aeSCathy Zhou static void vrrpd_process_adv(vrrp_vr_t *, vrrp_addr_t *, vrrp_pkt_t *);
2391cb875aeSCathy Zhou static vrrp_err_t vrrpd_send_adv(vrrp_vr_t *, boolean_t);
2401cb875aeSCathy Zhou 
2411cb875aeSCathy Zhou /* state transition functions */
2421cb875aeSCathy Zhou static vrrp_err_t vrrpd_state_i2m(vrrp_vr_t *);
2431cb875aeSCathy Zhou static vrrp_err_t vrrpd_state_i2b(vrrp_vr_t *);
2441cb875aeSCathy Zhou static void vrrpd_state_m2i(vrrp_vr_t *);
2451cb875aeSCathy Zhou static void vrrpd_state_b2i(vrrp_vr_t *);
2461cb875aeSCathy Zhou static vrrp_err_t vrrpd_state_b2m(vrrp_vr_t *);
2471cb875aeSCathy Zhou static vrrp_err_t vrrpd_state_m2b(vrrp_vr_t *);
2481cb875aeSCathy Zhou static void vrrpd_state_trans(vrrp_state_t, vrrp_state_t, vrrp_vr_t *);
2491cb875aeSCathy Zhou 
2501cb875aeSCathy Zhou static vrrp_err_t vrrpd_set_noaccept(vrrp_vr_t *, boolean_t);
2511cb875aeSCathy Zhou static vrrp_err_t vrrpd_virtualip_update(vrrp_vr_t *, boolean_t);
2521cb875aeSCathy Zhou static vrrp_err_t vrrpd_virtualip_updateone(vrrp_intf_t *, vrrp_ip_t *,
2531cb875aeSCathy Zhou     boolean_t);
2541cb875aeSCathy Zhou static int vrrpd_post_event(const char *, vrrp_state_t, vrrp_state_t);
2551cb875aeSCathy Zhou 
2561cb875aeSCathy Zhou static void vrrpd_initconf();
2571cb875aeSCathy Zhou static vrrp_err_t vrrpd_updateconf(vrrp_vr_conf_t *, uint_t);
2581cb875aeSCathy Zhou static vrrp_err_t vrrpd_write_vrconf(char *, size_t, vrrp_vr_conf_t *);
2591cb875aeSCathy Zhou static vrrp_err_t vrrpd_read_vrconf(char *, vrrp_vr_conf_t *);
2601cb875aeSCathy Zhou static vrrp_err_t vrrpd_readprop(const char *, vrrp_vr_conf_t *);
2611cb875aeSCathy Zhou static void vrrpd_cleanup();
2621cb875aeSCathy Zhou 
2631cb875aeSCathy Zhou static void vrrp_log(int, char *, ...);
2641cb875aeSCathy Zhou static int timeval_to_milli(struct timeval);
2651cb875aeSCathy Zhou static struct timeval timeval_delta(struct timeval, struct timeval);
2661cb875aeSCathy Zhou 
2671cb875aeSCathy Zhou typedef struct vrrpd_prop_s {
2681cb875aeSCathy Zhou 	char		*vs_propname;
2691cb875aeSCathy Zhou 	boolean_t	(*vs_propread)(vrrp_vr_conf_t *, const char *);
2701cb875aeSCathy Zhou 	int		(*vs_propwrite)(vrrp_vr_conf_t *, char *, size_t);
2711cb875aeSCathy Zhou } vrrp_prop_t;
2721cb875aeSCathy Zhou 
2731cb875aeSCathy Zhou /*
2741cb875aeSCathy Zhou  * persistent VRRP properties array
2751cb875aeSCathy Zhou  */
2761cb875aeSCathy Zhou static vrrp_prop_t vrrp_prop_info_tbl[] = {
2771cb875aeSCathy Zhou 	{"name", vrrp_rd_prop_name, vrrp_wt_prop_name},
2781cb875aeSCathy Zhou 	{"vrid", vrrp_rd_prop_vrid, vrrp_wt_prop_vrid},
2791cb875aeSCathy Zhou 	{"priority", vrrp_rd_prop_pri, vrrp_wt_prop_pri},
2801cb875aeSCathy Zhou 	{"adv_intval", vrrp_rd_prop_adver_int, vrrp_wt_prop_adver_int},
2811cb875aeSCathy Zhou 	{"preempt_mode", vrrp_rd_prop_preempt, vrrp_wt_prop_preempt},
2821cb875aeSCathy Zhou 	{"accept_mode", vrrp_rd_prop_accept, vrrp_wt_prop_accept},
2831cb875aeSCathy Zhou 	{"interface", vrrp_rd_prop_ifname, vrrp_wt_prop_ifname},
2841cb875aeSCathy Zhou 	{"af", vrrp_rd_prop_af, vrrp_wt_prop_af},
2851cb875aeSCathy Zhou 	{"enabled", vrrp_rd_prop_enabled, vrrp_wt_prop_enabled}
2861cb875aeSCathy Zhou };
2871cb875aeSCathy Zhou 
2881cb875aeSCathy Zhou #define	VRRP_PROP_INFO_TABSIZE	\
2891cb875aeSCathy Zhou 	(sizeof (vrrp_prop_info_tbl) / sizeof (vrrp_prop_t))
2901cb875aeSCathy Zhou 
2911cb875aeSCathy Zhou typedef void vrrp_cmd_func_t(void *, void *, size_t *);
2921cb875aeSCathy Zhou 
2931cb875aeSCathy Zhou typedef struct vrrp_cmd_info_s {
2941cb875aeSCathy Zhou 	vrrp_cmd_type_t	vi_cmd;
2951cb875aeSCathy Zhou 	size_t		vi_reqsize;
2961cb875aeSCathy Zhou 	size_t		vi_acksize;	/* 0 if the size is variable */
2971cb875aeSCathy Zhou 	boolean_t	vi_setop;	/* Set operation? Check credentials */
2981cb875aeSCathy Zhou 	vrrp_cmd_func_t	*vi_cmdfunc;
2991cb875aeSCathy Zhou } vrrp_cmd_info_t;
3001cb875aeSCathy Zhou 
3011cb875aeSCathy Zhou static vrrp_cmd_info_t vrrp_cmd_info_tbl[] = {
3021cb875aeSCathy Zhou 	{VRRP_CMD_CREATE, sizeof (vrrp_cmd_create_t),
3031cb875aeSCathy Zhou 	    sizeof (vrrp_ret_create_t), _B_TRUE, vrrpd_cmd_create},
3041cb875aeSCathy Zhou 	{VRRP_CMD_DELETE, sizeof (vrrp_cmd_delete_t),
3051cb875aeSCathy Zhou 	    sizeof (vrrp_ret_delete_t), _B_TRUE, vrrpd_cmd_delete},
3061cb875aeSCathy Zhou 	{VRRP_CMD_ENABLE, sizeof (vrrp_cmd_enable_t),
3071cb875aeSCathy Zhou 	    sizeof (vrrp_ret_enable_t), _B_TRUE, vrrpd_cmd_enable},
3081cb875aeSCathy Zhou 	{VRRP_CMD_DISABLE, sizeof (vrrp_cmd_disable_t),
3091cb875aeSCathy Zhou 	    sizeof (vrrp_ret_disable_t), _B_TRUE, vrrpd_cmd_disable},
3101cb875aeSCathy Zhou 	{VRRP_CMD_MODIFY, sizeof (vrrp_cmd_modify_t),
3111cb875aeSCathy Zhou 	    sizeof (vrrp_ret_modify_t), _B_TRUE, vrrpd_cmd_modify},
3121cb875aeSCathy Zhou 	{VRRP_CMD_QUERY, sizeof (vrrp_cmd_query_t), 0,
3131cb875aeSCathy Zhou 	    _B_FALSE, vrrpd_cmd_query},
3141cb875aeSCathy Zhou 	{VRRP_CMD_LIST, sizeof (vrrp_cmd_list_t), 0,
3151cb875aeSCathy Zhou 	    _B_FALSE, vrrpd_cmd_list}
3161cb875aeSCathy Zhou };
3171cb875aeSCathy Zhou 
3181cb875aeSCathy Zhou #define	VRRP_DOOR_INFO_TABLE_SIZE	\
3191cb875aeSCathy Zhou 	(sizeof (vrrp_cmd_info_tbl) / sizeof (vrrp_cmd_info_t))
3201cb875aeSCathy Zhou 
3211cb875aeSCathy Zhou static int
ipaddr_cmp(int af,vrrp_addr_t * addr1,vrrp_addr_t * addr2)3221cb875aeSCathy Zhou ipaddr_cmp(int af, vrrp_addr_t *addr1, vrrp_addr_t *addr2)
3231cb875aeSCathy Zhou {
3241cb875aeSCathy Zhou 	if (af == AF_INET) {
3251cb875aeSCathy Zhou 		return (memcmp(&addr1->in4.sin_addr,
3261cb875aeSCathy Zhou 		    &addr2->in4.sin_addr, sizeof (struct in_addr)));
3271cb875aeSCathy Zhou 	} else {
3281cb875aeSCathy Zhou 		return (memcmp(&addr1->in6.sin6_addr,
3291cb875aeSCathy Zhou 		    &addr2->in6.sin6_addr, sizeof (struct in6_addr)));
3301cb875aeSCathy Zhou 	}
3311cb875aeSCathy Zhou }
3321cb875aeSCathy Zhou 
3331cb875aeSCathy Zhou static vrrp_vr_t *
vrrpd_lookup_vr_by_vrid(char * ifname,vrid_t vrid,int af)3341cb875aeSCathy Zhou vrrpd_lookup_vr_by_vrid(char *ifname, vrid_t vrid, int af)
3351cb875aeSCathy Zhou {
3361cb875aeSCathy Zhou 	vrrp_vr_t *vr;
3371cb875aeSCathy Zhou 
3381cb875aeSCathy Zhou 	TAILQ_FOREACH(vr, &vrrp_vr_list, vvr_next) {
3391cb875aeSCathy Zhou 		if (strcmp(vr->vvr_conf.vvc_link, ifname) == 0 &&
3401cb875aeSCathy Zhou 		    vr->vvr_conf.vvc_vrid == vrid &&
3411cb875aeSCathy Zhou 		    vr->vvr_conf.vvc_af == af) {
3421cb875aeSCathy Zhou 			break;
3431cb875aeSCathy Zhou 		}
3441cb875aeSCathy Zhou 	}
3451cb875aeSCathy Zhou 	return (vr);
3461cb875aeSCathy Zhou }
3471cb875aeSCathy Zhou 
3481cb875aeSCathy Zhou static vrrp_vr_t *
vrrpd_lookup_vr_by_name(const char * name)3491cb875aeSCathy Zhou vrrpd_lookup_vr_by_name(const char *name)
3501cb875aeSCathy Zhou {
3511cb875aeSCathy Zhou 	vrrp_vr_t *vr;
3521cb875aeSCathy Zhou 
3531cb875aeSCathy Zhou 	TAILQ_FOREACH(vr, &vrrp_vr_list, vvr_next) {
3541cb875aeSCathy Zhou 		if (strcmp(vr->vvr_conf.vvc_name, name) == 0)
3551cb875aeSCathy Zhou 			break;
3561cb875aeSCathy Zhou 	}
3571cb875aeSCathy Zhou 	return (vr);
3581cb875aeSCathy Zhou }
3591cb875aeSCathy Zhou 
3601cb875aeSCathy Zhou static vrrp_intf_t *
vrrpd_lookup_if(const char * ifname,int af)3611cb875aeSCathy Zhou vrrpd_lookup_if(const char *ifname, int af)
3621cb875aeSCathy Zhou {
3631cb875aeSCathy Zhou 	vrrp_intf_t	*intf;
3641cb875aeSCathy Zhou 
3651cb875aeSCathy Zhou 	TAILQ_FOREACH(intf, &vrrp_intf_list, vvi_next) {
3661cb875aeSCathy Zhou 		if (strcmp(ifname, intf->vvi_ifname) == 0 &&
3671cb875aeSCathy Zhou 		    af == intf->vvi_af) {
3681cb875aeSCathy Zhou 			break;
3691cb875aeSCathy Zhou 		}
3701cb875aeSCathy Zhou 	}
3711cb875aeSCathy Zhou 	return (intf);
3721cb875aeSCathy Zhou }
3731cb875aeSCathy Zhou 
3741cb875aeSCathy Zhou static vrrp_err_t
vrrpd_create_if(const char * ifname,int af,uint32_t ifindex,vrrp_intf_t ** intfp)3751cb875aeSCathy Zhou vrrpd_create_if(const char *ifname, int af, uint32_t ifindex,
3761cb875aeSCathy Zhou     vrrp_intf_t **intfp)
3771cb875aeSCathy Zhou {
3781cb875aeSCathy Zhou 	vrrp_intf_t	*intf;
3791cb875aeSCathy Zhou 
3801cb875aeSCathy Zhou 	vrrp_log(VRRP_DBG0, "vrrpd_create_if(%s, %s, %d)",
3811cb875aeSCathy Zhou 	    ifname, af_str(af), ifindex);
3821cb875aeSCathy Zhou 
3831cb875aeSCathy Zhou 	if (((*intfp) = malloc(sizeof (vrrp_intf_t))) == NULL) {
3841cb875aeSCathy Zhou 		vrrp_log(VRRP_ERR, "vrrpd_create_if(): failed to "
3851cb875aeSCathy Zhou 		    "allocate %s/%s interface", ifname, af_str(af));
3861cb875aeSCathy Zhou 		return (VRRP_ENOMEM);
3871cb875aeSCathy Zhou 	}
3881cb875aeSCathy Zhou 
3891cb875aeSCathy Zhou 	intf = *intfp;
3901cb875aeSCathy Zhou 	TAILQ_INIT(&intf->vvi_iplist);
3911cb875aeSCathy Zhou 	(void) strlcpy(intf->vvi_ifname, ifname, sizeof (intf->vvi_ifname));
3921cb875aeSCathy Zhou 	intf->vvi_af = af;
3931cb875aeSCathy Zhou 	intf->vvi_sockfd = -1;
3941cb875aeSCathy Zhou 	intf->vvi_nvr = 0;
3951cb875aeSCathy Zhou 	intf->vvi_eid = -1;
3961cb875aeSCathy Zhou 	intf->vvi_pip = NULL;
3971cb875aeSCathy Zhou 	intf->vvi_ifindex = ifindex;
3981cb875aeSCathy Zhou 	intf->vvi_state = NODE_STATE_NEW;
3991cb875aeSCathy Zhou 	intf->vvi_vr_state = VRRP_STATE_INIT;
4001cb875aeSCathy Zhou 	TAILQ_INSERT_TAIL(&vrrp_intf_list, intf, vvi_next);
4011cb875aeSCathy Zhou 	return (VRRP_SUCCESS);
4021cb875aeSCathy Zhou }
4031cb875aeSCathy Zhou 
4041cb875aeSCathy Zhou /*
4051cb875aeSCathy Zhou  * An interface is deleted. If update_vr is true, the deletion of the interface
4061cb875aeSCathy Zhou  * may cause the state transition of assoicated VRRP router (if this interface
4071cb875aeSCathy Zhou  * is either the primary or the VNIC interface of the VRRP router); otherwise,
4081cb875aeSCathy Zhou  * simply delete the interface without updating the VRRP router.
4091cb875aeSCathy Zhou  */
4101cb875aeSCathy Zhou static void
vrrpd_delete_if(vrrp_intf_t * intf,boolean_t update_vr)4111cb875aeSCathy Zhou vrrpd_delete_if(vrrp_intf_t *intf, boolean_t update_vr)
4121cb875aeSCathy Zhou {
4131cb875aeSCathy Zhou 	vrrp_ip_t	*ip;
4141cb875aeSCathy Zhou 
4151cb875aeSCathy Zhou 	vrrp_log(VRRP_DBG0, "vrrpd_delete_if(%s, %s, %supdate_vr)",
4161cb875aeSCathy Zhou 	    intf->vvi_ifname, af_str(intf->vvi_af), update_vr ? "" : "no_");
4171cb875aeSCathy Zhou 
4181cb875aeSCathy Zhou 	if (update_vr) {
4191cb875aeSCathy Zhou 		/*
4201cb875aeSCathy Zhou 		 * If a this interface is the physical interface or the VNIC
4211cb875aeSCathy Zhou 		 * of a VRRP router, the deletion of the interface (no IP
4221cb875aeSCathy Zhou 		 * address exists on this interface) may cause the state
4231cb875aeSCathy Zhou 		 * transition of the VRRP router. call vrrpd_remove_if()
4241cb875aeSCathy Zhou 		 * to find all corresponding VRRP router and update their
4251cb875aeSCathy Zhou 		 * states.
4261cb875aeSCathy Zhou 		 */
4271cb875aeSCathy Zhou 		vrrpd_remove_if(intf, _B_FALSE);
4281cb875aeSCathy Zhou 	}
4291cb875aeSCathy Zhou 
4301cb875aeSCathy Zhou 	/*
4311cb875aeSCathy Zhou 	 * First remove and delete all the IP addresses on the interface
4321cb875aeSCathy Zhou 	 */
4331cb875aeSCathy Zhou 	while (!TAILQ_EMPTY(&intf->vvi_iplist)) {
4341cb875aeSCathy Zhou 		ip = TAILQ_FIRST(&intf->vvi_iplist);
4351cb875aeSCathy Zhou 		vrrpd_delete_ip(intf, ip);
4361cb875aeSCathy Zhou 	}
4371cb875aeSCathy Zhou 
4381cb875aeSCathy Zhou 	/*
4391cb875aeSCathy Zhou 	 * Then remove and delete the interface
4401cb875aeSCathy Zhou 	 */
4411cb875aeSCathy Zhou 	TAILQ_REMOVE(&vrrp_intf_list, intf, vvi_next);
4421cb875aeSCathy Zhou 	(void) free(intf);
4431cb875aeSCathy Zhou }
4441cb875aeSCathy Zhou 
4451cb875aeSCathy Zhou static vrrp_err_t
vrrpd_create_ip(vrrp_intf_t * intf,const char * lifname,vrrp_addr_t * addr,uint64_t flags)4461cb875aeSCathy Zhou vrrpd_create_ip(vrrp_intf_t *intf, const char *lifname, vrrp_addr_t *addr,
4471cb875aeSCathy Zhou     uint64_t flags)
4481cb875aeSCathy Zhou {
4491cb875aeSCathy Zhou 	vrrp_ip_t	*ip;
4501cb875aeSCathy Zhou 	char		abuf[INET6_ADDRSTRLEN];
4511cb875aeSCathy Zhou 
4521cb875aeSCathy Zhou 	/* LINTED E_CONSTANT_CONDITION */
4531cb875aeSCathy Zhou 	VRRPADDR2STR(intf->vvi_af, addr, abuf, INET6_ADDRSTRLEN, _B_FALSE);
4541cb875aeSCathy Zhou 	vrrp_log(VRRP_DBG0, "vrrpd_create_ip(%s, %s, %s, 0x%x)",
4551cb875aeSCathy Zhou 	    intf->vvi_ifname, lifname, abuf, flags);
4561cb875aeSCathy Zhou 
4571cb875aeSCathy Zhou 	if ((ip = malloc(sizeof (vrrp_ip_t))) == NULL) {
4581cb875aeSCathy Zhou 		vrrp_log(VRRP_ERR, "vrrpd_create_ip(%s, %s):"
4591cb875aeSCathy Zhou 		    "failed to allocate IP", lifname, abuf);
4601cb875aeSCathy Zhou 		return (VRRP_ENOMEM);
4611cb875aeSCathy Zhou 	}
4621cb875aeSCathy Zhou 
4631cb875aeSCathy Zhou 	(void) strncpy(ip->vip_lifname, lifname, sizeof (ip->vip_lifname));
4641cb875aeSCathy Zhou 	ip->vip_state = NODE_STATE_NEW;
4651cb875aeSCathy Zhou 	ip->vip_flags = flags;
4661cb875aeSCathy Zhou 	(void) memcpy(&ip->vip_addr, addr, sizeof (ip->vip_addr));
4671cb875aeSCathy Zhou 
4681cb875aeSCathy Zhou 	/*
4691cb875aeSCathy Zhou 	 * Make sure link-local IPv6 IP addresses are at the head of the list
4701cb875aeSCathy Zhou 	 */
4711cb875aeSCathy Zhou 	if (intf->vvi_af == AF_INET6 &&
4721cb875aeSCathy Zhou 	    IN6_IS_ADDR_LINKLOCAL(&addr->in6.sin6_addr)) {
4731cb875aeSCathy Zhou 		TAILQ_INSERT_HEAD(&intf->vvi_iplist, ip, vip_next);
4741cb875aeSCathy Zhou 	} else {
4751cb875aeSCathy Zhou 		TAILQ_INSERT_TAIL(&intf->vvi_iplist, ip, vip_next);
4761cb875aeSCathy Zhou 	}
4771cb875aeSCathy Zhou 	return (VRRP_SUCCESS);
4781cb875aeSCathy Zhou }
4791cb875aeSCathy Zhou 
4801cb875aeSCathy Zhou static void
vrrpd_delete_ip(vrrp_intf_t * intf,vrrp_ip_t * ip)4811cb875aeSCathy Zhou vrrpd_delete_ip(vrrp_intf_t *intf, vrrp_ip_t *ip)
4821cb875aeSCathy Zhou {
4831cb875aeSCathy Zhou 	char	abuf[INET6_ADDRSTRLEN];
4841cb875aeSCathy Zhou 	int	af = intf->vvi_af;
4851cb875aeSCathy Zhou 
4861cb875aeSCathy Zhou 	/* LINTED E_CONSTANT_CONDITION */
4871cb875aeSCathy Zhou 	VRRPADDR2STR(af, &ip->vip_addr, abuf, sizeof (abuf), _B_FALSE);
4881cb875aeSCathy Zhou 	vrrp_log(VRRP_DBG0, "vrrpd_delete_ip(%s, %s, %s) is %sprimary",
4891cb875aeSCathy Zhou 	    intf->vvi_ifname, ip->vip_lifname, abuf,
4901cb875aeSCathy Zhou 	    intf->vvi_pip == ip ? "" : "not ");
4911cb875aeSCathy Zhou 
4921cb875aeSCathy Zhou 	if (intf->vvi_pip == ip)
4931cb875aeSCathy Zhou 		intf->vvi_pip = NULL;
4941cb875aeSCathy Zhou 
4951cb875aeSCathy Zhou 	TAILQ_REMOVE(&intf->vvi_iplist, ip, vip_next);
4961cb875aeSCathy Zhou 	(void) free(ip);
4971cb875aeSCathy Zhou }
4981cb875aeSCathy Zhou 
4991cb875aeSCathy Zhou static char *
rtm_event2str(uchar_t event)5001cb875aeSCathy Zhou rtm_event2str(uchar_t event)
5011cb875aeSCathy Zhou {
5021cb875aeSCathy Zhou 	switch (event) {
5031cb875aeSCathy Zhou 	case RTM_NEWADDR:
5041cb875aeSCathy Zhou 		return ("RTM_NEWADDR");
5051cb875aeSCathy Zhou 	case RTM_DELADDR:
5061cb875aeSCathy Zhou 		return ("RTM_DELADDR");
5071cb875aeSCathy Zhou 	case RTM_IFINFO:
5081cb875aeSCathy Zhou 		return ("RTM_IFINFO");
5091cb875aeSCathy Zhou 	case RTM_ADD:
5101cb875aeSCathy Zhou 		return ("RTM_ADD");
5111cb875aeSCathy Zhou 	case RTM_DELETE:
5121cb875aeSCathy Zhou 		return ("RTM_DELETE");
5131cb875aeSCathy Zhou 	case RTM_CHANGE:
5141cb875aeSCathy Zhou 		return ("RTM_CHANGE");
5151cb875aeSCathy Zhou 	case RTM_OLDADD:
5161cb875aeSCathy Zhou 		return ("RTM_OLDADD");
5171cb875aeSCathy Zhou 	case RTM_OLDDEL:
5181cb875aeSCathy Zhou 		return ("RTM_OLDDEL");
5191cb875aeSCathy Zhou 	case RTM_CHGADDR:
5201cb875aeSCathy Zhou 		return ("RTM_CHGADDR");
5211cb875aeSCathy Zhou 	case RTM_FREEADDR:
5221cb875aeSCathy Zhou 		return ("RTM_FREEADDR");
5231cb875aeSCathy Zhou 	default:
5241cb875aeSCathy Zhou 		return ("RTM_OTHER");
5251cb875aeSCathy Zhou 	}
5261cb875aeSCathy Zhou }
5271cb875aeSCathy Zhou 
528c5e0ece0SCathy Zhou /*
529c5e0ece0SCathy Zhou  * This is called by the child process to inform the parent process to
530c5e0ece0SCathy Zhou  * exit with the given return value. Note that the child process
531c5e0ece0SCathy Zhou  * (the daemon process) informs the parent process to exit when anything
532c5e0ece0SCathy Zhou  * goes wrong or when all the intialization is done.
533c5e0ece0SCathy Zhou  */
534c5e0ece0SCathy Zhou static int
vrrpd_inform_parent_exit(int rv)535c5e0ece0SCathy Zhou vrrpd_inform_parent_exit(int rv)
536c5e0ece0SCathy Zhou {
537c5e0ece0SCathy Zhou 	int err = 0;
538c5e0ece0SCathy Zhou 
539c5e0ece0SCathy Zhou 	/*
540c5e0ece0SCathy Zhou 	 * If vrrp_debug_level is none-zero, vrrpd is not running as
541c5e0ece0SCathy Zhou 	 * a daemon. Return directly.
542c5e0ece0SCathy Zhou 	 */
543c5e0ece0SCathy Zhou 	if (vrrp_debug_level != 0)
544c5e0ece0SCathy Zhou 		return (0);
545c5e0ece0SCathy Zhou 
546c5e0ece0SCathy Zhou 	if (write(pfds[1], &rv, sizeof (int)) != sizeof (int)) {
547c5e0ece0SCathy Zhou 		err = errno;
548c5e0ece0SCathy Zhou 		(void) close(pfds[1]);
549c5e0ece0SCathy Zhou 		return (err);
550c5e0ece0SCathy Zhou 	}
551c5e0ece0SCathy Zhou 	(void) close(pfds[1]);
552c5e0ece0SCathy Zhou 	return (0);
553c5e0ece0SCathy Zhou }
554c5e0ece0SCathy Zhou 
5551cb875aeSCathy Zhou int
main(int argc,char * argv[])5561cb875aeSCathy Zhou main(int argc, char *argv[])
5571cb875aeSCathy Zhou {
5581cb875aeSCathy Zhou 	int c, err;
5591cb875aeSCathy Zhou 	struct sigaction sa;
5601cb875aeSCathy Zhou 	sigset_t mask;
5611cb875aeSCathy Zhou 	struct rlimit rl;
5621cb875aeSCathy Zhou 
5631cb875aeSCathy Zhou 	(void) setlocale(LC_ALL, "");
5641cb875aeSCathy Zhou 	(void) textdomain(TEXT_DOMAIN);
5651cb875aeSCathy Zhou 
5661cb875aeSCathy Zhou 	/*
5671cb875aeSCathy Zhou 	 * We need PRIV_SYS_CONFIG to post VRRP sysevent, PRIV_NET_RAWACESS
5681cb875aeSCathy Zhou 	 * and PRIV_NET_ICMPACCESS to open  the raw socket, PRIV_SYS_IP_CONFIG
5691cb875aeSCathy Zhou 	 * to bring up/down the virtual IP addresses, and PRIV_SYS_RESOURCE to
5701cb875aeSCathy Zhou 	 * setrlimit().
5711cb875aeSCathy Zhou 	 *
5721cb875aeSCathy Zhou 	 * Note that sysevent is not supported in non-global zones.
5731cb875aeSCathy Zhou 	 */
5741cb875aeSCathy Zhou 	if (getzoneid() == GLOBAL_ZONEID) {
5751cb875aeSCathy Zhou 		err = __init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, 0, 0,
5771cb875aeSCathy Zhou 		    PRIV_SYS_IP_CONFIG, PRIV_SYS_RESOURCE, NULL);
5781cb875aeSCathy Zhou 	} else {
5791cb875aeSCathy Zhou 		err = __init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, 0, 0,
5811cb875aeSCathy Zhou 		    PRIV_SYS_IP_CONFIG, PRIV_SYS_RESOURCE, NULL);
5821cb875aeSCathy Zhou 	}
5831cb875aeSCathy Zhou 
5841cb875aeSCathy Zhou 	if (err == -1) {
5851cb875aeSCathy Zhou 		vrrp_log(VRRP_ERR, "main(): init_daemon_priv() failed");
5861cb875aeSCathy Zhou 		return (EXIT_FAILURE);
5871cb875aeSCathy Zhou 	}
5881cb875aeSCathy Zhou 
5891cb875aeSCathy Zhou 	/*
5901cb875aeSCathy Zhou 	 * If vrrpd is started by other process, it will inherit the
5911cb875aeSCathy Zhou 	 * signal block mask. We unblock all signals to make sure the
5921cb875aeSCathy Zhou 	 * signal handling will work normally.
5931cb875aeSCathy Zhou 	 */
5941cb875aeSCathy Zhou 	(void) sigfillset(&mask);
5951cb875aeSCathy Zhou 	(void) thr_sigsetmask(SIG_UNBLOCK, &mask, NULL);
5961cb875aeSCathy Zhou 	sa.sa_handler = vrrpd_cleanup;
5971cb875aeSCathy Zhou 	sa.sa_flags = 0;
5981cb875aeSCathy Zhou 	(void) sigemptyset(&sa.sa_mask);
5991cb875aeSCathy Zhou 	(void) sigaction(SIGINT, &sa, NULL);
6001cb875aeSCathy Zhou 	(void) sigaction(SIGQUIT, &sa, NULL);
6011cb875aeSCathy Zhou 	(void) sigaction(SIGTERM, &sa, NULL);
6021cb875aeSCathy Zhou 
6031cb875aeSCathy Zhou 	vrrp_debug_level = 0;
6041cb875aeSCathy Zhou 	(void) strlcpy(vrrpd_conffile, VRRPCONF, sizeof (vrrpd_conffile));
6051cb875aeSCathy Zhou 	while ((c = getopt(argc, argv, "d:f:")) != EOF) {
6061cb875aeSCathy Zhou 		switch (c) {
6071cb875aeSCathy Zhou 		case 'd':
6081cb875aeSCathy Zhou 			vrrp_debug_level = atoi(optarg);
6091cb875aeSCathy Zhou 			break;
6101cb875aeSCathy Zhou 		case 'f':
6111cb875aeSCathy Zhou 			(void) strlcpy(vrrpd_conffile, optarg,
6121cb875aeSCathy Zhou 			    sizeof (vrrpd_conffile));
6131cb875aeSCathy Zhou 			break;
6141cb875aeSCathy Zhou 		default:
6151cb875aeSCathy Zhou 			break;
6161cb875aeSCathy Zhou 		}
6171cb875aeSCathy Zhou 	}
6181cb875aeSCathy Zhou 
6191cb875aeSCathy Zhou 	closefrom(3);
6201cb875aeSCathy Zhou 	if (vrrp_debug_level == 0 && (daemon_init() != 0)) {
6211cb875aeSCathy Zhou 		vrrp_log(VRRP_ERR, "main(): daemon_init() failed");
6221cb875aeSCathy Zhou 		return (EXIT_FAILURE);
6231cb875aeSCathy Zhou 	}
6241cb875aeSCathy Zhou 
6251cb875aeSCathy Zhou 	rl.rlim_cur = RLIM_INFINITY;
6261cb875aeSCathy Zhou 	rl.rlim_max = RLIM_INFINITY;
6271cb875aeSCathy Zhou 	if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
6281cb875aeSCathy Zhou 		vrrp_log(VRRP_ERR, "main(): setrlimit() failed");
629c5e0ece0SCathy Zhou 		goto child_out;
6301cb875aeSCathy Zhou 	}
6311cb875aeSCathy Zhou 
6321cb875aeSCathy Zhou 	if (vrrpd_init() != VRRP_SUCCESS) {
6331cb875aeSCathy Zhou 		vrrp_log(VRRP_ERR, "main(): vrrpd_init() failed");
634c5e0ece0SCathy Zhou 		goto child_out;
6351cb875aeSCathy Zhou 	}
6361cb875aeSCathy Zhou 
6371cb875aeSCathy Zhou 	/*
6381cb875aeSCathy Zhou 	 * Get rid of unneeded privileges.
6391cb875aeSCathy Zhou 	 */
6401cb875aeSCathy Zhou 	__fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
6421cb875aeSCathy Zhou 
6431cb875aeSCathy Zhou 	/*
6441cb875aeSCathy Zhou 	 * Read the configuration and initialize the existing VRRP
6451cb875aeSCathy Zhou 	 * configuration
6461cb875aeSCathy Zhou 	 */
6471cb875aeSCathy Zhou 	vrrpd_initconf();
6481cb875aeSCathy Zhou 
649c5e0ece0SCathy Zhou 	/*
650c5e0ece0SCathy Zhou 	 * Inform the parent process that it can successfully exit.
651c5e0ece0SCathy Zhou 	 */
652c5e0ece0SCathy Zhou 	if ((err = vrrpd_inform_parent_exit(EXIT_SUCCESS)) != 0) {
653c5e0ece0SCathy Zhou 		vrrpd_cleanup();
654c5e0ece0SCathy Zhou 		vrrp_log(VRRP_WARNING, "vrrpd_inform_parent_exit() failed: %s",
655c5e0ece0SCathy Zhou 		    strerror(err));
656c5e0ece0SCathy Zhou 		return (EXIT_FAILURE);
657c5e0ece0SCathy Zhou 	}
658c5e0ece0SCathy Zhou 
6591cb875aeSCathy Zhou 	/*
6601cb875aeSCathy Zhou 	 * Start the loop to handle the timer and the IO events.
6611cb875aeSCathy Zhou 	 */
6621cb875aeSCathy Zhou 	switch (iu_handle_events(vrrpd_eh, vrrpd_timerq)) {
6631cb875aeSCathy Zhou 	case -1:
6641cb875aeSCathy Zhou 		vrrp_log(VRRP_ERR, "main(): iu_handle_events() failed "
6651cb875aeSCathy Zhou 		    "abnormally");
6661cb875aeSCathy Zhou 		break;
6671cb875aeSCathy Zhou 	default:
6681cb875aeSCathy Zhou 		break;
6691cb875aeSCathy Zhou 	}
6701cb875aeSCathy Zhou 
6711cb875aeSCathy Zhou 	vrrpd_cleanup();
6721cb875aeSCathy Zhou 	return (EXIT_SUCCESS);
673c5e0ece0SCathy Zhou 
674c5e0ece0SCathy Zhou child_out:
675c5e0ece0SCathy Zhou 	(void) vrrpd_inform_parent_exit(EXIT_FAILURE);
676c5e0ece0SCathy Zhou 	return (EXIT_FAILURE);
6771cb875aeSCathy Zhou }
6781cb875aeSCathy Zhou 
6791cb875aeSCathy Zhou static int
daemon_init()6801cb875aeSCathy Zhou daemon_init()
6811cb875aeSCathy Zhou {
6821cb875aeSCathy Zhou 	pid_t	pid;
683c5e0ece0SCathy Zhou 	int	rv;
6841cb875aeSCathy Zhou 
6851cb875aeSCathy Zhou 	vrrp_log(VRRP_DBG0, "daemon_init()");
6861cb875aeSCathy Zhou 
6871cb875aeSCathy Zhou 	if (getenv("SMF_FMRI") == NULL) {
688*bbf21555SRichard Lowe 		vrrp_log(VRRP_ERR, "daemon_init(): vrrpd is an smf(7) managed "
689c5e0ece0SCathy Zhou 		    "service and should not be run from the command line.");
6901cb875aeSCathy Zhou 		return (-1);
6911cb875aeSCathy Zhou 	}
6921cb875aeSCathy Zhou 
693c5e0ece0SCathy Zhou 	/*
694c5e0ece0SCathy Zhou 	 * Create the pipe used for the child process to inform the parent
695c5e0ece0SCathy Zhou 	 * process to exit after all initialization is done.
696c5e0ece0SCathy Zhou 	 */
697c5e0ece0SCathy Zhou 	if (pipe(pfds) < 0) {
698c5e0ece0SCathy Zhou 		vrrp_log(VRRP_ERR, "daemon_init(): pipe() failed: %s",
699c5e0ece0SCathy Zhou 		    strerror(errno));
7001cb875aeSCathy Zhou 		return (-1);
701c5e0ece0SCathy Zhou 	}
7021cb875aeSCathy Zhou 
703c5e0ece0SCathy Zhou 	if ((pid = fork()) < 0) {
704c5e0ece0SCathy Zhou 		vrrp_log(VRRP_ERR, "daemon_init(): fork() failed: %s",
705c5e0ece0SCathy Zhou 		    strerror(errno));
706c5e0ece0SCathy Zhou 		(void) close(pfds[0]);
707c5e0ece0SCathy Zhou 		(void) close(pfds[1]);
708c5e0ece0SCathy Zhou 		return (-1);
709c5e0ece0SCathy Zhou 	}
710c5e0ece0SCathy Zhou 
711c5e0ece0SCathy Zhou 	if (pid != 0) { /* Parent */
712c5e0ece0SCathy Zhou 		(void) close(pfds[1]);
713c5e0ece0SCathy Zhou 
714c5e0ece0SCathy Zhou 		/*
715c5e0ece0SCathy Zhou 		 * Read the child process's return value from the pfds.
716c5e0ece0SCathy Zhou 		 * If the child process exits unexpectedly, read() returns -1.
717c5e0ece0SCathy Zhou 		 */
718c5e0ece0SCathy Zhou 		if (read(pfds[0], &rv, sizeof (int)) != sizeof (int)) {
719c5e0ece0SCathy Zhou 			vrrp_log(VRRP_ERR, "daemon_init(): child process "
720c5e0ece0SCathy Zhou 			    "exited unexpectedly %s", strerror(errno));
721c5e0ece0SCathy Zhou 			(void) kill(pid, SIGTERM);
722c5e0ece0SCathy Zhou 			rv = EXIT_FAILURE;
723c5e0ece0SCathy Zhou 		}
724c5e0ece0SCathy Zhou 		(void) close(pfds[0]);
725c5e0ece0SCathy Zhou 		exit(rv);
7261cb875aeSCathy Zhou 	}
7271cb875aeSCathy Zhou 
7281cb875aeSCathy Zhou 	/*
7291cb875aeSCathy Zhou 	 * in child process, became a daemon, and return to main() to continue.
7301cb875aeSCathy Zhou 	 */
731c5e0ece0SCathy Zhou 	(void) close(pfds[0]);
7321cb875aeSCathy Zhou 	(void) chdir("/");
7331cb875aeSCathy Zhou 	(void) setsid();
7341cb875aeSCathy Zhou 	(void) close(0);
7351cb875aeSCathy Zhou 	(void) close(1);
7361cb875aeSCathy Zhou 	(void) close(2);
7371cb875aeSCathy Zhou 	(void) open("/dev/null", O_RDWR, 0);
7381cb875aeSCathy Zhou 	(void) dup2(0, 1);
7391cb875aeSCathy Zhou 	(void) dup2(0, 2);
7401cb875aeSCathy Zhou 	openlog("vrrpd", LOG_PID, LOG_DAEMON);
7411cb875aeSCathy Zhou 	vrrp_logflag = 1;
7421cb875aeSCathy Zhou 	return (0);
7431cb875aeSCathy Zhou }
7441cb875aeSCathy Zhou 
7451cb875aeSCathy Zhou static vrrp_err_t
vrrpd_init()7461cb875aeSCathy Zhou vrrpd_init()
7471cb875aeSCathy Zhou {
7481cb875aeSCathy Zhou 	vrrp_err_t	err = VRRP_ESYS;
7491cb875aeSCathy Zhou 
7501cb875aeSCathy Zhou 	vrrp_log(VRRP_DBG0, "vrrpd_init()");
7511cb875aeSCathy Zhou 
7521cb875aeSCathy Zhou 	TAILQ_INIT(&vrrp_vr_list);
7531cb875aeSCathy Zhou 	TAILQ_INIT(&vrrp_intf_list);
7541cb875aeSCathy Zhou 
7551cb875aeSCathy Zhou 	if (vrrp_open(&vrrpd_vh) != VRRP_SUCCESS) {
7561cb875aeSCathy Zhou 		vrrp_log(VRRP_ERR, "vrrpd_init(): vrrp_open() failed");
7571cb875aeSCathy Zhou 		goto fail;
7581cb875aeSCathy Zhou 	}
7591cb875aeSCathy Zhou 
7601cb875aeSCathy Zhou 	if ((vrrpd_timerq = iu_tq_create()) == NULL) {
7611cb875aeSCathy Zhou 		vrrp_log(VRRP_ERR, "vrrpd_init(): iu_tq_create() failed");
7621cb875aeSCathy Zhou 		goto fail;
7631cb875aeSCathy Zhou 	}
7641cb875aeSCathy Zhou 
7651cb875aeSCathy Zhou 	if ((vrrpd_eh = iu_eh_create()) == NULL) {
7661cb875aeSCathy Zhou 		vrrp_log(VRRP_ERR, "vrrpd_init(): iu_eh_create() failed");
7671cb875aeSCathy Zhou 		goto fail;
7681cb875aeSCathy Zhou 	}
7691cb875aeSCathy Zhou 
7701cb875aeSCathy Zhou 	/*
7711cb875aeSCathy Zhou 	 * Create the AF_UNIX socket used to communicate with libvrrpadm.
7721cb875aeSCathy Zhou 	 *
7731cb875aeSCathy Zhou 	 * This socket is used to receive the administrative requests and
7741cb875aeSCathy Zhou 	 * send back the results.
7751cb875aeSCathy Zhou 	 */
7761cb875aeSCathy Zhou 	if (vrrpd_cmdsock_create() != VRRP_SUCCESS) {
7771cb875aeSCathy Zhou 		vrrp_log(VRRP_ERR, "vrrpd_init(): vrrpd_cmdsock_create() "
7781cb875aeSCathy Zhou 		    "failed");
7791cb875aeSCathy Zhou 		goto fail;
7801cb875aeSCathy Zhou 	}
7811cb875aeSCathy Zhou 
7821cb875aeSCathy Zhou 	/*
7831cb875aeSCathy Zhou 	 * Create the VRRP control socket used to bring up/down the virtual
7841cb875aeSCathy Zhou 	 * IP addresses. It is also used to set the IFF_NOACCEPT flag of
7851cb875aeSCathy Zhou 	 * the virtual IP addresses.
7861cb875aeSCathy Zhou 	 */
7871cb875aeSCathy Zhou 	if (vrrpd_ctlsock_create() != VRRP_SUCCESS) {
7881cb875aeSCathy Zhou 		vrrp_log(VRRP_ERR, "vrrpd_init(): vrrpd_ctlsock_create() "
7891cb875aeSCathy Zhou 		    "failed");
7901cb875aeSCathy Zhou 		goto fail;
7911cb875aeSCathy Zhou 	}
7921cb875aeSCathy Zhou 
7931cb875aeSCathy Zhou 	/*
7941cb875aeSCathy Zhou 	 * Create the PF_ROUTER socket used to listen to the routing socket
7951cb875aeSCathy Zhou 	 * messages and build the interface/IP address list.
7961cb875aeSCathy Zhou 	 */
7971cb875aeSCathy Zhou 	if (vrrpd_rtsock_create() != VRRP_SUCCESS) {
7981cb875aeSCathy Zhou 		vrrp_log(VRRP_ERR, "vrrpd_init(): vrrpd_rtsock_create() "
7991cb875aeSCathy Zhou 		    "failed");
8001cb875aeSCathy Zhou 		goto fail;
8011cb875aeSCathy Zhou 	}
8021cb875aeSCathy Zhou 
803f6da83d4SAnurag S. Maskey 	/* Open the libipadm handle */
804f6da83d4SAnurag S. Maskey 	if (ipadm_open(&vrrp_ipadm_handle, 0) != IPADM_SUCCESS) {
805f6da83d4SAnurag S. Maskey 		vrrp_log(VRRP_ERR, "vrrpd_init(): ipadm_open() failed");
806f6da83d4SAnurag S. Maskey 		goto fail;
807f6da83d4SAnurag S. Maskey 	}
808f6da83d4SAnurag S. Maskey 
8091cb875aeSCathy Zhou 	/*
8101cb875aeSCathy Zhou 	 * Build the list of interfaces and IP addresses. Also, start the time
8111cb875aeSCathy Zhou 	 * to scan the interfaces/IP addresses periodically.
8121cb875aeSCathy Zhou 	 */
8131cb875aeSCathy Zhou 	vrrpd_scan(AF_INET);
8141cb875aeSCathy Zhou 	vrrpd_scan(AF_INET6);
8151cb875aeSCathy Zhou 	if ((vrrp_scan_timer_id = iu_schedule_timer_ms(vrrpd_timerq,
8161cb875aeSCathy Zhou 	    vrrpd_scan_interval, vrrpd_scan_timer, NULL)) == -1) {
8171cb875aeSCathy Zhou 		vrrp_log(VRRP_ERR, "vrrpd_init(): start scan_timer failed");
8181cb875aeSCathy Zhou 		goto fail;
8191cb875aeSCathy Zhou 	}
8201cb875aeSCathy Zhou 
8211cb875aeSCathy Zhou 	/*
8221cb875aeSCathy Zhou 	 * Initialize the VRRP multicast address.
8231cb875aeSCathy Zhou 	 */
8241cb875aeSCathy Zhou 	bzero(&vrrp_muladdr4, sizeof (vrrp_addr_t));
8251cb875aeSCathy Zhou 	vrrp_muladdr4.in4.sin_family = AF_INET;
8261cb875aeSCathy Zhou 	(void) inet_pton(AF_INET, "", &vrrp_muladdr4.in4.sin_addr);
8271cb875aeSCathy Zhou 
8281cb875aeSCathy Zhou 	bzero(&vrrp_muladdr6, sizeof (vrrp_addr_t));
8291cb875aeSCathy Zhou 	vrrp_muladdr6.in6.sin6_family = AF_INET6;
8301cb875aeSCathy Zhou 	(void) inet_pton(AF_INET6, "ff02::12", &vrrp_muladdr6.in6.sin6_addr);
8311cb875aeSCathy Zhou 
8321cb875aeSCathy Zhou 	return (VRRP_SUCCESS);
8331cb875aeSCathy Zhou 
8341cb875aeSCathy Zhou fail:
8351cb875aeSCathy Zhou 	vrrpd_fini();
8361cb875aeSCathy Zhou 	return (err);
8371cb875aeSCathy Zhou }
8381cb875aeSCathy Zhou 
8391cb875aeSCathy Zhou static void
vrrpd_fini()8401cb875aeSCathy Zhou vrrpd_fini()
8411cb875aeSCathy Zhou {
8421cb875aeSCathy Zhou 	vrrp_log(VRRP_DBG0, "vrrpd_fini()");
8431cb875aeSCathy Zhou 
8441cb875aeSCathy Zhou 	(void) iu_cancel_timer(vrrpd_timerq, vrrp_scan_timer_id, NULL);
8451cb875aeSCathy Zhou 	vrrp_scan_timer_id = -1;
8461cb875aeSCathy Zhou 
8471cb875aeSCathy Zhou 	vrrpd_rtsock_destroy();
8481cb875aeSCathy Zhou 	vrrpd_ctlsock_destroy();
8491cb875aeSCathy Zhou 	vrrpd_cmdsock_destroy();
8501cb875aeSCathy Zhou 
8511cb875aeSCathy Zhou 	if (vrrpd_eh != NULL) {
8521cb875aeSCathy Zhou 		iu_eh_destroy(vrrpd_eh);
8531cb875aeSCathy Zhou 		vrrpd_eh = NULL;
8541cb875aeSCathy Zhou 	}
8551cb875aeSCathy Zhou 
8561cb875aeSCathy Zhou 	if (vrrpd_timerq != NULL) {
8571cb875aeSCathy Zhou 		iu_tq_destroy(vrrpd_timerq);
8581cb875aeSCathy Zhou 		vrrpd_timerq = NULL;
8591cb875aeSCathy Zhou 	}
8601cb875aeSCathy Zhou 
8611cb875aeSCathy Zhou 	vrrp_close(vrrpd_vh);
8621cb875aeSCathy Zhou 	vrrpd_vh = NULL;
8631cb875aeSCathy Zhou 	assert(TAILQ_EMPTY(&vrrp_vr_list));
8641cb875aeSCathy Zhou 	assert(TAILQ_EMPTY(&vrrp_intf_list));
865f6da83d4SAnurag S. Maskey 
866f6da83d4SAnurag S. Maskey 	ipadm_close(vrrp_ipadm_handle);
8671cb875aeSCathy Zhou }
8681cb875aeSCathy Zhou 
8691cb875aeSCathy Zhou static void
vrrpd_cleanup(void)8701cb875aeSCathy Zhou vrrpd_cleanup(void)
8711cb875aeSCathy Zhou {
8721cb875aeSCathy Zhou 	vrrp_vr_t	*vr;
8731cb875aeSCathy Zhou 	vrrp_intf_t	*intf;
8741cb875aeSCathy Zhou 
8751cb875aeSCathy Zhou 	vrrp_log(VRRP_DBG0, "vrrpd_cleanup()");
8761cb875aeSCathy Zhou 
8771cb875aeSCathy Zhou 	while (!TAILQ_EMPTY(&vrrp_vr_list)) {
8781cb875aeSCathy Zhou 		vr = TAILQ_FIRST(&vrrp_vr_list);
8791cb875aeSCathy Zhou 		vrrpd_delete_vr(vr);
8801cb875aeSCathy Zhou 	}
8811cb875aeSCathy Zhou 
8821cb875aeSCathy Zhou 	while (!TAILQ_EMPTY(&vrrp_intf_list)) {
8831cb875aeSCathy Zhou 		intf = TAILQ_FIRST(&vrrp_intf_list);
8841cb875aeSCathy Zhou 		vrrpd_delete_if(intf, _B_FALSE);
8851cb875aeSCathy Zhou 	}
8861cb875aeSCathy Zhou 
8871cb875aeSCathy Zhou 	vrrpd_fini();
8881cb875aeSCathy Zhou 	closelog();
8891cb875aeSCathy Zhou 	exit(1);
8901cb875aeSCathy Zhou }
8911cb875aeSCathy Zhou 
8921cb875aeSCathy Zhou /*
8931cb875aeSCathy Zhou  * Read the configuration file and initialize all the existing VRRP routers.
8941cb875aeSCathy Zhou  */
8951cb875aeSCathy Zhou static void
vrrpd_initconf()8961cb875aeSCathy Zhou vrrpd_initconf()
8971cb875aeSCathy Zhou {
8981cb875aeSCathy Zhou 	FILE *fp;
8991cb875aeSCathy Zhou 	char line[LINE_MAX];
9001cb875aeSCathy Zhou 	int linenum = 0;
9011cb875aeSCathy Zhou 	vrrp_vr_conf_t conf;
9021cb875aeSCathy Zhou 	vrrp_err_t err;
9031cb875aeSCathy Zhou 
9041cb875aeSCathy Zhou 	vrrp_log(VRRP_DBG0, "vrrpd_initconf()");
9051cb875aeSCathy Zhou 
9061cb875aeSCathy Zhou 	if ((fp = fopen(vrrpd_conffile, "rF")) == NULL) {
9071cb875aeSCathy Zhou 		vrrp_log(VRRP_ERR, "failed to open the configuration file %s",
9081cb875aeSCathy Zhou 		    vrrpd_conffile);
9091cb875aeSCathy Zhou 		return;
9101cb875aeSCathy Zhou 	}
9111cb875aeSCathy Zhou 
9121cb875aeSCathy Zhou 	while (fgets(line, sizeof (line), fp) != NULL) {
9131cb875aeSCathy Zhou 		linenum++;
9141cb875aeSCathy Zhou 		conf.vvc_vrid = VRRP_VRID_NONE;
9151cb875aeSCathy Zhou 		if ((err = vrrpd_read_vrconf(line, &conf)) != VRRP_SUCCESS) {
9161cb875aeSCathy Zhou 			vrrp_log(VRRP_ERR, "failed to parse %d line %s",
9171cb875aeSCathy Zhou 			    linenum, line);
9181cb875aeSCathy Zhou 			continue;
9191cb875aeSCathy Zhou 		}
9201cb875aeSCathy Zhou 
9211cb875aeSCathy Zhou 		/*
9221cb875aeSCathy Zhou 		 * Blank or comment line
9231cb875aeSCathy Zhou 		 */
9241cb875aeSCathy Zhou 		if (conf.vvc_vrid == VRRP_VRID_NONE)
9251cb875aeSCathy Zhou 			continue;
9261cb875aeSCathy Zhou 
9271cb875aeSCathy Zhou 		/*
9281cb875aeSCathy Zhou 		 * No need to update the configuration since the VRRP router
9291cb875aeSCathy Zhou 		 * created/enabled based on the existing configuration.
9301cb875aeSCathy Zhou 		 */
9311cb875aeSCathy Zhou 		if ((err = vrrpd_create(&conf, _B_FALSE)) != VRRP_SUCCESS) {
9321cb875aeSCathy Zhou 			vrrp_log(VRRP_ERR, "VRRP router %s creation failed: "
9331cb875aeSCathy Zhou 			    "%s", conf.vvc_name, vrrp_err2str(err));
9341cb875aeSCathy Zhou 			continue;
9351cb875aeSCathy Zhou 		}
9361cb875aeSCathy Zhou 
9371cb875aeSCathy Zhou 		if (conf.vvc_enabled &&
9381cb875aeSCathy Zhou 		    ((err = vrrpd_enable(conf.vvc_name, _B_FALSE)) !=
9391cb875aeSCathy Zhou 		    VRRP_SUCCESS)) {
9401cb875aeSCathy Zhou 			vrrp_log(VRRP_ERR, "VRRP router %s enable failed: %s",
9411cb875aeSCathy Zhou 			    conf.vvc_name, vrrp_err2str(err));
9421cb875aeSCathy Zhou 		}
9431cb875aeSCathy Zhou 	}
9441cb875aeSCathy Zhou 
9451cb875aeSCathy Zhou 	(void) fclose(fp);
9461cb875aeSCathy Zhou }
9471cb875aeSCathy Zhou 
9481cb875aeSCathy Zhou /*
9491cb875aeSCathy Zhou  * Create the AF_UNIX socket used to communicate with libvrrpadm.
9501cb875aeSCathy Zhou  *
9511cb875aeSCathy Zhou  * This socket is used to receive the administrative request and
9521cb875aeSCathy Zhou  * send back the results.
9531cb875aeSCathy Zhou  */
9541cb875aeSCathy Zhou static vrrp_err_t
vrrpd_cmdsock_create()9551cb875aeSCathy Zhou vrrpd_cmdsock_create()
9561cb875aeSCathy Zhou {
9571cb875aeSCathy Zhou 	iu_event_id_t		eid;
9581cb875aeSCathy Zhou 	struct sockaddr_un	laddr;
9591cb875aeSCathy Zhou 	int			sock, flags;
9601cb875aeSCathy Zhou 
9611cb875aeSCathy Zhou 	vrrp_log(VRRP_DBG0, "vrrpd_cmdsock_create()");
9621cb875aeSCathy Zhou 
9631cb875aeSCathy Zhou 	if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
9641cb875aeSCathy Zhou 		vrrp_log(VRRP_ERR, "vrrpd_cmdsock_create(): socket(AF_UNIX) "
9651cb875aeSCathy Zhou 		    "failed: %s", strerror(errno));
9661cb875aeSCathy Zhou 		return (VRRP_ESYS);
9671cb875aeSCathy Zhou 	}
9681cb875aeSCathy Zhou