]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
MRT: buildable and running again for BIRD 3
authorKaterina Kubecova <katerina.kubecova@nic.cz>
Fri, 27 Sep 2024 11:58:46 +0000 (13:58 +0200)
committerMaria Matejka <mq@ucw.cz>
Thu, 14 Nov 2024 10:41:37 +0000 (11:41 +0100)
Tests for MRT are scarce and not automated for now, so it may behave
weirdly in corner cases.

configure.ac
nest/route.h
proto/bgp/attrs.c
proto/bgp/bgp.h
proto/bgp/packets.c
proto/mrt/config.Y
proto/mrt/mrt.c
proto/mrt/mrt.h
sysdep/unix/io.c
sysdep/unix/unix.h

index ae8c81f798301bd2f9779c4923d3bee3883f9ddc..9c8092014d902af4bc9ffc48f46ccecdecd2a28e 100644 (file)
@@ -320,8 +320,7 @@ else
   AC_DEFINE([HAVE_CLOCK_MONOTONIC_COARSE], [1], [Define to 1 if coarse clock is available])
 fi
 
-# temporarily removed "mrt" from all_protocols to speed up 3.0-alpha1 release
-all_protocols="aggregator bfd babel bgp l3vpn ospf pipe radv rip rpki static"
+all_protocols="aggregator bfd babel bgp l3vpn ospf pipe radv rip rpki static mrt"
 all_protocols=`echo $all_protocols | sed 's/ /,/g'`
 
 if test "$with_protocols" = all ; then
index 72089929686e9c93775498d8c0b9eef5ac659bb6..ddcb9a85100221025287f8975cf17e012d354183 100644 (file)
@@ -125,7 +125,7 @@ struct rt_export_request {
   /* Table feeding contraption */
   struct rt_export_feeder {
     /* Formal name */
-    char *name;
+    const char *name;
 
     /* Enlisting */
     struct rt_exporter * _Atomic exporter;
index d293a71b2fcf063215679b4235497c7b8fe0cb97..3dba149e5e523334862aa63a34d4bece341142c0 100644 (file)
@@ -1433,7 +1433,10 @@ static inline int
 bgp_encode_attr(struct bgp_write_state *s, eattr *a, byte *buf, uint size)
 {
   const union bgp_attr_desc *desc = bgp_find_attr_desc(a);
-  ASSERT_DIE(desc);
+  if (s->ignore_non_bgp_attrs == 0)
+    ASSERT_DIE(desc);
+  else if (desc == NULL)
+    return 0;
   return desc->encode(s, a, buf, size);
 }
 
index e6db1114f62eb0256be1caa33a70c2822062d680..2e38a29a6a45482ff3278da7b9324e47ebc9e3a0 100644 (file)
@@ -513,6 +513,7 @@ struct bgp_write_state {
   int as4_session;
   int add_path;
   int mpls;
+  int ignore_non_bgp_attrs;
 
   eattr *mp_next_hop;
   const adata *mpls_labels;
index 401e2814f66b1cb17a943f056d39b79e11b73188..49d9e71df7061e2585766c4c7b7554182abaaf6f 100644 (file)
@@ -145,7 +145,7 @@ bgp_dump_message(struct bgp_conn *conn, byte *pkt, uint len)
   d.msg_len = len;
   d.add_path = bgp_estimate_add_path(conn->bgp, pkt, len);
 
-  mrt_dump_bgp_message(&d);
+  mrt_dump_bgp_message(&d, conn->bgp->p.pool);
 }
 
 void
@@ -157,7 +157,7 @@ bgp_dump_state_change(struct bgp_conn *conn, uint old, uint new)
   d.old_state = old;
   d.new_state = new;
 
-  mrt_dump_bgp_state_change(&d);
+  mrt_dump_bgp_state_change(&d, conn->bgp->p.pool);
 }
 
 static byte *
index d2136ed16f39bc7038660895174a27014615c689..78a14dd97abb1fff5b93769869c4a1572cdb510a 100644 (file)
@@ -28,6 +28,7 @@ proto: mrt_proto ;
 mrt_proto_start: proto_start MRT
 {
   this_proto = proto_config_new(&proto_mrt, $1);
+  this_proto->loop_order = DOMAIN_ORDER(proto);
 };
 
 mrt_proto_item:
index a1b53adfc0a420b77b7f5eb04661b7919dbc7844..bab2dc30170944434a4e1646d953e544962db1ed 100644 (file)
@@ -38,6 +38,7 @@
  * - RFC 6396 - MRT format standard
  * - RFC 8050 - ADD_PATH extension
  */
+#include <stdio.h>
 
 #include <unistd.h>
 #include <limits.h>
 
 #include "mrt.h"
 
+#include "lib/io-loop.h"
 #include "nest/cli.h"
 #include "filter/filter.h"
 #include "proto/bgp/bgp.h"
 #include "sysdep/unix/unix.h"
+#include "sysdep/unix/io-loop.h"
+#include "conf/conf.h"
 
 
 #ifdef PATH_MAX
@@ -65,6 +69,7 @@
       log(L_ERR "%s: " msg, s->proto->p.name, ## args);                \
   })
 
