Skip to content

Commit db4195b

Browse files
author
Ashish Singh
committed
[Link Event Damping] Port state change handler class.
- Class to handle the port state change event callback from SAI and sending the events to syncd main thread for processing by link event damper. Depends on: #1297 HLD: sonic-net/SONiC#1071
1 parent 1ef16ee commit db4195b

File tree

5 files changed

+167
-0
lines changed

5 files changed

+167
-0
lines changed

syncd/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ libSyncd_a_SOURCES = \
3434
NotificationQueue.cpp \
3535
PortMap.cpp \
3636
PortMapParser.cpp \
37+
PortStateChangeHandler.cpp \
3738
RedisClient.cpp \
3839
RedisNotificationProducer.cpp \
3940
RequestShutdownCommandLineOptions.cpp \

syncd/PortStateChangeHandler.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include "PortStateChangeHandler.h"
2+
3+
#include <string>
4+
5+
using namespace syncd;
6+
7+
PortStateChangeHandler::PortStateChangeHandler(
8+
_In_ std::shared_ptr<swss::SelectableEvent> portStateChangeEvent)
9+
: m_portStateChangeEvent(portStateChangeEvent)
10+
{
11+
SWSS_LOG_ENTER();
12+
13+
m_portStateChangeQueue = std::make_shared<portOperStatusNotificationQueue>(
14+
m_portStateChangeQueueSize);
15+
}
16+
17+
PortStateChangeHandler::~PortStateChangeHandler()
18+
{
19+
SWSS_LOG_ENTER();
20+
}
21+
22+
void PortStateChangeHandler::handlePortStateChangeNotification(
23+
_In_ uint32_t count,
24+
_In_ const sai_port_oper_status_notification_t *data)
25+
{
26+
SWSS_LOG_ENTER();
27+
28+
if (m_portStateChangeEvent == nullptr)
29+
{
30+
SWSS_LOG_THROW("Unexpected error: port state change event is null.");
31+
}
32+
33+
for (uint32_t idx = 0; idx < count; ++idx)
34+
{
35+
if (m_portStateChangeQueue->enqueue(data[idx]) == false)
36+
{
37+
SWSS_LOG_ERROR(
38+
"Unexpected error: failed to enqueue the port state change "
39+
"notification.");
40+
41+
return;
42+
}
43+
}
44+
45+
m_portStateChangeEvent->notify();
46+
}

syncd/PortStateChangeHandler.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#pragma once
2+
3+
extern "C" {
4+
#include "saimetadata.h"
5+
}
6+
7+
#include <memory>
8+
9+
#include "ConcurrentQueue.h"
10+
#include "swss/logger.h"
11+
#include "swss/selectableevent.h"
12+
13+
namespace syncd
14+
{
15+
16+
// Class to handle the port state change callback from SAI. This consists a
17+
// selectable event that will be used to send notification from producer thread
18+
// to consumer thread, and a mutex protected concurrent queue to share the port
19+
// state change notification data between producer and consumer threads.
20+
class PortStateChangeHandler
21+
{
22+
public:
23+
24+
using portOperStatusNotificationQueue =
25+
ConcurrentQueue<sai_port_oper_status_notification_t>;
26+
27+
PortStateChangeHandler(
28+
_In_ std::shared_ptr<swss::SelectableEvent> portStateChangeEvent);
29+
30+
virtual ~PortStateChangeHandler();
31+
32+
// Adds the port operational status notification data to a queue and generates a
33+
// notification event.
34+
void handlePortStateChangeNotification(
35+
_In_ uint32_t count,
36+
_In_ const sai_port_oper_status_notification_t *data);
37+
38+
// Returns the shared pointer of the queue.
39+
std::shared_ptr<portOperStatusNotificationQueue> getQueue() const
40+
{
41+
SWSS_LOG_ENTER();
42+
43+
return m_portStateChangeQueue;
44+
}
45+
46+
private:
47+
48+
// Choosing 4k max event queue size based on if we had 256 ports, it can
49+
// accommodate on average 16 port events per ports in worst case.
50+
static constexpr size_t m_portStateChangeQueueSize = 4096;
51+
52+
// SelectableEvent for producer to generate the event and for consumer to
53+
// listen on.
54+
std::shared_ptr<swss::SelectableEvent> m_portStateChangeEvent;
55+
56+
// Mutex protected queue to share the data between producer and consumer.
57+
std::shared_ptr<portOperStatusNotificationQueue> m_portStateChangeQueue;
58+
};
59+
} // namespace syncd

unittest/syncd/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ tests_SOURCES = main.cpp \
1616
TestNotificationProcessor.cpp \
1717
TestNotificationHandler.cpp \
1818
TestMdioIpcServer.cpp \
19+
TestPortStateChangeHandler.cpp \
1920
TestVendorSai.cpp
2021

2122
tests_CXXFLAGS = $(DBGFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS_COMMON)
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#include "PortStateChangeHandler.h"
2+
3+
#include <gtest/gtest.h>
4+
5+
using namespace syncd;
6+
7+
constexpr size_t portStateChangeQueueSize = 4096;
8+
9+
class PortStateChangeHandlerTest : public ::testing::Test
10+
{
11+
protected:
12+
PortStateChangeHandlerTest()
13+
: m_portStateChangeHandler(std::make_shared<swss::SelectableEvent>())
14+
{
15+
SWSS_LOG_ENTER();
16+
}
17+
18+
~PortStateChangeHandlerTest() override
19+
{
20+
SWSS_LOG_ENTER();
21+
}
22+
23+
PortStateChangeHandler m_portStateChangeHandler;
24+
};
25+
26+
TEST_F(PortStateChangeHandlerTest, VerifyGetQueue)
27+
{
28+
auto queue = m_portStateChangeHandler.getQueue();
29+
EXPECT_EQ(queue->size(), 0);
30+
}
31+
32+
TEST_F(PortStateChangeHandlerTest,
33+
HandlePortStateChangeNotificationFailsOnEnqueuingData)
34+
{
35+
auto queue = m_portStateChangeHandler.getQueue();
36+
EXPECT_EQ(queue->size(), 0);
37+
38+
// Insert enough data in the queue so it reaches its capacity.
39+
sai_port_oper_status_notification_t operStatus[portStateChangeQueueSize];
40+
m_portStateChangeHandler.handlePortStateChangeNotification(
41+
portStateChangeQueueSize, &operStatus[0]);
42+
EXPECT_EQ(queue->size(), portStateChangeQueueSize);
43+
44+
// Since queue is at its maximum capacity, adding a new element should cause
45+
// insert failure and new element should not get added.
46+
m_portStateChangeHandler.handlePortStateChangeNotification(/*count=*/1,
47+
&operStatus[0]);
48+
EXPECT_EQ(queue->size(), portStateChangeQueueSize);
49+
}
50+
51+
TEST_F(PortStateChangeHandlerTest, HandlePortStateChangeNotificationSucceeds)
52+
{
53+
auto queue = m_portStateChangeHandler.getQueue();
54+
EXPECT_EQ(queue->size(), 0);
55+
56+
sai_port_oper_status_notification_t operStatus;
57+
m_portStateChangeHandler.handlePortStateChangeNotification(/*count=*/1,
58+
&operStatus);
59+
EXPECT_EQ(queue->size(), 1);
60+
}

0 commit comments

Comments
 (0)