Skip to content

Commit 34666d4

Browse files
committed
netfilter: bridge: move br_netfilter out of the core
Jesper reported that br_netfilter always registers the hooks since this is part of the bridge core. This harms performance for people that don't need this. This patch modularizes br_netfilter so it can be rmmod'ed, thus, the hooks can be unregistered. I think the bridge netfilter should have been a separated module since the beginning, Patrick agreed on that. Note that this is breaking compatibility for users that expect that bridge netfilter is going to be available after explicitly 'modprobe bridge' or via automatic load through brctl. However, the damage can be easily undone by modprobing br_netfilter. The bridge core also spots a message to provide a clue to people that didn't notice that this has been deprecated. On top of that, the plan is that nftables will not rely on this software layer, but integrate the connection tracking into the bridge layer to enable stateful filtering and NAT, which is was bridge netfilter users seem to require. This patch still keeps the fake_dst_ops in the bridge core, since this is required by when the bridge port is initialized. So we can safely modprobe/rmmod br_netfilter anytime. Signed-off-by: Pablo Neira Ayuso <[email protected]> Acked-by: Florian Westphal <[email protected]>
1 parent 7276ca3 commit 34666d4

File tree

16 files changed

+151
-104
lines changed

16 files changed

+151
-104
lines changed

include/linux/netfilter_bridge.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ enum nf_br_hook_priorities {
1515
NF_BR_PRI_LAST = INT_MAX,
1616
};
1717

18-
#ifdef CONFIG_BRIDGE_NETFILTER
18+
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
1919

2020
#define BRNF_PKT_TYPE 0x01
2121
#define BRNF_BRIDGED_DNAT 0x02

include/linux/skbuff.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ struct nf_conntrack {
156156
};
157157
#endif
158158

159-
#ifdef CONFIG_BRIDGE_NETFILTER
159+
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
160160
struct nf_bridge_info {
161161
atomic_t use;
162162
unsigned int mask;
@@ -560,7 +560,7 @@ struct sk_buff {
560560
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
561561
struct nf_conntrack *nfct;
562562
#endif
563-
#ifdef CONFIG_BRIDGE_NETFILTER
563+
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
564564
struct nf_bridge_info *nf_bridge;
565565
#endif
566566

@@ -2977,7 +2977,7 @@ static inline void nf_conntrack_get(struct nf_conntrack *nfct)
29772977
atomic_inc(&nfct->use);
29782978
}
29792979
#endif
2980-
#ifdef CONFIG_BRIDGE_NETFILTER
2980+
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
29812981
static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge)
29822982
{
29832983
if (nf_bridge && atomic_dec_and_test(&nf_bridge->use))
@@ -2995,7 +2995,7 @@ static inline void nf_reset(struct sk_buff *skb)
29952995
nf_conntrack_put(skb->nfct);
29962996
skb->nfct = NULL;
29972997
#endif
2998-
#ifdef CONFIG_BRIDGE_NETFILTER
2998+
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
29992999
nf_bridge_put(skb->nf_bridge);
30003000
skb->nf_bridge = NULL;
30013001
#endif
@@ -3016,7 +3016,7 @@ static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src)
30163016
nf_conntrack_get(src->nfct);
30173017
dst->nfctinfo = src->nfctinfo;
30183018
#endif
3019-
#ifdef CONFIG_BRIDGE_NETFILTER
3019+
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
30203020
dst->nf_bridge = src->nf_bridge;
30213021
nf_bridge_get(src->nf_bridge);
30223022
#endif
@@ -3030,7 +3030,7 @@ static inline void nf_copy(struct sk_buff *dst, const struct sk_buff *src)
30303030
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
30313031
nf_conntrack_put(dst->nfct);
30323032
#endif
3033-
#ifdef CONFIG_BRIDGE_NETFILTER
3033+
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
30343034
nf_bridge_put(dst->nf_bridge);
30353035
#endif
30363036
__nf_copy(dst, src);

include/net/neighbour.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
373373
return 0;
374374
}
375375

