tcp: better TCP_SKB_CB layout to reduce cache line misses
[firefly-linux-kernel-4.4.55.git] / net / ipv6 / tcp_ipv6.c
index 29964c3d363c8a0e741b01b9df32fce3cdd7a1ba..132bac137aedb939fd7fbab60e5df76e47900904 100644 (file)
@@ -93,13 +93,16 @@ static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
 static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
 {
        struct dst_entry *dst = skb_dst(skb);
-       const struct rt6_info *rt = (const struct rt6_info *)dst;
 
-       dst_hold(dst);
-       sk->sk_rx_dst = dst;
-       inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
-       if (rt->rt6i_node)
-               inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum;
+       if (dst) {
+               const struct rt6_info *rt = (const struct rt6_info *)dst;
+
+               dst_hold(dst);
+               sk->sk_rx_dst = dst;
+               inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
+               if (rt->rt6i_node)
+                       inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum;
+       }
 }
 
 static void tcp_v6_hash(struct sock *sk)
@@ -738,8 +741,9 @@ static void tcp_v6_init_req(struct request_sock *req, struct sock *sk,
            ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL)
                ireq->ir_iif = inet6_iif(skb);
 
-       if (!TCP_SKB_CB(skb)->when &&
-           (ipv6_opt_accepted(sk, skb) || np->rxopt.bits.rxinfo ||
+       if (!TCP_SKB_CB(skb)->tcp_tw_isn &&
+           (ipv6_opt_accepted(sk, skb, &TCP_SKB_CB(skb)->header.h6) ||
+            np->rxopt.bits.rxinfo ||
             np->rxopt.bits.rxoinfo || np->rxopt.bits.rxhlim ||
             np->rxopt.bits.rxohlim || np->repflow)) {
                atomic_inc(&skb->users);
@@ -1364,7 +1368,7 @@ ipv6_pktoptions:
                        np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb));
                if (np->repflow)
                        np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb));
-               if (ipv6_opt_accepted(sk, opt_skb)) {
+               if (ipv6_opt_accepted(sk, opt_skb, &TCP_SKB_CB(opt_skb)->header.h6)) {
                        skb_set_owner_r(opt_skb, sk);
                        opt_skb = xchg(&np->pktoptions, opt_skb);
                } else {
@@ -1408,11 +1412,19 @@ static int tcp_v6_rcv(struct sk_buff *skb)
 
        th = tcp_hdr(skb);
        hdr = ipv6_hdr(skb);
+       /* This is tricky : We move IPCB at its correct location into TCP_SKB_CB()
+        * barrier() makes sure compiler wont play fool^Waliasing games.
+        */
+       memmove(&TCP_SKB_CB(skb)->header.h6, IP6CB(skb),
+               sizeof(struct inet6_skb_parm));
+       barrier();
+
        TCP_SKB_CB(skb)->seq = ntohl(th->seq);
        TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
                                    skb->len - th->doff*4);
        TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
-       TCP_SKB_CB(skb)->when = 0;
+       TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th);
+       TCP_SKB_CB(skb)->tcp_tw_isn = 0;
        TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr);
        TCP_SKB_CB(skb)->sacked = 0;