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,
5761cb875aeSCathy Zhou PRIV_SYS_CONFIG, PRIV_NET_RAWACCESS, PRIV_NET_ICMPACCESS,
5771cb875aeSCathy Zhou PRIV_SYS_IP_CONFIG, PRIV_SYS_RESOURCE, NULL);
5781cb875aeSCathy Zhou } else {
5791cb875aeSCathy Zhou err = __init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, 0, 0,
5801cb875aeSCathy Zhou PRIV_NET_RAWACCESS, PRIV_NET_ICMPACCESS,
5811cb875aeSCathy Zhou PRIV_SYS_IP_CONFIG, PRIV_SYS_RESOURCE, NULL);
5821cb875aeSCathy Zhou }
5831cb875aeSCathy Zhou
5841cb875aeSCathy Zhou if (err == -1) {
5851cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "main(): init_daemon_priv() failed");
5861cb875aeSCathy Zhou return (EXIT_FAILURE);
5871cb875aeSCathy Zhou }
5881cb875aeSCathy Zhou
5891cb875aeSCathy Zhou /*
5901cb875aeSCathy Zhou * If vrrpd is started by other process, it will inherit the
5911cb875aeSCathy Zhou * signal block mask. We unblock all signals to make sure the
5921cb875aeSCathy Zhou * signal handling will work normally.
5931cb875aeSCathy Zhou */
5941cb875aeSCathy Zhou (void) sigfillset(&mask);
5951cb875aeSCathy Zhou (void) thr_sigsetmask(SIG_UNBLOCK, &mask, NULL);
5961cb875aeSCathy Zhou sa.sa_handler = vrrpd_cleanup;
5971cb875aeSCathy Zhou sa.sa_flags = 0;
5981cb875aeSCathy Zhou (void) sigemptyset(&sa.sa_mask);
5991cb875aeSCathy Zhou (void) sigaction(SIGINT, &sa, NULL);
6001cb875aeSCathy Zhou (void) sigaction(SIGQUIT, &sa, NULL);
6011cb875aeSCathy Zhou (void) sigaction(SIGTERM, &sa, NULL);
6021cb875aeSCathy Zhou
6031cb875aeSCathy Zhou vrrp_debug_level = 0;
6041cb875aeSCathy Zhou (void) strlcpy(vrrpd_conffile, VRRPCONF, sizeof (vrrpd_conffile));
6051cb875aeSCathy Zhou while ((c = getopt(argc, argv, "d:f:")) != EOF) {
6061cb875aeSCathy Zhou switch (c) {
6071cb875aeSCathy Zhou case 'd':
6081cb875aeSCathy Zhou vrrp_debug_level = atoi(optarg);
6091cb875aeSCathy Zhou break;
6101cb875aeSCathy Zhou case 'f':
6111cb875aeSCathy Zhou (void) strlcpy(vrrpd_conffile, optarg,
6121cb875aeSCathy Zhou sizeof (vrrpd_conffile));
6131cb875aeSCathy Zhou break;
6141cb875aeSCathy Zhou default:
6151cb875aeSCathy Zhou break;
6161cb875aeSCathy Zhou }
6171cb875aeSCathy Zhou }
6181cb875aeSCathy Zhou
6191cb875aeSCathy Zhou closefrom(3);
6201cb875aeSCathy Zhou if (vrrp_debug_level == 0 && (daemon_init() != 0)) {
6211cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "main(): daemon_init() failed");
6221cb875aeSCathy Zhou return (EXIT_FAILURE);
6231cb875aeSCathy Zhou }
6241cb875aeSCathy Zhou
6251cb875aeSCathy Zhou rl.rlim_cur = RLIM_INFINITY;
6261cb875aeSCathy Zhou rl.rlim_max = RLIM_INFINITY;
6271cb875aeSCathy Zhou if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
6281cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "main(): setrlimit() failed");
629c5e0ece0SCathy Zhou goto child_out;
6301cb875aeSCathy Zhou }
6311cb875aeSCathy Zhou
6321cb875aeSCathy Zhou if (vrrpd_init() != VRRP_SUCCESS) {
6331cb875aeSCathy Zhou vrrp_log(VRRP_ERR, "main(): vrrpd_init() failed");
634c5e0ece0SCathy Zhou goto child_out;
6351cb875aeSCathy Zhou }
6361cb875aeSCathy Zhou
6371cb875aeSCathy Zhou /*
6381cb875aeSCathy Zhou * Get rid of unneeded privileges.
6391cb875aeSCathy Zhou */
6401cb875aeSCathy Zhou __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
6411cb875aeSCathy Zhou PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, PRIV_SYS_RESOURCE, NULL);
6421cb875aeSCathy Zhou
6431cb875aeSCathy Zhou /*
6441cb875aeSCathy Zhou * Read the configuration and initialize the existing VRRP
6451cb875aeSCathy Zhou * configuration
6461cb875aeSCathy Zhou */
6471cb875aeSCathy Zhou vrrpd_initconf();
6481cb875aeSCathy Zhou
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, "224.0.0.18", &vrrp_muladdr4.in4.sin_addr);
8271cb875aeSCathy Zhou
8281cb875aeSCathy Zhou bzero(&vrrp_muladdr6, sizeof (vrrp_addr_t));
8291cb875aeSCathy Zhou vrrp_muladdr6.in6.sin6_family = AF_INET6;
8301cb875aeSCathy Zhou (void) inet_pton(AF_INET6, "ff02::12", &vrrp_muladdr6.in6.sin6_addr);
8311cb875aeSCathy Zhou
8321cb875aeSCathy Zhou return (VRRP_SUCCESS);
8331cb875aeSCathy Zhou
8341cb875aeSCathy Zhou fail:
8351cb875aeSCathy Zhou vrrpd_fini();
8361cb875aeSCathy Zhou return (err);
8371cb875aeSCathy Zhou }
8381cb875aeSCathy Zhou
8391cb875aeSCathy Zhou static void
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
9691cb875ae