ethtool: don't allow disabling queues with umem installed
authorJakub Kicinski <jakub.kicinski@netronome.com>
Mon, 1 Oct 2018 12:51:36 +0000 (14:51 +0200)
committerDaniel Borkmann <daniel@iogearbox.net>
Fri, 5 Oct 2018 07:31:01 +0000 (09:31 +0200)
We already check the RSS indirection table does not use queues which
would be disabled by channel reconfiguration. Make sure user does not
try to disable queues which have a UMEM and zero-copy AF_XDP socket
installed.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
include/net/xdp_sock.h
net/core/ethtool.c
net/xdp/xdp_umem.c

index 70a115bea4f4241cdf4c5129517542ada48f3478..13acb9803a6dcac98e3b81bfb87374bb2ebf21ae 100644 (file)
@@ -86,6 +86,7 @@ struct xdp_umem_fq_reuse *xsk_reuseq_prepare(u32 nentries);
 struct xdp_umem_fq_reuse *xsk_reuseq_swap(struct xdp_umem *umem,
                                          struct xdp_umem_fq_reuse *newq);
 void xsk_reuseq_free(struct xdp_umem_fq_reuse *rq);
+struct xdp_umem *xdp_get_umem_from_qid(struct net_device *dev, u16 queue_id);
 
 static inline char *xdp_umem_get_data(struct xdp_umem *umem, u64 addr)
 {
@@ -183,6 +184,12 @@ static inline void xsk_reuseq_free(struct xdp_umem_fq_reuse *rq)
 {
 }
 
+static inline struct xdp_umem *xdp_get_umem_from_qid(struct net_device *dev,
+                                                    u16 queue_id)
+{
+       return NULL;
+}
+
 static inline char *xdp_umem_get_data(struct xdp_umem *umem, u64 addr)
 {
        return NULL;
index 9a648fb09594ea0b521f78594c531b9e3287535d..5a788adeba0b27221bf0d816d1a0127aa8dafbd4 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/sched/signal.h>
 #include <linux/net.h>
+#include <net/xdp_sock.h>
 
 /*
  * Some useful ethtool_ops methods that're device independent.
@@ -1656,7 +1657,9 @@ static noinline_for_stack int ethtool_set_channels(struct net_device *dev,
                                                   void __user *useraddr)
 {
        struct ethtool_channels channels, curr = { .cmd = ETHTOOL_GCHANNELS };
+       u16 from_channel, to_channel;
        u32 max_rx_in_use = 0;
+       unsigned int i;
 
        if (!dev->ethtool_ops->set_channels || !dev->ethtool_ops->get_channels)
                return -EOPNOTSUPP;
@@ -1680,6 +1683,14 @@ static noinline_for_stack int ethtool_set_channels(struct net_device *dev,
            (channels.combined_count + channels.rx_count) <= max_rx_in_use)
            return -EINVAL;
 
+       /* Disabling channels, query zero-copy AF_XDP sockets */
+       from_channel = channels.combined_count +
+               min(channels.rx_count, channels.tx_count);
+       to_channel = curr.combined_count + max(curr.rx_count, curr.tx_count);
+       for (i = from_channel; i < to_channel; i++)
+               if (xdp_get_umem_from_qid(dev, i))
+                       return -EINVAL;
+
        return dev->ethtool_ops->set_channels(dev, &channels);
 }
 
index 4d6c6652f5d132534744eb3890e673efbd42b198..773326f682b1c2a6359f03607de61e0a88959ae7 100644 (file)
@@ -55,8 +55,8 @@ static void xdp_reg_umem_at_qid(struct net_device *dev, struct xdp_umem *umem,
                dev->_tx[queue_id].umem = umem;
 }
 
-static struct xdp_umem *xdp_get_umem_from_qid(struct net_device *dev,
-                                             u16 queue_id)
+struct xdp_umem *xdp_get_umem_from_qid(struct net_device *dev,
+                                      u16 queue_id)
 {
        if (queue_id < dev->real_num_rx_queues)
                return dev->_rx[queue_id].umem;