Skip to content
Open
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
15 changes: 14 additions & 1 deletion orchagent/mirrororch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,14 @@ MirrorEntry::MirrorEntry(const string& platform) :
}

MirrorOrch::MirrorOrch(TableConnector stateDbConnector, TableConnector confDbConnector,
PortsOrch *portOrch, RouteOrch *routeOrch, NeighOrch *neighOrch, FdbOrch *fdbOrch, PolicerOrch *policerOrch) :
PortsOrch *portOrch, RouteOrch *routeOrch, NeighOrch *neighOrch, FdbOrch *fdbOrch, PolicerOrch *policerOrch, SwitchOrch *switchOrch) :
Orch(confDbConnector.first, confDbConnector.second),
m_portsOrch(portOrch),
m_routeOrch(routeOrch),
m_neighOrch(neighOrch),
m_fdbOrch(fdbOrch),
m_policerOrch(policerOrch),
m_switchOrch(switchOrch),
m_mirrorTable(stateDbConnector.first, stateDbConnector.second)
{
sai_status_t status;
Expand Down Expand Up @@ -812,6 +813,18 @@ bool MirrorOrch::setUnsetPortMirror(Port port,
bool set,
sai_object_id_t sessionId)
{
// Check if the mirror direction is supported by the ASIC
if (ingress && !m_switchOrch->isPortIngressMirrorSupported())
{
SWSS_LOG_ERROR("Port ingress mirror is not supported by the ASIC");
return false;
}
if (!ingress && !m_switchOrch->isPortEgressMirrorSupported())
{
SWSS_LOG_ERROR("Port egress mirror is not supported by the ASIC");
return false;
}

sai_status_t status;
sai_attribute_t port_attr;
port_attr.id = ingress ? SAI_PORT_ATTR_INGRESS_MIRROR_SESSION:
Expand Down
3 changes: 2 additions & 1 deletion orchagent/mirrororch.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class MirrorOrch : public Orch, public Observer, public Subject
{
public:
MirrorOrch(TableConnector appDbConnector, TableConnector confDbConnector,
PortsOrch *portOrch, RouteOrch *routeOrch, NeighOrch *neighOrch, FdbOrch *fdbOrch, PolicerOrch *policerOrch);
PortsOrch *portOrch, RouteOrch *routeOrch, NeighOrch *neighOrch, FdbOrch *fdbOrch, PolicerOrch *policerOrch, SwitchOrch *switchOrch);

bool bake() override;
void update(SubjectType, void *);
Expand All @@ -95,6 +95,7 @@ class MirrorOrch : public Orch, public Observer, public Subject
NeighOrch *m_neighOrch;
FdbOrch *m_fdbOrch;
PolicerOrch *m_policerOrch;
SwitchOrch *m_switchOrch;
// Maximum number of traffic classes starting at 0, thus queue can be 0 - m_maxNumTC-1
uint8_t m_maxNumTC;

Expand Down
2 changes: 1 addition & 1 deletion orchagent/orchdaemon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ bool OrchDaemon::init()

TableConnector stateDbMirrorSession(m_stateDb, STATE_MIRROR_SESSION_TABLE_NAME);
TableConnector confDbMirrorSession(m_configDb, CFG_MIRROR_SESSION_TABLE_NAME);
gMirrorOrch = new MirrorOrch(stateDbMirrorSession, confDbMirrorSession, gPortsOrch, gRouteOrch, gNeighOrch, gFdbOrch, gPolicerOrch);
gMirrorOrch = new MirrorOrch(stateDbMirrorSession, confDbMirrorSession, gPortsOrch, gRouteOrch, gNeighOrch, gFdbOrch, gPolicerOrch, gSwitchOrch);

TableConnector confDbAclTable(m_configDb, CFG_ACL_TABLE_TABLE_NAME);
TableConnector confDbAclTableType(m_configDb, CFG_ACL_TABLE_TYPE_TABLE_NAME);
Expand Down
58 changes: 58 additions & 0 deletions orchagent/switchorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ SwitchOrch::SwitchOrch(DBConnector *db, vector<TableConnector>& connectors, Tabl
initSensorsTable();
querySwitchTpidCapability();
querySwitchPortEgressSampleCapability();
querySwitchPortMirrorCapability();
querySwitchHashDefaults();
setSwitchIcmpOffloadCapability();

Expand Down Expand Up @@ -1859,6 +1860,63 @@ void SwitchOrch::querySwitchPortEgressSampleCapability()
set_switch_capability(fvVector);
}

void SwitchOrch::querySwitchPortMirrorCapability()
{
vector<FieldValueTuple> fvVector;
sai_status_t status = SAI_STATUS_SUCCESS;
sai_attr_capability_t capability;

// Check if SAI is capable of handling Port ingress mirror session
status = sai_query_attribute_capability(gSwitchId, SAI_OBJECT_TYPE_PORT,
SAI_PORT_ATTR_INGRESS_MIRROR_SESSION, &capability);
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_WARN("Could not query port ingress mirror capability %d", status);
fvVector.emplace_back(SWITCH_CAPABILITY_TABLE_PORT_INGRESS_MIRROR_CAPABLE, "true");
m_portIngressMirrorSupported = true;
}
else
{
if (capability.set_implemented)
{
fvVector.emplace_back(SWITCH_CAPABILITY_TABLE_PORT_INGRESS_MIRROR_CAPABLE, "true");
m_portIngressMirrorSupported = true;
}
else
{
fvVector.emplace_back(SWITCH_CAPABILITY_TABLE_PORT_INGRESS_MIRROR_CAPABLE, "false");
m_portIngressMirrorSupported = false;
}
SWSS_LOG_NOTICE("port ingress mirror capability %d", capability.set_implemented);
}

// Check if SAI is capable of handling Port egress mirror session
status = sai_query_attribute_capability(gSwitchId, SAI_OBJECT_TYPE_PORT,
SAI_PORT_ATTR_EGRESS_MIRROR_SESSION, &capability);
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_WARN("Could not query port egress mirror capability %d", status);
fvVector.emplace_back(SWITCH_CAPABILITY_TABLE_PORT_EGRESS_MIRROR_CAPABLE, "true");
m_portEgressMirrorSupported = true;
}
else
{
if (capability.set_implemented)
{
fvVector.emplace_back(SWITCH_CAPABILITY_TABLE_PORT_EGRESS_MIRROR_CAPABLE, "true");
m_portEgressMirrorSupported = true;
}
else
{
fvVector.emplace_back(SWITCH_CAPABILITY_TABLE_PORT_EGRESS_MIRROR_CAPABLE, "false");
m_portEgressMirrorSupported = false;
}
SWSS_LOG_NOTICE("port egress mirror capability %d", capability.set_implemented);
}

set_switch_capability(fvVector);
}

