zebra: Ensure master's ifname is known, even if slave comes up first

In if_netlink.c, when an interface structure, ifp, is first created,
its possible for the master to come up after the slave interface does.
This means, the slave interface has no way to display the master's ifname
in show outputs. To fix this, we need to allow creation by ifindex instead
of by ifname so that this issue is handled.

Signed-off-by: Dinesh G Dutt<5016467+ddutt@users.noreply.github.com>
This commit is contained in:
Dinesh G Dutt 2019-08-13 16:29:40 +00:00
parent eb4a93fb09
commit ea7ec26162
5 changed files with 93 additions and 15 deletions

View File

@ -132,18 +132,26 @@ static int if_cmp_index_func(const struct interface *ifp1,
} }
/* Create new interface structure. */ /* 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 vrf *vrf = vrf_get(vrf_id, NULL);
struct interface *ifp; struct interface *ifp;
ifp = XCALLOC(MTYPE_IF, sizeof(struct interface)); 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; 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 = list_new();
ifp->connected->del = (void (*)(void *))connected_free; 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; 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. */ /* Create new interface structure. */
void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id) 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; 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. */ /* Lookup interface by IPv4 address. */
struct interface *if_lookup_exact_address(void *src, int family, struct interface *if_lookup_exact_address(void *src, int family,
vrf_id_t vrf_id) 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; 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) void if_set_index(struct interface *ifp, ifindex_t ifindex)
{ {
struct vrf *vrf; struct vrf *vrf;

View File

@ -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 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(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(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, extern struct interface *if_lookup_exact_address(void *matchaddr, int family,
vrf_id_t vrf_id); vrf_id_t vrf_id);
extern struct connected *if_lookup_address(void *matchaddr, int family, 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_all_vrf(const char *ifname);
extern struct interface *if_lookup_by_name(const char *ifname, vrf_id_t vrf_id); 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_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); 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 /* Delete the interface, but do not free the structure, and leave it in the

View File

@ -590,7 +590,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
char *kind = NULL; char *kind = NULL;
char *desc = NULL; char *desc = NULL;
char *slave_kind = NULL; char *slave_kind = NULL;
struct zebra_ns *zns; struct zebra_ns *zns = NULL;
vrf_id_t vrf_id = VRF_DEFAULT; vrf_id_t vrf_id = VRF_DEFAULT;
zebra_iftype_t zif_type = ZEBRA_IF_OTHER; zebra_iftype_t zif_type = ZEBRA_IF_OTHER;
zebra_slave_iftype_t zif_slave_type = ZEBRA_IF_SLAVE_NONE; 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 link_ifindex = IFINDEX_INTERNAL;
ifindex_t bond_ifindex = IFINDEX_INTERNAL; ifindex_t bond_ifindex = IFINDEX_INTERNAL;
struct zebra_if *zif; struct zebra_if *zif;
struct vrf *vrf = NULL;
zns = zebra_ns_lookup(ns_id); zns = zebra_ns_lookup(ns_id);
ifi = NLMSG_DATA(h); 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]) if (tb[IFLA_LINK])
link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]); link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]);
/* Add interface. */ vrf = vrf_get(vrf_id, NULL);
ifp = if_get_by_name(name, vrf_id); /* Add interface.
set_ifindex(ifp, ifi->ifi_index, zns); * 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->flags = ifi->ifi_flags & 0x0000fffff;
ifp->mtu6 = ifp->mtu = *(uint32_t *)RTA_DATA(tb[IFLA_MTU]); ifp->mtu6 = ifp->mtu = *(uint32_t *)RTA_DATA(tb[IFLA_MTU]);
ifp->metric = 0; ifp->metric = 0;

View File

@ -99,15 +99,18 @@ void zebra_l2_unmap_slave_from_bridge(struct zebra_l2info_brslave *br_slave)
br_slave->br_if = NULL; 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; struct interface *bond_if;
/* TODO: Handle change of master */ /* TODO: Handle change of master */
bond_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), bond_if = if_lookup_by_index_all_vrf(bond_slave->bond_ifindex);
bond_slave->bond_ifindex);
if (bond_if) if (bond_if)
bond_slave->bond_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) 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 */ /* Set up or remove link with master */
if (bond_ifindex != IFINDEX_INTERNAL) 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) else if (old_bond_ifindex != IFINDEX_INTERNAL)
zebra_l2_unmap_slave_from_bond(&zif->bondslave_info); zebra_l2_unmap_slave_from_bond(&zif->bondslave_info);
} }

View File

@ -81,7 +81,7 @@ extern void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave);
extern void extern void
zebra_l2_unmap_slave_from_bridge(struct zebra_l2info_brslave *br_slave); zebra_l2_unmap_slave_from_bridge(struct zebra_l2info_brslave *br_slave);
extern void 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 extern void
zebra_l2_unmap_slave_from_bond(struct zebra_l2info_bondslave *bond_slave); zebra_l2_unmap_slave_from_bond(struct zebra_l2info_bondslave *bond_slave);
extern void zebra_l2_bridge_add_update(struct interface *ifp, extern void zebra_l2_bridge_add_update(struct interface *ifp,