summaryrefslogtreecommitdiff
path: root/nest/rt-table.c
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2014-03-24 12:41:43 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2014-03-24 12:41:43 +0100
commitc980f8002e0f0578d5e715d48d65d9fb9a0c5a70 (patch)
treef1d3be6b0992c7cb0be3694229ffb42dc740ae91 /nest/rt-table.c
parent2e84b4e82dbf8fce0fd12fb0c25d925ffd287970 (diff)
parent227af309e55a59f14d1a5a757f17900164bffc97 (diff)
Merge branch 'bgp-grace'
Diffstat (limited to 'nest/rt-table.c')
-rw-r--r--nest/rt-table.c153
1 files changed, 126 insertions, 27 deletions
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 8c91ea0a..4295f836 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -55,8 +55,10 @@ static void rt_free_hostcache(rtable *tab);
static void rt_notify_hostcache(rtable *tab, net *net);
static void rt_update_hostcache(rtable *tab);
static void rt_next_hop_update(rtable *tab);
-
+static inline int rt_prune_table(rtable *tab);
static inline void rt_schedule_gc(rtable *tab);
+static inline void rt_schedule_prune(rtable *tab);
+
static inline struct ea_list *
make_tmp_attrs(struct rte *rt, struct linpool *pool)
@@ -570,7 +572,7 @@ rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old, rte *befo
struct announce_hook *a;
WALK_LIST(a, tab->hooks)
{
- ASSERT(a->proto->core_state == FS_HAPPY || a->proto->core_state == FS_FEEDING);
+ ASSERT(a->proto->export_state != ES_DOWN);
if (a->proto->accept_ra_types == type)
if (type == RA_ACCEPTED)
rt_notify_accepted(a, net, new, old, before_old, tmpa, 0);
@@ -1108,6 +1110,69 @@ rt_examine(rtable *t, ip_addr prefix, int pxlen, struct proto *p, struct filter
return v > 0;
}
+
+/**
+ * rt_refresh_begin - start a refresh cycle
+ * @t: related routing table
+ * @ah: related announce hook
+ *
+ * This function starts a refresh cycle for given routing table and announce
+ * hook. The refresh cycle is a sequence where the protocol sends all its valid
+ * routes to the routing table (by rte_update()). After that, all protocol
+ * routes (more precisely routes with @ah as @sender) not sent during the
+ * refresh cycle but still in the table from the past are pruned. This is
+ * implemented by marking all related routes as stale by REF_STALE flag in
+ * rt_refresh_begin(), then marking all related stale routes with REF_DISCARD
+ * flag in rt_refresh_end() and then removing such routes in the prune loop.
+ */
+void
+rt_refresh_begin(rtable *t, struct announce_hook *ah)
+{
+ net *n;
+ rte *e;
+
+ FIB_WALK(&t->fib, fn)
+ {
+ n = (net *) fn;
+ for (e = n->routes; e; e = e->next)
+ if (e->sender == ah)
+ e->flags |= REF_STALE;
+ }
+ FIB_WALK_END;
+}
+
+/**
+ * rt_refresh_end - end a refresh cycle
+ * @t: related routing table
+ * @ah: related announce hook
+ *
+ * This function starts a refresh cycle for given routing table and announce
+ * hook. See rt_refresh_begin() for description of refresh cycles.
+ */
+void
+rt_refresh_end(rtable *t, struct announce_hook *ah)
+{
+ int prune = 0;
+ net *n;
+ rte *e;
+
+ FIB_WALK(&t->fib, fn)
+ {
+ n = (net *) fn;
+ for (e = n->routes; e; e = e->next)
+ if ((e->sender == ah) && (e->flags & REF_STALE))
+ {
+ e->flags |= REF_DISCARD;
+ prune = 1;
+ }
+ }
+ FIB_WALK_END;
+
+ if (prune)
+ rt_schedule_prune(t);
+}
+
+
/**
* rte_dump - dump a route
* @e: &rte to be dumped
@@ -1170,6 +1235,13 @@ rt_dump_all(void)
}
static inline void
+rt_schedule_prune(rtable *tab)
+{
+ rt_mark_for_prune(tab);
+ ev_schedule(tab->rt_event);
+}
+
+static inline void
rt_schedule_gc(rtable *tab)
{
if (tab->gc_scheduled)
@@ -1199,6 +1271,7 @@ rt_schedule_nhu(rtable *tab)
tab->nhu_state |= 1;
}
+
static void
rt_prune_nets(rtable *tab)
{
@@ -1242,6 +1315,14 @@ rt_event(void *ptr)
if (tab->nhu_state)
rt_next_hop_update(tab);
+ if (tab->prune_state)
+ if (!rt_prune_table(tab))
+ {
+ /* Table prune unfinished */
+ ev_schedule(tab->rt_event);
+ return;
+ }
+
if (tab->gc_scheduled)
{
rt_prune_nets(tab);
@@ -1283,8 +1364,8 @@ rt_init(void)
}
-static inline int
-rt_prune_step(rtable *tab, int step, int *max_feed)
+static int
+rt_prune_step(rtable *tab, int step, int *limit)
{
static struct rate_limit rl_flush;
struct fib_iterator *fit = &tab->prune_fit;
@@ -1294,13 +1375,13 @@ rt_prune_step(rtable *tab, int step, int *max_feed)
fib_check(&tab->fib);
#endif
- if (tab->prune_state == 0)
+ if (tab->prune_state == RPS_NONE)
return 1;
- if (tab->prune_state == 1)
+ if (tab->prune_state == RPS_SCHEDULED)
{
FIB_ITERATE_INIT(fit, &tab->fib);
- tab->prune_state = 2;
+ tab->prune_state = RPS_RUNNING;
}
again:
@@ -1312,9 +1393,10 @@ again:
rescan:
for (e=n->routes; e; e=e->next)
if (e->sender->proto->flushing ||
+ (e->flags & REF_DISCARD) ||
(step && e->attrs->src->proto->flushing))
{
- if (*max_feed <= 0)
+ if (*limit <= 0)
{
FIB_ITERATE_PUT(fit, fn);
return 0;
@@ -1325,7 +1407,7 @@ again:
n->n.prefix, n->n.pxlen, e->attrs->src->proto->name, tab->name);
rte_discard(tab, e);
- (*max_feed)--;
+ (*limit)--;
goto rescan;
}
@@ -1342,41 +1424,60 @@ again:
fib_check(&tab->fib);
#endif
- tab->prune_state = 0;
+ tab->prune_state = RPS_NONE;
return 1;
}
/**
+ * rt_prune_table - prune a routing table
+ *
+ * This function scans the routing table @tab and removes routes belonging to
+ * flushing protocols, discarded routes and also stale network entries, in a
+ * similar fashion like rt_prune_loop(). Returns 1 when all such routes are
+ * pruned. Contrary to rt_prune_loop(), this function is not a part of the
+ * protocol flushing loop, but it is called from rt_event() for just one routing
+ * table.
+ *
+ * Note that rt_prune_table() and rt_prune_loop() share (for each table) the
+ * prune state (@prune_state) and also the pruning iterator (@prune_fit).
+ */
+static inline int
+rt_prune_table(rtable *tab)
+{
+ int limit = 512;
+ return rt_prune_step(tab, 0, &limit);
+}
+
+/**
* rt_prune_loop - prune routing tables
*
- * The prune loop scans routing tables and removes routes belonging to
- * flushing protocols and also stale network entries. Returns 1 when
- * all such routes are pruned. It is a part of the protocol flushing
- * loop.
+ * The prune loop scans routing tables and removes routes belonging to flushing
+ * protocols, discarded routes and also stale network entries. Returns 1 when
+ * all such routes are pruned. It is a part of the protocol flushing loop.
*
- * The prune loop runs in two steps. In the first step it prunes just
- * the routes with flushing senders (in explicitly marked tables) so
- * the route removal is propagated as usual. In the second step, all
- * remaining relevant routes are removed. Ideally, there shouldn't be
- * any, but it happens when pipe filters are changed.
+ * The prune loop runs in two steps. In the first step it prunes just the routes
+ * with flushing senders (in explicitly marked tables) so the route removal is
+ * propagated as usual. In the second step, all remaining relevant routes are
+ * removed. Ideally, there shouldn't be any, but it happens when pipe filters
+ * are changed.
*/
int
rt_prune_loop(void)
{
static int step = 0;
- int max_feed = 512;
+ int limit = 512;
rtable *t;
again:
WALK_LIST(t, routing_tables)
- if (! rt_prune_step(t, step, &max_feed))
+ if (! rt_prune_step(t, step, &limit))
return 0;
if (step == 0)
{
/* Prepare for the second step */
WALK_LIST(t, routing_tables)
- t->prune_state = 1;
+ t->prune_state = RPS_SCHEDULED;
step = 1;
goto again;
@@ -1721,7 +1822,7 @@ again:
(p->accept_ra_types == RA_ACCEPTED))
if (rte_is_valid(e))
{
- if (p->core_state != FS_FEEDING)
+ if (p->export_state != ES_FEEDING)
return 1; /* In the meantime, the protocol fell down. */
do_feed_baby(p, p->accept_ra_types, h, n, e);
max_feed--;
@@ -1730,7 +1831,7 @@ again:
if (p->accept_ra_types == RA_ANY)
for(e = n->routes; rte_is_valid(e); e = e->next)
{
- if (p->core_state != FS_FEEDING)
+ if (p->export_state != ES_FEEDING)
return 1; /* In the meantime, the protocol fell down. */
do_feed_baby(p, RA_ANY, h, n, e);
max_feed--;
@@ -2223,9 +2324,7 @@ rt_show_cont(struct cli *c)
cli_printf(c, 8004, "Stopped due to reconfiguration");
goto done;
}
- if (d->export_protocol &&
- d->export_protocol->core_state != FS_HAPPY &&
- d->export_protocol->core_state != FS_FEEDING)
+ if (d->export_protocol && (d->export_protocol->export_state == ES_DOWN))
{
cli_printf(c, 8005, "Protocol is down");
goto done;