diff options
author | Alexei Starovoitov <ast@plumgrid.com> | 2015-03-16 21:06:02 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-03-17 15:06:31 -0400 |
commit | c24973957975403521ca76a776c2dfd12fbe9add (patch) | |
tree | 0a05287480110f113d719a1e3852b4f5e647685d /net/core | |
parent | 9cf7867c24bacdaa100e8a06b882005646a9095d (diff) |
bpf: allow BPF programs access 'protocol' and 'vlan_tci' fields
as a follow on to patch 70006af95515 ("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 <ast@plumgrid.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/filter.c | 72 |
1 files changed, 50 insertions, 22 deletions
diff --git a/net/core/filter.c b/net/core/filter.c index 4e9dd0ad0d5b..b95ae7fe7e4f 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
@@ -177,6 +177,35 @@ static u32 convert_skb_access(int skb_field, int dst_reg, int src_reg, | |||
177 | *insn++ = BPF_LDX_MEM(BPF_H, dst_reg, src_reg, | 177 | *insn++ = BPF_LDX_MEM(BPF_H, dst_reg, src_reg, |
178 | offsetof(struct sk_buff, queue_mapping)); | 178 | offsetof(struct sk_buff, queue_mapping)); |
179 | break; | 179 | 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; | ||
180 | } | 209 | } |
181 | 210 | ||
182 | return insn - insn_buf; | 211 | return insn - insn_buf; |
@@ -190,13 +219,8 @@ static bool convert_bpf_extensions(struct sock_filter *fp, | |||
190 | 219 | ||
191 | switch (fp->k) { | 220 | switch (fp->k) { |
192 | case SKF_AD_OFF + SKF_AD_PROTOCOL: | 221 | case SKF_AD_OFF + SKF_AD_PROTOCOL: |
193 | BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, protocol) != 2); | 222 | cnt = convert_skb_access(SKF_AD_PROTOCOL, BPF_REG_A, BPF_REG_CTX, insn); |
194 | 223 | insn += cnt - 1; | |
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); | ||
200 | break; | 224 | break; |
201 | 225 | ||
202 | case SKF_AD_OFF + SKF_AD_PKTTYPE: | 226 | case SKF_AD_OFF + SKF_AD_PKTTYPE: |
@@ -242,22 +266,15 @@ static bool convert_bpf_extensions(struct sock_filter *fp, | |||
242 | break; | 266 | break; |
243 | 267 | ||
244 | case SKF_AD_OFF + SKF_AD_VLAN_TAG: | 268 | case SKF_AD_OFF + SKF_AD_VLAN_TAG: |
245 | case SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT: | 269 | cnt = convert_skb_access(SKF_AD_VLAN_TAG, |
246 | BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, vlan_tci) != 2); | 270 | BPF_REG_A, BPF_REG_CTX, insn); |
247 | BUILD_BUG_ON(VLAN_TAG_PRESENT != 0x1000); | 271 | insn += cnt - 1; |
272 | break; | ||
248 | 273 | ||
249 | /* A = *(u16 *) (CTX + offsetof(vlan_tci)) */ | 274 | case SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT: |
250 | *insn++ = BPF_LDX_MEM(BPF_H, BPF_REG_A, BPF_REG_CTX, | 275 | cnt = convert_skb_access(SKF_AD_VLAN_TAG_PRESENT, |
251 | offsetof(struct sk_buff, vlan_tci)); | 276 | BPF_REG_A, BPF_REG_CTX, insn); |
252 | if (fp->k == SKF_AD_OFF + SKF_AD_VLAN_TAG) { | 277 | insn += cnt - 1; |
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 | } | ||
261 | break; | 278 | break; |
262 | 279 | ||
263 | case SKF_AD_OFF + SKF_AD_PAY_OFFSET: | 280 | 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, | |||
1215 | 1232 | ||
1216 | case offsetof(struct __sk_buff, queue_mapping): | 1233 | case offsetof(struct __sk_buff, queue_mapping): |
1217 | return convert_skb_access(SKF_AD_QUEUE, dst_reg, src_reg, insn); | 1234 | 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); | ||
1218 | } | 1246 | } |
1219 | 1247 | ||
1220 | return insn - insn_buf; | 1248 | return insn - insn_buf; |