From 9464e5b865a2995e436ce2986f5722921cb83394 Mon Sep 17 00:00:00 2001 From: Sharath Ramamurthy Date: Tue, 27 Jul 2021 21:59:00 +0530 Subject: [PATCH] zebra: Bug fixes in fdb read for flooded traffic and remote fdb cleanup upon vni removal This patch addresses following issues, - When the VLAN-VNI mapping is configured via a map and not using individual VXLAN interfaces, upon removal of a VNI ensure that the remote FDB entries are uninstalled correctly. - When VNI configuration is performed using VLAN-VNI mapping (i.e., without individual VXLAN interfaces) and flooded traffic is handled via multicast, the multicast group corresponding to the VNI needs to be explicitly read from the bridge FDB. This is relevant in the case of netlink interface to the kernel and for the scenario where a new VNI is provisioned or comes up. Signed-off-by: Sharath Ramamurthy --- zebra/if_netlink.c | 6 ++-- zebra/interface.c | 10 ++++-- zebra/rt.h | 2 ++ zebra/rt_netlink.c | 69 +++++++++++++++++++++++++++----------- zebra/rt_netlink.h | 2 ++ zebra/rtread_netlink.c | 6 ++++ zebra/rtread_sysctl.c | 5 +++ zebra/zebra_evpn.c | 10 ++++-- zebra/zebra_l2.h | 12 ++++--- zebra/zebra_l2_bridge_if.c | 5 ++- zebra/zebra_vxlan.c | 6 ++-- zebra/zebra_vxlan_if.c | 18 +++++----- 12 files changed, 108 insertions(+), 43 deletions(-) diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 6375fc1bd0..c097e23777 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -629,8 +629,10 @@ static int netlink_extract_vxlan_info(struct rtattr *link_data, } if (!svd) { - /* in case of svd we will not get vni info directly from the - * device */ + /* + * In case of svd we will not get vni info directly from the + * device + */ if (!attr[IFLA_VXLAN_ID]) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( diff --git a/zebra/interface.c b/zebra/interface.c index 11f61f64cf..dfac8ed2ec 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1893,12 +1893,15 @@ static inline bool if_is_protodown_applicable(struct interface *ifp) static void zebra_vxlan_if_vni_dump_vty(struct vty *vty, struct zebra_vxlan_vni *vni) { + char str[INET6_ADDRSTRLEN]; + vty_out(vty, " VxLAN Id %u", vni->vni); if (vni->access_vlan) vty_out(vty, " Access VLAN Id %u\n", vni->access_vlan); if (vni->mcast_grp.s_addr != INADDR_ANY) - vty_out(vty, " Mcast Group %s", inet_ntoa(vni->mcast_grp)); + vty_out(vty, " Mcast Group %s", + inet_ntop(AF_INET, &vni->mcast_grp, str, sizeof(str))); } static void zebra_vxlan_if_vni_dump_vty_json(struct zebra_vxlan_vni *vni, @@ -1938,6 +1941,7 @@ static void zebra_vxlan_if_vni_hash_dump_vty(struct hash_bucket *bucket, static void zebra_vxlan_if_dump_vty(struct vty *vty, struct zebra_if *zebra_if) { struct vxlan_if_dump_ctx dump_ctx; + char str[INET6_ADDRSTRLEN]; struct zebra_l2info_vxlan *vxlan_info; struct zebra_vxlan_vni_info *vni_info; @@ -1945,7 +1949,9 @@ static void zebra_vxlan_if_dump_vty(struct vty *vty, struct zebra_if *zebra_if) vni_info = &vxlan_info->vni_info; if (vxlan_info->vtep_ip.s_addr != INADDR_ANY) - vty_out(vty, " VTEP IP: %s", inet_ntoa(vxlan_info->vtep_ip)); + vty_out(vty, " VTEP IP: %s", + inet_ntop(AF_INET, &vxlan_info->vtep_ip, str, + sizeof(str))); if (vxlan_info->ifindex_link && (vxlan_info->link_nsid != NS_UNKNOWN)) { struct interface *ifp; diff --git a/zebra/rt.h b/zebra/rt.h index 8d5f780753..f17d11a5fb 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -104,6 +104,8 @@ extern void kernel_terminate(struct zebra_ns *zns, bool complete); extern void macfdb_read(struct zebra_ns *zns); extern void macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp, struct interface *br_if, vlanid_t vid); +extern void macfdb_read_mcast_entry_for_vni(struct zebra_ns *zns, + struct interface *ifp, vni_t vni); extern void macfdb_read_specific_mac(struct zebra_ns *zns, struct interface *br_if, const struct ethaddr *mac, vlanid_t vid); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 25cd50eef2..f205f297db 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -3596,6 +3596,7 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) /* For per vni device, vni comes from device itself */ if (IS_ZEBRA_IF_VXLAN(ifp) && IS_ZEBRA_VXLAN_IF_VNI(zif)) { struct zebra_vxlan_vni *vnip; + vnip = zebra_vxlan_if_vni_find(zif, 0); vni = vnip->vni; } @@ -3776,40 +3777,45 @@ int netlink_macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp, /* Request for MAC FDB for a specific MAC address in VLAN from the kernel */ -static int netlink_request_specific_mac_in_bridge(struct zebra_ns *zns, - int family, int type, - struct interface *br_if, - const struct ethaddr *mac, - vlanid_t vid) +static int netlink_request_specific_mac(struct zebra_ns *zns, int family, + int type, struct interface *ifp, + const struct ethaddr *mac, vlanid_t vid, + vni_t vni, uint8_t flags) { struct { struct nlmsghdr n; struct ndmsg ndm; char buf[256]; } req; - struct zebra_if *br_zif; + struct zebra_if *zif; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); req.n.nlmsg_type = type; /* RTM_GETNEIGH */ req.n.nlmsg_flags = NLM_F_REQUEST; req.ndm.ndm_family = family; /* AF_BRIDGE */ + req.ndm.ndm_flags = flags; /* req.ndm.ndm_state = NUD_REACHABLE; */ nl_attr_put(&req.n, sizeof(req), NDA_LLADDR, mac, 6); - br_zif = (struct zebra_if *)br_if->info; - if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif) && vid > 0) - nl_attr_put16(&req.n, sizeof(req), NDA_VLAN, vid); - - nl_attr_put32(&req.n, sizeof(req), NDA_MASTER, br_if->ifindex); + zif = (struct zebra_if *)ifp->info; + /* Is this a read on a VXLAN interface? */ + if (IS_ZEBRA_IF_VXLAN(ifp)) { + nl_attr_put32(&req.n, sizeof(req), NDA_VNI, vni); + /* TBD: Why is ifindex not filled in the non-vxlan case? */ + req.ndm.ndm_ifindex = ifp->ifindex; + } else { + if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif) && vid > 0) + nl_attr_put16(&req.n, sizeof(req), NDA_VLAN, vid); + nl_attr_put32(&req.n, sizeof(req), NDA_MASTER, ifp->ifindex); + } if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "%s: Tx family %s IF %s(%u) vrf %s(%u) MAC %pEA vid %u", - __func__, nl_family_to_str(req.ndm.ndm_family), - br_if->name, br_if->ifindex, br_if->vrf->name, - br_if->vrf->vrf_id, mac, vid); + zlog_debug("Tx %s %s IF %s(%u) MAC %pEA vid %u vni %u", + nl_msg_type_to_str(type), + nl_family_to_str(req.ndm.ndm_family), ifp->name, + ifp->ifindex, mac, vid, vni); return netlink_request(&zns->netlink_cmd, &req); } @@ -3825,9 +3831,34 @@ int netlink_macfdb_read_specific_mac(struct zebra_ns *zns, /* Get bridge FDB table for specific bridge - we do the VLAN filtering. */ - ret = netlink_request_specific_mac_in_bridge(zns, AF_BRIDGE, - RTM_GETNEIGH, - br_if, mac, vid); + ret = netlink_request_specific_mac(zns, AF_BRIDGE, RTM_GETNEIGH, br_if, + mac, vid, 0, 0); + if (ret < 0) + return ret; + + ret = netlink_parse_info(netlink_macfdb_table, &zns->netlink_cmd, + &dp_info, 1, 0); + + return ret; +} + +int netlink_macfdb_read_mcast_for_vni(struct zebra_ns *zns, + struct interface *ifp, vni_t vni) +{ + struct zebra_if *zif; + struct ethaddr mac = { .octet = {0} }; + struct zebra_dplane_info dp_info; + int ret = 0; + + zif = ifp->info; + if (IS_ZEBRA_VXLAN_IF_VNI(zif)) + return 0; + + zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/); + + /* Get specific FDB entry for BUM handling, if any */ + ret = netlink_request_specific_mac(zns, AF_BRIDGE, RTM_GETNEIGH, ifp, + &mac, 0, vni, NTF_SELF); if (ret < 0) return ret; diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index f7e777ba8f..b550cc06b7 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -94,6 +94,8 @@ extern int netlink_macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp, struct interface *br_if, vlanid_t vid); +extern int netlink_macfdb_read_mcast_for_vni(struct zebra_ns *zns, + struct interface *ifp, vni_t vni); extern int netlink_neigh_read(struct zebra_ns *zns); extern int netlink_neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if); diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c index 578f321279..a85d8a4894 100644 --- a/zebra/rtread_netlink.c +++ b/zebra/rtread_netlink.c @@ -47,6 +47,12 @@ void macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp, netlink_macfdb_read_for_bridge(zns, ifp, br_if, vid); } +void macfdb_read_mcast_entry_for_vni(struct zebra_ns *zns, + struct interface *ifp, vni_t vni) +{ + netlink_macfdb_read_mcast_for_vni(zns, ifp, vni); +} + void macfdb_read_specific_mac(struct zebra_ns *zns, struct interface *br_if, const struct ethaddr *mac, vlanid_t vid) { diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c index e80f665799..c8a89b3a55 100644 --- a/zebra/rtread_sysctl.c +++ b/zebra/rtread_sysctl.c @@ -88,6 +88,11 @@ void macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp, { } +void macfdb_read_mcast_entry_for_vni(struct zebra_ns *zns, + struct interface *ifp, vni_t vni) +{ +} + void macfdb_read_specific_mac(struct zebra_ns *zns, struct interface *br_if, const struct ethaddr *mac, vlanid_t vid) { diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c index 214f34c58e..77b028ad64 100644 --- a/zebra/zebra_evpn.c +++ b/zebra/zebra_evpn.c @@ -695,8 +695,10 @@ static int zebra_evpn_map_vlan_ns(struct ns *ns, if (vni_id) found = 1; } else { - /* See if this interface (or interface plus VLAN Id) maps to a - * VxLAN */ + /* + * See if this interface (or interface plus VLAN Id) maps to a + * VxLAN + */ /* TODO: Optimize with a hash. */ for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { tmp_if = (struct interface *)rn->info; @@ -982,6 +984,10 @@ void zebra_evpn_read_mac_neigh(struct zebra_evpn *zevpn, struct interface *ifp) macfdb_read_for_bridge(zns, ifp, zif->brslave_info.br_if, vni->access_vlan); + /* We need to specifically read and retrieve the entry for BUM handling + * via multicast, if any. + */ + macfdb_read_mcast_entry_for_vni(zns, ifp, zevpn->vni); vlan_if = zvni_map_to_svi(vni->access_vlan, zif->brslave_info.br_if); if (vlan_if) { /* Add SVI MAC */ diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h index 01084a09a9..84cdf9b484 100644 --- a/zebra/zebra_l2.h +++ b/zebra/zebra_l2.h @@ -57,7 +57,8 @@ struct zebra_l2_bridge_vlan { struct zebra_l2_bridge_if_ctx { /* input */ struct zebra_if *zif; - int (*func)(struct zebra_if *, struct zebra_l2_bridge_vlan *, void *); + int (*func)(struct zebra_if *zif, struct zebra_l2_bridge_vlan *vlan, + void *arg); /* input-output */ void *arg; @@ -97,10 +98,10 @@ struct zebra_vxlan_vni { struct in_addr mcast_grp; }; -typedef enum { +enum { ZEBRA_VXLAN_IF_VNI = 0, /* per vni vxlan if */ ZEBRA_VXLAN_IF_SVD /* single vxlan device */ -} zebra_vxlan_iftype_t; +}; struct zebra_vxlan_if_vlan_ctx { vlanid_t vid; @@ -110,14 +111,15 @@ struct zebra_vxlan_if_vlan_ctx { struct zebra_vxlan_if_ctx { /* input */ struct zebra_if *zif; - int (*func)(struct zebra_if *, struct zebra_vxlan_vni *, void *); + int (*func)(struct zebra_if *zif, struct zebra_vxlan_vni *vni, + void *arg); /* input-output */ void *arg; }; struct zebra_vxlan_vni_info { - zebra_vxlan_iftype_t iftype; + int iftype; union { struct zebra_vxlan_vni vni; /* per vni vxlan device vni info */ struct hash diff --git a/zebra/zebra_l2_bridge_if.c b/zebra/zebra_l2_bridge_if.c index 6dc3e93bb0..6574899927 100644 --- a/zebra/zebra_l2_bridge_if.c +++ b/zebra/zebra_l2_bridge_if.c @@ -174,7 +174,7 @@ static int zebra_l2_bridge_if_vlan_table_create(struct zebra_if *zif) if (!br->vlan_table) { br->vlan_table = zebra_l2_bridge_vlan_table_create(); if (!br->vlan_table) - return ENOMEM; + return -ENOMEM; } return 0; @@ -340,9 +340,8 @@ int zebra_l2_bridge_if_vlan_access_bd_ref(struct zebra_evpn_access_bd *bd) bvl.access_bd = bd; bvlan = zebra_l2_bridge_if_vlan_find(zif, bd->vid); - if (!bvlan) { + if (!bvlan) return zebra_l2_bridge_if_vlan_add(zif->ifp, &bvl); - } chgflags = ZEBRA_BRIDGEIF_ACCESS_BD_CHANGE; return zebra_l2_bridge_if_vlan_update(zif->ifp, &bvl, chgflags); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 9101dbe6a3..61cbc65e32 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -982,8 +982,10 @@ static int zevpn_build_vni_hash_table(struct zebra_if *zif, "Create L2-VNI hash for intf %s(%u) L2-VNI %u local IP %pI4", ifp->name, ifp->ifindex, vni, &vxl->vtep_ip); - /* EVPN hash entry is expected to exist, if the BGP process is - * killed */ + /* + * EVPN hash entry is expected to exist, if the BGP process is + * killed + */ zevpn = zebra_evpn_lookup(vni); if (zevpn) { zlog_debug( diff --git a/zebra/zebra_vxlan_if.c b/zebra/zebra_vxlan_if.c index 78a04372dc..df9ad7795f 100644 --- a/zebra/zebra_vxlan_if.c +++ b/zebra/zebra_vxlan_if.c @@ -156,11 +156,11 @@ static int zebra_vxlan_if_del_vni(struct interface *ifp, zebra_evpn_send_del_to_client(zevpn); /* Free up all neighbors and MAC, if any. */ - zebra_evpn_neigh_del_all(zevpn, 0, 0, DEL_ALL_NEIGH); - zebra_evpn_mac_del_all(zevpn, 0, 0, DEL_ALL_MAC); + zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH); + zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC); /* Free up all remote VTEPs, if any. */ - zebra_evpn_vtep_del_all(zevpn, 0); + zebra_evpn_vtep_del_all(zevpn, 1); /* Delete the hash entry. */ if (zebra_evpn_vxlan_del(zevpn)) { @@ -401,8 +401,10 @@ static int zebra_vxlan_if_add_vni(struct interface *ifp, zl3vni->local_vtep_ip = vxl->vtep_ip; zl3vni->vxlan_if = ifp; - /* Associate with SVI, if any. We can associate with svi-if only - * after association with vxlan_if is complete */ + /* + * Associate with SVI, if any. We can associate with svi-if only + * after association with vxlan_if is complete + */ zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni); @@ -498,8 +500,8 @@ static int zebra_vxlan_if_add_update_vni(struct zebra_if *zif, old_vni_table = (struct hash *)ctxt; memcpy(&vni_tmp, vni, sizeof(*vni)); - if ((hashcount(old_vni_table) == 0) - || !(old_vni = hash_release(old_vni_table, &vni_tmp))) { + old_vni = hash_release(old_vni_table, &vni_tmp); + if (!old_vni) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug("vxlan %s adding vni(%d, %d)", zif->ifp->name, vni->vni, vni->access_vlan); @@ -633,7 +635,7 @@ int zebra_vxlan_if_vni_table_create(struct zebra_if *zif) vni_info = VNI_INFO_FROM_ZEBRA_IF(zif); vni_info->vni_table = zebra_vxlan_vni_table_create(); if (!vni_info->vni_table) - return ENOMEM; + return -ENOMEM; return 0; } -- 2.39.5