OSDN Git Service

tcp: uniform the set up of sockets after successful connection
[android-x86/kernel.git] / net / ipv4 / tcp_fastopen.c
index e3c3322..29fff14 100644 (file)
@@ -9,15 +9,18 @@
 #include <net/inetpeer.h>
 #include <net/tcp.h>
 
-int sysctl_tcp_fastopen __read_mostly = TFO_CLIENT_ENABLE;
-
-struct tcp_fastopen_context __rcu *tcp_fastopen_ctx;
-
-static DEFINE_SPINLOCK(tcp_fastopen_ctx_lock);
-
-void tcp_fastopen_init_key_once(bool publish)
+void tcp_fastopen_init_key_once(struct net *net)
 {
-       static u8 key[TCP_FASTOPEN_KEY_LENGTH];
+       u8 key[TCP_FASTOPEN_KEY_LENGTH];
+       struct tcp_fastopen_context *ctxt;
+
+       rcu_read_lock();
+       ctxt = rcu_dereference(net->ipv4.tcp_fastopen_ctx);
+       if (ctxt) {
+               rcu_read_unlock();
+               return;
+       }
+       rcu_read_unlock();
 
        /* tcp_fastopen_reset_cipher publishes the new context
         * atomically, so we allow this race happening here.
@@ -25,8 +28,8 @@ void tcp_fastopen_init_key_once(bool publish)
         * All call sites of tcp_fastopen_cookie_gen also check
         * for a valid cookie, so this is an acceptable risk.
         */
-       if (net_get_random_once(key, sizeof(key)) && publish)
-               tcp_fastopen_reset_cipher(key, sizeof(key));
+       get_random_bytes(key, sizeof(key));
+       tcp_fastopen_reset_cipher(net, key, sizeof(key));
 }
 
 static void tcp_fastopen_ctx_free(struct rcu_head *head)
@@ -37,7 +40,22 @@ static void tcp_fastopen_ctx_free(struct rcu_head *head)
        kfree(ctx);
 }
 
-int tcp_fastopen_reset_cipher(void *key, unsigned int len)
+void tcp_fastopen_ctx_destroy(struct net *net)
+{
+       struct tcp_fastopen_context *ctxt;
+
+       spin_lock(&net->ipv4.tcp_fastopen_ctx_lock);
+
+       ctxt = rcu_dereference_protected(net->ipv4.tcp_fastopen_ctx,
+                               lockdep_is_held(&net->ipv4.tcp_fastopen_ctx_lock));
+       rcu_assign_pointer(net->ipv4.tcp_fastopen_ctx, NULL);
+       spin_unlock(&net->ipv4.tcp_fastopen_ctx_lock);
+
+       if (ctxt)
+               call_rcu(&ctxt->rcu, tcp_fastopen_ctx_free);
+}
+
+int tcp_fastopen_reset_cipher(struct net *net, void *key, unsigned int len)
 {
        int err;
        struct tcp_fastopen_context *ctx, *octx;
@@ -61,26 +79,27 @@ error:              kfree(ctx);
        }
        memcpy(ctx->key, key, len);
 
-       spin_lock(&tcp_fastopen_ctx_lock);
+       spin_lock(&net->ipv4.tcp_fastopen_ctx_lock);
 
-       octx = rcu_dereference_protected(tcp_fastopen_ctx,
-                               lockdep_is_held(&tcp_fastopen_ctx_lock));
-       rcu_assign_pointer(tcp_fastopen_ctx, ctx);
-       spin_unlock(&tcp_fastopen_ctx_lock);
+       octx = rcu_dereference_protected(net->ipv4.tcp_fastopen_ctx,
+                               lockdep_is_held(&net->ipv4.tcp_fastopen_ctx_lock));
+       rcu_assign_pointer(net->ipv4.tcp_fastopen_ctx, ctx);
+       spin_unlock(&net->ipv4.tcp_fastopen_ctx_lock);
 
        if (octx)
                call_rcu(&octx->rcu, tcp_fastopen_ctx_free);
        return err;
 }
 
