tcp: Consolidate calculation of total frame size

tcp_l2_buf_fill_headers() returns the size of the generated frame including
the ethernet header.  The caller then adds on the size of the vnet_len
field to get the total frame size to be passed to the tap device.

Outside the tap code, though, we never care about the ethernet header size
only the final total size we need to put into an iovec.  So, consolidate
the total frame size calculation within tcp_l2_buf_fill_headers().

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 2023-01-06 11:43:16 +11:00 committed by Stefano Brivio
parent dcea26076d
commit e4443ba9bd

35
tcp.c
View file

@ -1451,7 +1451,7 @@ void tcp_defer_handler(struct ctx *c)
* @check: Checksum, if already known * @check: Checksum, if already known
* @seq: Sequence number for this segment * @seq: Sequence number for this segment
* *
* Return: 802.3 length, host order * Return: frame length including L2 headers, host order
*/ */
static size_t tcp_l2_buf_fill_headers(const struct ctx *c, static size_t tcp_l2_buf_fill_headers(const struct ctx *c,
const struct tcp_tap_conn *conn, const struct tcp_tap_conn *conn,
@ -1459,7 +1459,7 @@ static size_t tcp_l2_buf_fill_headers(const struct ctx *c,
const uint16_t *check, uint32_t seq) const uint16_t *check, uint32_t seq)
{ {
const struct in_addr *a4 = inany_v4(&conn->addr); const struct in_addr *a4 = inany_v4(&conn->addr);
size_t ip_len, eth_len; size_t ip_len, tlen;
#define SET_TCP_HEADER_COMMON_V4_V6(b, conn, seq) \ #define SET_TCP_HEADER_COMMON_V4_V6(b, conn, seq) \
do { \ do { \
@ -1493,9 +1493,10 @@ do { \
tcp_update_check_tcp4(b); tcp_update_check_tcp4(b);
eth_len = ip_len + sizeof(struct ethhdr); tlen = ip_len + sizeof(struct ethhdr);
if (c->mode == MODE_PASST) if (c->mode == MODE_PASST)
b->vnet_len = htonl(eth_len); b->vnet_len = htonl(tlen);
tlen += sizeof(b->vnet_len);
} else { } else {
struct tcp6_l2_buf_t *b = (struct tcp6_l2_buf_t *)p; struct tcp6_l2_buf_t *b = (struct tcp6_l2_buf_t *)p;
@ -1518,14 +1519,14 @@ do { \
b->ip6h.flow_lbl[1] = (conn->sock >> 8) & 0xff; b->ip6h.flow_lbl[1] = (conn->sock >> 8) & 0xff;
b->ip6h.flow_lbl[2] = (conn->sock >> 0) & 0xff; b->ip6h.flow_lbl[2] = (conn->sock >> 0) & 0xff;
eth_len = ip_len + sizeof(struct ethhdr); tlen = ip_len + sizeof(struct ethhdr);
if (c->mode == MODE_PASST) if (c->mode == MODE_PASST)
b->vnet_len = htonl(eth_len); b->vnet_len = htonl(tlen);
tlen += sizeof(b->vnet_len);
} }
#undef SET_TCP_HEADER_COMMON_V4_V6 #undef SET_TCP_HEADER_COMMON_V4_V6
return eth_len; return tlen;
} }
/** /**
@ -1631,8 +1632,8 @@ static int tcp_send_flag(struct ctx *c, struct tcp_tap_conn *conn, int flags)
struct tcp6_l2_flags_buf_t *b6 = NULL; struct tcp6_l2_flags_buf_t *b6 = NULL;
struct tcp_info tinfo = { 0 }; struct tcp_info tinfo = { 0 };
socklen_t sl = sizeof(tinfo); socklen_t sl = sizeof(tinfo);
size_t optlen = 0, eth_len;
int s = conn->sock; int s = conn->sock;
size_t optlen = 0;
struct iovec *iov; struct iovec *iov;
struct tcphdr *th; struct tcphdr *th;
char *data; char *data;
@ -1721,9 +1722,8 @@ static int tcp_send_flag(struct ctx *c, struct tcp_tap_conn *conn, int flags)
th->syn = !!(flags & SYN); th->syn = !!(flags & SYN);
th->fin = !!(flags & FIN); th->fin = !!(flags & FIN);
eth_len = tcp_l2_buf_fill_headers(c, conn, p, optlen, iov->iov_len = tcp_l2_buf_fill_headers(c, conn, p, optlen,
NULL, conn->seq_to_tap); NULL, conn->seq_to_tap);
iov->iov_len = eth_len + sizeof(uint32_t);
if (th->ack) if (th->ack)
conn_flag(c, conn, ~ACK_TO_TAP_DUE); conn_flag(c, conn, ~ACK_TO_TAP_DUE);
@ -2083,25 +2083,22 @@ static void tcp_data_to_tap(struct ctx *c, struct tcp_tap_conn *conn,
ssize_t plen, int no_csum, uint32_t seq) ssize_t plen, int no_csum, uint32_t seq)
{ {
struct iovec *iov; struct iovec *iov;
size_t len;
if (CONN_V4(conn)) { if (CONN_V4(conn)) {
struct tcp4_l2_buf_t *b = &tcp4_l2_buf[tcp4_l2_buf_used]; struct tcp4_l2_buf_t *b = &tcp4_l2_buf[tcp4_l2_buf_used];
uint16_t *check = no_csum ? &(b - 1)->iph.check : NULL; uint16_t *check = no_csum ? &(b - 1)->iph.check : NULL;
len = tcp_l2_buf_fill_headers(c, conn, b, plen, check, seq);
iov = tcp4_l2_iov + tcp4_l2_buf_used++; iov = tcp4_l2_iov + tcp4_l2_buf_used++;
iov->iov_len = len + sizeof(b->vnet_len); iov->iov_len = tcp_l2_buf_fill_headers(c, conn, b, plen,
check, seq);
if (tcp4_l2_buf_used > ARRAY_SIZE(tcp4_l2_buf) - 1) if (tcp4_l2_buf_used > ARRAY_SIZE(tcp4_l2_buf) - 1)
tcp_l2_data_buf_flush(c); tcp_l2_data_buf_flush(c);
} else if (CONN_V6(conn)) { } else if (CONN_V6(conn)) {
struct tcp6_l2_buf_t *b = &tcp6_l2_buf[tcp6_l2_buf_used]; struct tcp6_l2_buf_t *b = &tcp6_l2_buf[tcp6_l2_buf_used];
len = tcp_l2_buf_fill_headers(c, conn, b, plen, NULL, seq);
iov = tcp6_l2_iov + tcp6_l2_buf_used++; iov = tcp6_l2_iov + tcp6_l2_buf_used++;
iov->iov_len = len + sizeof(b->vnet_len); iov->iov_len = tcp_l2_buf_fill_headers(c, conn, b, plen,
NULL, seq);
if (tcp6_l2_buf_used > ARRAY_SIZE(tcp6_l2_buf) - 1) if (tcp6_l2_buf_used > ARRAY_SIZE(tcp6_l2_buf) - 1)
tcp_l2_data_buf_flush(c); tcp_l2_data_buf_flush(c);
} }