public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
From: Jakub Kicinski <kuba@kernel.org>
To: Wei Wang <weibunny@fb.com>
Cc: <netdev@vger.kernel.org>, Daniel Zahka <daniel.zahka@gmail.com>,
	Willem de Bruijn <willemdebruijn.kernel@gmail.com>,
	David Wei <dw@davidwei.uk>, Andrew Lunn <andrew+netdev@lunn.ch>,
	"David S. Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@google.com>
Subject: Re: [PATCH v2 net-next 9/9] selftest/net: psp: Add test for dev-assoc/disassoc
Date: Fri, 6 Mar 2026 13:53:14 -0800	[thread overview]
Message-ID: <20260306135314.35b63df1@kernel.org> (raw)
In-Reply-To: <20260304000050.3366381-10-weibunny@fb.com>

On Tue, 3 Mar 2026 16:00:49 -0800 Wei Wang wrote:
> +def _data_basic_send_netkit_psp_assoc(cfg, version, ipver):
> +    """
> +    Test basic data send with netkit interface associated with PSP dev.
> +    """
> +
> +    _init_psp_dev(cfg, True)
> +    psp_dev_id_for_assoc = cfg.psp_dev_id
> +
> +    # Associate PSP device with nk_guest interface (in guest namespace)
> +    nk_guest_dev = ip(f"link show dev {cfg._nk_guest_ifname}", json=True, ns=cfg.netns)[0]

dev info is one of the few things the env class should have loaded for
us. Please add it if it's missing, we have it for other envs (env.dev,
env.remote_dev, nk should presumably be env.nk_dev ? or env.cont_dev ?)

> +    nk_guest_ifindex = nk_guest_dev['ifindex']
> +
> +    cfg.pspnl.dev_assoc({'id': psp_dev_id_for_assoc, 'ifindex': nk_guest_ifindex, 'nsid': cfg.psp_dev_peer_nsid})

Please wrap lines at 80 chars.

> +    # Check if assoc-list contains nk_guest
> +    dev_info = cfg.pspnl.dev_get({'id': psp_dev_id_for_assoc})
> +
> +    if 'assoc-list' in dev_info:
> +        found = False
> +        for assoc in dev_info['assoc-list']:
> +            if assoc['ifindex'] == nk_guest_ifindex and assoc['nsid'] == cfg.psp_dev_peer_nsid:
> +                found = True
> +                break

Should it not be the _only_ assoc? Maybe let's start with that
assumption and complicate the tests later if needed?
The other tests are rotating the keys and generally assuming full
control over PSP so I don't think we should cater to the case of
"something else is using PSP on the base system" here either.

