Add code to set the queue in an rflow as opposed to just setting the
CPU in an rps_dev_flow entry. set_rps_qid is the analogue for
set_rps_cpu but for setting queues. In get_rps_cpu, a check is
performed that identifier in the sock_flow_table refers to a queue;
when it does call set_rps_qid after converting the global qid in the
sock_flow_table to a device qid.

In rps_record_sock_flow check is there is a per task receive queue
for current (i.e. current->ptq_queues.rxq_id != NO_QUEUE). If there
is a queue then set in sock_flow_table instead of setting the running
CPU. Subsequently, the receive queue for the flow can be programmed
by aRFS logic (ndo_rx_flow_steer).
---
 include/linux/netdevice.h | 28 ++++++++++++++++++++++++----
 net/core/dev.c            | 36 ++++++++++++++++++++++++++++++++++++
 2 files changed, 60 insertions(+), 4 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index ca163925211a..3b39be470720 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -731,12 +731,25 @@ static inline void rps_dev_flow_set_cpu(struct 
rps_dev_flow *dev_flow, u16 cpu)
        if (WARN_ON(cpu > RPS_MAX_CPU))
                return;
 
-       /* Set the rflow target to the CPU atomically */
+       /* Set the device flow target to the CPU atomically */
        cpu_qid.use_qid = 0;
        cpu_qid.cpu = cpu;
        dev_flow->cpu_qid = cpu_qid;
 }
 
+static inline void rps_dev_flow_set_qid(struct rps_dev_flow *dev_flow, u16 qid)
+{
+       struct rps_cpu_qid cpu_qid;
+
+       if (WARN_ON(qid > RPS_MAX_QID))
+               return;
+
+       /* Set the device flow target to the CPU atomically */
+       cpu_qid.use_qid = 1;
+       cpu_qid.qid = qid;
+       dev_flow->cpu_qid = cpu_qid;
+}
+
 /*
  * The rps_dev_flow_table structure contains a table of flow mappings.
  */
@@ -797,11 +810,18 @@ static inline void rps_record_sock_flow(struct 
rps_sock_flow_table *table,
                                        u32 hash)
 {
        if (table && hash) {
-               u32 val = hash & table->cpu_masks.hash_mask;
                unsigned int index = hash & table->mask;
+               u32 val;
 
-               /* We only give a hint, preemption can change CPU under us */
-               val |= raw_smp_processor_id();
+#ifdef CONFIG_PER_THREAD_QUEUES
+               if (current->ptq_queues.rxq_id != NO_QUEUE)
+                       val = RPS_SOCK_FLOW_USE_QID |
+                             (hash & table->queue_masks.hash_mask) |
+                             current->ptq_queues.rxq_id;
+               else
+#endif
+                       val = (hash & table->cpu_masks.hash_mask) |
+                             raw_smp_processor_id();
 
                if (table->ents[index] != val)
                        table->ents[index] = val;
diff --git a/net/core/dev.c b/net/core/dev.c
index f4478c9b1c9c..1cad776e8847 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4308,6 +4308,25 @@ set_rps_cpu(struct net_device *dev, struct sk_buff *skb,
        return rflow;
 }
 
+static struct rps_dev_flow *
+set_rps_qid(struct net_device *dev, struct sk_buff *skb,
+           struct rps_dev_flow *rflow, u16 qid)
+{
+       if (qid > RPS_MAX_QID) {
+               rps_dev_flow_clear(rflow);
+               return rflow;
+       }
+
+#ifdef CONFIG_RFS_ACCEL
+       /* Should we steer this flow to a different hardware queue? */
+       if (skb_rx_queue_recorded(skb) && (dev->features & NETIF_F_NTUPLE) &&
+           qid != skb_get_rx_queue(skb) && qid < dev->real_num_rx_queues)
+               set_arfs_queue(dev, skb, rflow, qid);
+#endif
+       rps_dev_flow_set_qid(rflow, qid);
+       return rflow;
+}
+
 /*
  * get_rps_cpu is called from netif_receive_skb and returns the target
  * CPU from the RPS map of the receiving queue for a given skb.
@@ -4356,6 +4375,10 @@ static int get_rps_cpu(struct net_device *dev, struct 
sk_buff *skb,
 
                /* First check into global flow table if there is a match */
                ident = sock_flow_table->ents[hash & sock_flow_table->mask];
+
+               if (ident == RPS_SOCK_FLOW_NO_IDENT)
+                       goto try_rps;
+
                comparator = ((ident & RPS_SOCK_FLOW_USE_QID) ?
                                sock_flow_table->queue_masks.hash_mask :
                                sock_flow_table->cpu_masks.hash_mask);
@@ -4372,8 +4395,21 @@ static int get_rps_cpu(struct net_device *dev, struct 
sk_buff *skb,
                 * CPU. Proceed accordingly.
                 */
                if (ident & RPS_SOCK_FLOW_USE_QID) {
+                       u16 dqid, gqid;
+
                        /* A queue identifier is in the sock_flow_table entry */
 
+                       gqid = ident & sock_flow_table->queue_masks.mask;
+                       dqid = netdev_rx_gqid_to_dqid(dev, gqid);
+
+                       /* rflow has desired receive qid. Just set the qid in
+                        * HW and return to use current CPU. Note that we
+                        * don't consider OOO in this case.
+                        */
+                       rflow = set_rps_qid(dev, skb, rflow, dqid);
+
+                       *rflowp = rflow;
+
                        /* Don't use aRFS to set CPU in this case, skip to
                         * trying RPS
                         */
-- 
2.25.1

Reply via email to