public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: Jon Maloy <jmaloy@redhat.com>
To: sbrivio@redhat.com, dgibson@redhat.com,
	david@gibson.dropbear.id.au, jmaloy@redhat.com,
	passt-dev@passt.top
Subject: [PATCH v4 10/12] fwd: Unify fwd_set_observed_ip4() and fwd_set_observed_ip6()
Date: Tue, 17 Feb 2026 17:18:12 -0500	[thread overview]
Message-ID: <20260217221814.4053583-11-jmaloy@redhat.com> (raw)
In-Reply-To: <20260217221814.4053583-1-jmaloy@redhat.com>

Create a common fwd_set_observed() function that handles both IPv4 and
IPv6 observed addresses. The function determines the address family from
the input and uses the appropriate reserved position (0 for IPv4, 1 for
IPv6) for O(1) lookup.

Call sites are updated to use fwd_set_observed() directly with
union inany_addr.

This reduces code duplication and ensures consistent behavior between
IPv4 and IPv6 address tracking.

Signed-off-by: Jon Maloy <jmaloy@redhat.com>
---
 fwd.c     | 129 ++++++++++++++++++------------------------------------
 fwd.h     |   3 +-
 inany.h   |   3 ++
 migrate.c |   6 +--
 pasta.c   |   2 +-
 tap.c     |   4 +-
 6 files changed, 53 insertions(+), 94 deletions(-)

diff --git a/fwd.c b/fwd.c
index 8598fff..d5f4932 100644
--- a/fwd.c
+++ b/fwd.c
@@ -518,119 +518,76 @@ const union inany_addr *fwd_guest_addr(const struct ctx *c, sa_family_t af,
 }
 
 /**
- * fwd_set_observed_ip4() - Set observed IPv4 guest address
+ * fwd_set_observed() - Set observed guest address (IPv4 or IPv6)
  * @c:		Execution context
- * @addr:	IPv4 address observed in guest traffic
+ * @addr:	Address observed in guest traffic
  *
- * Mark @addr as the observed guest address. The observed address is always
- * kept at position 0 for O(1) lookup. Only one address can have the OBSERVED
- * flag at a time.
+ * Mark @addr as the observed guest address. Observed addresses are kept at
+ * reserved positions for O(1) lookup: position 0 for IPv4, position 1 for
+ * IPv6. Only one address per family can have the OBSERVED flag at a time.
+ * Link-local IPv6 addresses also get the LINKLOCAL flag.
  */
