]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Merge commit '1b9189d5' into haugesund
authorMaria Matejka <mq@ucw.cz>
Wed, 9 Mar 2022 12:13:05 +0000 (13:13 +0100)
committerMaria Matejka <mq@ucw.cz>
Wed, 9 Mar 2022 12:13:05 +0000 (13:13 +0100)
1  2 
filter/f-inst.c
nest/route.h
nest/rt-show.c
nest/rt-table.c
proto/babel/babel.c
proto/bgp/attrs.c
proto/bgp/bgp.h
proto/bgp/packets.c
sysdep/bsd/krt-sock.c
sysdep/linux/netlink.c

diff --cc filter/f-inst.c
Simple merge
diff --cc nest/route.h
index 595acabd96ca8a02ce2823db621256c89fe87b76,4944a854a0b70c56d72dca5119820c7ec41a7e31..c7fb67aa2b2f5c2d0571970a0a1f997c15ea79fc
@@@ -161,8 -157,8 +161,9 @@@ typedef struct rtable 
    resource r;
    node n;                             /* Node in list of all tables */
    pool *rp;                           /* Resource pool to allocate everything from, including itself */
+   struct slab *rte_slab;              /* Slab to allocate route objects */
    struct fib fib;
 +  struct f_trie *trie;                        /* Trie of prefixes defined in fib */
    char *name;                         /* Name of this table */
    list channels;                      /* List of attached channels (struct channel) */
    uint addr_type;                     /* Type of address data stored in table (NET_*) */
@@@ -309,17 -330,12 +353,13 @@@ static inline void rt_shutdown(rtable *
  
  static inline net *net_find(rtable *tab, const net_addr *addr) { return (net *) fib_find(&tab->fib, addr); }
  static inline net *net_find_valid(rtable *tab, const net_addr *addr)
- { net *n = net_find(tab, addr); return (n && rte_is_valid(n->routes)) ? n : NULL; }
+ { net *n = net_find(tab, addr); return (n && n->routes && rte_is_valid(&n->routes->rte)) ? n : NULL; }
  static inline net *net_get(rtable *tab, const net_addr *addr) { return (net *) fib_get(&tab->fib, addr); }
 -void *net_route(rtable *tab, const net_addr *n);
 +net *net_get(rtable *tab, const net_addr *addr);
 +net *net_route(rtable *tab, const net_addr *n);
  int net_roa_check(rtable *tab, const net_addr *n, u32 asn);
- rte *rte_find(net *net, struct rte_src *src);
- rte *rte_get_temp(struct rta *, struct rte_src *src);
- void rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
- /* rte_update() moved to protocol.h to avoid dependency conflicts */
- int rt_examine(rtable *t, net_addr *a, struct proto *p, const struct filter *filter);
- rte *rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int silent);
+ int rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filter);
+ rte *rt_export_merged(struct channel *c, net *net, linpool *pool, int silent);
  void rt_refresh_begin(rtable *t, struct channel *c);
  void rt_refresh_end(rtable *t, struct channel *c);
  void rt_modify_stale(rtable *t, struct channel *c);
@@@ -336,22 -350,9 +374,21 @@@ void rt_feed_channel_abort(struct chann
  int rt_reload_channel(struct channel *c);
  void rt_reload_channel_abort(struct channel *c);
  void rt_prune_sync(rtable *t, int all);
- int rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old, rte **old_exported, int refeed);
+ int rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old, struct rte_storage **old_exported, int refeed);
  struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
  
 +static inline int rt_is_ip(rtable *tab)
 +{ return (tab->addr_type == NET_IP4) || (tab->addr_type == NET_IP6); }
 +
 +static inline int rt_is_vpn(rtable *tab)
 +{ return (tab->addr_type == NET_VPN4) || (tab->addr_type == NET_VPN6); }
 +
 +static inline int rt_is_roa(rtable *tab)
 +{ return (tab->addr_type == NET_ROA4) || (tab->addr_type == NET_ROA6); }
 +
 +static inline int rt_is_flow(rtable *tab)
 +{ return (tab->addr_type == NET_FLOW4) || (tab->addr_type == NET_FLOW6); }
 +
  
  /* Default limit for ECMP next hops, defined in sysdep code */
  extern const int rt_default_ecmp;
