flow: Make side 0 always be the initiating side

Each flow in the flow table has two sides, 0 and 1, representing the
two interfaces between which passt/pasta will forward data for that flow.
Which side is which is currently up to the protocol specific code:  TCP
uses side 0 for the host/"sock" side and 1 for the guest/"tap" side, except
for spliced connections where it uses 0 for the initiating side and 1 for
the target side.  ICMP also uses 0 for the host/"sock" side and 1 for the
guest/"tap" side, but in its case the latter is always also the initiating
side.

Make this generically consistent by always using side 0 for the initiating
side and 1 for the target side.  This doesn't simplify a lot for now, and
arguably makes TCP slightly more complex, since we add an extra field to
the connection structure to record which is the guest facing side. This is
an interim change, which we'll be able to remove later.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>q
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
David Gibson 2024-05-21 15:57:06 +10:00 committed by Stefano Brivio
parent 0060acd11b
commit 43571852e6
7 changed files with 21 additions and 27 deletions

5
flow.c
View file

@ -152,12 +152,10 @@ static void flow_set_state(struct flow_common *f, enum flow_state state)
* flow_set_type() - Set type and move to TYPED * flow_set_type() - Set type and move to TYPED
* @flow: Flow to change state * @flow: Flow to change state
* @type: Type for new flow * @type: Type for new flow
* @iniside: Which side initiated the new flow
* *
* Return: @flow * Return: @flow
*/ */
union flow *flow_set_type(union flow *flow, enum flow_type type, union flow *flow_set_type(union flow *flow, enum flow_type type)
unsigned iniside)
{ {
struct flow_common *f = &flow->f; struct flow_common *f = &flow->f;
@ -165,7 +163,6 @@ union flow *flow_set_type(union flow *flow, enum flow_type type,
ASSERT(flow_new_entry == flow && f->state == FLOW_STATE_NEW); ASSERT(flow_new_entry == flow && f->state == FLOW_STATE_NEW);
ASSERT(f->type == FLOW_TYPE_NONE); ASSERT(f->type == FLOW_TYPE_NONE);
(void)iniside;
f->type = type; f->type = type;
flow_set_state(f, FLOW_STATE_TYPED); flow_set_state(f, FLOW_STATE_TYPED);
return flow; return flow;

5
flow.h
View file

@ -100,6 +100,11 @@ extern const uint8_t flow_proto[];
#define FLOW_PROTO(f) \ #define FLOW_PROTO(f) \
((f)->type < FLOW_NUM_TYPES ? flow_proto[(f)->type] : 0) ((f)->type < FLOW_NUM_TYPES ? flow_proto[(f)->type] : 0)
#define SIDES 2
#define INISIDE 0 /* Initiating side */
#define TGTSIDE 1 /* Target side */
/** /**
* struct flow_common - Common fields for packet flows * struct flow_common - Common fields for packet flows
* @state: State of the flow table entry * @state: State of the flow table entry

View file

@ -107,10 +107,8 @@ static inline flow_sidx_t flow_sidx(const struct flow_common *f,
union flow *flow_alloc(void); union flow *flow_alloc(void);
void flow_alloc_cancel(union flow *flow); void flow_alloc_cancel(union flow *flow);
union flow *flow_set_type(union flow *flow, enum flow_type type, union flow *flow_set_type(union flow *flow, enum flow_type type);
unsigned iniside); #define FLOW_SET_TYPE(flow_, t_, var_) (&flow_set_type((flow_), (t_))->var_)
#define FLOW_SET_TYPE(flow_, t_, var_, i_) \
(&flow_set_type((flow_), (t_), (i_))->var_)
void flow_activate(struct flow_common *f); void flow_activate(struct flow_common *f);
#define FLOW_ACTIVATE(flow_) \ #define FLOW_ACTIVATE(flow_) \

8
icmp.c
View file

@ -45,10 +45,6 @@
#define ICMP_ECHO_TIMEOUT 60 /* s, timeout for ICMP socket activity */ #define ICMP_ECHO_TIMEOUT 60 /* s, timeout for ICMP socket activity */
#define ICMP_NUM_IDS (1U << 16) #define ICMP_NUM_IDS (1U << 16)
/* Sides of a flow as we use them for ping streams */
#define SOCKSIDE 0
#define TAPSIDE 1
#define PINGF(idx) (&(FLOW(idx)->ping)) #define PINGF(idx) (&(FLOW(idx)->ping))
/* Indexed by ICMP echo identifier */ /* Indexed by ICMP echo identifier */
@ -167,7 +163,7 @@ static struct icmp_ping_flow *icmp_ping_new(const struct ctx *c,
if (!flow) if (!flow)
return NULL; return NULL;
pingf = FLOW_SET_TYPE(flow, flowtype, ping, TAPSIDE); pingf = FLOW_SET_TYPE(flow, flowtype, ping);
pingf->seq = -1; pingf->seq = -1;
pingf->id = id; pingf->id = id;
@ -180,7 +176,7 @@ static struct icmp_ping_flow *icmp_ping_new(const struct ctx *c,
bind_if = c->ip6.ifname_out; bind_if = c->ip6.ifname_out;
} }
ref.flowside = FLOW_SIDX(flow, SOCKSIDE); ref.flowside = FLOW_SIDX(flow, TGTSIDE);
pingf->sock = sock_l4(c, af, flow_proto[flowtype], bind_addr, bind_if, pingf->sock = sock_l4(c, af, flow_proto[flowtype], bind_addr, bind_if,
0, ref.data); 0, ref.data);

19
tcp.c
View file

@ -303,10 +303,6 @@
#include "flow_table.h" #include "flow_table.h"
/* Sides of a flow as we use them in "tap" connections */
#define SOCKSIDE 0
#define TAPSIDE 1
#define TCP_FRAMES_MEM 128 #define TCP_FRAMES_MEM 128
#define TCP_FRAMES \ #define TCP_FRAMES \
(c->mode == MODE_PASST ? TCP_FRAMES_MEM : 1) (c->mode == MODE_PASST ? TCP_FRAMES_MEM : 1)
@ -581,7 +577,7 @@ static int tcp_epoll_ctl(const struct ctx *c, struct tcp_tap_conn *conn)
{ {
int m = conn->in_epoll ? EPOLL_CTL_MOD : EPOLL_CTL_ADD; int m = conn->in_epoll ? EPOLL_CTL_MOD : EPOLL_CTL_ADD;
union epoll_ref ref = { .type = EPOLL_TYPE_TCP, .fd = conn->sock, union epoll_ref ref = { .type = EPOLL_TYPE_TCP, .fd = conn->sock,
.flowside = FLOW_SIDX(conn, SOCKSIDE) }; .flowside = FLOW_SIDX(conn, !conn->tapside), };
struct epoll_event ev = { .data.u64 = ref.u64 }; struct epoll_event ev = { .data.u64 = ref.u64 };
if (conn->events == CLOSED) { if (conn->events == CLOSED) {
@ -1134,7 +1130,7 @@ static uint64_t tcp_conn_hash(const struct ctx *c,
static inline unsigned tcp_hash_probe(const struct ctx *c, static inline unsigned tcp_hash_probe(const struct ctx *c,
const struct tcp_tap_conn *conn) const struct tcp_tap_conn *conn)
{ {
flow_sidx_t sidx = FLOW_SIDX(conn, TAPSIDE); flow_sidx_t sidx = FLOW_SIDX(conn, conn->tapside);
unsigned b = tcp_conn_hash(c, conn) % TCP_HASH_TABLE_SIZE; unsigned b = tcp_conn_hash(c, conn) % TCP_HASH_TABLE_SIZE;
/* Linear probing */ /* Linear probing */
@ -1154,7 +1150,7 @@ static void tcp_hash_insert(const struct ctx *c, struct tcp_tap_conn *conn)
{ {
unsigned b = tcp_hash_probe(c, conn); unsigned b = tcp_hash_probe(c, conn);
tc_hash[b] = FLOW_SIDX(conn, TAPSIDE); tc_hash[b] = FLOW_SIDX(conn, conn->tapside);
flow_dbg(conn, "hash table insert: sock %i, bucket: %u", conn->sock, b); flow_dbg(conn, "hash table insert: sock %i, bucket: %u", conn->sock, b);
} }
@ -2004,7 +2000,8 @@ static void tcp_conn_from_tap(struct ctx *c, sa_family_t af,
goto cancel; goto cancel;
} }
conn = FLOW_SET_TYPE(flow, FLOW_TCP, tcp, TAPSIDE); conn = FLOW_SET_TYPE(flow, FLOW_TCP, tcp);
conn->tapside = INISIDE;
conn->sock = s; conn->sock = s;
conn->timer = -1; conn->timer = -1;
conn_event(c, conn, TAP_SYN_RCVD); conn_event(c, conn, TAP_SYN_RCVD);
@ -2716,9 +2713,9 @@ static void tcp_tap_conn_from_sock(struct ctx *c, in_port_t dstport,
const union sockaddr_inany *sa, const union sockaddr_inany *sa,
const struct timespec *now) const struct timespec *now)
{ {
struct tcp_tap_conn *conn = FLOW_SET_TYPE(flow, FLOW_TCP, tcp, struct tcp_tap_conn *conn = FLOW_SET_TYPE(flow, FLOW_TCP, tcp);
SOCKSIDE);
conn->tapside = TGTSIDE;
conn->sock = s; conn->sock = s;
conn->timer = -1; conn->timer = -1;
conn->ws_to_tap = conn->ws_from_tap = 0; conn->ws_to_tap = conn->ws_from_tap = 0;
@ -2870,7 +2867,7 @@ void tcp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events)
struct tcp_tap_conn *conn = CONN(ref.flowside.flow); struct tcp_tap_conn *conn = CONN(ref.flowside.flow);
ASSERT(conn->f.type == FLOW_TCP); ASSERT(conn->f.type == FLOW_TCP);
ASSERT(ref.flowside.side == SOCKSIDE); ASSERT(ref.flowside.side == !conn->tapside);
if (conn->events == CLOSED) if (conn->events == CLOSED)
return; return;

View file

@ -13,6 +13,7 @@
* struct tcp_tap_conn - Descriptor for a TCP connection (not spliced) * struct tcp_tap_conn - Descriptor for a TCP connection (not spliced)
* @f: Generic flow information * @f: Generic flow information
* @in_epoll: Is the connection in the epoll set? * @in_epoll: Is the connection in the epoll set?
* @tapside: Which side of the flow faces the tap/guest interface
* @tap_mss: MSS advertised by tap/guest, rounded to 2 ^ TCP_MSS_BITS * @tap_mss: MSS advertised by tap/guest, rounded to 2 ^ TCP_MSS_BITS
* @sock: Socket descriptor number * @sock: Socket descriptor number
* @events: Connection events, implying connection states * @events: Connection events, implying connection states
@ -39,6 +40,7 @@ struct tcp_tap_conn {
struct flow_common f; struct flow_common f;
bool in_epoll :1; bool in_epoll :1;
unsigned tapside :1;
#define TCP_RETRANS_BITS 3 #define TCP_RETRANS_BITS 3
unsigned int retrans :TCP_RETRANS_BITS; unsigned int retrans :TCP_RETRANS_BITS;
@ -106,7 +108,6 @@ struct tcp_tap_conn {
uint32_t seq_init_from_tap; uint32_t seq_init_from_tap;
}; };
#define SIDES 2
/** /**
* struct tcp_splice_conn - Descriptor for a spliced TCP connection * struct tcp_splice_conn - Descriptor for a spliced TCP connection
* @f: Generic flow information * @f: Generic flow information

View file

@ -471,7 +471,7 @@ bool tcp_splice_conn_from_sock(const struct ctx *c,
return false; return false;
} }
conn = FLOW_SET_TYPE(flow, FLOW_TCP_SPLICE, tcp_splice, 0); conn = FLOW_SET_TYPE(flow, FLOW_TCP_SPLICE, tcp_splice);
conn->flags = af == AF_INET ? 0 : SPLICE_V6; conn->flags = af == AF_INET ? 0 : SPLICE_V6;
conn->s[0] = s0; conn->s[0] = s0;