Patchwork [RFC] netfilter: bridge: change indev name to vlan if vlan tag present

login
register
mail settings
Submitter Florian Westphal
Date March 26, 2012, 8:23 p.m.
Message ID <20120326202326.GB15638@Chamillionaire.breakpoint.cc>
Download mbox | patch
Permalink /patch/148833/
State Rejected
Headers show

Comments

Florian Westphal - March 26, 2012, 8:23 p.m.
If net.bridge.bridge-nf-filter-vlan-tagged is on, bridge
netfilter will remove skbs vlan header, then feeds the packet
to ip(6)tables.

This changes the in/out interface to the vlan interface; if such
an interface has been configured, to allow iptables rules to
determine the original vlan the packet arrived on (e.g.
-i br0.1 will now work if a br0.1 vlan exists on top of br0 bridge
interface).

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 net/bridge/br_netfilter.c |   31 +++++++++++++++++++++++--------
 1 files changed, 23 insertions(+), 8 deletions(-)
Pablo Neira - March 27, 2012, 3:37 p.m.
On Mon, Mar 26, 2012 at 10:23:26PM +0200, Florian Westphal wrote:
> If net.bridge.bridge-nf-filter-vlan-tagged is on, bridge
> netfilter will remove skbs vlan header, then feeds the packet
> to ip(6)tables.
> 
> This changes the in/out interface to the vlan interface; if such
> an interface has been configured, to allow iptables rules to
> determine the original vlan the packet arrived on (e.g.
> -i br0.1 will now work if a br0.1 vlan exists on top of br0 bridge
> interface).

Bart, can you see any problem with this approach?
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index dec4f38..087fbd1 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -503,6 +503,19 @@  bridged_dnat:
 	return 0;
 }
 
+static struct net_device *brnf_find_logical_dev(struct sk_buff *skb, const struct net_device *dev)
+{
+	struct net_device *vlan, *br;
+
+	br = bridge_parent(dev);
+	if (!vlan_tx_tag_present(skb))
+		return br;
+
+	vlan = __vlan_find_dev_deep(br, vlan_tx_tag_get(skb) & VLAN_VID_MASK);
+
+	return vlan ? vlan : br;
+}
+
 /* Some common code for IPv4/IPv6 */
 static struct net_device *setup_pre_routing(struct sk_buff *skb)
 {
@@ -515,7 +528,7 @@  static struct net_device *setup_pre_routing(struct sk_buff *skb)
 
 	nf_bridge->mask |= BRNF_NF_BRIDGE_PREROUTING;
 	nf_bridge->physindev = skb->dev;
-	skb->dev = bridge_parent(skb->dev);
+	skb->dev = brnf_find_logical_dev(skb, skb->dev);
 	if (skb->protocol == htons(ETH_P_8021Q))
 		nf_bridge->mask |= BRNF_8021Q;
 	else if (skb->protocol == htons(ETH_P_PPP_SES))
@@ -737,7 +750,7 @@  static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
 				     int (*okfn)(struct sk_buff *))
 {
 	struct nf_bridge_info *nf_bridge;
-	struct net_device *parent;
+	struct net_device *parent, *indev;
 	u_int8_t pf;
 
 	if (!skb->nf_bridge)
@@ -748,10 +761,6 @@  static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
 	if (!nf_bridge_unshare(skb))
 		return NF_DROP;
 
-	parent = bridge_parent(out);
-	if (!parent)
-		return NF_DROP;
-
 	if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb))
 		pf = PF_INET;
 	else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb))
@@ -759,6 +768,10 @@  static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
 	else
 		return NF_ACCEPT;
 
+	parent = brnf_find_logical_dev(skb, out);
+	if (!parent)
+		return NF_DROP;
+
 	nf_bridge_pull_encap_header(skb);
 
 	nf_bridge = skb->nf_bridge;
@@ -778,7 +791,9 @@  static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
 	else
 		skb->protocol = htons(ETH_P_IPV6);
 
-	NF_HOOK(pf, NF_INET_FORWARD, skb, bridge_parent(in), parent,
+	indev = brnf_find_logical_dev(skb, in);
+
+	NF_HOOK(pf, NF_INET_FORWARD, skb, indev, parent,
 		br_nf_forward_finish);
 
 	return NF_STOLEN;
@@ -850,7 +865,7 @@  static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
 				       int (*okfn)(struct sk_buff *))
 {
 	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
-	struct net_device *realoutdev = bridge_parent(skb->dev);
+	struct net_device *realoutdev = brnf_find_logical_dev(skb, out);
 	u_int8_t pf;
 
 	if (!nf_bridge || !(nf_bridge->mask & BRNF_BRIDGED))