Skip to content

Commit d5866a3

Browse files
authored
[vslib]: fix create MACsec SA error (#986)
* fix get_cipher_name from wrong attr variable Signed-off-by: Ze Gan <[email protected]> * Add unittest Signed-off-by: Ze Gan <[email protected]> * Re-create failed MACsec SAs Signed-off-by: Ze Gan <[email protected]>
1 parent f36f7ce commit d5866a3

8 files changed

+270
-8
lines changed

tests/aspell.en.pws

+1
Original file line numberDiff line numberDiff line change
@@ -449,3 +449,4 @@ zeromq
449449
zmq
450450
ZMQ
451451
ZMQ
452+
uncreated

unittest/vslib/Makefile.am

+2-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ tests_SOURCES = main.cpp \
4040
TestSwitch.cpp \
4141
TestSwitchMLNX2700.cpp \
4242
TestSwitchBCM56850.cpp \
43-
TestSwitchBCM81724.cpp
43+
TestSwitchBCM81724.cpp \
44+
TestSwitchStateBaseMACsec.cpp
4445

4546
tests_CXXFLAGS = $(DBGFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS_COMMON) -fno-access-control
4647
tests_LDADD = $(LDADD_GTEST) $(top_srcdir)/vslib/libSaiVS.a -lhiredis -lswsscommon -lnl-genl-3 -lnl-nf-3 -lnl-route-3 -lnl-3 \

unittest/vslib/TestMACsecAttr.cpp

+46
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
#include <gtest/gtest.h>
44

5+
#include <unordered_set>
6+
57
using namespace saivs;
68

79
TEST(MACsecAttr, ctr)
@@ -46,3 +48,47 @@ TEST(MACsecAttr, is_xpn)
4648

4749
EXPECT_TRUE(attr.is_xpn());
4850
}
51+
52+
TEST(MACsecAttr, unordered_set)
53+
{
54+
MACsecAttr attr1, attr2, attr3;
55+
std::unordered_set<MACsecAttr, MACsecAttr::Hash> attrSet;
56+
57+
attr1.m_macsecName = "abc";
58+
attr2.m_macsecName = "abc";
59+
attr3.m_macsecName = "123";
60+
attrSet.insert(attr1);
61+
62+
EXPECT_NE(attrSet.find(attr2), attrSet.end());
63+
EXPECT_EQ(attrSet.find(attr3), attrSet.end());
64+
65+
66+
attrSet.clear();
67+
attr1.m_sci = "0";
68+
attrSet.insert(attr1);
69+
70+
EXPECT_EQ(attrSet.find(attr2), attrSet.end());
71+
72+
attr2.m_sci = "0";
73+
74+
EXPECT_NE(attrSet.find(attr2), attrSet.end());
75+
76+
77+
attrSet.clear();
78+
attr1.m_sci = "0";
79+
attr1.m_an = 0;
80+
attrSet.insert(attr1);
81+
82+
EXPECT_EQ(attrSet.find(attr2), attrSet.end());
83+
84+
attr2.m_an = 0;
85+
86+
EXPECT_NE(attrSet.find(attr2), attrSet.end());
87+
88+
89+
attrSet.clear();
90+
attr1.m_authKey = "abc";
91+
attrSet.insert(attr1);
92+
93+
EXPECT_NE(attrSet.find(attr2), attrSet.end());
94+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#include "SwitchStateBase.h"
2+
#include "MACsecAttr.h"
3+
4+
#include <gtest/gtest.h>
5+
6+
#include <vector>
7+
8+
using namespace saivs;
9+
10+
TEST(SwitchStateBase, loadMACsecAttrFromMACsecSA)
11+
{
12+
auto sc = std::make_shared<SwitchConfig>(0, "");
13+
auto scc = std::make_shared<SwitchConfigContainer>();
14+
15+
SwitchStateBase ss(
16+
0x2100000000,
17+
std::make_shared<RealObjectIdManager>(0, scc),
18+
sc);
19+
20+
sai_attribute_t attr;
21+
std::vector<sai_attribute_t> attrs;
22+
MACsecAttr macsecAttr;
23+
24+
attr.id = SAI_MACSEC_SC_ATTR_FLOW_ID;
25+
attrs.push_back(attr);
26+
attr.id = SAI_MACSEC_SC_ATTR_MACSEC_SCI;
27+
attrs.push_back(attr);
28+
attr.id = SAI_MACSEC_SC_ATTR_ENCRYPTION_ENABLE;
29+
attrs.push_back(attr);
30+
attr.id = SAI_MACSEC_SC_ATTR_MACSEC_CIPHER_SUITE;
31+
attr.value.s32 = sai_macsec_cipher_suite_t::SAI_MACSEC_CIPHER_SUITE_GCM_AES_128;
32+
attrs.push_back(attr);
33+
EXPECT_EQ(
34+
SAI_STATUS_SUCCESS,
35+
ss.create_internal(
36+
SAI_OBJECT_TYPE_MACSEC_SC,
37+
"oid:0x0",
38+
0,
39+
static_cast<uint32_t>(attrs.size()),
40+
attrs.data()));
41+
42+
attr.id = SAI_MACSEC_SA_ATTR_SC_ID;
43+
attr.value.oid = 0;
44+
ss.loadMACsecAttrFromMACsecSA(0, 1 , &attr, macsecAttr);
45+
46+
EXPECT_EQ(macsecAttr.m_cipher, MACsecAttr::CIPHER_NAME_GCM_AES_128);
47+
}
48+
49+
TEST(SwitchStateBase, retryCreateIngressMaCsecSAs)
50+
{
51+
// Due to this function highly depends on system environment which cannot be tested directly,
52+
// Just create this Test block for passing coverage
53+
auto sc = std::make_shared<SwitchConfig>(0, "");
54+
auto scc = std::make_shared<SwitchConfigContainer>();
55+
56+
SwitchStateBase ss(
57+
0x2100000000,
58+
std::make_shared<RealObjectIdManager>(0, scc),
59+
sc);
60+
61+
MACsecAttr macsecAttr;
62+
63+
ss.m_uncreatedIngressMACsecSAs.insert(macsecAttr);
64+
65+
ss.retryCreateIngressMaCsecSAs();
66+
}
67+
68+
TEST(SwitchStateBase, removeMACsecPort)
69+
{
70+
auto sc = std::make_shared<SwitchConfig>(0, "");
71+
auto scc = std::make_shared<SwitchConfigContainer>();
72+
73+
SwitchStateBase ss(
74+
0x2100000000,
75+
std::make_shared<RealObjectIdManager>(0, scc),
76+
sc);
77+
78+
auto eq = std::make_shared<EventQueue>(std::make_shared<Signal>());
79+
80+
int s = socket(AF_INET, SOCK_DGRAM, 0);
81+
int fd = socket(AF_INET, SOCK_DGRAM, 0);
82+
auto hii = std::make_shared<HostInterfaceInfo>(0, s, fd, "tap", 0, eq);
83+
ss.m_hostif_info_map["tap"] = hii;
84+
85+
sai_attribute_t attr;
86+
std::vector<sai_attribute_t> attrs;
87+
attr.id = SAI_MACSEC_PORT_ATTR_MACSEC_DIRECTION;
88+
attrs.push_back(attr);
89+
attr.id = SAI_MACSEC_PORT_ATTR_PORT_ID;
90+
attr.value.oid = 0;
91+
attrs.push_back(attr);
92+
ss.create_internal(
93+
SAI_OBJECT_TYPE_MACSEC_PORT,
94+
"oid:0x0",
95+
0,
96+
static_cast<uint32_t>(attrs.size()),
97+
attrs.data());
98+
99+
ss.m_macsecFlowPortMap[0] = 0;
100+
ss.m_macsecFlowPortMap[1] = 1;
101+
102+
MACsecAttr macsecAttr;
103+
ss.m_uncreatedIngressMACsecSAs.insert(macsecAttr);
104+
macsecAttr.m_macsecName = "macsec_vtap";
105+
ss.m_uncreatedIngressMACsecSAs.insert(macsecAttr);
106+
107+
EXPECT_EQ(SAI_STATUS_SUCCESS, ss.removeMACsecPort(0));
108+
EXPECT_EQ(1, ss.m_macsecFlowPortMap.size());
109+
EXPECT_EQ(1, ss.m_uncreatedIngressMACsecSAs.size());
110+
}

vslib/MACsecAttr.cpp

+20-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include "saimacsec.h"
44
#include "swss/logger.h"
55

6+
#include <functional>
7+
68
using namespace saivs;
79

810
const std::string MACsecAttr::CIPHER_NAME_INVALID = "";
@@ -17,7 +19,17 @@ const std::string MACsecAttr::CIPHER_NAME_GCM_AES_XPN_256 = "GCM-AES-XPN-256";
1719

1820
const std::string MACsecAttr::DEFAULT_CIPHER_NAME = MACsecAttr::CIPHER_NAME_GCM_AES_128;
1921

20-
MACsecAttr::MACsecAttr()
22+
const macsec_an_t MACsecAttr::AN_INVALID = -1;
23+
24+
size_t MACsecAttr::Hash::operator()(const MACsecAttr &attr) const
25+
{
26+
SWSS_LOG_ENTER();
27+
28+
return std::hash<std::string>()(attr.m_macsecName) ^ std::hash<std::string>()(attr.m_sci) ^ attr.m_an;
29+
}
30+
31+
MACsecAttr::MACsecAttr() : m_an(AN_INVALID)
32+
2133
{
2234
SWSS_LOG_ENTER();
2335

@@ -62,3 +74,10 @@ bool MACsecAttr::is_xpn() const
6274

6375
return m_cipher == CIPHER_NAME_GCM_AES_XPN_128 || m_cipher == CIPHER_NAME_GCM_AES_XPN_256;
6476
}
77+
78+
bool MACsecAttr::operator==(const MACsecAttr &attr) const
79+
{
80+
SWSS_LOG_ENTER();
81+
82+
return m_macsecName == attr.m_macsecName && m_sci == attr.m_sci && m_an == attr.m_an;
83+
}

vslib/MACsecAttr.h

+9
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ namespace saivs
2727

2828
static const std::string DEFAULT_CIPHER_NAME;
2929

30+
static const macsec_an_t AN_INVALID;
31+
32+
struct Hash
33+
{
34+
size_t operator()(const MACsecAttr &attr) const;
35+
};
36+
3037
// Explicitly declare constructor and destructor as non-inline functions
3138
// to avoid 'call is unlikely and code size would grow [-Werror=inline]'
3239
MACsecAttr();
@@ -37,6 +44,8 @@ namespace saivs
3744

3845
bool is_xpn() const;
3946

47+
bool operator==(const MACsecAttr &attr) const;
48+
4049
std::string m_cipher;
4150
std::string m_vethName;
4251
std::string m_macsecName;

vslib/SwitchStateBase.h

+4
Original file line numberDiff line numberDiff line change
@@ -591,10 +591,14 @@ namespace saivs
591591
_In_ sai_object_id_t macsec_sa_id,
592592
_Out_ sai_attribute_t &attr);
593593

