From: Daniel Borkmann <daniel@iogearbox.net>
To: netdev@vger.kernel.org
Cc: bpf@vger.kernel.org, kuba@kernel.org, davem@davemloft.net,
razor@blackwall.org, pabeni@redhat.com, willemb@google.com,
sdf@fomichev.me, john.fastabend@gmail.com, martin.lau@kernel.org,
jordan@jrife.io, maciej.fijalkowski@intel.com,
magnus.karlsson@intel.com, dw@davidwei.uk, toke@redhat.com,
yangzhenze@bytedance.com, wangdongdong.6@bytedance.com
Subject: [PATCH net-next v11 03/14] net: Add lease info to queue-get response
Date: Fri, 3 Apr 2026 01:10:20 +0200 [thread overview]
Message-ID: <20260402231031.447597-4-daniel@iogearbox.net> (raw)
In-Reply-To: <20260402231031.447597-1-daniel@iogearbox.net>
Populate nested lease info to the queue-get response that returns the
ifindex, queue id with type and optionally netns id if the device
resides in a different netns.
Example with ynl client when using AF_XDP via queue leasing:
# ip a
[...]
4: enp10s0f0np0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 xdp/id:24 qdisc mq state UP group default qlen 1000
link/ether e8:eb:d3:a3:43:f6 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.2/24 scope global enp10s0f0np0
valid_lft forever preferred_lft forever
inet6 fe80::eaeb:d3ff:fea3:43f6/64 scope link proto kernel_ll
valid_lft forever preferred_lft forever
[...]
# ethtool -i enp10s0f0np0
driver: mlx5_core
[...]
# ynl --family netdev --output-json --do queue-get \
--json '{"ifindex": 4, "id": 15, "type": "rx"}'
{'id': 15,
'ifindex': 4,
'lease': {'ifindex': 8, 'netns-id': 0, 'queue': {'id': 1, 'type': 'rx'}},
'napi-id': 8227,
'type': 'rx',
'xsk': {}}
# ip netns list
foo (id: 0)
# ip netns exec foo ip a
[...]
8: nk@NONE: <BROADCAST,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
inet6 fe80::200:ff:fe00:0/64 scope link proto kernel_ll
valid_lft forever preferred_lft forever
[...]
# ip netns exec foo ethtool -i nk
driver: netkit
[...]
# ip netns exec foo ls /sys/class/net/nk/queues/
rx-0 rx-1 tx-0
# ip netns exec foo ynl --family netdev --output-json --do queue-get \
--json '{"ifindex": 8, "id": 1, "type": "rx"}'
{"id": 1, "type": "rx", "ifindex": 8, "xsk": {}}
Note that the caller of netdev_nl_queue_fill_one() holds the netdevice
lock. For the queue-get we do not lock both devices. When queues get
{un,}leased, both devices are locked, thus if __netif_get_rx_queue_lease()
returns a lease pointer, it points to a valid device. The netns-id is
fetched via peernet2id_alloc() similarly as done in OVS.
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Co-developed-by: David Wei <dw@davidwei.uk>
Signed-off-by: David Wei <dw@davidwei.uk>
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
---
include/net/netdev_rx_queue.h | 14 ++++++++
net/core/netdev-genl.c | 66 ++++++++++++++++++++++++++++++++---
net/core/netdev_rx_queue.c | 54 ++++++++++++++++++++++++++++
3 files changed, 130 insertions(+), 4 deletions(-)
diff --git a/include/net/netdev_rx_queue.h b/include/net/netdev_rx_queue.h
index 1d41c253f0a3..7e98c679ea84 100644
--- a/include/net/netdev_rx_queue.h
+++ b/include/net/netdev_rx_queue.h
@@ -67,6 +67,20 @@ get_netdev_rx_queue_index(struct netdev_rx_queue *queue)
return index;
}
+enum netif_lease_dir {
+ NETIF_VIRT_TO_PHYS,
+ NETIF_PHYS_TO_VIRT,
+};
+
+struct netdev_rx_queue *
+__netif_get_rx_queue_lease(struct net_device **dev, unsigned int *rxq,
+ enum netif_lease_dir dir);
+
+struct netdev_rx_queue *
+netif_get_rx_queue_lease_locked(struct net_device **dev, unsigned int *rxq);
+void netif_put_rx_queue_lease_locked(struct net_device *orig_dev,
+ struct net_device *dev);
+
int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq);
void netdev_rx_queue_lease(struct netdev_rx_queue *rxq_dst,
struct netdev_rx_queue *rxq_src);
diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c
index 5d5e5b9a8af0..515832854251 100644
--- a/net/core/netdev-genl.c
+++ b/net/core/netdev-genl.c
@@ -386,12 +386,63 @@ static int nla_put_napi_id(struct sk_buff *skb, const struct napi_struct *napi)
return 0;
}
+static int
+netdev_nl_queue_fill_lease(struct sk_buff *rsp, struct net_device *netdev,
+ u32 q_idx, u32 q_type)
+{
+ struct net_device *orig_netdev = netdev;
+ struct nlattr *nest_lease, *nest_queue;
+ struct netdev_rx_queue *rxq;
+ struct net *net, *peer_net;
+
+ rxq = __netif_get_rx_queue_lease(&netdev, &q_idx,
+ NETIF_PHYS_TO_VIRT);
+ if (!rxq || orig_netdev == netdev)
+ return 0;
+
+ nest_lease = nla_nest_start(rsp, NETDEV_A_QUEUE_LEASE);
+ if (!nest_lease)
+ goto nla_put_failure;
+
+ nest_queue = nla_nest_start(rsp, NETDEV_A_LEASE_QUEUE);
+ if (!nest_queue)
+ goto nla_put_failure;
+ if (nla_put_u32(rsp, NETDEV_A_QUEUE_ID, q_idx))
+ goto nla_put_failure;
+ if (nla_put_u32(rsp, NETDEV_A_QUEUE_TYPE, q_type))
+ goto nla_put_failure;
+ nla_nest_end(rsp, nest_queue);
+
+ if (nla_put_u32(rsp, NETDEV_A_LEASE_IFINDEX,
+ READ_ONCE(netdev->ifindex)))
+ goto nla_put_failure;
+
+ rcu_read_lock();
+ peer_net = dev_net_rcu(netdev);
+ net = dev_net_rcu(orig_netdev);
+ if (!net_eq(net, peer_net)) {
+ s32 id = peernet2id_alloc(net, peer_net, GFP_ATOMIC);
+
+ if (nla_put_s32(rsp, NETDEV_A_LEASE_NETNS_ID, id))
+ goto nla_put_failure_unlock;
+ }
+ rcu_read_unlock();
+ nla_nest_end(rsp, nest_lease);
+ return 0;
+
+nla_put_failure_unlock:
+ rcu_read_unlock();
+nla_put_failure:
+ return -ENOMEM;
+}
+
static int
netdev_nl_queue_fill_one(struct sk_buff *rsp, struct net_device *netdev,
u32 q_idx, u32 q_type, const struct genl_info *info)
{
struct pp_memory_provider_params *params;
- struct netdev_rx_queue *rxq;
+ struct net_device *orig_netdev = netdev;
+ struct netdev_rx_queue *rxq, *rxq_lease;
struct netdev_queue *txq;
void *hdr;
@@ -409,17 +460,22 @@ netdev_nl_queue_fill_one(struct sk_buff *rsp, struct net_device *netdev,
rxq = __netif_get_rx_queue(netdev, q_idx);
if (nla_put_napi_id(rsp, rxq->napi))
goto nla_put_failure;
+ if (netdev_nl_queue_fill_lease(rsp, netdev, q_idx, q_type))
+ goto nla_put_failure;
+ rxq_lease = netif_get_rx_queue_lease_locked(&netdev, &q_idx);
+ if (rxq_lease)
+ rxq = rxq_lease;
params = &rxq->mp_params;
if (params->mp_ops &&
params->mp_ops->nl_fill(params->mp_priv, rsp, rxq))
- goto nla_put_failure;
+ goto nla_put_failure_lease;
#ifdef CONFIG_XDP_SOCKETS
if (rxq->pool)
if (nla_put_empty_nest(rsp, NETDEV_A_QUEUE_XSK))
- goto nla_put_failure;
+ goto nla_put_failure_lease;
#endif
-
+ netif_put_rx_queue_lease_locked(orig_netdev, netdev);
break;
case NETDEV_QUEUE_TYPE_TX:
txq = netdev_get_tx_queue(netdev, q_idx);
@@ -437,6 +493,8 @@ netdev_nl_queue_fill_one(struct sk_buff *rsp, struct net_device *netdev,
return 0;
+nla_put_failure_lease:
+ netif_put_rx_queue_lease_locked(orig_netdev, netdev);
nla_put_failure:
genlmsg_cancel(rsp, hdr);
return -EMSGSIZE;
diff --git a/net/core/netdev_rx_queue.c b/net/core/netdev_rx_queue.c
index a1f23c2c96d4..a4d8cad6db74 100644
--- a/net/core/netdev_rx_queue.c
+++ b/net/core/netdev_rx_queue.c
@@ -41,6 +41,60 @@ bool netif_rxq_is_leased(struct net_device *dev, unsigned int rxq_idx)
return false;
}
+/* Virtual devices eligible for leasing have no dev->dev.parent, while
+ * physical devices always have one. Use this to enforce the correct
+ * lease traversal direction.
+ */
+static bool netif_lease_dir_ok(const struct net_device *dev,
+ enum netif_lease_dir dir)
+{
+ if (dir == NETIF_VIRT_TO_PHYS && !dev->dev.parent)
+ return true;
+ if (dir == NETIF_PHYS_TO_VIRT && dev->dev.parent)
+ return true;
+ return false;
+}
+
+struct netdev_rx_queue *
+__netif_get_rx_queue_lease(struct net_device **dev, unsigned int *rxq_idx,
+ enum netif_lease_dir dir)
+{
+ struct net_device *orig_dev = *dev;
+ struct netdev_rx_queue *rxq = __netif_get_rx_queue(orig_dev, *rxq_idx);
+
+ if (rxq->lease) {
+ if (!netif_lease_dir_ok(orig_dev, dir))
+ return NULL;
+ rxq = rxq->lease;
+ *rxq_idx = get_netdev_rx_queue_index(rxq);
+ *dev = rxq->dev;
+ }
+ return rxq;
+}
+
+struct netdev_rx_queue *
+netif_get_rx_queue_lease_locked(struct net_device **dev, unsigned int *rxq_idx)
+{
+ struct net_device *orig_dev = *dev;
+ struct netdev_rx_queue *rxq;
+
+ /* Locking order is always from the virtual to the physical device
+ * see netdev_nl_queue_create_doit().
+ */
+ netdev_ops_assert_locked(orig_dev);
+ rxq = __netif_get_rx_queue_lease(dev, rxq_idx, NETIF_VIRT_TO_PHYS);
+ if (rxq && orig_dev != *dev)
+ netdev_lock(*dev);
+ return rxq;
+}
+
+void netif_put_rx_queue_lease_locked(struct net_device *orig_dev,
+ struct net_device *dev)
+{
+ if (orig_dev != dev)
+ netdev_unlock(dev);
+}
+
/* See also page_pool_is_unreadable() */
bool netif_rxq_has_unreadable_mp(struct net_device *dev, unsigned int rxq_idx)
{
--
2.43.0
next prev parent reply other threads:[~2026-04-02 23:11 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-02 23:10 [PATCH net-next v11 00/14] netkit: Support for io_uring zero-copy and AF_XDP Daniel Borkmann
2026-04-02 23:10 ` [PATCH net-next v11 01/14] net: Add queue-create operation Daniel Borkmann
2026-04-02 23:10 ` [PATCH net-next v11 02/14] net: Implement netdev_nl_queue_create_doit Daniel Borkmann
2026-04-02 23:10 ` Daniel Borkmann [this message]
2026-04-08 3:40 ` [PATCH net-next v11 03/14] net: Add lease info to queue-get response Jakub Kicinski
2026-04-08 9:09 ` Daniel Borkmann
2026-04-08 22:12 ` Jakub Kicinski
2026-04-09 13:43 ` Daniel Borkmann
2026-04-09 13:52 ` Daniel Borkmann
2026-04-09 14:46 ` Jakub Kicinski
2026-04-09 15:32 ` Daniel Borkmann
2026-04-10 1:51 ` Jakub Kicinski
2026-04-10 11:10 ` Daniel Borkmann
2026-04-02 23:10 ` [PATCH net-next v11 04/14] net, ethtool: Disallow leased real rxqs to be resized Daniel Borkmann
2026-04-02 23:10 ` [PATCH net-next v11 05/14] net: Slightly simplify net_mp_{open,close}_rxq Daniel Borkmann
2026-04-02 23:10 ` [PATCH net-next v11 06/14] net: Proxy netif_mp_{open,close}_rxq for leased queues Daniel Borkmann
2026-04-02 23:10 ` [PATCH net-next v11 07/14] net: Proxy netdev_queue_get_dma_dev " Daniel Borkmann
2026-04-02 23:10 ` [PATCH net-next v11 08/14] xsk: Extend xsk_rcv_check validation Daniel Borkmann
2026-04-02 23:10 ` [PATCH net-next v11 09/14] xsk: Proxy pool management for leased queues Daniel Borkmann
2026-04-02 23:10 ` [PATCH net-next v11 10/14] netkit: Add single device mode for netkit Daniel Borkmann
2026-04-02 23:10 ` [PATCH net-next v11 11/14] netkit: Implement rtnl_link_ops->alloc and ndo_queue_create Daniel Borkmann
2026-04-02 23:10 ` [PATCH net-next v11 12/14] netkit: Add netkit notifier to check for unregistering devices Daniel Borkmann
2026-04-02 23:10 ` [PATCH net-next v11 13/14] netkit: Add xsk support for af_xdp applications Daniel Borkmann
2026-04-02 23:10 ` [PATCH net-next v11 14/14] selftests/net: Add queue leasing tests with netkit Daniel Borkmann
2026-04-08 23:22 ` Jakub Kicinski
2026-04-09 15:26 ` David Wei
2026-04-10 1:19 ` Jakub Kicinski
2026-04-07 9:50 ` [PATCH net-next v11 00/14] netkit: Support for io_uring zero-copy and AF_XDP Daniel Borkmann
2026-04-10 2:00 ` patchwork-bot+netdevbpf
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=20260402231031.447597-4-daniel@iogearbox.net \
--to=daniel@iogearbox.net \
--cc=bpf@vger.kernel.org \
--cc=davem@davemloft.net \
--cc=dw@davidwei.uk \
--cc=john.fastabend@gmail.com \
--cc=jordan@jrife.io \
--cc=kuba@kernel.org \
--cc=maciej.fijalkowski@intel.com \
--cc=magnus.karlsson@intel.com \
--cc=martin.lau@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=razor@blackwall.org \
--cc=sdf@fomichev.me \
--cc=toke@redhat.com \
--cc=wangdongdong.6@bytedance.com \
--cc=willemb@google.com \
--cc=yangzhenze@bytedance.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.