Dump the link-layer multicast addresses of a dummy device and verify that ifa_index restricts the dump to that device, that the all-hosts address joined on link up is listed without IFA_F_GLOBAL, that an address added with SIOCADDMULTI is listed with IFA_F_GLOBAL and IFA_MC_USERS, and that IFA_TARGET_NETNSID dumps another netns. Skip when the kernel does not support AF_PACKET dumps.
Signed-off-by: Yuyang Huang <[email protected]> --- tools/testing/selftests/net/rtnetlink.py | 71 +++++++++++++++++++++++- 1 file changed, 68 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/net/rtnetlink.py b/tools/testing/selftests/net/rtnetlink.py index 5cc3ebdcf08d..41da259c3a09 100755 --- a/tools/testing/selftests/net/rtnetlink.py +++ b/tools/testing/selftests/net/rtnetlink.py @@ -1,17 +1,21 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: GPL-2.0 +import errno import socket import struct import time from lib.py import bkg, ip, ksft_exit, ksft_run, ksft_eq, ksft_ge, ksft_true, KsftSkipEx -from lib.py import ksft_not_in, ksft_not_none -from lib.py import CmdExitFailure, NetNS, NetNSEnter, RtnlAddrFamily, RtnlRouteFamily +from lib.py import ksft_in, ksft_not_in, ksft_not_none +from lib.py import CmdExitFailure, NetNS, NetNSEnter, NlError, RtnlAddrFamily, RtnlRouteFamily from lib.py import defer IPV4_ALL_HOSTS_MULTICAST = b'\xe0\x00\x00\x01' IPV4_TEST_MULTICAST = b'\xef\x01\x01\x01' IPV6_TEST_MULTICAST = bytes.fromhex('ff020000000000000000000000000123') +ETH_ALL_HOSTS_MULTICAST = bytes.fromhex('01005e000001') +ETH_TEST_MULTICAST_STR = '01:00:5e:01:01:01' +ETH_TEST_MULTICAST = bytes.fromhex(ETH_TEST_MULTICAST_STR.replace(':', '')) def _users_for(rtnl: RtnlAddrFamily, family: int, grp: bytes, ifindex: int): @@ -105,6 +109,66 @@ def dump_mcaddr6_check() -> None: s2.close() +def dump_mcaddr_l2_check() -> None: + """ + Verify link-layer multicast addresses in an AF_PACKET RTM_GETMULTICAST + dump: the ifa-index filter, mc-users, the global flag and + target-netnsid. + """ + + with NetNS() as ns, NetNSEnter(str(ns)): + for ifname in ("dummy1", "dummy2"): + ip(f"link add name {ifname} type dummy") + ip(f"link set {ifname} up") + dev_idx = socket.if_nametoindex("dummy1") + ip(f"maddr add {ETH_TEST_MULTICAST_STR} dev dummy1") + + rtnl = RtnlAddrFamily() + try: + addresses = rtnl.getmulticast( + {"ifa-family": socket.AF_PACKET, "ifa-index": dev_idx}, + dump=True) + except NlError as e: + if e.error == errno.EOPNOTSUPP: + raise KsftSkipEx( + "kernel does not support AF_PACKET multicast dump") + raise + + # dummy2 has entries as well, only dummy1 may be listed + ksft_eq({addr['ifa-index'] for addr in addresses}, {dev_idx}, + "AF_PACKET multicast dump ignored ifa-index filter") + + entries = {addr['multicast']: addr for addr in addresses} + + # Bringing an Ethernet device up joins 224.0.0.1, which maps + # to 01:00:5e:00:00:01 in the device multicast list. + ksft_in(ETH_ALL_HOSTS_MULTICAST, entries, + "dummy1 does not have the all-hosts link-layer address") + ksft_not_in('global', entries[ETH_ALL_HOSTS_MULTICAST]['flags'], + "protocol entry is global") + + ksft_in(ETH_TEST_MULTICAST, entries, + "dummy1 does not have the SIOCADDMULTI address") + ksft_eq(entries[ETH_TEST_MULTICAST]['mc-users'], 1, + "unexpected mc-users for the SIOCADDMULTI address") + ksft_in('global', entries[ETH_TEST_MULTICAST]['flags'], + "SIOCADDMULTI entry is not global") + + # target-netnsid dumps another netns, ifa-index is relative to it + with NetNS() as peer: + ip(f"netns set {peer} 5") + ip("link add name dummy3 type dummy", ns=peer) + ip("link set dummy3 up", ns=peer) + peer_idx = ip("link show dummy3", json=True, ns=peer)[0]['ifindex'] + + addresses = rtnl.getmulticast( + {"ifa-family": socket.AF_PACKET, "target-netnsid": 5}, + dump=True) + ksft_eq({(addr['ifa-index'], addr['target-netnsid']) + for addr in addresses}, {(peer_idx, 5)}, + "target-netnsid did not dump the peer netns") + + def ipv4_devconf_notify() -> None: """ Configure an interface and set ipv4-devconf values through netlink @@ -315,7 +379,8 @@ def ipv6_route_del_reason_absent() -> None: def main() -> None: - ksft_run([dump_mcaddr_check, dump_mcaddr6_check, ipv4_devconf_notify, + ksft_run([dump_mcaddr_check, dump_mcaddr6_check, dump_mcaddr_l2_check, + ipv4_devconf_notify, ipv6_route_del_reason_expired, ipv6_route_del_reason_ra_withdrawn, ipv6_route_del_reason_absent]) -- 2.43.0