594+
void retryCreateIngressMaCsecSAs();
595+
594596
MACsecManager m_macsecManager;
595597

596598
std::unordered_map<sai_object_id_t, sai_object_id_t> m_macsecFlowPortMap;
597599

600+
std::unordered_set<MACsecAttr, MACsecAttr::Hash> m_uncreatedIngressMACsecSAs;
601+
598602
protected:
599603

600604
constexpr static const int maxDebugCounters = 32;

vslib/SwitchStateBaseMACsec.cpp

+78-6
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ sai_status_t SwitchStateBase::setAclEntryMACsecFlowActive(
9393
static_cast<std::uint32_t>(macsecAttr.m_an),
9494
macsecAttr.m_macsecName.c_str());
9595
}
96+
else
97+
{
98+
m_uncreatedIngressMACsecSAs.insert(macsecAttr);
99+
}
96100
}
97101
}
98102
}
@@ -199,6 +203,21 @@ sai_status_t SwitchStateBase::createMACsecSA(
199203
macsecAttr.m_sci.c_str(),
200204
static_cast<std::uint32_t>(macsecAttr.m_an),
201205
macsecAttr.m_macsecName.c_str());
206+
207+
// Maybe there are some uncreated ingress SAs that were added into m_uncreatedIngressMACsecSAs
208+
// because the corresponding egress SA has not been created.
209+
// So retry to create them.
210+
if (macsecAttr.m_direction == SAI_MACSEC_DIRECTION_EGRESS)
211+
{
212+
retryCreateIngressMaCsecSAs();
213+
}
214+
}
215+
else
216+
{
217+
// In Linux MACsec model, Egress SA need to be created before ingress SA.
218+
// So, if try to create the ingress SA firstly, it will failed.
219+
// But to create the egress SA should be always successful.
220+
m_uncreatedIngressMACsecSAs.insert(macsecAttr);
202221
}
203222
}
204223

