diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index 9cf75e82cb..84e7171c98 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -136,13 +136,20 @@ bool OrchDaemon::init() CoppOrch *copp_orch = new CoppOrch(m_applDb, APP_COPP_TABLE_NAME); TunnelDecapOrch *tunnel_decap_orch = new TunnelDecapOrch(m_applDb, APP_TUNNEL_DECAP_TABLE_NAME); - VxlanTunnelOrch *vxlan_tunnel_orch = new VxlanTunnelOrch(m_applDb, APP_VXLAN_TUNNEL_TABLE_NAME); + VxlanTunnelOrch *vxlan_tunnel_orch = new VxlanTunnelOrch(m_stateDb, m_applDb, APP_VXLAN_TUNNEL_TABLE_NAME); gDirectory.set(vxlan_tunnel_orch); VxlanTunnelMapOrch *vxlan_tunnel_map_orch = new VxlanTunnelMapOrch(m_applDb, APP_VXLAN_TUNNEL_MAP_TABLE_NAME); gDirectory.set(vxlan_tunnel_map_orch); 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); + + vector qos_tables = { CFG_TC_TO_QUEUE_MAP_TABLE_NAME, CFG_SCHEDULER_TABLE_NAME, @@ -275,7 +282,9 @@ bool OrchDaemon::init() m_orchList.push_back(chassis_frontend_orch); m_orchList.push_back(vrf_orch); 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); 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 d3ba42c4a0..6f00bf28f4 100644 --- a/orchagent/port.h +++ b/orchagent/port.h @@ -20,6 +20,8 @@ extern "C" { */ #define DEFAULT_MTU 1492 +#define VNID_NONE 0xFFFFFFFF + namespace swss { struct VlanMemberEntry @@ -46,6 +48,7 @@ class Port LOOPBACK, VLAN, LAG, + TUNNEL, SUBPORT, UNKNOWN } ; @@ -89,6 +92,7 @@ class Port sai_object_id_t m_hif_id = 0; sai_object_id_t m_lag_id = 0; sai_object_id_t m_lag_member_id = 0; + sai_object_id_t m_tunnel_id = 0; sai_object_id_t m_ingress_acl_table_group_id = 0; sai_object_id_t m_egress_acl_table_group_id = 0; vlan_members_t m_vlan_members; @@ -100,8 +104,10 @@ class Port std::vector m_queue_ids; std::vector m_priority_group_ids; sai_port_priority_flow_control_mode_t m_pfc_asym = SAI_PORT_PRIORITY_FLOW_CONTROL_MODE_COMBINED; - uint8_t m_pfc_bitmask = 0; - uint32_t m_nat_zone_id = 0; + uint8_t m_pfc_bitmask = 0; + uint32_t m_nat_zone_id = 0; + uint32_t m_vnid = VNID_NONE; + uint32_t m_fdb_count = 0; /* * Following two bit vectors are used to lock diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 0a6c3f4b4e..15cad5bc1f 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -3,6 +3,8 @@ #include "bufferorch.h" #include "neighorch.h" #include "gearboxutils.h" +#include "vxlanorch.h" +#include "directory.h" #include #include @@ -42,6 +44,7 @@ extern NeighOrch *gNeighOrch; extern CrmOrch *gCrmOrch; extern BufferOrch *gBufferOrch; extern FdbOrch *gFdbOrch; +extern Directory gDirectory; #define VLAN_PREFIX "Vlan" #define DEFAULT_VLAN_ID 1 @@ -1284,6 +1287,12 @@ bool PortsOrch::setPortPvid(Port &port, sai_uint32_t pvid) { SWSS_LOG_ENTER(); + if(port.m_type == Port::TUNNEL) + { + SWSS_LOG_ERROR("pvid setting for tunnel %s is not allowed", port.m_alias.c_str()); + return true; + } + if (port.m_rif_id) { SWSS_LOG_ERROR("pvid setting for router interface %s is not allowed", port.m_alias.c_str()); @@ -1348,6 +1357,11 @@ bool PortsOrch::setHostIntfsStripTag(Port &port, sai_hostif_vlan_tag_t strip) SWSS_LOG_ENTER(); vector portv; + if(port.m_type == Port::TUNNEL) + { + return true; + } + /* * Before SAI_HOSTIF_VLAN_TAG_ORIGINAL is supported by libsai from all asic vendors, * the VLAN tag on hostif is explicitly controlled with SAI_HOSTIF_VLAN_TAG_STRIP & @@ -1717,6 +1731,13 @@ void PortsOrch::updateDbPortOperStatus(const Port& port, sai_port_oper_status_t { SWSS_LOG_ENTER(); + if(port.m_type == Port::TUNNEL) + { + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); + tunnel_orch->updateDbTunnelOperStatus(port.m_alias, status); + return; + } + vector tuples; FieldValueTuple tuple("oper_status", oper_status_strings.at(status)); tuples.push_back(tuple); @@ -1809,7 +1830,7 @@ bool PortsOrch::initPort(const string &alias, const int index, const set &l /* Determine if the port has already been initialized before */ if (m_portList.find(alias) != m_portList.end() && m_portList[alias].m_port_id == id) { - SWSS_LOG_DEBUG("Port has already been initialized before alias:%s", alias.c_str()); + SWSS_LOG_INFO("Port has already been initialized before alias:%s", alias.c_str()); } else { @@ -1853,7 +1874,7 @@ bool PortsOrch::initPort(const string &alias, const int index, const set &l m_portList[alias].m_init = true; - SWSS_LOG_NOTICE("Initialized port %s", alias.c_str()); + SWSS_LOG_ERROR("Initialized port %s", alias.c_str()); } else { @@ -3333,26 +3354,46 @@ bool PortsOrch::addBridgePort(Port &port) sai_attribute_t attr; vector attrs; - attr.id = SAI_BRIDGE_PORT_ATTR_TYPE; - attr.value.s32 = SAI_BRIDGE_PORT_TYPE_PORT; - attrs.push_back(attr); - - attr.id = SAI_BRIDGE_PORT_ATTR_PORT_ID; if (port.m_type == Port::PHY) { + attr.id = SAI_BRIDGE_PORT_ATTR_TYPE; + attr.value.s32 = SAI_BRIDGE_PORT_TYPE_PORT; + attrs.push_back(attr); + + attr.id = SAI_BRIDGE_PORT_ATTR_PORT_ID; attr.value.oid = port.m_port_id; + attrs.push_back(attr); } else if (port.m_type == Port::LAG) { + attr.id = SAI_BRIDGE_PORT_ATTR_TYPE; + attr.value.s32 = SAI_BRIDGE_PORT_TYPE_PORT; + attrs.push_back(attr); + + attr.id = SAI_BRIDGE_PORT_ATTR_PORT_ID; attr.value.oid = port.m_lag_id; + attrs.push_back(attr); + } + else if (port.m_type == Port::TUNNEL) + { + attr.id = SAI_BRIDGE_PORT_ATTR_TYPE; + attr.value.s32 = SAI_BRIDGE_PORT_TYPE_TUNNEL; + attrs.push_back(attr); + + attr.id = SAI_BRIDGE_PORT_ATTR_TUNNEL_ID; + attr.value.oid = port.m_tunnel_id; + attrs.push_back(attr); + + attr.id = SAI_BRIDGE_PORT_ATTR_BRIDGE_ID; + attr.value.oid = m_default1QBridge; + attrs.push_back(attr); } else { - SWSS_LOG_ERROR("Failed to add bridge port %s to default 1Q bridge, invalid porty type %d", + SWSS_LOG_ERROR("Failed to add bridge port %s to default 1Q bridge, invalid port type %d", port.m_alias.c_str(), port.m_type); return false; } - attrs.push_back(attr); /* Create a bridge port with admin status set to UP */ attr.id = SAI_BRIDGE_PORT_ATTR_ADMIN_STATE; @@ -3522,6 +3563,14 @@ bool PortsOrch::removeVlan(Port vlan) return false; } + // Fail VLAN removal if there is a vnid associated + if (vlan.m_vnid != VNID_NONE) + { + SWSS_LOG_ERROR("VLAN-VNI mapping not yet removed. VLAN %s VNI %d", + vlan.m_alias.c_str(), vlan.m_vnid); + return false; + } + sai_status_t status = sai_vlan_api->remove_vlan(vlan.m_vlan_info.vlan_oid); if (status != SAI_STATUS_SUCCESS) { @@ -3660,6 +3709,14 @@ bool PortsOrch::removeVlanMember(Port &vlan, Port &port) return true; } +bool PortsOrch::isVlanMember(Port &vlan, Port &port) +{ + if (vlan.m_members.find(port.m_alias) == vlan.m_members.end()) + return false; + + return true; +} + bool PortsOrch::addLag(string lag_alias) { SWSS_LOG_ENTER(); @@ -3908,6 +3965,36 @@ bool PortsOrch::setDistributionOnLagMember(Port &lagMember, bool enableDistribut return true; } +bool PortsOrch::addTunnel(string tunnel_alias, sai_object_id_t tunnel_id, bool hwlearning) +{ + SWSS_LOG_ENTER(); + + Port tunnel(tunnel_alias, Port::TUNNEL); + tunnel.m_tunnel_id = tunnel_id; + if (hwlearning) + { + tunnel.m_learn_mode = "hardware"; + } + else + { + tunnel.m_learn_mode = "disable"; + } + m_portList[tunnel_alias] = tunnel; + + SWSS_LOG_INFO("addTunnel:: %" PRIx64, tunnel_id); + + return true; +} + +bool PortsOrch::removeTunnel(Port tunnel) +{ + SWSS_LOG_ENTER(); + + m_portList.erase(tunnel.m_alias); + + return true; +} + void PortsOrch::generateQueueMap() { if (m_isQueueMapGenerated) @@ -4116,6 +4203,11 @@ void PortsOrch::updatePortOperStatus(Port &port, sai_port_oper_status_t status) } port.m_oper_status = status; + if(port.m_type == Port::TUNNEL) + { + return; + } + bool isUp = status == SAI_PORT_OPER_STATUS_UP; if (port.m_type == Port::PHY) { diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index cff208399e..35e3af2627 100755 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -128,6 +128,15 @@ class PortsOrch : public Orch, public Subject void getLagMember(Port &lag, vector &portv); void updateChildPortsMtu(const Port &p, const uint32_t mtu); + bool addTunnel(string tunnel,sai_object_id_t, bool learning=true); + 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); + + private: unique_ptr m_counterTable; unique_ptr
m_counterLagTable; @@ -216,14 +225,10 @@ class PortsOrch : public Orch, public Subject bool addHostIntfs(Port &port, string alias, sai_object_id_t &host_intfs_id); bool setHostIntfsStripTag(Port &port, sai_hostif_vlan_tag_t strip); - bool addBridgePort(Port &port); - bool removeBridgePort(Port &port); bool setBridgePortLearnMode(Port &port, string learn_mode); bool addVlan(string vlan); bool removeVlan(Port vlan); - bool addVlanMember(Port &vlan, Port &port, string& tagging_mode); - bool removeVlanMember(Port &vlan, Port &port); bool addLag(string lag); bool removeLag(Port lag); @@ -278,6 +283,7 @@ class PortsOrch : public Orch, public Subject sai_acl_bind_point_type_t &sai_acl_bind_type); void initGearbox(); bool initGearboxPort(Port &port); + }; #endif /* SWSS_PORTSORCH_H */ diff --git a/orchagent/vxlanorch.cpp b/orchagent/vxlanorch.cpp index e385c64c20..c429925e5f 100644 --- a/orchagent/vxlanorch.cpp +++ b/orchagent/vxlanorch.cpp @@ -5,8 +5,6 @@ #include #include #include - - #include "sai.h" #include "macaddress.h" #include "ipaddress.h" @@ -15,6 +13,8 @@ #include "vxlanorch.h" #include "directory.h" #include "swssnet.h" +#include "warm_restart.h" +#include "tokenize.h" /* Global variables */ extern sai_object_id_t gSwitchId; @@ -75,6 +75,33 @@ static inline uint32_t tunnel_map_val (MAP_T map_t) return vxlanTunnelMapKeyVal.at(map_t).second; } +static inline MAP_T tunnel_map_type (tunnel_map_type_t type, bool isencap) +{ + if (isencap) + { + switch(type) + { + case TUNNEL_MAP_T_VLAN : return MAP_T::VLAN_ID_TO_VNI; + case TUNNEL_MAP_T_VIRTUAL_ROUTER: return MAP_T::VRID_TO_VNI; + case TUNNEL_MAP_T_BRIDGE: return MAP_T::BRIDGE_TO_VNI; + default: return MAP_T::MAP_TO_INVALID; + } + } + else + { + switch(type) + { + case TUNNEL_MAP_T_VLAN : return MAP_T::VNI_TO_VLAN_ID; + case TUNNEL_MAP_T_VIRTUAL_ROUTER: return MAP_T::VNI_TO_VRID; + case TUNNEL_MAP_T_BRIDGE: return MAP_T::VNI_TO_BRIDGE; + default: return MAP_T::MAP_TO_INVALID; + } + } +} + + +//------------------- SAI Interface functions --------------------------// + static sai_object_id_t create_tunnel_map(MAP_T map_t) { @@ -226,10 +253,11 @@ static sai_status_t create_nexthop_tunnel( // Create Tunnel static sai_object_id_t create_tunnel( - sai_object_id_t tunnel_encap_id, - sai_object_id_t tunnel_decap_id, + struct tunnel_ids_t* ids, sai_ip_address_t *src_ip, + sai_ip_address_t *dst_ip, sai_object_id_t underlay_rif, + bool p2p, sai_uint8_t encap_ttl=0) { sai_attribute_t attr; @@ -243,21 +271,42 @@ create_tunnel( attr.value.oid = underlay_rif; tunnel_attrs.push_back(attr); - sai_object_id_t decap_list[] = { tunnel_decap_id }; + sai_object_id_t map_list[TUNNEL_MAP_T_MAX_MAPPER+1]; + uint8_t num_map=0; + + for (int i=TUNNEL_MAP_T_VLAN;itunnel_decap_id[i] != SAI_NULL_OBJECT_ID) + { + map_list[num_map] = ids->tunnel_decap_id[i]; + SWSS_LOG_INFO("create_tunnel:maplist[%d]=0x%lx",num_map,map_list[num_map]); + num_map++; + } + } + attr.id = SAI_TUNNEL_ATTR_DECAP_MAPPERS; - attr.value.objlist.count = 1; - attr.value.objlist.list = decap_list; + attr.value.objlist.count = num_map; + attr.value.objlist.list = map_list; tunnel_attrs.push_back(attr); - if (tunnel_encap_id != SAI_NULL_OBJECT_ID) + sai_object_id_t emap_list[TUNNEL_MAP_T_MAX_MAPPER+1]; + uint8_t num_emap=0; + + for (int i=TUNNEL_MAP_T_VLAN;itunnel_encap_id[i] != SAI_NULL_OBJECT_ID) + { + emap_list[num_emap] = ids->tunnel_encap_id[i]; + SWSS_LOG_NOTICE("create_tunnel:encapmaplist[%d]=0x%lx",num_emap,emap_list[num_emap]); + num_emap++; + } } + attr.id = SAI_TUNNEL_ATTR_ENCAP_MAPPERS; + attr.value.objlist.count = num_emap; + attr.value.objlist.list = emap_list; + tunnel_attrs.push_back(attr); + // source ip if (src_ip != nullptr) { @@ -266,6 +315,23 @@ create_tunnel( tunnel_attrs.push_back(attr); } + // dest ip + if ((dst_ip != nullptr) && p2p) + { + attr.id = SAI_TUNNEL_ATTR_PEER_MODE; + attr.value.s32 = SAI_TUNNEL_PEER_MODE_P2P; + tunnel_attrs.push_back(attr); + attr.id = SAI_TUNNEL_ATTR_ENCAP_DST_IP; + attr.value.ipaddr = *dst_ip; + tunnel_attrs.push_back(attr); + } + else + { + attr.id = SAI_TUNNEL_ATTR_PEER_MODE; + attr.value.s32 = SAI_TUNNEL_PEER_MODE_P2MP; + tunnel_attrs.push_back(attr); + } + if (encap_ttl != 0) { attr.id = SAI_TUNNEL_ATTR_ENCAP_TTL_MODE; @@ -320,7 +386,7 @@ create_tunnel_termination( sai_attribute_t attr; std::vector tunnel_attrs; - if(dstip == nullptr) // It's P2MP tunnel + if (dstip == nullptr) // It's P2MP tunnel { attr.id = SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TYPE; attr.value.s32 = SAI_TUNNEL_TERM_TABLE_ENTRY_TYPE_P2MP; @@ -385,27 +451,65 @@ remove_tunnel_termination(sai_object_id_t term_table_id) } } +//------------------- VxlanTunnel Implementation --------------------------// + +VxlanTunnel::VxlanTunnel(string name, IpAddress srcIp, IpAddress dstIp, tunnel_creation_src_t src) + :tunnel_name_(name), src_ip_(srcIp), dst_ip_(dstIp), src_creation_(src) +{ + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); + + if (dstIp.isZero()) + { + tunnel_orch->addVTEP(this, srcIp); + vtep_ptr = NULL; + } + else if (src_creation_ == TNL_CREATION_SRC_EVPN) + { + vtep_ptr = tunnel_orch->getVTEP(srcIp); + tunnel_orch->addRemoveStateTableEntry(name,srcIp, dstIp, + src, true); + } +} + +VxlanTunnel::~VxlanTunnel() +{ + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); + tunnel_orch->addRemoveStateTableEntry(tunnel_name_,src_ip_, dst_ip_, + src_creation_, false); +} + bool VxlanTunnel::createTunnel(MAP_T encap, MAP_T decap, uint8_t encap_ttl) { try { sai_ip_address_t ips, ipd, *ip=nullptr; + uint8_t mapper_list = 0; swss::copy(ips, src_ip_); - ids_.tunnel_decap_id = SAI_NULL_OBJECT_ID; - ids_.tunnel_encap_id = SAI_NULL_OBJECT_ID; + // Only a single mapper type is created - if (decap != MAP_T::MAP_TO_INVALID) + if (decap == MAP_T::VNI_TO_BRIDGE) + { + TUNNELMAP_SET_BRIDGE(mapper_list); + } + else if (decap == MAP_T::VNI_TO_VLAN_ID) { - ids_.tunnel_decap_id = create_tunnel_map(decap); + TUNNELMAP_SET_VLAN(mapper_list); } + else + { + TUNNELMAP_SET_VRF(mapper_list); + } + + createMapperHw(mapper_list, (encap == MAP_T::MAP_TO_INVALID) ? + TUNNEL_MAP_USE_DECAP_ONLY: TUNNEL_MAP_USE_DEDICATED_ENCAP_DECAP); + if (encap != MAP_T::MAP_TO_INVALID) { - ids_.tunnel_encap_id = create_tunnel_map(encap); ip = &ips; } - ids_.tunnel_id = create_tunnel(ids_.tunnel_encap_id, ids_.tunnel_decap_id, ip, gUnderlayIfId, encap_ttl); + ids_.tunnel_id = create_tunnel(&ids_, ip, NULL, gUnderlayIfId, false, encap_ttl); ip = nullptr; if (!dst_ip_.isZero()) @@ -429,17 +533,17 @@ bool VxlanTunnel::createTunnel(MAP_T encap, MAP_T decap, uint8_t encap_ttl) return true; } -sai_object_id_t VxlanTunnel::addEncapMapperEntry(sai_object_id_t obj, uint32_t vni) +sai_object_id_t VxlanTunnel::addEncapMapperEntry(sai_object_id_t obj, uint32_t vni, tunnel_map_type_t type) { - const auto encap_id = getEncapMapId(); - const auto map_t = tunnel_map_.first; + const auto encap_id = getEncapMapId(type); + const auto map_t = tunnel_map_type(type,true); return create_tunnel_map_entry(map_t, encap_id, vni, 0, obj, true); } -sai_object_id_t VxlanTunnel::addDecapMapperEntry(sai_object_id_t obj, uint32_t vni) +sai_object_id_t VxlanTunnel::addDecapMapperEntry(sai_object_id_t obj, uint32_t vni, tunnel_map_type_t type) { - const auto decap_id = getDecapMapId(); - const auto map_t = tunnel_map_.second; + const auto decap_id = getDecapMapId(type); + const auto map_t = tunnel_map_type(type,false); return create_tunnel_map_entry(map_t, decap_id, vni, 0, obj); } @@ -458,19 +562,30 @@ std::pair VxlanTunnel::getMapperEntry(uint32_t return std::make_pair(SAI_NULL_OBJECT_ID, SAI_NULL_OBJECT_ID); } -void VxlanTunnel::updateNextHop(IpAddress& ipAddr, MacAddress macAddress, uint32_t vni, sai_object_id_t nh_id) +void VxlanTunnel::updateNextHop(IpAddress& ipAddr, MacAddress macAddress, + uint32_t vni, sai_object_id_t nh_id) { auto key = nh_key_t(ipAddr, macAddress, vni); + SWSS_LOG_INFO("Update NH tunnel for ip %s, mac %s, vni %d", + ipAddr.to_string().c_str(), macAddress.to_string().c_str(), vni); + auto it = nh_tunnels_.find(key); if (it == nh_tunnels_.end()) { nh_tunnels_[key] = {nh_id, 1}; return; + } + else + { + SWSS_LOG_INFO("Dup Update NH tunnel for ip %s, mac %s, vni %d", + ipAddr.to_string().c_str(), macAddress.to_string().c_str(), vni); } + } -sai_object_id_t VxlanTunnel::getNextHop(IpAddress& ipAddr, MacAddress macAddress, uint32_t vni) const +sai_object_id_t VxlanTunnel::getNextHop(IpAddress& ipAddr, + MacAddress macAddress, uint32_t vni) const { auto key = nh_key_t(ipAddr, macAddress, vni); @@ -487,12 +602,20 @@ void VxlanTunnel::incNextHopRefCount(IpAddress& ipAddr, MacAddress macAddress, u { auto key = nh_key_t(ipAddr, macAddress, vni); nh_tunnels_[key].ref_count ++; + SWSS_LOG_INFO("refcnt increment NH tunnel for ip %s, mac %s, vni %d, ref_count %d", + ipAddr.to_string().c_str(), macAddress.to_string().c_str(), vni, + nh_tunnels_[key].ref_count); + } void VxlanTunnel::decNextHopRefCount(IpAddress& ipAddr, MacAddress macAddress, uint32_t vni) { auto key = nh_key_t(ipAddr, macAddress, vni); nh_tunnels_[key].ref_count --; + SWSS_LOG_INFO("refcnt decrement NH tunnel for ip %s, mac %s, vni %d, ref_count %d", + ipAddr.to_string().c_str(), macAddress.to_string().c_str(), vni, + nh_tunnels_[key].ref_count); + } bool VxlanTunnel::removeNextHop(IpAddress& ipAddr, MacAddress macAddress, uint32_t vni) @@ -502,11 +625,14 @@ bool VxlanTunnel::removeNextHop(IpAddress& ipAddr, MacAddress macAddress, uint32 auto it = nh_tunnels_.find(key); if (it == nh_tunnels_.end()) { - SWSS_LOG_INFO("NH tunnel for '%s' doesn't exist", ipAddr.to_string().c_str()); + SWSS_LOG_INFO("remove NH tunnel for ip %s, mac %s, vni %d doesn't exist", + ipAddr.to_string().c_str(), macAddress.to_string().c_str(), vni); return false; } - SWSS_LOG_INFO("NH tunnel for ip '%s' ref_count '%d'", ipAddr.to_string().c_str(), nh_tunnels_[key].ref_count); + SWSS_LOG_INFO("remove NH tunnel for ip %s, mac %s, vni %d, ref_count %d", + ipAddr.to_string().c_str(), macAddress.to_string().c_str(), vni, + nh_tunnels_[key].ref_count); //Decrement ref count if already exists nh_tunnels_[key].ref_count --; @@ -515,6 +641,8 @@ bool VxlanTunnel::removeNextHop(IpAddress& ipAddr, MacAddress macAddress, uint32 { if (sai_next_hop_api->remove_next_hop(nh_tunnels_[key].nh_id) != SAI_STATUS_SUCCESS) { + SWSS_LOG_INFO("delete NH tunnel for ip '%s', mac '%s' vni %d failed", + ipAddr.to_string().c_str(), macAddress.to_string().c_str(), vni); string err_msg = "NH tunnel delete failed for " + ipAddr.to_string(); throw std::runtime_error(err_msg); } @@ -522,23 +650,528 @@ bool VxlanTunnel::removeNextHop(IpAddress& ipAddr, MacAddress macAddress, uint32 nh_tunnels_.erase(key); } - SWSS_LOG_INFO("NH tunnel for ip '%s', mac '%s' updated/deleted", - ipAddr.to_string().c_str(), macAddress.to_string().c_str()); + SWSS_LOG_INFO("NH tunnel for ip '%s', mac '%s' vni %d updated/deleted", + ipAddr.to_string().c_str(), macAddress.to_string().c_str(), vni); + + return true; +} + +bool VxlanTunnel::deleteMapperHw(uint8_t mapper_list, tunnel_map_use_t map_src) +{ + try + { + if (map_src == TUNNEL_MAP_USE_DEDICATED_ENCAP_DECAP) + { + if (IS_TUNNELMAP_SET_VLAN(mapper_list)) + { + remove_tunnel_map(ids_.tunnel_decap_id[TUNNEL_MAP_T_VLAN]); + remove_tunnel_map(ids_.tunnel_encap_id[TUNNEL_MAP_T_VLAN]); + } + + if (IS_TUNNELMAP_SET_VRF(mapper_list)) + { + remove_tunnel_map(ids_.tunnel_decap_id[TUNNEL_MAP_T_VIRTUAL_ROUTER]); + remove_tunnel_map(ids_.tunnel_encap_id[TUNNEL_MAP_T_VIRTUAL_ROUTER]); + } + + if (IS_TUNNELMAP_SET_BRIDGE(mapper_list)) + { + remove_tunnel_map(ids_.tunnel_decap_id[TUNNEL_MAP_T_BRIDGE]); + remove_tunnel_map(ids_.tunnel_encap_id[TUNNEL_MAP_T_BRIDGE]); + } + } + else if (map_src == TUNNEL_MAP_USE_COMMON_DECAP_DEDICATED_ENCAP) + { + if (IS_TUNNELMAP_SET_VLAN(mapper_list)) + { + remove_tunnel_map(ids_.tunnel_encap_id[TUNNEL_MAP_T_VLAN]); + } + + if (IS_TUNNELMAP_SET_VRF(mapper_list)) + { + remove_tunnel_map(ids_.tunnel_encap_id[TUNNEL_MAP_T_VIRTUAL_ROUTER]); + } + + if (IS_TUNNELMAP_SET_BRIDGE(mapper_list)) + { + remove_tunnel_map(ids_.tunnel_encap_id[TUNNEL_MAP_T_BRIDGE]); + } + } + else if (map_src == TUNNEL_MAP_USE_DECAP_ONLY) + { + if (IS_TUNNELMAP_SET_VLAN(mapper_list)) + { + remove_tunnel_map(ids_.tunnel_decap_id[TUNNEL_MAP_T_VLAN]); + } + + if (IS_TUNNELMAP_SET_VRF(mapper_list)) + { + remove_tunnel_map(ids_.tunnel_decap_id[TUNNEL_MAP_T_VIRTUAL_ROUTER]); + } + + if (IS_TUNNELMAP_SET_BRIDGE(mapper_list)) + { + remove_tunnel_map(ids_.tunnel_decap_id[TUNNEL_MAP_T_BRIDGE]); + } + } + } + + catch (const std::runtime_error& error) + { + SWSS_LOG_ERROR("Error deleting mapper %s: %s", tunnel_name_.c_str(), error.what()); + return false; + } + + return true; +} + +bool VxlanTunnel::createMapperHw(uint8_t mapper_list, tunnel_map_use_t map_src) +{ + try + { + for (int i=TUNNEL_MAP_T_VLAN; igetDecapMapId(TUNNEL_MAP_T_VLAN); + ids_.tunnel_encap_id[TUNNEL_MAP_T_VLAN] = create_tunnel_map(MAP_T::VLAN_ID_TO_VNI); + TUNNELMAP_SET_VLAN(encap_dedicated_mappers_); + } + + if (IS_TUNNELMAP_SET_VRF(mapper_list)) + { + ids_.tunnel_decap_id[TUNNEL_MAP_T_VIRTUAL_ROUTER] = vtep_ptr->getDecapMapId(TUNNEL_MAP_T_VIRTUAL_ROUTER); + ids_.tunnel_encap_id[TUNNEL_MAP_T_VIRTUAL_ROUTER] = create_tunnel_map(MAP_T::VRID_TO_VNI); + TUNNELMAP_SET_VRF(encap_dedicated_mappers_); + } + + if (IS_TUNNELMAP_SET_BRIDGE(mapper_list)) + { + ids_.tunnel_decap_id[TUNNEL_MAP_T_BRIDGE] = vtep_ptr->getDecapMapId(TUNNEL_MAP_T_BRIDGE); + ids_.tunnel_encap_id[TUNNEL_MAP_T_BRIDGE] = create_tunnel_map(MAP_T::BRIDGE_TO_VNI); + TUNNELMAP_SET_BRIDGE(encap_dedicated_mappers_); + } + } + else if (TUNNEL_MAP_USE_COMMON_ENCAP_DECAP == map_src) + { + if (IS_TUNNELMAP_SET_VLAN(mapper_list)) + { + ids_.tunnel_decap_id[TUNNEL_MAP_T_VLAN] = vtep_ptr->getDecapMapId(TUNNEL_MAP_T_VLAN); + ids_.tunnel_encap_id[TUNNEL_MAP_T_VLAN] = vtep_ptr->getEncapMapId(TUNNEL_MAP_T_VLAN); + } + + if (IS_TUNNELMAP_SET_VRF(mapper_list)) + { + ids_.tunnel_decap_id[TUNNEL_MAP_T_VIRTUAL_ROUTER] = vtep_ptr->getDecapMapId(TUNNEL_MAP_T_VIRTUAL_ROUTER); + ids_.tunnel_encap_id[TUNNEL_MAP_T_VIRTUAL_ROUTER] = vtep_ptr->getEncapMapId(TUNNEL_MAP_T_VIRTUAL_ROUTER); + } + + if (IS_TUNNELMAP_SET_BRIDGE(mapper_list)) + { + ids_.tunnel_decap_id[TUNNEL_MAP_T_BRIDGE] = vtep_ptr->getDecapMapId(TUNNEL_MAP_T_BRIDGE); + ids_.tunnel_encap_id[TUNNEL_MAP_T_BRIDGE] = vtep_ptr->getEncapMapId(TUNNEL_MAP_T_BRIDGE); + } + } + else if (TUNNEL_MAP_USE_DECAP_ONLY == map_src) + { + if (IS_TUNNELMAP_SET_VLAN(mapper_list)) + { + ids_.tunnel_decap_id[TUNNEL_MAP_T_VLAN] = create_tunnel_map(MAP_T::VNI_TO_VLAN_ID); + TUNNELMAP_SET_VLAN(decap_dedicated_mappers_); + } + + if (IS_TUNNELMAP_SET_VRF(mapper_list)) + { + ids_.tunnel_decap_id[TUNNEL_MAP_T_VIRTUAL_ROUTER] = create_tunnel_map(MAP_T::VNI_TO_VRID); + TUNNELMAP_SET_VRF(decap_dedicated_mappers_); + } + + if (IS_TUNNELMAP_SET_BRIDGE(mapper_list)) + { + ids_.tunnel_encap_id[TUNNEL_MAP_T_BRIDGE] = create_tunnel_map(MAP_T::BRIDGE_TO_VNI); + TUNNELMAP_SET_BRIDGE(decap_dedicated_mappers_); + } + } + } + + catch (const std::runtime_error& error) + { + SWSS_LOG_ERROR("Error creating tunnel %s: %s", tunnel_name_.c_str(), error.what()); + return false; + } + + return true; +} + +bool VxlanTunnel::deleteTunnelHw(uint8_t mapper_list, tunnel_map_use_t map_src, + bool with_term) +{ + try + { + if (with_term) + { + remove_tunnel_termination(ids_.tunnel_term_id); + } + + remove_tunnel_termination(ids_.tunnel_id); + deleteMapperHw(mapper_list, map_src); + } + + catch (const std::runtime_error& error) + { + SWSS_LOG_ERROR("Error deleting tunnel %s: %s", tunnel_name_.c_str(), error.what()); + return false; + } + + active_ = false; + + return true; +} + +//Creation of SAI Tunnel Object with multiple mapper types + +bool VxlanTunnel::createTunnelHw(uint8_t mapper_list, tunnel_map_use_t map_src, + bool with_term) +{ + bool p2p = false; + + try + { + sai_ip_address_t ips, ipd, *ip=nullptr; + swss::copy(ips, src_ip_); + + createMapperHw(mapper_list, map_src); + + ip = nullptr; + if (!dst_ip_.isZero()) + { + swss::copy(ipd, dst_ip_); + ip = &ipd; + p2p = (src_creation_ == TNL_CREATION_SRC_EVPN)? true:false; + SWSS_LOG_WARN("creation src = %d",src_creation_); + } + + ids_.tunnel_id = create_tunnel(&ids_, &ips, ip, gUnderlayIfId, p2p); + + if (with_term) + { + ids_.tunnel_term_id = create_tunnel_termination(ids_.tunnel_id, ips, + ip, gVirtualRouterId); + } + + active_ = true; + } + + catch (const std::runtime_error& error) + { + SWSS_LOG_ERROR("Error creating tunnel %s: %s", tunnel_name_.c_str(), error.what()); + return false; + } + + SWSS_LOG_INFO("Vxlan tunnel '%s' was created", tunnel_name_.c_str()); + return true; +} + +void VxlanTunnel::deletePendingSIPTunnel() +{ + if ((getDipTunnelCnt() == 0) && del_tnl_hw_pending) + { + uint8_t mapper_list=0; + + TUNNELMAP_SET_VLAN(mapper_list); + TUNNELMAP_SET_VRF(mapper_list); + deleteTunnelHw(mapper_list, TUNNEL_MAP_USE_DEDICATED_ENCAP_DECAP); + del_tnl_hw_pending = false; + SWSS_LOG_INFO("Removing SIP Tunnel HW which is pending"); + } + + return; +} + +int VxlanTunnel::getDipTunnelCnt() +{ + int ret; + + ret = (int)tnl_users_.size(); + return ret; +} + +void VxlanTunnel::increment_spurious_imr_add(const std::string remote_vtep) +{ + tunnel_refcnt_t tnl_refcnts; + + auto it = tnl_users_.find(remote_vtep); + if (it == tnl_users_.end()) + { + return ; + } + else + { + tnl_refcnts = it->second; + tnl_refcnts.spurious_add_imr_refcnt++; + tnl_users_[remote_vtep] = tnl_refcnts; + } +} + +void VxlanTunnel::increment_spurious_imr_del(const std::string remote_vtep) +{ + tunnel_refcnt_t tnl_refcnts; + + auto it = tnl_users_.find(remote_vtep); + if (it == tnl_users_.end()) + { + return ; + } + else + { + tnl_refcnts = it->second; + tnl_refcnts.spurious_del_imr_refcnt++; + tnl_users_[remote_vtep] = tnl_refcnts; + } +} + +int VxlanTunnel::getDipTunnelRefCnt(const std::string remote_vtep) +{ + tunnel_refcnt_t tnl_refcnts; + + auto it = tnl_users_.find(remote_vtep); + if (it == tnl_users_.end()) + { + return -1; + } + else + { + tnl_refcnts = it->second; + return (tnl_refcnts.imr_refcnt + tnl_refcnts.mac_refcnt + tnl_refcnts.ip_refcnt); + } +} + +int VxlanTunnel::getDipTunnelIMRRefCnt(const std::string remote_vtep) +{ + tunnel_refcnt_t tnl_refcnts; + + auto it = tnl_users_.find(remote_vtep); + if (it == tnl_users_.end()) + { + return -1; + } + else + { + tnl_refcnts = it->second; + return (tnl_refcnts.imr_refcnt); + } +} + +int VxlanTunnel::getDipTunnelIPRefCnt(const std::string remote_vtep) +{ + tunnel_refcnt_t tnl_refcnts; + + auto it = tnl_users_.find(remote_vtep); + if (it == tnl_users_.end()) + { + return -1; + } + else + { + tnl_refcnts = it->second; + return (tnl_refcnts.ip_refcnt); + } +} + +void VxlanTunnel::updateDipTunnelRefCnt(bool inc, tunnel_refcnt_t& tnl_refcnts, + tunnel_user_t usr) +{ + switch(usr) + { + case TUNNEL_USER_IMR: + { + if (inc) + { + tnl_refcnts.imr_refcnt++; + } + else + { + tnl_refcnts.imr_refcnt--; + } + + break; + } + case TUNNEL_USER_MAC: + { + if (inc) + { + tnl_refcnts.mac_refcnt++; + } + else + { + tnl_refcnts.mac_refcnt--; + } + + break; + } + case TUNNEL_USER_IP: + { + if (inc) + { + tnl_refcnts.ip_refcnt++; + } + else + { + tnl_refcnts.ip_refcnt--; + } + + break; + } + default : break; + } +} + +bool VxlanTunnel::createDynamicDIPTunnel(const std::string dip, tunnel_user_t usr) +{ + uint8_t mapper_list = 0; + tunnel_refcnt_t tnl_refcnts; + VxlanTunnel* dip_tunnel=NULL; + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); + string tunnel_name; + + auto it = tnl_users_.find(dip); + if (it == tnl_users_.end()) + { + tunnel_orch->getTunnelNameFromDIP(dip, tunnel_name); + auto dipaddr = IpAddress(dip); + dip_tunnel = (new VxlanTunnel(tunnel_name, src_ip_, dipaddr, TNL_CREATION_SRC_EVPN)); + tunnel_orch->addTunnel(tunnel_name,dip_tunnel); + + memset(&tnl_refcnts,0,sizeof(tunnel_refcnt_t)); + updateDipTunnelRefCnt(true,tnl_refcnts,usr); + tnl_users_[dip] = tnl_refcnts; + + TUNNELMAP_SET_VLAN(mapper_list); + TUNNELMAP_SET_VRF(mapper_list); + dip_tunnel->createTunnelHw(mapper_list,TUNNEL_MAP_USE_COMMON_ENCAP_DECAP, false); + SWSS_LOG_NOTICE("Created P2P Tunnel remote IP %s ", dip.c_str()); + } + else + { + tnl_refcnts = it->second; + updateDipTunnelRefCnt(true,tnl_refcnts,usr); + tnl_users_[dip] = tnl_refcnts; + } + + return true; +} + +bool VxlanTunnel::deleteDynamicDIPTunnel(const std::string dip, tunnel_user_t usr, + bool update_refcnt) +{ + uint8_t mapper_list = 0; + tunnel_refcnt_t tnl_refcnts; + VxlanTunnel* dip_tunnel = NULL; + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); + Port tunnelPort; + std::string tunnel_name; + + auto it = tnl_users_.find(dip); + if (it != tnl_users_.end()) + { + tnl_refcnts = it->second; + + if (update_refcnt) + { + updateDipTunnelRefCnt(false,tnl_refcnts,usr); + tnl_users_[dip] = tnl_refcnts; + } + + SWSS_LOG_INFO("diprefcnt = %d", + tnl_refcnts.imr_refcnt + tnl_refcnts.mac_refcnt + tnl_refcnts.ip_refcnt); + + if (tnl_refcnts.imr_refcnt + tnl_refcnts.mac_refcnt + tnl_refcnts.ip_refcnt) + { + return true; + } + + if (tunnel_orch->getTunnelPort(dip, tunnelPort)) + { + SWSS_LOG_NOTICE("DIP = %s Not deleting tunnel from HW as tunnelPort is not yet deleted. fdbcount = %d", + dip.c_str(),tunnelPort.m_fdb_count); + return true; + } + + tunnel_orch->getTunnelNameFromDIP(dip, tunnel_name); + dip_tunnel = tunnel_orch->getVxlanTunnel(tunnel_name); + if (!dip_tunnel) + { + SWSS_LOG_INFO("DIP Tunnel is NULL unexpected"); + return false; + } + + TUNNELMAP_SET_VLAN(mapper_list); + TUNNELMAP_SET_VRF(mapper_list); + dip_tunnel->deleteTunnelHw(mapper_list,TUNNEL_MAP_USE_COMMON_ENCAP_DECAP, false); + + tnl_users_.erase(dip); + + tunnel_orch->delTunnel(tunnel_name); + SWSS_LOG_NOTICE("P2P Tunnel deleted : %s", tunnel_name.c_str()); + } + else + { + SWSS_LOG_WARN("Unable to find dynamic tunnel for deletion"); + } return true; } +//------------------- VxlanTunnelOrch Implementation --------------------------// + sai_object_id_t -VxlanTunnelOrch::createNextHopTunnel(string tunnelName, IpAddress& ipAddr, MacAddress macAddress, uint32_t vni) +VxlanTunnelOrch::createNextHopTunnel(string tunnelName, IpAddress& ipAddr, + MacAddress macAddress, uint32_t vni) { SWSS_LOG_ENTER(); - if(!isTunnelExists(tunnelName)) + if (!isTunnelExists(tunnelName)) { SWSS_LOG_ERROR("Vxlan tunnel '%s' does not exists", tunnelName.c_str()); return SAI_NULL_OBJECT_ID; } + SWSS_LOG_NOTICE("NH tunnel create for %s, ip %s, mac %s, vni %d", + tunnelName.c_str(), ipAddr.to_string().c_str(), + macAddress.to_string().c_str(), vni); + auto tunnel_obj = getVxlanTunnel(tunnelName); sai_object_id_t nh_id, tunnel_id = tunnel_obj->getTunnelId(); @@ -576,7 +1209,11 @@ VxlanTunnelOrch::removeNextHopTunnel(string tunnelName, IpAddress& ipAddr, MacAd { SWSS_LOG_ENTER(); - if(!isTunnelExists(tunnelName)) + SWSS_LOG_NOTICE("NH tunnel remove for %s, ip %s, mac %s, vni %d", + tunnelName.c_str(), ipAddr.to_string().c_str(), + macAddress.to_string().c_str(), vni); + + if (!isTunnelExists(tunnelName)) { SWSS_LOG_ERROR("Vxlan tunnel '%s' does not exists", tunnelName.c_str()); return false; @@ -593,7 +1230,7 @@ bool VxlanTunnelOrch::createVxlanTunnelMap(string tunnelName, tunnel_map_type_t { SWSS_LOG_ENTER(); - if(!isTunnelExists(tunnelName)) + if (!isTunnelExists(tunnelName)) { SWSS_LOG_ERROR("Vxlan tunnel '%s' does not exists", tunnelName.c_str()); return false; @@ -613,6 +1250,8 @@ bool VxlanTunnelOrch::createVxlanTunnelMap(string tunnelName, tunnel_map_type_t } } + tunnel_obj->vlan_vrf_vni_count++; + try { /* @@ -641,7 +1280,7 @@ bool VxlanTunnelOrch::removeVxlanTunnelMap(string tunnelName, uint32_t vni) { SWSS_LOG_ENTER(); - if(!isTunnelExists(tunnelName)) + if (!isTunnelExists(tunnelName)) { SWSS_LOG_ERROR("Vxlan tunnel '%s' does not exists", tunnelName.c_str()); return false; @@ -675,6 +1314,35 @@ bool VxlanTunnelOrch::removeVxlanTunnelMap(string tunnelName, uint32_t vni) return false; } + // Update the map count and if this is the last mapping entry + // make SAI calls to delete the tunnel and tunnel termination objects. + + tunnel_obj->vlan_vrf_vni_count--; + if (tunnel_obj->vlan_vrf_vni_count == 0) + { + auto tunnel_term_id = vxlan_tunnel_table_[tunnelName].get()->getTunnelTermId(); + try + { + remove_tunnel_termination(tunnel_term_id); + } + catch(const std::runtime_error& error) + { + SWSS_LOG_ERROR("Error removing tunnel term entry. Tunnel: %s. Error: %s", tunnelName.c_str(), error.what()); + return false; + } + + auto tunnel_id = vxlan_tunnel_table_[tunnelName].get()->getTunnelId(); + try + { + remove_tunnel(tunnel_id); + } + catch(const std::runtime_error& error) + { + SWSS_LOG_ERROR("Error removing tunnel entry. Tunnel: %s. Error: %s", tunnelName.c_str(), error.what()); + return false; + } + } + SWSS_LOG_NOTICE("Vxlan map entry deleted for tunnel '%s' with vni '%d'", tunnelName.c_str(), vni); return true; } @@ -689,7 +1357,7 @@ bool VxlanTunnelOrch::addOperation(const Request& request) auto attr_names = request.getAttrFieldNames(); if (attr_names.count("dst_ip") == 0) { - if(src_ip.isV4()) { + if (src_ip.isV4()) { dst_ip = IpAddress("0.0.0.0"); } else { dst_ip = IpAddress("::"); @@ -698,22 +1366,21 @@ bool VxlanTunnelOrch::addOperation(const Request& request) else { dst_ip = request.getAttrIP("dst_ip"); - if((src_ip.isV4() && !dst_ip.isV4()) || + if ((src_ip.isV4() && !dst_ip.isV4()) || (!src_ip.isV4() && dst_ip.isV4())) { SWSS_LOG_ERROR("Format mismatch: 'src_ip' and 'dst_ip' must be of the same family"); return true; } } - const auto& tunnel_name = request.getKeyString(0); - if(isTunnelExists(tunnel_name)) + if (isTunnelExists(tunnel_name)) { SWSS_LOG_ERROR("Vxlan tunnel '%s' is already exists", tunnel_name.c_str()); return true; } - vxlan_tunnel_table_[tunnel_name] = std::unique_ptr(new VxlanTunnel(tunnel_name, src_ip, dst_ip)); + vxlan_tunnel_table_[tunnel_name] = std::unique_ptr(new VxlanTunnel(tunnel_name, src_ip, dst_ip, TNL_CREATION_SRC_CLI)); SWSS_LOG_NOTICE("Vxlan tunnel '%s' was added", tunnel_name.c_str()); return true; @@ -725,48 +1392,291 @@ bool VxlanTunnelOrch::delOperation(const Request& request) const auto& tunnel_name = request.getKeyString(0); - if(!isTunnelExists(tunnel_name)) + if (!isTunnelExists(tunnel_name)) { SWSS_LOG_ERROR("Vxlan tunnel '%s' doesn't exist", tunnel_name.c_str()); return true; } - auto tunnel_term_id = vxlan_tunnel_table_[tunnel_name].get()->getTunnelTermId(); - try + auto vtep_ptr = getVxlanTunnel(tunnel_name); + if (vtep_ptr && vtep_ptr->del_tnl_hw_pending) { - remove_tunnel_termination(tunnel_term_id); + SWSS_LOG_WARN("VTEP %s not deleted as hw delete is pending", tunnel_name.c_str()); + return false; } - catch(const std::runtime_error& error) + + vxlan_tunnel_table_.erase(tunnel_name); + + SWSS_LOG_NOTICE("Vxlan tunnel '%s' was removed", tunnel_name.c_str()); + + return true; +} + +bool VxlanTunnelOrch::addTunnelUser(const std::string remote_vtep, uint32_t vni_id, + uint32_t vlan, tunnel_user_t usr, + sai_object_id_t vrf_id) +{ + EvpnNvoOrch* evpn_orch = gDirectory.get(); + VxlanTunnel* dip_tunnel=NULL; + Port tunport; + string tunnel_name; + + if (TUNNEL_USER_MAC == usr) return true; + + auto vtep_ptr = evpn_orch->getEVPNVtep(); + + if (!vtep_ptr) { - SWSS_LOG_ERROR("Error removing tunnel term entry. Tunnel: %s. Error: %s", tunnel_name.c_str(), error.what()); + SWSS_LOG_WARN("Unable to find EVPN VTEP. user=%d remote_vtep=%s", + usr,remote_vtep.c_str()); return false; } - auto tunnel_id = vxlan_tunnel_table_[tunnel_name].get()->getTunnelId(); - try + if (!vtep_ptr->isActive()) { - remove_tunnel(tunnel_id); + SWSS_LOG_WARN("VTEP not yet active.user=%d remote_vtep=%s", + usr,remote_vtep.c_str()); + return false; } - catch(const std::runtime_error& error) + + 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)); + + if (!getTunnelPort(remote_vtep, tunport)) { - SWSS_LOG_ERROR("Error removing tunnel entry. Tunnel: %s. Error: %s", tunnel_name.c_str(), error.what()); - return false; + Port tunnelPort; + auto port_tunnel_name = getTunnelPortName(remote_vtep); + gPortsOrch->addTunnel(port_tunnel_name,dip_tunnel->getTunnelId(), false); + gPortsOrch->getPort(port_tunnel_name,tunnelPort); + gPortsOrch->addBridgePort(tunnelPort); } - vxlan_tunnel_table_.erase(tunnel_name); + return true; +} - SWSS_LOG_NOTICE("Vxlan tunnel '%s' was removed", tunnel_name.c_str()); +bool VxlanTunnelOrch::delTunnelUser(const std::string remote_vtep, uint32_t vni_id, + uint32_t vlan, tunnel_user_t usr, + sai_object_id_t vrf_id) +{ + 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) + { + SWSS_LOG_WARN("Unable to find VTEP. remote=%s vlan=%d usr=%d", + remote_vtep.c_str(), vlan, usr); + return true; + } + + Port tunnelPort; + gPortsOrch->getPort(port_tunnel_name,tunnelPort); + + if ((vtep_ptr->getDipTunnelRefCnt(remote_vtep) == 1) && + tunnelPort.m_fdb_count == 0) + { + bool ret; + + ret = gPortsOrch->removeBridgePort(tunnelPort); + if (!ret) + { + SWSS_LOG_ERROR("Remove Bridge port failed for remote = %s fdbcount = %d", + remote_vtep.c_str(), tunnelPort.m_fdb_count); + return true; + } + + gPortsOrch->removeTunnel(tunnelPort); + } + + vtep_ptr->deleteDynamicDIPTunnel(remote_vtep, usr); + SWSS_LOG_NOTICE("diprefcnt for remote %s = %d", + remote_vtep.c_str(), vtep_ptr->getDipTunnelRefCnt(remote_vtep)); + + vtep_ptr->deletePendingSIPTunnel(); return true; } +void VxlanTunnelOrch::deleteTunnelPort(Port &tunnelPort) +{ + bool ret; + EvpnNvoOrch* evpn_orch = gDirectory.get(); + std::string remote_vtep; + int refcnt; + + auto vtep_ptr = evpn_orch->getEVPNVtep(); + + if (!vtep_ptr) + { + SWSS_LOG_WARN("Unable to find VTEP. tunnelPort=%s",tunnelPort.m_alias.c_str()); + 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); + if (refcnt > 0) + { + SWSS_LOG_INFO("Tunnel bridge port not removed. remote = %s refcnt = %d", + remote_vtep.c_str(), refcnt); + return; + } + + // Remove Bridge port and Port objects for this DIP tunnel + ret = gPortsOrch->removeBridgePort(tunnelPort); + if (!ret) + { + SWSS_LOG_ERROR("Remove Bridge port failed for remote = %s fdbcount = %d", + remote_vtep.c_str(), tunnelPort.m_fdb_count); + return; + } + gPortsOrch->removeTunnel(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)); + + // 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 tunnelPortName = "Port_EVPN_" + remote_vtep; + return tunnelPortName; +} + +void VxlanTunnelOrch::getTunnelNameFromDIP(const string& dip, string& tunnel_name) +{ + tunnel_name = "EVPN_" + dip; + return; +} + +void VxlanTunnelOrch::getTunnelNameFromPort(string& tunnel_portname, string& tunnel_name) +{ + tunnel_name = tunnel_portname; + tunnel_name.erase(0, sizeof("Port_")-1); + + SWSS_LOG_DEBUG("tunnel name = %s",tunnel_name.c_str()); + + return; +} + +void VxlanTunnelOrch:: getTunnelDIPFromPort(Port& tunnelPort, string& remote_vtep) +{ + remote_vtep = tunnelPort.m_alias; + remote_vtep.erase(0,sizeof("Port_EVPN_")-1); +} + + +void VxlanTunnelOrch::updateDbTunnelOperStatus(string tunnel_portname, + sai_port_oper_status_t status) +{ + std::vector fvVector; + std::string tunnel_name; + + if (status == SAI_PORT_OPER_STATUS_UP) + { + fvVector.emplace_back("operstatus", "up"); + } + else + { + fvVector.emplace_back("operstatus", "down"); + } + + getTunnelNameFromPort(tunnel_portname, tunnel_name); + + m_stateVxlanTable.set(tunnel_name, fvVector); +} + +void VxlanTunnelOrch::addRemoveStateTableEntry(string tunnel_name, + IpAddress& sip, IpAddress& dip, + tunnel_creation_src_t src, bool add) + +{ + std::vector fvVector, tmpFvVector; + WarmStart::WarmStartState state; + + WarmStart::getWarmStartState("orchagent",state); + + if (add) + { + // Add tunnel entry only for non-warmboot case or WB with new tunnel coming up + // during WB + if ( (state != WarmStart::INITIALIZED) || + !m_stateVxlanTable.get(tunnel_name, tmpFvVector)) + { + fvVector.emplace_back("src_ip", (sip.to_string()).c_str()); + fvVector.emplace_back("dst_ip", (dip.to_string()).c_str()); + + if (src == TNL_CREATION_SRC_CLI) + { + fvVector.emplace_back("tnl_src", "CLI"); + } + else + { + fvVector.emplace_back("tnl_src", "EVPN"); + } + + fvVector.emplace_back("operstatus", "down"); + m_stateVxlanTable.set(tunnel_name, fvVector); + SWSS_LOG_INFO("adding tunnel %s during warmboot", tunnel_name.c_str()); + } + else + { + SWSS_LOG_NOTICE("Skip adding tunnel %s during warmboot", tunnel_name.c_str()); + } + } + else + { + m_stateVxlanTable.del(tunnel_name); + } +} + +bool VxlanTunnelOrch::getTunnelPort(const std::string& remote_vtep,Port& tunnelPort) +{ + auto port_tunnel_name = getTunnelPortName(remote_vtep); + + bool ret = gPortsOrch->getPort(port_tunnel_name,tunnelPort); + + SWSS_LOG_INFO("getTunnelPort and getPort return ret=%d name=%s", + ret,port_tunnel_name.c_str()); + + return ret; +} + +//------------------- VXLAN_TUNNEL_MAP Table --------------------------// + bool VxlanTunnelMapOrch::addOperation(const Request& request) { SWSS_LOG_ENTER(); - auto vlan_id = request.getAttrVlan("vlan"); + sai_vlan_id_t vlan_id = (sai_vlan_id_t)request.getAttrVlan("vlan"); Port tempPort; - if(!gPortsOrch->getVlanByVlanId(vlan_id, tempPort)) + + const auto full_tunnel_map_entry_name = request.getFullKey(); + SWSS_LOG_INFO("Full name = %s",full_tunnel_map_entry_name.c_str()); + + if (isTunnelMapExists(full_tunnel_map_entry_name)) + { + SWSS_LOG_ERROR("Vxlan tunnel map '%s' already exist", + full_tunnel_map_entry_name.c_str()); + return true; + } + + if (!gPortsOrch->getVlanByVlanId(vlan_id, tempPort)) { SWSS_LOG_WARN("Vxlan tunnel map vlan id doesn't exist: %d", vlan_id); return false; @@ -779,6 +1689,8 @@ bool VxlanTunnelMapOrch::addOperation(const Request& request) return true; } + tempPort.m_vnid = (uint32_t) vni_id; + auto tunnel_name = request.getKeyString(0); VxlanTunnelOrch* tunnel_orch = gDirectory.get(); if (!tunnel_orch->isTunnelExists(tunnel_name)) @@ -788,35 +1700,48 @@ bool VxlanTunnelMapOrch::addOperation(const Request& request) } auto tunnel_obj = tunnel_orch->getVxlanTunnel(tunnel_name); - if (!tunnel_obj->isActive()) + + // The hw delete is pending due to an earlier incomplete operation. + // process this add event when the deletion is complete. + if (tunnel_obj->del_tnl_hw_pending) { - //@Todo, currently only decap mapper is allowed - tunnel_obj->createTunnel(MAP_T::MAP_TO_INVALID, MAP_T::VNI_TO_VLAN_ID); + SWSS_LOG_WARN("Tunnel Mapper deletion is pending"); + return false; } - const auto full_tunnel_map_entry_name = request.getFullKey(); - if (isTunnelMapExists(full_tunnel_map_entry_name)) + if (!tunnel_obj->isActive()) { - SWSS_LOG_NOTICE("Vxlan tunnel map '%s' already exist", full_tunnel_map_entry_name.c_str()); - return true; + //@Todo, currently only decap mapper is allowed + //tunnel_obj->createTunnel(MAP_T::MAP_TO_INVALID, MAP_T::VNI_TO_VLAN_ID); + uint8_t mapper_list = 0; + TUNNELMAP_SET_VLAN(mapper_list); + TUNNELMAP_SET_VRF(mapper_list); + tunnel_obj->createTunnelHw(mapper_list,TUNNEL_MAP_USE_DEDICATED_ENCAP_DECAP); } - const auto tunnel_map_id = tunnel_obj->getDecapMapId(); + const auto tunnel_map_id = tunnel_obj->getDecapMapId(TUNNEL_MAP_T_VLAN); const auto tunnel_map_entry_name = request.getKeyString(1); + tunnel_obj->vlan_vrf_vni_count++; + SWSS_LOG_INFO("vni count increased to %d",tunnel_obj->vlan_vrf_vni_count); + try { auto tunnel_map_entry_id = create_tunnel_map_entry(MAP_T::VNI_TO_VLAN_ID, tunnel_map_id, vni_id, vlan_id); - vxlan_tunnel_map_table_[full_tunnel_map_entry_name] = tunnel_map_entry_id; + vxlan_tunnel_map_table_[full_tunnel_map_entry_name].map_entry_id = tunnel_map_entry_id; + vxlan_tunnel_map_table_[full_tunnel_map_entry_name].vlan_id = vlan_id; + vxlan_tunnel_map_table_[full_tunnel_map_entry_name].vni_id = vni_id; } catch(const std::runtime_error& error) { - SWSS_LOG_ERROR("Error adding tunnel map entry. Tunnel: %s. Entry: %s. Error: %s", + SWSS_LOG_WARN("Error adding tunnel map entry. Tunnel: %s. Entry: %s. Error: %s", tunnel_name.c_str(), tunnel_map_entry_name.c_str(), error.what()); return false; } + tunnel_orch->addVlanMappedToVni(vni_id, vlan_id); + SWSS_LOG_NOTICE("Vxlan tunnel map entry '%s' for tunnel '%s' was created", tunnel_map_entry_name.c_str(), tunnel_name.c_str()); @@ -827,6 +1752,7 @@ bool VxlanTunnelMapOrch::delOperation(const Request& request) { SWSS_LOG_ENTER(); + Port vlanPort; 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(); @@ -838,7 +1764,16 @@ bool VxlanTunnelMapOrch::delOperation(const Request& request) return true; } - auto tunnel_map_entry_id = vxlan_tunnel_map_table_[full_tunnel_map_entry_name]; + auto vlan_id = (sai_vlan_id_t) vxlan_tunnel_map_table_[full_tunnel_map_entry_name].vlan_id; + if (!gPortsOrch->getVlanByVlanId(vlan_id, vlanPort)) + { + SWSS_LOG_ERROR("Delete VLAN-VNI map.vlan id doesn't exist: %d", vlan_id); + return true; + } + + vlanPort.m_vnid = (uint32_t) VNID_NONE; + + auto tunnel_map_entry_id = vxlan_tunnel_map_table_[full_tunnel_map_entry_name].map_entry_id; try { remove_tunnel_map_entry(tunnel_map_entry_id); @@ -851,12 +1786,62 @@ 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()); + return false; + } + + auto tunnel_obj = tunnel_orch->getVxlanTunnel(tunnel_name); + tunnel_obj->vlan_vrf_vni_count--; + + SWSS_LOG_NOTICE("vni count = %d",tunnel_obj->vlan_vrf_vni_count); + + // Update the map count and if this is the last mapping entry + // make SAI calls to delete the tunnel and tunnel termination objects. + + if (tunnel_obj->vlan_vrf_vni_count == 0) + { + // If there are Dynamic DIP Tunnels referring to this SIP Tunnel + // then mark it as pending for delete. + if (tunnel_obj->getDipTunnelCnt() == 0) + { + uint8_t mapper_list=0; + TUNNELMAP_SET_VLAN(mapper_list); + TUNNELMAP_SET_VRF(mapper_list); + tunnel_obj->deleteTunnelHw(mapper_list, TUNNEL_MAP_USE_DEDICATED_ENCAP_DECAP); + } + else + { + tunnel_obj->del_tnl_hw_pending = true; + SWSS_LOG_WARN("Postponing the SIP Tunnel HW deletion DIP Tunnel count = %d", + tunnel_obj->getDipTunnelCnt()); + } + } + + vector map_entries = tokenize(tunnel_map_entry_name, '_'); + SWSS_LOG_INFO("Vxlan tunnel map '%s' size %ld", tunnel_map_entry_name.c_str(), + map_entries.size()); + if (map_entries.size() == 3) + { + SWSS_LOG_INFO("Vxlan tunnel map %s, %s, %s ", map_entries[0].c_str(), + map_entries[1].c_str(), + map_entries[2].c_str()); + uint32_t vni_id = static_cast(stoul(map_entries[1])); + if (vni_id) + { + tunnel_orch->delVlanMappedToVni(vni_id); + } + } SWSS_LOG_NOTICE("Vxlan tunnel map entry '%s' for tunnel '%s' was removed", tunnel_map_entry_name.c_str(), tunnel_name.c_str()); return true; } +//------------------- VXLAN_VRF_MAP Table --------------------------// + bool VxlanVrfMapOrch::addOperation(const Request& request) { SWSS_LOG_ENTER(); @@ -889,9 +1874,14 @@ bool VxlanVrfMapOrch::addOperation(const Request& request) string vrf_name = request.getAttrString("vrf"); VRFOrch* vrf_orch = gDirectory.get(); + SWSS_LOG_NOTICE("VRF VNI mapping '%s' update vrf %s, vni %d", + full_map_entry_name.c_str(), vrf_name.c_str(), vni_id); if (vrf_orch->isVRFexists(vrf_name)) { - tunnel_obj->createTunnel(MAP_T::VRID_TO_VNI, MAP_T::VNI_TO_VRID); + if (!tunnel_obj->isActive()) + { + tunnel_obj->createTunnel(MAP_T::VRID_TO_VNI, MAP_T::VNI_TO_VRID); + } vrf_id = vrf_orch->getVRFid(vrf_name); } else @@ -932,7 +1922,242 @@ bool VxlanVrfMapOrch::delOperation(const Request& request) { SWSS_LOG_ENTER(); - SWSS_LOG_ERROR("DEL operation is not implemented"); + VRFOrch* vrf_orch = gDirectory.get(); + const auto full_map_entry_name = request.getFullKey(); + + if (!isVrfMapExists(full_map_entry_name)) + { + SWSS_LOG_ERROR("VxlanVrfMapOrch Vxlan map '%s' do not exist", full_map_entry_name.c_str()); + return false; + } + + size_t pos = full_map_entry_name.find("Vrf"); + if (pos == string::npos) + { + SWSS_LOG_ERROR("VxlanVrfMapOrch no VRF in Vxlan map '%s'", full_map_entry_name.c_str()); + return false; + } + string vrf_name = full_map_entry_name.substr(pos); + + if (!vrf_orch->isVRFexists(vrf_name)) + { + SWSS_LOG_ERROR("VxlanVrfMapOrch VRF '%s' not present", vrf_name.c_str()); + return false; + } + SWSS_LOG_NOTICE("VxlanVrfMapOrch VRF VNI mapping '%s' remove vrf %s", full_map_entry_name.c_str(), vrf_name.c_str()); + vrf_map_entry_t entry; + try + { + /* + * Remove encap and decap mapper + */ + entry = vxlan_vrf_table_[full_map_entry_name]; + + SWSS_LOG_NOTICE("VxlanVrfMapOrch Vxlan tunnel VRF encap entry '%lx' decap entry '0x%lx'", + entry.encap_id, entry.decap_id); + + remove_tunnel_map_entry(entry.encap_id); + vrf_orch->decreaseVrfRefCount(vrf_name); + remove_tunnel_map_entry(entry.decap_id); + vrf_orch->decreaseVrfRefCount(vrf_name); + vxlan_vrf_table_.erase(full_map_entry_name); + vxlan_vrf_tunnel_.erase(vrf_name); + } + catch(const std::runtime_error& error) + { + SWSS_LOG_ERROR("VxlanVrfMapOrch Error removing tunnel map entry. Entry: %s. Error: %s", + full_map_entry_name.c_str(), error.what()); + return false; + } + + return true; +} + +//------------------- EVPN_REMOTE_VNI Table --------------------------// + +bool EvpnRemoteVniOrch::addOperation(const Request& request) +{ + SWSS_LOG_ENTER(); + + // Extract DIP and tunnel + auto remote_vtep = request.getKeyString(1); + + // Extract VLAN and VNI + auto vlan_name = request.getKeyString(0); + 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) + { + SWSS_LOG_ERROR("Vxlan tunnel map vni id is too big: %d", vni_id); + return true; + } + + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); + Port tunnelPort, vlanPort; + + if (!gPortsOrch->getVlanByVlanId(vlan_id, vlanPort)) + { + SWSS_LOG_WARN("Vxlan tunnel map vlan id doesn't exist: %d", vlan_id); + return false; + } + + if (tunnel_orch->getTunnelPort(remote_vtep,tunnelPort)) + { + SWSS_LOG_INFO("Vxlan tunnelPort exists: %s", remote_vtep.c_str()); + + if (gPortsOrch->isVlanMember(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", + remote_vtep.c_str(),vlan_id); + return true; + } + SWSS_LOG_WARN("tunnelPort %s already member of vid %d", + remote_vtep.c_str(),vlan_id); + vtep_ptr->increment_spurious_imr_add(remote_vtep); + return true; + } + } + + tunnel_orch->addTunnelUser(remote_vtep, vni_id, vlan_id, TUNNEL_USER_IMR); + + if (!tunnel_orch->getTunnelPort(remote_vtep,tunnelPort)) + { + SWSS_LOG_WARN("Vxlan tunnelPort doesn't exist: %s", remote_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); + + SWSS_LOG_INFO("remote_vtep=%s vni=%d vlanid=%d ", + remote_vtep.c_str(), vni_id, vlan_id); + + return true; +} + +bool EvpnRemoteVniOrch::delOperation(const Request& request) +{ + bool ret; + + SWSS_LOG_ENTER(); + + // Extract DIP and tunnel + auto remote_vtep = request.getKeyString(1); + + // Extract VLAN and VNI + auto vlan_name = request.getKeyString(0); + 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) + { + 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; + if (!gPortsOrch->getVlanByVlanId(vlan_id, vlanPort)) + { + SWSS_LOG_WARN("Vxlan tunnel map vlan id doesn't exist: %d", vlan_id); + return true; + } + + if (!tunnel_orch->getTunnelPort(remote_vtep,tunnelPort)) + { + SWSS_LOG_WARN("RemoteVniDel getTunnelPort Fails: %s", remote_vtep.c_str()); + return true; + } + + EvpnNvoOrch* evpn_orch = gDirectory.get(); + auto vtep_ptr = evpn_orch->getEVPNVtep(); + + if (!vtep_ptr) + { + SWSS_LOG_WARN("Remote VNI del: VTEP not found. remote=%s vid=%d", + remote_vtep.c_str(),vlan_id); + return true; + } + + if (!gPortsOrch->isVlanMember(vlanPort, tunnelPort)) + { + SWSS_LOG_WARN("marking it as spurious tunnelPort %s not a member of vid %d", + remote_vtep.c_str(), vlan_id); + vtep_ptr->increment_spurious_imr_del(remote_vtep); + return true; + } + + if (gPortsOrch->isVlanMember(vlanPort, tunnelPort)) + { + if (!gPortsOrch->removeVlanMember(vlanPort, tunnelPort)) + { + SWSS_LOG_WARN("RemoteVniDel remove vlan member fails: %s",remote_vtep.c_str()); + return true; + } + } + + SWSS_LOG_INFO("imrcount=%d fdbcount=%d ", + vtep_ptr->getDipTunnelIMRRefCnt(remote_vtep), + tunnelPort.m_fdb_count ); + + ret = tunnel_orch->delTunnelUser(remote_vtep, vni_id, vlan_id, TUNNEL_USER_IMR); + + SWSS_LOG_INFO("remote_vtep=%s vni=%d vlanid=%d ", + remote_vtep.c_str(), vni_id, vlan_id); + + + return ret; +} + +//------------------- EVPN_NVO Table --------------------------// + +bool EvpnNvoOrch::addOperation(const Request& request) +{ + SWSS_LOG_ENTER(); + + auto nvo_name = request.getKeyString(0); + auto vtep_name = request.getAttrString("source_vtep"); + + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); + + source_vtep_ptr = tunnel_orch->getVxlanTunnel(vtep_name); + + SWSS_LOG_INFO("evpnnvo: %s vtep : %s \n",nvo_name.c_str(), vtep_name.c_str()); return true; } + +bool EvpnNvoOrch::delOperation(const Request& request) +{ + SWSS_LOG_ENTER(); + + auto nvo_name = request.getKeyString(0); + + if (!source_vtep_ptr) + { + SWSS_LOG_WARN("NVO Delete failed as VTEP Ptr is NULL"); + return true; + } + + if (source_vtep_ptr->del_tnl_hw_pending) + { + SWSS_LOG_WARN("NVO not deleted as hw delete is pending"); + return false; + } + + source_vtep_ptr = NULL; + + SWSS_LOG_INFO("NVO: %s \n",nvo_name.c_str()); + + return true; +} + diff --git a/orchagent/vxlanorch.h b/orchagent/vxlanorch.h index 008175f92b..edc65d97fe 100644 --- a/orchagent/vxlanorch.h +++ b/orchagent/vxlanorch.h @@ -19,10 +19,40 @@ enum class MAP_T VNI_TO_BRIDGE }; +typedef enum +{ + TUNNEL_MAP_T_VLAN=0, + TUNNEL_MAP_T_BRIDGE, + TUNNEL_MAP_T_VIRTUAL_ROUTER, + TUNNEL_MAP_T_MAX_MAPPER, +} tunnel_map_type_t; + +#define TUNNELMAP_SET_VLAN(x) ((x)|= (1<> TunnelMapEntries; typedef std::unordered_map TunnelNHs; +typedef std::map TunnelUsers; class VxlanTunnel { public: - VxlanTunnel(string name, IpAddress srcIp, IpAddress dstIp) - :tunnel_name_(name), src_ip_(srcIp), dst_ip_(dstIp) { } + VxlanTunnel(string name, IpAddress srcIp, IpAddress dstIp, tunnel_creation_src_t src); + ~VxlanTunnel(); bool isActive() const { @@ -83,8 +138,10 @@ class VxlanTunnel } bool createTunnel(MAP_T encap, MAP_T decap, uint8_t encap_ttl=0); - sai_object_id_t addEncapMapperEntry(sai_object_id_t obj, uint32_t vni); - sai_object_id_t addDecapMapperEntry(sai_object_id_t obj, uint32_t vni); + sai_object_id_t addEncapMapperEntry(sai_object_id_t obj, uint32_t vni, + tunnel_map_type_t type=TUNNEL_MAP_T_VIRTUAL_ROUTER); + sai_object_id_t addDecapMapperEntry(sai_object_id_t obj, uint32_t vni, + tunnel_map_type_t type=TUNNEL_MAP_T_VIRTUAL_ROUTER); void insertMapperEntry(sai_object_id_t encap, sai_object_id_t decap, uint32_t vni); std::pair getMapperEntry(uint32_t vni); @@ -94,14 +151,19 @@ class VxlanTunnel return ids_.tunnel_id; } - sai_object_id_t getDecapMapId() const + sai_object_id_t getDecapMapId(tunnel_map_type_t type) const { - return ids_.tunnel_decap_id; + return ids_.tunnel_decap_id[type]; } - sai_object_id_t getEncapMapId() const + sai_object_id_t getEncapMapId(tunnel_map_type_t type) const { - return ids_.tunnel_encap_id; + return ids_.tunnel_encap_id[type]; + } + + string getTunnelName() const + { + return tunnel_name_; } sai_object_id_t getTunnelTermId() const @@ -117,11 +179,30 @@ class VxlanTunnel void incNextHopRefCount(IpAddress& ipAddr, MacAddress macAddress, uint32_t vni); void decNextHopRefCount(IpAddress& ipAddr, MacAddress macAddress, uint32_t vni); + bool deleteMapperHw(uint8_t mapper_list, tunnel_map_use_t map_src); + bool createMapperHw(uint8_t mapper_list, tunnel_map_use_t map_src); + bool createTunnelHw(uint8_t mapper_list, tunnel_map_use_t map_src, bool with_term = true); + bool deleteTunnelHw(uint8_t mapper_list, tunnel_map_use_t map_src, bool with_term = true); + void deletePendingSIPTunnel(); + void increment_spurious_imr_add(const std::string remote_vtep); + void increment_spurious_imr_del(const std::string remote_vtep); + void updateDipTunnelRefCnt(bool , tunnel_refcnt_t& , tunnel_user_t ); + // Total Routes using the DIP tunnel. + int getDipTunnelRefCnt(const std::string); + int getDipTunnelIMRRefCnt(const std::string); + int getDipTunnelIPRefCnt(const std::string); + // Total DIP tunnels associated with this SIP tunnel. + int getDipTunnelCnt(); + bool createDynamicDIPTunnel(const string dip, tunnel_user_t usr); + bool deleteDynamicDIPTunnel(const string dip, tunnel_user_t usr, bool update_refcnt = true); + uint32_t vlan_vrf_vni_count = 0; + bool del_tnl_hw_pending = false; + private: string tunnel_name_; bool active_ = false; - tunnel_ids_t ids_ = {0, 0, 0, 0}; + tunnel_ids_t ids_ = {{0}, {0}, 0, 0}; std::pair tunnel_map_ = { MAP_T::MAP_TO_INVALID, MAP_T::MAP_TO_INVALID }; TunnelMapEntries tunnel_map_entries_; @@ -129,6 +210,12 @@ class VxlanTunnel IpAddress src_ip_; IpAddress dst_ip_ = 0x0; + + TunnelUsers tnl_users_; + VxlanTunnel* vtep_ptr=NULL; + tunnel_creation_src_t src_creation_; + uint8_t encap_dedicated_mappers_ = 0; + uint8_t decap_dedicated_mappers_ = 0; }; const request_description_t vxlan_tunnel_request_description = { @@ -148,18 +235,17 @@ class VxlanTunnelRequest : public Request typedef std::unique_ptr VxlanTunnel_T; typedef std::map VxlanTunnelTable; - -typedef enum -{ - TUNNEL_MAP_T_VLAN, - TUNNEL_MAP_T_BRIDGE, - TUNNEL_MAP_T_VIRTUAL_ROUTER, -} tunnel_map_type_t; +typedef std::map VxlanVniVlanMapTable; +typedef std::map VTEPTable; class VxlanTunnelOrch : public Orch2 { public: - VxlanTunnelOrch(DBConnector *db, const std::string& tableName) : Orch2(db, tableName, request_) { } + VxlanTunnelOrch(DBConnector *statedb, DBConnector *db, const std::string& tableName) : + Orch2(db, tableName, request_), + m_stateVxlanTable(statedb, STATE_VXLAN_TUNNEL_TABLE_NAME) + {} + bool isTunnelExists(const std::string& tunnelName) const { @@ -171,6 +257,34 @@ class VxlanTunnelOrch : public Orch2 return vxlan_tunnel_table_.at(tunnelName).get(); } + bool addTunnel(const std::string tunnel_name,VxlanTunnel* tnlptr) + { + vxlan_tunnel_table_[tunnel_name] = (VxlanTunnel_T)tnlptr; + return true; + } + + bool delTunnel(const std::string tunnel_name) + { + vxlan_tunnel_table_.erase(tunnel_name); + return true; + } + + bool isVTEPExists(const IpAddress& sip) const + { + return vtep_table_.find(sip) != std::end(vtep_table_); + } + + VxlanTunnel* getVTEP(const IpAddress& sip) + { + return vtep_table_.at(sip); + } + + void addVTEP(VxlanTunnel* pvtep,const IpAddress& sip) + { + vtep_table_[sip] = pvtep; + } + + bool createVxlanTunnelMap(string tunnelName, tunnel_map_type_t mapType, uint32_t vni, sai_object_id_t encap, sai_object_id_t decap, uint8_t encap_ttl=0); @@ -182,12 +296,59 @@ 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 addTunnelUser(string remote_vtep, uint32_t vni_id, + uint32_t vlan, tunnel_user_t usr, + sai_object_id_t vrf_id=SAI_NULL_OBJECT_ID); + + bool delTunnelUser(string remote_vtep, uint32_t vni_id, + uint32_t vlan, tunnel_user_t usr, + sai_object_id_t vrf_id=SAI_NULL_OBJECT_ID); + + void deleteTunnelPort(Port &tunnelPort); + + void addRemoveStateTableEntry(const string, IpAddress&, IpAddress&, tunnel_creation_src_t, bool); + + std::string getTunnelPortName(const std::string& remote_vtep); + void getTunnelNameFromDIP(const string& dip, string& tunnel_name); + void getTunnelNameFromPort(string& tunnel_portname, string& tunnel_name); + void getTunnelDIPFromPort(Port& tunnelPort, string& remote_vtep); + void updateDbTunnelOperStatus(string tunnel_portname, + sai_port_oper_status_t status); + uint16_t getVlanMappedToVni(const uint32_t vni) + { + if (vxlan_vni_vlan_map_table_.find(vni) != std::end(vxlan_vni_vlan_map_table_)) + { + return vxlan_vni_vlan_map_table_.at(vni); + } + else + { + return 0; + } + } + + void addVlanMappedToVni(uint32_t vni, uint16_t vlan_id) + { + vxlan_vni_vlan_map_table_[vni] = vlan_id; + } + + void delVlanMappedToVni(uint32_t vni) + { + vxlan_vni_vlan_map_table_.erase(vni); + } + + + private: virtual bool addOperation(const Request& request); virtual bool delOperation(const Request& request); VxlanTunnelTable vxlan_tunnel_table_; VxlanTunnelRequest request_; + VxlanVniVlanMapTable vxlan_vni_vlan_map_table_; + VTEPTable vtep_table_; + Table m_stateVxlanTable; }; const request_description_t vxlan_tunnel_map_request_description = { @@ -199,7 +360,7 @@ const request_description_t vxlan_tunnel_map_request_description = { { "vni", "vlan" } }; -typedef std::map VxlanTunnelMapTable; +typedef std::map VxlanTunnelMapTable; class VxlanTunnelMapRequest : public Request { @@ -267,3 +428,66 @@ class VxlanVrfMapOrch : public Orch2 VxlanVrfTunnel vxlan_vrf_tunnel_; VxlanVrfRequest request_; }; + +//---------------- EVPN_REMOTE_VNI table --------------------- + +const request_description_t evpn_remote_vni_request_description = { + { REQ_T_STRING, REQ_T_STRING }, + { + { "vni", REQ_T_UINT }, + }, + { "vni" } +}; + +class EvpnRemoteVniRequest : public Request +{ +public: + EvpnRemoteVniRequest() : Request(evpn_remote_vni_request_description, ':') { } +}; + +class EvpnRemoteVniOrch : public Orch2 +{ +public: + EvpnRemoteVniOrch(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_; +}; + +//------------- EVPN_NVO Table ------------------------- + +const request_description_t evpn_nvo_request_description = { + { REQ_T_STRING}, + { + { "source_vtep", REQ_T_STRING }, + }, + { "source_vtep" } +}; + +class EvpnNvoRequest : public Request +{ +public: + EvpnNvoRequest() : Request(evpn_nvo_request_description, ':') { } +}; + +class EvpnNvoOrch : public Orch2 +{ +public: + EvpnNvoOrch(DBConnector *db, const std::string& tableName) : Orch2(db, tableName, request_) { } + + VxlanTunnel* getEVPNVtep() + { + return source_vtep_ptr; + } + +private: + virtual bool addOperation(const Request& request); + virtual bool delOperation(const Request& request); + + EvpnNvoRequest request_; + VxlanTunnel* source_vtep_ptr=NULL; +}; diff --git a/tests/test_vxlan_tunnel.py b/tests/test_vxlan_tunnel.py index eccffd6557..14fe28261f 100644 --- a/tests/test_vxlan_tunnel.py +++ b/tests/test_vxlan_tunnel.py @@ -40,6 +40,13 @@ def get_exist_entries(dvs, table): tbl = swsscommon.Table(db, table) return set(tbl.getKeys()) +def get_created_entry_mapid(db, table, existed_entries): + tbl = swsscommon.Table(db, table) + entries = set(tbl.getKeys()) + new_entries = list(entries - existed_entries) + new_entries.sort() + return new_entries + def get_created_entry(db, table, existed_entries): tbl = swsscommon.Table(db, table) entries = set(tbl.getKeys()) @@ -105,29 +112,35 @@ def create_vlan(dvs, vlan_name, vlan_ids): def check_vxlan_tunnel(dvs, src_ip, dst_ip, tunnel_map_ids, tunnel_map_entry_ids, tunnel_ids, tunnel_term_ids, lo_id): asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - tunnel_map_id = get_created_entry(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP", tunnel_map_ids) + tunnel_map_id = get_created_entry_mapid(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP", tunnel_map_ids) tunnel_id = get_created_entry(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL", tunnel_ids) tunnel_term_id = get_created_entry(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_TERM_TABLE_ENTRY", tunnel_term_ids) # check that the vxlan tunnel termination are there - assert how_many_entries_exist(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP") == (len(tunnel_map_ids) + 1), "The TUNNEL_MAP wasn't created" + assert how_many_entries_exist(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP") == (len(tunnel_map_ids) + 4), "The TUNNEL_MAP wasn't created" assert how_many_entries_exist(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP_ENTRY") == len(tunnel_map_entry_ids), "The TUNNEL_MAP_ENTRY is created too early" assert how_many_entries_exist(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL") == (len(tunnel_ids) + 1), "The TUNNEL wasn't created" assert how_many_entries_exist(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_TERM_TABLE_ENTRY") == (len(tunnel_term_ids) + 1), "The TUNNEL_TERM_TABLE_ENTRY wasm't created" default_vr_id = get_default_vr_id(asic_db) - check_object(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP", tunnel_map_id, + check_object(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP", tunnel_map_id[0], { 'SAI_TUNNEL_MAP_ATTR_TYPE': 'SAI_TUNNEL_MAP_TYPE_VNI_TO_VLAN_ID', } ) + decapstr = '2:' + tunnel_map_id[0] + ',' + tunnel_map_id[2] + encapstr = '2:' + tunnel_map_id[1] + ',' + tunnel_map_id[3] + check_object(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL", tunnel_id, { 'SAI_TUNNEL_ATTR_TYPE': 'SAI_TUNNEL_TYPE_VXLAN', 'SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE': lo_id, - 'SAI_TUNNEL_ATTR_DECAP_MAPPERS': '1:%s' % tunnel_map_id, + '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 } ) @@ -145,11 +158,11 @@ def check_vxlan_tunnel(dvs, src_ip, dst_ip, tunnel_map_ids, tunnel_map_entry_ids check_object(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_TERM_TABLE_ENTRY", tunnel_term_id, expected_attributes) - tunnel_map_ids.add(tunnel_map_id) + tunnel_map_ids.update(tunnel_map_id) tunnel_ids.add(tunnel_id) tunnel_term_ids.add(tunnel_term_id) - return tunnel_map_id + return tunnel_map_id[0] def create_vxlan_tunnel(dvs, name, src_ip, dst_ip, tunnel_map_ids, tunnel_map_entry_ids, tunnel_ids, tunnel_term_ids, lo_id, skip_dst_ip=False): @@ -199,9 +212,10 @@ def create_vxlan_tunnel_entry(dvs, tunnel_name, tunnel_map_entry_name, tunnel_ma ) if (tunnel_map_map.get(tunnel_name) is None): - tunnel_map_id = get_created_entry(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP", tunnel_map_ids) + tunnel_map_id = get_created_entry_mapid(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP", tunnel_map_ids) + vni_vlan_map_id = tunnel_map_id[0] else: - tunnel_map_id = tunnel_map_map[tunnel_name] + vni_vlan_map_id = tunnel_map_map[tunnel_name] tunnel_map_entry_id = get_created_entry(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP_ENTRY", tunnel_map_entry_ids) @@ -212,7 +226,7 @@ def create_vxlan_tunnel_entry(dvs, tunnel_name, tunnel_map_entry_name, tunnel_ma check_object(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP_ENTRY", tunnel_map_entry_id, { '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, + 'SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP': vni_vlan_map_id, 'SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_KEY': vni_id, 'SAI_TUNNEL_MAP_ENTRY_ATTR_VLAN_ID_VALUE': vlan_id, }