From: Felix Fietkau Date: Wed, 9 Sep 2015 18:40:15 +0000 (+0000) Subject: generic: Fix per interface nf_call_iptables setting X-Git-Tag: reboot~2095 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=5fcafa319d25ca79638e7d705cc4fd097b8bf33b;p=openwrt%2Fstaging%2Fjogo.git generic: Fix per interface nf_call_iptables setting commit r30917 ("kernel: bypass all netfilter hooks if the sysctls for that functionality have been disabled - eliminates the overhead of enabling CONFIG_BRIDGE_NETFILTER in the kernel config") introduced an optimization which should reduce/eliminate the overhead for traffic send over bridges on kernels compiled with CONFIG_BRIDGE_NETFILTER=y. But this optimization breaks the nf_call_iptables per bridge setting which is more fine grained than the global sysctl net.bridge.bridge-nf-call-iptables setting. A test reflecting a real world setup was created to identify if this really eliminates the overhead and if per-bridge nf_call_iptables could be used in some setups to increase the throughput. A Qualcomm Atheros QCA9558 based system with one ethernet and an ath9k wifi 3x3 in HT40 mode was used. Cables from the AP to the wifi station were used to reduce interference problems during the tests. The wlan interface was put in one bridge interface called br-wlan. This bridge usually contains some more wlan interfaces. The eth0 was put in a second bridge called br-lan. This usually contains some other privileged wlan or mesh interfaces. Routing was added between br-lan and br-wlan. Three kernels were tested: * (default) OpenWrt kernel for this device * (brfilter-global) OpenWrt kernel with CONFIG_BRIDGE_NETFILTER=y * (brfilter-local) OpenWrt kernel with CONFIG_BRIDGE_NETFILTER=y and without 644-bridge_optimize_netfilter_hooks.patch The changes to the the netfilter settings of the bridge were done via: * (brfilter-global) /sbin/sysctl -w net.bridge.bridge-nf-call-iptables=1 * (brfilter-lobal) echo 1 > /sys/class/net/br-lan/bridge/nf_call_iptables and/or echo 1 > /sys/class/net/br-wan/bridge/nf_call_iptables A station connected to the wlan0 (AP) interface was used to send traffic to a PC connected via ethernet. iperf with 3 concurrent transmissions was used to generate the traffic. | kernel | br-nf-* global | nf-call* iface | download | upload | |-----------------|----------------|----------------|----------|----------| | default | 0 | - | 209 | 268 | | brfilter-global | 0 | - | 185 | 243 | | brfilter-local | 0 | - | 187 | 243 | | brfilter-local | 0 | br-lan | 157 | 226 | | brfilter-local | 0 | br-lan br-wlan | 139 | 161 | | brfilter-global | 1 | - | 136 | 162 | Download/upload results in Mibit/s It can be seen that the patch doesn't eliminate the overhead. It can also be seen that the throughput of brfilter-global and brfilter-local with disabled filtering is the roughly the same. Also the throughput for brfilter-global and brfilter-local for enabled filtering on all bridges is roughly the same. But also the brfilter-local throughput is higher when only br-lan requires the filtering. This setting would not be possible with 644-bridge_optimize_netfilter_hooks.patch applied and thus can only be compared with brfilter-global and filtering enabled for all interfaces. Signed-off-by: Sven Eckelmann SVN-Revision: 46835 --- diff --git a/target/linux/generic/patches-3.18/644-bridge_optimize_netfilter_hooks.patch b/target/linux/generic/patches-3.18/644-bridge_optimize_netfilter_hooks.patch deleted file mode 100644 index 3572661745..0000000000 --- a/target/linux/generic/patches-3.18/644-bridge_optimize_netfilter_hooks.patch +++ /dev/null @@ -1,179 +0,0 @@ -From: Felix Fietkau -Subject: [PATCH] bridge: optimize netfilter hooks - -Bypass all netfilter hooks if the sysctls for that functionality have -been disabled - eliminates the overhead of enabling -CONFIG_BRIDGE_NETFILTER in the kernel config ---- ---- a/net/bridge/br_forward.c -+++ b/net/bridge/br_forward.c -@@ -53,7 +53,7 @@ EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit - - int br_forward_finish(struct sk_buff *skb) - { -- return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev, -+ return BR_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev, - br_dev_queue_push_xmit); - - } -@@ -77,7 +77,7 @@ static void __br_deliver(const struct ne - return; - } - -- NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, -+ BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, - br_forward_finish); - } - -@@ -98,7 +98,7 @@ static void __br_forward(const struct ne - skb->dev = to->dev; - skb_forward_csum(skb); - -- NF_HOOK(NFPROTO_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev, -+ BR_HOOK(NFPROTO_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev, - br_forward_finish); - } - ---- a/net/bridge/br_input.c -+++ b/net/bridge/br_input.c -@@ -53,7 +53,7 @@ static int br_pass_frame_up(struct sk_bu - if (!skb) - return NET_RX_DROP; - -- return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL, -+ return BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL, - netif_receive_skb); - } - -@@ -219,7 +219,7 @@ rx_handler_result_t br_handle_frame(stru - } - - /* Deliver packet to local host only */ -- if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, -+ if (BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, - NULL, br_handle_local_finish)) { - return RX_HANDLER_CONSUMED; /* consumed by filter */ - } else { -@@ -234,7 +234,7 @@ forward: - if (ether_addr_equal(p->br->dev->dev_addr, dest)) - skb->pkt_type = PACKET_HOST; - -- if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, -+ if (BR_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, - br_handle_local_finish)) - break; - -@@ -256,7 +256,7 @@ forward: - if (ether_addr_equal(p->br->dev->dev_addr, dest)) - skb->pkt_type = PACKET_HOST; - -- NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, -+ BR_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, - br_handle_frame_finish); - break; - default: ---- a/net/bridge/br_multicast.c -+++ b/net/bridge/br_multicast.c -@@ -814,7 +814,7 @@ static void __br_multicast_send_query(st - - if (port) { - skb->dev = port->dev; -- NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, -+ BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, - br_dev_queue_push_xmit); - } else { - br_multicast_select_own_querier(br, ip, skb); ---- a/net/bridge/br_netfilter.c -+++ b/net/bridge/br_netfilter.c -@@ -73,6 +73,15 @@ static int brnf_pass_vlan_indev __read_m - #define IS_ARP(skb) \ - (!vlan_tx_tag_present(skb) && skb->protocol == htons(ETH_P_ARP)) - -+int brnf_call_ebtables __read_mostly = 0; -+EXPORT_SYMBOL_GPL(brnf_call_ebtables); -+ -+bool br_netfilter_run_hooks(void) -+{ -+ return brnf_call_iptables | brnf_call_ip6tables | brnf_call_arptables | -+ brnf_call_ebtables; -+} -+ - static inline __be16 vlan_proto(const struct sk_buff *skb) - { - if (vlan_tx_tag_present(skb)) ---- a/net/bridge/br_private.h -+++ b/net/bridge/br_private.h -@@ -778,6 +778,24 @@ static inline void br_nf_core_fini(void) - #define br_netfilter_rtable_init(x) - #endif - -+#if IS_BUILTIN(CONFIG_BRIDGE_NETFILTER) -+extern int brnf_call_ebtables; -+bool br_netfilter_run_hooks(void); -+#else -+#define br_netfilter_run_hooks() false -+#endif -+ -+static inline int -+BR_HOOK(uint8_t pf, unsigned int hook, struct sk_buff *skb, -+ struct net_device *in, struct net_device *out, -+ int (*okfn)(struct sk_buff *)) -+{ -+ if (!br_netfilter_run_hooks()) -+ return okfn(skb); -+ -+ return NF_HOOK(pf, hook, skb, in, out, okfn); -+} -+ - /* br_stp.c */ - void br_log_state(const struct net_bridge_port *p); - void br_set_state(struct net_bridge_port *p, unsigned int state); ---- a/net/bridge/br_stp_bpdu.c -+++ b/net/bridge/br_stp_bpdu.c -@@ -54,7 +54,7 @@ static void br_send_bpdu(struct net_brid - - skb_reset_mac_header(skb); - -- NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, -+ BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, - dev_queue_xmit); - } - ---- a/net/bridge/netfilter/ebtables.c -+++ b/net/bridge/netfilter/ebtables.c -@@ -2414,11 +2414,19 @@ static int __init ebtables_init(void) - } - - printk(KERN_INFO "Ebtables v2.0 registered\n"); -+ -+#if IS_BUILTIN(CONFIG_BRIDGE_NETFILTER) -+ brnf_call_ebtables = 1; -+#endif -+ - return 0; - } - - static void __exit ebtables_fini(void) - { -+#if IS_BUILTIN(CONFIG_BRIDGE_NETFILTER) -+ brnf_call_ebtables = 0; -+#endif - nf_unregister_sockopt(&ebt_sockopts); - xt_unregister_target(&ebt_standard_target); - printk(KERN_INFO "Ebtables v2.0 unregistered\n"); ---- a/net/Kconfig -+++ b/net/Kconfig -@@ -177,11 +177,11 @@ config NETFILTER_ADVANCED - If unsure, say Y. - - config BRIDGE_NETFILTER -- tristate "Bridged IP/ARP packets filtering" -+ bool "Bridged IP/ARP packets filtering" - depends on BRIDGE - depends on NETFILTER && INET - depends on NETFILTER_ADVANCED -- default m -+ default y - ---help--- - Enabling this option will let arptables resp. iptables see bridged - ARP resp. IP traffic. If you want a bridging firewall, you probably diff --git a/target/linux/generic/patches-4.0/644-bridge_optimize_netfilter_hooks.patch b/target/linux/generic/patches-4.0/644-bridge_optimize_netfilter_hooks.patch deleted file mode 100644 index 8a11ae3f40..0000000000 --- a/target/linux/generic/patches-4.0/644-bridge_optimize_netfilter_hooks.patch +++ /dev/null @@ -1,179 +0,0 @@ -From: Felix Fietkau -Subject: [PATCH] bridge: optimize netfilter hooks - -Bypass all netfilter hooks if the sysctls for that functionality have -been disabled - eliminates the overhead of enabling -CONFIG_BRIDGE_NETFILTER in the kernel config ---- ---- a/net/bridge/br_forward.c -+++ b/net/bridge/br_forward.c -@@ -53,7 +53,7 @@ EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit - - int br_forward_finish(struct sk_buff *skb) - { -- return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev, -+ return BR_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev, - br_dev_queue_push_xmit); - - } -@@ -77,7 +77,7 @@ static void __br_deliver(const struct ne - return; - } - -- NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, -+ BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, - br_forward_finish); - } - -@@ -98,7 +98,7 @@ static void __br_forward(const struct ne - skb->dev = to->dev; - skb_forward_csum(skb); - -- NF_HOOK(NFPROTO_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev, -+ BR_HOOK(NFPROTO_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev, - br_forward_finish); - } - ---- a/net/bridge/br_input.c -+++ b/net/bridge/br_input.c -@@ -55,7 +55,7 @@ static int br_pass_frame_up(struct sk_bu - if (!skb) - return NET_RX_DROP; - -- return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL, -+ return BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL, - netif_receive_skb); - } - -@@ -280,7 +280,7 @@ rx_handler_result_t br_handle_frame(stru - } - - /* Deliver packet to local host only */ -- if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, -+ if (BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, - NULL, br_handle_local_finish)) { - return RX_HANDLER_CONSUMED; /* consumed by filter */ - } else { -@@ -295,7 +295,7 @@ forward: - if (ether_addr_equal(p->br->dev->dev_addr, dest)) - skb->pkt_type = PACKET_HOST; - -- if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, -+ if (BR_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, - br_handle_local_finish)) - break; - -@@ -317,7 +317,7 @@ forward: - if (ether_addr_equal(p->br->dev->dev_addr, dest)) - skb->pkt_type = PACKET_HOST; - -- NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, -+ BR_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, - br_handle_frame_finish); - break; - default: ---- a/net/bridge/br_multicast.c -+++ b/net/bridge/br_multicast.c -@@ -814,7 +814,7 @@ static void __br_multicast_send_query(st - - if (port) { - skb->dev = port->dev; -- NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, -+ BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, - br_dev_queue_push_xmit); - } else { - br_multicast_select_own_querier(br, ip, skb); ---- a/net/bridge/br_netfilter.c -+++ b/net/bridge/br_netfilter.c -@@ -74,6 +74,15 @@ static int brnf_pass_vlan_indev __read_m - #define IS_ARP(skb) \ - (!skb_vlan_tag_present(skb) && skb->protocol == htons(ETH_P_ARP)) - -+int brnf_call_ebtables __read_mostly = 0; -+EXPORT_SYMBOL_GPL(brnf_call_ebtables); -+ -+bool br_netfilter_run_hooks(void) -+{ -+ return brnf_call_iptables | brnf_call_ip6tables | brnf_call_arptables | -+ brnf_call_ebtables; -+} -+ - static inline __be16 vlan_proto(const struct sk_buff *skb) - { - if (skb_vlan_tag_present(skb)) ---- a/net/bridge/br_private.h -+++ b/net/bridge/br_private.h -@@ -773,6 +773,24 @@ static inline void br_nf_core_fini(void) - #define br_netfilter_rtable_init(x) - #endif - -+#if IS_BUILTIN(CONFIG_BRIDGE_NETFILTER) -+extern int brnf_call_ebtables; -+bool br_netfilter_run_hooks(void); -+#else -+#define br_netfilter_run_hooks() false -+#endif -+ -+static inline int -+BR_HOOK(uint8_t pf, unsigned int hook, struct sk_buff *skb, -+ struct net_device *in, struct net_device *out, -+ int (*okfn)(struct sk_buff *)) -+{ -+ if (!br_netfilter_run_hooks()) -+ return okfn(skb); -+ -+ return NF_HOOK(pf, hook, skb, in, out, okfn); -+} -+ - /* br_stp.c */ - void br_log_state(const struct net_bridge_port *p); - void br_set_state(struct net_bridge_port *p, unsigned int state); ---- a/net/bridge/br_stp_bpdu.c -+++ b/net/bridge/br_stp_bpdu.c -@@ -54,7 +54,7 @@ static void br_send_bpdu(struct net_brid - - skb_reset_mac_header(skb); - -- NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, -+ BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, - dev_queue_xmit); - } - ---- a/net/bridge/netfilter/ebtables.c -+++ b/net/bridge/netfilter/ebtables.c -@@ -2414,11 +2414,19 @@ static int __init ebtables_init(void) - } - - printk(KERN_INFO "Ebtables v2.0 registered\n"); -+ -+#if IS_BUILTIN(CONFIG_BRIDGE_NETFILTER) -+ brnf_call_ebtables = 1; -+#endif -+ - return 0; - } - - static void __exit ebtables_fini(void) - { -+#if IS_BUILTIN(CONFIG_BRIDGE_NETFILTER) -+ brnf_call_ebtables = 0; -+#endif - nf_unregister_sockopt(&ebt_sockopts); - xt_unregister_target(&ebt_standard_target); - printk(KERN_INFO "Ebtables v2.0 unregistered\n"); ---- a/net/Kconfig -+++ b/net/Kconfig -@@ -177,11 +177,11 @@ config NETFILTER_ADVANCED - If unsure, say Y. - - config BRIDGE_NETFILTER -- tristate "Bridged IP/ARP packets filtering" -+ bool "Bridged IP/ARP packets filtering" - depends on BRIDGE - depends on NETFILTER && INET - depends on NETFILTER_ADVANCED -- default m -+ default y - ---help--- - Enabling this option will let arptables resp. iptables see bridged - ARP resp. IP traffic. If you want a bridging firewall, you probably diff --git a/target/linux/generic/patches-4.1/644-bridge_optimize_netfilter_hooks.patch b/target/linux/generic/patches-4.1/644-bridge_optimize_netfilter_hooks.patch deleted file mode 100644 index f338e05d53..0000000000 --- a/target/linux/generic/patches-4.1/644-bridge_optimize_netfilter_hooks.patch +++ /dev/null @@ -1,179 +0,0 @@ -From: Felix Fietkau -Subject: [PATCH] bridge: optimize netfilter hooks - -Bypass all netfilter hooks if the sysctls for that functionality have -been disabled - eliminates the overhead of enabling -CONFIG_BRIDGE_NETFILTER in the kernel config ---- ---- a/net/bridge/br_forward.c -+++ b/net/bridge/br_forward.c -@@ -51,7 +51,7 @@ EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit - - int br_forward_finish(struct sock *sk, struct sk_buff *skb) - { -- return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, sk, skb, -+ return BR_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, sk, skb, - NULL, skb->dev, - br_dev_queue_push_xmit); - -@@ -76,7 +76,7 @@ static void __br_deliver(const struct ne - return; - } - -- NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, NULL, skb, -+ BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, NULL, skb, - NULL, skb->dev, - br_forward_finish); - } -@@ -98,7 +98,7 @@ static void __br_forward(const struct ne - skb->dev = to->dev; - skb_forward_csum(skb); - -- NF_HOOK(NFPROTO_BRIDGE, NF_BR_FORWARD, NULL, skb, -+ BR_HOOK(NFPROTO_BRIDGE, NF_BR_FORWARD, NULL, skb, - indev, skb->dev, - br_forward_finish); - } ---- a/net/bridge/br_input.c -+++ b/net/bridge/br_input.c -@@ -55,7 +55,7 @@ static int br_pass_frame_up(struct sk_bu - if (!skb) - return NET_RX_DROP; - -- return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, NULL, skb, -+ return BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, NULL, skb, - indev, NULL, - netif_receive_skb_sk); - } -@@ -284,7 +284,7 @@ rx_handler_result_t br_handle_frame(stru - } - - /* Deliver packet to local host only */ -- if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, NULL, skb, -+ if (BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, NULL, skb, - skb->dev, NULL, br_handle_local_finish)) { - return RX_HANDLER_CONSUMED; /* consumed by filter */ - } else { -@@ -299,7 +299,7 @@ forward: - if (ether_addr_equal(p->br->dev->dev_addr, dest)) - skb->pkt_type = PACKET_HOST; - -- if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, NULL, skb, skb->dev, NULL, -+ if (BR_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, NULL, skb, skb->dev, NULL, - br_handle_local_finish)) - break; - -@@ -321,7 +321,7 @@ forward: - if (ether_addr_equal(p->br->dev->dev_addr, dest)) - skb->pkt_type = PACKET_HOST; - -- NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, NULL, skb, -+ BR_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, NULL, skb, - skb->dev, NULL, - br_handle_frame_finish); - break; ---- a/net/bridge/br_multicast.c -+++ b/net/bridge/br_multicast.c -@@ -814,7 +814,7 @@ static void __br_multicast_send_query(st - - if (port) { - skb->dev = port->dev; -- NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, NULL, skb, -+ BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, NULL, skb, - NULL, skb->dev, - br_dev_queue_push_xmit); - } else { ---- a/net/bridge/br_netfilter.c -+++ b/net/bridge/br_netfilter.c -@@ -69,6 +69,15 @@ static int brnf_pass_vlan_indev __read_m - #define IS_ARP(skb) \ - (!skb_vlan_tag_present(skb) && skb->protocol == htons(ETH_P_ARP)) - -+int brnf_call_ebtables __read_mostly = 0; -+EXPORT_SYMBOL_GPL(brnf_call_ebtables); -+ -+bool br_netfilter_run_hooks(void) -+{ -+ return brnf_call_iptables | brnf_call_ip6tables | brnf_call_arptables | -+ brnf_call_ebtables; -+} -+ - static inline __be16 vlan_proto(const struct sk_buff *skb) - { - if (skb_vlan_tag_present(skb)) ---- a/net/bridge/br_private.h -+++ b/net/bridge/br_private.h -@@ -779,6 +779,24 @@ static inline void br_nf_core_fini(void) - #define br_netfilter_rtable_init(x) - #endif - -+#if IS_BUILTIN(CONFIG_BRIDGE_NETFILTER) -+extern int brnf_call_ebtables; -+bool br_netfilter_run_hooks(void); -+#else -+#define br_netfilter_run_hooks() false -+#endif -+ -+static inline int -+BR_HOOK(uint8_t pf, unsigned int hook, struct sock *sk, struct sk_buff *skb, -+ struct net_device *in, struct net_device *out, -+ int (*okfn)(struct sock *, struct sk_buff *)) -+{ -+ if (!br_netfilter_run_hooks()) -+ return okfn(sk, skb); -+ -+ return NF_HOOK(pf, hook, sk, skb, in, out, okfn); -+} -+ - /* br_stp.c */ - void br_log_state(const struct net_bridge_port *p); - void br_set_state(struct net_bridge_port *p, unsigned int state); ---- a/net/bridge/br_stp_bpdu.c -+++ b/net/bridge/br_stp_bpdu.c -@@ -54,7 +54,7 @@ static void br_send_bpdu(struct net_brid - - skb_reset_mac_header(skb); - -- NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, NULL, skb, -+ BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, NULL, skb, - NULL, skb->dev, - dev_queue_xmit_sk); - } ---- a/net/bridge/netfilter/ebtables.c -+++ b/net/bridge/netfilter/ebtables.c -@@ -2414,11 +2414,19 @@ static int __init ebtables_init(void) - } - - printk(KERN_INFO "Ebtables v2.0 registered\n"); -+ -+#if IS_BUILTIN(CONFIG_BRIDGE_NETFILTER) -+ brnf_call_ebtables = 1; -+#endif -+ - return 0; - } - - static void __exit ebtables_fini(void) - { -+#if IS_BUILTIN(CONFIG_BRIDGE_NETFILTER) -+ brnf_call_ebtables = 0; -+#endif - nf_unregister_sockopt(&ebt_sockopts); - xt_unregister_target(&ebt_standard_target); - printk(KERN_INFO "Ebtables v2.0 unregistered\n"); ---- a/net/Kconfig -+++ b/net/Kconfig -@@ -177,11 +177,11 @@ config NETFILTER_ADVANCED - If unsure, say Y. - - config BRIDGE_NETFILTER -- tristate "Bridged IP/ARP packets filtering" -+ bool "Bridged IP/ARP packets filtering" - depends on BRIDGE - depends on NETFILTER && INET - depends on NETFILTER_ADVANCED -- default m -+ default y - ---help--- - Enabling this option will let arptables resp. iptables see bridged - ARP resp. IP traffic. If you want a bridging firewall, you probably