On Wed, Jul 11, 2018 at 02:59:30PM +0200, Florian Riehm wrote: > Hi, > > successfully tested. I like the feature! Thanks!
> Some (mostly cosmetic) comments inline. I fixed them. Updated diff below. > Index: ospfe.c > =================================================================== > RCS file: /cvs/src/usr.sbin/ospf6d/ospfe.c,v > retrieving revision 1.51 > diff -u -p -r1.51 ospfe.c > --- ospfe.c 12 Aug 2017 16:27:50 -0000 1.51 > +++ ospfe.c 11 Jul 2018 11:29:44 -0000 > @@ -295,9 +295,27 @@ ospfe_dispatch_main(int fd, short event, > 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"); > + break; > You added the F_IFACE_CONFIGURED check in your second version of the diff, > because I found a bug. Is it still necessary to remove fatalx("interface lost > in > ospfe") ? No it is not necessary anymore. I added the fatalx back. OK? Index: kroute.c =================================================================== RCS file: /cvs/src/usr.sbin/ospf6d/kroute.c,v retrieving revision 1.56 diff -u -p -r1.56 kroute.c --- kroute.c 10 Jul 2018 12:17:38 -0000 1.56 +++ kroute.c 11 Jul 2018 13:23:28 -0000 @@ -810,13 +810,9 @@ if_change(u_short ifindex, int flags, st 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); Index: ospf6d.c =================================================================== RCS file: /cvs/src/usr.sbin/ospf6d/ospf6d.c,v retrieving revision 1.36 diff -u -p -r1.36 ospf6d.c --- ospf6d.c 9 Jul 2018 13:19:46 -0000 1.36 +++ ospf6d.c 9 Jul 2018 14:22:32 -0000 @@ -29,6 +29,7 @@ #include <netinet/in.h> #include <arpa/inet.h> +#include <net/if_types.h> #include <event.h> #include <err.h> @@ -485,17 +486,27 @@ ospf_redistribute(struct kroute *kr, u_i { 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_i 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_i 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_i 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_i 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; @@ -773,4 +785,15 @@ iface_lookup(struct area *area, struct i if (i->ifindex == iface->ifindex) 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); } Index: ospf6d.conf.5 =================================================================== RCS file: /cvs/src/usr.sbin/ospf6d/ospf6d.conf.5,v retrieving revision 1.14 diff -u -p -r1.14 ospf6d.conf.5 --- ospf6d.conf.5 18 Jun 2018 06:04:25 -0000 1.14 +++ ospf6d.conf.5 9 Jul 2018 17:18:40 -0000 @@ -109,14 +109,18 @@ option to ensure that no traffic tries t .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 ad .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 inter 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. Index: ospf6d.h =================================================================== RCS file: /cvs/src/usr.sbin/ospf6d/ospf6d.h,v retrieving revision 1.35 diff -u -p -r1.35 ospf6d.h --- ospf6d.h 8 Feb 2018 00:18:20 -0000 1.35 +++ ospf6d.h 10 Jul 2018 11:12:44 -0000 @@ -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 *, s 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 *); Index: ospfe.c =================================================================== RCS file: /cvs/src/usr.sbin/ospf6d/ospfe.c,v retrieving revision 1.52 diff -u -p -r1.52 ospfe.c --- ospfe.c 10 Jul 2018 21:21:56 -0000 1.52 +++ ospfe.c 11 Jul 2018 15:54:33 -0000 @@ -263,7 +263,7 @@ ospfe_dispatch_main(int fd, short event, { 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, 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); Index: parse.y =================================================================== RCS file: /cvs/src/usr.sbin/ospf6d/parse.y,v retrieving revision 1.36 diff -u -p -r1.36 parse.y --- parse.y 11 Jul 2018 10:23:47 -0000 1.36 +++ parse.y 11 Jul 2018 15:05:53 -0000 @@ -131,10 +131,11 @@ typedef struct { %token DEMOTE %token INCLUDE %token ERROR +%token DEPEND ON %token <v.string> STRING %token <v.number> NUMBER %type <v.number> yesno no optlist, optlist_l option demotecount -%type <v.string> string +%type <v.string> string dependon %type <v.redist> 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 op 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 op 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->cflag 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}, Index: printconf.c =================================================================== RCS file: /cvs/src/usr.sbin/ospf6d/printconf.c,v retrieving revision 1.5 diff -u -p -r1.5 printconf.c --- printconf.c 24 Dec 2016 14:58:55 -0000 1.5 +++ printconf.c 9 Jul 2018 13:23:06 -0000 @@ -90,9 +90,12 @@ print_redistribute(struct ospfd_conf *co 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); Index: rde.c =================================================================== RCS file: /cvs/src/usr.sbin/ospf6d/rde.c,v retrieving revision 1.77 diff -u -p -r1.77 rde.c --- rde.c 10 Jul 2018 21:21:56 -0000 1.77 +++ rde.c 11 Jul 2018 15:52:52 -0000 @@ -633,7 +633,7 @@ rde_dispatch_parent(int fd, short event, { 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, 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, 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, st 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. */