Remi Locherer(remi.loche...@relo.ch) on 2018.02.04 00:42:22 +0100:
> 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?

fwiw ok benno@

> 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;
>                               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;
> 

Reply via email to