Commit 42dc431f authored by Daniel Zahka's avatar Daniel Zahka Committed by Paolo Abeni
Browse files

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: default avatarDaniel Zahka <daniel.zahka@gmail.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 5cb409b3
Loading
Loading
Loading
Loading
+48 −0
Original line number Diff line number Diff line
@@ -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))
+1 −0
Original line number Diff line number Diff line
@@ -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;
+7 −0
Original line number Diff line number Diff line
@@ -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;