Skip to content

Commit c249739

Browse files
Alexei Starovoitovdavem330
authored andcommitted
bpf: allow BPF programs access 'protocol' and 'vlan_tci' fields
as a follow on to patch 70006af ("bpf: allow eBPF access skb fields") this patch allows 'protocol' and 'vlan_tci' fields to be accessible from extended BPF programs. The usage of 'protocol', 'vlan_present' and 'vlan_tci' fields is the same as corresponding SKF_AD_PROTOCOL, SKF_AD_VLAN_TAG_PRESENT and SKF_AD_VLAN_TAG accesses in classic BPF. Signed-off-by: Alexei Starovoitov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 9cf7867 commit c249739

3 files changed

Lines changed: 62 additions & 22 deletions

File tree

include/uapi/linux/bpf.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,9 @@ struct __sk_buff {
178178
__u32 pkt_type;
179179
__u32 mark;
180180
__u32 queue_mapping;
181+
__u32 protocol;
182+
__u32 vlan_present;
183+
__u32 vlan_tci;
181184
};
182185

183186
#endif /* _UAPI__LINUX_BPF_H__ */

net/core/filter.c

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,35 @@ static u32 convert_skb_access(int skb_field, int dst_reg, int src_reg,
177177
*insn++ = BPF_LDX_MEM(BPF_H, dst_reg, src_reg,
178178
offsetof(struct sk_buff, queue_mapping));
179179
break;
180+
181+
case SKF_AD_PROTOCOL:
182+
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, protocol) != 2);
183+
184+
/* dst_reg = *(u16 *) (src_reg + offsetof(protocol)) */
185+
*insn++ = BPF_LDX_MEM(BPF_H, dst_reg, src_reg,
186+
offsetof(struct sk_buff, protocol));
187+
/* dst_reg = ntohs(dst_reg) [emitting a nop or swap16] */
188+
*insn++ = BPF_ENDIAN(BPF_FROM_BE, dst_reg, 16);
189+
break;
190+
191+
case SKF_AD_VLAN_TAG:
192+
case SKF_AD_VLAN_TAG_PRESENT:
193+
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, vlan_tci) != 2);
194+
BUILD_BUG_ON(VLAN_TAG_PRESENT != 0x1000);
195+
196+
/* dst_reg = *(u16 *) (src_reg + offsetof(vlan_tci)) */
197+
*insn++ = BPF_LDX_MEM(BPF_H, dst_reg, src_reg,
198+
offsetof(struct sk_buff, vlan_tci));
199+
if (skb_field == SKF_AD_VLAN_TAG) {
200+
*insn++ = BPF_ALU32_IMM(BPF_AND, dst_reg,
201+
~VLAN_TAG_PRESENT);
202+
} else {
203+
/* dst_reg >>= 12 */
204+
*insn++ = BPF_ALU32_IMM(BPF_RSH, dst_reg, 12);
205+
/* dst_reg &= 1 */
206+
*insn++ = BPF_ALU32_IMM(BPF_AND, dst_reg, 1);
207+
}
208+
break;
180209
}
181210

182211
return insn - insn_buf;
@@ -190,13 +219,8 @@ static bool convert_bpf_extensions(struct sock_filter *fp,
190219

191220
switch (fp->k) {
192221
case SKF_AD_OFF + SKF_AD_PROTOCOL:
193-
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, protocol) != 2);
194-
195-
/* A = *(u16 *) (CTX + offsetof(protocol)) */
196-
*insn++ = BPF_LDX_MEM(BPF_H, BPF_REG_A, BPF_REG_CTX,
197-
offsetof(struct sk_buff, protocol));
198-
/* A = ntohs(A) [emitting a nop or swap16] */
199-
*insn = BPF_ENDIAN(BPF_FROM_BE, BPF_REG_A, 16);
222+
cnt = convert_skb_access(SKF_AD_PROTOCOL, BPF_REG_A, BPF_REG_CTX, insn);
223+
insn += cnt - 1;
200224
break;
201225

202226
case SKF_AD_OFF + SKF_AD_PKTTYPE:
@@ -242,22 +266,15 @@ static bool convert_bpf_extensions(struct sock_filter *fp,
242266
break;
243267

244268
case SKF_AD_OFF + SKF_AD_VLAN_TAG:
245-
case SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT:
246-
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, vlan_tci) != 2);
247-
BUILD_BUG_ON(VLAN_TAG_PRESENT != 0x1000);
269+
cnt = convert_skb_access(SKF_AD_VLAN_TAG,
270+
BPF_REG_A, BPF_REG_CTX, insn);
271+
insn += cnt - 1;
272+
break;
248273

249-
/* A = *(u16 *) (CTX + offsetof(vlan_tci)) */
250-
*insn++ = BPF_LDX_MEM(BPF_H, BPF_REG_A, BPF_REG_CTX,
251-
offsetof(struct sk_buff, vlan_tci));
252-
if (fp->k == SKF_AD_OFF + SKF_AD_VLAN_TAG) {
253-
*insn = BPF_ALU32_IMM(BPF_AND, BPF_REG_A,
254-
~VLAN_TAG_PRESENT);
255-
} else {
256-
/* A >>= 12 */
257-
*insn++ = BPF_ALU32_IMM(BPF_RSH, BPF_REG_A, 12);
258-
/* A &= 1 */
259-
*insn = BPF_ALU32_IMM(BPF_AND, BPF_REG_A, 1);
260-
}
274+
case SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT:
275+
cnt = convert_skb_access(SKF_AD_VLAN_TAG_PRESENT,
276+
BPF_REG_A, BPF_REG_CTX, insn);
277+
insn += cnt - 1;
261278
break;
262279

263280
case SKF_AD_OFF + SKF_AD_PAY_OFFSET:
@@ -1215,6 +1232,17 @@ static u32 sk_filter_convert_ctx_access(int dst_reg, int src_reg, int ctx_off,
12151232

12161233
case offsetof(struct __sk_buff, queue_mapping):
12171234
return convert_skb_access(SKF_AD_QUEUE, dst_reg, src_reg, insn);
1235+
1236+
case offsetof(struct __sk_buff, protocol):
1237+
return convert_skb_access(SKF_AD_PROTOCOL, dst_reg, src_reg, insn);
1238+
1239+
case offsetof(struct __sk_buff, vlan_present):
1240+
return convert_skb_access(SKF_AD_VLAN_TAG_PRESENT,
1241+
dst_reg, src_reg, insn);
1242+
1243+
case offsetof(struct __sk_buff, vlan_tci):
1244+
return convert_skb_access(SKF_AD_VLAN_TAG,
1245+
dst_reg, src_reg, insn);
12181246
}
12191247

12201248
return insn - insn_buf;

samples/bpf/test_verifier.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,15 @@ static struct bpf_test tests[] = {
658658
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
659659
offsetof(struct __sk_buff, queue_mapping)),
660660
BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 0),
661+
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
662+
offsetof(struct __sk_buff, protocol)),
663+
BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 0),
664+
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
665+
offsetof(struct __sk_buff, vlan_present)),
666+
BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 0),
667+
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
668+
offsetof(struct __sk_buff, vlan_tci)),
669+
BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 0),
661670
BPF_EXIT_INSN(),
662671
},
663672
.result = ACCEPT,

0 commit comments

Comments
 (0)