ip6_tunnel: disable caching when the traffic class is inherited
[pandora-kernel.git] / net / ipv6 / ip6_tunnel.c
index bdc15c9..195b083 100644 (file)
@@ -57,6 +57,7 @@
 MODULE_AUTHOR("Ville Nuorvala");
 MODULE_DESCRIPTION("IPv6 tunneling device");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_RTNL_LINK("ip6tnl");
 MODULE_ALIAS_NETDEV("ip6tnl0");
 
 #ifdef IP6_TNL_DEBUG
@@ -218,8 +219,8 @@ ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
 {
        struct ip6_tnl __rcu **tp = ip6_tnl_bucket(ip6n, &t->parms);
 
-       RCU_INIT_POINTER(t->next , rtnl_dereference(*tp));
-       RCU_INIT_POINTER(*tp, t);
+       rcu_assign_pointer(t->next , rtnl_dereference(*tp));
+       rcu_assign_pointer(*tp, t);
 }
 
 /**
@@ -237,7 +238,7 @@ ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
             (iter = rtnl_dereference(*tp)) != NULL;
             tp = &iter->next) {
                if (t == iter) {
-                       RCU_INIT_POINTER(*tp, t->next);
+                       rcu_assign_pointer(*tp, t->next);
                        break;
                }
        }
@@ -289,6 +290,8 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p)
        if ((err = register_netdevice(dev)) < 0)
                goto failed_free;
 
+       strcpy(t->parms.name, dev->name);
+
        dev_hold(dev);
        ip6_tnl_link(ip6n, t);
        return t;
@@ -686,7 +689,7 @@ static void ip6ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t,
                ipv6_copy_dscp(ipv6_get_dsfield(ipv6h), ipv6_hdr(skb));
 
        if (INET_ECN_is_ce(ipv6_get_dsfield(ipv6h)))
-               IP6_ECN_set_ce(ipv6_hdr(skb));
+               IP6_ECN_set_ce(skb, ipv6_hdr(skb));
 }
 
 /* called with rcu_read_lock() */
@@ -891,13 +894,22 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
        struct ipv6_tel_txoption opt;
        struct dst_entry *dst = NULL, *ndst = NULL;
        struct net_device *tdev;
+       bool use_cache = false;
        int mtu;
        unsigned int max_headroom = sizeof(struct ipv6hdr);
        u8 proto;
        int err = -1;
        int pkt_len;
 
-       if (!fl6->flowi6_mark)
+       if (!(t->parms.flags &
+                    (IP6_TNL_F_USE_ORIG_TCLASS | IP6_TNL_F_USE_ORIG_FWMARK))) {
+               /* enable the cache only only if the routing decision does
+                * not depend on the current inner header value
+                */
+               use_cache = true;
+       }
+
+       if (use_cache)
                dst = ip6_tnl_dst_check(t);
        if (!dst) {
                ndst = ip6_route_output(net, NULL, fl6);
@@ -956,7 +968,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
                skb = new_skb;
        }
        skb_dst_drop(skb);
-       if (fl6->flowi6_mark) {
+       if (!use_cache) {
                skb_dst_set(skb, dst);
                ndst = NULL;
        } else {
@@ -980,6 +992,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
        ipv6_addr_copy(&ipv6h->saddr, &fl6->saddr);
        ipv6_addr_copy(&ipv6h->daddr, &fl6->daddr);
        nf_reset(skb);
+       memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
        pkt_len = skb->len;
        err = ip6_local_out(skb);
 
@@ -1407,7 +1420,6 @@ ip6_tnl_dev_init_gen(struct net_device *dev)
        struct ip6_tnl *t = netdev_priv(dev);
 
        t->dev = dev;
-       strcpy(t->parms.name, dev->name);
        dev->tstats = alloc_percpu(struct pcpu_tstats);
        if (!dev->tstats)
                return -ENOMEM;
@@ -1449,7 +1461,7 @@ static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev)
 
        t->parms.proto = IPPROTO_IPV6;
        dev_hold(dev);
-       RCU_INIT_POINTER(ip6n->tnls_wc[0], t);
+       rcu_assign_pointer(ip6n->tnls_wc[0], t);
        return 0;
 }
 
@@ -1487,6 +1499,7 @@ static void __net_exit ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n)
 static int __net_init ip6_tnl_init_net(struct net *net)
 {
        struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
+       struct ip6_tnl *t = NULL;
        int err;
 
        ip6n->tnls[0] = ip6n->tnls_wc;
@@ -1507,6 +1520,10 @@ static int __net_init ip6_tnl_init_net(struct net *net)
        err = register_netdev(ip6n->fb_tnl_dev);
        if (err < 0)
                goto err_register;
+
+       t = netdev_priv(ip6n->fb_tnl_dev);
+
+       strcpy(t->parms.name, ip6n->fb_tnl_dev->name);
        return 0;
 
 err_register: