net: Enable Tx queue selection based on Rx queues
authorAmritha Nambiar <amritha.nambiar@intel.com>
Sat, 30 Jun 2018 04:27:02 +0000 (21:27 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 2 Jul 2018 00:06:24 +0000 (09:06 +0900)
This patch adds support to pick Tx queue based on the Rx queue(s) map
configuration set by the admin through the sysfs attribute
for each Tx queue. If the user configuration for receive queue(s) map
does not apply, then the Tx queue selection falls back to CPU(s) map
based selection and finally to hashing.

Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/sock.h
net/core/dev.c

index 2b097cc8972768aa4a164f0a686318ffe494976f..2ed99bfa45951a4db0c6da8b7291e0ca264a2fec 100644 (file)
@@ -1730,6 +1730,16 @@ static inline void sk_rx_queue_clear(struct sock *sk)
 #endif
 }
 
+#ifdef CONFIG_XPS
+static inline int sk_rx_queue_get(const struct sock *sk)
+{
+       if (sk && sk->sk_rx_queue_mapping != NO_QUEUE_MAPPING)
+               return sk->sk_rx_queue_mapping;
+
+       return -1;
+}
+#endif
+
 static inline void sk_set_socket(struct sock *sk, struct socket *sock)
 {
        sk_tx_queue_clear(sk);
index 43b5575e40c51fd5ce5514187089ee7a209ae8ac..08d58e0debe57351588df7560686652ccb64bf04 100644 (file)
@@ -3459,35 +3459,63 @@ sch_handle_egress(struct sk_buff *skb, int *ret, struct net_device *dev)
 }
 #endif /* CONFIG_NET_EGRESS */
 
-static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
+#ifdef CONFIG_XPS
+static int __get_xps_queue_idx(struct net_device *dev, struct sk_buff *skb,
+                              struct xps_dev_maps *dev_maps, unsigned int tci)
+{
+       struct xps_map *map;
+       int queue_index = -1;
+
+       if (dev->num_tc) {
+               tci *= dev->num_tc;
+               tci += netdev_get_prio_tc_map(dev, skb->priority);
+       }
+
+       map = rcu_dereference(dev_maps->attr_map[tci]);
+       if (map) {
+               if (map->len == 1)
+                       queue_index = map->queues[0];
+               else
+                       queue_index = map->queues[reciprocal_scale(
+                                               skb_get_hash(skb), map->len)];
+               if (unlikely(queue_index >= dev->real_num_tx_queues))
+                       queue_index = -1;
+       }
+       return queue_index;
+}
+#endif
+
+static int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
 {
 #ifdef CONFIG_XPS
        struct xps_dev_maps *dev_maps;
-       struct xps_map *map;
+       struct sock *sk = skb->sk;
        int queue_index = -1;
 
        if (!static_key_false(&xps_needed))
                return -1;
 
        rcu_read_lock();
-       dev_maps = rcu_dereference(dev->xps_cpus_map);
+       if (!static_key_false(&xps_rxqs_needed))
+               goto get_cpus_map;
+
+       dev_maps = rcu_dereference(dev->xps_rxqs_map);
        if (dev_maps) {
-               unsigned int tci = skb->sender_cpu - 1;
+               int tci = sk_rx_queue_get(sk);
 
-               if (dev->num_tc) {
-                       tci *= dev->num_tc;
-                       tci += netdev_get_prio_tc_map(dev, skb->priority);
-               }
+               if (tci >= 0 && tci < dev->num_rx_queues)
+                       queue_index = __get_xps_queue_idx(dev, skb, dev_maps,
+                                                         tci);
+       }
 
-               map = rcu_dereference(dev_maps->attr_map[tci]);
-               if (map) {
-                       if (map->len == 1)
-                               queue_index = map->queues[0];
-                       else
-                               queue_index = map->queues[reciprocal_scale(skb_get_hash(skb),
-                                                                          map->len)];
-                       if (unlikely(queue_index >= dev->real_num_tx_queues))
-                               queue_index = -1;
+get_cpus_map:
+       if (queue_index < 0) {
+               dev_maps = rcu_dereference(dev->xps_cpus_map);
+               if (dev_maps) {
+                       unsigned int tci = skb->sender_cpu - 1;
+
+                       queue_index = __get_xps_queue_idx(dev, skb, dev_maps,
+                                                         tci);
                }
        }
        rcu_read_unlock();