diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/net/bpf_jit_comp.c | 40 |
1 files changed, 39 insertions, 1 deletions
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index d11a47099d33..3cbe45381bbb 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* bpf_jit_comp.c : BPF JIT compiler | 1 | /* bpf_jit_comp.c : BPF JIT compiler |
2 | * | 2 | * |
3 | * Copyright (C) 2011 Eric Dumazet (eric.dumazet@gmail.com) | 3 | * Copyright (C) 2011-2013 Eric Dumazet (eric.dumazet@gmail.com) |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License | 6 | * modify it under the terms of the GNU General Public License |
@@ -124,6 +124,26 @@ static inline void bpf_flush_icache(void *start, void *end) | |||
124 | #define CHOOSE_LOAD_FUNC(K, func) \ | 124 | #define CHOOSE_LOAD_FUNC(K, func) \ |
125 | ((int)K < 0 ? ((int)K >= SKF_LL_OFF ? func##_negative_offset : func) : func##_positive_offset) | 125 | ((int)K < 0 ? ((int)K >= SKF_LL_OFF ? func##_negative_offset : func) : func##_positive_offset) |
126 | 126 | ||
127 | /* Helper to find the offset of pkt_type in sk_buff | ||
128 | * We want to make sure its still a 3bit field starting at a byte boundary. | ||
129 | */ | ||
130 | #define PKT_TYPE_MAX 7 | ||
131 | static int pkt_type_offset(void) | ||
132 | { | ||
133 | struct sk_buff skb_probe = { | ||
134 | .pkt_type = ~0, | ||
135 | }; | ||
136 | char *ct = (char *)&skb_probe; | ||
137 | unsigned int off; | ||
138 | |||
139 | for (off = 0; off < sizeof(struct sk_buff); off++) { | ||
140 | if (ct[off] == PKT_TYPE_MAX) | ||
141 | return off; | ||
142 | } | ||
143 | pr_err_once("Please fix pkt_type_offset(), as pkt_type couldn't be found\n"); | ||
144 | return -1; | ||
145 | } | ||
146 | |||
127 | void bpf_jit_compile(struct sk_filter *fp) | 147 | void bpf_jit_compile(struct sk_filter *fp) |
128 | { | 148 | { |
129 | u8 temp[64]; | 149 | u8 temp[64]; |
@@ -216,6 +236,7 @@ void bpf_jit_compile(struct sk_filter *fp) | |||
216 | case BPF_S_ANC_VLAN_TAG: | 236 | case BPF_S_ANC_VLAN_TAG: |
217 | case BPF_S_ANC_VLAN_TAG_PRESENT: | 237 | case BPF_S_ANC_VLAN_TAG_PRESENT: |
218 | case BPF_S_ANC_QUEUE: | 238 | case BPF_S_ANC_QUEUE: |
239 | case BPF_S_ANC_PKTTYPE: | ||
219 | case BPF_S_LD_W_ABS: | 240 | case BPF_S_LD_W_ABS: |
220 | case BPF_S_LD_H_ABS: | 241 | case BPF_S_LD_H_ABS: |
221 | case BPF_S_LD_B_ABS: | 242 | case BPF_S_LD_B_ABS: |
@@ -536,6 +557,23 @@ void bpf_jit_compile(struct sk_filter *fp) | |||
536 | EMIT3(0x83, 0xe0, 0x01); /* and $0x1,%eax */ | 557 | EMIT3(0x83, 0xe0, 0x01); /* and $0x1,%eax */ |
537 | } | 558 | } |
538 | break; | 559 | break; |
560 | case BPF_S_ANC_PKTTYPE: | ||
561 | { | ||
562 | int off = pkt_type_offset(); | ||
563 | |||
564 | if (off < 0) | ||
565 | goto out; | ||
566 | if (is_imm8(off)) { | ||
567 | /* movzbl off8(%rdi),%eax */ | ||
568 | EMIT4(0x0f, 0xb6, 0x47, off); | ||
569 | } else { | ||
570 | /* movbl off32(%rdi),%eax */ | ||
571 | EMIT3(0x0f, 0xb6, 0x87); | ||
572 | EMIT(off, 4); | ||
573 | } | ||
574 | EMIT3(0x83, 0xe0, PKT_TYPE_MAX); /* and $0x7,%eax */ | ||
575 | break; | ||
576 | } | ||
539 | case BPF_S_LD_W_ABS: | 577 | case BPF_S_LD_W_ABS: |
540 | func = CHOOSE_LOAD_FUNC(K, sk_load_word); | 578 | func = CHOOSE_LOAD_FUNC(K, sk_load_word); |
541 | common_load: seen |= SEEN_DATAREF; | 579 | common_load: seen |= SEEN_DATAREF; |