ethtool: check if there is at least one channel for TX/RX in the core
authorJakub Kicinski <kuba@kernel.org>
Fri, 15 May 2020 19:49:00 +0000 (12:49 -0700)
committerDavid S. Miller <davem@davemloft.net>
Sat, 16 May 2020 20:56:30 +0000 (13:56 -0700)
Having a channel config with no ability to RX or TX traffic is
clearly wrong. Check for this in the core so the drivers don't
have to.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Reviewed-by: Michal Kubecek <mkubecek@suse.cz>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ethtool/channels.c
net/ethtool/ioctl.c

index 389924b..3aa4975 100644 (file)
@@ -129,13 +129,13 @@ int ethnl_set_channels(struct sk_buff *skb, struct genl_info *info)
 {
        struct nlattr *tb[ETHTOOL_A_CHANNELS_MAX + 1];
        unsigned int from_channel, old_total, i;
+       bool mod = false, mod_combined = false;
        struct ethtool_channels channels = {};
        struct ethnl_req_info req_info = {};
        const struct nlattr *err_attr;
        const struct ethtool_ops *ops;
        struct net_device *dev;
        u32 max_rx_in_use = 0;
-       bool mod = false;
        int ret;
 
        ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb,
@@ -170,7 +170,8 @@ int ethnl_set_channels(struct sk_buff *skb, struct genl_info *info)
        ethnl_update_u32(&channels.other_count,
                         tb[ETHTOOL_A_CHANNELS_OTHER_COUNT], &mod);
        ethnl_update_u32(&channels.combined_count,
-                        tb[ETHTOOL_A_CHANNELS_COMBINED_COUNT], &mod);
+                        tb[ETHTOOL_A_CHANNELS_COMBINED_COUNT], &mod_combined);
+       mod |= mod_combined;
        ret = 0;
        if (!mod)
                goto out_ops;
@@ -193,6 +194,21 @@ int ethnl_set_channels(struct sk_buff *skb, struct genl_info *info)
                goto out_ops;
        }
 
+       /* ensure there is at least one RX and one TX channel */
+       if (!channels.combined_count && !channels.rx_count)
+               err_attr = tb[ETHTOOL_A_CHANNELS_RX_COUNT];
+       else if (!channels.combined_count && !channels.tx_count)
+               err_attr = tb[ETHTOOL_A_CHANNELS_TX_COUNT];
+       else
+               err_attr = NULL;
+       if (err_attr) {
+               if (mod_combined)
+                       err_attr = tb[ETHTOOL_A_CHANNELS_COMBINED_COUNT];
+               ret = -EINVAL;
+               NL_SET_ERR_MSG_ATTR(info->extack, err_attr, "requested channel counts would result in no RX or TX channel being configured");
+               goto out_ops;
+       }
+
        /* ensure the new Rx count fits within the configured Rx flow
         * indirection table settings
         */
index 52102ab..a574d60 100644 (file)
@@ -1676,6 +1676,11 @@ static noinline_for_stack int ethtool_set_channels(struct net_device *dev,
            channels.other_count > curr.max_other)
                return -EINVAL;
 
+       /* ensure there is at least one RX and one TX channel */
+       if (!channels.combined_count &&
+           (!channels.rx_count || !channels.tx_count))
+               return -EINVAL;
+
        /* ensure the new Rx count fits within the configured Rx flow
         * indirection table settings */
        if (netif_is_rxfh_configured(dev) &&