diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index cad14ebc9d31..4ffc8caef466 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -760,18 +760,33 @@ void FdbOrch::doTask(Consumer& consumer) } } + /* FDB type is either dynamic or static */ assert(type == "dynamic" || type == "dynamic_local" || type == "static" ); if(origin == FDB_ORIGIN_VXLAN_ADVERTIZED) { VxlanTunnelOrch* tunnel_orch = gDirectory.get(); - if(!remote_ip.length()) + if (tunnel_orch->isDipTunnelsSupported()) { - it = consumer.m_toSync.erase(it); - continue; + if(!remote_ip.length()) + { + it = consumer.m_toSync.erase(it); + continue; + } + port = tunnel_orch->getTunnelPortName(remote_ip); + } + else + { + EvpnNvoOrch* evpn_nvo_orch = gDirectory.get(); + VxlanTunnel* sip_tunnel = evpn_nvo_orch->getEVPNVtep(); + if (sip_tunnel == NULL) + { + it = consumer.m_toSync.erase(it); + continue; + } + port = tunnel_orch->getTunnelPortName(sip_tunnel->getSrcIP().to_string(), true); } - port = tunnel_orch->getTunnelPortName(remote_ip); } @@ -804,8 +819,6 @@ void FdbOrch::doTask(Consumer& consumer) } port = tunnel_orch->getTunnelPortName(remote_ip); } - - it = consumer.m_toSync.erase(it); } else @@ -1125,11 +1138,14 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, { Port vlan; Port port; + string end_point_ip = ""; + + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); SWSS_LOG_ENTER(); - SWSS_LOG_INFO("mac=%s bv_id=0x%" PRIx64 " port_name=%s type=%s origin=%d", + SWSS_LOG_INFO("mac=%s bv_id=0x%" PRIx64 " port_name=%s type=%s origin=%d remote_ip=%s", entry.mac.to_string().c_str(), entry.bv_id, port_name.c_str(), - fdbData.type.c_str(), fdbData.origin); + fdbData.type.c_str(), fdbData.origin, fdbData.remote_ip.c_str()); if (!m_portsOrch->getPort(entry.bv_id, vlan)) { @@ -1146,8 +1162,14 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, return true; } + /* Assign end point IP only in SIP tunnel scenario since Port + IP address + needed to uniquely identify Vlan member */ + if (!tunnel_orch->isDipTunnelsSupported()) + { + end_point_ip = fdbData.remote_ip; + } /* Retry until port is member of vlan*/ - if (vlan.m_members.find(port_name) == vlan.m_members.end()) + if (!m_portsOrch->isVlanMember(vlan, port, end_point_ip)) { SWSS_LOG_INFO("Saving a fdb entry until port %s becomes vlan %s member", port_name.c_str(), vlan.m_alias.c_str()); saved_fdb_entries[port_name].push_back({entry.mac, @@ -1163,6 +1185,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, Port oldPort; string oldType; + string oldRemoteIp; FdbOrigin oldOrigin = FDB_ORIGIN_INVALID ; bool macUpdate = false; @@ -1172,6 +1195,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, /* get existing port and type */ oldType = it->second.type; oldOrigin = it->second.origin; + oldRemoteIp = it->second.remote_ip; if (!m_portsOrch->getPortByBridgePortId(it->second.bridge_port_id, oldPort)) { @@ -1179,12 +1203,13 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, return false; } - if ((oldOrigin == fdbData.origin) && (oldType == fdbData.type) && (port.m_bridge_port_id == it->second.bridge_port_id)) + if ((oldOrigin == fdbData.origin) && (oldType == fdbData.type) && (port.m_bridge_port_id == it->second.bridge_port_id) + && (oldRemoteIp == fdbData.remote_ip)) { /* Duplicate Mac */ - SWSS_LOG_INFO("FdbOrch: mac=%s %s port=%s type=%s origin=%d is duplicate", entry.mac.to_string().c_str(), + SWSS_LOG_INFO("FdbOrch: mac=%s %s port=%s type=%s origin=%d remote_ip=%s is duplicate", entry.mac.to_string().c_str(), vlan.m_alias.c_str(), port_name.c_str(), - fdbData.type.c_str(), fdbData.origin); + fdbData.type.c_str(), fdbData.origin, fdbData.remote_ip.c_str()); return true; } else if (fdbData.origin != oldOrigin) diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index cacf8672f49e..a5e0ce8e6a6e 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -177,8 +177,6 @@ bool OrchDaemon::init() VxlanVrfMapOrch *vxlan_vrf_orch = new VxlanVrfMapOrch(m_applDb, APP_VXLAN_VRF_TABLE_NAME); gDirectory.set(vxlan_vrf_orch); - EvpnRemoteVniOrch* evpn_remote_vni_orch = new EvpnRemoteVniOrch(m_applDb, APP_VXLAN_REMOTE_VNI_TABLE_NAME); - gDirectory.set(evpn_remote_vni_orch); EvpnNvoOrch* evpn_nvo_orch = new EvpnNvoOrch(m_applDb, APP_VXLAN_EVPN_NVO_TABLE_NAME); gDirectory.set(evpn_nvo_orch); @@ -373,7 +371,20 @@ bool OrchDaemon::init() m_orchList.push_back(vxlan_tunnel_orch); m_orchList.push_back(evpn_nvo_orch); m_orchList.push_back(vxlan_tunnel_map_orch); - m_orchList.push_back(evpn_remote_vni_orch); + + if (vxlan_tunnel_orch->isDipTunnelsSupported()) + { + EvpnRemoteVnip2pOrch* evpn_remote_vni_orch = new EvpnRemoteVnip2pOrch(m_applDb, APP_VXLAN_REMOTE_VNI_TABLE_NAME); + gDirectory.set(evpn_remote_vni_orch); + m_orchList.push_back(evpn_remote_vni_orch); + } + else + { + EvpnRemoteVnip2mpOrch* evpn_remote_vni_orch = new EvpnRemoteVnip2mpOrch(m_applDb, APP_VXLAN_REMOTE_VNI_TABLE_NAME); + gDirectory.set(evpn_remote_vni_orch); + m_orchList.push_back(evpn_remote_vni_orch); + } + m_orchList.push_back(vxlan_vrf_orch); m_orchList.push_back(cfg_vnet_rt_orch); m_orchList.push_back(vnet_orch); diff --git a/orchagent/port.h b/orchagent/port.h index 57c9f6e2d948..31c3392fcd00 100644 --- a/orchagent/port.h +++ b/orchagent/port.h @@ -38,11 +38,17 @@ struct VlanMemberEntry typedef std::map vlan_members_t; +typedef std::map endpoint_ip_l2mc_group_member_map_t; + struct VlanInfo { sai_object_id_t vlan_oid = 0; sai_vlan_id_t vlan_id = 0; sai_object_id_t host_intf_id = SAI_NULL_OBJECT_ID; + sai_vlan_flood_control_type_t uuc_flood_type = SAI_VLAN_FLOOD_CONTROL_TYPE_ALL; + sai_vlan_flood_control_type_t bc_flood_type = SAI_VLAN_FLOOD_CONTROL_TYPE_ALL; + sai_object_id_t l2mc_group_id = SAI_NULL_OBJECT_ID; + endpoint_ip_l2mc_group_member_map_t l2mc_members; }; struct SystemPortInfo diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 2f5343782cdb..44919bfc43af 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -42,6 +42,7 @@ extern sai_acl_api_t* sai_acl_api; extern sai_queue_api_t *sai_queue_api; extern sai_object_id_t gSwitchId; extern sai_fdb_api_t *sai_fdb_api; +extern sai_l2mc_group_api_t *sai_l2mc_group_api; extern IntfsOrch *gIntfsOrch; extern NeighOrch *gNeighOrch; extern CrmOrch *gCrmOrch; @@ -470,6 +471,45 @@ PortsOrch::PortsOrch(DBConnector *db, DBConnector *stateDb, vector supported_flood_control_types(max_flood_control_types, 0); + sai_s32_list_t values; + values.count = max_flood_control_types; + values.list = supported_flood_control_types.data(); + + if (sai_query_attribute_enum_values_capability(gSwitchId, SAI_OBJECT_TYPE_VLAN, + SAI_VLAN_ATTR_UNKNOWN_UNICAST_FLOOD_CONTROL_TYPE, + &values) != SAI_STATUS_SUCCESS) + { + SWSS_LOG_NOTICE("This device does not support unknown unicast flood control types"); + } + else + { + for (uint32_t idx = 0; idx < values.count; idx++) + { + uuc_sup_flood_control_type.insert(static_cast(values.list[idx])); + } + } + + + supported_flood_control_types.assign(max_flood_control_types, 0); + values.count = max_flood_control_types; + values.list = supported_flood_control_types.data(); + + if (sai_query_attribute_enum_values_capability(gSwitchId, SAI_OBJECT_TYPE_VLAN, + SAI_VLAN_ATTR_BROADCAST_FLOOD_CONTROL_TYPE, + &values) != SAI_STATUS_SUCCESS) + { + SWSS_LOG_NOTICE("This device does not support broadcast flood control types"); + } + else + { + for (uint32_t idx = 0; idx < values.count; idx++) + { + bc_sup_flood_control_type.insert(static_cast(values.list[idx])); + } + } + /* Get default 1Q bridge and default VLAN */ vector attrs; attr.id = SAI_SWITCH_ATTR_DEFAULT_1Q_BRIDGE_ID; @@ -747,6 +787,24 @@ void PortsOrch::decreasePortRefCount(const string &alias) m_port_ref_count[alias]--; } +void PortsOrch::increaseBridgePortRefCount(Port &port) +{ + assert (m_bridge_port_ref_count.find(port.m_alias) != m_bridge_port_ref_count.end()); + m_bridge_port_ref_count[port.m_alias]++; +} + +void PortsOrch::decreaseBridgePortRefCount(Port &port) +{ + assert (m_bridge_port_ref_count.find(port.m_alias) != m_bridge_port_ref_count.end()); + m_bridge_port_ref_count[port.m_alias]--; +} + +bool PortsOrch::getBridgePortReferenceCount(Port &port) +{ + assert (m_bridge_port_ref_count.find(port.m_alias) != m_bridge_port_ref_count.end()); + return m_bridge_port_ref_count[port.m_alias]; +} + bool PortsOrch::getPortByBridgePortId(sai_object_id_t bridge_port_id, Port &port) { SWSS_LOG_ENTER(); @@ -4378,6 +4436,7 @@ bool PortsOrch::addVlan(string vlan_alias) sai_attribute_t attr; attr.id = SAI_VLAN_ATTR_VLAN_ID; attr.value.u16 = vlan_id; + sai_status_t status = sai_vlan_api->create_vlan(&vlan_oid, gSwitchId, 1, &attr); if (status != SAI_STATUS_SUCCESS) @@ -4395,6 +4454,8 @@ bool PortsOrch::addVlan(string vlan_alias) Port vlan(vlan_alias, Port::VLAN); vlan.m_vlan_info.vlan_oid = vlan_oid; vlan.m_vlan_info.vlan_id = vlan_id; + vlan.m_vlan_info.uuc_flood_type = SAI_VLAN_FLOOD_CONTROL_TYPE_ALL; + vlan.m_vlan_info.bc_flood_type = SAI_VLAN_FLOOD_CONTROL_TYPE_ALL; vlan.m_members = set(); m_portList[vlan_alias] = vlan; m_port_ref_count[vlan_alias] = 0; @@ -4475,10 +4536,23 @@ bool PortsOrch::getVlanByVlanId(sai_vlan_id_t vlan_id, Port &vlan) return false; } -bool PortsOrch::addVlanMember(Port &vlan, Port &port, string &tagging_mode) +bool PortsOrch::addVlanMember(Port &vlan, Port &port, string &tagging_mode, string end_point_ip) { SWSS_LOG_ENTER(); + if (!end_point_ip.empty()) + { + if ((uuc_sup_flood_control_type.find(SAI_VLAN_FLOOD_CONTROL_TYPE_COMBINED) + == uuc_sup_flood_control_type.end()) || + (bc_sup_flood_control_type.find(SAI_VLAN_FLOOD_CONTROL_TYPE_COMBINED) + == bc_sup_flood_control_type.end())) + { + SWSS_LOG_ERROR("Flood group with end point ip is not supported"); + return false; + } + return addVlanFloodGroups(vlan, port, end_point_ip); + } + sai_attribute_t attr; vector attrs; @@ -4490,6 +4564,7 @@ bool PortsOrch::addVlanMember(Port &vlan, Port &port, string &tagging_mode) attr.value.oid = port.m_bridge_port_id; attrs.push_back(attr); + sai_vlan_tagging_mode_t sai_tagging_mode = SAI_VLAN_TAGGING_MODE_TAGGED; attr.id = SAI_VLAN_MEMBER_ATTR_VLAN_TAGGING_MODE; if (tagging_mode == "untagged") @@ -4539,10 +4614,223 @@ bool PortsOrch::addVlanMember(Port &vlan, Port &port, string &tagging_mode) return true; } -bool PortsOrch::removeVlanMember(Port &vlan, Port &port) +bool PortsOrch::addVlanFloodGroups(Port &vlan, Port &port, string end_point_ip) +{ + SWSS_LOG_ENTER(); + + sai_object_id_t l2mc_group_id = SAI_NULL_OBJECT_ID; + sai_status_t status; + sai_attribute_t attr; + + if (vlan.m_vlan_info.uuc_flood_type != SAI_VLAN_FLOOD_CONTROL_TYPE_COMBINED) + { + attr.id = SAI_VLAN_ATTR_UNKNOWN_UNICAST_FLOOD_CONTROL_TYPE; + attr.value.s32 = SAI_VLAN_FLOOD_CONTROL_TYPE_COMBINED; + + status = sai_vlan_api->set_vlan_attribute(vlan.m_vlan_info.vlan_oid, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set l2mc flood type combined " + " to vlan %hu for unknown unicast flooding", vlan.m_vlan_info.vlan_id); + return false; + } + vlan.m_vlan_info.uuc_flood_type = SAI_VLAN_FLOOD_CONTROL_TYPE_COMBINED; + } + + if (vlan.m_vlan_info.bc_flood_type != SAI_VLAN_FLOOD_CONTROL_TYPE_COMBINED) + { + attr.id = SAI_VLAN_ATTR_BROADCAST_FLOOD_CONTROL_TYPE; + attr.value.s32 = SAI_VLAN_FLOOD_CONTROL_TYPE_COMBINED; + + status = sai_vlan_api->set_vlan_attribute(vlan.m_vlan_info.vlan_oid, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set l2mc flood type combined " + " to vlan %hu for broadcast flooding", vlan.m_vlan_info.vlan_id); + return false; + } + vlan.m_vlan_info.bc_flood_type = SAI_VLAN_FLOOD_CONTROL_TYPE_COMBINED; + } + + if (vlan.m_vlan_info.l2mc_group_id == SAI_NULL_OBJECT_ID) + { + status = sai_l2mc_group_api->create_l2mc_group(&l2mc_group_id, gSwitchId, 0, NULL); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create l2mc flood group"); + return false; + } + + if (vlan.m_vlan_info.uuc_flood_type == SAI_VLAN_FLOOD_CONTROL_TYPE_COMBINED) + { + attr.id = SAI_VLAN_ATTR_UNKNOWN_UNICAST_FLOOD_GROUP; + attr.value.oid = l2mc_group_id; + + status = sai_vlan_api->set_vlan_attribute(vlan.m_vlan_info.vlan_oid, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set l2mc group %" PRIx64 + " to vlan %hu for unknown unicast flooding", + l2mc_group_id, vlan.m_vlan_info.vlan_id); + return false; + } + } + if (vlan.m_vlan_info.bc_flood_type == SAI_VLAN_FLOOD_CONTROL_TYPE_COMBINED) + { + attr.id = SAI_VLAN_ATTR_BROADCAST_FLOOD_GROUP; + attr.value.oid = l2mc_group_id; + + status = sai_vlan_api->set_vlan_attribute(vlan.m_vlan_info.vlan_oid, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set l2mc group %" PRIx64 + " to vlan %hu for broadcast flooding", + l2mc_group_id, vlan.m_vlan_info.vlan_id); + return false; + } + } + vlan.m_vlan_info.l2mc_group_id = l2mc_group_id; + m_portList[vlan.m_alias] = vlan; + } + + vector attrs; + attr.id = SAI_L2MC_GROUP_MEMBER_ATTR_L2MC_GROUP_ID; + attr.value.oid = vlan.m_vlan_info.l2mc_group_id; + attrs.push_back(attr); + + attr.id = SAI_L2MC_GROUP_MEMBER_ATTR_L2MC_OUTPUT_ID; + attr.value.oid = port.m_bridge_port_id; + attrs.push_back(attr); + + attr.id = SAI_L2MC_GROUP_MEMBER_ATTR_L2MC_ENDPOINT_IP; + IpAddress remote = IpAddress(end_point_ip); + sai_ip_address_t ipaddr; + if (remote.isV4()) + { + ipaddr.addr_family = SAI_IP_ADDR_FAMILY_IPV4; + ipaddr.addr.ip4 = remote.getV4Addr(); + } + else + { + ipaddr.addr_family = SAI_IP_ADDR_FAMILY_IPV6; + memcpy(ipaddr.addr.ip6, remote.getV6Addr(), sizeof(ipaddr.addr.ip6)); + } + attr.value.ipaddr = ipaddr; + attrs.push_back(attr); + + sai_object_id_t l2mc_group_member = SAI_NULL_OBJECT_ID; + status = sai_l2mc_group_api->create_l2mc_group_member(&l2mc_group_member, gSwitchId, + static_cast(attrs.size()), + attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create l2mc group member for adding tunnel %s to vlan %hu", + end_point_ip.c_str(), vlan.m_vlan_info.vlan_id); + return false; + } + vlan.m_vlan_info.l2mc_members[end_point_ip] = l2mc_group_member; + m_portList[vlan.m_alias] = vlan; + increaseBridgePortRefCount(port); + return true; +} + + +bool PortsOrch::removeVlanEndPointIp(Port &vlan, Port &port, string end_point_ip) +{ + SWSS_LOG_ENTER(); + + sai_status_t status; + + if(vlan.m_vlan_info.l2mc_members.find(end_point_ip) == vlan.m_vlan_info.l2mc_members.end()) + { + SWSS_LOG_NOTICE("End point ip %s is not part of vlan %hu", + end_point_ip.c_str(), vlan.m_vlan_info.vlan_id); + return true; + } + + status = sai_l2mc_group_api->remove_l2mc_group_member(vlan.m_vlan_info.l2mc_members[end_point_ip]); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to remove end point ip %s from vlan %hu", + end_point_ip.c_str(), vlan.m_vlan_info.vlan_id); + return false; + } + decreaseBridgePortRefCount(port); + vlan.m_vlan_info.l2mc_members.erase(end_point_ip); + sai_object_id_t l2mc_group_id = SAI_NULL_OBJECT_ID; + sai_attribute_t attr; + + if (vlan.m_vlan_info.l2mc_members.empty()) + { + if (vlan.m_vlan_info.uuc_flood_type == SAI_VLAN_FLOOD_CONTROL_TYPE_COMBINED) + { + attr.id = SAI_VLAN_ATTR_UNKNOWN_UNICAST_FLOOD_GROUP; + attr.value.oid = SAI_NULL_OBJECT_ID; + + status = sai_vlan_api->set_vlan_attribute(vlan.m_vlan_info.vlan_oid, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set null l2mc group " + " to vlan %hu for unknown unicast flooding", + vlan.m_vlan_info.vlan_id); + return false; + } + attr.id = SAI_VLAN_ATTR_UNKNOWN_UNICAST_FLOOD_CONTROL_TYPE; + attr.value.s32 = SAI_VLAN_FLOOD_CONTROL_TYPE_ALL; + status = sai_vlan_api->set_vlan_attribute(vlan.m_vlan_info.vlan_oid, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set flood control type all" + " to vlan %hu for unknown unicast flooding", + vlan.m_vlan_info.vlan_id); + return false; + } + vlan.m_vlan_info.uuc_flood_type = SAI_VLAN_FLOOD_CONTROL_TYPE_ALL; + } + if (vlan.m_vlan_info.bc_flood_type == SAI_VLAN_FLOOD_CONTROL_TYPE_COMBINED) + { + attr.id = SAI_VLAN_ATTR_BROADCAST_FLOOD_GROUP; + attr.value.oid = SAI_NULL_OBJECT_ID; + + status = sai_vlan_api->set_vlan_attribute(vlan.m_vlan_info.vlan_oid, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set null l2mc group " + " to vlan %hu for broadcast flooding", + vlan.m_vlan_info.vlan_id); + return false; + } + attr.id = SAI_VLAN_ATTR_BROADCAST_FLOOD_CONTROL_TYPE; + attr.value.s32 = SAI_VLAN_FLOOD_CONTROL_TYPE_ALL; + status = sai_vlan_api->set_vlan_attribute(vlan.m_vlan_info.vlan_oid, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set flood control type all" + " to vlan %hu for broadcast flooding", + vlan.m_vlan_info.vlan_id); + return false; + } + vlan.m_vlan_info.bc_flood_type = SAI_VLAN_FLOOD_CONTROL_TYPE_ALL; + } + status = sai_l2mc_group_api->remove_l2mc_group(vlan.m_vlan_info.l2mc_group_id); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to remove l2mc group %" PRIx64, l2mc_group_id); + return false; + } + vlan.m_vlan_info.l2mc_group_id = SAI_NULL_OBJECT_ID; + } + return true; +} + +bool PortsOrch::removeVlanMember(Port &vlan, Port &port, string end_point_ip) { SWSS_LOG_ENTER(); + if (!end_point_ip.empty()) + { + return removeVlanEndPointIp(vlan, port, end_point_ip); + } sai_object_id_t vlan_member_id; sai_vlan_tagging_mode_t sai_tagging_mode; auto vlan_member = port.m_vlan_members.find(vlan.m_vlan_info.vlan_id); @@ -4586,8 +4874,16 @@ bool PortsOrch::removeVlanMember(Port &vlan, Port &port) return true; } -bool PortsOrch::isVlanMember(Port &vlan, Port &port) +bool PortsOrch::isVlanMember(Port &vlan, Port &port, string end_point_ip) { + if (!end_point_ip.empty()) + { + if (vlan.m_vlan_info.l2mc_members.find(end_point_ip) != vlan.m_vlan_info.l2mc_members.end()) + { + return true; + } + return false; + } if (vlan.m_members.find(port.m_alias) == vlan.m_members.end()) return false; diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index ce950330d6e9..851200b47c6e 100755 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -142,9 +142,14 @@ class PortsOrch : public Orch, public Subject bool removeTunnel(Port tunnel); bool addBridgePort(Port &port); bool removeBridgePort(Port &port); - bool addVlanMember(Port &vlan, Port &port, string& tagging_mode); - bool removeVlanMember(Port &vlan, Port &port); - bool isVlanMember(Port &vlan, Port &port); + bool addVlanMember(Port &vlan, Port &port, string& tagging_mode, string end_point_ip = ""); + bool removeVlanMember(Port &vlan, Port &port, string end_point_ip = ""); + bool isVlanMember(Port &vlan, Port &port, string end_point_ip = ""); + bool addVlanFloodGroups(Port &vlan, Port &port, string end_point_ip); + bool removeVlanEndPointIp(Port &vlan, Port &port, string end_point_ip); + void increaseBridgePortRefCount(Port &port); + void decreaseBridgePortRefCount(Port &port); + bool getBridgePortReferenceCount(Port &port); string m_inbandPortName = ""; bool isInbandPort(const string &alias); @@ -224,6 +229,10 @@ class PortsOrch : public Orch, public Subject unordered_map m_portOidToIndex; map m_port_ref_count; unordered_set m_pendingPortSet; + const uint32_t max_flood_control_types = 4; + set uuc_sup_flood_control_type; + set bc_sup_flood_control_type; + map m_bridge_port_ref_count; NotificationConsumer* m_portStatusNotificationConsumer; diff --git a/orchagent/routeorch.cpp b/orchagent/routeorch.cpp index 80b2b1e571c4..e8ebf9a6c5c3 100644 --- a/orchagent/routeorch.cpp +++ b/orchagent/routeorch.cpp @@ -2276,7 +2276,7 @@ bool RouteOrch::createRemoteVtep(sai_object_id_t vrf_id, const NextHopKey &nextH auto vtep_ptr = evpn_orch->getEVPNVtep(); if (vtep_ptr) { - ip_refcnt = vtep_ptr->getDipTunnelIPRefCnt(nextHop.ip_address.to_string()); + ip_refcnt = vtep_ptr->getRemoteEndPointIPRefCnt(nextHop.ip_address.to_string()); } SWSS_LOG_INFO("Routeorch Add Remote VTEP %s, VNI %d, VR_ID %" PRIx64 ", IP ref_cnt %d", nextHop.ip_address.to_string().c_str(), nextHop.vni, vrf_id, ip_refcnt); @@ -2296,7 +2296,7 @@ bool RouteOrch::deleteRemoteVtep(sai_object_id_t vrf_id, const NextHopKey &nextH auto vtep_ptr = evpn_orch->getEVPNVtep(); if (vtep_ptr) { - ip_refcnt = vtep_ptr->getDipTunnelIPRefCnt(nextHop.ip_address.to_string()); + ip_refcnt = vtep_ptr->getRemoteEndPointIPRefCnt(nextHop.ip_address.to_string()); } SWSS_LOG_INFO("Routeorch Del Remote VTEP %s, VNI %d, VR_ID %" PRIx64 ", IP ref_cnt %d", diff --git a/orchagent/saihelper.cpp b/orchagent/saihelper.cpp index 490efb90b360..ce8f7c0a278f 100644 --- a/orchagent/saihelper.cpp +++ b/orchagent/saihelper.cpp @@ -66,6 +66,7 @@ sai_nat_api_t* sai_nat_api; sai_isolation_group_api_t* sai_isolation_group_api; sai_system_port_api_t* sai_system_port_api; sai_macsec_api_t* sai_macsec_api; +sai_l2mc_group_api_t* sai_l2mc_group_api; extern sai_object_id_t gSwitchId; extern bool gSairedisRecord; @@ -189,6 +190,7 @@ void initSaiApi() sai_api_query(SAI_API_ISOLATION_GROUP, (void **)&sai_isolation_group_api); sai_api_query(SAI_API_SYSTEM_PORT, (void **)&sai_system_port_api); sai_api_query(SAI_API_MACSEC, (void **)&sai_macsec_api); + sai_api_query(SAI_API_L2MC_GROUP, (void **)&sai_l2mc_group_api); sai_log_set(SAI_API_SWITCH, SAI_LOG_LEVEL_NOTICE); sai_log_set(SAI_API_BRIDGE, SAI_LOG_LEVEL_NOTICE); @@ -221,6 +223,7 @@ void initSaiApi() sai_log_set((sai_api_t)SAI_API_NAT, SAI_LOG_LEVEL_NOTICE); sai_log_set(SAI_API_SYSTEM_PORT, SAI_LOG_LEVEL_NOTICE); sai_log_set(SAI_API_MACSEC, SAI_LOG_LEVEL_NOTICE); + sai_log_set(SAI_API_L2MC_GROUP, SAI_LOG_LEVEL_NOTICE); } void initSaiRedis(const string &record_location, const std::string &record_filename) diff --git a/orchagent/vxlanorch.cpp b/orchagent/vxlanorch.cpp index d983052a7c7b..0123ae272d29 100644 --- a/orchagent/vxlanorch.cpp +++ b/orchagent/vxlanorch.cpp @@ -5,7 +5,9 @@ #include #include #include +extern "C" { #include "sai.h" +} #include "macaddress.h" #include "ipaddress.h" #include "orch.h" @@ -15,6 +17,7 @@ #include "swssnet.h" #include "warm_restart.h" #include "tokenize.h" +#include "converter.h" /* Global variables */ extern sai_object_id_t gSwitchId; @@ -906,7 +909,10 @@ bool VxlanTunnel::createTunnelHw(uint8_t mapper_list, tunnel_map_use_t map_src, void VxlanTunnel::deletePendingSIPTunnel() { - if ((getDipTunnelCnt() == 0) && del_tnl_hw_pending) + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); + bool dip_tunnels_used = tunnel_orch->isDipTunnelsSupported(); + + if ((!dip_tunnels_used || getDipTunnelCnt() == 0) && del_tnl_hw_pending) { uint8_t mapper_list=0; @@ -962,7 +968,7 @@ void VxlanTunnel::increment_spurious_imr_del(const std::string remote_vtep) } } -int VxlanTunnel::getDipTunnelRefCnt(const std::string remote_vtep) +int VxlanTunnel::getRemoteEndPointRefCnt(const std::string remote_vtep) { tunnel_refcnt_t tnl_refcnts; @@ -978,7 +984,7 @@ int VxlanTunnel::getDipTunnelRefCnt(const std::string remote_vtep) } } -int VxlanTunnel::getDipTunnelIMRRefCnt(const std::string remote_vtep) +int VxlanTunnel::getRemoteEndPointIMRRefCnt(const std::string remote_vtep) { tunnel_refcnt_t tnl_refcnts; @@ -994,7 +1000,7 @@ int VxlanTunnel::getDipTunnelIMRRefCnt(const std::string remote_vtep) } } -int VxlanTunnel::getDipTunnelIPRefCnt(const std::string remote_vtep) +int VxlanTunnel::getRemoteEndPointIPRefCnt(const std::string remote_vtep) { tunnel_refcnt_t tnl_refcnts; @@ -1010,7 +1016,7 @@ int VxlanTunnel::getDipTunnelIPRefCnt(const std::string remote_vtep) } } -void VxlanTunnel::updateDipTunnelRefCnt(bool inc, tunnel_refcnt_t& tnl_refcnts, +void VxlanTunnel::updateRemoteEndPointRefCnt(bool inc, tunnel_refcnt_t& tnl_refcnts, tunnel_user_t usr) { switch(usr) @@ -1058,6 +1064,43 @@ void VxlanTunnel::updateDipTunnelRefCnt(bool inc, tunnel_refcnt_t& tnl_refcnts, } } +void VxlanTunnel::updateRemoteEndPointIpRef(const std::string remote_vtep, bool inc) +{ + tunnel_refcnt_t tnl_refcnts; + + auto it = tnl_users_.find(remote_vtep); + if (inc) + { + if (it == tnl_users_.end()) + { + memset(&tnl_refcnts, 0, sizeof(tunnel_refcnt_t)); + tnl_refcnts.ip_refcnt++; + tnl_users_[remote_vtep] = tnl_refcnts; + } + else + { + it->second.ip_refcnt++; + } + SWSS_LOG_DEBUG("Incrementing remote end point %s reference to %d", remote_vtep.c_str(), + it->second.ip_refcnt); + } + else + { + if (it == tnl_users_.end()) + { + SWSS_LOG_ERROR("Cannot decrement ref. End point not referenced %s", remote_vtep.c_str()); + } + it->second.ip_refcnt--; + + SWSS_LOG_DEBUG("Decrementing remote end point %s reference to %d", remote_vtep.c_str(), + it->second.ip_refcnt); + if (it->second.ip_refcnt == 0) + { + tnl_users_.erase(remote_vtep); + } + } +} + bool VxlanTunnel::createDynamicDIPTunnel(const std::string dip, tunnel_user_t usr) { uint8_t mapper_list = 0; @@ -1075,7 +1118,7 @@ bool VxlanTunnel::createDynamicDIPTunnel(const std::string dip, tunnel_user_t us tunnel_orch->addTunnel(tunnel_name,dip_tunnel); memset(&tnl_refcnts,0,sizeof(tunnel_refcnt_t)); - updateDipTunnelRefCnt(true,tnl_refcnts,usr); + updateRemoteEndPointRefCnt(true,tnl_refcnts,usr); tnl_users_[dip] = tnl_refcnts; TUNNELMAP_SET_VLAN(mapper_list); @@ -1086,7 +1129,7 @@ bool VxlanTunnel::createDynamicDIPTunnel(const std::string dip, tunnel_user_t us else { tnl_refcnts = it->second; - updateDipTunnelRefCnt(true,tnl_refcnts,usr); + updateRemoteEndPointRefCnt(true,tnl_refcnts,usr); tnl_users_[dip] = tnl_refcnts; } @@ -1110,7 +1153,7 @@ bool VxlanTunnel::deleteDynamicDIPTunnel(const std::string dip, tunnel_user_t us if (update_refcnt) { - updateDipTunnelRefCnt(false,tnl_refcnts,usr); + updateRemoteEndPointRefCnt(false,tnl_refcnts,usr); tnl_users_[dip] = tnl_refcnts; } @@ -1156,6 +1199,38 @@ bool VxlanTunnel::deleteDynamicDIPTunnel(const std::string dip, tunnel_user_t us //------------------- VxlanTunnelOrch Implementation --------------------------// +VxlanTunnelOrch::VxlanTunnelOrch(DBConnector *statedb, DBConnector *db, const std::string& tableName) : + Orch2(db, tableName, request_), + m_stateVxlanTable(statedb, STATE_VXLAN_TUNNEL_TABLE_NAME) +{ + uint32_t max_tunnel_modes = 2; + vector tunnel_peer_modes(max_tunnel_modes, 0); + sai_s32_list_t values; + values.count = max_tunnel_modes; + values.list = tunnel_peer_modes.data(); + sai_status_t status; + + status = sai_query_attribute_enum_values_capability(gSwitchId, SAI_OBJECT_TYPE_TUNNEL, + SAI_TUNNEL_ATTR_PEER_MODE, &values); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_WARN("Unable to get supported tunnel peer modes. Defaulting to P2P"); + is_dip_tunnel_supported = true; + } + else + { + is_dip_tunnel_supported = false; + for (uint32_t idx = 0; idx < values.count; idx++) + { + if (values.list[idx] == SAI_TUNNEL_PEER_MODE_P2P) + { + is_dip_tunnel_supported = true; + break; + } + } + } +} + sai_object_id_t VxlanTunnelOrch::createNextHopTunnel(string tunnelName, IpAddress& ipAddr, MacAddress macAddress, uint32_t vni) @@ -1444,13 +1519,19 @@ bool VxlanTunnelOrch::addTunnelUser(const std::string remote_vtep, uint32_t vni return false; } + if (!isDipTunnelsSupported()) + { + vtep_ptr->updateRemoteEndPointIpRef(remote_vtep, true); + return true; + } + vtep_ptr->createDynamicDIPTunnel(remote_vtep, usr); getTunnelNameFromDIP(remote_vtep, tunnel_name); dip_tunnel = getVxlanTunnel(tunnel_name); SWSS_LOG_NOTICE("diprefcnt for remote %s = %d", - remote_vtep.c_str(), vtep_ptr->getDipTunnelRefCnt(remote_vtep)); + remote_vtep.c_str(), vtep_ptr->getRemoteEndPointRefCnt(remote_vtep)); if (!getTunnelPort(remote_vtep, tunport)) { @@ -1470,9 +1551,7 @@ bool VxlanTunnelOrch::delTunnelUser(const std::string remote_vtep, uint32_t vni { if (TUNNEL_USER_MAC == usr) return true; - auto port_tunnel_name = getTunnelPortName(remote_vtep); EvpnNvoOrch* evpn_orch = gDirectory.get(); - auto vtep_ptr = evpn_orch->getEVPNVtep(); if (!vtep_ptr) @@ -1483,13 +1562,34 @@ bool VxlanTunnelOrch::delTunnelUser(const std::string remote_vtep, uint32_t vni } Port tunnelPort; - gPortsOrch->getPort(port_tunnel_name,tunnelPort); + bool ret; + string port_tunnel_name; - if ((vtep_ptr->getDipTunnelRefCnt(remote_vtep) == 1) && - tunnelPort.m_fdb_count == 0) + if (!isDipTunnelsSupported()) { - bool ret; + port_tunnel_name = getTunnelPortName(vtep_ptr->getSrcIP().to_string(), true); + gPortsOrch->getPort(port_tunnel_name,tunnelPort); + vtep_ptr->updateRemoteEndPointIpRef(remote_vtep, false); + if (vtep_ptr->del_tnl_hw_pending && !vtep_ptr->isTunnelReferenced()) + { + ret = gPortsOrch->removeBridgePort(tunnelPort); + if (!ret) + { + SWSS_LOG_ERROR("Remove Bridge port failed for source vtep = %s fdbcount = %d", + port_tunnel_name.c_str(), tunnelPort.m_fdb_count); + return true; + } + gPortsOrch->removeTunnel(tunnelPort); + vtep_ptr->deletePendingSIPTunnel(); + } + return true; + } + port_tunnel_name = getTunnelPortName(remote_vtep); + gPortsOrch->getPort(port_tunnel_name,tunnelPort); + if ((vtep_ptr->getRemoteEndPointRefCnt(remote_vtep) == 1) && + tunnelPort.m_fdb_count == 0) + { ret = gPortsOrch->removeBridgePort(tunnelPort); if (!ret) { @@ -1503,7 +1603,7 @@ bool VxlanTunnelOrch::delTunnelUser(const std::string remote_vtep, uint32_t vni vtep_ptr->deleteDynamicDIPTunnel(remote_vtep, usr); SWSS_LOG_NOTICE("diprefcnt for remote %s = %d", - remote_vtep.c_str(), vtep_ptr->getDipTunnelRefCnt(remote_vtep)); + remote_vtep.c_str(), vtep_ptr->getRemoteEndPointRefCnt(remote_vtep)); vtep_ptr->deletePendingSIPTunnel(); @@ -1525,14 +1625,31 @@ void VxlanTunnelOrch::deleteTunnelPort(Port &tunnelPort) return; } + /* P2MP scenario where P2MP tunnel port is used for FDB learning */ + if (!isDipTunnelsSupported()) + { + if (vtep_ptr->del_tnl_hw_pending && !vtep_ptr->isTunnelReferenced()) + { + ret = gPortsOrch->removeBridgePort(tunnelPort); + if (!ret) + { + SWSS_LOG_ERROR("Remove Bridge port failed for source vtep = %s fdbcount = %d", + tunnelPort.m_alias.c_str(), tunnelPort.m_fdb_count); + return; + } + gPortsOrch->removeTunnel(tunnelPort); + vtep_ptr->deletePendingSIPTunnel(); + } + return; + } getTunnelDIPFromPort(tunnelPort, remote_vtep); //If there are IMR/IP routes to the remote VTEP then ignore this call - refcnt = vtep_ptr->getDipTunnelRefCnt(remote_vtep); + refcnt = vtep_ptr->getRemoteEndPointRefCnt(remote_vtep); if (refcnt > 0) { SWSS_LOG_INFO("Tunnel bridge port not removed. remote = %s refcnt = %d", - remote_vtep.c_str(), refcnt); + remote_vtep.c_str(), refcnt); return; } @@ -1541,7 +1658,7 @@ void VxlanTunnelOrch::deleteTunnelPort(Port &tunnelPort) if (!ret) { SWSS_LOG_ERROR("Remove Bridge port failed for remote = %s fdbcount = %d", - remote_vtep.c_str(), tunnelPort.m_fdb_count); + remote_vtep.c_str(), tunnelPort.m_fdb_count); return; } gPortsOrch->removeTunnel(tunnelPort); @@ -1549,23 +1666,31 @@ void VxlanTunnelOrch::deleteTunnelPort(Port &tunnelPort) // Remove DIP Tunnel HW vtep_ptr->deleteDynamicDIPTunnel(remote_vtep, TUNNEL_USER_IMR, false); SWSS_LOG_NOTICE("diprefcnt for remote %s = %d", - remote_vtep.c_str(), vtep_ptr->getDipTunnelRefCnt(remote_vtep)); - + remote_vtep.c_str(), vtep_ptr->getRemoteEndPointRefCnt(remote_vtep)); // Remove SIP Tunnel HW which might be pending on delete vtep_ptr->deletePendingSIPTunnel(); return ; } -std::string VxlanTunnelOrch::getTunnelPortName(const std::string& remote_vtep) +std::string VxlanTunnelOrch::getTunnelPortName(const std::string& vtep, bool local) { - std::string tunnelPortName = "Port_EVPN_" + remote_vtep; + + std::string tunnelPortName; + if (local) + { + tunnelPortName = LOCAL_TUNNEL_PORT_PREFIX + vtep; + } + else + { + tunnelPortName = EVPN_TUNNEL_PORT_PREFIX + vtep; + } return tunnelPortName; } void VxlanTunnelOrch::getTunnelNameFromDIP(const string& dip, string& tunnel_name) { - tunnel_name = "EVPN_" + dip; + tunnel_name = EVPN_TUNNEL_NAME_PREFIX + dip; return; } @@ -1582,7 +1707,7 @@ void VxlanTunnelOrch::getTunnelNameFromPort(string& tunnel_portname, string& tun void VxlanTunnelOrch:: getTunnelDIPFromPort(Port& tunnelPort, string& remote_vtep) { remote_vtep = tunnelPort.m_alias; - remote_vtep.erase(0,sizeof("Port_EVPN_")-1); + remote_vtep.erase(0,sizeof(EVPN_TUNNEL_PORT_PREFIX)-1); } @@ -1650,9 +1775,9 @@ void VxlanTunnelOrch::addRemoveStateTableEntry(string tunnel_name, } } -bool VxlanTunnelOrch::getTunnelPort(const std::string& remote_vtep,Port& tunnelPort) +bool VxlanTunnelOrch::getTunnelPort(const std::string& vtep,Port& tunnelPort, bool local) { - auto port_tunnel_name = getTunnelPortName(remote_vtep); + auto port_tunnel_name = getTunnelPortName(vtep, local); bool ret = gPortsOrch->getPort(port_tunnel_name,tunnelPort); @@ -1662,6 +1787,49 @@ bool VxlanTunnelOrch::getTunnelPort(const std::string& remote_vtep,Port& tunnelP return ret; } +bool VxlanTunnel::isTunnelReferenced() +{ + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); + auto src_vtep = getSrcIP().to_string(); + auto port_tunnel_name = tunnel_orch->getTunnelPortName(src_vtep, true); + bool ret; + Port tunnelPort; + bool dip_tunnels_used = tunnel_orch->isDipTunnelsSupported(); + + ret = gPortsOrch->getPort(port_tunnel_name, tunnelPort); + if (!ret) + { + SWSS_LOG_ERROR("Get port failed for source vtep %s", port_tunnel_name.c_str()); + return false; + } + + + if (dip_tunnels_used) + { + return (getDipTunnelCnt() != 0); + } + else + { + if (tunnelPort.m_fdb_count != 0) + { + return true; + } + /* Bridge port will have reference since on IMET routes reception L2MC group member + would be created with end point IP and the P2MP tunnel bridge port */ + + if (gPortsOrch->getBridgePortReferenceCount(tunnelPort) != 0) + { + return true; + } + /* If there are routes pointing to the tunnel */ + if (!tnl_users_.empty()) + { + return true; + } + } + return false; +} + //------------------- VXLAN_TUNNEL_MAP Table --------------------------// bool VxlanTunnelMapOrch::addOperation(const Request& request) @@ -1688,7 +1856,7 @@ bool VxlanTunnelMapOrch::addOperation(const Request& request) } auto vni_id = static_cast(request.getAttrUint("vni")); - if (vni_id >= 1<<24) + if (vni_id >= MAX_VNI_ID) { SWSS_LOG_ERROR("Vxlan tunnel map vni id is too big: %d", vni_id); return true; @@ -1722,6 +1890,15 @@ bool VxlanTunnelMapOrch::addOperation(const Request& request) TUNNELMAP_SET_VLAN(mapper_list); TUNNELMAP_SET_VRF(mapper_list); tunnel_obj->createTunnelHw(mapper_list,TUNNEL_MAP_USE_DEDICATED_ENCAP_DECAP); + Port tunPort; + auto src_vtep = tunnel_obj->getSrcIP().to_string(); + if (!tunnel_orch->getTunnelPort(src_vtep, tunPort, true)) + { + auto port_tunnel_name = tunnel_orch->getTunnelPortName(src_vtep, true); + gPortsOrch->addTunnel(port_tunnel_name, tunnel_obj->getTunnelId(), false); + gPortsOrch->getPort(port_tunnel_name,tunPort); + gPortsOrch->addBridgePort(tunPort); + } } const auto tunnel_map_id = tunnel_obj->getDecapMapId(TUNNEL_MAP_T_VLAN); @@ -1761,7 +1938,7 @@ bool VxlanTunnelMapOrch::delOperation(const Request& request) const auto& tunnel_name = request.getKeyString(0); const auto& tunnel_map_entry_name = request.getKeyString(1); const auto& full_tunnel_map_entry_name = request.getFullKey(); - + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); if (!isTunnelMapExists(full_tunnel_map_entry_name)) { @@ -1791,7 +1968,6 @@ bool VxlanTunnelMapOrch::delOperation(const Request& request) vxlan_tunnel_map_table_.erase(full_tunnel_map_entry_name); - VxlanTunnelOrch* tunnel_orch = gDirectory.get(); if (!tunnel_orch->isTunnelExists(tunnel_name)) { SWSS_LOG_WARN("Vxlan tunnel '%s' doesn't exist", tunnel_name.c_str()); @@ -1808,10 +1984,31 @@ bool VxlanTunnelMapOrch::delOperation(const Request& request) if (tunnel_obj->vlan_vrf_vni_count == 0) { + Port tunnelPort; + auto src_vtep = tunnel_obj->getSrcIP().to_string(); + auto port_tunnel_name = tunnel_orch->getTunnelPortName(src_vtep, true); + bool ret; + + ret = gPortsOrch->getPort(port_tunnel_name, tunnelPort); // If there are Dynamic DIP Tunnels referring to this SIP Tunnel // then mark it as pending for delete. - if (tunnel_obj->getDipTunnelCnt() == 0) + if (!tunnel_obj->isTunnelReferenced()) { + if (!ret) + { + SWSS_LOG_ERROR("Get port failed for source vtep %s", port_tunnel_name.c_str()); + return true; + } + ret = gPortsOrch->removeBridgePort(tunnelPort); + if (!ret) + { + SWSS_LOG_ERROR("Remove Bridge port failed for source vtep = %s fdbcount = %d", + port_tunnel_name.c_str(), tunnelPort.m_fdb_count); + return true; + } + + gPortsOrch->removeTunnel(tunnelPort); + uint8_t mapper_list=0; TUNNELMAP_SET_VLAN(mapper_list); TUNNELMAP_SET_VRF(mapper_list); @@ -1820,8 +2017,16 @@ bool VxlanTunnelMapOrch::delOperation(const Request& request) else { tunnel_obj->del_tnl_hw_pending = true; - SWSS_LOG_WARN("Postponing the SIP Tunnel HW deletion DIP Tunnel count = %d", - tunnel_obj->getDipTunnelCnt()); + if (tunnel_orch->isDipTunnelsSupported()) + { + SWSS_LOG_WARN("Postponing the SIP Tunnel HW deletion DIP Tunnel count = %d", + tunnel_obj->getDipTunnelCnt()); + } + else + { + SWSS_LOG_WARN("Postponing the SIP Tunnel HW deletion Remote reference count = %d", + gPortsOrch->getBridgePortReferenceCount(tunnelPort)); + } } } @@ -1860,7 +2065,7 @@ bool VxlanVrfMapOrch::addOperation(const Request& request) } auto vni_id = static_cast(request.getAttrUint("vni")); - if (vni_id >= 1<<24) + if (vni_id >= MAX_VNI_ID) { SWSS_LOG_ERROR("Vxlan vni id is too big: %d", vni_id); return true; @@ -1982,7 +2187,7 @@ bool VxlanVrfMapOrch::delOperation(const Request& request) //------------------- EVPN_REMOTE_VNI Table --------------------------// -bool EvpnRemoteVniOrch::addOperation(const Request& request) +bool EvpnRemoteVnip2pOrch::addOperation(const Request& request) { SWSS_LOG_ENTER(); @@ -1994,7 +2199,7 @@ bool EvpnRemoteVniOrch::addOperation(const Request& request) sai_vlan_id_t vlan_id = (sai_vlan_id_t) stoi(vlan_name.substr(4)); auto vni_id = static_cast(request.getAttrUint("vni")); - if (vni_id >= 1<<24) + if (vni_id >= MAX_VNI_ID) { SWSS_LOG_ERROR("Vxlan tunnel map vni id is too big: %d", vni_id); return true; @@ -2049,7 +2254,7 @@ bool EvpnRemoteVniOrch::addOperation(const Request& request) return true; } -bool EvpnRemoteVniOrch::delOperation(const Request& request) +bool EvpnRemoteVnip2pOrch::delOperation(const Request& request) { bool ret; @@ -2063,7 +2268,7 @@ bool EvpnRemoteVniOrch::delOperation(const Request& request) sai_vlan_id_t vlan_id = (sai_vlan_id_t)stoi(vlan_name.substr(4)); auto vni_id = static_cast(request.getAttrUint("vni")); - if (vni_id >= 1<<24) + if (vni_id >= MAX_VNI_ID) { SWSS_LOG_ERROR("Vxlan tunnel map vni id is too big: %d", vni_id); return true; @@ -2113,7 +2318,7 @@ bool EvpnRemoteVniOrch::delOperation(const Request& request) } SWSS_LOG_INFO("imrcount=%d fdbcount=%d ", - vtep_ptr->getDipTunnelIMRRefCnt(remote_vtep), + vtep_ptr->getRemoteEndPointIMRRefCnt(remote_vtep), tunnelPort.m_fdb_count ); ret = tunnel_orch->delTunnelUser(remote_vtep, vni_id, vlan_id, TUNNEL_USER_IMR); @@ -2125,6 +2330,149 @@ bool EvpnRemoteVniOrch::delOperation(const Request& request) return ret; } +bool EvpnRemoteVnip2mpOrch::addOperation(const Request& request) +{ + SWSS_LOG_ENTER(); + + EvpnNvoOrch* evpn_orch = gDirectory.get(); + // Extract end point ip + auto end_point_ip = request.getKeyString(1); + + // Extract VLAN and VNI + auto vlan_name = request.getKeyString(0); + sai_vlan_id_t vlan_id = to_uint(vlan_name.substr(4), MIN_VLAN_ID, MAX_VLAN_ID); + + auto vni_id = static_cast(request.getAttrUint("vni")); + if (vni_id >= MAX_VNI_ID) + { + SWSS_LOG_ERROR("Vxlan tunnel map vni id is too big: %d", vni_id); + return true; + } + + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); + Port tunnelPort, vlanPort; + auto vtep_ptr = evpn_orch->getEVPNVtep(); + if (!vtep_ptr) + { + SWSS_LOG_WARN("Remote VNI add: Source VTEP not found. remote=%s vid=%d", + end_point_ip.c_str(),vlan_id); + return true; + } + + if (!gPortsOrch->getVlanByVlanId(vlan_id, vlanPort)) + { + SWSS_LOG_WARN("Vxlan tunnel map vlan id doesn't exist: %d", vlan_id); + return false; + } + + auto src_vtep = vtep_ptr->getSrcIP().to_string(); + if (tunnel_orch->getTunnelPort(src_vtep,tunnelPort, true)) + { + SWSS_LOG_INFO("Vxlan tunnelPort exists: %s", src_vtep.c_str()); + + if (gPortsOrch->isVlanMember(vlanPort, tunnelPort, end_point_ip)) + { + SWSS_LOG_WARN("Remote end point %s already member of vid %d", + end_point_ip.c_str(),vlan_id); + vtep_ptr->increment_spurious_imr_add(end_point_ip); + return true; + } + } + else + { + SWSS_LOG_WARN("Vxlan tunnelPort doesn't exist: %s", src_vtep.c_str()); + return false; + } + + // SAI Call to add tunnel to the VLAN flood domain + + string tagging_mode = "untagged"; + gPortsOrch->addVlanMember(vlanPort, tunnelPort, tagging_mode, end_point_ip); + + SWSS_LOG_INFO("end_point_ip=%s vni=%d vlanid=%d ", + end_point_ip.c_str(), vni_id, vlan_id); + + return true; +} + +bool EvpnRemoteVnip2mpOrch::delOperation(const Request& request) +{ + SWSS_LOG_ENTER(); + + // Extract end point ip + auto end_point_ip = request.getKeyString(1); + + // Extract VLAN and VNI + auto vlan_name = request.getKeyString(0); + sai_vlan_id_t vlan_id = to_uint(vlan_name.substr(4), MIN_VLAN_ID, MAX_VLAN_ID); + + auto vni_id = static_cast(request.getAttrUint("vni")); + if (vni_id >= MAX_VNI_ID) + { + SWSS_LOG_ERROR("Vxlan tunnel map vni id is too big: %d", vni_id); + return true; + } + + // SAI Call to add tunnel to the VLAN flood domain + + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); + Port vlanPort, tunnelPort; + EvpnNvoOrch* evpn_orch = gDirectory.get(); + + auto vtep_ptr = evpn_orch->getEVPNVtep(); + if (!vtep_ptr) + { + SWSS_LOG_WARN("Remote VNI add: VTEP not found. remote=%s vid=%d", + end_point_ip.c_str(), vlan_id); + return true; + } + + if (!gPortsOrch->getVlanByVlanId(vlan_id, vlanPort)) + { + SWSS_LOG_WARN("Vxlan tunnel map vlan id doesn't exist: %d", vlan_id); + return true; + } + + auto src_vtep = vtep_ptr->getSrcIP().to_string(); + if (!tunnel_orch->getTunnelPort(src_vtep,tunnelPort,true)) + { + SWSS_LOG_WARN("RemoteVniDel getTunnelPort Fails: %s", src_vtep.c_str()); + return true; + } + + + if (!gPortsOrch->isVlanMember(vlanPort, tunnelPort, end_point_ip)) + { + SWSS_LOG_WARN("marking it as spurious tunnelPort %s not a member of vid %d", + end_point_ip.c_str(), vlan_id); + vtep_ptr->increment_spurious_imr_del(end_point_ip); + return true; + } + + if (!gPortsOrch->removeVlanMember(vlanPort, tunnelPort, end_point_ip)) + { + SWSS_LOG_WARN("RemoteVniDel remove vlan member fails: vlan:%hu ip %s", + vlan_id, end_point_ip.c_str()); + return false; + } + + if (vtep_ptr->del_tnl_hw_pending && + !vtep_ptr->isTunnelReferenced()) + { + bool ret = gPortsOrch->removeBridgePort(tunnelPort); + if (!ret) + { + SWSS_LOG_ERROR("Remove Bridge port failed for source vtep = %s fdbcount = %d", + src_vtep.c_str(), tunnelPort.m_fdb_count); + return true; + } + gPortsOrch->removeTunnel(tunnelPort); + vtep_ptr->deletePendingSIPTunnel(); + } + + return true; +} + //------------------- EVPN_NVO Table --------------------------// bool EvpnNvoOrch::addOperation(const Request& request) diff --git a/orchagent/vxlanorch.h b/orchagent/vxlanorch.h index 9df5e34bb673..bd7bc4fabf08 100644 --- a/orchagent/vxlanorch.h +++ b/orchagent/vxlanorch.h @@ -35,6 +35,15 @@ typedef enum #define IS_TUNNELMAP_SET_VRF(x) ((x)& (1< VTEPTable; class VxlanTunnelOrch : public Orch2 { public: - VxlanTunnelOrch(DBConnector *statedb, DBConnector *db, const std::string& tableName) : - Orch2(db, tableName, request_), - m_stateVxlanTable(statedb, STATE_VXLAN_TUNNEL_TABLE_NAME) - {} - + VxlanTunnelOrch(DBConnector *statedb, DBConnector *db, const std::string& tableName); bool isTunnelExists(const std::string& tunnelName) const { @@ -296,7 +307,7 @@ class VxlanTunnelOrch : public Orch2 bool removeNextHopTunnel(string tunnelName, IpAddress& ipAddr, MacAddress macAddress, uint32_t vni=0); - bool getTunnelPort(const std::string& remote_vtep,Port& tunnelPort); + bool getTunnelPort(const std::string& vtep,Port& tunnelPort, bool local=false); bool addTunnelUser(string remote_vtep, uint32_t vni_id, uint32_t vlan, tunnel_user_t usr, @@ -310,7 +321,7 @@ class VxlanTunnelOrch : public Orch2 void addRemoveStateTableEntry(const string, IpAddress&, IpAddress&, tunnel_creation_src_t, bool); - std::string getTunnelPortName(const std::string& remote_vtep); + std::string getTunnelPortName(const std::string& vtep, bool local=false); void getTunnelNameFromDIP(const string& dip, string& tunnel_name); void getTunnelNameFromPort(string& tunnel_portname, string& tunnel_name); void getTunnelDIPFromPort(Port& tunnelPort, string& remote_vtep); @@ -338,6 +349,10 @@ class VxlanTunnelOrch : public Orch2 vxlan_vni_vlan_map_table_.erase(vni); } + bool isDipTunnelsSupported(void) + { + return is_dip_tunnel_supported; + } private: @@ -349,6 +364,7 @@ class VxlanTunnelOrch : public Orch2 VxlanVniVlanMapTable vxlan_vni_vlan_map_table_; VTEPTable vtep_table_; Table m_stateVxlanTable; + bool is_dip_tunnel_supported; }; const request_description_t vxlan_tunnel_map_request_description = { @@ -445,10 +461,23 @@ class EvpnRemoteVniRequest : public Request EvpnRemoteVniRequest() : Request(evpn_remote_vni_request_description, ':') { } }; -class EvpnRemoteVniOrch : public Orch2 +class EvpnRemoteVnip2pOrch : public Orch2 +{ +public: + EvpnRemoteVnip2pOrch(DBConnector *db, const std::string& tableName) : Orch2(db, tableName, request_) { } + + +private: + virtual bool addOperation(const Request& request); + virtual bool delOperation(const Request& request); + + EvpnRemoteVniRequest request_; +}; + +class EvpnRemoteVnip2mpOrch : public Orch2 { public: - EvpnRemoteVniOrch(DBConnector *db, const std::string& tableName) : Orch2(db, tableName, request_) { } + EvpnRemoteVnip2mpOrch(DBConnector *db, const std::string& tableName) : Orch2(db, tableName, request_) { } private: diff --git a/tests/conftest.py b/tests/conftest.py index a5e6dbd04666..d0ad19743c44 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -835,9 +835,10 @@ def get_map_iface_bridge_port_id(self, asic_db): status, data = tbl.get(key) assert status values = dict(data) - iface_id = values["SAI_BRIDGE_PORT_ATTR_PORT_ID"] - iface_name = port_id_2_iface[iface_id] - iface_2_bridge_port_id[iface_name] = key + if "SAI_BRIDGE_PORT_ATTR_PORT_ID" in values: + iface_id = values["SAI_BRIDGE_PORT_ATTR_PORT_ID"] + iface_name = port_id_2_iface[iface_id] + iface_2_bridge_port_id[iface_name] = key return iface_2_bridge_port_id diff --git a/tests/evpn_tunnel.py b/tests/evpn_tunnel.py new file mode 100644 index 000000000000..5002a1281c93 --- /dev/null +++ b/tests/evpn_tunnel.py @@ -0,0 +1,1108 @@ +from swsscommon import swsscommon +import time +import json +from pytest import * + +class VxlanEvpnHelper(object): + def create_entry(self, tbl, key, pairs): + fvs = swsscommon.FieldValuePairs(pairs) + tbl.set(key, fvs) + time.sleep(1) + + def create_entry_tbl(self, db, table, key, pairs): + tbl = swsscommon.Table(db, table) + self.create_entry(tbl, key, pairs) + + def delete_entry_tbl(self, db, table, key): + tbl = swsscommon.Table(db, table) + tbl._del(key) + time.sleep(1) + + def create_entry_pst(self, db, table, key, pairs): + tbl = swsscommon.ProducerStateTable(db, table) + self.create_entry(tbl, key, pairs) + + def delete_entry_pst(self, db, table, key): + tbl = swsscommon.ProducerStateTable(db, table) + tbl._del(key) + time.sleep(1) + + def how_many_entries_exist(self, db, table): + tbl = swsscommon.Table(db, table) + return len(tbl.getKeys()) + + def get_exist_entries(self, dvs, table): + db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + tbl = swsscommon.Table(db, table) + return set(tbl.getKeys()) + + def get_created_entry(self, db, table, existed_entries): + tbl = swsscommon.Table(db, table) + entries = set(tbl.getKeys()) + new_entries = list(entries - existed_entries) + assert len(new_entries) == 1, "Wrong number of created entries." + return new_entries[0] + + def get_created_entries(self, db, table, existed_entries, count): + tbl = swsscommon.Table(db, table) + entries = set(tbl.getKeys()) + new_entries = list(entries - existed_entries) + assert len(new_entries) == count, "Wrong number of created entries." + new_entries.sort() + return new_entries + + def get_deleted_entries(self, db, table, existed_entries, count): + tbl = swsscommon.Table(db, table) + entries = set(tbl.getKeys()) + old_entries = list(existed_entries - entries) + assert len(old_entries) == count, "Wrong number of deleted entries." + old_entries.sort() + return old_entries + + def check_object(self, db, table, key, expected_attributes): + tbl = swsscommon.Table(db, table) + keys = tbl.getKeys() + assert key in keys, "The desired key is not presented" + + status, fvs = tbl.get(key) + assert status, "Got an error when get a key" + + assert len(fvs) >= len(expected_attributes), "Incorrect attributes" + + for name, value in fvs: + if name in expected_attributes: + assert expected_attributes[name] == value, "Wrong value %s for the attribute %s = %s" % \ + (value, name, expected_attributes[name]) + + def get_key_with_attr(self, db, table, expected_attributes ): + tbl = swsscommon.Table(db, table) + keys = tbl.getKeys() + retkey = list() + + for key in keys: + status, fvs = tbl.get(key) + assert status, "Got an error when get a key" + + if len(fvs) < len(expected_attributes): + continue + + num_match = 0 + for name, value in fvs: + if name in expected_attributes: + if expected_attributes[name] == value: + num_match += 1 + if num_match == len(expected_attributes): + retkey.append(key) + + return retkey + + def check_deleted_object(self, db, table, key): + tbl = swsscommon.Table(db, table) + keys = tbl.getKeys() + assert key not in keys, "The desired key is not removed" + +class VxlanTunnel(object): + + ASIC_TUNNEL_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL" + ASIC_TUNNEL_MAP = "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP" + ASIC_TUNNEL_MAP_ENTRY = "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP_ENTRY" + ASIC_TUNNEL_TERM_ENTRY = "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_TERM_TABLE_ENTRY" + ASIC_BRIDGE_PORT = "ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT" + ASIC_VRF_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_VIRTUAL_ROUTER" + ASIC_RIF_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE" + ASIC_ROUTE_ENTRY = "ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY" + ASIC_NEXT_HOP = "ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP" + ASIC_NEXT_HOP_GRP = "ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP" + ASIC_NEXT_HOP_GRP_MEMBERS = "ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER" + + tunnel_map_ids = set() + tunnel_map_entry_ids = set() + tunnel_map_vrf_entry_ids = set() + tunnel_ids = set() + tunnel_term_ids = set() + bridgeport_ids = set() + tunnel_map_map = {} + tunnel = {} + tunnel_appdb = {} + tunnel_term = {} + map_entry_map = {} + dip_tunnel_map = {} + dip_tun_state_map = {} + diptunterm_map = {} + bridgeport_map = {} + vlan_id_map = {} + vlan_member_map = {} + l2mcgroup_member_map = {} + l2mcgroup_map = {} + vr_map = {} + vnet_vr_ids = set() + nh_ids = {} + nh_grp_id = set() + nh_grp_member_id = set() + route_id = {} + helper = None + switch_mac = None + + + def __init__(self): + self.helper = VxlanEvpnHelper() + + def create_evpn_nvo(self, dvs, nvoname, tnl_name): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + attrs = [ + ("source_vtep", tnl_name), + ] + + # create the VXLAN tunnel Term entry in Config DB + self.helper.create_entry_tbl( + conf_db, + "VXLAN_EVPN_NVO", nvoname, + attrs, + ) + + def remove_evpn_nvo(self, dvs, nvoname): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + self.helper.delete_entry_tbl(conf_db,"VXLAN_EVPN_NVO", nvoname) + + def create_vxlan_tunnel(self, dvs, name, src_ip, dst_ip = '0.0.0.0', skip_dst_ip=True): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + attrs = [ + ("src_ip", src_ip), + ] + + if not skip_dst_ip: + attrs.append(("dst_ip", dst_ip)) + + # create the VXLAN tunnel Term entry in Config DB + self.helper.create_entry_tbl( + conf_db, + "VXLAN_TUNNEL", name, + attrs, + ) + + def create_vxlan_tunnel_map(self, dvs, tnl_name, map_name, vni_id, vlan_id): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + attrs = [ + ("vni", vni_id), + ("vlan", vlan_id), + ] + + # create the VXLAN tunnel Term entry in Config DB + self.helper.create_entry_tbl( + conf_db, + "VXLAN_TUNNEL_MAP", "%s|%s" % (tnl_name, map_name), + attrs, + ) + + def create_evpn_remote_vni(self, dvs, vlan_id, remote_vtep, vnid): + app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + self.helper.create_entry_pst( + app_db, + "VXLAN_REMOTE_VNI_TABLE", "%s:%s" % (vlan_id, remote_vtep), + [ + ("vni", vnid), + ], + ) + time.sleep(2) + + def remove_vxlan_tunnel(self, dvs, tnl_name): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + # create the VXLAN tunnel Term entry in Config DB + self.helper.delete_entry_tbl( + conf_db, + "VXLAN_TUNNEL", tnl_name + ) + + def remove_vxlan_tunnel_map(self, dvs, tnl_name, map_name,vni_id, vlan_id): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + # Remove the VXLAN tunnel map entry in Config DB + self.helper.delete_entry_tbl( + conf_db, + "VXLAN_TUNNEL_MAP", "%s|%s" % (tnl_name, map_name) + ) + + def remove_evpn_remote_vni(self, dvs, vlan_id, remote_vtep ): + app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + self.helper.delete_entry_pst( + app_db, + "VXLAN_REMOTE_VNI_TABLE", "%s:%s" % (vlan_id, remote_vtep), + ) + time.sleep(2) + + def create_vxlan_vrf_tunnel_map(self, dvs, vrfname, vni_id): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + attrs = [ + ("vni", vni_id), + ] + + # create the VXLAN VRF tunnel Term entry in Config DB + self.helper.create_entry_tbl( + conf_db, + "VRF", vrfname, + attrs, + ) + + def remove_vxlan_vrf_tunnel_map(self, dvs, vrfname): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + attrs = [ + ("vni", "0"), + ] + + # remove the VXLAN VRF tunnel Term entry in Config DB + self.helper.create_entry_tbl( + conf_db, + "VRF", vrfname, + attrs, + ) + + def create_vlan1(self, dvs, vlan_name): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + vlan_id = vlan_name[4:] + + # create vlan + self.helper.create_entry_tbl( + conf_db, + "VLAN", vlan_name, + [ + ("vlanid", vlan_id), + ], + ) + + def create_vrf_route(self, dvs, prefix, vrf_name, endpoint, ifname, mac="", vni=0): + app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + + attrs = [ + ("nexthop", endpoint), + ("ifname", ifname), + ] + + if vni: + attrs.append(('vni_label', vni)) + + if mac: + attrs.append(('router_mac', mac)) + + self.helper.create_entry_pst( + app_db, + "ROUTE_TABLE", "%s:%s" % (vrf_name, prefix), + attrs, + ) + + time.sleep(2) + + def delete_vrf_route(self, dvs, prefix, vrf_name): + app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + + self.helper.delete_entry_pst(app_db, "ROUTE_TABLE", "%s:%s" % (vrf_name, prefix)) + + time.sleep(2) + + def create_vrf_route_ecmp(self, dvs, prefix, vrf_name, ecmp_nexthop_attributes): + app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + + self.helper.create_entry_pst( + app_db, + "ROUTE_TABLE", "%s:%s" % (vrf_name, prefix), + ecmp_nexthop_attributes, + ) + + time.sleep(2) + + def create_vlan(self, dvs, vlan_name, vlan_ids): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + vlan_id = vlan_name[4:] + + # create vlan + self.helper.create_entry_tbl( + conf_db, + "VLAN", vlan_name, + [ + ("vlanid", vlan_id), + ], + ) + + time.sleep(1) + + vlan_oid = self.helper.get_created_entry(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN", vlan_ids) + + self.helper.check_object(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN", vlan_oid, + { + "SAI_VLAN_ATTR_VLAN_ID": vlan_id, + } + ) + + return vlan_oid + + def remove_vlan(self, dvs, vlan): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + tbl = swsscommon.Table(conf_db, "VLAN") + tbl._del("Vlan" + vlan) + time.sleep(1) + + def create_vlan_member(self, dvs, vlan, interface, tagging_mode="untagged"): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + tbl = swsscommon.Table(conf_db, "VLAN_MEMBER") + fvs = swsscommon.FieldValuePairs([("tagging_mode", tagging_mode)]) + tbl.set("Vlan" + vlan + "|" + interface, fvs) + time.sleep(1) + + def remove_vlan_member(self, dvs, vlan, interface): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + tbl = swsscommon.Table(conf_db, "VLAN_MEMBER") + tbl._del("Vlan" + vlan + "|" + interface) + time.sleep(1) + + + def create_vlan_interface(self, dvs, vlan_name, ifname, vrf_name, ipaddr): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + # create a vlan member in config db + self.helper.create_entry_tbl( + conf_db, + "VLAN_MEMBER", "%s|%s" % (vlan_name, ifname), + [ + ("tagging_mode", "untagged"), + ], + ) + + time.sleep(1) + + # create vlan interface in config db + self.helper.create_entry_tbl( + conf_db, + "VLAN_INTERFACE", vlan_name, + [ + ("vrf_name", vrf_name), + ], + ) + + app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + self.helper.create_entry_pst( + app_db, + "INTF_TABLE", vlan_name, + [ + ("vrf_name", vrf_name), + ], + ) + time.sleep(2) + + self.helper.create_entry_tbl( + conf_db, + "VLAN_INTERFACE", "%s|%s" % (vlan_name, ipaddr), + [ + ("family", "IPv4"), + ], + ) + + time.sleep(2) + + def delete_vlan_interface(self, dvs, ifname, ipaddr): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + self.helper.delete_entry_tbl(conf_db, "VLAN_INTERFACE", "%s|%s" % (ifname, ipaddr)) + time.sleep(2) + + self.helper.delete_entry_tbl(conf_db, "VLAN_INTERFACE", ifname) + time.sleep(2) + + def get_switch_mac(self, dvs): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + tbl = swsscommon.Table(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_SWITCH') + + entries = tbl.getKeys() + mac = None + for entry in entries: + status, fvs = tbl.get(entry) + assert status, "Got an error when get a key" + for key, value in fvs: + if key == 'SAI_SWITCH_ATTR_SRC_MAC_ADDRESS': + mac = value + break + else: + assert False, 'Don\'t found switch mac' + + return mac + + def fetch_exist_entries(self, dvs): + self.tunnel_ids = self.helper.get_exist_entries(dvs, self.ASIC_TUNNEL_TABLE) + self.tunnel_map_ids = self.helper.get_exist_entries(dvs, self.ASIC_TUNNEL_MAP) + self.tunnel_map_entry_ids = self.helper.get_exist_entries(dvs, self.ASIC_TUNNEL_MAP_ENTRY) + self.tunnel_term_ids = self.helper.get_exist_entries(dvs, self.ASIC_TUNNEL_TERM_ENTRY) + self.bridgeport_ids = self.helper.get_exist_entries(dvs, self.ASIC_BRIDGE_PORT) + self.vnet_vr_ids = self.helper.get_exist_entries(dvs, self.ASIC_VRF_TABLE) + self.rifs = self.helper.get_exist_entries(dvs, self.ASIC_RIF_TABLE) + self.routes = self.helper.get_exist_entries(dvs, self.ASIC_ROUTE_ENTRY) + self.nhops = self.helper.get_exist_entries(dvs, self.ASIC_NEXT_HOP) + self.nhop_grp = self.helper.get_exist_entries(dvs, self.ASIC_NEXT_HOP_GRP) + self.nhop_grp_members = self.helper.get_exist_entries(dvs, self.ASIC_NEXT_HOP_GRP_MEMBERS) + + if self.switch_mac is None: + self.switch_mac = self.get_switch_mac(dvs) + + def check_vxlan_tunnel_map_entry_delete(self, dvs, tunnel_name, vidlist, vnilist): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + tbl = swsscommon.Table(asic_db, self.ASIC_TUNNEL_MAP_ENTRY) + + for x in range(len(vidlist)): + status, fvs = tbl.get(self.map_entry_map[tunnel_name + vidlist[x]]) + assert status == False, "SIP Tunnel Map entry not deleted" + iplinkcmd = "ip link show type vxlan dev " + tunnel_name + "-" + vidlist[x] + (exitcode, out) = dvs.runcmd(iplinkcmd) + assert exitcode != 0, "Kernel device not deleted" + + def check_vxlan_tunnel_map_entry(self, dvs, tunnel_name, vidlist, vnidlist): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + tbl = swsscommon.Table(asic_db, self.ASIC_TUNNEL_MAP_ENTRY) + + expected_attributes_1 = { + 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE': 'SAI_TUNNEL_MAP_TYPE_VNI_TO_VLAN_ID', + 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP': self.tunnel_map_map[tunnel_name][0], + 'SAI_TUNNEL_MAP_ENTRY_ATTR_VLAN_ID_VALUE': vidlist[0], + 'SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_KEY': vnidlist[0], + } + + for x in range(len(vidlist)): + expected_attributes_1['SAI_TUNNEL_MAP_ENTRY_ATTR_VLAN_ID_VALUE'] = vidlist[x] + expected_attributes_1['SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_KEY'] = vnidlist[x] + ret = self.helper.get_key_with_attr(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, expected_attributes_1) + assert len(ret) > 0, "SIP TunnelMap entry not created" + assert len(ret) == 1, "More than 1 SIP TunnMapEntry created" + self.map_entry_map[tunnel_name + vidlist[x]] = ret[0] + iplinkcmd = "ip link show type vxlan dev " + tunnel_name + "-" + vidlist[x] + (exitcode, out) = dvs.runcmd(iplinkcmd) + assert exitcode == 0, "Kernel device not created" + + def check_vxlan_sip_tunnel_delete(self, dvs, tunnel_name, sip): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + + tbl = swsscommon.Table(app_db, "VXLAN_TUNNEL_TABLE") + status, fvs = tbl.get(self.tunnel_appdb[tunnel_name]) + assert status == False, "SIP Tunnel entry not deleted from APP_DB" + + tbl = swsscommon.Table(asic_db, self.ASIC_TUNNEL_TERM_ENTRY) + status, fvs = tbl.get(self.tunnel_term[tunnel_name]) + assert status == False, "SIP Tunnel Term entry not deleted from ASIC_DB" + + tbl = swsscommon.Table(asic_db, self.ASIC_TUNNEL_TABLE) + status, fvs = tbl.get(self.tunnel[tunnel_name]) + assert status == False, "SIP Tunnel entry not deleted from ASIC_DB" + + tbl = swsscommon.Table(asic_db, self.ASIC_TUNNEL_MAP) + status, fvs = tbl.get(self.tunnel_map_map[tunnel_name][0]) + assert status == False, "SIP Tunnel mapper0 not deleted from ASIC_DB" + status, fvs = tbl.get(self.tunnel_map_map[tunnel_name][1]) + assert status == False, "SIP Tunnel mapper1 not deleted from ASIC_DB" + status, fvs = tbl.get(self.tunnel_map_map[tunnel_name][2]) + assert status == False, "SIP Tunnel mapper2 not deleted from ASIC_DB" + status, fvs = tbl.get(self.tunnel_map_map[tunnel_name][3]) + assert status == False, "SIP Tunnel mapper3 not deleted from ASIC_DB" + + tbl = swsscommon.Table(asic_db, self.ASIC_BRIDGE_PORT) + status, fvs = tbl.get(self.bridgeport_map[sip]) + assert status == False, "Tunnel bridgeport entry not deleted" + + def check_vxlan_sip_tunnel(self, dvs, tunnel_name, src_ip, vidlist, vnidlist, dst_ip = '0.0.0.0', skip_dst_ip = 'True'): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + + tunnel_map_id = self.helper.get_created_entries(asic_db, self.ASIC_TUNNEL_MAP, self.tunnel_map_ids, 4) + tunnel_id = self.helper.get_created_entry(asic_db, self.ASIC_TUNNEL_TABLE, self.tunnel_ids) + tunnel_term_id = self.helper.get_created_entry(asic_db, self.ASIC_TUNNEL_TERM_ENTRY, self.tunnel_term_ids) + tunnel_map_entry_id = self.helper.get_created_entries(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, self.tunnel_map_entry_ids, 3) + + # check that the vxlan tunnel termination are there + assert self.helper.how_many_entries_exist(asic_db, self.ASIC_TUNNEL_MAP) == (len(self.tunnel_map_ids) + 4), "The TUNNEL_MAP wasn't created" + assert self.helper.how_many_entries_exist(asic_db, self.ASIC_TUNNEL_MAP_ENTRY) == (len(self.tunnel_map_entry_ids) + 3), "The TUNNEL_MAP_ENTRY is created" + assert self.helper.how_many_entries_exist(asic_db, self.ASIC_TUNNEL_TABLE) == (len(self.tunnel_ids) + 1), "The TUNNEL wasn't created" + assert self.helper.how_many_entries_exist(asic_db, self.ASIC_TUNNEL_TERM_ENTRY) == (len(self.tunnel_term_ids) + 1), "The TUNNEL_TERM_TABLE_ENTRY wasm't created" + + self.helper.check_object(asic_db, self.ASIC_TUNNEL_MAP, tunnel_map_id[2], + { + 'SAI_TUNNEL_MAP_ATTR_TYPE': 'SAI_TUNNEL_MAP_TYPE_VNI_TO_VIRTUAL_ROUTER_ID', + } + ) + + self.helper.check_object(asic_db, self.ASIC_TUNNEL_MAP, tunnel_map_id[3], + { + 'SAI_TUNNEL_MAP_ATTR_TYPE': 'SAI_TUNNEL_MAP_TYPE_VIRTUAL_ROUTER_ID_TO_VNI', + } + ) + + decapstr = '2:' + tunnel_map_id[0] + ',' + tunnel_map_id[2] + encapstr = '2:' + tunnel_map_id[1] + ',' + tunnel_map_id[3] + #'SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE': loopback_id, + + self.helper.check_object(asic_db, self.ASIC_TUNNEL_TABLE, tunnel_id, + { + 'SAI_TUNNEL_ATTR_TYPE': 'SAI_TUNNEL_TYPE_VXLAN', + 'SAI_TUNNEL_ATTR_DECAP_MAPPERS': decapstr, + 'SAI_TUNNEL_ATTR_ENCAP_MAPPERS': encapstr, + 'SAI_TUNNEL_ATTR_PEER_MODE': 'SAI_TUNNEL_PEER_MODE_P2MP', + 'SAI_TUNNEL_ATTR_ENCAP_SRC_IP': src_ip, + } + ) + + expected_attributes = { + 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TYPE': 'SAI_TUNNEL_TERM_TABLE_ENTRY_TYPE_P2MP', + 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_DST_IP': src_ip, + 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TUNNEL_TYPE': 'SAI_TUNNEL_TYPE_VXLAN', + 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_ACTION_TUNNEL_ID': tunnel_id, + } + + if not skip_dst_ip: + expected_attributes['SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_SRC_IP'] = dst_ip + expected_attributes['SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TYPE'] = 'SAI_TUNNEL_TERM_TABLE_ENTRY_TYPE_P2P' + + self.helper.check_object(asic_db, self.ASIC_TUNNEL_TERM_ENTRY, tunnel_term_id, expected_attributes) + + expected_attributes_1 = { + 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE': 'SAI_TUNNEL_MAP_TYPE_VNI_TO_VLAN_ID', + 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP': tunnel_map_id[0], + 'SAI_TUNNEL_MAP_ENTRY_ATTR_VLAN_ID_VALUE': vidlist[0], + 'SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_KEY': vnidlist[0], + } + + for x in range(len(vidlist)): + expected_attributes_1['SAI_TUNNEL_MAP_ENTRY_ATTR_VLAN_ID_VALUE'] = vidlist[x] + expected_attributes_1['SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_KEY'] = vnidlist[x] + self.helper.check_object(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, tunnel_map_entry_id[x], expected_attributes_1) + + expected_siptnl_attributes = { + 'src_ip': src_ip, + } + + if not skip_dst_ip: + expected_siptnl_attributes['dst_ip'] = dst_ip + + ret = self.helper.get_key_with_attr(app_db, "VXLAN_TUNNEL_TABLE", expected_siptnl_attributes) + assert len(ret) > 0, "SIP Tunnel entry not created in APPDB" + assert len(ret) == 1, "More than 1 Tunn statetable entry created" + self.tunnel_appdb[tunnel_name] = ret[0] + + expected_bridgeport_attributes = { + 'SAI_BRIDGE_PORT_ATTR_TYPE': 'SAI_BRIDGE_PORT_TYPE_TUNNEL', + 'SAI_BRIDGE_PORT_ATTR_TUNNEL_ID': tunnel_id, + 'SAI_BRIDGE_PORT_ATTR_FDB_LEARNING_MODE': 'SAI_BRIDGE_PORT_FDB_LEARNING_MODE_DISABLE', + 'SAI_BRIDGE_PORT_ATTR_ADMIN_STATE': 'true', + } + ret = self.helper.get_key_with_attr(asic_db, self.ASIC_BRIDGE_PORT, expected_bridgeport_attributes) + assert len(ret) > 0, "Bridgeport entry not created" + assert len(ret) == 1, "More than 1 bridgeport entry created" + self.bridgeport_map[src_ip] = ret[0] + self.tunnel_map_ids.update(tunnel_map_id) + self.tunnel_ids.add(tunnel_id) + self.tunnel_term_ids.add(tunnel_term_id) + self.tunnel_map_map[tunnel_name] = tunnel_map_id + self.tunnel[tunnel_name] = tunnel_id + self.tunnel_term[tunnel_name] = tunnel_term_id + + def check_vxlan_dip_tunnel_delete(self, dvs, dip): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + state_db = swsscommon.DBConnector(swsscommon.STATE_DB, dvs.redis_sock, 0) + + tbl = swsscommon.Table(state_db, 'VXLAN_TUNNEL_TABLE') + status, fvs = tbl.get(self.dip_tun_state_map[dip]) + assert status == False, "State Table entry not deleted" + + tbl = swsscommon.Table(asic_db, self.ASIC_TUNNEL_TABLE) + status, fvs = tbl.get(self.dip_tunnel_map[dip]) + assert status == False, "Tunnel entry not deleted" + + tbl = swsscommon.Table(asic_db, self.ASIC_BRIDGE_PORT) + status, fvs = tbl.get(self.bridgeport_map[dip]) + assert status == False, "Tunnel bridgeport entry not deleted" + + def check_vxlan_dip_tunnel(self, dvs, vtep_name, src_ip, dip): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + state_db = swsscommon.DBConnector(swsscommon.STATE_DB, dvs.redis_sock, 0) + + expected_state_attributes = { + 'src_ip': src_ip, + 'dst_ip': dip, + 'tnl_src': 'EVPN', + } + + ret = self.helper.get_key_with_attr(state_db, 'VXLAN_TUNNEL_TABLE', expected_state_attributes) + assert len(ret) > 0, "Tunnel Statetable entry not created" + assert len(ret) == 1, "More than 1 Tunn statetable entry created" + self.dip_tun_state_map[dip] = ret[0] + + + tunnel_map_id = self.tunnel_map_map[vtep_name] + + decapstr = '2:' + tunnel_map_id[0] + ',' + tunnel_map_id[2] + encapstr = '2:' + tunnel_map_id[1] + ',' + tunnel_map_id[3] + + print(decapstr) + print(encapstr) + + expected_tun_attributes = { + 'SAI_TUNNEL_ATTR_TYPE': 'SAI_TUNNEL_TYPE_VXLAN', + 'SAI_TUNNEL_ATTR_PEER_MODE': 'SAI_TUNNEL_PEER_MODE_P2P', + 'SAI_TUNNEL_ATTR_DECAP_MAPPERS': decapstr, + 'SAI_TUNNEL_ATTR_ENCAP_MAPPERS': encapstr, + 'SAI_TUNNEL_ATTR_ENCAP_SRC_IP': src_ip, + 'SAI_TUNNEL_ATTR_ENCAP_DST_IP': dip, + } + + ret = self.helper.get_key_with_attr(asic_db, self.ASIC_TUNNEL_TABLE, expected_tun_attributes) + assert len(ret) > 0, "Tunnel entry not created" + assert len(ret) == 1, "More than 1 tunnel entry created" + + self.dip_tunnel_map[dip] = ret[0] + tunnel_id = ret[0] + + expected_bridgeport_attributes = { + 'SAI_BRIDGE_PORT_ATTR_TYPE': 'SAI_BRIDGE_PORT_TYPE_TUNNEL', + 'SAI_BRIDGE_PORT_ATTR_TUNNEL_ID': tunnel_id, + 'SAI_BRIDGE_PORT_ATTR_FDB_LEARNING_MODE': 'SAI_BRIDGE_PORT_FDB_LEARNING_MODE_DISABLE', + 'SAI_BRIDGE_PORT_ATTR_ADMIN_STATE': 'true', + } + + ret = self.helper.get_key_with_attr(asic_db, self.ASIC_BRIDGE_PORT, expected_bridgeport_attributes) + assert len(ret) > 0, "Bridgeport entry not created" + assert len(ret) == 1, "More than 1 bridgeport entry created" + + self.bridgeport_map[dip] = ret[0] + + def check_vlan_extension_delete(self, dvs, vlan_name, dip): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + tbl = swsscommon.Table(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_VLAN_MEMBER') + status, fvs = tbl.get(self.vlan_member_map[dip+vlan_name]) + assert status == False, "VLAN Member entry not deleted" + + def check_vlan_extension_delete_p2mp(self, dvs, vlan_name, sip, dip): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + tbl = swsscommon.Table(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_L2MC_GROUP_MEMBER') + status, fvs = tbl.get(self.l2mcgroup_member_map[dip+vlan_name]) + assert status == False, "L2MC Group Member entry not deleted" + + def check_vlan_extension(self, dvs, vlan_name, dip): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + expected_vlan_attributes = { + 'SAI_VLAN_ATTR_VLAN_ID': vlan_name, + } + ret = self.helper.get_key_with_attr(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_VLAN', expected_vlan_attributes) + assert len(ret) > 0, "VLAN entry not created" + assert len(ret) == 1, "More than 1 VLAN entry created" + + self.vlan_id_map[vlan_name] = ret[0] + + expected_vlan_member_attributes = { + 'SAI_VLAN_MEMBER_ATTR_VLAN_ID': self.vlan_id_map[vlan_name], + 'SAI_VLAN_MEMBER_ATTR_BRIDGE_PORT_ID': self.bridgeport_map[dip], + } + ret = self.helper.get_key_with_attr(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_VLAN_MEMBER', expected_vlan_member_attributes) + assert len(ret) > 0, "VLAN Member not created" + assert len(ret) == 1, "More than 1 VLAN member created" + self.vlan_member_map[dip+vlan_name] = ret[0] + + def check_vlan_extension_p2mp(self, dvs, vlan_name, sip, dip): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + tbl = swsscommon.Table(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_VLAN') + expected_vlan_attributes = { + 'SAI_VLAN_ATTR_VLAN_ID': vlan_name, + } + ret = self.helper.get_key_with_attr(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_VLAN', expected_vlan_attributes) + assert len(ret) > 0, "VLAN entry not created" + assert len(ret) == 1, "More than 1 VLAN entry created" + + self.vlan_id_map[vlan_name] = ret[0] + status, fvs = tbl.get(self.vlan_id_map[vlan_name]) + + print(fvs) + + uuc_flood_type = None + bc_flood_type = None + uuc_flood_group = None + bc_flood_group = None + + for attr,value in fvs: + if attr == 'SAI_VLAN_ATTR_UNKNOWN_UNICAST_FLOOD_CONTROL_TYPE': + uuc_flood_type = value + elif attr == 'SAI_VLAN_ATTR_BROADCAST_FLOOD_CONTROL_TYPE': + bc_flood_type = value + elif attr == 'SAI_VLAN_ATTR_UNKNOWN_UNICAST_FLOOD_GROUP': + uuc_flood_group = value + elif attr == 'SAI_VLAN_ATTR_BROADCAST_FLOOD_GROUP': + bc_flood_group = value + + assert uuc_flood_type == 'SAI_VLAN_FLOOD_CONTROL_TYPE_COMBINED', "Unknown unicast flood control type is not combined" + assert bc_flood_type == 'SAI_VLAN_FLOOD_CONTROL_TYPE_COMBINED', "Broadcast flood control type is not combined" + assert uuc_flood_group == bc_flood_group, "Unexpected two flood groups in VLAN" + + + expected_l2mc_group_member_attributes = { + 'SAI_L2MC_GROUP_MEMBER_ATTR_L2MC_GROUP_ID' : uuc_flood_group, + 'SAI_L2MC_GROUP_MEMBER_ATTR_L2MC_ENDPOINT_IP': dip, + 'SAI_L2MC_GROUP_MEMBER_ATTR_L2MC_OUTPUT_ID': self.bridgeport_map[sip], + } + + ret = self.helper.get_key_with_attr(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_L2MC_GROUP_MEMBER', expected_l2mc_group_member_attributes) + assert len(ret) > 0, "L2MC group Member not created" + assert len(ret) == 1, "More than 1 L2MC group member created" + self.l2mcgroup_member_map[dip+vlan_name] = ret[0] + + def check_vxlan_tunnel_entry(self, dvs, tunnel_name, vnet_name, vni_id): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + time.sleep(2) + + if (self.tunnel_map_map.get(tunnel_name) is None): + tunnel_map_id = self.helper.get_created_entries(asic_db, self.ASIC_TUNNEL_MAP, self.tunnel_map_ids, 2) + else: + tunnel_map_id = self.tunnel_map_map[tunnel_name] + + tunnel_map_entry_id = self.helper.get_created_entries(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, self.tunnel_map_entry_ids, 2) + + # check that the vxlan tunnel termination are there + assert self.helper.how_many_entries_exist(asic_db, self.ASIC_TUNNEL_MAP_ENTRY) == (len(self.tunnel_map_entry_ids) + 2), "The TUNNEL_MAP_ENTRY is created too early" + + self.helper.check_object(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, tunnel_map_entry_id[0], + { + 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE': 'SAI_TUNNEL_MAP_TYPE_VIRTUAL_ROUTER_ID_TO_VNI', + 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP': tunnel_map_id[1], + 'SAI_TUNNEL_MAP_ENTRY_ATTR_VIRTUAL_ROUTER_ID_KEY': self.vr_map[vnet_name].get('ing'), + 'SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_VALUE': vni_id, + } + ) + + self.helper.check_object(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, tunnel_map_entry_id[1], + { + 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE': 'SAI_TUNNEL_MAP_TYPE_VNI_TO_VIRTUAL_ROUTER_ID', + 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP': tunnel_map_id[0], + 'SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_KEY': vni_id, + 'SAI_TUNNEL_MAP_ENTRY_ATTR_VIRTUAL_ROUTER_ID_VALUE': self.vr_map[vnet_name].get('egr'), + } + ) + + self.tunnel_map_entry_ids.update(tunnel_map_entry_id) + + def check_vxlan_tunnel_vrf_map_entry(self, dvs, tunnel_name, vrf_name, vni_id): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + if (self.tunnel_map_map.get(tunnel_name) is None): + tunnel_map_id = self.helper.get_created_entries(asic_db, self.ASIC_TUNNEL_MAP, self.tunnel_map_ids, 4) + else: + tunnel_map_id = self.tunnel_map_map[tunnel_name] + + tunnel_map_entry_id = self.helper.get_created_entries(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, self.tunnel_map_entry_ids, 3) + + # check that the vxlan tunnel termination are there + assert self.helper.how_many_entries_exist(asic_db, self.ASIC_TUNNEL_MAP_ENTRY) == (len(self.tunnel_map_entry_ids) + 3), "The TUNNEL_MAP_ENTRY is created too early" + + self.helper.check_object(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, tunnel_map_entry_id[1], + { + 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE': 'SAI_TUNNEL_MAP_TYPE_VIRTUAL_ROUTER_ID_TO_VNI', + 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP': tunnel_map_id[3], + 'SAI_TUNNEL_MAP_ENTRY_ATTR_VIRTUAL_ROUTER_ID_KEY': self.vr_map[vrf_name].get('ing'), + 'SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_VALUE': vni_id, + } + ) + + self.tunnel_map_vrf_entry_ids.update(tunnel_map_entry_id[1]) + + self.helper.check_object(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, tunnel_map_entry_id[2], + { + 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE': 'SAI_TUNNEL_MAP_TYPE_VNI_TO_VIRTUAL_ROUTER_ID', + 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP': tunnel_map_id[2], + 'SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_KEY': vni_id, + 'SAI_TUNNEL_MAP_ENTRY_ATTR_VIRTUAL_ROUTER_ID_VALUE': self.vr_map[vrf_name].get('egr'), + } + ) + + self.tunnel_map_vrf_entry_ids.update(tunnel_map_entry_id[2]) + self.tunnel_map_entry_ids.update(tunnel_map_entry_id) + + def check_vxlan_tunnel_vrf_map_entry_remove(self, dvs, tunnel_name, vrf_name, vni_id): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + tunnel_map_entry_id = self.helper.get_deleted_entries(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, self.tunnel_map_entry_ids, 2) + self.helper.check_deleted_object(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, tunnel_map_entry_id[0]) + self.helper.check_deleted_object(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, tunnel_map_entry_id[1]) + for vrf_map_id in self.tunnel_map_vrf_entry_ids: + self.helper.check_deleted_object(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, vrf_map_id) + + def check_router_interface(self, dvs, name, vlan_oid, route_count): + # Check RIF in ingress VRF + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + expected_attr = { + "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID": self.vr_map[name].get('ing'), + "SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS": self.switch_mac, + } + + if vlan_oid: + expected_attr.update({'SAI_ROUTER_INTERFACE_ATTR_TYPE': 'SAI_ROUTER_INTERFACE_TYPE_VLAN'}) + expected_attr.update({'SAI_ROUTER_INTERFACE_ATTR_VLAN_ID': vlan_oid}) + else: + expected_attr.update({'SAI_ROUTER_INTERFACE_ATTR_TYPE': 'SAI_ROUTER_INTERFACE_TYPE_PORT'}) + + new_rif = self.helper.get_created_entry(asic_db, self.ASIC_RIF_TABLE, self.rifs) + self.helper.check_object(asic_db, self.ASIC_RIF_TABLE, new_rif, expected_attr) + + #IP2ME route will be created with every router interface + new_route = self.helper.get_created_entries(asic_db, self.ASIC_ROUTE_ENTRY, self.routes, route_count) + + self.rifs.add(new_rif) + self.routes.update(new_route) + + def check_del_router_interface(self, dvs, name): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + old_rif = self.helper.get_deleted_entries(asic_db, self.ASIC_RIF_TABLE, self.rifs, 1) + self.helper.check_deleted_object(asic_db, self.ASIC_RIF_TABLE, old_rif[0]) + + self.rifs.remove(old_rif[0]) + + def vrf_route_ids(self, dvs, vrf_name): + vr_set = set() + + vr_set.add(self.vr_map[vrf_name].get('ing')) + return vr_set + + def check_vrf_routes(self, dvs, prefix, vrf_name, endpoint, tunnel, mac="", vni=0, no_update=0): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + vr_ids = self.vrf_route_ids(dvs, vrf_name) + count = len(vr_ids) + + # Check routes in ingress VRF + expected_attr = { + "SAI_NEXT_HOP_ATTR_TYPE": "SAI_NEXT_HOP_TYPE_TUNNEL_ENCAP", + "SAI_NEXT_HOP_ATTR_IP": endpoint, + "SAI_NEXT_HOP_ATTR_TUNNEL_ID": self.tunnel[tunnel], + } + + if vni: + expected_attr.update({'SAI_NEXT_HOP_ATTR_TUNNEL_VNI': vni}) + + if mac: + expected_attr.update({'SAI_NEXT_HOP_ATTR_TUNNEL_MAC': mac}) + + if endpoint in self.nh_ids: + new_nh = self.nh_ids[endpoint] + else: + new_nh = self.helper.get_created_entry(asic_db, self.ASIC_NEXT_HOP, self.nhops) + self.nh_ids[endpoint] = new_nh + self.nhops.add(new_nh) + + self.helper.check_object(asic_db, self.ASIC_NEXT_HOP, new_nh, expected_attr) + if no_update: + count = 0 + new_route = self.helper.get_created_entries(asic_db, self.ASIC_ROUTE_ENTRY, self.routes, count) + + if count: + self.route_id[vrf_name + ":" + prefix] = new_route + + #Check if the route is in expected VRF + asic_vrs = set() + for idx in range(count): + self.helper.check_object(asic_db, self.ASIC_ROUTE_ENTRY, new_route[idx], + { + "SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID": new_nh, + } + ) + rt_key = json.loads(new_route[idx]) + asic_vrs.add(rt_key['vr']) + found_route = False + if rt_key['dest'] == prefix: + found_route = True + + assert found_route + + if count: + assert asic_vrs == vr_ids + + self.routes.update(new_route) + + return True + + def check_vrf_routes_ecmp(self, dvs, prefix, vrf_name, tunnel, nh_count, no_update=0): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + vr_ids = self.vrf_route_ids(dvs, vrf_name) + count = len(vr_ids) + + new_nhg = self.helper.get_created_entry(asic_db, self.ASIC_NEXT_HOP_GRP, self.nhop_grp) + self.nh_grp_id.add(new_nhg) + + if no_update: + count = 0 + + new_route = self.helper.get_created_entries(asic_db, self.ASIC_ROUTE_ENTRY, self.routes, count) + if count: + self.route_id[vrf_name + ":" + prefix] = new_route + + #Check if the route is in expected VRF + asic_vrs = set() + for idx in range(count): + self.helper.check_object(asic_db, self.ASIC_ROUTE_ENTRY, new_route[idx], + { + "SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID": new_nhg, + } + ) + rt_key = json.loads(new_route[idx]) + asic_vrs.add(rt_key['vr']) + + found_route = False + if rt_key['dest'] == prefix: + found_route = True + + assert found_route + + if count: + assert asic_vrs == vr_ids + + self.routes.update(new_route) + + new_nhg_members = self.helper.get_created_entries(asic_db, self.ASIC_NEXT_HOP_GRP_MEMBERS, self.nhop_grp_members, nh_count) + + for idx in range(nh_count): + self.nh_grp_member_id.add(new_nhg_members[idx]) + self.helper.check_object(asic_db, self.ASIC_NEXT_HOP_GRP_MEMBERS, new_nhg_members[idx], + { + "SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID": new_nhg, + } + ) + + nhid_list = list() + + nhg_member_tbl = swsscommon.Table(asic_db, self.ASIC_NEXT_HOP_GRP_MEMBERS) + + for k in new_nhg_members: + (status, fvs) = nhg_member_tbl.get(k) + assert status + + for v in fvs: + if v[0] == "SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID": + nhid = v[1] + nhid_list.append(nhid) + + return nhid_list + + def check_add_tunnel_nexthop(self, dvs, nh_id, endpoint, tunnel, mac, vni): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + # Check routes in ingress VRF + expected_attr = { + "SAI_NEXT_HOP_ATTR_TYPE": "SAI_NEXT_HOP_TYPE_TUNNEL_ENCAP", + "SAI_NEXT_HOP_ATTR_IP": endpoint, + "SAI_NEXT_HOP_ATTR_TUNNEL_ID": self.tunnel[tunnel], + "SAI_NEXT_HOP_ATTR_TUNNEL_VNI": vni, + "SAI_NEXT_HOP_ATTR_TUNNEL_MAC": mac, + } + + self.helper.check_object(asic_db, self.ASIC_NEXT_HOP, nh_id, expected_attr) + + def check_del_tunnel_nexthop(self, dvs, vrf_name, endpoint, tunnel, mac="", vni=0): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + del_nh_ids = self.helper.get_deleted_entries(asic_db, self.ASIC_NEXT_HOP, self.nhops, 1) + self.helper.check_deleted_object(asic_db, self.ASIC_NEXT_HOP, del_nh_ids[0]) + self.helper.check_deleted_object(asic_db, self.ASIC_NEXT_HOP, self.nh_ids[endpoint]) + assert del_nh_ids[0] == self.nh_ids[endpoint] + self.nh_ids.pop(endpoint) + return True + + def check_vrf_routes_ecmp_nexthop_grp_del(self, dvs, nh_count): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + nh_grp_id_len = len(self.nh_grp_id) + assert nh_grp_id_len == 1 + + for nh_grp_id in self.nh_grp_id: + self.helper.check_deleted_object(asic_db, self.ASIC_NEXT_HOP_GRP, nh_grp_id) + self.nh_grp_id.clear() + + nh_grp_member_id_len = len(self.nh_grp_member_id) + assert nh_grp_member_id_len == nh_count + + for nh_grp_member_id in self.nh_grp_member_id: + self.helper.check_deleted_object(asic_db, self.ASIC_NEXT_HOP_GRP_MEMBERS, nh_grp_member_id) + + self.nh_grp_member_id.clear() + + def check_del_vrf_routes(self, dvs, prefix, vrf_name): + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + del_route = self.helper.get_deleted_entries(asic_db, self.ASIC_ROUTE_ENTRY, self.routes, 1) + + for idx in range(1): + rt_key = json.loads(del_route[idx]) + found_route = False + if rt_key['dest'] == prefix: + found_route = True + + assert found_route + + self.helper.check_deleted_object(asic_db, self.ASIC_ROUTE_ENTRY, self.route_id[vrf_name + ":" + prefix]) + self.route_id.clear() + + return True + + def create_vrf(self, dvs, vrf_name): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + tbl = swsscommon.Table(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_VIRTUAL_ROUTER") + initial_entries = set(tbl.getKeys()) + + attrs = [ + ("vni", "0"), + ] + tbl = swsscommon.Table(conf_db, "VRF") + fvs = swsscommon.FieldValuePairs(attrs) + tbl.set(vrf_name, fvs) + time.sleep(2) + + tbl = swsscommon.Table(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_VIRTUAL_ROUTER") + current_entries = set(tbl.getKeys()) + assert len(current_entries - initial_entries) == 1 + + new_vr_ids = self.helper.get_created_entries(asic_db, self.ASIC_VRF_TABLE, self.vnet_vr_ids, 1) + self.vnet_vr_ids.update(new_vr_ids) + self.vr_map[vrf_name] = { 'ing':new_vr_ids[0], 'egr':new_vr_ids[0]} + + return list(current_entries - initial_entries)[0] + + def remove_vrf(self, dvs, vrf_name): + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + tbl = swsscommon.Table(conf_db, "VRF") + tbl._del(vrf_name) + time.sleep(2) + + def is_vrf_attributes_correct(self, db, table, key, expected_attributes): + tbl = swsscommon.Table(db, table) + keys = set(tbl.getKeys()) + assert key in keys, "The created key wasn't found" + + status, fvs = tbl.get(key) + assert status, "Got an error when get a key" + + # filter the fake 'NULL' attribute out + fvs = filter(lambda x : x != ('NULL', 'NULL'), fvs) + + attr_keys = {entry[0] for entry in fvs} + assert attr_keys == set(expected_attributes.keys()) + + for name, value in fvs: + assert expected_attributes[name] == value, "Wrong value %s for the attribute %s = %s" % \ + (value, name, expected_attributes[name]) + diff --git a/tests/test_evpn_fdb.py b/tests/test_evpn_fdb.py index 0989815b9d3a..f65e1d1e85fb 100644 --- a/tests/test_evpn_fdb.py +++ b/tests/test_evpn_fdb.py @@ -1,118 +1,8 @@ from swsscommon import swsscommon import time +from evpn_tunnel import VxlanTunnel,VxlanEvpnHelper -def create_entry(tbl, key, pairs): - fvs = swsscommon.FieldValuePairs(pairs) - tbl.set(key, fvs) - - # FIXME: better to wait until DB create them - time.sleep(1) - -def create_entry_tbl(db, table, key, pairs): - tbl = swsscommon.Table(db, table) - create_entry(tbl, key, pairs) - -def create_entry_pst(db, table, key, pairs): - tbl = swsscommon.ProducerStateTable(db, table) - create_entry(tbl, key, pairs) - -def delete_entry_pst(db, table, key): - tbl = swsscommon.ProducerStateTable(db, table) - tbl._del(key) - -def how_many_entries_exist(db, table): - tbl = swsscommon.Table(db, table) - return len(tbl.getKeys()) - -def remove_mac(db, table, mac, vlan): - tbl = swsscommon.Table(db, table) - tbl._del("Vlan" + vlan + "|" + mac.lower()) - time.sleep(1) - -def delete_entry_tbl(db, table, key): - tbl = swsscommon.Table(db, table) - tbl._del(key) - time.sleep(1) - -def create_evpn_nvo(db, nvoname, tnlname): - #conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - attrs = [ - ("source_vtep", tnlname), - ] - - # create the VXLAN tunnel Term entry in Config DB - create_entry_tbl( - db, - "VXLAN_EVPN_NVO", nvoname, - attrs, - ) - -def remove_evpn_nvo(db, nvoname): - #conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - delete_entry_tbl(db,"VXLAN_EVPN_NVO", nvoname,) - -def create_vxlan_tunnel(db, name, src_ip): - #conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - attrs = [ - ("src_ip", src_ip), - ] - - # create the VXLAN tunnel Term entry in Config DB - create_entry_tbl( - db, - "VXLAN_TUNNEL", name, - attrs, - ) - -def remove_vxlan_tunnel(db, tnlname): - #conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - # create the VXLAN tunnel Term entry in Config DB - delete_entry_tbl( - db, - "VXLAN_TUNNEL", tnlname, - ) - -def create_vxlan_tunnel_map(db, tnlname, mapname, vni_id, vlan_id): - #conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - attrs = [ - ("vni", vni_id), - ("vlan", vlan_id), - ] - - # create the VXLAN tunnel Term entry in Config DB - create_entry_tbl( - db, - "VXLAN_TUNNEL_MAP", "%s|%s" % (tnlname, mapname), - attrs, - ) - -def remove_vxlan_tunnel_map(db, tnlname, mapname): - #conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - # create the VXLAN tunnel Term entry in Config DB - delete_entry_tbl( - db, - "VXLAN_TUNNEL_MAP", "%s|%s" % (tnlname, mapname), - ) - -def create_evpn_remote_vni(db, vlan_id, remotevtep, vnid): - #app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - create_entry_pst( - db, - "VXLAN_REMOTE_VNI_TABLE", "%s:%s" % (vlan_id, remotevtep), - [ - ("vni", vnid), - ], - ) - -def remove_evpn_remote_vni(db, vlan_id, remotevtep ): - #app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - delete_entry_pst( - db, - "VXLAN_REMOTE_VNI_TABLE", "%s:%s" % (vlan_id, remotevtep), - ) +DVS_ENV = ["fake_platform=broadcom"] def get_vxlan_p2p_tunnel_bp(db, remote_ip): tnl_id = None @@ -159,6 +49,8 @@ def get_vxlan_p2p_tunnel_bp(db, remote_ip): def test_evpnFdb(dvs, testlog): + vxlan_obj = VxlanTunnel() + helper = VxlanEvpnHelper() dvs.setup_db() dvs.runcmd("sonic-clear fdb all") @@ -168,7 +60,7 @@ def test_evpnFdb(dvs, testlog): switch_id = dvs.getSwitchOid() print("Switch_id="+str(switch_id)) - vlan_before = how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN") + vlan_before = helper.how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN") # create vlan print("Creating Vlan3") @@ -176,7 +68,7 @@ def test_evpnFdb(dvs, testlog): dvs.create_vlan("3") time.sleep(2) - vlan_after = how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN") + vlan_after = helper.how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN") assert vlan_after - vlan_before == 1, "The Vlan3 wasn't created" print("Vlan3 is created") @@ -185,8 +77,8 @@ def test_evpnFdb(dvs, testlog): assert vlan_oid_3 is not None, "Could not find Vlan_oid" print("Vlan-3 vlan_oid="+str(vlan_oid_3)) - bp_before = how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT") - vm_before = how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN_MEMBER") + bp_before = helper.how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT") + vm_before = helper.how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN_MEMBER") print("Making Ethernet0 as a member of Vlan3") #dvs.runcmd("config vlan member add 3 Ethernet0") @@ -194,8 +86,8 @@ def test_evpnFdb(dvs, testlog): time.sleep(2) # check that the vlan information was propagated - bp_after = how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT") - vm_after = how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN_MEMBER") + bp_after = helper.how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT") + vm_after = helper.how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN_MEMBER") assert bp_after - bp_before == 1, "The bridge port wasn't created" assert vm_after - vm_before == 1, "The vlan member wasn't added" @@ -207,30 +99,30 @@ def test_evpnFdb(dvs, testlog): #create SIP side of tunnel source_tnl_name = "source_vtep_name" source_tnl_ip = "7.7.7.7" - create_vxlan_tunnel(dvs.cdb, source_tnl_name, source_tnl_ip) + vxlan_obj.create_vxlan_tunnel(dvs, source_tnl_name, source_tnl_ip) time.sleep(1) nvo_name = "evpn_nvo" - create_evpn_nvo(dvs.cdb, nvo_name, source_tnl_name) + vxlan_obj.create_evpn_nvo(dvs, nvo_name, source_tnl_name) time.sleep(1) map_name_vlan_3 = "map_3_3" - create_vxlan_tunnel_map(dvs.cdb, source_tnl_name, map_name_vlan_3, "3", "Vlan3") + vxlan_obj.create_vxlan_tunnel_map(dvs, source_tnl_name, map_name_vlan_3, "3", "Vlan3") time.sleep(1) remote_ip_6 = "6.6.6.6" - create_evpn_remote_vni(dvs.pdb, "Vlan3", remote_ip_6, "3") + vxlan_obj.create_evpn_remote_vni(dvs, "Vlan3", remote_ip_6, "3") remote_ip_8 = "8.8.8.8" - create_evpn_remote_vni(dvs.pdb, "Vlan3", remote_ip_8, "3") + vxlan_obj.create_evpn_remote_vni(dvs, "Vlan3", remote_ip_8, "3") time.sleep(1) #UT-1 Evpn Mac add from remote when tunnels are already created mac = "52:54:00:25:06:E9" print("Creating Evpn FDB Vlan3:"+mac.lower()+":6.6.6.6 in APP-DB") - create_entry_pst( + helper.create_entry_pst( dvs.pdb, "VXLAN_FDB_TABLE", "Vlan3:"+mac.lower(), [ @@ -260,7 +152,7 @@ def test_evpnFdb(dvs, testlog): #UT-2 Evpn Mac del from remote mac = "52:54:00:25:06:E9" print("Deleting Evpn FDB Vlan3:"+mac.lower()+":6.6.6.6 in APP-DB") - delete_entry_pst( + helper.delete_entry_pst( dvs.pdb, "VXLAN_FDB_TABLE", "Vlan3:"+mac.lower() ) @@ -285,7 +177,7 @@ def test_evpnFdb(dvs, testlog): print("Creating Local dynamic FDB Vlan3:"+mac.lower()+":Ethernet0 in APP-DB") # Create Dynamic MAC entry in APP DB - create_entry_pst( + helper.create_entry_pst( dvs.pdb, "FDB_TABLE", "Vlan3:"+mac.lower(), [ @@ -317,7 +209,7 @@ def test_evpnFdb(dvs, testlog): print("FDB Vlan3:"+mac+":Ethernet0 is created in STATE-DB") print("Creating Evpn FDB Vlan3:"+mac.lower()+":6.6.6.6 in APP-DB") - create_entry_pst( + helper.create_entry_pst( dvs.pdb, "VXLAN_FDB_TABLE", "Vlan3:"+mac.lower(), [ @@ -357,7 +249,7 @@ def test_evpnFdb(dvs, testlog): #UT-4 Evpn Sticky Mac add from remote mac = "52:54:00:25:06:E9" print("Creating Evpn Sticky FDB Vlan3:"+mac.lower()+":6.6.6.6 in APP-DB") - create_entry_pst( + helper.create_entry_pst( dvs.pdb, "VXLAN_FDB_TABLE", "Vlan3:"+mac.lower(), [ @@ -385,7 +277,7 @@ def test_evpnFdb(dvs, testlog): #UT-8 Evpn Mac add from remote when tunnels are already created mac = "52:54:00:25:06:E9" print("Creating Evpn FDB Vlan3:"+mac.lower()+":6.6.6.6 in APP-DB") - create_entry_pst( + helper.create_entry_pst( dvs.pdb, "VXLAN_FDB_TABLE", "Vlan3:"+mac.lower(), [ @@ -415,7 +307,7 @@ def test_evpnFdb(dvs, testlog): tnl_bp_oid_8 = get_vxlan_p2p_tunnel_bp(dvs.adb, remote_ip_8) print("Creating Evpn FDB Vlan3:"+mac.lower()+":8.8.8.8 in APP-DB") - create_entry_pst( + helper.create_entry_pst( dvs.pdb, "VXLAN_FDB_TABLE", "Vlan3:"+mac.lower(), [ @@ -445,7 +337,7 @@ def test_evpnFdb(dvs, testlog): #UT-9 Local mac move (delete and learn) when remote is already added mac = "52:54:00:25:06:E9" print("Deleting FDB Vlan3:52-54-00-25-06-E9:8.8.8.8 in ASIC-DB") - delete_entry_tbl(dvs.adb, "ASIC_STATE", "SAI_OBJECT_TYPE_FDB_ENTRY:{\"bvid\":\""+vlan_oid_3+"\",\"mac\":\""+mac+"\",\"switch_id\":\""+switch_id+"\"}") + helper.delete_entry_tbl(dvs.adb, "ASIC_STATE", "SAI_OBJECT_TYPE_FDB_ENTRY:{\"bvid\":\""+vlan_oid_3+"\",\"mac\":\""+mac+"\",\"switch_id\":\""+switch_id+"\"}") ntf = swsscommon.NotificationProducer(dvs.adb, "NOTIFICATIONS") fvp = swsscommon.FieldValuePairs() @@ -457,7 +349,7 @@ def test_evpnFdb(dvs, testlog): #raw_input("Check ASIC_DB.........") print("Creating FDB Vlan3:52-54-00-25-06-E9:Ethernet0 in ASIC-DB") - create_entry_tbl( + helper.create_entry_tbl( dvs.adb, "ASIC_STATE", "SAI_OBJECT_TYPE_FDB_ENTRY:{\"bvid\":\""+vlan_oid_3+"\",\"mac\":\"52:54:00:25:06:E9\",\"switch_id\":\""+switch_id+"\"}", [ diff --git a/tests/test_evpn_fdb_p2mp.py b/tests/test_evpn_fdb_p2mp.py new file mode 100644 index 000000000000..f8147351b370 --- /dev/null +++ b/tests/test_evpn_fdb_p2mp.py @@ -0,0 +1,376 @@ +from swsscommon import swsscommon +import time +from evpn_tunnel import VxlanTunnel,VxlanEvpnHelper + +DVS_ENV = ["fake_platform=mellanox"] + +def get_vxlan_p2mp_tunnel_bp(db, src_ip): + tnl_id = None + bp = None + print("src_ip = " + src_ip) + attributes = [("SAI_TUNNEL_ATTR_TYPE", "SAI_TUNNEL_TYPE_VXLAN"), + ("SAI_TUNNEL_ATTR_PEER_MODE", "SAI_TUNNEL_PEER_MODE_P2MP"), + ("SAI_TUNNEL_ATTR_ENCAP_SRC_IP", src_ip) + ] + tbl = swsscommon.Table(db, "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL") + keys = tbl.getKeys() + for key in keys: + status, fvs = tbl.get(key) + assert status, "Error reading from table ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL" + attrs = dict(attributes) + num_match = 0 + for k, v in fvs: + print("attr:value="+str(k)+":"+str(v)) + if k in attrs and attrs[k] == v: + num_match += 1 + if num_match == len(attributes): + tnl_id = str(key) + break + else: + tnl_id = None + + print("tnl_id = "+str(tnl_id)) + if tnl_id != None: + tbl = swsscommon.Table(db, "ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT") + keys = tbl.getKeys() + for key in keys: + status, fvs = tbl.get(key) + assert status, "Error reading from table ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT" + for k, v in fvs: + print("attr:value="+str(k)+":"+str(v)) + if k == "SAI_BRIDGE_PORT_ATTR_TUNNEL_ID" and tnl_id == v: + bp = key + break + if bp != None: + break + else: + pass + print("bp = "+str(bp)) + return bp + + +def test_evpnFdbP2MP(dvs, testlog): + vxlan_obj = VxlanTunnel() + helper = VxlanEvpnHelper() + dvs.setup_db() + + dvs.runcmd("sonic-clear fdb all") + time.sleep(2) + + #Find switch_id + switch_id = dvs.getSwitchOid() + print("Switch_id="+str(switch_id)) + + vlan_before = helper.how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN") + + # create vlan + print("Creating Vlan3") + dvs.create_vlan("3") + time.sleep(2) + + vlan_after = helper.how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN") + assert vlan_after - vlan_before == 1, "The Vlan3 wasn't created" + print("Vlan3 is created") + + # Find the vlan_oid to be used in DB communications + vlan_oid_3 = dvs.getVlanOid("3") + assert vlan_oid_3 is not None, "Could not find Vlan_oid" + print("Vlan-3 vlan_oid="+str(vlan_oid_3)) + + bp_before = helper.how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT") + vm_before = helper.how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN_MEMBER") + + print("Making Ethernet0 as a member of Vlan3") + dvs.create_vlan_member("3", "Ethernet0") + time.sleep(2) + + # check that the vlan information was propagated + bp_after = helper.how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT") + vm_after = helper.how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN_MEMBER") + + assert bp_after - bp_before == 1, "The bridge port wasn't created" + assert vm_after - vm_before == 1, "The vlan member wasn't added" + print("Ethernet0 is a member of Vlan3") + + # Get mapping between interface name and its bridge port_id + iface_2_bridge_port_id = dvs.get_map_iface_bridge_port_id(dvs.adb) + + #create SIP side of tunnel + source_tnl_name = "source_vtep_name" + source_tnl_ip = "7.7.7.7" + vxlan_obj.create_vxlan_tunnel(dvs, source_tnl_name, source_tnl_ip) + time.sleep(1) + + nvo_name = "evpn_nvo" + vxlan_obj.create_evpn_nvo(dvs, nvo_name, source_tnl_name) + time.sleep(1) + + map_name_vlan_3 = "map_3_3" + vxlan_obj.create_vxlan_tunnel_map(dvs, source_tnl_name, map_name_vlan_3, "3", "Vlan3") + time.sleep(1) + + remote_ip_6 = "6.6.6.6" + vxlan_obj.create_evpn_remote_vni(dvs, "Vlan3", remote_ip_6, "3") + remote_ip_8 = "8.8.8.8" + vxlan_obj.create_evpn_remote_vni(dvs, "Vlan3", remote_ip_8, "3") + time.sleep(1) + + #UT-1 Evpn Mac add from remote when tunnels are already created + mac = "52:54:00:25:06:E9" + print("Creating Evpn FDB Vlan3:"+mac.lower()+":6.6.6.6 in APP-DB") + helper.create_entry_pst( + dvs.pdb, + "VXLAN_FDB_TABLE", "Vlan3:"+mac.lower(), + [ + ("remote_vtep", remote_ip_6), + ("type", "dynamic"), + ("vni", "3") + ] + ) + time.sleep(1) + + tnl_bp_oid_6 = get_vxlan_p2mp_tunnel_bp(dvs.adb, source_tnl_ip) + + # check that the FDB entry is inserted into ASIC DB + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", mac), ("bvid", vlan_oid_3)], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), + ("SAI_FDB_ENTRY_ATTR_ENDPOINT_IP", remote_ip_6), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", str(tnl_bp_oid_6)), + ] + ) + assert ok == True, str(extra) + print("EVPN FDB Vlan3:"+mac.lower()+":"+remote_ip_6+" is created in ASIC-DB") + + time.sleep(1) + + #UT-2 Evpn Mac del from remote + mac = "52:54:00:25:06:E9" + print("Deleting Evpn FDB Vlan3:"+mac.lower()+":6.6.6.6 in APP-DB") + helper.delete_entry_pst( + dvs.pdb, + "VXLAN_FDB_TABLE", "Vlan3:"+mac.lower() + ) + time.sleep(1) + + # check that the FDB entry is deleted from ASIC DB + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", mac), ("bvid", vlan_oid_3)], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), + ("SAI_FDB_ENTRY_ATTR_ENDPOINT_IP", remote_ip_6), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", str(tnl_bp_oid_6)), + ] + ) + assert ok == False, str(extra) + print("EVPN FDB Vlan3:"+mac.lower()+":"+remote_ip_6+" is deleted from ASIC-DB") + + time.sleep(1) + + #UT-3 Evpn Mac add from remote when local mac is already present + mac = "52:54:00:25:06:E9" + + print("Creating Local dynamic FDB Vlan3:"+mac.lower()+":Ethernet0 in APP-DB") + # Create Dynamic MAC entry in APP DB + helper.create_entry_pst( + dvs.pdb, + "FDB_TABLE", "Vlan3:"+mac.lower(), + [ + ("port", "Ethernet0"), + ("type", "dynamic"), + ] + ) + + time.sleep(1) + + # check that the FDB entry was added in ASIC DB + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", mac), ("bvid", vlan_oid_3)], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_DYNAMIC"), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", iface_2_bridge_port_id["Ethernet0"])] + ) + assert ok, str(extra) + print("Dynamic FDB Vlan3:"+mac.lower()+":Ethernet0 is created in Asic-DB") + + # check that the FDB entry was added in STATE DB + mac1_found, extra = dvs.is_table_entry_exists(dvs.sdb, "FDB_TABLE", + "Vlan3:"+mac.lower(), + [("port", "Ethernet0"), + ("type", "dynamic"), + ] + ) + assert mac1_found, str(extra) + print("FDB Vlan3:"+mac+":Ethernet0 is created in STATE-DB") + + print("Creating Evpn FDB Vlan3:"+mac.lower()+":6.6.6.6 in APP-DB") + helper.create_entry_pst( + dvs.pdb, + "VXLAN_FDB_TABLE", "Vlan3:"+mac.lower(), + [ + ("remote_vtep", remote_ip_6), + ("type", "dynamic"), + ("vni", "3") + ] + ) + time.sleep(1) + + + # check that the FDB entry is inserted into ASIC DB + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", mac), ("bvid", str(dvs.getVlanOid("3")))], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), + ("SAI_FDB_ENTRY_ATTR_ENDPOINT_IP", remote_ip_6), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", str(tnl_bp_oid_6)), + ] + ) + assert ok, str(extra) + print("EVPN FDB Vlan3:"+mac.lower()+":"+remote_ip_6+" is created in ASIC-DB") + + # check that the Local FDB entry is deleted from STATE DB + mac1_found, extra = dvs.is_table_entry_exists(dvs.sdb, "FDB_TABLE", + "Vlan3:"+mac.lower(), + [("port", "Ethernet0"), + ("type", "dynamic"), + ] + ) + assert mac1_found == False, str(extra) + print("FDB Vlan3:"+mac+":Ethernet0 is deleted from STATE-DB") + + time.sleep(1) + + + #UT-4 Evpn Sticky Mac add from remote + mac = "52:54:00:25:06:E9" + print("Creating Evpn Sticky FDB Vlan3:"+mac.lower()+":6.6.6.6 in APP-DB") + helper.create_entry_pst( + dvs.pdb, + "VXLAN_FDB_TABLE", "Vlan3:"+mac.lower(), + [ + ("remote_vtep", remote_ip_6), + ("type", "static"), + ("vni", "3") + ] + ) + time.sleep(1) + + + # check that the FDB entry is inserted into ASIC DB + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", mac), ("bvid", str(dvs.getVlanOid("3")))], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), + ("SAI_FDB_ENTRY_ATTR_ENDPOINT_IP", remote_ip_6), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", str(tnl_bp_oid_6)), + ] + ) + assert ok, str(extra) + print("EVPN Sticky FDB Vlan3:"+mac.lower()+":"+remote_ip_6+" is created in ASIC-DB") + + #UT-8 Evpn Mac add from remote when tunnels are already created + mac = "52:54:00:25:06:E9" + print("Creating Evpn FDB Vlan3:"+mac.lower()+":6.6.6.6 in APP-DB") + helper.create_entry_pst( + dvs.pdb, + "VXLAN_FDB_TABLE", "Vlan3:"+mac.lower(), + [ + ("remote_vtep", remote_ip_6), + ("type", "dynamic"), + ("vni", "3") + ] + ) + time.sleep(1) + + # check that the FDB entry is inserted into ASIC DB + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", mac), ("bvid", vlan_oid_3)], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), + ("SAI_FDB_ENTRY_ATTR_ENDPOINT_IP", remote_ip_6), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", str(tnl_bp_oid_6)), + ] + ) + assert ok == True, str(extra) + print("EVPN FDB Vlan3:"+mac.lower()+":"+remote_ip_6+" is created in ASIC-DB") + + time.sleep(1) + + tnl_bp_oid_8 = get_vxlan_p2mp_tunnel_bp(dvs.adb, source_tnl_ip) + + print("Creating Evpn FDB Vlan3:"+mac.lower()+":8.8.8.8 in APP-DB") + helper.create_entry_pst( + dvs.pdb, + "VXLAN_FDB_TABLE", "Vlan3:"+mac.lower(), + [ + ("remote_vtep", remote_ip_8), + ("type", "dynamic"), + ("vni", "3") + ] + ) + time.sleep(1) + + # check that the FDB entry is inserted into ASIC DB + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", mac), ("bvid", vlan_oid_3)], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), + ("SAI_FDB_ENTRY_ATTR_ENDPOINT_IP", remote_ip_8), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", str(tnl_bp_oid_8)), + ] + ) + assert ok == True, str(extra) + print("EVPN FDB Vlan3:"+mac.lower()+":"+remote_ip_8+" is created in ASIC-DB") + + time.sleep(1) + + #UT-9 Local mac move (delete and learn) when remote is already added + mac = "52:54:00:25:06:E9" + print("Deleting FDB Vlan3:52-54-00-25-06-E9:8.8.8.8 in ASIC-DB") + helper.delete_entry_tbl(dvs.adb, "ASIC_STATE", "SAI_OBJECT_TYPE_FDB_ENTRY:{\"bvid\":\""+vlan_oid_3+"\",\"mac\":\""+mac+"\",\"switch_id\":\""+switch_id+"\"}") + + ntf = swsscommon.NotificationProducer(dvs.adb, "NOTIFICATIONS") + fvp = swsscommon.FieldValuePairs() + ntf_data = "[{\"fdb_entry\":\"{\\\"bvid\\\":\\\""+vlan_oid_3+"\\\",\\\"mac\\\":\\\""+mac+"\\\",\\\"switch_id\\\":\\\""+switch_id+"\\\"}\",\"fdb_event\":\"SAI_FDB_EVENT_AGED\",\"list\":[{\"id\":\"SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID\",\"value\":\""+str(tnl_bp_oid_8)+"\"}]}]" + ntf.send("fdb_event", ntf_data, fvp) + + time.sleep(2) + + print("Creating FDB Vlan3:52-54-00-25-06-E9:Ethernet0 in ASIC-DB") + helper.create_entry_tbl( + dvs.adb, + "ASIC_STATE", "SAI_OBJECT_TYPE_FDB_ENTRY:{\"bvid\":\""+vlan_oid_3+"\",\"mac\":\"52:54:00:25:06:E9\",\"switch_id\":\""+switch_id+"\"}", + [ + ("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_DYNAMIC"), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", iface_2_bridge_port_id["Ethernet0"]), + ] + ) + + ntf = swsscommon.NotificationProducer(dvs.adb, "NOTIFICATIONS") + fvp = swsscommon.FieldValuePairs() + ntf_data = "[{\"fdb_entry\":\"{\\\"bvid\\\":\\\""+vlan_oid_3+"\\\",\\\"mac\\\":\\\"52:54:00:25:06:E9\\\",\\\"switch_id\\\":\\\""+switch_id+"\\\"}\",\"fdb_event\":\"SAI_FDB_EVENT_LEARNED\",\"list\":[{\"id\":\"SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID\",\"value\":\""+iface_2_bridge_port_id["Ethernet0"]+"\"}]}]" + ntf.send("fdb_event", ntf_data, fvp) + + time.sleep(2) + + # check that the FDB entry was added in ASIC DB + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", "52:54:00:25:06:E9"), ("bvid", vlan_oid_3)], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_DYNAMIC"), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", iface_2_bridge_port_id["Ethernet0"])] + ) + assert ok, str(extra) + print("FDB Vlan3:52-54-00-25-06-E9:Ethernet0 is created in ASIC-DB") + + # check that the FDB entry was added in STATE DB + mac1_found, extra = dvs.is_table_entry_exists(dvs.sdb, "FDB_TABLE", + "Vlan3:52:54:00:25:06:e9", + [("port", "Ethernet0"), + ("type", "dynamic"), + ] + ) + assert mac1_found, str(extra) + print("FDB Vlan3:52-54-00-25-06-E9:Ethernet0 is created in STATE-DB") + + + dvs.remove_vlan_member("3", "Ethernet0") + dvs.remove_vlan("3") diff --git a/tests/test_evpn_l3_vxlan.py b/tests/test_evpn_l3_vxlan.py index 6f541b20a64b..64cc85ba8ab9 100644 --- a/tests/test_evpn_l3_vxlan.py +++ b/tests/test_evpn_l3_vxlan.py @@ -1,1010 +1,20 @@ from swsscommon import swsscommon -import time -import json import random import pytest from pprint import pprint +from evpn_tunnel import VxlanTunnel,VxlanEvpnHelper +import time - -def create_entry(tbl, key, pairs): - fvs = swsscommon.FieldValuePairs(pairs) - tbl.set(key, fvs) - time.sleep(1) - - -def create_entry_tbl(db, table, separator, key, pairs): - tbl = swsscommon.Table(db, table) - create_entry(tbl, key, pairs) - -def delete_entry_tbl(db, table, key): - tbl = swsscommon.Table(db, table) - tbl._del(key) - time.sleep(1) - -def create_entry_pst(db, table, separator, key, pairs): - tbl = swsscommon.ProducerStateTable(db, table) - create_entry(tbl, key, pairs) - -def delete_entry_pst(db, table, key): - tbl = swsscommon.ProducerStateTable(db, table) - tbl._del(key) - time.sleep(1) - -def how_many_entries_exist(db, table): - tbl = swsscommon.Table(db, table) - return len(tbl.getKeys()) - - -def entries(db, table): - tbl = swsscommon.Table(db, table) - return set(tbl.getKeys()) - - -def get_exist_entries(dvs, table): - db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - tbl = swsscommon.Table(db, table) - return set(tbl.getKeys()) - - -def get_created_entry(db, table, existed_entries): - tbl = swsscommon.Table(db, table) - entries = set(tbl.getKeys()) - new_entries = list(entries - existed_entries) - assert len(new_entries) == 1, "Wrong number of created entries." - return new_entries[0] - - -def get_created_entries(db, table, existed_entries, count): - tbl = swsscommon.Table(db, table) - entries = set(tbl.getKeys()) - new_entries = list(entries - existed_entries) - assert len(new_entries) == count, "Wrong number of created entries." - new_entries.sort() - return new_entries - -def get_deleted_entries(db, table, existed_entries, count): - tbl = swsscommon.Table(db, table) - entries = set(tbl.getKeys()) - old_entries = list(existed_entries - entries) - assert len(old_entries) == count, "Wrong number of deleted entries." - old_entries.sort() - return old_entries - -def get_default_vr_id(dvs): - db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - table = 'ASIC_STATE:SAI_OBJECT_TYPE_VIRTUAL_ROUTER' - tbl = swsscommon.Table(db, table) - keys = tbl.getKeys() - assert len(keys) == 1, "Wrong number of virtual routers found" - - return keys[0] - -def check_object(db, table, key, expected_attributes): - tbl = swsscommon.Table(db, table) - keys = tbl.getKeys() - assert key in keys, "The desired key is not presented" - - status, fvs = tbl.get(key) - assert status, "Got an error when get a key" - - assert len(fvs) >= len(expected_attributes), "Incorrect attributes" - - attr_keys = {entry[0] for entry in fvs} - - for name, value in fvs: - if name in expected_attributes: - assert expected_attributes[name] == value, "Wrong value %s for the attribute %s = %s" % \ - (value, name, expected_attributes[name]) - -def check_deleted_object(db, table, key): - tbl = swsscommon.Table(db, table) - keys = tbl.getKeys() - assert key not in keys, "The desired key is not removed" - -def get_key_with_attr(db, table, expected_attributes ): - tbl = swsscommon.Table(db, table) - keys = tbl.getKeys() - retkey = list() - #assert key in keys, "The desired key is not presented" - - for key in keys: - status, fvs = tbl.get(key) - assert status, "Got an error when get a key" - - assert len(fvs) >= len(expected_attributes), "Incorrect attributes" - - attr_keys = {entry[0] for entry in fvs} - - num_match = 0 - for name, value in fvs: - if name in expected_attributes: - if expected_attributes[name] == value: - num_match += 1 - if num_match == len(expected_attributes): - retkey.append(key) - - return retkey - -def create_vrf_routes(dvs, prefix, vrf_name, endpoint, ifname, mac="", vni=0): - app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - - attrs = [ - ("nexthop", endpoint), - ("ifname", ifname), - ] - - if vni: - attrs.append(('vni_label', vni)) - - if mac: - attrs.append(('router_mac', mac)) - - create_entry_pst( - app_db, - "ROUTE_TABLE", ':', "%s:%s" % (vrf_name, prefix), - attrs, - ) - - time.sleep(2) - -def delete_vrf_routes(dvs, prefix, vrf_name): - app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - - delete_entry_pst(app_db, "ROUTE_TABLE", "%s:%s" % (vrf_name, prefix)) - - time.sleep(2) - -def create_vrf_routes_ecmp(dvs, prefix, vrf_name, ecmp_nexthop_attributes): - app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - - create_entry_pst( - app_db, - "ROUTE_TABLE", ':', "%s:%s" % (vrf_name, prefix), - ecmp_nexthop_attributes, - ) - - time.sleep(2) - -def create_vlan(dvs, vlan_name, vlan_ids): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - vlan_id = vlan_name[4:] - - # create vlan - create_entry_tbl( - conf_db, - "VLAN", '|', vlan_name, - [ - ("vlanid", vlan_id), - ], - ) - - time.sleep(1) - - vlan_oid = get_created_entry(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN", vlan_ids) - - check_object(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN", vlan_oid, - { - "SAI_VLAN_ATTR_VLAN_ID": vlan_id, - } - ) - - return vlan_oid - -def remove_vlan(dvs, vlan): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - tbl = swsscommon.Table(conf_db, "VLAN") - tbl._del("Vlan" + vlan) - time.sleep(1) - -def create_vlan_member(dvs, vlan, interface, tagging_mode="untagged"): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - tbl = swsscommon.Table(conf_db, "VLAN_MEMBER") - fvs = swsscommon.FieldValuePairs([("tagging_mode", tagging_mode)]) - tbl.set("Vlan" + vlan + "|" + interface, fvs) - time.sleep(1) - -def remove_vlan_member(dvs, vlan, interface): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - tbl = swsscommon.Table(conf_db, "VLAN_MEMBER") - tbl._del("Vlan" + vlan + "|" + interface) - time.sleep(1) - -def create_vlan_interface(dvs, vlan_name, ifname, vrf_name, ipaddr): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - # create a vlan member in config db - create_entry_tbl( - conf_db, - "VLAN_MEMBER", '|', "%s|%s" % (vlan_name, ifname), - [ - ("tagging_mode", "untagged"), - ], - ) - - time.sleep(1) - - # create vlan interface in config db - create_entry_tbl( - conf_db, - "VLAN_INTERFACE", '|', vlan_name, - [ - ("vrf_name", vrf_name), - ], - ) - - app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - create_entry_pst( - app_db, - "INTF_TABLE", ':', vlan_name, - [ - ("vrf_name", vrf_name), - ], - ) - time.sleep(2) - - create_entry_tbl( - conf_db, - "VLAN_INTERFACE", '|', "%s|%s" % (vlan_name, ipaddr), - [ - ("family", "IPv4"), - ], - ) - - time.sleep(2) - - -def delete_vlan_interface(dvs, ifname, ipaddr): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - delete_entry_tbl(conf_db, "VLAN_INTERFACE", "%s|%s" % (ifname, ipaddr)) - time.sleep(2) - - delete_entry_tbl(conf_db, "VLAN_INTERFACE", ifname) - time.sleep(2) - -def create_evpn_nvo(dvs, nvoname, tnlname): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - attrs = [ - ("source_vtep", tnlname), - ] - - # create the VXLAN tunnel Term entry in Config DB - create_entry_tbl( - conf_db, - "VXLAN_EVPN_NVO", '|', nvoname, - attrs, - ) - -def remove_evpn_nvo(dvs, nvoname): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - delete_entry_tbl(conf_db,"VXLAN_EVPN_NVO", nvoname,) - -def create_vxlan_tunnel(dvs, name, src_ip): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - attrs = [ - ("src_ip", src_ip), - ] - - # create the VXLAN tunnel Term entry in Config DB - create_entry_tbl( - conf_db, - "VXLAN_TUNNEL", '|', name, - attrs, - ) - -def create_vxlan_tunnel_map(dvs, tnlname, mapname, vni_id, vlan_id): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - attrs = [ - ("vni", vni_id), - ("vlan", vlan_id), - ] - - # create the VXLAN tunnel Term entry in Config DB - create_entry_tbl( - conf_db, - "VXLAN_TUNNEL_MAP", '|', "%s|%s" % (tnlname, mapname), - attrs, - ) - - -def create_vxlan_vrf_tunnel_map(dvs, vrfname, vni_id): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - attrs = [ - ("vni", vni_id), - ] - - # create the VXLAN VRF tunnel Term entry in Config DB - create_entry_tbl( - conf_db, - "VRF", '|', vrfname, - attrs, - ) - -def remove_vxlan_vrf_tunnel_map(dvs, vrfname): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - attrs = [ - ("vni", "0"), - ] - - # remove the VXLAN VRF tunnel Term entry in Config DB - create_entry_tbl( - conf_db, - "VRF", '|', vrfname, - attrs, - ) - -def create_evpn_remote_vni(dvs, vlan_id, remotevtep, vnid): - app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - create_entry_pst( - app_db, - "VXLAN_REMOTE_VNI_TABLE", ':', "%s:%s" % (vlan_id, remotevtep), - [ - ("vni", vnid), - ], - ) - time.sleep(2) - -def remove_vxlan_tunnel(dvs, tnlname): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - # create the VXLAN tunnel Term entry in Config DB - delete_entry_tbl( - conf_db, - "VXLAN_TUNNEL", tnlname, - ) - -def remove_vxlan_tunnel_map(dvs, tnlname, mapname,vni_id, vlan_id): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - attrs = [ - ("vni", vni_id), - ("vlan", vlan_id), - ] - - # create the VXLAN tunnel Term entry in Config DB - delete_entry_tbl( - conf_db, - "VXLAN_TUNNEL_MAP", "%s|%s" % (tnlname, mapname), - ) - -def remove_evpn_remote_vni(dvs, vlan_id, remotevtep ): - app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - delete_entry_pst( - app_db, - "VXLAN_REMOTE_VNI_TABLE", "%s:%s" % (vlan_id, remotevtep), - ) - time.sleep(2) - -def create_vlan1(dvs, vlan_name): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - vlan_id = vlan_name[4:] - - # create vlan - create_entry_tbl( - conf_db, - "VLAN", '|', vlan_name, - [ - ("vlanid", vlan_id), - ], - ) - -def get_switch_mac(dvs): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - tbl = swsscommon.Table(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_SWITCH') - - entries = tbl.getKeys() - mac = None - for entry in entries: - status, fvs = tbl.get(entry) - assert status, "Got an error when get a key" - for key, value in fvs: - if key == 'SAI_SWITCH_ATTR_SRC_MAC_ADDRESS': - mac = value - break - else: - assert False, 'Don\'t found switch mac' - - return mac - -loopback_id = 0 -def_vr_id = 0 -switch_mac = None - - -class VxlanTunnel(object): - - ASIC_TUNNEL_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL" - ASIC_TUNNEL_MAP = "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP" - ASIC_TUNNEL_MAP_ENTRY = "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP_ENTRY" - ASIC_TUNNEL_TERM_ENTRY = "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_TERM_TABLE_ENTRY" - ASIC_BRIDGE_PORT = "ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT" - ASIC_VRF_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_VIRTUAL_ROUTER" - ASIC_RIF_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE" - ASIC_ROUTE_ENTRY = "ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY" - ASIC_NEXT_HOP = "ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP" - ASIC_NEXT_HOP_GRP = "ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP" - ASIC_NEXT_HOP_GRP_MEMBERS = "ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER" - - tunnel_map_ids = set() - tunnel_map_entry_ids = set() - tunnel_map_vrf_entry_ids = set() - tunnel_ids = set() - tunnel_term_ids = set() - bridgeport_ids = set() - tunnel_map_map = {} - tunnel = {} - tunnelterm = {} - mapentry_map = {} - diptunnel_map = {} - diptunterm_map = {} - diptunstate_map = {} - bridgeport_map = {} - vlan_id_map = {} - vlan_member_map = {} - vr_map = {} - vnet_vr_ids = set() - nh_ids = {} - nh_grp_id = set() - nh_grp_member_id = set() - route_id = {} - - def fetch_exist_entries(self, dvs): - self.tunnel_ids = get_exist_entries(dvs, self.ASIC_TUNNEL_TABLE) - self.tunnel_map_ids = get_exist_entries(dvs, self.ASIC_TUNNEL_MAP) - self.tunnel_map_entry_ids = get_exist_entries(dvs, self.ASIC_TUNNEL_MAP_ENTRY) - self.tunnel_term_ids = get_exist_entries(dvs, self.ASIC_TUNNEL_TERM_ENTRY) - self.bridgeport_ids = get_exist_entries(dvs, self.ASIC_BRIDGE_PORT) - self.vnet_vr_ids = get_exist_entries(dvs, self.ASIC_VRF_TABLE) - self.rifs = get_exist_entries(dvs, self.ASIC_RIF_TABLE) - self.routes = get_exist_entries(dvs, self.ASIC_ROUTE_ENTRY) - self.nhops = get_exist_entries(dvs, self.ASIC_NEXT_HOP) - self.nhop_grp = get_exist_entries(dvs, self.ASIC_NEXT_HOP_GRP) - self.nhop_grp_members = get_exist_entries(dvs, self.ASIC_NEXT_HOP_GRP_MEMBERS) - - global switch_mac - - if switch_mac is None: - switch_mac = get_switch_mac(dvs) - - def check_vxlan_tunnel_map_entry_delete(self, dvs, tunnel_name, vidlist, vnilist): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - tbl = swsscommon.Table(asic_db, self.ASIC_TUNNEL_MAP_ENTRY) - - for x in range(1): - status, fvs = tbl.get(self.mapentry_map[tunnel_name + vidlist[x]]) - assert status == False, "SIP Tunnel Map entry not deleted" - - def check_vxlan_tunnel_vlan_map_entry(self, dvs, tunnel_name, vidlist, vnidlist): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - tbl = swsscommon.Table(asic_db, self.ASIC_TUNNEL_MAP_ENTRY) - - expected_attributes_1 = { - 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE': 'SAI_TUNNEL_MAP_TYPE_VNI_TO_VLAN_ID', - 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP': self.tunnel_map_map[tunnel_name][0], - 'SAI_TUNNEL_MAP_ENTRY_ATTR_VLAN_ID_VALUE': vidlist[0], - 'SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_KEY': vnidlist[0], - } - - for x in range(1): - expected_attributes_1['SAI_TUNNEL_MAP_ENTRY_ATTR_VLAN_ID_VALUE'] = vidlist[x] - expected_attributes_1['SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_KEY'] = vnidlist[x] - ret = get_key_with_attr(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, expected_attributes_1) - assert len(ret) > 0, "SIP TunnelMap entry not created" - assert len(ret) == 1, "More than 1 SIP TunnMapEntry created" - self.mapentry_map[tunnel_name + vidlist[x]] = ret[0] - - - def check_vxlan_sip_tunnel_delete(self, dvs, tunnel_name): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - tbl = swsscommon.Table(asic_db, self.ASIC_TUNNEL_TERM_ENTRY) - status, fvs = tbl.get(self.tunnelterm[tunnel_name]) - assert status == False, "SIP Tunnel Term entry not deleted" - - tbl = swsscommon.Table(asic_db, self.ASIC_TUNNEL_TABLE) - status, fvs = tbl.get(self.tunnel[tunnel_name]) - assert status == False, "SIP Tunnel entry not deleted" - - tbl = swsscommon.Table(asic_db, self.ASIC_TUNNEL_MAP) - status, fvs = tbl.get(self.tunnel_map_map[tunnel_name][0]) - assert status == False, "SIP Tunnel mapper0 not deleted" - status, fvs = tbl.get(self.tunnel_map_map[tunnel_name][1]) - assert status == False, "SIP Tunnel mapper1 not deleted" - status, fvs = tbl.get(self.tunnel_map_map[tunnel_name][2]) - assert status == False, "SIP Tunnel mapper2 not deleted" - status, fvs = tbl.get(self.tunnel_map_map[tunnel_name][3]) - assert status == False, "SIP Tunnel mapper3 not deleted" - - def check_vxlan_sip_tunnel(self, dvs, tunnel_name, src_ip, vidlist, vnidlist): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - tunnel_map_id = get_created_entries(asic_db, self.ASIC_TUNNEL_MAP, self.tunnel_map_ids, 4) - tunnel_id = get_created_entry(asic_db, self.ASIC_TUNNEL_TABLE, self.tunnel_ids) - tunnel_term_id = get_created_entry(asic_db, self.ASIC_TUNNEL_TERM_ENTRY, self.tunnel_term_ids) - tunnel_map_entry_id = get_created_entries(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, self.tunnel_map_entry_ids, 3) - - # check that the vxlan tunnel termination are there - assert how_many_entries_exist(asic_db, self.ASIC_TUNNEL_MAP) == (len(self.tunnel_map_ids) + 4), "The TUNNEL_MAP wasn't created" - assert how_many_entries_exist(asic_db, self.ASIC_TUNNEL_MAP_ENTRY) == (len(self.tunnel_map_entry_ids) + 3), "The TUNNEL_MAP_ENTRY is created" - assert how_many_entries_exist(asic_db, self.ASIC_TUNNEL_TABLE) == (len(self.tunnel_ids) + 1), "The TUNNEL wasn't created" - assert how_many_entries_exist(asic_db, self.ASIC_TUNNEL_TERM_ENTRY) == (len(self.tunnel_term_ids) + 1), "The TUNNEL_TERM_TABLE_ENTRY wasm't created" - - check_object(asic_db, self.ASIC_TUNNEL_MAP, tunnel_map_id[2], - { - 'SAI_TUNNEL_MAP_ATTR_TYPE': 'SAI_TUNNEL_MAP_TYPE_VNI_TO_VIRTUAL_ROUTER_ID', - } - ) - - check_object(asic_db, self.ASIC_TUNNEL_MAP, tunnel_map_id[3], - { - 'SAI_TUNNEL_MAP_ATTR_TYPE': 'SAI_TUNNEL_MAP_TYPE_VIRTUAL_ROUTER_ID_TO_VNI', - } - ) - - decapstr = '2:' + tunnel_map_id[0] + ',' + tunnel_map_id[2] - encapstr = '2:' + tunnel_map_id[1] + ',' + tunnel_map_id[3] - - check_object(asic_db, self.ASIC_TUNNEL_TABLE, tunnel_id, - { - 'SAI_TUNNEL_ATTR_TYPE': 'SAI_TUNNEL_TYPE_VXLAN', - 'SAI_TUNNEL_ATTR_DECAP_MAPPERS': decapstr, - 'SAI_TUNNEL_ATTR_ENCAP_MAPPERS': encapstr, - 'SAI_TUNNEL_ATTR_ENCAP_SRC_IP': src_ip, - } - ) - - expected_attributes = { - 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TYPE': 'SAI_TUNNEL_TERM_TABLE_ENTRY_TYPE_P2MP', - 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_DST_IP': src_ip, - 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TUNNEL_TYPE': 'SAI_TUNNEL_TYPE_VXLAN', - 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_ACTION_TUNNEL_ID': tunnel_id, - } - - check_object(asic_db, self.ASIC_TUNNEL_TERM_ENTRY, tunnel_term_id, expected_attributes) - - expected_attributes_1 = { - 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE': 'SAI_TUNNEL_MAP_TYPE_VNI_TO_VLAN_ID', - 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP': tunnel_map_id[0], - 'SAI_TUNNEL_MAP_ENTRY_ATTR_VLAN_ID_VALUE': vidlist[0], - 'SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_KEY': vnidlist[0], - } - - for x in range(1): - expected_attributes_1['SAI_TUNNEL_MAP_ENTRY_ATTR_VLAN_ID_VALUE'] = vidlist[x] - expected_attributes_1['SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_KEY'] = vnidlist[x] - check_object(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, tunnel_map_entry_id[x], expected_attributes_1) - - self.tunnel_map_ids.update(tunnel_map_id) - self.tunnel_ids.add(tunnel_id) - self.tunnel_term_ids.add(tunnel_term_id) - self.tunnel_map_map[tunnel_name] = tunnel_map_id - self.tunnel[tunnel_name] = tunnel_id - self.tunnelterm[tunnel_name] = tunnel_term_id - - def check_vxlan_dip_tunnel_delete(self, dvs, dip): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - state_db = swsscommon.DBConnector(swsscommon.STATE_DB, dvs.redis_sock, 0) - - tbl = swsscommon.Table(state_db, 'VXLAN_TUNNEL_TABLE') - status, fvs = tbl.get(self.diptunstate_map[dip]) - assert status == False, "State Table entry not deleted" - - tbl = swsscommon.Table(asic_db, self.ASIC_TUNNEL_TABLE) - status, fvs = tbl.get(self.diptunnel_map[dip]) - assert status == False, "Tunnel entry not deleted" - - tbl = swsscommon.Table(asic_db, self.ASIC_BRIDGE_PORT) - status, fvs = tbl.get(self.bridgeport_map[dip]) - assert status == False, "Tunnel bridgeport entry not deleted" - - def check_vxlan_dip_tunnel(self, dvs, vtep_name, src_ip, dip): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - state_db = swsscommon.DBConnector(swsscommon.STATE_DB, dvs.redis_sock, 0) - - expected_state_attributes = { - 'src_ip': src_ip, - 'dst_ip': dip, - 'tnl_src': 'EVPN', - } - - ret = get_key_with_attr(state_db, 'VXLAN_TUNNEL_TABLE', expected_state_attributes) - assert len(ret) > 0, "Tunnel Statetable entry not created" - assert len(ret) == 1, "More than 1 Tunn statetable entry created" - self.diptunstate_map[dip] = ret[0] - - tunnel_map_id = self.tunnel_map_map[vtep_name] - - decapstr = '2:' + tunnel_map_id[0] + ',' + tunnel_map_id[2] - encapstr = '2:' + tunnel_map_id[1] + ',' + tunnel_map_id[3] - - expected_tun_attributes = { - 'SAI_TUNNEL_ATTR_TYPE': 'SAI_TUNNEL_TYPE_VXLAN', - 'SAI_TUNNEL_ATTR_PEER_MODE': 'SAI_TUNNEL_PEER_MODE_P2P', - 'SAI_TUNNEL_ATTR_DECAP_MAPPERS': decapstr, - 'SAI_TUNNEL_ATTR_ENCAP_MAPPERS': encapstr, - 'SAI_TUNNEL_ATTR_ENCAP_SRC_IP': src_ip, - 'SAI_TUNNEL_ATTR_ENCAP_DST_IP': dip, - } - - ret = get_key_with_attr(asic_db, self.ASIC_TUNNEL_TABLE, expected_tun_attributes) - assert len(ret) > 0, "Tunnel entry not created" - assert len(ret) == 1, "More than 1 tunnel entry created" - - self.diptunnel_map[dip] = ret[0] - tunnel_id = ret[0] - - expected_bridgeport_attributes = { - 'SAI_BRIDGE_PORT_ATTR_TYPE': 'SAI_BRIDGE_PORT_TYPE_TUNNEL', - 'SAI_BRIDGE_PORT_ATTR_TUNNEL_ID': tunnel_id, - 'SAI_BRIDGE_PORT_ATTR_FDB_LEARNING_MODE': 'SAI_BRIDGE_PORT_FDB_LEARNING_MODE_DISABLE', - 'SAI_BRIDGE_PORT_ATTR_ADMIN_STATE': 'true', - } - - ret = get_key_with_attr(asic_db, self.ASIC_BRIDGE_PORT, expected_bridgeport_attributes) - assert len(ret) > 0, "Bridgeport entry not created" - assert len(ret) == 1, "More than 1 bridgeport entry created" - - self.bridgeport_map[dip] = ret[0] - - def check_vlan_extension_delete(self, dvs, vlan_name, dip): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - tbl = swsscommon.Table(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_VLAN_MEMBER') - status, fvs = tbl.get(self.vlan_member_map[dip+vlan_name]) - assert status == False, "VLAN Member entry not deleted" - - def check_vlan_extension(self, dvs, vlan_name, dip): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - expected_vlan_attributes = { - 'SAI_VLAN_ATTR_VLAN_ID': vlan_name, - } - ret = get_key_with_attr(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_VLAN', expected_vlan_attributes) - assert len(ret) > 0, "VLAN entry not created" - assert len(ret) == 1, "More than 1 VLAN entry created" - - self.vlan_id_map[vlan_name] = ret[0] - - expected_vlan_member_attributes = { - 'SAI_VLAN_MEMBER_ATTR_VLAN_ID': self.vlan_id_map[vlan_name], - 'SAI_VLAN_MEMBER_ATTR_BRIDGE_PORT_ID': self.bridgeport_map[dip], - } - ret = get_key_with_attr(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_VLAN_MEMBER', expected_vlan_member_attributes) - assert len(ret) > 0, "VLAN Member not created" - assert len(ret) == 1, "More than 1 VLAN member created" - self.vlan_member_map[dip+vlan_name] = ret[0] - - def check_vxlan_tunnel_vrf_map_entry(self, dvs, tunnel_name, vrf_name, vni_id): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - - if (self.tunnel_map_map.get(tunnel_name) is None): - tunnel_map_id = get_created_entries(asic_db, self.ASIC_TUNNEL_MAP, self.tunnel_map_ids, 4) - else: - tunnel_map_id = self.tunnel_map_map[tunnel_name] - - tunnel_map_entry_id = get_created_entries(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, self.tunnel_map_entry_ids, 3) - - # check that the vxlan tunnel termination are there - assert how_many_entries_exist(asic_db, self.ASIC_TUNNEL_MAP_ENTRY) == (len(self.tunnel_map_entry_ids) + 3), "The TUNNEL_MAP_ENTRY is created too early" - - check_object(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, tunnel_map_entry_id[1], - { - 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE': 'SAI_TUNNEL_MAP_TYPE_VIRTUAL_ROUTER_ID_TO_VNI', - 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP': tunnel_map_id[3], - 'SAI_TUNNEL_MAP_ENTRY_ATTR_VIRTUAL_ROUTER_ID_KEY': self.vr_map[vrf_name].get('ing'), - 'SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_VALUE': vni_id, - } - ) - - self.tunnel_map_vrf_entry_ids.update(tunnel_map_entry_id[1]) - - check_object(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, tunnel_map_entry_id[2], - { - 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE': 'SAI_TUNNEL_MAP_TYPE_VNI_TO_VIRTUAL_ROUTER_ID', - 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP': tunnel_map_id[2], - 'SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_KEY': vni_id, - 'SAI_TUNNEL_MAP_ENTRY_ATTR_VIRTUAL_ROUTER_ID_VALUE': self.vr_map[vrf_name].get('egr'), - } - ) - - self.tunnel_map_vrf_entry_ids.update(tunnel_map_entry_id[2]) - self.tunnel_map_entry_ids.update(tunnel_map_entry_id) - - def check_vxlan_tunnel_vrf_map_entry_remove(self, dvs, tunnel_name, vrf_name, vni_id): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - tunnel_map_entry_id = get_deleted_entries(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, self.tunnel_map_entry_ids, 2) - check_deleted_object(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, tunnel_map_entry_id[0]) - check_deleted_object(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, tunnel_map_entry_id[1]) - for vrf_map_id in self.tunnel_map_vrf_entry_ids: - check_deleted_object(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, vrf_map_id) - - def check_router_interface(self, dvs, name, vlan_oid, route_count): - # Check RIF in ingress VRF - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - global switch_mac - - expected_attr = { - "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID": self.vr_map[name].get('ing'), - "SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS": switch_mac, - } - - if vlan_oid: - expected_attr.update({'SAI_ROUTER_INTERFACE_ATTR_TYPE': 'SAI_ROUTER_INTERFACE_TYPE_VLAN'}) - expected_attr.update({'SAI_ROUTER_INTERFACE_ATTR_VLAN_ID': vlan_oid}) - else: - expected_attr.update({'SAI_ROUTER_INTERFACE_ATTR_TYPE': 'SAI_ROUTER_INTERFACE_TYPE_PORT'}) - - new_rif = get_created_entry(asic_db, self.ASIC_RIF_TABLE, self.rifs) - check_object(asic_db, self.ASIC_RIF_TABLE, new_rif, expected_attr) - - #IP2ME route will be created with every router interface - new_route = get_created_entries(asic_db, self.ASIC_ROUTE_ENTRY, self.routes, route_count) - - self.rifs.add(new_rif) - self.routes.update(new_route) - - def check_del_router_interface(self, dvs, name): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - old_rif = get_deleted_entries(asic_db, self.ASIC_RIF_TABLE, self.rifs, 1) - check_deleted_object(asic_db, self.ASIC_RIF_TABLE, old_rif[0]) - - self.rifs.remove(old_rif[0]) - - def vrf_route_ids(self, dvs, vrf_name): - vr_set = set() - - vr_set.add(self.vr_map[vrf_name].get('ing')) - return vr_set - - def check_vrf_routes(self, dvs, prefix, vrf_name, endpoint, tunnel, mac="", vni=0, no_update=0): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - vr_ids = self.vrf_route_ids(dvs, vrf_name) - count = len(vr_ids) - - # Check routes in ingress VRF - expected_attr = { - "SAI_NEXT_HOP_ATTR_TYPE": "SAI_NEXT_HOP_TYPE_TUNNEL_ENCAP", - "SAI_NEXT_HOP_ATTR_IP": endpoint, - "SAI_NEXT_HOP_ATTR_TUNNEL_ID": self.tunnel[tunnel], - } - - if vni: - expected_attr.update({'SAI_NEXT_HOP_ATTR_TUNNEL_VNI': vni}) - - if mac: - expected_attr.update({'SAI_NEXT_HOP_ATTR_TUNNEL_MAC': mac}) - - if endpoint in self.nh_ids: - new_nh = self.nh_ids[endpoint] - else: - new_nh = get_created_entry(asic_db, self.ASIC_NEXT_HOP, self.nhops) - self.nh_ids[endpoint] = new_nh - self.nhops.add(new_nh) - - check_object(asic_db, self.ASIC_NEXT_HOP, new_nh, expected_attr) - if no_update: - count = 0 - new_route = get_created_entries(asic_db, self.ASIC_ROUTE_ENTRY, self.routes, count) - - if count: - self.route_id[vrf_name + ":" + prefix] = new_route - - #Check if the route is in expected VRF - asic_vrs = set() - for idx in range(count): - check_object(asic_db, self.ASIC_ROUTE_ENTRY, new_route[idx], - { - "SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID": new_nh, - } - ) - rt_key = json.loads(new_route[idx]) - asic_vrs.add(rt_key['vr']) - found_route = False - if rt_key['dest'] == prefix: - found_route = True - - assert found_route - - if count: - assert asic_vrs == vr_ids - - self.routes.update(new_route) - - return True - - def check_vrf_routes_ecmp(self, dvs, prefix, vrf_name, tunnel, nh_count, no_update=0): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - vr_ids = self.vrf_route_ids(dvs, vrf_name) - count = len(vr_ids) - - new_nhg = get_created_entry(asic_db, self.ASIC_NEXT_HOP_GRP, self.nhop_grp) - self.nh_grp_id.add(new_nhg) - - if no_update: - count = 0 - - new_route = get_created_entries(asic_db, self.ASIC_ROUTE_ENTRY, self.routes, count) - if count: - self.route_id[vrf_name + ":" + prefix] = new_route - - #Check if the route is in expected VRF - asic_vrs = set() - for idx in range(count): - check_object(asic_db, self.ASIC_ROUTE_ENTRY, new_route[idx], - { - "SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID": new_nhg, - } - ) - rt_key = json.loads(new_route[idx]) - asic_vrs.add(rt_key['vr']) - - found_route = False - if rt_key['dest'] == prefix: - found_route = True - - assert found_route - - if count: - assert asic_vrs == vr_ids - - self.routes.update(new_route) - - new_nhg_members = get_created_entries(asic_db, self.ASIC_NEXT_HOP_GRP_MEMBERS, self.nhop_grp_members, nh_count) - - for idx in range(nh_count): - self.nh_grp_member_id.add(new_nhg_members[idx]) - check_object(asic_db, self.ASIC_NEXT_HOP_GRP_MEMBERS, new_nhg_members[idx], - { - "SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID": new_nhg, - } - ) - - nhid_list = list() - - nhg_member_tbl = swsscommon.Table(asic_db, self.ASIC_NEXT_HOP_GRP_MEMBERS) - - for k in new_nhg_members: - (status, fvs) = nhg_member_tbl.get(k) - assert status - - for v in fvs: - if v[0] == "SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID": - nhid = v[1] - nhid_list.append(nhid) - - return nhid_list - - def check_add_tunnel_nexthop(self, dvs, nh_id, endpoint, tunnel, mac, vni): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - # Check routes in ingress VRF - expected_attr = { - "SAI_NEXT_HOP_ATTR_TYPE": "SAI_NEXT_HOP_TYPE_TUNNEL_ENCAP", - "SAI_NEXT_HOP_ATTR_IP": endpoint, - "SAI_NEXT_HOP_ATTR_TUNNEL_ID": self.tunnel[tunnel], - "SAI_NEXT_HOP_ATTR_TUNNEL_VNI": vni, - "SAI_NEXT_HOP_ATTR_TUNNEL_MAC": mac, - } - - check_object(asic_db, self.ASIC_NEXT_HOP, nh_id, expected_attr) - - def check_del_tunnel_nexthop(self, dvs, vrf_name, endpoint, tunnel, mac="", vni=0): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - del_nh_ids = get_deleted_entries(asic_db, self.ASIC_NEXT_HOP, self.nhops, 1) - check_deleted_object(asic_db, self.ASIC_NEXT_HOP, del_nh_ids[0]) - check_deleted_object(asic_db, self.ASIC_NEXT_HOP, self.nh_ids[endpoint]) - assert del_nh_ids[0] == self.nh_ids[endpoint] - self.nh_ids.pop(endpoint) - return True - - def check_vrf_routes_ecmp_nexthop_grp_del(self, dvs, nh_count): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - nh_grp_id_len = len(self.nh_grp_id) - assert nh_grp_id_len == 1 - - for nh_grp_id in self.nh_grp_id: - check_deleted_object(asic_db, self.ASIC_NEXT_HOP_GRP, nh_grp_id) - self.nh_grp_id.clear() - - nh_grp_member_id_len = len(self.nh_grp_member_id) - assert nh_grp_member_id_len == nh_count - - for nh_grp_member_id in self.nh_grp_member_id: - check_deleted_object(asic_db, self.ASIC_NEXT_HOP_GRP_MEMBERS, nh_grp_member_id) - - self.nh_grp_member_id.clear() - - def check_del_vrf_routes(self, dvs, prefix, vrf_name): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - del_route = get_deleted_entries(asic_db, self.ASIC_ROUTE_ENTRY, self.routes, 1) - - for idx in range(1): - rt_key = json.loads(del_route[idx]) - found_route = False - if rt_key['dest'] == prefix: - found_route = True - - assert found_route - - check_deleted_object(asic_db, self.ASIC_ROUTE_ENTRY, self.route_id[vrf_name + ":" + prefix]) - self.route_id.clear() - - return True - - def create_vrf(self, dvs, vrf_name): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - tbl = swsscommon.Table(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_VIRTUAL_ROUTER") - initial_entries = set(tbl.getKeys()) - - attrs = [ - ("vni", "0"), - ] - tbl = swsscommon.Table(conf_db, "VRF") - fvs = swsscommon.FieldValuePairs(attrs) - tbl.set(vrf_name, fvs) - time.sleep(2) - - tbl = swsscommon.Table(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_VIRTUAL_ROUTER") - current_entries = set(tbl.getKeys()) - assert len(current_entries - initial_entries) == 1 - - new_vr_ids = get_created_entries(asic_db, self.ASIC_VRF_TABLE, self.vnet_vr_ids, 1) - self.vnet_vr_ids.update(new_vr_ids) - self.vr_map[vrf_name] = { 'ing':new_vr_ids[0], 'egr':new_vr_ids[0]} - - return list(current_entries - initial_entries)[0] - - def remove_vrf(self, dvs, vrf_name): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - tbl = swsscommon.Table(conf_db, "VRF") - tbl._del(vrf_name) - time.sleep(2) - - - def is_vrf_attributes_correct(self, db, table, key, expected_attributes): - tbl = swsscommon.Table(db, table) - keys = set(tbl.getKeys()) - assert key in keys, "The created key wasn't found" - - status, fvs = tbl.get(key) - assert status, "Got an error when get a key" - - # filter the fake 'NULL' attribute out - fvs = filter(lambda x : x != ('NULL', 'NULL'), fvs) - - attr_keys = {entry[0] for entry in fvs} - assert attr_keys == set(expected_attributes.keys()) - - for name, value in fvs: - assert expected_attributes[name] == value, "Wrong value %s for the attribute %s = %s" % \ - (value, name, expected_attributes[name]) - +DVS_ENV = ["fake_platform=broadcom"] class TestL3Vxlan(object): def get_vxlan_obj(self): return VxlanTunnel() + def get_vxlan_helper(self): + return VxlanEvpnHelper() + def setup_db(self, dvs): self.pdb = swsscommon.DBConnector(0, dvs.redis_sock, 0) self.adb = swsscommon.DBConnector(1, dvs.redis_sock, 0) @@ -1015,6 +25,7 @@ def setup_db(self, dvs): # @pytest.mark.dev_sanity def test_sip_tunnel_vrf_vni_map(self, dvs, testlog): vxlan_obj = self.get_vxlan_obj() + helper = self.get_vxlan_helper() self.setup_db(dvs) tunnel_name = 'tunnel_2' @@ -1025,15 +36,15 @@ def test_sip_tunnel_vrf_vni_map(self, dvs, testlog): print ("\n\nTesting Create and Delete SIP Tunnel and VRF VNI Map entries") print ("\tCreate SIP Tunnel") - create_vlan1(dvs,"Vlan100") - create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') - create_evpn_nvo(dvs, 'nvo1', tunnel_name) + vxlan_obj.create_vlan1(dvs,"Vlan100") + vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.create_evpn_nvo(dvs, 'nvo1', tunnel_name) print ("\tCreate Vlan-VNI map and VRF-VNI map") - create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') vxlan_obj.create_vrf(dvs, "Vrf-RED") - create_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED', '1000') + vxlan_obj.create_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED', '1000') print ("\tTesting VRF-VNI map in APP DB") vlanlist = ['100'] @@ -1046,7 +57,7 @@ def test_sip_tunnel_vrf_vni_map(self, dvs, testlog): for an in range(len(exp_attrs)): exp_attr[exp_attrs[an][0]] = exp_attrs[an][1] - check_object(self.pdb, "VRF_TABLE", 'Vrf-RED', exp_attr) + helper.check_object(self.pdb, "VRF_TABLE", 'Vrf-RED', exp_attr) exp_attrs1 = [ ("vni", "1000"), @@ -1056,31 +67,32 @@ def test_sip_tunnel_vrf_vni_map(self, dvs, testlog): for an in range(len(exp_attrs1)): exp_attr1[exp_attrs1[an][0]] = exp_attrs1[an][1] - check_object(self.pdb, "VXLAN_VRF_TABLE", "%s:%s" % (tunnel_name, vrf_map_name), exp_attr1) + helper.check_object(self.pdb, "VXLAN_VRF_TABLE", "%s:%s" % (tunnel_name, vrf_map_name), exp_attr1) print ("\tTesting SIP Tunnel Creation") vxlan_obj.check_vxlan_sip_tunnel(dvs, tunnel_name, '6.6.6.6', vlanlist, vnilist) print ("\tTesting Tunnel Vlan VNI Map Entry") - vxlan_obj.check_vxlan_tunnel_vlan_map_entry(dvs, tunnel_name, vlanlist, vnilist) + vxlan_obj.check_vxlan_tunnel_map_entry(dvs, tunnel_name, vlanlist, vnilist) print ("\tTesting Tunnel VRF VNI Map Entry") vxlan_obj.check_vxlan_tunnel_vrf_map_entry(dvs, tunnel_name, 'Vrf-RED', '1000') print ("\tTesting Tunnel VRF VNI Map Entry removal") - remove_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED') + vxlan_obj.remove_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED') vxlan_obj.remove_vrf(dvs, "Vrf-RED") vxlan_obj.check_vxlan_tunnel_vrf_map_entry_remove(dvs, tunnel_name, 'Vrf-RED', '1000') print ("\tTesting Tunnel Vlan VNI Map entry removal") - remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') vxlan_obj.check_vxlan_tunnel_map_entry_delete(dvs, tunnel_name, vlanlist, vnilist) print ("\tTesting SIP Tunnel Deletion") - remove_vxlan_tunnel(dvs, tunnel_name) - remove_evpn_nvo(dvs, 'nvo1') - vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name) - remove_vlan(dvs, "100") + vxlan_obj.remove_vxlan_tunnel(dvs, tunnel_name) + vxlan_obj.remove_evpn_nvo(dvs, 'nvo1') + time.sleep(2) + vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.remove_vlan(dvs, "100") # Test 2 - Create and Delete DIP Tunnel on adding and removing prefix route @@ -1088,6 +100,7 @@ def test_sip_tunnel_vrf_vni_map(self, dvs, testlog): # @pytest.mark.dev_sanity def test_prefix_route_create_dip_tunnel(self, dvs, testlog): vxlan_obj = self.get_vxlan_obj() + helper = self.get_vxlan_helper() self.setup_db(dvs) tunnel_name = 'tunnel_2' @@ -1097,17 +110,17 @@ def test_prefix_route_create_dip_tunnel(self, dvs, testlog): print ("\n\nTesting Create and Delete DIP Tunnel on adding and removing prefix route") print ("\tCreate SIP Tunnel") - vlan_ids = get_exist_entries(dvs, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN") - vlan_oid = create_vlan(dvs,"Vlan100", vlan_ids) - create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') - create_evpn_nvo(dvs, 'nvo1', tunnel_name) + vlan_ids = helper.get_exist_entries(dvs, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN") + vlan_oid = vxlan_obj.create_vlan(dvs,"Vlan100", vlan_ids) + vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.create_evpn_nvo(dvs, 'nvo1', tunnel_name) print ("\tCreate Vlan-VNI map and VRF-VNI map") - create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') print ("\tTesting VRF-VNI map in APP DB") vxlan_obj.create_vrf(dvs, "Vrf-RED") - create_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED', '1000') + vxlan_obj.create_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED', '1000') vlanlist = ['100'] vnilist = ['1000'] @@ -1119,7 +132,7 @@ def test_prefix_route_create_dip_tunnel(self, dvs, testlog): for an in range(len(exp_attrs)): exp_attr[exp_attrs[an][0]] = exp_attrs[an][1] - check_object(self.pdb, "VRF_TABLE", 'Vrf-RED', exp_attr) + helper.check_object(self.pdb, "VRF_TABLE", 'Vrf-RED', exp_attr) exp_attrs1 = [ ("vni", "1000"), @@ -1129,31 +142,31 @@ def test_prefix_route_create_dip_tunnel(self, dvs, testlog): for an in range(len(exp_attrs1)): exp_attr1[exp_attrs1[an][0]] = exp_attrs1[an][1] - check_object(self.pdb, "VXLAN_VRF_TABLE", "%s:%s" % (tunnel_name, vrf_map_name), exp_attr1) + helper.check_object(self.pdb, "VXLAN_VRF_TABLE", "%s:%s" % (tunnel_name, vrf_map_name), exp_attr1) print ("\tTesting SIP Tunnel Creation") vxlan_obj.check_vxlan_sip_tunnel(dvs, tunnel_name, '6.6.6.6', vlanlist, vnilist) print ("\tTesting Tunnel Vlan Map Entry") - vxlan_obj.check_vxlan_tunnel_vlan_map_entry(dvs, tunnel_name, vlanlist, vnilist) + vxlan_obj.check_vxlan_tunnel_map_entry(dvs, tunnel_name, vlanlist, vnilist) print ("\tTesting Tunnel Vrf Map Entry") vxlan_obj.check_vxlan_tunnel_vrf_map_entry(dvs, tunnel_name, 'Vrf-RED', '1000') print ("\tTesting VLAN 100 interface creation") - create_vlan_interface(dvs, "Vlan100", "Ethernet24", "Vrf-RED", "100.100.3.1/24") + vxlan_obj.create_vlan_interface(dvs, "Vlan100", "Ethernet24", "Vrf-RED", "100.100.3.1/24") vxlan_obj.check_router_interface(dvs, 'Vrf-RED', vlan_oid, 2) print ("\tTest VRF IPv4 Route with Tunnel Nexthop Add") vxlan_obj.fetch_exist_entries(dvs) - create_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') + vxlan_obj.create_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') vxlan_obj.check_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') print ("\tTesting DIP tunnel 7.7.7.7 creation") vxlan_obj.check_vxlan_dip_tunnel(dvs, tunnel_name, '6.6.6.6', '7.7.7.7') print ("\tTest VRF IPv4 Route with Tunnel Nexthop Delete") - delete_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED') + vxlan_obj.delete_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED') vxlan_obj.check_del_tunnel_nexthop(dvs, 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') vxlan_obj.check_del_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED') @@ -1161,24 +174,25 @@ def test_prefix_route_create_dip_tunnel(self, dvs, testlog): vxlan_obj.check_vxlan_dip_tunnel_delete(dvs, '7.7.7.7') print ("\tTesting Tunnel Vrf Map Entry removal") - remove_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED') + vxlan_obj.remove_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED') vxlan_obj.check_vxlan_tunnel_vrf_map_entry_remove(dvs, tunnel_name, 'Vrf-RED', '1000') print ("\tTesting Vlan 100 interface delete") - delete_vlan_interface(dvs, "Vlan100", "100.100.3.1/24") + vxlan_obj.delete_vlan_interface(dvs, "Vlan100", "100.100.3.1/24") vxlan_obj.check_del_router_interface(dvs, "Vlan100") print ("\tTesting Tunnel Map entry removal") - remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') vxlan_obj.check_vxlan_tunnel_map_entry_delete(dvs, tunnel_name, vlanlist, vnilist) print ("\tTesting SIP Tunnel Deletion") - remove_vxlan_tunnel(dvs, tunnel_name) - remove_evpn_nvo(dvs, 'nvo1') - vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name) + vxlan_obj.remove_vxlan_tunnel(dvs, tunnel_name) + vxlan_obj.remove_evpn_nvo(dvs, 'nvo1') + time.sleep(2) + vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name, '6.6.6.6') vxlan_obj.remove_vrf(dvs, "Vrf-RED") - remove_vlan_member(dvs, "100", "Ethernet24") - remove_vlan(dvs, "100") + vxlan_obj.remove_vlan_member(dvs, "100", "Ethernet24") + vxlan_obj.remove_vlan(dvs, "100") # Test 3 - Create and Delete DIP Tunnel and Test IPv4 route and overlay nexthop add and delete @@ -1186,6 +200,7 @@ def test_prefix_route_create_dip_tunnel(self, dvs, testlog): # @pytest.mark.dev_sanity def test_dip_tunnel_ipv4_routes(self, dvs, testlog): vxlan_obj = self.get_vxlan_obj() + helper = self.get_vxlan_helper() self.setup_db(dvs) tunnel_name = 'tunnel_2' @@ -1195,15 +210,15 @@ def test_dip_tunnel_ipv4_routes(self, dvs, testlog): print ("\n\nTesting IPv4 Route and Overlay Nexthop Add and Delete") print ("\tCreate SIP Tunnel") - create_vlan1(dvs,"Vlan100") - create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') - create_evpn_nvo(dvs, 'nvo1', tunnel_name) + vxlan_obj.create_vlan1(dvs,"Vlan100") + vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.create_evpn_nvo(dvs, 'nvo1', tunnel_name) print ("\tCreate Vlan-VNI map and VRF-VNI map") - create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') vxlan_obj.create_vrf(dvs, "Vrf-RED") - create_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED', '1000') + vxlan_obj.create_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED', '1000') print ("\tTesting VRF-VNI map in APP DB") vlanlist = ['100'] @@ -1216,7 +231,7 @@ def test_dip_tunnel_ipv4_routes(self, dvs, testlog): for an in range(len(exp_attrs)): exp_attr[exp_attrs[an][0]] = exp_attrs[an][1] - check_object(self.pdb, "VRF_TABLE", 'Vrf-RED', exp_attr) + helper.check_object(self.pdb, "VRF_TABLE", 'Vrf-RED', exp_attr) exp_attrs1 = [ ("vni", "1000"), @@ -1226,26 +241,26 @@ def test_dip_tunnel_ipv4_routes(self, dvs, testlog): for an in range(len(exp_attrs1)): exp_attr1[exp_attrs1[an][0]] = exp_attrs1[an][1] - check_object(self.pdb, "VXLAN_VRF_TABLE", "%s:%s" % (tunnel_name, vrf_map_name), exp_attr1) + helper.check_object(self.pdb, "VXLAN_VRF_TABLE", "%s:%s" % (tunnel_name, vrf_map_name), exp_attr1) print ("\tTesting SIP Tunnel Creation") vxlan_obj.check_vxlan_sip_tunnel(dvs, tunnel_name, '6.6.6.6', vlanlist, vnilist) print ("\tTesting Tunnel Vlan Map Entry") - vxlan_obj.check_vxlan_tunnel_vlan_map_entry(dvs, tunnel_name, vlanlist, vnilist) + vxlan_obj.check_vxlan_tunnel_map_entry(dvs, tunnel_name, vlanlist, vnilist) print ("\tTesting Tunnel Vrf Map Entry") vxlan_obj.check_vxlan_tunnel_vrf_map_entry(dvs, tunnel_name, 'Vrf-RED', '1000') print ("\tTesting First DIP tunnel creation to 7.7.7.7") - create_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7', '1000') + vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7', '1000') vxlan_obj.check_vxlan_dip_tunnel(dvs, tunnel_name, '6.6.6.6', '7.7.7.7') print ("\tTesting VLAN 100 extension") vxlan_obj.check_vlan_extension(dvs, '100', '7.7.7.7') print ("\tTesting Second DIP tunnel creation to 8.8.8.8") - create_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8', '1000') + vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8', '1000') vxlan_obj.check_vxlan_dip_tunnel(dvs, tunnel_name, '6.6.6.6', '8.8.8.8') print ("\tTesting VLAN 100 extension to 8.8.8.8 and 7.7.7.7") @@ -1253,27 +268,27 @@ def test_dip_tunnel_ipv4_routes(self, dvs, testlog): vxlan_obj.check_vlan_extension(dvs, '100', '7.7.7.7') print ("\tTesting VLAN 100 interface creation") - create_vlan_interface(dvs, "Vlan100", "Ethernet24", "Vrf-RED", "100.100.3.1/24") + vxlan_obj.create_vlan_interface(dvs, "Vlan100", "Ethernet24", "Vrf-RED", "100.100.3.1/24") vxlan_obj.check_router_interface(dvs, 'Vrf-RED', vxlan_obj.vlan_id_map['100'], 2) print ("\tTest VRF IPv4 Route with Tunnel Nexthop 7.7.7.7 Add") vxlan_obj.fetch_exist_entries(dvs) - create_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') + vxlan_obj.create_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') vxlan_obj.check_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') print ("\tTest VRF IPv4 Route with Tunnel Nexthop 7.7.7.7 Delete") - delete_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED') + vxlan_obj.delete_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED') vxlan_obj.check_del_tunnel_nexthop(dvs, 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') vxlan_obj.check_del_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED') print ("\n\nTesting IPv4 Route and Overlay Nexthop Update") print ("\tTest VRF IPv4 Route with Tunnel Nexthop 7.7.7.7 Add") vxlan_obj.fetch_exist_entries(dvs) - create_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') + vxlan_obj.create_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') vxlan_obj.check_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') print ("\tTest Tunnel Nexthop change from 7.7.7.7 to 8.8.8.8") - create_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED', '8.8.8.8', "Vlan100", "00:22:22:22:22:22", '1000') + vxlan_obj.create_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED', '8.8.8.8', "Vlan100", "00:22:22:22:22:22", '1000') vxlan_obj.check_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED', '8.8.8.8', tunnel_name, "00:22:22:22:22:22", '1000', 1) print ("\tTest Previous Tunnel Nexthop 7.7.7.7 is removed") @@ -1281,7 +296,7 @@ def test_dip_tunnel_ipv4_routes(self, dvs, testlog): print ("\tTest VRF IPv4 Route and Tunnel Nexthop 8.8.8.8 Delete") vxlan_obj.fetch_exist_entries(dvs) - delete_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED') + vxlan_obj.delete_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED') vxlan_obj.check_del_tunnel_nexthop(dvs, 'Vrf-RED', '8.8.8.8', tunnel_name, "00:22:22:22:22:22", '1000') vxlan_obj.check_del_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED') @@ -1296,7 +311,7 @@ def test_dip_tunnel_ipv4_routes(self, dvs, testlog): ] print ("\tTest VRF IPv4 Route with ECMP Tunnel Nexthop [7.7.7.7 , 8.8.8.8] Add") - create_vrf_routes_ecmp(dvs, "80.80.1.0/24", 'Vrf-RED', ecmp_nexthop_attr) + vxlan_obj.create_vrf_route_ecmp(dvs, "80.80.1.0/24", 'Vrf-RED', ecmp_nexthop_attr) nh_count = 2 ecmp_nhid_list = vxlan_obj.check_vrf_routes_ecmp(dvs, "80.80.1.0/24", 'Vrf-RED', tunnel_name, nh_count) @@ -1306,9 +321,9 @@ def test_dip_tunnel_ipv4_routes(self, dvs, testlog): print ("\tTest VRF IPv4 Route with ECMP Tunnel Nexthop [7.7.7.7 , 8.8.8.8] Delete") vxlan_obj.fetch_exist_entries(dvs) - delete_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED') - check_deleted_object(self.adb, vxlan_obj.ASIC_NEXT_HOP, ecmp_nhid_list[0]) - check_deleted_object(self.adb, vxlan_obj.ASIC_NEXT_HOP, ecmp_nhid_list[1]) + vxlan_obj.delete_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED') + helper.check_deleted_object(self.adb, vxlan_obj.ASIC_NEXT_HOP, ecmp_nhid_list[0]) + helper.check_deleted_object(self.adb, vxlan_obj.ASIC_NEXT_HOP, ecmp_nhid_list[1]) vxlan_obj.check_vrf_routes_ecmp_nexthop_grp_del(dvs, 2) vxlan_obj.check_del_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED') @@ -1316,7 +331,7 @@ def test_dip_tunnel_ipv4_routes(self, dvs, testlog): print ("\n\nTest VRF IPv4 Route with Tunnel Nexthop update from non-ECMP to ECMP") print ("\tTest VRF IPv4 Route with Tunnel Nexthop 7.7.7.7 Add") vxlan_obj.fetch_exist_entries(dvs) - create_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') + vxlan_obj.create_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') vxlan_obj.check_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') ecmp_nexthop_attr = [ @@ -1327,7 +342,7 @@ def test_dip_tunnel_ipv4_routes(self, dvs, testlog): ] print ("\tTest VRF IPv4 Route with ECMP Tunnel Nexthop [7.7.7.7 , 8.8.8.8] Udpate") - create_vrf_routes_ecmp(dvs, "80.80.1.0/24", 'Vrf-RED', ecmp_nexthop_attr) + vxlan_obj.create_vrf_route_ecmp(dvs, "80.80.1.0/24", 'Vrf-RED', ecmp_nexthop_attr) nh_count = 2 ecmp_nhid_list = vxlan_obj.check_vrf_routes_ecmp(dvs, "80.80.1.0/24", 'Vrf-RED', tunnel_name, nh_count, 1) @@ -1337,7 +352,7 @@ def test_dip_tunnel_ipv4_routes(self, dvs, testlog): print ("\n\nTest VRF IPv4 Route with Tunnel Nexthop update from ECMP to non-ECMP") print ("\tTest VRF IPv4 Route with Tunnel Nexthop 8.8.8.8 Update") - create_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED', '8.8.8.8', "Vlan100", "00:22:22:22:22:22", '1000') + vxlan_obj.create_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED', '8.8.8.8', "Vlan100", "00:22:22:22:22:22", '1000') vxlan_obj.check_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED', '8.8.8.8', tunnel_name, "00:22:22:22:22:22", '1000', 1) print ("\tTest Tunnel Nexthop 7.7.7.7 is deleted") @@ -1348,41 +363,42 @@ def test_dip_tunnel_ipv4_routes(self, dvs, testlog): print ("\tTest VRF IPv4 Route with Tunnel Nexthop 8.8.8.8 Delete") vxlan_obj.fetch_exist_entries(dvs) - delete_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED') + vxlan_obj.delete_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED') vxlan_obj.check_del_tunnel_nexthop(dvs, 'Vrf-RED', '8.8.8.8', tunnel_name, "00:22:22:22:22:22", '1000') vxlan_obj.check_del_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED') print ("\n\nTest DIP and SIP Tunnel Deletion ") print ("\tTesting Tunnel Vrf VNI Map Entry removal") - remove_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED') + vxlan_obj.remove_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED') vxlan_obj.check_vxlan_tunnel_vrf_map_entry_remove(dvs, tunnel_name, 'Vrf-RED', '1000') print ("\tTesting LastVlan removal and DIP tunnel delete for 7.7.7.7") - remove_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7') + vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7') vxlan_obj.check_vlan_extension_delete(dvs, '100', '7.7.7.7') vxlan_obj.check_vxlan_dip_tunnel_delete(dvs, '7.7.7.7') print ("\tTesting LastVlan removal and DIP tunnel delete for 8.8.8.8") - remove_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8') + vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8') vxlan_obj.check_vlan_extension_delete(dvs, '100', '8.8.8.8') vxlan_obj.check_vxlan_dip_tunnel_delete(dvs, '8.8.8.8') print ("\tTesting Vlan 100 interface delete") - delete_vlan_interface(dvs, "Vlan100", "100.100.3.1/24") + vxlan_obj.delete_vlan_interface(dvs, "Vlan100", "100.100.3.1/24") vxlan_obj.check_del_router_interface(dvs, "Vlan100") print ("\tTesting Tunnel Map entry removal") - remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') vxlan_obj.check_vxlan_tunnel_map_entry_delete(dvs, tunnel_name, vlanlist, vnilist) print ("\tTesting SIP Tunnel Deletion") - remove_vxlan_tunnel(dvs, tunnel_name) - remove_evpn_nvo(dvs, 'nvo1') - vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name) + vxlan_obj.remove_vxlan_tunnel(dvs, tunnel_name) + vxlan_obj.remove_evpn_nvo(dvs, 'nvo1') + time.sleep(2) + vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name, '6.6.6.6') vxlan_obj.remove_vrf(dvs, "Vrf-RED") - remove_vlan_member(dvs, "100", "Ethernet24") - remove_vlan(dvs, "100") + vxlan_obj.remove_vlan_member(dvs, "100", "Ethernet24") + vxlan_obj.remove_vlan(dvs, "100") # Test 4 - Create and Delete DIP Tunnel and Test IPv6 route and overlay nexthop add and delete @@ -1390,6 +406,7 @@ def test_dip_tunnel_ipv4_routes(self, dvs, testlog): # @pytest.mark.dev_sanity def test_dip_tunnel_ipv6_routes(self, dvs, testlog): vxlan_obj = self.get_vxlan_obj() + helper = self.get_vxlan_helper() self.setup_db(dvs) tunnel_name = 'tunnel_2' @@ -1399,16 +416,16 @@ def test_dip_tunnel_ipv6_routes(self, dvs, testlog): print ("\n\nTesting IPv6 Route and Overlay Nexthop Add and Delete") print ("\tCreate SIP Tunnel") - create_vlan1(dvs,"Vlan100") - create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') - create_evpn_nvo(dvs, 'nvo1', tunnel_name) + vxlan_obj.create_vlan1(dvs,"Vlan100") + vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.create_evpn_nvo(dvs, 'nvo1', tunnel_name) print ("\tCreate Vlan-VNI map and VRF-VNI map") - create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') print ("\tTesting VRF-VNI map in APP DB") vxlan_obj.create_vrf(dvs, "Vrf-RED") - create_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED', '1000') + vxlan_obj.create_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED', '1000') vlanlist = ['100'] vnilist = ['1000'] @@ -1421,7 +438,7 @@ def test_dip_tunnel_ipv6_routes(self, dvs, testlog): exp_attr[exp_attrs[an][0]] = exp_attrs[an][1] print ("\tCheck VRF Table in APP DB") - check_object(self.pdb, "VRF_TABLE", 'Vrf-RED', exp_attr) + helper.check_object(self.pdb, "VRF_TABLE", 'Vrf-RED', exp_attr) exp_attrs1 = [ ("vni", "1000"), @@ -1431,26 +448,26 @@ def test_dip_tunnel_ipv6_routes(self, dvs, testlog): for an in range(len(exp_attrs1)): exp_attr1[exp_attrs1[an][0]] = exp_attrs1[an][1] - check_object(self.pdb, "VXLAN_VRF_TABLE", "%s:%s" % (tunnel_name, vrf_map_name), exp_attr1) + helper.check_object(self.pdb, "VXLAN_VRF_TABLE", "%s:%s" % (tunnel_name, vrf_map_name), exp_attr1) print ("\tTesting SIP Tunnel Creation") vxlan_obj.check_vxlan_sip_tunnel(dvs, tunnel_name, '6.6.6.6', vlanlist, vnilist) print ("\tTesting Tunnel Vlan Map Entry") - vxlan_obj.check_vxlan_tunnel_vlan_map_entry(dvs, tunnel_name, vlanlist, vnilist) + vxlan_obj.check_vxlan_tunnel_map_entry(dvs, tunnel_name, vlanlist, vnilist) print ("\tTesting Tunnel Vrf Map Entry") vxlan_obj.check_vxlan_tunnel_vrf_map_entry(dvs, tunnel_name, 'Vrf-RED', '1000') print ("\tTesting First DIP tunnel creation to 7.7.7.7") - create_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7', '1000') + vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7', '1000') vxlan_obj.check_vxlan_dip_tunnel(dvs, tunnel_name, '6.6.6.6', '7.7.7.7') print ("\tTesting VLAN 100 extension") vxlan_obj.check_vlan_extension(dvs, '100', '7.7.7.7') print ("\tTesting Second DIP tunnel creation to 8.8.8.8") - create_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8', '1000') + vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8', '1000') vxlan_obj.check_vxlan_dip_tunnel(dvs, tunnel_name, '6.6.6.6', '8.8.8.8') print ("\tTesting VLAN 100 extension to 8.8.8.8 and 7.7.7.7") @@ -1459,27 +476,27 @@ def test_dip_tunnel_ipv6_routes(self, dvs, testlog): vxlan_obj.fetch_exist_entries(dvs) print ("\tTesting VLAN 100 interface creation") - create_vlan_interface(dvs, "Vlan100", "Ethernet24", "Vrf-RED", "2001::8/64") + vxlan_obj.create_vlan_interface(dvs, "Vlan100", "Ethernet24", "Vrf-RED", "2001::8/64") vxlan_obj.check_router_interface(dvs, 'Vrf-RED', vxlan_obj.vlan_id_map['100'], 2) print ("\tTest VRF IPv6 Route with Tunnel Nexthop Add") vxlan_obj.fetch_exist_entries(dvs) - create_vrf_routes(dvs, "2002::8/64", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') + vxlan_obj.create_vrf_route(dvs, "2002::8/64", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') vxlan_obj.check_vrf_routes(dvs, "2002::8/64", 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') print ("\tTest VRF IPv6 Route with Tunnel Nexthop Delete") - delete_vrf_routes(dvs, "2002::8/64", 'Vrf-RED') + vxlan_obj.delete_vrf_route(dvs, "2002::8/64", 'Vrf-RED') vxlan_obj.check_del_tunnel_nexthop(dvs, 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') vxlan_obj.check_del_vrf_routes(dvs, "2002::8/64", 'Vrf-RED') print ("\n\nTesting IPv6 Route and Overlay Nexthop Update") print ("\tTest VRF IPv6 Route with Tunnel Nexthop 7.7.7.7 Add") vxlan_obj.fetch_exist_entries(dvs) - create_vrf_routes(dvs, "2002::8/64", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') + vxlan_obj.create_vrf_route(dvs, "2002::8/64", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') vxlan_obj.check_vrf_routes(dvs, "2002::8/64", 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') print ("\tTest Tunnel Nexthop change from 7.7.7.7 to 8.8.8.8") - create_vrf_routes(dvs, "2002::8/64", 'Vrf-RED', '8.8.8.8', "Vlan100", "00:22:22:22:22:22", '1000') + vxlan_obj.create_vrf_route(dvs, "2002::8/64", 'Vrf-RED', '8.8.8.8', "Vlan100", "00:22:22:22:22:22", '1000') vxlan_obj.check_vrf_routes(dvs, "2002::8/64", 'Vrf-RED', '8.8.8.8', tunnel_name, "00:22:22:22:22:22", '1000', 1) print ("\tTest Previous Tunnel Nexthop 7.7.7.7 is removed") @@ -1487,7 +504,7 @@ def test_dip_tunnel_ipv6_routes(self, dvs, testlog): print ("\tTest VRF IPv6 Route and Tunnel Nexthop 8.8.8.8 Delete") vxlan_obj.fetch_exist_entries(dvs) - delete_vrf_routes(dvs, "2002::8/64", 'Vrf-RED') + vxlan_obj.delete_vrf_route(dvs, "2002::8/64", 'Vrf-RED') vxlan_obj.check_del_tunnel_nexthop(dvs, 'Vrf-RED', '8.8.8.8', tunnel_name, "00:22:22:22:22:22", '1000') vxlan_obj.check_del_vrf_routes(dvs, "2002::8/64", 'Vrf-RED') @@ -1502,7 +519,7 @@ def test_dip_tunnel_ipv6_routes(self, dvs, testlog): ] print ("\tTest VRF IPv6 Route with ECMP Tunnel Nexthop [7.7.7.7 , 8.8.8.8] Add") - create_vrf_routes_ecmp(dvs, "2002::8/64", 'Vrf-RED', ecmp_nexthop_attr) + vxlan_obj.create_vrf_route_ecmp(dvs, "2002::8/64", 'Vrf-RED', ecmp_nexthop_attr) nh_count = 2 ecmp_nhid_list = vxlan_obj.check_vrf_routes_ecmp(dvs, "2002::8/64", 'Vrf-RED', tunnel_name, nh_count) @@ -1512,9 +529,9 @@ def test_dip_tunnel_ipv6_routes(self, dvs, testlog): print ("\tTest VRF IPv6 Route with ECMP Tunnel Nexthop [7.7.7.7 , 8.8.8.8] Delete") vxlan_obj.fetch_exist_entries(dvs) - delete_vrf_routes(dvs, "2002::8/64", 'Vrf-RED') - check_deleted_object(self.adb, vxlan_obj.ASIC_NEXT_HOP, ecmp_nhid_list[0]) - check_deleted_object(self.adb, vxlan_obj.ASIC_NEXT_HOP, ecmp_nhid_list[1]) + vxlan_obj.delete_vrf_route(dvs, "2002::8/64", 'Vrf-RED') + helper.check_deleted_object(self.adb, vxlan_obj.ASIC_NEXT_HOP, ecmp_nhid_list[0]) + helper.check_deleted_object(self.adb, vxlan_obj.ASIC_NEXT_HOP, ecmp_nhid_list[1]) vxlan_obj.check_vrf_routes_ecmp_nexthop_grp_del(dvs, 2) vxlan_obj.check_del_vrf_routes(dvs, "2002::8/64", 'Vrf-RED') @@ -1522,7 +539,7 @@ def test_dip_tunnel_ipv6_routes(self, dvs, testlog): print ("\n\nTest VRF IPv6 Route with Tunnel Nexthop update from non-ECMP to ECMP") print ("\tTest VRF IPv6 Route with Tunnel Nexthop 7.7.7.7 Add") vxlan_obj.fetch_exist_entries(dvs) - create_vrf_routes(dvs, "2002::8/64", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') + vxlan_obj.create_vrf_route(dvs, "2002::8/64", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') vxlan_obj.check_vrf_routes(dvs, "2002::8/64", 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') print ("\tTest VRF IPv4 Route with ECMP Tunnel Nexthop [7.7.7.7 , 8.8.8.8] Udpate") @@ -1533,7 +550,7 @@ def test_dip_tunnel_ipv6_routes(self, dvs, testlog): ("router_mac", "00:11:11:11:11:11,00:22:22:22:22:22"), ] - create_vrf_routes_ecmp(dvs, "2002::8/64", 'Vrf-RED', ecmp_nexthop_attr) + vxlan_obj.create_vrf_route_ecmp(dvs, "2002::8/64", 'Vrf-RED', ecmp_nexthop_attr) nh_count = 2 ecmp_nhid_list = vxlan_obj.check_vrf_routes_ecmp(dvs, "2002::8/64", 'Vrf-RED', tunnel_name, nh_count, 1) @@ -1543,7 +560,7 @@ def test_dip_tunnel_ipv6_routes(self, dvs, testlog): print ("\n\nTest VRF IPv6 Route with Tunnel Nexthop update from ECMP to non-ECMP") print ("\tTest VRF IPv6 Route with Tunnel Nexthop 8.8.8.8 Update") - create_vrf_routes(dvs, "2002::8/64", 'Vrf-RED', '8.8.8.8', "Vlan100", "00:22:22:22:22:22", '1000') + vxlan_obj.create_vrf_route(dvs, "2002::8/64", 'Vrf-RED', '8.8.8.8', "Vlan100", "00:22:22:22:22:22", '1000') vxlan_obj.check_vrf_routes(dvs, "2002::8/64", 'Vrf-RED', '8.8.8.8', tunnel_name, "00:22:22:22:22:22", '1000', 1) print ("\tTest Tunnel Nexthop 7.7.7.7 is deleted") @@ -1554,41 +571,42 @@ def test_dip_tunnel_ipv6_routes(self, dvs, testlog): print ("\tTest VRF IPv6 Route with Tunnel Nexthop 8.8.8.8 Delete") vxlan_obj.fetch_exist_entries(dvs) - delete_vrf_routes(dvs, "2002::8/64", 'Vrf-RED') + vxlan_obj.delete_vrf_route(dvs, "2002::8/64", 'Vrf-RED') vxlan_obj.check_del_tunnel_nexthop(dvs, 'Vrf-RED', '8.8.8.8', tunnel_name, "00:22:22:22:22:22", '1000') vxlan_obj.check_del_vrf_routes(dvs, "2002::8/64", 'Vrf-RED') print ("\n\nTest DIP and SIP Tunnel Deletion ") print ("\tTesting Tunnel Vrf Map Entry removal") - remove_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED') + vxlan_obj.remove_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED') vxlan_obj.check_vxlan_tunnel_vrf_map_entry_remove(dvs, tunnel_name, 'Vrf-RED', '1000') print ("\tTesting LastVlan removal and DIP tunnel delete for 7.7.7.7") - remove_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7') + vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7') vxlan_obj.check_vlan_extension_delete(dvs, '100', '7.7.7.7') vxlan_obj.check_vxlan_dip_tunnel_delete(dvs, '7.7.7.7') print ("\tTesting LastVlan removal and DIP tunnel delete for 8.8.8.8") - remove_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8') + vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8') vxlan_obj.check_vlan_extension_delete(dvs, '100', '8.8.8.8') vxlan_obj.check_vxlan_dip_tunnel_delete(dvs, '8.8.8.8') print ("\tTesting Vlan 100 interface delete") - delete_vlan_interface(dvs, "Vlan100", "2001::8/64") + vxlan_obj.delete_vlan_interface(dvs, "Vlan100", "2001::8/64") vxlan_obj.check_del_router_interface(dvs, "Vlan100") print ("\tTesting Tunnel Map entry removal") - remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') vxlan_obj.check_vxlan_tunnel_map_entry_delete(dvs, tunnel_name, vlanlist, vnilist) print ("\tTesting SIP Tunnel Deletion") - remove_vxlan_tunnel(dvs, tunnel_name) - remove_evpn_nvo(dvs, 'nvo1') - vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name) + vxlan_obj.remove_vxlan_tunnel(dvs, tunnel_name) + vxlan_obj.remove_evpn_nvo(dvs, 'nvo1') + time.sleep(2) + vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name, '6.6.6.6') vxlan_obj.remove_vrf(dvs, "Vrf-RED") - remove_vlan_member(dvs, "100", "Ethernet24") - remove_vlan(dvs, "100") + vxlan_obj.remove_vlan_member(dvs, "100", "Ethernet24") + vxlan_obj.remove_vlan(dvs, "100") # Add Dummy always-pass test at end as workaroud diff --git a/tests/test_evpn_l3_vxlan_p2mp.py b/tests/test_evpn_l3_vxlan_p2mp.py new file mode 100644 index 000000000000..c4cbb7e03111 --- /dev/null +++ b/tests/test_evpn_l3_vxlan_p2mp.py @@ -0,0 +1,596 @@ +from swsscommon import swsscommon +from evpn_tunnel import VxlanTunnel,VxlanEvpnHelper +import time + +DVS_ENV = ["fake_platform=mellanox"] + +class TestL3VxlanP2MP(object): + + def get_vxlan_obj(self): + return VxlanTunnel() + + def get_vxlan_helper(self): + return VxlanEvpnHelper() + + def setup_db(self, dvs): + self.pdb = swsscommon.DBConnector(0, dvs.redis_sock, 0) + self.adb = swsscommon.DBConnector(1, dvs.redis_sock, 0) + self.cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0) + +# Test 1 - Create and Delete SIP Tunnel and VRF VNI Map entries +# @pytest.mark.skip(reason="Starting Route Orch, VRF Orch to be merged") +# @pytest.mark.dev_sanity + def test_sip_tunnel_vrf_vni_map(self, dvs, testlog): + vxlan_obj = self.get_vxlan_obj() + helper = self.get_vxlan_helper() + + self.setup_db(dvs) + tunnel_name = 'tunnel_2' + map_name = 'map_1000_100' + vrf_map_name = 'evpn_map_1000_Vrf-RED' + + vxlan_obj.fetch_exist_entries(dvs) + + print ("\n\nTesting Create and Delete SIP Tunnel and VRF VNI Map entries") + print ("\tCreate SIP Tunnel") + vxlan_obj.create_vlan1(dvs,"Vlan100") + vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.create_evpn_nvo(dvs, 'nvo1', tunnel_name) + + print ("\tCreate Vlan-VNI map and VRF-VNI map") + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + + vxlan_obj.create_vrf(dvs, "Vrf-RED") + vxlan_obj.create_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED', '1000') + + print ("\tTesting VRF-VNI map in APP DB") + vlanlist = ['100'] + vnilist = ['1000'] + + exp_attrs = [ + ("vni", "1000"), + ] + exp_attr = {} + for an in range(len(exp_attrs)): + exp_attr[exp_attrs[an][0]] = exp_attrs[an][1] + + helper.check_object(self.pdb, "VRF_TABLE", 'Vrf-RED', exp_attr) + + exp_attrs1 = [ + ("vni", "1000"), + ("vlan", "Vlan100"), + ] + exp_attr1 = {} + for an in range(len(exp_attrs1)): + exp_attr1[exp_attrs1[an][0]] = exp_attrs1[an][1] + + helper.check_object(self.pdb, "VXLAN_VRF_TABLE", "%s:%s" % (tunnel_name, vrf_map_name), exp_attr1) + + print ("\tTesting SIP Tunnel Creation") + vxlan_obj.check_vxlan_sip_tunnel(dvs, tunnel_name, '6.6.6.6', vlanlist, vnilist) + + print ("\tTesting Tunnel Vlan VNI Map Entry") + vxlan_obj.check_vxlan_tunnel_map_entry(dvs, tunnel_name, vlanlist, vnilist) + + print ("\tTesting Tunnel VRF VNI Map Entry") + vxlan_obj.check_vxlan_tunnel_vrf_map_entry(dvs, tunnel_name, 'Vrf-RED', '1000') + + print ("\tTesting Tunnel VRF VNI Map Entry removal") + vxlan_obj.remove_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED') + vxlan_obj.remove_vrf(dvs, "Vrf-RED") + vxlan_obj.check_vxlan_tunnel_vrf_map_entry_remove(dvs, tunnel_name, 'Vrf-RED', '1000') + + print ("\tTesting Tunnel Vlan VNI Map entry removal") + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.check_vxlan_tunnel_map_entry_delete(dvs, tunnel_name, vlanlist, vnilist) + + print ("\tTesting SIP Tunnel Deletion") + vxlan_obj.remove_vxlan_tunnel(dvs, tunnel_name) + vxlan_obj.remove_evpn_nvo(dvs, 'nvo1') + time.sleep(2) + vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.remove_vlan(dvs, "100") + + +# Test 2 - Remote end point add +# @pytest.mark.skip(reason="Starting Route Orch, VRF Orch to be merged") +# @pytest.mark.dev_sanity + def test_prefix_route_create_remote_endpoint(self, dvs, testlog): + vxlan_obj = self.get_vxlan_obj() + helper = self.get_vxlan_helper() + + self.setup_db(dvs) + tunnel_name = 'tunnel_2' + map_name = 'map_1000_100' + vrf_map_name = 'evpn_map_1000_Vrf-RED' + vxlan_obj.fetch_exist_entries(dvs) + + print ("\tCreate SIP Tunnel") + vlan_ids = vxlan_obj.helper.get_exist_entries(dvs, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN") + vlan_oid = vxlan_obj.create_vlan(dvs,"Vlan100", vlan_ids) + vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.create_evpn_nvo(dvs, 'nvo1', tunnel_name) + + print ("\tCreate Vlan-VNI map and VRF-VNI map") + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + + print ("\tTesting VRF-VNI map in APP DB") + vxlan_obj.create_vrf(dvs, "Vrf-RED") + vxlan_obj.create_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED', '1000') + + vlanlist = ['100'] + vnilist = ['1000'] + + exp_attrs = [ + ("vni", "1000"), + ] + exp_attr = {} + for an in range(len(exp_attrs)): + exp_attr[exp_attrs[an][0]] = exp_attrs[an][1] + + helper.check_object(self.pdb, "VRF_TABLE", 'Vrf-RED', exp_attr) + + exp_attrs1 = [ + ("vni", "1000"), + ("vlan", "Vlan100"), + ] + exp_attr1 = {} + for an in range(len(exp_attrs1)): + exp_attr1[exp_attrs1[an][0]] = exp_attrs1[an][1] + + helper.check_object(self.pdb, "VXLAN_VRF_TABLE", "%s:%s" % (tunnel_name, vrf_map_name), exp_attr1) + + print ("\tTesting SIP Tunnel Creation") + vxlan_obj.check_vxlan_sip_tunnel(dvs, tunnel_name, '6.6.6.6', vlanlist, vnilist) + + print ("\tTesting Tunnel Vlan Map Entry") + vxlan_obj.check_vxlan_tunnel_map_entry(dvs, tunnel_name, vlanlist, vnilist) + + print ("\tTesting Tunnel Vrf Map Entry") + vxlan_obj.check_vxlan_tunnel_vrf_map_entry(dvs, tunnel_name, 'Vrf-RED', '1000') + + print ("\tTesting VLAN 100 interface creation") + vxlan_obj.create_vlan_interface(dvs, "Vlan100", "Ethernet24", "Vrf-RED", "100.100.3.1/24") + vxlan_obj.check_router_interface(dvs, 'Vrf-RED', vlan_oid, 2) + + print ("\tTest VRF IPv4 Route with Tunnel Nexthop Add") + vxlan_obj.fetch_exist_entries(dvs) + vxlan_obj.create_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') + vxlan_obj.check_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') + + print ("\tTest VRF IPv4 Route with Tunnel Nexthop Delete") + vxlan_obj.delete_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED') + vxlan_obj.check_del_tunnel_nexthop(dvs, 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') + vxlan_obj.check_del_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED') + + print ("\tTesting Tunnel Vrf Map Entry removal") + vxlan_obj.remove_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED') + vxlan_obj.check_vxlan_tunnel_vrf_map_entry_remove(dvs, tunnel_name, 'Vrf-RED', '1000') + + print ("\tTesting Vlan 100 interface delete") + vxlan_obj.delete_vlan_interface(dvs, "Vlan100", "100.100.3.1/24") + vxlan_obj.check_del_router_interface(dvs, "Vlan100") + + print ("\tTesting Tunnel Map entry removal") + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.check_vxlan_tunnel_map_entry_delete(dvs, tunnel_name, vlanlist, vnilist) + + print ("\tTesting SIP Tunnel Deletion") + vxlan_obj.remove_vxlan_tunnel(dvs, tunnel_name) + vxlan_obj.remove_evpn_nvo(dvs, 'nvo1') + time.sleep(2) + vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.remove_vrf(dvs, "Vrf-RED") + vxlan_obj.remove_vlan_member(dvs, "100", "Ethernet24") + vxlan_obj.remove_vlan(dvs, "100") + + +# Test 3 - Create and Delete remote end point and Test IPv4 route and overlay nexthop add and delete +# @pytest.mark.dev_sanity + def test_remote_ipv4_routes(self, dvs, testlog): + vxlan_obj = self.get_vxlan_obj() + helper = self.get_vxlan_helper() + + self.setup_db(dvs) + tunnel_name = 'tunnel_2' + map_name = 'map_1000_100' + vrf_map_name = 'evpn_map_1000_Vrf-RED' + vxlan_obj.fetch_exist_entries(dvs) + + print ("\n\nTesting IPv4 Route and Overlay Nexthop Add and Delete") + print ("\tCreate SIP Tunnel") + vxlan_obj.create_vlan1(dvs,"Vlan100") + vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.create_evpn_nvo(dvs, 'nvo1', tunnel_name) + + print ("\tCreate Vlan-VNI map and VRF-VNI map") + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + + vxlan_obj.create_vrf(dvs, "Vrf-RED") + vxlan_obj.create_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED', '1000') + + print ("\tTesting VRF-VNI map in APP DB") + vlanlist = ['100'] + vnilist = ['1000'] + + exp_attrs = [ + ("vni", "1000"), + ] + exp_attr = {} + for an in range(len(exp_attrs)): + exp_attr[exp_attrs[an][0]] = exp_attrs[an][1] + + helper.check_object(self.pdb, "VRF_TABLE", 'Vrf-RED', exp_attr) + + exp_attrs1 = [ + ("vni", "1000"), + ("vlan", "Vlan100"), + ] + exp_attr1 = {} + for an in range(len(exp_attrs1)): + exp_attr1[exp_attrs1[an][0]] = exp_attrs1[an][1] + + helper.check_object(self.pdb, "VXLAN_VRF_TABLE", "%s:%s" % (tunnel_name, vrf_map_name), exp_attr1) + + print ("\tTesting SIP Tunnel Creation") + vxlan_obj.check_vxlan_sip_tunnel(dvs, tunnel_name, '6.6.6.6', vlanlist, vnilist) + + print ("\tTesting Tunnel Vlan Map Entry") + vxlan_obj.check_vxlan_tunnel_map_entry(dvs, tunnel_name, vlanlist, vnilist) + + print ("\tTesting Tunnel Vrf Map Entry") + vxlan_obj.check_vxlan_tunnel_vrf_map_entry(dvs, tunnel_name, 'Vrf-RED', '1000') + + print ("\tTesting First Remote end point to 7.7.7.7") + vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7', '1000') + + print ("\tTesting VLAN 100 extension") + vxlan_obj.check_vlan_extension_p2mp(dvs, '100', '6.6.6.6', '7.7.7.7') + + print ("\tTesting Second remote end point to 8.8.8.8") + vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8', '1000') + + print ("\tTesting VLAN 100 extension to 8.8.8.8 and 7.7.7.7") + vxlan_obj.check_vlan_extension_p2mp(dvs, '100', '6.6.6.6', '8.8.8.8') + vxlan_obj.check_vlan_extension_p2mp(dvs, '100', '6.6.6.6', '7.7.7.7') + + print ("\tTesting VLAN 100 interface creation") + vxlan_obj.create_vlan_interface(dvs, "Vlan100", "Ethernet24", "Vrf-RED", "100.100.3.1/24") + vxlan_obj.check_router_interface(dvs, 'Vrf-RED', vxlan_obj.vlan_id_map['100'], 2) + + print ("\tTest VRF IPv4 Route with Tunnel Nexthop 7.7.7.7 Add") + vxlan_obj.fetch_exist_entries(dvs) + vxlan_obj.create_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') + vxlan_obj.check_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') + + print ("\tTest VRF IPv4 Route with Tunnel Nexthop 7.7.7.7 Delete") + vxlan_obj.delete_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED') + vxlan_obj.check_del_tunnel_nexthop(dvs, 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') + vxlan_obj.check_del_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED') + + print ("\n\nTesting IPv4 Route and Overlay Nexthop Update") + print ("\tTest VRF IPv4 Route with Tunnel Nexthop 7.7.7.7 Add") + vxlan_obj.fetch_exist_entries(dvs) + vxlan_obj.create_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') + vxlan_obj.check_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') + + print ("\tTest Tunnel Nexthop change from 7.7.7.7 to 8.8.8.8") + vxlan_obj.create_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED', '8.8.8.8', "Vlan100", "00:22:22:22:22:22", '1000') + vxlan_obj.check_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED', '8.8.8.8', tunnel_name, "00:22:22:22:22:22", '1000', 1) + + print ("\tTest Previous Tunnel Nexthop 7.7.7.7 is removed") + vxlan_obj.check_del_tunnel_nexthop(dvs, 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') + + print ("\tTest VRF IPv4 Route and Tunnel Nexthop 8.8.8.8 Delete") + vxlan_obj.fetch_exist_entries(dvs) + vxlan_obj.delete_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED') + vxlan_obj.check_del_tunnel_nexthop(dvs, 'Vrf-RED', '8.8.8.8', tunnel_name, "00:22:22:22:22:22", '1000') + vxlan_obj.check_del_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED') + + print ("\n\nTest VRF IPv4 Route with ECMP Tunnel Nexthop Add and Delete") + vxlan_obj.fetch_exist_entries(dvs) + + ecmp_nexthop_attr = [ + ("nexthop", "7.7.7.7,8.8.8.8"), + ("ifname", "Vlan100,Vlan100"), + ("vni_label", "1000,1000"), + ("router_mac", "00:11:11:11:11:11,00:22:22:22:22:22"), + ] + + print ("\tTest VRF IPv4 Route with ECMP Tunnel Nexthop [7.7.7.7 , 8.8.8.8] Add") + vxlan_obj.create_vrf_route_ecmp(dvs, "80.80.1.0/24", 'Vrf-RED', ecmp_nexthop_attr) + + nh_count = 2 + ecmp_nhid_list = vxlan_obj.check_vrf_routes_ecmp(dvs, "80.80.1.0/24", 'Vrf-RED', tunnel_name, nh_count) + assert nh_count == len(ecmp_nhid_list) + vxlan_obj.check_add_tunnel_nexthop(dvs, ecmp_nhid_list[0], '7.7.7.7', tunnel_name, '00:11:11:11:11:11', '1000') + vxlan_obj.check_add_tunnel_nexthop(dvs, ecmp_nhid_list[1], '8.8.8.8', tunnel_name, '00:22:22:22:22:22', '1000') + + print ("\tTest VRF IPv4 Route with ECMP Tunnel Nexthop [7.7.7.7 , 8.8.8.8] Delete") + vxlan_obj.fetch_exist_entries(dvs) + vxlan_obj.delete_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED') + helper.check_deleted_object(self.adb, vxlan_obj.ASIC_NEXT_HOP, ecmp_nhid_list[0]) + helper.check_deleted_object(self.adb, vxlan_obj.ASIC_NEXT_HOP, ecmp_nhid_list[1]) + + vxlan_obj.check_vrf_routes_ecmp_nexthop_grp_del(dvs, 2) + vxlan_obj.check_del_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED') + + print ("\n\nTest VRF IPv4 Route with Tunnel Nexthop update from non-ECMP to ECMP") + print ("\tTest VRF IPv4 Route with Tunnel Nexthop 7.7.7.7 Add") + vxlan_obj.fetch_exist_entries(dvs) + vxlan_obj.create_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') + vxlan_obj.check_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') + + ecmp_nexthop_attr = [ + ("nexthop", "7.7.7.7,8.8.8.8"), + ("ifname", "Vlan100,Vlan100"), + ("vni_label", "1000,1000"), + ("router_mac", "00:11:11:11:11:11,00:22:22:22:22:22"), + ] + + print ("\tTest VRF IPv4 Route with ECMP Tunnel Nexthop [7.7.7.7 , 8.8.8.8] Udpate") + vxlan_obj.create_vrf_route_ecmp(dvs, "80.80.1.0/24", 'Vrf-RED', ecmp_nexthop_attr) + + nh_count = 2 + ecmp_nhid_list = vxlan_obj.check_vrf_routes_ecmp(dvs, "80.80.1.0/24", 'Vrf-RED', tunnel_name, nh_count, 1) + assert nh_count == len(ecmp_nhid_list) + vxlan_obj.check_add_tunnel_nexthop(dvs, ecmp_nhid_list[0], '7.7.7.7', tunnel_name, '00:11:11:11:11:11', '1000') + vxlan_obj.check_add_tunnel_nexthop(dvs, ecmp_nhid_list[1], '8.8.8.8', tunnel_name, '00:22:22:22:22:22', '1000') + + print ("\n\nTest VRF IPv4 Route with Tunnel Nexthop update from ECMP to non-ECMP") + print ("\tTest VRF IPv4 Route with Tunnel Nexthop 8.8.8.8 Update") + vxlan_obj.create_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED', '8.8.8.8', "Vlan100", "00:22:22:22:22:22", '1000') + vxlan_obj.check_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED', '8.8.8.8', tunnel_name, "00:22:22:22:22:22", '1000', 1) + + print ("\tTest Tunnel Nexthop 7.7.7.7 is deleted") + vxlan_obj.check_del_tunnel_nexthop(dvs, 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') + + print ("\tTest Tunnel Nexthop ECMP Group is deleted") + vxlan_obj.check_vrf_routes_ecmp_nexthop_grp_del(dvs, 2) + + print ("\tTest VRF IPv4 Route with Tunnel Nexthop 8.8.8.8 Delete") + vxlan_obj.fetch_exist_entries(dvs) + vxlan_obj.delete_vrf_route(dvs, "80.80.1.0/24", 'Vrf-RED') + + vxlan_obj.check_del_tunnel_nexthop(dvs, 'Vrf-RED', '8.8.8.8', tunnel_name, "00:22:22:22:22:22", '1000') + vxlan_obj.check_del_vrf_routes(dvs, "80.80.1.0/24", 'Vrf-RED') + + print ("\n\nTest Remote end point remove and SIP Tunnel Deletion ") + print ("\tTesting Tunnel Vrf VNI Map Entry removal") + vxlan_obj.remove_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED') + vxlan_obj.check_vxlan_tunnel_vrf_map_entry_remove(dvs, tunnel_name, 'Vrf-RED', '1000') + + print ("\tTesting LastVlan removal and remote end point delete for 7.7.7.7") + vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7') + vxlan_obj.check_vlan_extension_delete_p2mp(dvs, '100', '6.6.6.6', '7.7.7.7') + + print ("\tTesting LastVlan removal and remote end point delete for 8.8.8.8") + vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8') + vxlan_obj.check_vlan_extension_delete_p2mp(dvs, '100', '6.6.6.6', '8.8.8.8') + + print ("\tTesting Vlan 100 interface delete") + vxlan_obj.delete_vlan_interface(dvs, "Vlan100", "100.100.3.1/24") + vxlan_obj.check_del_router_interface(dvs, "Vlan100") + + print ("\tTesting Tunnel Map entry removal") + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.check_vxlan_tunnel_map_entry_delete(dvs, tunnel_name, vlanlist, vnilist) + + print ("\tTesting SIP Tunnel Deletion") + vxlan_obj.remove_vxlan_tunnel(dvs, tunnel_name) + vxlan_obj.remove_evpn_nvo(dvs, 'nvo1') + time.sleep(2) + vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.remove_vrf(dvs, "Vrf-RED") + vxlan_obj.remove_vlan_member(dvs, "100", "Ethernet24") + vxlan_obj.remove_vlan(dvs, "100") + + +# Test 4 - Create and Delete remote endpoint and Test IPv6 route and overlay nexthop add and delete +# @pytest.mark.skip(reason="Starting Route Orch, VRF Orch to be merged") +# @pytest.mark.dev_sanity + def test_remote_ipv6_routes(self, dvs, testlog): + vxlan_obj = self.get_vxlan_obj() + helper = self.get_vxlan_helper() + + self.setup_db(dvs) + tunnel_name = 'tunnel_2' + map_name = 'map_1000_100' + vrf_map_name = 'evpn_map_1000_Vrf-RED' + vxlan_obj.fetch_exist_entries(dvs) + + print ("\n\nTesting IPv6 Route and Overlay Nexthop Add and Delete") + print ("\tCreate SIP Tunnel") + vxlan_obj.create_vlan1(dvs,"Vlan100") + vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.create_evpn_nvo(dvs, 'nvo1', tunnel_name) + + print ("\tCreate Vlan-VNI map and VRF-VNI map") + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + + print ("\tTesting VRF-VNI map in APP DB") + vxlan_obj.create_vrf(dvs, "Vrf-RED") + vxlan_obj.create_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED', '1000') + + vlanlist = ['100'] + vnilist = ['1000'] + + exp_attrs = [ + ("vni", "1000"), + ] + exp_attr = {} + for an in range(len(exp_attrs)): + exp_attr[exp_attrs[an][0]] = exp_attrs[an][1] + + print ("\tCheck VRF Table in APP DB") + helper.check_object(self.pdb, "VRF_TABLE", 'Vrf-RED', exp_attr) + + exp_attrs1 = [ + ("vni", "1000"), + ("vlan", "Vlan100"), + ] + exp_attr1 = {} + for an in range(len(exp_attrs1)): + exp_attr1[exp_attrs1[an][0]] = exp_attrs1[an][1] + + helper.check_object(self.pdb, "VXLAN_VRF_TABLE", "%s:%s" % (tunnel_name, vrf_map_name), exp_attr1) + + print ("\tTesting SIP Tunnel Creation") + vxlan_obj.check_vxlan_sip_tunnel(dvs, tunnel_name, '6.6.6.6', vlanlist, vnilist) + + print ("\tTesting Tunnel Vlan Map Entry") + vxlan_obj.check_vxlan_tunnel_map_entry(dvs, tunnel_name, vlanlist, vnilist) + + print ("\tTesting Tunnel Vrf Map Entry") + vxlan_obj.check_vxlan_tunnel_vrf_map_entry(dvs, tunnel_name, 'Vrf-RED', '1000') + + print ("\tTesting First remote endpoint creation to 7.7.7.7") + vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7', '1000') + + print ("\tTesting VLAN 100 extension") + vxlan_obj.check_vlan_extension_p2mp(dvs, '100', '6.6.6.6', '7.7.7.7') + + print ("\tTesting Second remote endpoint creation to 8.8.8.8") + vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8', '1000') + + print ("\tTesting VLAN 100 extension to 8.8.8.8 and 7.7.7.7") + vxlan_obj.check_vlan_extension_p2mp(dvs, '100', '6.6.6.6', '8.8.8.8') + vxlan_obj.check_vlan_extension_p2mp(dvs, '100', '6.6.6.6', '7.7.7.7') + + vxlan_obj.fetch_exist_entries(dvs) + print ("\tTesting VLAN 100 interface creation") + vxlan_obj.create_vlan_interface(dvs, "Vlan100", "Ethernet24", "Vrf-RED", "2001::8/64") + vxlan_obj.check_router_interface(dvs, 'Vrf-RED', vxlan_obj.vlan_id_map['100'], 2) + + print ("\tTest VRF IPv6 Route with Tunnel Nexthop Add") + vxlan_obj.fetch_exist_entries(dvs) + vxlan_obj.create_vrf_route(dvs, "2002::8/64", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') + vxlan_obj.check_vrf_routes(dvs, "2002::8/64", 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') + + print ("\tTest VRF IPv6 Route with Tunnel Nexthop Delete") + vxlan_obj.delete_vrf_route(dvs, "2002::8/64", 'Vrf-RED') + vxlan_obj.check_del_tunnel_nexthop(dvs, 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') + vxlan_obj.check_del_vrf_routes(dvs, "2002::8/64", 'Vrf-RED') + + print ("\n\nTesting IPv6 Route and Overlay Nexthop Update") + print ("\tTest VRF IPv6 Route with Tunnel Nexthop 7.7.7.7 Add") + vxlan_obj.fetch_exist_entries(dvs) + vxlan_obj.create_vrf_route(dvs, "2002::8/64", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') + vxlan_obj.check_vrf_routes(dvs, "2002::8/64", 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') + + print ("\tTest Tunnel Nexthop change from 7.7.7.7 to 8.8.8.8") + vxlan_obj.create_vrf_route(dvs, "2002::8/64", 'Vrf-RED', '8.8.8.8', "Vlan100", "00:22:22:22:22:22", '1000') + vxlan_obj.check_vrf_routes(dvs, "2002::8/64", 'Vrf-RED', '8.8.8.8', tunnel_name, "00:22:22:22:22:22", '1000', 1) + + print ("\tTest Previous Tunnel Nexthop 7.7.7.7 is removed") + vxlan_obj.check_del_tunnel_nexthop(dvs, 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') + + print ("\tTest VRF IPv6 Route and Tunnel Nexthop 8.8.8.8 Delete") + vxlan_obj.fetch_exist_entries(dvs) + vxlan_obj.delete_vrf_route(dvs, "2002::8/64", 'Vrf-RED') + vxlan_obj.check_del_tunnel_nexthop(dvs, 'Vrf-RED', '8.8.8.8', tunnel_name, "00:22:22:22:22:22", '1000') + vxlan_obj.check_del_vrf_routes(dvs, "2002::8/64", 'Vrf-RED') + + print ("\n\nTest VRF IPv6 Route with ECMP Tunnel Nexthop Add and delete") + vxlan_obj.fetch_exist_entries(dvs) + + ecmp_nexthop_attr = [ + ("nexthop", "7.7.7.7,8.8.8.8"), + ("ifname", "Vlan100,Vlan100"), + ("vni_label", "1000,1000"), + ("router_mac", "00:11:11:11:11:11,00:22:22:22:22:22"), + ] + + print ("\tTest VRF IPv6 Route with ECMP Tunnel Nexthop [7.7.7.7 , 8.8.8.8] Add") + vxlan_obj.create_vrf_route_ecmp(dvs, "2002::8/64", 'Vrf-RED', ecmp_nexthop_attr) + + nh_count = 2 + ecmp_nhid_list = vxlan_obj.check_vrf_routes_ecmp(dvs, "2002::8/64", 'Vrf-RED', tunnel_name, nh_count) + assert nh_count == len(ecmp_nhid_list) + vxlan_obj.check_add_tunnel_nexthop(dvs, ecmp_nhid_list[0], '7.7.7.7', tunnel_name, '00:11:11:11:11:11', '1000') + vxlan_obj.check_add_tunnel_nexthop(dvs, ecmp_nhid_list[1], '8.8.8.8', tunnel_name, '00:22:22:22:22:22', '1000') + + print ("\tTest VRF IPv6 Route with ECMP Tunnel Nexthop [7.7.7.7 , 8.8.8.8] Delete") + vxlan_obj.fetch_exist_entries(dvs) + vxlan_obj.delete_vrf_route(dvs, "2002::8/64", 'Vrf-RED') + helper.check_deleted_object(self.adb, vxlan_obj.ASIC_NEXT_HOP, ecmp_nhid_list[0]) + helper.check_deleted_object(self.adb, vxlan_obj.ASIC_NEXT_HOP, ecmp_nhid_list[1]) + + vxlan_obj.check_vrf_routes_ecmp_nexthop_grp_del(dvs, 2) + vxlan_obj.check_del_vrf_routes(dvs, "2002::8/64", 'Vrf-RED') + + print ("\n\nTest VRF IPv6 Route with Tunnel Nexthop update from non-ECMP to ECMP") + print ("\tTest VRF IPv6 Route with Tunnel Nexthop 7.7.7.7 Add") + vxlan_obj.fetch_exist_entries(dvs) + vxlan_obj.create_vrf_route(dvs, "2002::8/64", 'Vrf-RED', '7.7.7.7', "Vlan100", "00:11:11:11:11:11", '1000') + vxlan_obj.check_vrf_routes(dvs, "2002::8/64", 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') + + print ("\tTest VRF IPv4 Route with ECMP Tunnel Nexthop [7.7.7.7 , 8.8.8.8] Udpate") + ecmp_nexthop_attr = [ + ("nexthop", "7.7.7.7,8.8.8.8"), + ("ifname", "Vlan100,Vlan100"), + ("vni_label", "1000,1000"), + ("router_mac", "00:11:11:11:11:11,00:22:22:22:22:22"), + ] + + vxlan_obj.create_vrf_route_ecmp(dvs, "2002::8/64", 'Vrf-RED', ecmp_nexthop_attr) + + nh_count = 2 + ecmp_nhid_list = vxlan_obj.check_vrf_routes_ecmp(dvs, "2002::8/64", 'Vrf-RED', tunnel_name, nh_count, 1) + assert nh_count == len(ecmp_nhid_list) + vxlan_obj.check_add_tunnel_nexthop(dvs, ecmp_nhid_list[0], '7.7.7.7', tunnel_name, '00:11:11:11:11:11', '1000') + vxlan_obj.check_add_tunnel_nexthop(dvs, ecmp_nhid_list[1], '8.8.8.8', tunnel_name, '00:22:22:22:22:22', '1000') + + print ("\n\nTest VRF IPv6 Route with Tunnel Nexthop update from ECMP to non-ECMP") + print ("\tTest VRF IPv6 Route with Tunnel Nexthop 8.8.8.8 Update") + vxlan_obj.create_vrf_route(dvs, "2002::8/64", 'Vrf-RED', '8.8.8.8', "Vlan100", "00:22:22:22:22:22", '1000') + vxlan_obj.check_vrf_routes(dvs, "2002::8/64", 'Vrf-RED', '8.8.8.8', tunnel_name, "00:22:22:22:22:22", '1000', 1) + + print ("\tTest Tunnel Nexthop 7.7.7.7 is deleted") + vxlan_obj.check_del_tunnel_nexthop(dvs, 'Vrf-RED', '7.7.7.7', tunnel_name, "00:11:11:11:11:11", '1000') + + print ("\tTest Tunnel Nexthop ECMP Group is deleted") + vxlan_obj.check_vrf_routes_ecmp_nexthop_grp_del(dvs, 2) + + print ("\tTest VRF IPv6 Route with Tunnel Nexthop 8.8.8.8 Delete") + vxlan_obj.fetch_exist_entries(dvs) + vxlan_obj.delete_vrf_route(dvs, "2002::8/64", 'Vrf-RED') + + vxlan_obj.check_del_tunnel_nexthop(dvs, 'Vrf-RED', '8.8.8.8', tunnel_name, "00:22:22:22:22:22", '1000') + vxlan_obj.check_del_vrf_routes(dvs, "2002::8/64", 'Vrf-RED') + + print ("\n\nTest remote endpoint and SIP Tunnel Deletion ") + print ("\tTesting Tunnel Vrf Map Entry removal") + vxlan_obj.remove_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED') + vxlan_obj.check_vxlan_tunnel_vrf_map_entry_remove(dvs, tunnel_name, 'Vrf-RED', '1000') + + print ("\tTesting LastVlan removal and remote endpoint delete for 7.7.7.7") + vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7') + vxlan_obj.check_vlan_extension_delete_p2mp(dvs, '100', '6.6.6.6', '7.7.7.7') + + print ("\tTesting LastVlan removal and remote endpoint delete for 8.8.8.8") + vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8') + vxlan_obj.check_vlan_extension_delete_p2mp(dvs, '100', '6.6.6.6', '8.8.8.8') + + print ("\tTesting Vlan 100 interface delete") + vxlan_obj.delete_vlan_interface(dvs, "Vlan100", "2001::8/64") + vxlan_obj.check_del_router_interface(dvs, "Vlan100") + + print ("\tTesting Tunnel Map entry removal") + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.check_vxlan_tunnel_map_entry_delete(dvs, tunnel_name, vlanlist, vnilist) + + print ("\tTesting SIP Tunnel Deletion") + vxlan_obj.remove_vxlan_tunnel(dvs, tunnel_name) + vxlan_obj.remove_evpn_nvo(dvs, 'nvo1') + time.sleep(2) + vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.remove_vrf(dvs, "Vrf-RED") + vxlan_obj.remove_vlan_member(dvs, "100", "Ethernet24") + vxlan_obj.remove_vlan(dvs, "100") + + +# Add Dummy always-pass test at end as workaroud +# for issue when Flaky fail on final test it invokes module tear-down before retrying +def test_nonflaky_dummy(): + pass diff --git a/tests/test_evpn_tunnel.py b/tests/test_evpn_tunnel.py index c8a150595f60..d910dd9dedaf 100644 --- a/tests/test_evpn_tunnel.py +++ b/tests/test_evpn_tunnel.py @@ -1,535 +1,10 @@ -from swsscommon import swsscommon -import time import json import random import pytest from pprint import pprint +from evpn_tunnel import VxlanTunnel - -def create_entry(tbl, key, pairs): - fvs = swsscommon.FieldValuePairs(pairs) - tbl.set(key, fvs) - time.sleep(1) - -def create_entry_tbl(db, table, separator, key, pairs): - tbl = swsscommon.Table(db, table) - create_entry(tbl, key, pairs) - -def delete_entry_tbl(db, table, key): - tbl = swsscommon.Table(db, table) - tbl._del(key) - time.sleep(1) - -def create_entry_pst(db, table, separator, key, pairs): - tbl = swsscommon.ProducerStateTable(db, table) - create_entry(tbl, key, pairs) - -def delete_entry_pst(db, table, key): - tbl = swsscommon.ProducerStateTable(db, table) - tbl._del(key) - time.sleep(1) - -def how_many_entries_exist(db, table): - tbl = swsscommon.Table(db, table) - return len(tbl.getKeys()) - - -def entries(db, table): - tbl = swsscommon.Table(db, table) - return set(tbl.getKeys()) - -def get_exist_entries(dvs, table): - db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - tbl = swsscommon.Table(db, table) - return set(tbl.getKeys()) - - -def get_created_entry(db, table, existed_entries): - tbl = swsscommon.Table(db, table) - entries = set(tbl.getKeys()) - new_entries = list(entries - existed_entries) - assert len(new_entries) == 1, "Wrong number of created entries." - return new_entries[0] - -def get_created_entries(db, table, existed_entries, count): - tbl = swsscommon.Table(db, table) - entries = set(tbl.getKeys()) - new_entries = list(entries - existed_entries) - assert len(new_entries) == count, "Wrong number of created entries." - new_entries.sort() - return new_entries - -def get_default_vr_id(dvs): - db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - table = 'ASIC_STATE:SAI_OBJECT_TYPE_VIRTUAL_ROUTER' - tbl = swsscommon.Table(db, table) - keys = tbl.getKeys() - assert len(keys) == 1, "Wrong number of virtual routers found" - - return keys[0] - - -def check_object(db, table, key, expected_attributes): - tbl = swsscommon.Table(db, table) - keys = tbl.getKeys() - assert key in keys, "The desired key is not presented" - - status, fvs = tbl.get(key) - assert status, "Got an error when get a key" - - assert len(fvs) >= len(expected_attributes), "Incorrect attributes" - - attr_keys = {entry[0] for entry in fvs} - - for name, value in fvs: - if name in expected_attributes: - assert expected_attributes[name] == value, "Wrong value %s for the attribute %s = %s" % \ - (value, name, expected_attributes[name]) - -def get_key_with_attr(db, table, expected_attributes ): - tbl = swsscommon.Table(db, table) - keys = tbl.getKeys() - retkey = list() - #assert key in keys, "The desired key is not presented" - - for key in keys: - status, fvs = tbl.get(key) - assert status, "Got an error when get a key" - - assert len(fvs) >= len(expected_attributes), "Incorrect attributes" - - attr_keys = {entry[0] for entry in fvs} - - num_match = 0 - for name, value in fvs: - if name in expected_attributes: - if expected_attributes[name] == value: - num_match += 1 - if num_match == len(expected_attributes): - retkey.append(key) - - return retkey - - -def create_evpn_nvo(dvs, nvoname, tnl_name): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - attrs = [ - ("source_vtep", tnl_name), - ] - - # create the VXLAN tunnel Term entry in Config DB - create_entry_tbl( - conf_db, - "VXLAN_EVPN_NVO", '|', nvoname, - attrs, - ) - -def remove_evpn_nvo(dvs, nvoname): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - delete_entry_tbl(conf_db,"VXLAN_EVPN_NVO", nvoname,) - -def create_vxlan_tunnel(dvs, name, src_ip, dst_ip = '0.0.0.0', skip_dst_ip=True): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - attrs = [ - ("src_ip", src_ip), - ] - - if not skip_dst_ip: - attrs.append(("dst_ip", dst_ip)) - - # create the VXLAN tunnel Term entry in Config DB - create_entry_tbl( - conf_db, - "VXLAN_TUNNEL", '|', name, - attrs, - ) - -def create_vxlan_tunnel_map(dvs, tnl_name, map_name, vni_id, vlan_id): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - attrs = [ - ("vni", vni_id), - ("vlan", vlan_id), - ] - - # create the VXLAN tunnel Term entry in Config DB - create_entry_tbl( - conf_db, - "VXLAN_TUNNEL_MAP", '|', "%s|%s" % (tnl_name, map_name), - attrs, - ) - -def create_evpn_remote_vni(dvs, vlan_id, remote_vtep, vnid): - app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - create_entry_pst( - app_db, - "VXLAN_REMOTE_VNI_TABLE", ':', "%s:%s" % (vlan_id, remote_vtep), - [ - ("vni", vnid), - ], - ) - time.sleep(2) - -def remove_vxlan_tunnel(dvs, tnl_name): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - # create the VXLAN tunnel Term entry in Config DB - delete_entry_tbl( - conf_db, - "VXLAN_TUNNEL", tnl_name, - ) - -def remove_vxlan_tunnel_map(dvs, tnl_name, map_name,vni_id, vlan_id): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - attrs = [ - ("vni", vni_id), - ("vlan", vlan_id), - ] - - # create the VXLAN tunnel Term entry in Config DB - delete_entry_tbl( - conf_db, - "VXLAN_TUNNEL_MAP", "%s|%s" % (tnl_name, map_name), - ) - -def remove_evpn_remote_vni(dvs, vlan_id, remote_vtep ): - app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - delete_entry_pst( - app_db, - "VXLAN_REMOTE_VNI_TABLE", "%s:%s" % (vlan_id, remote_vtep), - ) - time.sleep(2) - -def create_vlan1(dvs, vlan_name): - conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) - - vlan_id = vlan_name[4:] - - # create vlan - create_entry_tbl( - conf_db, - "VLAN", '|', vlan_name, - [ - ("vlanid", vlan_id), - ], - ) - -loopback_id = 0 -def_vr_id = 0 -switch_mac = None - -class VxlanTunnel(object): - - ASIC_TUNNEL_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL" - ASIC_TUNNEL_MAP = "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP" - ASIC_TUNNEL_MAP_ENTRY = "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP_ENTRY" - ASIC_TUNNEL_TERM_ENTRY = "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_TERM_TABLE_ENTRY" - ASIC_BRIDGE_PORT = "ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT" - - tunnel_map_ids = set() - tunnel_map_entry_ids = set() - tunnel_ids = set() - tunnel_term_ids = set() - bridgeport_ids = set() - tunnel_map_map = {} - tunnel = {} - tunnel_appdb = {} - tunnel_term = {} - map_entry_map = {} - dip_tunnel_map = {} - dip_tun_state_map = {} - bridgeport_map = {} - vlan_id_map = {} - vlan_member_map = {} - - def fetch_exist_entries(self, dvs): - self.tunnel_ids = get_exist_entries(dvs, self.ASIC_TUNNEL_TABLE) - self.tunnel_map_ids = get_exist_entries(dvs, self.ASIC_TUNNEL_MAP) - self.tunnel_map_entry_ids = get_exist_entries(dvs, self.ASIC_TUNNEL_MAP_ENTRY) - self.tunnel_term_ids = get_exist_entries(dvs, self.ASIC_TUNNEL_TERM_ENTRY) - self.bridgeport_ids = get_exist_entries(dvs, self.ASIC_BRIDGE_PORT) - - def check_vxlan_tunnel_map_entry_delete(self, dvs, tunnel_name, vidlist, vnilist): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - tbl = swsscommon.Table(asic_db, self.ASIC_TUNNEL_MAP_ENTRY) - - for x in range(len(vidlist)): - status, fvs = tbl.get(self.map_entry_map[tunnel_name + vidlist[x]]) - assert status == False, "SIP Tunnel Map entry not deleted" - iplinkcmd = "ip link show type vxlan dev " + tunnel_name + "-" + vidlist[x] - (exitcode, out) = dvs.runcmd(iplinkcmd) - assert exitcode != 0, "Kernel device not deleted" - - def check_vxlan_tunnel_map_entry(self, dvs, tunnel_name, vidlist, vnidlist): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - tbl = swsscommon.Table(asic_db, self.ASIC_TUNNEL_MAP_ENTRY) - - expected_attributes_1 = { - 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE': 'SAI_TUNNEL_MAP_TYPE_VNI_TO_VLAN_ID', - 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP': self.tunnel_map_map[tunnel_name][0], - 'SAI_TUNNEL_MAP_ENTRY_ATTR_VLAN_ID_VALUE': vidlist[0], - 'SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_KEY': vnidlist[0], - } - - for x in range(len(vidlist)): - expected_attributes_1['SAI_TUNNEL_MAP_ENTRY_ATTR_VLAN_ID_VALUE'] = vidlist[x] - expected_attributes_1['SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_KEY'] = vnidlist[x] - ret = get_key_with_attr(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, expected_attributes_1) - assert len(ret) > 0, "SIP TunnelMap entry not created" - assert len(ret) == 1, "More than 1 SIP TunnMapEntry created" - self.map_entry_map[tunnel_name + vidlist[x]] = ret[0] - iplinkcmd = "ip link show type vxlan dev " + tunnel_name + "-" + vidlist[x] - (exitcode, out) = dvs.runcmd(iplinkcmd) - assert exitcode == 0, "Kernel device not created" - - - def check_vxlan_sip_tunnel_delete(self, dvs, tunnel_name): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - - tbl = swsscommon.Table(app_db, "VXLAN_TUNNEL_TABLE") - status, fvs = tbl.get(self.tunnel_appdb[tunnel_name]) - assert status == False, "SIP Tunnel entry not deleted from APP_DB" - - tbl = swsscommon.Table(asic_db, self.ASIC_TUNNEL_TERM_ENTRY) - status, fvs = tbl.get(self.tunnel_term[tunnel_name]) - assert status == False, "SIP Tunnel Term entry not deleted from ASIC_DB" - - tbl = swsscommon.Table(asic_db, self.ASIC_TUNNEL_TABLE) - status, fvs = tbl.get(self.tunnel[tunnel_name]) - assert status == False, "SIP Tunnel entry not deleted from ASIC_DB" - - tbl = swsscommon.Table(asic_db, self.ASIC_TUNNEL_MAP) - status, fvs = tbl.get(self.tunnel_map_map[tunnel_name][0]) - assert status == False, "SIP Tunnel mapper0 not deleted from ASIC_DB" - status, fvs = tbl.get(self.tunnel_map_map[tunnel_name][1]) - assert status == False, "SIP Tunnel mapper1 not deleted from ASIC_DB" - status, fvs = tbl.get(self.tunnel_map_map[tunnel_name][2]) - assert status == False, "SIP Tunnel mapper2 not deleted from ASIC_DB" - status, fvs = tbl.get(self.tunnel_map_map[tunnel_name][3]) - assert status == False, "SIP Tunnel mapper3 not deleted from ASIC_DB" - - def check_vxlan_sip_tunnel(self, dvs, tunnel_name, src_ip, vidlist, vnidlist, dst_ip = '0.0.0.0', skip_dst_ip = 'True'): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - - tunnel_map_id = get_created_entries(asic_db, self.ASIC_TUNNEL_MAP, self.tunnel_map_ids, 4) - tunnel_id = get_created_entry(asic_db, self.ASIC_TUNNEL_TABLE, self.tunnel_ids) - tunnel_term_id = get_created_entry(asic_db, self.ASIC_TUNNEL_TERM_ENTRY, self.tunnel_term_ids) - tunnel_map_entry_id = get_created_entries(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, self.tunnel_map_entry_ids, 3) - - # check that the vxlan tunnel termination are there - assert how_many_entries_exist(asic_db, self.ASIC_TUNNEL_MAP) == (len(self.tunnel_map_ids) + 4), "The TUNNEL_MAP wasn't created" - assert how_many_entries_exist(asic_db, self.ASIC_TUNNEL_MAP_ENTRY) == (len(self.tunnel_map_entry_ids) + 3), "The TUNNEL_MAP_ENTRY is created" - assert how_many_entries_exist(asic_db, self.ASIC_TUNNEL_TABLE) == (len(self.tunnel_ids) + 1), "The TUNNEL wasn't created" - assert how_many_entries_exist(asic_db, self.ASIC_TUNNEL_TERM_ENTRY) == (len(self.tunnel_term_ids) + 1), "The TUNNEL_TERM_TABLE_ENTRY wasm't created" - - check_object(asic_db, self.ASIC_TUNNEL_MAP, tunnel_map_id[2], - { - 'SAI_TUNNEL_MAP_ATTR_TYPE': 'SAI_TUNNEL_MAP_TYPE_VNI_TO_VIRTUAL_ROUTER_ID', - } - ) - - check_object(asic_db, self.ASIC_TUNNEL_MAP, tunnel_map_id[3], - { - 'SAI_TUNNEL_MAP_ATTR_TYPE': 'SAI_TUNNEL_MAP_TYPE_VIRTUAL_ROUTER_ID_TO_VNI', - } - ) - - decapstr = '2:' + tunnel_map_id[0] + ',' + tunnel_map_id[2] - encapstr = '2:' + tunnel_map_id[1] + ',' + tunnel_map_id[3] - #'SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE': loopback_id, - - check_object(asic_db, self.ASIC_TUNNEL_TABLE, tunnel_id, - { - 'SAI_TUNNEL_ATTR_TYPE': 'SAI_TUNNEL_TYPE_VXLAN', - 'SAI_TUNNEL_ATTR_DECAP_MAPPERS': decapstr, - 'SAI_TUNNEL_ATTR_ENCAP_MAPPERS': encapstr, - 'SAI_TUNNEL_ATTR_PEER_MODE': 'SAI_TUNNEL_PEER_MODE_P2MP', - 'SAI_TUNNEL_ATTR_ENCAP_SRC_IP': src_ip, - } - ) - - expected_attributes = { - 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TYPE': 'SAI_TUNNEL_TERM_TABLE_ENTRY_TYPE_P2MP', - 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_DST_IP': src_ip, - 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TUNNEL_TYPE': 'SAI_TUNNEL_TYPE_VXLAN', - 'SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_ACTION_TUNNEL_ID': tunnel_id, - } - - if not skip_dst_ip: - expected_attributes['SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_SRC_IP'] = dst_ip - expected_attributes['SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TYPE'] = 'SAI_TUNNEL_TERM_TABLE_ENTRY_TYPE_P2P' - - check_object(asic_db, self.ASIC_TUNNEL_TERM_ENTRY, tunnel_term_id, expected_attributes) - - expected_attributes_1 = { - 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE': 'SAI_TUNNEL_MAP_TYPE_VNI_TO_VLAN_ID', - 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP': tunnel_map_id[0], - 'SAI_TUNNEL_MAP_ENTRY_ATTR_VLAN_ID_VALUE': vidlist[0], - 'SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_KEY': vnidlist[0], - } - - for x in range(len(vidlist)): - expected_attributes_1['SAI_TUNNEL_MAP_ENTRY_ATTR_VLAN_ID_VALUE'] = vidlist[x] - expected_attributes_1['SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_KEY'] = vnidlist[x] - check_object(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, tunnel_map_entry_id[x], expected_attributes_1) - - expected_siptnl_attributes = { - 'src_ip': src_ip, - } - - if not skip_dst_ip: - expected_siptnl_attributes['dst_ip'] = dst_ip - - ret = get_key_with_attr(app_db, "VXLAN_TUNNEL_TABLE", expected_siptnl_attributes) - assert len(ret) > 0, "SIP Tunnel entry not created in APPDB" - assert len(ret) == 1, "More than 1 Tunn statetable entry created" - self.tunnel_appdb[tunnel_name] = ret[0] - - self.tunnel_map_ids.update(tunnel_map_id) - self.tunnel_ids.add(tunnel_id) - self.tunnel_term_ids.add(tunnel_term_id) - self.tunnel_map_map[tunnel_name] = tunnel_map_id - self.tunnel[tunnel_name] = tunnel_id - self.tunnel_term[tunnel_name] = tunnel_term_id - - def check_vxlan_dip_tunnel_delete(self, dvs, dip): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - state_db = swsscommon.DBConnector(swsscommon.STATE_DB, dvs.redis_sock, 0) - - tbl = swsscommon.Table(state_db, 'VXLAN_TUNNEL_TABLE') - status, fvs = tbl.get(self.dip_tun_state_map[dip]) - assert status == False, "State Table entry not deleted" - - tbl = swsscommon.Table(asic_db, self.ASIC_TUNNEL_TABLE) - status, fvs = tbl.get(self.dip_tunnel_map[dip]) - assert status == False, "Tunnel entry not deleted" - - tbl = swsscommon.Table(asic_db, self.ASIC_BRIDGE_PORT) - status, fvs = tbl.get(self.bridgeport_map[dip]) - assert status == False, "Tunnel bridgeport entry not deleted" - - def check_vxlan_dip_tunnel(self, dvs, vtep_name, src_ip, dip): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - state_db = swsscommon.DBConnector(swsscommon.STATE_DB, dvs.redis_sock, 0) - - expected_state_attributes = { - 'src_ip': src_ip, - 'dst_ip': dip, - 'tnl_src': 'EVPN', - } - - ret = get_key_with_attr(state_db, 'VXLAN_TUNNEL_TABLE', expected_state_attributes) - assert len(ret) > 0, "Tunnel Statetable entry not created" - assert len(ret) == 1, "More than 1 Tunn statetable entry created" - self.dip_tun_state_map[dip] = ret[0] - - - tunnel_map_id = self.tunnel_map_map[vtep_name] - - decapstr = '2:' + tunnel_map_id[0] + ',' + tunnel_map_id[2] - encapstr = '2:' + tunnel_map_id[1] + ',' + tunnel_map_id[3] - - print(decapstr) - print(encapstr) - - expected_tun_attributes = { - 'SAI_TUNNEL_ATTR_TYPE': 'SAI_TUNNEL_TYPE_VXLAN', - 'SAI_TUNNEL_ATTR_PEER_MODE': 'SAI_TUNNEL_PEER_MODE_P2P', - 'SAI_TUNNEL_ATTR_DECAP_MAPPERS': decapstr, - 'SAI_TUNNEL_ATTR_ENCAP_MAPPERS': encapstr, - 'SAI_TUNNEL_ATTR_ENCAP_SRC_IP': src_ip, - 'SAI_TUNNEL_ATTR_ENCAP_DST_IP': dip, - } - - ret = get_key_with_attr(asic_db, self.ASIC_TUNNEL_TABLE, expected_tun_attributes) - assert len(ret) > 0, "Tunnel entry not created" - assert len(ret) == 1, "More than 1 tunnel entry created" - - self.dip_tunnel_map[dip] = ret[0] - tunnel_id = ret[0] - - expected_bridgeport_attributes = { - 'SAI_BRIDGE_PORT_ATTR_TYPE': 'SAI_BRIDGE_PORT_TYPE_TUNNEL', - 'SAI_BRIDGE_PORT_ATTR_TUNNEL_ID': tunnel_id, - 'SAI_BRIDGE_PORT_ATTR_FDB_LEARNING_MODE': 'SAI_BRIDGE_PORT_FDB_LEARNING_MODE_DISABLE', - 'SAI_BRIDGE_PORT_ATTR_ADMIN_STATE': 'true', - } - - ret = get_key_with_attr(asic_db, self.ASIC_BRIDGE_PORT, expected_bridgeport_attributes) - assert len(ret) > 0, "Bridgeport entry not created" - assert len(ret) == 1, "More than 1 bridgeport entry created" - - self.bridgeport_map[dip] = ret[0] - - def check_vlan_extension_delete(self, dvs, vlan_name, dip): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - - tbl = swsscommon.Table(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_VLAN_MEMBER') - status, fvs = tbl.get(self.vlan_member_map[dip+vlan_name]) - assert status == False, "VLAN Member entry not deleted" - - def check_vlan_extension(self, dvs, vlan_name, dip): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - expected_vlan_attributes = { - 'SAI_VLAN_ATTR_VLAN_ID': vlan_name, - } - ret = get_key_with_attr(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_VLAN', expected_vlan_attributes) - assert len(ret) > 0, "VLAN entry not created" - assert len(ret) == 1, "More than 1 VLAN entry created" - - self.vlan_id_map[vlan_name] = ret[0] - - expected_vlan_member_attributes = { - 'SAI_VLAN_MEMBER_ATTR_VLAN_ID': self.vlan_id_map[vlan_name], - 'SAI_VLAN_MEMBER_ATTR_BRIDGE_PORT_ID': self.bridgeport_map[dip], - } - ret = get_key_with_attr(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_VLAN_MEMBER', expected_vlan_member_attributes) - assert len(ret) > 0, "VLAN Member not created" - assert len(ret) == 1, "More than 1 VLAN member created" - self.vlan_member_map[dip+vlan_name] = ret[0] - - def check_vxlan_tunnel_entry(self, dvs, tunnel_name, vnet_name, vni_id): - asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - - time.sleep(2) - - if (self.tunnel_map_map.get(tunnel_name) is None): - tunnel_map_id = get_created_entries(asic_db, self.ASIC_TUNNEL_MAP, self.tunnel_map_ids, 2) - else: - tunnel_map_id = self.tunnel_map_map[tunnel_name] - - tunnel_map_entry_id = get_created_entries(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, self.tunnel_map_entry_ids, 2) - - # check that the vxlan tunnel termination are there - assert how_many_entries_exist(asic_db, self.ASIC_TUNNEL_MAP_ENTRY) == (len(self.tunnel_map_entry_ids) + 2), "The TUNNEL_MAP_ENTRY is created too early" - - check_object(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, tunnel_map_entry_id[0], - { - 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE': 'SAI_TUNNEL_MAP_TYPE_VIRTUAL_ROUTER_ID_TO_VNI', - 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP': tunnel_map_id[1], - 'SAI_TUNNEL_MAP_ENTRY_ATTR_VIRTUAL_ROUTER_ID_KEY': self.vr_map[vnet_name].get('ing'), - 'SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_VALUE': vni_id, - } - ) - - check_object(asic_db, self.ASIC_TUNNEL_MAP_ENTRY, tunnel_map_entry_id[1], - { - 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE': 'SAI_TUNNEL_MAP_TYPE_VNI_TO_VIRTUAL_ROUTER_ID', - 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP': tunnel_map_id[0], - 'SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_KEY': vni_id, - 'SAI_TUNNEL_MAP_ENTRY_ATTR_VIRTUAL_ROUTER_ID_VALUE': self.vr_map[vnet_name].get('egr'), - } - ) - - self.tunnel_map_entry_ids.update(tunnel_map_entry_id) +DVS_ENV = ["fake_platform=broadcom"] class TestVxlanOrch(object): @@ -547,13 +22,13 @@ def test_p2mp_tunnel(self, dvs, testlog): vxlan_obj.fetch_exist_entries(dvs) - create_vlan1(dvs,"Vlan100") - create_vlan1(dvs,"Vlan101") - create_vlan1(dvs,"Vlan102") - create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') - create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') - create_vxlan_tunnel_map(dvs, tunnel_name, map_name_1, '1001', 'Vlan101') - create_vxlan_tunnel_map(dvs, tunnel_name, map_name_2, '1002', 'Vlan102') + vxlan_obj.create_vlan1(dvs,"Vlan100") + vxlan_obj.create_vlan1(dvs,"Vlan101") + vxlan_obj.create_vlan1(dvs,"Vlan102") + vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name_1, '1001', 'Vlan101') + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name_2, '1002', 'Vlan102') vlanlist = ['100', '101', '102'] vnilist = ['1000', '1001', '1002'] @@ -565,14 +40,14 @@ def test_p2mp_tunnel(self, dvs, testlog): vxlan_obj.check_vxlan_tunnel_map_entry(dvs, tunnel_name, vlanlist, vnilist) print("Testing Tunnel Map entry removal") - remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') - remove_vxlan_tunnel_map(dvs, tunnel_name, map_name_1, '1001', 'Vlan101') - remove_vxlan_tunnel_map(dvs, tunnel_name, map_name_2, '1002', 'Vlan102') + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name_1, '1001', 'Vlan101') + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name_2, '1002', 'Vlan102') vxlan_obj.check_vxlan_tunnel_map_entry_delete(dvs, tunnel_name, vlanlist, vnilist) print("Testing SIP Tunnel Deletion") - remove_vxlan_tunnel(dvs, tunnel_name) - vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name) + vxlan_obj.remove_vxlan_tunnel(dvs, tunnel_name) + vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name, '6.6.6.6') # Test 2 - DIP Tunnel Tests def test_p2p_tunnel(self, dvs, testlog): @@ -586,24 +61,24 @@ def test_p2p_tunnel(self, dvs, testlog): vnilist = ['1000', '1001', '1002'] vxlan_obj.fetch_exist_entries(dvs) - create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') - create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') - create_vxlan_tunnel_map(dvs, tunnel_name, map_name_1, '1001', 'Vlan101') - create_vxlan_tunnel_map(dvs, tunnel_name, map_name_2, '1002', 'Vlan102') + vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name_1, '1001', 'Vlan101') + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name_2, '1002', 'Vlan102') vxlan_obj.check_vxlan_sip_tunnel(dvs, tunnel_name, '6.6.6.6', vlanlist, vnilist) vxlan_obj.check_vxlan_tunnel_map_entry(dvs, tunnel_name, vlanlist, vnilist) - create_evpn_nvo(dvs, 'nvo1', tunnel_name) - create_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7', '1000') + vxlan_obj.create_evpn_nvo(dvs, 'nvo1', tunnel_name) + vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7', '1000') print("Testing DIP tunnel creation") vxlan_obj.check_vxlan_dip_tunnel(dvs, tunnel_name, '6.6.6.6', '7.7.7.7') print("Testing VLAN 100 extension") vxlan_obj.check_vlan_extension(dvs, '100', '7.7.7.7') - create_evpn_remote_vni(dvs, 'Vlan101', '7.7.7.7', '1001') - create_evpn_remote_vni(dvs, 'Vlan102', '7.7.7.7', '1002') + vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan101', '7.7.7.7', '1001') + vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan102', '7.7.7.7', '1002') print("Testing DIP tunnel not created again") vxlan_obj.check_vxlan_dip_tunnel(dvs, tunnel_name, '6.6.6.6', '7.7.7.7') @@ -615,7 +90,7 @@ def test_p2p_tunnel(self, dvs, testlog): vxlan_obj.check_vlan_extension(dvs, '102', '7.7.7.7') print("Testing another DIP tunnel to 8.8.8.8") - create_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8', '1000') + vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8', '1000') print("Testing DIP tunnel creation to 8.8.8.8") vxlan_obj.check_vxlan_dip_tunnel(dvs, tunnel_name, '6.6.6.6', '8.8.8.8') print("Testing VLAN 100 extension to 8.8.8.8 and 7.7.7.7") @@ -623,32 +98,32 @@ def test_p2p_tunnel(self, dvs, testlog): vxlan_obj.check_vlan_extension(dvs, '100', '7.7.7.7') print("Testing Vlan Extension removal") - remove_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7') - remove_evpn_remote_vni(dvs, 'Vlan101', '7.7.7.7') + vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7') + vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan101', '7.7.7.7') vxlan_obj.check_vlan_extension_delete(dvs, '100', '7.7.7.7') vxlan_obj.check_vlan_extension_delete(dvs, '101', '7.7.7.7') print("Testing DIP tunnel not deleted") vxlan_obj.check_vxlan_dip_tunnel(dvs, tunnel_name, '6.6.6.6', '7.7.7.7') print("Testing Last Vlan removal and DIP tunnel delete") - remove_evpn_remote_vni(dvs, 'Vlan102', '7.7.7.7') + vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan102', '7.7.7.7') vxlan_obj.check_vlan_extension_delete(dvs, '102', '7.7.7.7') vxlan_obj.check_vxlan_dip_tunnel_delete(dvs, '7.7.7.7') print("Testing Last Vlan removal and DIP tunnel delete for 8.8.8.8") - remove_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8') + vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8') vxlan_obj.check_vlan_extension_delete(dvs, '100', '8.8.8.8') vxlan_obj.check_vxlan_dip_tunnel_delete(dvs, '8.8.8.8') - remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') - remove_vxlan_tunnel_map(dvs, tunnel_name, map_name_1, '1001', 'Vlan101') - remove_vxlan_tunnel_map(dvs, tunnel_name, map_name_2, '1002', 'Vlan102') + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name_1, '1001', 'Vlan101') + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name_2, '1002', 'Vlan102') vxlan_obj.check_vxlan_tunnel_map_entry_delete(dvs, tunnel_name, vlanlist, vnilist) print("Testing SIP Tunnel Deletion") - remove_evpn_nvo(dvs, 'nvo1') - remove_vxlan_tunnel(dvs, tunnel_name) - vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name) + vxlan_obj.remove_evpn_nvo(dvs, 'nvo1') + vxlan_obj.remove_vxlan_tunnel(dvs, tunnel_name) + vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name, '6.6.6.6') # Test 3 - Create and Delete SIP Tunnel and Map entries @@ -662,13 +137,13 @@ def test_p2mp_tunnel_with_dip(self, dvs, testlog): vxlan_obj.fetch_exist_entries(dvs) - create_vlan1(dvs,"Vlan100") - create_vlan1(dvs,"Vlan101") - create_vlan1(dvs,"Vlan102") - create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6', '2.2.2.2', False) - create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') - create_vxlan_tunnel_map(dvs, tunnel_name, map_name_1, '1001', 'Vlan101') - create_vxlan_tunnel_map(dvs, tunnel_name, map_name_2, '1002', 'Vlan102') + vxlan_obj.create_vlan1(dvs,"Vlan100") + vxlan_obj.create_vlan1(dvs,"Vlan101") + vxlan_obj.create_vlan1(dvs,"Vlan102") + vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6', '2.2.2.2', False) + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name_1, '1001', 'Vlan101') + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name_2, '1002', 'Vlan102') vlanlist = ['100', '101', '102'] vnilist = ['1000', '1001', '1002'] @@ -680,11 +155,11 @@ def test_p2mp_tunnel_with_dip(self, dvs, testlog): vxlan_obj.check_vxlan_tunnel_map_entry(dvs, tunnel_name, vlanlist, vnilist) print("Testing Tunnel Map entry removal") - remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') - remove_vxlan_tunnel_map(dvs, tunnel_name, map_name_1, '1001', 'Vlan101') - remove_vxlan_tunnel_map(dvs, tunnel_name, map_name_2, '1002', 'Vlan102') + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name_1, '1001', 'Vlan101') + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name_2, '1002', 'Vlan102') vxlan_obj.check_vxlan_tunnel_map_entry_delete(dvs, tunnel_name, vlanlist, vnilist) print("Testing SIP Tunnel Deletion") - remove_vxlan_tunnel(dvs, tunnel_name) - vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name) + vxlan_obj.remove_vxlan_tunnel(dvs, tunnel_name) + vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name, '6.6.6.6') diff --git a/tests/test_evpn_tunnel_p2mp.py b/tests/test_evpn_tunnel_p2mp.py new file mode 100644 index 000000000000..e9463be94ae5 --- /dev/null +++ b/tests/test_evpn_tunnel_p2mp.py @@ -0,0 +1,113 @@ +from evpn_tunnel import VxlanTunnel + +DVS_ENV = ["fake_platform=mellanox"] + +class TestVxlanOrchP2MP(object): + + def get_vxlan_obj(self): + return VxlanTunnel() + +# Test 1 - Create and Delete SIP Tunnel and Map entries + def test_p2mp_tunnel(self, dvs, testlog): + vxlan_obj = self.get_vxlan_obj() + + tunnel_name = 'tunnel_1' + map_name = 'map_1000_100' + map_name_1 = 'map_1001_101' + map_name_2 = 'map_1002_102' + + vxlan_obj.fetch_exist_entries(dvs) + + vxlan_obj.create_vlan1(dvs,"Vlan100") + vxlan_obj.create_vlan1(dvs,"Vlan101") + vxlan_obj.create_vlan1(dvs,"Vlan102") + vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name_1, '1001', 'Vlan101') + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name_2, '1002', 'Vlan102') + + vlanlist = ['100', '101', '102'] + vnilist = ['1000', '1001', '1002'] + + print("Testing SIP Tunnel Creation") + vxlan_obj.check_vxlan_sip_tunnel(dvs, tunnel_name, '6.6.6.6', vlanlist, vnilist) + + print("Testing Tunnel Map Entry") + vxlan_obj.check_vxlan_tunnel_map_entry(dvs, tunnel_name, vlanlist, vnilist) + + print("Testing Tunnel Map entry removal") + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name_1, '1001', 'Vlan101') + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name_2, '1002', 'Vlan102') + vxlan_obj.check_vxlan_tunnel_map_entry_delete(dvs, tunnel_name, vlanlist, vnilist) + + print("Testing SIP Tunnel Deletion") + vxlan_obj.remove_vxlan_tunnel(dvs, tunnel_name) + vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name, '6.6.6.6') + +# Test 2 - Vlan extension Tests + def test_vlan_extension(self, dvs, testlog): + vxlan_obj = self.get_vxlan_obj() + + tunnel_name = 'tunnel_2' + map_name = 'map_1000_100' + map_name_1 = 'map_1001_101' + map_name_2 = 'map_1002_102' + vlanlist = ['100', '101', '102'] + vnilist = ['1000', '1001', '1002'] + + vxlan_obj.fetch_exist_entries(dvs) + vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name_1, '1001', 'Vlan101') + vxlan_obj.create_vxlan_tunnel_map(dvs, tunnel_name, map_name_2, '1002', 'Vlan102') + + vxlan_obj.check_vxlan_sip_tunnel(dvs, tunnel_name, '6.6.6.6', vlanlist, vnilist) + vxlan_obj.check_vxlan_tunnel_map_entry(dvs, tunnel_name, vlanlist, vnilist) + + vxlan_obj.create_evpn_nvo(dvs, 'nvo1', tunnel_name) + vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7', '1000') + + print("Testing VLAN 100 extension") + vxlan_obj.check_vlan_extension_p2mp(dvs, '100', '6.6.6.6', '7.7.7.7') + + vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan101', '7.7.7.7', '1001') + vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan102', '7.7.7.7', '1002') + + print("Testing VLAN 101 extension") + vxlan_obj.check_vlan_extension_p2mp(dvs, '101', '6.6.6.6', '7.7.7.7') + + print("Testing VLAN 102 extension") + vxlan_obj.check_vlan_extension_p2mp(dvs, '102', '6.6.6.6', '7.7.7.7') + + print("Testing another remote endpoint to 8.8.8.8") + vxlan_obj.create_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8', '1000') + print("Testing remote endpoint creation to 8.8.8.8") + + print("Testing VLAN 100 extension to 8.8.8.8 and 7.7.7.7") + vxlan_obj.check_vlan_extension_p2mp(dvs, '100', '6.6.6.6', '8.8.8.8') + vxlan_obj.check_vlan_extension_p2mp(dvs, '100', '6.6.6.6', '7.7.7.7') + + print("Testing Vlan Extension removal") + vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '7.7.7.7') + vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan101', '7.7.7.7') + vxlan_obj.check_vlan_extension_delete_p2mp(dvs, '100', '6.6.6.6', '7.7.7.7') + vxlan_obj.check_vlan_extension_delete_p2mp(dvs, '101', '6.6.6.6', '7.7.7.7') + + print("Testing Last Vlan removal and remote endpoint delete") + vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan102', '7.7.7.7') + vxlan_obj.check_vlan_extension_delete_p2mp(dvs, '102', '6.6.6.6', '7.7.7.7') + + print("Testing Last Vlan removal and remote endpoint delete for 8.8.8.8") + vxlan_obj.remove_evpn_remote_vni(dvs, 'Vlan100', '8.8.8.8') + vxlan_obj.check_vlan_extension_delete_p2mp(dvs, '100', '6.6.6.6', '8.8.8.8') + + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name, '1000', 'Vlan100') + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name_1, '1001', 'Vlan101') + vxlan_obj.remove_vxlan_tunnel_map(dvs, tunnel_name, map_name_2, '1002', 'Vlan102') + vxlan_obj.check_vxlan_tunnel_map_entry_delete(dvs, tunnel_name, vlanlist, vnilist) + + print("Testing SIP Tunnel Deletion") + vxlan_obj.remove_evpn_nvo(dvs, 'nvo1') + vxlan_obj.remove_vxlan_tunnel(dvs, tunnel_name) + vxlan_obj.check_vxlan_sip_tunnel_delete(dvs, tunnel_name, '6.6.6.6')