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=R/XiykpR; 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 82D385A0269 for ; Mon, 13 Apr 2026 02:53:35 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1776041614; 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=6bdu34OjfONBqjzxUYpmZGCD05bQ3hb/MlwhK5I8DOw=; b=R/XiykpRbFvKywcn6IA4Xm+I6crSkCyXWLtj5CpydDcQaBszhP68f/z0q/rjsmIP7FAn7S Hf+KM2H9UtLGY4NcsbjNKhXraK065U/fMYXxPIAZPwpcvIoz/w1XjkKMbygJuwSMZrDQY9 KaAnhvY75mXCK8uBUeoW/4QUX7/FVPo= Received: from mx-prod-mc-06.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-470-Jljz1ZvzM-65aAWDAebElg-1; Sun, 12 Apr 2026 20:53:32 -0400 X-MC-Unique: Jljz1ZvzM-65aAWDAebElg-1 X-Mimecast-MFC-AGG-ID: Jljz1ZvzM-65aAWDAebElg_1776041612 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (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-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id DA953180049F; Mon, 13 Apr 2026 00:53:31 +0000 (UTC) Received: from jmaloy-thinkpadp16vgen1.rmtcaqc.csb (unknown [10.22.64.70]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 2881D30001A1; Mon, 13 Apr 2026 00:53:31 +0000 (UTC) From: Jon Maloy To: sbrivio@redhat.com, david@gibson.dropbear.id.au, jmaloy@redhat.com, passt-dev@passt.top Subject: [PATCH v7 09/13] conf, pasta: Track observed guest IPv6 addresses in unified address array Date: Sun, 12 Apr 2026 20:53:15 -0400 Message-ID: <20260413005319.3295910-10-jmaloy@redhat.com> In-Reply-To: <20260413005319.3295910-1-jmaloy@redhat.com> References: <20260413005319.3295910-1-jmaloy@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: tLbZuNUKiC42NTp0pLJSD3pBZvuR_XzF7WknwMHlPpI_1776041612 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit content-type: text/plain; charset="US-ASCII"; x-default=true Message-ID-Hash: PJFMQCRRFTEZXOEFYRDCPBHUOHCB22CC X-Message-ID-Hash: PJFMQCRRFTEZXOEFYRDCPBHUOHCB22CC 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 Stefano's concern about DHCPv6 reply addresses. - Some other updates based on feedback from David and Stefano. --- conf.c | 4 ---- dhcpv6.c | 4 +--- fwd.c | 38 +++++++++++++++++++++++--------------- inany.h | 3 +++ migrate.c | 37 +++++++++++++++++++++++++++---------- passt.h | 4 ---- pasta.c | 11 +++++++---- tap.c | 17 +++++------------ 8 files changed, 66 insertions(+), 52 deletions(-) diff --git a/conf.c b/conf.c index f503d0f..3cb3553 100644 --- a/conf.c +++ b/conf.c @@ -827,7 +827,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) { @@ -836,9 +835,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 0a064a9..447aaba 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; @@ -683,8 +683,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 8c7bf91..b177be9 100644 --- a/fwd.c +++ b/fwd.c @@ -1095,14 +1095,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; } @@ -1305,10 +1297,20 @@ 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 { + const struct guest_addr *a; + + 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; } @@ -1346,10 +1348,16 @@ uint8_t fwd_nat_from_host(const struct ctx *c, tgt->eaddr = a->addr; } else { - if (inany_is_linklocal6(&tgt->oaddr)) - tgt->eaddr.a6 = c->ip6.addr_ll_seen; - else - tgt->eaddr.a6 = c->ip6.addr_seen; + bool ll = inany_is_linklocal6(&tgt->oaddr); + uint8_t excl = ll ? ~CONF_ADDR_LINKLOCAL : CONF_ADDR_LINKLOCAL; + const struct guest_addr *a; + + a = fwd_select_addr(c, AF_INET6, CONF_ADDR_OBSERVED, + CONF_ADDR_USER | CONF_ADDR_HOST, excl); + if (!a) + return PIF_NONE; + + tgt->eaddr = a->addr; } return PIF_TAP; diff --git a/inany.h b/inany.h index 0450c45..ddcf93d 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 1e02720..2dc4dd9 100644 --- a/migrate.c +++ b/migrate.c @@ -56,21 +56,30 @@ 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; - /* IPv4 observed address, with fallback to configured address */ + /* IPv4 observed address, with fallback to any other non-LL address */ a = fwd_select_addr(c, AF_INET, CONF_ADDR_OBSERVED, CONF_ADDR_USER | CONF_ADDR_HOST, CONF_ADDR_LINKLOCAL); 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,19 +100,27 @@ 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; (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; - - if (addrs.addr4.s_addr) + if (addrs.addr4.s_addr) { fwd_set_addr(c, &inany_from_v4(addrs.addr4), CONF_ADDR_OBSERVED, 0); - + } + 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); + } memcpy(c->guest_mac, addrs.mac, sizeof(c->guest_mac)); return 0; diff --git a/passt.h b/passt.h index 5da1d55..3ef84eb 100644 --- a/passt.h +++ b/passt.h @@ -121,8 +121,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] @@ -138,8 +136,6 @@ struct ip4_ctx { * @no_copy_addrs: Don't copy all addresses when configuring namespace */ struct ip6_ctx { - 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 f949dc2..f7f1e07 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 7f04e12..7f7f0ce 100644 --- a/tap.c +++ b/tap.c @@ -933,20 +933,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 (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.addr_seen)) { - c->ip6.addr_seen = *saddr; - } - - if (!fwd_get_addr(c, AF_INET6, 0, 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 (!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