]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Route destination field merged with nexthop attribute; splitting flowspec validation...
authorMaria Matejka <mq@ucw.cz>
Sun, 15 May 2022 16:09:30 +0000 (18:09 +0200)
committerMaria Matejka <mq@ucw.cz>
Mon, 30 May 2022 12:39:09 +0000 (14:39 +0200)
As there is either a nexthop or another destination specification
(or othing in case of ROAs and Flowspec), it may be merged together.
This code is somehow quirky and should be replaced in future by better
implementation of nexthop.

Also flowspec validation result has its own attribute now as it doesn't
have anything to do with route nexthop.

21 files changed:
filter/f-inst.c
lib/route.h
lib/type.h
nest/config.Y
nest/rt-attr.c
nest/rt-dev.c
nest/rt-show.c
nest/rt-table.c
nest/rt.h
proto/babel/babel.c
proto/bgp/attrs.c
proto/bgp/bgp.h
proto/bgp/packets.c
proto/ospf/rt.c
proto/ospf/topology.c
proto/perf/perf.c
proto/rip/rip.c
proto/rpki/rpki.c
proto/static/static.c
sysdep/linux/netlink.c
sysdep/unix/krt.c

index 8ce78a998e63f72d9d00ae4359bbfa1a8be64cd1..c2abd5aa4b68f30ffbe925c94bc395308756dae5 100644 (file)
       STATIC_ATTR;
       ACCESS_RTE;
       ACCESS_EATTRS;