-void fwd_set_observed_ip4(struct ctx *c, const struct in_addr *addr)
+void fwd_set_observed(struct ctx *c, const union inany_addr *addr)
 {
-	struct inany_addr_entry *e = &c->addrs[0];
-	int i;
-
-	if (!addr->s_addr)
-		return;
-
-	/* Fast path: check if already observed at position 0 */
-	if (c->addr_count > 0 && (e->flags & CONF_ADDR_OBSERVED) &&
-	    inany_equals4(&e->addr, addr))
-		return;
-
-	/* Slow path: new observed address - insert at position 0 */
-	if (c->addr_count >= INANY_MAX_ADDRS) {
-		debug("Address table full, can't add observed IPv4");
-		return;
-	}
-
-	/* Make room and insert at position 0 */
-	memmove(&c->addrs[1], e, c->addr_count * sizeof(*e));
-	c->addr_count++;
-	inany_from_af(&e->addr, AF_INET, addr);
-	e->prefix_len = 0;
-	e->flags = CONF_ADDR_OBSERVED;
-
-	/* Handle old observed IPv4 address, if any */
-	for (i = 1; i < c->addr_count; i++) {
-		e = &c->addrs[i];
-
-		if (!inany_v4(&e->addr) || !(e->flags & CONF_ADDR_OBSERVED))
-			continue;
-
-		e->flags &= ~CONF_ADDR_OBSERVED;
-
-		/* Remove if no other flags, or if addr is duplicate */
-		if (!e->flags || inany_equals4(&e->addr, addr)) {
-			memmove(&c->addrs[i], &c->addrs[i + 1],
-				(c->addr_count - i - 1) * sizeof(*e));
-			c->addr_count--;
-		}
-		break;
-	}
-}
-
-/**
- * fwd_set_observed_ip6() - Set observed IPv6 guest address
- * @c:		Execution context
- * @addr:	IPv6 address observed in guest traffic
- *
- * Mark @addr as the observed guest address. The observed address is always
- * kept at position 1 for O(1) lookup. Only one IPv6 address can have the
- * OBSERVED flag at a time. Link-local addresses also get LINKLOCAL flag.
- */
-void fwd_set_observed_ip6(struct ctx *c, const struct in6_addr *addr)
-{
-	struct inany_addr_entry *e;
 	uint8_t flags = CONF_ADDR_OBSERVED;
+	bool is_v4 = !!inany_v4(addr);
+	struct inany_addr_entry *e;
+	int pos = is_v4 ? 0 : 1;
 	int i;
 
-	if (IN6_IS_ADDR_UNSPECIFIED(addr))
-		return;
-
-	if (IN6_IS_ADDR_LINKLOCAL(addr))
-		flags |= CONF_ADDR_LINKLOCAL;
+	/* Check for unspecified address */
+	if (is_v4) {
+		if (inany_is_unspecified4(addr))
+			return;
+	} else {
+		if (IN6_IS_ADDR_UNSPECIFIED(&addr->a6))
+			return;
+		if (IN6_IS_ADDR_LINKLOCAL(&addr->a6))
+			flags |= CONF_ADDR_LINKLOCAL;
+	}
 
-	/* Fast path: check if already observed at position 1 */
-	if (c->addr_count > 1) {
-		e = &c->addrs[1];
-		if ((e->flags & CONF_ADDR_OBSERVED) && !inany_v4(&e->addr) &&
-		    IN6_ARE_ADDR_EQUAL(&e->addr.a6, addr))
+	/* Fast path: check if already observed at reserved position */
+	if (c->addr_count > pos) {
+		e = &c->addrs[pos];
+		if ((e->flags & CONF_ADDR_OBSERVED) &&
+		    (is_v4 == !!inany_v4(&e->addr)) &&
+		    inany_equals(&e->addr, addr))
 			return;
 	}
 
-	/* Slow path: new observed address - insert at position 1 */
+	/* Slow path: new observed address */
 	if (c->addr_count >= INANY_MAX_ADDRS) {
-		debug("Address table full, can't add observed IPv6");
+		debug("Address table full, can't add observed %s",
+		      is_v4 ? "IPv4" : "IPv6");
 		return;
 	}
 
-	/* Make room at position 1 */
-	if (c->addr_count > 1) {
-		e = &c->addrs[1];
-		memmove(&c->addrs[2], e, (c->addr_count - 1) * sizeof(*e));
+	/* Make room at reserved position */
+	if (c->addr_count > pos) {
+		e = &c->addrs[pos];
+		memmove(&c->addrs[pos + 1], e,
+			(c->addr_count - pos) * sizeof(*e));
 	}
 	c->addr_count++;
 
-	/* Insert new observed address at position 1 */
-	e = &c->addrs[1];
-	e->addr.a6 = *addr;
-	e->prefix_len = 64;
+	/* Insert new observed address */
+	e = &c->addrs[pos];
+	e->addr = *addr;
+	e->prefix_len = is_v4 ? 0 : 64;
 	e->flags = flags;
 
-	/* Clean up: find and handle old observed IPv6 address */
-	for (i = 2; i < c->addr_count; i++) {
+	/* Clean up: find and handle old observed address of same family */
+	for (i = pos + 1; i < c->addr_count; i++) {
 		e = &c->addrs[i];
 
-		if (inany_v4(&e->addr) || !(e->flags & CONF_ADDR_OBSERVED))
+		if ((is_v4 != !!inany_v4(&e->addr)) ||
+		    !(e->flags & CONF_ADDR_OBSERVED))
 			continue;
 
-		/* Found old observed - clear flag */
 		e->flags &= ~CONF_ADDR_OBSERVED;
 
 		/* Remove if no other flags, or if addr is duplicate */
-		if (!e->flags || IN6_ARE_ADDR_EQUAL(&e->addr.a6, addr)) {
+		if (!e->flags || inany_equals(&e->addr, addr)) {
 			memmove(&c->addrs[i], &c->addrs[i + 1],
 				(c->addr_count - i - 1) * sizeof(*e));
 			c->addr_count--;
diff --git a/fwd.h b/fwd.h
index 4de3890..7bdf462 100644
--- a/fwd.h
+++ b/fwd.h
@@ -17,8 +17,7 @@ void fwd_probe_ephemeral(void);
 bool fwd_port_is_ephemeral(in_port_t port);
 const union inany_addr *fwd_guest_addr(const struct ctx *c, sa_family_t af,
 				       uint8_t incl, uint8_t excl);
-void fwd_set_observed_ip4(struct ctx *c, const struct in_addr *addr);
-void fwd_set_observed_ip6(struct ctx *c, const struct in6_addr *addr);
+void fwd_set_observed(struct ctx *c, const union inany_addr *addr);
 
 enum fwd_ports_mode {
 	FWD_UNSET = 0,
diff --git a/inany.h b/inany.h
index c7d6027..8b7caa5 100644
--- a/inany.h
+++ b/inany.h
@@ -54,6 +54,9 @@ extern const union inany_addr inany_any4;
 #define inany_from_v4(a4)	\
 	((union inany_addr)INANY_INIT4((a4)))
 
+#define inany_from_v6(addr)	\
+	((union inany_addr){ .a6 = (addr) })
+
 /** 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 6577334..2dc5c8a 100644
--- a/migrate.c
+++ b/migrate.c
@@ -111,13 +111,13 @@ static int seen_addrs_target_v1(struct ctx *c,
 	addr6 = addrs.addr6;
 	addr6_ll = addrs.addr6_ll;
 
-	fwd_set_observed_ip4(c, &addr4);
+	fwd_set_observed(c, &inany_from_v4(addr4));
 
 	/* Prefer global over link-local if both present (only one slot) */
 	if (!IN6_IS_ADDR_UNSPECIFIED(&addr6))
-		fwd_set_observed_ip6(c, &addr6);
+		fwd_set_observed(c, &inany_from_v6(addr6));
 	else
-		fwd_set_observed_ip6(c, &addr6_ll);
+		fwd_set_observed(c, &inany_from_v6(addr6_ll));
 
 	memcpy(c->guest_mac, addrs.mac, sizeof(c->guest_mac));
 
diff --git a/pasta.c b/pasta.c
index f16d508..a134af8 100644
--- a/pasta.c
+++ b/pasta.c
@@ -362,7 +362,7 @@ static void pasta_ns_conf_ip6(struct ctx *c)
 		warn("Can't get LL address from namespace: %s",
 		     strerror_(-rc));
 	else
-		fwd_set_observed_ip6(c, &addr_ll);
+		fwd_set_observed(c, &inany_from_v6(addr_ll));
 
 	rc = nl_addr_set_ll_nodad(nl_sock_ns, c->pasta_ifi);
 	if (rc < 0) {
diff --git a/tap.c b/tap.c
index be698eb..643c139 100644
--- a/tap.c
+++ b/tap.c
@@ -170,7 +170,7 @@ void tap_send_single(const struct ctx *c, const void *data, size_t l2len)
  */
 static void tap_check_src_addr4(struct ctx *c, const struct in_addr *addr)
 {
-	fwd_set_observed_ip4(c, addr);
+	fwd_set_observed(c, &inany_from_v4(*addr));
 }
 
 /**
@@ -180,7 +180,7 @@ static void tap_check_src_addr4(struct ctx *c, const struct in_addr *addr)
  */
 static void tap_check_src_addr6(struct ctx *c, const struct in6_addr *addr)
 {
-	fwd_set_observed_ip6(c, addr);
+	fwd_set_observed(c, &inany_from_v6(*addr));
 }
 
 /**
-- 
2.52.0


  parent reply	other threads:[~2026-02-17 22:18 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-17 22:18 [PATCH v4 00/12] Introduce multiple addresses Jon Maloy
2026-02-17 22:18 ` [PATCH v4 01/12] ip: Introduce unified multi-address data structures Jon Maloy
2026-02-17 22:18 ` [PATCH v4 02/12] ip: Introduce for_each_addr() macro for address iteration Jon Maloy
2026-02-17 22:18 ` [PATCH v4 03/12] fwd: Unify guest accessibility checks with unified address array Jon Maloy
2026-02-17 22:18 ` [PATCH v4 04/12] arp: Check all configured addresses in ARP filtering Jon Maloy
2026-02-17 22:18 ` [PATCH v4 05/12] pasta: Extract pasta_ns_conf_ip4/6() to reduce nesting Jon Maloy
2026-02-17 22:18 ` [PATCH v4 06/12] netlink: Return prefix length for IPv6 addresses in nl_addr_get() Jon Maloy
2026-02-17 22:18 ` [PATCH v4 07/12] conf: Allow multiple -a/--address options per address family Jon Maloy
2026-02-17 22:18 ` [PATCH v4 08/12] ip: Track observed guest IPv4 addresses in unified address array Jon Maloy
2026-02-18 14:14   ` Jon Maloy
2026-02-17 22:18 ` [PATCH v4 09/12] ip: Track observed guest IPv6 " Jon Maloy
2026-02-17 22:18 ` Jon Maloy [this message]
2026-02-17 22:18 ` [PATCH v4 11/12] migrate: Rename v1 address functions to v2 for clarity Jon Maloy
2026-02-17 22:18 ` [PATCH v4 12/12] migrate: Update protocol to v3 for multi-address support Jon Maloy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260217221814.4053583-11-jmaloy@redhat.com \
    --to=jmaloy@redhat.com \
    --cc=david@gibson.dropbear.id.au \
    --cc=dgibson@redhat.com \
    --cc=passt-dev@passt.top \
    --cc=sbrivio@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://passt.top/passt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).