diff --cc nest/rt-show.c
index 198779665515b516679a4f33a27e835cccdf97f4,ae5000f51f6c82be38688e0eb06ae28731712c98..7b05c64ed8a50d0b51813f6bb5c446975640491e
@@@ -111,12 -109,13 +110,12 @@@ rt_show_net(struct cli *c, net *n, stru
    ASSUME(!d->export_mode || ec);
  
    int first = 1;
 +  int first_show = 1;
    int pass = 0;
  
-   for (e = n->routes; e; e = e->next)
 -  bsnprintf(ia, sizeof(ia), "%N", n->n.addr);
 -
+   for (struct rte_storage *er = n->routes; er; er = er->next)
      {
-       if (rte_is_filtered(e) != d->filtered)
+       if (rte_is_filtered(&er->rte) != d->filtered)
        continue;
  
        d->rt_counter++;
        goto skip;
  
        if (d->stats < 2)
-       rt_show_rte(c, ia, e, d, (e->net->routes == ee));
 +      {
 +      if (first_show)
 +        net_format(n->n.addr, ia, sizeof(ia));
 +      else
 +        ia[0] = 0;
 +
+       rt_show_rte(c, ia, &e, d, (n->routes == er));
 +      first_show = 0;
 +      }
  
        d->show_counter++;
 -      ia[0] = 0;
  
      skip:
-       if (e != ee)
-       {
-       rte_free(e);
-       e = ee;
-       }
        lp_flush(c->show_pool);
  
        if (d->primary_only)
diff --cc nest/rt-table.c
index b3ca3d050ed894f46c7614396fe6e69c6da4eedc,c49400b7c71c4c9b40614eb3a347edfa459e77e5..9a9d57ad37253f01bf0d42245c92c2bc81a8bbf8
@@@ -1176,14 -798,10 +1089,14 @@@ rte_validate(rte *e
      return 0;
    }
  
-   if (net_type_match(n->n.addr, NB_DEST) == !e->attrs->dest)
+   if (net_type_match(n, NB_DEST) == !e->attrs->dest)
    {
-     if (net_is_flow(n->n.addr) && (e->attrs->dest == RTD_UNREACHABLE))
 +    /* Exception for flowspec that failed validation */
++    if (net_is_flow(n) && (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);
+       n, e->attrs->dest, e->sender->proto->name);
      return 0;
    }
  
@@@ -2209,29 -1655,34 +2056,27 @@@ rt_prune_table(rtable *tab
  again:
    FIB_ITERATE_START(&tab->fib, fit, net, n)
      {
-       rte *e;
      rescan:
-       for (e=n->routes; e; e=e->next)
 +      if (limit <= 0)
 +      {
 +      FIB_ITERATE_PUT(fit);
 +      ev_schedule(tab->rt_event);
 +      return;
 +      }
 +
+       for (struct rte_storage *e=n->routes; e; e=e->next)
        {
-       if (e->sender->flush_active || (e->flags & REF_DISCARD))
+       if (e->rte.sender->flush_active || (e->rte.flags & REF_DISCARD))
          {
-           rte_discard(e);
 -          if (limit <= 0)
 -            {
 -              FIB_ITERATE_PUT(fit);
 -              ev_schedule(tab->rt_event);
 -              return;
 -            }
 -
+           rte_discard(n, &e->rte);
            limit--;
  
            goto rescan;
          }
  
-       if (e->flags & REF_MODIFY)
+       if (e->rte.flags & REF_MODIFY)
          {
-           rte_modify(e);
 -          if (limit <= 0)
 -            {
 -              FIB_ITERATE_PUT(fit);
 -              ev_schedule(tab->rt_event);
 -              return;
 -            }
 -
+           rte_modify(n, &e->rte);
            limit--;
  
            goto rescan;
@@@ -2483,27 -1846,9 +2328,27 @@@ no_nexthop
      }
  }
  
- static inline rte *
- rt_next_hop_update_rte(rtable *tab UNUSED, rte *old)
 +static inline int
 +rta_next_hop_outdated(rta *a)
 +{
 +  struct hostentry *he = a->hostentry;
 +
 +  if (!he)
 +    return 0;
 +
 +  if (!he->src)
 +    return a->dest != RTD_UNREACHABLE;
 +
 +  return (a->dest != he->dest) || (a->igp_metric != he->igp_metric) ||
 +    (!he->nexthop_linkable) || !nexthop_same(&(a->nh), &(he->src->nh));
 +}
 +
+ static inline struct rte_storage *
+ rt_next_hop_update_rte(rtable *tab, net *n, rte *old)
  {
 +  if (!rta_next_hop_outdated(old->attrs))
 +    return NULL;
 +
    rta *a = alloca(RTA_MAX_SIZE);
    memcpy(a, old->attrs, rta_size(old->attrs));
  
    rta_apply_hostentry(a, old->attrs->hostentry, &mls);
    a->cached = 0;
  
-   rte *e = sl_alloc(rte_slab);
-   memcpy(e, old, sizeof(rte));
-   e->attrs = rta_lookup(a);
-   rt_lock_source(e->src);
+   rte e0 = *old;
+   e0.attrs = a;
  
-   return e;
+   return rte_store(&e0, n, tab);
  }
  
-   rte *rb = nb ? nb->routes : NULL;
 +
 +#ifdef CONFIG_BGP
 +
 +static inline int
 +net_flow_has_dst_prefix(const net_addr *n)
 +{
 +  ASSUME(net_is_flow(n));
 +
 +  if (n->pxlen)
 +    return 1;
 +
 +  if (n->type == NET_FLOW4)
 +  {
 +    const net_addr_flow4 *n4 = (void *) n;
 +    return (n4->length > sizeof(net_addr_flow4)) && (n4->data[0] == FLOW_TYPE_DST_PREFIX);
 +  }
 +  else
 +  {
 +    const net_addr_flow6 *n6 = (void *) n;
 +    return (n6->length > sizeof(net_addr_flow6)) && (n6->data[0] == FLOW_TYPE_DST_PREFIX);
 +  }
 +}
 +
 +static inline int
 +rta_as_path_is_empty(rta *a)
 +{
 +  eattr *e = ea_find(a->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH));
 +  return !e || (as_path_getlen(e->u.ptr) == 0);
 +}
 +
 +static inline u32
 +rta_get_first_asn(rta *a)
 +{
 +  eattr *e = ea_find(a->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH));
 +  u32 asn;
 +
 +  return (e && as_path_get_first_regular(e->u.ptr, &asn)) ? asn : 0;
 +}
 +
 +int
 +rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, int interior)
 +{
 +  ASSERT(rt_is_ip(tab_ip));
 +  ASSERT(rt_is_flow(tab_flow));
 +  ASSERT(tab_ip->trie);
 +
 +  /* RFC 8955 6. a) Flowspec has defined dst prefix */
 +  if (!net_flow_has_dst_prefix(n))
 +    return 0;
 +
 +  /* RFC 9117 4.1. Accept  AS_PATH is empty (fr */
 +  if (interior && rta_as_path_is_empty(a))
 +    return 1;
 +
 +
 +  /* RFC 8955 6. b) Flowspec and its best-match route have the same originator */
 +
 +  /* Find flowspec dst prefix */
 +  net_addr dst;
 +  if (n->type == NET_FLOW4)
 +    net_fill_ip4(&dst, net4_prefix(n), net4_pxlen(n));
 +  else
 +    net_fill_ip6(&dst, net6_prefix(n), net6_pxlen(n));
 +
 +  /* Find best-match BGP unicast route for flowspec dst prefix */
 +  net *nb = net_route(tab_ip, &dst);
-     rte *rc = nc->routes;
++  const rte *rb = nb ? &nb->routes->rte : NULL;
 +
 +  /* Register prefix to trie for tracking further changes */
 +  int max_pxlen = (n->type == NET_FLOW4) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH;
 +  trie_add_prefix(tab_flow->flowspec_trie, &dst, (nb ? nb->n.addr->pxlen : 0), max_pxlen);
 +
 +  /* No best-match BGP route -> no flowspec */
 +  if (!rb || (rb->attrs->source != RTS_BGP))
 +    return 0;
 +
 +  /* Find ORIGINATOR_ID values */
 +  u32 orig_a = ea_get_int(a->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID), 0);
 +  u32 orig_b = ea_get_int(rb->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID), 0);
 +
 +  /* Originator is either ORIGINATOR_ID (if present), or BGP neighbor address (if not) */
 +  if ((orig_a != orig_b) || (!orig_a && !orig_b && !ipa_equal(a->from, rb->attrs->from)))
 +    return 0;
 +
 +
 +  /* Find ASN of the best-match route, for use in next checks */
 +  u32 asn_b = rta_get_first_asn(rb->attrs);
 +  if (!asn_b)
 +    return 0;
 +
 +  /* RFC 9117 4.2. For EBGP, flowspec and its best-match route are from the same AS */
 +  if (!interior && (rta_get_first_asn(a) != asn_b))
 +    return 0;
 +
 +  /* RFC 8955 6. c) More-specific routes are from the same AS as the best-match route */
 +  TRIE_WALK(tab_ip->trie, subnet, &dst)
 +  {
 +    net *nc = net_find_valid(tab_ip, &subnet);
 +    if (!nc)
 +      continue;
 +
- static rte *
- rt_flowspec_update_rte(rtable *tab, rte *r)
++    const rte *rc = &nc->routes->rte;
 +    if (rc->attrs->source != RTS_BGP)
 +      return 0;
 +
 +    if (rta_get_first_asn(rc->attrs) != asn_b)
 +      return 0;
 +  }
 +  TRIE_WALK_END;
 +
 +  return 1;
 +}
 +
 +#endif /* CONFIG_BGP */
 +
