Hi,
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.
This is similar to what we have for ospfd.
A configuration using this feature looks like this:
----
redistribute default depend on carp0
redistribute rtlabel toOSPF depend on carp0
area 0.0.0.0 {
interface vether0 {
depend on carp0
}
interface vether77 {
passive
depend on carp0
}
}
----
3 LSA types are affected by this:
- ext lsa (redistribute)
- router lsa (active interfaces)
- intra area lsa (passive interfaces)
Comments, OKs?
Remi
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 10 Jul 2018 12:38:26 -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.51
diff -u -p -r1.51 ospfe.c
--- ospfe.c 12 Aug 2017 16:27:50 -0000 1.51
+++ ospfe.c 10 Jul 2018 12:46:37 -0000
@@ -260,7 +260,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;
@@ -295,9 +295,25 @@ 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);
+ }
+ }
+ }
+
iface = if_find(ifp->ifindex);
if (iface == NULL)
- fatalx("interface lost in ospfe");
+ break;
wasvalid = (iface->flags & IFF_UP) &&
LINK_STATE_IS_UP(iface->linkstate);
@@ -834,7 +850,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;
@@ -859,7 +879,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;
@@ -919,7 +944,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.34
diff -u -p -r1.34 parse.y
--- parse.y 9 Jul 2018 12:05:11 -0000 1.34
+++ parse.y 10 Jul 2018 10:32:24 -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.76
diff -u -p -r1.76 rde.c
--- rde.c 12 Jun 2018 20:12:36 -0000 1.76
+++ rde.c 10 Jul 2018 09:52:42 -0000
@@ -630,7 +630,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;
@@ -640,7 +640,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) {
@@ -706,6 +706,25 @@ 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");
@@ -1529,8 +1548,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. */