Skip to content

Commit 5f05e25

Browse files
ameryhungKernel Patches Daemon
authored andcommitted
bpf: Support pulling non-linear xdp data
Add kfunc, bpf_xdp_pull_data(), to support pulling data from xdp fragments. Similar to bpf_skb_pull_data(), bpf_xdp_pull_data() makes the first len bytes of data directly readable and writable in bpf programs. If the "len" argument is larger than the linear data size, data in fragments will be copied to the linear data area when there is enough room. Specifically, the kfunc will try to use the tailroom first. When the tailroom is not enough, metadata and data will be shifted down to make room for pulling data. A use case of the kfunc is to decapsulate headers residing in xdp fragments. It is possible for a NIC driver to place headers in xdp fragments. To keep using direct packet access for parsing and decapsulating headers, users can pull headers into the linear data area by calling bpf_xdp_pull_data() and then pop the header with bpf_xdp_adjust_head(). Reviewed-by: Jakub Kicinski <[email protected]> Signed-off-by: Amery Hung <[email protected]>
1 parent 8d8a2e2 commit 5f05e25

File tree

1 file changed

+91
-0
lines changed

1 file changed

+91
-0
lines changed

net/core/filter.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12216,6 +12216,96 @@ __bpf_kfunc int bpf_sock_ops_enable_tx_tstamp(struct bpf_sock_ops_kern *skops,
1221612216
return 0;
1221712217
}
1221812218

12219+
/**
12220+
* bpf_xdp_pull_data() - Pull in non-linear xdp data.
12221+
* @x: &xdp_md associated with the XDP buffer
12222+
* @len: length of data to be made directly accessible in the linear part
12223+
*
12224+
* Pull in data in case the XDP buffer associated with @x is non-linear and
12225+
* not all @len are in the linear data area.
12226+
*
12227+
* Direct packet access allows reading and writing linear XDP data through
12228+
* packet pointers (i.e., &xdp_md->data + offsets). The amount of data which
12229+
* ends up in the linear part of the xdp_buff depends on the NIC and its
12230+
* configuration. When a frag-capable XDP program wants to directly access
12231+
* headers that may be in the non-linear area, call this kfunc to make sure
12232+
* the data is available in the linear area. Alternatively, use dynptr or
12233+
* bpf_xdp_{load,store}_bytes() to access data without pulling.
12234+
*
12235+
* This kfunc can also be used with bpf_xdp_adjust_head() to decapsulate
12236+
* headers in the non-linear data area.
12237+
*
12238+
* A call to this kfunc may reduce headroom. If there is not enough tailroom
12239+
* in the linear data area, metadata and data will be shifted down.
12240+
*
12241+
* A call to this kfunc is susceptible to change the buffer geometry.
12242+
* Therefore, at load time, all checks on pointers previously done by the
12243+
* verifier are invalidated and must be performed again, if the kfunc is used
12244+
* in combination with direct packet access.
12245+
*
12246+
* Return:
12247+
* * %0 - success
12248+
* * %-EINVAL - invalid len
12249+
*/
12250+
__bpf_kfunc int bpf_xdp_pull_data(struct xdp_md *x, u32 len)
12251+
{
12252+
struct xdp_buff *xdp = (struct xdp_buff *)x;
12253+
struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp);
12254+
int i, delta, shift, headroom, tailroom, n_frags_free = 0;
12255+
void *data_hard_end = xdp_data_hard_end(xdp);
12256+
int data_len = xdp->data_end - xdp->data;
12257+
void *start;
12258+
12259+
if (len <= data_len)
12260+
return 0;
12261+
12262+
if (unlikely(len > xdp_get_buff_len(xdp)))
12263+
return -EINVAL;
12264+
12265+
start = xdp_data_meta_unsupported(xdp) ? xdp->data : xdp->data_meta;
12266+
12267+
headroom = start - xdp->data_hard_start - sizeof(struct xdp_frame);
12268+
tailroom = data_hard_end - xdp->data_end;
12269+
12270+
delta = len - data_len;
12271+
if (unlikely(delta > tailroom + headroom))
12272+
return -EINVAL;
12273+
12274+
shift = delta - tailroom;
12275+
if (shift > 0) {
12276+
memmove(start - shift, start, xdp->data_end - start);
12277+
12278+
xdp->data_meta -= shift;
12279+
xdp->data -= shift;
12280+
xdp->data_end -= shift;
12281+
}
12282+
12283+
for (i = 0; i < sinfo->nr_frags && delta; i++) {
12284+
skb_frag_t *frag = &sinfo->frags[i];
12285+
u32 shrink = min_t(u32, delta, skb_frag_size(frag));
12286+
12287+
memcpy(xdp->data_end, skb_frag_address(frag), shrink);
12288+
12289+
xdp->data_end += shrink;
12290+
sinfo->xdp_frags_size -= shrink;
12291+
delta -= shrink;
12292+
if (bpf_xdp_shrink_data(xdp, frag, shrink, false))
12293+
n_frags_free++;
12294+
}
12295+
12296+
if (unlikely(n_frags_free)) {
12297+
memmove(sinfo->frags, sinfo->frags + n_frags_free,
12298+
(sinfo->nr_frags - n_frags_free) * sizeof(skb_frag_t));
12299+
12300+
sinfo->nr_frags -= n_frags_free;
12301+
12302+
if (!sinfo->nr_frags)
12303+
xdp_buff_clear_frags_flag(xdp);
12304+
}
12305+
12306+
return 0;
12307+
}
12308+
1221912309
__bpf_kfunc_end_defs();
1222012310

1222112311
int bpf_dynptr_from_skb_rdonly(struct __sk_buff *skb, u64 flags,
@@ -12243,6 +12333,7 @@ BTF_KFUNCS_END(bpf_kfunc_check_set_skb_meta)
1224312333

1224412334
BTF_KFUNCS_START(bpf_kfunc_check_set_xdp)
1224512335
BTF_ID_FLAGS(func, bpf_dynptr_from_xdp)
12336+
BTF_ID_FLAGS(func, bpf_xdp_pull_data)
1224612337
BTF_KFUNCS_END(bpf_kfunc_check_set_xdp)
1224712338

1224812339
BTF_KFUNCS_START(bpf_kfunc_check_set_sock_addr)

0 commit comments

Comments
 (0)