376-
#ifdef CONFIG_BRIDGE_NETFILTER
376+
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
377377
static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb)
378378
{
379379
unsigned int seq, hh_alen;

include/net/netfilter/ipv4/nf_reject.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ static void nf_send_reset(struct sk_buff *oldskb, int hook)
9898

9999
nf_ct_attach(nskb, oldskb);
100100

101-
#ifdef CONFIG_BRIDGE_NETFILTER
101+
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
102102
/* If we use ip_local_out for bridged traffic, the MAC source on
103103
* the RST will be ours, instead of the destination's. This confuses
104104
* some routers/firewalls, and they drop the packet. So we need to

include/net/netfilter/ipv6/nf_reject.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ static void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
147147

148148
nf_ct_attach(nskb, oldskb);
149149

150-
#ifdef CONFIG_BRIDGE_NETFILTER
150+
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
151151
/* If we use ip6_local_out for bridged traffic, the MAC source on
152152
* the RST will be ours, instead of the destination's. This confuses
153153
* some routers/firewalls, and they drop the packet. So we need to

net/Kconfig

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,10 +176,11 @@ config NETFILTER_ADVANCED
176176
If unsure, say Y.
177177

178178
config BRIDGE_NETFILTER
179-
bool "Bridged IP/ARP packets filtering"
180-
depends on BRIDGE && NETFILTER && INET
179+
tristate "Bridged IP/ARP packets filtering"
180+
depends on (BRIDGE || BRIDGE=n)
181+
depends on NETFILTER && INET
181182
depends on NETFILTER_ADVANCED
182-
default y
183+
default m
183184
---help---
184185
Enabling this option will let arptables resp. iptables see bridged
185186
ARP resp. IP traffic. If you want a bridging firewall, you probably

net/bridge/Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ obj-$(CONFIG_BRIDGE) += bridge.o
66

77
bridge-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \
88
br_ioctl.o br_stp.o br_stp_bpdu.o \
9-
br_stp_if.o br_stp_timer.o br_netlink.o
9+
br_stp_if.o br_stp_timer.o br_netlink.o \
10+
br_nf_core.o
1011

1112
bridge-$(CONFIG_SYSFS) += br_sysfs_if.o br_sysfs_br.o
1213

13-
bridge-$(CONFIG_BRIDGE_NETFILTER) += br_netfilter.o
14+
obj-$(CONFIG_BRIDGE_NETFILTER) += br_netfilter.o
1415

1516
bridge-$(CONFIG_BRIDGE_IGMP_SNOOPING) += br_multicast.o br_mdb.o
1617

net/bridge/br.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ static int __init br_init(void)
161161
if (err)
162162
goto err_out1;
163163

164-
err = br_netfilter_init();
164+
err = br_nf_core_init();
165165
if (err)
166166
goto err_out2;
167167

@@ -179,11 +179,16 @@ static int __init br_init(void)
179179
br_fdb_test_addr_hook = br_fdb_test_addr;
180180
#endif
181181

182+
pr_info("bridge: automatic filtering via arp/ip/ip6tables has been "
183+
"deprecated. Update your scripts to load br_netfilter if you "
184+
"need this.\n");
185+
182186
return 0;
187+
183188
err_out4:
184189
unregister_netdevice_notifier(&br_device_notifier);
185190
err_out3:
186-
br_netfilter_fini();
191+
br_nf_core_fini();
187192
err_out2:
188193
unregister_pernet_subsys(&br_net_ops);
189194
err_out1:
@@ -196,20 +201,17 @@ static int __init br_init(void)
196201
static void __exit br_deinit(void)
197202
{
198203
stp_proto_unregister(&br_stp_proto);
199-
200204
br_netlink_fini();
201205
unregister_netdevice_notifier(&br_device_notifier);
202206
brioctl_set(NULL);
203-
204207
unregister_pernet_subsys(&br_net_ops);
205208

206209
rcu_barrier(); /* Wait for completion of call_rcu()'s */
207210

208-
br_netfilter_fini();
211+
br_nf_core_fini();
209212
#if IS_ENABLED(CONFIG_ATM_LANE)
210213
br_fdb_test_addr_hook = NULL;
211214
#endif
212-
213215
br_fdb_fini();
214216
}
215217

net/bridge/br_device.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
3636
u16 vid = 0;
3737

3838
rcu_read_lock();
39-
#ifdef CONFIG_BRIDGE_NETFILTER
39+
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
4040
if (skb->nf_bridge && (skb->nf_bridge->mask & BRNF_BRIDGED_DNAT)) {
4141
br_nf_pre_routing_finish_bridge_slow(skb);
4242
rcu_read_unlock();
@@ -167,7 +167,7 @@ static int br_change_mtu(struct net_device *dev, int new_mtu)
167167

168168
dev->mtu = new_mtu;
169169

170-
#ifdef CONFIG_BRIDGE_NETFILTER
170+
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
171171
/* remember the MTU in the rtable for PMTU */
172172
dst_metric_set(&br->fake_rtable.dst, RTAX_MTU, new_mtu);
173173
#endif

net/bridge/br_forward.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,15 @@ int br_dev_queue_push_xmit(struct sk_buff *skb)
4949

5050
return 0;
5151
}
52+
EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit);
5253

5354
int br_forward_finish(struct sk_buff *skb)
5455
{
5556
return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev,
5657
br_dev_queue_push_xmit);
5758

5859
}
60+
EXPORT_SYMBOL_GPL(br_forward_finish);
5961

6062
static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
6163
{

net/bridge/br_input.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
140140
kfree_skb(skb);
141141
goto out;
142142
}
143+
EXPORT_SYMBOL_GPL(br_handle_frame_finish);
143144

144145
/* note: already called with rcu_read_lock */
145146
static int br_handle_local_finish(struct sk_buff *skb)

net/bridge/br_netfilter.c

Lines changed: 16 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -111,66 +111,6 @@ static inline __be16 pppoe_proto(const struct sk_buff *skb)
111111
pppoe_proto(skb) == htons(PPP_IPV6) && \
112112
brnf_filter_pppoe_tagged)
113113

