<div dir="ltr"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">But there is still always 1 dmabuf to 1 socket association (on rx), right?<br></blockquote><div>In practice yes, but my understanding is that such association is only enforced by NIC features such as flow steering.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">So why not have a separate control channel action to say: this socket fd<br>is supposed to receive into this dmabuf fd?<br></blockquote><div> Are you proposing also adding the installation of corresponding flow steering into this action? Or just add checks to make sure the flow steering won't be removed?</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Nov 6, 2023 at 2:59 PM Stanislav Fomichev <<a href="mailto:sdf@google.com" target="_blank">sdf@google.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 11/06, Mina Almasry wrote:<br>
> On Mon, Nov 6, 2023 at 1:59 PM Stanislav Fomichev <<a href="mailto:sdf@google.com" target="_blank">sdf@google.com</a>> wrote:<br>
> ><br>
> > On 11/06, Mina Almasry wrote:<br>
> > > On Mon, Nov 6, 2023 at 11:34 AM David Ahern <<a href="mailto:dsahern@kernel.org" target="_blank">dsahern@kernel.org</a>> wrote:<br>
> > > ><br>
> > > > On 11/6/23 11:47 AM, Stanislav Fomichev wrote:<br>
> > > > > On 11/05, Mina Almasry wrote:<br>
> > > > >> For device memory TCP, we expect the skb headers to be available in host<br>
> > > > >> memory for access, and we expect the skb frags to be in device memory<br>
> > > > >> and unaccessible to the host. We expect there to be no mixing and<br>
> > > > >> matching of device memory frags (unaccessible) with host memory frags<br>
> > > > >> (accessible) in the same skb.<br>
> > > > >><br>
> > > > >> Add a skb->devmem flag which indicates whether the frags in this skb<br>
> > > > >> are device memory frags or not.<br>
> > > > >><br>
> > > > >> __skb_fill_page_desc() now checks frags added to skbs for page_pool_iovs,<br>
> > > > >> and marks the skb as skb->devmem accordingly.<br>
> > > > >><br>
> > > > >> Add checks through the network stack to avoid accessing the frags of<br>
> > > > >> devmem skbs and avoid coalescing devmem skbs with non devmem skbs.<br>
> > > > >><br>
> > > > >> Signed-off-by: Willem de Bruijn <<a href="mailto:willemb@google.com" target="_blank">willemb@google.com</a>><br>
> > > > >> Signed-off-by: Kaiyuan Zhang <<a href="mailto:kaiyuanz@google.com" target="_blank">kaiyuanz@google.com</a>><br>
> > > > >> Signed-off-by: Mina Almasry <<a href="mailto:almasrymina@google.com" target="_blank">almasrymina@google.com</a>><br>
> > > > >><br>
> > > > >> ---<br>
> > > > >>  include/linux/skbuff.h | 14 +++++++-<br>
> > > > >>  include/net/tcp.h      |  5 +--<br>
> > > > >>  net/core/datagram.c    |  6 ++++<br>
> > > > >>  net/core/gro.c         |  5 ++-<br>
> > > > >>  net/core/skbuff.c      | 77 ++++++++++++++++++++++++++++++++++++------<br>
> > > > >>  net/ipv4/tcp.c         |  6 ++++<br>
> > > > >>  net/ipv4/tcp_input.c   | 13 +++++--<br>
> > > > >>  net/ipv4/tcp_output.c  |  5 ++-<br>
> > > > >>  net/packet/af_packet.c |  4 +--<br>
> > > > >>  9 files changed, 115 insertions(+), 20 deletions(-)<br>
> > > > >><br>
> > > > >> diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h<br>
> > > > >> index 1fae276c1353..8fb468ff8115 100644<br>
> > > > >> --- a/include/linux/skbuff.h<br>
> > > > >> +++ b/include/linux/skbuff.h<br>
> > > > >> @@ -805,6 +805,8 @@ typedef unsigned char *sk_buff_data_t;<br>
> > > > >>   *  @csum_level: indicates the number of consecutive checksums found in<br>
> > > > >>   *          the packet minus one that have been verified as<br>
> > > > >>   *          CHECKSUM_UNNECESSARY (max 3)<br>
> > > > >> + *  @devmem: indicates that all the fragments in this skb are backed by<br>
> > > > >> + *          device memory.<br>
> > > > >>   *  @dst_pending_confirm: need to confirm neighbour<br>
> > > > >>   *  @decrypted: Decrypted SKB<br>
> > > > >>   *  @slow_gro: state present at GRO time, slower prepare step required<br>
> > > > >> @@ -991,7 +993,7 @@ struct sk_buff {<br>
> > > > >>  #if IS_ENABLED(CONFIG_IP_SCTP)<br>
> > > > >>      __u8                    csum_not_inet:1;<br>
> > > > >>  #endif<br>
> > > > >> -<br>
> > > > >> +    __u8                    devmem:1;<br>
> > > > >>  #if defined(CONFIG_NET_SCHED) || defined(CONFIG_NET_XGRESS)<br>
> > > > >>      __u16                   tc_index;       /* traffic control index */<br>
> > > > >>  #endif<br>
> > > > >> @@ -1766,6 +1768,12 @@ static inline void skb_zcopy_downgrade_managed(struct sk_buff *skb)<br>
> > > > >>              __skb_zcopy_downgrade_managed(skb);<br>
> > > > >>  }<br>
> > > > >><br>
> > > > >> +/* Return true if frags in this skb are not readable by the host. */<br>
> > > > >> +static inline bool skb_frags_not_readable(const struct sk_buff *skb)<br>
> > > > >> +{<br>
> > > > >> +    return skb->devmem;<br>
> > > > ><br>
> > > > > bikeshedding: should we also rename 'devmem' sk_buff flag to 'not_readable'?<br>
> > > > > It better communicates the fact that the stack shouldn't dereference the<br>
> > > > > frags (because it has 'devmem' fragments or for some other potential<br>
> > > > > future reason).<br>
> > > ><br>
> > > > +1.<br>
> > > ><br>
> > > > Also, the flag on the skb is an optimization - a high level signal that<br>
> > > > one or more frags is in unreadable memory. There is no requirement that<br>
> > > > all of the frags are in the same memory type.<br>
> ><br>
> > David: maybe there should be such a requirement (that they all are<br>
> > unreadable)? Might be easier to support initially; we can relax later<br>
> > on.<br>
> ><br>
> <br>
> Currently devmem == not_readable, and the restriction is that all the<br>
> frags in the same skb must be either all readable or all unreadable<br>
> (all devmem or all non-devmem).<br>
> <br>
> > > The flag indicates that the skb contains all devmem dma-buf memory<br>
> > > specifically, not generic 'not_readable' frags as the comment says:<br>
> > ><br>
> > > + *     @devmem: indicates that all the fragments in this skb are backed by<br>
> > > + *             device memory.<br>
> > ><br>
> > > The reason it's not a generic 'not_readable' flag is because handing<br>
> > > off a generic not_readable skb to the userspace is semantically not<br>
> > > what we're doing. recvmsg() is augmented in this patch series to<br>
> > > return a devmem skb to the user via a cmsg_devmem struct which refers<br>
> > > specifically to the memory in the dma-buf. recvmsg() in this patch<br>
> > > series is not augmented to give any 'not_readable' skb to the<br>
> > > userspace.<br>
> > ><br>
> > > IMHO skb->devmem + an skb_frags_not_readable() as implemented is<br>
> > > correct. If a new type of unreadable skbs are introduced to the stack,<br>
> > > I imagine the stack would implement:<br>
> > ><br>
> > > 1. new header flag: skb->newmem<br>
> > > 2.<br>
> > ><br>
> > > static inline bool skb_frags_not_readable(const struct skb_buff *skb)<br>
> > > {<br>
> > >     return skb->devmem || skb->newmem;<br>
> > > }<br>
> > ><br>
> > > 3. tcp_recvmsg_devmem() would handle skb->devmem skbs is in this patch<br>
> > > series, but tcp_recvmsg_newmem() would handle skb->newmem skbs.<br>
> ><br>
> > You copy it to the userspace in a special way because your frags<br>
> > are page_is_page_pool_iov(). I agree with David, the skb bit is<br>
> > just and optimization.<br>
> ><br>
> > For most of the core stack, it doesn't matter why your skb is not<br>
> > readable. For a few places where it matters (recvmsg?), you can<br>
> > double-check your frags (all or some) with page_is_page_pool_iov.<br>
> ><br>
> <br>
> I see, we can do that then. I.e. make the header flag 'not_readable'<br>
> and check the frags to decide to delegate to tcp_recvmsg_devmem() or<br>
> something else. We can even assume not_readable == devmem because<br>
> currently devmem is the only type of unreadable frag currently.<br>
> <br>
> > Unrelated: we probably need socket to dmabuf association as well (via<br>
> > netlink or something).<br>
> <br>
> Not sure this is possible. The dma-buf is bound to the rx-queue, and<br>
> any packets that land on that rx-queue are bound to that dma-buf,<br>
> regardless of which socket that packet belongs to. So the association<br>
> IMO must be rx-queue to dma-buf, not socket to dma-buf.<br>
<br>
But there is still always 1 dmabuf to 1 socket association (on rx), right?<br>
Because otherwise, there is no way currently to tell, at recvmsg, which<br>
dmabuf the received token belongs to.<br>
<br>
So why not have a separate control channel action to say: this socket fd<br>
is supposed to receive into this dmabuf fd? This action would put<br>
the socket into permanent 'MSG_SOCK_DEVMEM' mode. Maybe you can also<br>
put some checks at the lower level to to enforce this dmabuf<br>
association. (to avoid any potential issues with flow steering)<br>
<br>
We'll still have dmabuf to rx-queue association because of various reasons..<br>
</blockquote></div></div>