tcp, tcp_splice: Avoid double layered dispatch for connected TCP sockets

Currently connected TCP sockets have the same epoll type, whether they're
for a "tap" connection or a spliced connection.  This means that
tcp_sock_handler() has to do a secondary check on the type of the
connection to call the right function.  We can avoid this by adding a new
epoll type and dispatching directly to the right thing.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
David Gibson 2024-01-16 11:50:38 +11:00 committed by Stefano Brivio
parent 70121ca1ec
commit 02e092b4fe
5 changed files with 27 additions and 39 deletions

View file

@ -50,6 +50,7 @@
#include "pasta.h" #include "pasta.h"
#include "arch.h" #include "arch.h"
#include "log.h" #include "log.h"
#include "tcp_splice.h"
#define EPOLL_EVENTS 8 #define EPOLL_EVENTS 8
@ -61,6 +62,7 @@ char pkt_buf[PKT_BUF_BYTES] __attribute__ ((aligned(PAGE_SIZE)));
char *epoll_type_str[] = { char *epoll_type_str[] = {
[EPOLL_TYPE_TCP] = "connected TCP socket", [EPOLL_TYPE_TCP] = "connected TCP socket",
[EPOLL_TYPE_TCP_SPLICE] = "connected spliced TCP socket",
[EPOLL_TYPE_TCP_LISTEN] = "listening TCP socket", [EPOLL_TYPE_TCP_LISTEN] = "listening TCP socket",
[EPOLL_TYPE_TCP_TIMER] = "TCP timer", [EPOLL_TYPE_TCP_TIMER] = "TCP timer",
[EPOLL_TYPE_UDP] = "UDP socket", [EPOLL_TYPE_UDP] = "UDP socket",
@ -373,8 +375,10 @@ loop:
pasta_netns_quit_handler(&c, quit_fd); pasta_netns_quit_handler(&c, quit_fd);
break; break;
case EPOLL_TYPE_TCP: case EPOLL_TYPE_TCP:
if (!c.no_tcp) tcp_sock_handler(&c, ref, eventmask);
tcp_sock_handler(&c, ref, eventmask); break;
case EPOLL_TYPE_TCP_SPLICE:
tcp_splice_sock_handler(&c, ref, eventmask);
break; break;
case EPOLL_TYPE_TCP_LISTEN: case EPOLL_TYPE_TCP_LISTEN:
tcp_listen_handler(&c, ref, &now); tcp_listen_handler(&c, ref, &now);

View file

@ -51,6 +51,8 @@ enum epoll_type {
EPOLL_TYPE_NONE = 0, EPOLL_TYPE_NONE = 0,
/* Connected TCP sockets */ /* Connected TCP sockets */
EPOLL_TYPE_TCP, EPOLL_TYPE_TCP,
/* Connected TCP sockets (spliced) */
EPOLL_TYPE_TCP_SPLICE,
/* Listening TCP sockets */ /* Listening TCP sockets */
EPOLL_TYPE_TCP_LISTEN, EPOLL_TYPE_TCP_LISTEN,
/* timerfds used for TCP timers */ /* timerfds used for TCP timers */

36
tcp.c
View file

@ -2804,14 +2804,18 @@ void tcp_timer_handler(struct ctx *c, union epoll_ref ref)
} }
/** /**
* tcp_tap_sock_handler() - Handle new data from non-spliced socket * tcp_sock_handler() - Handle new data from non-spliced socket
* @c: Execution context * @c: Execution context
* @conn: Connection state * @ref: epoll reference
* @events: epoll events bitmap * @events: epoll events bitmap
*/ */
static void tcp_tap_sock_handler(struct ctx *c, struct tcp_tap_conn *conn, void tcp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events)
uint32_t events)
{ {
struct tcp_tap_conn *conn = CONN(ref.flowside.flow);
ASSERT(conn->f.type == FLOW_TCP);
ASSERT(ref.flowside.side == SOCKSIDE);
if (conn->events == CLOSED) if (conn->events == CLOSED)
return; return;
@ -2858,30 +2862,6 @@ static void tcp_tap_sock_handler(struct ctx *c, struct tcp_tap_conn *conn,
} }
} }
/**
* tcp_sock_handler() - Handle new data from socket, or timerfd event
* @c: Execution context
* @ref: epoll reference
* @events: epoll events bitmap
*/
void tcp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events)
{
union flow *flow = FLOW(ref.flowside.flow);
switch (flow->f.type) {
case FLOW_TCP:
tcp_tap_sock_handler(c, &flow->tcp, events);
break;
case FLOW_TCP_SPLICE:
tcp_splice_sock_handler(c, &flow->tcp_splice, ref.flowside.side,
events);
break;
default:
die("Unexpected %s in tcp_sock_handler_compact()",
FLOW_TYPE(&flow->f));
}
}
/** /**
* tcp_sock_init_af() - Initialise listening socket for a given af and port * tcp_sock_init_af() - Initialise listening socket for a given af and port
* @c: Execution context * @c: Execution context

View file

@ -127,9 +127,9 @@ static int tcp_splice_epoll_ctl(const struct ctx *c,
{ {
int m = conn->in_epoll ? EPOLL_CTL_MOD : EPOLL_CTL_ADD; int m = conn->in_epoll ? EPOLL_CTL_MOD : EPOLL_CTL_ADD;
const union epoll_ref ref[SIDES] = { const union epoll_ref ref[SIDES] = {
{ .type = EPOLL_TYPE_TCP, .fd = conn->s[0], { .type = EPOLL_TYPE_TCP_SPLICE, .fd = conn->s[0],
.flowside = FLOW_SIDX(conn, 0) }, .flowside = FLOW_SIDX(conn, 0) },
{ .type = EPOLL_TYPE_TCP, .fd = conn->s[1], { .type = EPOLL_TYPE_TCP_SPLICE, .fd = conn->s[1],
.flowside = FLOW_SIDX(conn, 1) } .flowside = FLOW_SIDX(conn, 1) }
}; };
struct epoll_event ev[SIDES] = { { .data.u64 = ref[0].u64 }, struct epoll_event ev[SIDES] = { { .data.u64 = ref[0].u64 },
@ -484,18 +484,20 @@ bool tcp_splice_conn_from_sock(const struct ctx *c,
/** /**
* tcp_splice_sock_handler() - Handler for socket mapped to spliced connection * tcp_splice_sock_handler() - Handler for socket mapped to spliced connection
* @c: Execution context * @c: Execution context
* @conn: Connection state * @ref: epoll reference
* @side: Side of the connection on which an event has occurred
* @events: epoll events bitmap * @events: epoll events bitmap
* *
* #syscalls:pasta splice * #syscalls:pasta splice
*/ */
void tcp_splice_sock_handler(struct ctx *c, struct tcp_splice_conn *conn, void tcp_splice_sock_handler(struct ctx *c, union epoll_ref ref,
int side, uint32_t events) uint32_t events)
{ {
struct tcp_splice_conn *conn = CONN(ref.flowside.flow);
unsigned side = ref.flowside.side, fromside;
uint8_t lowat_set_flag, lowat_act_flag; uint8_t lowat_set_flag, lowat_act_flag;
int eof, never_read; int eof, never_read;
unsigned fromside;
ASSERT(conn->f.type == FLOW_TCP_SPLICE);
if (conn->events == SPLICE_CLOSED) if (conn->events == SPLICE_CLOSED)
return; return;

View file

@ -8,8 +8,8 @@
struct tcp_splice_conn; struct tcp_splice_conn;
void tcp_splice_sock_handler(struct ctx *c, struct tcp_splice_conn *conn, void tcp_splice_sock_handler(struct ctx *c, union epoll_ref ref,
int side, uint32_t events); uint32_t events);
bool tcp_splice_conn_from_sock(const struct ctx *c, bool tcp_splice_conn_from_sock(const struct ctx *c,
union tcp_listen_epoll_ref ref, union tcp_listen_epoll_ref ref,
struct tcp_splice_conn *conn, int s, struct tcp_splice_conn *conn, int s,