[Devel] [PATCH 8/9] netns ebtables: deal with fake netdevices et al

Alexey Dobriyan adobriyan at gmail.com
Thu Jul 31 18:39:38 PDT 2008


Bridge netfilter code uses fake netdevice and fake rtable. Fake means
"static struct net_device". So these should be logically created in
bridge's portion of struct netns.

But!

Adding "struct net_device __fake_net_device" creates header circular dependency,
which is PITA to resolve. I couldn't, so fake netdevice and fake rtable
are created dynamically. :-(

Signed-off-by: Alexey Dobriyan <adobriyan at gmail.com>
---

 include/net/netns/bridge.h |   11 ++++-
 net/bridge/br_netfilter.c  |   88 ++++++++++++++++++++++++++++++++-------------
 2 files changed, 71 insertions(+), 28 deletions(-)

--- a/include/net/netns/bridge.h
+++ b/include/net/netns/bridge.h
@@ -3,10 +3,15 @@
 
 #include <linux/list.h>
 
+struct net_device;
+struct rtable;
+
 struct netns_br {
 	struct list_head	ebt_tables;
-	struct ebt_table *broute_table;
-	struct ebt_table *frame_filter;
-	struct ebt_table *frame_nat;
+	struct ebt_table	*broute_table;
+	struct ebt_table	*frame_filter;
+	struct ebt_table	*frame_nat;
+	struct net_device	*__fake_net_device;
+	struct rtable		*__fake_rtable;
 };
 #endif
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -109,24 +109,47 @@ static inline __be16 pppoe_proto(const struct sk_buff *skb)
  * refragmentation needs it, and the rt_flags entry because
  * ipt_REJECT needs it.  Future netfilter modules might
  * require us to fill additional fields. */
-static struct net_device __fake_net_device = {
-	.hard_header_len	= ETH_HLEN,
+static int br_netfilter_net_init(struct net *net)
+{
+	net->br.__fake_net_device = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+	if (!net->br.__fake_net_device)
+		return -ENOMEM;
+	net->br.__fake_rtable = kmalloc(sizeof(struct rtable), GFP_KERNEL);
+	if (!net->br.__fake_rtable) {
+		kfree(net->br.__fake_net_device);
+		return -ENOMEM;
+	}
+
+	*net->br.__fake_net_device = (struct net_device) {
+		.hard_header_len	= ETH_HLEN,
 #ifdef CONFIG_NET_NS
-	.nd_net			= &init_net,
+		.nd_net			= net,
 #endif
-};
+	};
+	*net->br.__fake_rtable = (struct rtable) {
+		.u = {
+			.dst = {
+				.__refcnt	= ATOMIC_INIT(1),
+				.dev		= net->br.__fake_net_device,
+				.path		= &net->br.__fake_rtable->u.dst,
+				.metrics	= {[RTAX_MTU - 1] = 1500},
+				.flags		= DST_NOXFRM,
+			}
+		},
+		.rt_flags	= 0,
+	};
+	return 0;
+}
 
-static struct rtable __fake_rtable = {
-	.u = {
-		.dst = {
-			.__refcnt		= ATOMIC_INIT(1),
-			.dev			= &__fake_net_device,
-			.path			= &__fake_rtable.u.dst,
-			.metrics		= {[RTAX_MTU - 1] = 1500},
-			.flags			= DST_NOXFRM,
-		}
-	},
-	.rt_flags	= 0,
+static void br_netfilter_net_exit(struct net *net)
+{
+	kfree(net->br.__fake_rtable);
+	kfree(net->br.__fake_net_device);
+}
+
+static struct pernet_operations br_netfilter_net_ops = {
+	.init = br_netfilter_net_init,
+	.exit = br_netfilter_net_exit,
 };
 
 static inline struct net_device *bridge_parent(const struct net_device *dev)
@@ -218,6 +241,7 @@ int nf_bridge_copy_header(struct sk_buff *skb)
  * bridge PRE_ROUTING hook. */
 static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
 {
+	struct net *net = dev_net(skb->dev);
 	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
 
 	if (nf_bridge->mask & BRNF_PKT_TYPE) {
@@ -226,8 +250,8 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
 	}
 	nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
 
-	skb->rtable = &__fake_rtable;
-	dst_hold(&__fake_rtable.u.dst);
+	skb->rtable = net->br.__fake_rtable;
+	dst_hold(&net->br.__fake_rtable->u.dst);
 
 	skb->dev = nf_bridge->physindev;
 	nf_bridge_push_encap_header(skb);
@@ -323,6 +347,7 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
 static int br_nf_pre_routing_finish(struct sk_buff *skb)
 {
 	struct net_device *dev = skb->dev;
+	struct net *net = dev_net(dev);
 	struct iphdr *iph = ip_hdr(skb);
 	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
 	int err;
@@ -356,7 +381,7 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb)
 			if (err != -EHOSTUNREACH || !in_dev || IN_DEV_FORWARD(in_dev))
 				goto free_skb;
 
-			if (!ip_route_output_key(&init_net, &rt, &fl)) {
+			if (!ip_route_output_key(net, &rt, &fl)) {
 				/* - Bridged-and-DNAT'ed traffic doesn't
 				 *   require ip_forwarding. */
 				if (((struct dst_entry *)rt)->dev == dev) {
@@ -391,8 +416,8 @@ bridged_dnat:
 			skb->pkt_type = PACKET_HOST;
 		}
 	} else {
-		skb->rtable = &__fake_rtable;
-		dst_hold(&__fake_rtable.u.dst);
+		skb->rtable = net->br.__fake_rtable;
+		dst_hold(&net->br.__fake_rtable->u.dst);
 	}
 
 	skb->dev = nf_bridge->physindev;
@@ -611,8 +636,10 @@ static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff *skb,
 				   const struct net_device *out,
 				   int (*okfn)(struct sk_buff *))
 {
-	if (skb->rtable == &__fake_rtable) {
-		dst_release(&__fake_rtable.u.dst);
+	struct net *net = dev_net(in);
+
+	if (skb->rtable == net->br.__fake_rtable) {
+		dst_release(&net->br.__fake_rtable->u.dst);
 		skb->rtable = NULL;
 	}
 
@@ -979,18 +1006,28 @@ int __init br_netfilter_init(void)
 
 	ret = nf_register_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
 	if (ret < 0)
-		return ret;
+		goto out;
+	ret = register_pernet_subsys(&br_netfilter_net_ops);
+	if (ret < 0)
+		goto out_net_ops;
 #ifdef CONFIG_SYSCTL
 	brnf_sysctl_header = register_sysctl_paths(brnf_path, brnf_table);
 	if (brnf_sysctl_header == NULL) {
 		printk(KERN_WARNING
 		       "br_netfilter: can't register to sysctl.\n");
-		nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto out_sysctl;
 	}
 #endif
 	printk(KERN_NOTICE "Bridge firewalling registered\n");
 	return 0;
+
+out_sysctl:
+	unregister_pernet_subsys(&br_netfilter_net_ops);
+out_net_ops:
+	nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
+out:
+	return ret;
 }
 
 void br_netfilter_fini(void)
@@ -999,4 +1036,5 @@ void br_netfilter_fini(void)
 #ifdef CONFIG_SYSCTL
 	unregister_sysctl_table(brnf_sysctl_header);
 #endif
+	unregister_pernet_subsys(&br_netfilter_net_ops);
 }
-- 
1.5.4.5


_______________________________________________
Containers mailing list
Containers at lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers




More information about the Devel mailing list