Skip to content

Commit 6763a1f

Browse files
test: update new test cases for bridge polling
Test that bridge polling discovers downstream endpoints and creates endpoints d-bus object. Test that polling stops once downstream endpoint is discovered. and continues unless endpoint reponds to send polling command GET_ENDPOINT_ID. Test that once brige endpoint is removed, downstream endpoints associated to the brige also gets removed too. Update bridge pool size to handle recursive bridge logic. Test that endpoint polling continues with recursive bridge topology as well Signed-off-by: Faizan Ali <faizana@nvidia.com>
1 parent ffdcc99 commit 6763a1f

File tree

2 files changed

+296
-8
lines changed

2 files changed

+296
-8
lines changed

tests/mctpenv/__init__.py

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,32 @@ def reset(self):
349349
def add_bridged_ep(self, ep):
350350
self.bridged_eps.append(ep)
351351

352+
def pool_size(self):
353+
size = 0
354+
if self.bridged_eps:
355+
size += len(self.bridged_eps)
356+
for br_ep in self.bridged_eps:
357+
size += br_ep.pool_size()
358+
return size
359+
360+
def assign_eids_recursive(self, pool_start):
361+
next_eid = pool_start
362+
for br_ep in self.bridged_eps:
363+
br_ep.eid = next_eid
364+
next_eid += 1
365+
# Recursively assign to this endpoint's children
366+
next_eid = br_ep.assign_eids_recursive(next_eid)
367+
return next_eid
368+
369+
def lookup_route_recursive(self, eid):
370+
for br_ep in self.bridged_eps:
371+
if eid == br_ep.eid:
372+
return br_ep
373+
374+
if br_ep.lookup_route_recursive(eid) is not None:
375+
return br_ep
376+
return None
377+
352378
async def handle_mctp_message(self, sock, addr, data):
353379
# for us?
354380
if addr.eid == 0 or addr.eid == self.eid:
@@ -357,9 +383,9 @@ async def handle_mctp_message(self, sock, addr, data):
357383
else:
358384
print(f"unknown MCTP message type {a.type}")
359385
else:
360-
for br_ep in self.bridged_eps:
361-
if addr.eid == br_ep.eid:
362-
return await br_ep.handle_mctp_message(sock, addr, data)
386+
br_ep = self.lookup_route_recursive(addr.eid)
387+
if br_ep:
388+
return await br_ep.handle_mctp_message(sock, addr, data)
363389

364390
async def handle_mctp_control(self, sock, addr, data):
365391
flags, opcode = data[0:2]
@@ -382,7 +408,7 @@ async def handle_mctp_control(self, sock, addr, data):
382408
# Set Endpoint ID
383409
(op, eid) = data[2:]
384410
self.eid = eid
385-
pool_size = len(self.bridged_eps)
411+
pool_size = self.pool_size()
386412
alloc_status = 0x00
387413
# request a pool if we have one
388414
if pool_size:
@@ -393,7 +419,7 @@ async def handle_mctp_control(self, sock, addr, data):
393419
elif opcode == 2:
394420
# Get Endpoint ID
395421
ep_type = 0
396-
if len(self.bridged_eps) > 0:
422+
if self.pool_size() > 0:
397423
ep_type = 0x1 << 4
398424
data = bytes(hdr + [0x00, self.eid, ep_type, 0x00])
399425
await sock.send(raddr, data)
@@ -417,9 +443,8 @@ async def handle_mctp_control(self, sock, addr, data):
417443
alloc_status = 0x01
418444
else:
419445
self.allocated_pool = (pool_start, pool_size)
420-
# Assign sequential EIDs starting from pool_start
421-
for (n, ep) in enumerate(self.bridged_eps[:pool_size]):
422-
ep.eid = self.allocated_pool[0] + n
446+
# Recursively assign EIDs to all downstream endpoints
447+
self.assign_eids_recursive(pool_start)
423448

424449
data = bytes(hdr + [0x00, alloc_status,
425450
self.allocated_pool[1], self.allocated_pool[0]])

