diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 47a101e619..6c71fddbbf 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -585,6 +585,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) zebra_slave_iftype_t zif_slave_type = ZEBRA_IF_SLAVE_NONE; ifindex_t bridge_ifindex = IFINDEX_INTERNAL; ifindex_t link_ifindex = IFINDEX_INTERNAL; + struct zebra_if *zif; zns = zebra_ns_lookup(ns_id); ifi = NLMSG_DATA(h); @@ -679,8 +680,12 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (IS_ZEBRA_IF_VRF(ifp)) SET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK); - /* Update link. */ - zebra_if_update_link(ifp, link_ifindex, ns_id); + /* Just set the @link/lower-device ifindex. During nldump interfaces are + * not ordered in any fashion so we may end up getting upper devices + * before lower devices. We will setup the real linkage once the dump + * is complete. */ + zif = (struct zebra_if *)ifp->info; + zif->link_ifindex = link_ifindex; /* Hardware type and address. */ ifp->ll_type = netlink_to_zebra_link_type(ifi->ifi_type); @@ -754,6 +759,9 @@ int interface_lookup_netlink(struct zebra_ns *zns) if (ret < 0) return ret; + /* fixup linkages */ + zebra_if_update_all_links(); + /* Get IPv4 address of the interfaces. */ ret = netlink_request_intf_addr(zns, AF_INET, RTM_GETADDR, 0); if (ret < 0) diff --git a/zebra/interface.c b/zebra/interface.c index ca90c18cf2..9e43a5b53c 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -999,6 +999,37 @@ void zebra_if_update_link(struct interface *ifp, ifindex_t link_ifindex, link_ifindex); } +/* during initial link dump kernel does not order lower devices before + * upper devices so we need to fixup link dependencies at the end of dump */ +void zebra_if_update_all_links(void) +{ + struct route_node *rn; + struct interface *ifp; + struct zebra_if *zif; + struct zebra_ns *ns; + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info("fixup link dependencies"); + + ns = zebra_ns_lookup(NS_DEFAULT); + for (rn = route_top(ns->if_table); rn; rn = route_next(rn)) { + ifp = (struct interface *)rn->info; + if (!ifp) + continue; + zif = ifp->info; + if ((zif->link_ifindex != IFINDEX_INTERNAL) && !zif->link) { + zif->link = if_lookup_by_index_per_ns(ns, + zif->link_ifindex); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("interface %s/%d's lower fixup to %s/%d", + ifp->name, ifp->ifindex, + zif->link?zif->link->name:"unk", + zif->link_ifindex); + } + } +} + + /* Output prefix string to vty. */ static int prefix_vty_out(struct vty *vty, struct prefix *p) diff --git a/zebra/interface.h b/zebra/interface.h index 02a05e6146..c6d8b24b01 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -348,6 +348,7 @@ extern int ipv6_address_configured(struct interface *ifp); extern void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id); extern void zebra_if_update_link(struct interface *ifp, ifindex_t link_ifindex, ns_id_t ns_id); +extern void zebra_if_update_all_links(void); extern void vrf_add_update(struct vrf *vrfp);