summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilippe Guibert <philippe.guibert@6wind.com>2019-04-02 18:40:35 +0200
committerPhilippe Guibert <philippe.guibert@6wind.com>2019-06-12 08:37:58 +0200
commit921a85ba8c92eea6e104dea002870e323e5a19b5 (patch)
treec42a5c6de193adc9c6b4e037a90b7d5a7aa7693a
parent8205b1b455ee9c4b271ce76590a7489d1e0e4175 (diff)
zebra, ifp: on netlink discovery, anticipate the vrf creation
there may be cases where the vrf is yet allocated from the vty, and the discovery process did not make the relationship between the vrf_id and the name of the vrf. For instance, by parsing an interface belonging to vrf-id X, it is not sure that vrf-id X and vrfname XX are talking about the same vrf. For that, lets allocate the vrf, and lets try to detect there is a duplicate case in vrf, so that the merge can be done without any impact for the user. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
-rw-r--r--lib/if.c2
-rw-r--r--lib/vrf.c18
-rw-r--r--zebra/if_netlink.c4
3 files changed, 22 insertions, 2 deletions
diff --git a/lib/if.c b/lib/if.c
index 0cfd591160..a803754375 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -177,6 +177,8 @@ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id)
if (ifp->ifindex != IFINDEX_INTERNAL)
IFINDEX_RB_INSERT(vrf, ifp);
+ if (!old_vrf->name)
+ return;
/*
* HACK: Change the interface VRF in the running configuration directly,
* bypassing the northbound layer. This is necessary to avoid deleting
diff --git a/lib/vrf.c b/lib/vrf.c
index 229f19f29a..862a3da067 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -176,6 +176,24 @@ struct vrf *vrf_get(vrf_id_t vrf_id, const char *name)
name, vrf_id, vrf->vrf_id);
return NULL;
}
+ /* look for duplicates. case is followine one:
+ * - a vrf is configured per name -> vrfA
+ * - netlink discovery creates a vrf with vrf_id ->vrfB
+ * - then, netlink discovers vrf, and associated vrf_id and name
+ * -> so vrfA and vrfB must be merged
+ */
+ if (vrf && vrf_id != VRF_UNKNOWN
+ && vrf->vrf_id == VRF_UNKNOWN) {
+ struct vrf *vrf2 = vrf_lookup_by_id(vrf_id);
+ struct interface *ifp;
+
+ if (vrf2 && !vrf2->name && vrf2 != vrf) {
+ /* move vrf2 context to vrf */
+ FOR_ALL_INTERFACES (vrf2, ifp)
+ if_update_to_new_vrf(ifp, vrf);
+ vrf_delete(vrf2);
+ }
+ }
/* Try to find VRF both by ID and name */
if (!vrf && vrf_id != VRF_UNKNOWN)
vrf = vrf_lookup_by_id(vrf_id);
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index 4b998bcdc4..2c94dd52b5 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -665,6 +665,8 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
&& !vrf_is_backend_netns()) {
zif_slave_type = ZEBRA_IF_SLAVE_VRF;
vrf_id = *(uint32_t *)RTA_DATA(tb[IFLA_MASTER]);
+ /* vrf can be needed before vrf netlink discovery */
+ vrf_get(vrf_id, NULL);
} else if (slave_kind && (strcmp(slave_kind, "bridge") == 0)) {
zif_slave_type = ZEBRA_IF_SLAVE_BRIDGE;
bridge_ifindex =
@@ -677,9 +679,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
}
if (vrf_is_backend_netns())
vrf_id = (vrf_id_t)ns_id;
-
vrf = vrf_lookup_by_id(vrf_id);
-
/* If linking to another interface, note it. */
if (tb[IFLA_LINK])
link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]);