]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Merge commit 'b20b6a9ad204f2648ed3d62720435bb21dfb947c' into thread-next
authorMaria Matejka <mq@ucw.cz>
Wed, 11 Oct 2023 20:26:41 +0000 (22:26 +0200)
committerMaria Matejka <mq@ucw.cz>
Wed, 11 Oct 2023 20:26:41 +0000 (22:26 +0200)
1  2 
proto/bgp/attrs.c
proto/bgp/bgp.h
proto/bgp/packets.c

index 6335a1e19051a9e109ab09dd96d1ca6ef24d6898,adc201a7b05183aaa951a9e8c3a5f39373d8bd79..6fd7abaeb5a7474c546a7f35e6f7969c2d46b906
@@@ -1665,10 -1629,12 +1665,13 @@@ bgp_defer_bucket(struct bgp_channel *bc
  }
  
  void
 -bgp_withdraw_bucket(struct bgp_channel *c, struct bgp_bucket *b)
 +bgp_withdraw_bucket(struct bgp_channel *bc, struct bgp_bucket *b)
  {
 -  struct bgp_proto *p = (void *) c->c.proto;
+   if (b->bmp)
+     return;
 +  struct bgp_proto *p = (void *) bc->c.proto;
 +  struct bgp_pending_tx *c = bc->ptx;
    struct bgp_bucket *wb = bgp_get_withdraw_bucket(c);
  
    log(L_ERR "%s: Attribute list too long", p->p.name);
@@@ -1814,238 -1730,6 +1817,242 @@@ bgp_free_prefix(struct bgp_pending_tx *
      mb_free(px);
  }
  
 +void
 +bgp_done_prefix(struct bgp_channel *c, struct bgp_prefix *px, struct bgp_bucket *buck)
 +{
++  /* BMP hack */
++  if (buck->bmp)
++    return;
++
 +  /* Cleanup: We're called from bucket senders. */
 +  ASSERT_DIE(px->cur == buck);
 +  rem_node(&px->buck_node_xx);
 +
 +  /* We may want to store the updates */
 +  if (c->c.out_table)
 +  {
 +    /* Nothing to be sent right now */
 +    px->cur = NULL;
 +
 +    /* Unref the previous sent version */
 +    if (px->last)
 +      px->last->px_uc--;
 +
 +    /* Ref the current sent version */
 +    if (!IS_WITHDRAW_BUCKET(buck))
 +    {
 +      px->last = buck;
 +      px->last->px_uc++;
 +      return;
 +    }
 +
 +    /* Prefixes belonging to the withdraw bucket are freed always */
 +  }
 +
 +  bgp_free_prefix(c->ptx, px);
 +}
 +
 +static void
 +bgp_pending_tx_rfree(resource *r)
 +{
 +  struct bgp_pending_tx *ptx = SKIP_BACK(struct bgp_pending_tx, r, r);
 +
 +  HASH_WALK(ptx->prefix_hash, next, n)
 +    rt_unlock_source(rt_find_source_global(n->path_id));
 +  HASH_WALK_END;
 +}
 +
 +static void bgp_pending_tx_dump(resource *r UNUSED, unsigned indent UNUSED) { debug("\n"); }
 +
 +static struct resclass bgp_pending_tx_class = {
 +  .name = "BGP Pending TX",
 +  .size = sizeof(struct bgp_pending_tx),
 +  .free = bgp_pending_tx_rfree,
 +  .dump = bgp_pending_tx_dump,
 +};
 +
 +void
 +bgp_init_pending_tx(struct bgp_channel *c)
 +{
 +  ASSERT_DIE(!c->ptx);
 +
 +  pool *p = rp_new(c->pool, proto_domain(c->c.proto), "BGP Pending TX");
 +  c->ptx = ralloc(p, &bgp_pending_tx_class);
 +  c->ptx->pool = p;
 +
 +  bgp_init_bucket_table(c->ptx);
 +  bgp_init_prefix_table(c);
 +}
 +
 +void
 +bgp_free_pending_tx(struct bgp_channel *c)
 +{
 +  ASSERT_DIE(c->ptx);
 +  ASSERT_DIE(c->ptx->pool);
 +
 +  rp_free(c->ptx->pool);
 +  c->ptx = NULL;
 +}
 +
 +
 +/*
 + *    Prefix hash table exporter
 + */
 +
 +struct bgp_out_export_hook {
 +  struct rt_export_hook h;
 +  u32 hash_iter;                              /* Iterator over hash */
 +};
 +
 +static void
 +bgp_out_table_feed(void *data)
 +{
 +  struct bgp_out_export_hook *hook = data;
 +  struct bgp_channel *bc = SKIP_BACK(struct bgp_channel, prefix_exporter, hook->h.table);
 +  struct bgp_pending_tx *c = bc->ptx;
 +
 +  int max = 512;
 +
 +  const net_addr *neq = (hook->h.req->addr_mode == TE_ADDR_EQUAL) ? hook->h.req->addr : NULL;
 +  const net_addr *cand = NULL;
 +
 +  do {
 +    HASH_WALK_ITER(c->prefix_hash, PXH, n, hook->hash_iter)
 +    {
 +      switch (hook->h.req->addr_mode)
 +      {
 +      case TE_ADDR_IN:
 +        if (!net_in_netX(n->net, hook->h.req->addr))
 +          continue;
 +        /* fall through */
 +      case TE_ADDR_NONE:
 +        /* Splitting only for multi-net exports */
 +        if (--max <= 0)
 +          HASH_WALK_ITER_PUT;
 +        break;
 +
 +      case TE_ADDR_FOR:
 +        if (!neq)
 +        {
 +          if (net_in_netX(hook->h.req->addr, n->net) && (!cand || (n->net->length > cand->length)))
 +            cand = n->net;
 +          continue;
 +        }
 +        /* fall through */
 +      case TE_ADDR_EQUAL:
 +        if (!net_equal(n->net, neq))
 +          continue;
 +        break;
 +      }
 +
 +      struct bgp_bucket *buck = n->cur ?: n->last;
 +      ea_list *ea = NULL;
 +      if (buck == c->withdraw_bucket)
 +      ea_set_dest(&ea, 0, RTD_UNREACHABLE);
 +      else
 +      {
 +      ea = buck->eattrs;
 +      eattr *eanh = bgp_find_attr(ea, BA_NEXT_HOP);
 +      ASSERT_DIE(eanh);
 +      const ip_addr *nh = (const void *) eanh->u.ptr->data;
 +
 +      struct nexthop_adata nhad = {
 +        .ad = { .length = sizeof (struct nexthop_adata) - sizeof (struct adata), },
 +        .nh = { .gw = nh[0], },
 +      };
 +
 +      ea_set_attr(&ea, EA_LITERAL_DIRECT_ADATA(&ea_gen_nexthop, 0, tmp_copy_adata(&nhad.ad)));
 +      }
 +
 +      struct rte_storage es = {
 +      .rte = {
 +        .attrs = ea,
 +        .net = n->net,
 +        .src = rt_find_source_global(n->path_id),
 +        .sender = NULL,
 +        .lastmod = n->lastmod,
 +        .flags = n->cur ? REF_PENDING : 0,
 +      },
 +      };
 +
 +      struct rt_pending_export rpe = {
 +      .new = &es, .new_best = &es,
 +      };
 +
 +      if (hook->h.req->export_bulk)
 +      {
 +      const rte *feed = &es.rte;
 +      hook->h.req->export_bulk(hook->h.req, n->net, &rpe, &rpe, &feed, 1);
 +      }
 +      else if (hook->h.req->export_one)
 +      hook->h.req->export_one(hook->h.req, n->net, &rpe);
 +      else
 +      bug("No export method in export request");
 +    }
 +    HASH_WALK_ITER_END;
 +
 +    neq = cand;
 +    cand = NULL;
 +  } while (neq);
 +
 +  if (hook->hash_iter)
 +    ev_schedule_work(&hook->h.event);
 +  else
 +    rt_set_export_state(&hook->h, BIT32_ALL(TES_FEEDING), TES_READY);
 +}
 +
 +static void
 +bgp_out_table_export_start(struct rt_exporter *re, struct rt_export_request *req)
 +{
 +  req->hook = rt_alloc_export(re, req->pool, sizeof(struct bgp_out_export_hook));
 +  req->hook->req = req;
 +
 +  struct bgp_out_export_hook *hook = SKIP_BACK(struct bgp_out_export_hook, h, req->hook);
 +
 +  hook->h.event.hook = bgp_out_table_feed;
 +  rt_init_export(re, req->hook);
 +}
 +
 +static void
 +bgp_out_table_export_stop(struct rt_export_hook *hook)
 +{
 +  rt_set_export_state(hook, BIT32_ALL(TES_HUNGRY, TES_FEEDING, TES_READY), TES_STOP);
 +  rt_stop_export_common(hook);
 +}
 +
 +static void
 +bgp_out_table_export_done(void *data)
 +{
 +  struct bgp_out_export_hook *hook = data;
 +  struct rt_export_request *req = hook->h.req;
 +  void (*stopped)(struct rt_export_request *) = hook->h.stopped;
 +
 +  rt_export_stopped(&hook->h);
 +  CALL(stopped, req);
 +}
 +
 +static const struct rt_exporter_class bgp_out_table_export_class = {
 +  .start = bgp_out_table_export_start,
 +  .stop = bgp_out_table_export_stop,
 +  .done = bgp_out_table_export_done,
 +};
 +
 +void
 +bgp_setup_out_table(struct bgp_channel *c)
 +{
 +  ASSERT_DIE(c->c.out_table == NULL);
 +
 +  c->prefix_exporter = (struct rt_exporter) {
 +    .class = &bgp_out_table_export_class,
 +    .addr_type = c->c.table->addr_type,
 +    .rp = c->c.proto->pool,
 +  };
 +
 +  rt_exporter_init(&c->prefix_exporter);
 +
 +  c->c.out_table = &c->prefix_exporter;
 +}
 +
  
  /*
   *    BGP protocol glue
diff --cc proto/bgp/bgp.h
index c371307de871969677eb8033fd2ab28f703e3f2c,7368654573ba2cc4b4c0cd8bc52f1a33c2eeee42..7e35b37c1beeba87af03ca2a47460d5cd8f1516a
@@@ -422,9 -411,9 +422,10 @@@ struct bgp_prefix 
  struct bgp_bucket {
    node send_node;                     /* Node in send queue */
    struct bgp_bucket *next;            /* Node in bucket hash table */
 -  list prefixes;                      /* Prefixes in this bucket (struct bgp_prefix) */
 +  list prefixes;                      /* Prefixes to send in this bucket (struct bgp_prefix) */
    u32 hash;                           /* Hash over extended attributes */
-   u32 px_uc;                          /* How many prefixes are linking this bucket */
++  u32 px_uc:31;                               /* How many prefixes are linking this bucket */
+   u32 bmp:1;                          /* Temporary bucket for BMP encoding */
    ea_list eattrs[0];                  /* Per-bucket extended attributes */
  };
  
Simple merge