Skip to content

Commit 6b976e9

Browse files
authored
[swss] Support FIPS MACSec POST (sonic-net#3836)
Add SAI MACSec POST support in SWSS When FIPS is enabled in SONiC, enable MACSecPOST in switch creation. If MACSec POST is only supported in MACSec init, create MACSec objects and enable POST when initializing MACSecOrch. Set SAI POST status in StateDB accordingly based on SAI POST status notificaiton. MACSecMgr does not process any MACSec configuration if SAI POST fails. With the PR, the only case that Orchagent declares SAI MACSec POST to fail is: FIPS is enabled in SONiC; AND SAI supports MACSec POST; AND SAI returns failure on MACSec POST. We particularly verified the following on switch with current BRCM SAI (13.2.1.0) that does not support MACSec POST yet: MACSec ports came up fine when FIPS is not enabled in SONiC; MACSec ports came up fine when FIPS is enabled in SONiC and SAI does not support MACSec POST.
1 parent d0b2561 commit 6b976e9

12 files changed

Lines changed: 570 additions & 3 deletions

File tree

cfgmgr/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ tunnelmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CF
9696
tunnelmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN)
9797
tunnelmgrd_LDADD = $(LDFLAGS_ASAN) $(COMMON_LIBS) $(SAIMETA_LIBS)
9898

99-
macsecmgrd_SOURCES = macsecmgrd.cpp macsecmgr.cpp $(COMMON_ORCH_SOURCE) shellcmd.h
99+
macsecmgrd_SOURCES = macsecmgrd.cpp macsecmgr.cpp $(COMMON_ORCH_SOURCE) shellcmd.h $(top_srcdir)/orchagent/macsecpost.cpp
100100
macsecmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN)
101101
macsecmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN)
102102
macsecmgrd_LDADD = $(LDFLAGS_ASAN) $(COMMON_LIBS) $(SAIMETA_LIBS)

cfgmgr/macsecmgrd.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <select.h>
1818

1919
#include "macsecmgr.h"
20+
#include "macsecpost.h"
2021

2122
using namespace std;
2223
using namespace swss;
@@ -76,9 +77,28 @@ int main(int argc, char **argv)
7677
s.addSelectables(o->getSelectables());
7778
}
7879

