Skip to content

Commit d9ff286

Browse files
Eric Dumazetborkmann
authored andcommitted
bpf: allow BPF programs access skb_shared_info->gso_segs field
This adds the ability to read gso_segs from a BPF program. v3: Use BPF_REG_AX instead of BPF_REG_TMP for the temporary register, as suggested by Martin. v2: refined Eddie Hao patch to address Alexei feedback. Signed-off-by: Eric Dumazet <[email protected]> Cc: Eddie Hao <[email protected]> Cc: Martin KaFai Lau <[email protected]> Acked-by: Martin KaFai Lau <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]>
1 parent 866e6ac commit d9ff286

File tree

4 files changed

+59
-0
lines changed

4 files changed

+59
-0
lines changed

include/uapi/linux/bpf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2540,6 +2540,7 @@ struct __sk_buff {
25402540
__bpf_md_ptr(struct bpf_flow_keys *, flow_keys);
25412541
__u64 tstamp;
25422542
__u32 wire_len;
2543+
__u32 gso_segs;
25432544
};
25442545

25452546
struct bpf_tunnel_key {

net/core/filter.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6700,6 +6700,27 @@ static u32 bpf_convert_ctx_access(enum bpf_access_type type,
67006700
target_size));
67016701
break;
67026702

6703+
case offsetof(struct __sk_buff, gso_segs):
6704+
/* si->dst_reg = skb_shinfo(SKB); */
6705+
#ifdef NET_SKBUFF_DATA_USES_OFFSET
6706+
*insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, head),
6707+
si->dst_reg, si->src_reg,
6708+
offsetof(struct sk_buff, head));
6709+
*insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, end),
6710+
BPF_REG_AX, si->src_reg,
6711+
offsetof(struct sk_buff, end));
6712+
*insn++ = BPF_ALU64_REG(BPF_ADD, si->dst_reg, BPF_REG_AX);
6713+
#else
6714+
*insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, end),
6715+
si->dst_reg, si->src_reg,
6716+
offsetof(struct sk_buff, end));
6717+
#endif
6718+
*insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct skb_shared_info, gso_segs),
6719+
si->dst_reg, si->dst_reg,
6720+
bpf_target_off(struct skb_shared_info,
6721+
gso_segs, 2,
6722+
target_size));
6723+
break;
67036724
case offsetof(struct __sk_buff, wire_len):
67046725
BUILD_BUG_ON(FIELD_SIZEOF(struct qdisc_skb_cb, pkt_len) != 4);
67056726

tools/include/uapi/linux/bpf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2540,6 +2540,7 @@ struct __sk_buff {
25402540
__bpf_md_ptr(struct bpf_flow_keys *, flow_keys);
25412541
__u64 tstamp;
25422542
__u32 wire_len;
2543+
__u32 gso_segs;
25432544
};
25442545

25452546
struct bpf_tunnel_key {

tools/testing/selftests/bpf/test_verifier.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5663,6 +5663,42 @@ static struct bpf_test tests[] = {
56635663
.result = ACCEPT,
56645664
.prog_type = BPF_PROG_TYPE_CGROUP_SKB,
56655665
},
5666+
{
5667+
"read gso_segs from CGROUP_SKB",
5668+
.insns = {
5669+
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
5670+
offsetof(struct __sk_buff, gso_segs)),
5671+
BPF_MOV64_IMM(BPF_REG_0, 0),
5672+
BPF_EXIT_INSN(),
5673+
},
5674+
.result = ACCEPT,
5675+
.prog_type = BPF_PROG_TYPE_CGROUP_SKB,
5676+
},
5677+
{
5678+
"write gso_segs from CGROUP_SKB",
5679+
.insns = {
5680+
BPF_MOV64_IMM(BPF_REG_0, 0),
5681+
BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0,
5682+
offsetof(struct __sk_buff, gso_segs)),
5683+
BPF_MOV64_IMM(BPF_REG_0, 0),
5684+
BPF_EXIT_INSN(),
5685+
},
5686+
.result = REJECT,
5687+
.result_unpriv = REJECT,
5688+
.errstr = "invalid bpf_context access off=164 size=4",
5689+
.prog_type = BPF_PROG_TYPE_CGROUP_SKB,
5690+
},
5691+
{
5692+
"read gso_segs from CLS",
5693+
.insns = {
5694+
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
5695+
offsetof(struct __sk_buff, gso_segs)),
5696+
BPF_MOV64_IMM(BPF_REG_0, 0),
5697+
BPF_EXIT_INSN(),
5698+
},
5699+
.result = ACCEPT,
5700+
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
5701+
},
56665702
{
56675703
"multiple registers share map_lookup_elem result",
56685704
.insns = {

0 commit comments

Comments
 (0)