From 605df8d44fab7a39429ed2d165fd06f0d98d3d0b Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 26 Apr 2023 23:02:09 -0400 Subject: [PATCH] zebra: Use zebra dplane for RTM link and addr a) Move the reads of link and address information into the dplane b) Move the startup read of data into the dplane as well. c) Break up startup reading of the linux kernel data into multiple phases. As that we have implied ordering of data that must be read first and if the dplane has taken over some data reading then we must delay initial read-in of other data. Fixes: #13288 Signed-off-by: Donald Sharp --- zebra/if_netlink.c | 852 +++++++++-------------------------------- zebra/interface.c | 778 ++++++++++++++++++++++++++++++++++++- zebra/kernel_netlink.c | 20 +- zebra/kernel_socket.c | 8 + zebra/rt.h | 2 + zebra/rule_netlink.c | 1 + zebra/zebra_dplane.h | 13 + zebra/zebra_l2.c | 9 +- zebra/zebra_l2.h | 22 +- zebra/zebra_ns.c | 36 +- zebra/zebra_ns.h | 2 + zebra/zebra_rib.c | 2 + 12 files changed, 1033 insertions(+), 712 deletions(-) diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 55d63cc4eb..8767b2622c 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -64,64 +64,21 @@ extern struct zebra_privs_t zserv_privs; -/* Note: on netlink systems, there should be a 1-to-1 mapping between interface - names and ifindex values. */ -static void set_ifindex(struct interface *ifp, ifindex_t ifi_index, - struct zebra_ns *zns) -{ - struct interface *oifp; - - if (((oifp = if_lookup_by_index_per_ns(zns, ifi_index)) != NULL) - && (oifp != ifp)) { - if (ifi_index == IFINDEX_INTERNAL) - flog_err( - EC_LIB_INTERFACE, - "Netlink is setting interface %s ifindex to reserved internal value %u", - ifp->name, ifi_index); - else { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "interface index %d was renamed from %s to %s", - ifi_index, oifp->name, ifp->name); - if (if_is_up(oifp)) - flog_err( - EC_LIB_INTERFACE, - "interface rename detected on up interface: index %d was renamed from %s to %s, results are uncertain!", - ifi_index, oifp->name, ifp->name); - if_delete_update(&oifp); - } - } - if_set_index(ifp, ifi_index); -} - /* Utility function to parse hardware link-layer address and update ifp */ static void netlink_interface_update_hw_addr(struct rtattr **tb, - struct interface *ifp) + struct zebra_dplane_ctx *ctx) { - int i; - if (tb[IFLA_ADDRESS]) { int hw_addr_len; hw_addr_len = RTA_PAYLOAD(tb[IFLA_ADDRESS]); if (hw_addr_len > INTERFACE_HWADDR_MAX) - zlog_debug("Hardware address is too large: %d", - hw_addr_len); - else { - ifp->hw_addr_len = hw_addr_len; - memcpy(ifp->hw_addr, RTA_DATA(tb[IFLA_ADDRESS]), - hw_addr_len); - - for (i = 0; i < hw_addr_len; i++) - if (ifp->hw_addr[i] != 0) - break; - - if (i == hw_addr_len) - ifp->hw_addr_len = 0; - else - ifp->hw_addr_len = hw_addr_len; - } + zlog_warn("Hardware address is too large: %d", + hw_addr_len); + else + dplane_ctx_set_ifp_hw_addr(ctx, hw_addr_len, + RTA_DATA(tb[IFLA_ADDRESS])); } } @@ -236,26 +193,6 @@ static enum zebra_link_type netlink_to_zebra_link_type(unsigned int hwt) } } -static inline void zebra_if_set_ziftype(struct interface *ifp, - enum zebra_iftype zif_type, - enum zebra_slave_iftype zif_slave_type) -{ - struct zebra_if *zif; - - zif = (struct zebra_if *)ifp->info; - zif->zif_slave_type = zif_slave_type; - - if (zif->zif_type != zif_type) { - zif->zif_type = zif_type; - /* If the if_type has been set to bond initialize ES info - * against it. XXX - note that we don't handle the case where - * a zif changes from bond to non-bond; it is really - * an unexpected/error condition. - */ - zebra_evpn_if_init(zif); - } -} - static void netlink_determine_zebra_iftype(const char *kind, enum zebra_iftype *zif_type) { @@ -283,16 +220,11 @@ static void netlink_determine_zebra_iftype(const char *kind, } static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb, - uint32_t ns_id, const char *name) + uint32_t ns_id, const char *name, + struct zebra_dplane_ctx *ctx) { - struct ifinfomsg *ifi; struct rtattr *linkinfo[IFLA_INFO_MAX + 1]; struct rtattr *attr[IFLA_VRF_MAX + 1]; - struct vrf *vrf = NULL; - struct zebra_vrf *zvrf; - uint32_t nl_table_id; - - ifi = NLMSG_DATA(h); netlink_parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb); @@ -314,75 +246,8 @@ static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb, return; } - nl_table_id = *(uint32_t *)RTA_DATA(attr[IFLA_VRF_TABLE]); - - if (h->nlmsg_type == RTM_NEWLINK) { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("RTM_NEWLINK for VRF %s(%u) table %u", name, - ifi->ifi_index, nl_table_id); - - if (!vrf_lookup_by_id((vrf_id_t)ifi->ifi_index)) { - vrf_id_t exist_id; - - exist_id = - zebra_vrf_lookup_by_table(nl_table_id, ns_id); - if (exist_id != VRF_DEFAULT) { - vrf = vrf_lookup_by_id(exist_id); - - flog_err( - EC_ZEBRA_VRF_MISCONFIGURED, - "VRF %s id %u table id overlaps existing vrf %s, misconfiguration exiting", - name, ifi->ifi_index, vrf->name); - exit(-1); - } - } - - vrf = vrf_update((vrf_id_t)ifi->ifi_index, name); - if (!vrf) { - flog_err(EC_LIB_INTERFACE, "VRF %s id %u not created", - name, ifi->ifi_index); - return; - } - - /* - * This is the only place that we get the actual kernel table_id - * being used. We need it to set the table_id of the routes - * we are passing to the kernel.... And to throw some totally - * awesome parties. that too. - * - * At this point we *must* have a zvrf because the vrf_create - * callback creates one. We *must* set the table id - * before the vrf_enable because of( at the very least ) - * static routes being delayed for installation until - * during the vrf_enable callbacks. - */ - zvrf = (struct zebra_vrf *)vrf->info; - zvrf->table_id = nl_table_id; - - /* Enable the created VRF. */ - if (!vrf_enable(vrf)) { - flog_err(EC_LIB_INTERFACE, - "Failed to enable VRF %s id %u", name, - ifi->ifi_index); - return; - } - - } else // h->nlmsg_type == RTM_DELLINK - { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("RTM_DELLINK for VRF %s(%u)", name, - ifi->ifi_index); - - vrf = vrf_lookup_by_id((vrf_id_t)ifi->ifi_index); - - if (!vrf) { - flog_warn(EC_ZEBRA_VRF_NOT_FOUND, "%s: vrf not found", - __func__); - return; - } - - vrf_delete(vrf); - } + dplane_ctx_set_ifp_table_id( + ctx, *(uint32_t *)RTA_DATA(attr[IFLA_VRF_TABLE])); } static uint32_t get_iflink_speed(struct interface *interface, int *error) @@ -663,62 +528,59 @@ static int netlink_extract_vxlan_info(struct rtattr *link_data, * bridge interface is added or updated, take further actions to map * its members. Likewise, for VxLAN interface. */ -static void netlink_interface_update_l2info(struct interface *ifp, +static void netlink_interface_update_l2info(struct zebra_dplane_ctx *ctx, + enum zebra_iftype zif_type, struct rtattr *link_data, int add, ns_id_t link_nsid) { + struct zebra_l2info_bridge bridge_info; + struct zebra_l2info_vlan vlan_info; + struct zebra_l2info_vxlan vxlan_info; + struct zebra_l2info_gre gre_info; + if (!link_data) return; - if (IS_ZEBRA_IF_BRIDGE(ifp)) { - struct zebra_l2info_bridge bridge_info; - + switch (zif_type) { + case ZEBRA_IF_BRIDGE: netlink_extract_bridge_info(link_data, &bridge_info); - zebra_l2_bridge_add_update(ifp, &bridge_info); - } else if (IS_ZEBRA_IF_VLAN(ifp)) { - struct zebra_l2info_vlan vlan_info; - + dplane_ctx_set_ifp_bridge_info(ctx, &bridge_info); + break; + case ZEBRA_IF_VLAN: netlink_extract_vlan_info(link_data, &vlan_info); - zebra_l2_vlanif_update(ifp, &vlan_info); - zebra_evpn_acc_bd_svi_set(ifp->info, NULL, - !!if_is_operative(ifp)); - } else if (IS_ZEBRA_IF_VXLAN(ifp)) { - struct zebra_l2info_vxlan vxlan_info; - + dplane_ctx_set_ifp_vlan_info(ctx, &vlan_info); + break; + case ZEBRA_IF_VXLAN: netlink_extract_vxlan_info(link_data, &vxlan_info); vxlan_info.link_nsid = link_nsid; - zebra_l2_vxlanif_add_update(ifp, &vxlan_info, add); - if (link_nsid != NS_UNKNOWN && - vxlan_info.ifindex_link) - zebra_if_update_link(ifp, vxlan_info.ifindex_link, - link_nsid); - } else if (IS_ZEBRA_IF_GRE(ifp)) { - struct zebra_l2info_gre gre_info; - + dplane_ctx_set_ifp_vxlan_info(ctx, &vxlan_info); + break; + case ZEBRA_IF_GRE: netlink_extract_gre_info(link_data, &gre_info); gre_info.link_nsid = link_nsid; - zebra_l2_greif_add_update(ifp, &gre_info, add); - if (link_nsid != NS_UNKNOWN && - gre_info.ifindex_link) - zebra_if_update_link(ifp, gre_info.ifindex_link, - link_nsid); + dplane_ctx_set_ifp_gre_info(ctx, &gre_info); + break; + case ZEBRA_IF_OTHER: + case ZEBRA_IF_VRF: + case ZEBRA_IF_MACVLAN: + case ZEBRA_IF_VETH: + case ZEBRA_IF_BOND: + break; } } -static int netlink_bridge_vxlan_vlan_vni_map_update(struct interface *ifp, - struct rtattr *af_spec) +static int +netlink_bridge_vxlan_vlan_vni_map_update(struct zebra_dplane_ctx *ctx, + struct rtattr *af_spec) { int rem; - vni_t vni_id; - vlanid_t vid; uint16_t flags; struct rtattr *i; - struct zebra_vxlan_vni vni; - struct zebra_vxlan_vni *vnip; - struct hash *vni_table = NULL; + struct zebra_vxlan_vni_array *vniarray = NULL; struct zebra_vxlan_vni vni_end; struct zebra_vxlan_vni vni_start; struct rtattr *aftb[IFLA_BRIDGE_VLAN_TUNNEL_MAX + 1]; + int32_t count = 0; memset(&vni_start, 0, sizeof(vni_start)); memset(&vni_end, 0, sizeof(vni_end)); @@ -737,80 +599,46 @@ static int netlink_bridge_vxlan_vlan_vni_map_update(struct interface *ifp, /* vlan-vni info missing */ return 0; + count++; flags = 0; - memset(&vni, 0, sizeof(vni)); + vniarray = XREALLOC( + MTYPE_TMP, vniarray, + sizeof(struct zebra_vxlan_vni_array) + + count * sizeof(struct zebra_vxlan_vni)); + + memset(&vniarray->vnis[count - 1], 0, + sizeof(struct zebra_vxlan_vni)); - vni.vni = *(vni_t *)RTA_DATA(aftb[IFLA_BRIDGE_VLAN_TUNNEL_ID]); - vni.access_vlan = *(vlanid_t *)RTA_DATA( + vniarray->vnis[count - 1].vni = + *(vni_t *)RTA_DATA(aftb[IFLA_BRIDGE_VLAN_TUNNEL_ID]); + vniarray->vnis[count - 1].access_vlan = *(vlanid_t *)RTA_DATA( aftb[IFLA_BRIDGE_VLAN_TUNNEL_VID]); if (aftb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS]) flags = *(uint16_t *)RTA_DATA( aftb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS]); - if (flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) { - vni_start = vni; - continue; - } - - if (flags & BRIDGE_VLAN_INFO_RANGE_END) - vni_end = vni; - - if (!(flags & BRIDGE_VLAN_INFO_RANGE_END)) { - vni_start = vni; - vni_end = vni; - } - - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "Vlan-Vni(%d:%d-%d:%d) update for VxLAN IF %s(%u)", - vni_start.access_vlan, vni_end.access_vlan, - vni_start.vni, vni_end.vni, ifp->name, - ifp->ifindex); - - if (!vni_table) { - vni_table = zebra_vxlan_vni_table_create(); - if (!vni_table) - return 0; - } - - for (vid = vni_start.access_vlan, vni_id = vni_start.vni; - vid <= vni_end.access_vlan; vid++, vni_id++) { - - memset(&vni, 0, sizeof(vni)); - vni.vni = vni_id; - vni.access_vlan = vid; - vnip = hash_get(vni_table, &vni, zebra_vxlan_vni_alloc); - if (!vnip) - return 0; - } - - memset(&vni_start, 0, sizeof(vni_start)); - memset(&vni_end, 0, sizeof(vni_end)); + vniarray->vnis[count - 1].flags = flags; } - if (vni_table) - zebra_vxlan_if_vni_table_add_update(ifp, vni_table); - + if (count) { + vniarray->count = count; + dplane_ctx_set_ifp_vxlan_vni_array(ctx, vniarray); + } return 0; } -static int netlink_bridge_vxlan_update(struct interface *ifp, - struct rtattr *af_spec) +static int netlink_bridge_vxlan_update(struct zebra_dplane_ctx *ctx, + struct rtattr *af_spec) { struct rtattr *aftb[IFLA_BRIDGE_MAX + 1]; struct bridge_vlan_info *vinfo; - struct zebra_if *zif; - vlanid_t access_vlan; + struct zebra_dplane_bridge_vlan_info bvinfo; if (!af_spec) return 0; - zif = (struct zebra_if *)ifp->info; - - /* Single vxlan devices has vni-vlan range to update */ - if (IS_ZEBRA_VXLAN_IF_SVD(zif)) - return netlink_bridge_vxlan_vlan_vni_map_update(ifp, af_spec); + netlink_bridge_vxlan_vlan_vni_map_update(ctx, af_spec); /* There is a 1-to-1 mapping of VLAN to VxLAN - hence * only 1 access VLAN is accepted. @@ -820,119 +648,73 @@ static int netlink_bridge_vxlan_update(struct interface *ifp, return 0; vinfo = RTA_DATA(aftb[IFLA_BRIDGE_VLAN_INFO]); - if (!(vinfo->flags & BRIDGE_VLAN_INFO_PVID)) - return 0; + bvinfo.flags = vinfo->flags; + bvinfo.vid = vinfo->vid; - access_vlan = (vlanid_t)vinfo->vid; - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("Access VLAN %u for VxLAN IF %s(%u)", access_vlan, - ifp->name, ifp->ifindex); - zebra_l2_vxlanif_update_access_vlan(ifp, access_vlan); + dplane_ctx_set_ifp_bridge_vlan_info(ctx, &bvinfo); return 0; } -static void netlink_bridge_vlan_update(struct interface *ifp, - struct rtattr *af_spec) +static void netlink_bridge_vlan_update(struct zebra_dplane_ctx *ctx, + struct rtattr *af_spec) { struct rtattr *i; int rem; - uint16_t vid_range_start = 0; - struct zebra_if *zif; - bitfield_t old_vlan_bitmap; struct bridge_vlan_info *vinfo; - - zif = (struct zebra_if *)ifp->info; - - /* cache the old bitmap addrs */ - old_vlan_bitmap = zif->vlan_bitmap; - /* create a new bitmap space for re-eval */ - bf_init(zif->vlan_bitmap, IF_VLAN_BITMAP_MAX); + struct zebra_dplane_bridge_vlan_info_array *bvarray = NULL; + int32_t count = 0; if (af_spec) { for (i = RTA_DATA(af_spec), rem = RTA_PAYLOAD(af_spec); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { - if (i->rta_type != IFLA_BRIDGE_VLAN_INFO) continue; - vinfo = RTA_DATA(i); - - if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) { - vid_range_start = vinfo->vid; - continue; - } - - if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END)) - vid_range_start = vinfo->vid; + count++; + bvarray = XREALLOC( + MTYPE_TMP, bvarray, + sizeof(struct + zebra_dplane_bridge_vlan_info_array) + + count * sizeof(struct + zebra_dplane_bridge_vlan_info)); - zebra_vlan_bitmap_compute(ifp, vid_range_start, - vinfo->vid); + vinfo = RTA_DATA(i); + bvarray->array[count - 1].flags = vinfo->flags; + bvarray->array[count - 1].vid = vinfo->vid; } } - zebra_vlan_mbr_re_eval(ifp, old_vlan_bitmap); - - bf_free(old_vlan_bitmap); + if (count) { + bvarray->count = count; + dplane_ctx_set_ifp_bridge_vlan_info_array(ctx, bvarray); + } } -static int netlink_bridge_interface(struct nlmsghdr *h, int len, ns_id_t ns_id, - int startup) +static int netlink_bridge_interface(struct zebra_dplane_ctx *ctx, + struct rtattr *af_spec, int startup) { - char *name = NULL; - struct ifinfomsg *ifi; - struct rtattr *tb[IFLA_MAX + 1]; - struct interface *ifp; - struct zebra_if *zif; - struct rtattr *af_spec; - - /* Fetch name and ifindex */ - ifi = NLMSG_DATA(h); - netlink_parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); - - if (tb[IFLA_IFNAME] == NULL) - return -1; - name = (char *)RTA_DATA(tb[IFLA_IFNAME]); - - /* The interface should already be known, if not discard. */ - ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), ifi->ifi_index); - if (!ifp) { - zlog_debug("Cannot find bridge IF %s(%u)", name, - ifi->ifi_index); - return 0; - } - - /* We are only interested in the access VLAN i.e., AF_SPEC */ - af_spec = tb[IFLA_AF_SPEC]; - if (IS_ZEBRA_IF_VXLAN(ifp)) - return netlink_bridge_vxlan_update(ifp, af_spec); + netlink_bridge_vxlan_update(ctx, af_spec); /* build vlan bitmap associated with this interface if that * device type is interested in the vlans */ - zif = (struct zebra_if *)ifp->info; - if (bf_is_inited(zif->vlan_bitmap)) - netlink_bridge_vlan_update(ifp, af_spec); + netlink_bridge_vlan_update(ctx, af_spec); + dplane_provider_enqueue_to_zebra(ctx); return 0; } -static bool is_if_protodown_reason_only_frr(uint32_t rc_bitfield) -{ - return (rc_bitfield == (((uint32_t)1) << if_netlink_get_frr_protodown_r_bit())); -} - /* * Process interface protodown dplane update. * * If the interface is an es bond member then it must follow EVPN's * protodown setting. */ -static void netlink_proc_dplane_if_protodown(struct zebra_if *zif, +static void netlink_proc_dplane_if_protodown(struct zebra_dplane_ctx *ctx, struct rtattr **tb) { bool protodown; - bool old_protodown; uint32_t rc_bitfield = 0; struct rtattr *pd_reason_info[IFLA_MAX + 1]; @@ -947,59 +729,9 @@ static void netlink_proc_dplane_if_protodown(struct zebra_if *zif, pd_reason_info[IFLA_PROTO_DOWN_REASON_VALUE]); } - /* - * Set our reason code to note it wasn't us. - * If the reason we got from the kernel is ONLY frr though, don't - * set it. - */ - COND_FLAG(zif->protodown_rc, ZEBRA_PROTODOWN_EXTERNAL, - protodown && rc_bitfield && - !is_if_protodown_reason_only_frr(rc_bitfield)); - - - old_protodown = !!ZEBRA_IF_IS_PROTODOWN(zif); - if (protodown == old_protodown) - return; - - if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("interface %s dplane change, protdown %s", - zif->ifp->name, protodown ? "on" : "off"); - - /* Set protodown, respectively */ - COND_FLAG(zif->flags, ZIF_FLAG_PROTODOWN, protodown); - - if (zebra_evpn_is_es_bond_member(zif->ifp)) { - /* Check it's not already being sent to the dplane first */ - if (protodown && - CHECK_FLAG(zif->flags, ZIF_FLAG_SET_PROTODOWN)) { - if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "bond mbr %s protodown on recv'd but already sent protodown on to the dplane", - zif->ifp->name); - return; - } - - if (!protodown && - CHECK_FLAG(zif->flags, ZIF_FLAG_UNSET_PROTODOWN)) { - if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "bond mbr %s protodown off recv'd but already sent protodown off to the dplane", - zif->ifp->name); - return; - } - - if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "bond mbr %s reinstate protodown %s in the dplane", - zif->ifp->name, old_protodown ? "on" : "off"); - - if (old_protodown) - SET_FLAG(zif->flags, ZIF_FLAG_SET_PROTODOWN); - else - SET_FLAG(zif->flags, ZIF_FLAG_UNSET_PROTODOWN); - - dplane_intf_update(zif->ifp); - } + dplane_ctx_set_ifp_rc_bitfield(ctx, rc_bitfield); + dplane_ctx_set_ifp_protodown(ctx, protodown); + dplane_ctx_set_ifp_protodown_set(ctx, true); } static uint8_t netlink_parse_lacp_bypass(struct rtattr **linkinfo) @@ -1016,29 +748,6 @@ static uint8_t netlink_parse_lacp_bypass(struct rtattr **linkinfo) return bypass; } -/* - * Only called at startup to cleanup leftover protodown reasons we may - * have not cleaned up. We leave protodown set though. - */ -static void if_sweep_protodown(struct zebra_if *zif) -{ - bool protodown; - - protodown = !!ZEBRA_IF_IS_PROTODOWN(zif); - - if (!protodown) - return; - - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("interface %s sweeping protodown %s reason 0x%x", - zif->ifp->name, protodown ? "on" : "off", - zif->protodown_rc); - - /* Only clear our reason codes, leave external if it was set */ - UNSET_FLAG(zif->protodown_rc, ZEBRA_PROTODOWN_ALL); - dplane_intf_update(zif->ifp); -} - /* Request for specific interface or address information from the kernel */ static int netlink_request_intf_addr(struct nlsock *netlink_cmd, int family, int type, uint32_t filter_mask) @@ -1085,7 +794,7 @@ int interface_lookup_netlink(struct zebra_ns *zns) { int ret; struct zebra_dplane_info dp_info; - struct nlsock *netlink_cmd = &zns->netlink_cmd; + struct nlsock *netlink_cmd = &zns->netlink_dplane_out; /* Capture key info from ns struct */ zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/); @@ -1109,6 +818,13 @@ int interface_lookup_netlink(struct zebra_ns *zns) if (ret < 0) return ret; + return ret; +} + +void interface_list_tunneldump(struct zebra_ns *zns) +{ + int ret; + /* * So netlink_tunneldump_read will initiate a request * per tunnel to get data. If we are on a kernel that @@ -1121,13 +837,12 @@ int interface_lookup_netlink(struct zebra_ns *zns) */ ret = netlink_tunneldump_read(zns); if (ret < 0) - return ret; + return; - /* fixup linkages */ - zebra_if_update_all_links(zns); - return 0; + zebra_dplane_startup_stage(zns, ZEBRA_DPLANE_TUNNELS_READ); } + /** * interface_addr_lookup_netlink() - Look up interface addresses * @@ -1147,8 +862,8 @@ static int interface_addr_lookup_netlink(struct zebra_ns *zns) ret = netlink_request_intf_addr(netlink_cmd, AF_INET, RTM_GETADDR, 0); if (ret < 0) return ret; - ret = netlink_parse_info(netlink_interface_addr, netlink_cmd, &dp_info, - 0, true); + ret = netlink_parse_info(netlink_interface_addr_dplane, netlink_cmd, + &dp_info, 0, true); if (ret < 0) return ret; @@ -1156,8 +871,8 @@ static int interface_addr_lookup_netlink(struct zebra_ns *zns) ret = netlink_request_intf_addr(netlink_cmd, AF_INET6, RTM_GETADDR, 0); if (ret < 0) return ret; - ret = netlink_parse_info(netlink_interface_addr, netlink_cmd, &dp_info, - 0, true); + ret = netlink_parse_info(netlink_interface_addr_dplane, netlink_cmd, + &dp_info, 0, true); if (ret < 0) return ret; @@ -1768,7 +1483,6 @@ int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id, /* Enqueue ctx for main pthread to process */ dplane_provider_enqueue_to_zebra(ctx); - return 0; } @@ -1778,27 +1492,21 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) struct ifinfomsg *ifi; struct rtattr *tb[IFLA_MAX + 1]; struct rtattr *linkinfo[IFLA_MAX + 1]; - struct interface *ifp; char *name = NULL; char *kind = NULL; - char *desc = NULL; char *slave_kind = NULL; - struct zebra_ns *zns; vrf_id_t vrf_id = VRF_DEFAULT; enum zebra_iftype zif_type = ZEBRA_IF_OTHER; enum zebra_slave_iftype zif_slave_type = ZEBRA_IF_SLAVE_NONE; ifindex_t bridge_ifindex = IFINDEX_INTERNAL; ifindex_t bond_ifindex = IFINDEX_INTERNAL; ifindex_t link_ifindex = IFINDEX_INTERNAL; - uint8_t old_hw_addr[INTERFACE_HWADDR_MAX]; - struct zebra_if *zif; ns_id_t link_nsid = ns_id; ifindex_t master_infindex = IFINDEX_INTERNAL; uint8_t bypass = 0; frrtrace(3, frr_zebra, netlink_interface, h, ns_id, startup); - zns = zebra_ns_lookup(ns_id); ifi = NLMSG_DATA(h); /* assume if not default zns, then new VRF */ @@ -1827,10 +1535,6 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) return -1; } - /* We are interested in some AF_BRIDGE notifications. */ - if (ifi->ifi_family == AF_BRIDGE) - return netlink_bridge_interface(h, len, ns_id, startup); - /* Looking up interface name. */ memset(linkinfo, 0, sizeof(linkinfo)); netlink_parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(ifi), len, @@ -1877,18 +1581,47 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) link_nsid = *(ns_id_t *)RTA_DATA(tb[IFLA_LINK_NETNSID]); link_nsid = ns_id_get_absolute(ns_id, link_nsid); } - if (tb[IFLA_IFALIAS]) { - desc = (char *)RTA_DATA(tb[IFLA_IFALIAS]); - } - /* See if interface is present. */ - ifp = if_lookup_by_name_per_ns(zns, name); + struct zebra_dplane_ctx *ctx = dplane_ctx_alloc(); + dplane_ctx_set_ns_id(ctx, ns_id); + dplane_ctx_set_ifp_link_nsid(ctx, link_nsid); + dplane_ctx_set_ifp_zif_type(ctx, zif_type); + dplane_ctx_set_ifindex(ctx, ifi->ifi_index); + dplane_ctx_set_ifname(ctx, name); + dplane_ctx_set_ifp_startup(ctx, startup); + dplane_ctx_set_ifp_family(ctx, ifi->ifi_family); + + /* We are interested in some AF_BRIDGE notifications. */ +#ifndef AF_BRIDGE +#define AF_BRIDGE 7 +#endif + if (ifi->ifi_family == AF_BRIDGE) { + dplane_ctx_set_op(ctx, DPLANE_OP_INTF_INSTALL); + return netlink_bridge_interface(ctx, tb[IFLA_AF_SPEC], startup); + } if (h->nlmsg_type == RTM_NEWLINK) { + dplane_ctx_set_ifp_link_ifindex(ctx, link_ifindex); + dplane_ctx_set_op(ctx, DPLANE_OP_INTF_INSTALL); + dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_QUEUED); + if (tb[IFLA_IFALIAS]) { + dplane_ctx_set_ifp_desc(ctx, + RTA_DATA(tb[IFLA_IFALIAS])); + } + if (!tb[IFLA_MTU]) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "RTM_NEWLINK for interface %s(%u) without MTU set", + name, ifi->ifi_index); + return 0; + } + dplane_ctx_set_ifp_mtu(ctx, *(int *)RTA_DATA(tb[IFLA_MTU])); + /* If VRF, create or update the VRF structure itself. */ if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) { - netlink_vrf_change(h, tb[IFLA_LINKINFO], ns_id, name); - vrf_id = (vrf_id_t)ifi->ifi_index; + netlink_vrf_change(h, tb[IFLA_LINKINFO], ns_id, name, + ctx); + vrf_id = ifi->ifi_index; } if (tb[IFLA_MASTER]) { @@ -1911,277 +1644,45 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) } else zif_slave_type = ZEBRA_IF_SLAVE_OTHER; } + dplane_ctx_set_ifp_zif_slave_type(ctx, zif_slave_type); + dplane_ctx_set_ifp_vrf_id(ctx, vrf_id); + dplane_ctx_set_ifp_master_ifindex(ctx, master_infindex); + dplane_ctx_set_ifp_bridge_ifindex(ctx, bridge_ifindex); + dplane_ctx_set_ifp_bond_ifindex(ctx, bond_ifindex); + dplane_ctx_set_ifp_bypass(ctx, bypass); + dplane_ctx_set_ifp_zltype( + ctx, netlink_to_zebra_link_type(ifi->ifi_type)); + if (vrf_is_backend_netns()) - vrf_id = (vrf_id_t)ns_id; - if (ifp == NULL - || !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { - /* Add interface notification from kernel */ - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "RTM_NEWLINK ADD for %s(%u) vrf_id %u type %d sl_type %d master %u flags 0x%x", - name, ifi->ifi_index, vrf_id, zif_type, - zif_slave_type, master_infindex, - ifi->ifi_flags); - - if (ifp == NULL) { - /* unknown interface */ - ifp = if_get_by_name(name, vrf_id, NULL); - } else { - /* pre-configured interface, learnt now */ - if (ifp->vrf->vrf_id != vrf_id) - if_update_to_new_vrf(ifp, vrf_id); - } - - /* Update interface information. */ - set_ifindex(ifp, ifi->ifi_index, zns); - ifp->flags = ifi->ifi_flags & 0x0000fffff; - if (!tb[IFLA_MTU]) { - zlog_debug( - "RTM_NEWLINK for interface %s(%u) without MTU set", - name, ifi->ifi_index); - return 0; - } - ifp->mtu6 = ifp->mtu = *(int *)RTA_DATA(tb[IFLA_MTU]); - ifp->metric = 0; - ifp->speed = get_iflink_speed(ifp, NULL); - ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN; - - /* Set interface type */ - zebra_if_set_ziftype(ifp, zif_type, zif_slave_type); - if (IS_ZEBRA_IF_VRF(ifp)) - SET_FLAG(ifp->status, - ZEBRA_INTERFACE_VRF_LOOPBACK); - - /* Update link. */ - zebra_if_update_link(ifp, link_ifindex, link_nsid); - - /* - * 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; - - ifp->ll_type = - netlink_to_zebra_link_type(ifi->ifi_type); - netlink_interface_update_hw_addr(tb, ifp); - - /* Inform clients, install any configured addresses. */ - if_add_update(ifp); - - /* Extract and save L2 interface information, take - * additional actions. */ - netlink_interface_update_l2info( - ifp, linkinfo[IFLA_INFO_DATA], - 1, link_nsid); - if (IS_ZEBRA_IF_BOND(ifp)) - zebra_l2if_update_bond(ifp, true); - if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) - zebra_l2if_update_bridge_slave( - ifp, bridge_ifindex, ns_id, - ZEBRA_BRIDGE_NO_ACTION); - else if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) - zebra_l2if_update_bond_slave(ifp, bond_ifindex, - !!bypass); - - if (tb[IFLA_PROTO_DOWN]) { - netlink_proc_dplane_if_protodown(ifp->info, tb); - if (startup) - if_sweep_protodown(zif); - } - if (IS_ZEBRA_IF_BRIDGE(ifp)) { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "RTM_NEWLINK ADD for %s(%u), vlan-aware %d", - name, ifp->ifindex, - IS_ZEBRA_IF_BRIDGE_VLAN_AWARE( - zif)); - } - } else if (ifp->vrf->vrf_id != vrf_id) { - /* VRF change for an interface. */ - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "RTM_NEWLINK vrf-change for %s(%u) vrf_id %u -> %u flags 0x%x", - name, ifp->ifindex, ifp->vrf->vrf_id, - vrf_id, ifi->ifi_flags); + dplane_ctx_set_ifp_vrf_id(ctx, ns_id); - if_handle_vrf_change(ifp, vrf_id); - } else { - bool was_bridge_slave, was_bond_slave; - uint8_t chgflags = ZEBRA_BRIDGE_NO_ACTION; - zif = ifp->info; + dplane_ctx_set_ifp_flags(ctx, ifi->ifi_flags & 0x0000fffff); - /* Interface update. */ - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "RTM_NEWLINK update for %s(%u) sl_type %d master %u flags 0x%x", - name, ifp->ifindex, zif_slave_type, - master_infindex, ifi->ifi_flags); + if (tb[IFLA_PROTO_DOWN]) { + dplane_ctx_set_ifp_protodown_set(ctx, true); + netlink_proc_dplane_if_protodown(ctx, tb); + } else + dplane_ctx_set_ifp_protodown_set(ctx, false); - set_ifindex(ifp, ifi->ifi_index, zns); - if (!tb[IFLA_MTU]) { - zlog_debug( - "RTM_NEWLINK for interface %s(%u) without MTU set", - name, ifi->ifi_index); - return 0; - } - ifp->mtu6 = ifp->mtu = *(int *)RTA_DATA(tb[IFLA_MTU]); - ifp->metric = 0; - - /* Update interface type - NOTE: Only slave_type can - * change. */ - was_bridge_slave = IS_ZEBRA_IF_BRIDGE_SLAVE(ifp); - was_bond_slave = IS_ZEBRA_IF_BOND_SLAVE(ifp); - zebra_if_set_ziftype(ifp, zif_type, zif_slave_type); - - memcpy(old_hw_addr, ifp->hw_addr, INTERFACE_HWADDR_MAX); - - /* Update link. */ - zebra_if_update_link(ifp, link_ifindex, link_nsid); - - ifp->ll_type = - netlink_to_zebra_link_type(ifi->ifi_type); - netlink_interface_update_hw_addr(tb, ifp); - - if (tb[IFLA_PROTO_DOWN]) - netlink_proc_dplane_if_protodown(ifp->info, tb); - - if (if_is_no_ptm_operative(ifp)) { - bool is_up = if_is_operative(ifp); - ifp->flags = ifi->ifi_flags & 0x0000fffff; - if (!if_is_no_ptm_operative(ifp) || - CHECK_FLAG(zif->flags, - ZIF_FLAG_PROTODOWN)) { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "Intf %s(%u) has gone DOWN", - name, ifp->ifindex); - if_down(ifp); - rib_update(RIB_UPDATE_KERNEL); - } else if (if_is_operative(ifp)) { - bool mac_updated = false; - - /* Must notify client daemons of new - * interface status. */ - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "Intf %s(%u) PTM up, notifying clients", - name, ifp->ifindex); - if_up(ifp, !is_up); - - /* Update EVPN VNI when SVI MAC change - */ - if (memcmp(old_hw_addr, ifp->hw_addr, - INTERFACE_HWADDR_MAX)) - mac_updated = true; - if (IS_ZEBRA_IF_VLAN(ifp) - && mac_updated) { - struct interface *link_if; - - link_if = - if_lookup_by_index_per_ns( - zebra_ns_lookup(NS_DEFAULT), - link_ifindex); - if (link_if) - zebra_vxlan_svi_up(ifp, - link_if); - } else if (mac_updated - && IS_ZEBRA_IF_BRIDGE(ifp)) { - zlog_debug( - "Intf %s(%u) bridge changed MAC address", - name, ifp->ifindex); - chgflags = - ZEBRA_BRIDGE_MASTER_MAC_CHANGE; - } - } - } else { - ifp->flags = ifi->ifi_flags & 0x0000fffff; - if (if_is_operative(ifp) && - !CHECK_FLAG(zif->flags, - ZIF_FLAG_PROTODOWN)) { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "Intf %s(%u) has come UP", - name, ifp->ifindex); - if_up(ifp, true); - if (IS_ZEBRA_IF_BRIDGE(ifp)) - chgflags = - ZEBRA_BRIDGE_MASTER_UP; - } else { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "Intf %s(%u) has gone DOWN", - name, ifp->ifindex); - if_down(ifp); - rib_update(RIB_UPDATE_KERNEL); - } - } - - /* Extract and save L2 interface information, take - * additional actions. */ - netlink_interface_update_l2info( - ifp, linkinfo[IFLA_INFO_DATA], - 0, link_nsid); - if (IS_ZEBRA_IF_BRIDGE(ifp)) - zebra_l2if_update_bridge(ifp, chgflags); - if (IS_ZEBRA_IF_BOND(ifp)) - zebra_l2if_update_bond(ifp, true); - if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) || was_bridge_slave) - zebra_l2if_update_bridge_slave( - ifp, bridge_ifindex, ns_id, chgflags); - else if (IS_ZEBRA_IF_BOND_SLAVE(ifp) || was_bond_slave) - zebra_l2if_update_bond_slave(ifp, bond_ifindex, - !!bypass); - if (IS_ZEBRA_IF_BRIDGE(ifp)) { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "RTM_NEWLINK update for %s(%u), vlan-aware %d", - name, ifp->ifindex, - IS_ZEBRA_IF_BRIDGE_VLAN_AWARE( - zif)); - } - } + netlink_interface_update_hw_addr(tb, ctx); - zif = ifp->info; - if (zif) { - XFREE(MTYPE_ZIF_DESC, zif->desc); - if (desc) - zif->desc = XSTRDUP(MTYPE_ZIF_DESC, desc); - } + /* Extract and save L2 interface information, take + * additional actions. */ + netlink_interface_update_l2info( + ctx, zif_type, linkinfo[IFLA_INFO_DATA], 1, link_nsid); } else { - /* Delete interface notification from kernel */ - if (ifp == NULL) { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "RTM_DELLINK for unknown interface %s(%u)", - name, ifi->ifi_index); - return 0; - } - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("RTM_DELLINK for %s(%u)", name, - ifp->ifindex); - - if (IS_ZEBRA_IF_BOND(ifp)) - zebra_l2if_update_bond(ifp, false); - if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) - zebra_l2if_update_bond_slave(ifp, bond_ifindex, false); - /* Special handling for bridge or VxLAN interfaces. */ - if (IS_ZEBRA_IF_BRIDGE(ifp)) - zebra_l2_bridge_del(ifp); - else if (IS_ZEBRA_IF_VXLAN(ifp)) - zebra_l2_vxlanif_del(ifp); - - if_delete_update(&ifp); - - /* If VRF, delete the VRF structure itself. */ - if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) - netlink_vrf_change(h, tb[IFLA_LINKINFO], ns_id, name); + zlog_debug("RTM_DELLINK for %s(%u), enqueuing to zebra", + name, ifi->ifi_index); + + dplane_ctx_set_op(ctx, DPLANE_OP_INTF_DELETE); + dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_QUEUED); + + dplane_ctx_set_ifp_bond_ifindex(ctx, bond_ifindex); } + dplane_provider_enqueue_to_zebra(ctx); + return 0; } @@ -2258,6 +1759,13 @@ ssize_t netlink_intf_msg_encode(uint16_t cmd, void interface_list(struct zebra_ns *zns) { interface_lookup_netlink(zns); + + zebra_dplane_startup_stage(zns, ZEBRA_DPLANE_INTERFACES_READ); +} + +void interface_list_second(struct zebra_ns *zns) +{ + zebra_if_update_all_links(zns); /* We add routes for interface address, * so we need to get the nexthop info * from the kernel before we can do that @@ -2265,6 +1773,8 @@ void interface_list(struct zebra_ns *zns) netlink_nexthop_read(zns); interface_addr_lookup_netlink(zns); + + zebra_dplane_startup_stage(zns, ZEBRA_DPLANE_ADDRESSES_READ); } /** diff --git a/zebra/interface.c b/zebra/interface.c index 8cf934bf76..e923c0a187 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1294,6 +1294,9 @@ static void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx, const struct prefix *addr, *dest = NULL; enum dplane_op_e op; + if (!ifp) + return; + op = dplane_ctx_get_op(ctx); addr = dplane_ctx_get_intf_addr(ctx); @@ -1412,6 +1415,13 @@ static void zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx, enum dplane_netconf_status_e mpls, mcast_on, linkdown; bool *mcast_set, *linkdown_set; + if (!ifp && ifindex != -1 && ifindex != -2) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: Can't find ifp(%u)", __func__, ifindex); + + return; + } + afi = dplane_ctx_get_afi(ctx); mpls = dplane_ctx_get_netconf_mpls(ctx); linkdown = dplane_ctx_get_netconf_linkdown(ctx); @@ -1481,6 +1491,753 @@ static void zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx, (*linkdown_set ? "ON" : "OFF")); } +static void interface_vrf_change(enum dplane_op_e op, ifindex_t ifindex, + const char *name, uint32_t tableid, + ns_id_t ns_id) +{ + struct vrf *vrf; + struct zebra_vrf *zvrf = NULL; + + if (op == DPLANE_OP_INTF_DELETE) { + if (IS_ZEBRA_DEBUG_DPLANE) + zlog_debug("DPLANE_OP_INTF_DELETE for VRF %s(%u)", name, + ifindex); + + vrf = vrf_lookup_by_id((vrf_id_t)ifindex); + if (!vrf) { + flog_warn(EC_ZEBRA_VRF_NOT_FOUND, + "%s(%u): vrf not found", name, ifindex); + return; + } + + vrf_delete(vrf); + } else { + if (IS_ZEBRA_DEBUG_DPLANE) + zlog_debug( + "DPLANE_OP_INTF_UPDATE for VRF %s(%u) table %u", + name, ifindex, tableid); + + if (!vrf_lookup_by_id((vrf_id_t)ifindex)) { + vrf_id_t exist_id; + + exist_id = zebra_vrf_lookup_by_table(tableid, ns_id); + if (exist_id != VRF_DEFAULT) { + vrf = vrf_lookup_by_id(exist_id); + + flog_err( + EC_ZEBRA_VRF_MISCONFIGURED, + "VRF %s id %u table id overlaps existing vrf %s(%d), misconfiguration exiting", + name, ifindex, vrf->name, vrf->vrf_id); + exit(-1); + } + } + + vrf = vrf_update((vrf_id_t)ifindex, name); + if (!vrf) { + flog_err(EC_LIB_INTERFACE, "VRF %s id %u not created", + name, ifindex); + return; + } + + /* + * This is the only place that we get the actual kernel table_id + * being used. We need it to set the table_id of the routes + * we are passing to the kernel.... And to throw some totally + * awesome parties. that too. + * + * At this point we *must* have a zvrf because the vrf_create + * callback creates one. We *must* set the table id + * before the vrf_enable because of( at the very least ) + * static routes being delayed for installation until + * during the vrf_enable callbacks. + */ + zvrf = (struct zebra_vrf *)vrf->info; + zvrf->table_id = tableid; + + /* Enable the created VRF. */ + if (!vrf_enable(vrf)) { + flog_err(EC_LIB_INTERFACE, + "Failed to enable VRF %s id %u", name, + ifindex); + return; + } + } +} + +/* + * Note: on netlink systems, there should be a 1-to-1 mapping + * between interface names and ifindex values. + */ +static void set_ifindex(struct interface *ifp, ifindex_t ifi_index, + struct zebra_ns *zns) +{ + struct interface *oifp; + + oifp = if_lookup_by_index_per_ns(zns, ifi_index); + if ((oifp != NULL) && (oifp != ifp)) { + if (ifi_index == IFINDEX_INTERNAL) + flog_err( + EC_LIB_INTERFACE, + "Netlink is setting interface %s ifindex to reserved internal value %u", + ifp->name, ifi_index); + else { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "interface index %d was renamed from %s to %s", + ifi_index, oifp->name, ifp->name); + if (if_is_up(oifp)) + flog_err( + EC_LIB_INTERFACE, + "interface rename detected on up interface: index %d was renamed from %s to %s, results are uncertain!", + ifi_index, oifp->name, ifp->name); + if_delete_update(&oifp); + } + } + if_set_index(ifp, ifi_index); +} + +static inline void zebra_if_set_ziftype(struct interface *ifp, + enum zebra_iftype zif_type, + enum zebra_slave_iftype zif_slave_type) +{ + struct zebra_if *zif; + + zif = (struct zebra_if *)ifp->info; + zif->zif_slave_type = zif_slave_type; + + if (zif->zif_type != zif_type) { + zif->zif_type = zif_type; + /* If the if_type has been set to bond initialize ES info + * against it. XXX - note that we don't handle the case where + * a zif changes from bond to non-bond; it is really + * an unexpected/error condition. + */ + zebra_evpn_if_init(zif); + } +} + +static void interface_update_hw_addr(struct zebra_dplane_ctx *ctx, + struct interface *ifp) +{ + int i; + + ifp->hw_addr_len = dplane_ctx_get_ifp_hw_addr_len(ctx); + memcpy(ifp->hw_addr, dplane_ctx_get_ifp_hw_addr(ctx), ifp->hw_addr_len); + + for (i = 0; i < ifp->hw_addr_len; i++) + if (ifp->hw_addr[i] != 0) + break; + + if (i == ifp->hw_addr_len) + ifp->hw_addr_len = 0; +} + +static void interface_update_l2info(struct zebra_dplane_ctx *ctx, + struct interface *ifp, + enum zebra_iftype zif_type, int add, + ns_id_t link_nsid) +{ + const struct zebra_l2info_vxlan *vxlan_info; + const struct zebra_l2info_gre *gre_info; + + switch (zif_type) { + case ZEBRA_IF_BRIDGE: + zebra_l2_bridge_add_update(ifp, + dplane_ctx_get_ifp_bridge_info(ctx)); + break; + case ZEBRA_IF_VLAN: + zebra_l2_vlanif_update(ifp, dplane_ctx_get_ifp_vlan_info(ctx)); + zebra_evpn_acc_bd_svi_set(ifp->info, NULL, + !!if_is_operative(ifp)); + break; + case ZEBRA_IF_VXLAN: + vxlan_info = dplane_ctx_get_ifp_vxlan_info(ctx); + zebra_l2_vxlanif_add_update(ifp, vxlan_info, add); + if (link_nsid != NS_UNKNOWN && vxlan_info->ifindex_link) + zebra_if_update_link(ifp, vxlan_info->ifindex_link, + link_nsid); + break; + case ZEBRA_IF_GRE: + gre_info = dplane_ctx_get_ifp_gre_info(ctx); + zebra_l2_greif_add_update(ifp, gre_info, add); + if (link_nsid != NS_UNKNOWN && gre_info->ifindex_link) + zebra_if_update_link(ifp, gre_info->ifindex_link, + link_nsid); + break; + case ZEBRA_IF_OTHER: + case ZEBRA_IF_VRF: + case ZEBRA_IF_MACVLAN: + case ZEBRA_IF_VETH: + case ZEBRA_IF_BOND: + break; + } +} + +static bool is_if_protodown_reason_only_frr(uint32_t rc_bitfield) +{ + uint8_t frr_protodown_r_bit = if_netlink_get_frr_protodown_r_bit(); + + return (rc_bitfield == (((uint32_t)1) << frr_protodown_r_bit)); +} + +static void interface_if_protodown(struct interface *ifp, bool protodown, + uint32_t rc_bitfield) +{ + struct zebra_if *zif = ifp->info; + bool old_protodown; + + /* + * Set our reason code to note it wasn't us. + * If the reason we got from the kernel is ONLY frr though, don't + * set it. + */ + COND_FLAG(zif->protodown_rc, ZEBRA_PROTODOWN_EXTERNAL, + protodown && rc_bitfield && + !is_if_protodown_reason_only_frr(rc_bitfield)); + + + old_protodown = !!ZEBRA_IF_IS_PROTODOWN(zif); + if (protodown == old_protodown) + return; + + if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_DPLANE) + zlog_debug("interface %s dplane change, protodown %s", + ifp->name, protodown ? "on" : "off"); + + /* Set protodown, respectively */ + COND_FLAG(zif->flags, ZIF_FLAG_PROTODOWN, protodown); + + if (zebra_evpn_is_es_bond_member(ifp)) { + /* Check it's not already being sent to the dplane first */ + if (protodown && + CHECK_FLAG(zif->flags, ZIF_FLAG_SET_PROTODOWN)) { + if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "bond mbr %s protodown on recv'd but already sent protodown on to the dplane", + ifp->name); + return; + } + + if (!protodown && + CHECK_FLAG(zif->flags, ZIF_FLAG_UNSET_PROTODOWN)) { + if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "bond mbr %s protodown off recv'd but already sent protodown off to the dplane", + ifp->name); + return; + } + + if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "bond mbr %s reinstate protodown %s in the dplane", + ifp->name, old_protodown ? "on" : "off"); + + if (old_protodown) + SET_FLAG(zif->flags, ZIF_FLAG_SET_PROTODOWN); + else + SET_FLAG(zif->flags, ZIF_FLAG_UNSET_PROTODOWN); + + dplane_intf_update(zif->ifp); + } +} + +static void if_sweep_protodown(struct zebra_if *zif) +{ + bool protodown; + + protodown = !!ZEBRA_IF_IS_PROTODOWN(zif); + + if (!protodown) + return; + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("interface %s sweeping protodown %s reason 0x%x", + zif->ifp->name, protodown ? "on" : "off", + zif->protodown_rc); + + /* Only clear our reason codes, leave external if it was set */ + UNSET_FLAG(zif->protodown_rc, ZEBRA_PROTODOWN_ALL); + dplane_intf_update(zif->ifp); +} + +static void +interface_bridge_vxlan_vlan_vni_map_update(struct zebra_dplane_ctx *ctx, + struct interface *ifp) +{ + const struct zebra_vxlan_vni_array *vniarray = + dplane_ctx_get_ifp_vxlan_vni_array(ctx); + struct zebra_vxlan_vni vni_start, vni_end; + struct hash *vni_table = NULL; + struct zebra_vxlan_vni vni, *vnip; + vni_t vni_id; + vlanid_t vid; + int i; + + memset(&vni_start, 0, sizeof(vni_start)); + memset(&vni_end, 0, sizeof(vni_end)); + + for (i = 0; i < vniarray->count; i++) { + uint16_t flags = vniarray->vnis[i].flags; + + if (flags & DPLANE_BRIDGE_VLAN_INFO_RANGE_BEGIN) { + vni_start = vniarray->vnis[i]; + continue; + } + + if (flags & DPLANE_BRIDGE_VLAN_INFO_RANGE_END) + vni_end = vniarray->vnis[i]; + + if (!(flags & DPLANE_BRIDGE_VLAN_INFO_RANGE_END)) { + vni_start = vniarray->vnis[i]; + vni_end = vniarray->vnis[i]; + } + + if (IS_ZEBRA_DEBUG_DPLANE) + zlog_debug( + "Vlan-Vni(%d:%d-%d:%d) update for VxLAN IF %s(%u)", + vni_start.access_vlan, vni_end.access_vlan, + vni_start.vni, vni_end.vni, ifp->name, + ifp->ifindex); + + if (!vni_table) { + vni_table = zebra_vxlan_vni_table_create(); + if (!vni_table) + return; + } + + for (vid = vni_start.access_vlan, vni_id = vni_start.vni; + vid <= vni_end.access_vlan; vid++, vni_id++) { + + memset(&vni, 0, sizeof(vni)); + vni.vni = vni_id; + vni.access_vlan = vid; + vnip = hash_get(vni_table, &vni, zebra_vxlan_vni_alloc); + if (!vnip) + return; + } + + memset(&vni_start, 0, sizeof(vni_start)); + memset(&vni_end, 0, sizeof(vni_end)); + } + + if (vni_table) + zebra_vxlan_if_vni_table_add_update(ifp, vni_table); +} + +static void interface_bridge_vxlan_update(struct zebra_dplane_ctx *ctx, + struct interface *ifp) +{ + struct zebra_if *zif = ifp->info; + const struct zebra_dplane_bridge_vlan_info *bvinfo; + + if (IS_ZEBRA_VXLAN_IF_SVD(zif)) + interface_bridge_vxlan_vlan_vni_map_update(ctx, ifp); + + bvinfo = dplane_ctx_get_ifp_bridge_vlan_info(ctx); + + if (!(bvinfo->flags & DPLANE_BRIDGE_VLAN_INFO_PVID)) + return; + + if (IS_ZEBRA_DEBUG_DPLANE) + zlog_debug("Access VLAN %u for VxLAN IF %s(%u)", bvinfo->vid, + ifp->name, ifp->ifindex); + + zebra_l2_vxlanif_update_access_vlan(ifp, bvinfo->vid); +} + +static void interface_bridge_vlan_update(struct zebra_dplane_ctx *ctx, + struct interface *ifp) +{ + struct zebra_if *zif = ifp->info; + const struct zebra_dplane_bridge_vlan_info_array *bvarray; + struct zebra_dplane_bridge_vlan_info bvinfo; + bitfield_t old_vlan_bitmap; + uint16_t vid_range_start = 0; + int32_t i; + + /* cache the old bitmap addrs */ + old_vlan_bitmap = zif->vlan_bitmap; + /* create a new bitmap space for re-eval */ + bf_init(zif->vlan_bitmap, IF_VLAN_BITMAP_MAX); + + /* Could we have multiple bridge vlan infos? */ + bvarray = dplane_ctx_get_ifp_bridge_vlan_info_array(ctx); + if (!bvarray) + return; + + for (i = 0; i < bvarray->count; i++) { + bvinfo = bvarray->array[i]; + + if (bvinfo.flags & DPLANE_BRIDGE_VLAN_INFO_RANGE_BEGIN) { + vid_range_start = bvinfo.vid; + continue; + } + + if (!(bvinfo.flags & DPLANE_BRIDGE_VLAN_INFO_RANGE_END)) + vid_range_start = bvinfo.vid; + + zebra_vlan_bitmap_compute(ifp, vid_range_start, bvinfo.vid); + } + + zebra_vlan_mbr_re_eval(ifp, old_vlan_bitmap); + bf_free(old_vlan_bitmap); +} + +static void interface_bridge_handling(struct zebra_dplane_ctx *ctx, + struct interface *ifp, + enum zebra_iftype zif_type) +{ + struct zebra_if *zif; + + if (!ifp) { + zlog_warn("Cannot find bridge if %s(%u)", + dplane_ctx_get_ifname(ctx), + dplane_ctx_get_ifindex(ctx)); + return; + } + + if (IS_ZEBRA_IF_VXLAN(ifp)) + return interface_bridge_vxlan_update(ctx, ifp); + + /* + * build vlan bitmap associated with this interface if that + * device type is interested in the vlans + */ + zif = ifp->info; + if (bf_is_inited(zif->vlan_bitmap)) + interface_bridge_vlan_update(ctx, ifp); +} + +static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx) +{ + enum dplane_op_e op = dplane_ctx_get_op(ctx); + const char *name = dplane_ctx_get_ifname(ctx); + ns_id_t ns_id = dplane_ctx_get_ns_id(ctx); + ifindex_t ifindex = dplane_ctx_get_ifindex(ctx); + ifindex_t bond_ifindex = dplane_ctx_get_ifp_bond_ifindex(ctx); + uint32_t tableid = dplane_ctx_get_ifp_table_id(ctx); + enum zebra_iftype zif_type = dplane_ctx_get_ifp_zif_type(ctx); + struct interface *ifp; + struct zebra_ns *zns; + + zns = zebra_ns_lookup(ns_id); + if (!zns) { + zlog_err("Where is our namespace?"); + return; + } + + if (IS_ZEBRA_DEBUG_DPLANE) + zlog_debug("%s for %s(%u)", dplane_op2str(op), name, ifindex); + + ifp = if_lookup_by_name_per_ns(zns, name); + if (op == DPLANE_OP_INTF_DELETE) { + /* Delete interface notification from kernel */ + if (ifp == NULL) { + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug( + "Delete LINK received for unknown interface %s(%u)", + name, ifindex); + return; + } + + if (IS_ZEBRA_IF_BOND(ifp)) + zebra_l2if_update_bond(ifp, false); + if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) + zebra_l2if_update_bond_slave(ifp, bond_ifindex, false); + /* Special handling for bridge or VxLAN interfaces. */ + if (IS_ZEBRA_IF_BRIDGE(ifp)) + zebra_l2_bridge_del(ifp); + else if (IS_ZEBRA_IF_VXLAN(ifp)) + zebra_l2_vxlanif_del(ifp); + + if_delete_update(&ifp); + + if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) + interface_vrf_change(op, ifindex, name, tableid, ns_id); + } else { + ifindex_t master_ifindex, bridge_ifindex, bond_ifindex, + link_ifindex; + enum zebra_slave_iftype zif_slave_type; + uint8_t bypass; + uint64_t flags; + vrf_id_t vrf_id; + uint32_t mtu; + ns_id_t link_nsid; + struct zebra_if *zif; + bool protodown, protodown_set, startup; + uint32_t rc_bitfield; + uint8_t old_hw_addr[INTERFACE_HWADDR_MAX]; + char *desc; + uint8_t family; + + /* If VRF, create or update the VRF structure itself. */ + if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) + interface_vrf_change(op, ifindex, name, tableid, ns_id); + + master_ifindex = dplane_ctx_get_ifp_master_ifindex(ctx); + zif_slave_type = dplane_ctx_get_ifp_zif_slave_type(ctx); + bridge_ifindex = dplane_ctx_get_ifp_bridge_ifindex(ctx); + bond_ifindex = dplane_ctx_get_ifp_bond_ifindex(ctx); + bypass = dplane_ctx_get_ifp_bypass(ctx); + flags = dplane_ctx_get_ifp_flags(ctx); + vrf_id = dplane_ctx_get_ifp_vrf_id(ctx); + mtu = dplane_ctx_get_ifp_mtu(ctx); + link_ifindex = dplane_ctx_get_ifp_link_ifindex(ctx); + link_nsid = dplane_ctx_get_ifp_link_nsid(ctx); + protodown_set = dplane_ctx_get_ifp_protodown_set(ctx); + protodown = dplane_ctx_get_ifp_protodown(ctx); + rc_bitfield = dplane_ctx_get_ifp_rc_bitfield(ctx); + startup = dplane_ctx_get_ifp_startup(ctx); + desc = dplane_ctx_get_ifp_desc(ctx); + family = dplane_ctx_get_ifp_family(ctx); + +#ifndef AF_BRIDGE + /* + * Work around to make free bsd happy at the moment + */ +#define AF_BRIDGE 7 +#endif + if (family == AF_BRIDGE) + return interface_bridge_handling(ctx, ifp, zif_type); + + if (ifp == NULL || + !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { + /* Add interface notification from kernel */ + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "RTM_NEWLINK ADD for %s(%u) vrf_id %u type %d sl_type %d master %u", + name, ifindex, vrf_id, zif_type, + zif_slave_type, master_ifindex); + + if (ifp == NULL) { + /* unknown interface */ + ifp = if_get_by_name(name, vrf_id, NULL); + } else { + /* pre-configured interface, learnt now */ + if (ifp->vrf->vrf_id != vrf_id) + if_update_to_new_vrf(ifp, vrf_id); + } + + /* Update interface information. */ + set_ifindex(ifp, ifindex, zns); + ifp->flags = flags; + ifp->mtu6 = ifp->mtu = mtu; + ifp->metric = 0; + ifp->speed = kernel_get_speed(ifp, NULL); + ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN; + + /* Set interface type */ + zebra_if_set_ziftype(ifp, zif_type, zif_slave_type); + if (IS_ZEBRA_IF_VRF(ifp)) + SET_FLAG(ifp->status, + ZEBRA_INTERFACE_VRF_LOOPBACK); + + /* Update link. */ + zebra_if_update_link(ifp, link_ifindex, link_nsid); + + /* + * 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; + + ifp->ll_type = dplane_ctx_get_ifp_zltype(ctx); + interface_update_hw_addr(ctx, ifp); + + /* Inform clients, install any configured addresses. */ + if_add_update(ifp); + + /* + * Extract and save L2 interface information, take + * additional actions. + */ + interface_update_l2info(ctx, ifp, zif_type, 1, + link_nsid); + if (IS_ZEBRA_IF_BOND(ifp)) + zebra_l2if_update_bond(ifp, true); + if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) + zebra_l2if_update_bridge_slave( + ifp, bridge_ifindex, ns_id, + ZEBRA_BRIDGE_NO_ACTION); + else if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) + zebra_l2if_update_bond_slave(ifp, bond_ifindex, + !!bypass); + + if (protodown_set) { + interface_if_protodown(ifp, protodown, + rc_bitfield); + if (startup) + if_sweep_protodown(zif); + } + + if (IS_ZEBRA_IF_BRIDGE(ifp)) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "RTM_NEWLINK ADD for %s(%u), vlan-aware %d", + name, ifp->ifindex, + IS_ZEBRA_IF_BRIDGE_VLAN_AWARE( + zif)); + } + } else if (ifp->vrf->vrf_id != vrf_id) { + /* VRF change for an interface. */ + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "RTM_NEWLINK vrf-change for %s(%u) vrf_id %u -> %u", + name, ifp->ifindex, ifp->vrf->vrf_id, + vrf_id); + + if_handle_vrf_change(ifp, vrf_id); + } else { + bool was_bridge_slave, was_bond_slave; + uint8_t chgflags = ZEBRA_BRIDGE_NO_ACTION; + + zif = ifp->info; + + /* Interface update. */ + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "RTM_NEWLINK update for %s(%u) sl_type %d master %u", + name, ifp->ifindex, zif_slave_type, + master_ifindex); + + set_ifindex(ifp, ifindex, zns); + ifp->mtu6 = ifp->mtu = mtu; + ifp->metric = 0; + + /* + * Update interface type - NOTE: Only slave_type can + * change. + */ + was_bridge_slave = IS_ZEBRA_IF_BRIDGE_SLAVE(ifp); + was_bond_slave = IS_ZEBRA_IF_BOND_SLAVE(ifp); + zebra_if_set_ziftype(ifp, zif_type, zif_slave_type); + + memcpy(old_hw_addr, ifp->hw_addr, INTERFACE_HWADDR_MAX); + + /* Update link. */ + zebra_if_update_link(ifp, link_ifindex, link_nsid); + + ifp->ll_type = dplane_ctx_get_ifp_zltype(ctx); + interface_update_hw_addr(ctx, ifp); + + if (protodown_set) + interface_if_protodown(ifp, protodown, + rc_bitfield); + + if (if_is_no_ptm_operative(ifp)) { + bool is_up = if_is_operative(ifp); + + ifp->flags = flags; + if (!if_is_no_ptm_operative(ifp) || + CHECK_FLAG(zif->flags, + ZIF_FLAG_PROTODOWN)) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "Intf %s(%u) has gone DOWN", + name, ifp->ifindex); + if_down(ifp); + rib_update(RIB_UPDATE_KERNEL); + } else if (if_is_operative(ifp)) { + bool mac_updated = false; + + /* + * Must notify client daemons of new + * interface status. + */ + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "Intf %s(%u) PTM up, notifying clients", + name, ifp->ifindex); + if_up(ifp, !is_up); + + /* + * Update EVPN VNI when SVI MAC change + */ + if (memcmp(old_hw_addr, ifp->hw_addr, + INTERFACE_HWADDR_MAX)) + mac_updated = true; + if (IS_ZEBRA_IF_VLAN(ifp) && + mac_updated) { + struct interface *link_if; + + link_if = if_lookup_by_index_per_ns( + zebra_ns_lookup( + NS_DEFAULT), + link_ifindex); + if (link_if) + zebra_vxlan_svi_up( + ifp, link_if); + } else if (mac_updated && + IS_ZEBRA_IF_BRIDGE(ifp)) { + zlog_debug( + "Intf %s(%u) bridge changed MAC address", + name, ifp->ifindex); + chgflags = + ZEBRA_BRIDGE_MASTER_MAC_CHANGE; + } + } + } else { + ifp->flags = flags; + if (if_is_operative(ifp) && + !CHECK_FLAG(zif->flags, + ZIF_FLAG_PROTODOWN)) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "Intf %s(%u) has come UP", + name, ifp->ifindex); + if_up(ifp, true); + if (IS_ZEBRA_IF_BRIDGE(ifp)) + chgflags = + ZEBRA_BRIDGE_MASTER_UP; + } else { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "Intf %s(%u) has gone DOWN", + name, ifp->ifindex); + if_down(ifp); + rib_update(RIB_UPDATE_KERNEL); + } + } + + /* + * Extract and save L2 interface information, take + * additional actions. + */ + interface_update_l2info(ctx, ifp, zif_type, 0, + link_nsid); + if (IS_ZEBRA_IF_BRIDGE(ifp)) + zebra_l2if_update_bridge(ifp, chgflags); + if (IS_ZEBRA_IF_BOND(ifp)) + zebra_l2if_update_bond(ifp, true); + if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) || was_bridge_slave) + zebra_l2if_update_bridge_slave( + ifp, bridge_ifindex, ns_id, chgflags); + else if (IS_ZEBRA_IF_BOND_SLAVE(ifp) || was_bond_slave) + zebra_l2if_update_bond_slave(ifp, bond_ifindex, + !!bypass); + if (IS_ZEBRA_IF_BRIDGE(ifp)) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "RTM_NEWLINK update for %s(%u), vlan-aware %d", + name, ifp->ifindex, + IS_ZEBRA_IF_BRIDGE_VLAN_AWARE( + zif)); + } + } + + zif = ifp->info; + if (zif) { + XFREE(MTYPE_ZIF_DESC, zif->desc); + if (desc[0]) + zif->desc = XSTRDUP(MTYPE_ZIF_DESC, desc); + } + } +} + void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx) { struct zebra_ns *zns; @@ -1510,17 +2267,6 @@ void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx) } ifp = if_lookup_by_index_per_ns(zns, ifindex); - if (ifp == NULL) { - if (op != DPLANE_OP_INTF_NETCONFIG || - (ifindex != -1 && ifindex != -2)) { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "%s: can't find ifp at nsid %u index %d", - __func__, ns_id, ifindex); - - return; - } - } switch (op) { case DPLANE_OP_INTF_ADDR_ADD: @@ -1531,7 +2277,15 @@ void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_INTF_INSTALL: case DPLANE_OP_INTF_UPDATE: case DPLANE_OP_INTF_DELETE: - zebra_if_update_ctx(ctx, ifp); + /* + * Queued from the dplane means it is something + * that we need to handle( create/delete the + * interface as needed ) + */ + if (dp_res == ZEBRA_DPLANE_REQUEST_QUEUED) + zebra_if_dplane_ifp_handling(ctx); + else + zebra_if_update_ctx(ctx, ifp); break; case DPLANE_OP_INTF_NETCONFIG: diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 2fab21ed93..f0d4427688 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -398,7 +398,7 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, case RTM_NEWLINK: return netlink_link_change(h, ns_id, startup); case RTM_DELLINK: - return netlink_link_change(h, ns_id, startup); + return 0; case RTM_NEWNEIGH: case RTM_DELNEIGH: case RTM_GETNEIGH: @@ -474,6 +474,7 @@ static int dplane_netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, case RTM_NEWLINK: case RTM_DELLINK: + return netlink_link_change(h, ns_id, startup); default: break; @@ -1169,7 +1170,6 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), h->nlmsg_type, h->nlmsg_len, h->nlmsg_seq, h->nlmsg_pid); - /* * Ignore messages that maybe sent from * other actors besides the kernel @@ -1778,17 +1778,11 @@ void kernel_init(struct zebra_ns *zns) * groups are added further below after SOL_NETLINK is verified to * exist. */ - groups = RTMGRP_LINK | - RTMGRP_IPV4_ROUTE | - RTMGRP_IPV4_IFADDR | - RTMGRP_IPV6_ROUTE | - RTMGRP_IPV6_IFADDR | - RTMGRP_IPV4_MROUTE | - RTMGRP_NEIGH | - ((uint32_t) 1 << (RTNLGRP_IPV4_RULE - 1)) | - ((uint32_t) 1 << (RTNLGRP_IPV6_RULE - 1)) | - ((uint32_t) 1 << (RTNLGRP_NEXTHOP - 1)) | - ((uint32_t) 1 << (RTNLGRP_TC - 1)); + groups = RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_IPV4_MROUTE | + RTMGRP_NEIGH | ((uint32_t)1 << (RTNLGRP_IPV4_RULE - 1)) | + ((uint32_t)1 << (RTNLGRP_IPV6_RULE - 1)) | + ((uint32_t)1 << (RTNLGRP_NEXTHOP - 1)) | + ((uint32_t)1 << (RTNLGRP_TC - 1)); dplane_groups = (RTMGRP_LINK | RTMGRP_IPV4_IFADDR | diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index ccbe9b27cf..fff3e6416f 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -1468,6 +1468,14 @@ static void routing_socket(struct zebra_ns *zns) event_add_read(zrouter.master, kernel_read, NULL, routing_sock, NULL); } +void interface_list_second(struct zebra_ns *zns) +{ +} + +void interface_list_tunneldump(struct zebra_ns *zns) +{ +} + /* Exported interface function. This function simply calls routing_socket (). */ void kernel_init(struct zebra_ns *zns) diff --git a/zebra/rt.h b/zebra/rt.h index 2e3495a037..af170a22aa 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -84,6 +84,8 @@ extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute); * state. */ extern void interface_list(struct zebra_ns *zns); +extern void interface_list_tunneldump(struct zebra_ns *zns); +extern void interface_list_second(struct zebra_ns *zns); extern void kernel_init(struct zebra_ns *zns); extern void kernel_terminate(struct zebra_ns *zns, bool complete); extern void macfdb_read(struct zebra_ns *zns); diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c index 518c948c99..3bb4936b81 100644 --- a/zebra/rule_netlink.c +++ b/zebra/rule_netlink.c @@ -400,6 +400,7 @@ int netlink_rules_read(struct zebra_ns *zns) ret = netlink_parse_info(netlink_rule_change, &zns->netlink_cmd, &dp_info, 0, true); + return ret; } diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index be18115939..4be3f28874 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -409,6 +409,19 @@ uint8_t dplane_ctx_get_ifp_family(const struct zebra_dplane_ctx *ctx); struct zebra_vxlan_vni_array; void dplane_ctx_set_ifp_vxlan_vni_array(struct zebra_dplane_ctx *ctx, struct zebra_vxlan_vni_array *vniarray); + +/* + * These defines mirror the values for bridge values in linux + * at this point since we only have a linux implementation + * we don't need to do any type of translation. Let's just + * pass these through and use them + */ +#define DPLANE_BRIDGE_VLAN_INFO_PVID \ + (1 << 1) /* VLAN is PVID, ingress untagged */ +#define DPLANE_BRIDGE_VLAN_INFO_RANGE_BEGIN \ + (1 << 3) /* VLAN is start of vlan range */ +#define DPLANE_BRIDGE_VLAN_INFO_RANGE_END \ + (1 << 4) /* VLAN is end of vlan range */ const struct zebra_vxlan_vni_array * dplane_ctx_get_ifp_vxlan_vni_array(const struct zebra_dplane_ctx *ctx); struct zebra_dplane_bridge_vlan_info { diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c index 52ef7350f1..39c1319f31 100644 --- a/zebra/zebra_l2.c +++ b/zebra/zebra_l2.c @@ -244,7 +244,7 @@ void zebra_l2if_update_bond(struct interface *ifp, bool add) * map slaves (if any) to the bridge. */ void zebra_l2_bridge_add_update(struct interface *ifp, - struct zebra_l2info_bridge *bridge_info) + const struct zebra_l2info_bridge *bridge_info) { struct zebra_if *zif; struct zebra_l2_bridge_if *br; @@ -283,7 +283,7 @@ void zebra_l2if_update_bridge(struct interface *ifp, uint8_t chgflags) * VLAN Id and this cannot change. */ void zebra_l2_vlanif_update(struct interface *ifp, - struct zebra_l2info_vlan *vlan_info) + const struct zebra_l2info_vlan *vlan_info) { struct zebra_if *zif; @@ -300,7 +300,7 @@ void zebra_l2_vlanif_update(struct interface *ifp, * clients about GRE information. */ void zebra_l2_greif_add_update(struct interface *ifp, - struct zebra_l2info_gre *gre_info, int add) + const struct zebra_l2info_gre *gre_info, int add) { struct zebra_if *zif; struct in_addr old_vtep_ip; @@ -327,7 +327,8 @@ void zebra_l2_greif_add_update(struct interface *ifp, * IP and VLAN mapping, but the latter is handled separately. */ void zebra_l2_vxlanif_add_update(struct interface *ifp, - struct zebra_l2info_vxlan *vxlan_info, int add) + const struct zebra_l2info_vxlan *vxlan_info, + int add) { struct zebra_if *zif; uint16_t chgflags = 0; diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h index c63310e279..588917f4c0 100644 --- a/zebra/zebra_l2.h +++ b/zebra/zebra_l2.h @@ -80,6 +80,12 @@ struct zebra_vxlan_vni { vni_t vni; /* VNI */ vlanid_t access_vlan; /* Access VLAN - for VLAN-aware bridge. */ struct in_addr mcast_grp; + uint16_t flags; +}; + +struct zebra_vxlan_vni_array { + uint16_t count; + struct zebra_vxlan_vni vnis[0]; }; enum { @@ -159,17 +165,19 @@ extern void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave, struct zebra_ns *zns); extern void zebra_l2_unmap_slave_from_bridge(struct zebra_l2info_brslave *br_slave); -extern void zebra_l2_bridge_add_update(struct interface *ifp, - struct zebra_l2info_bridge *bridge_info); +extern void +zebra_l2_bridge_add_update(struct interface *ifp, + const struct zebra_l2info_bridge *bridge_info); extern void zebra_l2_bridge_del(struct interface *ifp); extern void zebra_l2_vlanif_update(struct interface *ifp, - struct zebra_l2info_vlan *vlan_info); + const struct zebra_l2info_vlan *vlan_info); extern void zebra_l2_greif_add_update(struct interface *ifp, - struct zebra_l2info_gre *vxlan_info, + const struct zebra_l2info_gre *vxlan_info, int add); -extern void zebra_l2_vxlanif_add_update(struct interface *ifp, - struct zebra_l2info_vxlan *vxlan_info, - int add); +extern void +zebra_l2_vxlanif_add_update(struct interface *ifp, + const struct zebra_l2info_vxlan *vxlan_info, + int add); extern void zebra_l2_vxlanif_update_access_vlan(struct interface *ifp, vlanid_t access_vlan); extern void zebra_l2_greif_del(struct interface *ifp); diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index 6bb5e971e6..ffdb9df531 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -23,6 +23,7 @@ #include "rib.h" #include "table_manager.h" #include "zebra_errors.h" +#include "zebra_dplane.h" extern struct zebra_privs_t zserv_privs; @@ -101,6 +102,36 @@ int zebra_ns_disabled(struct ns *ns) return zebra_ns_disable_internal(zns, true); } +void zebra_ns_startup_continue(struct zebra_dplane_ctx *ctx) +{ + struct zebra_ns *zns = zebra_ns_lookup(dplane_ctx_get_ns_id(ctx)); + enum zebra_dplane_startup_notifications spot; + + if (!zns) { + zlog_err("%s: No Namespace associated with %u", __func__, + dplane_ctx_get_ns_id(ctx)); + return; + } + + spot = dplane_ctx_get_startup_spot(ctx); + + switch (spot) { + case ZEBRA_DPLANE_INTERFACES_READ: + interface_list_tunneldump(zns); + break; + case ZEBRA_DPLANE_TUNNELS_READ: + interface_list_second(zns); + break; + case ZEBRA_DPLANE_ADDRESSES_READ: + route_read(zns); + + vlan_read(zns); + kernel_read_pbr_rules(zns); + kernel_read_tc_qdisc(zns); + break; + } +} + /* Do global enable actions - open sockets, read kernel config etc. */ int zebra_ns_enable(ns_id_t ns_id, void **info) { @@ -111,11 +142,6 @@ int zebra_ns_enable(ns_id_t ns_id, void **info) kernel_init(zns); zebra_dplane_ns_enable(zns, true); interface_list(zns); - route_read(zns); - - vlan_read(zns); - kernel_read_pbr_rules(zns); - kernel_read_tc_qdisc(zns); return 0; } diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index e759d522fa..edf2611971 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -68,6 +68,8 @@ int zebra_ns_final_shutdown(struct ns *ns, void **param_out __attribute__((unused))); int zebra_ns_config_write(struct vty *vty, struct ns *ns); +void zebra_ns_startup_continue(struct zebra_dplane_ctx *ctx); + #ifdef __cplusplus } #endif diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 18345b052f..93b33c9abd 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -4862,7 +4862,9 @@ static void rib_process_dplane_results(struct event *thread) case DPLANE_OP_NEIGH_TABLE_UPDATE: case DPLANE_OP_GRE_SET: case DPLANE_OP_NONE: + break; case DPLANE_OP_STARTUP_STAGE: + zebra_ns_startup_continue(ctx); break; } /* Dispatch by op code */ -- 2.39.5