With the "depend on" option routes are sent out with a metric of 65535 if
authorremi <remi@openbsd.org>
Thu, 12 Jul 2018 12:19:05 +0000 (12:19 +0000)
committerremi <remi@openbsd.org>
Thu, 12 Jul 2018 12:19:05 +0000 (12:19 +0000)
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
usr.sbin/ospf6d/ospf6d.c
usr.sbin/ospf6d/ospf6d.conf.5
usr.sbin/ospf6d/ospf6d.h
usr.sbin/ospf6d/ospfe.c
usr.sbin/ospf6d/parse.y
usr.sbin/ospf6d/printconf.c
usr.sbin/ospf6d/rde.c

index 5e485ff..7d798cd 100644 (file)
@@ -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 <norby@openbsd.org>
@@ -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);
index 0e40111..dcea8c7 100644 (file)
@@ -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 <claudio@openbsd.org>
@@ -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_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);
+}
index ddcb1be..ac0c51a 100644 (file)
@@ -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 <norby@openbsd.org>
 .\" Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -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.
index 0b6d883..38314e2 100644 (file)
@@ -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 <norby@openbsd.org>
@@ -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 *);
index 98e4240..7ce0392 100644 (file)
@@ -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 <claudio@openbsd.org>
@@ -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);
index ca95db4..75ffb78 100644 (file)
@@ -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 <norby@openbsd.org>
@@ -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 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},
index 17a0ac1..a8e77ac 100644 (file)
@@ -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 <norby@openbsd.org>
@@ -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);
index 7e630e6..eaeccac 100644 (file)
@@ -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 <claudio@openbsd.org>
@@ -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. */