From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=none (p=none dis=none) header.from=gibson.dropbear.id.au Authentication-Results: passt.top; dkim=pass (2048-bit key; secure) header.d=gibson.dropbear.id.au header.i=@gibson.dropbear.id.au header.a=rsa-sha256 header.s=202512 header.b=PfdgbTDJ; dkim-atps=neutral Received: from mail.ozlabs.org (gandalf.ozlabs.org [150.107.74.76]) by passt.top (Postfix) with ESMTPS id 4AE015A065B for ; Mon, 15 Dec 2025 11:08:25 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202512; t=1765793302; bh=m1WrQsWZCgpO854CMPVUR5xhpOBQsPWJ3+TLM0TZQlo=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=PfdgbTDJDGcz3HyEsgoi6DMci0MNdbAHg+pyjbVa0gXKx42WA9GdG1UJfn6gXBqoR kIe05dTi1qwch/Ak/swmB4vRuNQ1lnYGiQwrJU+1UvJlUk6U5Cs4ow26C0X+yU3avZ 3beSEElxPr9uxgfWQpv2aJjG5foR5l/5SvyaoNPPFx9iQeO5QS5yEijtcPZRG56yiZ J7gEWIlEbuSQwp2M1tkR7IS64LxnwqJiyIt36x4cVcr+xqpYd/Agj6s+IQYU4V6yFQ h2MkxBl3QyZ61+iMERQsx+d25DW+O/c2yEKz+O5WoSiz39NuCrfiMElXEHFzVLw1/K MeVLtrj6qXyDw== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4dVG3V29gbz4wF0; Mon, 15 Dec 2025 21:08:22 +1100 (AEDT) Date: Mon, 15 Dec 2025 20:53:02 +1100 From: David Gibson To: Jon Maloy Subject: Re: [RFC 03/12] conf: Allow multiple -a/--address options per address family Message-ID: References: <20251215015441.887736-1-jmaloy@redhat.com> <20251215015441.887736-4-jmaloy@redhat.com> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="9shM39w8YxWubDjV" Content-Disposition: inline In-Reply-To: <20251215015441.887736-4-jmaloy@redhat.com> Message-ID-Hash: STLVHWJKU2IEV4UOJP5RI4LD2FLJSICD X-Message-ID-Hash: STLVHWJKU2IEV4UOJP5RI4LD2FLJSICD X-MailFrom: dgibson@gandalf.ozlabs.org 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 CC: sbrivio@redhat.com, dgibson@redhat.com, passt-dev@passt.top 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: --9shM39w8YxWubDjV Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Sun, Dec 14, 2025 at 08:54:32PM -0500, Jon Maloy wrote: > We enable configuration of multiple IPv4 and IPv6 addresses by allowing > repeated use of the -a/--address option. >=20 > - We update option parsing to append addresses to the addrs[] array. >=20 > - Each address specified via -a does initially get a class-based default > prefix. >=20 > - If no -a option is given, address and prefix are inherited from > the template interface, just like now. >=20 > - The -n/--netmask option applies only to the first address, in addrs[0]. I know this is temporary, but this seems a really bad semantic. Might be worth merging this patch with the -n patch. > - We configure all indicated addresses in the namespace interface. >=20 > Signed-off-by: Jon Maloy > --- > conf.c | 74 ++++++++++++++++++++++++++++++++++++++------------------- > pasta.c | 24 ++++++++++++++----- > 2 files changed, 68 insertions(+), 30 deletions(-) >=20 > diff --git a/conf.c b/conf.c > index 31acc20..e9f217b 100644 > --- a/conf.c > +++ b/conf.c > @@ -741,7 +741,7 @@ static unsigned int conf_ip4(unsigned int ifi, struct= ip4_ctx *ip4, > =20 > ip4->our_tap_addr =3D ip4->guest_gw; > =20 > - if (IN4_IS_ADDR_UNSPECIFIED(&ip4->addrs[0].addr)) > + if (!ip4->addr_count) > return 0; > =20 > return ifi; > @@ -756,6 +756,7 @@ static void conf_ip4_local(struct ip4_ctx *ip4) > ip4->addr_seen =3D ip4->addrs[0].addr =3D IP4_LL_GUEST_ADDR; > ip4->our_tap_addr =3D ip4->guest_gw =3D IP4_LL_GUEST_GW; > ip4->addrs[0].prefix_len =3D IP4_LL_PREFIX_LEN; > + ip4->addr_count =3D 1; Doesn't this belong in an earlier patch? Also, kind of pre-existing, but I don't think conf_ip4_local() should overwrite an address specified with -a. I think we want to change that to either be skipped if -a is used, or to add the link local address to the ones given explicitly. > =20 > ip4->no_copy_addrs =3D ip4->no_copy_routes =3D true; > } > @@ -810,8 +811,7 @@ static unsigned int conf_ip6(unsigned int ifi, struct= ip6_ctx *ip6, > if (IN6_IS_ADDR_LINKLOCAL(&ip6->guest_gw)) > ip6->our_tap_ll =3D ip6->guest_gw; > =20 > - if (IN6_IS_ADDR_UNSPECIFIED(&ip6->addrs[0].addr) || > - IN6_IS_ADDR_UNSPECIFIED(&ip6->our_tap_ll)) > + if (!ip6->addr_count || IN6_IS_ADDR_UNSPECIFIED(&ip6->our_tap_ll)) > return 0; > =20 > return ifi; > @@ -903,9 +903,11 @@ static void usage(const char *name, FILE *f, int sta= tus) > " default: 65520: maximum 802.3 MTU minus 802.3 header\n" > " length, rounded to 32 bits (IPv4 words)\n" > " -a, --address ADDR Assign IPv4 or IPv6 address ADDR\n" > - " can be specified zero to two times (for IPv4 and IPv6)\n" > + " can be specified multiple times (limit: %d IPv4, %d IPv6)\n" man page might need an update too. > " default: use addresses from interface with default route\n" > - " -n, --netmask MASK Assign IPv4 MASK, dot-decimal or bits\n" > + " -n, --netmask MASK Assign IPv4 MASK, dot-decimal or bits\n", > + IP4_MAX_ADDRS, IP6_MAX_ADDRS); > + FPRINTF(f, > " default: netmask from matching address on the host\n" > " -M, --mac-addr ADDR Use source MAC address ADDR\n" > " default: 9a:55:9a:55:9a:55 (locally administered)\n" > @@ -1159,9 +1161,11 @@ static void conf_print(const struct ctx *c) > (32 - c->ip4.addrs[0].prefix_len)); > =20 > info("DHCP:"); > - info(" assign: %s", > - inet_ntop(AF_INET, &c->ip4.addrs[0].addr, > - buf4, sizeof(buf4))); > + for (i =3D 0; i < (int)c->ip4.addr_count; i++) { > + info(" assign: %s", > + inet_ntop(AF_INET, &c->ip4.addrs[i].addr, > + buf4, sizeof(buf4))); > + } This is misleading. We allow multiple addresses, but (at least as of this patch) DHCP will only assign one of them. In fact I'm not sure we can assign multiple addresses with DHCP, short of rarely-supported extensions. > info(" mask: %s", > inet_ntop(AF_INET, &mask, buf4, sizeof(buf4))); > info(" router: %s", > @@ -1198,9 +1202,11 @@ static void conf_print(const struct ctx *c) > else > goto dns6; > =20 > - info(" assign: %s", > - inet_ntop(AF_INET6, &c->ip6.addrs[0].addr, > - buf6, sizeof(buf6))); > + for (i =3D 0; i < (int)c->ip6.addr_count; i++) { > + info(" assign: %s", > + inet_ntop(AF_INET6, &c->ip6.addrs[i].addr, > + buf6, sizeof(buf6))); > + } Similar comments, though I think DHCPv6 can assign multiple addresses (it's still not implemented as of this patch, though). > info(" router: %s", > inet_ntop(AF_INET6, &c->ip6.guest_gw, buf6, sizeof(buf6))); > info(" our link-local: %s", > @@ -1517,6 +1523,8 @@ void conf(struct ctx *c, int argc, char **argv) > struct fqdn *dnss =3D c->dns_search; > unsigned int ifi4 =3D 0, ifi6 =3D 0; > const char *logfile =3D NULL; > + struct in6_addr addr6; > + struct in_addr addr4; > size_t logsize =3D 0; > char *runas =3D NULL; > long fd_tap_opt; > @@ -1821,23 +1829,41 @@ void conf(struct ctx *c, int argc, char **argv) > break; > } > case 'a': > - if (inet_pton(AF_INET6, optarg, > - &c->ip6.addrs[0].addr) && > - !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.addrs[0].addr) && > - !IN6_IS_ADDR_LOOPBACK(&c->ip6.addrs[0].addr) && > - !IN6_IS_ADDR_V4MAPPED(&c->ip6.addrs[0].addr) && > - !IN6_IS_ADDR_V4COMPAT(&c->ip6.addrs[0].addr) && > - !IN6_IS_ADDR_MULTICAST(&c->ip6.addrs[0].addr)) { > + if (inet_pton(AF_INET6, optarg, &addr6) && > + !IN6_IS_ADDR_UNSPECIFIED(&addr6) && > + !IN6_IS_ADDR_LOOPBACK(&addr6) && > + !IN6_IS_ADDR_V4MAPPED(&addr6) && > + !IN6_IS_ADDR_V4COMPAT(&addr6) && > + !IN6_IS_ADDR_MULTICAST(&addr6)) { > + unsigned int i =3D c->ip6.addr_count; > + > + if (i >=3D IP6_MAX_ADDRS) > + die("Too many IPv6 addresses"); > + > + c->ip6.addrs[i].addr =3D addr6; > + c->ip6.addrs[i].prefix_len =3D 64; > + c->ip6.addrs[i].permanent =3D true; > + c->ip6.addr_count++; > if (c->mode =3D=3D MODE_PASTA) > c->ip6.no_copy_addrs =3D true; > break; > } > =20 > - if (inet_pton(AF_INET, optarg, &c->ip4.addrs[0].addr) && > - !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.addrs[0].addr) && > - !IN4_IS_ADDR_BROADCAST(&c->ip4.addrs[0].addr) && > - !IN4_IS_ADDR_LOOPBACK(&c->ip4.addrs[0].addr) && > - !IN4_IS_ADDR_MULTICAST(&c->ip4.addrs[0].addr)) { > + if (inet_pton(AF_INET, optarg, &addr4) && > + !IN4_IS_ADDR_UNSPECIFIED(&addr4) && > + !IN4_IS_ADDR_BROADCAST(&addr4) && > + !IN4_IS_ADDR_LOOPBACK(&addr4) && > + !IN4_IS_ADDR_MULTICAST(&addr4)) { > + unsigned int i =3D c->ip4.addr_count; > + > + if (i >=3D IP4_MAX_ADDRS) > + die("Too many IPv4 addresses"); > + > + c->ip4.addrs[i].addr =3D addr4; > + c->ip4.addrs[i].prefix_len =3D > + ip4_default_prefix_len(&addr4); > + c->ip4.addrs[i].permanent =3D true; > + c->ip4.addr_count++; > if (c->mode =3D=3D MODE_PASTA) > c->ip4.no_copy_addrs =3D true; > break; > @@ -2135,7 +2161,7 @@ void conf(struct ctx *c, int argc, char **argv) > if (!c->ifi6) { > c->no_ndp =3D 1; > c->no_dhcpv6 =3D 1; > - } else if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.addrs[0].addr)) { > + } else if (!c->ip6.addr_count) { > c->no_dhcpv6 =3D 1; > } > =20 > diff --git a/pasta.c b/pasta.c > index 49b393c..fe2908f 100644 > --- a/pasta.c > +++ b/pasta.c > @@ -329,10 +329,16 @@ void pasta_ns_conf(struct ctx *c) > =20 > if (c->ifi4) { > if (c->ip4.no_copy_addrs) { > - rc =3D nl_addr_set(nl_sock_ns, c->pasta_ifi, > - AF_INET, > - &c->ip4.addrs[0].addr, > - c->ip4.addrs[0].prefix_len); > + int i; > + > + for (i =3D 0; i < c->ip4.addr_count; i++) { > + rc =3D nl_addr_set(nl_sock_ns, > + c->pasta_ifi, AF_INET, > + &c->ip4.addrs[i].addr, > + c->ip4.addrs[i].prefix_len); > + if (rc < 0) > + break; > + } Maybe it belongs in a different patch, but multiple address support might less us partially unify the "copy addrs" and "no_copy_addrs" paths. Rather than copying addresses direct from the host into the guest, we optionally add host addresses into the address list, then unconditionally set everything in the list in the guest. > } else { > rc =3D nl_addr_dup(nl_sock, c->ifi4, > nl_sock_ns, c->pasta_ifi, > @@ -378,12 +384,18 @@ void pasta_ns_conf(struct ctx *c) > 0, IFF_NOARP); > =20 > if (c->ip6.no_copy_addrs) { > - struct in6_addr *a =3D &c->ip6.addrs[0].addr; > + struct in6_addr *a; > + int i; > =20 > - if (!IN6_IS_ADDR_UNSPECIFIED(a)) { > + for (i =3D 0; i < c->ip6.addr_count; i++) { > + a =3D &c->ip6.addrs[i].addr; > + if (IN6_IS_ADDR_UNSPECIFIED(a)) > + continue; > rc =3D nl_addr_set(nl_sock_ns, > c->pasta_ifi, > AF_INET6, a, 64); > + if (rc < 0) > + break; > } > } else { > rc =3D nl_addr_dup(nl_sock, c->ifi6, > --=20 > 2.51.1 >=20 --=20 David Gibson (he or they) | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you, not the other way | around. http://www.ozlabs.org/~dgibson --9shM39w8YxWubDjV Content-Type: application/pgp-signature; name=signature.asc -----BEGIN PGP SIGNATURE----- iQIzBAEBCgAdFiEEO+dNsU4E3yXUXRK2zQJF27ox2GcFAmk/2n0ACgkQzQJF27ox 2GfGpw//eGB2Kys9DPjsaAtr9POq6LWuxPyp+oGbFw9fNNmqAtLLCiGVzkWEkz0z NV7zhGRlk58yLhj+EYGw0lTaGH6DGGi1LDllXaQV5qtaBadHijU8u2hbAWsaw7iU hH2SBFqwFggvUBWVBmL8qu7xhZPM3mINCEWBK0hUUSyG7UepKxyvl272BGqKDP/X NI+9C9/hsUoc6mNPa1EmsNK1bCHYsOPyHWjcb341D/1DeI1scf0X54+Zgsr+TqMC wKra5yAYaF6ZsGZGaJk8mhEvrLQtiVZbSowkm8arg8kRhvLoVVqF3xSjohXr2BkH mNj9AueJST2mKqbBmTVktrRq13pGC/vF3iU44rwZimeg9bSMigEWeyKOVhU6SIVo dNbSIQdX7gSVTfLCgT/yuJQr4ODf/0DiVu70qOcXaKEiBF0zRdTw2ym4eVpSFlTO u1Q1tIDlweqvZy5SuR2MVZ7vo9gn+TacrVpwlnTHbVWBbJ3b058YxCt1pm0i1nHH IToJ3Wp5LJRrAtuldn101yJBgaXiMnTb0ZalTzKCdNleyHD/MsZio/CduFAjwLkh B1gIOvqyAfQVk6RkM521QsAPmxbi7zfPMDk3LmfvYyoJygHYGop7UHyTXh+SGUnV iDQI2WGZ1V9BtEndaC3V6xlKKmI1wwtMY2OunAhbQHZ+23fBx6A= =N1x9 -----END PGP SIGNATURE----- --9shM39w8YxWubDjV--