void SwitchOrch::querySwitchTpidCapability()
{
SWSS_LOG_ENTER();
Expand Down
11 changes: 11 additions & 0 deletions orchagent/switchorch.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
#define SWITCH_CAPABILITY_TABLE_REG_FATAL_ASIC_SDK_HEALTH_CATEGORY "REG_FATAL_ASIC_SDK_HEALTH_CATEGORY"
#define SWITCH_CAPABILITY_TABLE_REG_WARNING_ASIC_SDK_HEALTH_CATEGORY "REG_WARNING_ASIC_SDK_HEALTH_CATEGORY"
#define SWITCH_CAPABILITY_TABLE_REG_NOTICE_ASIC_SDK_HEALTH_CATEGORY "REG_NOTICE_ASIC_SDK_HEALTH_CATEGORY"
#define SWITCH_CAPABILITY_TABLE_PORT_INGRESS_MIRROR_CAPABLE "PORT_INGRESS_MIRROR_CAPABLE"
#define SWITCH_CAPABILITY_TABLE_PORT_EGRESS_MIRROR_CAPABLE "PORT_EGRESS_MIRROR_CAPABLE"

#define SWITCH_STAT_COUNTER_FLEX_COUNTER_GROUP "SWITCH_STAT_COUNTER"

Expand Down Expand Up @@ -78,6 +80,10 @@ class SwitchOrch : public Orch
// Statistics
void generateSwitchCounterIdList();

// Mirror capability interface for MirrorOrch
bool isPortIngressMirrorSupported() const { return m_portIngressMirrorSupported; }
bool isPortEgressMirrorSupported() const { return m_portEgressMirrorSupported; }

private:
void doTask(Consumer &consumer);
void doTask(swss::SelectableTimer &timer);
Expand All @@ -89,6 +95,7 @@ class SwitchOrch : public Orch
void initSensorsTable();
void querySwitchTpidCapability();
void querySwitchPortEgressSampleCapability();
void querySwitchPortMirrorCapability();

// Statistics
void generateSwitchCounterNameMap() const;
Expand Down Expand Up @@ -148,6 +155,10 @@ class SwitchOrch : public Orch
bool m_orderedEcmpEnable = false;
bool m_PfcDlrInitEnable = false;

// Port mirror capabilities
bool m_portIngressMirrorSupported = false;
bool m_portEgressMirrorSupported = false;

// ASIC SDK health event
std::shared_ptr<swss::DBConnector> m_stateDbForNotification = nullptr;
std::shared_ptr<swss::Table> m_asicSdkHealthEventTable = nullptr;
Expand Down
1 change: 1 addition & 0 deletions tests/mock_tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ tests_SOURCES = aclorch_ut.cpp \
mock_dash_orch_test.cpp \
zmq_orch_ut.cpp \
mock_saihelper.cpp \
mirrororch_ut.cpp \
$(top_srcdir)/warmrestart/warmRestartHelper.cpp \
$(top_srcdir)/lib/gearboxutils.cpp \
$(top_srcdir)/lib/subintf.cpp \
Expand Down
2 changes: 1 addition & 1 deletion tests/mock_tests/aclorch_ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ namespace aclorch_test

ASSERT_EQ(gMirrorOrch, nullptr);
gMirrorOrch = new MirrorOrch(stateDbMirrorSession, confDbMirrorSession,
gPortsOrch, gRouteOrch, gNeighOrch, gFdbOrch, policer_orch);
gPortsOrch, gRouteOrch, gNeighOrch, gFdbOrch, policer_orch, gSwitchOrch);

