On Sun, Feb 04, 2018 at 12:42:22AM +0100, Remi Locherer wrote: > Hi > > This adds a new feature to ospfd: depend on interface. > > A ospfd.conf using it looks like this: > > --%<-- > redistribute default depend on carp0 > area 0.0.0.0 { > interface em2 { depend on carp0 } > [...] > } > --%<-- > > This router would send out the default route and the em2 network with > default metrics as long as carp0 is master. When carp0 becomes backup these > routes are advertised with metric 65535. > > "depend on" can also be used with other interface types than carp. > > This diff was started by benno@ at p2k17 (redistribute and config parser). > I added the interface part. jca@ contributed several improvements. > > Comments, OKs? > > Remi > > > Index: ospfd.c > =================================================================== > RCS file: /cvs/src/usr.sbin/ospfd/ospfd.c,v > retrieving revision 1.94 > diff -u -p -r1.94 ospfd.c > --- ospfd.c 24 Jan 2017 04:24:25 -0000 1.94 > +++ ospfd.c 21 Jan 2018 14:01:42 -0000 > @@ -29,6 +29,7 @@ > > #include <netinet/in.h> > #include <arpa/inet.h> > +#include <net/if_types.h> > > #include <event.h> > #include <err.h> > @@ -512,18 +513,30 @@ imsg_compose_event(struct imsgev *iev, u > 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; ^ ^ Please remove the () around depend_ok here. The () are not needed. There is many more of these. > return (r->type & REDIST_NO ? 0 : 1); > } > break; > @@ -538,7 +551,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; > @@ -548,7 +561,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; > @@ -559,7 +572,8 @@ ospf_redistribute(struct kroute *kr, u_i > 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_i > 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 > 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); > } > @@ -856,4 +874,15 @@ iface_lookup(struct area *area, struct i > i->mask.s_addr == iface->mask.s_addr) > 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); > } > Index: ospfd.conf.5 > =================================================================== > RCS file: /cvs/src/usr.sbin/ospfd/ospfd.conf.5,v > retrieving revision 1.49 > diff -u -p -r1.49 ospfd.conf.5 > --- ospfd.conf.5 7 Nov 2017 06:32:02 -0000 1.49 > +++ ospfd.conf.5 21 Jan 2018 14:01:42 -0000 > @@ -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 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 > @@ -344,6 +357,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 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 , > Index: ospfd.h > =================================================================== > RCS file: /cvs/src/usr.sbin/ospfd/ospfd.h,v > retrieving revision 1.97 > diff -u -p -r1.97 ospfd.h > --- ospfd.h 24 Jan 2017 04:24:25 -0000 1.97 > +++ ospfd.h 21 Jan 2018 14:01:42 -0000 > @@ -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 *, 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 kif *kif); > > /* printconf.c */ > void print_config(struct ospfd_conf *); > Index: ospfe.c > =================================================================== > RCS file: /cvs/src/usr.sbin/ospfd/ospfe.c,v > retrieving revision 1.99 > diff -u -p -r1.99 ospfe.c > --- ospfe.c 24 Jan 2017 04:24:25 -0000 1.99 > +++ ospfe.c 21 Jan 2018 14:01:42 -0000 > @@ -181,10 +181,7 @@ ospfe(struct ospfd_conf *xconf, int pipe > 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, > 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++; > @@ -977,6 +996,9 @@ orig_rtr_lsa(struct area *area) > /* RFC 3137: stub router support */ > 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 = > Index: parse.y > =================================================================== > RCS file: /cvs/src/usr.sbin/ospfd/parse.y,v > retrieving revision 1.83 > diff -u -p -r1.83 parse.y > --- parse.y 5 Jan 2017 13:53:09 -0000 1.83 > +++ parse.y 21 Jan 2018 14:01:42 -0000 > @@ -132,11 +132,12 @@ 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 > msec > %type <v.number> deadtime > -%type <v.string> string > +%type <v.string> string dependon > %type <v.redist> 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 '/ > 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 '/ > 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 '/ > 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->passi > 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}, > @@ -1288,6 +1342,16 @@ conf_check_rdomain(unsigned int rdomain) > } > > 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) > { > struct area *a; > @@ -1296,6 +1360,8 @@ clear_config(struct ospfd_conf *xconf) > LIST_REMOVE(a, entry); > area_del(a); > } > + > + conf_clear_redist_list(&xconf->redist_list); > > free(xconf); > } > Index: printconf.c > =================================================================== > RCS file: /cvs/src/usr.sbin/ospfd/printconf.c,v > retrieving revision 1.17 > diff -u -p -r1.17 printconf.c > --- printconf.c 19 Nov 2016 12:46:46 -0000 1.17 > +++ printconf.c 21 Jan 2018 14:01:42 -0000 > @@ -94,9 +94,12 @@ print_redistribute(struct redist_list *r > 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 { > Index: rde.c > =================================================================== > RCS file: /cvs/src/usr.sbin/ospfd/rde.c,v > retrieving revision 1.108 > diff -u -p -r1.108 rde.c > --- rde.c 24 Jan 2017 04:24:25 -0000 1.108 > +++ rde.c 21 Jan 2018 14:01:42 -0000 > @@ -98,7 +98,6 @@ rde(struct ospfd_conf *xconf, int pipe_p > 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_p > 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; >
Looks good otherwise. -- :wq Claudio