]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: ethtool: add hds_config member in ethtool_netdev_state
authorTaehee Yoo <ap420073@gmail.com>
Tue, 14 Jan 2025 14:28:43 +0000 (14:28 +0000)
committerJakub Kicinski <kuba@kernel.org>
Wed, 15 Jan 2025 22:42:11 +0000 (14:42 -0800)
When tcp-data-split is UNKNOWN mode, drivers arbitrarily handle it.
For example, bnxt_en driver automatically enables if at least one of
LRO/GRO/JUMBO is enabled.
If tcp-data-split is UNKNOWN and LRO is enabled, a driver returns
ENABLES of tcp-data-split, not UNKNOWN.
So, `ethtool -g eth0` shows tcp-data-split is enabled.

The problem is in the setting situation.
In the ethnl_set_rings(), it first calls get_ringparam() to get the
current driver's config.
At that moment, if driver's tcp-data-split config is UNKNOWN, it returns
ENABLE if LRO/GRO/JUMBO is enabled.
Then, it sets values from the user and driver's current config to
kernel_ethtool_ringparam.
Last it calls .set_ringparam().
The driver, especially bnxt_en driver receives
ETHTOOL_TCP_DATA_SPLIT_ENABLED.
But it can't distinguish whether it is set by the user or just the
current config.

When user updates ring parameter, the new hds_config value is updated
and current hds_config value is stored to old_hdsconfig.
Driver's .set_ringparam() callback can distinguish a passed
tcp-data-split value is came from user explicitly.
If .set_ringparam() is failed, hds_config is rollbacked immediately.

Suggested-by: Jakub Kicinski <kuba@kernel.org>
Reviewed-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Taehee Yoo <ap420073@gmail.com>
Link: https://patch.msgid.link/20250114142852.3364986-2-ap420073@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/linux/ethtool.h
include/linux/netdevice.h
net/core/dev.c
net/ethtool/rings.c

index 20a86bd5f4e3436230aa25ebf0532abb40840d56..d79bd201c1c89e73431d070bd5c9aebe123f7886 100644 (file)
@@ -1157,12 +1157,14 @@ int ethtool_virtdev_set_link_ksettings(struct net_device *dev,
  * @rss_ctx:           XArray of custom RSS contexts
  * @rss_lock:          Protects entries in @rss_ctx.  May be taken from
  *                     within RTNL.
+ * @hds_config:                HDS value from userspace.
  * @wol_enabled:       Wake-on-LAN is enabled
  * @module_fw_flash_in_progress: Module firmware flashing is in progress.
  */
 struct ethtool_netdev_state {
        struct xarray           rss_ctx;
        struct mutex            rss_lock;
+       u8                      hds_config;
        unsigned                wol_enabled:1;
        unsigned                module_fw_flash_in_progress:1;
 };
index bced03fb349e55cb62533230cb824909dbfb1375..3e6336775baf054f410ac1a7c6844657ca305f32 100644 (file)
@@ -4082,6 +4082,7 @@ struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
 int bpf_xdp_link_attach(const union bpf_attr *attr, struct bpf_prog *prog);
 u8 dev_xdp_prog_count(struct net_device *dev);
 int dev_xdp_propagate(struct net_device *dev, struct netdev_bpf *bpf);
+u8 dev_xdp_sb_prog_count(struct net_device *dev);
 u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode);
 
 u32 dev_get_min_mp_channel_count(const struct net_device *dev);
index fda4e1039bf01d46cfaa5f134d20e1d2bcdcfdfc..5ef817d656ef6fc23fc29befadf9f74dadb92af3 100644 (file)
@@ -9550,6 +9550,18 @@ u8 dev_xdp_prog_count(struct net_device *dev)
 }
 EXPORT_SYMBOL_GPL(dev_xdp_prog_count);
 
+u8 dev_xdp_sb_prog_count(struct net_device *dev)
+{
+       u8 count = 0;
+       int i;
+
+       for (i = 0; i < __MAX_XDP_MODE; i++)
+               if (dev->xdp_state[i].prog &&
+                   !dev->xdp_state[i].prog->aux->xdp_has_frags)
+                       count++;
+       return count;
+}
+
 int dev_xdp_propagate(struct net_device *dev, struct netdev_bpf *bpf)
 {
        if (!dev->netdev_ops->ndo_bpf)
index b7865a14fdf8fab5c54a6d66cd167bbfd60d65bc..b2a2586b241f67c14d93c48843a3cbce59c73260 100644 (file)
@@ -203,6 +203,7 @@ ethnl_set_rings(struct ethnl_req_info *req_info, struct genl_info *info)
 
        dev->ethtool_ops->get_ringparam(dev, &ringparam,
                                        &kernel_ringparam, info->extack);
+       kernel_ringparam.tcp_data_split = dev->ethtool->hds_config;
 
        ethnl_update_u32(&ringparam.rx_pending, tb[ETHTOOL_A_RINGS_RX], &mod);
        ethnl_update_u32(&ringparam.rx_mini_pending,
@@ -225,6 +226,14 @@ ethnl_set_rings(struct ethnl_req_info *req_info, struct genl_info *info)
        if (!mod)
                return 0;
 
+       if (kernel_ringparam.tcp_data_split == ETHTOOL_TCP_DATA_SPLIT_ENABLED &&
+           dev_xdp_sb_prog_count(dev)) {
+               NL_SET_ERR_MSG_ATTR(info->extack,
+                                   tb[ETHTOOL_A_RINGS_TCP_DATA_SPLIT],
+                                   "tcp-data-split can not be enabled with single buffer XDP");
+               return -EINVAL;
+       }
+
        /* ensure new ring parameters are within limits */
        if (ringparam.rx_pending > ringparam.rx_max_pending)
                err_attr = tb[ETHTOOL_A_RINGS_RX];
@@ -252,6 +261,9 @@ ethnl_set_rings(struct ethnl_req_info *req_info, struct genl_info *info)
 
        ret = dev->ethtool_ops->set_ringparam(dev, &ringparam,
                                              &kernel_ringparam, info->extack);
+       if (!ret)
+               dev->ethtool->hds_config = kernel_ringparam.tcp_data_split;
+
        return ret < 0 ? ret : 1;
 }