ipv6: introduce tcp_v6_iif()

Commit 971f10eca1 ("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:
Eric Dumazet 2014-10-17 09:17:20 -07:00 committed by David S. Miller
parent 70b33fb0dd
commit 870c315138
5 changed files with 30 additions and 15 deletions

View File

@ -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,

View File

@ -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.
*/ */

View File

@ -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 ...

View File

@ -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);

View File

@ -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),