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:
parent
b3b3451ae2
commit
48afbe321e
1 changed files with 20 additions and 3 deletions
23
tcp.c
23
tcp.c
|
@ -954,7 +954,7 @@ static void tcp_conn_from_tap(struct ctx *c, int af, void *addr,
|
||||||
|
|
||||||
tcp_act_set(s);
|
tcp_act_set(s);
|
||||||
|
|
||||||
ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP | EPOLLERR | EPOLLHUP;
|
ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP | EPOLLHUP;
|
||||||
ev.data.fd = s;
|
ev.data.fd = s;
|
||||||
|
|
||||||
tc[s].seq_init_from_tap = ntohl(th->seq);
|
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);
|
tcp_act_set(s);
|
||||||
|
|
||||||
ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP | EPOLLERR | EPOLLHUP;
|
ev.events = EPOLLRDHUP | EPOLLHUP;
|
||||||
ev.data.fd = s;
|
ev.data.fd = s;
|
||||||
epoll_ctl(c->epollfd, EPOLL_CTL_ADD, s, &ev);
|
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 */
|
/* TODO: Implement message batching for TCP */
|
||||||
struct tcphdr *th = (struct tcphdr *)msg[0].l4h;
|
struct tcphdr *th = (struct tcphdr *)msg[0].l4h;
|
||||||
|
struct epoll_event ev = { 0 };
|
||||||
size_t len = msg[0].l4_len;
|
size_t len = msg[0].l4_len;
|
||||||
|
|
||||||
size_t off, skip = 0;
|
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_set_state(s, ESTABLISHED);
|
||||||
tcp_send_to_tap(c, s, ACK, NULL, 0);
|
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;
|
break;
|
||||||
case TAP_SYN_RCVD:
|
case TAP_SYN_RCVD:
|
||||||
if (th->fin) {
|
if (th->fin) {
|
||||||
|
@ -1379,7 +1390,7 @@ static void tcp_connect_finish(struct ctx *c, int s)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Drop EPOLLOUT, only used to wait for connect() to complete */
|
/* 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;
|
ev.data.fd = s;
|
||||||
epoll_ctl(c->epollfd, EPOLL_CTL_MOD, s, &ev);
|
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;
|
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);
|
sl = sizeof(so);
|
||||||
if ((events & EPOLLERR) ||
|
if ((events & EPOLLERR) ||
|
||||||
getsockopt(s, SOL_SOCKET, SO_ACCEPTCONN, &so, &sl)) {
|
getsockopt(s, SOL_SOCKET, SO_ACCEPTCONN, &so, &sl)) {
|
||||||
|
|
Loading…
Reference in a new issue