Skip to content

Commit bdedf69

Browse files
authored
Modify coppmgr mergeConfig to support preserving copp tables through reboot. (#2548)
This PR should be merged together with sonic-net/sonic-utilities#2524 and is required to 202205 and 202211. This PR implements [fastboot] Preserve CoPP table HLD to improve fastboot flow (sonic-net/SONiC#1107). - What I did Modified coppmgr mergeConfig logic to support preserving copp tables contents through reboot. Handle duplicates, overwrites, unsupported keys preserved and new keys. According to sonic-net/SONiC#1107 - Why I did it To shorten dataplane downtime on fast-reboot. - How I verified it Manual tests (community fast-reboot test)
1 parent 7891e78 commit bdedf69

File tree

5 files changed

+246
-0
lines changed

5 files changed

+246
-0
lines changed

cfgmgr/coppmgr.cpp

+57
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include "shellcmd.h"
1010
#include "warm_restart.h"
1111
#include "json.hpp"
12+
#include <unordered_map>
13+
#include <unordered_set>
1214

1315
using json = nlohmann::json;
1416

@@ -255,6 +257,42 @@ void CoppMgr::mergeConfig(CoppCfg &init_cfg, CoppCfg &m_cfg, std::vector<std::st
255257
}
256258
}
257259

260+
bool CoppMgr::isDupEntry(const std::string &key, std::vector<FieldValueTuple> &fvs)
261+
{
262+
/* Compare with the existing contents of copp tables, in case for a key K preserved fvs are the same
263+
* as the fvs in trap_group_fvs it will be ignored as a duplicate continue to next key.
264+
* In case one of the fvs differs the preserved entry will be deleted and new entry will be set instead.
265+
*/
266+
std::vector<FieldValueTuple> preserved_fvs;
267+
bool key_found = m_coppTable.get(key, preserved_fvs);
268+
if (!key_found)
269+
{
270+
return false;
271+
}
272+
else
273+
{
274+
unordered_map<string, string> preserved_copp_entry;
275+
for (auto prev_fv : preserved_fvs)
276+
{
277+
preserved_copp_entry[fvField(prev_fv)] = fvValue(prev_fv);
278+
}
279+
for (auto fv: fvs)
280+
{
281+
string field = fvField(fv);
282+
string value = fvValue(fv);
283+
auto preserved_copp_it = preserved_copp_entry.find(field);
284+
bool field_found = (preserved_copp_it != preserved_copp_entry.end());
285+
if ((!field_found) || (field_found && preserved_copp_it->second.compare(value)))
286+
{
287+
// overwrite -> delete preserved entry from copp table and set a new entry instead
288+
m_coppTable.del(key);
289+
return false;
290+
}
291+
}
292+
}
293+
return true;
294+
}
295+
258296
CoppMgr::CoppMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const vector<string> &tableNames) :
259297
Orch(cfgDb, tableNames),
260298
m_cfgCoppTrapTable(cfgDb, CFG_COPP_TRAP_TABLE_NAME),
@@ -270,16 +308,19 @@ CoppMgr::CoppMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, c
270308
std::vector<string> group_keys;
271309
std::vector<string> trap_keys;
272310
std::vector<string> feature_keys;
311+
std::vector<string> preserved_copp_keys;
273312

274313
std::vector<string> group_cfg_keys;
275314
std::vector<string> trap_cfg_keys;
315+
unordered_set<string> supported_copp_keys;
276316

277317
CoppCfg group_cfg;
278318
CoppCfg trap_cfg;
279319

280320
m_cfgCoppGroupTable.getKeys(group_cfg_keys);
281321
m_cfgCoppTrapTable.getKeys(trap_cfg_keys);
282322
m_cfgFeatureTable.getKeys(feature_keys);
323+
m_coppTable.getKeys(preserved_copp_keys);
283324

284325

285326
for (auto i: feature_keys)
@@ -352,15 +393,31 @@ CoppMgr::CoppMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, c
352393