Let's also check how the attributes look from inside the netns
and how they look if the netkit and netdevsim are in the same netns?
(unless you already have that. this patch is a bit enormous :()

> +        ksft_true(found, "Associated device not found in dev_get() response")
> +    else:
> +        raise RuntimeError("No assoc-list in dev_get() response after association")

KsftFailEx() ?

> +    # Enter guest namespace (netns) to run PSP test
> +    with NetNSEnter(cfg.netns.name):
> +        cfg.pspnl = PSPFamily()
> +
> +        s = _make_psp_conn(cfg, version, ipver)
> +
> +        rx_assoc = cfg.pspnl.rx_assoc({"version": version,
> +                                       "dev-id": cfg.psp_dev_id,
> +                                       "sock-fd": s.fileno()})
> +        rx = rx_assoc['rx-key']
> +        tx = _spi_xchg(s, rx)
> +
> +        cfg.pspnl.tx_assoc({"dev-id": cfg.psp_dev_id,
> +                            "version": version,
> +                            "tx-key": tx,
> +                            "sock-fd": s.fileno()})
> +
> +        data_len = _send_careful(cfg, s, 100)
> +        _check_data_rx(cfg, data_len)
> +        _close_psp_conn(cfg, s)
> +
> +    # Clean up - back in host namespace
> +    cfg.pspnl = PSPFamily()
> +    cfg.pspnl.dev_disassoc({'id': psp_dev_id_for_assoc, 'ifindex': nk_guest_ifindex, 'nsid': cfg.psp_dev_peer_nsid})
> +
> +    del cfg.psp_dev_id
> +    del cfg.psp_info
> +
> +
> +def _key_rotation_notify_multi_ns_netkit(cfg, version, ipver):
> +    """ Test key rotation notifications across multiple namespaces using netkit """
> +    import threading

I don't think we need threading for this test.. ?
If we open a socket while in one netns and then switch the netns back
the previously opened socket should still be in the netns? So we can
just ntf_check() directly from the main thread? 

> +    _init_psp_dev(cfg, True)
> +    psp_dev_id_for_assoc = cfg.psp_dev_id
> +
> +    # Associate PSP device with nk_guest interface (in guest namespace)
> +    nk_guest_dev = ip(f"link show dev {cfg._nk_guest_ifname}", json=True, ns=cfg.netns)[0]
> +    nk_guest_ifindex = nk_guest_dev['ifindex']
> +
> +    cfg.pspnl.dev_assoc({'id': psp_dev_id_for_assoc, 'ifindex': nk_guest_ifindex, 'nsid': cfg.psp_dev_peer_nsid})
> +
> +    results = {'main_ns': None, 'peer_ns': None}
> +
> +    def listen_in_namespace(ns_name, result_key):
> +        """Listen for key rotation notifications in a namespace"""
> +        try:
> +            if ns_name:
> +                ctx = NetNSEnter(ns_name)
> +            else:
> +                from contextlib import nullcontext
> +                ctx = nullcontext()
> +
> +            with ctx:
> +                pspnl = PSPFamily()
> +                pspnl.ntf_subscribe('use')
> +
> +                collected_notifications = []
> +                for i in range(100):
> +                    pspnl.check_ntf()
> +
> +                    try:
> +                        while True:
> +                            msg = pspnl.async_msg_queue.get_nowait()
> +                            collected_notifications.append(msg['msg'])
> +                    except:
> +                        pass
> +
> +                    if collected_notifications:
> +                        results[result_key] = collected_notifications
> +                        break
> +
> +                    time.sleep(0.1)
> +                else:
> +                    # Timeout - no notification received
> +                    results[result_key] = []
> +        except Exception as e:
> +            results[result_key] = {'error': str(e)}
> +
> +    # Create listener threads
> +    # Main namespace listener
> +    main_ns_thread = threading.Thread(
> +        target=listen_in_namespace,
> +        args=(None, 'main_ns'),
> +        name='main_ns_listener'
> +    )
> +    # Guest namespace listener (netkit peer)
> +    guest_ns_thread = threading.Thread(
> +        target=listen_in_namespace,
> +        args=(cfg.netns.name, 'peer_ns'),
> +        name='guest_ns_listener'
> +    )
> +
> +    main_ns_thread.start()
> +    guest_ns_thread.start()
> +
> +    time.sleep(0.5)
> +
> +    # Trigger key rotation on the PSP device
> +    cfg.pspnl.key_rotate({"id": psp_dev_id_for_assoc})
> +
> +    main_ns_thread.join(timeout=15)
> +    guest_ns_thread.join(timeout=15)
> +
> +    # Verify notifications were received in both namespaces
> +    ksft_not_none(results['main_ns'], "No result from main namespace listener")
> +    ksft_not_none(results['peer_ns'], "No result from guest namespace listener")
> +
> +    # Check for errors in listeners
> +    if isinstance(results['main_ns'], dict) and 'error' in results['main_ns']:
> +        raise RuntimeError(f"Main NS listener error: {results['main_ns']['error']}")
> +    if isinstance(results['peer_ns'], dict) and 'error' in results['peer_ns']:
> +        raise RuntimeError(f"Guest NS listener error: {results['peer_ns']['error']}")
> +
> +    # Verify that both namespaces received at least one notification
> +    ksft_gt(len(results['main_ns']), 0, "No key rotation notification received in main namespace")
> +    ksft_gt(len(results['peer_ns']), 0, "No key rotation notification received in guest namespace")
> +
> +    # Verify the notification contains the expected dev_id
> +    main_ns_has_dev = any(
> +        ntf.get('id') == psp_dev_id_for_assoc
> +        for ntf in results['main_ns']
> +    )
> +    guest_ns_has_dev = any(
> +        ntf.get('id') == psp_dev_id_for_assoc
> +        for ntf in results['peer_ns']
> +    )
> +
> +    ksft_true(main_ns_has_dev, "Key rotation notification for correct device not found in main namespace")
> +    ksft_true(guest_ns_has_dev, "Key rotation notification for correct device not found in guest namespace")
> +
> +    # Clean up
> +    cfg.pspnl.dev_disassoc({'id': psp_dev_id_for_assoc, 'ifindex': nk_guest_ifindex, 'nsid': cfg.psp_dev_peer_nsid})
> +    del cfg.psp_dev_id
> +    del cfg.psp_info
> +
> +
> +def _dev_change_notify_multi_ns_netkit(cfg, version, ipver):
> +    """ Test dev_change notifications across multiple namespaces using netkit """
> +    import threading
> +
> +    _init_psp_dev(cfg, True)
> +    psp_dev_id_for_assoc = cfg.psp_dev_id
> +
> +    # Associate PSP device with nk_guest interface (in guest namespace)
> +    nk_guest_dev = ip(f"link show dev {cfg._nk_guest_ifname}", json=True, ns=cfg.netns)[0]
> +    nk_guest_ifindex = nk_guest_dev['ifindex']
> +
> +    cfg.pspnl.dev_assoc({'id': psp_dev_id_for_assoc, 'ifindex': nk_guest_ifindex, 'nsid': cfg.psp_dev_peer_nsid})
> +
> +    results = {'main_ns': None, 'peer_ns': None}
> +
> +    def listen_in_namespace(ns_name, result_key):
> +        """Listen for dev_change notifications in a namespace"""
> +        try:
> +            if ns_name:
> +                ctx = NetNSEnter(ns_name)
> +            else:
> +                from contextlib import nullcontext
> +                ctx = nullcontext()
> +
> +            with ctx:
> +                pspnl = PSPFamily()
> +                pspnl.ntf_subscribe('mgmt')
> +
> +                collected_notifications = []
> +                for i in range(100):
> +                    pspnl.check_ntf()
> +
> +                    try:
> +                        while True:
> +                            msg = pspnl.async_msg_queue.get_nowait()
> +                            collected_notifications.append(msg['msg'])
> +                    except:
> +                        pass
> +
> +                    if collected_notifications:
> +                        results[result_key] = collected_notifications
> +                        break
> +
> +                    time.sleep(0.1)
> +                else:
> +                    # Timeout - no notification received
> +                    results[result_key] = []
> +        except Exception as e:
> +            results[result_key] = {'error': str(e)}
> +
> +    # Create listener threads
> +    # Main namespace listener
> +    main_ns_thread = threading.Thread(
> +        target=listen_in_namespace,
> +        args=(None, 'main_ns'),
> +        name='main_ns_listener'
> +    )
> +    # Guest namespace listener (netkit peer)
> +    guest_ns_thread = threading.Thread(
> +        target=listen_in_namespace,
> +        args=(cfg.netns.name, 'peer_ns'),
> +        name='guest_ns_listener'
> +    )
> +
> +    main_ns_thread.start()
> +    guest_ns_thread.start()
> +
> +    time.sleep(1.0)  # Give threads time to subscribe
> +
> +    # Trigger dev_change by calling dev_set (notification is always sent)
> +    cfg.pspnl.dev_set({'id': psp_dev_id_for_assoc, 'psp-versions-ena': cfg.psp_info['psp-versions-cap']})
> +
> +    main_ns_thread.join(timeout=15)
> +    guest_ns_thread.join(timeout=15)
> +
> +    # Verify notifications were received in both namespaces
> +    ksft_not_none(results['main_ns'], "No result from main namespace listener")
> +    ksft_not_none(results['peer_ns'], "No result from guest namespace listener")
> +
> +    # Check for errors in listeners
> +    if isinstance(results['main_ns'], dict) and 'error' in results['main_ns']:
> +        raise RuntimeError(f"Main NS listener error: {results['main_ns']['error']}")
> +    if isinstance(results['peer_ns'], dict) and 'error' in results['peer_ns']:
> +        raise RuntimeError(f"Guest NS listener error: {results['peer_ns']['error']}")
> +
> +    # Verify that both namespaces received at least one notification
> +    ksft_gt(len(results['main_ns']), 0, "No dev_change notification received in main namespace")
> +    ksft_gt(len(results['peer_ns']), 0, "No dev_change notification received in guest namespace")
> +
> +    # Verify the notification contains the expected dev_id
> +    main_ns_has_dev = any(
> +        ntf.get('id') == psp_dev_id_for_assoc
> +        for ntf in results['main_ns']
> +    )
> +    guest_ns_has_dev = any(
> +        ntf.get('id') == psp_dev_id_for_assoc
> +        for ntf in results['peer_ns']
> +    )
> +
> +    ksft_true(main_ns_has_dev, "Dev_change notification for correct device not found in main namespace")
> +    ksft_true(guest_ns_has_dev, "Dev_change notification for correct device not found in guest namespace")
> +
> +    # Clean up
> +    cfg.pspnl.dev_disassoc({'id': psp_dev_id_for_assoc, 'ifindex': nk_guest_ifindex, 'nsid': cfg.psp_dev_peer_nsid})
> +    del cfg.psp_dev_id
> +    del cfg.psp_info
> +
> +
> +def _psp_dev_get_check_netkit_psp_assoc(cfg, version, ipver):
> +    """ Check psp dev-get output with netkit interface associated with PSP dev """
> +
> +    _init_psp_dev(cfg, True)
> +    psp_dev_id_for_assoc = cfg.psp_dev_id
> +
> +    # Associate PSP device with nk_guest interface (in guest namespace)
> +    nk_guest_dev = ip(f"link show dev {cfg._nk_guest_ifname}", json=True, ns=cfg.netns)[0]
> +    nk_guest_ifindex = nk_guest_dev['ifindex']
> +
> +    cfg.pspnl.dev_assoc({'id': psp_dev_id_for_assoc, 'ifindex': nk_guest_ifindex, 'nsid': cfg.psp_dev_peer_nsid})
> +
> +    # Check 1: In default netns, verify dev-get has correct ifindex and assoc-list
> +    dev_info = cfg.pspnl.dev_get({'id': psp_dev_id_for_assoc})
> +
> +    # Verify the PSP device has the correct ifindex
> +    ksft_eq(dev_info['ifindex'], cfg.psp_ifindex)
> +
> +    # Verify assoc-list exists and contains the associated nk_guest with correct ifindex and nsid
> +    ksft_true('assoc-list' in dev_info, "No assoc-list in dev_get() response after association")
> +    found = False
> +    for assoc in dev_info['assoc-list']:
> +        if assoc['ifindex'] == nk_guest_ifindex and assoc['nsid'] == cfg.psp_dev_peer_nsid:
> +            found = True
> +            break
> +    ksft_true(found, "Associated device not found in assoc-list with correct ifindex and nsid")
> +
> +    # Check 2: In guest netns, verify dev-get has assoc-list with nk_guest device
> +    with NetNSEnter(cfg.netns.name):
> +        peer_pspnl = PSPFamily()
> +
> +        # Dump all devices in the guest namespace
> +        peer_devices = peer_pspnl.dev_get({}, dump=True)
> +
> +        # Find the device with by-association flag
> +        peer_dev = None
> +        for dev in peer_devices:
> +            if dev.get('by-association'):
> +                peer_dev = dev
> +                break
> +
> +        ksft_not_none(peer_dev, "No PSP device found with by-association flag in guest netns")
> +
> +        # Verify assoc-list contains the nk_guest device
> +        ksft_true('assoc-list' in peer_dev and len(peer_dev['assoc-list']) > 0,
> +                  "Guest device should have assoc-list with local devices")
> +
> +        # Verify the assoc-list contains nk_guest ifindex with nsid=-1 (same namespace)
> +        found = False
> +        for assoc in peer_dev['assoc-list']:
> +            if assoc['ifindex'] == nk_guest_ifindex:
> +                ksft_eq(assoc['nsid'], -1,
> +                        "nsid should be -1 (NETNSA_NSID_NOT_ASSIGNED) for same-namespace device")
> +                found = True
> +                break
> +        ksft_true(found, "nk_guest ifindex not found in assoc-list")
> +
> +    # Clean up
> +    cfg.pspnl.dev_disassoc({'id': psp_dev_id_for_assoc, 'ifindex': nk_guest_ifindex, 'nsid': cfg.psp_dev_peer_nsid})
> +
> +    del cfg.psp_dev_id
> +    del cfg.psp_info
> +
> +
> +def _psp_dev_assoc_cleanup_on_netkit_del(cfg):
> +    """ Test that assoc-list is cleared when associated netkit interface is deleted """
> +    import subprocess

use cmd()?  feels like this code is AI generated
please review it carefully before repost

      reply	other threads:[~2026-03-06 21:53 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-04  0:00 [PATCH v2 net-next 0/9] psp: Add support for dev-assoc/disassoc Wei Wang
2026-03-04  0:00 ` [PATCH v2 net-next 2/9] selftests/net: Export Netlink class via lib.py Wei Wang
2026-03-04  0:00 ` [PATCH v2 net-next 3/9] selftests/net: Add env for container based tests Wei Wang
2026-03-04  0:00 ` [PATCH v2 net-next 4/9] selftests/net: Add netkit container ping test Wei Wang
2026-03-04  0:00 ` [PATCH v2 net-next 5/9] psp: add unprivileged version of psp_device_get_locked Wei Wang
2026-03-04 15:00   ` Daniel Zahka
2026-03-04 16:25   ` Willem de Bruijn
2026-03-04 17:42     ` Wei Wang
2026-03-04 18:01       ` Daniel Zahka
2026-03-04 18:03         ` Daniel Zahka
2026-03-04 22:31           ` Wei Wang
2026-03-04 23:41             ` Willem de Bruijn
2026-03-06 21:34               ` Jakub Kicinski
2026-03-04  0:00 ` [PATCH v2 net-next 6/9] psp: Add new netlink cmd for dev-assoc and dev-disassoc Wei Wang
2026-03-04 15:20   ` Daniel Zahka
2026-03-04 16:17   ` Daniel Zahka
2026-03-04 17:28     ` Wei Wang
2026-03-04  0:00 ` [PATCH v2 net-next 7/9] psp: add a new netdev event for dev unregister Wei Wang
2026-03-04  0:00 ` [PATCH v2 net-next 8/9] selftests/net: Add bpf skb forwarding program Wei Wang
2026-03-04  0:00 ` [PATCH v2 net-next 9/9] selftest/net: psp: Add test for dev-assoc/disassoc Wei Wang
2026-03-06 21:53   ` Jakub Kicinski [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260306135314.35b63df1@kernel.org \
    --to=kuba@kernel.org \
    --cc=andrew+netdev@lunn.ch \
    --cc=daniel.zahka@gmail.com \
    --cc=davem@davemloft.net \
    --cc=dw@davidwei.uk \
    --cc=edumazet@google.com \
    --cc=netdev@vger.kernel.org \
    --cc=weibunny@fb.com \
    --cc=willemdebruijn.kernel@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox