Commit d04686d9 authored by Daniel Borkmann's avatar Daniel Borkmann Committed by Jakub Kicinski
Browse files

net: Implement netdev_nl_queue_create_doit



Implement netdev_nl_queue_create_doit which creates a new rx queue in a
virtual netdev and then leases it to a rx queue in a physical netdev.

Example with ynl client:

  # ynl --family netdev --output-json --do queue-create \
        --json '{"ifindex": 8, "type": "rx", "lease": {"ifindex": 4, "queue": {"type": "rx", "id": 15}}}'
  {'id': 1}

Note that the netdevice locking order is always from the virtual to
the physical device.

Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Co-developed-by: default avatarDavid Wei <dw@davidwei.uk>
Signed-off-by: default avatarDavid Wei <dw@davidwei.uk>
Reviewed-by: default avatarNikolay Aleksandrov <razor@blackwall.org>
Link: https://patch.msgid.link/20260402231031.447597-3-daniel@iogearbox.net


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 7789c6bb
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -329,6 +329,12 @@ by setting ``request_ops_lock`` to true. Code comments and docs refer
to drivers which have ops called under the instance lock as "ops locked".
See also the documentation of the ``lock`` member of struct net_device.

There is also a case of taking two per-netdev locks in sequence when netdev
queues are leased, that is, the netdev-scope lock is taken for both the
virtual and the physical device. To prevent deadlocks, the virtual device's
lock must always be acquired before the physical device's (see
``netdev_nl_queue_create_doit``).

In the future, there will be an option for individual
drivers to opt out of using ``rtnl_lock`` and instead perform their control
operations directly under the netdev instance lock.
+8 −1
Original line number Diff line number Diff line
@@ -2561,7 +2561,14 @@ struct net_device {
	 * Also protects some fields in:
	 *	struct napi_struct, struct netdev_queue, struct netdev_rx_queue
	 *
	 * Ordering: take after rtnl_lock.
	 * Ordering:
	 *
	 * - take after rtnl_lock
	 *
	 * - for the case of netdev queue leasing, the netdev-scope lock is
	 *   taken for both the virtual and the physical device; to prevent
	 *   deadlocks, the virtual device's lock must always be acquired
	 *   before the physical device's (see netdev_nl_queue_create_doit)
	 */
	struct mutex		lock;

+16 −3
Original line number Diff line number Diff line
@@ -150,6 +150,11 @@ enum {
 *			When NIC-wide config is changed the callback will
 *			be invoked for all queues.
 *
 * @ndo_queue_create:	Create a new RX queue on a virtual device that will
 *			be paired with a physical device's queue via leasing.
 *			Return the new queue id on success, negative error
 *			on failure.
 *
 * @supported_params:	Bitmask of supported parameters, see QCFG_*.
 *
 * Note that @ndo_queue_mem_alloc and @ndo_queue_mem_free may be called while
@@ -178,6 +183,8 @@ struct netdev_queue_mgmt_ops {
				     struct netlink_ext_ack *extack);
	struct device *	(*ndo_queue_get_dma_dev)(struct net_device *dev,
						 int idx);
	int	(*ndo_queue_create)(struct net_device *dev,
				    struct netlink_ext_ack *extack);

	unsigned int supported_params;
};
@@ -185,7 +192,7 @@ struct netdev_queue_mgmt_ops {
void netdev_queue_config(struct net_device *dev, int rxq,
			 struct netdev_queue_config *qcfg);

bool netif_rxq_has_unreadable_mp(struct net_device *dev, int idx);
bool netif_rxq_has_unreadable_mp(struct net_device *dev, unsigned int rxq_idx);

/**
 * DOC: Lockless queue stopping / waking helpers.
@@ -374,5 +381,11 @@ static inline unsigned int netif_xmit_timeout_ms(struct netdev_queue *txq)
	})

struct device *netdev_queue_get_dma_dev(struct net_device *dev, int idx);

#endif
bool netdev_can_create_queue(const struct net_device *dev,
			     struct netlink_ext_ack *extack);
bool netdev_can_lease_queue(const struct net_device *dev,
			    struct netlink_ext_ack *extack);
bool netdev_queue_busy(struct net_device *dev, unsigned int idx,
		       enum netdev_queue_type type,
		       struct netlink_ext_ack *extack);
#endif /* _LINUX_NET_QUEUES_H */
+13 −2
Original line number Diff line number Diff line
@@ -31,6 +31,14 @@ struct netdev_rx_queue {
	struct napi_struct		*napi;
	struct netdev_queue_config	qcfg;
	struct pp_memory_provider_params mp_params;

	/* If a queue is leased, then the lease pointer is always
	 * valid. From the physical device it points to the virtual
	 * queue, and from the virtual device it points to the
	 * physical queue.
	 */
	struct netdev_rx_queue		*lease;
	netdevice_tracker		lease_tracker;
} ____cacheline_aligned_in_smp;

/*
@@ -60,5 +68,8 @@ get_netdev_rx_queue_index(struct netdev_rx_queue *queue)
}

int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq);

#endif
void netdev_rx_queue_lease(struct netdev_rx_queue *rxq_dst,
			   struct netdev_rx_queue *rxq_src);
void netdev_rx_queue_unlease(struct netdev_rx_queue *rxq_dst,
			     struct netdev_rx_queue *rxq_src);
#endif /* _LINUX_NETDEV_RX_QUEUE_H */
+8 −0
Original line number Diff line number Diff line
@@ -1121,6 +1121,14 @@ netdev_get_by_index_lock_ops_compat(struct net *net, int ifindex)
	return __netdev_put_lock_ops_compat(dev, net);
}

struct net_device *
netdev_put_lock(struct net_device *dev, struct net *net,
		netdevice_tracker *tracker)
{
	netdev_tracker_free(dev, tracker);
	return __netdev_put_lock(dev, net);
}

struct net_device *
netdev_xa_find_lock(struct net *net, struct net_device *dev,
		    unsigned long *index)
Loading