]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Kernel protocol now uses out_table resync mechanism for periodic scanning
authorMaria Matejka <mq@ucw.cz>
Tue, 23 Feb 2021 22:54:13 +0000 (23:54 +0100)
committerMaria Matejka <mq@ucw.cz>
Sat, 20 Mar 2021 23:28:17 +0000 (00:28 +0100)
nest/proto.c
nest/protocol.h
nest/route.h
nest/rt-table.c
sysdep/unix/krt.c
sysdep/unix/krt.h

index 2ffb897c75cd07e93031bf63795204ecbf2a76b6..945524a1d3545812cc7a8cfaa80703423c1df037 100644 (file)
@@ -542,8 +542,12 @@ channel_reset_import(struct channel *c)
 static void
 channel_reset_export(struct channel *c)
 {
+  if (c->out_flush_refeed)
+    rt_out_flush(c);
+
   /* Just free the routes */
   rt_prune_sync(c->out_table, 1);
+  bmap_reset(&c->out_seen_map, 1024);
 }
 
 /* Called by protocol to activate in_table */
@@ -584,6 +588,10 @@ channel_do_start(struct channel *c)
 
   bmap_init(&c->export_map, c->proto->pool, 1024);
   bmap_init(&c->export_reject_map, c->proto->pool, 1024);
+
+  if (c->out_table)
+    bmap_init(&c->out_seen_map, c->proto->pool, 1024);
+
   memset(&c->stats, 0, sizeof(struct proto_stats));
 
   channel_reset_limit(&c->rx_limit);
@@ -618,6 +626,8 @@ channel_do_flush(struct channel *c)
   /* This have to be done in here, as channel pool is freed before channel_do_down() */
   bmap_free(&c->export_map);
   bmap_free(&c->export_reject_map);
+  if (c->out_table)
+    bmap_free(&c->out_seen_map);
   c->in_table = NULL;
   c->reload_event = NULL;
   c->out_table = NULL;
