]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: fix cleanup of meta queues on vrf disable 10409/head
authorIgor Ryzhov <iryzhov@nfware.com>
Sun, 23 Jan 2022 17:22:42 +0000 (20:22 +0300)
committerIgor Ryzhov <iryzhov@nfware.com>
Tue, 1 Feb 2022 15:20:30 +0000 (18:20 +0300)
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>
zebra/rib.h
zebra/zebra_rib.c
zebra/zebra_vrf.c

index a0ec1f0e4f73c342c7d656f5fb7248a7f0fcca9c..d5aec5d4c1b78837b507b840b73b3fe01e5b3400 100644 (file)
@@ -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;
 
index 1374b932ae60448c85384e3de38f98e41a3419e5..96897e112807ba926709f0a95a56b68f8c4e37ce 100644 (file)
@@ -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)
 {
index 842dc3f576a20311cd9e55ac3150c95763bae2f4..f88a65d9520806efdf70a6ca0f0bdc808387b1dc 100644 (file)
@@ -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);