tests/test_mctpd.py

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,3 +1376,266 @@ async def test_register_vdm_type_support_errors(dbus, mctpd):
13761376
with pytest.raises(asyncdbus.errors.DBusError) as ex:
13771377
await mctp.call_register_vdm_type_support(0x00, v_type, 0x0001)
13781378
assert str(ex.value) == "VDM type already registered"
1379+
1380+
""" Test that we use endpoint poll interval from the config and
1381+
that we discover bridged endpoints via polling"""
1382+
async def test_bridged_endpoint_poll(dbus, sysnet, nursery, autojump_clock):
1383+
poll_interval = 2500
1384+
config = f"""
1385+
[bus-owner]
1386+
endpoint_poll_ms = {poll_interval}
1387+
"""
1388+
1389+
mctpd = MctpdWrapper(dbus, sysnet, config = config)
1390+
await mctpd.start_mctpd(nursery)
1391+
1392+
iface = mctpd.system.interfaces[0]
1393+
ep = mctpd.network.endpoints[0]
1394+
mctp = await mctpd_mctp_iface_obj(dbus, iface)
1395+
1396+
bridged_ep = [
1397+
Endpoint(iface, bytes(), types = [0, 1]),
1398+
Endpoint(iface, bytes(), types = [0, 1])
1399+
]
1400+
for bep in bridged_ep:
1401+
mctpd.network.add_endpoint(bep)
1402+
ep.add_bridged_ep(bep)
1403+
1404+
(eid, _, path, new) = await mctp.call_assign_endpoint(ep.lladdr)
1405+
assert new
1406+
1407+
mctp_obj = await dbus.get_proxy_object(MCTPD_C, MCTPD_MCTP_P)
1408+
mctp_objmgr = await mctp_obj.get_interface(DBUS_OBJECT_MANAGER_I)
1409+
endpoint_added = trio.Semaphore(initial_value=0)
1410+
1411+
# We expect two bridged endpoints to be discovered
1412+
expected_bridged_eps = len(bridged_ep)
1413+
bridged_endpoints_found = []
1414+
1415+
def ep_added(ep_path, content):
1416+
if MCTPD_ENDPOINT_I in content:
1417+
bridged_endpoints_found.append(ep_path)
1418+
endpoint_added.release()
1419+
1420+
await mctp_objmgr.on_interfaces_added(ep_added)
1421+
1422+
# Wait for all expected bridged endpoints to be discovered
1423+
with trio.move_on_after(poll_interval / 1000 * 2) as expected:
1424+
for i in range(expected_bridged_eps):
1425+
await endpoint_added.acquire()
1426+
1427+
# Verify we found all expected bridged endpoints
1428+
assert not expected.cancelled_caught, "Timeout waiting for bridged endpoints"
1429+
assert len(bridged_endpoints_found) == expected_bridged_eps
1430+
1431+
res = await mctpd.stop_mctpd()
1432+
assert res == 0
1433+
1434+
""" Test that all downstream endpoints are removed when the bridge
1435+
endpoint is removed"""
1436+
async def test_bridged_endpoint_remove(dbus, sysnet, nursery, autojump_clock):
1437+
poll_interval = 2500
1438+
config = f"""
1439+
[bus-owner]
1440+
endpoint_poll_ms = {poll_interval}
1441+
"""
1442+
1443+
mctpd = MctpdWrapper(dbus, sysnet, config = config)
1444+
await mctpd.start_mctpd(nursery)
1445+
1446+
iface = mctpd.system.interfaces[0]
1447+
ep = mctpd.network.endpoints[0]
1448+
mctp = await mctpd_mctp_iface_obj(dbus, iface)
1449+
1450+
bridged_ep = [
1451+
Endpoint(iface, bytes(), types = [0, 1]),
1452+
Endpoint(iface, bytes(), types = [0, 1])
1453+
]
1454+
for bep in bridged_ep:
1455+
mctpd.network.add_endpoint(bep)
1456+
ep.add_bridged_ep(bep)
1457+
1458+
(eid, _, path, new) = await mctp.call_assign_endpoint(ep.lladdr)
1459+
assert new
1460+
1461+
# Wait for the bridged endpoints to be discovered
1462+
await trio.sleep(poll_interval / 1000)
1463+
removed = trio.Semaphore(initial_value = 0)
1464+
removed_eps = []
1465+
1466+
# Capture the removed endpoints
1467+
def ep_removed(ep_path, interfaces):
1468+
if MCTPD_ENDPOINT_I in interfaces:
1469+
removed.release()
1470+
removed_eps.append(ep_path)
1471+
1472+
mctp_obj = await dbus.get_proxy_object(MCTPD_C, MCTPD_MCTP_P)
1473+
mctp_objmgr = await mctp_obj.get_interface(DBUS_OBJECT_MANAGER_I)
1474+
await mctp_objmgr.on_interfaces_removed(ep_removed)
1475+
1476+
# Remove the bridge endpoint
1477+
bridge_obj = await mctpd_mctp_endpoint_control_obj(dbus, path)
1478+
await bridge_obj.call_remove()
1479+
1480+
# Assert that all downstream endpoints were removed
1481+
assert len(removed_eps) == (len(bridged_ep) + 1)
1482+
res = await mctpd.stop_mctpd()
1483+
assert res == 0
1484+
1485+
""" Test that polling stops once endponit has been discovered """
1486+
async def test_bridged_endpoint_poll_stop(dbus, sysnet, nursery, autojump_clock):
1487+
poll_interval = 2500
1488+
config = f"""
1489+
[bus-owner]
1490+
endpoint_poll_ms = {poll_interval}
1491+
"""
1492+
1493+
mctpd = MctpdWrapper(dbus, sysnet, config = config)
1494+
await mctpd.start_mctpd(nursery)
1495+
1496+
iface = mctpd.system.interfaces[0]
1497+
ep = mctpd.network.endpoints[0]
1498+
mctp = await mctpd_mctp_iface_obj(dbus, iface)
1499+
poll_count = 0
1500+
1501+
class BridgedEndpoint(Endpoint):
1502+
async def handle_mctp_control(self, sock, src_addr, msg):
1503+
flags, opcode = msg[0:2]
1504+
if opcode == 0x2: # Get Endpoint ID
1505+
nonlocal poll_count
1506+
poll_count += 1
1507+
return await super().handle_mctp_control(sock, src_addr, msg)
1508+
1509+
bridged_ep = BridgedEndpoint(iface, bytes(), types = [0, 1])
1510+
mctpd.network.add_endpoint(bridged_ep)
1511+
ep.add_bridged_ep(bridged_ep)
1512+
1513+
(eid, _, path, new) = await mctp.call_assign_endpoint(ep.lladdr)
1514+
assert new
1515+
1516+
mctp_obj = await dbus.get_proxy_object(MCTPD_C, MCTPD_MCTP_P)
1517+
mctp_objmgr = await mctp_obj.get_interface(DBUS_OBJECT_MANAGER_I)
1518+
endpoint_added = trio.Semaphore(initial_value=0)
1519+
poll_count_by_discovery = 0
1520+
1521+
def ep_added(ep_path, content):
1522+
if MCTPD_ENDPOINT_I in content:
1523+
nonlocal poll_count_by_discovery
1524+
poll_count_by_discovery = poll_count
1525+
endpoint_added.release()
1526+
1527+
await mctp_objmgr.on_interfaces_added(ep_added)
1528+
1529+
# Wait longer than the poll interval for the bridged endpoint
1530+
# to be discovered
1531+
await trio.sleep(poll_interval / 1000)
1532+
1533+
# We should have only poll until the discovery thus count should
1534+
# be the same even after longer wait.
1535+
assert poll_count == poll_count_by_discovery
1536+
1537+
res = await mctpd.stop_mctpd()
1538+
assert res == 0
1539+
1540+
""" Test that polling continues until the endpoint is discovered """
1541+
async def test_bridged_endpoint_poll_continue(dbus, sysnet, nursery, autojump_clock):
1542+
poll_interval = 2500
1543+
config = f"""
1544+
[bus-owner]
1545+
endpoint_poll_ms = {poll_interval}
1546+
"""
1547+
1548+
mctpd = MctpdWrapper(dbus, sysnet, config = config)
1549+
await mctpd.start_mctpd(nursery)
1550+
1551+
iface = mctpd.system.interfaces[0]
1552+
ep = mctpd.network.endpoints[0]
1553+
mctp = await mctpd_mctp_iface_obj(dbus, iface)
1554+
poll_count = 0
1555+
1556+
class BridgedEndpoint(Endpoint):
1557+
async def handle_mctp_control(self, sock, src_addr, msg):
1558+
flags, opcode = msg[0:2]
1559+
# dont respond to simiulate device not accessible
1560+
# but increment poll count for the Get Endpoint ID
1561+
if opcode == 0x2: # Get Endpoint ID
1562+
nonlocal poll_count
1563+
poll_count += 1
1564+
return None
1565+
1566+
bridged_ep = BridgedEndpoint(iface, bytes(), types = [0, 1])
1567+
mctpd.network.add_endpoint(bridged_ep)
1568+
ep.add_bridged_ep(bridged_ep)
1569+
1570+
(eid, _, path, new) = await mctp.call_assign_endpoint(ep.lladdr)
1571+
assert new
1572+
1573+
# Wait for sometime to continue polling
1574+
await trio.sleep(poll_interval / 1000)
1575+
1576+
poll_count_before = poll_count
1577+
# Wait more to see if poll count increments
1578+
await trio.sleep(1)
1579+
assert poll_count > poll_count_before
1580+
1581+
res = await mctpd.stop_mctpd()
1582+
assert res == 0
1583+
1584+
""" Test polling continues for recursive bridged endpoints"""
1585+
async def test_bridge_behind_another_bridge_poll(dbus, sysnet, nursery, autojump_clock):
1586+
poll_interval = 2500
1587+
config = f"""
1588+
[bus-owner]
1589+
endpoint_poll_ms = {poll_interval}
1590+
"""
1591+
1592+
mctpd = MctpdWrapper(dbus, sysnet, config = config)
1593+
await mctpd.start_mctpd(nursery)
1594+
1595+
iface = mctpd.system.interfaces[0]
1596+
bridge1_ep = mctpd.network.endpoints[0]
1597+
mctp = await mctpd_mctp_iface_obj(dbus, iface)
1598+
1599+
bridged1_ep = [
1600+
Endpoint(iface, bytes(), types = [0, 1]),
1601+
Endpoint(iface, bytes(), types = [0, 1])
1602+
]
1603+
for bep in bridged1_ep:
1604+
mctpd.network.add_endpoint(bep)
1605+
bridge1_ep.add_bridged_ep(bep)
1606+
1607+
bridge2_ep = Endpoint(iface, bytes([0x01]), types = [0, 1])
1608+
bridge2_ep.add_bridged_ep(Endpoint(iface, bytes([0x00]), types = [0, 1]))
1609+
mctpd.network.add_endpoint(bridge2_ep.bridged_eps[0])
1610+
mctpd.network.add_endpoint(bridge2_ep)
1611+
bridge1_ep.add_bridged_ep(bridge2_ep)
1612+
1613+
(eid, _, path, new) = await mctp.call_assign_endpoint(bridge1_ep.lladdr)
1614+
assert new
1615+
1616+
mctp_obj = await dbus.get_proxy_object(MCTPD_C, MCTPD_MCTP_P)
1617+
mctp_objmgr = await mctp_obj.get_interface(DBUS_OBJECT_MANAGER_I)
1618+
endpoint_added = trio.Semaphore(initial_value=0)
1619+
1620+
# We expect two bridged endpoints to be discovered
1621+
expected_bridged_eps = bridge1_ep.pool_size()
1622+
bridged_endpoints_found = []
1623+
1624+
def ep_added(ep_path, content):
1625+
if MCTPD_ENDPOINT_I in content:
1626+
bridged_endpoints_found.append(ep_path)
1627+
endpoint_added.release()
1628+
1629+
await mctp_objmgr.on_interfaces_added(ep_added)
1630+
1631+
# Wait for all expected bridged endpoints to be discovered
1632+
with trio.move_on_after(poll_interval / 1000 * 2) as expected:
1633+
for i in range(expected_bridged_eps):
1634+
await endpoint_added.acquire()
1635+
1636+
# Verify we found all expected bridged endpoints
1637+
assert not expected.cancelled_caught, "Timeout waiting for bridged endpoints"
1638+
assert len(bridged_endpoints_found) == expected_bridged_eps
1639+
1640+
res = await mctpd.stop_mctpd()
1641+
assert res == 0

0 commit comments

Comments
 (0)