aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2016-09-21 11:35:01 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2016-09-24 15:25:48 -0400
commitc5136b15ea364124299c8a9ba96b300e96061e3a (patch)
treec5ffa93a950d60bdc5bc0690743c5bc806cd0904 /net
parent50f4c7b73f831a53fa9ddeb9bdf4cfb5b23d3aa7 (diff)
netfilter: bridge: add and use br_nf_hook_thresh
This replaces the last uses of NF_HOOK_THRESH(). Followup patch will remove it and rename nf_hook_thresh. The reason is that inet (non-bridge) netfilter no longer invokes the hooks from hooks, so we do no longer need the thresh value to skip hooks with a lower priority. The bridge netfilter however may need to do this. br_nf_hook_thresh is a wrapper that is supposed to do this, i.e. only call hooks with a priority that exceeds NF_BR_PRI_BRNF. It's used only in the recursion cases of br_netfilter. It invokes nf_hook_slow while holding an rcu read-side critical section to make a future cleanup simpler. Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Aaron Conole <aconole@bytheb.org> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br_netfilter_hooks.c60
-rw-r--r--net/bridge/br_netfilter_ipv6.c12
2 files changed, 56 insertions, 16 deletions
diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c
index 77e7f69bf80d..6029af47377d 100644
--- a/net/bridge/br_netfilter_hooks.c
+++ b/net/bridge/br_netfilter_hooks.c
@@ -30,6 +30,7 @@
30#include <linux/netfilter_ipv6.h> 30#include <linux/netfilter_ipv6.h>
31#include <linux/netfilter_arp.h> 31#include <linux/netfilter_arp.h>
32#include <linux/in_route.h> 32#include <linux/in_route.h>
33#include <linux/rculist.h>
33#include <linux/inetdevice.h> 34#include <linux/inetdevice.h>
34 35
35#include <net/ip.h> 36#include <net/ip.h>
@@ -395,11 +396,10 @@ bridged_dnat:
395 skb->dev = nf_bridge->physindev; 396 skb->dev = nf_bridge->physindev;
396 nf_bridge_update_protocol(skb); 397 nf_bridge_update_protocol(skb);
397 nf_bridge_push_encap_header(skb); 398 nf_bridge_push_encap_header(skb);
398 NF_HOOK_THRESH(NFPROTO_BRIDGE, 399 br_nf_hook_thresh(NF_BR_PRE_ROUTING,
399 NF_BR_PRE_ROUTING, 400 net, sk, skb, skb->dev,
400 net, sk, skb, skb->dev, NULL, 401 NULL,
401 br_nf_pre_routing_finish_bridge, 402 br_nf_pre_routing_finish);
402 1);
403 return 0; 403 return 0;
404 } 404 }
405 ether_addr_copy(eth_hdr(skb)->h_dest, dev->dev_addr); 405 ether_addr_copy(eth_hdr(skb)->h_dest, dev->dev_addr);
@@ -417,10 +417,8 @@ bridged_dnat:
417 skb->dev = nf_bridge->physindev; 417 skb->dev = nf_bridge->physindev;
418 nf_bridge_update_protocol(skb); 418 nf_bridge_update_protocol(skb);
419 nf_bridge_push_encap_header(skb); 419 nf_bridge_push_encap_header(skb);
420 NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, net, sk, skb, 420 br_nf_hook_thresh(NF_BR_PRE_ROUTING, net, sk, skb, skb->dev, NULL,
421 skb->dev, NULL, 421 br_handle_frame_finish);
422 br_handle_frame_finish, 1);
423
424 return 0; 422 return 0;
425} 423}
426 424
@@ -992,6 +990,50 @@ static struct notifier_block brnf_notifier __read_mostly = {
992 .notifier_call = brnf_device_event, 990 .notifier_call = brnf_device_event,
993}; 991};
994 992
993/* recursively invokes nf_hook_slow (again), skipping already-called
994 * hooks (< NF_BR_PRI_BRNF).
995 *
996 * Called with rcu read lock held.
997 */
998int br_nf_hook_thresh(unsigned int hook, struct net *net,
999 struct sock *sk, struct sk_buff *skb,
1000 struct net_device *indev,
1001 struct net_device *outdev,
1002 int (*okfn)(struct net *, struct sock *,
1003 struct sk_buff *))
1004{
1005 struct nf_hook_ops *elem;
1006 struct nf_hook_state state;
1007 struct list_head *head;
1008 int ret;
1009
1010 head = &net->nf.hooks[NFPROTO_BRIDGE][hook];
1011
1012 list_for_each_entry_rcu(elem, head, list) {
1013 struct nf_hook_ops *next;
1014
1015 next = list_entry_rcu(list_next_rcu(&elem->list),
1016 struct nf_hook_ops, list);
1017 if (next->priority <= NF_BR_PRI_BRNF)
1018 continue;
1019 }
1020
1021 if (&elem->list == head)
1022 return okfn(net, sk, skb);
1023
1024 /* We may already have this, but read-locks nest anyway */
1025 rcu_read_lock();
1026 nf_hook_state_init(&state, head, hook, NF_BR_PRI_BRNF + 1,
1027 NFPROTO_BRIDGE, indev, outdev, sk, net, okfn);
1028
1029 ret = nf_hook_slow(skb, &state);
1030 rcu_read_unlock();
1031 if (ret == 1)
1032 ret = okfn(net, sk, skb);
1033
1034 return ret;
1035}
1036
995#ifdef CONFIG_SYSCTL 1037#ifdef CONFIG_SYSCTL
996static 1038static
997int brnf_sysctl_call_tables(struct ctl_table *ctl, int write, 1039int brnf_sysctl_call_tables(struct ctl_table *ctl, int write,
diff --git a/net/bridge/br_netfilter_ipv6.c b/net/bridge/br_netfilter_ipv6.c
index 5e59a8457e7b..5989661c659f 100644
--- a/net/bridge/br_netfilter_ipv6.c
+++ b/net/bridge/br_netfilter_ipv6.c
@@ -187,10 +187,9 @@ static int br_nf_pre_routing_finish_ipv6(struct net *net, struct sock *sk, struc
187 skb->dev = nf_bridge->physindev; 187 skb->dev = nf_bridge->physindev;
188 nf_bridge_update_protocol(skb); 188 nf_bridge_update_protocol(skb);
189 nf_bridge_push_encap_header(skb); 189 nf_bridge_push_encap_header(skb);
190 NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, 190 br_nf_hook_thresh(NF_BR_PRE_ROUTING,
191 net, sk, skb, skb->dev, NULL, 191 net, sk, skb, skb->dev, NULL,
192 br_nf_pre_routing_finish_bridge, 192 br_nf_pre_routing_finish_bridge);
193 1);
194 return 0; 193 return 0;
195 } 194 }
196 ether_addr_copy(eth_hdr(skb)->h_dest, dev->dev_addr); 195 ether_addr_copy(eth_hdr(skb)->h_dest, dev->dev_addr);
@@ -207,9 +206,8 @@ static int br_nf_pre_routing_finish_ipv6(struct net *net, struct sock *sk, struc
207 skb->dev = nf_bridge->physindev; 206 skb->dev = nf_bridge->physindev;
208 nf_bridge_update_protocol(skb); 207 nf_bridge_update_protocol(skb);
209 nf_bridge_push_encap_header(skb); 208 nf_bridge_push_encap_header(skb);
210 NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, net, sk, skb, 209 br_nf_hook_thresh(NF_BR_PRE_ROUTING, net, sk, skb,
211 skb->dev, NULL, 210 skb->dev, NULL, br_handle_frame_finish);
212 br_handle_frame_finish, 1);
213 211
214 return 0; 212 return 0;
215} 213}