]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Implement onlink flag for nexthops
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Tue, 4 Jul 2017 21:36:21 +0000 (23:36 +0200)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Tue, 4 Jul 2017 21:36:21 +0000 (23:36 +0200)
Add proper support for per-nexthop onlink flag in routes to handle next
hop addresses that are not covered by interface IP ranges. Supported by
kernel and static protocols.

Thanks to Vincent Bernat for the idea.

nest/route.h
nest/rt-attr.c
nest/rt-show.c
nest/rt-table.c
proto/static/config.Y
proto/static/static.c
proto/static/static.h
sysdep/linux/netlink.c

index 6c9b00c2317882d5f26030bd15c3ec22e8841196..c1a60ccc62e990f9bbe79ae1ed9527ab5a6ef2b7 100644 (file)
@@ -366,12 +366,16 @@ struct nexthop {
   ip_addr gw;                          /* Next hop */
   struct iface *iface;                 /* Outgoing interface */
   struct nexthop *next;
+  byte flags;
   byte weight;
   byte labels_orig;                    /* Number of labels before hostentry was applied */
   byte labels;                         /* Number of all labels */
   u32 label[0];
 };
 
+#define RNF_ONLINK             0x1     /* Gateway is onlink regardless of IP ranges */
+
+
 struct rte_src {
   struct rte_src *next;                        /* Hash chain */
   struct proto *proto;                 /* Protocol the source is based on */
index 1b7f5836c2261aa3e1dc33c2938f2f364b4ba9d1..761ba9fe8faaa6656323cb50a990c2a9564e72cb 100644 (file)
@@ -171,7 +171,9 @@ nexthop__same(struct nexthop *x, struct nexthop *y)
 {
   for (; x && y; x = x->next, y = y->next)
   {
-    if (!ipa_equal(x->gw, y->gw) || (x->iface != y->iface) || (x->weight != y->weight) || (x->labels != y->labels))
+    if (!ipa_equal(x->gw, y->gw) || (x->iface != y->iface) ||
+       (x->flags != y->flags) || (x->weight != y->weight) ||
+       (x->labels != y->labels))
       return 0;
 
     for (int i = 0; i < x->labels; i++)
@@ -193,6 +195,8 @@ nexthop_compare_node(struct nexthop *x, struct nexthop *y)
   if (!y)
     return -1;
 
+  /* Should we also compare flags ? */
+
   r = ((int) y->weight) - ((int) x->weight);
   if (r)
     return r;
index 3f5ef04d15f112a0df1439d8a46fc9bdb727fc99..afde2810f57b16dfb7a6f63936c5db4f819adc86 100644 (file)
@@ -70,6 +70,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
     for (nh = &(a->nh); nh; nh = nh->next)
     {
       char mpls[MPLS_MAX_LABEL_STACK*12 + 5], *lsp = mpls;
+      char *onlink = (nh->flags & RNF_ONLINK) ? " onlink" : "";
 
       if (nh->labels)
         {
@@ -80,9 +81,11 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
       *lsp = '\0';
 
       if (a->nh.next)
-       cli_printf(c, -1007, "\tvia %I%s on %s weight %d", nh->gw, mpls, nh->iface->name, nh->weight + 1);
+       cli_printf(c, -1007, "\tvia %I%s on %s%s weight %d",
+                  nh->gw, mpls, nh->iface->name, onlink, nh->weight + 1);
       else
-       cli_printf(c, -1007, "\tvia %I%s on %s", nh->gw, mpls, nh->iface->name);
+       cli_printf(c, -1007, "\tvia %I%s on %s%s",
+                  nh->gw, mpls, nh->iface->name, onlink);
     }
 
   if (d->verbose)
index 85a951b866bf88ecf91ee54be8c513870db30162..2bb78cf2d6a24e6fc61dece1af367efe90b833b8 100644 (file)
@@ -1819,7 +1819,10 @@ no_nexthop:
       }
     }
     if (ipa_nonzero(nh->gw))
-      nhp->gw = nh->gw;                /* Router nexthop */
+    {
+      nhp->gw = nh->gw;                        /* Router nexthop */
+      nhp->flags |= (nh->flags & RNF_ONLINK);
+    }
     else if (ipa_nonzero(he->link))
       nhp->gw = he->link;              /* Device nexthop with link-local address known */
     else
index 66ae3c980e3808fd23f48323e97f7cda48ef55d3..66e5ea4c2d4a639def71cbbfbdbcf3ddcdc98bf3 100644 (file)
@@ -44,7 +44,7 @@ static_route_finish(void)
 CF_DECLS
 
 CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE, CHECK, LINK)
-CF_KEYWORDS(WEIGHT, RECURSIVE, IGP, TABLE, BLACKHOLE, UNREACHABLE, BFD, MPLS)
+CF_KEYWORDS(ONLINK, WEIGHT, RECURSIVE, IGP, TABLE, BLACKHOLE, UNREACHABLE, BFD, MPLS)
 
 
 CF_GRAMMAR
@@ -87,6 +87,9 @@ stat_nexthop:
   | stat_nexthop MPLS label_stack {
     this_snh->mls = $3;
   }
+  | stat_nexthop ONLINK bool {
+    this_snh->onlink = $3;
+  }
   | stat_nexthop WEIGHT expr {
     this_snh->weight = $3 - 1;
     if (($3<1) || ($3>256)) cf_error("Weight must be in range 1-256");
index bb1501a5bf27e4e8194c367a17e6fcbe671d9199..ede4c7345bcd0c8359494bf4dc38a7da3f7b32e6 100644 (file)
@@ -71,6 +71,7 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
       struct nexthop *nh = allocz(NEXTHOP_MAX_SIZE);
       nh->gw = r2->via;
       nh->iface = r2->neigh->iface;
+      nh->flags = r2->onlink ? RNF_ONLINK : 0;
       nh->weight = r2->weight;
       if (r2->mls)
       {
@@ -205,7 +206,8 @@ static_add_rte(struct static_proto *p, struct static_route *r)
     for (r2 = r; r2; r2 = r2->mp_next)
     {
       n = ipa_nonzero(r2->via) ?
-       neigh_find2(&p->p, &r2->via, r2->iface, NEF_STICKY) :
+       neigh_find2(&p->p, &r2->via, r2->iface,
+                   NEF_STICKY | (r2->onlink ? NEF_ONLINK : 0)) :
        neigh_find_iface(&p->p, r2->iface);
 
       if (!n)
@@ -267,8 +269,9 @@ static_same_dest(struct static_route *x, struct static_route *y)
     {
       if (!ipa_equal(x->via, y->via) ||
          (x->iface != y->iface) ||
-         (x->use_bfd != y->use_bfd) ||
+         (x->onlink != y->onlink) ||
          (x->weight != y->weight) ||
+         (x->use_bfd != y->use_bfd) ||
          (!x->mls != !y->mls) ||
          ((x->mls) && (y->mls) && (x->mls->len != y->mls->len)))
        return 0;
@@ -614,11 +617,13 @@ static_show_rt(struct static_route *r)
     for (r2 = r; r2; r2 = r2->mp_next)
     {
       if (r2->iface && ipa_zero(r2->via))
-       cli_msg(-1009, "\tdev %s%s%s", r2->iface->name,
-               r2->bfd_req ? " (bfd)" : "", r2->active ? "" : " (dormant)");
+       cli_msg(-1009, "\tdev %s%s", r2->iface->name,
+               r2->active ? "" : " (dormant)");
       else
-       cli_msg(-1009, "\tvia %I%J%s%s", r2->via, r2->iface,
-               r2->bfd_req ? " (bfd)" : "", r2->active ? "" : " (dormant)");
+       cli_msg(-1009, "\tvia %I%J%s%s%s", r2->via, r2->iface,
+               r2->onlink ? " onlink" : "",
+               r2->bfd_req ? " (bfd)" : "",
+               r2->active ? "" : " (dormant)");
     }
     break;
   }
index c84dfa98f34feed0abf94d9a0ddf0ffc20e77836..b202c0b1d336241e5ae85e453b3a56c860a70678 100644 (file)
@@ -43,6 +43,7 @@ struct static_route {
   byte dest;                           /* Destination type (RTD_*) */
   byte state;                          /* State of route announcement (SRS_*) */
   byte active;                         /* Next hop is active (nbr/iface/BFD available) */
+  byte onlink;                         /* Gateway is onlink regardless of IP ranges */
   byte weight;                         /* Multipath next hop weight */
   byte use_bfd;                                /* Configured to use BFD */
   struct bfd_request *bfd_req;         /* BFD request, if BFD is used */
index 40d1196ea835afd1cacd39ad51f5ed01720c14f6..2b7b13fb9aa6d7827f36cf2d6167118380315e34 100644 (file)
@@ -622,6 +622,9 @@ nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af)
 
     nl_add_nexthop(h, bufsize, nh, af);
 
+    if (nh->flags & RNF_ONLINK)
+      rtnh->rtnh_flags |= RTNH_F_ONLINK;
+
     nl_close_nexthop(h, rtnh);
   }
 
@@ -660,6 +663,7 @@ nl_parse_multipath(struct krt_proto *p, struct rtattr *ra)
       rv->next = NULL;
       last = &(rv->next);
 
+      rv->flags = 0;
       rv->weight = nh->rtnh_hops;
       rv->iface = if_find_by_index(nh->rtnh_ifindex);
       if (!rv->iface)
@@ -672,9 +676,12 @@ nl_parse_multipath(struct krt_proto *p, struct rtattr *ra)
        {
          rv->gw = rta_get_ipa(a[RTA_GATEWAY]);
 
+         if (nh->rtnh_flags & RTNH_F_ONLINK)
+           rv->flags |= RNF_ONLINK;
+
          neighbor *nbr;
          nbr = neigh_find2(&p->p, &rv->gw, rv->iface,
-                           (nh->rtnh_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0);
+                           (rv->flags & RNF_ONLINK) ? NEF_ONLINK : 0);
          if (!nbr || (nbr->scope == SCOPE_HOST))
            return NULL;
        }
@@ -1228,6 +1235,9 @@ dest:
       {
        nl_add_attr_u32(&r->h, rsize, RTA_OIF, nh->iface->index);
        nl_add_nexthop(&r->h, rsize, nh, p->af);
+
+       if (nh->flags & RNF_ONLINK)
+         r->r.rtm_flags |= RTNH_F_ONLINK;
       }
       break;
     case RTD_BLACKHOLE:
@@ -1543,9 +1553,12 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
          if ((i->rtm_family == AF_INET6) && ipa_in_netX(ra->nh.gw, (net_addr *) &sit))
            return;
 
+         if (i->rtm_flags & RTNH_F_ONLINK)
+           ra->nh.flags |= RNF_ONLINK;
+
          neighbor *nbr;
          nbr = neigh_find2(&p->p, &(ra->nh.gw), ra->nh.iface,
-                           (i->rtm_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0);
+                           (ra->nh.flags & RNF_ONLINK) ? NEF_ONLINK : 0);
          if (!nbr || (nbr->scope == SCOPE_HOST))
            {
              log(L_ERR "KRT: Received route %N with strange next-hop %I", net->n.addr,