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]
Date:   Mon, 06 Dec 2021 09:16:58 -0800
From:   John Fastabend <john.fastabend@...il.com>
To:     Lorenzo Bianconi <lorenzo.bianconi@...hat.com>,
        John Fastabend <john.fastabend@...il.com>
Cc:     Lorenzo Bianconi <lorenzo@...nel.org>, bpf@...r.kernel.org,
        netdev@...r.kernel.org, davem@...emloft.net, kuba@...nel.org,
        ast@...nel.org, daniel@...earbox.net, shayagr@...zon.com,
        dsahern@...nel.org, brouer@...hat.com, echaudro@...hat.com,
        jasowang@...hat.com, alexander.duyck@...il.com, saeed@...nel.org,
        maciej.fijalkowski@...el.com, magnus.karlsson@...el.com,
        tirthendu.sarkar@...el.com, toke@...hat.com
Subject: Re: [PATCH v19 bpf-next 12/23] bpf: add multi-buff support to the
 bpf_xdp_adjust_tail() API

Lorenzo Bianconi wrote:
> > Lorenzo Bianconi wrote:
> > > From: Eelco Chaudron <echaudro@...hat.com>
> > > 
> > > This change adds support for tail growing and shrinking for XDP multi-buff.
> > > 
> > > When called on a multi-buffer packet with a grow request, it will work
> > > on the last fragment of the packet. So the maximum grow size is the
> > > last fragments tailroom, i.e. no new buffer will be allocated.
> > > A XDP mb capable driver is expected to set frag_size in xdp_rxq_info data
> > > structure to notify the XDP core the fragment size. frag_size set to 0 is
> > > interpreted by the XDP core as tail growing is not allowed.
> > > Introduce __xdp_rxq_info_reg utility routine to initialize frag_size field.
> > > 
> > > When shrinking, it will work from the last fragment, all the way down to
> > > the base buffer depending on the shrinking size. It's important to mention
> > > that once you shrink down the fragment(s) are freed, so you can not grow
> > > again to the original size.
> > > 
> > > Acked-by: Jakub Kicinski <kuba@...nel.org>
> > > Co-developed-by: Lorenzo Bianconi <lorenzo@...nel.org>
> > > Signed-off-by: Lorenzo Bianconi <lorenzo@...nel.org>
> > > Signed-off-by: Eelco Chaudron <echaudro@...hat.com>
> > > ---

[...]

pasting full function here to help following along.

+
+static int bpf_xdp_mb_shrink_tail(struct xdp_buff *xdp, int offset)
+{
+	struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp);
+	int i, n_frags_free = 0, len_free = 0;
+
+	if (unlikely(offset > (int)xdp_get_buff_len(xdp) - ETH_HLEN))
+		return -EINVAL;
+
+	for (i = sinfo->nr_frags - 1; i >= 0 && offset > 0; i--) {
+		skb_frag_t *frag = &sinfo->frags[i];
+		int size = skb_frag_size(frag);
+		int shrink = min_t(int, offset, size);
+
+		len_free += shrink;
+		offset -= shrink;
+
+		if (unlikely(size == shrink)) {
+			struct page *page = skb_frag_page(frag);
+
+			__xdp_return(page_address(page), &xdp->rxq->mem,
+				     false, NULL);
+			n_frags_free++;
+		} else {
+			skb_frag_size_set(frag, size - shrink);
+			break;
+		}
+	}
+	sinfo->nr_frags -= n_frags_free;
+	sinfo->xdp_frags_size -= len_free;
+
+	if (unlikely(offset > 0)) {
+		xdp_buff_clear_mb(xdp);
+		xdp->data_end -= offset;
+	}
+
+	return 0;
+}
+

> > 
> > hmm whats the case for offset to != 0? Seems with initial unlikely
> > check and shrinking while walking backwards through the frags it
> > should be zero? Maybe a comment would help?
> 
> Looking at the code, offset can be > 0 here whenever we reduce the mb frame to
> a legacy frame (so whenever offset will move the boundary into the linear
> area).

But still missing if we need to clear the mb bit or not when we shrink down
to a single frag. I think its fine, but worth double checking. As an example
consider I shrink 2k from a 3k pkt with two frags, one full 2k and another
1k extra,

On the first run through,

 i = 1;
 offset = 2k

+	for (i = sinfo->nr_frags - 1; i >= 0 && offset > 0; i--) {
+		skb_frag_t *frag = &sinfo->frags[i];
+		int size = skb_frag_size(frag);
+		int shrink = min_t(int, offset, size);

shrink = 1k; // min_t(int, offset, size) -> size

+
+		len_free += shrink;
+		offset -= shrink;

offset = 1k

+		if (unlikely(size == shrink)) {
+			struct page *page = skb_frag_page(frag);
+
+			__xdp_return(page_address(page), &xdp->rxq->mem,
+				     false, NULL);
+			n_frags_free++;

Will free the frag

Then next run through

i = 0;
offset = 1k;

+		skb_frag_t *frag = &sinfo->frags[i];
+		int size = skb_frag_size(frag);
+		int shrink = min_t(int, offset, size);

shrink = 1k; // min_t(int, offset, size) -> offset

+
+		len_free += shrink;
+		offset -= shrink;

offset = 0k

+
+		if (unlikely(size == shrink)) { ...
+		} else {
+			skb_frag_size_set(frag, size - shrink);
+			break;
+		}

Then later there is the check 'if (unlikely(offset > 0) { ...}', but that
wont hit this case and we shrunk it back to a single frag. Did we want
to clear the mb in this case? I'm not seeing how it harms things to have
the mb bit set just trying to follow code here.

Would offset > 0 indicate we weren't able to shrink the xdp buff enough
for some reason. Need some coffee perhaps.

Thanks,
John

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