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/linux | |
| 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/linux')
| -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 45266b75409..4609b85e559 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 cb8178ab3c5..364bcf212f7 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 d0ae90af0b4..79aafbbf430 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 |