-static bool __tcp_fastopen_cookie_gen(const void *path,
+static bool __tcp_fastopen_cookie_gen(struct net *net,
+                                     const void *path,
                                      struct tcp_fastopen_cookie *foc)
 {
        struct tcp_fastopen_context *ctx;
        bool ok = false;
 
        rcu_read_lock();
-       ctx = rcu_dereference(tcp_fastopen_ctx);
+       ctx = rcu_dereference(net->ipv4.tcp_fastopen_ctx);
        if (ctx) {
                crypto_cipher_encrypt_one(ctx->tfm, foc->val, path);
                foc->len = TCP_FASTOPEN_COOKIE_SIZE;
@@ -96,7 +115,8 @@ static bool __tcp_fastopen_cookie_gen(const void *path,
  *
  * XXX (TFO) - refactor when TCP_FASTOPEN_COOKIE_SIZE != AES_BLOCK_SIZE.
  */
-static bool tcp_fastopen_cookie_gen(struct request_sock *req,
+static bool tcp_fastopen_cookie_gen(struct net *net,
+                                   struct request_sock *req,
                                    struct sk_buff *syn,
                                    struct tcp_fastopen_cookie *foc)
 {
@@ -104,7 +124,7 @@ static bool tcp_fastopen_cookie_gen(struct request_sock *req,
                const struct iphdr *iph = ip_hdr(syn);
 
                __be32 path[4] = { iph->saddr, iph->daddr, 0, 0 };
-               return __tcp_fastopen_cookie_gen(path, foc);
+               return __tcp_fastopen_cookie_gen(net, path, foc);
        }
 
 #if IS_ENABLED(CONFIG_IPV6)
@@ -112,13 +132,13 @@ static bool tcp_fastopen_cookie_gen(struct request_sock *req,
                const struct ipv6hdr *ip6h = ipv6_hdr(syn);
                struct tcp_fastopen_cookie tmp;
 
-               if (__tcp_fastopen_cookie_gen(&ip6h->saddr, &tmp)) {
+               if (__tcp_fastopen_cookie_gen(net, &ip6h->saddr, &tmp)) {
                        struct in6_addr *buf = &tmp.addr;
                        int i;
 
                        for (i = 0; i < 4; i++)
                                buf->s6_addr32[i] ^= ip6h->daddr.s6_addr32[i];
-                       return __tcp_fastopen_cookie_gen(buf, foc);
+                       return __tcp_fastopen_cookie_gen(net, buf, foc);
                }
        }
 #endif
@@ -216,12 +236,7 @@ static struct sock *tcp_fastopen_create_child(struct sock *sk,
        refcount_set(&req->rsk_refcnt, 2);
 
        /* Now finish processing the fastopen child socket. */
-       inet_csk(child)->icsk_af_ops->rebuild_header(child);
-       tcp_init_congestion_control(child);
-       tcp_mtup_init(child);
-       tcp_init_metrics(child);
-       tcp_call_bpf(child, BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB);
-       tcp_init_buffer_space(child);
+       tcp_init_transfer(child, BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB);
 
        tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
 
@@ -279,25 +294,26 @@ struct sock *tcp_try_fastopen(struct sock *sk, struct sk_buff *skb,
                              struct request_sock *req,
                              struct tcp_fastopen_cookie *foc)
 {
-       struct tcp_fastopen_cookie valid_foc = { .len = -1 };
        bool syn_data = TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq + 1;
+       int tcp_fastopen = sock_net(sk)->ipv4.sysctl_tcp_fastopen;
+       struct tcp_fastopen_cookie valid_foc = { .len = -1 };
        struct sock *child;
 
        if (foc->len == 0) /* Client requests a cookie */
                NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPFASTOPENCOOKIEREQD);
 
-       if (!((sysctl_tcp_fastopen & TFO_SERVER_ENABLE) &&
+       if (!((tcp_fastopen & TFO_SERVER_ENABLE) &&
              (syn_data || foc->len >= 0) &&
              tcp_fastopen_queue_check(sk))) {
                foc->len = -1;
                return NULL;
        }
 
-       if (syn_data && (sysctl_tcp_fastopen & TFO_SERVER_COOKIE_NOT_REQD))
+       if (syn_data && (tcp_fastopen & TFO_SERVER_COOKIE_NOT_REQD))
                goto fastopen;
 
        if (foc->len >= 0 &&  /* Client presents or requests a cookie */
-           tcp_fastopen_cookie_gen(req, skb, &valid_foc) &&
+           tcp_fastopen_cookie_gen(sock_net(sk), req, skb, &valid_foc) &&
            foc->len == TCP_FASTOPEN_COOKIE_SIZE &&
            foc->len == valid_foc.len &&
            !memcmp(foc->val, valid_foc.val, foc->len)) {
@@ -347,7 +363,7 @@ bool tcp_fastopen_cookie_check(struct sock *sk, u16 *mss,
                return false;
        }
 
-       if (sysctl_tcp_fastopen & TFO_CLIENT_NO_COOKIE) {
+       if (sock_net(sk)->ipv4.sysctl_tcp_fastopen & TFO_CLIENT_NO_COOKIE) {
                cookie->len = -1;
                return true;
        }
@@ -401,25 +417,16 @@ EXPORT_SYMBOL(tcp_fastopen_defer_connect);
  * TFO connection with data exchanges.
  */
 
-/* Default to 1hr */
-unsigned int sysctl_tcp_fastopen_blackhole_timeout __read_mostly = 60 * 60;
-static atomic_t tfo_active_disable_times __read_mostly = ATOMIC_INIT(0);
-static unsigned long tfo_active_disable_stamp __read_mostly;
-
 /* Disable active TFO and record current jiffies and
  * tfo_active_disable_times
  */
 void tcp_fastopen_active_disable(struct sock *sk)
 {
-       atomic_inc(&tfo_active_disable_times);
-       tfo_active_disable_stamp = jiffies;
-       NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPFASTOPENBLACKHOLE);
-}
+       struct net *net = sock_net(sk);
 
-/* Reset tfo_active_disable_times to 0 */
-void tcp_fastopen_active_timeout_reset(void)
-{
-       atomic_set(&tfo_active_disable_times, 0);
+       atomic_inc(&net->ipv4.tfo_active_disable_times);
+       net->ipv4.tfo_active_disable_stamp = jiffies;
+       NET_INC_STATS(net, LINUX_MIB_TCPFASTOPENBLACKHOLE);
 }
 
 /* Calculate timeout for tfo active disable
@@ -428,17 +435,18 @@ void tcp_fastopen_active_timeout_reset(void)
  */
 bool tcp_fastopen_active_should_disable(struct sock *sk)
 {
-       int tfo_da_times = atomic_read(&tfo_active_disable_times);
-       int multiplier;
+       unsigned int tfo_bh_timeout = sock_net(sk)->ipv4.sysctl_tcp_fastopen_blackhole_timeout;
+       int tfo_da_times = atomic_read(&sock_net(sk)->ipv4.tfo_active_disable_times);
        unsigned long timeout;
+       int multiplier;
 
        if (!tfo_da_times)
                return false;
 
        /* Limit timout to max: 2^6 * initial timeout */
        multiplier = 1 << min(tfo_da_times - 1, 6);
-       timeout = multiplier * sysctl_tcp_fastopen_blackhole_timeout * HZ;
-       if (time_before(jiffies, tfo_active_disable_stamp + timeout))
+       timeout = multiplier * tfo_bh_timeout * HZ;
+       if (time_before(jiffies, sock_net(sk)->ipv4.tfo_active_disable_stamp + timeout))
                return true;
 
        /* Mark check bit so we can check for successful active TFO
@@ -474,10 +482,10 @@ void tcp_fastopen_active_disable_ofo_check(struct sock *sk)
                        }
                }
        } else if (tp->syn_fastopen_ch &&
-                  atomic_read(&tfo_active_disable_times)) {
+                  atomic_read(&sock_net(sk)->ipv4.tfo_active_disable_times)) {
                dst = sk_dst_get(sk);
                if (!(dst && dst->dev && (dst->dev->flags & IFF_LOOPBACK)))
-                       tcp_fastopen_active_timeout_reset();
+                       atomic_set(&sock_net(sk)->ipv4.tfo_active_disable_times, 0);
                dst_release(dst);
        }
 }