vrrpd.c revision aab83bb83be7342f6cfccaed8d5fe0b2f404855d
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * CDDL HEADER START
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * The contents of this file are subject to the terms of the
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * Common Development and Distribution License (the "License").
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * You may not use this file except in compliance with the License.
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * See the License for the specific language governing permissions
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * and limitations under the License.
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * When distributing Covered Code, include this CDDL HEADER in each
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * If applicable, add the following below this CDDL HEADER, with the
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * fields enclosed by brackets "[]" replaced with your own identifying
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * information: Portions Copyright [yyyy] [name of copyright owner]
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * CDDL HEADER END
2db6d663182655cb393dc2c15668bc9293364594Joshua M. Clulow * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * Copyright (c) 2012, Joyent, Inc. All rights reserved.
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * A VRRP router can be only start participating the VRRP protocol of a virtual
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * router when all the following conditions are met:
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * - The VRRP router is enabled (vr->vvr_conf.vvc_enabled is _B_TRUE)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * - The RX socket is successfully created over the physical interface to
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * receive the VRRP multicast advertisement. Note that one RX socket can
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * be shared by several VRRP routers configured over the same physical
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * interface. (See vrrpd_init_rxsock())
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * - The TX socket is successfully created over the VNIC interface to send
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * the VRRP advertisment. (See vrrpd_init_txsock())
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * - The primary IP address has been successfully selected over the physical
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * interface. (See vrrpd_select_primary())
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * If a VRRP router is enabled but the other conditions haven't be satisfied,
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * the router will be stay at the VRRP_STATE_INIT state. If all the above
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * conditions are met, the VRRP router will be transit to either
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * the VRRP_STATE_MASTER or the VRRP_STATE_BACKUP state, depends on the VRRP
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby#define skip_whitespace(p) while (isspace(*(p))) ++(p)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbytypedef struct vrrpd_rtsock_s {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbystatic ipadm_handle_t vrrp_ipadm_handle = NULL; /* libipadm handle */
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbystatic int vrrp_logflag = 0;
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbystatic int vrrpd_cmdsock_fd = -1; /* socket to communicate */
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbystatic int vrrpd_ctlsock_fd = -1; /* socket to bring up/down */
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby /* the virtual IP addresses */
2db6d663182655cb393dc2c15668bc9293364594Joshua M. Clulow * Multicast address of VRRP advertisement in network byte order
static char *af_str(int);
static int daemon_init();
static void vrrpd_fini();
static void vrrpd_cmdsock_destroy();
static void vrrpd_rtsock_destroy();
static void vrrpd_ctlsock_destroy();
static void vrrpd_scan(int);
static void vrrpd_init_ipcache(int);
static void vrrpd_update_ipcache(int);
int, uint64_t);
static void vrrpd_reenable_all_vr();
static void vrrpd_initconf();
static void vrrpd_cleanup();
static void vrrp_log(int, char *, ...);
typedef struct vrrpd_prop_s {
char *vs_propname;
} vrrp_prop_t;
#define VRRP_PROP_INFO_TABSIZE \
typedef struct vrrp_cmd_info_s {
#define VRRP_DOOR_INFO_TABLE_SIZE \
static vrrp_vr_t *
return (vr);
static vrrp_vr_t *
return (vr);
static vrrp_intf_t *
return (intf);
static vrrp_err_t
return (VRRP_ENOMEM);
return (VRRP_SUCCESS);
if (update_vr) {
static vrrp_err_t
return (VRRP_ENOMEM);
return (VRRP_SUCCESS);
switch (event) {
case RTM_NEWADDR:
case RTM_DELADDR:
case RTM_IFINFO:
case RTM_ADD:
case RTM_DELETE:
case RTM_CHANGE:
case RTM_OLDADD:
case RTM_OLDDEL:
case RTM_CHGADDR:
case RTM_FREEADDR:
int err = 0;
if (vrrp_debug_level != 0)
return (err);
int c, err;
return (EXIT_FAILURE);
vrrp_debug_level = 0;
sizeof (vrrpd_conffile));
return (EXIT_FAILURE);
goto child_out;
goto child_out;
return (EXIT_FAILURE);
return (EXIT_SUCCESS);
return (EXIT_FAILURE);
int rv;
(void) setsid();
(void) close(0);
static vrrp_err_t
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
* to scan the interfaces/IP addresses periodically.
goto fail;
return (VRRP_SUCCESS);
fail:
vrrpd_fini();
return (err);
vrrpd_cleanup(void)
vrrpd_fini();
closelog();
int linenum = 0;
linenum++;
VRRP_SUCCESS)) {
static vrrp_err_t
return (VRRP_ESYS);
return (VRRP_ESYS);
return (VRRP_ESYS);
return (VRRP_ESYS);
return (VRRP_SUCCESS);
static vrrp_err_t
return (VRRP_ESYS);
return (VRRP_SUCCESS);
NULL);
static vrrp_err_t
int s, s6;
return (VRRP_ESYS);
(void) close(s);
return (VRRP_ESYS);
(void) close(s);
return (VRRP_ESYS);
(void) close(s);
return (VRRP_ESYS);
vrrpd_ctlsock_fd = s;
return (VRRP_SUCCESS);
static boolean_t
return (_B_TRUE);
return (_B_FALSE);
goto done;
goto done;
done:
return (success);
void *arg)
int connfd, i;
cursize = 0;
} else if (len > 0) {
for (i = 0; i < VRRP_DOOR_INFO_TABLE_SIZE; i++) {
goto done;
} else if (len > 0) {
goto done;
done:
if (err != 0) {
cursize = 0;
} else if (len > 0) {
* Process the routing socket messages and update the interfaces/IP addresses
int nbytes;
if (nbytes <= 0) {
case RTM_FREEADDR:
case RTM_CHGADDR:
case RTM_NEWADDR:
case RTM_DELADDR:
if (scanif)
goto again;
static ipadm_status_t
char *lifname;
int ifindex;
return (IPADM_SUCCESS);
== VRRP_EAGAIN) {
return (ipstatus);
static vrrp_err_t
return (err);
return (VRRP_EAGAIN);
sizeof (vrrp_addr_t));
return (err);
return (VRRP_SUCCESS);
_B_FALSE);
_B_FALSE);
VRRP_SUCCESS) {
if (need_reenable)
static vrrp_ip_t *
return (NULL);
return (pip);
static vrrp_err_t
int nfd;
return (VRRP_EDB);
return (VRRP_EDB);
return (VRRP_EDB);
goto done;
VRRP_SUCCESS) {
goto done;
goto done;
goto done;
goto done;
goto done;
done:
return (err);
static vrrp_err_t
for (i = 0; i < VRRP_PROP_INFO_TABSIZE; i++) {
if (n < 0 || n >= len)
len -= n;
line += n;
if (n < 0 || n >= len)
len -= n;
line += n;
if (i != VRRP_PROP_INFO_TABSIZE) {
return (VRRP_EDB);
if (n < 0 || n >= len) {
return (VRRP_EDB);
return (VRRP_SUCCESS);
static vrrp_err_t
char *next;
return (VRRP_SUCCESS);
return (err);
static vrrp_err_t
char *pstr;
return (VRRP_EINVAL);
for (i = 0; i < VRRP_PROP_INFO_TABSIZE; i++) {
if (i == VRRP_PROP_INFO_TABSIZE) {
return (VRRP_EINVAL);
return (VRRP_SUCCESS);
static boolean_t
static boolean_t
static boolean_t
return (_B_FALSE);
return (_B_TRUE);
static boolean_t
static boolean_t
static boolean_t
return (_B_FALSE);
return (_B_TRUE);
static boolean_t
return (_B_FALSE);
return (_B_TRUE);
static boolean_t
return (_B_FALSE);
return (_B_TRUE);
static boolean_t
static vrrp_err_t
return (VRRP_ENOMEM);
return (VRRP_SUCCESS);
static vrrp_err_t
return (VRRP_SUCCESS);
return (err);
return (err);
if (primary_addr_gone) {
return (VRRP_EINVAL);
return (VRRP_EINVALVRNAME);
return (VRRP_EINSTEXIST);
return (VRRP_EVREXIST);
return (err);
return (err);
static vrrp_err_t
return (VRRP_ENOTFOUND);
return (err);
return (VRRP_SUCCESS);
static vrrp_err_t
return (VRRP_ENOTFOUND);
return (VRRP_EALREADY);
return (VRRP_EINVALLINK);
goto fail;
goto fail;
return (VRRP_SUCCESS);
fail:
return (err);
static vrrp_err_t
return (VRRP_ENOTFOUND);
return (VRRP_EALREADY);
return (err);
return (VRRP_SUCCESS);
static vrrp_err_t
int pri;
if (mask == 0)
return (VRRP_SUCCESS);
return (VRRP_ENOTFOUND);
return (VRRP_EINVAL);
return (VRRP_EINVAL);
return (VRRP_EINVAL);
return (err);
if (set_accept)
return (err);
return (VRRP_SUCCESS);
vipcnt++;
vipcnt = 0;
static size_t
int nip = 0;
if (nip == 0) {
return (size);
static vrrp_err_t
return (VRRP_ETOOSMALL);
return (VRRP_ESYS);
return (VRRP_SUCCESS);
static vrrp_err_t
return (VRRP_ETOOSMALL);
hoplimit_space = sizeof (int);
return (VRRP_ENOMEM);
return (VRRP_ESYS);
return (VRRP_SUCCESS);
static vrrp_err_t
return (VRRP_EINVAL);
int addr_cmp;
_B_FALSE);
peer);
if (addr_cmp == 0) {
peer);
static vrrp_err_t
peer);
return (VRRP_EINVAL);
return (VRRP_EINVAL);
return (VRRP_EINVAL);
sizeof (struct in6_addr))) {
return (VRRP_EINVAL);
return (VRRP_EINVAL);
return (VRRP_SUCCESS);
static vrrp_err_t
return (VRRP_EINVAL);
return (VRRP_EINVAL);
return (VRRP_EINVAL);
static vrrp_err_t
int ttl;
return (VRRP_EINVAL);
case IPV6_HOPLIMIT:
return (VRRP_EINVAL);
case IPV6_PKTINFO:
sizeof (abuf)));
return (VRRP_EINVAL);
void *arg)
int len;
sizeof (struct sockaddr_in6);
static vrrp_err_t
return (VRRP_SUCCESS);
return (VRRP_ENOPRIM);
goto done;
(void *)&vrrp_muladdr4;
(void *)&vrrp_muladdr6;
sizeof (struct sockaddr_storage));
sizeof (struct group_req)) < 0) {
goto done;
goto done;
goto done;
goto done;
done:
return (err);
static vrrp_err_t
int af;
return (VRRP_SUCCESS);
return (VRRP_ENOVIRT);
goto done;
done:
return (err);
static vrrp_err_t
char off = 0;
return (VRRP_SUCCESS);
goto done;
sizeof (on)) < 0) {
goto done;
goto done;
_B_FALSE);
done:
return (err);
static vrrp_err_t
return (VRRP_SUCCESS);
goto done;
goto done;
goto done;
done:
return (err);
static uint16_t
int nleft;
uint16_t *w;
w = (uint16_t *)p;
sum += *w++;
struct pshv4 {
static uint16_t
int nleft;
uint16_t *w;
int sum = 0;
while (nleft > 0) {
sum += *w++;
struct pshv6 {
static uint16_t
int nleft;
uint16_t *w;
int sum = 0;
while (nleft > 0) {
sum += *w++;
return (err);
return (VRRP_ESYS);
return (VRRP_SUCCESS);
return (err);
return (VRRP_ESYS);
return (VRRP_SUCCESS);
return (err);
return (VRRP_ESYS);
return (VRRP_SUCCESS);
return (err);
return (VRRP_SUCCESS);
static vrrp_err_t
return (VRRP_SUCCESS);
return (VRRP_ESYS);
if (on)
return (VRRP_ESYS);
return (VRRP_SUCCESS);
static vrrp_err_t
return (VRRP_ESYS);
return (VRRP_SUCCESS);
if (checkonly) {
return (VRRP_ESYS);
return (VRRP_ESYS);
return (VRRP_SUCCESS);
static vrrp_err_t
return (VRRP_ENOVIRT);
return (VRRP_SUCCESS);
goto failed;
VRRP_EVENT_CUR_VERSION) != 0)
goto failed;
goto failed;
goto failed;
goto failed;
static struct timeval
struct timeval t;
if (t.tv_usec < 0) {
t.tv_sec--;
if (vrrp_logflag == 0) {
switch (level) {
case VRRP_ERR:
case VRRP_WARNING:
case VRRP_NOTICE:
case VRRP_DBG0: