From a48944c1b557a81a65b5ba7683aa8f6377119957 Mon Sep 17 00:00:00 2001 From: Sonic Build Admin Date: Wed, 22 Apr 2026 23:49:03 +0000 Subject: [PATCH] vpp: implement CRM counters for neighbour, nexthop, nexthop group and members ### why vpp doesn't track the usage of neighbour, nexthop, nexthop group and members due to it doesn't have hard limit on those objects except heap memory allocated to vpp process. But for test coverage with crm/test_crm.py, we need to track the usage although the max of those objects can be very large. ### what this PR does 1. implement CRM counters for neighbour, nexthop, nexthop group and members 2. refactor CRM functions to a new class CRMTracker for better code maintenance. ### how is it tested passed crm/test_crm.py Signed-off-by: Sonic Build Admin --- vslib/Makefile.am | 1 + vslib/vpp/CRMTracker.cpp | 293 +++++++++++++++++++++++++++++++++++++++ vslib/vpp/CRMTracker.h | 87 ++++++++++++ vslib/vpp/SwitchVpp.cpp | 210 +++++++++++++--------------- vslib/vpp/SwitchVpp.h | 14 +- 5 files changed, 479 insertions(+), 126 deletions(-) create mode 100644 vslib/vpp/CRMTracker.cpp create mode 100644 vslib/vpp/CRMTracker.h diff --git a/vslib/Makefile.am b/vslib/Makefile.am index 69ef2384..a62e1dee 100644 --- a/vslib/Makefile.am +++ b/vslib/Makefile.am @@ -75,6 +75,7 @@ libSaiVS_a_SOURCES = \ if USE_VPP libSaiVS_a_SOURCES +=\ + vpp/CRMTracker.cpp \ vpp/SaiObjectDB.cpp \ vpp/SwitchVpp.cpp \ vpp/SwitchVppAcl.cpp \ diff --git a/vslib/vpp/CRMTracker.cpp b/vslib/vpp/CRMTracker.cpp new file mode 100644 index 00000000..cb90111c --- /dev/null +++ b/vslib/vpp/CRMTracker.cpp @@ -0,0 +1,293 @@ +#include "CRMTracker.h" + +using namespace saivs; + +CRMTracker::CRMTracker() +{ + SWSS_LOG_ENTER(); +} + +void CRMTracker::loadProfileValues( + const std::map& profileMap) +{ + SWSS_LOG_ENTER(); + + if (profileMap.empty()) + { + SWSS_LOG_NOTICE("CRM: profile map is empty, using defaults"); + return; + } + + static const std::pair keys[] = { + { "SAI_VPP_MAX_IPV4_ROUTE_ENTRIES", &CRMTracker::m_maxIPv4RouteEntries }, + { "SAI_VPP_MAX_IPV6_ROUTE_ENTRIES", &CRMTracker::m_maxIPv6RouteEntries }, + { "SAI_VPP_MAX_FDB_ENTRIES", &CRMTracker::m_maxFdbEntries }, + { "SAI_VPP_MAX_IPV4_NEIGHBOR_ENTRIES", &CRMTracker::m_maxIPv4NeighborEntries }, + { "SAI_VPP_MAX_IPV6_NEIGHBOR_ENTRIES", &CRMTracker::m_maxIPv6NeighborEntries }, + { "SAI_VPP_MAX_IPV4_NEXTHOP_ENTRIES", &CRMTracker::m_maxIPv4NextHopEntries }, + { "SAI_VPP_MAX_IPV6_NEXTHOP_ENTRIES", &CRMTracker::m_maxIPv6NextHopEntries }, + { "SAI_VPP_MAX_NEXTHOP_GROUP_ENTRIES", &CRMTracker::m_maxNextHopGroupEntries }, + { "SAI_VPP_MAX_NEXTHOP_GROUP_MEMBER_ENTRIES", &CRMTracker::m_maxNextHopGroupMemberEntries }, + }; + + for (const auto& kv : keys) + { + auto it = profileMap.find(kv.first); + if (it != profileMap.end()) + { + this->*(kv.second) = (uint32_t)std::stoul(it->second); + } + } + + SWSS_LOG_NOTICE("CRM: profile loaded (IPv4Route=%u, IPv6Route=%u, FDB=%u, " + "IPv4Nbr=%u, IPv6Nbr=%u, IPv4NH=%u, IPv6NH=%u, NHG=%u, NHGMbr=%u)", + m_maxIPv4RouteEntries, m_maxIPv6RouteEntries, m_maxFdbEntries, + m_maxIPv4NeighborEntries, m_maxIPv6NeighborEntries, + m_maxIPv4NextHopEntries, m_maxIPv6NextHopEntries, + m_maxNextHopGroupEntries, m_maxNextHopGroupMemberEntries); +} + +std::vector CRMTracker::getInitialValues() const +{ + SWSS_LOG_ENTER(); + + return { + { SAI_SWITCH_ATTR_AVAILABLE_IPV4_ROUTE_ENTRY, m_maxIPv4RouteEntries }, + { SAI_SWITCH_ATTR_AVAILABLE_IPV6_ROUTE_ENTRY, m_maxIPv6RouteEntries }, + { SAI_SWITCH_ATTR_AVAILABLE_FDB_ENTRY, m_maxFdbEntries }, + { SAI_SWITCH_ATTR_AVAILABLE_IPV4_NEIGHBOR_ENTRY, m_maxIPv4NeighborEntries }, + { SAI_SWITCH_ATTR_AVAILABLE_IPV6_NEIGHBOR_ENTRY, m_maxIPv6NeighborEntries }, + { SAI_SWITCH_ATTR_AVAILABLE_IPV4_NEXTHOP_ENTRY, m_maxIPv4NextHopEntries }, + { SAI_SWITCH_ATTR_AVAILABLE_IPV6_NEXTHOP_ENTRY, m_maxIPv6NextHopEntries }, + { SAI_SWITCH_ATTR_AVAILABLE_NEXT_HOP_GROUP_ENTRY, m_maxNextHopGroupEntries }, + { SAI_SWITCH_ATTR_AVAILABLE_NEXT_HOP_GROUP_MEMBER_ENTRY, m_maxNextHopGroupMemberEntries }, + { SAI_SWITCH_ATTR_AVAILABLE_SNAT_ENTRY, m_maxSNATEntries }, + { SAI_SWITCH_ATTR_AVAILABLE_DNAT_ENTRY, m_maxDNATEntries }, + { SAI_SWITCH_ATTR_AVAILABLE_IPMC_ENTRY, m_maxIPMCEntries }, + { SAI_SWITCH_ATTR_AVAILABLE_DOUBLE_NAT_ENTRY, m_maxDoubleNATEntries }, + }; +} + +bool CRMTracker::handles(sai_switch_attr_t attr_id) const +{ + SWSS_LOG_ENTER(); + + switch (attr_id) + { + case SAI_SWITCH_ATTR_AVAILABLE_IPV4_ROUTE_ENTRY: + case SAI_SWITCH_ATTR_AVAILABLE_IPV6_ROUTE_ENTRY: + case SAI_SWITCH_ATTR_AVAILABLE_FDB_ENTRY: + case SAI_SWITCH_ATTR_AVAILABLE_IPV4_NEIGHBOR_ENTRY: + case SAI_SWITCH_ATTR_AVAILABLE_IPV6_NEIGHBOR_ENTRY: + case SAI_SWITCH_ATTR_AVAILABLE_IPV4_NEXTHOP_ENTRY: + case SAI_SWITCH_ATTR_AVAILABLE_IPV6_NEXTHOP_ENTRY: + case SAI_SWITCH_ATTR_AVAILABLE_NEXT_HOP_GROUP_ENTRY: + case SAI_SWITCH_ATTR_AVAILABLE_NEXT_HOP_GROUP_MEMBER_ENTRY: + case SAI_SWITCH_ATTR_AVAILABLE_SNAT_ENTRY: + case SAI_SWITCH_ATTR_AVAILABLE_DNAT_ENTRY: + case SAI_SWITCH_ATTR_AVAILABLE_IPMC_ENTRY: + case SAI_SWITCH_ATTR_AVAILABLE_DOUBLE_NAT_ENTRY: + return true; + default: + return false; + } +} + +uint32_t CRMTracker::getAvailable(sai_switch_attr_t attr_id) const +{ + SWSS_LOG_ENTER(); + + uint32_t max_val = 0; + uint32_t used = 0; + + switch (attr_id) + { + case SAI_SWITCH_ATTR_AVAILABLE_IPV4_ROUTE_ENTRY: + max_val = m_maxIPv4RouteEntries; used = m_ipv4RouteCount; break; + case SAI_SWITCH_ATTR_AVAILABLE_IPV6_ROUTE_ENTRY: + max_val = m_maxIPv6RouteEntries; used = m_ipv6RouteCount; break; + case SAI_SWITCH_ATTR_AVAILABLE_FDB_ENTRY: + max_val = m_maxFdbEntries; used = m_fdbCount; break; + case SAI_SWITCH_ATTR_AVAILABLE_IPV4_NEIGHBOR_ENTRY: + max_val = m_maxIPv4NeighborEntries; used = m_ipv4NeighborCount; break; + case SAI_SWITCH_ATTR_AVAILABLE_IPV6_NEIGHBOR_ENTRY: + max_val = m_maxIPv6NeighborEntries; used = m_ipv6NeighborCount; break; + case SAI_SWITCH_ATTR_AVAILABLE_IPV4_NEXTHOP_ENTRY: + max_val = m_maxIPv4NextHopEntries; used = m_ipv4NexthopCount; break; + case SAI_SWITCH_ATTR_AVAILABLE_IPV6_NEXTHOP_ENTRY: + max_val = m_maxIPv6NextHopEntries; used = m_ipv6NexthopCount; break; + case SAI_SWITCH_ATTR_AVAILABLE_NEXT_HOP_GROUP_ENTRY: + max_val = m_maxNextHopGroupEntries; used = m_nhgCount; break; + case SAI_SWITCH_ATTR_AVAILABLE_NEXT_HOP_GROUP_MEMBER_ENTRY: + max_val = m_maxNextHopGroupMemberEntries; used = m_nhgMemberCount; break; + case SAI_SWITCH_ATTR_AVAILABLE_SNAT_ENTRY: + max_val = m_maxSNATEntries; used = 0; break; + case SAI_SWITCH_ATTR_AVAILABLE_DNAT_ENTRY: + max_val = m_maxDNATEntries; used = 0; break; + case SAI_SWITCH_ATTR_AVAILABLE_IPMC_ENTRY: + max_val = m_maxIPMCEntries; used = 0; break; + case SAI_SWITCH_ATTR_AVAILABLE_DOUBLE_NAT_ENTRY: + max_val = m_maxDoubleNATEntries; used = 0; break; + default: + SWSS_LOG_WARN("CRM: getAvailable called with unhandled attr %d", attr_id); + return 0; + } + + return (max_val > used) ? (max_val - used) : 0; +} + +// Route tracking + +void CRMTracker::onRouteCreated(bool ipv4) +{ + SWSS_LOG_ENTER(); + + if (ipv4) + { + m_ipv4RouteCount++; + SWSS_LOG_DEBUG("CRM: IPv4 route created, count: %u", m_ipv4RouteCount); + } + else + { + m_ipv6RouteCount++; + SWSS_LOG_DEBUG("CRM: IPv6 route created, count: %u", m_ipv6RouteCount); + } +} + +void CRMTracker::onRouteRemoved(bool ipv4) +{ + SWSS_LOG_ENTER(); + + if (ipv4) + { + if (m_ipv4RouteCount > 0) m_ipv4RouteCount--; + SWSS_LOG_DEBUG("CRM: IPv4 route removed, count: %u", m_ipv4RouteCount); + } + else + { + if (m_ipv6RouteCount > 0) m_ipv6RouteCount--; + SWSS_LOG_DEBUG("CRM: IPv6 route removed, count: %u", m_ipv6RouteCount); + } +} + +// FDB tracking + +void CRMTracker::onFdbCreated() +{ + SWSS_LOG_ENTER(); + + m_fdbCount++; + SWSS_LOG_DEBUG("CRM: FDB entry created, count: %u", m_fdbCount); +} + +void CRMTracker::onFdbRemoved() +{ + SWSS_LOG_ENTER(); + + if (m_fdbCount > 0) m_fdbCount--; + SWSS_LOG_DEBUG("CRM: FDB entry removed, count: %u", m_fdbCount); +} + +// Neighbor tracking + +void CRMTracker::onNeighborCreated(bool ipv4) +{ + SWSS_LOG_ENTER(); + + if (ipv4) + { + m_ipv4NeighborCount++; + SWSS_LOG_DEBUG("CRM: IPv4 neighbor created, count: %u", m_ipv4NeighborCount); + } + else + { + m_ipv6NeighborCount++; + SWSS_LOG_DEBUG("CRM: IPv6 neighbor created, count: %u", m_ipv6NeighborCount); + } +} + +void CRMTracker::onNeighborRemoved(bool ipv4) +{ + SWSS_LOG_ENTER(); + + if (ipv4) + { + if (m_ipv4NeighborCount > 0) m_ipv4NeighborCount--; + SWSS_LOG_DEBUG("CRM: IPv4 neighbor removed, count: %u", m_ipv4NeighborCount); + } + else + { + if (m_ipv6NeighborCount > 0) m_ipv6NeighborCount--; + SWSS_LOG_DEBUG("CRM: IPv6 neighbor removed, count: %u", m_ipv6NeighborCount); + } +} + +// Nexthop tracking + +void CRMTracker::onNexthopCreated(bool ipv4) +{ + SWSS_LOG_ENTER(); + + if (ipv4) + { + m_ipv4NexthopCount++; + SWSS_LOG_DEBUG("CRM: IPv4 nexthop created, count: %u", m_ipv4NexthopCount); + } + else + { + m_ipv6NexthopCount++; + SWSS_LOG_DEBUG("CRM: IPv6 nexthop created, count: %u", m_ipv6NexthopCount); + } +} + +void CRMTracker::onNexthopRemoved(bool ipv4) +{ + SWSS_LOG_ENTER(); + + if (ipv4) + { + if (m_ipv4NexthopCount > 0) m_ipv4NexthopCount--; + SWSS_LOG_DEBUG("CRM: IPv4 nexthop removed, count: %u", m_ipv4NexthopCount); + } + else + { + if (m_ipv6NexthopCount > 0) m_ipv6NexthopCount--; + SWSS_LOG_DEBUG("CRM: IPv6 nexthop removed, count: %u", m_ipv6NexthopCount); + } +} + +// Nexthop group tracking + +void CRMTracker::onNhgCreated() +{ + SWSS_LOG_ENTER(); + + m_nhgCount++; + SWSS_LOG_DEBUG("CRM: NHG created, count: %u", m_nhgCount); +} + +void CRMTracker::onNhgRemoved() +{ + SWSS_LOG_ENTER(); + + if (m_nhgCount > 0) m_nhgCount--; + SWSS_LOG_DEBUG("CRM: NHG removed, count: %u", m_nhgCount); +} + +// Nexthop group member tracking + +void CRMTracker::onNhgMemberCreated() +{ + SWSS_LOG_ENTER(); + + m_nhgMemberCount++; + SWSS_LOG_DEBUG("CRM: NHG member created, count: %u", m_nhgMemberCount); +} + +void CRMTracker::onNhgMemberRemoved() +{ + SWSS_LOG_ENTER(); + + if (m_nhgMemberCount > 0) m_nhgMemberCount--; + SWSS_LOG_DEBUG("CRM: NHG member removed, count: %u", m_nhgMemberCount); +} diff --git a/vslib/vpp/CRMTracker.h b/vslib/vpp/CRMTracker.h new file mode 100644 index 00000000..748dfbd4 --- /dev/null +++ b/vslib/vpp/CRMTracker.h @@ -0,0 +1,87 @@ +#pragma once + +extern "C" { +#include "sai.h" +} + +#include "swss/logger.h" + +#include +#include +#include + +namespace saivs +{ + struct CRMInitValue + { + sai_switch_attr_t attr_id; + uint32_t value; + }; + + class CRMTracker + { + public: + + CRMTracker(); + + void loadProfileValues(const std::map& profileMap); + + std::vector getInitialValues() const; + + uint32_t getAvailable(sai_switch_attr_t attr_id) const; + + bool handles(sai_switch_attr_t attr_id) const; + + // Route tracking + void onRouteCreated(bool ipv4); + void onRouteRemoved(bool ipv4); + + // FDB tracking + void onFdbCreated(); + void onFdbRemoved(); + + // Neighbor tracking + void onNeighborCreated(bool ipv4); + void onNeighborRemoved(bool ipv4); + + // Nexthop tracking + void onNexthopCreated(bool ipv4); + void onNexthopRemoved(bool ipv4); + + // Nexthop group tracking + void onNhgCreated(); + void onNhgRemoved(); + + // Nexthop group member tracking + void onNhgMemberCreated(); + void onNhgMemberRemoved(); + + private: + + // Configurable limits (defaults from SwitchStateBase) + uint32_t m_maxIPv4RouteEntries = 100000; + uint32_t m_maxIPv6RouteEntries = 10000; + uint32_t m_maxFdbEntries = 800; + uint32_t m_maxIPv4NeighborEntries = 4000; + uint32_t m_maxIPv6NeighborEntries = 2000; + uint32_t m_maxIPv4NextHopEntries = 32000; + uint32_t m_maxIPv6NextHopEntries = 32000; + uint32_t m_maxNextHopGroupEntries = 400; + uint32_t m_maxNextHopGroupMemberEntries = 16000; + uint32_t m_maxSNATEntries = 100; + uint32_t m_maxDNATEntries = 100; + uint32_t m_maxIPMCEntries = 100; + uint32_t m_maxDoubleNATEntries = 50; + + // Usage counters + uint32_t m_ipv4RouteCount = 0; + uint32_t m_ipv6RouteCount = 0; + uint32_t m_fdbCount = 0; + uint32_t m_ipv4NeighborCount = 0; + uint32_t m_ipv6NeighborCount = 0; + uint32_t m_ipv4NexthopCount = 0; + uint32_t m_ipv6NexthopCount = 0; + uint32_t m_nhgCount = 0; + uint32_t m_nhgMemberCount = 0; + }; +} diff --git a/vslib/vpp/SwitchVpp.cpp b/vslib/vpp/SwitchVpp.cpp index 4f60ba6c..712791f0 100644 --- a/vslib/vpp/SwitchVpp.cpp +++ b/vslib/vpp/SwitchVpp.cpp @@ -865,16 +865,7 @@ sai_status_t SwitchVpp::create( sai_status_t status = addIpRoute(serializedObjectId, switch_id, attr_count, attr_list); if (status == SAI_STATUS_SUCCESS) { - if (isIPv4Route(serializedObjectId)) - { - m_ipv4_route_count++; - SWSS_LOG_DEBUG("CRM: IPv4 route created, count: %u", m_ipv4_route_count); - } - else - { - m_ipv6_route_count++; - SWSS_LOG_DEBUG("CRM: IPv6 route created, count: %u", m_ipv6_route_count); - } + m_crmTracker.onRouteCreated(isIPv4Route(serializedObjectId)); } return status; } @@ -897,17 +888,41 @@ sai_status_t SwitchVpp::create( if (object_type == SAI_OBJECT_TYPE_NEXT_HOP) { - return createNexthop(serializedObjectId, switch_id, attr_count, attr_list); + sai_status_t status = createNexthop(serializedObjectId, switch_id, attr_count, attr_list); + if (status == SAI_STATUS_SUCCESS) + { + bool ipv4 = true; + for (uint32_t i = 0; i < attr_count; i++) + { + if (attr_list[i].id == SAI_NEXT_HOP_ATTR_IP) + { + ipv4 = (attr_list[i].value.ipaddr.addr_family == SAI_IP_ADDR_FAMILY_IPV4); + break; + } + } + m_crmTracker.onNexthopCreated(ipv4); + } + return status; } if (object_type == SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER) { - return createNexthopGroupMember(serializedObjectId, switch_id, attr_count, attr_list); + sai_status_t status = createNexthopGroupMember(serializedObjectId, switch_id, attr_count, attr_list); + if (status == SAI_STATUS_SUCCESS) + { + m_crmTracker.onNhgMemberCreated(); + } + return status; } if (object_type == SAI_OBJECT_TYPE_NEIGHBOR_ENTRY) { - return addIpNbr(serializedObjectId, switch_id, attr_count, attr_list); + sai_status_t status = addIpNbr(serializedObjectId, switch_id, attr_count, attr_list); + if (status == SAI_STATUS_SUCCESS) + { + m_crmTracker.onNeighborCreated(isIPv4Neighbor(serializedObjectId)); + } + return status; } if (object_type == SAI_OBJECT_TYPE_ACL_ENTRY) @@ -970,8 +985,7 @@ sai_status_t SwitchVpp::create( sai_status_t status = FdbEntryadd(serializedObjectId, switch_id, attr_count, attr_list); if (status == SAI_STATUS_SUCCESS) { - m_fdb_entry_count++; - SWSS_LOG_DEBUG("CRM: FDB entry created, count: %u", m_fdb_entry_count); + m_crmTracker.onFdbCreated(); } return status; } @@ -994,6 +1008,16 @@ sai_status_t SwitchVpp::create( return createLagMember(object_id, switch_id, attr_count, attr_list); } + if (object_type == SAI_OBJECT_TYPE_NEXT_HOP_GROUP) + { + sai_status_t status = create_internal(object_type, serializedObjectId, switch_id, attr_count, attr_list); + if (status == SAI_STATUS_SUCCESS) + { + m_crmTracker.onNhgCreated(); + } + return status; + } + return create_internal(object_type, serializedObjectId, switch_id, attr_count, attr_list); } @@ -1148,16 +1172,7 @@ sai_status_t SwitchVpp::remove( sai_status_t status = removeIpRoute(serializedObjectId); if (status == SAI_STATUS_SUCCESS) { - if (wasIPv4) - { - if (m_ipv4_route_count > 0) m_ipv4_route_count--; - SWSS_LOG_DEBUG("CRM: IPv4 route removed, count: %u", m_ipv4_route_count); - } - else - { - if (m_ipv6_route_count > 0) m_ipv6_route_count--; - SWSS_LOG_DEBUG("CRM: IPv6 route removed, count: %u", m_ipv6_route_count); - } + m_crmTracker.onRouteRemoved(wasIPv4); } return status; } @@ -1183,17 +1198,45 @@ sai_status_t SwitchVpp::remove( if (object_type == SAI_OBJECT_TYPE_NEXT_HOP) { - return removeNexthop(serializedObjectId); + // Determine IP family before remove (object still exists) + bool ipv4 = true; + auto nh_obj = get_sai_object(SAI_OBJECT_TYPE_NEXT_HOP, serializedObjectId); + if (nh_obj) + { + sai_attribute_t ip_attr; + ip_attr.id = SAI_NEXT_HOP_ATTR_IP; + if (nh_obj->get_attr(ip_attr) == SAI_STATUS_SUCCESS) + { + ipv4 = (ip_attr.value.ipaddr.addr_family == SAI_IP_ADDR_FAMILY_IPV4); + } + } + sai_status_t status = removeNexthop(serializedObjectId); + if (status == SAI_STATUS_SUCCESS) + { + m_crmTracker.onNexthopRemoved(ipv4); + } + return status; } if (object_type == SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER) { - return removeNexthopGroupMember(serializedObjectId); + sai_status_t status = removeNexthopGroupMember(serializedObjectId); + if (status == SAI_STATUS_SUCCESS) + { + m_crmTracker.onNhgMemberRemoved(); + } + return status; } if (object_type == SAI_OBJECT_TYPE_NEIGHBOR_ENTRY) { - return removeIpNbr(serializedObjectId); + bool ipv4 = isIPv4Neighbor(serializedObjectId); + sai_status_t status = removeIpNbr(serializedObjectId); + if (status == SAI_STATUS_SUCCESS) + { + m_crmTracker.onNeighborRemoved(ipv4); + } + return status; } if (object_type == SAI_OBJECT_TYPE_ACL_ENTRY) @@ -1258,8 +1301,7 @@ sai_status_t SwitchVpp::remove( sai_status_t status = FdbEntrydel(serializedObjectId); if (status == SAI_STATUS_SUCCESS) { - if (m_fdb_entry_count > 0) m_fdb_entry_count--; - SWSS_LOG_DEBUG("CRM: FDB entry removed, count: %u", m_fdb_entry_count); + m_crmTracker.onFdbRemoved(); } return status; } @@ -1268,6 +1310,16 @@ sai_status_t SwitchVpp::remove( return bfd_session_del(serializedObjectId); } + if (object_type == SAI_OBJECT_TYPE_NEXT_HOP_GROUP) + { + sai_status_t status = remove_internal(object_type, serializedObjectId); + if (status == SAI_STATUS_SUCCESS) + { + m_crmTracker.onNhgRemoved(); + } + return status; + } + return remove_internal(object_type, serializedObjectId); } @@ -2047,81 +2099,27 @@ bool SwitchVpp::isIPv4Route( return route_entry.destination.addr_family == SAI_IP_ADDR_FAMILY_IPV4; } -void SwitchVpp::loadCrmProfileValues() +bool SwitchVpp::isIPv4Neighbor( + const std::string &serializedObjectId) { SWSS_LOG_ENTER(); - const auto &profileMap = m_switchConfig->m_profileMap; - - if (profileMap.empty()) - { - SWSS_LOG_NOTICE("CRM: profile map is empty, using defaults (IPv4=%u, IPv6=%u, FDB=%u)", - m_vppMaxIPv4RouteEntries, m_vppMaxIPv6RouteEntries, m_vppMaxFdbEntries); - return; - } - - auto it = profileMap.find("SAI_VPP_MAX_IPV4_ROUTE_ENTRIES"); - if (it != profileMap.end()) - { - m_vppMaxIPv4RouteEntries = (uint32_t)std::stoul(it->second); - } - - it = profileMap.find("SAI_VPP_MAX_IPV6_ROUTE_ENTRIES"); - if (it != profileMap.end()) - { - m_vppMaxIPv6RouteEntries = (uint32_t)std::stoul(it->second); - } - - it = profileMap.find("SAI_VPP_MAX_FDB_ENTRIES"); - if (it != profileMap.end()) - { - m_vppMaxFdbEntries = (uint32_t)std::stoul(it->second); - } - - SWSS_LOG_NOTICE("CRM: profile loaded (IPv4=%u, IPv6=%u, FDB=%u)", - m_vppMaxIPv4RouteEntries, m_vppMaxIPv6RouteEntries, m_vppMaxFdbEntries); + sai_neighbor_entry_t neighbor_entry; + sai_deserialize_neighbor_entry(serializedObjectId, neighbor_entry); + return neighbor_entry.ip_address.addr_family == SAI_IP_ADDR_FAMILY_IPV4; } sai_status_t SwitchVpp::set_static_crm_values() { SWSS_LOG_ENTER(); - // Load configurable CRM limits from sai_vpp.profile - loadCrmProfileValues(); + m_crmTracker.loadProfileValues(m_switchConfig->m_profileMap); - // Override the base class static values with our configurable ones sai_attribute_t attr; - - attr.id = SAI_SWITCH_ATTR_AVAILABLE_IPV4_ROUTE_ENTRY; - attr.value.u32 = m_vppMaxIPv4RouteEntries; - CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); - - attr.id = SAI_SWITCH_ATTR_AVAILABLE_IPV6_ROUTE_ENTRY; - attr.value.u32 = m_vppMaxIPv6RouteEntries; - CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); - - attr.id = SAI_SWITCH_ATTR_AVAILABLE_FDB_ENTRY; - attr.value.u32 = m_vppMaxFdbEntries; - CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); - - // For remaining resources (nexthop, neighbor, nhg, etc.), use base class defaults - std::map remaining_resources = { - { SAI_SWITCH_ATTR_AVAILABLE_IPV4_NEXTHOP_ENTRY, m_maxIPv4NextHopEntries }, - { SAI_SWITCH_ATTR_AVAILABLE_IPV6_NEXTHOP_ENTRY, m_maxIPv6NextHopEntries }, - { SAI_SWITCH_ATTR_AVAILABLE_IPV4_NEIGHBOR_ENTRY, m_maxIPv4NeighborEntries }, - { SAI_SWITCH_ATTR_AVAILABLE_IPV6_NEIGHBOR_ENTRY, m_maxIPv6NeighborEntries }, - { SAI_SWITCH_ATTR_AVAILABLE_NEXT_HOP_GROUP_MEMBER_ENTRY, m_maxNextHopGroupMemberEntries }, - { SAI_SWITCH_ATTR_AVAILABLE_NEXT_HOP_GROUP_ENTRY, m_maxNextHopGroupEntries }, - { SAI_SWITCH_ATTR_AVAILABLE_SNAT_ENTRY, m_maxSNATEntries }, - { SAI_SWITCH_ATTR_AVAILABLE_DNAT_ENTRY, m_maxDNATEntries }, - { SAI_SWITCH_ATTR_AVAILABLE_IPMC_ENTRY, m_maxIPMCEntries }, - { SAI_SWITCH_ATTR_AVAILABLE_DOUBLE_NAT_ENTRY, m_maxDoubleNATEntries } - }; - - for (auto const &resource: remaining_resources) + for (const auto& v : m_crmTracker.getInitialValues()) { - attr.id = resource.first; - attr.value.u32 = resource.second; + attr.id = v.attr_id; + attr.value.u32 = v.value; CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); } @@ -2172,31 +2170,13 @@ sai_status_t SwitchVpp::refresh_read_only( } // Dynamic CRM resource availability: return max - used - if (meta->objecttype == SAI_OBJECT_TYPE_SWITCH) + if (meta->objecttype == SAI_OBJECT_TYPE_SWITCH && + m_crmTracker.handles((sai_switch_attr_t)meta->attrid)) { sai_attribute_t attr; attr.id = meta->attrid; - - switch (meta->attrid) - { - case SAI_SWITCH_ATTR_AVAILABLE_IPV4_ROUTE_ENTRY: - attr.value.u32 = (m_vppMaxIPv4RouteEntries > m_ipv4_route_count) - ? (m_vppMaxIPv4RouteEntries - m_ipv4_route_count) : 0; - return set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr); - - case SAI_SWITCH_ATTR_AVAILABLE_IPV6_ROUTE_ENTRY: - attr.value.u32 = (m_vppMaxIPv6RouteEntries > m_ipv6_route_count) - ? (m_vppMaxIPv6RouteEntries - m_ipv6_route_count) : 0; - return set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr); - - case SAI_SWITCH_ATTR_AVAILABLE_FDB_ENTRY: - attr.value.u32 = (m_vppMaxFdbEntries > m_fdb_entry_count) - ? (m_vppMaxFdbEntries - m_fdb_entry_count) : 0; - return set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr); - - default: - break; - } + attr.value.u32 = m_crmTracker.getAvailable((sai_switch_attr_t)meta->attrid); + return set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr); } // For all other cases, delegate to the base class implementation diff --git a/vslib/vpp/SwitchVpp.h b/vslib/vpp/SwitchVpp.h index 30d4961b..2285b796 100644 --- a/vslib/vpp/SwitchVpp.h +++ b/vslib/vpp/SwitchVpp.h @@ -8,6 +8,7 @@ #include "TunnelManager.h" #include "SwitchVppNexthop.h" #include "SwitchVppAcl.h" +#include "CRMTracker.h" #include "vppxlate/SaiVppXlate.h" @@ -974,19 +975,10 @@ namespace saivs std::map> m_hostif_info_map; - // CRM resource limits (configurable via profile map from -p argument) - uint32_t m_vppMaxIPv4RouteEntries = m_maxIPv4RouteEntries; - uint32_t m_vppMaxIPv6RouteEntries = m_maxIPv6RouteEntries; - uint32_t m_vppMaxFdbEntries = m_maxFdbEntries; - - // CRM resource tracking counters - uint32_t m_ipv4_route_count = 0; - uint32_t m_ipv6_route_count = 0; - uint32_t m_fdb_entry_count = 0; + CRMTracker m_crmTracker; bool isIPv4Route(const std::string &serializedObjectId); - - void loadCrmProfileValues(); + bool isIPv4Neighbor(const std::string &serializedObjectId); virtual sai_status_t set_static_crm_values() override;