mptcp: implement delayed seq generation for passive fastopen
authorDmytro Shytyi <dmytro@shytyi.net>
Fri, 25 Nov 2022 22:29:50 +0000 (23:29 +0100)
committerJakub Kicinski <kuba@kernel.org>
Wed, 30 Nov 2022 04:24:25 +0000 (20:24 -0800)
With fastopen in place, the first subflow socket is created before the
MPC handshake completes, and we need to properly initialize the sequence
numbers at MPC ACK reception.

Co-developed-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Co-developed-by: Matthieu Baerts <matthieu.baerts@tessares.net>
Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net>
Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/mptcp/Makefile
net/mptcp/fastopen.c [new file with mode: 0644]
net/mptcp/options.c
net/mptcp/protocol.c
net/mptcp/protocol.h
net/mptcp/subflow.c

index 6e7df47..a3829ce 100644 (file)
@@ -2,7 +2,7 @@
 obj-$(CONFIG_MPTCP) += mptcp.o
 
 mptcp-y := protocol.o subflow.o options.o token.o crypto.o ctrl.o pm.o diag.o \
-          mib.o pm_netlink.o sockopt.o pm_userspace.o
+          mib.o pm_netlink.o sockopt.o pm_userspace.o fastopen.o
 
 obj-$(CONFIG_SYN_COOKIES) += syncookies.o
 obj-$(CONFIG_INET_MPTCP_DIAG) += mptcp_diag.o
diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c
new file mode 100644 (file)
index 0000000..19c332a
--- /dev/null
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0
+/* MPTCP Fast Open Mechanism
+ *
+ * Copyright (c) 2021-2022, Dmytro SHYTYI
+ */
+
+#include "protocol.h"
+
+void mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow,
+                                  const struct mptcp_options_received *mp_opt)
+{
+       struct sock *sk = (struct sock *)msk;
+       struct sk_buff *skb;
+
+       mptcp_data_lock(sk);
+       skb = skb_peek_tail(&sk->sk_receive_queue);
+       if (skb) {
+               WARN_ON_ONCE(MPTCP_SKB_CB(skb)->end_seq);
+               pr_debug("msk %p moving seq %llx -> %llx end_seq %llx -> %llx", sk,
+                        MPTCP_SKB_CB(skb)->map_seq, MPTCP_SKB_CB(skb)->map_seq + msk->ack_seq,
+                        MPTCP_SKB_CB(skb)->end_seq, MPTCP_SKB_CB(skb)->end_seq + msk->ack_seq);
+               MPTCP_SKB_CB(skb)->map_seq += msk->ack_seq;
+               MPTCP_SKB_CB(skb)->end_seq += msk->ack_seq;
+       }
+
+       pr_debug("msk=%p ack_seq=%llx", msk, msk->ack_seq);
+       mptcp_data_unlock(sk);
+}
index ae07646..5ded85e 100644 (file)
@@ -939,7 +939,7 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk,
                    subflow->mp_join && (mp_opt->suboptions & OPTIONS_MPTCP_MPJ) &&
                    !subflow->request_join)
                        tcp_send_ack(ssk);
-               goto fully_established;
+               goto check_notify;
        }
 
        /* we must process OoO packets before the first subflow is fully
@@ -950,6 +950,8 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk,
        if (TCP_SKB_CB(skb)->seq != subflow->ssn_offset + 1) {
                if (subflow->mp_join)
                        goto reset;
+               if (subflow->is_mptfo && mp_opt->suboptions & OPTION_MPTCP_MPC_ACK)
+                       goto set_fully_established;
                return subflow->mp_capable;
        }
 
@@ -961,7 +963,7 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk,
                 */
                subflow->fully_established = 1;
                WRITE_ONCE(msk->fully_established, true);
