diff options
Diffstat (limited to 'zebra')
-rw-r--r-- | zebra/if_netlink.c | 852 | ||||
-rw-r--r-- | zebra/interface.c | 778 | ||||
-rw-r--r-- | zebra/kernel_netlink.c | 20 | ||||
-rw-r--r-- | zebra/kernel_socket.c | 8 | ||||
-rw-r--r-- | zebra/rt.h | 2 | ||||
-rw-r--r-- | zebra/rule_netlink.c | 1 | ||||
-rw-r--r-- | zebra/zebra_dplane.h | 13 | ||||
-rw-r--r-- | zebra/zebra_l2.c | 9 | ||||
-rw-r--r-- | zebra/zebra_l2.h | 22 | ||||
-rw-r--r-- | zebra/zebra_ns.c | 36 | ||||
-rw-r--r-- | zebra/zebra_ns.h | 2 | ||||
-rw-r--r-- | 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 55d63cc4e..8767b2622 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 8cf934bf7..e923c0a18 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 2fab21ed9..f0d442768 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 ccbe9b27c..fff3e6416 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 2e3495a03..af170a22a 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 518c948c9..3bb4936b8 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 be1811593..4be3f2887 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 52ef7350f..39c1319f3 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 c63310e27..588917f4c 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 6bb5e971e..ffdb9df53 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 e759d522f..edf261197 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 18345b052..93b33c9ab 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 */ |