From: Xuan Zhuo <xuanzhuo@linux.alibaba.com> Date: 2021-01-21 13:52:09
v3:
Optimized code
v2:
1. add priv_flags IFF_TX_SKB_NO_LINEAR instead of netdev_feature
2. split the patch to three:
a. add priv_flags IFF_TX_SKB_NO_LINEAR
b. virtio net add priv_flags IFF_TX_SKB_NO_LINEAR
c. When there is support this flag, construct skb without linear space
3. use ERR_PTR() and PTR_ERR() to handle the err
v1 message log:
---------------
This patch is used to construct skb based on page to save memory copy
overhead.
This has one problem:
We construct the skb by fill the data page as a frag into the skb. In
this way, the linear space is empty, and the header information is also
in the frag, not in the linear space, which is not allowed for some
network cards. For example, Mellanox Technologies MT27710 Family
[ConnectX-4 Lx] will get the following error message:
mlx5_core 0000:3b:00.1 eth1: Error cqe on cqn 0x817, ci 0x8, qn 0x1dbb, opcode 0xd, syndrome 0x1, vendor syndrome 0x68
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000030: 00 00 00 00 60 10 68 01 0a 00 1d bb 00 0f 9f d2
WQE DUMP: WQ size 1024 WQ cur size 0, WQE index 0xf, len: 64
00000000: 00 00 0f 0a 00 1d bb 03 00 00 00 08 00 00 00 00
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000020: 00 00 00 2b 00 08 00 00 00 00 00 05 9e e3 08 00
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
mlx5_core 0000:3b:00.1 eth1: ERR CQE on SQ: 0x1dbb
I also tried to use build_skb to construct skb, but because of the
existence of skb_shinfo, it must be behind the linear space, so this
method is not working. We can't put skb_shinfo on desc->addr, it will be
exposed to users, this is not safe.
Finally, I added a feature NETIF_F_SKB_NO_LINEAR to identify whether the
network card supports the header information of the packet in the frag
and not in the linear space.
---------------- Performance Testing ------------
The test environment is Aliyun ECS server.
Test cmd:
xdpsock-ieth0-t-S-s<msgsize>
Test result data:
size 64 512 1024 1500
copy 1916747 1775988 1600203 1440054
page 1974058 1953655 1945463 1904478
percent 3.0% 10.0% 21.58% 32.3%
Xuan Zhuo (3):
net: add priv_flags for allow tx skb without linear
virtio-net: support IFF_TX_SKB_NO_LINEAR
xsk: build skb by page
drivers/net/virtio_net.c | 3 +-
include/linux/netdevice.h | 3 ++
net/xdp/xsk.c | 104 ++++++++++++++++++++++++++++++++++++++--------
3 files changed, 91 insertions(+), 19 deletions(-)
--
1.8.3.1
From: Xuan Zhuo <xuanzhuo@linux.alibaba.com> Date: 2021-01-21 13:49:12
Virtio net supports the case where the skb linear space is empty, so add
priv_flags.
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
---
drivers/net/virtio_net.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
@@ -2972,7 +2972,8 @@ static int virtnet_probe(struct virtio_device *vdev)return-ENOMEM;/* Set up network device as normal. */-dev->priv_flags|=IFF_UNICAST_FLT|IFF_LIVE_ADDR_CHANGE;+dev->priv_flags|=IFF_UNICAST_FLT|IFF_LIVE_ADDR_CHANGE|+IFF_TX_SKB_NO_LINEAR;dev->netdev_ops=&virtnet_netdev;dev->features=NETIF_F_HIGHDMA;
From: Xuan Zhuo <xuanzhuo@linux.alibaba.com> Date: 2021-01-21 13:50:58
This patch is used to construct skb based on page to save memory copy
overhead.
This function is implemented based on IFF_TX_SKB_NO_LINEAR. Only the
network card priv_flags supports IFF_TX_SKB_NO_LINEAR will use page to
directly construct skb. If this feature is not supported, it is still
necessary to copy data to construct skb.
---------------- Performance Testing ------------
The test environment is Aliyun ECS server.
Test cmd:
@@ -446,43 +527,30 @@ static int xsk_generic_xmit(struct sock *sk)gotoout;while(xskq_cons_peek_desc(xs->tx,&desc,xs->pool)){-char*buffer;-u64addr;-u32len;-if(max_batch--==0){err=-EAGAIN;gotoout;}-len=desc.len;-skb=sock_alloc_send_skb(sk,len,1,&err);-if(unlikely(!skb))+skb=xsk_build_skb(xs,&desc);+if(IS_ERR(skb)){+err=PTR_ERR(skb);gotoout;+}-skb_put(skb,len);-addr=desc.addr;-buffer=xsk_buff_raw_get_data(xs->pool,addr);-err=skb_store_bits(skb,0,buffer,len);/* This is the backpressure mechanism for the Tx path.*Reservespaceinthecompletionqueueandonlyproceed*ifthereisspaceinit.Thisavoidshavingtoimplement*anybufferingintheTxpath.*/spin_lock_irqsave(&xs->pool->cq_lock,flags);-if(unlikely(err)||xskq_prod_reserve(xs->pool->cq)){+if(xskq_prod_reserve(xs->pool->cq)){spin_unlock_irqrestore(&xs->pool->cq_lock,flags);kfree_skb(skb);gotoout;}spin_unlock_irqrestore(&xs->pool->cq_lock,flags);-skb->dev=xs->dev;-skb->priority=sk->sk_priority;-skb->mark=sk->sk_mark;-skb_shinfo(skb)->destructor_arg=(void*)(long)desc.addr;-skb->destructor=xsk_destruct_skb;-err=__dev_direct_xmit(skb,xs->queue_id);if(err==NETDEV_TX_BUSY){/* Tell user-space to retry the send */
From: Magnus Karlsson <hidden> Date: 2021-01-21 15:19:05
On Thu, Jan 21, 2021 at 2:51 PM Xuan Zhuo [off-list ref] wrote:
This patch is used to construct skb based on page to save memory copy
overhead.
This function is implemented based on IFF_TX_SKB_NO_LINEAR. Only the
network card priv_flags supports IFF_TX_SKB_NO_LINEAR will use page to
directly construct skb. If this feature is not supported, it is still
necessary to copy data to construct skb.
---------------- Performance Testing ------------
The test environment is Aliyun ECS server.
Test cmd:
Applied, compiled and tried it out on my NIC that does not support
IFF_TX_SKB_NO_LINEAR and it works fine. Thank you Xuan for all your
efforts. Appreciated.
Now it would be nice if we could get some physical NIC drivers to
support this too. Some probably already do and can just set the bit,
while others need some modifications to support this.
Acked-by: Magnus Karlsson <magnus.karlsson@intel.com>
@@ -446,43 +527,30 @@ static int xsk_generic_xmit(struct sock *sk)gotoout;while(xskq_cons_peek_desc(xs->tx,&desc,xs->pool)){-char*buffer;-u64addr;-u32len;-if(max_batch--==0){err=-EAGAIN;gotoout;}-len=desc.len;-skb=sock_alloc_send_skb(sk,len,1,&err);-if(unlikely(!skb))+skb=xsk_build_skb(xs,&desc);+if(IS_ERR(skb)){+err=PTR_ERR(skb);gotoout;+}-skb_put(skb,len);-addr=desc.addr;-buffer=xsk_buff_raw_get_data(xs->pool,addr);-err=skb_store_bits(skb,0,buffer,len);/* This is the backpressure mechanism for the Tx path.*Reservespaceinthecompletionqueueandonlyproceed*ifthereisspaceinit.Thisavoidshavingtoimplement*anybufferingintheTxpath.*/spin_lock_irqsave(&xs->pool->cq_lock,flags);-if(unlikely(err)||xskq_prod_reserve(xs->pool->cq)){+if(xskq_prod_reserve(xs->pool->cq)){spin_unlock_irqrestore(&xs->pool->cq_lock,flags);kfree_skb(skb);gotoout;}spin_unlock_irqrestore(&xs->pool->cq_lock,flags);-skb->dev=xs->dev;-skb->priority=sk->sk_priority;-skb->mark=sk->sk_mark;-skb_shinfo(skb)->destructor_arg=(void*)(long)desc.addr;-skb->destructor=xsk_destruct_skb;-err=__dev_direct_xmit(skb,xs->queue_id);if(err==NETDEV_TX_BUSY){/* Tell user-space to retry the send */--
From: Eric Dumazet <hidden> Date: 2021-01-21 15:43:44
On 1/21/21 2:47 PM, Xuan Zhuo wrote:
quoted hunk
This patch is used to construct skb based on page to save memory copy
overhead.
This function is implemented based on IFF_TX_SKB_NO_LINEAR. Only the
network card priv_flags supports IFF_TX_SKB_NO_LINEAR will use page to
directly construct skb. If this feature is not supported, it is still
necessary to copy data to construct skb.
---------------- Performance Testing ------------
The test environment is Aliyun ECS server.
Test cmd:
From: Alexander Lobakin <hidden> Date: 2021-01-22 11:49:43
From: Eric Dumazet <redacted>
Date: Thu, 21 Jan 2021 16:41:33 +0100
On 1/21/21 2:47 PM, Xuan Zhuo wrote:
quoted
This patch is used to construct skb based on page to save memory copy
overhead.
This function is implemented based on IFF_TX_SKB_NO_LINEAR. Only the
network card priv_flags supports IFF_TX_SKB_NO_LINEAR will use page to
directly construct skb. If this feature is not supported, it is still
necessary to copy data to construct skb.
---------------- Performance Testing ------------
The test environment is Aliyun ECS server.
Test cmd:
From: Alexander Lobakin <hidden> Date: 2021-01-22 11:57:31
From: Alexander Lobakin <redacted>
Date: Fri, 22 Jan 2021 11:47:45 +0000
From: Eric Dumazet <redacted>
Date: Thu, 21 Jan 2021 16:41:33 +0100
quoted
On 1/21/21 2:47 PM, Xuan Zhuo wrote:
quoted
This patch is used to construct skb based on page to save memory copy
overhead.
This function is implemented based on IFF_TX_SKB_NO_LINEAR. Only the
network card priv_flags supports IFF_TX_SKB_NO_LINEAR will use page to
directly construct skb. If this feature is not supported, it is still
necessary to copy data to construct skb.
---------------- Performance Testing ------------
The test environment is Aliyun ECS server.
Test cmd:
This is not the truesize, unfortunately.
We need to account for the number of pages, not number of bytes.
The easiest solution is:
skb->truesize += PAGE_SIZE * i;
i would be equal to skb_shinfo(skb)->nr_frags after exiting the loop.
Oops, pls ignore this. I forgot that XSK buffers are not
"one per page".
We need to count the number of pages manually and then do
skb->truesize += PAGE_SIZE * npages;
Right.
From: Magnus Karlsson <hidden> Date: 2021-01-22 12:21:07
On Fri, Jan 22, 2021 at 12:57 PM Alexander Lobakin [off-list ref] wrote:
From: Alexander Lobakin <redacted>
Date: Fri, 22 Jan 2021 11:47:45 +0000
quoted
From: Eric Dumazet <redacted>
Date: Thu, 21 Jan 2021 16:41:33 +0100
quoted
On 1/21/21 2:47 PM, Xuan Zhuo wrote:
quoted
This patch is used to construct skb based on page to save memory copy
overhead.
This function is implemented based on IFF_TX_SKB_NO_LINEAR. Only the
network card priv_flags supports IFF_TX_SKB_NO_LINEAR will use page to
directly construct skb. If this feature is not supported, it is still
necessary to copy data to construct skb.
---------------- Performance Testing ------------
The test environment is Aliyun ECS server.
Test cmd:
This is not the truesize, unfortunately.
We need to account for the number of pages, not number of bytes.
The easiest solution is:
skb->truesize += PAGE_SIZE * i;
i would be equal to skb_shinfo(skb)->nr_frags after exiting the loop.
Oops, pls ignore this. I forgot that XSK buffers are not
"one per page".
We need to count the number of pages manually and then do
skb->truesize += PAGE_SIZE * npages;
Right.
There are two possible packet buffer (chunks) sizes in a umem, 2K and
4K on a system with a PAGE_SIZE of 4K. If I remember correctly, and
please correct me if wrong, truesize is used for memory accounting.
But in this code, no kernel memory has been allocated (apart from the
skb). The page is just a part of the umem that has been already
allocated beforehand and by user-space in this case. So what should
truesize be in this case? Do we add 0, chunk_size * i, or the
complicated case of counting exactly how many 4K pages that are used
when the chunk_size is 2K, as two chunks could occupy the same page,
or just the upper bound of PAGE_SIZE * i that is likely a good
approximation in most cases? Just note that there might be other uses
of truesize that I am unaware of that could impact this choice.
From: Alexander Lobakin <hidden> Date: 2021-01-22 12:30:26
From: Alexander Lobakin <redacted>
Date: Fri, 22 Jan 2021 11:55:35 +0000
From: Alexander Lobakin <redacted>
Date: Fri, 22 Jan 2021 11:47:45 +0000
quoted
From: Eric Dumazet <redacted>
Date: Thu, 21 Jan 2021 16:41:33 +0100
quoted
On 1/21/21 2:47 PM, Xuan Zhuo wrote:
quoted
This patch is used to construct skb based on page to save memory copy
overhead.
This function is implemented based on IFF_TX_SKB_NO_LINEAR. Only the
network card priv_flags supports IFF_TX_SKB_NO_LINEAR will use page to
directly construct skb. If this feature is not supported, it is still
necessary to copy data to construct skb.
---------------- Performance Testing ------------
The test environment is Aliyun ECS server.
Test cmd:
Also,
maybe we should allocate it with NET_SKB_PAD so NIC drivers could
use some reserved space?
skb = sock_alloc_send_skb(&xs->sk, NET_SKB_PAD, 1, &err);
...
skb_reserve(skb, NET_SKB_PAD);
Eric, what do you think?
This is not the truesize, unfortunately.
We need to account for the number of pages, not number of bytes.
The easiest solution is:
skb->truesize += PAGE_SIZE * i;
i would be equal to skb_shinfo(skb)->nr_frags after exiting the loop.
Oops, pls ignore this. I forgot that XSK buffers are not
"one per page".
We need to count the number of pages manually and then do
skb->truesize += PAGE_SIZE * npages;
Right.
From: Alexander Lobakin <hidden> Date: 2021-01-22 12:40:49
From: Magnus Karlsson <redacted>
Date: Fri, 22 Jan 2021 13:18:47 +0100
On Fri, Jan 22, 2021 at 12:57 PM Alexander Lobakin [off-list ref] wrote:
quoted
From: Alexander Lobakin <redacted>
Date: Fri, 22 Jan 2021 11:47:45 +0000
quoted
From: Eric Dumazet <redacted>
Date: Thu, 21 Jan 2021 16:41:33 +0100
quoted
On 1/21/21 2:47 PM, Xuan Zhuo wrote:
quoted
This patch is used to construct skb based on page to save memory copy
overhead.
This function is implemented based on IFF_TX_SKB_NO_LINEAR. Only the
network card priv_flags supports IFF_TX_SKB_NO_LINEAR will use page to
directly construct skb. If this feature is not supported, it is still
necessary to copy data to construct skb.
---------------- Performance Testing ------------
The test environment is Aliyun ECS server.
Test cmd:
This is not the truesize, unfortunately.
We need to account for the number of pages, not number of bytes.
The easiest solution is:
skb->truesize += PAGE_SIZE * i;
i would be equal to skb_shinfo(skb)->nr_frags after exiting the loop.
Oops, pls ignore this. I forgot that XSK buffers are not
"one per page".
We need to count the number of pages manually and then do
skb->truesize += PAGE_SIZE * npages;
Right.
There are two possible packet buffer (chunks) sizes in a umem, 2K and
4K on a system with a PAGE_SIZE of 4K. If I remember correctly, and
please correct me if wrong, truesize is used for memory accounting.
But in this code, no kernel memory has been allocated (apart from the
skb). The page is just a part of the umem that has been already
allocated beforehand and by user-space in this case. So what should
truesize be in this case? Do we add 0, chunk_size * i, or the
complicated case of counting exactly how many 4K pages that are used
when the chunk_size is 2K, as two chunks could occupy the same page,
or just the upper bound of PAGE_SIZE * i that is likely a good
approximation in most cases? Just note that there might be other uses
of truesize that I am unaware of that could impact this choice.
Truesize is "what amount of memory does this skb occupy with all its
fragments, linear space and struct sk_buff itself". The closest it
will be to the actual value, the better.
In this case, I think adding of chunk_size * i would be enough.
(PAGE_SIZE * i can be overwhelming when chunk_size is 2K, especially
for setups with PAGE_SIZE > SZ_4K)
From: Magnus Karlsson <hidden> Date: 2021-01-22 12:56:12
On Fri, Jan 22, 2021 at 1:39 PM Alexander Lobakin [off-list ref] wrote:
From: Magnus Karlsson <redacted>
Date: Fri, 22 Jan 2021 13:18:47 +0100
quoted
On Fri, Jan 22, 2021 at 12:57 PM Alexander Lobakin [off-list ref] wrote:
quoted
From: Alexander Lobakin <redacted>
Date: Fri, 22 Jan 2021 11:47:45 +0000
quoted
From: Eric Dumazet <redacted>
Date: Thu, 21 Jan 2021 16:41:33 +0100
quoted
On 1/21/21 2:47 PM, Xuan Zhuo wrote:
quoted
This patch is used to construct skb based on page to save memory copy
overhead.
This function is implemented based on IFF_TX_SKB_NO_LINEAR. Only the
network card priv_flags supports IFF_TX_SKB_NO_LINEAR will use page to
directly construct skb. If this feature is not supported, it is still
necessary to copy data to construct skb.
---------------- Performance Testing ------------
The test environment is Aliyun ECS server.
Test cmd:
This is not the truesize, unfortunately.
We need to account for the number of pages, not number of bytes.
The easiest solution is:
skb->truesize += PAGE_SIZE * i;
i would be equal to skb_shinfo(skb)->nr_frags after exiting the loop.
Oops, pls ignore this. I forgot that XSK buffers are not
"one per page".
We need to count the number of pages manually and then do
skb->truesize += PAGE_SIZE * npages;
Right.
There are two possible packet buffer (chunks) sizes in a umem, 2K and
4K on a system with a PAGE_SIZE of 4K. If I remember correctly, and
please correct me if wrong, truesize is used for memory accounting.
But in this code, no kernel memory has been allocated (apart from the
skb). The page is just a part of the umem that has been already
allocated beforehand and by user-space in this case. So what should
truesize be in this case? Do we add 0, chunk_size * i, or the
complicated case of counting exactly how many 4K pages that are used
when the chunk_size is 2K, as two chunks could occupy the same page,
or just the upper bound of PAGE_SIZE * i that is likely a good
approximation in most cases? Just note that there might be other uses
of truesize that I am unaware of that could impact this choice.
Truesize is "what amount of memory does this skb occupy with all its
fragments, linear space and struct sk_buff itself". The closest it
will be to the actual value, the better.
In this case, I think adding of chunk_size * i would be enough.
Sounds like a good approximation to me.
(PAGE_SIZE * i can be overwhelming when chunk_size is 2K, especially
for setups with PAGE_SIZE > SZ_4K)
You are right. That would be quite horrible on a system with a page size of 64K.