]> git.proxmox.com Git - mirror_frr.git/commitdiff
zebra: treat vrf add for existing vrf as update
authorsudhanshukumar22 <sudhanshu.kumar@broadcom.com>
Thu, 12 Nov 2020 12:37:30 +0000 (04:37 -0800)
committersudhanshukumar22 <sudhanshu.kumar@broadcom.com>
Mon, 1 Feb 2021 16:33:13 +0000 (08:33 -0800)
Description: When we get a new vrf add and vrf with same name, but different vrf-id already
exists in the database, we should treat vrf add as update.
This happens mostly when there are lots of vrf and other configuration being replayed.
There may be a stale vrf delete followed by new vrf add. This
can cause timing race condition where vrf delete could be missed and
further same vrf add would get rejected instead of treating last arrived
vrf add as update.

Treat vrf add for existing vrf as update.
Implicitly disable this VRF to cleanup routes and other functions as part of vrf disable.
Update vrf_id for the vrf and update vrf_id tree.
Re-enable VRF so that all routes are freshly installed.

Above 3 steps are mandatory since it can happen that with config reload
stale routes which are installed in vrf-1 table might contain routes from
older vrf-0 table which might have got deleted due to missing vrf-0 in new configuration.

Signed-off-by: sudhanshukumar22 <sudhanshu.kumar@broadcom.com>
lib/vrf.c
lib/vrf.h
zebra/if_netlink.c

index 1a9cd7e451b589f587b89735ce1f7e1821a463d7..07080daabf963976f035694db5af64989a11076e 100644 (file)
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -214,6 +214,53 @@ struct vrf *vrf_get(vrf_id_t vrf_id, const char *name)
        return vrf;
 }
 
+/* Update a VRF. If not found, create one.
+ * Arg:
+ *   name   - The name of the vrf.
+ *   vrf_id - The vrf_id of the vrf.
+ * Description: This function first finds the vrf using its name. If the vrf is
+ * found and the vrf-id of the existing vrf does not match the new vrf id, it
+ * will disable the existing vrf and update it with new vrf-id. If the vrf is
+ * not found, it will create the vrf with given name and the new vrf id.
+ */
+struct vrf *vrf_update(vrf_id_t new_vrf_id, const char *name)
+{
+       struct vrf *vrf = NULL;
+
+       /*Treat VRF add for existing vrf as update
+        * Update VRF ID and also update in VRF ID table
+        */
+       if (name)
+               vrf = vrf_lookup_by_name(name);
+       if (vrf && new_vrf_id != VRF_UNKNOWN && vrf->vrf_id != VRF_UNKNOWN
+           && vrf->vrf_id != new_vrf_id) {
+               if (debug_vrf) {
+                       zlog_debug(
+                               "Vrf Update event: %s old id: %u, new id: %u",
+                               name, vrf->vrf_id, new_vrf_id);
+               }
+
+               /*Disable the vrf to simulate implicit delete
+                * so that all stale routes are deleted
+                * This vrf will be enabled down the line
+                */
+               vrf_disable(vrf);
+
+
+               RB_REMOVE(vrf_id_head, &vrfs_by_id, vrf);
+               vrf->vrf_id = new_vrf_id;
+               RB_INSERT(vrf_id_head, &vrfs_by_id, vrf);
+
+       } else {
+
+               /*
+                * vrf_get is implied creation if it does not exist
+                */
+               vrf = vrf_get(new_vrf_id, name);
+       }
+       return vrf;
+}
+
 /* Delete a VRF. This is called when the underlying VRF goes away, a
  * pre-configured VRF is deleted or when shutting down (vrf_terminate()).
  */
index c636b9ea7eebc1331165f53d1c565fc7038d9330..81473ae7e52c5b30b2f9cad5835fcfd348352b2f 100644 (file)
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -114,6 +114,7 @@ extern struct vrf_name_head vrfs_by_name;
 extern struct vrf *vrf_lookup_by_id(vrf_id_t);
 extern struct vrf *vrf_lookup_by_name(const char *);
 extern struct vrf *vrf_get(vrf_id_t, const char *);
+extern struct vrf *vrf_update(vrf_id_t new_vrf_id, const char *name);
 extern const char *vrf_id_to_name(vrf_id_t vrf_id);
 extern vrf_id_t vrf_name_to_id(const char *);
 
index e4dd745f42799f0ba62322db293d4e6917dbb8d4..00471b9645fba9b452cd84746626b50c7d96b99d 100644 (file)
@@ -301,7 +301,7 @@ static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb,
        struct ifinfomsg *ifi;
        struct rtattr *linkinfo[IFLA_INFO_MAX + 1];
        struct rtattr *attr[IFLA_VRF_MAX + 1];
-       struct vrf *vrf;
+       struct vrf *vrf = NULL;
        struct zebra_vrf *zvrf;
        uint32_t nl_table_id;
 
@@ -350,11 +350,7 @@ static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb,
                        }
                }
 
-               /*
-                * vrf_get is implied creation if it does not exist
-                */
-               vrf = vrf_get((vrf_id_t)ifi->ifi_index,
-                             name); // It would create vrf
+               vrf = vrf_update((vrf_id_t)ifi->ifi_index, name);
                if (!vrf) {
                        flog_err(EC_LIB_INTERFACE, "VRF %s id %u not created",
                                 name, ifi->ifi_index);