diff options
Diffstat (limited to 'net/ipv6/ip6_tunnel.c')
| -rw-r--r-- | net/ipv6/ip6_tunnel.c | 54 | 
1 files changed, 32 insertions, 22 deletions
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 0bc98886c38..bdc15c9003d 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -218,8 +218,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_assign_pointer(t->next , rtnl_dereference(*tp)); -	rcu_assign_pointer(*tp, t); +	RCU_INIT_POINTER(t->next , rtnl_dereference(*tp)); +	RCU_INIT_POINTER(*tp, t);  }  /** @@ -237,7 +237,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_assign_pointer(*tp, t->next); +			RCU_INIT_POINTER(*tp, t->next);  			break;  		}  	} @@ -350,7 +350,7 @@ ip6_tnl_dev_uninit(struct net_device *dev)  	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);  	if (dev == ip6n->fb_tnl_dev) -		rcu_assign_pointer(ip6n->tnls_wc[0], NULL); +		RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL);  	else  		ip6_tnl_unlink(ip6n, t);  	ip6_tnl_dst_reset(t); @@ -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; +	struct dst_entry *dst = NULL, *ndst = NULL;  	struct net_device *tdev;  	int mtu;  	unsigned int max_headroom = sizeof(struct ipv6hdr); @@ -897,19 +897,20 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,  	int err = -1;  	int pkt_len; -	if ((dst = ip6_tnl_dst_check(t)) != NULL) -		dst_hold(dst); -	else { -		dst = ip6_route_output(net, NULL, fl6); +	if (!fl6->flowi6_mark) +		dst = ip6_tnl_dst_check(t); +	if (!dst) { +		ndst = ip6_route_output(net, NULL, fl6); -		if (dst->error) +		if (ndst->error)  			goto tx_err_link_failure; -		dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), NULL, 0); -		if (IS_ERR(dst)) { -			err = PTR_ERR(dst); -			dst = NULL; +		ndst = xfrm_lookup(net, ndst, flowi6_to_flowi(fl6), NULL, 0); +		if (IS_ERR(ndst)) { +			err = PTR_ERR(ndst); +			ndst = NULL;  			goto tx_err_link_failure;  		} +		dst = ndst;  	}  	tdev = dst->dev; @@ -955,8 +956,12 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,  		skb = new_skb;  	}  	skb_dst_drop(skb); -	skb_dst_set(skb, dst_clone(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; @@ -987,13 +992,14 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,  		stats->tx_errors++;  		stats->tx_aborted_errors++;  	} -	ip6_tnl_dst_store(t, dst); +	if (ndst) +		ip6_tnl_dst_store(t, ndst);  	return 0;  tx_err_link_failure:  	stats->tx_carrier_errors++;  	dst_link_failure(skb);  tx_err_dst_release: -	dst_release(dst); +	dst_release(ndst);  	return err;  } @@ -1020,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) { @@ -1069,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) { @@ -1439,7 +1449,7 @@ static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev)  	t->parms.proto = IPPROTO_IPV6;  	dev_hold(dev); -	rcu_assign_pointer(ip6n->tnls_wc[0], t); +	RCU_INIT_POINTER(ip6n->tnls_wc[0], t);  	return 0;  }  |