filter: introduce SKF_AD_VLAN_TPID BPF extension

If vlan offloading takes place then vlan header is removed from frame
and its contents, both vlan_tci and vlan_proto, is available to user
space via TPACKET interface. However, only vlan_tci can be used in BPF
filters.

This commit introduces a new BPF extension. It makes possible to load
the value of vlan_proto (vlan TPID) to register A. Support for classic
BPF and eBPF is being added, analogous to skb->protocol.

Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Alexei Starovoitov <ast@plumgrid.com>
Cc: Jiri Pirko <jpirko@redhat.com>

Signed-off-by: Michal Sekletar <msekleta@redhat.com>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Alexei Starovoitov <ast@plumgrid.com>
Reviewed-by: Jiri Pirko <jiri@resnulli.us>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Michal Sekletar 2015-03-24 14:48:41 +01:00 committed by David S. Miller
parent f6bb76cd4d
commit 27cd545247
7 changed files with 35 additions and 3 deletions

View File

@ -280,7 +280,8 @@ Possible BPF extensions are shown in the following table:
rxhash skb->hash rxhash skb->hash
cpu raw_smp_processor_id() cpu raw_smp_processor_id()
vlan_tci skb_vlan_tag_get(skb) vlan_tci skb_vlan_tag_get(skb)
vlan_pr skb_vlan_tag_present(skb) vlan_avail skb_vlan_tag_present(skb)
vlan_tpid skb->vlan_proto
rand prandom_u32() rand prandom_u32()
These extensions can also be prefixed with '#'. These extensions can also be prefixed with '#'.

View File

@ -454,6 +454,7 @@ static inline u16 bpf_anc_helper(const struct sock_filter *ftest)
BPF_ANCILLARY(VLAN_TAG_PRESENT); BPF_ANCILLARY(VLAN_TAG_PRESENT);
BPF_ANCILLARY(PAY_OFFSET); BPF_ANCILLARY(PAY_OFFSET);
BPF_ANCILLARY(RANDOM); BPF_ANCILLARY(RANDOM);
BPF_ANCILLARY(VLAN_TPID);
} }
/* Fallthrough. */ /* Fallthrough. */
default: default:

View File

@ -182,6 +182,7 @@ struct __sk_buff {
__u32 protocol; __u32 protocol;
__u32 vlan_present; __u32 vlan_present;
__u32 vlan_tci; __u32 vlan_tci;
__u32 vlan_proto;
}; };
#endif /* _UAPI__LINUX_BPF_H__ */ #endif /* _UAPI__LINUX_BPF_H__ */

View File

@ -77,7 +77,8 @@ struct sock_fprog { /* Required for SO_ATTACH_FILTER. */
#define SKF_AD_VLAN_TAG_PRESENT 48 #define SKF_AD_VLAN_TAG_PRESENT 48
#define SKF_AD_PAY_OFFSET 52 #define SKF_AD_PAY_OFFSET 52
#define SKF_AD_RANDOM 56 #define SKF_AD_RANDOM 56
#define SKF_AD_MAX 60 #define SKF_AD_VLAN_TPID 60
#define SKF_AD_MAX 64
#define SKF_NET_OFF (-0x100000) #define SKF_NET_OFF (-0x100000)
#define SKF_LL_OFF (-0x200000) #define SKF_LL_OFF (-0x200000)

View File

@ -272,6 +272,16 @@ static bool convert_bpf_extensions(struct sock_filter *fp,
insn += cnt - 1; insn += cnt - 1;
break; break;
case SKF_AD_OFF + SKF_AD_VLAN_TPID:
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, vlan_proto) != 2);
/* A = *(u16 *) (CTX + offsetof(vlan_proto)) */
*insn++ = BPF_LDX_MEM(BPF_H, BPF_REG_A, BPF_REG_CTX,
offsetof(struct sk_buff, vlan_proto));
/* A = ntohs(A) [emitting a nop or swap16] */
*insn = BPF_ENDIAN(BPF_FROM_BE, BPF_REG_A, 16);
break;
case SKF_AD_OFF + SKF_AD_PAY_OFFSET: case SKF_AD_OFF + SKF_AD_PAY_OFFSET:
case SKF_AD_OFF + SKF_AD_NLATTR: case SKF_AD_OFF + SKF_AD_NLATTR:
case SKF_AD_OFF + SKF_AD_NLATTR_NEST: case SKF_AD_OFF + SKF_AD_NLATTR_NEST:
@ -1226,6 +1236,13 @@ static u32 sk_filter_convert_ctx_access(int dst_reg, int src_reg, int ctx_off,
offsetof(struct sk_buff, protocol)); offsetof(struct sk_buff, protocol));
break; break;
case offsetof(struct __sk_buff, vlan_proto):
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, vlan_proto) != 2);
*insn++ = BPF_LDX_MEM(BPF_H, dst_reg, src_reg,
offsetof(struct sk_buff, vlan_proto));
break;
case offsetof(struct __sk_buff, mark): case offsetof(struct __sk_buff, mark):
return convert_skb_access(SKF_AD_MARK, dst_reg, src_reg, insn); return convert_skb_access(SKF_AD_MARK, dst_reg, src_reg, insn);

