diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2011-04-20 05:27:32 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-04-28 02:05:08 -0400 |
commit | 0a14842f5a3c0e88a1e59fac5c3025db39721f74 (patch) | |
tree | 4d0832c4c9ced2503e2d899eb56952f87511d4ab /include | |
parent | b678027cb77b079bc8e5b94172995d173bdb494b (diff) |
net: filter: Just In Time compiler for x86-64
In order to speedup packet filtering, here is an implementation of a
JIT compiler for x86_64
It is disabled by default, and must be enabled by the admin.
echo 1 >/proc/sys/net/core/bpf_jit_enable
It uses module_alloc() and module_free() to get memory in the 2GB text
kernel range since we call helpers functions from the generated code.
EAX : BPF A accumulator
EBX : BPF X accumulator
RDI : pointer to skb (first argument given to JIT function)
RBP : frame pointer (even if CONFIG_FRAME_POINTER=n)
r9d : skb->len - skb->data_len (headlen)
r8 : skb->data
To get a trace of generated code, use :
echo 2 >/proc/sys/net/core/bpf_jit_enable
Example of generated code :
# tcpdump -p -n -s 0 -i eth1 host 192.168.20.0/24
flen=18 proglen=147 pass=3 image=ffffffffa00b5000
JIT code: ffffffffa00b5000: 55 48 89 e5 48 83 ec 60 48 89 5d f8 44 8b 4f 60
JIT code: ffffffffa00b5010: 44 2b 4f 64 4c 8b 87 b8 00 00 00 be 0c 00 00 00
JIT code: ffffffffa00b5020: e8 24 7b f7 e0 3d 00 08 00 00 75 28 be 1a 00 00
JIT code: ffffffffa00b5030: 00 e8 fe 7a f7 e0 24 00 3d 00 14 a8 c0 74 49 be
JIT code: ffffffffa00b5040: 1e 00 00 00 e8 eb 7a f7 e0 24 00 3d 00 14 a8 c0
JIT code: ffffffffa00b5050: 74 36 eb 3b 3d 06 08 00 00 74 07 3d 35 80 00 00
JIT code: ffffffffa00b5060: 75 2d be 1c 00 00 00 e8 c8 7a f7 e0 24 00 3d 00
JIT code: ffffffffa00b5070: 14 a8 c0 74 13 be 26 00 00 00 e8 b5 7a f7 e0 24
JIT code: ffffffffa00b5080: 00 3d 00 14 a8 c0 75 07 b8 ff ff 00 00 eb 02 31
JIT code: ffffffffa00b5090: c0 c9 c3
BPF program is 144 bytes long, so native program is almost same size ;)
(000) ldh [12]
(001) jeq #0x800 jt 2 jf 8
(002) ld [26]
(003) and #0xffffff00
(004) jeq #0xc0a81400 jt 16 jf 5
(005) ld [30]
(006) and #0xffffff00
(007) jeq #0xc0a81400 jt 16 jf 17
(008) jeq #0x806 jt 10 jf 9
(009) jeq #0x8035 jt 10 jf 17
(010) ld [28]
(011) and #0xffffff00
(012) jeq #0xc0a81400 jt 16 jf 13
(013) ld [38]
(014) and #0xffffff00
(015) jeq #0xc0a81400 jt 16 jf 17
(016) ret #65535
(017) ret #0
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
Cc: Ben Hutchings <bhutchings@solarflare.com>
Cc: Hagen Paul Pfeifer <hagen@jauu.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/filter.h | 76 | ||||
-rw-r--r-- | include/linux/netdevice.h | 1 | ||||
-rw-r--r-- | include/linux/skbuff.h | 2 |
3 files changed, 78 insertions, 1 deletions
diff --git a/include/linux/filter.h b/include/linux/filter.h index 45266b75409a..4609b85e559d 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h | |||
@@ -135,6 +135,8 @@ struct sk_filter | |||
135 | { | 135 | { |
136 | atomic_t refcnt; | 136 | atomic_t refcnt; |
137 | unsigned int len; /* Number of filter blocks */ | 137 | unsigned int len; /* Number of filter blocks */ |
138 | unsigned int (*bpf_func)(const struct sk_buff *skb, | ||
139 | const struct sock_filter *filter); | ||
138 | struct rcu_head rcu; | 140 | struct rcu_head rcu; |
139 | struct sock_filter insns[0]; | 141 | struct sock_filter insns[0]; |
140 | }; | 142 | }; |
@@ -153,6 +155,80 @@ extern unsigned int sk_run_filter(const struct sk_buff *skb, | |||
153 | extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk); | 155 | extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk); |
154 | extern int sk_detach_filter(struct sock *sk); | 156 | extern int sk_detach_filter(struct sock *sk); |
155 | extern int sk_chk_filter(struct sock_filter *filter, int flen); | 157 | extern int sk_chk_filter(struct sock_filter *filter, int flen); |
158 | |||
159 | #ifdef CONFIG_BPF_JIT | ||
160 | extern void bpf_jit_compile(struct sk_filter *fp); | ||
161 | extern void bpf_jit_free(struct sk_filter *fp); | ||
162 | #define SK_RUN_FILTER(FILTER, SKB) (*FILTER->bpf_func)(SKB, FILTER->insns) | ||
163 | #else | ||
164 | static inline void bpf_jit_compile(struct sk_filter *fp) | ||
165 | { | ||
166 | } | ||
167 | static inline void bpf_jit_free(struct sk_filter *fp) | ||
168 | { | ||
169 | } | ||
170 | #define SK_RUN_FILTER(FILTER, SKB) sk_run_filter(SKB, FILTER->insns) | ||
171 | #endif | ||
172 | |||
173 | enum { | ||
174 | BPF_S_RET_K = 1, | ||
175 | BPF_S_RET_A, | ||
176 | BPF_S_ALU_ADD_K, | ||
177 | BPF_S_ALU_ADD_X, | ||
178 | BPF_S_ALU_SUB_K, | ||
179 | BPF_S_ALU_SUB_X, | ||
180 | BPF_S_ALU_MUL_K, | ||
181 | BPF_S_ALU_MUL_X, | ||
182 | BPF_S_ALU_DIV_X, | ||
183 | BPF_S_ALU_AND_K, | ||
184 | BPF_S_ALU_AND_X, | ||
185 | BPF_S_ALU_OR_K, | ||
186 | BPF_S_ALU_OR_X, | ||
187 | BPF_S_ALU_LSH_K, | ||
188 | BPF_S_ALU_LSH_X, | ||
189 | BPF_S_ALU_RSH_K, | ||
190 | BPF_S_ALU_RSH_X, | ||
191 | BPF_S_ALU_NEG, | ||
192 | BPF_S_LD_W_ABS, | ||
193 | BPF_S_LD_H_ABS, | ||
194 | BPF_S_LD_B_ABS, | ||
195 | BPF_S_LD_W_LEN, | ||
196 | BPF_S_LD_W_IND, | ||
197 | BPF_S_LD_H_IND, | ||
198 | BPF_S_LD_B_IND, | ||
199 | BPF_S_LD_IMM, | ||
200 | BPF_S_LDX_W_LEN, | ||
201 | BPF_S_LDX_B_MSH, | ||
202 | BPF_S_LDX_IMM, | ||
203 | BPF_S_MISC_TAX, | ||
204 | BPF_S_MISC_TXA, | ||
205 | BPF_S_ALU_DIV_K, | ||
206 | BPF_S_LD_MEM, | ||
207 | BPF_S_LDX_MEM, | ||
208 | BPF_S_ST, | ||
209 | BPF_S_STX, | ||
210 | BPF_S_JMP_JA, | ||
211 | BPF_S_JMP_JEQ_K, | ||
212 | BPF_S_JMP_JEQ_X, | ||
213 | BPF_S_JMP_JGE_K, | ||
214 | BPF_S_JMP_JGE_X, | ||
215 | BPF_S_JMP_JGT_K, | ||
216 | BPF_S_JMP_JGT_X, | ||
217 | BPF_S_JMP_JSET_K, | ||
218 | BPF_S_JMP_JSET_X, | ||
219 | /* Ancillary data */ | ||
220 | BPF_S_ANC_PROTOCOL, | ||
221 | BPF_S_ANC_PKTTYPE, | ||
222 | BPF_S_ANC_IFINDEX, | ||
223 | BPF_S_ANC_NLATTR, | ||
224 | BPF_S_ANC_NLATTR_NEST, | ||
225 | BPF_S_ANC_MARK, | ||
226 | BPF_S_ANC_QUEUE, | ||
227 | BPF_S_ANC_HATYPE, | ||
228 | BPF_S_ANC_RXHASH, | ||
229 | BPF_S_ANC_CPU, | ||
230 | }; | ||
231 | |||
156 | #endif /* __KERNEL__ */ | 232 | #endif /* __KERNEL__ */ |
157 | 233 | ||
158 | #endif /* __LINUX_FILTER_H__ */ | 234 | #endif /* __LINUX_FILTER_H__ */ |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index cb8178ab3c52..364bcf212f71 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -2514,6 +2514,7 @@ extern struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev, | |||
2514 | extern int netdev_max_backlog; | 2514 | extern int netdev_max_backlog; |
2515 | extern int netdev_tstamp_prequeue; | 2515 | extern int netdev_tstamp_prequeue; |
2516 | extern int weight_p; | 2516 | extern int weight_p; |
2517 | extern int bpf_jit_enable; | ||
2517 | extern int netdev_set_master(struct net_device *dev, struct net_device *master); | 2518 | extern int netdev_set_master(struct net_device *dev, struct net_device *master); |
2518 | extern int netdev_set_bond_master(struct net_device *dev, | 2519 | extern int netdev_set_bond_master(struct net_device *dev, |
2519 | struct net_device *master); | 2520 | struct net_device *master); |
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index d0ae90af0b40..79aafbbf430a 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
@@ -391,8 +391,8 @@ struct sk_buff { | |||
391 | 391 | ||
392 | __u32 rxhash; | 392 | __u32 rxhash; |
393 | 393 | ||
394 | __u16 queue_mapping; | ||
394 | kmemcheck_bitfield_begin(flags2); | 395 | kmemcheck_bitfield_begin(flags2); |
395 | __u16 queue_mapping:16; | ||
396 | #ifdef CONFIG_IPV6_NDISC_NODETYPE | 396 | #ifdef CONFIG_IPV6_NDISC_NODETYPE |
397 | __u8 ndisc_nodetype:2; | 397 | __u8 ndisc_nodetype:2; |
398 | #endif | 398 | #endif |