Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions syncd/EventThrottle.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include "EventThrottle.h"

#include "swss/logger.h"

using namespace syncd;

/*
* Defines fdb event notification limit. When this many notification will be
* seen in specific period of time then receiving of this event will be dropped.
*/
#define FDB_EVENT_NOTIFICATION_LIMIT (10)

#define FDB_EVENT_NOTIFICATION_LIMIT_TIMESPAN_NS (1000*1000*1000)
#define ONE_SECOND_TIMESPAN_NS (1000*1000*1000)

EventThrottle::EventThrottle(
_In_ const std::string& name):
m_name(name),
m_count(0),
m_dropped(0)
{
SWSS_LOG_ENTER();

m_time = getTime();
}

uint64_t EventThrottle::getTime()
{
// SWSS_LOG_ENTER(); // disabled

return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}

bool EventThrottle::shouldEnqueue()
{
// SWSS_LOG_ENTER(); // disabled

auto time = getTime();

if (time < m_time)
{
m_dropped++;
return false;
}

if (m_dropped)
{
SWSS_LOG_WARN("dropped fdb event %s %ld times", m_name.c_str(), m_dropped);
m_dropped = 0;
}

if (m_count == 0)
{
m_time = getTime(); // first notification time stamp
}

m_count++;

if (m_count < FDB_EVENT_NOTIFICATION_LIMIT)
return true;

if (time - m_time < FDB_EVENT_NOTIFICATION_LIMIT_TIMESPAN_NS)
{
SWSS_LOG_WARN("fdb entry %s seen %ld times, dropping for 1 seconds",
m_name.c_str(),
m_count);

// set time in the future for 1 second, this will cause drop
m_time = time + ONE_SECOND_TIMESPAN_NS;
}

m_count = 0;

return true;
}
30 changes: 30 additions & 0 deletions syncd/EventThrottle.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include "swss/sal.h"

#include <string>

namespace syncd
{
class EventThrottle
{
public:

EventThrottle(
_In_ const std::string& name);

public:

static uint64_t getTime();

bool shouldEnqueue();

private:

std::string m_name;

uint64_t m_time;
uint64_t m_count;
uint64_t m_dropped;
};
}
32 changes: 32 additions & 0 deletions syncd/FdbEntryKeyHasher.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include "FdbEntryKeyHasher.h"

#include "swss/logger.h"

#include <cstring>

using namespace syncd;

std::size_t FdbEntryKeyHasher::operator()(
_In_ const sai_fdb_entry_t& fe) const
{
// SWSS_LOG_ENTER(); // disabled for performance reasons

uint32_t data;

// use low 4 bytes of mac address as hash value
// use memcpy instead of cast because of strict-aliasing rules
memcpy(&data, fe.mac_address + 2, sizeof(uint32_t));

return data;
}

bool FdbEntryKeyHasher::operator()(
_In_ const sai_fdb_entry_t& a,
_In_ const sai_fdb_entry_t& b) const
{
// SWSS_LOG_ENTER(); // disabled for performance reasons

return a.switch_id == b.switch_id &&
a.bv_id == b.bv_id &&
memcmp(a.mac_address, b.mac_address, sizeof(a.mac_address)) == 0;
}
22 changes: 22 additions & 0 deletions syncd/FdbEntryKeyHasher.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

extern "C" {
#include "saimetadata.h"
}

#include "swss/sal.h"

#include <cstddef>

