#define RTE_IN_TABLE_WRITABLE \
byte pflags; /* Protocol-specific flags; may change in-table (!) */ \
+ byte flags; /* Table-specific flags */ \
u8 stale_cycle; /* Auxiliary value for route refresh; may change in-table (!) */ \
typedef struct rte {
RTE_IN_TABLE_WRITABLE;
- byte flags; /* Table-specific flags */
u8 generation; /* If this route import is based on other previously exported route,
this value should be 1 + MAX(generation of the parent routes).
Otherwise the route is independent and this value is zero. */
} rte;
#define REF_FILTERED 2 /* Route is rejected by import filter */
+#define REF_OBSOLETE 16 /* Route is obsolete, pending propagation */
#define REF_PENDING 32 /* Route has not propagated completely yet */
/* Route is valid for propagation (may depend on other flags in the future), accepts NULL */
* rte_free() deletes the given &rte from the routing table it's linked to.
*/
-void
+static void
rte_free(struct rte_storage *e, struct rtable_private *tab)
{
struct netindex *i = RTE_GET_NETINDEX(&e->rte);
else
hook->stats.withdraws_received++;
+ if (rpe->old)
+ ASSERT_DIE(rpe->old->flags & REF_OBSOLETE);
+
if (hook->req->export_one)
hook->req->export_one(hook->req, n, rpe);
else if (hook->req->export_bulk)
if (rpe->old)
{
+ ASSERT_DIE(rpe->old->flags & REF_OBSOLETE);
hmap_clear(&tab->id_map, rpe->old->id);
rte_free(SKIP_BACK(struct rte_storage, rte, rpe->old), tab);
}
return;
}
+ /* Mark the old route as obsolete */
+ if (old)
+ SKIP_BACK(struct rte_storage, rte, old)->flags |= REF_OBSOLETE;
+
/* If rejected by import limit, we need to pretend there is no route */
if (req->preimport && (req->preimport(req, new, old) == 0))
{
struct rte_storage *put;
if (updates[i].new.attrs)
+ {
put = updates[i].new_stored = rte_store(&updates[i].new, ni, tab);
+ updates[i].old->flags |= REF_OBSOLETE;
+ }
else
put = updates[i].old;