114-
static void fake_update_pmtu(struct dst_entry *dst, struct sock *sk,
115-
struct sk_buff *skb, u32 mtu)
116-
{
117-
}
118-
119-
static void fake_redirect(struct dst_entry *dst, struct sock *sk,
120-
struct sk_buff *skb)
121-
{
122-
}
123-
124-
static u32 *fake_cow_metrics(struct dst_entry *dst, unsigned long old)
125-
{
126-
return NULL;
127-
}
128-
129-
static struct neighbour *fake_neigh_lookup(const struct dst_entry *dst,
130-
struct sk_buff *skb,
131-
const void *daddr)
132-
{
133-
return NULL;
134-
}
135-
136-
static unsigned int fake_mtu(const struct dst_entry *dst)
137-
{
138-
return dst->dev->mtu;
139-
}
140-
141-
static struct dst_ops fake_dst_ops = {
142-
.family = AF_INET,
143-
.protocol = cpu_to_be16(ETH_P_IP),
144-
.update_pmtu = fake_update_pmtu,
145-
.redirect = fake_redirect,
146-
.cow_metrics = fake_cow_metrics,
147-
.neigh_lookup = fake_neigh_lookup,
148-
.mtu = fake_mtu,
149-
};
150-
151-
/*
152-
* Initialize bogus route table used to keep netfilter happy.
153-
* Currently, we fill in the PMTU entry because netfilter
154-
* refragmentation needs it, and the rt_flags entry because
155-
* ipt_REJECT needs it. Future netfilter modules might
156-
* require us to fill additional fields.
157-
*/
158-
static const u32 br_dst_default_metrics[RTAX_MAX] = {
159-
[RTAX_MTU - 1] = 1500,
160-
};
161-
162-
void br_netfilter_rtable_init(struct net_bridge *br)
163-
{
164-
struct rtable *rt = &br->fake_rtable;
165-
166-
atomic_set(&rt->dst.__refcnt, 1);
167-
rt->dst.dev = br->dev;
168-
rt->dst.path = &rt->dst;
169-
dst_init_metrics(&rt->dst, br_dst_default_metrics, true);
170-
rt->dst.flags = DST_NOXFRM | DST_FAKE_RTABLE;
171-
rt->dst.ops = &fake_dst_ops;
172-
}
173-
174114
static inline struct rtable *bridge_parent_rtable(const struct net_device *dev)
175115
{
176116
struct net_bridge_port *port;
@@ -1031,38 +971,42 @@ static struct ctl_table brnf_table[] = {
1031971
};
1032972
#endif
1033973

1034-
int __init br_netfilter_init(void)
974+
static int __init br_netfilter_init(void)
1035975
{
1036976
int ret;
1037977

1038-
ret = dst_entries_init(&fake_dst_ops);
978+
ret = nf_register_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
1039979
if (ret < 0)
1040980
return ret;
1041981

1042-
ret = nf_register_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
1043-
if (ret < 0) {
1044-
dst_entries_destroy(&fake_dst_ops);
1045-
return ret;
1046-
}
1047982
#ifdef CONFIG_SYSCTL
1048983
brnf_sysctl_header = register_net_sysctl(&init_net, "net/bridge", brnf_table);
1049984
if (brnf_sysctl_header == NULL) {
1050985
printk(KERN_WARNING
1051986
"br_netfilter: can't register to sysctl.\n");
1052-
nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
1053-
dst_entries_destroy(&fake_dst_ops);
1054-
return -ENOMEM;
987+
ret = -ENOMEM;
988+
goto err1;
1055989
}
1056990
#endif
1057991
printk(KERN_NOTICE "Bridge firewalling registered\n");
1058992
return 0;
993+
err1:
994+
nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
995+
return ret;
1059996
}
1060997

1061-
void br_netfilter_fini(void)
998+
static void __exit br_netfilter_fini(void)
1062999
{
10631000
nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
10641001
#ifdef CONFIG_SYSCTL
10651002
unregister_net_sysctl_table(brnf_sysctl_header);
10661003
#endif
1067-
dst_entries_destroy(&fake_dst_ops);
10681004
}
1005+
1006+
module_init(br_netfilter_init);
1007+
module_exit(br_netfilter_fini);
1008+
1009+
MODULE_LICENSE("GPL");
1010+
MODULE_AUTHOR("Lennert Buytenhek <[email protected]>");
1011+
MODULE_AUTHOR("Bart De Schuymer <[email protected]>");
1012+
MODULE_DESCRIPTION("Linux ethernet netfilter firewall bridge");

net/bridge/br_netlink.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ int __init br_netlink_init(void)
602602
return err;
603603
}
604604

605-
void __exit br_netlink_fini(void)
605+
void br_netlink_fini(void)
606606
{
607607
br_mdb_uninit();
608608
rtnl_af_unregister(&br_af_ops);

0 commit comments

Comments
 (0)