Instead of passing separate pointers to the TCP header and SYN options,
pass an iov_tail pointing to the start of the TCP payload area.
tcp_prepare_flags() then uses with_header() and IOV_DROP_HEADER() to
access the TCP header and SYN options directly within the iov, matching
the iov_tail-based approach already used by tcp_fill_headers().
Signed-off-by: Laurent Vivier
---
tcp.c | 71 +++++++++++++++++++++++++++-----------------------
tcp_buf.c | 8 +++---
tcp_internal.h | 2 +-
tcp_vu.c | 9 +++----
4 files changed, 48 insertions(+), 42 deletions(-)
diff --git a/tcp.c b/tcp.c
index 058792d5b184..ad601567d39f 100644
--- a/tcp.c
+++ b/tcp.c
@@ -1295,8 +1295,7 @@ static int tcp_rewind_seq(const struct ctx *c, struct tcp_tap_conn *conn)
* @c: Execution context
* @conn: Connection pointer
* @flags: TCP flags: if not set, send segment only if ACK is due
- * @th: TCP header to update
- * @opts: TCP option buffer (output parameter)
+ * @payload: TCP payload including TCP header
* @optlen: size of the TCP option buffer (output parameter)
*
* Return: < 0 error code on connection reset,
@@ -1304,10 +1303,11 @@ static int tcp_rewind_seq(const struct ctx *c, struct tcp_tap_conn *conn)
* 1 otherwise
*/
int tcp_prepare_flags(const struct ctx *c, struct tcp_tap_conn *conn,
- int flags, struct tcphdr *th, struct tcp_syn_opts *opts,
+ int flags, const struct iov_tail *payload,
size_t *optlen)
{
struct tcp_info_linux tinfo = { 0 };
+ struct iov_tail current = *payload;
socklen_t sl = sizeof(tinfo);
int s = conn->sock;
@@ -1330,6 +1330,40 @@ int tcp_prepare_flags(const struct ctx *c, struct tcp_tap_conn *conn,
*optlen = 0;
if (flags & SYN) {
+ conn->ws_to_tap = MIN(MAX_WS, tinfo.tcpi_snd_wscale);
+
+ *optlen = sizeof(struct tcp_syn_opts);
+ } else {
+ flags |= ACK;
+ }
+
+ with_header(struct tcphdr, th, ¤t) {
+ th->doff = (sizeof(*th) + *optlen) / 4;
+
+ th->ack = !!(flags & ACK);
+ th->psh = !!(flags & PSH);
+ th->rst = !!(flags & RST);
+ th->syn = !!(flags & SYN);
+ th->fin = !!(flags & FIN);
+
+ if (th->ack) {
+ if (SEQ_GE(conn->seq_ack_to_tap, conn->seq_from_tap) &&
+ conn->wnd_to_tap)
+ conn_flag(c, conn, ~ACK_TO_TAP_DUE);
+ else
+ conn_flag(c, conn, ACK_TO_TAP_DUE);
+ }
+
+ if (th->fin)
+ conn_flag(c, conn, ACK_FROM_TAP_DUE);
+
+ /* RFC 793, 3.1: "[...] and the first data octet is ISN+1." */
+ if (th->fin || th->syn)
+ conn->seq_to_tap++;
+ }
+ IOV_DROP_HEADER(¤t, struct tcphdr);
+
+ if (*optlen) {
int mss;
if (!c->mtu) {
@@ -1348,37 +1382,10 @@ int tcp_prepare_flags(const struct ctx *c, struct tcp_tap_conn *conn,
mss = ROUND_DOWN(mss, PAGE_SIZE);
}
- conn->ws_to_tap = MIN(MAX_WS, tinfo.tcpi_snd_wscale);
-
- *opts = TCP_SYN_OPTS(mss, conn->ws_to_tap);
- *optlen = sizeof(*opts);
- } else {
- flags |= ACK;
+ with_header(struct tcp_syn_opts, opts, ¤t)
+ *opts = TCP_SYN_OPTS(mss, conn->ws_to_tap);
}
- th->doff = (sizeof(*th) + *optlen) / 4;
-
- th->ack = !!(flags & ACK);
- th->psh = !!(flags & PSH);
- th->rst = !!(flags & RST);
- th->syn = !!(flags & SYN);
- th->fin = !!(flags & FIN);
-
- if (th->ack) {
- if (SEQ_GE(conn->seq_ack_to_tap, conn->seq_from_tap) &&
- conn->wnd_to_tap)
- conn_flag(c, conn, ~ACK_TO_TAP_DUE);
- else
- conn_flag(c, conn, ACK_TO_TAP_DUE);
- }
-
- if (th->fin)
- conn_flag(c, conn, ACK_FROM_TAP_DUE);
-
- /* RFC 793, 3.1: "[...] and the first data octet is ISN+1." */
- if (th->fin || th->syn)
- conn->seq_to_tap++;
-
return 1;
}
diff --git a/tcp_buf.c b/tcp_buf.c
index 891043c96dcb..ffd250c8798f 100644
--- a/tcp_buf.c
+++ b/tcp_buf.c
@@ -197,7 +197,7 @@ static void tcp_l2_buf_fill_headers(const struct ctx *c,
*/
int tcp_buf_send_flag(const struct ctx *c, struct tcp_tap_conn *conn, int flags)
{
- struct tcp_payload_t *payload;
+ struct iov_tail tail;
struct iovec *iov;
size_t optlen;
size_t l4len;
@@ -211,10 +211,10 @@ int tcp_buf_send_flag(const struct ctx *c, struct tcp_tap_conn *conn, int flags)
iov[TCP_IOV_IP] = IOV_OF_LVALUE(tcp6_payload_ip[tcp_payload_used]);
iov[TCP_IOV_ETH] = IOV_OF_LVALUE(tcp_eth_hdr[tcp_payload_used]);
- payload = iov[TCP_IOV_PAYLOAD].iov_base;
+ iov[TCP_IOV_PAYLOAD].iov_len = sizeof(struct tcp_payload_t);
+ tail = IOV_TAIL(&iov[TCP_IOV_PAYLOAD], 1, 0);
seq = conn->seq_to_tap;
- ret = tcp_prepare_flags(c, conn, flags, &payload->th,
- (struct tcp_syn_opts *)&payload->data, &optlen);
+ ret = tcp_prepare_flags(c, conn, flags, &tail, &optlen);
if (ret <= 0)
return ret;
diff --git a/tcp_internal.h b/tcp_internal.h
index 136e947f6e70..9f745d0752ff 100644
--- a/tcp_internal.h
+++ b/tcp_internal.h
@@ -190,7 +190,7 @@ size_t tcp_fill_headers(const struct ctx *c, struct tcp_tap_conn *conn,
int tcp_update_seqack_wnd(const struct ctx *c, struct tcp_tap_conn *conn,
bool force_seq, struct tcp_info_linux *tinfo);
int tcp_prepare_flags(const struct ctx *c, struct tcp_tap_conn *conn,
- int flags, struct tcphdr *th, struct tcp_syn_opts *opts,
+ int flags, const struct iov_tail *payload,
size_t *optlen);
int tcp_set_peek_offset(const struct tcp_tap_conn *conn, int offset);
diff --git a/tcp_vu.c b/tcp_vu.c
index 96cd9da1caae..d6bd6a34d6da 100644
--- a/tcp_vu.c
+++ b/tcp_vu.c
@@ -90,7 +90,6 @@ int tcp_vu_send_flag(const struct ctx *c, struct tcp_tap_conn *conn, int flags)
struct ipv6hdr *ip6h = NULL;
struct iphdr *ip4h = NULL;
struct iovec flags_iov[2];
- struct tcp_syn_opts *opts;
struct iov_tail payload;
size_t optlen, hdrlen;
struct tcphdr *th;
@@ -104,13 +103,13 @@ int tcp_vu_send_flag(const struct ctx *c, struct tcp_tap_conn *conn, int flags)
elem_cnt = vu_collect(vdev, vq, &flags_elem[0], 1,
&flags_iov[0], 1, NULL,
- hdrlen + sizeof(*opts), NULL);
+ hdrlen + sizeof(struct tcp_syn_opts), NULL);
if (elem_cnt != 1)
return -1;
assert(flags_elem[0].in_num == 1);
assert(flags_elem[0].in_sg[0].iov_len >=
- MAX(hdrlen + sizeof(*opts), ETH_ZLEN + VNET_HLEN));
+ MAX(hdrlen + sizeof(struct tcp_syn_opts), ETH_ZLEN + VNET_HLEN));
vu_set_vnethdr(flags_elem[0].in_sg[0].iov_base, 1);
@@ -139,8 +138,8 @@ int tcp_vu_send_flag(const struct ctx *c, struct tcp_tap_conn *conn, int flags)
th->ack = 1;
seq = conn->seq_to_tap;
- opts = (struct tcp_syn_opts *)(th + 1);
- ret = tcp_prepare_flags(c, conn, flags, th, opts, &optlen);
+ payload = IOV_TAIL(flags_elem[0].in_sg, 1, hdrlen - sizeof(*th));
+ ret = tcp_prepare_flags(c, conn, flags, &payload, &optlen);
if (ret <= 0) {
vu_queue_rewind(vq, 1);
return ret;
--
2.53.0