]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Nexthop: Fixed hostentry
authorJan Moskyto Matejka <mq@ucw.cz>
Fri, 24 Feb 2017 13:05:11 +0000 (14:05 +0100)
committerJan Moskyto Matejka <mq@ucw.cz>
Fri, 24 Feb 2017 13:05:11 +0000 (14:05 +0100)
nest/route.h
nest/rt-attr.c
nest/rt-table.c
proto/bgp/packets.c
proto/static/static.c

index 928a022d03ed1261dfe689973dfb2a5369e584cc..98bef1fdd726d956397b59cb5c49140813f30f7f 100644 (file)
@@ -200,8 +200,8 @@ struct hostentry {
   unsigned hash_key;                   /* Hash key */
   unsigned uc;                         /* Use count */
   struct rta *src;                     /* Source rta entry */
-  struct nexthop *nh;                  /* Chosen next hop */
   byte dest;                           /* Chosen route destination type (RTD_...) */
+  byte nexthop_linkable;               /* Nexthop list is completely non-device */
   u32 igp_metric;                      /* Chosen route IGP metric */
 };
 
@@ -344,8 +344,8 @@ struct nexthop {
   struct iface *iface;                 /* Outgoing interface */
   struct nexthop *next;
   byte weight;
-  byte labels_append;                  /* Number of labels before hostentry was applied */
-  byte labels;                         /* Number of labels prepended */
+  byte labels_orig;                    /* Number of labels before hostentry was applied */
+  byte labels;                         /* Number of all labels */
   u32 label[0];
 };
 
index afc97e221db0001b4f49f2a59826ceee906a55b9..2c8ee7dbe8a8d69c660e773890f3609a57e9891a 100644 (file)
@@ -1155,12 +1155,12 @@ rta__free(rta *a)
   *a->pprev = a->next;
   if (a->next)
     a->next->pprev = a->pprev;
-  a->aflags = 0;               /* Poison the entry */
   rt_unlock_hostentry(a->hostentry);
   rt_unlock_source(a->src);
   if (a->nh.next)
     nexthop_free(a->nh.next);
   ea_free(a->eattrs);
+  a->aflags = 0;               /* Poison the entry */
   sl_free(rta_slab(a), a);
 }
 
index 1e1dde253621a0aaf1d0c2b870cb51ec34b87cc1..8765d293c3905fac4ea398f65a549faf4c31f4cc 100644 (file)
@@ -1764,7 +1764,7 @@ rta_next_hop_outdated(rta *a)
     return a->dest != RTD_UNREACHABLE;
 
   return (a->dest != he->dest) || (a->igp_metric != he->igp_metric) ||
-    !nexthop_same(&(a->nh), he->nh);
+    (!he->nexthop_linkable) || !nexthop_same(&(a->nh), &(he->src->nh));
 }
 
 static inline void
@@ -1774,39 +1774,49 @@ rta_apply_hostentry(rta *a, struct hostentry *he)
   a->dest = he->dest;
   a->igp_metric = he->igp_metric;
 
-  if (a->nh.labels_append == 0)
+  if ((a->nh.labels_orig == 0) && (!a->nh.next) && he->nexthop_linkable)
   {
-    a->nh = *(he->nh);
-    a->nh.labels_append = 0;
+    a->nh = he->src->nh;
     return;
   }
 
