See below. > -----Original Message----- > From: Tung Nguyen <tung.q.ngu...@dektech.com.au> > Sent: 14-Nov-19 03:28 > To: tipc-discussion@lists.sourceforge.net; Jon Maloy > <jon.ma...@ericsson.com>; ma...@donjonn.com; > ying....@windriver.com > Subject: [tipc-discussion] [net v2 1/1] tipc: fix duplicate SYN messages > under link congestion > > Scenario: > 1. A client socket initiates a SYN message to a listening socket. > 2. The send link is congested, the SYN message is put in the > send link and a wakeup message is put in wakeup queue. > 3. The congestion situation is abated, the wakeup message is > pulled out of the wakeup queue. Function tipc_sk_push_backlog() > is called to send out delayed messages by Nagle. However, > the client socket is still in CONNECTING state. So, it sends > the SYN message in the socket write queue to the listening socket > again. > 4. The listening socket receives the first SYN message and creates > first server socket. The client socket receives ACK- and establishes > a connection to the first server socket. The client socket closes > its connection with the first server socket. > 5. The listening socket receives the second SYN message and creates > second server socket. The second server socket sends ACK- to the > client socket, but it has been closed. It results in connection > refuse error when reading from the server socket in user space. > > Solution: return from function tipc_sk_push_backlog() immediately > if there is pending SYN message in the socket write queue. > > v2: use Jon's suggestion. > > Fixes: c0bceb97db9e ("tipc: add smart nagle feature") > Signed-off-by: Tung Nguyen <tung.q.ngu...@dektech.com.au> > --- > net/tipc/socket.c | 16 ++++++++++------ > 1 file changed, 10 insertions(+), 6 deletions(-) > > diff --git a/net/tipc/socket.c b/net/tipc/socket.c > index 5d7859a..7a402ee 100644 > --- a/net/tipc/socket.c > +++ b/net/tipc/socket.c > @@ -540,12 +540,10 @@ static void __tipc_shutdown(struct socket *sock, int > error) > tipc_wait_for_cond(sock, &timeout, (!tsk->cong_link_cnt && > !tsk_conn_cong(tsk))); > > - /* Push out unsent messages or remove if pending SYN */ > - skb = skb_peek(&sk->sk_write_queue); > - if (skb && !msg_is_syn(buf_msg(skb))) > - tipc_sk_push_backlog(tsk); > - else > - __skb_queue_purge(&sk->sk_write_queue); > + /* Push out delayed messages if in Nagle mode */ > + tipc_sk_push_backlog(tsk); > + /* Remove pending SYN */ > + __skb_queue_purge(&sk->sk_write_queue); > > /* Reject all unreceived messages, except on an active connection > * (which disconnects locally & sends a 'FIN+' to peer). > @@ -1248,11 +1246,17 @@ static void tipc_sk_push_backlog(struct tipc_sock > *tsk) > struct sk_buff_head *txq = &tsk->sk.sk_write_queue; > struct net *net = sock_net(&tsk->sk); > u32 dnode = tsk_peer_node(tsk); > + struct sk_buff *skb; > int rc; > > if (skb_queue_empty(txq) || tsk->cong_link_cnt) > return; > > + skb = skb_peek(txq);
Move this line to before the if() clause.Then test for if (!skb ||...) instead of skb_queue_empty(). This way we should save a couple of instructions. Acked-by:jon > + /* Do not send SYN again after congestion */ > + if (msg_is_syn(buf_msg(skb))) > + return; > + > tsk->snt_unacked += tsk->snd_backlog; > tsk->snd_backlog = 0; > tsk->expect_ack = true; > -- > 2.1.4 _______________________________________________ tipc-discussion mailing list tipc-discussion@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tipc-discussion