index cb368ac315336697ff65af28efee1ac067cd1966..fd7d532dd040bf4b09d26de8654bcdb7f26c7dc1 100644 (file)
@@ -509,6 +509,7 @@ struct channel {
   const struct filter *out_filter;     /* Output filter */
   struct bmap export_map;              /* Keeps track which routes were really exported */
   struct bmap export_reject_map;       /* Keeps track which routes were rejected by export filter */
+  struct bmap out_seen_map;            /* Keeps track which routes have been seen by out_sync */
   struct channel_limit rx_limit;       /* Receive limit (for in_keep_filtered) */
   struct channel_limit in_limit;       /* Input limit */
   struct channel_limit out_limit;      /* Output limit */
@@ -546,6 +547,7 @@ struct channel {
   u8 reload_pending;                   /* Reloading and another reload is scheduled */
   u8 refeed_pending;                   /* Refeeding and another refeed is scheduled */
   u8 rpki_reload;                      /* RPKI changes trigger channel reload */
+  u8 out_flush_refeed;                 /* Feed by withdrawals on export reset */
 
   list net_feed;                       /* Active net feeders (struct channel_net_feed) */
 
index 41765638a29cd9b99da1deea406a688f72995af6..d89b2f59a0961a21a2c378481304e19d60032b67 100644 (file)
@@ -367,8 +367,12 @@ void rt_feed_channel_abort(struct channel *c);
 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, rte *new, rte *old, struct rte_storage **old_stored, int refeed);
+int rte_update_out(struct channel *c, rte *new, rte *old, struct rte_storage **old_stored, u32 id, int refeed);
 struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
+void rt_out_sync_start(struct channel *c);
+_Bool rt_out_sync_mark(struct channel *c, struct rte_export *e);
+void rt_out_sync_finish(struct channel *c);
+void rt_out_flush(struct channel *c);
 
 
 /* Default limit for ECMP next hops, defined in sysdep code */
index d5f0582278970a499c5a76aaff3d4d1f1fa48841..3c868f99f3dfdc489292f43c8af7aca970cf065d 100644 (file)
@@ -691,7 +691,7 @@ rt_notify_merged(struct channel *c, struct rte_export_internal *e)
   /* Prepare new merged route */
   if (e->new_best)
   {
-    ep->new_id = e->new->id;
+    ep->new_id = e->new_best->id;
     if (!rt_export_merged(c, e->net, &ep->new, rte_update_pool, 0))
       ep->new.attrs = NULL;
   }
@@ -774,7 +774,7 @@ rte_export_store(struct channel *c, struct rte_export_internal *e)
   /* Apply export table */
   if (c->out_table)
   {
-    if (!rte_update_out(c, &(e->pub.new), &(e->pub.old), &(e->old_stored), e->refeed))
+    if (!rte_update_out(c, &(e->pub.new), &(e->pub.old), &(e->old_stored), e->pub.new_id, e->refeed))
       return 0;
   }
   else if (c->out_filter != FILTER_ACCEPT)
@@ -2471,7 +2471,7 @@ rt_prune_sync(rtable *t, int all)
  */
 
 int
-rte_update_out(struct channel *c, rte *new, rte *old, struct rte_storage **old_stored, int refeed)
+rte_update_out(struct channel *c, rte *new, rte *old, struct rte_storage **old_stored, u32 id, int refeed)
 {
   struct rtable *tab = c->out_table;
   struct rte_storage **pos;
@@ -2533,6 +2533,7 @@ rte_update_out(struct channel *c, rte *new, rte *old, struct rte_storage **old_s
   struct rte_storage *e = rte_store(new, net);
   e->sender = c;
   e->lastmod = current_time();
+  e->id = id;
   e->next = *pos;
   *pos = e;
   tab->rt_count++;
@@ -2545,6 +2546,79 @@ drop_withdraw:
   return 0;
 }
 
+void
+rt_out_sync_start(struct channel *c)
+{
+  ASSERT_DIE(c->out_table);
+  ASSERT_DIE(c->ra_mode != RA_ANY);
+  bmap_reset(&c->out_seen_map, 1024);
+}
+
+_Bool
+rt_out_sync_mark(struct channel *c, struct rte_export *e)
+{
+  ASSERT_DIE(c->out_table);
+  ASSERT_DIE(c->ra_mode != RA_ANY);
+
+  net *n = net_find(c->out_table, e->old.net);
+  if (!n || !n->routes)
+    return 1;
+
+  e->new = rte_copy(n->routes);
+  e->new_id = n->routes->id;
+
+  if (bmap_test(&c->out_seen_map, n->routes->id))
+    return 0;
+
+  bmap_set(&c->out_seen_map, n->routes->id);
+  return 1;
+}
+
+void
+rt_out_sync_finish(struct channel *c)
+{
+  ASSERT_DIE(c->out_table);
+  ASSERT_DIE(c->ra_mode != RA_ANY);
+
+  FIB_WALK(&c->out_table->fib, net, n)
+  {
+    if (!n->routes)
+      continue;
+
+    if (!bmap_test(&c->out_seen_map, n->routes->id))
+    {
+      struct rte_export ex = {
+       .new_id = n->routes->id,
+       .new = rte_copy(n->routes),
+      };
+
+      c->proto->rt_notify(c, &ex);
+    }
+  }
+  FIB_WALK_END;
+  bmap_reset(&c->out_seen_map, 1024);
+}
+
+void
+rt_out_flush(struct channel *c)
+{
+  ASSERT_DIE(c->out_table);
+  ASSERT_DIE(c->ra_mode != RA_ANY);
+
+  FIB_WALK(&c->out_table->fib, net, n)
+  {
+    if (!n->routes)
+      continue;
+
+    struct rte_export ex = {
+      .old_id = n->routes->id,
+      .old = rte_copy(n->routes),
+    };
+
+    c->proto->rt_notify(c, &ex);
+  }
+  FIB_WALK_END;
+}
 
 /*
  *     Hostcache
index c4c74e13c53b68d202b369be7df0ad151163be98..38d874441a37aa7f7fefae1487cc79a7ff262e71 100644 (file)
  */
 
 pool *krt_pool;
-static linpool *krt_filter_lp;
 static list krt_proto_list;
 
 void
 krt_io_init(void)
 {
   krt_pool = rp_new(&root_pool, "Kernel Syncer");
-  krt_filter_lp = lp_new_default(krt_pool);
   init_list(&krt_proto_list);
   krt_sys_io_init();
 }
@@ -538,61 +536,6 @@ krt_dump(struct proto *P)
  *     Routes
  */
 
-static inline int
-krt_is_installed(struct krt_proto *p, net *n)
-{
-  return n->routes && bmap_test(&p->p.main_channel->export_map, n->routes->id);
-}
-
-static void
-krt_flush_routes(struct krt_proto *p)
-{
-  struct rtable *t = p->p.main_channel->table;
-
-  KRT_TRACE(p, D_EVENTS, "Flushing kernel routes");
-  FIB_WALK(&t->fib, net, n)
-    {
-      if (krt_is_installed(p, n))
-       {
-         struct rte_export e = {
-           .old = rte_copy(n->routes),
-           .old_id = n->routes->id,
-         };
-
-         /* FIXME: this does not work if gw is changed in export filter */
-         krt_replace_rte(p, &e);
-       }
-    }
-  FIB_WALK_END;
-}
-
-static _Bool
-krt_export_net(struct krt_proto *p, net *net, rte *rt)
-{
-  struct channel *c = p->p.main_channel;
-  const struct filter *filter = c->out_filter;
-
-  if (c->ra_mode == RA_MERGED)
-    return rt_export_merged(c, net, rt, krt_filter_lp, 1);
-
-  if (!rte_is_valid(net->routes))
-    return 0;
-
-  if (filter == FILTER_REJECT)
-    return 0;
-
-  /* We could run krt_preexport() here, but it is already handled by krt_is_installed() */
-  *rt = rte_copy(net->routes);
-
-  if (filter == FILTER_ACCEPT)
-    return 1;
-
-  if (f_run(filter, rt, krt_filter_lp, FF_SILENT) > F_ACCEPT)
-    return 0;
-
-  return 1;
-}
-
 static int
 krt_same_dest(rte *k, rte *e)
 {
@@ -644,24 +587,14 @@ krt_got_route(struct krt_proto *p, rte *e, s8 src)
   if (!p->ready)
     goto ignore;
 
-  net *n = net_find(p->p.main_channel->table, e->net);
-
-  if (!n || !krt_is_installed(p, n))
-    goto delete;
-
-  /* Rejected by filters */
-  if (!krt_export_net(p, n, &ex.new))
-    goto delete;
-
-  /* Route to this destination was already seen. Strange, but it happens... */
-  if (bmap_test(&p->seen_map, n->routes->id))
+  if (!rt_out_sync_mark(p->p.main_channel, &ex))
     goto aseen;
 
-  /* Mark route as seen */
-  bmap_set(&p->seen_map, n->routes->id);
+  if (!ex.new.attrs)
+    goto delete;
 
   /* TODO: There also may be changes in route eattrs, we ignore that for now. */
-  if (!bmap_test(&p->sync_map, n->routes->id) || !krt_same_dest(e, &ex.new))
+  if (!bmap_test(&p->sync_map, ex.new_id) || !krt_same_dest(e, &ex.new))
     goto update;
 
   goto seen;
@@ -680,7 +613,6 @@ ignore:
 
 update:
   krt_trace_in(p, &ex.new, "updating");
-  ex.new_id = n->routes->id;
   krt_replace_rte(p, &ex);
   goto done;
 
@@ -690,39 +622,23 @@ delete:
   goto done;
 
 done:
-  lp_flush(krt_filter_lp);
+  return;
 }
 
 static void
 krt_init_scan(struct krt_proto *p)
 {
-  bmap_reset(&p->seen_map, 1024);
+  rt_out_sync_start(p->p.main_channel);
 }
 
 static void
 krt_prune(struct krt_proto *p)
 {
-  struct rtable *t = p->p.main_channel->table;
-
-  KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
-  FIB_WALK(&t->fib, net, n)
-  {
-    if (p->ready && krt_is_installed(p, n) && !bmap_test(&p->seen_map, n->routes->id))
-    {
-      struct rte_export ex = {
-       .new_id = n->routes->id
-      };
+  KRT_TRACE(p, D_EVENTS, "Sync finished, pruning table %s", p->p.main_channel->table->name);
 
-      if (krt_export_net(p, n, &ex.new))
-      {
-       krt_trace_in(p, &ex.new, "installing");
-       krt_replace_rte(p, &ex);
-      }
-
-      lp_flush(krt_filter_lp);
-    }
-  }
-  FIB_WALK_END;
+  p->pruning = 1;
+  rt_out_sync_finish(p->p.main_channel);
+  p->pruning = 0;
 
 #ifdef KRT_ALLOW_LEARN
   if (KRT_CF->learn)
@@ -897,7 +813,7 @@ krt_rt_notify(struct channel *ch, struct rte_export *e)
     return;
 #endif
 
-  if (p->initialized)          /* Before first scan we don't touch the routes */
+  if (p->initialized || p->ready && p->pruning)                /* Before first scan we don't touch the routes */
     krt_replace_rte(p, e);
 }
 
@@ -994,6 +910,7 @@ krt_init(struct proto_config *CF)
   // struct krt_config *cf = (void *) CF;
 
   p->p.main_channel = proto_add_channel(&p->p, proto_cf_main_channel(CF));
+  p->p.main_channel->out_flush_refeed = 1;
 
   p->p.preexport = krt_preexport;
   p->p.rt_notify = krt_rt_notify;
@@ -1022,12 +939,11 @@ krt_start(struct proto *P)
   }
 
   /* If it is needed, setup out table automagically */
-  if (!TRIVIAL_FILTER(p->p.main_channel->out_filter))
+  /* For now, setup out table always. 
+  if (!TRIVIAL_FILTER(p->p.main_channel->out_filter)) */
     channel_setup_out_table(p->p.main_channel);
 
-
   bmap_init(&p->sync_map, p->p.pool, 1024);
-  bmap_init(&p->seen_map, p->p.pool, 1024);
   add_tail(&krt_proto_list, &p->krt_node);
 
 #ifdef KRT_ALLOW_LEARN
@@ -1057,7 +973,7 @@ krt_shutdown(struct proto *P)
 
   /* FIXME we should flush routes even when persist during reconfiguration */
   if (p->initialized && !KRT_CF->persist && (P->down_code != PDC_CMD_GR_DOWN))
-    krt_flush_routes(p);
+    rt_out_flush(p->p.main_channel);
 
   p->ready = 0;
   p->initialized = 0;
@@ -1073,12 +989,9 @@ krt_shutdown(struct proto *P)
 }
 
 static int
-krt_channel_reconfigure(struct channel *C, struct channel_config *CC, int *import_changed UNUSED, int *export_changed)
+krt_channel_reconfigure(struct channel *C UNUSED, struct channel_config *CC UNUSED, int *import_changed UNUSED, int *export_changed)
 {
-  if (!*export_changed)
-    return 1;
-
-  return (TRIVIAL_FILTER(C->out_filter) == TRIVIAL_FILTER(CC->out_filter));
+  return !*export_changed;
 }
 
 static int
index a0c60d8024add0f051182f2fe07d1bb7fccce372..bdb5af7c3575d77d4581e0bf7585fafe923dc24a 100644 (file)
@@ -60,11 +60,11 @@ struct krt_proto {
 #endif
 
   struct bmap sync_map;                /* Keeps track which exported routes were successfully written to kernel */
-  struct bmap seen_map;                /* Routes seen during last periodic scan */
   node krt_node;               /* Node in krt_proto_list */
   byte af;                     /* Kernel address family (AF_*) */
   byte ready;                  /* Initial feed has been finished */
   byte initialized;            /* First scan has been finished */
+  byte pruning;                        /* Pruning */
   byte reload;                 /* Next scan is doing reload */
 };