From ac149fe2d4b0b348de756f506aa184faf55d228a Mon Sep 17 00:00:00 2001 From: remi Date: Mon, 5 Feb 2018 12:11:28 +0000 Subject: [PATCH] Introduce "depend on". This allows ospfd to set the metric dependent on the status of another interface. in collaboration with benno@ jca@ OK benno@ jca@ --- usr.sbin/ospfd/ospfd.c | 45 ++++++++++++++++---- usr.sbin/ospfd/ospfd.conf.5 | 24 +++++++++-- usr.sbin/ospfd/ospfd.h | 7 +++- usr.sbin/ospfd/ospfe.c | 36 ++++++++++++---- usr.sbin/ospfd/parse.y | 82 +++++++++++++++++++++++++++++++++---- usr.sbin/ospfd/printconf.c | 11 +++-- usr.sbin/ospfd/rde.c | 8 +--- 7 files changed, 176 insertions(+), 37 deletions(-) diff --git a/usr.sbin/ospfd/ospfd.c b/usr.sbin/ospfd/ospfd.c index 6e907d4b328..381b35fc600 100644 --- a/usr.sbin/ospfd/ospfd.c +++ b/usr.sbin/ospfd/ospfd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ospfd.c,v 1.94 2017/01/24 04:24:25 benno Exp $ */ +/* $OpenBSD: ospfd.c,v 1.95 2018/02/05 12:11:28 remi Exp $ */ /* * Copyright (c) 2005 Claudio Jeker @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -512,18 +513,30 @@ imsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, int ospf_redistribute(struct kroute *kr, u_int32_t *metric) { + struct in_addr addr; + struct kif *kif; struct redistribute *r; - u_int8_t is_default = 0; + int is_default = 0, depend_ok = 1; + + bzero(&addr, sizeof(addr)); /* only allow 0.0.0.0/0 via REDIST_DEFAULT */ if (kr->prefix.s_addr == INADDR_ANY && kr->prefixlen == 0) is_default = 1; SIMPLEQ_FOREACH(r, &ospfd_conf->redist_list, entry) { + if (r->dependon[0] != '\0') { + if ((kif = kif_findname(r->dependon, addr, NULL))) + depend_ok = ifstate_is_up(kif); + 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; @@ -538,7 +551,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; @@ -548,7 +561,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; @@ -559,7 +572,8 @@ ospf_redistribute(struct kroute *kr, u_int32_t *metric) if (r->addr.s_addr == INADDR_ANY && r->mask.s_addr == INADDR_ANY) { if (is_default) { - *metric = r->metric; + *metric = depend_ok ? r->metric : + MAX_METRIC; return (r->type & REDIST_NO ? 0 : 1); } else return (0); @@ -568,13 +582,13 @@ ospf_redistribute(struct kroute *kr, u_int32_t *metric) if ((kr->prefix.s_addr & r->mask.s_addr) == (r->addr.s_addr & r->mask.s_addr) && kr->prefixlen >= mask2prefixlen(r->mask.s_addr)) { - *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; @@ -841,6 +855,10 @@ merge_interfaces(struct area *a, struct area *xa) if (ospfd_process == PROC_OSPF_ENGINE) if_fsm(i, IF_EVT_UP); } + + strlcpy(i->dependon, xi->dependon, + sizeof(i->dependon)); + i->depend_ok = xi->depend_ok; } return (dirty); } @@ -857,3 +875,14 @@ iface_lookup(struct area *area, struct iface *iface) return (i); return (NULL); } + +int +ifstate_is_up(struct kif *kif) +{ + if (!(kif->flags & IFF_UP)) + return (0); + if (kif->if_type == IFT_CARP && + kif->link_state == LINK_STATE_UNKNOWN) + return (0); + return LINK_STATE_IS_UP(kif->link_state); +} diff --git a/usr.sbin/ospfd/ospfd.conf.5 b/usr.sbin/ospfd/ospfd.conf.5 index 0564ccdbbf9..ec5f1984a69 100644 --- a/usr.sbin/ospfd/ospfd.conf.5 +++ b/usr.sbin/ospfd/ospfd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ospfd.conf.5,v 1.49 2017/11/07 06:32:02 remi Exp $ +.\" $OpenBSD: ospfd.conf.5,v 1.50 2018/02/05 12:11:28 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: November 7 2017 $ +.Dd $Mdocdate: February 5 2018 $ .Dt OSPFD.CONF 5 .Os .Sh NAME @@ -115,14 +115,19 @@ Table 0 is the default table. .Ic default Pc .Sm on .Op Ic set ... +.Op Ic depend on Ar interface .Xc .It Xo .Op Ic no -.Ic redistribute Ar prefix Op Ic set ... +.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 ... +.Ic redistribute rtlabel Ar label +.Op Ic set ... +.Op Ic depend on Ar interface .Xc If set to .Ic connected , @@ -154,6 +159,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 @@ -344,6 +357,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 Ic on Ar interface +A metric of 65535 is used if the specified interface is down or in status +backup. .It Ic fast-hello-interval Ic msec Ar milliseconds If the interface is configured to use .Ic router-dead-time minimal , diff --git a/usr.sbin/ospfd/ospfd.h b/usr.sbin/ospfd/ospfd.h index bbf3ce01197..ba3ffbc56cb 100644 --- a/usr.sbin/ospfd/ospfd.h +++ b/usr.sbin/ospfd/ospfd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ospfd.h,v 1.97 2017/01/24 04:24:25 benno Exp $ */ +/* $OpenBSD: ospfd.h,v 1.98 2018/02/05 12:11:28 remi Exp $ */ /* * Copyright (c) 2004 Esben Norby @@ -149,6 +149,7 @@ struct redistribute { u_int32_t metric; u_int16_t label; u_int16_t type; + char dependon[IFNAMSIZ]; }; SIMPLEQ_HEAD(redist_list, redistribute); @@ -325,6 +326,7 @@ struct iface { char name[IF_NAMESIZE]; char demote_group[IFNAMSIZ]; + char dependon[IFNAMSIZ]; char auth_key[MAX_SIMPLE_AUTH_LEN]; struct in_addr addr; struct in_addr dst; @@ -346,6 +348,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; @@ -553,6 +556,7 @@ int carp_demote_set(char *, int); /* parse.y */ struct ospfd_conf *parse_config(char *, int); int cmdline_symset(char *); +void conf_clear_redist_list(struct redist_list *); /* in_cksum.c */ u_int16_t in_cksum(void *, size_t); @@ -603,6 +607,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 kif *kif); /* printconf.c */ void print_config(struct ospfd_conf *); diff --git a/usr.sbin/ospfd/ospfe.c b/usr.sbin/ospfd/ospfe.c index 86f7e796c40..693e3a6d5a9 100644 --- a/usr.sbin/ospfd/ospfe.c +++ b/usr.sbin/ospfd/ospfe.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ospfe.c,v 1.99 2017/01/24 04:24:25 benno Exp $ */ +/* $OpenBSD: ospfe.c,v 1.100 2018/02/05 12:11:28 remi Exp $ */ /* * Copyright (c) 2005 Claudio Jeker @@ -181,10 +181,7 @@ ospfe(struct ospfd_conf *xconf, int pipe_parent2ospfe[2], int pipe_ospfe2rde[2], event_add(&oeconf->ev, NULL); /* remove unneeded config stuff */ - while ((r = SIMPLEQ_FIRST(&oeconf->redist_list)) != NULL) { - SIMPLEQ_REMOVE_HEAD(&oeconf->redist_list, entry); - free(r); - } + conf_clear_redist_list(&oeconf->redist_list); LIST_FOREACH(area, &oeconf->area_list, entry) { while ((r = SIMPLEQ_FIRST(&area->redist_list)) != NULL) { SIMPLEQ_REMOVE_HEAD(&area->redist_list, entry); @@ -346,6 +343,21 @@ ospfe_dispatch_main(int fd, short event, void *bula) iface->name); } } + if (strcmp(kif->ifname, + iface->dependon) == 0) { + log_warnx("interface %s" + " changed state, %s" + " depends on it", + kif->ifname, + iface->name); + iface->depend_ok = + ifstate_is_up(kif); + + if ((iface->flags & + IFF_UP) && + LINK_STATE_IS_UP(iface->linkstate)) + orig_rtr_lsa(iface->area); + } } } break; @@ -847,6 +859,9 @@ orig_rtr_lsa(struct area *area) if (oeconf->flags & OSPFD_FLAG_STUB_ROUTER || oe_nofib) rtr_link.metric = MAX_METRIC; + else if (iface->dependon[0] != '\0' && + iface->depend_ok == 0) + rtr_link.metric = MAX_METRIC; else rtr_link.metric = htons(iface->metric); num_links++; @@ -916,12 +931,16 @@ orig_rtr_lsa(struct area *area) rtr_link.num_tos = 0; /* - * backup carp interfaces are anounced with high metric - * for faster failover. + * backup carp interfaces and interfaces that depend + * on an interface that is down are announced with + * high metric for faster failover. */ if (iface->if_type == IFT_CARP && iface->linkstate == LINK_STATE_DOWN) rtr_link.metric = MAX_METRIC; + else if (iface->dependon[0] != '\0' && + iface->depend_ok == 0) + rtr_link.metric = MAX_METRIC; else rtr_link.metric = htons(iface->metric); num_links++; @@ -978,6 +997,9 @@ orig_rtr_lsa(struct area *area) if (oe_nofib || oeconf->flags & OSPFD_FLAG_STUB_ROUTER) rtr_link.metric = MAX_METRIC; + else if (iface->dependon[0] != '\0' && + iface->depend_ok == 0) + rtr_link.metric = MAX_METRIC; else rtr_link.metric = htons(iface->metric); diff --git a/usr.sbin/ospfd/parse.y b/usr.sbin/ospfd/parse.y index 78d5e969f50..03d9ca912ab 100644 --- a/usr.sbin/ospfd/parse.y +++ b/usr.sbin/ospfd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.83 2017/01/05 13:53:09 krw Exp $ */ +/* $OpenBSD: parse.y,v 1.84 2018/02/05 12:11:28 remi Exp $ */ /* * Copyright (c) 2004, 2005 Esben Norby @@ -132,11 +132,12 @@ typedef struct { %token DEMOTE %token INCLUDE %token ERROR +%token DEPEND ON %token STRING %token NUMBER %type yesno no optlist optlist_l option demotecount msec %type deadtime -%type string +%type string dependon %type redistribute %% @@ -278,7 +279,7 @@ conf_main : ROUTERID STRING { ; -redistribute : no REDISTRIBUTE NUMBER '/' NUMBER optlist { +redistribute : no REDISTRIBUTE NUMBER '/' NUMBER optlist dependon { struct redistribute *r; if ((r = calloc(1, sizeof(*r))) == NULL) @@ -295,9 +296,14 @@ redistribute : no REDISTRIBUTE NUMBER '/' NUMBER optlist { if ($1) r->type |= REDIST_NO; r->metric = $6; + if ($7) { + strlcpy(r->dependon, $7, sizeof(r->dependon)); + } else + r->dependon[0] = '\0'; + free($7); $$ = r; } - | no REDISTRIBUTE STRING optlist { + | no REDISTRIBUTE STRING optlist dependon { struct redistribute *r; if ((r = calloc(1, sizeof(*r))) == NULL) @@ -320,10 +326,15 @@ redistribute : no REDISTRIBUTE NUMBER '/' NUMBER 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) @@ -333,19 +344,23 @@ redistribute : no REDISTRIBUTE NUMBER '/' NUMBER 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; } ; optlist : /* empty */ { $$ = DEFAULT_REDIST_METRIC; } - | SET option { + | SET option { $$ = $2; if (($$ & LSA_METRIC_MASK) == 0) $$ |= DEFAULT_REDIST_METRIC; } - | SET optnl '{' optnl optlist_l optnl '}' { + | SET optnl '{' optnl optlist_l optnl '}' { $$ = $5; if (($$ & LSA_METRIC_MASK) == 0) $$ |= DEFAULT_REDIST_METRIC; @@ -388,6 +403,26 @@ option : METRIC NUMBER { } ; +dependon : /* empty */ { $$ = NULL; } + | DEPEND ON STRING { + struct in_addr addr; + struct kif *kif; + + if (strlen($3) >= IFNAMSIZ) { + yyerror("interface name %s too long", $3); + free($3); + YYERROR; + } + bzero(&addr, sizeof(addr)); + if ((kif = kif_findname($3, addr, NULL)) == NULL) { + yyerror("unknown interface %s", $3); + free($3); + YYERROR; + } + $$ = $3; + } + ; + authmd : AUTHMD NUMBER STRING { if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) { yyerror("auth-md key-id out of range " @@ -693,6 +728,23 @@ interfaceoptsl : PASSIVE { iface->passive = 1; } YYERROR; } } + | dependon { + struct in_addr addr; + struct kif *kif; + + if ($1) { + strlcpy(iface->dependon, $1, + sizeof(iface->dependon)); + bzero(&addr, sizeof(addr)); + kif = kif_findname($1, addr, NULL); + iface->depend_ok = ifstate_is_up(kif); + } else { + iface->dependon[0] = '\0'; + iface->depend_ok = 1; + } + + free($1); + } | defaults ; @@ -736,6 +788,7 @@ lookup(char *s) {"auth-md-keyid", AUTHMDKEYID}, {"auth-type", AUTHTYPE}, {"demote", DEMOTE}, + {"depend", DEPEND}, {"external-tag", EXTTAG}, {"fast-hello-interval", FASTHELLOINTERVAL}, {"fib-update", FIBUPDATE}, @@ -746,6 +799,7 @@ lookup(char *s) {"minimal", MINIMAL}, {"msec", MSEC}, {"no", NO}, + {"on", ON}, {"passive", PASSIVE}, {"rdomain", RDOMAIN}, {"redistribute", REDISTRIBUTE}, @@ -1287,6 +1341,16 @@ conf_check_rdomain(unsigned int rdomain) return (errs); } +void +conf_clear_redist_list(struct redist_list *rl) +{ + struct redistribute *r; + while ((r = SIMPLEQ_FIRST(rl)) != NULL) { + SIMPLEQ_REMOVE_HEAD(rl, entry); + free(r); + } +} + void clear_config(struct ospfd_conf *xconf) { @@ -1297,6 +1361,8 @@ clear_config(struct ospfd_conf *xconf) area_del(a); } + conf_clear_redist_list(&xconf->redist_list); + free(xconf); } diff --git a/usr.sbin/ospfd/printconf.c b/usr.sbin/ospfd/printconf.c index fa5536c1f99..5fd501b07f8 100644 --- a/usr.sbin/ospfd/printconf.c +++ b/usr.sbin/ospfd/printconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: printconf.c,v 1.17 2016/11/19 12:46:46 sthen Exp $ */ +/* $OpenBSD: printconf.c,v 1.18 2018/02/05 12:11:28 remi Exp $ */ /* * Copyright (c) 2004, 2005 Esben Norby @@ -94,9 +94,12 @@ print_redistribute(struct redist_list *rlh) 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"); } } @@ -120,8 +123,10 @@ print_iface(struct iface *iface) printf("\t\tmetric %d\n", iface->metric); - if (*iface->demote_group) + if (iface->demote_group[0] != '\0') printf("\t\tdemote %s\n", iface->demote_group); + if (iface->dependon[0] != '\0') + printf("\t\tdepend on %s\n", iface->dependon); if (iface->passive) printf("\t\tpassive\n"); else { diff --git a/usr.sbin/ospfd/rde.c b/usr.sbin/ospfd/rde.c index 941a25d67f2..6ff3edc9183 100644 --- a/usr.sbin/ospfd/rde.c +++ b/usr.sbin/ospfd/rde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.108 2017/01/24 04:24:25 benno Exp $ */ +/* $OpenBSD: rde.c,v 1.109 2018/02/05 12:11:28 remi Exp $ */ /* * Copyright (c) 2004, 2005 Claudio Jeker @@ -98,7 +98,6 @@ rde(struct ospfd_conf *xconf, int pipe_parent2rde[2], int pipe_ospfe2rde[2], struct area *area; struct iface *iface; struct passwd *pw; - struct redistribute *r; pid_t pid; switch (pid = fork()) { @@ -188,10 +187,7 @@ rde(struct ospfd_conf *xconf, int pipe_parent2rde[2], int pipe_ospfe2rde[2], LIST_FOREACH(iface, &area->iface_list, entry) md_list_clr(&iface->auth_md_list); - while ((r = SIMPLEQ_FIRST(&rdeconf->redist_list)) != NULL) { - SIMPLEQ_REMOVE_HEAD(&rdeconf->redist_list, entry); - free(r); - } + conf_clear_redist_list(&rdeconf->redist_list); gettimeofday(&now, NULL); rdeconf->uptime = now.tv_sec; -- 2.20.1