lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20200624171749.11927-11-tom@herbertland.com>
Date:   Wed, 24 Jun 2020 10:17:49 -0700
From:   Tom Herbert <tom@...bertland.com>
To:     netdev@...r.kernel.org
Cc:     Tom Herbert <tom@...bertland.com>
Subject: [RFC PATCH 10/11] ptq: Hook up receive side of Per Queue Threads

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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