Skip to content

Commit a35afac

Browse files
stepanblyschaklguohan
authored andcommitted
[portsorch] use ingress/egress disable for LAG member enable/disable (#1166)
Originally portsorch was designed to remove LAG member from LAG when member gets disabled by teamd. This could lead to potential issues including flood to that port and loops, since after removal member becomes a switch port. Now, portsorch will make use of SAI_LAG_MEMBER_ATTR_INGRESS_DISABLE and SAI_LAG_MEMBER_ATTR_EGRESS_DISABLE to control collection/distribution through that LAG member port. With this new flow, teammgrd and teamsyncd are candidates to be refactored, especially teamsyncd warm reboot logic, since now we don't need to compare old, new lags and lag members. Teamsyncd's job is simply to signal "status" field update without waiting for reconciliation timer to expire. e.g. one port channel went down on peer: ``` admin@arc-switch1025:~$ show interfaces portchannel Flags: A - active, I - inactive, Up - up, Dw - Down, N/A - not available, S - selected, D - deselected, * - not synced No. Team Dev Protocol Ports ----- --------------- ----------- -------------- 0001 PortChannel0001 LACP(A)(Up) Ethernet112(S) 0002 PortChannel0002 LACP(A)(Up) Ethernet116(S) 0003 PortChannel0003 LACP(A)(Up) Ethernet120(S) 0004 PortChannel0004 LACP(A)(Dw) Ethernet124(D) admin@arc-switch1025:~$ docker exec -it syncd sx_api_lag_dump.py LAG Members Table =============================================================================================================== | SWID| LAG Logical Port| LAG Oper State| PVID| Member Port ID| Port Label| Collector| Distributor| Oper State| =============================================================================================================== | 0 0x10000000 UP 1| 0x11900| 29| Enable| Enable| UP| =============================================================================================================== | 0 0x10000100 UP 1| 0x11b00| 30| Enable| Enable| UP| =============================================================================================================== | 0 0x10000200 UP 1| 0x11d00| 31| Enable| Enable| UP| =============================================================================================================== | 0 0x10000300 DOWN 1| 0x11f00| 32| Disable| Disable| UP| =============================================================================================================== ``` Signed-off-by: Stepan Blyschak <[email protected]>
1 parent faab3e1 commit a35afac

File tree

3 files changed

+115
-23
lines changed

3 files changed

+115
-23
lines changed

orchagent/portsorch.cpp

Lines changed: 78 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2472,39 +2472,51 @@ void PortsOrch::doLagMemberTask(Consumer &consumer)
24722472
status = fvValue(i);
24732473
}
24742474

2475-
/* Sync an enabled member */
2476-
if (status == "enabled")
2475+
if (lag.m_members.find(port_alias) == lag.m_members.end())
24772476
{
2478-
/* Duplicate entry */
2479-
if (lag.m_members.find(port_alias) != lag.m_members.end())
2477+
/* Assert the port doesn't belong to any LAG already */
2478+
assert(!port.m_lag_id && !port.m_lag_member_id);
2479+
2480+
if (!addLagMember(lag, port))
24802481
{
2481-
it = consumer.m_toSync.erase(it);
2482+
it++;
24822483
continue;
24832484
}
2485+
}
24842486

2485-
/* Assert the port doesn't belong to any LAG */
2486-
assert(!port.m_lag_id && !port.m_lag_member_id);
2487-
2488-
if (addLagMember(lag, port))
2487+
/* Sync an enabled member */
2488+
if (status == "enabled")
2489+
{
2490+
/* enable collection first, distribution-only mode
2491+
* is not supported on Mellanox platform
2492+
*/
2493+
if (setCollectionOnLagMember(port, true) &&
2494+
setDistributionOnLagMember(port, true))
2495+
{
24892496
it = consumer.m_toSync.erase(it);
2497+
}
24902498
else
2499+
{
24912500
it++;
2501+
continue;
2502+
}
24922503
}
24932504
/* Sync an disabled member */
24942505
else /* status == "disabled" */
24952506
{
2496-
/* "status" is "disabled" at start when m_lag_id and
2497-
* m_lag_member_id are absent */
2498-
if (!port.m_lag_id || !port.m_lag_member_id)
2507+
/* disable distribution first, distribution-only mode
2508+
* is not supported on Mellanox platform
2509+
*/
2510+
if (setDistributionOnLagMember(port, false) &&
2511+
setCollectionOnLagMember(port, false))
24992512
{
25002513
it = consumer.m_toSync.erase(it);
2501-
continue;
25022514
}
2503-
2504-
if (removeLagMember(lag, port))
2505-
it = consumer.m_toSync.erase(it);
25062515
else
2516+
{
25072517
it++;
2518+
continue;
2519+
}
25082520
}
25092521
}
25102522
/* Remove a LAG member */
@@ -2522,9 +2534,13 @@ void PortsOrch::doLagMemberTask(Consumer &consumer)
25222534
}
25232535

25242536
if (removeLagMember(lag, port))
2537+
{
25252538
it = consumer.m_toSync.erase(it);
2539+
}
25262540
else
2541+
{
25272542
it++;
2543+
}
25282544
}
25292545
else
25302546
{
@@ -3318,6 +3334,52 @@ bool PortsOrch::removeLagMember(Port &lag, Port &port)
33183334
return true;
33193335
}
33203336

