summaryrefslogtreecommitdiffstats
path: root/net/ethtool
diff options
context:
space:
mode:
authorDaniel Zahka <daniel.zahka@gmail.com>2024-10-11 20:35:47 +0200
committerPaolo Abeni <pabeni@redhat.com>2024-10-17 10:22:01 +0200
commit42dc431f5d0ea9e9c9caf74dcb5b290ce4dd80b4 (patch)
tree34a6aaaaae7d7d6369c0987746af26a65d538b1a /net/ethtool
parentnet: phy: realtek: clear 1000Base-T link partner advertisement (diff)
downloadlinux-42dc431f5d0ea9e9c9caf74dcb5b290ce4dd80b4.tar.xz
linux-42dc431f5d0ea9e9c9caf74dcb5b290ce4dd80b4.zip
ethtool: rss: prevent rss ctx deletion when in use
ntuple filters can specify an rss context to use for packet hashing and queue selection. When a filter is referencing an rss context, it should be invalid for that context to be deleted. A list of active ntuple filters and their associated rss contexts can be compiled by querying a device's ethtool_ops.get_rxnfc. This patch checks to see if any ntuple filters are referencing an rss context during context deletion, and prevents the deletion if the requested context is still in use. Signed-off-by: Daniel Zahka <daniel.zahka@gmail.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Diffstat (limited to 'net/ethtool')
-rw-r--r--net/ethtool/common.c48
-rw-r--r--net/ethtool/common.h1
-rw-r--r--net/ethtool/ioctl.c7
3 files changed, 56 insertions, 0 deletions
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index dd345efa114b..0d62363dbd9d 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -684,6 +684,54 @@ int ethtool_check_max_channel(struct net_device *dev,
return 0;
}
+int ethtool_check_rss_ctx_busy(struct net_device *dev, u32 rss_context)
+{
+ const struct ethtool_ops *ops = dev->ethtool_ops;
+ struct ethtool_rxnfc *info;
+ int rc, i, rule_cnt;
+
+ if (!ops->get_rxnfc)
+ return 0;
+
+ rule_cnt = ethtool_get_rxnfc_rule_count(dev);
+ if (!rule_cnt)
+ return 0;
+
+ if (rule_cnt < 0)
+ return -EINVAL;
+
+ info = kvzalloc(struct_size(info, rule_locs, rule_cnt), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->cmd = ETHTOOL_GRXCLSRLALL;
+ info->rule_cnt = rule_cnt;
+ rc = ops->get_rxnfc(dev, info, info->rule_locs);
+ if (rc)
+ goto out_free;
+
+ for (i = 0; i < rule_cnt; i++) {
+ struct ethtool_rxnfc rule_info = {
+ .cmd = ETHTOOL_GRXCLSRULE,
+ .fs.location = info->rule_locs[i],
+ };
+
+ rc = ops->get_rxnfc(dev, &rule_info, NULL);
+ if (rc)
+ goto out_free;
+
+ if (rule_info.fs.flow_type & FLOW_RSS &&
+ rule_info.rss_context == rss_context) {
+ rc = -EBUSY;
+ goto out_free;
+ }
+ }
+
+out_free:
+ kvfree(info);
+ return rc;
+}
+
int ethtool_check_ops(const struct ethtool_ops *ops)
{
if (WARN_ON(ops->set_coalesce && !ops->supported_coalesce_params))
diff --git a/net/ethtool/common.h b/net/ethtool/common.h
index d55d5201b085..4a2de3ce7354 100644
--- a/net/ethtool/common.h
+++ b/net/ethtool/common.h
@@ -47,6 +47,7 @@ bool convert_legacy_settings_to_link_ksettings(
int ethtool_check_max_channel(struct net_device *dev,
struct ethtool_channels channels,
struct genl_info *info);
+int ethtool_check_rss_ctx_busy(struct net_device *dev, u32 rss_context);
int __ethtool_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info *info);
extern const struct ethtool_phy_ops *ethtool_phy_ops;
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 04b34dc6b369..5cc131cdb1bc 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -1462,6 +1462,13 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
mutex_lock(&dev->ethtool->rss_lock);
locked = true;
}
+
+ if (rxfh.rss_context && rxfh_dev.rss_delete) {
+ ret = ethtool_check_rss_ctx_busy(dev, rxfh.rss_context);
+ if (ret)
+ goto out;
+ }
+
if (create) {
if (rxfh_dev.rss_delete) {
ret = -EINVAL;