fib_dxr: check if cached fib_data matches the new request in dxr_init()

When calling dxr_init(), the FIB_ALGO infrastructure may provide a
pointer to a previous dxr instance, which permits reuse of auxiliary
dxr structures, i.e. incremental lookup structure updates.  For dxr this
is a crucial feature provided by FIB_ALGO, since dxr incremental updates
are typically several orders of magnitude faster than full lookup table
rebuilds.

However, the auxiliary dxr structure caches a pointer to struct fib_data and
relies upon it for performing incremental updates.  Apparently, incremental
rebuild requests from FIB_ALGO, i.e. a calls to dxr_init() with a pointer
old_data set, may (under not yet fully understood circumstances) be invoked
within a different fib_data context than the one cached in the previous
version of dxr auxiliary structures.  In such (rare) events, we ignore the
offered old dxr context, and proceed with a full lookup structure rebuild
instead of attempting an incremental one using a fib_data context which
may or may not no longer be valid, and thus lead to a system crash.

PR:		278422
MFC after:	1 week
Approved by:    re (cperciva)

(cherry picked from commit 4ab122e8ef)
(cherry picked from commit d6e32525c7)
This commit is contained in:
Marko Zec 2024-05-17 17:55:43 +02:00
parent 0e5e6a9419
commit 782f020042

View File

@ -1139,7 +1139,8 @@ dxr_init(uint32_t fibnum, struct fib_data *fd, void *old_data, void **data)
}
/* Check whether we may reuse the old auxiliary structures */
if (old_dxr != NULL && old_dxr->aux != NULL) {
if (old_dxr != NULL && old_dxr->aux != NULL &&
old_dxr->aux->fd == fd) {
da = old_dxr->aux;
atomic_add_int(&da->refcnt, 1);
}
@ -1275,7 +1276,7 @@ dxr_change_rib_batch(struct rib_head *rnh, struct fib_change_queue *q,
da = dxr->aux;
MPASS(da != NULL);
MPASS(da->fd != NULL);
MPASS(da->fd == dxr->fd);
MPASS(da->refcnt > 0);
FIB_PRINTF(LOG_INFO, da->fd, "processing %d update(s)", q->count);