From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pl1-f171.google.com (mail-pl1-f171.google.com [209.85.214.171]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9C6B940960C for ; Tue, 30 Jun 2026 11:02:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.171 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782817350; cv=none; b=iZrMOAX2uiHcNFffX32/tjhbUtOu3ZEU7i4uhEH3UPzej8GZ+hMsI6PXQKLRITFSBUtbxbglwa0vHKxY3mbAjxlYOLKuqEfeOhwYFvBz40BziFRQkYEbeH+qjfnpomA4/8oVZ/CuLl9Vh0wRKY/jRKHSrAgCaKzki6l+7DnhAFU= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782817350; c=relaxed/simple; bh=8wZAl9dIq90GZLioFiUpzFcU9diyNdRhpnpQypxIlwA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bDgvnB9WrZjq3Y6QCxMvXdnMNPicr9H8dYzRnvnd9cgGP4ngsAyMOX616Urxu4CGEzkk+njhJbxhYce3aWXts7obKP38tbPnaH3jUrqoUbIwTi3mhRxaN6HBbm0ekv0fDgTg5CpRD1QTar4j1tqa7PPfwRQ/tVMMy4AACob506A= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=fOqY/0CC; arc=none smtp.client-ip=209.85.214.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="fOqY/0CC" Received: by mail-pl1-f171.google.com with SMTP id d9443c01a7336-2c9b42be8feso25212105ad.2 for ; Tue, 30 Jun 2026 04:02:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1782817349; x=1783422149; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=710DEh42/SxcOGjoC0hzcAfTSmEIF90NLkpYChDQKCY=; b=fOqY/0CCbio+7XRNKbwvkNQ0tt5ObisYqS/+D6LvltV0Lr2egGZJKkUPRyoa94YJb7 rOeV5e9VSwaLUAYjyCxiWZSzh5Qu4hn7VxN23Xqf3NaZbmD9zDdJjaEizKuJHsDXuYhJ xddvtCjL+UpB+vmHW2+9cmKn3tjmAAX0N4Mzh3gy/+d+DK1NwsHVMATDzkyQxUKWuL7F bBwcD9Ff1Tat8XQKHYv6KlZC4dD5CO4zvTTrn1zbGLSU9AU2ztT0BXPeQHoIdkdB5otJ w4oL8i75Fwd9bs+oU+og107VD/qozD2+xKTOvz65j09vACl4TR8cz520SUF2yVT9oAZb cLmQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782817349; x=1783422149; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=710DEh42/SxcOGjoC0hzcAfTSmEIF90NLkpYChDQKCY=; b=l1Iz1emZc8uvr3U9geyt8oLmFBT/i8tAZI9ztys/u70SIkf2CVx/sV3qU9oJpQWPjy z/6wCubkcAAnvPOitFCWzrbLQbc1GBoPyVYcfsINnzgcLCAI5XMY8uKP0aB5IHGZui2G oox68f3VWcT1H0XNOBSO1eKsRaUfHw3sXZGVzM5HO8WEB+yvcWj/wN6mzo6IlRKFhjU9 vxce/U12w0tkDGoOPeDRRH+2NV2SAsDtqxF3OH5/wQwJQfqxvJiGfPaKOkEBLBW2tEXj 6TPD+f8zrKfEyA49RzY21Q7tiWKOjn446k6CZbOh+fPelB3ZsD/yO7z9553W8k6f1SBR kK9g== X-Forwarded-Encrypted: i=1; AHgh+RptGXQqYpfY1ID89PIP+n+eutvQYh0VAnFQxfYopt3HhWZPC6Y6oRxUEkS04FC8t5itj07krdx6IbLpuzI=@vger.kernel.org X-Gm-Message-State: AOJu0YzdcSPcrgivi8dQxks2sCLF/c/3nGc3ZGqvsBZyUCVcSy+VCjdG TLR0I1Z2wQAFlkfBRdhAyamEXgiJpxNnaWTpwQhsA3XfqovkX+2nuQlaCogAqeA6 X-Gm-Gg: AfdE7ckjLVIMWc0bJp5hVIQ3NvKPXtK5DJzVd2g7dFf+Pc83X2Ii0+y1WGwJZU8Lsm4 /zJ5Fil9e5nL56oF/qtw6EPDhOFAkUOQgEb2T5Oa6WsZi0UhS744XySo4qXkgD1sggX6XmffhHA zmLNrzFiuR6aRdXiMZjMIC6p19C765UjCnSu67qIEjBLAVnjqDJiPkfOUTLKqmsTjbHCe4ggfyj Zn4iwqn+dG133I+UVK+WYohk1sjgf/MT1mbYOmjnFRQ5NAxqSg/dHGyKTXlV0/s4bkiIGPzt4v8 s25Vp91d/AwFZNKBmhWBYXqRXw2RiA/tAAgNrSQUtCidACqNgV8DIz1LIfqJtuejBMoDexkfzop pQP3kvRu/fqeoghfPk/kP8JbLmi1m42Ty9G1cRJ3u3Rd1f1qdQu4Xv7foxTn6gPYjd5fQwdu17E hZD9khg/cVshNKVRRr2sdn1wXfGsPl8jDJwiCE5HT6 X-Received: by 2002:a17:902:f645:b0:2c6:ad70:d870 with SMTP id d9443c01a7336-2ca2d54457emr24425215ad.13.1782817348784; Tue, 30 Jun 2026 04:02:28 -0700 (PDT) Received: from m-upc-A520M-HDV.lan ([2400:2410:3f60:500:ae0d:35d1:dac9:a0e9]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2ca37a701b5sm11455265ad.17.2026.06.30.04.02.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 30 Jun 2026 04:02:28 -0700 (PDT) From: Yuyang Huang To: Yuyang Huang Cc: "David S. Miller" , Andrew Lunn , David Ahern , Donald Hunter , Eric Dumazet , Ido Schimmel , Jakub Kicinski , Paolo Abeni , Shuah Khan , Simon Horman , linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, netdev@vger.kernel.org Subject: [PATCH net-next 3/3] selftests: net: check multicast group user count Date: Tue, 30 Jun 2026 20:02:07 +0900 Message-ID: <20260630110207.37841-4-sigefriedhyy@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260630110207.37841-1-sigefriedhyy@gmail.com> References: <20260630110207.37841-1-sigefriedhyy@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Extend the RTM_GETMULTICAST dump test to verify IFA_MC_USERS for both IPv4 and IPv6 multicast groups. Run each protocol test in a fresh network namespace to avoid changing host-network state or racing with unrelated multicast users. Join a fixed multicast group twice using separate sockets and check that the reported user count increases by two. Signed-off-by: Yuyang Huang --- tools/testing/selftests/net/rtnetlink.py | 101 ++++++++++++++++++++--- 1 file changed, 90 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/net/rtnetlink.py b/tools/testing/selftests/net/rtnetlink.py index 3622413d793d..0c67c7c00d84 100755 --- a/tools/testing/selftests/net/rtnetlink.py +++ b/tools/testing/selftests/net/rtnetlink.py @@ -2,27 +2,106 @@ # SPDX-License-Identifier: GPL-2.0 import socket +import struct import time -from lib.py import bkg, ip, ksft_exit, ksft_run, ksft_ge, ksft_true, KsftSkipEx +from lib.py import bkg, ip, ksft_exit, ksft_run, ksft_eq, ksft_ge, ksft_true, KsftSkipEx from lib.py import CmdExitFailure, NetNS, NetNSEnter, RtnlAddrFamily IPV4_ALL_HOSTS_MULTICAST = b'\xe0\x00\x00\x01' +IPV4_TEST_MULTICAST = b'\xef\x01\x01\x01' +IPV6_TEST_MULTICAST = bytes.fromhex('ff020000000000000000000000000123') + + +def _users_for(rtnl: RtnlAddrFamily, family: int, grp: bytes, ifindex: int): + """Return mc-users for grp on ifindex, or 0 if absent.""" + + addrs = rtnl.getmulticast({"ifa-family": family}, dump=True) + matches = [addr for addr in addrs + if addr['multicast'] == grp and addr['ifa-index'] == ifindex] + if not matches: + return 0 + if 'mc-users' not in matches[0]: + return None + + return matches[0]['mc-users'] + def dump_mcaddr_check() -> None: """ - Verify that at least one interface has the IPv4 all-hosts multicast address. - At least the loopback interface should have this address. + Verify IPv4 multicast addresses and their user counts in RTM_GETMULTICAST. + """ + + with NetNS() as ns: + with NetNSEnter(str(ns)): + ip("link set lo up") + rtnl = RtnlAddrFamily() + lo_idx = socket.if_nametoindex('lo') + addresses = rtnl.getmulticast({"ifa-family": socket.AF_INET}, dump=True) + + all_host_multicasts = [ + addr for addr in addresses + if addr['multicast'] == IPV4_ALL_HOSTS_MULTICAST + ] + + ksft_ge(len(all_host_multicasts), 1, + "No interface found with the IPv4 all-hosts multicast address") + + mreq = IPV4_TEST_MULTICAST + socket.inet_aton('127.0.0.1') + before = _users_for(rtnl, socket.AF_INET, IPV4_TEST_MULTICAST, lo_idx) + if before is None: + raise KsftSkipEx("kernel does not expose IFA_MC_USERS") + + s1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s1.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) + s2.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) + + after_join = _users_for(rtnl, socket.AF_INET, + IPV4_TEST_MULTICAST, lo_idx) + if after_join is None: + raise KsftSkipEx("kernel does not expose IFA_MC_USERS") + ksft_eq(after_join - before, 2, + f"users delta != 2 after two joins " + f"(before={before}, after={after_join})") + finally: + s1.close() + s2.close() + + +def dump_mcaddr6_check() -> None: + """ + Verify IPv6 multicast addresses and their user counts in RTM_GETMULTICAST. """ - rtnl = RtnlAddrFamily() - addresses = rtnl.getmulticast({"ifa-family": socket.AF_INET}, dump=True) + with NetNS() as ns: + with NetNSEnter(str(ns)): + ip("link set lo up") + rtnl = RtnlAddrFamily() + lo_idx = socket.if_nametoindex('lo') + before = _users_for(rtnl, socket.AF_INET6, + IPV6_TEST_MULTICAST, lo_idx) + if before is None: + raise KsftSkipEx("kernel does not expose IFA_MC_USERS for IPv6") + + mreq = IPV6_TEST_MULTICAST + struct.pack('=I', lo_idx) + s1 = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) + s2 = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) + try: + s1.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq) + s2.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq) - all_host_multicasts = [ - addr for addr in addresses if addr['multicast'] == IPV4_ALL_HOSTS_MULTICAST - ] + after_join = _users_for(rtnl, socket.AF_INET6, + IPV6_TEST_MULTICAST, lo_idx) + if after_join is None: + raise KsftSkipEx("kernel does not expose IFA_MC_USERS for IPv6") + ksft_eq(after_join - before, 2, + f"IPv6 users delta != 2 after two joins " + f"(before={before}, after={after_join})") + finally: + s1.close() + s2.close() - ksft_ge(len(all_host_multicasts), 1, - "No interface found with the IPv4 all-hosts multicast address") def ipv4_devconf_notify() -> None: """ @@ -56,7 +135,7 @@ def ipv4_devconf_notify() -> None: f"No 'forwarding on' notificiation found for interface {ifname}") def main() -> None: - ksft_run([dump_mcaddr_check, ipv4_devconf_notify]) + ksft_run([dump_mcaddr_check, dump_mcaddr6_check, ipv4_devconf_notify]) ksft_exit() if __name__ == "__main__": -- 2.43.0