auto consumer = unique_ptr<Consumer>(new Consumer(
new swss::ConsumerStateTable(m_app_db.get(), APP_PORT_TABLE_NAME, 1, 1), gPortsOrch, APP_PORT_TABLE_NAME));
Expand Down
57 changes: 57 additions & 0 deletions tests/mock_tests/mirrororch_ut.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Make selected privates visible for unit testing
#define private public
#include "directory.h"
#undef private

#define protected public
#include "orch.h"
#undef protected

#define private public
#include "switchorch.h"
#undef private

#include "portsorch.h"
#define private public
#include "mirrororch.h"
#undef private
#include "mock_orch_test.h"

namespace mirrororch_test
{
using namespace mock_orch_test;

class MirrorOrchTest : public MockOrchTest
{
};

TEST_F(MirrorOrchTest, RejectsIngressWhenUnsupported)
{
// Ensure environment initialized by MockOrchTest
ASSERT_NE(gSwitchOrch, nullptr);
ASSERT_NE(gMirrorOrch, nullptr);

// Force ingress unsupported and egress supported
gSwitchOrch->m_portIngressMirrorSupported = false;
gSwitchOrch->m_portEgressMirrorSupported = true;

Port dummyPort; // Unused due to early return
auto ret = gMirrorOrch->setUnsetPortMirror(dummyPort, /*ingress*/ true, /*set*/ true, /*sessionId*/ SAI_NULL_OBJECT_ID);
ASSERT_FALSE(ret);
}

TEST_F(MirrorOrchTest, RejectsEgressWhenUnsupported)
{
ASSERT_NE(gSwitchOrch, nullptr);
ASSERT_NE(gMirrorOrch, nullptr);

// Force egress unsupported and ingress supported
gSwitchOrch->m_portIngressMirrorSupported = true;
gSwitchOrch->m_portEgressMirrorSupported = false;

Port dummyPort; // Unused due to early return
auto ret = gMirrorOrch->setUnsetPortMirror(dummyPort, /*ingress*/ false, /*set*/ true, /*sessionId*/ SAI_NULL_OBJECT_ID);
ASSERT_FALSE(ret);
}
}

