From: Tom Herbert <hidden> Date: 2016-09-29 03:54:42
This patch set introduces transmit flow steering for socketless packets.
The idea is that we record the transmit queues in a flow table that is
indexed by skbuff hash. The flow table entries have two values: the
queue_index and the head cnt of packets from the TX queue. We only allow
a queue to change for a flow if the tail cnt in the TX queue advances
beyond the recorded head cnt. That is the condition that should indicate
that all outstanding packets for the flow have completed transmission so
the queue can change.
Tracking the inflight queue is performed as part of DQL. Two fields are
added to the dql structure: num_enqueue_ops and num_completed_ops.
num_enqueue_ops incremented in dql_queued and num_completed_ops is
incremented in dql_completed by the number of operations completed (a
new argument to the function).
This patch set creates /sys/class/net/eth*/xps_dev_flow_table_cnt
which number of entries in the XPS flow table.
Note that the functionality here is technically best effort (for
instance we don't obtain a lock while processing a flow table entry).
Under high load it is possible that OOO packets can still be generated
due to XPS if two threads are hammering on the same flow table entry.
The assumption of these patches is that OOO packets are not the end of
the world and these should prevent OOO in most common use cases with
XPS.
This is a followup to previous RFC version. Fixes from RFC are:
- Move counters to DQL
- Fixed typo
- Simplified get flow index funtion
- Fixed sysfs flow_table_cnt to properly use DEVICE_ATTR_RW
- Renamed the mechanism
V2:
- Added documentation in scaling.txt and sysfs documentation
- Call skb_tx_hash directly from get_xps_queue. This allows
the socketless transmit flow steering to work properly if
a flow is bouncing between non-XPS and XPS CPUS. (suggested
by Alexander Duyck).
- Added a whold bunch of tested results provided by Rick Jones
(Thanks Rick!)
Tested:
Manually forced all packets to go through the xps_flows path.
Observed that some flows were deferred to change queues because
packets were in flight witht the flow bucket.
Testing done by Rick Jones:
Here is a quick look at performance tests for the result of trying the
prototype fix for the packet reordering problem with VMs sending over
an XPS-configured NIC. In particular, the Emulex/Avago/Broadcom
Skyhawk. The fix was applied to a 4.4 kernel.
Before: 3884 Mbit/s
After: 8897 Mbit/s
That was from a VM on a node with a Skyhawk and 2 E5-2640 processors
to baremetal E5-2640 with a BE3. Physical MTU was 1500, the VM's
vNIC's MTU was 1400. Systems were HPE ProLiants in OS Control Mode
for power management, with the "performance" frequency governor
loaded. An OpenStack Mitaka setup with Distributed Virtual Router.
We had some other NIC types in the setup as well. XPS was also
enabled on the ConnectX3-Pro. It was not enabled on the 82599ES (a
function of the kernel being used, which had it disabled from the
first reports of XPS negatively affecting VM traffic at the beginning
of the year)
Average Mbit/s From NIC type To Bare Metal BE3:
NIC Type,
CPU on VM Host Before After
------------------------------------------------
ConnectX-3 Pro,E5-2670v3 9224 9271
BE3, E5-2640 9016 9022
82599, E5-2640 9192 9003
BCM57840, E5-2640 9213 9153
Skyhawk, E5-2640 3884 8897
For completeness:
Average Mbit/s To NIC type from Bare Metal BE3:
NIC Type,
CPU on VM Host Before After
------------------------------------------------
ConnectX-3 Pro,E5-2670v3 9322 9144
BE3, E5-2640 9074 9017
82599, E5-2640 8670 8564
BCM57840, E5-2640 2468 * 7979
Skyhawk, E5-2640 8897 9269
* This is the Busted bnx2x NIC FW GRO implementation issue. It was
not visible in the "After" because the system was setup to disable
the NIC FW GRO by the time it booted on the fix kernel.
Average Transactions/s Between NIC type and Bare Metal BE3:
NIC Type,
CPU on VM Host Before After
------------------------------------------------
ConnectX-3 Pro,E5-2670v3 12421 12612
BE3, E5-2640 8178 8484
82599, E5-2640 8499 8549
BCM57840, E5-2640 8544 8560
Skyhawk, E5-2640 8537 8701
Tom Herbert (5):
net: Set SW hash in skb_set_hash_from_sk
dql: Add counters for number of queuing and completion operations
net: Add xps_dev_flow_table_cnt
xps_flows: XPS for packets that don't have a socket
xps: Documentation for transmit socketles flow steering
Documentation/ABI/testing/sysfs-class-net | 8 +++
Documentation/networking/scaling.txt | 26 ++++++++
include/linux/dynamic_queue_limits.h | 7 +-
include/linux/netdevice.h | 26 +++++++-
include/net/sock.h | 6 +-
lib/dynamic_queue_limits.c | 3 +-
net/Kconfig | 6 ++
net/core/dev.c | 87 +++++++++++++++++++------
net/core/net-sysfs.c | 103 ++++++++++++++++++++++++++++++
9 files changed, 246 insertions(+), 26 deletions(-)
--
2.9.3
From: Tom Herbert <hidden> Date: 2016-09-29 03:54:46
Use the __skb_set_sw_hash to set the hash in an skbuff from the socket
txhash.
Signed-off-by: Tom Herbert <redacted>
---
include/net/sock.h | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
From: Tom Herbert <hidden> Date: 2016-09-29 03:54:47
Add two new counters to struct dql that are num_enqueue_ops and
num_completed_ops. num_enqueue_ops is incremented by one in each call to
dql_queued. num_enqueue_ops is incremented in dql_completed which takes
an argument indicating number of operations completed. These counters
are only intended for statistics and do not impact the BQL algorithm.
We add a new sysfs entry in byte_queue_limits named inflight_pkts.
This provides the number of packets in flight for the queue by
dql->num_enqueue_ops - dql->num_completed_ops.
Signed-off-by: Tom Herbert <redacted>
---
include/linux/dynamic_queue_limits.h | 7 ++++++-
include/linux/netdevice.h | 2 +-
lib/dynamic_queue_limits.c | 3 ++-
net/core/net-sysfs.c | 14 ++++++++++++++
4 files changed, 23 insertions(+), 3 deletions(-)
@@ -43,6 +43,8 @@ struct dql {unsignedintadj_limit;/* limit + num_completed */unsignedintlast_obj_cnt;/* Count at last queuing */+unsignedintnum_enqueue_ops;/* Number of queue operations */+/* Fields accessed only by completion path (dql_completed) */unsignedintlimit____cacheline_aligned_in_smp;/* Current limit */
@@ -55,6 +57,8 @@ struct dql {unsignedintlowest_slack;/* Lowest slack found */unsignedlongslack_start_time;/* Time slacks seen */+unsignedintnum_completed_ops;/* Number of complete ops */+/* Configuration */unsignedintmax_limit;/* Max limit */unsignedintmin_limit;/* Minimum limit */
@@ -83,6 +87,7 @@ static inline void dql_queued(struct dql *dql, unsigned int count)barrier();dql->num_queued+=count;+dql->num_enqueue_ops++;}/* Returns how many objects can be queued, < 0 indicates over limit. */
@@ -92,7 +97,7 @@ static inline int dql_avail(const struct dql *dql)}/* Record number of completed objects and recalculate the limit. */-voiddql_completed(structdql*dql,unsignedintcount);+voiddql_completed(structdql*dql,unsignedintcount,unsignedintops);/* Reset dql state */voiddql_reset(structdql*dql);
@@ -14,7 +14,7 @@#define AFTER_EQ(A, B) ((int)((A) - (B)) >= 0)/* Records completed count and recalculates the queue limit */-voiddql_completed(structdql*dql,unsignedintcount)+voiddql_completed(structdql*dql,unsignedintcount,unsignedintops){unsignedintinprogress,prev_inprogress,limit;unsignedintovlimit,completed,num_queued;
From: Tom Herbert <hidden> Date: 2016-09-29 03:54:48
Add infrastructure and definitions to create XFS flow tables. This
creates the new sys entry /sys/class/net/eth*/xps_dev_flow_table_cnt
Signed-off-by: Tom Herbert <redacted>
---
include/linux/netdevice.h | 24 +++++++++++++
net/core/net-sysfs.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 113 insertions(+)
From: Tom Herbert <hidden> Date: 2016-09-29 03:54:49
xps_flows maintains a per device flow table that is indexed by the
skbuff hash. The table is only consulted when there is no queue saved in
a transmit socket for an skbuff.
Each entry in the flow table contains a queue index and a queue
pointer. The queue pointer is set when a queue is chosen using a
flow table entry. This pointer is set to the head pointer in the
transmit queue (which is maintained by BQL).
The new function get_xps_flows_index that looks up flows in the
xps_flows table. The entry returned gives the last queue a matching flow
used. The returned queue is compared against the normal XPS queue. If
they are different, then we only switch if the tail pointer in the TX
queue has advanced past the pointer saved in the entry. In this
way OOO should be avoided when XPS wants to use a different queue.
Signed-off-by: Tom Herbert <redacted>
---
net/Kconfig | 6 ++++
net/core/dev.c | 87 +++++++++++++++++++++++++++++++++++++++++++++-------------
2 files changed, 74 insertions(+), 19 deletions(-)
@@ -3210,6 +3210,7 @@ sch_handle_egress(struct sk_buff *skb, int *ret, struct net_device *dev)}#endif /* CONFIG_NET_EGRESS */+/* Must be called with RCU read_lock */staticinlineintget_xps_queue(structnet_device*dev,structsk_buff*skb){#ifdef CONFIG_XPS
@@ -3228,15 +3228,62 @@ static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)elsequeue_index=map->queues[reciprocal_scale(skb_get_hash(skb),map->len)];-if(unlikely(queue_index>=dev->real_num_tx_queues))-queue_index=-1;+if(queue_index>=0&&+likely(queue_index<dev->real_num_tx_queues))+returnqueue_index;}}-rcu_read_unlock();+#endif+returnskb_tx_hash(dev,skb);+}++/* Must be called with RCU read_lock */+staticintget_xps_flows_index(structnet_device*dev,structsk_buff*skb)+{+#ifdef CONFIG_XPS_FLOWS+structxps_dev_flow_table*flow_table;+structxps_dev_flowent;+intqueue_index;+structnetdev_queue*txq;+u32hash;++queue_index=get_xps_queue(dev,skb);+if(queue_index<0)+return-1;++flow_table=rcu_dereference(dev->xps_flow_table);+if(!flow_table)+returnqueue_index;++hash=skb_get_hash(skb);+if(!hash)+returnqueue_index;++ent.v64=flow_table->flows[hash&flow_table->mask].v64;++if(queue_index!=ent.queue_index&&+ent.queue_index>=0&&+ent.queue_index<dev->real_num_tx_queues){+txq=netdev_get_tx_queue(dev,ent.queue_index);+if((int)(txq->dql.num_completed_ops-ent.queue_ptr)<0){+/* The current queue's tail has not advanced beyond the+*lastpacketthatwasenqueuedusingthetableentry.+*Wecan'tchangequeueswithoutriskingOOO.Stick+*withthequeuelistedintheflowtable.+*/+queue_index=ent.queue_index;+}+}++/* Save the updated entry */+txq=netdev_get_tx_queue(dev,queue_index);+ent.queue_index=queue_index;+ent.queue_ptr=txq->dql.num_enqueue_ops;+flow_table->flows[hash&flow_table->mask].v64=ent.v64;returnqueue_index;#else-return-1;+returnget_xps_queue(dev,skb);#endif}
@@ -3244,22 +3291,24 @@ static u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb){structsock*sk=skb->sk;intqueue_index=sk_tx_queue_get(sk);--if(queue_index<0||skb->ooo_okay||-queue_index>=dev->real_num_tx_queues){-intnew_index=get_xps_queue(dev,skb);-if(new_index<0)-new_index=skb_tx_hash(dev,skb);--if(queue_index!=new_index&&sk&&-sk_fullsock(sk)&&-rcu_access_pointer(sk->sk_dst_cache))-sk_tx_queue_set(sk,new_index);--queue_index=new_index;+intnew_index;++if(queue_index<0){+/* Socket did not provide a queue index, try xps_flows */+new_index=get_xps_flows_index(dev,skb);+}elseif(skb->ooo_okay||queue_index>=dev->real_num_tx_queues){+/* Queue index in socket, see if we can find a better one */+new_index=get_xps_queue(dev,skb);+}else{+/* Valid queue in socket and can't send OOO. Just return it */+returnqueue_index;}-returnqueue_index;+if(queue_index!=new_index&&sk&&sk_fullsock(sk)&&+rcu_access_pointer(sk->sk_dst_cache))+sk_tx_queue_set(sk,new_index);++returnnew_index;}structnetdev_queue*netdev_pick_tx(structnet_device*dev,
@@ -251,3 +251,11 @@ Contact: netdev@vger.kernel.org Description: Indicates the unique physical switch identifier of a switch this port belongs to, as a string.++What: /sys/class/net/<iface>/xps_dev_flow_table_cnt+Date: October 2016+KernelVersion: 4.8+Contact: netdev@vger.kernel.org+Description:+ Indicates the number of entries in the XPS socketless flow+ table.
@@ -400,6 +400,26 @@ transport layer is responsible for setting ooo_okay appropriately. TCP, for instance, sets the flag when all data for a connection has been acknowledged.+XPS: Transmit Socketless Flow Steering+======================================++Not all flows have an associated socket in which the transmit queue and+ooo information can be saved. For instance, packets being transmitted over+OVS for VMs do not have a socket that is visible to the kernel. To allow+XPS to be effectively used a flow hash table is employed to save queue and+ooo information for such socketless flows.++The idea is that transmit queues are saved for socketless flows in a+flow table that is indexed by skbuff hash. The flow table entries have+two values: the queue_index and the head cnt of packets from the TX+queue. When a packet is being sent without an associated socket the+hash table is consulted which returns the queue_index to use. The+returned queue is compared to the queue that would be selected by XPS.+If they are are different the XPS queue is selected only if the tail cnt+in the TX queue advances beyond the recorded head cnt. This checks if+sending the packet on the new queue could cause ooo packets for the+flow.+ ==== XPS Configuration XPS is only available if the kconfig symbol CONFIG_XPS is enabled (on by
@@ -409,6 +429,12 @@ queue is configured using the sysfs file entry: /sys/class/net/<dev>/queues/tx-<n>/xps_cpus+Transmit socketless flow steering is enabled by setting the number of+entries in the XPS flow table. This is configured in the sysfs file+entry:++/sys/class/net/<dev>/xps_dev_flow_table_cnt+ == Suggested Configuration For a network device with a single transmission queue, XPS configuration
From: Eric Dumazet <hidden> Date: 2016-09-29 04:54:17
On Wed, 2016-09-28 at 20:54 -0700, Tom Herbert wrote:
xps_flows maintains a per device flow table that is indexed by the
skbuff hash. The table is only consulted when there is no queue saved in
a transmit socket for an skbuff.
Each entry in the flow table contains a queue index and a queue
pointer. The queue pointer is set when a queue is chosen using a
flow table entry. This pointer is set to the head pointer in the
transmit queue (which is maintained by BQL).
The new function get_xps_flows_index that looks up flows in the
xps_flows table. The entry returned gives the last queue a matching flow
used. The returned queue is compared against the normal XPS queue. If
they are different, then we only switch if the tail pointer in the TX
queue has advanced past the pointer saved in the entry. In this
way OOO should be avoided when XPS wants to use a different queue.
There is something I do not understand with this.
If this OOO avoidance is tied to BQL, it means that packets sitting in a
qdisc wont be part of the detection.
So packets of flow X could possibly be queued on multiple qdiscs.
From: Tom Herbert <hidden> Date: 2016-09-29 12:53:50
On Thu, Sep 29, 2016 at 12:54 AM, Eric Dumazet [off-list ref] wrote:
On Wed, 2016-09-28 at 20:54 -0700, Tom Herbert wrote:
quoted
xps_flows maintains a per device flow table that is indexed by the
skbuff hash. The table is only consulted when there is no queue saved in
a transmit socket for an skbuff.
Each entry in the flow table contains a queue index and a queue
pointer. The queue pointer is set when a queue is chosen using a
flow table entry. This pointer is set to the head pointer in the
transmit queue (which is maintained by BQL).
The new function get_xps_flows_index that looks up flows in the
xps_flows table. The entry returned gives the last queue a matching flow
used. The returned queue is compared against the normal XPS queue. If
they are different, then we only switch if the tail pointer in the TX
queue has advanced past the pointer saved in the entry. In this
way OOO should be avoided when XPS wants to use a different queue.
There is something I do not understand with this.
If this OOO avoidance is tied to BQL, it means that packets sitting in a
qdisc wont be part of the detection.
So packets of flow X could possibly be queued on multiple qdiscs.
Hi Eric,
I'm not sure I understand your concern. If packets for flow X can be
queued on multiple qdiscs wouldn't that mean that flow will be subject
to ooo transmission regardless of this patch? In other words here
we're trying to keep packets for the flow in order as they are emitted
from the qdiscs which we assume maintains ordering of packets in a
flow.
Tom
From: Eric Dumazet <hidden> Date: 2016-09-29 13:18:33
On Thu, 2016-09-29 at 08:53 -0400, Tom Herbert wrote:
On Thu, Sep 29, 2016 at 12:54 AM, Eric Dumazet [off-list ref] wrote:
quoted
On Wed, 2016-09-28 at 20:54 -0700, Tom Herbert wrote:
quoted
xps_flows maintains a per device flow table that is indexed by the
skbuff hash. The table is only consulted when there is no queue saved in
a transmit socket for an skbuff.
Each entry in the flow table contains a queue index and a queue
pointer. The queue pointer is set when a queue is chosen using a
flow table entry. This pointer is set to the head pointer in the
transmit queue (which is maintained by BQL).
The new function get_xps_flows_index that looks up flows in the
xps_flows table. The entry returned gives the last queue a matching flow
used. The returned queue is compared against the normal XPS queue. If
they are different, then we only switch if the tail pointer in the TX
queue has advanced past the pointer saved in the entry. In this
way OOO should be avoided when XPS wants to use a different queue.
There is something I do not understand with this.
If this OOO avoidance is tied to BQL, it means that packets sitting in a
qdisc wont be part of the detection.
So packets of flow X could possibly be queued on multiple qdiscs.
Hi Eric,
I'm not sure I understand your concern. If packets for flow X can be
queued on multiple qdiscs wouldn't that mean that flow will be subject
to ooo transmission regardless of this patch? In other words here
we're trying to keep packets for the flow in order as they are emitted
from the qdiscs which we assume maintains ordering of packets in a
flow.
Well, then what this patch series is solving ?
You have a producer of packets running on 8 vcpus in a VM.
Packets are exiting the VM and need to be queued on a mq NIC in the
hypervisor.
Flow X can be scheduled on any of these 8 vcpus, so XPS is currently
selecting different TXQ.
Your patch aims to detect this and steer packets to one TXQ, but not
using a static hash() % num_real_queues (as RSS would have done on a NIC
at RX), but trying to please XPS (as : selecting a queue close to the
CPU producing the packet. VM with one vcpu, and cpu bounded, would
really be happy to not spread packets all over the queues)
Your mechanism relies on counters updated at the time packets are given
to the NIC, not at the time packets are given to the txq (and eventually
sit for a while in the qdisc right before BQL layer)
dev_queue_xmit() is not talking to the device directly...
All I am saying is that the producer/consumer counters you added are not
at the right place.
You tried hard to not change the drivers, by adding something to
existing BQL. But packets can sit in a qdisc for a while...
So you added 2 potential cache lines misses per outgoing packet, but
with no guarantee that OOO are really avoided.
From: Tom Herbert <hidden> Date: 2016-09-29 14:08:16
On Thu, Sep 29, 2016 at 9:18 AM, Eric Dumazet [off-list ref] wrote:
On Thu, 2016-09-29 at 08:53 -0400, Tom Herbert wrote:
quoted
On Thu, Sep 29, 2016 at 12:54 AM, Eric Dumazet [off-list ref] wrote:
quoted
On Wed, 2016-09-28 at 20:54 -0700, Tom Herbert wrote:
quoted
xps_flows maintains a per device flow table that is indexed by the
skbuff hash. The table is only consulted when there is no queue saved in
a transmit socket for an skbuff.
Each entry in the flow table contains a queue index and a queue
pointer. The queue pointer is set when a queue is chosen using a
flow table entry. This pointer is set to the head pointer in the
transmit queue (which is maintained by BQL).
The new function get_xps_flows_index that looks up flows in the
xps_flows table. The entry returned gives the last queue a matching flow
used. The returned queue is compared against the normal XPS queue. If
they are different, then we only switch if the tail pointer in the TX
queue has advanced past the pointer saved in the entry. In this
way OOO should be avoided when XPS wants to use a different queue.
There is something I do not understand with this.
If this OOO avoidance is tied to BQL, it means that packets sitting in a
qdisc wont be part of the detection.
So packets of flow X could possibly be queued on multiple qdiscs.
Hi Eric,
I'm not sure I understand your concern. If packets for flow X can be
queued on multiple qdiscs wouldn't that mean that flow will be subject
to ooo transmission regardless of this patch? In other words here
we're trying to keep packets for the flow in order as they are emitted
from the qdiscs which we assume maintains ordering of packets in a
flow.
Well, then what this patch series is solving ?
It addresses the issue that Rick Jones pointed out was happening with
XPS. When packets are sent for a flow that has no socket and XPS is
enabled then each packet uses the XPS queue based on the running CPU.
Since the thread sending on a flow can be rescheduled on different
CPUs this is creating ooo packets. In this case the ooo is being
caused by interaction with XPS.
You have a producer of packets running on 8 vcpus in a VM.
Packets are exiting the VM and need to be queued on a mq NIC in the
hypervisor.
Flow X can be scheduled on any of these 8 vcpus, so XPS is currently
selecting different TXQ.
Your patch aims to detect this and steer packets to one TXQ, but not
using a static hash() % num_real_queues (as RSS would have done on a NIC
at RX), but trying to please XPS (as : selecting a queue close to the
CPU producing the packet. VM with one vcpu, and cpu bounded, would
really be happy to not spread packets all over the queues)
You're not describing this patch, you're describing how XPS works in
the first place. This patch is done to make socketless packets work
well with XPS. If all you want is a static hash() % num_real_queues
then just disable XPS to get that.
Your mechanism relies on counters updated at the time packets are given
to the NIC, not at the time packets are given to the txq (and eventually
sit for a while in the qdisc right before BQL layer)
dev_queue_xmit() is not talking to the device directly...
All I am saying is that the producer/consumer counters you added are not
at the right place.
You tried hard to not change the drivers, by adding something to
existing BQL. But packets can sit in a qdisc for a while...
But again, this patch is to prevent ooo being caused by an interaction
with XPS. It does not address ooo being caused by qdiscs or VMs, but
then I don't see that as being the issue reported by Rick.
So you added 2 potential cache lines misses per outgoing packet, but
with no guarantee that OOO are really avoided.
From: Eric Dumazet <hidden> Date: 2016-09-29 14:51:37
On Thu, 2016-09-29 at 10:08 -0400, Tom Herbert wrote:
It addresses the issue that Rick Jones pointed out was happening with
XPS. When packets are sent for a flow that has no socket and XPS is
enabled then each packet uses the XPS queue based on the running CPU.
Since the thread sending on a flow can be rescheduled on different
CPUs this is creating ooo packets. In this case the ooo is being
caused by interaction with XPS.
Nope, your patch does not address the problem properly.
I am not sure I want to spend more time explaining the issue.
Lets talk about this in Tokyo next week.
From: Eric Dumazet <hidden> Date: 2016-09-29 15:15:45
On Thu, 2016-09-29 at 07:51 -0700, Eric Dumazet wrote:
On Thu, 2016-09-29 at 10:08 -0400, Tom Herbert wrote:
quoted
It addresses the issue that Rick Jones pointed out was happening with
XPS. When packets are sent for a flow that has no socket and XPS is
enabled then each packet uses the XPS queue based on the running CPU.
Since the thread sending on a flow can be rescheduled on different
CPUs this is creating ooo packets. In this case the ooo is being
caused by interaction with XPS.
Nope, your patch does not address the problem properly.
I am not sure I want to spend more time explaining the issue.
Lets talk about this in Tokyo next week.
Just as a reminder, sorry to bother you, stating some obvious facts for
both of us. We have public exchanges, so we also need to re-explain how
things work.
Queue selection on xmit happens before we hit the qdisc and its delays.
So when you access txq->dql.num_completed_ops and
txq->dql.num_enqueue_ops you can observe values that do not change for a
while.
Say a thread runs on a VM, and sends 2 packets P1, P2 on the same flow
(skb_get_hash() returns the same value for these 2 packets)
P1 is sent on behalf of CPU 1, we pickup queue txq1, and queue the
packet on its qdisc . Transmit does not happen because of some
constraints like rate limiting or scheduling constraints.
P2 is sent on behalf of CPU 2, we pickup queue txq2, notice that prior
packet chose txq1. We check txq1->dql and decide it is fine to use txq2,
since the dql params of txq1 were not changed yet.
( txq->dql.num_completed_ops == ent.queue_ptr )
Note that in RFS case, we have the guarantee that we observe 'live
queues' since they are the per cpu backlog.
So input_queue_head_incr() and input_queue_tail_incr_save() are
correctly doing the OOO prevention, because a queued packet immediately
changes the state.
So really your patch works if you have no qdisc, or a non congested
qdisc. (Think if P1 is dropped by a full pfifo or pfifo_fast : We really
want to avoid steering P2, P3, ..., PN on this full pfifo while maybe
other txq are idle). Strange attractors are back (check commit
9b462d02d6dd6 )
You could avoid (ab)using BQL with a different method, grabbing
skb->destructor for the packets that are socketless
The hash table would simply track the sum of skb->truesize to allow flow
migration. This would be self contained and not intrusive.
From: Rick Jones <hidden> Date: 2016-09-29 16:35:28
On 09/29/2016 06:18 AM, Eric Dumazet wrote:
Well, then what this patch series is solving ?
You have a producer of packets running on 8 vcpus in a VM.
Packets are exiting the VM and need to be queued on a mq NIC in the
hypervisor.
Flow X can be scheduled on any of these 8 vcpus, so XPS is currently
selecting different TXQ.
Just for completeness, in my testing, the VMs were single-vCPU.
rick jones
From: Tom Herbert <hidden> Date: 2016-09-29 20:32:41
On Thu, Sep 29, 2016 at 11:15 AM, Eric Dumazet [off-list ref] wrote:
On Thu, 2016-09-29 at 07:51 -0700, Eric Dumazet wrote:
quoted
On Thu, 2016-09-29 at 10:08 -0400, Tom Herbert wrote:
quoted
It addresses the issue that Rick Jones pointed out was happening with
XPS. When packets are sent for a flow that has no socket and XPS is
enabled then each packet uses the XPS queue based on the running CPU.
Since the thread sending on a flow can be rescheduled on different
CPUs this is creating ooo packets. In this case the ooo is being
caused by interaction with XPS.
Nope, your patch does not address the problem properly.
I am not sure I want to spend more time explaining the issue.
Lets talk about this in Tokyo next week.
Just as a reminder, sorry to bother you, stating some obvious facts for
both of us. We have public exchanges, so we also need to re-explain how
things work.
Queue selection on xmit happens before we hit the qdisc and its delays.
So when you access txq->dql.num_completed_ops and
txq->dql.num_enqueue_ops you can observe values that do not change for a
while.
Say a thread runs on a VM, and sends 2 packets P1, P2 on the same flow
(skb_get_hash() returns the same value for these 2 packets)
P1 is sent on behalf of CPU 1, we pickup queue txq1, and queue the
packet on its qdisc . Transmit does not happen because of some
constraints like rate limiting or scheduling constraints.
P2 is sent on behalf of CPU 2, we pickup queue txq2, notice that prior
packet chose txq1. We check txq1->dql and decide it is fine to use txq2,
since the dql params of txq1 were not changed yet.
( txq->dql.num_completed_ops == ent.queue_ptr )
Note that in RFS case, we have the guarantee that we observe 'live
queues' since they are the per cpu backlog.
So input_queue_head_incr() and input_queue_tail_incr_save() are
correctly doing the OOO prevention, because a queued packet immediately
changes the state.
So really your patch works if you have no qdisc, or a non congested
qdisc. (Think if P1 is dropped by a full pfifo or pfifo_fast : We really
want to avoid steering P2, P3, ..., PN on this full pfifo while maybe
other txq are idle). Strange attractors are back (check commit
9b462d02d6dd6 )
Understood.
You could avoid (ab)using BQL with a different method, grabbing
skb->destructor for the packets that are socketless
The hash table would simply track the sum of skb->truesize to allow flow
migration. This would be self contained and not intrusive.