Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mptcp: implement and use MPTCP-level retransmission

On timeout event, schedule a work queue to do the retransmission.
Retransmission code closely resembles the sendmsg() implementation and
re-uses mptcp_sendmsg_frag, providing a dummy msghdr - for flags'
sake - and peeking the relevant dfrag from the rtx head.

Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Paolo Abeni and committed by
David S. Miller
3b1d6210 3f8e0aae

+95 -4
+94 -4
net/mptcp/protocol.c
··· 283 283 void mptcp_data_acked(struct sock *sk) 284 284 { 285 285 mptcp_reset_timer(sk); 286 + 287 + if (!sk_stream_is_writeable(sk) && 288 + schedule_work(&mptcp_sk(sk)->work)) 289 + sock_hold(sk); 286 290 } 287 291 288 292 static void mptcp_stop_timer(struct sock *sk) ··· 904 900 { 905 901 struct mptcp_sock *msk = mptcp_sk(sk); 906 902 907 - if (atomic64_read(&msk->snd_una) == msk->write_seq) 903 + if (atomic64_read(&msk->snd_una) == msk->write_seq) { 908 904 mptcp_stop_timer(sk); 909 - else 910 - mptcp_reset_timer(sk); 905 + } else { 906 + set_bit(MPTCP_WORK_RTX, &msk->flags); 907 + if (schedule_work(&msk->work)) 908 + sock_hold(sk); 909 + } 911 910 } 912 911 913 912 static void mptcp_retransmit_timer(struct timer_list *t) ··· 930 923 } 931 924 bh_unlock_sock(sk); 932 925 sock_put(sk); 926 + } 927 + 928 + /* Find an idle subflow. Return NULL if there is unacked data at tcp 929 + * level. 930 + * 931 + * A backup subflow is returned only if that is the only kind available. 932 + */ 933 + static struct sock *mptcp_subflow_get_retrans(const struct mptcp_sock *msk) 934 + { 935 + struct mptcp_subflow_context *subflow; 936 + struct sock *backup = NULL; 937 + 938 + sock_owned_by_me((const struct sock *)msk); 939 + 940 + mptcp_for_each_subflow(msk, subflow) { 941 + struct sock *ssk = mptcp_subflow_tcp_sock(subflow); 942 + 943 + /* still data outstanding at TCP level? Don't retransmit. */ 944 + if (!tcp_write_queue_empty(ssk)) 945 + return NULL; 946 + 947 + if (subflow->backup) { 948 + if (!backup) 949 + backup = ssk; 950 + continue; 951 + } 952 + 953 + return ssk; 954 + } 955 + 956 + return backup; 933 957 } 934 958 935 959 /* subflow sockets can be either outgoing (connect) or incoming ··· 996 958 static void mptcp_worker(struct work_struct *work) 997 959 { 998 960 struct mptcp_sock *msk = container_of(work, struct mptcp_sock, work); 999 - struct sock *sk = &msk->sk.icsk_inet.sk; 961 + struct sock *ssk, *sk = &msk->sk.icsk_inet.sk; 962 + int orig_len, orig_offset, ret, mss_now = 0, size_goal = 0; 963 + struct mptcp_data_frag *dfrag; 964 + u64 orig_write_seq; 965 + size_t copied = 0; 966 + struct msghdr msg; 967 + long timeo = 0; 1000 968 1001 969 lock_sock(sk); 970 + mptcp_clean_una(sk); 1002 971 __mptcp_flush_join_list(msk); 1003 972 __mptcp_move_skbs(msk); 973 + 974 + if (!test_and_clear_bit(MPTCP_WORK_RTX, &msk->flags)) 975 + goto unlock; 976 + 977 + dfrag = mptcp_rtx_head(sk); 978 + if (!dfrag) 979 + goto unlock; 980 + 981 + ssk = mptcp_subflow_get_retrans(msk); 982 + if (!ssk) 983 + goto reset_unlock; 984 + 985 + lock_sock(ssk); 986 + 987 + msg.msg_flags = MSG_DONTWAIT; 988 + orig_len = dfrag->data_len; 989 + orig_offset = dfrag->offset; 990 + orig_write_seq = dfrag->data_seq; 991 + while (dfrag->data_len > 0) { 992 + ret = mptcp_sendmsg_frag(sk, ssk, &msg, dfrag, &timeo, &mss_now, 993 + &size_goal); 994 + if (ret < 0) 995 + break; 996 + 997 + copied += ret; 998 + dfrag->data_len -= ret; 999 + dfrag->offset += ret; 1000 + } 1001 + if (copied) 1002 + tcp_push(ssk, msg.msg_flags, mss_now, tcp_sk(ssk)->nonagle, 1003 + size_goal); 1004 + 1005 + dfrag->data_seq = orig_write_seq; 1006 + dfrag->offset = orig_offset; 1007 + dfrag->data_len = orig_len; 1008 + 1009 + mptcp_set_timeout(sk, ssk); 1010 + release_sock(ssk); 1011 + 1012 + reset_unlock: 1013 + if (!mptcp_timer_pending(sk)) 1014 + mptcp_reset_timer(sk); 1015 + 1016 + unlock: 1004 1017 release_sock(sk); 1005 1018 sock_put(sk); 1006 1019 } ··· 1213 1124 lock_sock(sk); 1214 1125 __mptcp_clear_xmit(sk); 1215 1126 release_sock(sk); 1127 + mptcp_cancel_work(sk); 1216 1128 return tcp_disconnect(sk, flags); 1217 1129 } 1218 1130
+1
net/mptcp/protocol.h
··· 88 88 /* MPTCP socket flags */ 89 89 #define MPTCP_DATA_READY 0 90 90 #define MPTCP_SEND_SPACE 1 91 + #define MPTCP_WORK_RTX 2 91 92 92 93 static inline __be32 mptcp_option(u8 subopt, u8 len, u8 nib, u8 field) 93 94 {