2 changes: 1 addition & 1 deletion tests/mock_tests/mock_orch_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ void MockOrchTest::SetUp()

TableConnector stateDbMirrorSession(m_state_db.get(), STATE_MIRROR_SESSION_TABLE_NAME);
TableConnector confDbMirrorSession(m_config_db.get(), CFG_MIRROR_SESSION_TABLE_NAME);
gMirrorOrch = new MirrorOrch(stateDbMirrorSession, confDbMirrorSession, gPortsOrch, gRouteOrch, gNeighOrch, gFdbOrch, gPolicerOrch);
gMirrorOrch = new MirrorOrch(stateDbMirrorSession, confDbMirrorSession, gPortsOrch, gRouteOrch, gNeighOrch, gFdbOrch, gPolicerOrch, gSwitchOrch);
gDirectory.set(gMirrorOrch);
ut_orch_list.push_back((Orch **)&gMirrorOrch);
global_orch_list.insert((Orch **)&gMirrorOrch);
Expand Down
15 changes: 15 additions & 0 deletions tests/mock_tests/switchorch_ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "mock_orchagent_main.h"
#include "mock_table.h"
#include "mock_response_publisher.h"
#include "switchorch.h"

extern void on_switch_asic_sdk_health_event(sai_object_id_t switch_id,
sai_switch_asic_sdk_health_severity_t severity,
Expand Down Expand Up @@ -287,6 +288,13 @@ namespace switchorch_test
ASSERT_EQ(value, "true");
gSwitchOrch->m_switchTable.hget("switch", SWITCH_CAPABILITY_TABLE_REG_NOTICE_ASIC_SDK_HEALTH_CATEGORY, value);
ASSERT_EQ(value, "true");

// Test that mirror capabilities are also queried and stored
// The actual values depend on the SAI implementation, but we can verify the entries exist
bool ingress_exists = gSwitchOrch->m_switchTable.hget("switch", SWITCH_CAPABILITY_TABLE_PORT_INGRESS_MIRROR_CAPABLE, value);
ASSERT_TRUE(ingress_exists);
bool egress_exists = gSwitchOrch->m_switchTable.hget("switch", SWITCH_CAPABILITY_TABLE_PORT_EGRESS_MIRROR_CAPABLE, value);
ASSERT_TRUE(egress_exists);
}

TEST_F(SwitchOrchTest, SwitchOrchTestCheckCapabilityUnsupported)
Expand All @@ -307,6 +315,13 @@ namespace switchorch_test
gSwitchOrch->m_switchTable.hget("switch", SWITCH_CAPABILITY_TABLE_REG_NOTICE_ASIC_SDK_HEALTH_CATEGORY, value);
ASSERT_EQ(value, "false");

// Test that mirror capabilities are also queried and stored
// The actual values depend on the SAI implementation, but we can verify the entries exist
bool ingress_exists = gSwitchOrch->m_switchTable.hget("switch", SWITCH_CAPABILITY_TABLE_PORT_INGRESS_MIRROR_CAPABLE, value);
ASSERT_TRUE(ingress_exists);
bool egress_exists = gSwitchOrch->m_switchTable.hget("switch", SWITCH_CAPABILITY_TABLE_PORT_EGRESS_MIRROR_CAPABLE, value);
ASSERT_TRUE(egress_exists);

// case: unsupported severity. To satisfy coverage.
vector<string> ts;
std::deque<KeyOpFieldsValuesTuple> entries;
Expand Down
Loading