summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Ryzhov <iryzhov@nfware.com>2022-01-23 20:22:42 +0300
committerIgor Ryzhov <iryzhov@nfware.com>2022-02-01 18:20:30 +0300
commit0ef6eacc95c82014c04f13be3b641ff3983040ca (patch)
treeffbd3d6951c5baa1a955beba32891a610b5ceb1a
parent7a90d91586290d872c05960427df2d3f031cc5e5 (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>
-rw-r--r--zebra/rib.h2
-rw-r--r--zebra/zebra_rib.c53
-rw-r--r--zebra/zebra_vrf.c34
3 files changed, 57 insertions, 32 deletions
diff --git a/zebra/rib.h b/zebra/rib.h
index a0ec1f0e4f..d5aec5d4c1 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -481,6 +481,8 @@ int zebra_rib_queue_evpn_rem_vtep_del(vrf_id_t vrf_id, vni_t vni,
struct in_addr vtep_ip);
extern void meta_queue_free(struct meta_queue *mq);
+extern void rib_meta_queue_free_vrf(struct meta_queue *mq,
+ struct zebra_vrf *zvrf);
extern int zebra_rib_labeled_unicast(struct route_entry *re);
extern struct route_table *rib_table_ipv6;
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)
{
diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c
index 842dc3f576..f88a65d952 100644
--- a/zebra/zebra_vrf.c
+++ b/zebra/zebra_vrf.c
@@ -177,7 +177,6 @@ static int zebra_vrf_disable(struct vrf *vrf)
struct interface *ifp;
afi_t afi;
safi_t safi;
- unsigned i;
assert(zvrf);
if (IS_ZEBRA_DEBUG_EVENT)
@@ -222,21 +221,7 @@ static int zebra_vrf_disable(struct vrf *vrf)
if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp);
/* clean-up work queues */
- for (i = 0; i < MQ_SIZE; i++) {
- struct listnode *lnode, *nnode;
- struct route_node *rnode;
- rib_dest_t *dest;
-
- for (ALL_LIST_ELEMENTS(zrouter.mq->subq[i], lnode, nnode,
- rnode)) {
- dest = rib_dest_from_rnode(rnode);
- if (dest && rib_dest_vrf(dest) == zvrf) {
- route_unlock_node(rnode);
- list_delete_node(zrouter.mq->subq[i], lnode);
- zrouter.mq->size--;
- }
- }
- }
+ rib_meta_queue_free_vrf(zrouter.mq, zvrf);
/* Cleanup (free) routing tables and NHT tables. */
for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
@@ -262,7 +247,6 @@ static int zebra_vrf_delete(struct vrf *vrf)
{
struct zebra_vrf *zvrf = vrf->info;
struct other_route_table *otable;
- unsigned i;
assert(zvrf);
if (IS_ZEBRA_DEBUG_EVENT)
@@ -272,21 +256,7 @@ static int zebra_vrf_delete(struct vrf *vrf)
table_manager_disable(zvrf);
/* clean-up work queues */
- for (i = 0; i < MQ_SIZE; i++) {
- struct listnode *lnode, *nnode;
- struct route_node *rnode;
- rib_dest_t *dest;
-
- for (ALL_LIST_ELEMENTS(zrouter.mq->subq[i], lnode, nnode,
- rnode)) {
- dest = rib_dest_from_rnode(rnode);
- if (dest && rib_dest_vrf(dest) == zvrf) {
- route_unlock_node(rnode);
- list_delete_node(zrouter.mq->subq[i], lnode);
- zrouter.mq->size--;
- }
- }
- }
+ rib_meta_queue_free_vrf(zrouter.mq, zvrf);
/* Free Vxlan and MPLS. */
zebra_vxlan_close_tables(zvrf);