summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--zebra/if_netlink.c12
-rw-r--r--zebra/interface.c31
-rw-r--r--zebra/interface.h1
3 files changed, 42 insertions, 2 deletions
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);