353394
if (!trap_group_fvs.empty())
354395
{
396+
supported_copp_keys.emplace(i.first);
397+
if (isDupEntry(i.first, trap_group_fvs))
398+
{
399+
continue;
400+
}
355401
m_appCoppTable.set(i.first, trap_group_fvs);
356402
}
403+
357404
setCoppGroupStateOk(i.first);
358405
auto g_cfg = std::find(group_cfg_keys.begin(), group_cfg_keys.end(), i.first);
359406
if (g_cfg != group_cfg_keys.end())
360407
{
361408
g_copp_init_set.insert(i.first);
362409
}
363410
}
411+
412+
// Delete unsupported keys from preserved copp tables
413+
for (auto it : preserved_copp_keys)
414+
{
415+
auto copp_it = supported_copp_keys.find(it);
416+
if (copp_it == supported_copp_keys.end())
417+
{
418+
m_coppTable.del(it);
419+
}
420+
}
364421
}
365422

366423
void CoppMgr::setCoppGroupStateOk(string alias)

cfgmgr/coppmgr.h

+1
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ class CoppMgr : public Orch
100100
bool isTrapGroupInstalled(std::string key);
101101
bool isFeatureEnabled(std::string feature);
102102
void mergeConfig(CoppCfg &init_cfg, CoppCfg &m_cfg, std::vector<std::string> &cfg_keys, Table &cfgTable);
103+
bool isDupEntry(const std::string &key, std::vector<FieldValueTuple> &fvs);
103104

104105
void removeTrap(std::string key);
105106
void addTrap(std::string trap_ids, std::string trap_group);

tests/mock_tests/Makefile.am

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ tests_SOURCES = aclorch_ut.cpp \
3030
bufferorch_ut.cpp \
3131
buffermgrdyn_ut.cpp \
3232
fdborch/flush_syncd_notif_ut.cpp \
33+
copp_ut.cpp \
3334
copporch_ut.cpp \
3435
saispy_ut.cpp \
3536
consumer_ut.cpp \

tests/mock_tests/copp_cfg.json

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
{
2+
"COPP_GROUP": {
3+
"default": {
4+
"queue": "0",
5+
"meter_type":"packets",
6+
"mode":"sr_tcm",
7+
"cir":"600",
8+
"cbs":"600",
9+
"red_action":"drop"
10+
},
11+
"queue4_group1": {
12+
"trap_action":"trap",
13+
"trap_priority":"4",
14+
"queue": "4"
15+
},
16+
"queue4_group2": {
17+
"trap_action":"copy",
18+
"trap_priority":"4",
19+
"queue": "4",
20+
"meter_type":"packets",
21+
"mode":"sr_tcm",
22+
"cir":"600",
23+
"cbs":"600",
24+
"red_action":"drop"
25+
},
26+
"queue4_group3": {
27+
"trap_action":"trap",
28+
"trap_priority":"4",
29+
"queue": "4"
30+
},
31+
"queue1_group1": {
32+
"trap_action":"trap",
33+
"trap_priority":"1",
34+
"queue": "1",
35+
"meter_type":"packets",
36+
"mode":"sr_tcm",
37+
"cir":"6000",
38+
"cbs":"6000",
39+
"red_action":"drop"
40+
},
41+
"queue1_group2": {
42+
"trap_action":"trap",
43+
"trap_priority":"1",
44+
"queue": "1",
45+
"meter_type":"packets",
46+
"mode":"sr_tcm",
47+
"cir":"600",
48+
"cbs":"600",
49+
"red_action":"drop"
50+
},
51+
"queue2_group1": {
52+
"cbs": "1000",
53+
"cir": "1000",
54+
"genetlink_mcgrp_name": "packets",
55+
"genetlink_name": "psample",
56+
"meter_type": "packets",
57+
"mode": "sr_tcm",
58+
"queue": "2",
59+
"red_action": "drop",
60+
"trap_action": "trap",
61+
"trap_priority": "1"
62+
63+
}
64+
},
65+
"COPP_TRAP": {
66+
"bgp": {
67+
"trap_ids": "bgp,bgpv6",
68+
"trap_group": "queue4_group1"
69+
},
70+
"lacp": {
71+
"trap_ids": "lacp",
72+
"trap_group": "queue4_group1",
73+
"always_enabled": "true"
74+
},
75+
"arp": {
76+
"trap_ids": "arp_req,arp_resp,neigh_discovery",
77+
"trap_group": "queue4_group2",
78+
"always_enabled": "true"
79+
},
80+
"lldp": {
81+
"trap_ids": "lldp",
82+
"trap_group": "queue4_group3"
83+
},
84+
"dhcp_relay": {
85+
"trap_ids": "dhcp,dhcpv6",
86+
"trap_group": "queue4_group3"
87+
},
88+
"udld": {
89+
"trap_ids": "udld",
90+
"trap_group": "queue4_group3",
91+
"always_enabled": "true"
92+
},
93+
"ip2me": {
94+
"trap_ids": "ip2me",
95+
"trap_group": "queue1_group1",
96+
"always_enabled": "true"
97+
},
98+
"macsec": {
99+
"trap_ids": "eapol",
100+
"trap_group": "queue4_group3"
101+
},
102+
"nat": {
103+
"trap_ids": "src_nat_miss,dest_nat_miss",
104+
"trap_group": "queue1_group2"
105+
},
106+
"sflow": {
107+
"trap_group": "queue2_group1",
108+
"trap_ids": "sample_packet"
109+
}
110+
}
111+
}

