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]);