namespace syncd
{
struct FdbEntryKeyHasher
{
std::size_t operator()(
_In_ const sai_fdb_entry_t& fe) const;

bool operator()(
_In_ const sai_fdb_entry_t& a,
_In_ const sai_fdb_entry_t& b) const;
};
}
2 changes: 2 additions & 0 deletions syncd/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ libSyncd_a_SOURCES = \
CommandLineOptions.cpp \
CommandLineOptionsParser.cpp \
ComparisonLogic.cpp \
EventThrottle.cpp \
FdbEntryKeyHasher.cpp \
FlexCounter.cpp \
FlexCounterManager.cpp \
GlobalSwitchId.cpp \
Expand Down
35 changes: 32 additions & 3 deletions syncd/NotificationHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,15 +127,45 @@ void NotificationHandler::updateNotificationsPointers(
// TODO use same Notification class from sairedis lib
// then this will handle deserialize free

bool NotificationHandler::shouldEnqueueFdbEvent(
_In_ const sai_fdb_event_notification_data_t& data)
{
SWSS_LOG_ENTER();

auto& entry = data.fdb_entry;

auto throttle = m_fdbThrottleHash[entry];

if (throttle == nullptr)
{
std::string name = sai_serialize_fdb_entry(data.fdb_entry);

m_fdbThrottleHash[entry] = throttle = std::make_shared<EventThrottle>(name);
}

return throttle->shouldEnqueue();
}

void NotificationHandler::onFdbEvent(
_In_ uint32_t count,
_In_ const sai_fdb_event_notification_data_t *data)
{
SWSS_LOG_ENTER();

std::string s = sai_serialize_fdb_event_ntf(count, data);
/*
* Split fdb event to single notifications in case that it contains
* multiple events and one of them need to be dropped.
*/

enqueueNotification(SAI_SWITCH_NOTIFICATION_NAME_FDB_EVENT, s);
for (uint32_t idx = 0; idx < count; idx++)
{
if (shouldEnqueueFdbEvent(data[idx]))
{
std::string s = sai_serialize_fdb_event_ntf(1, &data[idx]);

enqueueNotification(SAI_SWITCH_NOTIFICATION_NAME_FDB_EVENT, s);
}
}
}

void NotificationHandler::onPortStateChange(
Expand Down Expand Up @@ -219,4 +249,3 @@ void NotificationHandler::enqueueNotification(

enqueueNotification(op, data, entry);
}

8 changes: 8 additions & 0 deletions syncd/NotificationHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ extern "C"{

#include "NotificationQueue.h"
#include "NotificationProcessor.h"
#include "EventThrottle.h"
#include "FdbEntryKeyHasher.h"

#include "swss/table.h"

#include <string>
#include <vector>
#include <memory>
#include <unordered_map>

namespace syncd
{
Expand Down Expand Up @@ -71,12 +74,17 @@ namespace syncd
_In_ const std::string& op,
_In_ const std::string& data);

bool shouldEnqueueFdbEvent(
_In_ const sai_fdb_event_notification_data_t& data);

private:

sai_switch_notifications_t m_switchNotifications;

std::shared_ptr<NotificationQueue> m_notificationQueue;

std::shared_ptr<NotificationProcessor> m_processor;

std::unordered_map<sai_fdb_entry_t, std::shared_ptr<EventThrottle>, FdbEntryKeyHasher, FdbEntryKeyHasher> m_fdbThrottleHash;
};
}
3 changes: 3 additions & 0 deletions unittest/syncd/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ tests_SOURCES = main.cpp \
MockableSaiInterface.cpp \
MockHelper.cpp \
TestCommandLineOptions.cpp \
TestEventThrottle.cpp \
TestFdbEntryKeyHasher.cpp \
TestFlexCounter.cpp \
TestNotificationHandler.cpp \
TestNotificationQueue.cpp

tests_CXXFLAGS = $(DBGFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS_COMMON)
Expand Down
8 changes: 0 additions & 8 deletions unittest/syncd/MockHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,3 @@ namespace test_syncd {
mock_objectTypeQuery_result = mock_result;
}
}

namespace syncd {
sai_object_type_t VidManager::objectTypeQuery(_In_ sai_object_id_t objectId)
{
SWSS_LOG_ENTER();
return test_syncd::mock_objectTypeQuery_result;
}
}
31 changes: 31 additions & 0 deletions unittest/syncd/TestEventThrottle.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "EventThrottle.h"

#include <gtest/gtest.h>

#include <memory>

using namespace syncd;

TEST(EventThrottle, getTime)
{
EXPECT_NE(EventThrottle::getTime(), 0);
}

TEST(EventThrottle, shouldEnqueue)
{
EventThrottle et("test");

for (int i = 0; i < 10; i++)
{
EXPECT_TRUE(et.shouldEnqueue());
}

for (int i = 0; i < 100; i++)
{
EXPECT_FALSE(et.shouldEnqueue());
}

sleep(1);

EXPECT_TRUE(et.shouldEnqueue());
}
31 changes: 31 additions & 0 deletions unittest/syncd/TestFdbEntryKeyHasher.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "FdbEntryKeyHasher.h"

#include <gtest/gtest.h>

#include <memory>

using namespace syncd;

TEST(FdbEntryKeyHasher, operator_eq)
{
sai_fdb_entry_t a;
sai_fdb_entry_t b;

memset(&a, 0, sizeof(a));
memset(&b, 0, sizeof(a));

FdbEntryKeyHasher kh;

EXPECT_TRUE(kh.operator()(a, b));
}

TEST(FdbEntryKeyHasher, operator_hash)
{
sai_fdb_entry_t a;

memset(&a, 0, sizeof(a));

FdbEntryKeyHasher kh;

EXPECT_EQ(kh.operator()(a), 0);
}
Loading