3337+
bool PortsOrch::setCollectionOnLagMember(Port &lagMember, bool enableCollection)
3338+
{
3339+
/* Port must be LAG member */
3340+
assert(port.m_lag_member_id);
3341+
3342+
sai_status_t status = SAI_STATUS_FAILURE;
3343+
sai_attribute_t attr {};
3344+
3345+
attr.id = SAI_LAG_MEMBER_ATTR_INGRESS_DISABLE;
3346+
attr.value.booldata = !enableCollection;
3347+
3348+
status = sai_lag_api->set_lag_member_attribute(lagMember.m_lag_member_id, &attr);
3349+
if (status != SAI_STATUS_SUCCESS)
3350+
{
3351+
SWSS_LOG_ERROR("Failed to %s collection on LAG member %s",
3352+
enableCollection ? "enable" : "disable",
3353+
lagMember.m_alias.c_str());
3354+
return false;
3355+
}
3356+
3357+
return true;
3358+
}
3359+
3360+
bool PortsOrch::setDistributionOnLagMember(Port &lagMember, bool enableDistribution)
3361+
{
3362+
/* Port must be LAG member */
3363+
assert(port.m_lag_member_id);
3364+
3365+
sai_status_t status = SAI_STATUS_FAILURE;
3366+
sai_attribute_t attr {};
3367+
3368+
attr.id = SAI_LAG_MEMBER_ATTR_EGRESS_DISABLE;
3369+
attr.value.booldata = !enableDistribution;
3370+
3371+
status = sai_lag_api->set_lag_member_attribute(lagMember.m_lag_member_id, &attr);
3372+
if (status != SAI_STATUS_SUCCESS)
3373+
{
3374+
SWSS_LOG_ERROR("Failed to %s distribution on LAG member %s",
3375+
enableDistribution ? "enable" : "disable",
3376+
lagMember.m_alias.c_str());
3377+
return false;
3378+
}
3379+
3380+
return true;
3381+
}
3382+
33213383
void PortsOrch::generateQueueMap()
33223384
{
33233385
if (m_isQueueMapGenerated)

orchagent/portsorch.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ class PortsOrch : public Orch, public Subject
172172
bool removeLag(Port lag);
173173
bool addLagMember(Port &lag, Port &port);
174174
bool removeLagMember(Port &lag, Port &port);
175+
bool setCollectionOnLagMember(Port &lagMember, bool enableCollection);
176+
bool setDistributionOnLagMember(Port &lagMember, bool enableDistribution);
175177
void getLagMember(Port &lag, vector<Port> &portv);
176178

177179
bool addPort(const set<int> &lane_set, uint32_t speed, int an=0, string fec="");

tests/test_portchannel.py

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,41 @@ def test_Portchannel(self, dvs, testlog):
3333
assert len(lagms) == 1
3434

3535
(status, fvs) = lagmtbl.get(lagms[0])
36-
for fv in fvs:
37-
if fv[0] == "SAI_LAG_MEMBER_ATTR_LAG_ID":
38-
assert fv[1] == lags[0]
39-
elif fv[0] == "SAI_LAG_MEMBER_ATTR_PORT_ID":
40-
assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet0"
41-
else:
42-
assert False
36+
fvs = dict(fvs)
37+
assert status
38+
assert "SAI_LAG_MEMBER_ATTR_LAG_ID" in fvs
39+
assert fvs.pop("SAI_LAG_MEMBER_ATTR_LAG_ID") == lags[0]
40+
assert "SAI_LAG_MEMBER_ATTR_PORT_ID" in fvs
41+
assert dvs.asicdb.portoidmap[fvs.pop("SAI_LAG_MEMBER_ATTR_PORT_ID")] == "Ethernet0"
42+
assert "SAI_LAG_MEMBER_ATTR_INGRESS_DISABLE" in fvs
43+
assert fvs.pop("SAI_LAG_MEMBER_ATTR_INGRESS_DISABLE") == "false"
44+
assert "SAI_LAG_MEMBER_ATTR_EGRESS_DISABLE" in fvs
45+
assert fvs.pop("SAI_LAG_MEMBER_ATTR_EGRESS_DISABLE") == "false"
46+
assert not fvs
47+
48+
ps = swsscommon.ProducerStateTable(db, "LAG_MEMBER_TABLE")
49+
fvs = swsscommon.FieldValuePairs([("status", "disabled")])
50+
51+
ps.set("PortChannel0001:Ethernet0", fvs)
52+
53+
time.sleep(1)
54+
55+
lagmtbl = swsscommon.Table(asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER")
56+
lagms = lagmtbl.getKeys()
57+
assert len(lagms) == 1
58+
59+
(status, fvs) = lagmtbl.get(lagms[0])
60+
fvs = dict(fvs)
61+
assert status
62+
assert "SAI_LAG_MEMBER_ATTR_LAG_ID" in fvs
63+
assert fvs.pop("SAI_LAG_MEMBER_ATTR_LAG_ID") == lags[0]
64+
assert "SAI_LAG_MEMBER_ATTR_PORT_ID" in fvs
65+
assert dvs.asicdb.portoidmap[fvs.pop("SAI_LAG_MEMBER_ATTR_PORT_ID")] == "Ethernet0"
66+
assert "SAI_LAG_MEMBER_ATTR_INGRESS_DISABLE" in fvs
67+
assert fvs.pop("SAI_LAG_MEMBER_ATTR_INGRESS_DISABLE") == "true"
68+
assert "SAI_LAG_MEMBER_ATTR_EGRESS_DISABLE" in fvs
69+
assert fvs.pop("SAI_LAG_MEMBER_ATTR_EGRESS_DISABLE") == "true"
70+
assert not fvs
4371

4472
# remove port channel member
4573
ps = swsscommon.ProducerStateTable(db, "LAG_MEMBER_TABLE")

0 commit comments

Comments
 (0)