aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2015-03-10 05:27:18 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2015-03-10 10:03:02 -0400
commit1a4ba64d16a42c1b31d52b671accd7f9103e2626 (patch)
treef1f61462f14d2017965dae56d82cd05d947cc854 /net
parenta03a8dbe20eff6d57aae3147577bf84b52aba4e6 (diff)
netfilter: bridge: use rcu hook to resolve br_netfilter dependency
e5de75b ("netfilter: bridge: move DNAT helper to br_netfilter") results in the following link problem: net/bridge/br_device.c:29: undefined reference to `br_nf_prerouting_finish_bridge` Moreover it creates a hard dependency between br_netfilter and the bridge core, which is what we've been trying to avoid so far. Resolve this problem by using a hook structure so we reduce #ifdef pollution and keep bridge netfilter specific code under br_netfilter.c which was the original intention. Reported-by: Simon Horman <simon.horman@netronome.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br_device.c7
-rw-r--r--net/bridge/br_netfilter.c9
-rw-r--r--net/bridge/br_private.h10
3 files changed, 18 insertions, 8 deletions
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 294cbcc49263..4ff77a16956c 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -25,6 +25,9 @@
25#define COMMON_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | \ 25#define COMMON_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | \
26 NETIF_F_GSO_MASK | NETIF_F_HW_CSUM) 26 NETIF_F_GSO_MASK | NETIF_F_HW_CSUM)
27 27
28const struct nf_br_ops __rcu *nf_br_ops __read_mostly;
29EXPORT_SYMBOL_GPL(nf_br_ops);
30
28/* net device transmit always called with BH disabled */ 31/* net device transmit always called with BH disabled */
29netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) 32netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
30{ 33{
@@ -33,10 +36,12 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
33 struct net_bridge_fdb_entry *dst; 36 struct net_bridge_fdb_entry *dst;
34 struct net_bridge_mdb_entry *mdst; 37 struct net_bridge_mdb_entry *mdst;
35 struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats); 38 struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats);
39 const struct nf_br_ops *nf_ops;
36 u16 vid = 0; 40 u16 vid = 0;
37 41
38 rcu_read_lock(); 42 rcu_read_lock();
39 if (br_nf_prerouting_finish_bridge(skb)) { 43 nf_ops = rcu_dereference(nf_br_ops);
44 if (nf_ops && nf_ops->br_dev_xmit_hook(skb)) {
40 rcu_read_unlock(); 45 rcu_read_unlock();
41 return NETDEV_TX_OK; 46 return NETDEV_TX_OK;
42 } 47 }
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index a8361c7cdf81..b260a97275db 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -914,7 +914,7 @@ static void br_nf_pre_routing_finish_bridge_slow(struct sk_buff *skb)
914 br_handle_frame_finish(skb); 914 br_handle_frame_finish(skb);
915} 915}
916 916
917int br_nf_prerouting_finish_bridge(struct sk_buff *skb) 917static int br_nf_dev_xmit(struct sk_buff *skb)
918{ 918{
919 if (skb->nf_bridge && (skb->nf_bridge->mask & BRNF_BRIDGED_DNAT)) { 919 if (skb->nf_bridge && (skb->nf_bridge->mask & BRNF_BRIDGED_DNAT)) {
920 br_nf_pre_routing_finish_bridge_slow(skb); 920 br_nf_pre_routing_finish_bridge_slow(skb);
@@ -922,7 +922,10 @@ int br_nf_prerouting_finish_bridge(struct sk_buff *skb)
922 } 922 }
923 return 0; 923 return 0;
924} 924}
925EXPORT_SYMBOL_GPL(br_nf_prerouting_finish_bridge); 925
926static const struct nf_br_ops br_ops = {
927 .br_dev_xmit_hook = br_nf_dev_xmit,
928};
926 929
927void br_netfilter_enable(void) 930void br_netfilter_enable(void)
928{ 931{
@@ -1061,12 +1064,14 @@ static int __init br_netfilter_init(void)
1061 return -ENOMEM; 1064 return -ENOMEM;
1062 } 1065 }
1063#endif 1066#endif
1067 RCU_INIT_POINTER(nf_br_ops, &br_ops);
1064 printk(KERN_NOTICE "Bridge firewalling registered\n"); 1068 printk(KERN_NOTICE "Bridge firewalling registered\n");
1065 return 0; 1069 return 0;
1066} 1070}
1067 1071
1068static void __exit br_netfilter_fini(void) 1072static void __exit br_netfilter_fini(void)
1069{ 1073{
1074 RCU_INIT_POINTER(nf_br_ops, NULL);
1070 nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops)); 1075 nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
1071#ifdef CONFIG_SYSCTL 1076#ifdef CONFIG_SYSCTL
1072 unregister_net_sysctl_table(brnf_sysctl_header); 1077 unregister_net_sysctl_table(brnf_sysctl_header);
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index f0a0438dbd6d..b46fa0c5b8ec 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -763,17 +763,17 @@ static inline int br_vlan_enabled(struct net_bridge *br)
763} 763}
764#endif 764#endif
765 765
766struct nf_br_ops {
767 int (*br_dev_xmit_hook)(struct sk_buff *skb);
768};
769extern const struct nf_br_ops __rcu *nf_br_ops;
770
766/* br_netfilter.c */ 771/* br_netfilter.c */
767#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) 772#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
768int br_nf_prerouting_finish_bridge(struct sk_buff *skb);
769int br_nf_core_init(void); 773int br_nf_core_init(void);
770void br_nf_core_fini(void); 774void br_nf_core_fini(void);
771void br_netfilter_rtable_init(struct net_bridge *); 775void br_netfilter_rtable_init(struct net_bridge *);
772#else 776#else
773static inline int br_nf_prerouting_finish_bridge(struct sk_buff *skb)
774{
775 return 0;
776}
777static inline int br_nf_core_init(void) { return 0; } 777static inline int br_nf_core_init(void) { return 0; }
778static inline void br_nf_core_fini(void) {} 778static inline void br_nf_core_fini(void) {}
779#define br_netfilter_rtable_init(x) 779#define br_netfilter_rtable_init(x)