filter: introduce SKF_AD_VLAN_TPID BPF extension
authorMichal Sekletar <msekleta@redhat.com>
Tue, 24 Mar 2015 13:48:41 +0000 (14:48 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 24 Mar 2015 19:25:15 +0000 (15:25 -0400)
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>
Documentation/networking/filter.txt
include/linux/filter.h
include/uapi/linux/bpf.h
include/uapi/linux/filter.h
net/core/filter.c
tools/net/bpf_exp.l
tools/net/bpf_exp.y

index 9930ecfbb4658f7bd93969b52440e49eeb753de2..135581f015e1eb4298c063ebd938ccf2ec2cb461 100644 (file)
@@ -280,7 +280,8 @@ Possible BPF extensions are shown in the following table:
   rxhash                                skb->hash
   cpu                                   raw_smp_processor_id()
   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()
 
 These extensions can also be prefixed with '#'.
index 9ee8c67ea249fd492c28069b5ee388c308917ce1..fa11b3a367be54c4f73427d3c323c9c4936aca3a 100644 (file)
@@ -454,6 +454,7 @@ static inline u16 bpf_anc_helper(const struct sock_filter *ftest)
                BPF_ANCILLARY(VLAN_TAG_PRESENT);
                BPF_ANCILLARY(PAY_OFFSET);
                BPF_ANCILLARY(RANDOM);
+               BPF_ANCILLARY(VLAN_TPID);
                }
                /* Fallthrough. */
        default:
index 3dd314a45d0dab826dbc9ef8a0e96831932d6dd5..27dc4ec588402e2cf1ee5e285719fc8eb4ea876e 100644 (file)
@@ -182,6 +182,7 @@ struct __sk_buff {
        __u32 protocol;
        __u32 vlan_present;
        __u32 vlan_tci;
+       __u32 vlan_proto;
 };
 
 #endif /* _UAPI__LINUX_BPF_H__ */
index 47785d5ecf17d465add70aae88c536bb4ca92ece..34c7936ca114e726190fde39f80f481186cf3174 100644 (file)
@@ -77,7 +77,8 @@ struct sock_fprog {   /* Required for SO_ATTACH_FILTER. */
 #define SKF_AD_VLAN_TAG_PRESENT 48
 #define SKF_AD_PAY_OFFSET      52
 #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_LL_OFF    (-0x200000)
 
index 084eacc4d1d441453469ebb4148aa587bd89f1a0..32f43c59908c49daacbbb5e2060e057fd3eed422 100644 (file)
@@ -272,6 +272,16 @@ static bool convert_bpf_extensions(struct sock_filter *fp,
                insn += cnt - 1;
                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_NLATTR:
        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));
                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):
                return convert_skb_access(SKF_AD_MARK, dst_reg, src_reg, insn);
 
index 833a96611da6d042e089294990801817d0f1ade9..c83af3fb77de99e77c3119e051092e707768e93f 100644 (file)
@@ -92,6 +92,8 @@ extern void yyerror(const char *str);
 "#"?("cpu")    { return K_CPU; }
 "#"?("vlan_tci") { return K_VLANT; }
 "#"?("vlan_pr")        { return K_VLANP; }
+"#"?("vlan_avail")     { return K_VLANP; }
+"#"?("vlan_tpid")      { return K_VLANTPID; }
 "#"?("rand")   { return K_RAND; }
 
 ":"            { return ':'; }
index e6306c51c26f9e7cb53342ad088a9db1e4e32423..f8332749b44c49a45b2c9f10165f7b9ee6d62cd4 100644 (file)
@@ -56,7 +56,7 @@ static void bpf_set_jmp_label(char *label, enum jmp_type type);
 %token OP_LDXI
 
 %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' '*' '&' '#' '%'
 
@@ -167,6 +167,9 @@ ldb
        | OP_LDB K_RAND {
                bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
                                   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
@@ -218,6 +221,9 @@ ldh
        | OP_LDH K_RAND {
                bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
                                   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
@@ -274,6 +280,9 @@ ld
        | OP_LD K_RAND {
                bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
                                   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 ']' {
                bpf_set_curr_instr(BPF_LD | BPF_MEM, 0, 0, $4); }
        | OP_LD '[' 'x' '+' number ']' {