+extern proto_state_table proto_state_table_pub;
 
 /*
  *     MRT buffer code
@@ -78,6 +83,13 @@ mrt_buffer_init(buffer *b, pool *pool, size_t n)
   b->end = b->start + n;
 }
 
+static void
+mrt_buffer_free(buffer *b)
+{
+  mb_free(b->start);
+  b->start = b->pos = b->end = NULL;
+}
+
 static void
 mrt_buffer_grow(buffer *b, size_t n)
 {
@@ -216,46 +228,6 @@ bstrsub(char *dst, size_t n, const char *src, const char *key, const char *val)
   return 1;
 }
 
-static inline rtable *
-mrt_next_table_(rtable *tab, rtable *tab_ptr, const char *pattern)
-{
-  /* Handle explicit table, return it in the first pass */
-  if (tab_ptr)
-    return !tab ? tab_ptr : NULL;
-
-  /* Walk routing_tables list, starting after tab (if non-NULL) */
-  for (node *tn = tab ? tab->n.next : HEAD(routing_tables);
-       NODE_VALID(tn);
-       tn = tn->next)
-  {
-    tab = SKIP_BACK(rtable, n, tn);
-    if (patmatch(pattern, tab->name) &&
-       ((tab->addr_type == NET_IP4) || (tab->addr_type == NET_IP6)))
-      return tab;
-  }
-
-  return NULL;
-}
-
-static rtable *
-mrt_next_table(struct mrt_table_dump_state *s)
-{
-  rtable *tab = mrt_next_table_(s->table, s->table_ptr, s->table_expr);
-
-  if (s->table)
-    RT_LOCKED(s->table, tab)
-      rt_unlock_table(tab);
-
-  s->table = tab;
-  s->ipv4 = tab ? (tab->addr_type == NET_IP4) : 0;
-
-  if (s->table)
-    RT_LOCKED(s->table, tab)
-      rt_lock_table(tab);
-
-  return s->table;
-}
-
 static int
 mrt_open_file(struct mrt_table_dump_state *s)
 {
@@ -263,15 +235,16 @@ mrt_open_file(struct mrt_table_dump_state *s)
   char name[BIRD_PATH_MAX];
   btime now = current_time();
   btime now_real = current_real_time();
+  rtable *tab = s->table_list[s->table_cur];
 
-  if (!bstrsub(fmt1, sizeof(fmt1), s->filename, "%N", s->table->name) ||
+  if (!bstrsub(fmt1, sizeof(fmt1), s->filename, "%N", tab->name) ||
       !tm_format_real_time(name, sizeof(name), fmt1, now_real))
   {
     mrt_log(s, "Invalid filename '%s'", s->filename);
     return 0;
   }
 
-  s->file = rf_open(s->pool, name, "a");
+  s->file = rf_open(s->pool, name, RF_APPEND, 0);
   if (!s->file)
   {
     mrt_log(s, "Unable to open MRT file '%s': %m", name);
@@ -354,19 +327,33 @@ static void
 mrt_peer_table_dump(struct mrt_table_dump_state *s)
 {
   mrt_init_message(&s->buf, MRT_TABLE_DUMP_V2, MRT_PEER_INDEX_TABLE);
-  mrt_peer_table_header(s, config->router_id, s->table->name);
+  mrt_peer_table_header(s, OBSREF_GET(config)->router_id, s->table_open->name);
 
   /* 0 is fake peer for non-BGP routes */
   mrt_peer_table_entry(s, 0, 0, IPA_NONE);
 
 #ifdef CONFIG_BGP
-  struct proto *P;
-  WALK_LIST(P, proto_list)
-    if ((P->proto == &proto_bgp) && (P->proto_state != PS_DOWN))
+  PST_LOCKED(ts)
+  {
+    for(u32 i = 0; i < ts->length_states; i++)
     {
-      struct bgp_proto *p = (void *) P;
-      mrt_peer_table_entry(s, p->remote_id, p->remote_as, p->remote_ip);
+      ea_list *eal = ts->states[i];
+      if (eal)
+        ea_free_later(ea_ref(eal));
+      else
+        continue;
+
+      struct protocol *type = (struct protocol *)ea_get_ptr(eal, &ea_protocol_type, 0);
+      int state = ea_get_int(eal, &ea_state, 0);
+      if ((type == &proto_bgp) && (state != PS_DOWN))
+      {
+        int rem_id = ea_get_int(eal, &ea_bgp_rem_id, 0);
+        int rem_as = ea_get_int(eal, &ea_bgp_rem_as, 0);
+        ip_addr *rem_ip = (ip_addr *)ea_get_adata(eal, &ea_bgp_rem_ip)->data;
+        mrt_peer_table_entry(s, rem_id, rem_as, *rem_ip);
+      }
     }
+  }
 #endif
 
   /* Fix Peer Count */
@@ -388,7 +375,7 @@ mrt_peer_table_flush(struct mrt_table_dump_state *s)
  */
 
 static void
-mrt_rib_table_header(struct mrt_table_dump_state *s, net_addr *n)
+mrt_rib_table_header(struct mrt_table_dump_state *s, const net_addr *n)
 {
   buffer *b = &s->buf;
 
@@ -432,7 +419,7 @@ mrt_rib_table_entry_bgp_attrs(struct mrt_table_dump_state *s, rte *r)
     return;
 
   /* Attribute list must be normalized for bgp_encode_attrs() */
-  if (!rta_is_cached(r->attrs))
+  if (!r->attrs->stored)
     eattrs = ea_normalize(eattrs, 0);
 
   mrt_buffer_need(b, MRT_ATTR_BUFFER_SIZE);
@@ -440,6 +427,7 @@ mrt_rib_table_entry_bgp_attrs(struct mrt_table_dump_state *s, rte *r)
 
   s->bws->mp_reach = !s->ipv4;
   s->bws->mp_next_hop = NULL;
+  s->bws->ignore_non_bgp_attrs = 1;
 
   /* Encode BGP attributes */
   int len = bgp_encode_attrs(s->bws, eattrs, pos, b->end);
@@ -503,7 +491,7 @@ mrt_rib_table_entry(struct mrt_table_dump_state *s, rte *r)
 }
 
 static void
-mrt_rib_table_dump(struct mrt_table_dump_state *s, net *n, int add_path)
+mrt_rib_table_dump(struct mrt_table_dump_state *s, const struct rt_export_feed *feed, int add_path)
 {
   s->add_path = s->bws->add_path = add_path;
 
@@ -512,23 +500,23 @@ mrt_rib_table_dump(struct mrt_table_dump_state *s, net *n, int add_path)
     (!add_path ? MRT_RIB_IPV6_UNICAST : MRT_RIB_IPV6_UNICAST_ADDPATH);
 
   mrt_init_message(&s->buf, MRT_TABLE_DUMP_V2, subtype);
-  mrt_rib_table_header(s, n->n.addr);
+  mrt_rib_table_header(s, feed->block[0].net);
 
-  for (struct rte_storage *rt, *rt0 = n->routes; rt = rt0; rt0 = rt0->next)
+  for (uint i = 0; i < feed->count_routes; i++)
   {
-    if (rte_is_filtered(&rt->rte))
+    rte *rte = &feed->block[i];
+    if (rte_is_filtered(rte))
       continue;
 
     /* Skip routes that should be reported in the other phase */
-    if (!s->always_add_path && (!rt->rte.src->private_id != !s->add_path))
+    if (!s->always_add_path && (!rte->src->private_id != !s->add_path))
     {
       s->want_add_path = 1;
       continue;
     }
 
-    rte e = rt->rte;
-    if (f_run(s->filter, &e, 0) <= F_ACCEPT)
-      mrt_rib_table_entry(s, &e);
+    if (f_run(s->filter, rte, 0) <= F_ACCEPT)
+      mrt_rib_table_entry(s, rte);
 
     lp_flush(s->linpool);
   }
@@ -547,25 +535,80 @@ mrt_rib_table_dump(struct mrt_table_dump_state *s, net *n, int add_path)
   mrt_dump_message(&s->buf, s->fd);
 }
 
+/*
+ *     MRT Table Dump: table lists
+ */
+
+static uint
+mrt_get_table_list(pool *p, const char *pattern, rtable ***tl)
+{
+  ASSERT_DIE(the_bird_locked());
+
+  rtable *tab;
+  node *n;
+
+  /*
+   * CAVEAT directly accessing tab->priv.deleted; this is safe due to
+   * the_bird_locked(), and this value changes only from the main loop.
+   * But this is a fragile piece of code which may need some rethinking
+   * later on.
+   */
+
+  uint count = 0;
+  WALK_LIST2(tab, n, routing_tables, n)
+    if (!OBSREF_GET(tab->priv.deleted) &&
+       patmatch(pattern, tab->name) &&
+       ((tab->addr_type == NET_IP4) || (tab->addr_type == NET_IP6)))
+      count++;
+
+  *tl = mb_alloc(p, sizeof **tl * count);
+
+  uint pos = 0;
+  WALK_LIST2(tab, n, routing_tables, n)
+    if (!OBSREF_GET(tab->priv.deleted) &&
+       patmatch(pattern, tab->name) &&
+       ((tab->addr_type == NET_IP4) || (tab->addr_type == NET_IP6)))
+    {
+      (*tl)[pos++] = tab;
+      rt_lock_table(tab);
+    }
+
+  ASSERT_DIE(pos == count);
+  return pos;
+}
+
+static void
+mrt_free_table_list(rtable **tl, int len)
+{
+  for (int i=0; i<len; i++)
+    rt_unlock_table(tl[i]);
+
+  mb_free(tl);
+}
+
 
 /*
  *     MRT Table Dump: main logic
  */
 
 static struct mrt_table_dump_state *
-mrt_table_dump_init(pool *pp)
+mrt_table_dump_init(pool *pp, const char *name)
 {
-  pool *pool = rp_new(pp, "MRT Table Dump");
-  struct mrt_table_dump_state *s = mb_allocz(pool, sizeof(struct mrt_table_dump_state));
+  pool *pool = rp_new(pp, pp->domain, "MRT Table Dump");
+  struct mrt_table_dump_state *s = mb_allocz(pool, sizeof *s);
 
   s->pool = pool;
   s->linpool = lp_new(pool);
   s->peer_lp = lp_new(pool);
   mrt_buffer_init(&s->buf, pool, 2 * MRT_ATTR_BUFFER_SIZE);
 
+  s->feeder = (struct rt_export_feeder) {
+    .name = name,
+  };
+
   /* We lock the current config as we may reference it indirectly by filter */
-  s->config = config;
-  config_add_obstacle(s->config);
+
+  OBSREF_SET(s->config, OBSREF_GET(config));
 
   s->fd = -1;
 
@@ -575,28 +618,20 @@ mrt_table_dump_init(pool *pp)
 static void
 mrt_table_dump_free(struct mrt_table_dump_state *s)
 {
-  if (s->table)
-    RT_LOCKED(s->table, tab)
-    {
-      if (s->table_open)
-       FIB_ITERATE_UNLINK(&s->fit, &tab->fib);
-
-      rt_unlock_table(tab);
-    }
-
-  if (s->table_ptr)
-    RT_LOCKED(s->table_ptr, tab)
-      rt_unlock_table(tab);
+  OBSREF_CLEAR(s->config);
 
-  config_del_obstacle(s->config);
+  if (s->table_open)
+    RT_LOCKED(s->table_open, tab)
+      rt_feeder_unsubscribe(&s->feeder);
 
   rp_free(s->pool);
 }
 
 
-static int
-mrt_table_dump_step(struct mrt_table_dump_state *s)
+static void
+mrt_table_dump_step(void *_s)
 {
+  struct mrt_table_dump_state *s = _s;
   struct bgp_write_state bws = { .as4_session = 1 };
 
   s->max = 2048;
@@ -605,49 +640,49 @@ mrt_table_dump_step(struct mrt_table_dump_state *s)
   if (s->table_open)
     goto step;
 
-  while (mrt_next_table(s))
+  while (++s->table_cur < s->table_end)
   {
     if (!mrt_open_file(s))
       continue;
 
-    mrt_peer_table_dump(s);
+    s->table_open = s->table_list[s->table_cur];
+    s->ipv4 = (s->table_open->addr_type == NET_IP4);
 
-    RT_LOCKED(s->table, tab)
-    {
+    mrt_peer_table_dump(s);
 
-    FIB_ITERATE_INIT(&s->fit, &tab->fib);
-    s->table_open = 1;
+    RT_LOCKED(s->table_open, tab)
+      rt_feeder_subscribe(&tab->export_all, &s->feeder);
 
-  step:
-    FIB_ITERATE_START(&tab->fib, &s->fit, net, n)
+  step: ;
+    RT_FEED_WALK(&s->feeder, route_feed)
     {
-      if (s->max < 0)
-      {
-       FIB_ITERATE_PUT(&s->fit);
-       RT_RETURN(tab, 0);
-      }
-
       /* With Always ADD_PATH option, we jump directly to second phase */
       s->want_add_path = s->always_add_path;
 
       if (s->want_add_path == 0)
-       mrt_rib_table_dump(s, n, 0);
+        mrt_rib_table_dump(s, route_feed, 0);
 
       if (s->want_add_path == 1)
-       mrt_rib_table_dump(s, n, 1);
-    }
-    FIB_ITERATE_END;
-    s->table_open = 0;
+        mrt_rib_table_dump(s, route_feed, 1);
 
+      MAYBE_DEFER_TASK(s->target, s->event,
+         "MRT dump %s", s->feeder.name);
     }
 
+    RT_LOCKED(s->table_open, tab)
+      rt_feeder_unsubscribe(&s->feeder);
+
+    s->table_open = NULL;
+
     mrt_close_file(s);
     mrt_peer_table_flush(s);
   }
 
-  return 1;
+  CALL(s->cleanup, s);
 }
 
+static void mrt_proto_dump_done(struct mrt_table_dump_state *s);
+
 static void
 mrt_timer(timer *t)
 {
@@ -662,44 +697,40 @@ mrt_timer(timer *t)
 
   TRACE(D_EVENTS, "RIB table dump started");
 
-  struct mrt_table_dump_state *s = mrt_table_dump_init(p->p.pool);
+  struct mrt_table_dump_state *s = mrt_table_dump_init(p->p.pool, p->p.name);
 
   s->proto = p;
-  s->table_expr = cf->table_expr;
-  s->table_ptr = cf->table_cf ? cf->table_cf->table : NULL;
+  s->table_list = p->table_list;
+  s->table_cur = -1;
+  s->table_end = p->table_list_len;
   s->filter = cf->filter;
   s->filename = cf->filename;
   s->always_add_path = cf->always_add_path;
+  s->cleanup = mrt_proto_dump_done;
 
-  if (s->table_ptr)
-    RT_LOCKED(s->table_ptr, tab)
-      rt_lock_table(tab);
+  s->event = ev_new_init(s->pool, mrt_table_dump_step, s);
+  s->target = proto_work_list(&p->p);
 
   p->table_dump = s;
-  ev_schedule(p->event);
+  ev_send_loop(p->p.loop, s->event);
 }
 
 static void
-mrt_event(void *P)
+mrt_proto_dump_done(struct mrt_table_dump_state *s)
 {
-  struct mrt_proto *p = P;
-
-  if (!p->table_dump)
-    return;
-
-  if (!mrt_table_dump_step(p->table_dump))
-  {
-    ev_schedule(p->event);
-    return;
-  }
+  struct mrt_proto *p = s->proto;
 
+  ASSERT_DIE(p->table_dump == s);
   mrt_table_dump_free(p->table_dump);
   p->table_dump = NULL;
 
   TRACE(D_EVENTS, "RIB table dump done");
 
   if (p->p.proto_state == PS_STOP)
+  {
+    mrt_free_table_list(p->table_list, p->table_list_len);
     proto_notify_state(&p->p, PS_DOWN);
+  }
 }
 
 
@@ -708,24 +739,29 @@ mrt_event(void *P)
  */
 
 static void
-mrt_dump_cont(struct cli *c)
+mrt_cli_dump_done(struct mrt_table_dump_state *s)
 {
-  if (!mrt_table_dump_step(c->rover))
-    return;
+  struct cli *c = s->cli;
+  ASSERT_DIE(c->rover == c);
 
   cli_printf(c, 0, "");
-  mrt_table_dump_free(c->rover);
+  mrt_table_dump_free(s);
   c->cont = NULL;
   c->cleanup = NULL;
   c->rover = NULL;
 }
 
-static int
+static void
+mrt_dump_cont(struct cli *c)
+{
+  return mrt_table_dump_step(c->rover);
+}
+
+void
 mrt_dump_cleanup(struct cli *c)
 {
   mrt_table_dump_free(c->rover);
   c->rover = NULL;
-  return 0;
 }
 
 void
@@ -740,17 +776,33 @@ mrt_dump_cmd(struct mrt_dump_data *d)
   if (!d->filename)
     cf_error("File not specified");
 
-  struct mrt_table_dump_state *s = mrt_table_dump_init(this_cli->pool);
+  struct mrt_table_dump_state *s = mrt_table_dump_init(this_cli->pool, "cli-mrt");
 
   s->cli = this_cli;
-  s->table_expr = d->table_expr;
-  s->table_ptr = d->table_ptr;
+
+  /* Either allocate single-pointer block or a full table list.
+   * We rather allocate the block anyway to make simpler cleanup,
+   * than to resolve corner cases in the end.
+   *
+   * This is the version for MRT requested from CLI */
+  if (d->table_ptr)
+  {
+    s->table_end = 1;
+    s->table_list = mb_allocz(s->pool, sizeof *s->table_list);
+    s->table_list[0] = d->table_ptr;
+    rt_lock_table(s->table_list[0]);
+  }
+  else
+    s->table_end = mrt_get_table_list(s->pool, d->table_expr, &s->table_list);
+
+  s->table_cur = -1;
+
   s->filter = d->filter;
   s->filename = d->filename;
 
-  if (s->table_ptr)
-    RT_LOCKED(s->table_ptr, tab)
-      rt_lock_table(tab);
+  s->event = this_cli->event;
+  s->target = &global_work_list;
+  s->cleanup = mrt_cli_dump_done;
 
   this_cli->cont = mrt_dump_cont;
   this_cli->cleanup = mrt_dump_cleanup;
@@ -763,14 +815,12 @@ mrt_dump_cmd(struct mrt_dump_data *d)
  */
 
 static buffer *
-mrt_bgp_buffer(void)
+mrt_bgp_buffer(pool *p)
 {
   /* Static buffer for BGP4MP dump, TODO: change to use MRT protocol */
-  static buffer b;
-
-  if (!b.start)
-    mrt_buffer_init(&b, &root_pool, 1024);
+  static _Thread_local buffer b;
 
+  mrt_buffer_init(&b, p, 1024);
   return &b;
 }
 
@@ -804,7 +854,7 @@ mrt_bgp_header(buffer *b, struct mrt_bgp_data *d)
 }
 
 void
-mrt_dump_bgp_message(struct mrt_bgp_data *d)
+mrt_dump_bgp_message(struct mrt_bgp_data *d, pool *p)
 {
   const u16 subtypes[] = {
     MRT_BGP4MP_MESSAGE,                        MRT_BGP4MP_MESSAGE_AS4,
@@ -813,15 +863,16 @@ mrt_dump_bgp_message(struct mrt_bgp_data *d)
     MRT_BGP4MP_MESSAGE_LOCAL_ADDPATH,  MRT_BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH,
   };
 
-  buffer *b = mrt_bgp_buffer();
+  buffer *b = mrt_bgp_buffer(p);
   mrt_init_message(b, MRT_BGP4MP, subtypes[d->as4 + 4*d->add_path]);
   mrt_bgp_header(b, d);
   mrt_put_data(b, d->message, d->msg_len);
-  mrt_dump_message(b, config->mrtdump_file);
+  mrt_dump_message(b, rf_fileno(OBSREF_GET(config)->mrtdump_file));
+  mrt_buffer_free(b);
 }
 
 void
-mrt_dump_bgp_state_change(struct mrt_bgp_data *d)
+mrt_dump_bgp_state_change(struct mrt_bgp_data *d, pool *p)
 {
   /* Convert state from our BS_* values to values used in MRTDump */
   const u16 states[BS_MAX] = {1, 2, 3, 4, 5, 6, 1};
@@ -832,12 +883,13 @@ mrt_dump_bgp_state_change(struct mrt_bgp_data *d)
   /* Always use AS4 mode for STATE_CHANGE */
   d->as4 = 1;
 
-  buffer *b = mrt_bgp_buffer();
+  buffer *b = mrt_bgp_buffer(p);
   mrt_init_message(b, MRT_BGP4MP, MRT_BGP4MP_STATE_CHANGE_AS4);
   mrt_bgp_header(b, d);
   mrt_put_u16(b, states[d->old_state]);
   mrt_put_u16(b, states[d->new_state]);
-  mrt_dump_message(b, config->mrtdump_file);
+  mrt_dump_message(b, rf_fileno(OBSREF_GET(config)->mrtdump_file));
+  mrt_buffer_free(b);
 }
 
 
@@ -853,6 +905,9 @@ mrt_check_config(struct proto_config *CF)
   if (!cf->table_expr && !cf->table_cf)
     cf_error("Table not specified");
 
+  if (cf->table_expr && cf->table_cf)
+    cf_error("Clashing table specifiers");
+
   if (!cf->filename)
     cf_error("File not specified");
 
@@ -860,6 +915,25 @@ mrt_check_config(struct proto_config *CF)
     cf_error("Period not specified");
 }
 
+static void
+mrt_proto_get_table_list(struct mrt_proto *p, struct mrt_config *cf)
+{
+  /* Either allocate single-pointer block or a full table list.
+   * We rather allocate the block anyway to make simpler cleanup,
+   * than to resolve corner cases in the end.
+   *
+   * This is the version for MRT (pseudo)protocol */
+  if (cf->table_cf)
+  {
+    p->table_list_len = 1;
+    p->table_list = mb_allocz(p->p.pool, sizeof *p->table_list);
+    p->table_list[0] = cf->table_cf->table;
+    rt_lock_table(p->table_list[0]);
+  }
+  else
+    p->table_list_len = mrt_get_table_list(p->p.pool, cf->table_expr, &p->table_list);
+}
+
 static struct proto *
 mrt_init(struct proto_config *CF)
 {
@@ -875,9 +949,10 @@ mrt_start(struct proto *P)
   struct mrt_config *cf = (void *) (P->cf);
 
   p->timer = tm_new_init(P->pool, mrt_timer, p, cf->period S, 0);
-  p->event = ev_new_init(P->pool, mrt_event, p);
 
-  tm_start(p->timer, cf->period S);
+  tm_start_in(p->timer, cf->period S, p->p.loop);
+
+  mrt_proto_get_table_list(p, cf);
 
   return PS_UP;
 }
@@ -887,7 +962,11 @@ mrt_shutdown(struct proto *P)
 {
   struct mrt_proto *p = (void *) P;
 
-  return p->table_dump ? PS_STOP : PS_DOWN;
+  if (p->table_dump)
+    return PS_STOP;
+
+  mrt_free_table_list(p->table_list, p->table_list_len);
+  return PS_DOWN;
 }
 
 static int
@@ -904,9 +983,14 @@ mrt_reconfigure(struct proto *P, struct proto_config *CF)
     btime now = current_time();
     btime new_time = p->timer->expires - (old->period S) + (new->period S);
     p->timer->recurrent = new->period S;
-    tm_set(p->timer, MAX(now, new_time));
+    tm_set_in(p->timer, MAX(now, new_time), p->p.loop);
   }
 
+  if (!p->table_dump)
+    mrt_free_table_list(p->table_list, p->table_list_len);
+
+  mrt_proto_get_table_list(p, new);
+
   return 1;
 }
 
index 04865089d70688f496ae2e1b481b35896c8f0c01..b256ca9e9737832ed55db8c30eef2c33b6076c6d 100644 (file)
@@ -36,6 +36,9 @@ struct mrt_proto {
 
   struct mrt_target *file;
   struct mrt_table_dump_state *table_dump;
+
+  rtable **table_list;
+  int table_list_len;
 };
 
 struct mrt_dump_data {
@@ -56,11 +59,10 @@ struct mrt_peer_entry {
 struct mrt_table_dump_state {
   struct mrt_proto *proto;             /* Protocol for regular MRT dumps (or NULL) */
   struct cli *cli;                     /* CLI for irregular MRT dumps (or NULL) */
-  struct config *config;               /* Config valid during start of dump, locked */
+  config_ref config;           /* Config valid during start of dump, locked */
 
                                        /* Configuration information */
-  const char *table_expr;              /* Wildcard for table name (or NULL) */
-  rtable *table_ptr;                   /* Explicit table (or NULL) */
+  struct rt_export_feeder feeder;      /* Table feeder */
   const struct filter *filter;         /* Optional filter */
   const char *filename;                        /* Filename pattern */
   int always_add_path;                 /* Always use *_ADDPATH message subtypes */
@@ -73,9 +75,9 @@ struct mrt_table_dump_state {
 
   HASH(struct mrt_peer_entry) peer_hash; /* Hash for peers to find the index */
 
-  rtable *table;                       /* Processed table, NULL initially */
-  struct fib_iterator fit;             /* Iterator in processed table */
-  int table_open;                      /* Whether iterator is linked */
+  rtable **table_list;                 /* List of tables to process */
+  int table_cur, table_end;            /* Table list iterator */
+  rtable *table_open;                  /* Table to which the iterator is linked */
 
   int ipv4;                            /* Processed table is IPv4 */
   int add_path;                                /* Current message subtype is *_ADDPATH */
@@ -92,6 +94,11 @@ struct mrt_table_dump_state {
 
   struct rfile *file;                  /* tracking for mrt table dump file */
   int fd;
+
+  event *event;                                /* defer event */
+  event_list *target;                  /* defer target */
+
+  void (*cleanup)(struct mrt_table_dump_state *);      /* call when done */
 };
 
 struct mrt_bgp_data {
@@ -147,12 +154,12 @@ struct mrt_bgp_data {
 
 #ifdef CONFIG_MRT
 void mrt_dump_cmd(struct mrt_dump_data *d);
-void mrt_dump_bgp_message(struct mrt_bgp_data *d);
-void mrt_dump_bgp_state_change(struct mrt_bgp_data *d);
+void mrt_dump_bgp_message(struct mrt_bgp_data *d, pool *p);
+void mrt_dump_bgp_state_change(struct mrt_bgp_data *d, pool *p);
 void mrt_check_config(struct proto_config *C);
 #else
-static inline void mrt_dump_bgp_message(struct mrt_bgp_data *d UNUSED) { }
-static inline void mrt_dump_bgp_state_change(struct mrt_bgp_data *d UNUSED) { }
+static inline void mrt_dump_bgp_message(struct mrt_bgp_data *d UNUSED, pool *p UNUSED) { }
+static inline void mrt_dump_bgp_state_change(struct mrt_bgp_data *d UNUSED, pool *p UNUSED) { }
 #endif
 
 #endif /* _BIRD_MRT_H_ */
index 892044c5df047c31ae58a755ef582230735ac5d1..51de4a7807a21da81ff8c1a8a4860d7ce009ce9f 100644 (file)
@@ -106,6 +106,12 @@ static struct resclass rf_class = {
   NULL
 };
 
+int
+rf_fileno(struct rfile *f)
+{
+  return f->fd;
+}
+
 static int
 rf_open_get_fd(const char *name, enum rf_mode mode)
 {
index 5e2144e41fca2d7ed4dbcc7adbfdbe017cf78c12..e7c4c143649b0eb8ca56f9d1a3e7c9e2e7636487 100644 (file)
@@ -126,6 +126,7 @@ off_t rf_size(struct rfile *);
 int rf_same(struct rfile *, struct rfile *);
 int rf_writev(struct rfile *, struct iovec *, int);
 void rf_write_crude(struct rfile *, const char *, int);
+int rf_fileno(struct rfile *f);
 
 extern struct rfile rf_stderr;