80+
bool isPostStateReady = false;
81+
7982
SWSS_LOG_NOTICE("starting main loop");
8083
while (!received_sigterm)
8184
{
85+
/* Don't process any config until POST state is ready */
86+
if (!isPostStateReady)
87+
{
88+
std::string state = getMacsecPostState(&stateDb);
89+
if (state == "pass" || state == "disabled")
90+
{
91+
SWSS_LOG_NOTICE("FIPS MACSec POST ready: state %s", state.c_str());
92+
isPostStateReady = true;
93+
}
94+
else
95+
{
96+
/* Yield before retry */
97+
sleep(1);
98+
continue;
99+
}
100+
}
101+
82102
Selectable *sel;
83103
int ret;
84104

orchagent/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ orchagent_SOURCES = \
132132
twamporch.cpp \
133133
stporch.cpp \
134134
nexthopkey.cpp \
135+
macsecpost.cpp \
135136
high_frequency_telemetry/hftelorch.cpp \
136137
high_frequency_telemetry/hftelprofile.cpp \
137138
high_frequency_telemetry/counternameupdater.cpp \

orchagent/macsecorch.cpp

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#include "macsecorch.h"
2+
#include "macsecpost.h"
3+
#include "notifier.h"
24

35
#include <macaddress.h>
46
#include <sai_serialize.h>
@@ -599,6 +601,7 @@ MACsecOrch::MACsecOrch(
599601
const std::vector<std::string> &tables,
600602
PortsOrch *port_orch) : Orch(app_db, tables),
601603
m_port_orch(port_orch),
604+
m_state_db(state_db),
602605
m_state_macsec_port(state_db, STATE_MACSEC_PORT_TABLE_NAME),
603606
m_state_macsec_egress_sc(state_db, STATE_MACSEC_EGRESS_SC_TABLE_NAME),
604607
m_state_macsec_ingress_sc(state_db, STATE_MACSEC_INGRESS_SC_TABLE_NAME),
@@ -649,6 +652,53 @@ MACsecOrch::MACsecOrch(
649652
saiAclFieldSciMatchSupported = false;
650653
}
651654
}
655+
656+
// Add handler for POST completion callback/notification.
657+
string post_state = getMacsecPostState(m_state_db);
658+
if (post_state == "switch-level-post-in-progress" ||
659+
post_state == "macsec-level-post-in-progress" )
660+
{
661+
m_notificationsDb = make_shared<DBConnector>("ASIC_DB", 0);
662+
m_postCompletionNotificationConsumer = new swss::NotificationConsumer(m_notificationsDb.get(), "NOTIFICATIONS");
663+
auto postCompletionNotificatier = new Notifier(m_postCompletionNotificationConsumer, this, "POST_COMPLETION__NOTIFICATIONS");
664+
Orch::addExecutor(postCompletionNotificatier);
665+
}
666+
667+
if (post_state == "switch-level-post-in-progress")
668+
{
669+
// POST was already enabled in switch init. The completion notification may have already been sent
670+
// before MACSecOrch is initialized. So query if POST is completed or not.
671+
sai_attribute_t attr;
672+
attr.id = SAI_SWITCH_ATTR_MACSEC_POST_STATUS;
673+
if (sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr) == SAI_STATUS_SUCCESS)
674+
{
675+
if (attr.value.s32 == SAI_SWITCH_MACSEC_POST_STATUS_PASS)
676+
{
677+
setMacsecPostState(m_state_db, "pass");
678+
SWSS_LOG_NOTICE("Switch MACSec POST passed");
679+
}
680+
else if (attr.value.s32 == SAI_SWITCH_MACSEC_POST_STATUS_FAIL)
681+
{
682+
setMacsecPostState(m_state_db, "fail");
683+
SWSS_LOG_ERROR("Switch MACSec POST failed: oid %" PRIu64, gSwitchId);
684+
}
685+
else
686+
{
687+
SWSS_LOG_NOTICE("Switch MACSec POST status: %d", attr.value.s32);
688+
}
689+
}
690+
else
691+
{
692+
SWSS_LOG_ERROR("Failed to get MACSec POST status");
693+
}
694+
}
695+
else if (post_state == "macsec-level-post-in-progress")
696+
{
697+
// POST is only supported in MACSec init. Create MACSec and enable POST.
698+
m_enable_post = true;
699+
initMACsecObject(gSwitchId);
700+
SWSS_LOG_NOTICE("Init MACSec objects and enable POST");
701+
}
652702
}
653703

654704
MACsecOrch::~MACsecOrch()
@@ -661,6 +711,127 @@ MACsecOrch::~MACsecOrch()
661711
}
662712
}
663713