@@ -221,17 +240,31 @@ sai_status_t SwitchStateBase::removeMACsecPort(
221240
}
222241
}
223242

224-
auto itr = m_macsecFlowPortMap.begin();
243+
auto flowItr = m_macsecFlowPortMap.begin();
225244

226-
while (itr != m_macsecFlowPortMap.end())
245+
while (flowItr != m_macsecFlowPortMap.end())
227246
{
228-
if (itr->second == macsecPortId)
247+
if (flowItr->second == macsecPortId)
229248
{
230-
itr = m_macsecFlowPortMap.erase(itr);
249+
flowItr = m_macsecFlowPortMap.erase(flowItr);
231250
}
232251
else
233252
{
234-
itr ++;
253+
flowItr ++;
254+
}
255+
}
256+
257+
auto saItr = m_uncreatedIngressMACsecSAs.begin();
258+
259+
while (saItr != m_uncreatedIngressMACsecSAs.end())
260+
{
261+
if (saItr->m_macsecName == macsecAttr.m_macsecName)
262+
{
263+
saItr = m_uncreatedIngressMACsecSAs.erase(saItr);
264+
}
265+
else
266+
{
267+
saItr ++;
235268
}
236269
}
237270

@@ -257,6 +290,20 @@ sai_status_t SwitchStateBase::removeMACsecSC(
257290
}
258291
}
259292