View File

@ -92,6 +92,8 @@ extern void yyerror(const char *str);
"#"?("cpu") { return K_CPU; } "#"?("cpu") { return K_CPU; }
"#"?("vlan_tci") { return K_VLANT; } "#"?("vlan_tci") { return K_VLANT; }
"#"?("vlan_pr") { return K_VLANP; } "#"?("vlan_pr") { return K_VLANP; }
"#"?("vlan_avail") { return K_VLANP; }
"#"?("vlan_tpid") { return K_VLANTPID; }
"#"?("rand") { return K_RAND; } "#"?("rand") { return K_RAND; }
":" { return ':'; } ":" { return ':'; }

View File

@ -56,7 +56,7 @@ static void bpf_set_jmp_label(char *label, enum jmp_type type);
%token OP_LDXI %token OP_LDXI
%token K_PKT_LEN K_PROTO K_TYPE K_NLATTR K_NLATTR_NEST K_MARK K_QUEUE K_HATYPE %token K_PKT_LEN K_PROTO K_TYPE K_NLATTR K_NLATTR_NEST K_MARK K_QUEUE K_HATYPE
%token K_RXHASH K_CPU K_IFIDX K_VLANT K_VLANP K_POFF K_RAND %token K_RXHASH K_CPU K_IFIDX K_VLANT K_VLANP K_VLANTPID K_POFF K_RAND
%token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%' %token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%'
@ -167,6 +167,9 @@ ldb
| OP_LDB K_RAND { | OP_LDB K_RAND {
bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_RANDOM); } SKF_AD_OFF + SKF_AD_RANDOM); }
| OP_LDB K_VLANTPID {
bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_VLAN_TPID); }
; ;
ldh ldh
@ -218,6 +221,9 @@ ldh
| OP_LDH K_RAND { | OP_LDH K_RAND {
bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_RANDOM); } SKF_AD_OFF + SKF_AD_RANDOM); }
| OP_LDH K_VLANTPID {
bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_VLAN_TPID); }
; ;
ldi ldi
@ -274,6 +280,9 @@ ld
| OP_LD K_RAND { | OP_LD K_RAND {
bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_RANDOM); } SKF_AD_OFF + SKF_AD_RANDOM); }
| OP_LD K_VLANTPID {
bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_VLAN_TPID); }
| OP_LD 'M' '[' number ']' { | OP_LD 'M' '[' number ']' {
bpf_set_curr_instr(BPF_LD | BPF_MEM, 0, 0, $4); } bpf_set_curr_instr(BPF_LD | BPF_MEM, 0, 0, $4); }
| OP_LD '[' 'x' '+' number ']' { | OP_LD '[' 'x' '+' number ']' {