From 2d6975d7a3625de2b9d14d556dbcd42fb8cbfa57 Mon Sep 17 00:00:00 2001 From: Arvind Bhat Date: Thu, 6 Oct 2022 15:14:46 -0700 Subject: [PATCH] SAI NAT aging notification (#987) The sairedis changes related to the SAI here: opencomputeproject/SAI#1365 --- lib/Switch.cpp | 5 + meta/Makefile.am | 1 + meta/Meta.cpp | 49 +++++++++ meta/Meta.h | 7 ++ meta/MetaKeyHasher.cpp | 2 +- meta/NotificationFactory.cpp | 4 + meta/NotificationNatEvent.cpp | 97 +++++++++++++++++ meta/NotificationNatEvent.h | 35 ++++++ meta/SaiSerialize.cpp | 106 +++++++++++++++++++ meta/sai_serialize.h | 16 +++ syncd/NotificationHandler.cpp | 15 +++ syncd/NotificationHandler.h | 4 + syncd/NotificationProcessor.cpp | 99 +++++++++++++++++ syncd/NotificationProcessor.h | 10 ++ syncd/SwitchNotifications.cpp | 10 ++ syncd/SwitchNotifications.h | 17 ++- syncd/Syncd.cpp | 6 ++ unittest/lib/TestSwitch.cpp | 5 +- unittest/meta/Makefile.am | 1 + unittest/meta/TestNotificationFactory.cpp | 9 ++ unittest/meta/TestNotificationNatEvent.cpp | 88 +++++++++++++++ unittest/meta/TestSaiSerialize.cpp | 5 + unittest/syncd/Makefile.am | 2 + unittest/syncd/TestNotificationHandler.cpp | 32 ++++++ unittest/syncd/TestNotificationProcessor.cpp | 52 +++++++++ 25 files changed, 674 insertions(+), 3 deletions(-) create mode 100644 meta/NotificationNatEvent.cpp create mode 100644 meta/NotificationNatEvent.h create mode 100644 unittest/meta/TestNotificationNatEvent.cpp create mode 100644 unittest/syncd/TestNotificationHandler.cpp create mode 100644 unittest/syncd/TestNotificationProcessor.cpp diff --git a/lib/Switch.cpp b/lib/Switch.cpp index 8e513e145..c7af4a297 100644 --- a/lib/Switch.cpp +++ b/lib/Switch.cpp @@ -93,6 +93,11 @@ void Switch::updateNotifications( (sai_fdb_event_notification_fn)attr.value.ptr; break; + case SAI_SWITCH_ATTR_NAT_EVENT_NOTIFY: + m_switchNotifications.on_nat_event = + (sai_nat_event_notification_fn)attr.value.ptr; + break; + case SAI_SWITCH_ATTR_PORT_STATE_CHANGE_NOTIFY: m_switchNotifications.on_port_state_change = (sai_port_state_change_notification_fn)attr.value.ptr; diff --git a/meta/Makefile.am b/meta/Makefile.am index 89cf12562..0667fb4ba 100644 --- a/meta/Makefile.am +++ b/meta/Makefile.am @@ -29,6 +29,7 @@ libsaimeta_la_SOURCES = \ Notification.cpp \ NotificationFactory.cpp \ NotificationFdbEvent.cpp \ + NotificationNatEvent.cpp \ NotificationPortStateChange.cpp \ NotificationQueuePfcDeadlock.cpp \ NotificationSwitchShutdownRequest.cpp \ diff --git a/meta/Meta.cpp b/meta/Meta.cpp index 2db3fc09e..ba2d33b40 100644 --- a/meta/Meta.cpp +++ b/meta/Meta.cpp @@ -7594,6 +7594,55 @@ void Meta::meta_sai_on_fdb_event( } } +void Meta::meta_sai_on_nat_event_single( + _In_ const sai_nat_event_notification_data_t& data) +{ + SWSS_LOG_ENTER(); + + const sai_object_meta_key_t meta_key_nat = { .objecttype = SAI_OBJECT_TYPE_NAT_ENTRY, .objectkey = { .key = { .nat_entry = data.nat_entry } } }; + + switch (data.event_type) + { + case SAI_NAT_EVENT_AGED: + + if (!m_saiObjectCollection.objectExists(meta_key_nat)) + { + SWSS_LOG_WARN("object key %s doesn't exist but received AGED event", + sai_serialize_object_meta_key(meta_key_nat).c_str()); + break; + } + // meta_generic_validation_post_remove is not done at this point + // as Nat-orch will be performing the cleanup for both Aging and + // Hit-bit implementations. + + break; + + case SAI_NAT_EVENT_NONE: + default: + + SWSS_LOG_ERROR("got NAT_ENTRY notification with unknown event_type %d, bug?", data.event_type); + break; + } +} + +void Meta::meta_sai_on_nat_event( + _In_ uint32_t count, + _In_ const sai_nat_event_notification_data_t *data) +{ + SWSS_LOG_ENTER(); + + if (count && data == NULL) + { + SWSS_LOG_ERROR("nat_event_notification_data pointer is NULL when count is %u", count); + return; + } + + for (uint32_t i = 0; i < count; ++i) + { + meta_sai_on_nat_event_single(data[i]); + } +} + void Meta::meta_sai_on_switch_state_change( _In_ sai_object_id_t switch_id, _In_ sai_switch_oper_status_t switch_oper_status) diff --git a/meta/Meta.h b/meta/Meta.h index 82418a91d..dc66946f8 100644 --- a/meta/Meta.h +++ b/meta/Meta.h @@ -197,6 +197,10 @@ namespace saimeta _In_ uint32_t count, _In_ const sai_fdb_event_notification_data_t *data); + void meta_sai_on_nat_event( + _In_ uint32_t count, + _In_ const sai_nat_event_notification_data_t *data); + void meta_sai_on_switch_state_change( _In_ sai_object_id_t switch_id, _In_ sai_switch_oper_status_t switch_oper_status); @@ -227,6 +231,9 @@ namespace saimeta void meta_sai_on_fdb_event_single( _In_ const sai_fdb_event_notification_data_t& data); + void meta_sai_on_nat_event_single( + _In_ const sai_nat_event_notification_data_t& data); + void meta_sai_on_port_state_change_single( _In_ const sai_port_oper_status_notification_t& data); diff --git a/meta/MetaKeyHasher.cpp b/meta/MetaKeyHasher.cpp index cdeb68c7d..cebdd67ed 100644 --- a/meta/MetaKeyHasher.cpp +++ b/meta/MetaKeyHasher.cpp @@ -322,7 +322,7 @@ static inline std::size_t sai_get_hash( // TODO revisit - may depend on nat_type - return ne.data.key.src_ip ^ ne.data.key.dst_ip; + return ne.data.key.src_ip ^ ne.data.key.dst_ip ^ ne.data.key.proto ^ ne.data.key.l4_src_port ^ ne.data.key.l4_dst_port; } static inline std::size_t sai_get_hash( diff --git a/meta/NotificationFactory.cpp b/meta/NotificationFactory.cpp index c9adf4863..9682848d8 100644 --- a/meta/NotificationFactory.cpp +++ b/meta/NotificationFactory.cpp @@ -1,5 +1,6 @@ #include "NotificationFactory.h" #include "NotificationFdbEvent.h" +#include "NotificationNatEvent.h" #include "NotificationPortStateChange.h" #include "NotificationQueuePfcDeadlock.h" #include "NotificationSwitchShutdownRequest.h" @@ -20,6 +21,9 @@ std::shared_ptr NotificationFactory::deserialize( if (name == SAI_SWITCH_NOTIFICATION_NAME_FDB_EVENT) return std::make_shared(serializedNotification); + if (name == SAI_SWITCH_NOTIFICATION_NAME_NAT_EVENT) + return std::make_shared(serializedNotification); + if (name == SAI_SWITCH_NOTIFICATION_NAME_PORT_STATE_CHANGE) return std::make_shared(serializedNotification); diff --git a/meta/NotificationNatEvent.cpp b/meta/NotificationNatEvent.cpp new file mode 100644 index 000000000..5653e877c --- /dev/null +++ b/meta/NotificationNatEvent.cpp @@ -0,0 +1,97 @@ +#include "NotificationNatEvent.h" + +#include "swss/logger.h" + +#include "sai_serialize.h" + +using namespace sairedis; + +NotificationNatEvent::NotificationNatEvent( + _In_ const std::string& serializedNotification): + Notification( + SAI_SWITCH_NOTIFICATION_TYPE_NAT_EVENT, + serializedNotification), + m_natEventNotificationData(nullptr) +{ + SWSS_LOG_ENTER(); + + sai_deserialize_nat_event_ntf( + serializedNotification, + m_count, + &m_natEventNotificationData); +} + +NotificationNatEvent::~NotificationNatEvent() +{ + SWSS_LOG_ENTER(); + + sai_deserialize_free_nat_event_ntf(m_count, m_natEventNotificationData); +} + +sai_object_id_t NotificationNatEvent::getSwitchId() const +{ + SWSS_LOG_ENTER(); + + if (m_natEventNotificationData == nullptr) + { + return SAI_NULL_OBJECT_ID; + } + + for (uint32_t idx = 0; idx < m_count; idx++) + { + auto& nat = m_natEventNotificationData[idx].nat_entry; + + if (nat.switch_id != SAI_NULL_OBJECT_ID) + { + return nat.switch_id; + } + } + + return SAI_NULL_OBJECT_ID; +} + +sai_object_id_t NotificationNatEvent::getAnyObjectId() const +{ + SWSS_LOG_ENTER(); + + if (m_natEventNotificationData == nullptr) + { + return SAI_NULL_OBJECT_ID; + } + + for (uint32_t idx = 0; idx < m_count; idx++) + { + auto& nat = m_natEventNotificationData[idx].nat_entry; + + if (nat.switch_id != SAI_NULL_OBJECT_ID) + { + return nat.switch_id; + } + + if (nat.vr_id != SAI_NULL_OBJECT_ID) + { + return nat.vr_id; + } + } + + return SAI_NULL_OBJECT_ID; +} + +void NotificationNatEvent::processMetadata( + _In_ std::shared_ptr meta) const +{ + SWSS_LOG_ENTER(); + + meta->meta_sai_on_nat_event(m_count, m_natEventNotificationData); +} + +void NotificationNatEvent::executeCallback( + _In_ const sai_switch_notifications_t& switchNotifications) const +{ + SWSS_LOG_ENTER(); + + if (switchNotifications.on_nat_event) + { + switchNotifications.on_nat_event(m_count, m_natEventNotificationData); + } +} diff --git a/meta/NotificationNatEvent.h b/meta/NotificationNatEvent.h new file mode 100644 index 000000000..e762c109a --- /dev/null +++ b/meta/NotificationNatEvent.h @@ -0,0 +1,35 @@ +#pragma once + +#include "Notification.h" + +namespace sairedis +{ + class NotificationNatEvent: + public Notification + { + public: + + NotificationNatEvent( + _In_ const std::string& serializedNotification); + + virtual ~NotificationNatEvent(); + + public: + + virtual sai_object_id_t getSwitchId() const override; + + virtual sai_object_id_t getAnyObjectId() const override; + + virtual void processMetadata( + _In_ std::shared_ptr meta) const override; + + virtual void executeCallback( + _In_ const sai_switch_notifications_t& switchNotifications) const override; + + private: + + uint32_t m_count; + + sai_nat_event_notification_data_t* m_natEventNotificationData; + }; +} diff --git a/meta/SaiSerialize.cpp b/meta/SaiSerialize.cpp index 1911954a0..862a382dc 100644 --- a/meta/SaiSerialize.cpp +++ b/meta/SaiSerialize.cpp @@ -1940,6 +1940,28 @@ static json sai_serialize_json_fdb_event_notification_data( return j; } +std::string sai_serialize_nat_event( + _In_ sai_nat_event_t event) +{ + SWSS_LOG_ENTER(); + + return sai_serialize_enum(event, &sai_metadata_enum_sai_nat_event_t); +} + +static json sai_serialize_json_nat_event_notification_data( + _In_ const sai_nat_event_notification_data_t& nat_event) +{ + SWSS_LOG_ENTER(); + + json j; + + j["nat_event"] = sai_serialize_nat_event(nat_event.event_type); + j["nat_entry"] = sai_serialize_nat_entry(nat_event.nat_entry); + + // we don't need count since it can be deduced + return j; +} + std::string sai_serialize_bfd_session_state( _In_ sai_bfd_session_state_t status) { @@ -1972,6 +1994,30 @@ std::string sai_serialize_fdb_event_ntf( return j.dump(); } +std::string sai_serialize_nat_event_ntf( + _In_ uint32_t count, + _In_ const sai_nat_event_notification_data_t* nat_event) +{ + SWSS_LOG_ENTER(); + + if (nat_event == NULL) + { + SWSS_LOG_THROW("nat_event pointer is null"); + } + + json j = json::array(); + + for (uint32_t i = 0; i < count; ++i) + { + json item = sai_serialize_json_nat_event_notification_data(nat_event[i]); + + j.push_back(item); + } + + // we don't need count since it can be deduced + return j.dump(); +} + std::string sai_serialize_port_oper_status_ntf( _In_ uint32_t count, _In_ const sai_port_oper_status_notification_t* port_oper_status) @@ -3444,6 +3490,15 @@ void sai_deserialize_fdb_event( sai_deserialize_enum(s, &sai_metadata_enum_sai_fdb_event_t, (int32_t&)event); } +void sai_deserialize_nat_event( + _In_ const std::string& s, + _Out_ sai_nat_event_t& event) +{ + SWSS_LOG_ENTER(); + + sai_deserialize_enum(s, &sai_metadata_enum_sai_nat_event_t, (int32_t&)event); +} + void sai_deserialize_bfd_session_state( _In_ const std::string& s, _Out_ sai_bfd_session_state_t& state) @@ -3906,6 +3961,37 @@ void sai_deserialize_fdb_event_ntf( *fdb_event = data; } +static void sai_deserialize_json_nat_event_notification_data( + _In_ const json& j, + _Out_ sai_nat_event_notification_data_t& nat) +{ + SWSS_LOG_ENTER(); + + sai_deserialize_nat_event(j["nat_event"], nat.event_type); + sai_deserialize_nat_entry(j["nat_entry"], nat.nat_entry); +} + +void sai_deserialize_nat_event_ntf( + _In_ const std::string& s, + _Out_ uint32_t &count, + _Out_ sai_nat_event_notification_data_t** nat_event) +{ + SWSS_LOG_ENTER(); + + json j = json::parse(s); + + count = (uint32_t)j.size(); + + auto data = new sai_nat_event_notification_data_t[count]; + + for (uint32_t i = 0; i < count; ++i) + { + sai_deserialize_json_nat_event_notification_data(j[i], data[i]); + } + + *nat_event = data; +} + void sai_deserialize_port_oper_status_ntf( _In_ const std::string& s, _Out_ uint32_t &count, @@ -4170,6 +4256,26 @@ void sai_deserialize_free_fdb_event_ntf( delete[] fdb_event; } +void sai_deserialize_free_nat_event( + _In_ sai_nat_event_notification_data_t& nat_event) +{ + SWSS_LOG_ENTER(); +} + +void sai_deserialize_free_nat_event_ntf( + _In_ uint32_t count, + _In_ sai_nat_event_notification_data_t* nat_event) +{ + SWSS_LOG_ENTER(); + + for (uint32_t i = 0; i < count; ++i) + { + sai_deserialize_free_nat_event(nat_event[i]); + } + + delete[] nat_event; +} + void sai_deserialize_free_port_oper_status_ntf( _In_ uint32_t count, _In_ sai_port_oper_status_notification_t* port_oper_status) diff --git a/meta/sai_serialize.h b/meta/sai_serialize.h index 3cbef0222..7c2827b0c 100644 --- a/meta/sai_serialize.h +++ b/meta/sai_serialize.h @@ -33,6 +33,9 @@ sai_status_t transfer_attributes( std::string sai_serialize_fdb_event( _In_ sai_fdb_event_t event); +std::string sai_serialize_nat_event( + _In_ sai_nat_event_t event); + std::string sai_serialize_ipv6( _In_ const sai_ip6_t& ip); @@ -232,6 +235,10 @@ std::string sai_serialize_fdb_event_ntf( _In_ uint32_t count, _In_ const sai_fdb_event_notification_data_t* fdb_event); +std::string sai_serialize_nat_event_ntf( + _In_ uint32_t count, + _In_ const sai_nat_event_notification_data_t* nat_event); + std::string sai_serialize_port_oper_status_ntf( _In_ uint32_t count, _In_ const sai_port_oper_status_notification_t* port_oper_status); @@ -394,6 +401,11 @@ void sai_deserialize_fdb_event_ntf( _Out_ uint32_t &count, _Out_ sai_fdb_event_notification_data_t** fdbdata); +void sai_deserialize_nat_event_ntf( + _In_ const std::string& s, + _Out_ uint32_t &count, + _Out_ sai_nat_event_notification_data_t** natdata); + void sai_deserialize_port_oper_status_ntf( _In_ const std::string& s, _Out_ uint32_t &count, @@ -421,6 +433,10 @@ void sai_deserialize_free_fdb_event_ntf( _In_ uint32_t count, _In_ sai_fdb_event_notification_data_t* fdbdata); +void sai_deserialize_free_nat_event_ntf( + _In_ uint32_t count, + _In_ sai_nat_event_notification_data_t* natdata); + void sai_deserialize_free_port_oper_status_ntf( _In_ uint32_t count, _In_ sai_port_oper_status_notification_t* portoperstatus); diff --git a/syncd/NotificationHandler.cpp b/syncd/NotificationHandler.cpp index 2e897a1fb..7e0c29573 100644 --- a/syncd/NotificationHandler.cpp +++ b/syncd/NotificationHandler.cpp @@ -100,6 +100,10 @@ void NotificationHandler::updateNotificationsPointers( attr.value.ptr = (void*)m_switchNotifications.on_fdb_event; break; + case SAI_SWITCH_ATTR_NAT_EVENT_NOTIFY: + attr.value.ptr = (void*)m_switchNotifications.on_nat_event; + break; + case SAI_SWITCH_ATTR_PORT_STATE_CHANGE_NOTIFY: attr.value.ptr = (void*)m_switchNotifications.on_port_state_change; break; @@ -138,6 +142,17 @@ void NotificationHandler::onFdbEvent( enqueueNotification(SAI_SWITCH_NOTIFICATION_NAME_FDB_EVENT, s); } +void NotificationHandler::onNatEvent( + _In_ uint32_t count, + _In_ const sai_nat_event_notification_data_t *data) +{ + SWSS_LOG_ENTER(); + + std::string s = sai_serialize_nat_event_ntf(count, data); + + enqueueNotification(SAI_SWITCH_NOTIFICATION_NAME_NAT_EVENT, s); +} + void NotificationHandler::onPortStateChange( _In_ uint32_t count, _In_ const sai_port_oper_status_notification_t *data) diff --git a/syncd/NotificationHandler.h b/syncd/NotificationHandler.h index 4c3e7a934..060009b49 100644 --- a/syncd/NotificationHandler.h +++ b/syncd/NotificationHandler.h @@ -41,6 +41,10 @@ namespace syncd _In_ uint32_t count, _In_ const sai_fdb_event_notification_data_t *data); + void onNatEvent( + _In_ uint32_t count, + _In_ const sai_nat_event_notification_data_t *data); + void onPortStateChange( _In_ uint32_t count, _In_ const sai_port_oper_status_notification_t *data); diff --git a/syncd/NotificationProcessor.cpp b/syncd/NotificationProcessor.cpp index 3392d3ddc..a758fd37d 100644 --- a/syncd/NotificationProcessor.cpp +++ b/syncd/NotificationProcessor.cpp @@ -347,6 +347,86 @@ void NotificationProcessor::process_on_fdb_event( } } +/** + * @Brief Check NAT event notification data. + * + * Every OID field in notification data as well as all OID attributes are + * checked if given OID (returned from ASIC) is already present in the syncd + * local database. If vendor SAI will return unknown/invalid OID, this + * function will return false. + * + * @param data NAT event notification data + * + * @return False if any of OID values is not present in local DB, otherwise + * true. + */ +bool NotificationProcessor::check_nat_event_notification_data( + _In_ const sai_nat_event_notification_data_t& data) +{ + SWSS_LOG_ENTER(); + + bool result = true; + + if (!m_translator->checkRidExists(data.nat_entry.vr_id, true)) + { + SWSS_LOG_ERROR("vr_id RID 0x%" PRIx64 " is not present on local ASIC DB: %s", data.nat_entry.vr_id, + sai_serialize_nat_entry(data.nat_entry).c_str()); + + result = false; + } + + if (!m_translator->checkRidExists(data.nat_entry.switch_id) || data.nat_entry.switch_id == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_ERROR("switch_id RID 0x%" PRIx64 " is not present on local ASIC DB: %s", data.nat_entry.switch_id, + sai_serialize_nat_entry(data.nat_entry).c_str()); + + result = false; + } + + return result; +} + +void NotificationProcessor::process_on_nat_event( + _In_ uint32_t count, + _In_ sai_nat_event_notification_data_t *data) +{ + SWSS_LOG_ENTER(); + + SWSS_LOG_INFO("nat event count: %u", count); + + bool sendntf = true; + + for (uint32_t i = 0; i < count; i++) + { + sai_nat_event_notification_data_t *nat = &data[i]; + + sendntf &= check_nat_event_notification_data(*nat); + + if (!sendntf) + { + SWSS_LOG_ERROR("invalid OIDs in nat notifications, NOT translating and NOT storing in ASIC DB"); + continue; + } + + SWSS_LOG_DEBUG("nat %u: type: %d", i, nat->event_type); + + nat->nat_entry.switch_id = m_translator->translateRidToVid(nat->nat_entry.switch_id, SAI_NULL_OBJECT_ID); + + nat->nat_entry.vr_id = m_translator->translateRidToVid(nat->nat_entry.vr_id, nat->nat_entry.switch_id, true); + } + + if (sendntf) + { + std::string s = sai_serialize_nat_event_ntf(count, data); + + sendNotification(SAI_SWITCH_NOTIFICATION_NAME_NAT_EVENT, s); + } + else + { + SWSS_LOG_ERROR("NAT notification was not sent since it contain invalid OIDs, bug?"); + } +} + void NotificationProcessor::process_on_queue_deadlock_event( _In_ uint32_t count, _In_ sai_queue_deadlock_notification_data_t *data) @@ -494,6 +574,21 @@ void NotificationProcessor::handle_fdb_event( sai_deserialize_free_fdb_event_ntf(count, fdbevent); } +void NotificationProcessor::handle_nat_event( + _In_ const std::string &data) +{ + SWSS_LOG_ENTER(); + + uint32_t count; + sai_nat_event_notification_data_t *natevent = NULL; + + sai_deserialize_nat_event_ntf(data, count, &natevent); + + process_on_nat_event(count, natevent); + + sai_deserialize_free_nat_event_ntf(count, natevent); +} + void NotificationProcessor::handle_queue_deadlock( _In_ const std::string &data) { @@ -575,6 +670,10 @@ void NotificationProcessor::syncProcessNotification( { handle_fdb_event(data); } + else if (notification == SAI_SWITCH_NOTIFICATION_NAME_NAT_EVENT) + { + handle_nat_event(data); + } else if (notification == SAI_SWITCH_NOTIFICATION_NAME_PORT_STATE_CHANGE) { handle_port_state_change(data); diff --git a/syncd/NotificationProcessor.h b/syncd/NotificationProcessor.h index d378fe612..f7ac2c674 100644 --- a/syncd/NotificationProcessor.h +++ b/syncd/NotificationProcessor.h @@ -58,6 +58,9 @@ namespace syncd bool check_fdb_event_notification_data( _In_ const sai_fdb_event_notification_data_t& data); + bool check_nat_event_notification_data( + _In_ const sai_nat_event_notification_data_t& data); + bool contains_fdb_flush_event( _In_ uint32_t count, _In_ const sai_fdb_event_notification_data_t *data); @@ -73,6 +76,10 @@ namespace syncd _In_ uint32_t count, _In_ sai_fdb_event_notification_data_t *data); + void process_on_nat_event( + _In_ uint32_t count, + _In_ sai_nat_event_notification_data_t *data); + void process_on_queue_deadlock_event( _In_ uint32_t count, _In_ sai_queue_deadlock_notification_data_t *data); @@ -96,6 +103,9 @@ namespace syncd void handle_fdb_event( _In_ const std::string &data); + void handle_nat_event( + _In_ const std::string &data); + void handle_queue_deadlock( _In_ const std::string &data); diff --git a/syncd/SwitchNotifications.cpp b/syncd/SwitchNotifications.cpp index a39b4ab48..75d176e74 100644 --- a/syncd/SwitchNotifications.cpp +++ b/syncd/SwitchNotifications.cpp @@ -47,6 +47,16 @@ void SwitchNotifications::SlotBase::onFdbEvent( return m_slots.at(context)->m_handler->onFdbEvent(count,data); } +void SwitchNotifications::SlotBase::onNatEvent( + _In_ int context, + _In_ uint32_t count, + _In_ const sai_nat_event_notification_data_t *data) +{ + SWSS_LOG_ENTER(); + + return m_slots.at(context)->m_handler->onNatEvent(count,data); +} + void SwitchNotifications::SlotBase::onPortStateChange( _In_ int context, _In_ uint32_t count, diff --git a/syncd/SwitchNotifications.h b/syncd/SwitchNotifications.h index 798f7cb9f..e5789e241 100644 --- a/syncd/SwitchNotifications.h +++ b/syncd/SwitchNotifications.h @@ -40,6 +40,11 @@ namespace syncd _In_ uint32_t count, _In_ const sai_fdb_event_notification_data_t *data); + static void onNatEvent( + _In_ int context, + _In_ uint32_t count, + _In_ const sai_nat_event_notification_data_t *data); + static void onPortStateChange( _In_ int context, _In_ uint32_t count, @@ -82,7 +87,7 @@ namespace syncd .on_bfd_session_state_change = &Slot::onBfdSessionStateChange, .on_fdb_event = &Slot::onFdbEvent, .on_ipsec_sa_status_change = nullptr, - .on_nat_event = nullptr, + .on_nat_event = &Slot::onNatEvent, .on_packet_event = nullptr, .on_port_state_change = &Slot::onPortStateChange, .on_queue_pfc_deadlock = &Slot::onQueuePfcDeadlock, @@ -104,6 +109,15 @@ namespace syncd return SlotBase::onFdbEvent(context, count, data); } + static void onNatEvent( + _In_ uint32_t count, + _In_ const sai_nat_event_notification_data_t *data) + { + SWSS_LOG_ENTER(); + + return SlotBase::onNatEvent(context, count, data); + } + static void onPortStateChange( _In_ uint32_t count, _In_ const sai_port_oper_status_notification_t *data) @@ -164,6 +178,7 @@ namespace syncd public: // wrapped methods std::function onFdbEvent; + std::function onNatEvent; std::function onPortStateChange; std::function onQueuePfcDeadlock; std::function onSwitchShutdownRequest; diff --git a/syncd/Syncd.cpp b/syncd/Syncd.cpp index 123bec25e..fd29a87ab 100644 --- a/syncd/Syncd.cpp +++ b/syncd/Syncd.cpp @@ -140,6 +140,7 @@ Syncd::Syncd( m_handler = std::make_shared(m_processor); m_sn.onFdbEvent = std::bind(&NotificationHandler::onFdbEvent, m_handler.get(), _1, _2); + m_sn.onNatEvent = std::bind(&NotificationHandler::onNatEvent, m_handler.get(), _1, _2); m_sn.onPortStateChange = std::bind(&NotificationHandler::onPortStateChange, m_handler.get(), _1, _2); m_sn.onQueuePfcDeadlock = std::bind(&NotificationHandler::onQueuePfcDeadlock, m_handler.get(), _1, _2); m_sn.onSwitchShutdownRequest = std::bind(&NotificationHandler::onSwitchShutdownRequest, m_handler.get(), _1); @@ -1397,6 +1398,10 @@ sai_status_t Syncd::processBulkEntry( sai_deserialize_route_entry(objectIds[idx], metaKey.objectkey.key.route_entry); break; + case SAI_OBJECT_TYPE_NAT_ENTRY: + sai_deserialize_nat_entry(objectIds[idx], metaKey.objectkey.key.nat_entry); + break; + case SAI_OBJECT_TYPE_FDB_ENTRY: sai_deserialize_fdb_entry(objectIds[idx], metaKey.objectkey.key.fdb_entry); break; @@ -4014,6 +4019,7 @@ void Syncd::performWarmRestartSingleSwitch( SAI_SWITCH_ATTR_SWITCH_STATE_CHANGE_NOTIFY, SAI_SWITCH_ATTR_SHUTDOWN_REQUEST_NOTIFY, SAI_SWITCH_ATTR_FDB_EVENT_NOTIFY, + SAI_SWITCH_ATTR_NAT_EVENT_NOTIFY, SAI_SWITCH_ATTR_PORT_STATE_CHANGE_NOTIFY, SAI_SWITCH_ATTR_QUEUE_PFC_DEADLOCK_NOTIFY, SAI_SWITCH_ATTR_BFD_SESSION_STATE_CHANGE_NOTIFY diff --git a/unittest/lib/TestSwitch.cpp b/unittest/lib/TestSwitch.cpp index 5e7bc9294..0969095e1 100644 --- a/unittest/lib/TestSwitch.cpp +++ b/unittest/lib/TestSwitch.cpp @@ -35,6 +35,7 @@ TEST(Switch, updateNotifications) attrs[4].value.ptr = (void*)1; attrs[5].value.ptr = (void*)1; attrs[6].value.ptr = (void*)1; + attrs[7].value.ptr = (void*)1; attrs[0].id = SAI_SWITCH_ATTR_SWITCH_STATE_CHANGE_NOTIFY; attrs[1].id = SAI_SWITCH_ATTR_SHUTDOWN_REQUEST_NOTIFY; @@ -43,7 +44,8 @@ TEST(Switch, updateNotifications) attrs[4].id = SAI_SWITCH_ATTR_PACKET_EVENT_NOTIFY; attrs[5].id = SAI_SWITCH_ATTR_QUEUE_PFC_DEADLOCK_NOTIFY; attrs[6].id = SAI_SWITCH_ATTR_BFD_SESSION_STATE_CHANGE_NOTIFY; - attrs[7].id = SAI_SWITCH_ATTR_INIT_SWITCH; + attrs[7].id = SAI_SWITCH_ATTR_NAT_EVENT_NOTIFY; + attrs[8].id = SAI_SWITCH_ATTR_INIT_SWITCH; s->updateNotifications(8, attrs); @@ -56,4 +58,5 @@ TEST(Switch, updateNotifications) EXPECT_EQ((void*)1, sn.on_queue_pfc_deadlock); EXPECT_EQ((void*)1, sn.on_switch_shutdown_request); EXPECT_EQ((void*)1, sn.on_switch_state_change); + EXPECT_EQ((void*)1, sn.on_nat_event); } diff --git a/unittest/meta/Makefile.am b/unittest/meta/Makefile.am index 48a52f103..49a10f265 100644 --- a/unittest/meta/Makefile.am +++ b/unittest/meta/Makefile.am @@ -19,6 +19,7 @@ tests_SOURCES = \ TestMetaKeyHasher.cpp \ TestNotificationFactory.cpp \ TestNotificationFdbEvent.cpp \ + TestNotificationNatEvent.cpp \ TestNotificationPortStateChange.cpp \ TestNotificationQueuePfcDeadlock.cpp \ TestNotificationSwitchShutdownRequest.cpp \ diff --git a/unittest/meta/TestNotificationFactory.cpp b/unittest/meta/TestNotificationFactory.cpp index 35a354ea8..02a68f68c 100644 --- a/unittest/meta/TestNotificationFactory.cpp +++ b/unittest/meta/TestNotificationFactory.cpp @@ -27,6 +27,15 @@ TEST(NotificationFactory, deserialize_fdb_event) EXPECT_EQ(ntf->getNotificationType(), SAI_SWITCH_NOTIFICATION_TYPE_FDB_EVENT); } +TEST(NotificationFactory, deserialize_nat_event) +{ + auto ntf = NotificationFactory::deserialize( + SAI_SWITCH_NOTIFICATION_NAME_NAT_EVENT, + "[{\"nat_entry\":\"{\\\"nat_data\\\":{\\\"key\\\":{\\\"dst_ip\\\":\\\"10.10.10.10\\\",\\\"l4_dst_port\\\":\\\"20006\\\",\\\"l4_src_port\\\":\\\"0\\\",\\\"proto\\\":\\\"6\\\",\\\"src_ip\\\":\\\"0.0.0.0\\\"},\\\"mask\\\":{\\\"dst_ip\\\":\\\"255.255.255.255\\\",\\\"l4_dst_port\\\":\\\"65535\\\",\\\"l4_src_port\\\":\\\"0\\\",\\\"proto\\\":\\\"255\\\",\\\"src_ip\\\":\\\"0.0.0.0\\\"}},\\\"nat_type\\\":\\\"SAI_NAT_TYPE_DESTINATION_NAT\\\",\\\"switch_id\\\":\\\"oid:0x21000000000000\\\",\\\"vr\\\":\\\"oid:0x3000000000048\\\"}\",\"nat_event\":\"SAI_NAT_EVENT_AGED\"}]"); + + EXPECT_EQ(ntf->getNotificationType(), SAI_SWITCH_NOTIFICATION_TYPE_NAT_EVENT); +} + TEST(NotificationFactory, deserialize_port_state_change) { auto ntf = NotificationFactory::deserialize( diff --git a/unittest/meta/TestNotificationNatEvent.cpp b/unittest/meta/TestNotificationNatEvent.cpp new file mode 100644 index 000000000..e79f28ff3 --- /dev/null +++ b/unittest/meta/TestNotificationNatEvent.cpp @@ -0,0 +1,88 @@ +#include "NotificationNatEvent.h" +#include "Meta.h" +#include "MetaTestSaiInterface.h" + +#include "sairediscommon.h" +#include "sai_serialize.h" + +#include + +#include + +using namespace sairedis; +using namespace saimeta; + +static std::string s = +"[{\"nat_entry\":\"{\\\"nat_data\\\":{\\\"key\\\":{\\\"dst_ip\\\":\\\"10.10.10.10\\\",\\\"l4_dst_port\\\":\\\"20006\\\",\\\"l4_src_port\\\":\\\"0\\\",\\\"proto\\\":\\\"6\\\",\\\"src_ip\\\":\\\"0.0.0.0\\\"},\\\"mask\\\":{\\\"dst_ip\\\":\\\"255.255.255.255\\\",\\\"l4_dst_port\\\":\\\"65535\\\",\\\"l4_src_port\\\":\\\"0\\\",\\\"proto\\\":\\\"255\\\",\\\"src_ip\\\":\\\"0.0.0.0\\\"}},\\\"nat_type\\\":\\\"SAI_NAT_TYPE_DESTINATION_NAT\\\",\\\"switch_id\\\":\\\"oid:0x21000000000000\\\",\\\"vr\\\":\\\"oid:0x3000000000048\\\"}\",\"nat_event\":\"SAI_NAT_EVENT_AGED\"}]"; + +static std::string null = +"[{\"nat_entry\":\"{\\\"nat_data\\\":{\\\"key\\\":{\\\"dst_ip\\\":\\\"10.10.10.10\\\",\\\"l4_dst_port\\\":\\\"20006\\\",\\\"l4_src_port\\\":\\\"0\\\",\\\"proto\\\":\\\"6\\\",\\\"src_ip\\\":\\\"0.0.0.0\\\"},\\\"mask\\\":{\\\"dst_ip\\\":\\\"255.255.255.255\\\",\\\"l4_dst_port\\\":\\\"65535\\\",\\\"l4_src_port\\\":\\\"0\\\",\\\"proto\\\":\\\"255\\\",\\\"src_ip\\\":\\\"0.0.0.0\\\"}},\\\"nat_type\\\":\\\"SAI_NAT_TYPE_DESTINATION_NAT\\\",\\\"switch_id\\\":\\\"oid:0x0\\\",\\\"vr\\\":\\\"oid:0x3000000000048\\\"}\",\"nat_event\":\"SAI_NAT_EVENT_AGED\"}]"; + +static std::string fullnull = "[]"; + +static std::string none = +"[{\"nat_entry\":\"{\\\"nat_data\\\":{\\\"key\\\":{\\\"dst_ip\\\":\\\"10.10.10.10\\\",\\\"l4_dst_port\\\":\\\"20006\\\",\\\"l4_src_port\\\":\\\"0\\\",\\\"proto\\\":\\\"6\\\",\\\"src_ip\\\":\\\"0.0.0.0\\\"},\\\"mask\\\":{\\\"dst_ip\\\":\\\"255.255.255.255\\\",\\\"l4_dst_port\\\":\\\"65535\\\",\\\"l4_src_port\\\":\\\"0\\\",\\\"proto\\\":\\\"255\\\",\\\"src_ip\\\":\\\"0.0.0.0\\\"}},\\\"nat_type\\\":\\\"SAI_NAT_TYPE_DESTINATION_NAT\\\",\\\"switch_id\\\":\\\"oid:0x21000000000000\\\",\\\"vr\\\":\\\"oid:0x3000000000048\\\"}\",\"nat_event\":\"SAI_NAT_EVENT_NONE\"}]"; + +TEST(NotificationNatEvent, ctr) +{ + NotificationNatEvent n(s); +} + +TEST(NotificationNatEvent, getSwitchId) +{ + NotificationNatEvent n(s); + + EXPECT_EQ(n.getSwitchId(), 0x21000000000000); + + NotificationNatEvent n2(null); + + EXPECT_EQ(n2.getSwitchId(), 0); +} + +TEST(NotificationNatEvent, getAnyObjectId) +{ + NotificationNatEvent n(s); + + EXPECT_EQ(n.getAnyObjectId(), 0x21000000000000); + + NotificationNatEvent n2(null); + + EXPECT_EQ(n2.getAnyObjectId(), 0x3000000000048); + + NotificationNatEvent n3(fullnull); + + EXPECT_EQ(n3.getSwitchId(), 0x0); + + EXPECT_EQ(n3.getAnyObjectId(), 0x0); +} + +TEST(NotificationNatEvent, processMetadata) +{ + NotificationNatEvent n(s); + + auto sai = std::make_shared(); + auto meta = std::make_shared(sai); + + n.processMetadata(meta); + + NotificationNatEvent n4(none); + n4.processMetadata(meta); +} + +static void on_nat_event( + _In_ uint32_t count, + _In_ const sai_nat_event_notification_data_t *data) +{ + SWSS_LOG_ENTER(); +} + +TEST(NotificationNatEvent, executeCallback) +{ + NotificationNatEvent n(s); + + sai_switch_notifications_t ntfs; + + ntfs.on_nat_event = &on_nat_event; + + n.executeCallback(ntfs); +} diff --git a/unittest/meta/TestSaiSerialize.cpp b/unittest/meta/TestSaiSerialize.cpp index 88026c765..b976009bc 100644 --- a/unittest/meta/TestSaiSerialize.cpp +++ b/unittest/meta/TestSaiSerialize.cpp @@ -453,6 +453,11 @@ TEST(SaiSerialize, sai_serialize_fdb_event_ntf) EXPECT_THROW(sai_serialize_fdb_event_ntf(1, nullptr), std::runtime_error); } +TEST(SaiSerialize, sai_serialize_nat_event_ntf) +{ + EXPECT_THROW(sai_serialize_nat_event_ntf(1, nullptr), std::runtime_error); +} + TEST(SaiSerialize, sai_serialize_port_oper_status_ntf) { sai_port_oper_status_notification_t ntf; diff --git a/unittest/syncd/Makefile.am b/unittest/syncd/Makefile.am index 1c15332d8..69ebd53f0 100644 --- a/unittest/syncd/Makefile.am +++ b/unittest/syncd/Makefile.am @@ -12,6 +12,8 @@ tests_SOURCES = main.cpp \ TestFlexCounter.cpp \ TestVirtualOidTranslator.cpp \ TestNotificationQueue.cpp \ + TestNotificationProcessor.cpp \ + TestNotificationHandler.cpp \ TestVendorSai.cpp tests_CXXFLAGS = $(DBGFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS_COMMON) diff --git a/unittest/syncd/TestNotificationHandler.cpp b/unittest/syncd/TestNotificationHandler.cpp new file mode 100644 index 000000000..9891dfebf --- /dev/null +++ b/unittest/syncd/TestNotificationHandler.cpp @@ -0,0 +1,32 @@ +#include "NotificationProcessor.h" +#include "NotificationHandler.h" +#include "meta/sai_serialize.h" + +#include + +using namespace syncd; + +static std::string natData = +"[{\"nat_entry\":\"{\\\"nat_data\\\":{\\\"key\\\":{\\\"dst_ip\\\":\\\"10.10.10.10\\\",\\\"l4_dst_port\\\":\\\"20006\\\",\\\"l4_src_port\\\":\\\"0\\\",\\\"proto\\\":\\\"6\\\",\\\"src_ip\\\":\\\"0.0.0.0\\\"},\\\"mask\\\":{\\\"dst_ip\\\":\\\"255.255.255.255\\\",\\\"l4_dst_port\\\":\\\"65535\\\",\\\"l4_src_port\\\":\\\"0\\\",\\\"proto\\\":\\\"255\\\",\\\"src_ip\\\":\\\"0.0.0.0\\\"}},\\\"nat_type\\\":\\\"SAI_NAT_TYPE_DESTINATION_NAT\\\",\\\"switch_id\\\":\\\"oid:0x21000000000000\\\",\\\"vr\\\":\\\"oid:0x3000000000048\\\"}\",\"nat_event\":\"SAI_NAT_EVENT_AGED\"}]"; + +TEST(NotificationHandler, NotificationHandlerTest) +{ + std::vector attrs; + sai_attribute_t attr; + attr.id = SAI_SWITCH_ATTR_NAT_EVENT_NOTIFY; + attr.value.ptr = (void *) 1; + + attrs.push_back(attr); + + auto notificationProcessor = + std::make_shared(nullptr, nullptr, nullptr); + auto notificationHandler = + std::make_shared(notificationProcessor); + + notificationHandler->updateNotificationsPointers(1, attrs.data()); + uint32_t count; + sai_nat_event_notification_data_t *natevent = NULL; + + sai_deserialize_nat_event_ntf(natData, count, &natevent); + notificationHandler->onNatEvent(count, natevent); +} diff --git a/unittest/syncd/TestNotificationProcessor.cpp b/unittest/syncd/TestNotificationProcessor.cpp new file mode 100644 index 000000000..b2b4ddf90 --- /dev/null +++ b/unittest/syncd/TestNotificationProcessor.cpp @@ -0,0 +1,52 @@ +#include "VirtualOidTranslator.h" +#include "RedisNotificationProducer.h" +#include "NotificationProcessor.h" +#include "lib/RedisVidIndexGenerator.h" +#include "lib/sairediscommon.h" +#include "vslib/Sai.h" + +#include + +using namespace syncd; + +static std::string natData = +"[{\"nat_entry\":\"{\\\"nat_data\\\":{\\\"key\\\":{\\\"dst_ip\\\":\\\"10.10.10.10\\\",\\\"l4_dst_port\\\":\\\"20006\\\",\\\"l4_src_port\\\":\\\"0\\\",\\\"proto\\\":\\\"6\\\",\\\"src_ip\\\":\\\"0.0.0.0\\\"},\\\"mask\\\":{\\\"dst_ip\\\":\\\"255.255.255.255\\\",\\\"l4_dst_port\\\":\\\"65535\\\",\\\"l4_src_port\\\":\\\"0\\\",\\\"proto\\\":\\\"255\\\",\\\"src_ip\\\":\\\"0.0.0.0\\\"}},\\\"nat_type\\\":\\\"SAI_NAT_TYPE_DESTINATION_NAT\\\",\\\"switch_id\\\":\\\"oid:0x21000000000000\\\",\\\"vr\\\":\\\"oid:0x3000000000048\\\"}\",\"nat_event\":\"SAI_NAT_EVENT_AGED\"}]"; + +TEST(NotificationProcessor, NotificationProcessorTest) +{ + auto sai = std::make_shared(); + auto dbAsic = std::make_shared("ASIC_DB", 0); + auto client = std::make_shared(dbAsic); + auto producer = std::make_shared("ASIC_DB"); + + auto notificationProcessor = std::make_shared(producer, client, + [](const swss::KeyOpFieldsValuesTuple&){}); + EXPECT_NE(notificationProcessor, nullptr); + + auto switchConfigContainer = std::make_shared(); + auto redisVidIndexGenerator = std::make_shared(dbAsic, REDIS_KEY_VIDCOUNTER); + EXPECT_NE(redisVidIndexGenerator, nullptr); + + auto virtualObjectIdManager = std::make_shared(0, switchConfigContainer, redisVidIndexGenerator); + EXPECT_NE(virtualObjectIdManager, nullptr); + + auto translator = std::make_shared(client, + virtualObjectIdManager, + sai); + EXPECT_NE(translator, nullptr); + notificationProcessor->m_translator = translator; + + // Check NAT notification without RIDs + std::vector natEntry; + swss::KeyOpFieldsValuesTuple natFV(SAI_SWITCH_NOTIFICATION_NAME_NAT_EVENT, natData, natEntry); + notificationProcessor->syncProcessNotification(natFV); + + // Check NAT notification with RIDs present + translator->insertRidAndVid(0x21000000000000,0x210000000000); + translator->insertRidAndVid(0x3000000000048,0x30000000048); + + notificationProcessor->syncProcessNotification(natFV); + + translator->eraseRidAndVid(0x21000000000000,0x210000000000); + translator->eraseRidAndVid(0x3000000000048,0x30000000048); +}