diff options
author | Florian Westphal <fw@strlen.de> | 2016-09-21 11:35:01 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2016-09-24 15:25:48 -0400 |
commit | c5136b15ea364124299c8a9ba96b300e96061e3a (patch) | |
tree | c5ffa93a950d60bdc5bc0690743c5bc806cd0904 /net | |
parent | 50f4c7b73f831a53fa9ddeb9bdf4cfb5b23d3aa7 (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.c | 60 | ||||
-rw-r--r-- | net/bridge/br_netfilter_ipv6.c | 12 |
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 | */ | ||
998 | int 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 |
996 | static | 1038 | static |
997 | int brnf_sysctl_call_tables(struct ctl_table *ctl, int write, | 1039 | int 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 | } |