]> git.puffer.fish Git - matthieu/frr.git/commitdiff
zebra: fix cleanup of meta queues on vrf disable
authorIgor Ryzhov <iryzhov@nfware.com>
Sun, 23 Jan 2022 17:22:42 +0000 (20:22 +0300)
committerMark Stapp <mstapp@nvidia.com>
Wed, 2 Feb 2022 16:32:10 +0000 (11:32 -0500)
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>
(cherry picked from commit 0ef6eacc95c82014c04f13be3b641ff3983040ca)

zebra/rib.h
zebra/zebra_rib.c
zebra/zebra_vrf.c

index 8887053a4c8041091c92b961acc39b7ebd154c5b..4332cda0d12c55d14a7d068a234e9de1e7effed6 100644 (file)
@@ -480,6 +480,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;
 
index 24c51e485ff5c8ef8e64922298f04722cfd9c1e0..0142097c2ede516d7b217edc4747866d1df14fd3 100644 (file)
@@ -2938,6 +2938,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)
 {
index 4fbcc6f596479de406eabcdf9fe86bf793cac1fb..f91e769fd4bd3ca4db478588204d6f4170389f98 100644 (file)
@@ -169,7 +169,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)
@@ -214,21 +213,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++) {
@@ -257,7 +242,6 @@ static int zebra_vrf_delete(struct vrf *vrf)
        struct route_table *table;
        afi_t afi;
        safi_t safi;
-       unsigned i;
 
        assert(zvrf);
        if (IS_ZEBRA_DEBUG_EVENT)
@@ -265,21 +249,7 @@ static int zebra_vrf_delete(struct vrf *vrf)
                           zvrf_id(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);