diff --git a/cfgmgr/vrfmgr.cpp b/cfgmgr/vrfmgr.cpp index 25ca1253e3..d9164f47c5 100644 --- a/cfgmgr/vrfmgr.cpp +++ b/cfgmgr/vrfmgr.cpp @@ -19,6 +19,7 @@ VrfMgr::VrfMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, con Orch(cfgDb, tableNames), m_appVrfTableProducer(appDb, APP_VRF_TABLE_NAME), m_appVnetTableProducer(appDb, APP_VNET_TABLE_NAME), + m_appVxlanVrfTableProducer(appDb, APP_VXLAN_VRF_TABLE_NAME), m_stateVrfTable(stateDb, STATE_VRF_TABLE_NAME), m_stateVrfObjectTable(stateDb, STATE_VRF_OBJECT_TABLE_NAME) { @@ -203,23 +204,40 @@ void VrfMgr::doTask(Consumer &consumer) string op = kfvOp(t); if (op == SET_COMMAND) { - if (!setLink(vrfName)) + if (consumer.getTableName() == CFG_VXLAN_EVPN_NVO_TABLE_NAME) { - SWSS_LOG_ERROR("Failed to create vrf netdev %s", vrfName.c_str()); - } - - vector fvVector; - fvVector.emplace_back("state", "ok"); - m_stateVrfTable.set(vrfName, fvVector); - - SWSS_LOG_NOTICE("Created vrf netdev %s", vrfName.c_str()); - if (consumer.getTableName() == CFG_VRF_TABLE_NAME) - { - m_appVrfTableProducer.set(vrfName, kfvFieldsValues(t)); + doVrfEvpnNvoAddTask(t); } else { - m_appVnetTableProducer.set(vrfName, kfvFieldsValues(t)); + if (!setLink(vrfName)) + { + SWSS_LOG_ERROR("Failed to create vrf netdev %s", vrfName.c_str()); + } + + bool status = true; + vector fvVector; + fvVector.emplace_back("state", "ok"); + m_stateVrfTable.set(vrfName, fvVector); + + SWSS_LOG_NOTICE("Created vrf netdev %s", vrfName.c_str()); + if (consumer.getTableName() == CFG_VRF_TABLE_NAME) + { + status = doVrfVxlanTableCreateTask (t); + if (status == false) + { + SWSS_LOG_ERROR("VRF VNI Map Config Failed"); + it = consumer.m_toSync.erase(it); + continue; + } + + m_appVrfTableProducer.set(vrfName, kfvFieldsValues(t)); + + } + else + { + m_appVnetTableProducer.set(vrfName, kfvFieldsValues(t)); + } } } else if (op == DEL_COMMAND) @@ -229,7 +247,11 @@ void VrfMgr::doTask(Consumer &consumer) * Now state VRF_TABLE|Vrf represent vrf exist in appDB, if it exist vrf device is always effective. * VRFOrch add/del state VRF_OBJECT_TABLE|Vrf to represent object existence. VNETOrch is not do so now. */ - if (consumer.getTableName() == CFG_VRF_TABLE_NAME) + if (consumer.getTableName() == CFG_VXLAN_EVPN_NVO_TABLE_NAME) + { + doVrfEvpnNvoDelTask (t); + } + else if (consumer.getTableName() == CFG_VRF_TABLE_NAME) { vector temp; @@ -242,6 +264,7 @@ void VrfMgr::doTask(Consumer &consumer) continue; } + doVrfVxlanTableRemoveTask (t); m_appVrfTableProducer.del(vrfName); m_stateVrfTable.del(vrfName); } @@ -258,9 +281,12 @@ void VrfMgr::doTask(Consumer &consumer) m_stateVrfTable.del(vrfName); } - if (!delLink(vrfName)) + if (consumer.getTableName() != CFG_VXLAN_EVPN_NVO_TABLE_NAME) { - SWSS_LOG_ERROR("Failed to remove vrf netdev %s", vrfName.c_str()); + if (!delLink(vrfName)) + { + SWSS_LOG_ERROR("Failed to remove vrf netdev %s", vrfName.c_str()); + } } SWSS_LOG_NOTICE("Removed vrf netdev %s", vrfName.c_str()); @@ -273,3 +299,187 @@ void VrfMgr::doTask(Consumer &consumer) it = consumer.m_toSync.erase(it); } } + +bool VrfMgr::doVrfEvpnNvoAddTask(const KeyOpFieldsValuesTuple & t) +{ + SWSS_LOG_ENTER(); + string tunnel_name = ""; + const vector& data = kfvFieldsValues(t); + for (auto idx : data) + { + const auto &field = fvField(idx); + const auto &value = fvValue(idx); + + if (field == "source_vtep") + { + tunnel_name = value; + } + } + + if (m_evpnVxlanTunnel.empty()) + { + m_evpnVxlanTunnel = tunnel_name; + VrfVxlanTableSync(true); + } + + SWSS_LOG_INFO("Added evpn nvo tunnel %s", m_evpnVxlanTunnel.c_str()); + return true; +} + +bool VrfMgr::doVrfEvpnNvoDelTask(const KeyOpFieldsValuesTuple & t) +{ + SWSS_LOG_ENTER(); + + if (!m_evpnVxlanTunnel.empty()) + { + VrfVxlanTableSync(false); + m_evpnVxlanTunnel = ""; + } + + SWSS_LOG_INFO("Removed evpn nvo tunnel %s", m_evpnVxlanTunnel.c_str()); + return true; +} + +bool VrfMgr::doVrfVxlanTableCreateTask(const KeyOpFieldsValuesTuple & t) +{ + SWSS_LOG_ENTER(); + + auto vrf_name = kfvKey(t); + uint32_t vni = 0, old_vni = 0; + string s_vni = ""; + bool add = true; + + const vector& data = kfvFieldsValues(t); + for (auto idx : data) + { + const auto &field = fvField(idx); + const auto &value = fvValue(idx); + + if (field == "vni") + { + s_vni = value; + vni = static_cast(stoul(value)); + } + } + + if (vni != 0) + { + for (auto itr : m_vrfVniMapTable) + { + if (vni == itr.second) + { + SWSS_LOG_ERROR(" vni %d is already mapped to vrf %s", vni, itr.first.c_str()); + return false; + } + } + } + + old_vni = getVRFmappedVNI(vrf_name); + SWSS_LOG_INFO("VRF VNI map update vrf %s, vni %d, old_vni %d", vrf_name.c_str(), vni, old_vni); + if (vni != old_vni) + { + if (vni == 0) + { + m_vrfVniMapTable.erase(vrf_name); + s_vni = to_string(old_vni); + add = false; + } + else + { + if (old_vni != 0) + { + SWSS_LOG_ERROR(" vrf %s is already mapped to vni %d", vrf_name.c_str(), old_vni); + return false; + } + m_vrfVniMapTable[vrf_name] = vni; + } + + } + + if ((vni == 0) && add) + { + return true; + } + + SWSS_LOG_INFO("VRF VNI map update vrf %s, s_vni %s, add %d", vrf_name.c_str(), s_vni.c_str(), add); + doVrfVxlanTableUpdate(vrf_name, s_vni, add); + return true; +} + +bool VrfMgr::doVrfVxlanTableRemoveTask(const KeyOpFieldsValuesTuple & t) +{ + SWSS_LOG_ENTER(); + + auto vrf_name = kfvKey(t); + uint32_t vni = 0; + string s_vni = ""; + + vni = getVRFmappedVNI(vrf_name); + SWSS_LOG_INFO("VRF VNI map remove vrf %s, vni %d", vrf_name.c_str(), vni); + if (vni != 0) + { + s_vni = to_string(vni); + doVrfVxlanTableUpdate(vrf_name, s_vni, false); + m_vrfVniMapTable.erase(vrf_name); + } + + return true; +} + +bool VrfMgr::doVrfVxlanTableUpdate(const string& vrf_name, const string& vni, bool add) +{ + SWSS_LOG_ENTER(); + string key; + + if (m_evpnVxlanTunnel.empty()) + { + SWSS_LOG_INFO("NVO Tunnel not present. vrf %s, vni %s, add %d", vrf_name.c_str(), vni.c_str(), add); + return false; + } + + key = m_evpnVxlanTunnel + ":" + "evpn_map_" + vni + "_" + vrf_name; + + std::vector fvVector; + FieldValueTuple v1("vni", vni); + FieldValueTuple v2("vrf", vrf_name); + fvVector.push_back(v1); + fvVector.push_back(v2); + + SWSS_LOG_INFO("VRF VNI map table update vrf %s, vni %s, add %d", vrf_name.c_str(), vni.c_str(), add); + if (add) + { + m_appVxlanVrfTableProducer.set(key, fvVector); + } + else + { + m_appVxlanVrfTableProducer.del(key); + } + + return true; +} + +void VrfMgr::VrfVxlanTableSync(bool add) +{ + SWSS_LOG_ENTER(); + string s_vni = ""; + + for (auto itr : m_vrfVniMapTable) + { + s_vni = to_string(itr.second); + SWSS_LOG_INFO("vrf %s, vni %s, add %d", (itr.first).c_str(), s_vni.c_str(), add); + doVrfVxlanTableUpdate(itr.first, s_vni, add); + } +} + +uint32_t VrfMgr::getVRFmappedVNI(const std::string& vrf_name) +{ + if (m_vrfVniMapTable.find(vrf_name) != std::end(m_vrfVniMapTable)) + { + return m_vrfVniMapTable.at(vrf_name); + } + else + { + return 0; + } +} + diff --git a/cfgmgr/vrfmgr.h b/cfgmgr/vrfmgr.h index f8da87d318..5e656813bb 100644 --- a/cfgmgr/vrfmgr.h +++ b/cfgmgr/vrfmgr.h @@ -12,11 +12,16 @@ using namespace std; namespace swss { +typedef std::unordered_map VRFNameVNIMapTable; + class VrfMgr : public Orch { public: VrfMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const std::vector &tableNames); using Orch::doTask; + std::string m_evpnVxlanTunnel; + + uint32_t getVRFmappedVNI(const std::string& vrf_name); private: bool delLink(const std::string& vrfName); @@ -25,13 +30,20 @@ class VrfMgr : public Orch void recycleTable(uint32_t table); uint32_t getFreeTable(void); void handleVnetConfigSet(KeyOpFieldsValuesTuple &t); + bool doVrfEvpnNvoAddTask(const KeyOpFieldsValuesTuple & t); + bool doVrfEvpnNvoDelTask(const KeyOpFieldsValuesTuple & t); + bool doVrfVxlanTableCreateTask(const KeyOpFieldsValuesTuple & t); + bool doVrfVxlanTableRemoveTask(const KeyOpFieldsValuesTuple & t); + bool doVrfVxlanTableUpdate(const string& vrf_name, const string& vni, bool add); + void VrfVxlanTableSync(bool add); void doTask(Consumer &consumer); std::map m_vrfTableMap; std::set m_freeTables; + VRFNameVNIMapTable m_vrfVniMapTable; Table m_stateVrfTable, m_stateVrfObjectTable; - ProducerStateTable m_appVrfTableProducer, m_appVnetTableProducer; + ProducerStateTable m_appVrfTableProducer, m_appVnetTableProducer, m_appVxlanVrfTableProducer; }; } diff --git a/cfgmgr/vrfmgrd.cpp b/cfgmgr/vrfmgrd.cpp index c81f7bdadd..2ecdf7968f 100644 --- a/cfgmgr/vrfmgrd.cpp +++ b/cfgmgr/vrfmgrd.cpp @@ -44,6 +44,7 @@ int main(int argc, char **argv) vector cfg_vrf_tables = { CFG_VRF_TABLE_NAME, CFG_VNET_TABLE_NAME, + CFG_VXLAN_EVPN_NVO_TABLE_NAME, }; DBConnector cfgDb("CONFIG_DB", 0); diff --git a/orchagent/mirrororch.cpp b/orchagent/mirrororch.cpp index 1abb522e21..b9656ba216 100644 --- a/orchagent/mirrororch.cpp +++ b/orchagent/mirrororch.cpp @@ -64,8 +64,9 @@ MirrorEntry::MirrorEntry(const string& platform) : greType = 0x88be; } + string alias = ""; nexthopInfo.prefix = IpPrefix("0.0.0.0/0"); - nexthopInfo.nexthop = NextHopKey("0.0.0.0", ""); + nexthopInfo.nexthop = NextHopKey("0.0.0.0", alias); } MirrorOrch::MirrorOrch(TableConnector stateDbConnector, TableConnector confDbConnector, @@ -1203,7 +1204,8 @@ void MirrorOrch::updateNextHop(const NextHopUpdate& update) } else { - session.nexthopInfo.nexthop = NextHopKey("0.0.0.0", ""); + string alias = ""; + session.nexthopInfo.nexthop = NextHopKey("0.0.0.0", alias); } // Update State DB Nexthop diff --git a/orchagent/neighorch.cpp b/orchagent/neighorch.cpp index c379035d02..a3ff4b197b 100644 --- a/orchagent/neighorch.cpp +++ b/orchagent/neighorch.cpp @@ -4,6 +4,7 @@ #include "swssnet.h" #include "crmorch.h" #include "routeorch.h" +#include "directory.h" extern sai_neighbor_api_t* sai_neighbor_api; extern sai_next_hop_api_t* sai_next_hop_api; @@ -12,6 +13,7 @@ extern PortsOrch *gPortsOrch; extern sai_object_id_t gSwitchId; extern CrmOrch *gCrmOrch; extern RouteOrch *gRouteOrch; +extern Directory gDirectory; extern FgNhgOrch *gFgNhgOrch; const int neighorch_pri = 30; @@ -337,6 +339,23 @@ bool NeighOrch::removeNextHop(const IpAddress &ipAddress, const string &alias) return true; } +bool NeighOrch::removeOverlayNextHop(const NextHopKey &nexthop) +{ + SWSS_LOG_ENTER(); + + assert(hasNextHop(nexthop)); + + if (m_syncdNextHops[nexthop].ref_count > 0) + { + SWSS_LOG_ERROR("Failed to remove still referenced next hop %s on %s", + nexthop.ip_address.to_string().c_str(), nexthop.alias.c_str()); + return false; + } + + m_syncdNextHops.erase(nexthop); + return true; +} + sai_object_id_t NeighOrch::getNextHopId(const NextHopKey &nexthop) { assert(hasNextHop(nexthop)); @@ -552,8 +571,8 @@ bool NeighOrch::addNeighbor(const NeighborEntry &neighborEntry, const MacAddress return false; } } - - SWSS_LOG_NOTICE("Created neighbor %s on %s", macAddress.to_string().c_str(), alias.c_str()); + SWSS_LOG_NOTICE("Created neighbor ip %s, %s on %s", ip_address.to_string().c_str(), + macAddress.to_string().c_str(), alias.c_str()); m_intfsOrch->increaseRouterIntfsRefCount(alias); if (neighbor_entry.ip_address.addr_family == SAI_IP_ADDR_FAMILY_IPV4) @@ -708,3 +727,73 @@ bool NeighOrch::removeNeighbor(const NeighborEntry &neighborEntry) return true; } + +sai_object_id_t NeighOrch::addTunnelNextHop(const NextHopKey& nh) +{ + SWSS_LOG_ENTER(); + sai_object_id_t nh_id = SAI_NULL_OBJECT_ID; + + EvpnNvoOrch* evpn_orch = gDirectory.get(); + auto vtep_ptr = evpn_orch->getEVPNVtep(); + + if(!vtep_ptr) + { + SWSS_LOG_ERROR("Add Tunnel next hop unable to find EVPN VTEP"); + return nh_id; + } + + auto tun_name = vtep_ptr->getTunnelName(); + + VxlanTunnelOrch* vxlan_orch = gDirectory.get(); + IpAddress tnl_dip = nh.ip_address; + nh_id = vxlan_orch->createNextHopTunnel(tun_name, tnl_dip, nh.mac_address, nh.vni); + + if (nh_id == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_ERROR("Failed to create Tunnel next hop %s, %s@%d@%s", tun_name.c_str(), nh.ip_address.to_string().c_str(), + nh.vni, nh.mac_address.to_string().c_str()); + return nh_id; + } + + SWSS_LOG_NOTICE("Created Tunnel next hop %s, %s@%d@%s", tun_name.c_str(), nh.ip_address.to_string().c_str(), + nh.vni, nh.mac_address.to_string().c_str()); + + NextHopEntry next_hop_entry; + next_hop_entry.next_hop_id = nh_id; + next_hop_entry.ref_count = 0; + next_hop_entry.nh_flags = 0; + m_syncdNextHops[nh] = next_hop_entry; + + return nh_id; +} + +bool NeighOrch::removeTunnelNextHop(const NextHopKey& nh) +{ + SWSS_LOG_ENTER(); + + EvpnNvoOrch* evpn_orch = gDirectory.get(); + auto vtep_ptr = evpn_orch->getEVPNVtep(); + + if(!vtep_ptr) + { + SWSS_LOG_ERROR("Remove Tunnel next hop unable to find EVPN VTEP"); + return false; + } + + auto tun_name = vtep_ptr->getTunnelName(); + + VxlanTunnelOrch* vxlan_orch = gDirectory.get(); + + IpAddress tnl_dip = nh.ip_address; + if (!vxlan_orch->removeNextHopTunnel(tun_name, tnl_dip, nh.mac_address, nh.vni)) + { + SWSS_LOG_ERROR("Failed to remove Tunnel next hop %s, %s@%d@%s", tun_name.c_str(), nh.ip_address.to_string().c_str(), + nh.vni, nh.mac_address.to_string().c_str()); + return false; + } + + SWSS_LOG_NOTICE("Removed Tunnel next hop %s, %s@%d@%s", tun_name.c_str(), nh.ip_address.to_string().c_str(), + nh.vni, nh.mac_address.to_string().c_str()); + return true; +} + diff --git a/orchagent/neighorch.h b/orchagent/neighorch.h index aa235bd55c..e7b57b7dca 100644 --- a/orchagent/neighorch.h +++ b/orchagent/neighorch.h @@ -52,9 +52,12 @@ class NeighOrch : public Orch, public Subject, public Observer bool getNeighborEntry(const NextHopKey&, NeighborEntry&, MacAddress&); bool getNeighborEntry(const IpAddress&, NeighborEntry&, MacAddress&); + sai_object_id_t addTunnelNextHop(const NextHopKey&); + bool removeTunnelNextHop(const NextHopKey&); + bool ifChangeInformNextHop(const string &, bool); bool isNextHopFlagSet(const NextHopKey &, const uint32_t); - + bool removeOverlayNextHop(const NextHopKey &); void update(SubjectType, void *); private: diff --git a/orchagent/nexthopgroupkey.h b/orchagent/nexthopgroupkey.h index aeeca8ba96..22e75de551 100644 --- a/orchagent/nexthopgroupkey.h +++ b/orchagent/nexthopgroupkey.h @@ -11,6 +11,7 @@ class NextHopGroupKey /* ip_string@if_alias separated by ',' */ NextHopGroupKey(const std::string &nexthops) { + m_overlay_nexthops = false; auto nhv = tokenize(nexthops, NHG_DELIMITER); for (const auto &nh : nhv) { @@ -18,6 +19,18 @@ class NextHopGroupKey } } + /* ip_string|if_alias|vni|router_mac separated by ',' */ + NextHopGroupKey(const std::string &nexthops, bool overlay_nh) + { + m_overlay_nexthops = true; + auto nhv = tokenize(nexthops, NHG_DELIMITER); + for (const auto &nh_str : nhv) + { + auto nh = NextHopKey(nh_str, overlay_nh); + m_nexthops.insert(nh); + } + } + inline const std::set &getNextHops() const { return m_nexthops; @@ -124,13 +137,21 @@ class NextHopGroupKey { nhs_str += NHG_DELIMITER; } - - nhs_str += it->to_string(); + if (m_overlay_nexthops) { + nhs_str += it->to_string(m_overlay_nexthops); + } else { + nhs_str += it->to_string(); + } } return nhs_str; } + inline bool is_overlay_nexthop() const + { + return m_overlay_nexthops; + } + void clear() { m_nexthops.clear(); @@ -138,6 +159,7 @@ class NextHopGroupKey private: std::set m_nexthops; + bool m_overlay_nexthops; }; #endif /* SWSS_NEXTHOPGROUPKEY_H */ diff --git a/orchagent/nexthopkey.h b/orchagent/nexthopkey.h index 757436226b..69a94505ae 100644 --- a/orchagent/nexthopkey.h +++ b/orchagent/nexthopkey.h @@ -13,10 +13,12 @@ struct NextHopKey { IpAddress ip_address; // neighbor IP address string alias; // incoming interface alias + uint32_t vni; // Encap VNI overlay nexthop + MacAddress mac_address; // Overlay Nexthop MAC. NextHopKey() = default; - NextHopKey(const std::string &ipstr, const std::string &alias) : ip_address(ipstr), alias(alias) {} - NextHopKey(const IpAddress &ip, const std::string &alias) : ip_address(ip), alias(alias) {} + NextHopKey(const std::string &ipstr, const std::string &alias) : ip_address(ipstr), alias(alias), vni(0), mac_address() {} + NextHopKey(const IpAddress &ip, const std::string &alias) : ip_address(ip), alias(alias), vni(0), mac_address() {} NextHopKey(const std::string &str) { if (str.find(NHG_DELIMITER) != string::npos) @@ -25,6 +27,8 @@ struct NextHopKey throw std::invalid_argument(err); } auto keys = tokenize(str, NH_DELIMITER); + vni = 0; + mac_address = MacAddress(); if (keys.size() == 1) { ip_address = keys[0]; @@ -45,19 +49,44 @@ struct NextHopKey throw std::invalid_argument(err); } } + NextHopKey(const std::string &str, bool overlay_nh) + { + if (str.find(NHG_DELIMITER) != string::npos) + { + std::string err = "Error converting " + str + " to NextHop"; + throw std::invalid_argument(err); + } + auto keys = tokenize(str, NH_DELIMITER); + if (keys.size() != 4) + { + std::string err = "Error converting " + str + " to NextHop"; + throw std::invalid_argument(err); + } + ip_address = keys[0]; + alias = keys[1]; + vni = static_cast(std::stoul(keys[2])); + mac_address = keys[3]; + } + const std::string to_string() const { return ip_address.to_string() + NH_DELIMITER + alias; } + const std::string to_string(bool overlay_nh) const + { + std::string s_vni = std::to_string(vni); + return ip_address.to_string() + NH_DELIMITER + alias + NH_DELIMITER + s_vni + NH_DELIMITER + mac_address.to_string(); + } + bool operator<(const NextHopKey &o) const { - return tie(ip_address, alias) < tie(o.ip_address, o.alias); + return tie(ip_address, alias, vni, mac_address) < tie(o.ip_address, o.alias, o.vni, o.mac_address); } bool operator==(const NextHopKey &o) const { - return (ip_address == o.ip_address) && (alias == o.alias); + return (ip_address == o.ip_address) && (alias == o.alias) && (vni == o.vni) && (mac_address == o.mac_address); } bool operator!=(const NextHopKey &o) const diff --git a/orchagent/port.h b/orchagent/port.h index 6f00bf28f4..8462aca120 100644 --- a/orchagent/port.h +++ b/orchagent/port.h @@ -81,6 +81,7 @@ class Port bool m_autoneg = false; bool m_admin_state_up = false; bool m_init = false; + bool m_l3_vni = false; sai_object_id_t m_port_id = 0; sai_port_fec_mode_t m_fec_mode = SAI_PORT_FEC_MODE_NONE; VlanInfo m_vlan_info; @@ -108,6 +109,7 @@ class Port uint32_t m_nat_zone_id = 0; uint32_t m_vnid = VNID_NONE; uint32_t m_fdb_count = 0; + uint32_t m_up_member_count = 0; /* * Following two bit vectors are used to lock diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 15cad5bc1f..3afa68e24d 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -4385,6 +4385,49 @@ void PortsOrch::getPortSerdesVal(const std::string& val_str, } } +/* Bring up/down Vlan interface associated with L3 VNI*/ +bool PortsOrch::updateL3VniStatus(uint16_t vlan_id, bool isUp) +{ + Port vlan; + string vlan_alias; + + vlan_alias = VLAN_PREFIX + to_string(vlan_id); + SWSS_LOG_INFO("update L3Vni Status for Vlan %d with isUp %d vlan %s", + vlan_id, isUp, vlan_alias.c_str()); + + if (!getPort(vlan_alias, vlan)) + { + SWSS_LOG_INFO("Failed to locate VLAN %d", vlan_id); + return false; + } + + SWSS_LOG_INFO("member count %d, l3vni %d", vlan.m_up_member_count, vlan.m_l3_vni); + if (isUp) { + auto old_count = vlan.m_up_member_count; + vlan.m_up_member_count++; + if (old_count == 0) + { + /* updateVlanOperStatus(vlan, true); */ /* TBD */ + vlan.m_oper_status = SAI_PORT_OPER_STATUS_UP; + } + vlan.m_l3_vni = true; + } else { + vlan.m_up_member_count--; + if (vlan.m_up_member_count == 0) + { + /* updateVlanOperStatus(vlan, false); */ /* TBD */ + vlan.m_oper_status = SAI_PORT_OPER_STATUS_DOWN; + } + vlan.m_l3_vni = false; + } + + m_portList[vlan_alias] = vlan; + + SWSS_LOG_INFO("Updated L3Vni status of VLAN %d member count %d", vlan_id, vlan.m_up_member_count); + + return true; +} + /* * If Gearbox is enabled (wait for GearboxConfigDone), * then initialize global storage maps @@ -4604,6 +4647,7 @@ bool PortsOrch::initGearboxPort(Port &port) m_gearboxPortListLaneMap[port.m_port_id] = make_tuple(systemPort, linePort); } } + return true; } diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index 35e3af2627..42cb7278b8 100755 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -125,6 +125,7 @@ class PortsOrch : public Orch, public Subject bool addSubPort(Port &port, const string &alias, const bool &adminUp = true, const uint32_t &mtu = 0); bool removeSubPort(const string &alias); + bool updateL3VniStatus(uint16_t vlan_id, bool status); void getLagMember(Port &lag, vector &portv); void updateChildPortsMtu(const Port &p, const uint32_t mtu); @@ -136,7 +137,6 @@ class PortsOrch : public Orch, public Subject bool removeVlanMember(Port &vlan, Port &port); bool isVlanMember(Port &vlan, Port &port); - private: unique_ptr m_counterTable; unique_ptr
m_counterLagTable; diff --git a/orchagent/routeorch.cpp b/orchagent/routeorch.cpp index 7166effcd5..03efd31543 100644 --- a/orchagent/routeorch.cpp +++ b/orchagent/routeorch.cpp @@ -5,6 +5,7 @@ #include "logger.h" #include "swssnet.h" #include "crmorch.h" +#include "directory.h" extern sai_object_id_t gVirtualRouterId; extern sai_object_id_t gSwitchId; @@ -15,6 +16,7 @@ extern sai_switch_api_t* sai_switch_api; extern PortsOrch *gPortsOrch; extern CrmOrch *gCrmOrch; +extern Directory gDirectory; /* Default maximum number of next hop groups */ #define DEFAULT_NUMBER_OF_ECMP_GROUPS 128 @@ -495,7 +497,10 @@ void RouteOrch::doTask(Consumer& consumer) { string ips; string aliases; + string vni_labels; + string remote_macs; bool& excp_intfs_flag = ctx.excp_intfs_flag; + bool overlay_nh = false; for (auto i : kfvFieldsValues(t)) { @@ -504,10 +509,21 @@ void RouteOrch::doTask(Consumer& consumer) if (fvField(i) == "ifname") aliases = fvValue(i); + + if (fvField(i) == "vni_label") { + vni_labels = fvValue(i); + overlay_nh = true; + } + + if (fvField(i) == "router_mac") + remote_macs = fvValue(i); } + vector& ipv = ctx.ipv; ipv = tokenize(ips, ','); vector alsv = tokenize(aliases, ','); + vector vni_labelv = tokenize(vni_labels, ','); + vector rmacv = tokenize(remote_macs, ','); /* * For backward compatibility, adjust ip string from old format to @@ -560,14 +576,31 @@ void RouteOrch::doTask(Consumer& consumer) continue; } - string nhg_str = ipv[0] + NH_DELIMITER + alsv[0]; - for (uint32_t i = 1; i < ipv.size(); i++) + string nhg_str = ""; + NextHopGroupKey& nhg = ctx.nhg; + + if (overlay_nh == false) { - nhg_str += NHG_DELIMITER + ipv[i] + NH_DELIMITER + alsv[i]; + nhg_str = ipv[0] + NH_DELIMITER + alsv[0]; + + for (uint32_t i = 1; i < ipv.size(); i++) + { + nhg_str += NHG_DELIMITER + ipv[i] + NH_DELIMITER + alsv[i]; + } + + nhg = NextHopGroupKey(nhg_str); + } + else + { + nhg_str = ipv[0] + NH_DELIMITER + "vni" + alsv[0] + NH_DELIMITER + vni_labelv[0] + NH_DELIMITER + rmacv[0]; + for (uint32_t i = 1; i < ipv.size(); i++) + { + nhg_str += NHG_DELIMITER + ipv[i] + NH_DELIMITER + "vni" + alsv[i] + NH_DELIMITER + vni_labelv[i] + NH_DELIMITER + rmacv[i]; + } - NextHopGroupKey& nhg = ctx.nhg; - nhg = NextHopGroupKey(nhg_str); + nhg = NextHopGroupKey(nhg_str, overlay_nh); + } if (ipv.size() == 1 && IpAddress(ipv[0]).isZero()) { @@ -811,7 +844,17 @@ void RouteOrch::increaseNextHopRefCount(const NextHopGroupKey &nexthops) } else if (nexthops.getSize() == 1) { - NextHopKey nexthop(nexthops.to_string()); + NextHopKey nexthop; + bool overlay_nh = nexthops.is_overlay_nexthop(); + if (overlay_nh) + { + nexthop = NextHopKey (nexthops.to_string(), overlay_nh); + } + else + { + nexthop = NextHopKey (nexthops.to_string()); + } + if (nexthop.ip_address.isZero()) m_intfsOrch->increaseRouterIntfsRefCount(nexthop.alias); else @@ -822,6 +865,7 @@ void RouteOrch::increaseNextHopRefCount(const NextHopGroupKey &nexthops) m_syncdNextHopGroups[nexthops].ref_count ++; } } + void RouteOrch::decreaseNextHopRefCount(const NextHopGroupKey &nexthops) { /* Return when there is no next hop (dropped) */ @@ -831,7 +875,17 @@ void RouteOrch::decreaseNextHopRefCount(const NextHopGroupKey &nexthops) } else if (nexthops.getSize() == 1) { - NextHopKey nexthop(nexthops.to_string()); + NextHopKey nexthop; + bool overlay_nh = nexthops.is_overlay_nexthop(); + if (overlay_nh) + { + nexthop = NextHopKey (nexthops.to_string(), overlay_nh); + } + else + { + nexthop = NextHopKey (nexthops.to_string()); + } + if (nexthop.ip_address.isZero()) m_intfsOrch->decreaseRouterIntfsRefCount(nexthop.alias); else @@ -1045,6 +1099,7 @@ bool RouteOrch::removeNextHopGroup(const NextHopGroupKey &nexthops) sai_object_id_t next_hop_group_id; auto next_hop_group_entry = m_syncdNextHopGroups.find(nexthops); sai_status_t status; + bool overlay_nh = nexthops.is_overlay_nexthop(); assert(next_hop_group_entry != m_syncdNextHopGroups.end()); @@ -1105,6 +1160,24 @@ bool RouteOrch::removeNextHopGroup(const NextHopGroupKey &nexthops) for (auto it : next_hop_set) { m_neighOrch->decreaseNextHopRefCount(it); + if (overlay_nh && !m_neighOrch->getNextHopRefCount(it)) + { + if(!m_neighOrch->removeTunnelNextHop(it)) + { + SWSS_LOG_ERROR("Tunnel Nexthop %s delete failed", nexthops.to_string().c_str()); + } + else + { + m_neighOrch->removeOverlayNextHop(it); + SWSS_LOG_INFO("Tunnel Nexthop %s delete success", nexthops.to_string().c_str()); + SWSS_LOG_INFO("delete remote vtep %s", it.to_string(true).c_str()); + status = deleteRemoteVtep(SAI_NULL_OBJECT_ID, it); + if (status == false) + { + SWSS_LOG_ERROR("Failed to delete remote vtep %s ecmp", it.to_string(true).c_str()); + } + } + } } m_syncdNextHopGroups.erase(nexthops); @@ -1164,7 +1237,9 @@ bool RouteOrch::addRoute(RouteBulkContext& ctx, const NextHopGroupKey &nextHops) } /* next_hop_id indicates the next hop id or next hop group id of this route */ - sai_object_id_t next_hop_id; + sai_object_id_t next_hop_id = SAI_NULL_OBJECT_ID; + bool overlay_nh = false; + bool status = false; if (m_syncdRoutes.find(vrf_id) == m_syncdRoutes.end()) { @@ -1172,12 +1247,26 @@ bool RouteOrch::addRoute(RouteBulkContext& ctx, const NextHopGroupKey &nextHops) m_vrfOrch->increaseVrfRefCount(vrf_id); } + if (nextHops.is_overlay_nexthop()) + { + overlay_nh = true; + } + auto it_route = m_syncdRoutes.at(vrf_id).find(ipPrefix); /* The route is pointing to a next hop */ if (nextHops.getSize() == 1) { - NextHopKey nexthop(nextHops.to_string()); + NextHopKey nexthop; + if (overlay_nh) + { + nexthop = NextHopKey(nextHops.to_string(), overlay_nh); + } + else + { + nexthop = NextHopKey(nextHops.to_string()); + } + if (nexthop.ip_address.isZero()) { next_hop_id = m_intfsOrch->getRouterIntfsId(nexthop.alias); @@ -1197,9 +1286,28 @@ bool RouteOrch::addRoute(RouteBulkContext& ctx, const NextHopGroupKey &nextHops) } else { - SWSS_LOG_INFO("Failed to get next hop %s for %s", - nextHops.to_string().c_str(), ipPrefix.to_string().c_str()); - return false; + if(overlay_nh) + { + SWSS_LOG_INFO("create remote vtep %s", nexthop.to_string(overlay_nh).c_str()); + status = createRemoteVtep(vrf_id, nexthop); + if (status == false) + { + SWSS_LOG_ERROR("Failed to create remote vtep %s", nexthop.to_string(overlay_nh).c_str()); + return false; + } + next_hop_id = m_neighOrch->addTunnelNextHop(nexthop); + if (next_hop_id == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_ERROR("Failed to create Tunnel Nexthop %s", nexthop.to_string(overlay_nh).c_str()); + return false; + } + } + else + { + SWSS_LOG_INFO("Failed to get next hop %s for %s", + nextHops.to_string().c_str(), ipPrefix.to_string().c_str()); + return false; + } } } } @@ -1212,13 +1320,55 @@ bool RouteOrch::addRoute(RouteBulkContext& ctx, const NextHopGroupKey &nextHops) /* Try to create a new next hop group */ if (!addNextHopGroup(nextHops)) { + /* NextHopGroup is in "Ip1|alias1,Ip2|alias2,..." format*/ + std::vector nhops = tokenize(nextHops.to_string(), ','); + for(auto it = nhops.begin(); it != nhops.end(); ++it) + { + NextHopKey nextHop; + if (overlay_nh) + { + nextHop = NextHopKey(*it, overlay_nh); + } + else + { + nextHop = NextHopKey(*it); + } + + if(!m_neighOrch->hasNextHop(nextHop)) + { + if(overlay_nh) + { + SWSS_LOG_INFO("create remote vtep %s ecmp", nextHop.to_string(overlay_nh).c_str()); + status = createRemoteVtep(vrf_id, nextHop); + if (status == false) + { + SWSS_LOG_ERROR("Failed to create remote vtep %s ecmp", nextHop.to_string(overlay_nh).c_str()); + return false; + } + next_hop_id = m_neighOrch->addTunnelNextHop(nextHop); + if (next_hop_id == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_ERROR("Failed to create Tunnel Nexthop %s", nextHop.to_string(overlay_nh).c_str()); + return false; + } + } + } + } /* Failed to create the next hop group and check if a temporary route is needed */ /* If the current next hop is part of the next hop group to sync, * then return false and no need to add another temporary route. */ if (it_route != m_syncdRoutes.at(vrf_id).end() && it_route->second.getSize() == 1) { - NextHopKey nexthop(it_route->second.to_string()); + NextHopKey nexthop; + auto old_nextHops = it_route->second; + + if (old_nextHops.is_overlay_nexthop()) { + nexthop = NextHopKey(it_route->second.to_string(), true); + } else { + nexthop = NextHopKey(it_route->second.to_string()); + } + if (nextHops.contains(nexthop)) { return false; @@ -1310,7 +1460,13 @@ bool RouteOrch::addRoutePost(const RouteBulkContext& ctx, const NextHopGroupKey /* The route is pointing to a next hop */ if (nextHops.getSize() == 1) { - NextHopKey nexthop(nextHops.to_string()); + NextHopKey nexthop; + if(nextHops.is_overlay_nexthop()) { + nexthop = NextHopKey(nextHops.to_string(), true); + } else { + nexthop = NextHopKey(nextHops.to_string()); + } + if (nexthop.ip_address.isZero()) { next_hop_id = m_intfsOrch->getRouterIntfsId(nexthop.alias); @@ -1371,6 +1527,7 @@ bool RouteOrch::addRoutePost(const RouteBulkContext& ctx, const NextHopGroupKey /* Increase the ref_count for the next hop (group) entry */ increaseNextHopRefCount(nextHops); + SWSS_LOG_INFO("Post create route %s with next hop(s) %s", ipPrefix.to_string().c_str(), nextHops.to_string().c_str()); } @@ -1402,11 +1559,17 @@ bool RouteOrch::addRoutePost(const RouteBulkContext& ctx, const NextHopGroupKey increaseNextHopRefCount(nextHops); decreaseNextHopRefCount(it_route->second); + auto ol_nextHops = it_route->second; if (it_route->second.getSize() > 1 && m_syncdNextHopGroups[it_route->second].ref_count == 0) { m_bulkNhgReducedRefCnt.emplace(it_route->second); + } else if (ol_nextHops.is_overlay_nexthop()){ + + SWSS_LOG_NOTICE("Update overlay Nexthop %s", ol_nextHops.to_string().c_str()); + removeOverlayNextHops(vrf_id, ol_nextHops); } + SWSS_LOG_INFO("Post set route %s with next hop(s) %s", ipPrefix.to_string().c_str(), nextHops.to_string().c_str()); } @@ -1545,10 +1708,16 @@ bool RouteOrch::removeRoutePost(const RouteBulkContext& ctx) * Decrease the reference count only when the route is pointing to a next hop. */ decreaseNextHopRefCount(it_route->second); + + auto ol_nextHops = it_route->second; + if (it_route->second.getSize() > 1 && m_syncdNextHopGroups[it_route->second].ref_count == 0) { m_bulkNhgReducedRefCnt.emplace(it_route->second); + } else if (ol_nextHops.is_overlay_nexthop()){ + SWSS_LOG_NOTICE("Remove overlay Nexthop %s", ol_nextHops.to_string().c_str()); + removeOverlayNextHops(vrf_id, ol_nextHops); } SWSS_LOG_INFO("Remove route %s with next hop(s) %s", @@ -1577,3 +1746,77 @@ bool RouteOrch::removeRoutePost(const RouteBulkContext& ctx) return true; } + +bool RouteOrch::createRemoteVtep(sai_object_id_t vrf_id, const NextHopKey &nextHop) +{ + SWSS_LOG_ENTER(); + EvpnNvoOrch* evpn_orch = gDirectory.get(); + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); + bool status = false; + int ip_refcnt = 0; + + status = tunnel_orch->addTunnelUser(nextHop.ip_address.to_string(), nextHop.vni, 0, TUNNEL_USER_IP, vrf_id); + + auto vtep_ptr = evpn_orch->getEVPNVtep(); + if (vtep_ptr) + { + ip_refcnt = vtep_ptr->getDipTunnelIPRefCnt(nextHop.ip_address.to_string()); + } + SWSS_LOG_INFO("Routeorch Add Remote VTEP %s, VNI %d, VR_ID %lx, IP ref_cnt %d", + nextHop.ip_address.to_string().c_str(), nextHop.vni, vrf_id, ip_refcnt); + return status; +} + +bool RouteOrch::deleteRemoteVtep(sai_object_id_t vrf_id, const NextHopKey &nextHop) +{ + SWSS_LOG_ENTER(); + EvpnNvoOrch* evpn_orch = gDirectory.get(); + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); + bool status = false; + int ip_refcnt = 0; + + status = tunnel_orch->delTunnelUser(nextHop.ip_address.to_string(), nextHop.vni, 0, TUNNEL_USER_IP, vrf_id); + + auto vtep_ptr = evpn_orch->getEVPNVtep(); + if (vtep_ptr) + { + ip_refcnt = vtep_ptr->getDipTunnelIPRefCnt(nextHop.ip_address.to_string()); + } + + SWSS_LOG_INFO("Routeorch Del Remote VTEP %s, VNI %d, VR_ID %lx, IP ref_cnt %d", + nextHop.ip_address.to_string().c_str(), nextHop.vni, vrf_id, ip_refcnt); + return status; +} + +bool RouteOrch::removeOverlayNextHops(sai_object_id_t vrf_id, const NextHopGroupKey &ol_nextHops) +{ + SWSS_LOG_ENTER(); + bool status = false; + + SWSS_LOG_NOTICE("Remove overlay Nexthop %s", ol_nextHops.to_string().c_str()); + for (auto &tunnel_nh : ol_nextHops.getNextHops()) + { + if (!m_neighOrch->getNextHopRefCount(tunnel_nh)) + { + if(!m_neighOrch->removeTunnelNextHop(tunnel_nh)) + { + SWSS_LOG_ERROR("Tunnel Nexthop %s delete failed", ol_nextHops.to_string().c_str()); + } + else + { + m_neighOrch->removeOverlayNextHop(tunnel_nh); + SWSS_LOG_INFO("Tunnel Nexthop %s delete success", ol_nextHops.to_string().c_str()); + SWSS_LOG_INFO("delete remote vtep %s", tunnel_nh.to_string(true).c_str()); + status = deleteRemoteVtep(vrf_id, tunnel_nh); + if (status == false) + { + SWSS_LOG_ERROR("Failed to delete remote vtep %s ecmp", tunnel_nh.to_string(true).c_str()); + return false; + } + } + } + } + + return true; +} + diff --git a/orchagent/routeorch.h b/orchagent/routeorch.h index 4618b72804..e57bcddde4 100644 --- a/orchagent/routeorch.h +++ b/orchagent/routeorch.h @@ -6,6 +6,7 @@ #include "switchorch.h" #include "intfsorch.h" #include "neighorch.h" +#include "vxlanorch.h" #include "ipaddress.h" #include "ipaddresses.h" @@ -107,6 +108,10 @@ class RouteOrch : public Orch, public Subject bool validnexthopinNextHopGroup(const NextHopKey&); bool invalidnexthopinNextHopGroup(const NextHopKey&); + bool createRemoteVtep(sai_object_id_t, const NextHopKey&); + bool deleteRemoteVtep(sai_object_id_t, const NextHopKey&); + bool removeOverlayNextHops(sai_object_id_t, const NextHopGroupKey&); + void notifyNextHopChangeObservers(sai_object_id_t, const IpPrefix&, const NextHopGroupKey&, bool); const NextHopGroupKey getSyncdRouteNhgKey(sai_object_id_t vrf_id, const IpPrefix& ipPrefix); bool createFineGrainedNextHopGroup(sai_object_id_t &next_hop_group_id, vector &nhg_attrs); diff --git a/orchagent/vrforch.cpp b/orchagent/vrforch.cpp index 62b56e1e0e..ee0d9d4ac2 100644 --- a/orchagent/vrforch.cpp +++ b/orchagent/vrforch.cpp @@ -10,16 +10,22 @@ #include "orch.h" #include "request_parser.h" #include "vrforch.h" +#include "vxlanorch.h" +#include "directory.h" using namespace std; using namespace swss; extern sai_virtual_router_api_t* sai_virtual_router_api; extern sai_object_id_t gSwitchId; +extern Directory gDirectory; +extern PortsOrch* gPortsOrch; bool VRFOrch::addOperation(const Request& request) { SWSS_LOG_ENTER(); + uint32_t vni = 0; + bool error = true; sai_attribute_t attr; vector attrs; @@ -57,6 +63,11 @@ bool VRFOrch::addOperation(const Request& request) attr.id = SAI_VIRTUAL_ROUTER_ATTR_UNKNOWN_L3_MULTICAST_PACKET_ACTION; attr.value.s32 = request.getAttrPacketAction("l3_mc_action"); } + else if (name == "vni") + { + vni = static_cast(request.getAttrUint(name)); + continue; + } else { SWSS_LOG_ERROR("Logic error: Unknown attribute: %s", name.c_str()); @@ -84,6 +95,15 @@ bool VRFOrch::addOperation(const Request& request) vrf_table_[vrf_name].vrf_id = router_id; vrf_table_[vrf_name].ref_count = 0; vrf_id_table_[router_id] = vrf_name; + if (vni != 0) + { + SWSS_LOG_INFO("VRF '%s' vni %d add", vrf_name.c_str(), vni); + error = updateVrfVNIMap(vrf_name, vni); + if (error == false) + { + return false; + } + } m_stateVrfObjectTable.hset(vrf_name, "state", "ok"); SWSS_LOG_NOTICE("VRF '%s' was added", vrf_name.c_str()); } @@ -103,6 +123,13 @@ bool VRFOrch::addOperation(const Request& request) } } + SWSS_LOG_INFO("VRF '%s' vni %d modify", vrf_name.c_str(), vni); + error = updateVrfVNIMap(vrf_name, vni); + if (error == false) + { + return false; + } + SWSS_LOG_NOTICE("VRF '%s' was updated", vrf_name.c_str()); } @@ -112,6 +139,7 @@ bool VRFOrch::addOperation(const Request& request) bool VRFOrch::delOperation(const Request& request) { SWSS_LOG_ENTER(); + bool error = true; const std::string& vrf_name = request.getKeyString(0); if (vrf_table_.find(vrf_name) == std::end(vrf_table_)) @@ -133,9 +161,105 @@ bool VRFOrch::delOperation(const Request& request) vrf_table_.erase(vrf_name); vrf_id_table_.erase(router_id); + error = delVrfVNIMap(vrf_name, 0); + if (error == false) + { + return false; + } m_stateVrfObjectTable.del(vrf_name); SWSS_LOG_NOTICE("VRF '%s' was removed", vrf_name.c_str()); return true; } + +bool VRFOrch::updateVrfVNIMap(const std::string& vrf_name, uint32_t vni) +{ + SWSS_LOG_ENTER(); + uint32_t old_vni = 0; + uint16_t vlan_id = 0; + EvpnNvoOrch* evpn_orch = gDirectory.get(); + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); + bool error = true; + + old_vni = getVRFmappedVNI(vrf_name); + SWSS_LOG_INFO("VRF '%s' vni %d old_vni %d", vrf_name.c_str(), vni, old_vni); + + if (old_vni != vni) + { + if (vni == 0) + { + error = delVrfVNIMap(vrf_name, old_vni); + if (error == false) + { + return false; + } + } else { + //update l3vni table, if vlan/vni is received later will be able to update L3VniStatus. + l3vni_table_[vni].vlan_id = 0; + l3vni_table_[vni].l3_vni = true; + auto evpn_vtep_ptr = evpn_orch->getEVPNVtep(); + if(!evpn_vtep_ptr) + { + SWSS_LOG_NOTICE("updateVrfVNIMap unable to find EVPN VTEP"); + return false; + } + + vrf_vni_map_table_[vrf_name] = vni; + vlan_id = tunnel_orch->getVlanMappedToVni(vni); + l3vni_table_[vni].vlan_id = vlan_id; + SWSS_LOG_INFO("addL3VniStatus vni %d vlan %d", vni, vlan_id); + if (vlan_id != 0) + { + /*call VE UP*/ + error = gPortsOrch->updateL3VniStatus(vlan_id, true); + SWSS_LOG_INFO("addL3VniStatus vni %d vlan %d, status %d", vni, vlan_id, error); + } + } + SWSS_LOG_INFO("VRF '%s' vni %d map update", vrf_name.c_str(), vni); + } + + return true; +} + +bool VRFOrch::delVrfVNIMap(const std::string& vrf_name, uint32_t vni) +{ + SWSS_LOG_ENTER(); + bool status = true; + uint16_t vlan_id = 0; + + SWSS_LOG_INFO("VRF '%s' VNI %d map", vrf_name.c_str(), vni); + if (vni == 0) { + vni = getVRFmappedVNI(vrf_name); + } + + if (vni != 0) + { + vlan_id = l3vni_table_[vni].vlan_id; + SWSS_LOG_INFO("delL3VniStatus vni %d vlan %d", vni, vlan_id); + if (vlan_id != 0) + { + /*call VE Down*/ + status = gPortsOrch->updateL3VniStatus(vlan_id, false); + SWSS_LOG_INFO("delL3VniStatus vni %d vlan %d, status %d", vni, vlan_id, status); + } + l3vni_table_.erase(vni); + vrf_vni_map_table_.erase(vrf_name); + } + + SWSS_LOG_INFO("VRF '%s' VNI %d map removed", vrf_name.c_str(), vni); + return true; +} + +int VRFOrch::updateL3VniVlan(uint32_t vni, uint16_t vlan_id) +{ + bool status = true; + l3vni_table_[vni].vlan_id = vlan_id; + + SWSS_LOG_INFO("updateL3VniStatus vni %d vlan %d", vni, vlan_id); + /*call VE UP*/ + status = gPortsOrch->updateL3VniStatus(vlan_id, true); + SWSS_LOG_INFO("updateL3VniStatus vni %d vlan %d, status %d", vni, vlan_id, status); + + return 0; +} diff --git a/orchagent/vrforch.h b/orchagent/vrforch.h index 41ad55a003..68a871b809 100644 --- a/orchagent/vrforch.h +++ b/orchagent/vrforch.h @@ -11,8 +11,16 @@ struct VrfEntry int ref_count; }; +struct VNIEntry +{ + uint16_t vlan_id; + bool l3_vni; +}; + typedef std::unordered_map VRFTable; typedef std::unordered_map VRFIdNameTable; +typedef std::unordered_map VRFNameVNIMapTable; +typedef std::unordered_map L3VNITable; const request_description_t request_description = { { REQ_T_STRING }, @@ -24,6 +32,7 @@ const request_description_t request_description = { { "ip_opt_action", REQ_T_PACKET_ACTION }, { "l3_mc_action", REQ_T_PACKET_ACTION }, { "fallback", REQ_T_BOOL }, + { "vni", REQ_T_UINT } }, { } // no mandatory attributes }; @@ -109,14 +118,54 @@ class VRFOrch : public Orch2 } } + int getVrfRefCount(const std::string& name) + { + if (vrf_table_.find(name) != std::end(vrf_table_)) + { + return vrf_table_.at(name).ref_count; + } + else + { + return -1; + } + } + + uint32_t getVRFmappedVNI(const std::string& vrf_name) const + { + if (vrf_vni_map_table_.find(vrf_name) != std::end(vrf_vni_map_table_)) + { + return vrf_vni_map_table_.at(vrf_name); + } + else + { + return 0; + } + } + + int getL3VniVlan(const uint32_t vni) const + { + if (l3vni_table_.find(vni) != std::end(l3vni_table_)) + { + return l3vni_table_.at(vni).vlan_id; + } + else + { + return (-1); + } + } + int updateL3VniVlan(uint32_t vni, uint16_t vlan_id); private: virtual bool addOperation(const Request& request); virtual bool delOperation(const Request& request); + bool updateVrfVNIMap(const std::string& vrf_name, uint32_t vni); + bool delVrfVNIMap(const std::string& vrf_name, uint32_t vni); VRFTable vrf_table_; VRFIdNameTable vrf_id_table_; VRFRequest request_; + VRFNameVNIMapTable vrf_vni_map_table_; swss::Table m_stateVrfObjectTable; + L3VNITable l3vni_table_; }; #endif // __VRFORCH_H diff --git a/orchagent/vxlanorch.cpp b/orchagent/vxlanorch.cpp index c429925e5f..4f20d7d60b 100644 --- a/orchagent/vxlanorch.cpp +++ b/orchagent/vxlanorch.cpp @@ -1898,7 +1898,9 @@ bool VxlanVrfMapOrch::addOperation(const Request& request) * Create encap and decap mapper */ entry.encap_id = tunnel_obj->addEncapMapperEntry(vrf_id, vni_id); + vrf_orch->increaseVrfRefCount(vrf_name); entry.decap_id = tunnel_obj->addDecapMapperEntry(vrf_id, vni_id); + vrf_orch->increaseVrfRefCount(vrf_name); SWSS_LOG_DEBUG("Vxlan tunnel encap entry '%" PRIx64 "' decap entry '0x%" PRIx64 "'", entry.encap_id, entry.decap_id); @@ -2160,4 +2162,3 @@ bool EvpnNvoOrch::delOperation(const Request& request) return true; } -