From b369bb29aca569aad7ccbea63daec6ecb044ff4b Mon Sep 17 00:00:00 2001 From: Tapash Das <48195098+tapashdas@users.noreply.github.com> Date: Sat, 19 Dec 2020 00:32:50 +0530 Subject: [PATCH] Added support for EVPN L3 VXLAN as described in the PR Azure/SONiC#437 (#1267) VRFMgr Changes to update VRF VNI Map information and notify VRFOrch. Neighbor Orch changes to Add and Remove Tunnel Nexthops. Nexthop Key changes to accommodate VNI and Router MAC. Route Orch changes to Add and Remove Overlay routes, Create and Delete Overlay Nexthops. Port Orch changes to bring Up / Down Router Interface (IRB Vlan interface) on VRF - VNI Bind / Unbind. --- cfgmgr/vrfmgr.cpp | 242 +++++++++++++++++++++++++++++--- cfgmgr/vrfmgr.h | 14 +- cfgmgr/vrfmgrd.cpp | 1 + orchagent/mirrororch.cpp | 6 +- orchagent/neighorch.cpp | 93 ++++++++++++- orchagent/neighorch.h | 5 +- orchagent/nexthopgroupkey.h | 26 +++- orchagent/nexthopkey.h | 37 ++++- orchagent/port.h | 2 + orchagent/portsorch.cpp | 44 ++++++ orchagent/portsorch.h | 2 +- orchagent/routeorch.cpp | 271 ++++++++++++++++++++++++++++++++++-- orchagent/routeorch.h | 5 + orchagent/vrforch.cpp | 124 +++++++++++++++++ orchagent/vrforch.h | 49 +++++++ orchagent/vxlanorch.cpp | 3 +- 16 files changed, 880 insertions(+), 44 deletions(-) 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 2878a5265d..a0665406a1 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, @@ -1185,7 +1186,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 62b087cf71..fb0b8b6434 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 25a64b553b..966d61cbbc 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -4409,6 +4409,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 @@ -4628,6 +4671,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 f4d24f6a4c..6e25454f13 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; } -