xdp: generic XDP handling of xdp_rxq_info
authorJesper Dangaard Brouer <brouer@redhat.com>
Wed, 3 Jan 2018 10:26:09 +0000 (11:26 +0100)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 5 Jan 2018 23:21:22 +0000 (15:21 -0800)
Hook points for xdp_rxq_info:
 * reg  : netif_alloc_rx_queues
 * unreg: netif_free_rx_queues

The net_device have some members (num_rx_queues + real_num_rx_queues)
and data-area (dev->_rx with struct netdev_rx_queue's) that were
primarily used for exporting information about RPS (CONFIG_RPS) queues
to sysfs (CONFIG_SYSFS).

For generic XDP extend struct netdev_rx_queue with the xdp_rxq_info,
and remove some of the CONFIG_SYSFS ifdefs.

Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
include/linux/netdevice.h
net/core/dev.c

index 49bfc6e..440b000 100644 (file)
@@ -44,6 +44,7 @@
 #include <net/dcbnl.h>
 #endif
 #include <net/netprio_cgroup.h>
+#include <net/xdp.h>
 
 #include <linux/netdev_features.h>
 #include <linux/neighbour.h>
@@ -686,6 +687,7 @@ struct netdev_rx_queue {
 #endif
        struct kobject                  kobj;
        struct net_device               *dev;
+       struct xdp_rxq_info             xdp_rxq;
 } ____cacheline_aligned_in_smp;
 
 /*
index 2eb66c0..d7925ef 100644 (file)
@@ -3906,9 +3906,33 @@ drop:
        return NET_RX_DROP;
 }
 
+static struct netdev_rx_queue *netif_get_rxqueue(struct sk_buff *skb)
+{
+       struct net_device *dev = skb->dev;
+       struct netdev_rx_queue *rxqueue;
+
+       rxqueue = dev->_rx;
+
+       if (skb_rx_queue_recorded(skb)) {
+               u16 index = skb_get_rx_queue(skb);
+
+               if (unlikely(index >= dev->real_num_rx_queues)) {
+                       WARN_ONCE(dev->real_num_rx_queues > 1,
+                                 "%s received packet on queue %u, but number "
+                                 "of RX queues is %u\n",
+                                 dev->name, index, dev->real_num_rx_queues);
+
+                       return rxqueue; /* Return first rxqueue */
+               }
+               rxqueue += index;
+       }
+       return rxqueue;
+}
+
 static u32 netif_receive_generic_xdp(struct sk_buff *skb,
                                     struct bpf_prog *xdp_prog)
 {
+       struct netdev_rx_queue *rxqueue;
        u32 metalen, act = XDP_DROP;
        struct xdp_buff xdp;
        void *orig_data;
@@ -3952,6 +3976,9 @@ static u32 netif_receive_generic_xdp(struct sk_buff *skb,
        xdp.data_hard_start = skb->data - skb_headroom(skb);
        orig_data = xdp.data;
 
+       rxqueue = netif_get_rxqueue(skb);
+       xdp.rxq = &rxqueue->xdp_rxq;
+
        act = bpf_prog_run_xdp(xdp_prog, &xdp);
 
        off = xdp.data - orig_data;
@@ -7589,12 +7616,12 @@ void netif_stacked_transfer_operstate(const struct net_device *rootdev,
 }
 EXPORT_SYMBOL(netif_stacked_transfer_operstate);
 
-#ifdef CONFIG_SYSFS
 static int netif_alloc_rx_queues(struct net_device *dev)
 {
        unsigned int i, count = dev->num_rx_queues;
        struct netdev_rx_queue *rx;
        size_t sz = count * sizeof(*rx);
+       int err = 0;
 
        BUG_ON(count < 1);
 
@@ -7604,11 +7631,39 @@ static int netif_alloc_rx_queues(struct net_device *dev)
 
        dev->_rx = rx;
 
-       for (i = 0; i < count; i++)
+       for (i = 0; i < count; i++) {
                rx[i].dev = dev;
+
+               /* XDP RX-queue setup */
+               err = xdp_rxq_info_reg(&rx[i].xdp_rxq, dev, i);
+               if (err < 0)
+                       goto err_rxq_info;
+       }
        return 0;
+
+err_rxq_info:
+       /* Rollback successful reg's and free other resources */
+       while (i--)
+               xdp_rxq_info_unreg(&rx[i].xdp_rxq);
+       kfree(dev->_rx);
+       dev->_rx = NULL;
+       return err;
+}
+
+static void netif_free_rx_queues(struct net_device *dev)
+{
+       unsigned int i, count = dev->num_rx_queues;
+       struct netdev_rx_queue *rx;
+
+       /* netif_alloc_rx_queues alloc failed, resources have been unreg'ed */
+       if (!dev->_rx)
+               return;
+
+       rx = dev->_rx;
+
+       for (i = 0; i < count; i++)
+               xdp_rxq_info_unreg(&rx[i].xdp_rxq);
 }
-#endif
 
 static void netdev_init_one_queue(struct net_device *dev,
                                  struct netdev_queue *queue, void *_unused)
@@ -8169,12 +8224,10 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
                return NULL;
        }
 
-#ifdef CONFIG_SYSFS
        if (rxqs < 1) {
                pr_err("alloc_netdev: Unable to allocate device with zero RX queues\n");
                return NULL;
        }
-#endif
 
        alloc_size = sizeof(struct net_device);
        if (sizeof_priv) {
@@ -8231,12 +8284,10 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
        if (netif_alloc_netdev_queues(dev))
                goto free_all;
 
-#ifdef CONFIG_SYSFS
        dev->num_rx_queues = rxqs;
        dev->real_num_rx_queues = rxqs;
        if (netif_alloc_rx_queues(dev))
                goto free_all;
-#endif
 
        strcpy(dev->name, name);
        dev->name_assign_type = name_assign_type;
@@ -8275,9 +8326,7 @@ void free_netdev(struct net_device *dev)
 
        might_sleep();
        netif_free_tx_queues(dev);
-#ifdef CONFIG_SYSFS
-       kvfree(dev->_rx);
-#endif
+       netif_free_rx_queues(dev);
 
        kfree(rcu_dereference_protected(dev->ingress_queue, 1));