Introduce "depend on". This allows ospfd to set the metric dependent
authorremi <remi@openbsd.org>
Mon, 5 Feb 2018 12:11:28 +0000 (12:11 +0000)
committerremi <remi@openbsd.org>
Mon, 5 Feb 2018 12:11:28 +0000 (12:11 +0000)
on the status of another interface.

in collaboration with benno@ jca@
OK benno@ jca@

usr.sbin/ospfd/ospfd.c
usr.sbin/ospfd/ospfd.conf.5
usr.sbin/ospfd/ospfd.h
usr.sbin/ospfd/ospfe.c
usr.sbin/ospfd/parse.y
usr.sbin/ospfd/printconf.c
usr.sbin/ospfd/rde.c

index 6e907d4..381b35f 100644 (file)
@@ -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 <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>
@@ -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);
+}
index 0564ccd..ec5f198 100644 (file)
@@ -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 <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: 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 ,
index bbf3ce0..ba3ffbc 100644 (file)
@@ -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 <norby@openbsd.org>
@@ -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 *);
index 86f7e79..693e3a6 100644 (file)
@@ -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 <claudio@openbsd.org>
@@ -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);
index 78d5e96..03d9ca9 100644 (file)
@@ -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 <norby@openbsd.org>
@@ -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 '/' 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);
 }
 
index fa5536c..5fd501b 100644 (file)
@@ -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 <norby@openbsd.org>
@@ -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 {
index 941a25d..6ff3edc 100644 (file)
@@ -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 <claudio@openbsd.org>
@@ -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;