aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@plumgrid.com>2015-03-16 21:06:02 -0400
committerDavid S. Miller <davem@davemloft.net>2015-03-17 15:06:31 -0400
commitc24973957975403521ca76a776c2dfd12fbe9add (patch)
tree0a05287480110f113d719a1e3852b4f5e647685d /net/core
parent9cf7867c24bacdaa100e8a06b882005646a9095d (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.c72
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;