diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2011-09-20 14:50:00 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-09-20 14:50:00 -0400 |
commit | d24f22f3df9ac3f3af95e850df0b576d41bd3cfe (patch) | |
tree | db5cf4d94fa9b56fafa677dda417fc1f9a919cc7 | |
parent | 46151ae81758f05086e17fd4e4da129afe100f93 (diff) | |
download | lwn-d24f22f3df9ac3f3af95e850df0b576d41bd3cfe.tar.gz lwn-d24f22f3df9ac3f3af95e850df0b576d41bd3cfe.zip |
ip6_tunnel: add optional fwmark inherit
Add IP6_TNL_F_USE_ORIG_FWMARK to ip6_tunnel, so that ip6_tnl_xmit2()
makes a route lookup taking into account skb->fwmark and doesnt cache
lookup result.
This permits more flexibility in policies and firewall setups.
To setup such a tunnel, "fwmark inherit" option should be added to "ip
-f inet6 tunnel" command.
Reported-by: Anders Franzen <Anders.Franzen@ericsson.com>
CC: Hans Schillström <hans.schillstrom@ericsson.com>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/ip6_tunnel.h | 2 | ||||
-rw-r--r-- | net/ipv6/ip6_tunnel.c | 23 |
2 files changed, 18 insertions, 7 deletions
diff --git a/include/linux/ip6_tunnel.h b/include/linux/ip6_tunnel.h index acb9ad684d63..bf22b0317902 100644 --- a/include/linux/ip6_tunnel.h +++ b/include/linux/ip6_tunnel.h @@ -16,6 +16,8 @@ #define IP6_TNL_F_MIP6_DEV 0x8 /* copy DSCP from the outer packet */ #define IP6_TNL_F_RCV_DSCP_COPY 0x10 +/* copy fwmark from inner packet */ +#define IP6_TNL_F_USE_ORIG_FWMARK 0x20 struct ip6_tnl_parm { char name[IFNAMSIZ]; /* name of tunnel device */ diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 694d70a8a0ee..bdc15c9003d7 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -889,7 +889,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, struct net_device_stats *stats = &t->dev->stats; struct ipv6hdr *ipv6h = ipv6_hdr(skb); struct ipv6_tel_txoption opt; - struct dst_entry *dst, *ndst = NULL; + struct dst_entry *dst = NULL, *ndst = NULL; struct net_device *tdev; int mtu; unsigned int max_headroom = sizeof(struct ipv6hdr); @@ -897,7 +897,8 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, int err = -1; int pkt_len; - dst = ip6_tnl_dst_check(t); + if (!fl6->flowi6_mark) + dst = ip6_tnl_dst_check(t); if (!dst) { ndst = ip6_route_output(net, NULL, fl6); @@ -955,8 +956,12 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, skb = new_skb; } skb_dst_drop(skb); - skb_dst_set_noref(skb, dst); - + if (fl6->flowi6_mark) { + skb_dst_set(skb, dst); + ndst = NULL; + } else { + skb_dst_set_noref(skb, dst); + } skb->transport_header = skb->network_header; proto = fl6->flowi6_proto; @@ -1021,9 +1026,11 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) dsfield = ipv4_get_dsfield(iph); - if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)) + if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS) fl6.flowlabel |= htonl((__u32)iph->tos << IPV6_TCLASS_SHIFT) & IPV6_TCLASS_MASK; + if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) + fl6.flowi6_mark = skb->mark; err = ip6_tnl_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu); if (err != 0) { @@ -1070,10 +1077,12 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) fl6.flowi6_proto = IPPROTO_IPV6; dsfield = ipv6_get_dsfield(ipv6h); - if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)) + if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS) fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_TCLASS_MASK); - if ((t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)) + if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL) fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_FLOWLABEL_MASK); + if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) + fl6.flowi6_mark = skb->mark; err = ip6_tnl_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu); if (err != 0) { |