-      struct rta *rta = (*fs->rte)->attrs;
 
       switch (sa.sa_code)
       {
       case SA_NET:     RESULT(sa.type, net, (*fs->rte)->net->n.addr); break;
       case SA_PROTO:   RESULT(sa.type, s, (*fs->rte)->src->proto->name); break;
-      case SA_DEST:    RESULT(sa.type, i, rta->dest); break;
       default:
        {
-         struct eattr *nh_ea = ea_find(*fs->eattrs, &ea_gen_nexthop);
-         struct nexthop *nh = nh_ea ? &((struct nexthop_adata *) nh_ea->u.ptr)->nh : NULL;
+         struct eattr *nhea = ea_find(*fs->eattrs, &ea_gen_nexthop);
+         struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
+         struct nexthop *nh = nhad ? &nhad->nh : NULL;
 
          switch (sa.sa_code)
          {
+           case SA_DEST:
+             RESULT(sa.type, i, nhad ?
+                 (NEXTHOP_IS_REACHABLE(nhad) ? RTD_UNICAST : nhad->dest)
+                 : RTD_NONE);
+             break;
            case SA_GW:
              RESULT(sa.type, ip, nh ? nh->gw : IPA_NONE);
              break;
 
     f_rta_cow(fs);
     {
-      struct rta *rta = (*fs->rte)->attrs;
+      union {
+       struct nexthop_adata nha;
+       struct {
+         struct adata ad;
+         struct nexthop nh;
+         u32 label;
+       };
+      } nha;
+
+      nha.ad = (struct adata) {
+       .length = sizeof (struct nexthop_adata) - sizeof (struct adata),
+      };
 
-      if (sa.sa_code == SA_DEST)
+      eattr *a = NULL;
+
+      switch (sa.sa_code)
+      {
+      case SA_DEST:
        {
          int i = v1.val.i;
          if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT))
            runtime( "Destination can be changed only to blackhole, unreachable or prohibit" );
 
-         rta->dest = i;
-         ea_unset_attr(fs->eattrs, 1, &ea_gen_nexthop);
+         nha.nha.dest = i;
+         nha.ad.length = NEXTHOP_DEST_SIZE;
+         break;
        }
-      else
-      {
-       union {
-         struct nexthop_adata nha;
-         struct {
-           struct adata ad;
-           struct nexthop nh;
-           u32 label;
-         };
-       } nha;
-
-       nha.ad = (struct adata) {
-         .length = sizeof (struct nexthop_adata) - sizeof (struct adata),
-       };
-
-       eattr *a = NULL;
-
-       switch (sa.sa_code)
-         {
       case SA_GW:
        {
          struct eattr *nh_ea = ea_find(*fs->eattrs, &ea_gen_nexthop);
          if (!n || (n->scope == SCOPE_HOST))
            runtime( "Invalid gw address" );
 
-         rta->dest = RTD_UNICAST;
          nha.nh = (struct nexthop) {
            .gw = ip,
            .iface = n->iface,
          if (!ifa)
            runtime( "Invalid iface name" );
 
-         rta->dest = RTD_UNICAST;
          nha.nh = (struct nexthop) {
            .iface = ifa,
          };
          int i = v1.val.i;
          if (i < 1 || i > 256)
            runtime( "Setting weight value out of bounds" );
-         if (rta->dest != RTD_UNICAST)
-           runtime( "Setting weight needs regular nexthop " );
 
          struct eattr *nh_ea = ea_find(*fs->eattrs, &ea_gen_nexthop);
          if (!nh_ea)
            runtime( "No nexthop to set weight on" );
 
-         struct nexthop_adata *nhax = (struct nexthop_adata *)
-           tmp_copy_adata(&((struct nexthop_adata *) nh_ea->u.ptr)->ad);
+         struct nexthop_adata *nhad = (struct nexthop_adata *) nh_ea->u.ptr;
+         if (!NEXTHOP_IS_REACHABLE(nhad))
+           runtime( "Setting weight needs regular nexthop " );
+
+         struct nexthop_adata *nhax = (struct nexthop_adata *) tmp_copy_adata(&nhad->ad);
 
          /* Set weight on all next hops */
          NEXTHOP_WALK(nh, nhax)
 
       default:
        bug("Invalid static attribute access (%u/%u)", sa.type, sa.sa_code);
-         }
+      }
 
-       if (!a)
-         a = ea_set_attr(fs->eattrs,
-             EA_LITERAL_DIRECT_ADATA(&ea_gen_nexthop, 0, tmp_copy_adata(&nha.ad)));
+      if (!a)
+       a = ea_set_attr(fs->eattrs,
+           EA_LITERAL_DIRECT_ADATA(&ea_gen_nexthop, 0, tmp_copy_adata(&nha.ad)));
 
-       a->originated = 1;
-       a->fresh = 1;
-      }
+      a->originated = 1;
+      a->fresh = 1;
     }
   }
 
index 3ce8021dcbf5ded53f35d2c7efc4c4296514a969..1d8877c8008f1dfd088ff039e0022e2f5805b15f 100644 (file)
@@ -76,9 +76,17 @@ struct nexthop {
 /* For packing one into eattrs */
 struct nexthop_adata {
   struct adata ad;
-  struct nexthop nh;
+  /* There is either a set of nexthops or a special destination (RTD_*) */
+  union {
+    struct nexthop nh;
+    uint dest;
+  };
 };
 
+#define NEXTHOP_DEST_SIZE      (OFFSETOF(struct nexthop_adata, dest) + sizeof(uint) - OFFSETOF(struct adata, data))
+#define NEXTHOP_DEST_LITERAL(x)        ((struct nexthop_adata) { \
+      .ad.length = NEXTHOP_DEST_SIZE, .dest = (x), })
+
 #define RNF_ONLINK             0x1     /* Gateway is onlink regardless of IP ranges */
 
 
@@ -88,7 +96,6 @@ typedef struct rta {
   u32 hash_key;                                /* Hash over important fields */
   struct ea_list *eattrs;              /* Extended Attribute chain */
   u16 cached:1;                                /* Are attributes cached? */
-  u16 dest:4;                          /* Route destination type (RTD_...) */
 } rta;
 
 #define RTS_STATIC 1                   /* Normal static route */
@@ -109,7 +116,7 @@ typedef struct rta {
 #define RTS_MAX 16
 
 #define RTD_NONE 0                     /* Undefined next hop */
-#define RTD_UNICAST 1                  /* Next hop is neighbor router */
+#define RTD_UNICAST 1                  /* A standard next hop */
 #define RTD_BLACKHOLE 2                        /* Silently drop packets */
 #define RTD_UNREACHABLE 3              /* Reject as unreachable */
 #define RTD_PROHIBIT 4                 /* Administratively prohibited */
@@ -120,10 +127,6 @@ extern const char * rta_dest_names[RTD_MAX];
 static inline const char *rta_dest_name(uint n)
 { return (n < RTD_MAX) ? rta_dest_names[n] : "???"; }
 
-/* Route has regular, reachable nexthop (i.e. not RTD_UNREACHABLE and like) */
-static inline int rte_is_reachable(rte *r)
-{ return r->attrs->dest == RTD_UNICAST; }
-
 
 /*
  *     Extended Route Attributes
@@ -331,9 +334,24 @@ extern struct ea_class ea_gen_source;
 static inline u32 rt_get_source_attr(rte *rt)
 { return ea_get_int(rt->attrs->eattrs, &ea_gen_source, 0); }
 
+/* Flowspec validation result */
+#define FLOWSPEC_UNKNOWN       0
+#define FLOWSPEC_VALID         1
+#define FLOWSPEC_INVALID       2
+
+extern struct ea_class ea_gen_flowspec_valid;
+static inline u32 rt_get_flowspec_valid(rte *rt)
+{ return ea_get_int(rt->attrs->eattrs, &ea_gen_flowspec_valid, FLOWSPEC_UNKNOWN); }
+
 /* Next hop: For now, stored as adata */
 extern struct ea_class ea_gen_nexthop;
 
+static inline void ea_set_dest(struct ea_list **to, uint flags, uint dest)
+{
+  struct nexthop_adata nhad = NEXTHOP_DEST_LITERAL(dest);
+  ea_set_attr_data(to, &ea_gen_nexthop, flags, &nhad.ad.data, nhad.ad.length);
+}
+
 /* Next hop structures */
 
 #define NEXTHOP_ALIGNMENT      (_Alignof(struct nexthop))
@@ -359,7 +377,35 @@ struct nexthop_adata *nexthop_merge(struct nexthop_adata *x, struct nexthop_adat
 struct nexthop_adata *nexthop_sort(struct nexthop_adata *x, linpool *lp);
 int nexthop_is_sorted(struct nexthop_adata *x);
 
+#define NEXTHOP_IS_REACHABLE(nhad)     ((nhad)->ad.length > NEXTHOP_DEST_SIZE)
 
+/* Route has regular, reachable nexthop (i.e. not RTD_UNREACHABLE and like) */
+static inline int rte_is_reachable(rte *r)
+{
+  eattr *nhea = ea_find(r->attrs->eattrs, &ea_gen_nexthop);
+  if (!nhea)
+    return 0;
+
+  struct nexthop_adata *nhad = (void *) nhea->u.ptr;
+  return NEXTHOP_IS_REACHABLE(nhad);
+}
+
+static inline int nhea_dest(eattr *nhea)
+{
+  if (!nhea)
+    return RTD_NONE;
+
+  struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
+  if (NEXTHOP_IS_REACHABLE(nhad))
+    return RTD_UNICAST;
+  else
+    return nhad->dest;
+}
+
+static inline int rte_dest(rte *r)
+{
+  return nhea_dest(ea_find(r->attrs->eattrs, &ea_gen_nexthop));
+}
 
 void rta_init(void);
 #define rta_size(...) (sizeof(rta))
index 65a032ec6d08b9471e03b6b8726f6730b5a59649..b54744c1b6e5455cf7df02808e746d4f0bcc4218 100644 (file)
@@ -66,6 +66,7 @@ enum btype {
 
   T_ENUM_BGP_ORIGIN = 0x11,    /* BGP Origin enum */
   T_ENUM_RA_PREFERENCE = 0x13, /* RA Preference enum */
+  T_ENUM_FLOWSPEC_VALID = 0x15,        /* Flowspec validation result */
 
 #define EAF_TYPE__MAX 0x1f
 #define EAF_EMBEDDED 0x01              /* Data stored in eattr.u.data (part of type spec) */
index c144f0f36f16452c1e0f796de6448e7004a2f258..6a35cdd27aeda2d82cfe0a414e4607ed8f5f10a9 100644 (file)
@@ -133,7 +133,7 @@ CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, IPV6_SADR, VPN4,
 CF_ENUM(T_ENUM_RTS, RTS_, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
        RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE, BABEL)
 CF_ENUM(T_ENUM_SCOPE, SCOPE_, HOST, LINK, SITE, ORGANIZATION, UNIVERSE, UNDEFINED)
-CF_ENUM(T_ENUM_RTD, RTD_, UNICAST, BLACKHOLE, UNREACHABLE, PROHIBIT)
+CF_ENUM(T_ENUM_RTD, RTD_, BLACKHOLE, UNREACHABLE, PROHIBIT)
 CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID)
 CF_ENUM_PX(T_ENUM_AF, AF_, AFI_, IPV4, IPV6)
 
index cf3ab659d85d3b99ef0b89a32a841a0ae0128525..b5be936ba043c26c0aebfdd15d9ddcff43578600 100644 (file)
@@ -166,6 +166,12 @@ const char * rta_dest_names[RTD_MAX] = {
   [RTD_PROHIBIT]       = "prohibited",
 };
 
+struct ea_class ea_gen_flowspec_valid = {
+  .name = "flowspec_valid",
+  .type = T_ENUM_FLOWSPEC_VALID,
+  .readonly = 1,
+};
+
 pool *rta_pool;
 
 static slab *rta_slab;
@@ -1246,20 +1252,13 @@ rta_alloc_hash(void)
 static inline uint
 rta_hash(rta *a)
 {
-  u64 h;
-  mem_hash_init(&h);
-#define BMIX(f) mem_hash_mix_num(&h, a->f);
-  BMIX(dest);
-#undef MIX
-
-  return mem_hash_value(&h) ^ ea_hash(a->eattrs);
+  return ea_hash(a->eattrs);
 }
 
 static inline int
 rta_same(rta *x, rta *y)
 {
-  return (x->dest == y->dest &&
-         ea_same(x->eattrs, y->eattrs));
+  return ea_same(x->eattrs, y->eattrs);
 }
 
 static rta *
@@ -1382,10 +1381,8 @@ rta_do_cow(rta *o, linpool *lp)
 void
 rta_dump(rta *a)
 {
-  static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" };
-
-  debug("uc=%d %s h=%04x",
-       a->uc, rtd[a->dest], a->hash_key);
+  debug("uc=%d h=%04x",
+       a->uc, a->hash_key);
   if (!a->cached)
     debug(" !CACHED");
   if (a->eattrs)
@@ -1449,6 +1446,7 @@ rta_init(void)
   ea_register_init(&ea_gen_source);
   ea_register_init(&ea_gen_nexthop);
   ea_register_init(&ea_gen_hostentry);
+  ea_register_init(&ea_gen_flowspec_valid);
 }
 
 /*
index 9953e2702050b84b017c1d8bdf0c02ab1b2fca0e..c50e018c3a7feb6dd015512a5a21d013cf31ed8f 100644 (file)
@@ -82,10 +82,7 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
       /* Use iface ID as local source ID */
       struct rte_src *src = rt_get_source(P, ad->iface->index);
 
-      rta a0 = {
-       .dest = RTD_UNICAST,
-      };
-
+      rta a0 = {};
       struct nexthop_adata nhad = {
        .nh = { .iface = ad->iface, },
        .ad = { .length = (void *) NEXTHOP_NEXT(&nhad.nh) - (void *) nhad.ad.data, },
index 32f7aa2d9649db471039d045f34a560ad867a951..0ad8f5c645546caccdf9c17ea0b3fffd388bb373 100644 (file)
@@ -47,6 +47,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary
   void (*get_route_info)(struct rte *, byte *buf);
   eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
   struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
+  int dest = NEXTHOP_IS_REACHABLE(nhad) ? RTD_UNICAST : nhad->dest;
 
   tm_format_time(tm, &config->tf_route, e->lastmod);
   ip_addr a_from = ea_get_ip(a->eattrs, &ea_gen_from, IPA_NONE);
@@ -68,10 +69,10 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary
   if (d->last_table != d->tab)
     rt_show_table(c, d);
 
-  cli_printf(c, -1007, "%-20s %s [%s %s%s]%s%s", ia, rta_dest_name(a->dest),
+  cli_printf(c, -1007, "%-20s %s [%s %s%s]%s%s", ia, rta_dest_name(dest),
             e->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info);
 
-  if (a->dest == RTD_UNICAST)
+  if (dest == RTD_UNICAST)
     NEXTHOP_WALK(nh, nhad)
     {
       char mpls[MPLS_MAX_LABEL_STACK*12 + 5], *lsp = mpls;
index d98f33e4dd7dc5ccc73a85aef0744c37f8c1644e..539e04d01eec71ea033367c64e8b456bd9d7f063 100644 (file)
@@ -699,7 +699,7 @@ rte_trace(struct channel *c, rte *e, int dir, char *msg)
 {
   log(L_TRACE "%s.%s %c %s %N %uL %uG %s",
       c->proto->name, c->name ?: "?", dir, msg, e->net->n.addr, e->src->private_id, e->src->global_id,
-      rta_dest_name(e->attrs->dest));
+      rta_dest_name(rte_dest(e)));
 }
 
 static inline void
@@ -1177,26 +1177,17 @@ rte_validate(rte *e)
     return 0;
   }
 
-  if (net_type_match(n->n.addr, NB_DEST) == !e->attrs->dest)
-  {
-    /* Exception for flowspec that failed validation */
-    if (net_is_flow(n->n.addr) && (e->attrs->dest == RTD_UNREACHABLE))
-      return 1;
-
-    log(L_WARN "Ignoring route %N with invalid dest %d received via %s",
-       n->n.addr, e->attrs->dest, e->sender->proto->name);
-    return 0;
-  }
-
   eattr *nhea = ea_find(e->attrs->eattrs, &ea_gen_nexthop);
-  if ((!nhea) != (e->attrs->dest != RTD_UNICAST))
+  int dest = nhea_dest(nhea);
+
+  if (net_type_match(n->n.addr, NB_DEST) == !dest)
   {
-    log(L_WARN "Ignoring route %N with destination %d and %snexthop received via %s",
-       n->n.addr, e->attrs->dest, (nhea ? "" : "no "), e->sender->proto->name);
+    log(L_WARN "Ignoring route %N with invalid dest %d received via %s",
+       n->n.addr, dest, e->sender->proto->name);
     return 0;
   }
 
-  if ((e->attrs->dest == RTD_UNICAST) &&
+  if ((dest == RTD_UNICAST) &&
       !nexthop_is_sorted((struct nexthop_adata *) nhea->u.ptr))
   {
     log(L_WARN "Ignoring unsorted multipath route %N received via %s",
@@ -2431,26 +2422,27 @@ rta_apply_hostentry(rta *a, struct hostentry_adata *head)
   u32 *labels = head->labels;
   u32 lnum = (u32 *) (head->ad.data + head->ad.length) - labels;
 
-  a->dest = he->dest;
-
   ea_set_attr_u32(&a->eattrs, &ea_gen_igp_metric, 0, he->igp_metric);
 
-  if (a->dest != RTD_UNICAST)
+  if (!he->src)
   {
-    /* No nexthop */
-    ea_unset_attr(&a->eattrs, 0, &ea_gen_nexthop);
+    ea_set_dest(&a->eattrs, 0, RTD_UNREACHABLE);
     return;
   }
 
-  if (!lnum && he->nexthop_linkable)
+  eattr *he_nh_ea = ea_find(he->src->eattrs, &ea_gen_nexthop);
+  ASSERT_DIE(he_nh_ea);
+
+  struct nexthop_adata *nhad = (struct nexthop_adata *) he_nh_ea->u.ptr;
+  int idest = nhea_dest(he_nh_ea);
+
+  if ((idest != RTD_UNICAST) ||
+      !lnum && he->nexthop_linkable)
   { /* Just link the nexthop chain, no label append happens. */
     ea_copy_attr(&a->eattrs, he->src->eattrs, &ea_gen_nexthop);
     return;
   }
 
-  eattr *he_nh_ea = ea_find(he->src->eattrs, &ea_gen_nexthop);
-  struct nexthop_adata *nhad = (struct nexthop_adata *) he_nh_ea->u.ptr;
-
   uint total_size = OFFSETOF(struct nexthop_adata, nh);
 
   NEXTHOP_WALK(nh, nhad)
@@ -2467,10 +2459,14 @@ rta_apply_hostentry(rta *a, struct hostentry_adata *head)
 
   if (total_size == OFFSETOF(struct nexthop_adata, nh))
   {
-    a->dest = RTD_UNREACHABLE;
     log(L_WARN "No valid nexthop remaining, setting route unreachable");
 
-    ea_unset_attr(&a->eattrs, 0, &ea_gen_nexthop);
+    struct nexthop_adata nha = {
+      .ad.length = NEXTHOP_DEST_SIZE,
+      .dest = RTD_UNREACHABLE,
+    };
+
+    ea_set_attr_data(&a->eattrs, &ea_gen_nexthop, 0, &nha.ad.data, nha.ad.length);
     return;
   }
 
@@ -2511,19 +2507,28 @@ rta_apply_hostentry(rta *a, struct hostentry_adata *head)
 static inline struct hostentry_adata *
 rta_next_hop_outdated(rta *a)
 {
+  /* First retrieve the hostentry */
   eattr *heea = ea_find(a->eattrs, &ea_gen_hostentry);
   if (!heea)
     return NULL;
 
   struct hostentry_adata *head = (struct hostentry_adata *) heea->u.ptr;
 
+  /* If no nexthop is present, we have to create one */
+  eattr *a_nh_ea = ea_find(a->eattrs, &ea_gen_nexthop);
+  if (!a_nh_ea)
+    return head;
+
+  struct nexthop_adata *nhad = (struct nexthop_adata *) a_nh_ea->u.ptr;
+
+  /* Shortcut for unresolvable hostentry */
   if (!head->he->src)
-    return (a->dest != RTD_UNREACHABLE) ? head : NULL;
+    return NEXTHOP_IS_REACHABLE(nhad) ? head : NULL;
 
+  /* Comparing our nexthop with the hostentry nexthop */
   eattr *he_nh_ea = ea_find(head->he->src->eattrs, &ea_gen_nexthop);
-  eattr *a_nh_ea = ea_find(a->eattrs, &ea_gen_nexthop);
 
-  return ((a->dest != head->he->dest) ||
+  return (
       (ea_get_int(a->eattrs, &ea_gen_igp_metric, IGP_METRIC_UNKNOWN) != head->he->igp_metric) ||
       (!head->he->nexthop_linkable) ||
       (!he_nh_ea != !a_nh_ea) ||
@@ -2682,16 +2687,16 @@ rt_flowspec_update_rte(rtable *tab, rte *r)
   const net_addr *n = r->net->n.addr;
   struct bgp_proto *p = (void *) r->src->proto;
   int valid = rt_flowspec_check(bc->base_table, tab, n, r->attrs, p->is_interior);
-  int dest = valid ? RTD_NONE : RTD_UNREACHABLE;
-
-  if (dest == r->attrs->dest)
+  int old = rt_get_flowspec_valid(r);
+  if (old == valid)
     return NULL;
 
   rta *a = alloca(RTA_MAX_SIZE);
   memcpy(a, r->attrs, rta_size(r->attrs));
-  a->dest = dest;
   a->cached = 0;
 
+  ea_set_attr_u32(&a->eattrs, &ea_gen_flowspec_valid, 0, valid);
+
   rte *new = sl_alloc(rte_slab);
   memcpy(new, r, sizeof(rte));
   new->attrs = rta_lookup(a);
@@ -3524,7 +3529,6 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
 
   /* Reset the hostentry */
   he->src = NULL;
-  he->dest = RTD_UNREACHABLE;
   he->nexthop_linkable = 0;
   he->igp_metric = 0;
 
@@ -3545,16 +3549,12 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
          goto done;
        }
 
-      if (a->dest == RTD_UNICAST)
-       {
-         eattr *ea = ea_find(a->eattrs, &ea_gen_nexthop);
-         if (!ea)
-           {
-             log(L_WARN "No nexthop in unicast route");
-             goto done;
-           }
-           
-         NEXTHOP_WALK(nh, (struct nexthop_adata *) ea->u.ptr)
+      eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
+      ASSERT_DIE(nhea);
+      struct nexthop_adata *nhad = (void *) nhea->u.ptr;
+
+      if (NEXTHOP_IS_REACHABLE(nhad))
+         NEXTHOP_WALK(nh, nhad)
            if (ipa_zero(nh->gw))
              {
                if (if_local_addr(he->addr, nh->iface))
@@ -3567,10 +3567,8 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
 
                direct++;
              }
-       }
 
       he->src = rta_clone(a);
-      he->dest = a->dest;
       he->nexthop_linkable = !direct;
       he->igp_metric = rt_get_igp_metric(e);
     }
index eb3f845402279ed216da0fb401c0607b8bcfb38f..6f15fec69fd52581e759b08321c23feeaae2e0c2 100644 (file)
--- a/nest/rt.h
+++ b/nest/rt.h
@@ -144,7 +144,6 @@ struct hostentry {
   unsigned hash_key;                   /* Hash key */
   unsigned uc;                         /* Use count */
   struct rta *src;                     /* Source rta entry */
-  byte dest;                           /* Chosen route destination type (RTD_...) */
   byte nexthop_linkable;               /* Nexthop list is completely non-device */
   u32 igp_metric;                      /* Chosen route IGP metric */
 };
index 9a43f484fe5c313a97e4adf249bf8ef384f99519..b90dcd3f5da322f9eb1ec09bc82588ef80fa08e8 100644 (file)
@@ -677,10 +677,7 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
       }
     };
 
-    rta a0 = {
-      .dest = RTD_UNICAST,
-      .eattrs = &eattrs.l,
-    };
+    rta a0 = { .eattrs = &eattrs.l, };
 
     rta *a = rta_lookup(&a0);
     rte *rte = rte_get_temp(a, p->p.main_source);
@@ -691,12 +688,11 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
   else if (e->valid && (e->router_id != p->router_id))
   {
     /* Unreachable */
-    rta a0 = {
-      .dest = RTD_UNREACHABLE,
-    };
+    rta a0 = {};
 
     ea_set_attr_u32(&a0.eattrs, &ea_gen_preference, 0, 1);
     ea_set_attr_u32(&a0.eattrs, &ea_gen_source, 0, RTS_BABEL);
+    ea_set_dest(&a0.eattrs, 0, RTD_UNREACHABLE);
 
     rta *a = rta_lookup(&a0);
     rte *rte = rte_get_temp(a, p->p.main_source);
@@ -2263,9 +2259,13 @@ babel_kick_timer(struct babel_proto *p)
 static int
 babel_preexport(struct proto *P, struct rte *new)
 {
-  struct rta *a = new->attrs;
+  if (new->src->proto != P)
+    return 0;
+
   /* Reject our own unreachable routes */
-  if ((a->dest == RTD_UNREACHABLE) && (new->src->proto == P))
+  eattr *ea = ea_find(new->attrs->eattrs, &ea_gen_nexthop);
+  struct nexthop_adata *nhad = (void *) ea->u.ptr;
+  if (!NEXTHOP_IS_REACHABLE(nhad))
     return -1;
 
   return 0;
index 1efc26cec1abc157b11d7a1d4c39abef7cbb1d99..6a9e4026c9834fc54898a2b4a94619e38346ad89 100644 (file)
@@ -1711,9 +1711,20 @@ bgp_preexport(struct proto *P, rte *e)
   if (src == NULL)
     return 0;
 
-  /* Reject flowspec that failed validation */
-  if ((e->attrs->dest == RTD_UNREACHABLE) && net_is_flow(e->net->n.addr))
-      return -1;
+  /* Reject flowspec that failed or are pending validation */
+  if (net_is_flow(e->net->n.addr))
+    switch (rt_get_flowspec_valid(e))
+    {
+      case FLOWSPEC_VALID:
+       break;
+      case FLOWSPEC_INVALID:
+       return -1;
+      case FLOWSPEC_UNKNOWN:
+       if ((rt_get_source_attr(e) == RTS_BGP) &&
+           ((struct bgp_channel *) e->sender)->base_table)
+         return -1;
+       break;
+    }
 
   /* IBGP route reflection, RFC 4456 */
   if (p->is_internal && src->is_internal && (p->local_as == src->local_as))
index 6abb7870dd484c2d07406353c79e960af59b99e5..2f98dc1b540655a4a6caa9521798667036a67dc7 100644 (file)
@@ -519,7 +519,9 @@ struct rte_source *bgp_get_source(struct bgp_proto *p, u32 path_id);
 static inline int
 rte_resolvable(rte *rt)
 {
-  return rt->attrs->dest != RTD_UNREACHABLE;
+  eattr *nhea = ea_find(rt->attrs->eattrs, &ea_gen_nexthop);
+  struct nexthop_adata *nhad = (void *) nhea->u.ptr;
+  return NEXTHOP_IS_REACHABLE(nhad) || (nhad->dest != RTD_UNREACHABLE);
 }
 
 
index b07320aa576e02c13df0eac94cfec0f9729e5eae..4c46c60e7231d4d67235620cddefd5a3057a9de1 100644 (file)
@@ -968,7 +968,6 @@ bgp_apply_next_hop(struct bgp_parse_state *s, rta *a, ip_addr gw, ip_addr ll)
 
     ea_set_attr_u32(&a->eattrs, &ea_gen_igp_metric, 0, c->cf->cost);
 
-    a->dest = RTD_UNICAST;
     struct nexthop_adata nhad = {
       .nh = {
        .gw = nbr->addr,
@@ -1003,8 +1002,7 @@ bgp_apply_mpls_labels(struct bgp_parse_state *s, rta *a, u32 lnum, u32 labels[ln
   {
     REPORT("Too many MPLS labels ($u)", lnum);
 
-    a->dest = RTD_UNREACHABLE;
-    ea_unset_attr(&a->eattrs, 0, &ea_gen_nexthop);
+    ea_set_dest(&a->eattrs, 0, RTD_UNREACHABLE);
     return;
   }
 
@@ -1039,15 +1037,21 @@ static void
 bgp_apply_flow_validation(struct bgp_parse_state *s, const net_addr *n, rta *a)
 {
   struct bgp_channel *c = s->channel;
-  int valid = rt_flowspec_check(c->base_table, c->c.table, n, a, s->proto->is_interior);
-  a->dest = valid ? RTD_NONE : RTD_UNREACHABLE;
+  uint valid = rt_flowspec_check(c->base_table, c->c.table, n, a, s->proto->is_interior);
 
-  /* Invalidate cached rta if dest changes */
-  if (s->cached_rta && (s->cached_rta->dest != a->dest))
+  /* Invalidate cached rta */
+  if (s->cached_rta)
   {
+    /* Has't changed */
+    if (valid == ea_get_int(s->cached_rta->eattrs, &ea_gen_flowspec_valid, FLOWSPEC_UNKNOWN))
+      return;
+
     rta_free(s->cached_rta);
     s->cached_rta = NULL;
   }
+
+  /* Set the value */
+  ea_set_attr_u32(&a->eattrs, &ea_gen_flowspec_valid, 0, valid);
 }
 
 static int
@@ -1107,17 +1111,14 @@ bgp_use_gateway(struct bgp_export_state *s)
   if (c->cf->next_hop_self && bgp_match_src(s, c->cf->next_hop_self))
     return NULL;
 
-  /* Unreachable */
-  if (ra->dest != RTD_UNICAST)
-    return NULL;
-
   eattr *nhea = ea_find(ra->eattrs, &ea_gen_nexthop);
   if (!nhea)
     return NULL;
 
   /* We need one valid global gateway */
   struct nexthop_adata *nhad = (struct nexthop_adata *) nhea->u.ptr;
-  if (!NEXTHOP_ONE(nhad) || ipa_zero(nhad->nh.gw) ||
+  if (!NEXTHOP_IS_REACHABLE(nhad) ||
+      !NEXTHOP_ONE(nhad) || ipa_zero(nhad->nh.gw) ||
       ipa_is_link_local(nhad->nh.gw))
     return NULL;
 
index 6070fd347a3e7ee667f6f0976798b51b908f37f0..afe4a01f61e5b8de0d4ad3905b8d64c59a8eba24 100644 (file)
@@ -1983,8 +1983,7 @@ ort_changed(ort *nf, rta *nr)
 
   if (!or ||
     (nf->n.metric1 != nf->old_metric1) || (nf->n.metric2 != nf->old_metric2) ||
-    (nf->n.tag != nf->old_tag) || (nf->n.rid != nf->old_rid) ||
-    (nr->dest != or->dest))
+    (nf->n.tag != nf->old_tag) || (nf->n.rid != nf->old_rid))
     return 1;
 
   eattr *nhea_n = ea_find(nr->eattrs, &ea_gen_nexthop);
@@ -2049,7 +2048,6 @@ again1:
     if (nf->n.type) /* Add the route */
     {
       rta a0 = {
-       .dest = RTD_UNICAST,
       };
 
       struct {
index ca4620cca9b145a1bf40f7fd9185029a812c87fa..09ec9f28261e29d7e73243020e489072f7e83ed9 100644 (file)
@@ -1366,16 +1366,9 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
   uint tag = ea_get_int(a->eattrs, &ea_ospf_tag, 0);
 
   ip_addr fwd = IPA_NONE;
-  if (a->dest == RTD_UNICAST)
+  eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
+  if (nhea)
   {
-    eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
-    if (!nhea)
-    {
-      log(L_ERR "%s: Unicast route without nexthop for %N",
-         p->p.name, n->n.addr);
-      return;
-    }
-
     struct nexthop_adata *nhad = (struct nexthop_adata *) nhea->u.ptr;
     if (use_gw_for_fwaddr(p, nhad->nh.gw, nhad->nh.iface))
       fwd = nhad->nh.gw;
index 8642e0a19955e51aeb7b4ba91c3960f70ee6fe30..d1ff6adfa64ee81c3e21b32a59472c5f73a088b2 100644 (file)
@@ -142,9 +142,7 @@ perf_loop(void *data)
     *((net_addr_ip4 *) &(p->data[i].net)) = random_net_ip4();
 
     if (!p->attrs_per_rte || !(i % p->attrs_per_rte)) {
-      struct rta a0 = {
-       .dest = RTD_UNICAST,
-      };
+      struct rta a0 = {};
 
       ea_set_attr_u32(&a0.eattrs, &ea_gen_preference, 0, p->p.main_channel->preference);
       ea_set_attr_u32(&a0.eattrs, &ea_gen_source, 0, RTS_PERF);
index 425a411ce0e4609455724aabacd0d55ff45d30b7..a0f2fdc03d63e87ca14ee7df3fe73af53bf1f9ff 100644 (file)
@@ -151,9 +151,7 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
   if (rt)
   {
     /* Update */
-    rta a0 = {
-      .dest = RTD_UNICAST,
-    };
+    rta a0 = {};
 
     struct {
       ea_list l;
index 56d8add2fcbdba360289eaa37e201db267965a60..4318cbb7694451d9dfb8ce72f5688fa1e3c571bf 100644 (file)
@@ -120,9 +120,7 @@ rpki_table_add_roa(struct rpki_cache *cache, struct channel *channel, const net_
 {
   struct rpki_proto *p = cache->p;
 
-  rta a0 = {
-    .dest = RTD_NONE,
-  };
+  rta a0 = {};
 
   ea_set_attr_u32(&a0.eattrs, &ea_gen_preference, 0, channel->preference);
   ea_set_attr_u32(&a0.eattrs, &ea_gen_source, 0, RTS_RPKI);
index 5102617f235b1fe86cb06370fe3341855af4d6fa..806849c432baaf09e4baf08ac84c55462a3accc7 100644 (file)
@@ -55,7 +55,6 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
 {
   rta *a = allocz(RTA_MAX_SIZE);
   struct rte_src *src = static_get_source(p, r->index);
-  a->dest = r->dest;
   ea_set_attr_u32(&a->eattrs, &ea_gen_preference, 0, p->p.main_channel->preference);
   ea_set_attr_u32(&a->eattrs, &ea_gen_source, 0, RTS_STATIC);
 
@@ -97,7 +96,7 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
        nhad->ad.data, (void *) nh - (void *) nhad->ad.data);
   }
 
-  if (r->dest == RTDX_RECURSIVE)
+  else if (r->dest == RTDX_RECURSIVE)
   {
     rtable *tab = ipa_is_ip4(r->via) ? p->igp_table_ip4 : p->igp_table_ip6;
     u32 *labels = r->mls ? (void *) r->mls->data : NULL;
@@ -107,6 +106,9 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
        r->via, IPA_NONE, lnum, labels);
   }
 
+  else if (r->dest)
+    ea_set_dest(&a->eattrs, 0, r->dest);
+
   /* Already announced */
   if (r->state == SRS_CLEAN)
     return;
index fdfd48855fe1a84398289487717a564cb2c84be8..40f6212ec61d82a738ff55565fba5444d8af42c7 100644 (file)
@@ -1407,11 +1407,16 @@ HASH_DEFINE_REHASH_FN(RTH, struct krt_proto)
 int
 krt_capable(rte *e)
 {
-  rta *a = e->attrs;
+  eattr *ea = ea_find(e->attrs->eattrs, &ea_gen_nexthop);
+  if (!ea)
+    return 0;
+
+  struct nexthop_adata *nhad = (void *) ea->u.ptr;
+  if (NEXTHOP_IS_REACHABLE(nhad))
+    return 1;
 
-  switch (a->dest)
+  switch (nhad->dest)
   {
-    case RTD_UNICAST:
     case RTD_BLACKHOLE:
     case RTD_UNREACHABLE:
     case RTD_PROHIBIT:
@@ -1591,7 +1596,7 @@ nl_add_rte(struct krt_proto *p, rte *e)
   eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
   struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
 
-  if (krt_ecmp6(p) && nhad && !NEXTHOP_ONE(nhad))
+  if (krt_ecmp6(p) && nhad && NEXTHOP_IS_REACHABLE(nhad) && !NEXTHOP_ONE(nhad))
   {
     uint cnt = 0;
     NEXTHOP_WALK(nh, nhad)
@@ -1616,7 +1621,8 @@ nl_add_rte(struct krt_proto *p, rte *e)
     return err;
   }
 
-  return nl_send_route(p, e, NL_OP_ADD, a->dest, nhad);
+  return nl_send_route(p, e, NL_OP_ADD,
+      NEXTHOP_IS_REACHABLE(nhad) ? RTD_UNICAST : nhad->dest, nhad);
 }
 
 static inline int
@@ -1638,7 +1644,8 @@ nl_replace_rte(struct krt_proto *p, rte *e)
   rta *a = e->attrs;
   eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
   struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
-  return nl_send_route(p, e, NL_OP_REPLACE, a->dest, nhad);
+  return nl_send_route(p, e, NL_OP_REPLACE,
+      NEXTHOP_IS_REACHABLE(nhad) ? RTD_UNICAST : nhad->dest, nhad);
 }
 
 
@@ -1901,8 +1908,6 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
   switch (i->rtm_type)
     {
     case RTN_UNICAST:
-      ra->dest = RTD_UNICAST;
-
       if (a[RTA_MULTIPATH])
         {
          struct nexthop_adata *nh = nl_parse_multipath(s, p, n, a[RTA_MULTIPATH], i->rtm_family, krt_src);
@@ -1953,15 +1958,40 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
            }
        }
 
+#ifdef HAVE_MPLS_KERNEL
+      if ((i->rtm_family == AF_MPLS) && a[RTA_NEWDST] && !a[RTA_MULTIPATH])
+       nhad.nh.labels = rta_get_mpls(a[RTA_NEWDST], nhad.nh.label);
+
+      if (a[RTA_ENCAP] && a[RTA_ENCAP_TYPE] && !a[RTA_MULTIPATH])
+       {
+         switch (rta_get_u16(a[RTA_ENCAP_TYPE]))
+           {
+             case LWTUNNEL_ENCAP_MPLS:
+               {
+                 struct rtattr *enca[BIRD_RTA_MAX];
+                 nl_attr_len = RTA_PAYLOAD(a[RTA_ENCAP]);
+                 nl_parse_attrs(RTA_DATA(a[RTA_ENCAP]), encap_mpls_want, enca, sizeof(enca));
+                 nhad.nh.labels = rta_get_mpls(enca[RTA_DST], nhad.nh.label);
+                 break;
+               }
+             default:
+               SKIP("unknown encapsulation method %d\n", rta_get_u16(a[RTA_ENCAP_TYPE]));
+               break;
+           }
+       }
+#endif
+
+      /* Finalize the nexthop */
+      nhad.ad.length = (void *) NEXTHOP_NEXT(&nhad.nh) - (void *) nhad.ad.data;
       break;
     case RTN_BLACKHOLE:
-      ra->dest = RTD_BLACKHOLE;
+      nhad.nhad = NEXTHOP_DEST_LITERAL(RTD_BLACKHOLE);
       break;
     case RTN_UNREACHABLE:
-      ra->dest = RTD_UNREACHABLE;
+      nhad.nhad = NEXTHOP_DEST_LITERAL(RTD_UNREACHABLE);
       break;
     case RTN_PROHIBIT:
-      ra->dest = RTD_PROHIBIT;
+      nhad.nhad = NEXTHOP_DEST_LITERAL(RTD_PROHIBIT);
       break;
     /* FIXME: What about RTN_THROW? */
     default:
@@ -1969,32 +1999,6 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
       return;
     }
 
-#ifdef HAVE_MPLS_KERNEL
-  if ((i->rtm_family == AF_MPLS) && a[RTA_NEWDST] && !a[RTA_MULTIPATH])
-    nhad.nh.labels = rta_get_mpls(a[RTA_NEWDST], nhad.nh.label);
-
-  if (a[RTA_ENCAP] && a[RTA_ENCAP_TYPE] && !a[RTA_MULTIPATH])
-    {
-      switch (rta_get_u16(a[RTA_ENCAP_TYPE]))
-       {
-         case LWTUNNEL_ENCAP_MPLS:
-           {
-             struct rtattr *enca[BIRD_RTA_MAX];
-             nl_attr_len = RTA_PAYLOAD(a[RTA_ENCAP]);
-             nl_parse_attrs(RTA_DATA(a[RTA_ENCAP]), encap_mpls_want, enca, sizeof(enca));
-             nhad.nh.labels = rta_get_mpls(enca[RTA_DST], nhad.nh.label);
-             break;
-           }
-         default:
-           SKIP("unknown encapsulation method %d\n", rta_get_u16(a[RTA_ENCAP_TYPE]));
-           break;
-       }
-    }
-#endif
-
-  /* Finalize the nexthop */
-  nhad.ad.length = (void *) NEXTHOP_NEXT(&nhad.nh) - (void *) nhad.ad.data;
-
   if (i->rtm_scope != def_scope)
     ea_set_attr(&ra->eattrs,
        EA_LITERAL_EMBEDDED(&ea_krt_scope, 0, i->rtm_scope));
index 89e9e97ee76ef4c8190055096dee0c579935ca59..a07899369b605af6fe63efcf0471c25552231a27 100644 (file)
@@ -608,17 +608,10 @@ krt_same_dest(rte *k, rte *e)
 {
   rta *ka = k->attrs, *ea = e->attrs;
 
-  if (ka->dest != ea->dest)
-    return 0;
-
-  if (ka->dest != RTD_UNICAST)
-    return 1;
-
   eattr *nhea_k = ea_find(ka->eattrs, &ea_gen_nexthop);
   eattr *nhea_e = ea_find(ea->eattrs, &ea_gen_nexthop);
 
-  ASSUME(nhea_k && nhea_e);
-  return adata_same(nhea_k->u.ptr, nhea_e->u.ptr);
+  return (!nhea_k == !nhea_e) && adata_same(nhea_k->u.ptr, nhea_e->u.ptr);
 }
 
 /*