summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Thomas McBride <mcbride@cvs.openbsd.org>2006-06-01 22:43:13 +0000
committerRyan Thomas McBride <mcbride@cvs.openbsd.org>2006-06-01 22:43:13 +0000
commit7cc0bcb3caa70f0c856cc5ff4119c1becd83708d (patch)
treeb5d4382246fb77c4ddd64d4634ca2b4b5d0ea462
parentfff1c1e24f6f58e55881a74c755dfe1e500b1ad0 (diff)
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@
-rw-r--r--usr.sbin/sasyncd/carp.c154
-rw-r--r--usr.sbin/sasyncd/conf.y16
-rw-r--r--usr.sbin/sasyncd/net_ctl.c9
-rw-r--r--usr.sbin/sasyncd/sasyncd.c7
-rw-r--r--usr.sbin/sasyncd/sasyncd.conf.57
-rw-r--r--usr.sbin/sasyncd/sasyncd.h14
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 <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
-#include <netinet/ip_carp.h>
+#include <net/route.h>
#include <errno.h>
#include <stdio.h>
@@ -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 = "<unknown>";
- 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> STRING
%token <val> VALUE
-%type <val> af port interval mode flushmode
+%type <val> 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 */
/*