Skip to content

Commit 175f3de

Browse files
authored
Update ECMP NHopGroup for Port Channel oper down (sonic-net#1030)
* Remove nexthop member from nexthopgroup on detecting portchannel down * Code cleanup * Fix spacing errors * Create new Test 1. Add 4 PortChannels 2. Add to nexthop group * Check for 3 NH group members after bringing down a portchannel
1 parent 182940d commit 175f3de

File tree

2 files changed

+186
-0
lines changed

2 files changed

+186
-0
lines changed

orchagent/portsorch.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -2174,6 +2174,17 @@ void PortsOrch::doLagTask(Consumer &consumer)
21742174
{
21752175
mtu = (uint32_t)stoul(fvValue(i));
21762176
}
2177+
if (fvField(i) == "oper_status")
2178+
{
2179+
if (fvValue(i) == "down")
2180+
{
2181+
gNeighOrch->ifChangeInformNextHop(alias, false);
2182+
}
2183+
else
2184+
{
2185+
gNeighOrch->ifChangeInformNextHop(alias, true);
2186+
}
2187+
}
21772188
}
21782189

21792190
// Create a new LAG when the new alias comes

tests/test_portchannel.py

+175
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,178 @@ def test_Portchannel(self, dvs, testlog):
5757

5858
lagms = lagmtbl.getKeys()
5959
assert len(lagms) == 0
60+
61+
62+
def test_Portchannel_oper_down(self, dvs, testlog):
63+
64+
self.adb = swsscommon.DBConnector(1, dvs.redis_sock, 0)
65+
self.cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0)
66+
self.pdb = swsscommon.DBConnector(0, dvs.redis_sock, 0)
67+
68+
# Create 4 PortChannels
69+
tbl = swsscommon.Table(self.cdb, "PORTCHANNEL")
70+
fvs = swsscommon.FieldValuePairs([("admin_status", "up"),("mtu", "9100"),("oper_status", "up")])
71+
72+
tbl.set("PortChannel001", fvs)
73+
time.sleep(1)
74+
tbl.set("PortChannel002", fvs)
75+
time.sleep(1)
76+
tbl.set("PortChannel003", fvs)
77+
time.sleep(1)
78+
tbl.set("PortChannel004", fvs)
79+
time.sleep(1)
80+
81+
tbl = swsscommon.Table(self.cdb, "PORTCHANNEL_MEMBER")
82+
fvs = swsscommon.FieldValuePairs([("NULL", "NULL")])
83+
tbl.set("PortChannel001|Ethernet0", fvs)
84+
time.sleep(1)
85+
tbl.set("PortChannel002|Ethernet4", fvs)
86+
time.sleep(1)
87+
tbl.set("PortChannel003|Ethernet8", fvs)
88+
time.sleep(1)
89+
tbl.set("PortChannel004|Ethernet12", fvs)
90+
time.sleep(1)
91+
92+
tbl = swsscommon.Table(self.cdb, "PORTCHANNEL_INTERFACE")
93+
fvs = swsscommon.FieldValuePairs([("NULL", "NULL")])
94+
tbl.set("PortChannel001", fvs)
95+
tbl.set("PortChannel001|40.0.0.0/31", fvs)
96+
time.sleep(1)
97+
tbl.set("PortChannel002", fvs)
98+
tbl.set("PortChannel002|40.0.0.2/31", fvs)
99+
time.sleep(1)
100+
tbl.set("PortChannel003", fvs)
101+
tbl.set("PortChannel003|40.0.0.4/31", fvs)
102+
time.sleep(1)
103+
tbl.set("PortChannel004", fvs)
104+
tbl.set("PortChannel004|40.0.0.6/31", fvs)
105+
time.sleep(1)
106+
107+
# check application database
108+
tbl = swsscommon.Table(self.pdb, "INTF_TABLE:PortChannel001")
109+
intf_entries = tbl.getKeys()
110+
assert len(intf_entries) == 1
111+
assert intf_entries[0] == "40.0.0.0/31"
112+
tbl = swsscommon.Table(self.pdb, "INTF_TABLE:PortChannel002")
113+
intf_entries = tbl.getKeys()
114+
assert len(intf_entries) == 1
115+
assert intf_entries[0] == "40.0.0.2/31"
116+
tbl = swsscommon.Table(self.pdb, "INTF_TABLE:PortChannel003")
117+
intf_entries = tbl.getKeys()
118+
assert len(intf_entries) == 1
119+
assert intf_entries[0] == "40.0.0.4/31"
120+
tbl = swsscommon.Table(self.pdb, "INTF_TABLE:PortChannel004")
121+
intf_entries = tbl.getKeys()
122+
assert len(intf_entries) == 1
123+
assert intf_entries[0] == "40.0.0.6/31"
124+
125+
126+
# set oper_status for PortChannels
127+
ps = swsscommon.ProducerStateTable(self.pdb, "LAG_TABLE")
128+
fvs = swsscommon.FieldValuePairs([("admin_status", "up"),("mtu", "9100"),("oper_status", "up")])
129+
ps.set("PortChannel001", fvs)
130+
ps.set("PortChannel002", fvs)
131+
ps.set("PortChannel003", fvs)
132+
ps.set("PortChannel004", fvs)
133+
time.sleep(1)
134+
135+
dvs.runcmd("arp -s 40.0.0.1 00:00:00:00:00:01")
136+
time.sleep(1)
137+
dvs.runcmd("arp -s 40.0.0.3 00:00:00:00:00:03")
138+
time.sleep(1)
139+
dvs.runcmd("arp -s 40.0.0.5 00:00:00:00:00:05")
140+
time.sleep(1)
141+
dvs.runcmd("arp -s 40.0.0.7 00:00:00:00:00:07")
142+
time.sleep(1)
143+
144+
ps = swsscommon.ProducerStateTable(self.pdb, "ROUTE_TABLE")
145+
fvs = swsscommon.FieldValuePairs([("nexthop","40.0.0.1,40.0.0.3,40.0.0.5,40.0.0.7"), ("ifname", "PortChannel001,PortChannel002,PortChannel003,PortChannel004")])
146+
147+
ps.set("2.2.2.0/24", fvs)
148+
time.sleep(1)
149+
150+
# check if route has propagated to ASIC DB
151+
re_tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY")
152+
153+
found_route = False
154+
for key in re_tbl.getKeys():
155+
route = json.loads(key)
156+
if route["dest"] == "2.2.2.0/24":
157+
found_route = True
158+
break
159+
160+
assert found_route
161+
162+
# check if route points to next hop group
163+
nhg_tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP")
164+
(status, fvs) = re_tbl.get(key)
165+
for v in fvs:
166+
if v[0] == "SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID":
167+
nhg_id = v[1]
168+
169+
(status, fvs) = nhg_tbl.get(nhg_id)
170+
assert status
171+
172+
# check if next hop group consists of 4 members
173+
nhg_member_tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER")
174+
keys = nhg_member_tbl.getKeys()
175+
assert len(keys) == 4
176+
177+
for key in keys:
178+
(status, fvs) = nhg_member_tbl.get(key)
179+
for v in fvs:
180+
if v[0] == "SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID":
181+
assert v[1] == nhg_id
182+
183+
# bring PortChannel down
184+
dvs.servers[0].runcmd("ip link set down dev eth0")
185+
time.sleep(1)
186+
ps = swsscommon.ProducerStateTable(self.pdb, "LAG_TABLE")
187+
fvs = swsscommon.FieldValuePairs([("admin_status", "up"),("mtu", "9100"),("oper_status", "down")])
188+
ps.set("PortChannel001", fvs)
189+
time.sleep(1)
190+
191+
# check if next hop group consists of 3 member
192+
keys = nhg_member_tbl.getKeys()
193+
assert len(keys) == 3
194+
195+
# remove IP address
196+
tbl = swsscommon.Table(self.cdb, "PORTCHANNEL_INTERFACE")
197+
tbl._del("PortChannel001|40.0.0.0/31")
198+
tbl._del("PortChannel002|40.0.0.2/31")
199+
tbl._del("PortChannel003|40.0.0.4/31")
200+
tbl._del("PortChannel004|40.0.0.6/31")
201+
time.sleep(1)
202+
203+
# check application database
204+
tbl = swsscommon.Table(self.pdb, "INTF_TABLE:PortChannel001")
205+
intf_entries = tbl.getKeys()
206+
assert len(intf_entries) == 0
207+
208+
tbl = swsscommon.Table(self.pdb, "INTF_TABLE:PortChannel002")
209+
intf_entries = tbl.getKeys()
210+
assert len(intf_entries) == 0
211+
212+
tbl = swsscommon.Table(self.pdb, "INTF_TABLE:PortChannel003")
213+
intf_entries = tbl.getKeys()
214+
assert len(intf_entries) == 0
215+
216+
tbl = swsscommon.Table(self.pdb, "INTF_TABLE:PortChannel004")
217+
intf_entries = tbl.getKeys()
218+
assert len(intf_entries) == 0
219+
220+
# remove PortChannel members
221+
tbl = swsscommon.Table(self.cdb, "PORTCHANNEL_MEMBER")
222+
tbl._del("PortChannel001|Ethernet0")
223+
tbl._del("PortChannel002|Ethernet4")
224+
tbl._del("PortChannel003|Ethernet8")
225+
tbl._del("PortChannel004|Ethernet12")
226+
time.sleep(1)
227+
228+
# remove PortChannel
229+
tbl = swsscommon.Table(self.cdb, "PORTCHANNEL")
230+
tbl._del("PortChannel001")
231+
tbl._del("PortChannel002")
232+
tbl._del("PortChannel003")
233+
tbl._del("PortChannel004")
234+
time.sleep(1)

0 commit comments

Comments
 (0)