diff options
author | David Gibson <david@gibson.dropbear.id.au> | 2024-10-24 15:59:20 +1100 |
---|---|---|
committer | Stefano Brivio <sbrivio@redhat.com> | 2024-10-25 14:26:48 +0200 |
commit | 13f0291ede19fc6baea02e8327acec144bdf79e6 (patch) | |
tree | 326b0c815818e4b56549e71edf5623c6c40c65e5 /tcp.c | |
parent | 9e4615b40bfa7f1b692c3c3360d88a22c453b016 (diff) | |
download | passt-13f0291ede19fc6baea02e8327acec144bdf79e6.tar passt-13f0291ede19fc6baea02e8327acec144bdf79e6.tar.gz passt-13f0291ede19fc6baea02e8327acec144bdf79e6.tar.bz2 passt-13f0291ede19fc6baea02e8327acec144bdf79e6.tar.lz passt-13f0291ede19fc6baea02e8327acec144bdf79e6.tar.xz passt-13f0291ede19fc6baea02e8327acec144bdf79e6.tar.zst passt-13f0291ede19fc6baea02e8327acec144bdf79e6.zip |
tcp: Remove compile-time dependency on struct tcp_info version
In the Makefile we probe to create several defines based on the presence
of particular fields in struct tcp_info. These defines are used for two
purposes, neither of which they accomplish well:
1) Determining if the tcp_info fields are available at runtime. For this
purpose the defines are Just Plain Wrong, since the runtime kernel may
not be the same as the compile time kernel. We corrected this for
tcp_snd_wnd, but not for tcpi_bytes_acked or tcpi_min_rtt
2) Allowing the source to compile against older kernel headers which don't
have the fields in question. This works in theory, but it does mean
we won't be able to use the fields, even if later run against a
newer kernel. Furthermore, it's quite fragile: without much more
thorough tests of builds in different environments that we're currently
set up for, it's very easy to miss cases where we're accessing a field
without protection from an #ifdef. For example we currently access
tcpi_snd_wnd without #ifdefs in tcp_update_seqack_wnd().
Improve this with a different approach, borrowed from qemu (which has many
instances of similar problems). Don't compile against linux/tcp.h, using
netinet/tcp.h instead. Then for when we need an extension field, define
a struct tcp_info_linux, copied from the kernel, with all the fields we're
interested in. That may need updating from future kernel versions, but
only when we want to use a new extension, so it shouldn't be frequent.
This allows us to remove the HAS_SND_WND define entirely. We keep
HAS_BYTES_ACKED and HAS_MIN_RTT now, since they're used for purpose (1),
we'll fix that in a later patch.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
[sbrivio: Trivial grammar fixes in comments]
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Diffstat (limited to 'tcp.c')
-rw-r--r-- | tcp.c | 30 |
1 files changed, 9 insertions, 21 deletions
@@ -274,6 +274,7 @@ #include <net/if.h> #include <netinet/in.h> #include <netinet/ip.h> +#include <netinet/tcp.h> #include <stdint.h> #include <stdbool.h> #include <stddef.h> @@ -286,8 +287,6 @@ #include <time.h> #include <arpa/inet.h> -#include <linux/tcp.h> /* For struct tcp_info */ - #include "checksum.h" #include "util.h" #include "iov.h" @@ -303,6 +302,7 @@ #include "flow_table.h" #include "tcp_internal.h" +#include "tcp_info.h" #include "tcp_buf.h" /* MSS rounding: see SET_MSS() */ @@ -318,11 +318,6 @@ #define LOW_RTT_TABLE_SIZE 8 #define LOW_RTT_THRESHOLD 10 /* us */ -/* We need to include <linux/tcp.h> for tcpi_bytes_acked, instead of - * <netinet/tcp.h>, but that doesn't include a definition for SOL_TCP - */ -#define SOL_TCP IPPROTO_TCP - #define ACK_IF_NEEDED 0 /* See tcp_send_flag() */ #define CONN_IS_CLOSING(conn) \ @@ -365,14 +360,11 @@ char tcp_buf_discard [MAX_WINDOW]; /* Does the kernel support TCP_PEEK_OFF? */ bool peek_offset_cap; -#ifdef HAS_SND_WND + /* Does the kernel report sending window in TCP_INFO (kernel commit * 8f7baad7f035) */ bool snd_wnd_cap; -#else -#define snd_wnd_cap (false) -#endif /* sendmsg() to socket */ static struct iovec tcp_iov [UIO_MAXIOV]; @@ -678,7 +670,7 @@ static int tcp_rtt_dst_low(const struct tcp_tap_conn *conn) * @tinfo: Pointer to struct tcp_info for socket */ static void tcp_rtt_dst_check(const struct tcp_tap_conn *conn, - const struct tcp_info *tinfo) + const struct tcp_info_linux *tinfo) { #ifdef HAS_MIN_RTT const struct flowside *tapside = TAPFLOW(conn); @@ -1114,13 +1106,13 @@ size_t tcp_l2_buf_fill_headers(const struct tcp_tap_conn *conn, * Return: 1 if sequence or window were updated, 0 otherwise */ int tcp_update_seqack_wnd(const struct ctx *c, struct tcp_tap_conn *conn, - bool force_seq, struct tcp_info *tinfo) + bool force_seq, struct tcp_info_linux *tinfo) { uint32_t prev_wnd_to_tap = conn->wnd_to_tap << conn->ws_to_tap; uint32_t prev_ack_to_tap = conn->seq_ack_to_tap; /* cppcheck-suppress [ctunullpointer, unmatchedSuppression] */ socklen_t sl = sizeof(*tinfo); - struct tcp_info tinfo_new; + struct tcp_info_linux tinfo_new; uint32_t new_wnd_to_tap = prev_wnd_to_tap; int s = conn->sock; @@ -1235,7 +1227,7 @@ int tcp_prepare_flags(const struct ctx *c, struct tcp_tap_conn *conn, int flags, struct tcphdr *th, struct tcp_syn_opts *opts, size_t *optlen) { - struct tcp_info tinfo = { 0 }; + struct tcp_info_linux tinfo = { 0 }; socklen_t sl = sizeof(tinfo); int s = conn->sock; @@ -2578,7 +2570,6 @@ static bool tcp_probe_peek_offset_cap(sa_family_t af) return ret; } -#ifdef HAS_SND_WND /** * tcp_probe_snd_wnd_cap() - Check if TCP_INFO reports tcpi_snd_wnd * @@ -2586,7 +2577,7 @@ static bool tcp_probe_peek_offset_cap(sa_family_t af) */ static bool tcp_probe_snd_wnd_cap(void) { - struct tcp_info tinfo; + struct tcp_info_linux tinfo; socklen_t sl = sizeof(tinfo); int s; @@ -2604,13 +2595,12 @@ static bool tcp_probe_snd_wnd_cap(void) close(s); - if (sl < (offsetof(struct tcp_info, tcpi_snd_wnd) + + if (sl < (offsetof(struct tcp_info_linux, tcpi_snd_wnd) + sizeof(tinfo.tcpi_snd_wnd))) return false; return true; } -#endif /* HAS_SND_WND */ /** * tcp_init() - Get initial sequence, hash secret, initialise per-socket data @@ -2645,9 +2635,7 @@ int tcp_init(struct ctx *c) (!c->ifi6 || tcp_probe_peek_offset_cap(AF_INET6)); debug("SO_PEEK_OFF%ssupported", peek_offset_cap ? " " : " not "); -#ifdef HAS_SND_WND snd_wnd_cap = tcp_probe_snd_wnd_cap(); -#endif debug("TCP_INFO tcpi_snd_wnd field%ssupported", snd_wnd_cap ? " " : " not "); |