tests/mock_tests/copp_ut.cpp

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#include "gtest/gtest.h"
2+
#include <string>
3+
#include "schema.h"
4+
#include "warm_restart.h"
5+
#include "ut_helper.h"
6+
#include "coppmgr.h"
7+
#include "coppmgr.cpp"
8+
#include <fstream>
9+
#include <streambuf>
10+
using namespace std;
11+
using namespace swss;
12+
13+
void create_init_file()
14+
{
15+
int status = system("sudo mkdir /etc/sonic/");
16+
ASSERT_EQ(status, 0);
17+
18+
status = system("sudo chmod 777 /etc/sonic/");
19+
ASSERT_EQ(status, 0);
20+
21+
status = system("sudo cp copp_cfg.json /etc/sonic/");
22+
ASSERT_EQ(status, 0);
23+
}
24+
25+
void cleanup()
26+
{
27+
int status = system("sudo rm -rf /etc/sonic/");
28+
ASSERT_EQ(status, 0);
29+
}
30+
31+
TEST(CoppMgrTest, CoppTest)
32+
{
33+
create_init_file();
34+
35+
const vector<string> cfg_copp_tables = {
36+
CFG_COPP_TRAP_TABLE_NAME,
37+
CFG_COPP_GROUP_TABLE_NAME,
38+
CFG_FEATURE_TABLE_NAME,
39+
};
40+
41+
WarmStart::initialize("coppmgrd", "swss");
42+
WarmStart::checkWarmStart("coppmgrd", "swss");
43+
44+
DBConnector cfgDb("CONFIG_DB", 0);
45+
DBConnector appDb("APPL_DB", 0);
46+
DBConnector stateDb("STATE_DB", 0);
47+
48+
/* The test will set an entry with queue1_group1|cbs value which differs from the init value
49+
* found in the copp_cfg.json file. Then coppmgr constructor will be called and it will detect
50+
* that there is already an entry for queue1_group1|cbs with different value and it should be
51+
* overwritten with the init value.
52+
* hget will verify that this indeed happened.
53+
*/
54+
Table coppTable = Table(&appDb, APP_COPP_TABLE_NAME);
55+
coppTable.set("queue1_group1",
56+
{
57+
{"cbs", "6100"},
58+
{"cir", "6000"},
59+
{"meter_type", "packets"},
60+
{"mode", "sr_tcm"},
61+
{"queue", "1"},
62+
{"red_action", "drop"},
63+
{"trap_action", "trap"},
64+
{"trap_priority", "1"},
65+
{"trap_ids", "ip2me"}
66+
});
67+
68+
CoppMgr coppmgr(&cfgDb, &appDb, &stateDb, cfg_copp_tables);
69+
70+
string overide_val;
71+
coppTable.hget("queue1_group1", "cbs",overide_val);
72+
EXPECT_EQ( overide_val, "6000");
73+
74+
cleanup();
75+
}
76+

0 commit comments

Comments
 (0)