From a66c91f28b18519c5399bcf1794de7b53f089505 Mon Sep 17 00:00:00 2001 From: remi Date: Thu, 12 Jul 2018 12:19:05 +0000 Subject: [PATCH] With the "depend on" option routes are sent out with a metric of 65535 if the referenced interface is down or in state backup. This is especially useful on a carp cluster to ensure all traffic goes to the carp master. ok friehm@ jca@ --- usr.sbin/ospf6d/kroute.c | 12 +++------ usr.sbin/ospf6d/ospf6d.c | 37 +++++++++++++++++++++----- usr.sbin/ospf6d/ospf6d.conf.5 | 19 +++++++++++-- usr.sbin/ospf6d/ospf6d.h | 6 ++++- usr.sbin/ospf6d/ospfe.c | 40 ++++++++++++++++++++++++---- usr.sbin/ospf6d/parse.y | 50 ++++++++++++++++++++++++++++++++--- usr.sbin/ospf6d/printconf.c | 9 +++++-- usr.sbin/ospf6d/rde.c | 29 ++++++++++++++++---- 8 files changed, 168 insertions(+), 34 deletions(-) diff --git a/usr.sbin/ospf6d/kroute.c b/usr.sbin/ospf6d/kroute.c index 5e485ff83f6..7d798cd038a 100644 --- a/usr.sbin/ospf6d/kroute.c +++ b/usr.sbin/ospf6d/kroute.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kroute.c,v 1.56 2018/07/10 12:17:38 friehm Exp $ */ +/* $OpenBSD: kroute.c,v 1.57 2018/07/12 12:19:05 remi Exp $ */ /* * Copyright (c) 2004 Esben Norby @@ -810,13 +810,9 @@ if_change(u_short ifindex, int flags, struct if_data *ifd) return; } - /* inform engine and rde about state change if interface is used */ - if (iface->cflags & F_IFACE_CONFIGURED) { - main_imsg_compose_ospfe(IMSG_IFINFO, 0, iface, - sizeof(struct iface)); - main_imsg_compose_rde(IMSG_IFINFO, 0, iface, - sizeof(struct iface)); - } + /* inform engine and rde about state change */ + main_imsg_compose_rde(IMSG_IFINFO, 0, iface, sizeof(struct iface)); + main_imsg_compose_ospfe(IMSG_IFINFO, 0, iface, sizeof(struct iface)); isvalid = (iface->flags & IFF_UP) && LINK_STATE_IS_UP(iface->linkstate); diff --git a/usr.sbin/ospf6d/ospf6d.c b/usr.sbin/ospf6d/ospf6d.c index 0e40111b526..dcea8c7a86b 100644 --- a/usr.sbin/ospf6d/ospf6d.c +++ b/usr.sbin/ospf6d/ospf6d.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ospf6d.c,v 1.36 2018/07/09 13:19:46 remi Exp $ */ +/* $OpenBSD: ospf6d.c,v 1.37 2018/07/12 12:19:05 remi Exp $ */ /* * Copyright (c) 2005 Claudio Jeker @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -485,17 +486,27 @@ ospf_redistribute(struct kroute *kr, u_int32_t *metric) { struct redistribute *r; struct in6_addr ina, inb; + struct iface *iface; u_int8_t is_default = 0; + int depend_ok; /* only allow ::/0 via REDIST_DEFAULT */ if (IN6_IS_ADDR_UNSPECIFIED(&kr->prefix) && kr->prefixlen == 0) is_default = 1; SIMPLEQ_FOREACH(r, &ospfd_conf->redist_list, entry) { + if (r->dependon[0] != '\0') { + if ((iface = if_findname(r->dependon))) + depend_ok = ifstate_is_up(iface); + else + depend_ok = 0; + } else + depend_ok = 1; + switch (r->type & ~REDIST_NO) { case REDIST_LABEL: if (kr->rtlabel == r->label) { - *metric = r->metric; + *metric = depend_ok ? r->metric : MAX_METRIC; return (r->type & REDIST_NO ? 0 : 1); } break; @@ -510,7 +521,7 @@ ospf_redistribute(struct kroute *kr, u_int32_t *metric) if (kr->flags & F_DYNAMIC) continue; if (kr->flags & F_STATIC) { - *metric = r->metric; + *metric = depend_ok ? r->metric : MAX_METRIC; return (r->type & REDIST_NO ? 0 : 1); } break; @@ -520,7 +531,7 @@ ospf_redistribute(struct kroute *kr, u_int32_t *metric) if (kr->flags & F_DYNAMIC) continue; if (kr->flags & F_CONNECTED) { - *metric = r->metric; + *metric = depend_ok ? r->metric : MAX_METRIC; return (r->type & REDIST_NO ? 0 : 1); } break; @@ -531,7 +542,8 @@ ospf_redistribute(struct kroute *kr, u_int32_t *metric) if (IN6_IS_ADDR_UNSPECIFIED(&r->addr) && r->prefixlen == 0) { if (is_default) { - *metric = r->metric; + *metric = depend_ok ? r->metric : + MAX_METRIC; return (r->type & REDIST_NO ? 0 : 1); } else return (0); @@ -541,13 +553,13 @@ ospf_redistribute(struct kroute *kr, u_int32_t *metric) inet6applymask(&inb, &r->addr, r->prefixlen); if (IN6_ARE_ADDR_EQUAL(&ina, &inb) && kr->prefixlen >= r->prefixlen) { - *metric = r->metric; + *metric = depend_ok ? r->metric : MAX_METRIC; return (r->type & REDIST_NO ? 0 : 1); } break; case REDIST_DEFAULT: if (is_default) { - *metric = r->metric; + *metric = depend_ok ? r->metric : MAX_METRIC; return (r->type & REDIST_NO ? 0 : 1); } break; @@ -774,3 +786,14 @@ iface_lookup(struct area *area, struct iface *iface) return (i); return (NULL); } + +int +ifstate_is_up(struct iface *iface) +{ + if (!(iface->flags & IFF_UP)) + return (0); + if (iface->if_type == IFT_CARP && + iface->linkstate == LINK_STATE_UNKNOWN) + return (0); + return LINK_STATE_IS_UP(iface->linkstate); +} diff --git a/usr.sbin/ospf6d/ospf6d.conf.5 b/usr.sbin/ospf6d/ospf6d.conf.5 index ddcb1be1851..ac0c51a6535 100644 --- a/usr.sbin/ospf6d/ospf6d.conf.5 +++ b/usr.sbin/ospf6d/ospf6d.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ospf6d.conf.5,v 1.14 2018/06/18 06:04:25 jmc Exp $ +.\" $OpenBSD: ospf6d.conf.5,v 1.15 2018/07/12 12:19:05 remi Exp $ .\" .\" Copyright (c) 2005 Esben Norby .\" Copyright (c) 2004 Claudio Jeker @@ -17,7 +17,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: June 18 2018 $ +.Dd $Mdocdate: July 12 2018 $ .Dt OSPF6D.CONF 5 .Os .Sh NAME @@ -109,14 +109,18 @@ option to ensure that no traffic tries to transit via this router. .Ic default Pc .Sm on .Op Ic set ...\& +.Bk -words +.Op Ic depend on Ar interface .Xc .It Xo .Op Ic no .Ic redistribute Ar prefix Op Ic set ...\& +.Op Ic depend on Ar interface .Xc .It Xo .Op Ic no .Ic redistribute rtlabel Ar label Op Ic set ...\& +.Op Ic depend on Ar interface .Xc If set to .Ic connected , @@ -148,6 +152,14 @@ which will be set no matter what, and additionally .Ic no cannot be used together with it. .Pp +With the +.Ic depend on +option, redistributed routes will have a metric of 65535 if the specified +.Ar interface +is down or in state backup. +This is especially useful on a carp cluster to ensure all traffic goes to +the carp master. +.Pp It is possible to set the route .Ic metric and @@ -267,6 +279,9 @@ demotion counter by 1 on the given interface group, usually when the interface state is going down. The demotion counter will be decreased when the interface state is active again. +.It Ic depend on Ar interface +A metric of 65535 is used if the specified interface is down or in status +backup. .It Ic hello-interval Ar seconds Set the hello interval. The default value is 10; valid range is 1\-65535 seconds. diff --git a/usr.sbin/ospf6d/ospf6d.h b/usr.sbin/ospf6d/ospf6d.h index 0b6d8835a99..38314e2992c 100644 --- a/usr.sbin/ospf6d/ospf6d.h +++ b/usr.sbin/ospf6d/ospf6d.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ospf6d.h,v 1.35 2018/02/08 00:18:20 claudio Exp $ */ +/* $OpenBSD: ospf6d.h,v 1.36 2018/07/12 12:19:05 remi Exp $ */ /* * Copyright (c) 2004, 2007 Esben Norby @@ -299,6 +299,7 @@ struct iface { char name[IF_NAMESIZE]; char demote_group[IFNAMSIZ]; + char dependon[IFNAMSIZ]; struct in6_addr addr; struct in6_addr dst; struct in_addr abr_id; @@ -314,6 +315,7 @@ struct iface { int fd; int state; int mtu; + int depend_ok; u_int16_t flags; u_int16_t transmit_delay; u_int16_t hello_interval; @@ -358,6 +360,7 @@ struct redistribute { u_int16_t label; u_int16_t type; u_int8_t prefixlen; + char dependon[IFNAMSIZ]; }; struct ospfd_conf { @@ -578,6 +581,7 @@ void merge_config(struct ospfd_conf *, struct ospfd_conf *); void imsg_event_add(struct imsgev *); int imsg_compose_event(struct imsgev *, u_int16_t, u_int32_t, pid_t, int, void *, u_int16_t); +int ifstate_is_up(struct iface *iface); /* printconf.c */ void print_config(struct ospfd_conf *); diff --git a/usr.sbin/ospf6d/ospfe.c b/usr.sbin/ospf6d/ospfe.c index 98e42409a07..7ce0392aec5 100644 --- a/usr.sbin/ospf6d/ospfe.c +++ b/usr.sbin/ospf6d/ospfe.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ospfe.c,v 1.52 2018/07/10 21:21:56 friehm Exp $ */ +/* $OpenBSD: ospfe.c,v 1.53 2018/07/12 12:19:05 remi Exp $ */ /* * Copyright (c) 2005 Claudio Jeker @@ -263,7 +263,7 @@ ospfe_dispatch_main(int fd, short event, void *bula) { static struct area *narea; struct area *area; - struct iface *iface, *ifp; + struct iface *iface, *ifp, *i; struct ifaddrchange *ifc; struct iface_addr *ia, *nia; struct imsg imsg; @@ -298,6 +298,24 @@ ospfe_dispatch_main(int fd, short event, void *bula) fatalx("IFINFO imsg with wrong len"); ifp = imsg.data; + LIST_FOREACH(area, &oeconf->area_list, entry) { + LIST_FOREACH(i, &area->iface_list, entry) { + if (strcmp(i->dependon, + ifp->name) == 0) { + log_warnx("interface %s" + " changed state, %s" + " depends on it", + ifp->name, i->name); + i->depend_ok = + ifstate_is_up(ifp); + if (ifstate_is_up(i)) + orig_rtr_lsa(i); + } + } + } + + if (!(ifp->cflags & F_IFACE_CONFIGURED)) + break; iface = if_find(ifp->ifindex); if (iface == NULL) fatalx("interface lost in ospfe"); @@ -837,7 +855,11 @@ orig_rtr_lsa_area(struct area *area) log_debug("orig_rtr_lsa: point-to-point, " "interface %s", iface->name); rtr_link.type = LINK_TYPE_POINTTOPOINT; - rtr_link.metric = htons(iface->metric); + if (iface->dependon[0] != '\0' && + iface->depend_ok == 0) + rtr_link.metric = MAX_METRIC; + else + rtr_link.metric = htons(iface->metric); rtr_link.iface_id = htonl(iface->ifindex); rtr_link.nbr_iface_id = htonl(nbr->iface_id); rtr_link.nbr_rtr_id = nbr->id.s_addr; @@ -862,7 +884,12 @@ orig_rtr_lsa_area(struct area *area) "interface %s", iface->name); rtr_link.type = LINK_TYPE_TRANSIT_NET; - rtr_link.metric = htons(iface->metric); + if (iface->dependon[0] != '\0' && + iface->depend_ok == 0) + rtr_link.metric = MAX_METRIC; + else + rtr_link.metric = + htons(iface->metric); rtr_link.iface_id = htonl(iface->ifindex); rtr_link.nbr_iface_id = htonl(iface->dr->iface_id); rtr_link.nbr_rtr_id = iface->dr->id.s_addr; @@ -922,7 +949,10 @@ orig_rtr_lsa_area(struct area *area) /* RFC 3137: stub router support */ if (oe_nofib || oeconf->flags & OSPFD_FLAG_STUB_ROUTER) - rtr_link.metric = 0xffff; + rtr_link.metric = MAX_METRIC; + else if (iface->dependon[0] != '\0' && + iface->dependon_ok == 0) + rtr_link.metric = MAX_METRIC; else rtr_link.metric = htons(iface->metric); diff --git a/usr.sbin/ospf6d/parse.y b/usr.sbin/ospf6d/parse.y index ca95db4bc60..75ffb782d7b 100644 --- a/usr.sbin/ospf6d/parse.y +++ b/usr.sbin/ospf6d/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.36 2018/07/11 10:23:47 remi Exp $ */ +/* $OpenBSD: parse.y,v 1.37 2018/07/12 12:19:05 remi Exp $ */ /* * Copyright (c) 2004, 2005 Esben Norby @@ -131,10 +131,11 @@ typedef struct { %token DEMOTE %token INCLUDE %token ERROR +%token DEPEND ON %token STRING %token NUMBER %type yesno no optlist, optlist_l option demotecount -%type string +%type string dependon %type redistribute %% @@ -259,7 +260,7 @@ conf_main : ROUTERID STRING { | defaults ; -redistribute : no REDISTRIBUTE STRING optlist { +redistribute : no REDISTRIBUTE STRING optlist dependon { struct redistribute *r; if ((r = calloc(1, sizeof(*r))) == NULL) @@ -282,10 +283,15 @@ redistribute : no REDISTRIBUTE STRING optlist { if ($1) r->type |= REDIST_NO; r->metric = $4; + if ($5) + strlcpy(r->dependon, $5, sizeof(r->dependon)); + else + r->dependon[0] = '\0'; free($3); + free($5); $$ = r; } - | no REDISTRIBUTE RTLABEL STRING optlist { + | no REDISTRIBUTE RTLABEL STRING optlist dependon { struct redistribute *r; if ((r = calloc(1, sizeof(*r))) == NULL) @@ -295,7 +301,12 @@ redistribute : no REDISTRIBUTE STRING optlist { if ($1) r->type |= REDIST_NO; r->metric = $5; + if ($6) + strlcpy(r->dependon, $6, sizeof(r->dependon)); + else + r->dependon[0] = '\0'; free($4); + free($6); $$ = r; } ; @@ -349,6 +360,22 @@ option : METRIC NUMBER { } ; +dependon : /* empty */ { $$ = NULL; } + | DEPEND ON STRING { + if (strlen($3) >= IFNAMSIZ) { + yyerror("interface name %s too long", $3); + free($3); + YYERROR; + } + if ((if_findname($3)) == NULL) { + yyerror("unknown interface %s", $3); + free($3); + YYERROR; + } + $$ = $3; + } + ; + defaults : METRIC NUMBER { if ($2 < MIN_METRIC || $2 > MAX_METRIC) { yyerror("metric out of range (%d-%d)", @@ -524,6 +551,19 @@ interfaceoptsl : PASSIVE { iface->cflags |= F_IFACE_PASSIVE; } YYERROR; } } + | dependon { + struct iface *depend_if = NULL; + + if ($1) { + strlcpy(iface->dependon, $1, + sizeof(iface->dependon)); + depend_if = if_findname($1); + iface->depend_ok = ifstate_is_up(depend_if); + } else { + iface->dependon[0] = '\0'; + iface->depend_ok = 1; + } + } | defaults ; @@ -563,6 +603,7 @@ lookup(char *s) static const struct keywords keywords[] = { {"area", AREA}, {"demote", DEMOTE}, + {"depend", DEPEND}, {"external-tag", EXTTAG}, {"fib-update", FIBUPDATE}, {"hello-interval", HELLOINTERVAL}, @@ -570,6 +611,7 @@ lookup(char *s) {"interface", INTERFACE}, {"metric", METRIC}, {"no", NO}, + {"on", ON}, {"passive", PASSIVE}, {"redistribute", REDISTRIBUTE}, {"retransmit-interval", RETRANSMITINTERVAL}, diff --git a/usr.sbin/ospf6d/printconf.c b/usr.sbin/ospf6d/printconf.c index 17a0ac11dbc..a8e77ac962d 100644 --- a/usr.sbin/ospf6d/printconf.c +++ b/usr.sbin/ospf6d/printconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: printconf.c,v 1.5 2016/12/24 14:58:55 jca Exp $ */ +/* $OpenBSD: printconf.c,v 1.6 2018/07/12 12:19:05 remi Exp $ */ /* * Copyright (c) 2004, 2005 Esben Norby @@ -90,9 +90,12 @@ print_redistribute(struct ospfd_conf *conf) printf("%sredistribute default ", print_no(r->type)); break; } - printf("set { metric %d type %d }\n", + printf("set { metric %d type %d }", (r->metric & LSA_METRIC_MASK), ((r->metric & LSA_ASEXT_E_FLAG) == 0 ? 1 : 2)); + if (r->dependon[0]) + printf(" depend on %s", r->dependon); + printf("\n"); } } @@ -119,6 +122,8 @@ print_iface(struct iface *iface) printf("\t\tpassive\n"); if (*iface->demote_group) printf("\t\tdemote %s\n", iface->demote_group); + if (iface->dependon[0] != '\0') + printf("\t\tdepend on %s\n", iface->dependon); printf("\t\tretransmit-interval %d\n", iface->rxmt_interval); printf("\t\trouter-dead-time %d\n", iface->dead_interval); diff --git a/usr.sbin/ospf6d/rde.c b/usr.sbin/ospf6d/rde.c index 7e630e6ed4e..eaeccace4f0 100644 --- a/usr.sbin/ospf6d/rde.c +++ b/usr.sbin/ospf6d/rde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.77 2018/07/10 21:21:56 friehm Exp $ */ +/* $OpenBSD: rde.c,v 1.78 2018/07/12 12:19:05 remi Exp $ */ /* * Copyright (c) 2004, 2005 Claudio Jeker @@ -633,7 +633,7 @@ rde_dispatch_parent(int fd, short event, void *bula) { static struct area *narea; struct area *area; - struct iface *iface, *ifp; + struct iface *iface, *ifp, *i; struct ifaddrchange *ifc; struct iface_addr *ia, *nia; struct imsg imsg; @@ -643,7 +643,7 @@ rde_dispatch_parent(int fd, short event, void *bula) struct lsa *lsa; struct vertex *v; ssize_t n; - int shut = 0, link_ok, prev_link_ok; + int shut = 0, link_ok, prev_link_ok, orig_lsa; unsigned int ifindex; if (event & EV_READ) { @@ -709,6 +709,24 @@ rde_dispatch_parent(int fd, short event, void *bula) fatalx("IFINFO imsg with wrong len"); ifp = imsg.data; + + LIST_FOREACH(area, &rdeconf->area_list, entry) { + orig_lsa = 0; + LIST_FOREACH(i, &area->iface_list, entry) { + if (strcmp(i->dependon, + ifp->name) == 0) { + i->depend_ok = + ifstate_is_up(ifp); + if (ifstate_is_up(i)) + orig_lsa = 1; + } + } + if (orig_lsa) + orig_intra_area_prefix_lsas(area); + } + + if (!(ifp->cflags & F_IFACE_CONFIGURED)) + break; iface = if_find(ifp->ifindex); if (iface == NULL) fatalx("interface lost in rde"); @@ -1532,8 +1550,9 @@ orig_intra_lsa_rtr(struct area *area, struct vertex *old) iface->state & IF_STA_LOOPBACK) { lsa_prefix->prefixlen = 128; lsa_prefix->metric = 0; - } else if (iface->if_type == IFT_CARP && - iface->linkstate == LINK_STATE_DOWN) { + } else if ((iface->if_type == IFT_CARP && + iface->linkstate == LINK_STATE_DOWN) || + !(iface->depend_ok)) { /* carp interfaces in state backup are * announced with high metric for faster * failover. */ -- 2.20.1