From 7cc0bcb3caa70f0c856cc5ff4119c1becd83708d Mon Sep 17 00:00:00 2001 From: Ryan Thomas McBride Date: Thu, 1 Jun 2006 22:43:13 +0000 Subject: Instead of polling the carp interface to detect a switch between MASTER and BACKUP, listen to the routing socket for link change messages. Based on a diff from nathanael at polymorpheous dot com. ok moritz@ --- usr.sbin/sasyncd/carp.c | 154 ++++++++++++++++++++++++---------------- usr.sbin/sasyncd/conf.y | 16 ++--- usr.sbin/sasyncd/net_ctl.c | 9 +-- usr.sbin/sasyncd/sasyncd.c | 7 +- usr.sbin/sasyncd/sasyncd.conf.5 | 7 +- usr.sbin/sasyncd/sasyncd.h | 14 ++-- 6 files changed, 116 insertions(+), 91 deletions(-) diff --git a/usr.sbin/sasyncd/carp.c b/usr.sbin/sasyncd/carp.c index dee7e4451b5..918328dc51e 100644 --- a/usr.sbin/sasyncd/carp.c +++ b/usr.sbin/sasyncd/carp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: carp.c,v 1.2 2006/01/26 09:53:46 moritz Exp $ */ +/* $OpenBSD: carp.c,v 1.3 2006/06/01 22:43:12 mcbride Exp $ */ /* * Copyright (c) 2005 Håkan Olsson. All rights reserved. @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include @@ -43,19 +43,33 @@ #include "sasyncd.h" -/* For some reason, ip_carp.h does not define this. */ -#define CARP_INIT 0 -#define CARP_BACKUP 1 -#define CARP_MASTER 2 +static enum RUNSTATE +carp_map_state(u_char link_state) +{ + enum RUNSTATE state = FAIL; + + switch(link_state) { + case LINK_STATE_UP: + state = MASTER; + break; + case LINK_STATE_DOWN: + state = SLAVE; + break; + case LINK_STATE_UNKNOWN: + state = INIT; + break; + } + + return state; +} /* Returns 1 for the CARP MASTER, 0 for BACKUP/INIT, -1 on error. */ static enum RUNSTATE carp_get_state(char *ifname) { struct ifreq ifr; - struct carpreq carp; + struct if_data ifrdat; int s, saved_errno; - char *state; if (!ifname || !*ifname) { errno = ENOENT; @@ -69,58 +83,40 @@ carp_get_state(char *ifname) if (s < 0) return FAIL; - ifr.ifr_data = (caddr_t)&carp; - if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1) { + ifr.ifr_data = (caddr_t)&ifrdat; + if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1) { saved_errno = errno; close(s); errno = saved_errno; return FAIL; } close(s); + return carp_map_state(ifrdat.ifi_link_state); +} - switch (carp.carpr_state) { - case CARP_INIT: - state = "INIT"; - break; - - case CARP_BACKUP: - state = "BACKUP"; - break; - - case CARP_MASTER: - state = "MASTER"; - break; - - default: - state = ""; - break; - } - - log_msg(4, "carp_get_state: %s vhid %d state %s(%d)", ifname, - carp.carpr_vhid, state, carp.carpr_state); +const char* +carp_state_name(enum RUNSTATE state) +{ + static const char *carpstate[] = CARPSTATES; - if (carp.carpr_vhid > 0) - return carp.carpr_state == CARP_MASTER ? MASTER : SLAVE; - else - return FAIL; + if (state < 0 || state > FAIL) + state = FAIL; + return carpstate[state]; } void -carp_check_state(void) +carp_update_state(enum RUNSTATE current_state) { - enum RUNSTATE current_state = carp_get_state(cfgstate.carp_ifname); - static char *carpstate[] = CARPSTATES; if (current_state < 0 || current_state > FAIL) { - log_err("carp_state_tracker: invalid result on interface " - "%s, abort", cfgstate.carp_ifname); + log_err("carp_update_state: invalid carp state, abort"); cfgstate.runstate = FAIL; return; } if (current_state != cfgstate.runstate) { - log_msg(1, "carp_state_tracker: switching state to %s", - carpstate[current_state]); + log_msg(1, "carp_update_state: switching state to %s", + carp_state_name(current_state)); cfgstate.runstate = current_state; if (current_state == MASTER) pfkey_set_promisc(); @@ -128,49 +124,81 @@ carp_check_state(void) } } -static void -carp_state_tracker(void *v_arg) +void +carp_check_state() { - static int failures = 0; - u_int32_t next_check; + carp_update_state(carp_get_state(cfgstate.carp_ifname)); +} - carp_check_state(); +void +carp_set_rfd(fd_set *fds) +{ + if (cfgstate.route_socket != -1) + FD_SET(cfgstate.route_socket, fds); +} - if (cfgstate.runstate == FAIL) - if (++failures < 3) - log_err("carp_state_tracker"); +static void +carp_read(void) +{ + char msg[2048]; + struct if_msghdr *ifm = (struct if_msghdr *)&msg; + int len; - if (failures > 5) - next_check = 600; - else - next_check = cfgstate.carp_check_interval + failures * 10; + len = read(cfgstate.route_socket, msg, sizeof(msg)); - if (timer_add("carp_state_tracker", next_check, carp_state_tracker, - NULL)) - log_msg(0, "carp_state_tracker: failed to renew event"); - return; + if (len >= sizeof(struct if_msghdr) && + ifm->ifm_version == RTM_VERSION && + ifm->ifm_type == RTM_IFINFO) + carp_update_state(carp_map_state(ifm->ifm_data.ifi_link_state)); } -/* Initialize the CARP state tracker. */ +void +carp_read_message(fd_set *fds) +{ + if (cfgstate.route_socket != -1) + if (FD_ISSET(cfgstate.route_socket, fds)) + (void)carp_read(); +} + +/* Initialize the CARP state. */ int carp_init(void) { - enum RUNSTATE initial_state; + cfgstate.route_socket = -1; if (cfgstate.lockedstate != INIT) { cfgstate.runstate = cfgstate.lockedstate; log_msg(1, "carp_init: locking runstate to %s", - cfgstate.runstate == MASTER ? "MASTER" : "SLAVE"); + carp_state_name(cfgstate.runstate)); return 0; } - initial_state = carp_get_state(cfgstate.carp_ifname); - if (initial_state == FAIL) { + if (!cfgstate.carp_ifname || !*cfgstate.carp_ifname) { + fprintf(stderr, "No carp interface\n"); + return -1; + } + + cfgstate.carp_ifindex = if_nametoindex(cfgstate.carp_ifname); + if (!cfgstate.carp_ifindex) { + fprintf(stderr, "No carp interface index\n"); + return -1; + } + + cfgstate.route_socket = socket(PF_ROUTE, SOCK_RAW, 0); + if (cfgstate.route_socket < 0) { + fprintf(stderr, "No routing socket\n"); + return -1; + } + + cfgstate.runstate = carp_get_state(cfgstate.carp_ifname); + if (cfgstate.runstate == FAIL) { fprintf(stderr, "Failed to check interface \"%s\".\n", cfgstate.carp_ifname); fprintf(stderr, "Correct or manually select runstate.\n"); return -1; } + log_msg(1, "carp_init: initializing runstate to %s", + carp_state_name(cfgstate.runstate)); - return timer_add("carp_state_tracker", 0, carp_state_tracker, NULL); + return 0; } diff --git a/usr.sbin/sasyncd/conf.y b/usr.sbin/sasyncd/conf.y index 1156ff6b1b0..51108fd5293 100644 --- a/usr.sbin/sasyncd/conf.y +++ b/usr.sbin/sasyncd/conf.y @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.y,v 1.8 2006/03/31 17:38:18 pat Exp $ */ +/* $OpenBSD: conf.y,v 1.9 2006/06/01 22:43:12 mcbride Exp $ */ /* * Copyright (c) 2005 Håkan Olsson. All rights reserved. @@ -62,7 +62,7 @@ void yyerror(const char *); %token SKIPSLAVE %token STRING %token VALUE -%type af port interval mode flushmode +%type af port mode flushmode %% /* Rules */ @@ -97,23 +97,17 @@ modes : SKIPSLAVE } ; -interval : /* empty */ { $$ = CARP_DEFAULT_INTERVAL; } - | INTERVAL VALUE { $$ = $2; } - ; - flushmode : STARTUP { $$ = FM_STARTUP; } | NEVER { $$ = FM_NEVER; } | SYNC { $$ = FM_SYNC; } ; -setting : CARP INTERFACE STRING interval +setting : CARP INTERFACE STRING { if (cfgstate.carp_ifname) free(cfgstate.carp_ifname); cfgstate.carp_ifname = $3; - cfgstate.carp_check_interval = $4; - log_msg(2, "config: carp interface %s interval %d", - $3, $4); + log_msg(2, "config: carp interface %s", $3); } | FLUSHMODE flushmode { @@ -204,7 +198,6 @@ match(char *token) { "inet", INET }, { "inet6", INET6 }, { "interface", INTERFACE }, - { "interval", INTERVAL }, { "listen", LISTEN }, { "master", Y_MASTER }, { "mode", MODE }, @@ -346,7 +339,6 @@ conf_init(int argc, char **argv) cfgstate.runstate = INIT; LIST_INIT(&cfgstate.peerlist); - cfgstate.carp_check_interval = CARP_DEFAULT_INTERVAL; cfgstate.listen_port = SASYNCD_DEFAULT_PORT; while ((ch = getopt(argc, argv, "c:dv")) != -1) { diff --git a/usr.sbin/sasyncd/net_ctl.c b/usr.sbin/sasyncd/net_ctl.c index 820551b4cad..811ed648ba5 100644 --- a/usr.sbin/sasyncd/net_ctl.c +++ b/usr.sbin/sasyncd/net_ctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: net_ctl.c,v 1.6 2005/05/26 19:19:51 ho Exp $ */ +/* $OpenBSD: net_ctl.c,v 1.7 2006/06/01 22:43:12 mcbride Exp $ */ /* * Copyright (c) 2005 Håkan Olsson. All rights reserved. @@ -53,8 +53,6 @@ struct ctlmsg { static int net_ctl_check_state(struct syncpeer *p, enum RUNSTATE nstate) { - static char *runstate[] = CARPSTATES; - if (nstate < INIT || nstate > FAIL) { log_msg(0, "net_ctl: got bad state %d from peer \"%s\"", nstate, p->name); @@ -70,7 +68,7 @@ net_ctl_check_state(struct syncpeer *p, enum RUNSTATE nstate) if (p->runstate != nstate) { p->runstate = nstate; log_msg(1, "net_ctl: peer \"%s\" state change to %s", p->name, - runstate[nstate]); + carp_state_name(nstate)); } return 0; } @@ -181,7 +179,6 @@ void net_ctl_update_state(void) { struct syncpeer *p; - static char *carpstate[] = CARPSTATES; /* We may have new peers available. */ net_connect(); @@ -190,7 +187,7 @@ net_ctl_update_state(void) if (p->socket == -1) continue; log_msg(4, "net_ctl: sending my state %s to peer \"%s\"", - carpstate[cfgstate.runstate], p->name); + carp_state_name(cfgstate.runstate), p->name); net_ctl_send_state(p); } } diff --git a/usr.sbin/sasyncd/sasyncd.c b/usr.sbin/sasyncd/sasyncd.c index d5193fa4b5e..d9277382b93 100644 --- a/usr.sbin/sasyncd/sasyncd.c +++ b/usr.sbin/sasyncd/sasyncd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sasyncd.c,v 1.9 2005/05/26 19:18:16 ho Exp $ */ +/* $OpenBSD: sasyncd.c,v 1.10 2006/06/01 22:43:12 mcbride Exp $ */ /* * Copyright (c) 2005 Håkan Olsson. All rights reserved. @@ -92,6 +92,10 @@ sasyncd_run(pid_t ppid) if (cfgstate.pfkey_socket + 1 > maxfd) maxfd = cfgstate.pfkey_socket + 1; + carp_set_rfd(rfds); + if (cfgstate.route_socket + 1 > maxfd) + maxfd = cfgstate.route_socket + 1; + timeout = &tv; timer_next_event(&tv); @@ -106,6 +110,7 @@ sasyncd_run(pid_t ppid) net_send_messages(wfds); pfkey_read_message(rfds); pfkey_send_message(wfds); + carp_read_message(rfds); } timer_run(); diff --git a/usr.sbin/sasyncd/sasyncd.conf.5 b/usr.sbin/sasyncd/sasyncd.conf.5 index 90b12e2a13d..05981e463cc 100644 --- a/usr.sbin/sasyncd/sasyncd.conf.5 +++ b/usr.sbin/sasyncd/sasyncd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: sasyncd.conf.5,v 1.10 2006/05/26 04:02:59 deraadt Exp $ +.\" $OpenBSD: sasyncd.conf.5,v 1.11 2006/06/01 22:43:12 mcbride Exp $ .\" .\" Copyright (c) 2005 Håkan Olsson. All rights reserved. .\" @@ -60,16 +60,13 @@ The following configuration settings are understood: .Bl -tag -width Ds .It Xo .Ic carp interface -.Ar interface Op Ic interval Ar seconds +.Ar interface .Xc Specify which .Xr carp 4 interface .Nm sasyncd should track master/slave state on. -Optionally state how often the daemon should check the interface -for state changes. -Defaults to once every 10 seconds. .It Ic flushmode sync | startup | never Controls how the .Xr sasyncd 8 diff --git a/usr.sbin/sasyncd/sasyncd.h b/usr.sbin/sasyncd/sasyncd.h index c5d5ba6a798..f5ecd723831 100644 --- a/usr.sbin/sasyncd/sasyncd.h +++ b/usr.sbin/sasyncd/sasyncd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sasyncd.h,v 1.8 2005/05/28 01:07:52 ho Exp $ */ +/* $OpenBSD: sasyncd.h,v 1.9 2006/06/01 22:43:12 mcbride Exp $ */ /* * Copyright (c) 2005 Håkan Olsson. All rights reserved. @@ -46,12 +46,14 @@ struct cfgstate { u_int32_t flags; char *carp_ifname; - int carp_check_interval; + int carp_ifindex; char *sharedkey; int pfkey_socket; + int route_socket; + char *listen_on; in_port_t listen_port; sa_family_t listen_family; @@ -94,8 +96,12 @@ extern struct cfgstate cfgstate; int conf_init(int, char **); /* carp.c */ -void carp_check_state(void); -int carp_init(void); +int carp_init(void); +void carp_check_state(void); +void carp_update_state(enum RUNSTATE); +void carp_set_rfd(fd_set *); +void carp_read_message(fd_set *); +const char* carp_state_name(enum RUNSTATE); /* log.c */ /* -- cgit v1.2.3