tcp: Preserve data sent during SOCK_SYN_SENT state

Seen with iperf3 server on tap side: connection state is SOCK_SYN_SENT,
we haven't got an ACK from the tap yet (that's why we're not in
ESTABLISHED), but a data packet comes. Don't read this data until we
reach the ESTABLISHED state, by keeping EPOLLIN disabled until that
point.

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
Stefano Brivio 2021-04-25 10:46:42 +02:00
parent b3b3451ae2
commit 48afbe321e

23
tcp.c
View file

@ -954,7 +954,7 @@ static void tcp_conn_from_tap(struct ctx *c, int af, void *addr,
tcp_act_set(s);
ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP | EPOLLERR | EPOLLHUP;
ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP | EPOLLHUP;
ev.data.fd = s;
tc[s].seq_init_from_tap = ntohl(th->seq);
@ -1059,7 +1059,7 @@ static void tcp_conn_from_sock(struct ctx *c, int fd)
tcp_act_set(s);
ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP | EPOLLERR | EPOLLHUP;
ev.events = EPOLLRDHUP | EPOLLHUP;
ev.data.fd = s;
epoll_ctl(c->epollfd, EPOLL_CTL_ADD, s, &ev);
@ -1209,6 +1209,7 @@ int tcp_tap_handler(struct ctx *c, int af, void *addr,
{
/* TODO: Implement message batching for TCP */
struct tcphdr *th = (struct tcphdr *)msg[0].l4h;
struct epoll_event ev = { 0 };
size_t len = msg[0].l4_len;
size_t off, skip = 0;
@ -1272,6 +1273,16 @@ int tcp_tap_handler(struct ctx *c, int af, void *addr,
tcp_set_state(s, ESTABLISHED);
tcp_send_to_tap(c, s, ACK, NULL, 0);
/* The client might have sent data already, which we didn't
* dequeue waiting for SYN,ACK from tap -- check now.
*/
tcp_data_from_sock(c, s);
ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP | EPOLLHUP;
ev.data.fd = s;
epoll_ctl(c->epollfd, EPOLL_CTL_MOD, s, &ev);
break;
case TAP_SYN_RCVD:
if (th->fin) {
@ -1379,7 +1390,7 @@ static void tcp_connect_finish(struct ctx *c, int s)
return;
/* Drop EPOLLOUT, only used to wait for connect() to complete */
ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP | EPOLLERR | EPOLLHUP;
ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP | EPOLLHUP;
ev.data.fd = s;
epoll_ctl(c->epollfd, EPOLL_CTL_MOD, s, &ev);
@ -1403,6 +1414,12 @@ void tcp_sock_handler(struct ctx *c, int s, uint32_t events)
return;
}
if (tc[s].s == SOCK_SYN_SENT) {
/* This can only be a socket error or a shutdown from remote */
tcp_rst(c, s);
return;
}
sl = sizeof(so);
if ((events & EPOLLERR) ||
getsockopt(s, SOL_SOCKET, SO_ACCEPTCONN, &so, &sl)) {