-  int labels_append = a->nh.labels_append;
-  u32 label_stack[MPLS_MAX_LABEL_STACK];
-  memcpy(label_stack, a->nh.label, labels_append * sizeof(u32));
-
-  struct nexthop *nhp = NULL;
-  for (struct nexthop *nh = he->nh; nh; nh = nh->next)
+  struct nexthop *nhp = alloca(NEXTHOP_MAX_SIZE);
+  
+  for (struct nexthop *nhe = &(a->nh); nhe; nhe = nhe->next)
   {
-    nhp = nhp ? (nhp->next = lp_alloc(rte_update_pool, NEXTHOP_MAX_SIZE)) : &(a->nh);
-    nhp->gw = ipa_nonzero(nh->gw) ? nh->gw : he->link;
-    nhp->iface = nh->iface; /* FIXME: This is at least strange, if not utter nonsense. */
-    nhp->weight = nh->weight;
-    nhp->labels = nh->labels + labels_append;
-    nhp->labels_append = labels_append;
-    if (nhp->labels <= MPLS_MAX_LABEL_STACK)
-    {
-      memcpy(nhp->label, nh->label, nh->labels * sizeof(u32));
-      memcpy(&(nhp->label[nh->labels]), label_stack, labels_append * sizeof(u32));
-    }
-    else
+    int labels_orig = nhe->labels_orig;            /* Number of labels (at the bottom of stack) */
+    u32 label_stack[MPLS_MAX_LABEL_STACK];
+    memcpy(label_stack, nhe->label, labels_orig * sizeof(u32));
+
+    for (struct nexthop *nh = &(he->src->nh); nh; nh = nh->next)
     {
-      log(L_WARN "Sum of label stack sizes %d + %d = %d exceedes allowed maximum (%d)",
-         nh->labels, labels_append, nhp->labels, MPLS_MAX_LABEL_STACK);
-      a->dest = RTD_UNREACHABLE;
-      break;
+      nhp->iface = nh->iface;
+      nhp->weight = nh->weight; /* FIXME: Ignoring the recursive nexthop's weight */
+      nhp->labels = nh->labels + labels_orig;
+      nhp->labels_orig = labels_orig;
+      if (nhp->labels <= MPLS_MAX_LABEL_STACK)
+      {
+       memcpy(nhp->label, nh->label, nh->labels * sizeof(u32)); /* First the hostentry labels */
+       memcpy(&(nhp->label[nh->labels]), label_stack, labels_orig * sizeof(u32)); /* Then the bottom labels */
+      }
+      else
+      {
+       log(L_WARN "Sum of label stack sizes %d + %d = %d exceedes allowed maximum (%d)",
+           nh->labels, labels_orig, nhp->labels, MPLS_MAX_LABEL_STACK);
+       continue;
+      }
+      if (ipa_nonzero(nh->gw))
+       nhp->gw = nh->gw;               /* Router nexthop */
+      else if (ipa_nonzero(he->link))
+       nhp->gw = he->link;             /* Device nexthop with link-local address known */
+      else
+       nhp->gw = he->addr;             /* Device nexthop with link-local address unknown */
+
+      nhp = (nhp->next = lp_alloc(rte_update_pool, NEXTHOP_MAX_SIZE));
     }
   }
+
+  memcpy(&(a->nh), nhp, nexthop_size(nhp));
 }
 
 static inline rte *
@@ -2231,12 +2241,12 @@ hc_new_hostentry(struct hostcache *hc, ip_addr a, ip_addr ll, rtable *dep, unsig
 {
   struct hostentry *he = sl_alloc(hc->slab);
 
-  he->addr = a;
-  he->link = ll;
-  he->tab = dep;
-  he->hash_key = k;
-  he->uc = 0;
-  he->src = NULL;
+  *he = (struct hostentry) {
+    .addr = a,
+    .link = ll,
+    .tab = dep,
+    .hash_key = k,
+  };
 
   add_tail(&hc->hostentries, &he->ln);
   hc_insert(hc, he);
@@ -2357,6 +2367,7 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
 
   /* Reset the hostentry */
   he->src = NULL;
+  he->nexthop_linkable = 0;
   he->dest = RTD_UNREACHABLE;
   he->igp_metric = 0;
 
@@ -2377,28 +2388,14 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
          goto done;
        }
 
-      if ((a->dest == RTD_UNICAST) && ipa_zero(a->nh.gw) && !a->next)
-       {
-         /* We have singlepath device route */
-         if (if_local_addr(he->addr, a->nh.iface))
-           {
-             /* The host address is a local address, this is not valid */
-             log(L_WARN "Next hop address %I is a local address of iface %s",
-                 he->addr, a->nh.iface->name);
-             goto done;
-           }
-
-         /* The host is directly reachable, use link as a gateway */
-         he->nh = NULL;
-         he->dest = RTD_UNICAST;
-       }
-      else
-       {
-         /* The host is reachable through some route entry */
-         he->nh = &(a->nh);
-         he->dest = a->dest;
-       }
-
+      he->nexthop_linkable = 1;
+      for (struct nexthop *nh = &(a->nh); nh; nh = nh->next)
+       if (ipa_zero(nh->gw))
+         {
+           he->nexthop_linkable = 0;
+           break;
+         }
+  
       he->src = rta_clone(a);
       he->igp_metric = rt_get_igp_metric(e);
     }
index 2106e0d1d93202d0192d28a94f88bddb55d98d2d..bee9248a72cfa122ea7286cf579b89ca2fc5486f 100644 (file)
@@ -1705,7 +1705,7 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis
 
   if (ea)
   {
-    a = allocz(sizeof(struct rta));
+    a = allocz(RTA_MAX_SIZE);
 
     a->source = RTS_BGP;
     a->scope = SCOPE_UNIVERSE;
index e5251bf6ca46680b9ec096864741d69dad3c1be0..63ee2518cfb77da2aa4cca927f8c23ad417e2ab9 100644 (file)
@@ -120,7 +120,7 @@ drop:
 
   if (r->dest == RTDX_RECURSIVE)
     {
-      ap->nh.labels_append = ap->nh.labels = r->label_count;
+      ap->nh.labels_orig = ap->nh.labels = r->label_count;
       memcpy(ap->nh.label, r->label_stack, r->label_count * sizeof(u32));
       rta_set_recursive_next_hop(p->main_channel->table, ap, p_igp_table(p), r->via, IPA_NONE);
     }