net, ethtool: Disallow leased real rxqs to be resized
Similar to AF_XDP, do not allow queues in a physical netdev to be resized by ethtool -L when they are leased. Cover channel resize paths (both netlink and ioctl) to reject resizing when the queues would be affected. Given we need to have different checks for RX vs TX, detangle the code into a two-loop version rather than the range of new_combined + min(new_rx, new_tx) to old_combined + max(old_rx, old_tx). 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> Link: https://patch.msgid.link/20260402231031.447597-5-daniel@iogearbox.net Signed-off-by: Jakub Kicinski <kuba@kernel.org>master
parent
21d58b35e5
commit
22fdf28f7c
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <net/xdp_sock_drv.h>
|
||||
#include <net/netdev_queues.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "netlink.h"
|
||||
|
|
@ -109,7 +109,7 @@ ethnl_set_channels_validate(struct ethnl_req_info *req_info,
|
|||
static int
|
||||
ethnl_set_channels(struct ethnl_req_info *req_info, struct genl_info *info)
|
||||
{
|
||||
unsigned int from_channel, old_total, i;
|
||||
unsigned int old_combined, old_rx, old_tx, i;
|
||||
bool mod = false, mod_combined = false;
|
||||
struct net_device *dev = req_info->dev;
|
||||
struct ethtool_channels channels = {};
|
||||
|
|
@ -118,8 +118,9 @@ ethnl_set_channels(struct ethnl_req_info *req_info, struct genl_info *info)
|
|||
int ret;
|
||||
|
||||
dev->ethtool_ops->get_channels(dev, &channels);
|
||||
old_total = channels.combined_count +
|
||||
max(channels.rx_count, channels.tx_count);
|
||||
old_combined = channels.combined_count;
|
||||
old_rx = channels.rx_count;
|
||||
old_tx = channels.tx_count;
|
||||
|
||||
ethnl_update_u32(&channels.rx_count, tb[ETHTOOL_A_CHANNELS_RX_COUNT],
|
||||
&mod);
|
||||
|
|
@ -169,14 +170,19 @@ ethnl_set_channels(struct ethnl_req_info *req_info, struct genl_info *info)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Disabling channels, query zero-copy AF_XDP sockets */
|
||||
from_channel = channels.combined_count +
|
||||
min(channels.rx_count, channels.tx_count);
|
||||
for (i = from_channel; i < old_total; i++)
|
||||
if (xsk_get_pool_from_qid(dev, i)) {
|
||||
GENL_SET_ERR_MSG(info, "requested channel counts are too low for existing zerocopy AF_XDP sockets");
|
||||
/* ensure channels are not busy at the moment */
|
||||
for (i = channels.combined_count + channels.rx_count;
|
||||
i < old_combined + old_rx; i++) {
|
||||
if (netdev_queue_busy(dev, i, NETDEV_QUEUE_TYPE_RX,
|
||||
info->extack))
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
for (i = channels.combined_count + channels.tx_count;
|
||||
i < old_combined + old_tx; i++) {
|
||||
if (netdev_queue_busy(dev, i, NETDEV_QUEUE_TYPE_TX,
|
||||
info->extack))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = dev->ethtool_ops->set_channels(dev, &channels);
|
||||
return ret < 0 ? ret : 1;
|
||||
|
|
|
|||
|
|
@ -27,12 +27,12 @@
|
|||
#include <linux/net.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/utsname.h>
|
||||
#include <linux/ethtool_netlink.h>
|
||||
#include <net/devlink.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/xdp_sock_drv.h>
|
||||
#include <net/flow_offload.h>
|
||||
#include <net/netdev_lock.h>
|
||||
#include <linux/ethtool_netlink.h>
|
||||
#include <net/netdev_queues.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
|
@ -2250,7 +2250,6 @@ static noinline_for_stack int ethtool_set_channels(struct net_device *dev,
|
|||
void __user *useraddr)
|
||||
{
|
||||
struct ethtool_channels channels, curr = { .cmd = ETHTOOL_GCHANNELS };
|
||||
u16 from_channel, to_channel;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
|
|
@ -2284,13 +2283,17 @@ static noinline_for_stack int ethtool_set_channels(struct net_device *dev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Disabling channels, query zero-copy AF_XDP sockets */
|
||||
from_channel = channels.combined_count +
|
||||
min(channels.rx_count, channels.tx_count);
|
||||
to_channel = curr.combined_count + max(curr.rx_count, curr.tx_count);
|
||||
for (i = from_channel; i < to_channel; i++)
|
||||
if (xsk_get_pool_from_qid(dev, i))
|
||||
/* Disabling channels, query busy queues (AF_XDP, queue leasing) */
|
||||
for (i = channels.combined_count + channels.rx_count;
|
||||
i < curr.combined_count + curr.rx_count; i++) {
|
||||
if (netdev_queue_busy(dev, i, NETDEV_QUEUE_TYPE_RX, NULL))
|
||||
return -EINVAL;
|
||||
}
|
||||
for (i = channels.combined_count + channels.tx_count;
|
||||
i < curr.combined_count + curr.tx_count; i++) {
|
||||
if (netdev_queue_busy(dev, i, NETDEV_QUEUE_TYPE_TX, NULL))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = dev->ethtool_ops->set_channels(dev, &channels);
|
||||
if (!ret)
|
||||
|
|
|
|||
Loading…
Reference in New Issue