714+
void MACsecOrch::doTask(NotificationConsumer &consumer)
715+
{
716+
SWSS_LOG_ENTER();
717+
718+
if (&consumer != m_postCompletionNotificationConsumer)
719+
{
720+
return;
721+
}
722+
723+
std::deque<KeyOpFieldsValuesTuple> entries;
724+
consumer.pops(entries);
725+
for (auto& entry : entries)
726+
{
727+
handleNotification(consumer, entry);
728+
}
729+
}
730+
731+
void MACsecOrch::handleNotification(NotificationConsumer &consumer, KeyOpFieldsValuesTuple& entry)
732+
{
733+
SWSS_LOG_ENTER();
734+
735+
if (&consumer != m_postCompletionNotificationConsumer)
736+
{
737+
return;
738+
}
739+
740+
auto op = kfvOp(entry);
741+
auto data = kfvKey(entry);
742+
SWSS_LOG_NOTICE("Received SAI notification: op %s, data %s", op.c_str(), data.c_str());
743+
744+
if (op == "switch_macsec_post_status")
745+
{
746+
sai_object_id_t switch_id;
747+
sai_switch_macsec_post_status_t switch_macsec_post_status;
748+
sai_deserialize_switch_macsec_post_status_ntf(data, switch_id, switch_macsec_post_status);
749+
750+
string post_state = getMacsecPostState(m_state_db);
751+
if (post_state == "switch-level-post-in-progress")
752+
{
753+
// MACSec POST was enabled in switch init. SAI enables POST in all HW MACSec engines.
754+
// The returned POST status is the aggregated result for all HW MACSec engines.
755+
756+
if (switch_macsec_post_status == SAI_SWITCH_MACSEC_POST_STATUS_PASS)
757+
{
758+
setMacsecPostState(m_state_db, "pass");
759+
SWSS_LOG_NOTICE("Switch MACSec POST passed");
760+
}
761+
else if (switch_macsec_post_status == SAI_SWITCH_MACSEC_POST_STATUS_FAIL)
762+
{
763+
setMacsecPostState(m_state_db, "fail");
764+
SWSS_LOG_ERROR("Switch MACSec POST failed");
765+
}
766+
}
767+
else if (post_state == "macsec-level-post-in-progress")
768+
{
769+
SWSS_LOG_ERROR("POST enabled in MACSec init, but got notification from switch init");
770+
}
771+
}
772+
773+
if (op == "macsec_post_status")
774+
{
775+
sai_object_id_t macsec_id;
776+
sai_macsec_post_status_t macsec_post_status;
777+
sai_deserialize_macsec_post_status_ntf(data, macsec_id, macsec_post_status);
778+
779+
if (m_enable_post)
780+
{
781+
// MACSec POST was enabled in MACSec object init. Since two MACSec objects were created
782+
// (one for each direction), two POST status must be returend from SAI. POST is considered
783+
// pass only if POST passes in both MACSec objects.
784+
785+
string direction = "unknown";
786+
auto macsec_obj = m_macsec_objs.find(gSwitchId);
787+
if (macsec_obj->second.m_ingress_id == macsec_id)
788+
{
789+
direction = "ingress";
790+
}
791+
else if (macsec_obj->second.m_egress_id == macsec_id)
792+
{
793+
direction = "egress";
794+
}
795+
796+
if (macsec_post_status == SAI_MACSEC_POST_STATUS_PASS)
797+
{
798+
if (direction == "ingress")
799+
{
800+
SWSS_LOG_NOTICE("Ingress MACSec POST passed");
801+
macsec_obj->second.m_ingress_post_passed = true;
802+
}
803+
else if (direction == "egress")
804+
{
805+
SWSS_LOG_NOTICE("Egress MACSec POST passed");
806+
macsec_obj->second.m_egress_post_passed = true;
807+
}
808+
809+
// Check if POST passed on both MACSec objects.
810+
if (macsec_obj->second.m_ingress_post_passed && macsec_obj->second.m_egress_post_passed)
811+
{
812+
setMacsecPostState(m_state_db, "pass");
813+
SWSS_LOG_NOTICE("Ingress and egress MACSec POST passed");
814+
}
815+
}
816+
else if(macsec_post_status == SAI_MACSEC_POST_STATUS_FAIL)
817+
{
818+
if (direction == "ingress")
819+
{
820+
SWSS_LOG_ERROR("Ingress MACSec POST failed");
821+
}
822+
else if (direction == "egress")
823+
{
824+
SWSS_LOG_ERROR("Egress MACSec POST failed");
825+
}
826+
827+
// Consider POST failed since it failed on one MACSec object.
828+
setMacsecPostState(m_state_db, "fail");
829+
SWSS_LOG_ERROR("MACSec POST failed");
830+
}
831+
}
832+
}
833+
}
834+
664835
void MACsecOrch::doTask(Consumer &consumer)
665836
{
666837
SWSS_LOG_ENTER();
@@ -1044,6 +1215,13 @@ bool MACsecOrch::initMACsecObject(sai_object_id_t switch_id)
10441215
attr.value.booldata = true;
10451216
attrs.push_back(attr);
10461217

1218+
if (m_enable_post)
1219+
{
1220+
attr.id = SAI_MACSEC_ATTR_ENABLE_POST;
1221+
attr.value.booldata = true;
1222+
attrs.push_back(attr);
1223+
}
1224+
10471225
sai_status_t status = sai_macsec_api->create_macsec(
10481226
&macsec_obj.first->second.m_egress_id,
10491227
switch_id,
@@ -1069,6 +1247,13 @@ bool MACsecOrch::initMACsecObject(sai_object_id_t switch_id)
10691247
attr.value.booldata = true;
10701248
attrs.push_back(attr);
10711249

1250+
if (m_enable_post)
1251+
{
1252+
attr.id = SAI_MACSEC_ATTR_ENABLE_POST;
1253+
attr.value.booldata = true;
1254+
attrs.push_back(attr);
1255+
}
1256+
10721257
status = sai_macsec_api->create_macsec(
10731258
&macsec_obj.first->second.m_ingress_id,
10741259
switch_id,

orchagent/macsecorch.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ class MACsecOrch : public Orch
4040

4141
private:
4242
void doTask(Consumer &consumer);
43+
void doTask(NotificationConsumer &consumer);
44+
void handleNotification(NotificationConsumer &consumer, KeyOpFieldsValuesTuple& entry);
4345

4446
public:
4547
using TaskArgs = std::vector<FieldValueTuple>;
@@ -57,6 +59,11 @@ class MACsecOrch : public Orch
5759
task_process_status taskUpdateIngressSA(const std::string & port_sci_an, const TaskArgs & sa_attr);
5860
task_process_status taskDeleteIngressSA(const std::string & port_sci_an, const TaskArgs & sa_attr);
5961

62+
DBConnector * m_state_db;
63+
shared_ptr<DBConnector> m_notificationsDb;
64+
NotificationConsumer* m_postCompletionNotificationConsumer;
65+
bool m_enable_post;
66+
6067
PortsOrch * m_port_orch;
6168

6269
Table m_state_macsec_port;
@@ -117,6 +124,8 @@ class MACsecOrch : public Orch
117124
map<std::string, std::shared_ptr<MACsecPort> > m_macsec_ports;
118125
bool m_sci_in_ingress_macsec_acl;
119126
sai_uint8_t m_max_sa_per_sc;
127+
bool m_egress_post_passed;
128+
bool m_ingress_post_passed;
120129
};
121130
map<sai_object_id_t, MACsecObject> m_macsec_objs;
122131
map<std::string, std::shared_ptr<MACsecPort> > m_macsec_ports;

orchagent/macsecpost.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include "dbconnector.h"
2+
#include "macsecpost.h"
3+
#include "redisutility.h"
4+
#include "schema.h"
5+
#include "table.h"
6+
7+
namespace swss {
8+
9+
void setMacsecPostState(DBConnector *stateDb, string postState)
10+
{
11+
Table macsecPostStateTable = Table(stateDb, STATE_FIPS_MACSEC_POST_TABLE_NAME);
12+
vector<FieldValueTuple> fvts;
13+
FieldValueTuple postStateFvt("post_state", postState);
14+
fvts.push_back(postStateFvt);
15+
16+
auto now = std::chrono::system_clock::now();
17+
std::time_t now_c = std::chrono::system_clock::to_time_t(now);
18+
char buffer[32];
19+
std::strftime(buffer, sizeof(buffer), "%a %b %d %H:%M:%S %Y", std::gmtime(&now_c));
20+
FieldValueTuple lastUpdateTimeFvt("last_update_time", buffer);
21+
fvts.push_back(lastUpdateTimeFvt);
22+
23+
macsecPostStateTable.set("sai", fvts);
24+
}
25+
26+
string getMacsecPostState(DBConnector *stateDb)
27+
{
28+
std::string postState = "";
29+
std::vector<FieldValueTuple> fvts;
30+
Table macsecPostStateTable = Table(stateDb, STATE_FIPS_MACSEC_POST_TABLE_NAME);
31+
if (macsecPostStateTable.get("sai", fvts))
32+
{
33+
auto state = fvsGetValue(fvts, "post_state", true);
34+
if (state)
35+
{
36+
postState = *state;
37+
}
38+
}
39+
return postState;
40+
}
41+
42+
}

orchagent/macsecpost.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#ifndef ORCHAGENT_MACSECPOST_H
2+
#define ORCHAGENT_MACSECPOST_H
3+
4+
using namespace std;
5+
6+
namespace swss {
7+
8+
void setMacsecPostState(DBConnector *stateDb, string postState);
9+
string getMacsecPostState(DBConnector *stateDb);
10+
11+
}
12+
13+
#endif // ORCHAGENT_MACSECPOST_H

0 commit comments

Comments
 (0)