293+
auto saItr = m_uncreatedIngressMACsecSAs.begin();
294+
295+
while (saItr != m_uncreatedIngressMACsecSAs.end())
296+
{
297+
if (saItr->m_macsecName == macsecAttr.m_macsecName && saItr->m_sci == macsecAttr.m_sci)
298+
{
299+
saItr = m_uncreatedIngressMACsecSAs.erase(saItr);
300+
}
301+
else
302+
{
303+
saItr ++;
304+
}
305+
}
306+
260307
auto sid = sai_serialize_object_id(macsecScId);
261308
return remove_internal(SAI_OBJECT_TYPE_MACSEC_SC, sid);
262309
}
@@ -550,7 +597,7 @@ sai_status_t SwitchStateBase::loadMACsecAttrFromMACsecSA(
550597

551598
CHECK_STATUS(get(SAI_OBJECT_TYPE_MACSEC_SC, attr->value.oid, static_cast<uint32_t>(attrs.size()), attrs.data()));
552599

553-
macsecAttr.m_cipher = MACsecAttr::get_cipher_name(attr->value.s32);
600+
macsecAttr.m_cipher = MACsecAttr::get_cipher_name(attrs[3].value.s32);
554601

555602
if (macsecAttr.m_cipher == MACsecAttr::CIPHER_NAME_INVALID)
556603
{
@@ -841,3 +888,28 @@ sai_status_t SwitchStateBase::getMACsecSAPacketNumber(
841888

842889
return SAI_STATUS_FAILURE;
843890
}
891+
892+
void SwitchStateBase::retryCreateIngressMaCsecSAs()
893+
{
894+
SWSS_LOG_ENTER();
895+
896+
auto itr = m_uncreatedIngressMACsecSAs.begin();
897+
898+
while (itr != m_uncreatedIngressMACsecSAs.end())
899+
{
900+
if (m_macsecManager.create_macsec_sa(*itr))
901+
{
902+
SWSS_LOG_NOTICE(
903+
"Enable MACsec SA %s:%u at the device %s",
904+
itr->m_sci.c_str(),
905+
static_cast<std::uint32_t>(itr->m_an),
906+
itr->m_macsecName.c_str());
907+
908+
itr = m_uncreatedIngressMACsecSAs.erase(itr);
909+
}
910+
else
911+
{
912+
itr ++;
913+
}
914+
}
915+
}

0 commit comments

Comments
 (0)