-               goto fully_established;
+               goto check_notify;
        }
 
        /* If the first established packet does not contain MP_CAPABLE + data
@@ -980,11 +982,12 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk,
        if (mp_opt->deny_join_id0)
                WRITE_ONCE(msk->pm.remote_deny_join_id0, true);
 
+set_fully_established:
        if (unlikely(!READ_ONCE(msk->pm.server_side)))
                pr_warn_once("bogus mpc option on established client sk");
        mptcp_subflow_fully_established(subflow, mp_opt);
 
-fully_established:
+check_notify:
        /* if the subflow is not already linked into the conn_list, we can't
         * notify the PM: this subflow is still on the listener queue
         * and the PM possibly acquiring the subflow lock could race with
index 66a599d..3fa0aa4 100644 (file)
@@ -36,15 +36,6 @@ struct mptcp6_sock {
 };
 #endif
 
-struct mptcp_skb_cb {
-       u64 map_seq;
-       u64 end_seq;
-       u32 offset;
-       u8  has_rxtstamp:1;
-};
-
-#define MPTCP_SKB_CB(__skb)    ((struct mptcp_skb_cb *)&((__skb)->cb[0]))
-
 enum {
        MPTCP_CMSG_TS = BIT(0),
        MPTCP_CMSG_INQ = BIT(1),
index b5abea3..618ac85 100644 (file)
 #define MPTCP_CONNECTED                6
 #define MPTCP_RESET_SCHEDULER  7
 
+struct mptcp_skb_cb {
+       u64 map_seq;
+       u64 end_seq;
+       u32 offset;
+       u8  has_rxtstamp:1;
+};
+
+#define MPTCP_SKB_CB(__skb)    ((struct mptcp_skb_cb *)&((__skb)->cb[0]))
+
 static inline bool before64(__u64 seq1, __u64 seq2)
 {
        return (__s64)(seq1 - seq2) < 0;
@@ -471,7 +480,9 @@ struct mptcp_subflow_context {
                disposable : 1,     /* ctx can be free at ulp release time */
                stale : 1,          /* unable to snd/rcv data, do not use for xmit */
                local_id_valid : 1, /* local_id is correctly initialized */
-               valid_csum_seen : 1;        /* at least one csum validated */
+               valid_csum_seen : 1,        /* at least one csum validated */
+               is_mptfo : 1,       /* subflow is doing TFO */
+               __unused : 8;
        enum mptcp_data_avail data_avail;
        u32     remote_nonce;
        u64     thmac;
@@ -829,6 +840,9 @@ void mptcp_event_addr_announced(const struct sock *ssk, const struct mptcp_addr_
 void mptcp_event_addr_removed(const struct mptcp_sock *msk, u8 id);
 bool mptcp_userspace_pm_active(const struct mptcp_sock *msk);
 
+void mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow,
+                                  const struct mptcp_options_received *mp_opt);
+
 static inline bool mptcp_pm_should_add_signal(struct mptcp_sock *msk)
 {
        return READ_ONCE(msk->pm.addr_signal) &
index eca4de0..cbeb771 100644 (file)
@@ -664,6 +664,9 @@ void mptcp_subflow_fully_established(struct mptcp_subflow_context *subflow,
        subflow_set_remote_key(msk, subflow, mp_opt);
        subflow->fully_established = 1;
        WRITE_ONCE(msk->fully_established, true);
+
+       if (subflow->is_mptfo)
+               mptcp_fastopen_gen_msk_ackseq(msk, subflow, mp_opt);
 }
 
 static struct sock *subflow_syn_recv_sock(const struct sock *sk,
@@ -779,7 +782,7 @@ create_child:
                        /* with OoO packets we can reach here without ingress
                         * mpc option
                         */
-                       if (mp_opt.suboptions & OPTIONS_MPTCP_MPC)
+                       if (mp_opt.suboptions & OPTION_MPTCP_MPC_ACK)
                                mptcp_subflow_fully_established(ctx, &mp_opt);
                } else if (ctx->mp_join) {
                        struct mptcp_sock *owner;