diff options
Diffstat (limited to 'nest')
-rw-r--r-- | nest/protocol.h | 1 | ||||
-rw-r--r-- | nest/route.h | 3 | ||||
-rw-r--r-- | nest/rt-table.c | 59 |
3 files changed, 63 insertions, 0 deletions
diff --git a/nest/protocol.h b/nest/protocol.h index f0b65598..343ce523 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -229,6 +229,7 @@ struct proto { int (*rte_better)(struct rte *, struct rte *); int (*rte_same)(struct rte *, struct rte *); int (*rte_mergable)(struct rte *, struct rte *); + struct rte * (*rte_modify)(struct rte *, struct linpool *); void (*rte_insert)(struct network *, struct rte *); void (*rte_remove)(struct network *, struct rte *); diff --git a/nest/route.h b/nest/route.h index cad15440..2ec1dc7f 100644 --- a/nest/route.h +++ b/nest/route.h @@ -231,6 +231,7 @@ typedef struct rte { #ifdef CONFIG_BGP struct { u8 suppressed; /* Used for deterministic MED comparison */ + s8 stale; /* Route is LLGR_STALE, -1 if unknown */ } bgp; #endif #ifdef CONFIG_BABEL @@ -254,6 +255,7 @@ typedef struct rte { #define REF_FILTERED 2 /* Route is rejected by import filter */ #define REF_STALE 4 /* Route is stale in a refresh cycle */ #define REF_DISCARD 8 /* Route is scheduled for discard */ +#define REF_MODIFY 16 /* Route is scheduled for modify */ /* Route is valid for propagation (may depend on other flags in the future), accepts NULL */ static inline int rte_is_valid(rte *r) { return r && !(r->flags & REF_FILTERED); } @@ -297,6 +299,7 @@ int rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter); rte *rt_export_merged(struct channel *c, net *net, rte **rt_free, 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); void rt_schedule_prune(rtable *t); void rte_dump(rte *); void rte_free(rte *); diff --git a/nest/rt-table.c b/nest/rt-table.c index 9dcbda05..036b34c4 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1437,6 +1437,28 @@ rte_discard(rte *old) /* Non-filtered route deletion, used during garbage collec rte_update_unlock(); } +/* Modify existing route by protocol hook, used for long-lived graceful restart */ +static inline void +rte_modify(rte *old) +{ + rte_update_lock(); + + rte *new = old->sender->proto->rte_modify(old, rte_update_pool); + if (new != old) + { + if (new) + { + if (!rta_is_cached(new->attrs)) + new->attrs = rta_lookup(new->attrs); + new->flags = (old->flags & ~REF_MODIFY) | REF_COW; + } + + rte_recalculate(old->sender, old->net, new, old->attrs->src); + } + + rte_update_unlock(); +} + /* Check rtable for best route to given net whether it would be exported do p */ int rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter) @@ -1521,6 +1543,26 @@ rt_refresh_end(rtable *t, struct channel *c) rt_schedule_prune(t); } +void +rt_modify_stale(rtable *t, struct channel *c) +{ + int prune = 0; + + FIB_WALK(&t->fib, net, n) + { + rte *e; + for (e = n->routes; e; e = e->next) + if ((e->sender == c) && (e->flags & REF_STALE) && !(e->flags & REF_FILTERED)) + { + e->flags |= REF_MODIFY; + prune = 1; + } + } + FIB_WALK_END; + + if (prune) + rt_schedule_prune(t); +} /** * rte_dump - dump a route @@ -1712,6 +1754,7 @@ again: rescan: for (e=n->routes; e; e=e->next) + { if (e->sender->flush_active || (e->flags & REF_DISCARD)) { if (limit <= 0) @@ -1727,6 +1770,22 @@ again: goto rescan; } + if (e->flags & REF_MODIFY) + { + if (limit <= 0) + { + FIB_ITERATE_PUT(fit); + ev_schedule(tab->rt_event); + return; + } + + rte_modify(e); + limit--; + + goto rescan; + } + } + if (!n->routes) /* Orphaned FIB entry */ { FIB_ITERATE_PUT(fit); |