The payload can be TCP + data or TCP + flags:
struct tcp_l2_flags_t {
struct tcphdr th;
char opts[OPT_MSS_LEN + OPT_WS_LEN + 1];
};
struct tcp_l2_payload_t {
struct tcphdr th; /* 20 bytes */
uint8_t data[MSS]; /* 65516 bytes */
#ifdef __AVX2__
} __attribute__ ((packed, aligned(32)));
#else
} __attribute__ ((packed, aligned(__alignof__(unsigned int))));
#endif
Not sure if we'd be better off with this approach, or having both IP
and L4 headers together, and the L4 payload in another. The latter
would mean duplicating the TCP or UDP headers between the IPv4 and
IPv6 cases, but it allows the data buffers - which will be used
directly on the socket side.
The main idea behind using iovec is to separate tcphdr and iphdr structures, allowing for
direct access to the pointers of tcphdr and iphdr without concerns about pointer
alignment. Moreover, having tcphdr and TCP payload in the same vector can make sense when
computing the TCP checksum, as the checksum includes tcphdr and the payload.
Thanks,
Laurent