diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 3b4e048aff..6375fc1bd0 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -720,16 +720,110 @@ static void netlink_interface_update_l2info(struct interface *ifp, } } +static int netlink_bridge_vxlan_vlan_vni_map_update(struct interface *ifp, + 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 vni_end; + struct zebra_vxlan_vni vni_start; + struct rtattr *aftb[IFLA_BRIDGE_VLAN_TUNNEL_MAX + 1]; + + 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_TUNNEL_INFO) + continue; + + memset(aftb, 0, sizeof(aftb)); + netlink_parse_rtattr_nested(aftb, IFLA_BRIDGE_VLAN_TUNNEL_MAX, + i); + if (!aftb[IFLA_BRIDGE_VLAN_TUNNEL_ID] + || !aftb[IFLA_BRIDGE_VLAN_TUNNEL_VID]) + /* vlan-vni info missing */ + return 0; + + flags = 0; + memset(&vni, 0, sizeof(vni)); + + vni.vni = *(vni_t *)RTA_DATA(aftb[IFLA_BRIDGE_VLAN_TUNNEL_ID]); + vni.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)); + } + + if (vni_table) + zebra_vxlan_if_vni_table_add_update(ifp, vni_table); + + return 0; +} + static int netlink_bridge_vxlan_update(struct interface *ifp, struct rtattr *af_spec) { struct rtattr *aftb[IFLA_BRIDGE_MAX + 1]; struct bridge_vlan_info *vinfo; + struct zebra_if *zif; vlanid_t access_vlan; 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); + /* There is a 1-to-1 mapping of VLAN to VxLAN - hence * only 1 access VLAN is accepted. */ diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 6fbe350435..25cd50eef2 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -3633,12 +3633,12 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) return 0; if (vni_mcast_grp) - /* TODO: handle mcast group update for svd */ + return zebra_vxlan_if_vni_mcast_group_update( + ifp, vni, &vtep_ip); - return zebra_vxlan_dp_network_mac_add( - ifp, br_if, &mac, vid, vni, nhg_id, - sticky, - !!(ndm->ndm_flags & NTF_EXT_LEARNED)); + return zebra_vxlan_dp_network_mac_add( + ifp, br_if, &mac, vid, vni, nhg_id, sticky, + !!(ndm->ndm_flags & NTF_EXT_LEARNED)); } return zebra_vxlan_local_mac_add_update(ifp, br_if, &mac, vid, @@ -3660,11 +3660,11 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) if (dst_present) { if (vni_mcast_grp) - /* TODO: handle mcast group update for svd */ + return zebra_vxlan_if_vni_mcast_group_update(ifp, vni, + NULL); - if (is_zero_mac(&mac)) - return zebra_vxlan_check_readd_vtep(ifp, vni, - vtep_ip); + if (is_zero_mac(&mac)) + return zebra_vxlan_check_readd_vtep(ifp, vni, vtep_ip); return 0; } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 28ffafec5a..db231217b5 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -917,6 +917,131 @@ int zebra_evpn_vxlan_del(struct zebra_evpn *zevpn) return zebra_evpn_del(zevpn); } +static int zevpn_build_vni_hash_table(struct zebra_if *zif, + struct zebra_vxlan_vni *vnip, void *arg) +{ + vni_t vni; + struct zebra_evpn *zevpn; + struct zebra_l3vni *zl3vni; + struct interface *ifp; + struct zebra_l2info_vxlan *vxl; + + ifp = zif->ifp; + vxl = &zif->l2info.vxl; + vni = vnip->vni; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Build vni table for vni %u for Intf %s", vni, + ifp->name); + + /* L3-VNI and L2-VNI are handled seperately */ + zl3vni = zl3vni_lookup(vni); + if (zl3vni) { + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "create L3-VNI hash for Intf %s(%u) L3-VNI %u", + ifp->name, ifp->ifindex, vni); + + /* associate with vxlan_if */ + zl3vni->local_vtep_ip = vxl->vtep_ip; + zl3vni->vxlan_if = ifp; + + /* + * we need to associate with SVI. + * we can associate with svi-if only after association + * with vxlan-intf is complete + */ + zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); + + /* Associate l3vni to mac-vlan and extract VRR MAC */ + zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni); + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "create l3vni %u svi_if %s mac_vlan_if %s", vni, + zl3vni->svi_if ? zl3vni->svi_if->name : "NIL", + zl3vni->mac_vlan_if ? zl3vni->mac_vlan_if->name + : "NIL"); + + if (is_l3vni_oper_up(zl3vni)) + zebra_vxlan_process_l3vni_oper_up(zl3vni); + + } else { + struct interface *vlan_if = NULL; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "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 */ + zevpn = zebra_evpn_lookup(vni); + if (zevpn) { + zlog_debug( + "EVPN hash already present for IF %s(%u) L2-VNI %u", + ifp->name, ifp->ifindex, vni); + + /* + * Inform BGP if intf is up and mapped to + * bridge. + */ + if (if_is_operative(ifp) && zif->brslave_info.br_if) + zebra_evpn_send_add_to_client(zevpn); + + /* Send Local MAC-entries to client */ + zebra_evpn_send_mac_list_to_client(zevpn); + + /* Send Loval Neighbor entries to client */ + zebra_evpn_send_neigh_to_client(zevpn); + } else { + zevpn = zebra_evpn_add(vni); + if (!zevpn) { + zlog_debug( + "Failed to add EVPN hash, IF %s(%u) L2-VNI %u", + ifp->name, ifp->ifindex, vni); + return 0; + } + + if (zevpn->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr + || zevpn->mcast_grp.s_addr + != vnip->mcast_grp.s_addr) { + zebra_vxlan_sg_deref(zevpn->local_vtep_ip, + zevpn->mcast_grp); + zebra_vxlan_sg_ref(vxl->vtep_ip, + vnip->mcast_grp); + zevpn->local_vtep_ip = vxl->vtep_ip; + zevpn->mcast_grp = vnip->mcast_grp; + /* on local vtep-ip check if ES + * orig-ip needs to be updated + */ + zebra_evpn_es_set_base_evpn(zevpn); + } + zevpn_vxlan_if_set(zevpn, ifp, true /* set */); + vlan_if = zvni_map_to_svi(vnip->access_vlan, + zif->brslave_info.br_if); + if (vlan_if) { + zevpn->svi_if = vlan_if; + zevpn->vrf_id = vlan_if->vrf->vrf_id; + zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id); + if (zl3vni) + listnode_add_sort(zl3vni->l2vnis, + zevpn); + } + + /* + * Inform BGP if intf is up and mapped to + * bridge. + */ + if (if_is_operative(ifp) && zif->brslave_info.br_if) + zebra_evpn_send_add_to_client(zevpn); + } + } + + return 0; +} + static int zevpn_build_hash_table_zns(struct ns *ns, void *param_in __attribute__((unused)), void **param_out __attribute__((unused))) @@ -930,12 +1055,8 @@ static int zevpn_build_hash_table_zns(struct ns *ns, /* Walk VxLAN interfaces and create EVPN hash. */ for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { - vni_t vni; - struct zebra_evpn *zevpn = NULL; - struct zebra_l3vni *zl3vni = NULL; struct zebra_if *zif; struct zebra_l2info_vxlan *vxl; - struct zebra_vxlan_vni *vnip; ifp = (struct interface *)rn->info; if (!ifp) @@ -945,127 +1066,23 @@ static int zevpn_build_hash_table_zns(struct ns *ns, continue; vxl = &zif->l2info.vxl; - vnip = zebra_vxlan_if_vni_find(zif, 0); - vni = vnip->vni; /* link of VXLAN interface should be in zebra_evpn_vrf */ if (zvrf->zns->ns_id != vxl->link_nsid) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "Intf %s(%u) VNI %u, link not in same " + "Intf %s(%u) link not in same " "namespace than BGP EVPN core instance ", - ifp->name, ifp->ifindex, vni); + ifp->name, ifp->ifindex); continue; } - /* L3-VNI and L2-VNI are handled seperately */ - zl3vni = zl3vni_lookup(vni); - if (zl3vni) { - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "create L3-VNI hash for Intf %s(%u) L3-VNI %u", - ifp->name, ifp->ifindex, vni); + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Building vni table for %s-if %s", + IS_ZEBRA_VXLAN_IF_VNI(zif) ? "vni" : "svd", + ifp->name); - /* associate with vxlan_if */ - zl3vni->local_vtep_ip = vxl->vtep_ip; - zl3vni->vxlan_if = ifp; - - /* - * we need to associate with SVI. - * we can associate with svi-if only after association - * with vxlan-intf is complete - */ - zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); - - /* Associate l3vni to mac-vlan and extract VRR MAC */ - zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni); - - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("create l3vni %u svi_if %s mac_vlan_if %s", - vni, zl3vni->svi_if ? zl3vni->svi_if->name - : "NIL", - zl3vni->mac_vlan_if ? - zl3vni->mac_vlan_if->name : "NIL"); - - if (is_l3vni_oper_up(zl3vni)) - zebra_vxlan_process_l3vni_oper_up(zl3vni); - - } else { - struct interface *vlan_if = NULL; - - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "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 */ - zevpn = zebra_evpn_lookup(vni); - if (zevpn) { - zlog_debug( - "EVPN hash already present for IF %s(%u) L2-VNI %u", - ifp->name, ifp->ifindex, vni); - - /* - * Inform BGP if intf is up and mapped to - * bridge. - */ - if (if_is_operative(ifp) && - zif->brslave_info.br_if) - zebra_evpn_send_add_to_client(zevpn); - - /* Send Local MAC-entries to client */ - zebra_evpn_send_mac_list_to_client(zevpn); - - /* Send Loval Neighbor entries to client */ - zebra_evpn_send_neigh_to_client(zevpn); - } else { - zevpn = zebra_evpn_add(vni); - if (!zevpn) { - zlog_debug( - "Failed to add EVPN hash, IF %s(%u) L2-VNI %u", - ifp->name, ifp->ifindex, vni); - return NS_WALK_CONTINUE; - } - - if (zevpn->local_vtep_ip.s_addr - != vxl->vtep_ip.s_addr - || zevpn->mcast_grp.s_addr - != vnip->mcast_grp.s_addr) { - zebra_vxlan_sg_deref( - zevpn->local_vtep_ip, - zevpn->mcast_grp); - zebra_vxlan_sg_ref(vxl->vtep_ip, - vnip->mcast_grp); - zevpn->local_vtep_ip = vxl->vtep_ip; - zevpn->mcast_grp = vnip->mcast_grp; - /* on local vtep-ip check if ES - * orig-ip needs to be updated - */ - zebra_evpn_es_set_base_evpn(zevpn); - } - zevpn_vxlan_if_set(zevpn, ifp, true /* set */); - vlan_if = zvni_map_to_svi( - vnip->access_vlan, - zif->brslave_info.br_if); - if (vlan_if) { - zevpn->svi_if = vlan_if; - zevpn->vrf_id = vlan_if->vrf->vrf_id; - zl3vni = zl3vni_from_vrf( - vlan_if->vrf->vrf_id); - if (zl3vni) - listnode_add_sort( - zl3vni->l2vnis, zevpn); - } - - /* - * Inform BGP if intf is up and mapped to - * bridge. - */ - if (if_is_operative(ifp) && - zif->brslave_info.br_if) - zebra_evpn_send_add_to_client(zevpn); - } - } + zebra_vxlan_if_vni_iterate(zif, zevpn_build_vni_hash_table, + NULL); } return NS_WALK_CONTINUE; }