From: Stanislav Fomichev <stfomichev@gmail.com>
To: Mina Almasry <almasrymina@google.com>
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-doc@vger.kernel.org, kvm@vger.kernel.org,
virtualization@lists.linux.dev, linux-kselftest@vger.kernel.org,
"David S. Miller" <davem@davemloft.net>,
"Eric Dumazet" <edumazet@google.com>,
"Jakub Kicinski" <kuba@kernel.org>,
"Paolo Abeni" <pabeni@redhat.com>,
"Simon Horman" <horms@kernel.org>,
"Donald Hunter" <donald.hunter@gmail.com>,
"Jonathan Corbet" <corbet@lwn.net>,
"Andrew Lunn" <andrew+netdev@lunn.ch>,
"David Ahern" <dsahern@kernel.org>,
"Stefan Hajnoczi" <stefanha@redhat.com>,
"Stefano Garzarella" <sgarzare@redhat.com>,
"Michael S. Tsirkin" <mst@redhat.com>,
"Jason Wang" <jasowang@redhat.com>,
"Xuan Zhuo" <xuanzhuo@linux.alibaba.com>,
"Eugenio Pérez" <eperezma@redhat.com>,
"Shuah Khan" <shuah@kernel.org>,
sdf@fomichev.me, asml.silence@gmail.com, dw@davidwei.uk,
"Jamal Hadi Salim" <jhs@mojatatu.com>,
"Victor Nogueira" <victor@mojatatu.com>,
"Pedro Tammela" <pctammela@mojatatu.com>,
"Kaiyuan Zhang" <kaiyuanz@google.com>
Subject: Re: [PATCH RFC net-next v2 5/6] net: devmem: Implement TX path
Date: Thu, 30 Jan 2025 15:07:44 -0800 [thread overview]
Message-ID: <Z5wGQCZUwiiovJHk@mini-arch> (raw)
In-Reply-To: <20250130211539.428952-6-almasrymina@google.com>
On 01/30, Mina Almasry wrote:
> Augment dmabuf binding to be able to handle TX. Additional to all the RX
> binding, we also create tx_vec needed for the TX path.
>
> Provide API for sendmsg to be able to send dmabufs bound to this device:
>
> - Provide a new dmabuf_tx_cmsg which includes the dmabuf to send from.
> - MSG_ZEROCOPY with SCM_DEVMEM_DMABUF cmsg indicates send from dma-buf.
>
> Devmem is uncopyable, so piggyback off the existing MSG_ZEROCOPY
> implementation, while disabling instances where MSG_ZEROCOPY falls back
> to copying.
>
> We additionally pipe the binding down to the new
> zerocopy_fill_skb_from_devmem which fills a TX skb with net_iov netmems
> instead of the traditional page netmems.
>
> We also special case skb_frag_dma_map to return the dma-address of these
> dmabuf net_iovs instead of attempting to map pages.
>
> Based on work by Stanislav Fomichev <sdf@fomichev.me>. A lot of the meat
> of the implementation came from devmem TCP RFC v1[1], which included the
> TX path, but Stan did all the rebasing on top of netmem/net_iov.
>
> Cc: Stanislav Fomichev <sdf@fomichev.me>
> Signed-off-by: Kaiyuan Zhang <kaiyuanz@google.com>
> Signed-off-by: Mina Almasry <almasrymina@google.com>
>
>
> ---
>
> v2:
> - Remove dmabuf_offset from the dmabuf cmsg.
> - Update zerocopy_fill_skb_from_devmem to interpret the
> iov_base/iter_iov_addr as the offset into the dmabuf to send from
> (Stan).
> - Remove the confusing binding->tx_iter which is not needed if we
> interpret the iov_base/iter_iov_addr as offset into the dmabuf (Stan).
> - Remove check for binding->sgt and binding->sgt->nents in dmabuf
> binding.
> - Simplify the calculation of binding->tx_vec.
> - Check in net_devmem_get_binding that the binding we're returning
> has ifindex matching the sending socket (Willem).
> ---
> include/linux/skbuff.h | 15 +++-
> include/net/sock.h | 1 +
> include/uapi/linux/uio.h | 6 +-
> net/core/datagram.c | 41 ++++++++++-
> net/core/devmem.c | 96 +++++++++++++++++++++++--
> net/core/devmem.h | 42 +++++++++--
> net/core/netdev-genl.c | 65 ++++++++++++++++-
> net/core/skbuff.c | 6 +-
> net/core/sock.c | 8 +++
> net/ipv4/tcp.c | 36 +++++++---
> net/vmw_vsock/virtio_transport_common.c | 3 +-
> 11 files changed, 285 insertions(+), 34 deletions(-)
>
> diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
> index bb2b751d274a..3ff8f568c382 100644
> --- a/include/linux/skbuff.h
> +++ b/include/linux/skbuff.h
> @@ -1711,9 +1711,12 @@ struct ubuf_info *msg_zerocopy_realloc(struct sock *sk, size_t size,
>
> void msg_zerocopy_put_abort(struct ubuf_info *uarg, bool have_uref);
>
> +struct net_devmem_dmabuf_binding;
> +
> int __zerocopy_sg_from_iter(struct msghdr *msg, struct sock *sk,
> struct sk_buff *skb, struct iov_iter *from,
> - size_t length);
> + size_t length,
> + struct net_devmem_dmabuf_binding *binding);
>
> int zerocopy_fill_skb_from_iter(struct sk_buff *skb,
> struct iov_iter *from, size_t length);
> @@ -1721,12 +1724,14 @@ int zerocopy_fill_skb_from_iter(struct sk_buff *skb,
> static inline int skb_zerocopy_iter_dgram(struct sk_buff *skb,
> struct msghdr *msg, int len)
> {
> - return __zerocopy_sg_from_iter(msg, skb->sk, skb, &msg->msg_iter, len);
> + return __zerocopy_sg_from_iter(msg, skb->sk, skb, &msg->msg_iter, len,
> + NULL);
> }
>
> int skb_zerocopy_iter_stream(struct sock *sk, struct sk_buff *skb,
> struct msghdr *msg, int len,
> - struct ubuf_info *uarg);
> + struct ubuf_info *uarg,
> + struct net_devmem_dmabuf_binding *binding);
>
> /* Internal */
> #define skb_shinfo(SKB) ((struct skb_shared_info *)(skb_end_pointer(SKB)))
> @@ -3697,6 +3702,10 @@ static inline dma_addr_t __skb_frag_dma_map(struct device *dev,
> size_t offset, size_t size,
> enum dma_data_direction dir)
> {
> + if (skb_frag_is_net_iov(frag)) {
> + return netmem_to_net_iov(frag->netmem)->dma_addr + offset +
> + frag->offset;
> + }
> return dma_map_page(dev, skb_frag_page(frag),
> skb_frag_off(frag) + offset, size, dir);
> }
> diff --git a/include/net/sock.h b/include/net/sock.h
> index 8036b3b79cd8..09eb918525b6 100644
> --- a/include/net/sock.h
> +++ b/include/net/sock.h
> @@ -1822,6 +1822,7 @@ struct sockcm_cookie {
> u32 tsflags;
> u32 ts_opt_id;
> u32 priority;
> + u32 dmabuf_id;
> };
>
> static inline void sockcm_init(struct sockcm_cookie *sockc,
> diff --git a/include/uapi/linux/uio.h b/include/uapi/linux/uio.h
> index 649739e0c404..866bd5dfe39f 100644
> --- a/include/uapi/linux/uio.h
> +++ b/include/uapi/linux/uio.h
> @@ -38,10 +38,14 @@ struct dmabuf_token {
> __u32 token_count;
> };
>
> +struct dmabuf_tx_cmsg {
> + __u32 dmabuf_id;
> +};
> +
> /*
> * UIO_MAXIOV shall be at least 16 1003.1g (5.4.1.1)
> */
> -
> +
> #define UIO_FASTIOV 8
> #define UIO_MAXIOV 1024
>
> diff --git a/net/core/datagram.c b/net/core/datagram.c
> index f0693707aece..c989606ff58d 100644
> --- a/net/core/datagram.c
> +++ b/net/core/datagram.c
> @@ -63,6 +63,8 @@
> #include <net/busy_poll.h>
> #include <crypto/hash.h>
>
> +#include "devmem.h"
> +
> /*
> * Is a socket 'connection oriented' ?
> */
> @@ -692,9 +694,42 @@ int zerocopy_fill_skb_from_iter(struct sk_buff *skb,
> return 0;
> }
>
> +static int
> +zerocopy_fill_skb_from_devmem(struct sk_buff *skb, struct iov_iter *from,
> + int length,
> + struct net_devmem_dmabuf_binding *binding)
> +{
> + int i = skb_shinfo(skb)->nr_frags;
> + size_t virt_addr, size, off;
> + struct net_iov *niov;
> +
> + while (length && iov_iter_count(from)) {
> + if (i == MAX_SKB_FRAGS)
> + return -EMSGSIZE;
> +
> + virt_addr = (size_t)iter_iov_addr(from);
> + niov = net_devmem_get_niov_at(binding, virt_addr, &off, &size);
> + if (!niov)
> + return -EFAULT;
> +
> + size = min_t(size_t, size, length);
> + size = min_t(size_t, size, iter_iov_len(from));
> +
> + get_netmem(net_iov_to_netmem(niov));
> + skb_add_rx_frag_netmem(skb, i, net_iov_to_netmem(niov), off,
> + size, PAGE_SIZE);
> + iov_iter_advance(from, size);
> + length -= size;
> + i++;
> + }
> +
> + return 0;
> +}
> +
> int __zerocopy_sg_from_iter(struct msghdr *msg, struct sock *sk,
> struct sk_buff *skb, struct iov_iter *from,
> - size_t length)
> + size_t length,
> + struct net_devmem_dmabuf_binding *binding)
> {
> unsigned long orig_size = skb->truesize;
> unsigned long truesize;
> @@ -702,6 +737,8 @@ int __zerocopy_sg_from_iter(struct msghdr *msg, struct sock *sk,
>
> if (msg && msg->msg_ubuf && msg->sg_from_iter)
> ret = msg->sg_from_iter(skb, from, length);
> + else if (unlikely(binding))
> + ret = zerocopy_fill_skb_from_devmem(skb, from, length, binding);
> else
> ret = zerocopy_fill_skb_from_iter(skb, from, length);
>
> @@ -735,7 +772,7 @@ int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *from)
> if (skb_copy_datagram_from_iter(skb, 0, from, copy))
> return -EFAULT;
>
> - return __zerocopy_sg_from_iter(NULL, NULL, skb, from, ~0U);
> + return __zerocopy_sg_from_iter(NULL, NULL, skb, from, ~0U, NULL);
> }
> EXPORT_SYMBOL(zerocopy_sg_from_iter);
>
> diff --git a/net/core/devmem.c b/net/core/devmem.c
> index 20985a570662..796338b1599e 100644
> --- a/net/core/devmem.c
> +++ b/net/core/devmem.c
> @@ -16,6 +16,7 @@
> #include <net/netdev_queues.h>
> #include <net/netdev_rx_queue.h>
> #include <net/page_pool/helpers.h>
> +#include <net/sock.h>
> #include <trace/events/page_pool.h>
>
> #include "devmem.h"
> @@ -64,8 +65,10 @@ void __net_devmem_dmabuf_binding_free(struct net_devmem_dmabuf_binding *binding)
> dma_buf_detach(binding->dmabuf, binding->attachment);
> dma_buf_put(binding->dmabuf);
> xa_destroy(&binding->bound_rxqs);
> + kfree(binding->tx_vec);
> kfree(binding);
> }
> +EXPORT_SYMBOL(__net_devmem_dmabuf_binding_free);
>
> struct net_iov *
> net_devmem_alloc_dmabuf(struct net_devmem_dmabuf_binding *binding)
> @@ -110,6 +113,13 @@ void net_devmem_unbind_dmabuf(struct net_devmem_dmabuf_binding *binding)
> unsigned long xa_idx;
> unsigned int rxq_idx;
>
> + xa_erase(&net_devmem_dmabuf_bindings, binding->id);
> +
> + /* Ensure no tx net_devmem_lookup_dmabuf() are in flight after the
> + * erase.
> + */
> + synchronize_net();
> +
> if (binding->list.next)
> list_del(&binding->list);
>
> @@ -123,8 +133,6 @@ void net_devmem_unbind_dmabuf(struct net_devmem_dmabuf_binding *binding)
> WARN_ON(netdev_rx_queue_restart(binding->dev, rxq_idx));
> }
>
> - xa_erase(&net_devmem_dmabuf_bindings, binding->id);
> -
> net_devmem_dmabuf_binding_put(binding);
> }
>
> @@ -185,8 +193,9 @@ int net_devmem_bind_dmabuf_to_queue(struct net_device *dev, u32 rxq_idx,
> }
>
> struct net_devmem_dmabuf_binding *
> -net_devmem_bind_dmabuf(struct net_device *dev, unsigned int dmabuf_fd,
> - struct netlink_ext_ack *extack)
> +net_devmem_bind_dmabuf(struct net_device *dev,
> + enum dma_data_direction direction,
> + unsigned int dmabuf_fd, struct netlink_ext_ack *extack)
> {
> struct net_devmem_dmabuf_binding *binding;
> static u32 id_alloc_next;
> @@ -229,7 +238,7 @@ net_devmem_bind_dmabuf(struct net_device *dev, unsigned int dmabuf_fd,
> }
>
> binding->sgt = dma_buf_map_attachment_unlocked(binding->attachment,
> - DMA_FROM_DEVICE);
> + direction);
> if (IS_ERR(binding->sgt)) {
> err = PTR_ERR(binding->sgt);
> NL_SET_ERR_MSG(extack, "Failed to map dmabuf attachment");
> @@ -240,13 +249,22 @@ net_devmem_bind_dmabuf(struct net_device *dev, unsigned int dmabuf_fd,
> * binding can be much more flexible than that. We may be able to
> * allocate MTU sized chunks here. Leave that for future work...
> */
> - binding->chunk_pool =
> - gen_pool_create(PAGE_SHIFT, dev_to_node(&dev->dev));
> + binding->chunk_pool = gen_pool_create(PAGE_SHIFT,
> + dev_to_node(&dev->dev));
> if (!binding->chunk_pool) {
> err = -ENOMEM;
> goto err_unmap;
> }
>
> + if (direction == DMA_TO_DEVICE) {
> + binding->tx_vec = kcalloc(dmabuf->size / PAGE_SIZE,
> + sizeof(struct net_iov *), GFP_KERNEL);
Let's make this kvcalloc (and kvfree in the release path)? Otherwise
we'll get ENOMEM here for a reasonably sized dmabufs..
The rest looks good, I'll try to run it on my side today/tomorrow..
next prev parent reply other threads:[~2025-01-30 23:07 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-30 21:15 [PATCH RFC net-next v2 0/6] Device memory TCP TX Mina Almasry
2025-01-30 21:15 ` [PATCH RFC net-next v2 1/6] net: add devmem TCP TX documentation Mina Almasry
2025-01-30 22:59 ` Stanislav Fomichev
2025-01-30 23:22 ` Mina Almasry
2025-01-31 17:39 ` Stanislav Fomichev
2025-01-30 21:15 ` [PATCH RFC net-next v2 2/6] selftests: ncdevmem: Implement devmem TCP TX Mina Almasry
2025-01-30 23:05 ` Stanislav Fomichev
2025-01-30 23:29 ` Mina Almasry
2025-01-31 17:41 ` Stanislav Fomichev
2025-01-31 17:45 ` Stanislav Fomichev
2025-01-30 21:15 ` [PATCH RFC net-next v2 3/6] net: add get_netmem/put_netmem support Mina Almasry
2025-01-30 21:15 ` [PATCH RFC net-next v2 4/6] net: devmem: TCP tx netlink api Mina Almasry
2025-01-31 8:29 ` Simon Horman
2025-01-30 21:15 ` [PATCH RFC net-next v2 5/6] net: devmem: Implement TX path Mina Almasry
2025-01-30 23:07 ` Stanislav Fomichev [this message]
2025-01-31 9:09 ` Simon Horman
2025-01-30 21:15 ` [PATCH RFC net-next v2 6/6] net: devmem: make dmabuf unbinding scheduled work Mina Almasry
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Z5wGQCZUwiiovJHk@mini-arch \
--to=stfomichev@gmail.com \
--cc=almasrymina@google.com \
--cc=andrew+netdev@lunn.ch \
--cc=asml.silence@gmail.com \
--cc=corbet@lwn.net \
--cc=davem@davemloft.net \
--cc=donald.hunter@gmail.com \
--cc=dsahern@kernel.org \
--cc=dw@davidwei.uk \
--cc=edumazet@google.com \
--cc=eperezma@redhat.com \
--cc=horms@kernel.org \
--cc=jasowang@redhat.com \
--cc=jhs@mojatatu.com \
--cc=kaiyuanz@google.com \
--cc=kuba@kernel.org \
--cc=kvm@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=mst@redhat.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=pctammela@mojatatu.com \
--cc=sdf@fomichev.me \
--cc=sgarzare@redhat.com \
--cc=shuah@kernel.org \
--cc=stefanha@redhat.com \
--cc=victor@mojatatu.com \
--cc=virtualization@lists.linux.dev \
--cc=xuanzhuo@linux.alibaba.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.