diff options
author | Florian Westphal <fw@strlen.de> | 2019-04-11 10:36:41 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2019-04-11 19:47:39 -0400 |
commit | 971502d77faa50a37c89bc6d172450294ad9a5fd (patch) | |
tree | 432504faa8b09801a8b004ffb298c4ce7827a799 | |
parent | f12064d1b402c60c5db9c4b63d5ed6d7facb33f6 (diff) |
bridge: netfilter: unroll NF_HOOK helper in bridge input path
Replace NF_HOOK() based invocation of the netfilter hooks with a private
copy of nf_hook_slow().
This copy has one difference: it can return the rx handler value expected
by the stack, i.e. RX_HANDLER_CONSUMED or RX_HANDLER_PASS.
This is needed by the next patch to invoke the ebtables
"broute" table via the standard netfilter hooks rather than the custom
"br_should_route_hook" indirection that is used now.
When the skb is to be "brouted", we must return RX_HANDLER_PASS from the
bridge rx input handler, but there is no way to indicate this via
NF_HOOK(), unless perhaps by some hack such as exposing bridge_cb in the
netfilter core or a percpu flag.
text data bss dec filename
3369 56 0 3425 net/bridge/br_input.o.before
3458 40 0 3498 net/bridge/br_input.o.after
This allows removal of the "br_should_route_hook" in the next patch.
Signed-off-by: Florian Westphal <fw@strlen.de>
Acked-by: David S. Miller <davem@davemloft.net>
Acked-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r-- | include/net/netfilter/nf_queue.h | 3 | ||||
-rw-r--r-- | net/bridge/br_input.c | 55 | ||||
-rw-r--r-- | net/netfilter/core.c | 1 | ||||
-rw-r--r-- | net/netfilter/nf_internals.h | 3 | ||||
-rw-r--r-- | net/netfilter/nf_queue.c | 1 |
5 files changed, 56 insertions, 7 deletions
diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h index a50a69f5334c..7239105d9d2e 100644 --- a/include/net/netfilter/nf_queue.h +++ b/include/net/netfilter/nf_queue.h | |||
@@ -119,4 +119,7 @@ nfqueue_hash(const struct sk_buff *skb, u16 queue, u16 queues_total, u8 family, | |||
119 | return queue; | 119 | return queue; |
120 | } | 120 | } |
121 | 121 | ||
122 | int nf_queue(struct sk_buff *skb, struct nf_hook_state *state, | ||
123 | const struct nf_hook_entries *entries, unsigned int index, | ||
124 | unsigned int verdict); | ||
122 | #endif /* _NF_QUEUE_H */ | 125 | #endif /* _NF_QUEUE_H */ |
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index e2f93e5c72da..4ac34fb5f943 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/netdevice.h> | 16 | #include <linux/netdevice.h> |
17 | #include <linux/etherdevice.h> | 17 | #include <linux/etherdevice.h> |
18 | #include <linux/netfilter_bridge.h> | 18 | #include <linux/netfilter_bridge.h> |
19 | #include <net/netfilter/nf_queue.h> | ||
19 | #include <linux/neighbour.h> | 20 | #include <linux/neighbour.h> |
20 | #include <net/arp.h> | 21 | #include <net/arp.h> |
21 | #include <linux/export.h> | 22 | #include <linux/export.h> |
@@ -206,6 +207,55 @@ static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_bu | |||
206 | return 0; | 207 | return 0; |
207 | } | 208 | } |
208 | 209 | ||
210 | static int nf_hook_bridge_pre(struct sk_buff *skb, struct sk_buff **pskb) | ||
211 | { | ||
212 | #ifdef CONFIG_NETFILTER_FAMILY_BRIDGE | ||
213 | struct nf_hook_entries *e = NULL; | ||
214 | struct nf_hook_state state; | ||
215 | unsigned int verdict, i; | ||
216 | struct net *net; | ||
217 | int ret; | ||
218 | |||
219 | net = dev_net(skb->dev); | ||
220 | #ifdef HAVE_JUMP_LABEL | ||
221 | if (!static_key_false(&nf_hooks_needed[NFPROTO_BRIDGE][NF_BR_PRE_ROUTING])) | ||
222 | goto frame_finish; | ||
223 | #endif | ||
224 | |||
225 | e = rcu_dereference(net->nf.hooks_bridge[NF_BR_PRE_ROUTING]); | ||
226 | if (!e) | ||
227 | goto frame_finish; | ||
228 | |||
229 | nf_hook_state_init(&state, NF_BR_PRE_ROUTING, | ||
230 | NFPROTO_BRIDGE, skb->dev, NULL, NULL, | ||
231 | net, br_handle_frame_finish); | ||
232 | |||
233 | for (i = 0; i < e->num_hook_entries; i++) { | ||
234 | verdict = nf_hook_entry_hookfn(&e->hooks[i], skb, &state); | ||
235 | switch (verdict & NF_VERDICT_MASK) { | ||
236 | case NF_ACCEPT: | ||
237 | break; | ||
238 | case NF_DROP: | ||
239 | kfree_skb(skb); | ||
240 | return RX_HANDLER_CONSUMED; | ||
241 | case NF_QUEUE: | ||
242 | ret = nf_queue(skb, &state, e, i, verdict); | ||
243 | if (ret == 1) | ||
244 | continue; | ||
245 | return RX_HANDLER_CONSUMED; | ||
246 | default: /* STOLEN */ | ||
247 | return RX_HANDLER_CONSUMED; | ||
248 | } | ||
249 | } | ||
250 | frame_finish: | ||
251 | net = dev_net(skb->dev); | ||
252 | br_handle_frame_finish(net, NULL, skb); | ||
253 | #else | ||
254 | br_handle_frame_finish(dev_net(skb->dev), NULL, skb); | ||
255 | #endif | ||
256 | return RX_HANDLER_CONSUMED; | ||
257 | } | ||
258 | |||
209 | /* | 259 | /* |
210 | * Return NULL if skb is handled | 260 | * Return NULL if skb is handled |
211 | * note: already called with rcu_read_lock | 261 | * note: already called with rcu_read_lock |
@@ -304,10 +354,7 @@ forward: | |||
304 | if (ether_addr_equal(p->br->dev->dev_addr, dest)) | 354 | if (ether_addr_equal(p->br->dev->dev_addr, dest)) |
305 | skb->pkt_type = PACKET_HOST; | 355 | skb->pkt_type = PACKET_HOST; |
306 | 356 | ||
307 | NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, | 357 | return nf_hook_bridge_pre(skb, pskb); |
308 | dev_net(skb->dev), NULL, skb, skb->dev, NULL, | ||
309 | br_handle_frame_finish); | ||
310 | break; | ||
311 | default: | 358 | default: |
312 | drop: | 359 | drop: |
313 | kfree_skb(skb); | 360 | kfree_skb(skb); |
diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 93aaec3a54ec..71f06900473e 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/mm.h> | 23 | #include <linux/mm.h> |
24 | #include <linux/rcupdate.h> | 24 | #include <linux/rcupdate.h> |
25 | #include <net/net_namespace.h> | 25 | #include <net/net_namespace.h> |
26 | #include <net/netfilter/nf_queue.h> | ||
26 | #include <net/sock.h> | 27 | #include <net/sock.h> |
27 | 28 | ||
28 | #include "nf_internals.h" | 29 | #include "nf_internals.h" |
diff --git a/net/netfilter/nf_internals.h b/net/netfilter/nf_internals.h index e15779fd58e3..d6c43902ebd7 100644 --- a/net/netfilter/nf_internals.h +++ b/net/netfilter/nf_internals.h | |||
@@ -7,9 +7,6 @@ | |||
7 | #include <linux/netdevice.h> | 7 | #include <linux/netdevice.h> |
8 | 8 | ||
9 | /* nf_queue.c */ | 9 | /* nf_queue.c */ |
10 | int nf_queue(struct sk_buff *skb, struct nf_hook_state *state, | ||
11 | const struct nf_hook_entries *entries, unsigned int index, | ||
12 | unsigned int verdict); | ||
13 | void nf_queue_nf_hook_drop(struct net *net); | 10 | void nf_queue_nf_hook_drop(struct net *net); |
14 | 11 | ||
15 | /* nf_log.c */ | 12 | /* nf_log.c */ |
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index a36a77bae1d6..9dc1d6e04946 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c | |||
@@ -240,6 +240,7 @@ int nf_queue(struct sk_buff *skb, struct nf_hook_state *state, | |||
240 | 240 | ||
241 | return 0; | 241 | return 0; |
242 | } | 242 | } |
243 | EXPORT_SYMBOL_GPL(nf_queue); | ||
243 | 244 | ||
244 | static unsigned int nf_iterate(struct sk_buff *skb, | 245 | static unsigned int nf_iterate(struct sk_buff *skb, |
245 | struct nf_hook_state *state, | 246 | struct nf_hook_state *state, |