From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: passt.top; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=PBwFdGiO; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by passt.top (Postfix) with ESMTPS id AC2C35A061B for ; Fri, 26 Jun 2026 04:45:36 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1782441935; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=23oTNgi2EGQCky+YP4mIflaEBoZ3pot23kauwJfzRYU=; b=PBwFdGiOjtNufPSQxca9zG8Ewxo+qD5j5+80x68fGyL7JfUwpiui2nbbztnGJcCAc39cb+ ohniLM1sRRpT1GssXGLpoeSQXXs7BmfgGTaAjR701dYx+7TGn0ANUuUFahn5NTog7nS/Jv Brke38Nx3Dte3DYReXwYGdbN383GiyM= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-202--wB1sGSiPIqyTESEsYN_0Q-1; Thu, 25 Jun 2026 22:45:34 -0400 X-MC-Unique: -wB1sGSiPIqyTESEsYN_0Q-1 X-Mimecast-MFC-AGG-ID: -wB1sGSiPIqyTESEsYN_0Q_1782441933 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 3390D1805C2D; Fri, 26 Jun 2026 02:45:33 +0000 (UTC) Received: from jmaloy-thinkpadp16vgen1.rmtcaqc.csb (unknown [10.22.88.44]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 79C221956087; Fri, 26 Jun 2026 02:45:32 +0000 (UTC) From: Jon Maloy To: sbrivio@redhat.com, david@gibson.dropbear.id.au, jmaloy@redhat.com, passt-dev@passt.top Subject: [PATCH v8 10/14] conf, pasta: Track observed guest IPv6 addresses in unified address array Date: Thu, 25 Jun 2026 22:45:15 -0400 Message-ID: <20260626024519.3701556-11-jmaloy@redhat.com> In-Reply-To: <20260626024519.3701556-1-jmaloy@redhat.com> References: <20260626024519.3701556-1-jmaloy@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: gvGHpjIj0XuKL7M6cOUgtwmtj7B4XGFMIdkOpCVgQLM_1782441933 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit content-type: text/plain; charset="US-ASCII"; x-default=true Message-ID-Hash: ATKHVFGD3QUSIPHSYVMWEZGWP6O2AEJM X-Message-ID-Hash: ATKHVFGD3QUSIPHSYVMWEZGWP6O2AEJM X-MailFrom: jmaloy@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: We remove the addr_seen and addr_ll_seen fields in struct ip6_ctx and replace them by setting CONF_ADDR_OBSERVED and CONF_ADDR_LINKLOCAL flags in the corresponding entry in the unified address array. The observed IPv6 address is always added/moved to position 0 in the array, improving chances for fast lookup. The separate check against addr_seen in fwd_guest_accessible() can now be removed because the observed address is now in the unified array, and the existing for_each_addr() loop already checks against all addresses, including this one. This completes the unification of address storage for both IPv4 and IPv6, enabling future support for multiple guest addresses per family. Signed-off-by: Jon Maloy --- v5: - Made to use same algorithm and function as IPv4 for inserting observed into the array. v6: - Re-introduced code that by accident had been moved to the previous commit. - Some fixes based on feedback from David G. v7: - Added a commit at the beginning of the series addressing Stefanos's concern about DHCPv6 reply addresses. - Some other updates based on feedback from David and Stefano. v8: - Adapted to previous changes in this series. - A couple of minor fixes in migrate.c (David) - Refactored parts of fwd_nat_from_host() to get v6 LINK_LOCAL selection criteria right. (David) --- conf.c | 4 ---- dhcpv6.c | 4 +--- fwd.c | 58 +++++++++++++++++++++++++++++++++---------------------- inany.h | 3 +++ migrate.c | 37 +++++++++++++++++++++++++++-------- passt.h | 4 ---- pasta.c | 11 +++++++---- tap.c | 19 +++++------------- 8 files changed, 80 insertions(+), 60 deletions(-) diff --git a/conf.c b/conf.c index 32734188..69c1c439 100644 --- a/conf.c +++ b/conf.c @@ -473,7 +473,6 @@ static unsigned int conf_ip6(struct ctx *c, unsigned int ifi) strerror_(-rc)); return 0; } - a = fwd_get_addr(c, AF_INET6, CONF_ADDR_HOST, 0); } else { rc = nl_addr_get_ll(nl_sock, ifi, &ip6->our_tap_ll); if (rc < 0) { @@ -482,9 +481,6 @@ static unsigned int conf_ip6(struct ctx *c, unsigned int ifi) } } - if (a) - ip6->addr_seen = a->addr.a6; - if (IN6_IS_ADDR_LINKLOCAL(&ip6->guest_gw)) ip6->our_tap_ll = ip6->guest_gw; diff --git a/dhcpv6.c b/dhcpv6.c index f64cbc24..f5de90cd 100644 --- a/dhcpv6.c +++ b/dhcpv6.c @@ -567,8 +567,8 @@ int dhcpv6(struct ctx *c, struct iov_tail *data, struct opt_hdr client_id_storage; /* cppcheck-suppress [variableScope,unmatchedSuppression] */ struct opt_ia_na ia_storage; - const struct guest_addr *a; const struct in6_addr *src; + const struct guest_addr *a; struct msg_hdr mh_storage; const struct msg_hdr *mh; struct udphdr uh_storage; @@ -685,8 +685,6 @@ int dhcpv6(struct ctx *c, struct iov_tail *data, resp.hdr.xid = mh->xid; tap_udp6_send(c, src, 547, saddr, 546, mh->xid, &resp, n); - if (a) - c->ip6.addr_seen = a->addr.a6; return 1; } diff --git a/fwd.c b/fwd.c index 10ed6034..e4090f4d 100644 --- a/fwd.c +++ b/fwd.c @@ -949,14 +949,6 @@ static bool fwd_guest_accessible(const struct ctx *c, return false; } - /* For IPv6, addr_seen starts unspecified, because we don't know what LL - * address the guest will take until we see it. Only check against it - * if it has been set to a real address. - */ - if (!IN6_IS_ADDR_UNSPECIFIED(&c->ip6.addr_seen) && - inany_equals6(addr, &c->ip6.addr_seen)) - return false; - return true; } @@ -1128,6 +1120,8 @@ uint8_t fwd_nat_from_host(const struct ctx *c, const struct fwd_rule *rule, uint8_t proto, const struct flowside *ini, struct flowside *tgt) { + const struct guest_addr *a = NULL; + /* Common for spliced and non-spliced cases */ tgt->eport = rule->to + (ini->oport - rule->first); @@ -1148,8 +1142,6 @@ uint8_t fwd_nat_from_host(const struct ctx *c, if (c->host_lo_to_ns_lo) { tgt->eaddr = inany_loopback4; } else { - const struct guest_addr *a; - a = fwd_select_addr(c, AF_INET, CONF_ADDR_OBSERVED, CONF_ADDR_USER | @@ -1161,10 +1153,18 @@ uint8_t fwd_nat_from_host(const struct ctx *c, } tgt->oaddr = inany_any4; } else { - if (c->host_lo_to_ns_lo) + if (c->host_lo_to_ns_lo) { tgt->eaddr = inany_loopback6; - else - tgt->eaddr.a6 = c->ip6.addr_seen; + } else { + a = fwd_select_addr(c, AF_INET6, + CONF_ADDR_OBSERVED, + CONF_ADDR_USER | + CONF_ADDR_HOST, + CONF_ADDR_LINKLOCAL); + if (!a) + return PIF_NONE; + tgt->eaddr = a->addr; + } tgt->oaddr = inany_any6; } @@ -1193,20 +1193,32 @@ uint8_t fwd_nat_from_host(const struct ctx *c, tgt->oport = ini->eport; if (inany_v4(&tgt->oaddr)) { - const struct guest_addr *a; - a = fwd_select_addr(c, AF_INET, CONF_ADDR_OBSERVED, CONF_ADDR_USER | CONF_ADDR_HOST, 0); - if (!a) - return PIF_NONE; - - tgt->eaddr = a->addr; + } else if (!inany_is_linklocal6(&tgt->oaddr)) { + a = fwd_select_addr(c, AF_INET6, CONF_ADDR_OBSERVED, + CONF_ADDR_USER | CONF_ADDR_HOST, + CONF_ADDR_LINKLOCAL); } else { - if (inany_is_linklocal6(&tgt->oaddr)) - tgt->eaddr.a6 = c->ip6.addr_ll_seen; - else - tgt->eaddr.a6 = c->ip6.addr_seen; + const struct guest_addr *tmp; + + /* Preferably, we want an entry with both flags set */ + for_each_addr(tmp, c->addrs, c->addr_count, AF_INET6) { + if (!(tmp->flags & CONF_ADDR_OBSERVED)) + continue; + if (!(tmp->flags & CONF_ADDR_LINKLOCAL)) + continue; + a = tmp; + break; + } + /* If not, LINK_LOCAL only will do */ + if (!a) + a = fwd_get_addr(c, AF_INET6, CONF_ADDR_LINKLOCAL, 0); } + if (!a) + return PIF_NONE; + + tgt->eaddr = a->addr; return PIF_TAP; } diff --git a/inany.h b/inany.h index 95756eb8..14390c29 100644 --- a/inany.h +++ b/inany.h @@ -60,6 +60,9 @@ extern const union inany_addr inany_any4; #define inany_from_v4(a4) \ ((union inany_addr)INANY_INIT4((a4))) +#define inany_from_v6(v6) \ + ((union inany_addr){ .a6 = (v6) }) + /** union sockaddr_inany - Either a sockaddr_in or a sockaddr_in6 * @sa_family: Address family, AF_INET or AF_INET6 * @sa: Plain struct sockaddr (useful to avoid casts) diff --git a/migrate.c b/migrate.c index 795f2818..3ca97bf6 100644 --- a/migrate.c +++ b/migrate.c @@ -57,10 +57,7 @@ struct migrate_seen_addrs_v2 { static int seen_addrs_source_v2(struct ctx *c, const struct migrate_stage *stage, int fd) { - struct migrate_seen_addrs_v2 addrs = { - .addr6 = c->ip6.addr_seen, - .addr6_ll = c->ip6.addr_ll_seen, - }; + struct migrate_seen_addrs_v2 addrs = { 0 }; const struct guest_addr *a; (void)stage; @@ -71,6 +68,18 @@ static int seen_addrs_source_v2(struct ctx *c, if (a) addrs.addr4 = *inany_v4(&a->addr); + /* IPv6 observed address, with fallback to any other non-LL address */ + a = fwd_select_addr(c, AF_INET6, CONF_ADDR_OBSERVED, + CONF_ADDR_USER | CONF_ADDR_HOST, + CONF_ADDR_LINKLOCAL); + if (a) + addrs.addr6 = a->addr.a6; + + /* IPv6 link-local address */ + a = fwd_get_addr(c, AF_INET6, CONF_ADDR_LINKLOCAL, 0); + if (a) + addrs.addr6_ll = a->addr.a6; + memcpy(addrs.mac, c->guest_mac, sizeof(addrs.mac)); if (write_all_buf(fd, &addrs, sizeof(addrs))) @@ -91,17 +100,29 @@ static int seen_addrs_target_v2(struct ctx *c, const struct migrate_stage *stage, int fd) { struct migrate_seen_addrs_v2 addrs; + struct in6_addr addr6, addr6_ll; + struct in_addr addr4; (void)stage; if (read_all_buf(fd, &addrs, sizeof(addrs))) return errno; - c->ip6.addr_seen = addrs.addr6; - c->ip6.addr_ll_seen = addrs.addr6_ll; + addr6 = addrs.addr6; + if (!IN6_IS_ADDR_UNSPECIFIED(&addr6)) { + fwd_set_addr(c, &inany_from_v6(addr6), + CONF_ADDR_OBSERVED, 0); + } + + addr6_ll = addrs.addr6_ll; + if (!IN6_IS_ADDR_UNSPECIFIED(&addr6_ll)) { + fwd_set_addr(c, &inany_from_v6(addr6_ll), + CONF_ADDR_OBSERVED | CONF_ADDR_LINKLOCAL, 0); + } - if (!IN4_IS_ADDR_UNSPECIFIED(&addrs.addr4)) { - fwd_set_addr(c, &inany_from_v4(addrs.addr4), + addr4 = addrs.addr4; + if (!IN4_IS_ADDR_UNSPECIFIED(&addr4)) { + fwd_set_addr(c, &inany_from_v4(addr4), CONF_ADDR_OBSERVED, 0); } memcpy(c->guest_mac, addrs.mac, sizeof(c->guest_mac)); diff --git a/passt.h b/passt.h index 20ad7022..005f7631 100644 --- a/passt.h +++ b/passt.h @@ -123,8 +123,6 @@ struct ip4_ctx { /** * struct ip6_ctx - IPv6 execution context - * @addr_seen: Latest IPv6 global/site address seen as source from tap - * @addr_ll_seen: Latest IPv6 link-local address seen as source from tap * @guest_gw: IPv6 gateway as seen by the guest * @map_host_loopback: Outbound connections to this address are NATted to the * host's [::1] @@ -141,8 +139,6 @@ struct ip4_ctx { */ struct ip6_ctx { /* PIF_TAP addresses */ - struct in6_addr addr_seen; - struct in6_addr addr_ll_seen; struct in6_addr guest_gw; struct in6_addr map_host_loopback; struct in6_addr map_guest_addr; diff --git a/pasta.c b/pasta.c index 56df2fdc..575b9315 100644 --- a/pasta.c +++ b/pasta.c @@ -366,6 +366,7 @@ static int pasta_conf_routes(struct ctx *c, sa_family_t af, int ifi, void pasta_ns_conf(struct ctx *c) { unsigned int flags = IFF_UP; + struct in6_addr addr_ll; int rc; rc = nl_link_set_flags(nl_sock_ns, 1 /* lo */, IFF_UP, IFF_UP); @@ -415,12 +416,14 @@ void pasta_ns_conf(struct ctx *c) if (!c->ifi6) return; - rc = nl_addr_get_ll(nl_sock_ns, c->pasta_ifi, - &c->ip6.addr_ll_seen); - if (rc < 0) + rc = nl_addr_get_ll(nl_sock_ns, c->pasta_ifi, &addr_ll); + if (rc < 0) { warn("Can't get LL address from namespace: %s", strerror_(-rc)); - + } else { + fwd_set_addr(c, &inany_from_v6(addr_ll), + CONF_ADDR_LINKLOCAL | CONF_ADDR_OBSERVED, 0); + } rc = nl_addr_set_ll_nodad(nl_sock_ns, c->pasta_ifi); if (rc < 0) warn("Can't set nodad for LL in namespace: %s", diff --git a/tap.c b/tap.c index 93db2f86..e7d37082 100644 --- a/tap.c +++ b/tap.c @@ -1000,22 +1000,13 @@ resume: continue; } - if (IN6_IS_ADDR_LINKLOCAL(saddr)) { - c->ip6.addr_ll_seen = *saddr; + if (!IN6_IS_ADDR_UNSPECIFIED(saddr)) { + uint8_t flags = CONF_ADDR_OBSERVED; - if (!fwd_get_addr(c, AF_INET6, CONF_ADDR_USER, 0) && - IN6_IS_ADDR_UNSPECIFIED(&c->ip6.addr_seen)) { - c->ip6.addr_seen = *saddr; - } - - if (!fwd_get_addr(c, AF_INET6, CONF_ADDR_USER, 0)) { - union inany_addr addr = { .a6 = *saddr }; + if (IN6_IS_ADDR_LINKLOCAL(saddr)) + flags |= CONF_ADDR_LINKLOCAL; - fwd_set_addr(c, &addr, CONF_ADDR_LINKLOCAL, 64); - } - } else if (!fwd_get_addr(c, AF_INET6, CONF_ADDR_USER, 0) && - !IN6_IS_ADDR_UNSPECIFIED(saddr)) { - c->ip6.addr_seen = *saddr; + fwd_set_addr(c, &inany_from_v6(*saddr), flags, 0); } if (proto == IPPROTO_ICMPV6) { -- 2.52.0