Currently the only address we explicitly track in the TCP connection
structure is the tap side forwarding address - that is the remote address
from the guest's point of view. The tap side correspondent address - the
local address from the guest's point of view - is assumed to always be one
of the handful of guest addresses we track as addr_seen (one each for IPv4,
IPv6 global and IPv6 link-local).
We want to generalize our forwarding model to allow the guest to have
multiple addresses. As a start on this, track the tap-side correspondent
address in the connection structure, only using one of the addr_seen
variables when we start a new connection.
Signed-off-by: David Gibson
---
tcp.c | 37 +++++++++++++++++--------------------
tcp_conn.h | 2 ++
2 files changed, 19 insertions(+), 20 deletions(-)
diff --git a/tcp.c b/tcp.c
index ac7ae60..6c4d71e 100644
--- a/tcp.c
+++ b/tcp.c
@@ -1449,7 +1449,7 @@ do { \
ip_len = plen + sizeof(struct iphdr) + sizeof(struct tcphdr);
b->iph.tot_len = htons(ip_len);
b->iph.saddr = a4->s_addr;
- b->iph.daddr = c->ip4.addr_seen.s_addr;
+ b->iph.daddr = inany_v4(&conn->caddr)->s_addr;
if (check)
b->iph.check = *check;
@@ -1468,10 +1468,7 @@ do { \
b->ip6h.payload_len = htons(plen + sizeof(struct tcphdr));
b->ip6h.saddr = conn->faddr.a6;
- if (IN6_IS_ADDR_LINKLOCAL(&b->ip6h.saddr))
- b->ip6h.daddr = c->ip6.addr_ll_seen;
- else
- b->ip6h.daddr = c->ip6.addr_seen;
+ b->ip6h.daddr = conn->caddr.a6;
memset(b->ip6h.flow_lbl, 0, 3);
@@ -1820,13 +1817,12 @@ static void tcp_clamp_window(const struct ctx *c, struct tcp_tap_conn *conn,
/**
* tcp_seq_init() - Calculate initial sequence number according to RFC 6528
* @c: Execution context
- * @conn: TCP connection, with faddr, fport and cport populated
+ * @conn: TCP connection, with faddr, fport, caddr, cport populated
* @now: Current timestamp
*/
static void tcp_seq_init(const struct ctx *c, struct tcp_tap_conn *conn,
const struct timespec *now)
{
- union inany_addr aany;
struct {
union inany_addr src;
in_port_t srcport;
@@ -1835,16 +1831,11 @@ static void tcp_seq_init(const struct ctx *c, struct tcp_tap_conn *conn,
} __attribute__((__packed__)) in = {
.src = conn->faddr,
.srcport = conn->cport,
+ .dst = conn->caddr,
.dstport = conn->fport,
};
uint32_t ns, seq = 0;
- if (CONN_V4(conn))
- inany_from_af(&aany, AF_INET, &c->ip4.addr);
- else
- inany_from_af(&aany, AF_INET6, &c->ip6.addr);
- in.dst = aany;
-
seq = siphash_36b((uint8_t *)&in, c->tcp.hash_secret);
/* 32ns ticks, overflows 32 bits every 137s */
@@ -2011,8 +2002,6 @@ static void tcp_conn_from_tap(struct ctx *c,
socklen_t sl;
int s, mss;
- (void)saddr;
-
if (c->tcp.conn_count >= TCP_MAX_CONNS)
return;
@@ -2061,6 +2050,9 @@ static void tcp_conn_from_tap(struct ctx *c,
conn->wnd_from_tap = 1;
inany_from_af(&conn->faddr, af, daddr);
+ inany_from_af(&conn->caddr, af, saddr);
+ conn->fport = ntohs(th->dest);
+ conn->cport = ntohs(th->source);
if (af == AF_INET) {
sa = (struct sockaddr *)&addr4;
@@ -2070,9 +2062,6 @@ static void tcp_conn_from_tap(struct ctx *c,
sl = sizeof(addr6);
}
- conn->fport = ntohs(th->dest);
- conn->cport = ntohs(th->source);
-
conn->seq_init_from_tap = ntohl(th->seq);
conn->seq_from_tap = conn->seq_init_from_tap + 1;
conn->seq_ack_to_tap = conn->seq_from_tap;
@@ -2731,10 +2720,18 @@ static void tcp_tap_conn_from_sock(struct ctx *c, union epoll_ref ref,
conn_event(c, conn, SOCK_ACCEPTED);
inany_from_sockaddr(&conn->faddr, &conn->fport, sa);
- conn->cport = ref.r.p.tcp.tcp.index;
-
tcp_snat_inbound(c, &conn->faddr);
+ if (CONN_V4(conn)) {
+ inany_from_af(&conn->caddr, AF_INET, &c->ip4.addr_seen);
+ } else {
+ if (IN6_IS_ADDR_LINKLOCAL(&conn->faddr.a6))
+ conn->caddr.a6 = c->ip6.addr_ll_seen;
+ else
+ conn->caddr.a6 = c->ip6.addr_seen;
+ }
+ conn->cport = ref.r.p.tcp.tcp.index;
+
tcp_seq_init(c, conn, now);
tcp_hash_insert(c, conn);
diff --git a/tcp_conn.h b/tcp_conn.h
index ba2a1ef..9151c18 100644
--- a/tcp_conn.h
+++ b/tcp_conn.h
@@ -35,6 +35,7 @@ extern const char *tcp_common_flag_str[];
* @ws_to_tap: Window scaling factor advertised to tap/guest
* @sndbuf: Sending buffer in kernel, rounded to 2 ^ SNDBUF_BITS
* @seq_dup_ack_approx: Last duplicate ACK number sent to tap
+ * @caddr: Guest side correspondent address (guest's local address)
* @faddr: Guest side forwarding address (guest's remote address)
* @cport: Guest side correspondent port (guest's local port)
* @fport: Guest side forwarding port (guest's remote port)
@@ -105,6 +106,7 @@ struct tcp_tap_conn {
uint8_t seq_dup_ack_approx;
+ union inany_addr caddr;
union inany_addr faddr;
in_port_t cport;
in_port_t fport;
--
2.41.0