Skip to content

Commit f13aaed

Browse files
authored
Disable FDB hardware learning on all bridge ports before planned warm restart (sonic-net#628)
* Disable FDB learning on all bridge ports before freezing orchagent * Refine create_bridge_port attr * Flush before freeze * Add vs test * Fix error message * Generalize setBridgePortLearningFDB() * Tune test
1 parent 65b015b commit f13aaed

File tree

6 files changed

+105
-65
lines changed

6 files changed

+105
-65
lines changed

orchagent/orchdaemon.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,14 @@ void OrchDaemon::start()
363363
// Should sleep here or continue handling timers and etc.??
364364
if (!gSwitchOrch->checkRestartNoFreeze())
365365
{
366+
// Disable FDB learning on all bridge ports
367+
for (auto& pair: gPortsOrch->getAllPorts())
368+
{
369+
auto& port = pair.second;
370+
gPortsOrch->setBridgePortLearningFDB(port, SAI_BRIDGE_PORT_FDB_LEARNING_MODE_DISABLE);
371+
}
372+
flush();
373+
366374
SWSS_LOG_WARN("Orchagent is frozen for warm restart!");
367375
sleep(UINT_MAX);
368376
}

orchagent/portsorch.cpp

+26
Original file line numberDiff line numberDiff line change
@@ -2312,6 +2312,27 @@ bool PortsOrch::addHostIntfs(Port &port, string alias, sai_object_id_t &host_int
23122312
return true;
23132313
}
23142314

2315+
bool PortsOrch::setBridgePortLearningFDB(Port &port, sai_bridge_port_fdb_learning_mode_t mode)
2316+
{
2317+
// TODO: how to support 1D bridge?
2318+
if (port.m_type != Port::PHY) return false;
2319+
2320+
auto bridge_port_id = port.m_bridge_port_id;
2321+
if (bridge_port_id == SAI_NULL_OBJECT_ID) return false;
2322+
2323+
sai_attribute_t bport_attr;
2324+
bport_attr.id = SAI_BRIDGE_PORT_ATTR_FDB_LEARNING_MODE;
2325+
bport_attr.value.s32 = mode;
2326+
auto status = sai_bridge_api->set_bridge_port_attribute(bridge_port_id, &bport_attr);
2327+
if (status != SAI_STATUS_SUCCESS)
2328+
{
2329+
SWSS_LOG_ERROR("Failed to set bridge port %lx learning_mode attribute: %d", bridge_port_id, status);
2330+
return false;
2331+
}
2332+
SWSS_LOG_NOTICE("Disable FDB learning on bridge port %s(%lx)", port.m_alias.c_str(), bridge_port_id);
2333+
return true;
2334+
}
2335+
23152336
bool PortsOrch::addBridgePort(Port &port)
23162337
{
23172338
SWSS_LOG_ENTER();
@@ -2350,6 +2371,11 @@ bool PortsOrch::addBridgePort(Port &port)
23502371
attr.value.booldata = true;
23512372
attrs.push_back(attr);
23522373

2374+
/* And with hardware FDB learning mode set to HW (explicit default value) */
2375+
attr.id = SAI_BRIDGE_PORT_ATTR_FDB_LEARNING_MODE;
2376+
attr.value.s32 = SAI_BRIDGE_PORT_FDB_LEARNING_MODE_HW;
2377+
attrs.push_back(attr);
2378+
23532379
sai_status_t status = sai_bridge_api->create_bridge_port(&port.m_bridge_port_id, gSwitchId, (uint32_t)attrs.size(), attrs.data());
23542380
if (status != SAI_STATUS_SUCCESS)
23552381
{

orchagent/portsorch.h

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class PortsOrch : public Orch, public Subject
5959
bool bake() override;
6060
void cleanPortTable(const vector<string>& keys);
6161
bool getBridgePort(sai_object_id_t id, Port &port);
62+
bool setBridgePortLearningFDB(Port &port, sai_bridge_port_fdb_learning_mode_t mode);
6263
bool getPort(string alias, Port &port);
6364
bool getPort(sai_object_id_t id, Port &port);
6465
bool getPortByBridgePortId(sai_object_id_t bridge_port_id, Port &port);

tests/conftest.py

+21-12
Original file line numberDiff line numberDiff line change
@@ -269,15 +269,28 @@ def copy_file(self, path, filename):
269269
self.ctn.put_archive(path, tarstr.getvalue())
270270
tarstr.close()
271271

272+
def get_map_iface_bridge_port_id(self, asic_db):
273+
port_id_2_iface = self.asicdb.portoidmap
274+
tbl = swsscommon.Table(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT")
275+
iface_2_bridge_port_id = {}
276+
for key in tbl.getKeys():
277+
status, data = tbl.get(key)
278+
assert status
279+
values = dict(data)
280+
iface_id = values["SAI_BRIDGE_PORT_ATTR_PORT_ID"]
281+
iface_name = port_id_2_iface[iface_id]
282+
iface_2_bridge_port_id[iface_name] = key
283+
284+
return iface_2_bridge_port_id
285+
272286
def is_table_entry_exists(self, db, table, keyregex, attributes):
273287
tbl = swsscommon.Table(db, table)
274288
keys = tbl.getKeys()
275289

276-
exists = False
277290
extra_info = []
278-
key_found = False
279291
for key in keys:
280-
key_found = re.match(keyregex, key)
292+
if re.match(keyregex, key) is None:
293+
continue
281294

282295
status, fvs = tbl.get(key)
283296
assert status, "Error reading from table %s" % table
@@ -288,17 +301,13 @@ def is_table_entry_exists(self, db, table, keyregex, attributes):
288301
del d_attributes[k]
289302

290303
if len(d_attributes) != 0:
291-
exists = False
292304
extra_info.append("Desired attributes %s was not found for key %s" % (str(d_attributes), key))
293305
else:
294-
exists = True
295-
break
296-
297-
if not key_found:
298-
exists = False
299-
extra_info.append("Desired key with parameters %s was not found" % str(key_values))
300-
301-
return exists, extra_info
306+
return True, extra_info
307+
else:
308+
if not extra_info:
309+
extra_info.append("Desired key regex %s was not found" % str(keyregex))
310+
return False, extra_info
302311

303312
def is_fdb_entry_exists(self, db, table, key_values, attributes):
304313
tbl = swsscommon.Table(db, table)

tests/test_fdb_cold.py

+1-16
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,6 @@ def create_entry_pst(db, table, key, pairs):
2020
tbl = swsscommon.ProducerStateTable(db, table)
2121
create_entry(tbl, key, pairs)
2222

23-
24-
def get_map_iface_bridge_port_id(asic_db, dvs):
25-
port_id_2_iface = dvs.asicdb.portoidmap
26-
tbl = swsscommon.Table(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT")
27-
iface_2_bridge_port_id = {}
28-
for key in tbl.getKeys():
29-
status, data = tbl.get(key)
30-
assert status
31-
values = dict(data)
32-
iface_id = values["SAI_BRIDGE_PORT_ATTR_PORT_ID"]
33-
iface_name = port_id_2_iface[iface_id]
34-
iface_2_bridge_port_id[iface_name] = key
35-
36-
return iface_2_bridge_port_id
37-
3823
def how_many_entries_exist(db, table):
3924
tbl = swsscommon.Table(db, table)
4025
return len(tbl.getKeys())
@@ -90,7 +75,7 @@ def test_FDBAddedAfterMemberCreated(dvs):
9075
assert vm_after - vm_before == 1, "The vlan member wasn't added"
9176

9277
# Get mapping between interface name and its bridge port_id
93-
iface_2_bridge_port_id = get_map_iface_bridge_port_id(dvs.adb, dvs)
78+
iface_2_bridge_port_id = dvs.get_map_iface_bridge_port_id(dvs.adb)
9479

9580
# check that the FDB entry was inserted into ASIC DB
9681
assert how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY") == 1, "The fdb entry wasn't inserted to ASIC"

tests/test_fdb_warm.py

+48-37
Original file line numberDiff line numberDiff line change
@@ -20,29 +20,14 @@ def create_entry_pst(db, table, key, pairs):
2020
tbl = swsscommon.ProducerStateTable(db, table)
2121
create_entry(tbl, key, pairs)
2222

23-
24-
def get_map_iface_bridge_port_id(asic_db, dvs):
25-
port_id_2_iface = dvs.asicdb.portoidmap
26-
tbl = swsscommon.Table(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT")
27-
iface_2_bridge_port_id = {}
28-
for key in tbl.getKeys():
29-
status, data = tbl.get(key)
30-
assert status
31-
values = dict(data)
32-
iface_id = values["SAI_BRIDGE_PORT_ATTR_PORT_ID"]
33-
iface_name = port_id_2_iface[iface_id]
34-
iface_2_bridge_port_id[iface_name] = key
35-
36-
return iface_2_bridge_port_id
37-
3823
def how_many_entries_exist(db, table):
3924
tbl = swsscommon.Table(db, table)
4025
return len(tbl.getKeys())
4126

4227
def test_fdb_notifications(dvs):
4328
dvs.setup_db()
4429

45-
#dvs.runcmd("sonic-clear fdb all")
30+
dvs.runcmd("sonic-clear fdb all")
4631

4732
dvs.runcmd("crm config polling interval 1")
4833
dvs.setReadOnlyAttr('SAI_OBJECT_TYPE_SWITCH', 'SAI_SWITCH_ATTR_AVAILABLE_FDB_ENTRY', '1000')
@@ -55,6 +40,20 @@ def test_fdb_notifications(dvs):
5540
dvs.create_vlan_member("6", "Ethernet64")
5641
dvs.create_vlan_member("6", "Ethernet68")
5742

43+
# Get mapping between interface name and its bridge port_id
44+
time.sleep(2)
45+
iface_2_bridge_port_id = dvs.get_map_iface_bridge_port_id(dvs.adb)
46+
47+
# check FDB learning mode
48+
ok, extra = dvs.is_table_entry_exists(dvs.adb, 'ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT',
49+
iface_2_bridge_port_id["Ethernet64"],
50+
[("SAI_BRIDGE_PORT_ATTR_FDB_LEARNING_MODE", "SAI_BRIDGE_PORT_FDB_LEARNING_MODE_HW")])
51+
assert ok, str(extra)
52+
ok, extra = dvs.is_table_entry_exists(dvs.adb, 'ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT',
53+
iface_2_bridge_port_id["Ethernet68"],
54+
[("SAI_BRIDGE_PORT_ATTR_FDB_LEARNING_MODE", "SAI_BRIDGE_PORT_FDB_LEARNING_MODE_HW")])
55+
assert ok, str(extra)
56+
5857
# bring up vlan and member
5958
dvs.set_interface_status("Vlan6", "up")
6059
dvs.add_ip_address("Vlan6", "6.6.6.1/24")
@@ -72,9 +71,6 @@ def test_fdb_notifications(dvs):
7271
rc = dvs.servers[17].runcmd("ping -c 1 6.6.6.6")
7372
assert rc == 0
7473

75-
# Get mapping between interface name and its bridge port_id
76-
time.sleep(2)
77-
iface_2_bridge_port_id = get_map_iface_bridge_port_id(dvs.adb, dvs)
7874

7975
# check that the FDB entries were inserted into ASIC DB
8076
ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY",
@@ -113,24 +109,34 @@ def test_fdb_notifications(dvs):
113109
assert ok, str(extra)
114110

115111
# enable warm restart
116-
# TODO: use cfg command to config it
117-
create_entry_tbl(
118-
dvs.cdb,
119-
swsscommon.CFG_WARM_RESTART_TABLE_NAME, "swss",
120-
[
121-
("enable", "true"),
122-
]
123-
)
112+
(exitcode, result) = dvs.runcmd("config warm_restart enable swss")
113+
assert exitcode == 0
114+
115+
# freeze orchagent for warm restart
116+
(exitcode, result) = dvs.runcmd("/usr/bin/orchagent_restart_check")
117+
assert result == "RESTARTCHECK succeeded\n"
118+
time.sleep(2)
124119

125120
try:
126121
# restart orchagent
127122
dvs.stop_swss()
123+
124+
# check FDB learning mode
125+
ok, extra = dvs.is_table_entry_exists(dvs.adb, 'ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT',
126+
iface_2_bridge_port_id["Ethernet64"],
127+
[("SAI_BRIDGE_PORT_ATTR_FDB_LEARNING_MODE", "SAI_BRIDGE_PORT_FDB_LEARNING_MODE_DISABLE")])
128+
assert ok, str(extra)
129+
ok, extra = dvs.is_table_entry_exists(dvs.adb, 'ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT',
130+
iface_2_bridge_port_id["Ethernet68"],
131+
[("SAI_BRIDGE_PORT_ATTR_FDB_LEARNING_MODE", "SAI_BRIDGE_PORT_FDB_LEARNING_MODE_DISABLE")])
132+
assert ok, str(extra)
133+
128134
dvs.start_swss()
129135
time.sleep(2)
130136

131137
# Get mapping between interface name and its bridge port_id
132138
# Note: they are changed
133-
iface_2_bridge_port_id = get_map_iface_bridge_port_id(dvs.adb, dvs)
139+
iface_2_bridge_port_id = dvs.get_map_iface_bridge_port_id(dvs.adb)
134140

135141
# check that the FDB entries were inserted into ASIC DB
136142
ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY",
@@ -148,17 +154,22 @@ def test_fdb_notifications(dvs):
148154
)
149155
assert ok, str(extra)
150156

157+
# check FDB learning mode
158+
ok, extra = dvs.is_table_entry_exists(dvs.adb, 'ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT',
159+
iface_2_bridge_port_id["Ethernet64"],
160+
[("SAI_BRIDGE_PORT_ATTR_FDB_LEARNING_MODE", "SAI_BRIDGE_PORT_FDB_LEARNING_MODE_HW")])
161+
assert ok, str(extra)
162+
ok, extra = dvs.is_table_entry_exists(dvs.adb, 'ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT',
163+
iface_2_bridge_port_id["Ethernet68"],
164+
[("SAI_BRIDGE_PORT_ATTR_FDB_LEARNING_MODE", "SAI_BRIDGE_PORT_FDB_LEARNING_MODE_HW")])
165+
assert ok, str(extra)
166+
151167
time.sleep(2)
152168
counter_restarted = dvs.getCrmCounterValue('STATS', 'crm_stats_fdb_entry_used')
153169
assert counter_inserted == counter_restarted
154170

155171
finally:
156-
# disable warm restart
157-
# TODO: use cfg command to config it
158-
create_entry_tbl(
159-
dvs.cdb,
160-
swsscommon.CFG_WARM_RESTART_TABLE_NAME, "swss",
161-
[
162-
("enable", "false"),
163-
]
164-
)
172+
# enable warm restart
173+
dvs.runcmd("config warm_restart enable swss")
174+
# slow down crm polling
175+
dvs.runcmd("crm config polling interval 10000")

0 commit comments

Comments
 (0)