diff options
author | 2007-05-29 22:08:25 +0000 | |
---|---|---|
committer | 2007-05-29 22:08:25 +0000 | |
commit | fba2d3d0ed78659b3eaed86dbc20ef17780ed1fb (patch) | |
tree | 14226c6f664488715ff3772b1e8146981d5a07c0 | |
parent | I suck. Forgot splx() in the early return path. (diff) | |
download | wireguard-openbsd-fba2d3d0ed78659b3eaed86dbc20ef17780ed1fb.tar.xz wireguard-openbsd-fba2d3d0ed78659b3eaed86dbc20ef17780ed1fb.zip |
Demote support for ospfd. It is possible to specify a demote group on
interfaces and areas. With this carp setups using ospfd are more reliable
because we can fail over if the OSPF connectivity is (partially) lost.
OK norby@
-rw-r--r-- | usr.sbin/ospfd/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/ospfd/area.c | 11 | ||||
-rw-r--r-- | usr.sbin/ospfd/carp.c | 181 | ||||
-rw-r--r-- | usr.sbin/ospfd/interface.c | 15 | ||||
-rw-r--r-- | usr.sbin/ospfd/ospfd.c | 18 | ||||
-rw-r--r-- | usr.sbin/ospfd/ospfd.h | 20 | ||||
-rw-r--r-- | usr.sbin/ospfd/ospfe.c | 42 | ||||
-rw-r--r-- | usr.sbin/ospfd/ospfe.h | 4 | ||||
-rw-r--r-- | usr.sbin/ospfd/parse.y | 42 | ||||
-rw-r--r-- | usr.sbin/ospfd/printconf.c | 7 |
10 files changed, 331 insertions, 13 deletions
diff --git a/usr.sbin/ospfd/Makefile b/usr.sbin/ospfd/Makefile index 20b20bb1149..2e13a46dce0 100644 --- a/usr.sbin/ospfd/Makefile +++ b/usr.sbin/ospfd/Makefile @@ -1,8 +1,8 @@ -# $OpenBSD: Makefile,v 1.6 2006/11/26 11:31:13 deraadt Exp $ +# $OpenBSD: Makefile,v 1.7 2007/05/29 22:08:25 claudio Exp $ PROG= ospfd -SRCS= area.c auth.c buffer.c control.c database.c hello.c \ +SRCS= area.c auth.c buffer.c carp.c control.c database.c hello.c \ imsg.c in_cksum.c interface.c iso_cksum.c kroute.c lsack.c \ lsreq.c lsupdate.c log.c neighbor.c ospfd.c ospfe.c packet.c \ parse.y printconf.c rde.c rde_lsdb.c rde_spf.c name2id.c diff --git a/usr.sbin/ospfd/area.c b/usr.sbin/ospfd/area.c index 7b37ea9f040..169e791e054 100644 --- a/usr.sbin/ospfd/area.c +++ b/usr.sbin/ospfd/area.c @@ -1,4 +1,4 @@ -/* $OpenBSD: area.c,v 1.4 2005/05/26 18:59:14 norby Exp $ */ +/* $OpenBSD: area.c,v 1.5 2007/05/29 22:08:25 claudio Exp $ */ /* * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> @@ -53,6 +53,10 @@ area_del(struct area *area) struct vertex *v, *nv; struct rde_nbr *n; + /* area is removed so neutralize the demotion done by the area */ + if (area->active == 0) + ospfe_demote_area(area, 1); + /* clean lists */ while ((iface = LIST_FIRST(&area->iface_list)) != NULL) { LIST_REMOVE(iface, entry); @@ -90,12 +94,17 @@ area_find(struct ospfd_conf *conf, struct in_addr area_id) void area_track(struct area *area, int state) { + int old = area->active; + if (state & NBR_STA_FULL) area->active++; else if (area->active == 0) fatalx("king bula sez: area already inactive"); else area->active--; + + if (area->active == 0 || old == 0) + ospfe_demote_area(area, old == 0); } int diff --git a/usr.sbin/ospfd/carp.c b/usr.sbin/ospfd/carp.c new file mode 100644 index 00000000000..b633ba01708 --- /dev/null +++ b/usr.sbin/ospfd/carp.c @@ -0,0 +1,181 @@ +/* $OpenBSD: carp.c,v 1.1 2007/05/29 22:08:25 claudio Exp $ */ + +/* + * Copyright (c) 2006 Henning Brauer <henning@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <net/if.h> + +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include "ospfd.h" +#include "log.h" + +struct carpgroup { + TAILQ_ENTRY(carpgroup) entry; + char *group; + int do_demote; + int changed_by; +}; + +TAILQ_HEAD(carpgroups, carpgroup) carpgroups = + TAILQ_HEAD_INITIALIZER(carpgroups); + +struct carpgroup *carp_group_find(char *group); +int carp_demote_ioctl(char *, int); + +struct carpgroup * +carp_group_find(char *group) +{ + struct carpgroup *c; + + TAILQ_FOREACH(c, &carpgroups, entry) + if (!strcmp(c->group, group)) + return (c); + + return (NULL); +} + +int +carp_demote_init(char *group, int force) +{ + struct carpgroup *c; + int level; + + if ((c = carp_group_find(group)) == NULL) { + if ((c = calloc(1, sizeof(struct carpgroup))) == NULL) { + log_warn("carp_demote_init calloc"); + return (-1); + } + if ((c->group = strdup(group)) == NULL) { + log_warn("carp_demote_init strdup"); + free(c); + return (-1); + } + + /* only demote if this group already is demoted */ + if ((level = carp_demote_get(group)) == -1) + return (-1); + if (level > 0 || force) + c->do_demote = 1; + + TAILQ_INSERT_TAIL(&carpgroups, c, entry); + } + + return (0); +} + +void +carp_demote_shutdown(void) +{ + struct carpgroup *c; + + while ((c = TAILQ_FIRST(&carpgroups)) != NULL) { + TAILQ_REMOVE(&carpgroups, c, entry); + for (; c->changed_by > 0; c->changed_by--) + if (c->do_demote) + carp_demote_ioctl(c->group, -1); + + free(c->group); + free(c); + } +} + +int +carp_demote_get(char *group) +{ + int s; + struct ifgroupreq ifgr; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + log_warn("carp_demote_get: socket"); + return (-1); + } + + bzero(&ifgr, sizeof(ifgr)); + strlcpy(ifgr.ifgr_name, group, sizeof(ifgr.ifgr_name)); + + if (ioctl(s, SIOCGIFGATTR, (caddr_t)&ifgr) == -1) { + if (errno == ENOENT) + log_warnx("group \"%s\" does not exist", group); + else + log_warn("carp_demote_get: ioctl"); + close(s); + return (-1); + } + + close(s); + return ((int)ifgr.ifgr_attrib.ifg_carp_demoted); +} + +int +carp_demote_set(char *group, int demote) +{ + struct carpgroup *c; + + if ((c = carp_group_find(group)) == NULL) { + log_warnx("carp_group_find for %s returned NULL?!", group); + return (-1); + } + + if (c->changed_by + demote < 0) { + log_warnx("carp_demote_set: changed_by + demote < 0"); + return (-1); + } + + if (c->do_demote && carp_demote_ioctl(group, demote) == -1) + return (-1); + + c->changed_by += demote; + + /* enable demotion when we return to 0, i. e. all sessions up */ + if (demote < 0 && c->changed_by == 0) + c->do_demote = 1; + + return (0); +} + +int +carp_demote_ioctl(char *group, int demote) +{ + int s, res; + struct ifgroupreq ifgr; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + log_warn("carp_demote_get: socket"); + return (-1); + } + + bzero(&ifgr, sizeof(ifgr)); + strlcpy(ifgr.ifgr_name, group, sizeof(ifgr.ifgr_name)); + ifgr.ifgr_attrib.ifg_carp_demoted = demote; + + if ((res = ioctl(s, SIOCSIFGATTR, (caddr_t)&ifgr)) == -1) + log_warn("unable to %s the demote state " + "of group '%s'", (demote > 0) ? "increment" : "decrement", + group); + else + log_info("%s the demote state of group '%s'", + (demote > 0) ? "incremented" : "decremented", group); + + close(s); + return (res); +} diff --git a/usr.sbin/ospfd/interface.c b/usr.sbin/ospfd/interface.c index 8d6f2f7e940..393d277ab96 100644 --- a/usr.sbin/ospfd/interface.c +++ b/usr.sbin/ospfd/interface.c @@ -1,4 +1,4 @@ -/* $OpenBSD: interface.c,v 1.58 2007/02/01 13:25:28 claudio Exp $ */ +/* $OpenBSD: interface.c,v 1.59 2007/05/29 22:08:25 claudio Exp $ */ /* * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> @@ -139,6 +139,13 @@ if_fsm(struct iface *iface, enum iface_event event) if (iface->state != old_state) orig_rtr_lsa(iface->area); + if (old_state & (IF_STA_MULTI | IF_STA_POINTTOPOINT) && + (iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0) + ospfe_demote_iface(iface, 0); + if ((old_state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0 && + iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) + ospfe_demote_iface(iface, 1); + log_debug("if_fsm: event %s resulted in action %s and changing " "state for interface %s from %s to %s", if_event_names[event], if_action_names[iface_fsm[i].action], @@ -209,6 +216,10 @@ if_del(struct iface *iface) log_debug("if_del: interface %s", iface->name); + /* revert the demotion when the interface is deleted */ + if ((iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0) + ospfe_demote_iface(iface, 1); + /* clear lists etc */ while ((nbr = LIST_FIRST(&iface->nbr_list)) != NULL) nbr_del(nbr); @@ -237,6 +248,8 @@ if_init(struct ospfd_conf *xconf, struct iface *iface) evtimer_set(&iface->wait_timer, if_wait_timer, iface); iface->fd = xconf->ospf_socket; + + ospfe_demote_iface(iface, 0); } /* timers */ diff --git a/usr.sbin/ospfd/ospfd.c b/usr.sbin/ospfd/ospfd.c index d27330b1094..e71744f1119 100644 --- a/usr.sbin/ospfd/ospfd.c +++ b/usr.sbin/ospfd/ospfd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ospfd.c,v 1.45 2007/03/25 15:48:54 claudio Exp $ */ +/* $OpenBSD: ospfd.c,v 1.46 2007/05/29 22:08:25 claudio Exp $ */ /* * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> @@ -117,7 +117,7 @@ usage(void) { extern char *__progname; - fprintf(stderr, "usage: %s [-dnv] [-f file]\n", __progname); + fprintf(stderr, "usage: %s [-cdnv] [-f file]\n", __progname); exit(1); } @@ -135,8 +135,11 @@ main(int argc, char *argv[]) conffile = CONF_FILE; ospfd_process = PROC_MAIN; - while ((ch = getopt(argc, argv, "df:nv")) != -1) { + while ((ch = getopt(argc, argv, "cdf:nv")) != -1) { switch (ch) { + case 'c': + opts |= OSPFD_OPT_FORCE_DEMOTE; + break; case 'd': debug = 1; break; @@ -295,6 +298,7 @@ ospfd_shutdown(void) control_cleanup(); kr_shutdown(); + carp_demote_shutdown(); do { if ((pid = wait(NULL)) == -1 && @@ -339,6 +343,7 @@ main_dispatch_ospfe(int fd, short event, void *bula) { struct imsgbuf *ibuf = bula; struct imsg imsg; + struct demote_msg dmsg; ssize_t n; switch (event) { @@ -389,6 +394,12 @@ main_dispatch_ospfe(int fd, short event, void *bula) else log_warnx("IFINFO request with wrong len"); break; + case IMSG_DEMOTE: + if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(dmsg)) + fatalx("invalid size of OE request"); + memcpy(&dmsg, imsg.data, sizeof(dmsg)); + carp_demote_set(dmsg.demote_group, dmsg.level); + break; default: log_debug("main_dispatch_ospfe: error handling imsg %d", imsg.hdr.type); @@ -667,6 +678,7 @@ merge_config(struct ospfd_conf *conf, struct ospfd_conf *xconf) LIST_INSERT_HEAD(&conf->area_list, xa, entry); if (ospfd_process == PROC_OSPF_ENGINE) { /* start interfaces */ + ospfe_demote_area(xa, 0); LIST_FOREACH(iface, &xa->iface_list, entry) { if_init(conf, iface); if (if_fsm(iface, IF_EVT_UP)) { diff --git a/usr.sbin/ospfd/ospfd.h b/usr.sbin/ospfd/ospfd.h index ece2f416e89..7da4116f7b2 100644 --- a/usr.sbin/ospfd/ospfd.h +++ b/usr.sbin/ospfd/ospfd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ospfd.h,v 1.66 2007/03/21 10:54:30 claudio Exp $ */ +/* $OpenBSD: ospfd.h,v 1.67 2007/05/29 22:08:25 claudio Exp $ */ /* * Copyright (c) 2004 Esben Norby <norby@openbsd.org> @@ -144,7 +144,8 @@ enum imsg_type { IMSG_RECONF_AREA, IMSG_RECONF_IFACE, IMSG_RECONF_AUTHMD, - IMSG_RECONF_END + IMSG_RECONF_END, + IMSG_DEMOTE }; struct imsg_hdr { @@ -172,12 +173,14 @@ struct area { LIST_HEAD(, iface) iface_list; LIST_HEAD(, rde_nbr) nbr_list; /* list addr_range_list; */ + char demote_group[IFNAMSIZ]; u_int32_t stub_default_cost; u_int32_t num_spf_calc; int active; u_int8_t transit; u_int8_t stub; u_int8_t dirty; + u_int8_t demote_level; }; /* interface states */ @@ -328,6 +331,7 @@ struct iface { struct lsa_head ls_ack_list; char name[IF_NAMESIZE]; + char demote_group[IFNAMSIZ]; char auth_key[MAX_SIMPLE_AUTH_LEN]; struct in_addr addr; struct in_addr dst; @@ -396,6 +400,7 @@ struct ospfd_conf { #define OSPFD_OPT_VERBOSE2 0x00000002 #define OSPFD_OPT_NOACTION 0x00000004 #define OSPFD_OPT_STUB_ROUTER 0x00000008 +#define OSPFD_OPT_FORCE_DEMOTE 0x00000010 u_int32_t spf_delay; u_int32_t spf_hold_time; time_t uptime; @@ -526,6 +531,11 @@ struct ctl_sum_area { u_int32_t num_lsa; }; +struct demote_msg { + char demote_group[IF_NAMESIZE]; + int level; +}; + /* area.c */ struct area *area_new(void); int area_del(struct area *); @@ -545,6 +555,12 @@ void msgbuf_init(struct msgbuf *); void msgbuf_clear(struct msgbuf *); int msgbuf_write(struct msgbuf *); +/* carp.c */ +int carp_demote_init(char *, int); +void carp_demote_shutdown(void); +int carp_demote_get(char *); +int carp_demote_set(char *, int); + /* parse.y */ struct ospfd_conf *parse_config(char *, int); int cmdline_symset(char *); diff --git a/usr.sbin/ospfd/ospfe.c b/usr.sbin/ospfd/ospfe.c index f97fd09d02b..90c30d427d4 100644 --- a/usr.sbin/ospfd/ospfe.c +++ b/usr.sbin/ospfd/ospfe.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ospfe.c,v 1.54 2007/03/21 10:54:30 claudio Exp $ */ +/* $OpenBSD: ospfe.c,v 1.55 2007/05/29 22:08:25 claudio Exp $ */ /* * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> @@ -179,6 +179,7 @@ ospfe(struct ospfd_conf *xconf, int pipe_parent2ospfe[2], int pipe_ospfe2rde[2], /* start interfaces */ LIST_FOREACH(area, &oeconf->area_list, entry) { + ospfe_demote_area(area, 0); LIST_FOREACH(iface, &area->iface_list, entry) { if_init(xconf, iface); if (if_fsm(iface, IF_EVT_UP)) { @@ -1043,3 +1044,42 @@ ospfe_nbr_ctl(struct ctl_conn *c) imsg_compose(&c->ibuf, IMSG_CTL_END, 0, 0, NULL, 0); } + +void +ospfe_demote_area(struct area *area, int active) +{ + struct demote_msg dmsg; + + if (ospfd_process != PROC_OSPF_ENGINE || + area->demote_group[0] == '\0') + return; + + bzero(&dmsg, sizeof(dmsg)); + strlcpy(dmsg.demote_group, area->demote_group, + sizeof(dmsg.demote_group)); + dmsg.level = area->demote_level; + if (active) + dmsg.level = -dmsg.level; + + ospfe_imsg_compose_parent(IMSG_DEMOTE, 0, &dmsg, sizeof(dmsg)); +} + +void +ospfe_demote_iface(struct iface *iface, int active) +{ + struct demote_msg dmsg; + + if (ospfd_process != PROC_OSPF_ENGINE || + iface->demote_group[0] == '\0') + return; + + bzero(&dmsg, sizeof(dmsg)); + strlcpy(dmsg.demote_group, iface->demote_group, + sizeof(dmsg.demote_group)); + if (active) + dmsg.level = -1; + else + dmsg.level = 1; + + ospfe_imsg_compose_parent(IMSG_DEMOTE, 0, &dmsg, sizeof(dmsg)); +} diff --git a/usr.sbin/ospfd/ospfe.h b/usr.sbin/ospfd/ospfe.h index fa27628090c..e828fe6465d 100644 --- a/usr.sbin/ospfd/ospfe.h +++ b/usr.sbin/ospfd/ospfe.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ospfe.h,v 1.35 2007/03/21 10:54:30 claudio Exp $ */ +/* $OpenBSD: ospfe.h,v 1.36 2007/05/29 22:08:25 claudio Exp $ */ /* * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> @@ -130,6 +130,8 @@ void ospfe_iface_ctl(struct ctl_conn *, unsigned int); void ospfe_nbr_ctl(struct ctl_conn *); void orig_rtr_lsa(struct area *); void orig_net_lsa(struct iface *); +void ospfe_demote_area(struct area *, int); +void ospfe_demote_iface(struct iface *, int); /* interface.c */ int if_fsm(struct iface *, enum iface_event); diff --git a/usr.sbin/ospfd/parse.y b/usr.sbin/ospfd/parse.y index 564928298c7..9d96f6641b1 100644 --- a/usr.sbin/ospfd/parse.y +++ b/usr.sbin/ospfd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.47 2007/03/28 14:17:13 claudio Exp $ */ +/* $OpenBSD: parse.y,v 1.48 2007/05/29 22:08:25 claudio Exp $ */ /* * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> @@ -112,6 +112,7 @@ typedef struct { %token RETRANSMITINTERVAL ROUTERDEADTIME ROUTERPRIORITY %token SET TYPE %token YES NO +%token DEMOTE %token ERROR %token <v.string> STRING %type <v.number> number yesno no optlist, optlist_l option @@ -470,6 +471,28 @@ areaopts_l : areaopts_l areaoptsl nl ; areaoptsl : interface + | DEMOTE STRING number { + if ($3 > 255) { + yyerror("demote count too big: max 255"); + free($2); + YYERROR; + } + area->demote_level = $3; + if (strlcpy(area->demote_group, $2, + sizeof(area->demote_group)) >= + sizeof(area->demote_group)) { + yyerror("demote group name \"%s\" too long"); + free($2); + YYERROR; + } + free($2); + if (carp_demote_init(area->demote_group, + conf->opts & OSPFD_OPT_FORCE_DEMOTE) == -1) { + yyerror("error initializing group \"%s\"", + area->demote_group); + YYERROR; + } + } | defaults ; @@ -544,6 +567,22 @@ interfaceopts_l : interfaceopts_l interfaceoptsl nl ; interfaceoptsl : PASSIVE { iface->passive = 1; } + | DEMOTE STRING { + if (strlcpy(iface->demote_group, $2, + sizeof(iface->demote_group)) >= + sizeof(iface->demote_group)) { + yyerror("demote group name \"%s\" too long"); + free($2); + YYERROR; + } + free($2); + if (carp_demote_init(iface->demote_group, + conf->opts & OSPFD_OPT_FORCE_DEMOTE) == -1) { + yyerror("error initializing group \"%s\"", + iface->demote_group); + YYERROR; + } + } | defaults ; @@ -585,6 +624,7 @@ lookup(char *s) {"auth-md", AUTHMD}, {"auth-md-keyid", AUTHMDKEYID}, {"auth-type", AUTHTYPE}, + {"demote", DEMOTE}, {"fib-update", FIBUPDATE}, {"hello-interval", HELLOINTERVAL}, {"interface", INTERFACE}, diff --git a/usr.sbin/ospfd/printconf.c b/usr.sbin/ospfd/printconf.c index b7f2445e22d..510a7ae87a6 100644 --- a/usr.sbin/ospfd/printconf.c +++ b/usr.sbin/ospfd/printconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: printconf.c,v 1.8 2007/03/22 16:00:46 claudio Exp $ */ +/* $OpenBSD: printconf.c,v 1.9 2007/05/29 22:08:25 claudio Exp $ */ /* * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> @@ -107,6 +107,8 @@ print_iface(struct iface *iface) if (iface->passive) printf("\t\tpassive\n"); + if (*iface->demote_group) + printf("\t\tdemote %s\n", iface->demote_group); printf("\t\tretransmit-interval %d\n", iface->rxmt_interval); printf("\t\trouter-dead-time %d\n", iface->dead_interval); @@ -145,6 +147,9 @@ print_config(struct ospfd_conf *conf) LIST_FOREACH(area, &conf->area_list, entry) { printf("area %s {\n", inet_ntoa(area->id)); + if (*area->demote_group) + printf("\tdemote %s %d\n", area->demote_group, + area->demote_level); LIST_FOREACH(iface, &area->iface_list, entry) { print_iface(iface); } |