-   const net_addr *n = r->net->n.addr;
++static struct rte_storage *
++rt_flowspec_update_rte(rtable *tab, net *n, rte *r)
 +{
 +#ifdef CONFIG_BGP
 +  if (r->attrs->source != RTS_BGP)
 +    return NULL;
 +
 +  struct bgp_channel *bc = (struct bgp_channel *) r->sender;
 +  if (!bc->base_table)
 +    return NULL;
 +
-   int valid = rt_flowspec_check(bc->base_table, tab, n, r->attrs, p->is_interior);
 +  struct bgp_proto *p = (void *) r->src->proto;
-   rte *new = sl_alloc(rte_slab);
-   memcpy(new, r, sizeof(rte));
-   new->attrs = rta_lookup(a);
++  int valid = rt_flowspec_check(bc->base_table, tab, n->n.addr, r->attrs, p->is_interior);
 +  int dest = valid ? RTD_NONE : RTD_UNREACHABLE;
 +
 +  if (dest == r->attrs->dest)
 +    return NULL;
 +
 +  rta *a = alloca(RTA_MAX_SIZE);
 +  memcpy(a, r->attrs, rta_size(r->attrs));
 +  a->dest = dest;
 +  a->cached = 0;
 +
-   return new;
++  rte new;
++  memcpy(&new, r, sizeof(rte));
++  new.attrs = a;
 +
++  return rte_store(&new, n, tab);
 +#else
 +  return NULL;
 +#endif
 +}
 +
 +
  static inline int
  rt_next_hop_update_net(rtable *tab, net *n)
  {
      return 0;
  
    for (k = &n->routes; e = *k; k = &e->next)
 -    if (rta_next_hop_outdated(e->rte.attrs))
 +  {
 +    if (!net_is_flow(n->n.addr))
-       new = rt_next_hop_update_rte(tab, e);
++      new = rt_next_hop_update_rte(tab, n, &e->rte);
 +    else
-       new = rt_flowspec_update_rte(tab, e);
++      new = rt_flowspec_update_rte(tab, n, &e->rte);
 +
 +    if (new)
        {
 -      new = rt_next_hop_update_rte(tab, n, &e->rte);
+       new->next = e->next;
        *k = new;
  
-       rte_trace_in(D_ROUTES, new->sender, new, "updated");
+       rte_trace_in(D_ROUTES, new->rte.sender, &new->rte, "updated");
        rte_announce_i(tab, RA_ANY, n, new, e, NULL, NULL);
  
        /* Call a pre-comparison hook */
Simple merge
index 65e87c96851cd8914cd5f8d2498b01887e7b91d1,1d9b363041a4c13269c650837c71fc074546f933..1b36368fa1d24860312a6c00fbc51edb0e73fe98
@@@ -1689,10 -1682,6 +1689,10 @@@ bgp_preexport(struct channel *c, rte *e
    if (src == NULL)
      return 0;
  
-   if ((e->attrs->dest == RTD_UNREACHABLE) && net_is_flow(e->net->n.addr))
-       return -1;
 +  /* Reject flowspec that failed validation */
++  if ((e->attrs->dest == RTD_UNREACHABLE) && net_is_flow(e->net))
++    return -1;
 +
    /* IBGP route reflection, RFC 4456 */
    if (p->is_internal && src->is_internal && (p->local_as == src->local_as))
    {
@@@ -1860,11 -1849,7 +1860,11 @@@ bgp_rt_notify(struct proto *P, struct c
  
    if (new)
    {
 -    struct ea_list *attrs = bgp_update_attrs(p, c, new, new->attrs->eattrs, bgp_linpool2);
 +    struct ea_list *attrs = bgp_update_attrs(p, c, new, new->attrs->eattrs, tmp_linpool);
 +
 +    /* Error during attribute processing */
 +    if (!attrs)
-       log(L_ERR "%s: Invalid route %N withdrawn", p->p.name, n->n.addr);
++      log(L_ERR "%s: Invalid route %N withdrawn", p->p.name, n);
  
      /* If attributes are invalid, we fail back to withdraw */
      buck = attrs ? bgp_get_bucket(c, attrs) : bgp_get_withdraw_bucket(c);
diff --cc proto/bgp/bgp.h
index bff49c3a455772d13f1b12beb918bfc281cf6e22,c79dd1b2480aa1a30376e21126d95b66e356460d..655b263609e5b77083d3e8a3447e5db2b947c082
@@@ -518,9 -517,9 +518,9 @@@ struct rte_source *bgp_find_source(stru
  struct rte_source *bgp_get_source(struct bgp_proto *p, u32 path_id);
  
  static inline int
- rte_resolvable(rte *rt)
+ rta_resolvable(rta *a)
  {
-   return rt->attrs->dest != RTD_UNREACHABLE;
 -  return a->dest == RTD_UNICAST;
++  return a->dest != RTD_UNREACHABLE;
  }
  
  
index 66f14150b395a281394b477024856e4f104232ad,647551e5f99c6e373fda547777a0ddb4354e5bb9..7be346776e10557d24b688d637a2ff80f2a00ea9
@@@ -1371,12 -1348,8 +1371,12 @@@ bgp_rte_update(struct bgp_parse_state *
  
    if (!a0)
    {
 +    /* Route update was changed to withdraw */
 +    if (s->err_withdraw && s->reach_nlri_step)
 +      REPORT("Invalid route %N withdrawn", n);
 +
      /* Route withdraw */
-     rte_update3(&s->channel->c, n, NULL, s->last_src);
+     rte_update(&s->channel->c, n, NULL, s->last_src);
      return;
    }
  
Simple merge
index e103c8ef1665c800c575f11011a468763e1de585,bff2d579f4eb265d85bdbcdef1e1da3b6e38650e..35ba116ceb501a79a7589d640953a462c26cce9b
@@@ -1778,9 -1681,12 +1777,9 @@@ nl_parse_route(struct nl_parse_state *s
  
        if (a[RTA_MULTIPATH])
          {
-         struct nexthop *nh = nl_parse_multipath(s, p, n, a[RTA_MULTIPATH], i->rtm_family, krt_src);
 -        struct nexthop *nh = nl_parse_multipath(s, p, a[RTA_MULTIPATH], i->rtm_family);
++        struct nexthop *nh = nl_parse_multipath(s, p, net, a[RTA_MULTIPATH], i->rtm_family, krt_src);
          if (!nh)
 -          {
 -            log(L_ERR "KRT: Received strange multipath route %N", net);
 -            return;
 -          }
 +          SKIP("strange RTA_MULTIPATH\n");
  
          nexthop_link(ra, nh);
          break;