]> git.puffer.fish Git - mirror/frr.git/commitdiff
lib: fix vrf deletion when the last interface is deleted 9981/head
authorIgor Ryzhov <iryzhov@nfware.com>
Fri, 5 Nov 2021 22:22:07 +0000 (01:22 +0300)
committerIgor Ryzhov <iryzhov@nfware.com>
Thu, 11 Nov 2021 11:57:59 +0000 (14:57 +0300)
Currently, we automatically delete an inactive VRF when its last
interface is deleted. This code introduces a couple of crashes because
of the following problems:
- vrf_delete is called before calling if_del hook, so daemons may try to
  dereference an ifp->vrf pointer which is freed
- in if_terminate, we continue to use the VRF in the loop condition
  after the last interface is deleted

This check is needed only when the interface is deleted by the user,
because if the interface is deleted by the system, VRF must still exist
in the system. Move the check to appropriate places to fix crashes.

Signed-off-by: Igor Ryzhov <iryzhov@nfware.com>
lib/if.c
lib/vrf.c
ospfd/ospf_interface.c

index 71d2f5d9ccdafffac02d279b7bb3f1691916f52a..a40f04f5a250230c4c49ff46cd1aabbf91906afb 100644 (file)
--- a/lib/if.c
+++ b/lib/if.c
@@ -303,9 +303,6 @@ void if_delete(struct interface **ifp)
        if (ptr->ifindex != IFINDEX_INTERNAL)
                IFINDEX_RB_REMOVE(vrf, ptr);
 
-       if (!vrf_is_enabled(vrf))
-               vrf_delete(vrf);
-
        if_delete_retain(ptr);
 
        list_delete(&ptr->connected);
@@ -1420,7 +1417,7 @@ static int lib_interface_create(struct nb_cb_create_args *args)
 static int lib_interface_destroy(struct nb_cb_destroy_args *args)
 {
        struct interface *ifp;
-
+       struct vrf *vrf;
 
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -1436,9 +1433,13 @@ static int lib_interface_destroy(struct nb_cb_destroy_args *args)
                break;
        case NB_EV_APPLY:
                ifp = nb_running_unset_entry(args->dnode);
+               vrf = ifp->vrf;
 
                ifp->configured = false;
                if_delete(&ifp);
+
+               if (!vrf_is_enabled(vrf))
+                       vrf_delete(vrf);
                break;
        }
 
index aaedb638001b37776b4876d3841a48455727e1cc..a9a5a83794eada5043ca05b78a3441c91099b2d6 100644 (file)
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -539,13 +539,10 @@ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *),
 
 static void vrf_terminate_single(struct vrf *vrf)
 {
-       int enabled = vrf_is_enabled(vrf);
-
        /* Clear configured flag and invoke delete. */
        UNSET_FLAG(vrf->status, VRF_CONFIGURED);
        if_terminate(vrf);
-       if (enabled)
-               vrf_delete(vrf);
+       vrf_delete(vrf);
 }
 
 /* Terminate VRF module. */
index 60e109ea8006c24820f98de12a00b283d1867eeb..ccfeddfc662041bce3a32de32c2c46f7a63fb654 100644 (file)
@@ -971,11 +971,14 @@ struct ospf_interface *ospf_vl_new(struct ospf *ospf,
 static void ospf_vl_if_delete(struct ospf_vl_data *vl_data)
 {
        struct interface *ifp = vl_data->vl_oi->ifp;
+       struct vrf *vrf = ifp->vrf;
 
        vl_data->vl_oi->address->u.prefix4.s_addr = INADDR_ANY;
        vl_data->vl_oi->address->prefixlen = 0;
        ospf_if_free(vl_data->vl_oi);
        if_delete(&ifp);
+       if (!vrf_is_enabled(vrf))
+               vrf_delete(vrf);
        vlink_count--;
 }