]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
ethtool: rss: prevent rss ctx deletion when in use
authorDaniel Zahka <daniel.zahka@gmail.com>
Fri, 11 Oct 2024 18:35:47 +0000 (11:35 -0700)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 17 Oct 2024 08:22:01 +0000 (10:22 +0200)
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>
net/ethtool/common.c
net/ethtool/common.h
net/ethtool/ioctl.c

index dd345efa114bc95aad298951b88442ba72b74613..0d62363dbd9d24fbd375ad3d7f52889e5a8702a8 100644 (file)
@@ -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))
index d55d5201b085da67da1493aca3c8cec9cc092375..4a2de3ce7354f8b957922f8d98a10e7f34e034db 100644 (file)
@@ -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;
index 04b34dc6b36969d489cec5905602f39d178824a9..5cc131cdb1bc36dc9a6ac22a423ea00e8a690682 100644 (file)
@@ -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;