summaryrefslogtreecommitdiff
path: root/nest
diff options
context:
space:
mode:
Diffstat (limited to 'nest')
-rw-r--r--nest/protocol.h1
-rw-r--r--nest/route.h3
-rw-r--r--nest/rt-table.c62
3 files changed, 66 insertions, 0 deletions
diff --git a/nest/protocol.h b/nest/protocol.h
index 4fb76e2b..af988c88 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -213,6 +213,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 0834da45..ab1ba50e 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -219,6 +219,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
@@ -241,6 +242,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); }
@@ -279,6 +281,7 @@ int rt_examine(rtable *t, ip_addr prefix, int pxlen, struct proto *p, struct fil
rte *rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, struct ea_list **tmpa, linpool *pool, int silent);
void rt_refresh_begin(rtable *t, struct announce_hook *ah);
void rt_refresh_end(rtable *t, struct announce_hook *ah);
+void rt_modify_stale(rtable *t, struct announce_hook *ah);
void rte_dump(rte *);
void rte_free(rte *);
rte *rte_do_cow(rte *);
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 83f0e713..93075c7b 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -1295,6 +1295,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, ip_addr prefix, int pxlen, struct proto *p, struct filter *filter)
@@ -1385,6 +1407,29 @@ rt_refresh_end(rtable *t, struct announce_hook *ah)
rt_schedule_prune(t);
}
+void
+rt_modify_stale(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_FILTERED))
+ {
+ e->flags |= REF_MODIFY;
+ prune = 1;
+ }
+ }
+ FIB_WALK_END;
+
+ if (prune)
+ rt_schedule_prune(t);
+}
+
/**
* rte_dump - dump a route
@@ -1604,6 +1649,7 @@ again:
rescan:
for (e=n->routes; e; e=e->next)
+ {
if (e->sender->proto->flushing || (e->flags & REF_DISCARD))
{
if (*limit <= 0)
@@ -1617,6 +1663,22 @@ again:
goto rescan;
}
+
+ if (e->flags & REF_MODIFY)
+ {
+ if (*limit <= 0)
+ {
+ FIB_ITERATE_PUT(fit, fn);
+ return 0;
+ }
+
+ rte_modify(e);
+ (*limit)--;
+
+ goto rescan;
+ }
+ }
+
if (!n->routes) /* Orphaned FIB entry */
{
FIB_ITERATE_PUT(fit, fn);