From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=74.125.82.199 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794709576; b=NHS1qnnhNw21beo2NSlOJYS7dhSoguG6WsBvrsgkmVlkC8lJHzgIExxLI4AcAwxrCzne w06OYi0BZ76Q0NnQd3be9st1C+XsEL05axYDvqKNB7tR6jgqOlyIA+5fCzi7n/76lPP3Y SEU1IEjelJRJOlF0y0ulWN+F8eSjAzfw236ERBLf8DvvGpLkBmVcqVx9JFDhYT0uGhqlU 5qb5Xve9+p7ySkebqq2sxXGX4P2SAV31r1vBxr1hh19Bq9F/wXFIAHtbcIoNCxN5d3sYn K7OnEuYfbsOixVdbO3Im+ESee4ApQuPv1qcpEEuEpcRWGZuj9g79elKijdhqAvV3RbQ== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794709576; h=DMARC-Filter:Received:DKIM-Signature:X-Google-DKIM-Signature: X-Gm-Message-State:X-Received:Date:In-Reply-To:Mime-Version: References:X-Mailer:Message-ID:Subject:From:To:Cc:Content-Type; bh=PtHeqDpn0F+FD4D08P2fvOlL4SuwQcvcficGZrgtsYM=; b=qEr+zW80weUUdr2q/hUdEIvjqVcgRGlzuOt2eAHdIRk8WX9xUuQKF5oqJG1Cy0goSS31 BgyEL7PLXzhuJgDfMn350lmNEwZQsvRzHi8jiHM/g075DlthQcX6AAyRKPBOl9GAzW232 xQKpA+3KrzcMPiYF2iq8aze12DMwKm1l7560kGWEQ8oSgOMrL9ukgDxmyhkFT6E4viflV EbR67kQyGkIg4OG0VsoQhV00jCY+XDZMR3RE5SLzW2otG0RRF/pZNvIK80ko+YSxcNyKT 9OK1xfAT+mOzh/1zNAs86UamZg1RDU/u9QjW9rUT824wKwQDAykaoyWn3T6vfSfjyNw== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass header.from=google.com; spf=pass smtp.mailfrom=flex--almasrymina.bounces.google.com; dkim=pass header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20260707 header.b=RWIuLnAm; arc=none smtp.remote-ip=74.125.82.199 Received: from mail-dy1-f199.google.com (mail-dy1-f199.google.com [74.125.82.199]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 79103606A880 for ; Sun, 15 Nov 2026 02:26:16 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org 79103606A880 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--almasrymina.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20260707 header.b=RWIuLnAm Received: by mail-dy1-f199.google.com with SMTP id 5a478bee46e88-375f0fd31f4so491679eec.0 for ; Sat, 14 Nov 2026 18:26:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20260707; t=1794709576; x=1795314376; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=PtHeqDpn0F+FD4D08P2fvOlL4SuwQcvcficGZrgtsYM=; b=RWIuLnAmyxQGxVWkdrGCJ/0/6Q60rFIC+A5rzmBrXqbBUQOTDFoCmWY15oxMiawi36 8dL3srAMlkK3y5x8anTOgJRF6AXwbd5+H1IpbjnxLUpiWepOvfr6qUG2LEQKMH8x4MJ0 Kvn2DF4BwqAy7JvfnulXXzq0kFKGeePxYQFzKqPJkS0xWFsqhl9m7Ulo355lX83z7QQ2 nwpSZoqpFkl3i9Re2r/WZmZbW21iBDYAZ/FBUragQT1NxGh43eJBOkmtcnkC9/yvFzW/ mAT7DNFbPSV8DhiC67vw6JPAXagYOMs7MSZ1lsTBIo8ZjEBhfti6tktzr13f0smQjUHk KG8Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1794709576; x=1795314376; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=PtHeqDpn0F+FD4D08P2fvOlL4SuwQcvcficGZrgtsYM=; b=mzeW3jyWDJXBsobP1FA6q8I9Xa8DGKUARTjlyRsXeNjOp8VZGwhYyZ41SMmhLg4rA1 M6nJXzxDbaPFPLm7v2NIIMlrSxQSrgTrUpoC1+XOtqvanKP7Cr4J5VNyg8CUm0OO34t9 qPCYgWJUS4DNlTogdWdDR7NL3SIMA9i0l8GQb9b3FRO+yH+GkIjmnmeW5B/en/dIMjZT aJFJSk6lQNKrQKRLRBc20AfoqCTQqkGstFTr1/R1Vd4mcFGj6HCS0CWZNaDyjJ827T1N RQ+IoJc2SIczzXEVoRfPQbQ41dgK47Gxb57hhyC2cK9/rOy9vyHq7SWL4RwCH3pJM8vh ugSw== X-Gm-Message-State: APuU4Z8cSNjOuryW+uChK1BlJ1mN7NmqFXuYZYNZaBI54/9tuO95HUWi njFhN2VvFqkk6gvUX6u4HFDJWqal0pTKLue7PC6l9fyuG7ddPYUeTt/he0HOOS1/tBQXYjLH6K3 3jxeTyIX7OzsoS5vZB1LF4GLB7O9U2NI4dPijeKQfL05d+AjMiosbB7gpauq2MZkT81Tjnfa5Jt jIfivA8eeiiRMuxRUCBdcV0Q4UtjbeVvfkivrViJtV6kZVpGCSnIWPXvM+1O/aVNY= X-Received: from dyab25.prod.google.com ([2002:a05:693c:8319:b0:372:7af9:c0a7]) (user=almasrymina job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:cca2:b0:36e:371:8255 with SMTP id 5a478bee46e88-379603825bemr6161512eec.0.1794709575230; Sat, 14 Nov 2026 18:26:15 -0800 (PST) Date: Sun, 15 Nov 2026 02:26:07 +0000 In-Reply-To: <20261115022607.348112-1-almasrymina@google.com> X-Mailing-List: netdev@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list Mime-Version: 1.0 References: <20261115022607.348112-1-almasrymina@google.com> X-Mailer: git-send-email 2.56.0.611.g1030f0b940-goog Message-ID: <20261115022607.348112-7-almasrymina@google.com> Subject: [PATCH net-next v3 6/6] selftests: net: add leased devmem RX and TX netdev unregister tests From: Mina Almasry To: netdev@vger.kernel.org Cc: Mina Almasry , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Shuah Khan , linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Weiming Shi , Daniel Borkmann , Nikolay Aleksandrov , David Wei , Stanislav Fomichev , Bobby Eshleman , Dragos Tatulea Content-Type: text/plain; charset="UTF-8" Extend nl_netdev.py to cover netdev unregistration while devmem RX and TX bindings are active on a virtual netkit device leasing an RX queue from netdevsim: 1. devmem_lease_bind_rx_unregister_check: binds an RX dmabuf to a netkit device backed by a leased netdevsim queue and verifies clean teardown both when the virtual netkit device is deleted first (unleasing the queue while netdevsim remains up) and when the underlying netdevsim device is unregistered directly (which uninstalls the physical queue memory provider and cascades unregistration to the leasing netkit). 2. devmem_lease_bind_tx_unregister_check: binds a TX dmabuf to a netkit device backed by a leased netdevsim queue and verifies clean teardown both when the virtual netkit device is deleted first and when the underlying netdevsim device is unregistered directly. Reviewed-by: Dragos Tatulea Signed-off-by: Mina Almasry --- tools/testing/selftests/net/nl_netdev.py | 159 ++++++++++++++++++++++- 1 file changed, 155 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/net/nl_netdev.py b/tools/testing/selftests/net/nl_netdev.py index dd0321c0b463a..2e4e34257e873 100755 --- a/tools/testing/selftests/net/nl_netdev.py +++ b/tools/testing/selftests/net/nl_netdev.py @@ -12,8 +12,10 @@ import os import struct from os import system from lib.py import ksft_run, ksft_exit, KsftFailEx, KsftSkipEx -from lib.py import ksft_eq, ksft_ge, ksft_ne, ksft_raises, ksft_busy_wait -from lib.py import EthtoolFamily, NetdevFamily, NetdevSimDev, NlError, defer, ip +from lib.py import ksft_eq, ksft_ge, ksft_in, ksft_ne, ksft_not_in +from lib.py import ksft_raises, ksft_busy_wait +from lib.py import EthtoolFamily, NetdevFamily, NetdevSimDev, Netlink +from lib.py import NlError, RtnlFamily, cmd, defer, ip def empty_check(nf) -> None: @@ -423,12 +425,22 @@ def _dmabuf_attach_count(dmabuf_fd) -> int: raise KsftFailEx(f"dma-buf {ino} not found in {path}") -def _devmem_bind(bind, attrs) -> None: +def _devmem_bind(bind, attrs, phys_attrs=None) -> None: """Run a devmem bind op, skip the test if the device can't do devmem.""" try: bind(attrs) except NlError as e: if e.error == errno.EOPNOTSUPP: + if phys_attrs is not None: + try: + bind(phys_attrs) + except NlError as probe_e: + if probe_e.error == errno.EOPNOTSUPP: + raise KsftSkipEx( + f"devmem binding not supported: {probe_e}" + ) from probe_e + raise e from probe_e + raise raise KsftSkipEx(f"devmem binding not supported: {e}") from e raise @@ -483,6 +495,143 @@ def devmem_bind_tx_unregister_check(_nf) -> None: nf_priv.close() +def _create_netkit_single(rxqueues=2): + """Create a single-device netkit interface for queue lease tests.""" + ifname = f"nk{os.getpid()}" + try: + with RtnlFamily() as rtnl: + rtnl.newlink( + { + "ifname": ifname, + "linkinfo": { + "kind": "netkit", + "data": { + "mode": "l2", + "pairing": "single", + }, + }, + "num-rx-queues": rxqueues, + }, + flags=[Netlink.NLM_F_CREATE, Netlink.NLM_F_EXCL], + ) + except NlError as e: + if e.error in (errno.EOPNOTSUPP, errno.ENOENT): + raise KsftSkipEx(f"netkit single mode not supported: {e}") from e + raise + defer(cmd, f"ip link del dev {ifname}", fail=False) + + link = ip(f"-d link show dev {ifname}", json=True)[0] + return ifname, link["ifindex"] + + +def _queue_lease(nf, nk_ifindex, phys_ifindex, phys_qid=1): + try: + return nf.queue_create({ + "ifindex": nk_ifindex, + "type": "rx", + "lease": { + "ifindex": phys_ifindex, + "queue": {"id": phys_qid, "type": "rx"}, + }, + }) + except NlError as e: + if e.error == errno.EOPNOTSUPP: + raise KsftSkipEx(f"queue lease not supported: {e}") from e + raise + + +def devmem_lease_bind_rx_unregister_check(nf) -> None: + """Verify leased RX devmem bindings detach cleanly on virt/phys unregister.""" + for remove_virt_first in (False, True): + dmabuf_fd = _create_udmabuf() + defer(os.close, dmabuf_fd) + nf_priv = NetdevFamily() + defer(nf_priv.close) + nsimdev = NetdevSimDev(queue_count=2) + defer(nsimdev.remove) + nsim = nsimdev.nsims[0] + + ip(f"link set dev {nsim.ifname} up") + with EthtoolFamily() as ef: + ef.rings_set({"header": {"dev-index": nsim.ifindex}, + "tcp-data-split": "enabled"}) + + nk_ifname, nk_ifindex = _create_netkit_single(rxqueues=2) + ip(f"link set dev {nk_ifname} up") + + res = _queue_lease(nf, nk_ifindex, nsim.ifindex) + + _devmem_bind(nf_priv.bind_rx, { + "ifindex": nk_ifindex, + "fd": dmabuf_fd, + "queues": [{"id": res["id"], "type": "rx"}], + }, phys_attrs={ + "ifindex": nsim.ifindex, + "fd": dmabuf_fd, + "queues": [{"id": 0, "type": "rx"}], + }) + ksft_ge(_dmabuf_attach_count(dmabuf_fd), 1) + phys_q = nf.queue_get({"ifindex": nsim.ifindex, "id": 1, "type": "rx"}) + ksft_in("dmabuf", phys_q) + ksft_in("lease", phys_q) + + if remove_virt_first: + ip(f"link del dev {nk_ifname}") + phys_q = nf.queue_get({"ifindex": nsim.ifindex, "id": 1, + "type": "rx"}) + ksft_not_in("dmabuf", phys_q) + ksft_not_in("lease", phys_q) + ksft_ge(_dmabuf_attach_count(dmabuf_fd), 1) + nsimdev.remove() + else: + nsimdev.remove() + ksft_ne(cmd(f"ip link show dev {nk_ifname}", fail=False).ret, 0) + cmd(f"ip link del dev {nk_ifname}", fail=False) + ksft_eq(_dmabuf_attach_count(dmabuf_fd), 0) + + nf_priv.close() + + +def devmem_lease_bind_tx_unregister_check(nf) -> None: + """Verify leased TX devmem bindings detach cleanly on virt/phys unregister.""" + for remove_virt_first in (False, True): + dmabuf_fd = _create_udmabuf() + defer(os.close, dmabuf_fd) + nf_priv = NetdevFamily() + defer(nf_priv.close) + nsimdev = NetdevSimDev(queue_count=2) + defer(nsimdev.remove) + nsim = nsimdev.nsims[0] + + ip(f"link set dev {nsim.ifname} up") + + nk_ifname, nk_ifindex = _create_netkit_single(rxqueues=2) + ip(f"link set dev {nk_ifname} up") + + _queue_lease(nf, nk_ifindex, nsim.ifindex) + + _devmem_bind(nf_priv.bind_tx, { + "ifindex": nk_ifindex, + "fd": dmabuf_fd, + }, phys_attrs={ + "ifindex": nsim.ifindex, + "fd": dmabuf_fd, + }) + ksft_ge(_dmabuf_attach_count(dmabuf_fd), 1) + + if remove_virt_first: + ip(f"link del dev {nk_ifname}") + ksft_ge(_dmabuf_attach_count(dmabuf_fd), 1) + nsimdev.remove() + else: + nsimdev.remove() + ksft_ne(cmd(f"ip link show dev {nk_ifname}", fail=False).ret, 0) + cmd(f"ip link del dev {nk_ifname}", fail=False) + ksft_eq(_dmabuf_attach_count(dmabuf_fd), 0) + + nf_priv.close() + + def main() -> None: """ Ksft boiler plate main """ nf = NetdevFamily() @@ -498,7 +647,9 @@ def main() -> None: page_pool_ifindex_leak_check, page_pool_stats_ifindex_check, devmem_bind_rx_unregister_check, - devmem_bind_tx_unregister_check + devmem_bind_tx_unregister_check, + devmem_lease_bind_rx_unregister_check, + devmem_lease_bind_tx_unregister_check ], args=(nf, )) ksft_exit() -- 2.56.0.611.g1030f0b940-goog