diff --git a/lib/if.c b/lib/if.c index f7a167f251..9ee2f02e62 100644 --- a/lib/if.c +++ b/lib/if.c @@ -132,18 +132,26 @@ static int if_cmp_index_func(const struct interface *ifp1, } /* Create new interface structure. */ -struct interface *if_create(const char *name, vrf_id_t vrf_id) +static struct interface *if_create_backend(const char *name, ifindex_t ifindex, + vrf_id_t vrf_id) { struct vrf *vrf = vrf_get(vrf_id, NULL); struct interface *ifp; ifp = XCALLOC(MTYPE_IF, sizeof(struct interface)); - ifp->ifindex = IFINDEX_INTERNAL; - - assert(name); - strlcpy(ifp->name, name, sizeof(ifp->name)); ifp->vrf_id = vrf_id; - IFNAME_RB_INSERT(vrf, ifp); + + if (name) { + strlcpy(ifp->name, name, sizeof(ifp->name)); + IFNAME_RB_INSERT(vrf, ifp); + } else + ifp->name[0] = '\0'; + + if (ifindex != IFINDEX_INTERNAL) + if_set_index(ifp, ifindex); + else + ifp->ifindex = ifindex; /* doesn't add it to the list */ + ifp->connected = list_new(); ifp->connected->del = (void (*)(void *))connected_free; @@ -158,6 +166,16 @@ struct interface *if_create(const char *name, vrf_id_t vrf_id) return ifp; } +struct interface *if_create(const char *name, vrf_id_t vrf_id) +{ + return if_create_backend(name, IFINDEX_INTERNAL, vrf_id); +} + +struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id) +{ + return if_create_backend(NULL, ifindex, vrf_id); +} + /* Create new interface structure. */ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id) { @@ -302,6 +320,23 @@ struct interface *if_lookup_by_name_all_vrf(const char *name) return NULL; } +struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex) +{ + struct vrf *vrf; + struct interface *ifp; + + if (ifindex == IFINDEX_INTERNAL) + return NULL; + + RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { + ifp = if_lookup_by_index(ifindex, vrf->vrf_id); + if (ifp) + return ifp; + } + + return NULL; +} + /* Lookup interface by IPv4 address. */ struct interface *if_lookup_exact_address(void *src, int family, vrf_id_t vrf_id) @@ -447,6 +482,34 @@ struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id) return NULL; } +struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id) +{ + struct interface *ifp; + + switch (vrf_get_backend()) { + case VRF_BACKEND_UNKNOWN: + case VRF_BACKEND_NETNS: + ifp = if_lookup_by_index(ifindex, vrf_id); + if (ifp) + return ifp; + return if_create_ifindex(ifindex, vrf_id); + case VRF_BACKEND_VRF_LITE: + ifp = if_lookup_by_index_all_vrf(ifindex); + if (ifp) { + if (ifp->vrf_id == vrf_id) + return ifp; + /* If it came from the kernel or by way of zclient, + * believe it and update the ifp accordingly. + */ + if_update_to_new_vrf(ifp, vrf_id); + return ifp; + } + return if_create_ifindex(ifindex, vrf_id); + } + + return NULL; +} + void if_set_index(struct interface *ifp, ifindex_t ifindex) { struct vrf *vrf; diff --git a/lib/if.h b/lib/if.h index 603c9c3780..871e319f29 100644 --- a/lib/if.h +++ b/lib/if.h @@ -478,7 +478,9 @@ extern int if_cmp_name_func(const char *p1, const char *p2); */ extern void if_update_to_new_vrf(struct interface *, vrf_id_t vrf_id); extern struct interface *if_create(const char *name, vrf_id_t vrf_id); +extern struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id); extern struct interface *if_lookup_by_index(ifindex_t, vrf_id_t vrf_id); +extern struct interface *if_lookup_by_index_all_vrf(ifindex_t); extern struct interface *if_lookup_exact_address(void *matchaddr, int family, vrf_id_t vrf_id); extern struct connected *if_lookup_address(void *matchaddr, int family, @@ -493,6 +495,7 @@ size_t if_lookup_by_hwaddr(const uint8_t *hw_addr, size_t addrsz, extern struct interface *if_lookup_by_name_all_vrf(const char *ifname); extern struct interface *if_lookup_by_name(const char *ifname, vrf_id_t vrf_id); extern struct interface *if_get_by_name(const char *ifname, vrf_id_t vrf_id); +extern struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id); extern void if_set_index(struct interface *ifp, ifindex_t ifindex); /* Delete the interface, but do not free the structure, and leave it in the diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 63e72fed00..2c536c5d1f 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -590,7 +590,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) char *kind = NULL; char *desc = NULL; char *slave_kind = NULL; - struct zebra_ns *zns; + struct zebra_ns *zns = NULL; vrf_id_t vrf_id = VRF_DEFAULT; zebra_iftype_t zif_type = ZEBRA_IF_OTHER; zebra_slave_iftype_t zif_slave_type = ZEBRA_IF_SLAVE_NONE; @@ -598,6 +598,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) ifindex_t link_ifindex = IFINDEX_INTERNAL; ifindex_t bond_ifindex = IFINDEX_INTERNAL; struct zebra_if *zif; + struct vrf *vrf = NULL; zns = zebra_ns_lookup(ns_id); ifi = NLMSG_DATA(h); @@ -681,9 +682,17 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (tb[IFLA_LINK]) link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]); - /* Add interface. */ - ifp = if_get_by_name(name, vrf_id); - set_ifindex(ifp, ifi->ifi_index, zns); + vrf = vrf_get(vrf_id, NULL); + /* Add interface. + * We add by index first because in some cases such as the master + * interface, we have the index before we have the name. Fixing + * back references on the slave interfaces is painful if not done + * this way, i.e. by creating by ifindex. + */ + ifp = if_get_by_ifindex(ifi->ifi_index, vrf_id); + set_ifindex(ifp, ifi->ifi_index, zns); /* add it to ns struct */ + strlcpy(ifp->name, name, sizeof(ifp->name)); + IFNAME_RB_INSERT(vrf, ifp); ifp->flags = ifi->ifi_flags & 0x0000fffff; ifp->mtu6 = ifp->mtu = *(uint32_t *)RTA_DATA(tb[IFLA_MTU]); ifp->metric = 0; diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c index ca37dd748e..e549d80a5c 100644 --- a/zebra/zebra_l2.c +++ b/zebra/zebra_l2.c @@ -99,15 +99,18 @@ void zebra_l2_unmap_slave_from_bridge(struct zebra_l2info_brslave *br_slave) br_slave->br_if = NULL; } -void zebra_l2_map_slave_to_bond(struct zebra_l2info_bondslave *bond_slave) +void zebra_l2_map_slave_to_bond(struct zebra_l2info_bondslave *bond_slave, + vrf_id_t vrf_id) { struct interface *bond_if; /* TODO: Handle change of master */ - bond_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), - bond_slave->bond_ifindex); + bond_if = if_lookup_by_index_all_vrf(bond_slave->bond_ifindex); if (bond_if) bond_slave->bond_if = bond_if; + else + bond_slave->bond_if = if_create_ifindex(bond_slave->bond_ifindex, + vrf_id); } void zebra_l2_unmap_slave_from_bond(struct zebra_l2info_bondslave *bond_slave) @@ -282,7 +285,7 @@ void zebra_l2if_update_bond_slave(struct interface *ifp, ifindex_t bond_ifindex) /* Set up or remove link with master */ if (bond_ifindex != IFINDEX_INTERNAL) - zebra_l2_map_slave_to_bond(&zif->bondslave_info); + zebra_l2_map_slave_to_bond(&zif->bondslave_info, ifp->vrf_id); else if (old_bond_ifindex != IFINDEX_INTERNAL) zebra_l2_unmap_slave_from_bond(&zif->bondslave_info); } diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h index 33aa2e3746..d9f0eec3f8 100644 --- a/zebra/zebra_l2.h +++ b/zebra/zebra_l2.h @@ -81,7 +81,7 @@ extern void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave); extern void zebra_l2_unmap_slave_from_bridge(struct zebra_l2info_brslave *br_slave); extern void -zebra_l2_map_slave_to_bond(struct zebra_l2info_bondslave *bond_slave); +zebra_l2_map_slave_to_bond(struct zebra_l2info_bondslave *bond_slave, vrf_id_t); extern void zebra_l2_unmap_slave_from_bond(struct zebra_l2info_bondslave *bond_slave); extern void zebra_l2_bridge_add_update(struct interface *ifp,