diff options
| author | Igor Ryzhov <iryzhov@nfware.com> | 2022-01-23 20:22:42 +0300 |
|---|---|---|
| committer | Igor Ryzhov <iryzhov@nfware.com> | 2022-02-01 18:20:30 +0300 |
| commit | 0ef6eacc95c82014c04f13be3b641ff3983040ca (patch) | |
| tree | ffbd3d6951c5baa1a955beba32891a610b5ceb1a /zebra/zebra_rib.c | |
| parent | 7a90d91586290d872c05960427df2d3f031cc5e5 (diff) | |
zebra: fix cleanup of meta queues on vrf disable
Current code treats all metaqueues as lists of route_node structures.
However, some queues contain other structures that need to be cleaned up
differently. Casting the elements of those queues to struct route_node
and dereferencing them leads to a crash. The crash may be seen when
executing bgp_multi_vrf_topo2.
Fix the code by using the proper list element types.
Signed-off-by: Igor Ryzhov <iryzhov@nfware.com>
Diffstat (limited to 'zebra/zebra_rib.c')
| -rw-r--r-- | zebra/zebra_rib.c | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 1374b932ae..96897e1128 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2944,6 +2944,59 @@ void meta_queue_free(struct meta_queue *mq) XFREE(MTYPE_WORK_QUEUE, mq); } +void rib_meta_queue_free_vrf(struct meta_queue *mq, struct zebra_vrf *zvrf) +{ + vrf_id_t vrf_id = zvrf->vrf->vrf_id; + unsigned int i; + + for (i = 0; i < MQ_SIZE; i++) { + struct listnode *lnode, *nnode; + void *data; + bool del; + + for (ALL_LIST_ELEMENTS(mq->subq[i], lnode, nnode, data)) { + del = false; + + if (i == META_QUEUE_EVPN) { + struct wq_evpn_wrapper *w = data; + + if (w->vrf_id == vrf_id) { + XFREE(MTYPE_WQ_WRAPPER, w); + del = true; + } + } else if (i == + route_info[ZEBRA_ROUTE_NHG].meta_q_map) { + struct wq_nhg_wrapper *w = data; + + if (w->type == WQ_NHG_WRAPPER_TYPE_CTX && + w->u.ctx->vrf_id == vrf_id) { + nhg_ctx_free(&w->u.ctx); + XFREE(MTYPE_WQ_WRAPPER, w); + del = true; + } else if (w->type == WQ_NHG_WRAPPER_TYPE_NHG && + w->u.nhe->vrf_id == vrf_id) { + zebra_nhg_free(w->u.nhe); + XFREE(MTYPE_WQ_WRAPPER, w); + del = true; + } + } else { + struct route_node *rnode = data; + rib_dest_t *dest = rib_dest_from_rnode(rnode); + + if (dest && rib_dest_vrf(dest) == zvrf) { + route_unlock_node(rnode); + del = true; + } + } + + if (del) { + list_delete_node(mq->subq[i], lnode); + mq->size--; + } + } + } +} + /* initialise zebra rib work queue */ static void rib_queue_init(void) { |
