forked from mirrors/linux
		
	ipv6: introduce tcp_v6_iif()
Commit971f10eca1("tcp: better TCP_SKB_CB layout to reduce cache line misses") added a regression for SO_BINDTODEVICE on IPv6. This is because we still use inet6_iif() which expects that IP6 control block is still at the beginning of skb->cb[] This patch adds tcp_v6_iif() helper and uses it where necessary. Because __inet6_lookup_skb() is used by TCP and DCCP, we add an iif parameter to it. Signed-off-by: Eric Dumazet <edumazet@google.com> Fixes:971f10eca1("tcp: better TCP_SKB_CB layout to reduce cache line misses") Acked-by: Cong Wang <cwang@twopensource.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									70b33fb0dd
								
							
						
					
					
						commit
						870c315138
					
				
					 5 changed files with 30 additions and 15 deletions
				
			
		| 
						 | 
					@ -80,7 +80,8 @@ static inline struct sock *__inet6_lookup(struct net *net,
 | 
				
			||||||
static inline struct sock *__inet6_lookup_skb(struct inet_hashinfo *hashinfo,
 | 
					static inline struct sock *__inet6_lookup_skb(struct inet_hashinfo *hashinfo,
 | 
				
			||||||
					      struct sk_buff *skb,
 | 
										      struct sk_buff *skb,
 | 
				
			||||||
					      const __be16 sport,
 | 
										      const __be16 sport,
 | 
				
			||||||
					      const __be16 dport)
 | 
										      const __be16 dport,
 | 
				
			||||||
 | 
										      int iif)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sock *sk = skb_steal_sock(skb);
 | 
						struct sock *sk = skb_steal_sock(skb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -90,7 +91,7 @@ static inline struct sock *__inet6_lookup_skb(struct inet_hashinfo *hashinfo,
 | 
				
			||||||
	return __inet6_lookup(dev_net(skb_dst(skb)->dev), hashinfo,
 | 
						return __inet6_lookup(dev_net(skb_dst(skb)->dev), hashinfo,
 | 
				
			||||||
			      &ipv6_hdr(skb)->saddr, sport,
 | 
								      &ipv6_hdr(skb)->saddr, sport,
 | 
				
			||||||
			      &ipv6_hdr(skb)->daddr, ntohs(dport),
 | 
								      &ipv6_hdr(skb)->daddr, ntohs(dport),
 | 
				
			||||||
			      inet6_iif(skb));
 | 
								      iif);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
 | 
					struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -729,6 +729,15 @@ struct tcp_skb_cb {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TCP_SKB_CB(__skb)	((struct tcp_skb_cb *)&((__skb)->cb[0]))
 | 
					#define TCP_SKB_CB(__skb)	((struct tcp_skb_cb *)&((__skb)->cb[0]))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* This is the variant of inet6_iif() that must be used by TCP,
 | 
				
			||||||
 | 
					 * as TCP moves IP6CB into a different location in skb->cb[]
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline int tcp_v6_iif(const struct sk_buff *skb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return TCP_SKB_CB(skb)->header.h6.iif;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Due to TSO, an SKB can be composed of multiple actual
 | 
					/* Due to TSO, an SKB can be composed of multiple actual
 | 
				
			||||||
 * packets.  To keep these tracked properly, we use this.
 | 
					 * packets.  To keep these tracked properly, we use this.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -757,7 +757,8 @@ static int dccp_v6_rcv(struct sk_buff *skb)
 | 
				
			||||||
	/* Step 2:
 | 
						/* Step 2:
 | 
				
			||||||
	 *	Look up flow ID in table and get corresponding socket */
 | 
						 *	Look up flow ID in table and get corresponding socket */
 | 
				
			||||||
	sk = __inet6_lookup_skb(&dccp_hashinfo, skb,
 | 
						sk = __inet6_lookup_skb(&dccp_hashinfo, skb,
 | 
				
			||||||
			        dh->dccph_sport, dh->dccph_dport);
 | 
								        dh->dccph_sport, dh->dccph_dport,
 | 
				
			||||||
 | 
									inet6_iif(skb));
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Step 2:
 | 
						 * Step 2:
 | 
				
			||||||
	 *	If no socket ...
 | 
						 *	If no socket ...
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -214,7 +214,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
 | 
				
			||||||
	/* So that link locals have meaning */
 | 
						/* So that link locals have meaning */
 | 
				
			||||||
	if (!sk->sk_bound_dev_if &&
 | 
						if (!sk->sk_bound_dev_if &&
 | 
				
			||||||
	    ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL)
 | 
						    ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL)
 | 
				
			||||||
		ireq->ir_iif = inet6_iif(skb);
 | 
							ireq->ir_iif = tcp_v6_iif(skb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ireq->ir_mark = inet_request_mark(sk, skb);
 | 
						ireq->ir_mark = inet_request_mark(sk, skb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -424,6 +424,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 | 
				
			||||||
		if (sock_owned_by_user(sk))
 | 
							if (sock_owned_by_user(sk))
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Note : We use inet6_iif() here, not tcp_v6_iif() */
 | 
				
			||||||
		req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr,
 | 
							req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr,
 | 
				
			||||||
					   &hdr->saddr, inet6_iif(skb));
 | 
										   &hdr->saddr, inet6_iif(skb));
 | 
				
			||||||
		if (!req)
 | 
							if (!req)
 | 
				
			||||||
| 
						 | 
					@ -738,7 +739,7 @@ static void tcp_v6_init_req(struct request_sock *req, struct sock *sk,
 | 
				
			||||||
	/* So that link locals have meaning */
 | 
						/* So that link locals have meaning */
 | 
				
			||||||
	if (!sk->sk_bound_dev_if &&
 | 
						if (!sk->sk_bound_dev_if &&
 | 
				
			||||||
	    ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL)
 | 
						    ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL)
 | 
				
			||||||
		ireq->ir_iif = inet6_iif(skb);
 | 
							ireq->ir_iif = tcp_v6_iif(skb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!TCP_SKB_CB(skb)->tcp_tw_isn &&
 | 
						if (!TCP_SKB_CB(skb)->tcp_tw_isn &&
 | 
				
			||||||
	    (ipv6_opt_accepted(sk, skb, &TCP_SKB_CB(skb)->header.h6) ||
 | 
						    (ipv6_opt_accepted(sk, skb, &TCP_SKB_CB(skb)->header.h6) ||
 | 
				
			||||||
| 
						 | 
					@ -860,7 +861,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fl6.flowi6_proto = IPPROTO_TCP;
 | 
						fl6.flowi6_proto = IPPROTO_TCP;
 | 
				
			||||||
	if (rt6_need_strict(&fl6.daddr) && !oif)
 | 
						if (rt6_need_strict(&fl6.daddr) && !oif)
 | 
				
			||||||
		fl6.flowi6_oif = inet6_iif(skb);
 | 
							fl6.flowi6_oif = tcp_v6_iif(skb);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		fl6.flowi6_oif = oif;
 | 
							fl6.flowi6_oif = oif;
 | 
				
			||||||
	fl6.flowi6_mark = IP6_REPLY_MARK(net, skb->mark);
 | 
						fl6.flowi6_mark = IP6_REPLY_MARK(net, skb->mark);
 | 
				
			||||||
| 
						 | 
					@ -918,7 +919,7 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
 | 
				
			||||||
		sk1 = inet6_lookup_listener(dev_net(skb_dst(skb)->dev),
 | 
							sk1 = inet6_lookup_listener(dev_net(skb_dst(skb)->dev),
 | 
				
			||||||
					   &tcp_hashinfo, &ipv6h->saddr,
 | 
										   &tcp_hashinfo, &ipv6h->saddr,
 | 
				
			||||||
					   th->source, &ipv6h->daddr,
 | 
										   th->source, &ipv6h->daddr,
 | 
				
			||||||
					   ntohs(th->source), inet6_iif(skb));
 | 
										   ntohs(th->source), tcp_v6_iif(skb));
 | 
				
			||||||
		if (!sk1)
 | 
							if (!sk1)
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1000,13 +1001,14 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk, struct sk_buff *skb)
 | 
				
			||||||
	/* Find possible connection requests. */
 | 
						/* Find possible connection requests. */
 | 
				
			||||||
	req = inet6_csk_search_req(sk, &prev, th->source,
 | 
						req = inet6_csk_search_req(sk, &prev, th->source,
 | 
				
			||||||
				   &ipv6_hdr(skb)->saddr,
 | 
									   &ipv6_hdr(skb)->saddr,
 | 
				
			||||||
				   &ipv6_hdr(skb)->daddr, inet6_iif(skb));
 | 
									   &ipv6_hdr(skb)->daddr, tcp_v6_iif(skb));
 | 
				
			||||||
	if (req)
 | 
						if (req)
 | 
				
			||||||
		return tcp_check_req(sk, skb, req, prev, false);
 | 
							return tcp_check_req(sk, skb, req, prev, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo,
 | 
						nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo,
 | 
				
			||||||
					 &ipv6_hdr(skb)->saddr, th->source,
 | 
										 &ipv6_hdr(skb)->saddr, th->source,
 | 
				
			||||||
			&ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb));
 | 
										 &ipv6_hdr(skb)->daddr, ntohs(th->dest),
 | 
				
			||||||
 | 
										 tcp_v6_iif(skb));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (nsk) {
 | 
						if (nsk) {
 | 
				
			||||||
		if (nsk->sk_state != TCP_TIME_WAIT) {
 | 
							if (nsk->sk_state != TCP_TIME_WAIT) {
 | 
				
			||||||
| 
						 | 
					@ -1090,7 +1092,7 @@ static struct sock *tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 | 
				
			||||||
		newnp->ipv6_fl_list = NULL;
 | 
							newnp->ipv6_fl_list = NULL;
 | 
				
			||||||
		newnp->pktoptions  = NULL;
 | 
							newnp->pktoptions  = NULL;
 | 
				
			||||||
		newnp->opt	   = NULL;
 | 
							newnp->opt	   = NULL;
 | 
				
			||||||
		newnp->mcast_oif   = inet6_iif(skb);
 | 
							newnp->mcast_oif   = tcp_v6_iif(skb);
 | 
				
			||||||
		newnp->mcast_hops  = ipv6_hdr(skb)->hop_limit;
 | 
							newnp->mcast_hops  = ipv6_hdr(skb)->hop_limit;
 | 
				
			||||||
		newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb));
 | 
							newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb));
 | 
				
			||||||
		if (np->repflow)
 | 
							if (np->repflow)
 | 
				
			||||||
| 
						 | 
					@ -1174,7 +1176,7 @@ static struct sock *tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 | 
				
			||||||
			skb_set_owner_r(newnp->pktoptions, newsk);
 | 
								skb_set_owner_r(newnp->pktoptions, newsk);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	newnp->opt	  = NULL;
 | 
						newnp->opt	  = NULL;
 | 
				
			||||||
	newnp->mcast_oif  = inet6_iif(skb);
 | 
						newnp->mcast_oif  = tcp_v6_iif(skb);
 | 
				
			||||||
	newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
 | 
						newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
 | 
				
			||||||
	newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb));
 | 
						newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb));
 | 
				
			||||||
	if (np->repflow)
 | 
						if (np->repflow)
 | 
				
			||||||
| 
						 | 
					@ -1360,7 +1362,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
 | 
				
			||||||
	if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt &&
 | 
						if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt &&
 | 
				
			||||||
	    !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) {
 | 
						    !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) {
 | 
				
			||||||
		if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
 | 
							if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
 | 
				
			||||||
			np->mcast_oif = inet6_iif(opt_skb);
 | 
								np->mcast_oif = tcp_v6_iif(opt_skb);
 | 
				
			||||||
		if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
 | 
							if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
 | 
				
			||||||
			np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
 | 
								np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
 | 
				
			||||||
		if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass)
 | 
							if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass)
 | 
				
			||||||
| 
						 | 
					@ -1427,7 +1429,8 @@ static int tcp_v6_rcv(struct sk_buff *skb)
 | 
				
			||||||
	TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr);
 | 
						TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr);
 | 
				
			||||||
	TCP_SKB_CB(skb)->sacked = 0;
 | 
						TCP_SKB_CB(skb)->sacked = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
 | 
						sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest,
 | 
				
			||||||
 | 
									tcp_v6_iif(skb));
 | 
				
			||||||
	if (!sk)
 | 
						if (!sk)
 | 
				
			||||||
		goto no_tcp_socket;
 | 
							goto no_tcp_socket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1514,7 +1517,7 @@ static int tcp_v6_rcv(struct sk_buff *skb)
 | 
				
			||||||
		sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo,
 | 
							sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo,
 | 
				
			||||||
					    &ipv6_hdr(skb)->saddr, th->source,
 | 
										    &ipv6_hdr(skb)->saddr, th->source,
 | 
				
			||||||
					    &ipv6_hdr(skb)->daddr,
 | 
										    &ipv6_hdr(skb)->daddr,
 | 
				
			||||||
					    ntohs(th->dest), inet6_iif(skb));
 | 
										    ntohs(th->dest), tcp_v6_iif(skb));
 | 
				
			||||||
		if (sk2 != NULL) {
 | 
							if (sk2 != NULL) {
 | 
				
			||||||
			struct inet_timewait_sock *tw = inet_twsk(sk);
 | 
								struct inet_timewait_sock *tw = inet_twsk(sk);
 | 
				
			||||||
			inet_twsk_deschedule(tw, &tcp_death_row);
 | 
								inet_twsk_deschedule(tw, &tcp_death_row);
 | 
				
			||||||
| 
						 | 
					@ -1553,6 +1556,7 @@ static void tcp_v6_early_demux(struct sk_buff *skb)
 | 
				
			||||||
	if (th->doff < sizeof(struct tcphdr) / 4)
 | 
						if (th->doff < sizeof(struct tcphdr) / 4)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Note : We use inet6_iif() here, not tcp_v6_iif() */
 | 
				
			||||||
	sk = __inet6_lookup_established(dev_net(skb->dev), &tcp_hashinfo,
 | 
						sk = __inet6_lookup_established(dev_net(skb->dev), &tcp_hashinfo,
 | 
				
			||||||
					&hdr->saddr, th->source,
 | 
										&hdr->saddr, th->source,
 | 
				
			||||||
					&hdr->daddr, ntohs(th->dest),
 | 
										&hdr->daddr, ntohs(th->dest),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue