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=202602 header.b=KGohOPqw; dkim-atps=neutral Received: from mail.ozlabs.org (gandalf.ozlabs.org [150.107.74.76]) by passt.top (Postfix) with ESMTPS id 38C425A0269 for ; Wed, 27 May 2026 05:56:07 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202602; t=1779854165; bh=zvuwtOJrIqOxDk0iEk8t+LmHYZ+vYz1xf6R4lJQetPA=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=KGohOPqwlrzLk1bq1EKOoiDdD76AEm2HJz0eKQq1kZM5u3Zmu/0wJJ4xYiZBIhgVN tYmxwn9CeGnenMdmiH3NvpaMCTLETSy/XdJr89LnKwIOrHSf+5aPOF8RY1bODU1V4R tVR6uQK0kqlhiGT94WQvJ8yi9DS5uKN1cszbWh4c3dXWO8vqQsunKcfXu5x1150FqG E8sqhhQluNHraaaVHge4TT8gTxQVLKEmmcBNJkU+Sk3idXUjUICFbIrtQ9ZV9EjiQZ qq/7HkZZpDAbSp39z+D8r6MaDRrVspvKt6iEieFjDKzTuDWIqrUg3vb66xIg0xoF49 VL7D+oo4f8Q6w== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4gQG4h75RQz4w1j; Wed, 27 May 2026 13:56:04 +1000 (AEST) Date: Wed, 27 May 2026 13:55:58 +1000 From: David Gibson To: Jon Maloy Subject: Re: [PATCH v7 10/13] migrate: Update protocol to v3 for multi-address support Message-ID: References: <20260413005319.3295910-1-jmaloy@redhat.com> <20260413005319.3295910-11-jmaloy@redhat.com> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="uAOaL1FzYTqQAZss" Content-Disposition: inline In-Reply-To: <20260413005319.3295910-11-jmaloy@redhat.com> Message-ID-Hash: UCVVHHRBRQ3AHUAITOMMYFP3IZZX2453 X-Message-ID-Hash: UCVVHHRBRQ3AHUAITOMMYFP3IZZX2453 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, 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: --uAOaL1FzYTqQAZss Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Sun, Apr 12, 2026 at 08:53:16PM -0400, Jon Maloy wrote: > We update the migration protocol to version 3 to support distributing > multiple addresses from the unified address array. The new protocol > migrates all address entries in the array, along with their prefix > lengths and flags, and leaves it to the receiver to filter which > ones he wants to apply. >=20 > Signed-off-by: Jon Maloy >=20 > --- > v4: - Broke out as separate commit > - Made number of transferable addresses variable >=20 > v6: - Separated internal and wire transfer format >=20 > v7: - Using uint32_t instead of uint8_t for fields in migration format > - Replaced term "wire format" with "migration format" > - Some other minor changes after feedback from Stefano. > --- > migrate.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 179 insertions(+) >=20 > diff --git a/migrate.c b/migrate.c > index 2dc4dd9..93f67ae 100644 > --- a/migrate.c > +++ b/migrate.c > @@ -44,6 +44,71 @@ struct migrate_seen_addrs_v2 { > unsigned char mac[ETH_ALEN]; > } __attribute__((packed)); > =20 > +/** > + * Migration format flags for address migration (v3) > + * These are stable values - do not change existing assignments > + */ > +#define MIGRATE_ADDR_USER BIT(0) > +#define MIGRATE_ADDR_HOST BIT(1) > +#define MIGRATE_ADDR_LINKLOCAL BIT(2) > +#define MIGRATE_ADDR_OBSERVED BIT(3) > + > +/** > + * struct migrate_addr_v3 - Migration format for a single address entry > + * @addr: IPv6 or IPv4-mapped address (16 bytes) > + * @prefix_len: Prefix length > + * @flags: MIGRATE_ADDR_* flags (migration format) > + */ > +struct migrate_addr_v3 { > + struct in6_addr addr; > + uint32_t prefix_len; > + uint32_t flags; Since this is 32-bit... > +} __attribute__((__packed__)); > + > +/** > + * flags_to_migration() - Convert internal flags to stable migration for= mat > + * @flags: Internal CONF_ADDR_* flags > + * > + * Return: Migration format MIGRATE_ADDR_* flags > + */ > +static uint8_t flags_to_migration(uint8_t flags) =2E.. this should probably also return 32-bit. > +{ > + uint8_t migration =3D 0; > + > + if (flags & CONF_ADDR_USER) > + migration |=3D MIGRATE_ADDR_USER; > + if (flags & CONF_ADDR_HOST) > + migration |=3D MIGRATE_ADDR_HOST; > + if (flags & CONF_ADDR_LINKLOCAL) > + migration |=3D MIGRATE_ADDR_LINKLOCAL; > + if (flags & CONF_ADDR_OBSERVED) > + migration |=3D MIGRATE_ADDR_OBSERVED; > + > + return migration; That way you could also include the htonl() / ntohl() as part of the conversion functions. > +} > + > +/** > + * flags_from_migration() - Convert migration format flags to internal f= ormat > + * @migration: Migration format MIGRATE_ADDR_* flags > + * > + * Return: Internal CONF_ADDR_* flags > + */ > +static uint8_t flags_from_migration(uint8_t migration) Same comments here, but in reverse. > +{ > + uint8_t flags =3D 0; > + > + if (migration & MIGRATE_ADDR_USER) > + flags |=3D CONF_ADDR_USER; > + if (migration & MIGRATE_ADDR_HOST) > + flags |=3D CONF_ADDR_HOST; > + if (migration & MIGRATE_ADDR_LINKLOCAL) > + flags |=3D CONF_ADDR_LINKLOCAL; > + if (migration & MIGRATE_ADDR_OBSERVED) > + flags |=3D CONF_ADDR_OBSERVED; > + > + return flags; > +} > + > /** > * seen_addrs_source_v2() - Copy and send guest observed addresses from = source > * @c: Execution context > @@ -126,6 +191,99 @@ static int seen_addrs_target_v2(struct ctx *c, > return 0; > } > =20 > +/** > + * addrs_source_v3() - Send all addresses with flags from source > + * @c: Execution context > + * @stage: Migration stage, unused > + * @fd: File descriptor for state transfer > + * > + * Send all address entries using a stable migration format. Each field = is > + * serialised explicitly to avoid coupling the migration format to inter= nal > + * structure layout or flag bit assignments. > + * > + * Return: 0 on success, positive error code on failure > + */ > +/* cppcheck-suppress [constParameterCallback, unmatchedSuppression] */ > +static int addrs_source_v3(struct ctx *c, > + const struct migrate_stage *stage, int fd) > +{ > + uint8_t addr_count =3D c->addr_count; > + const struct guest_addr *a; > + > + (void)stage; > + > + /* Send count first */ > + if (write_all_buf(fd, &addr_count, sizeof(addr_count))) > + return errno; I'd be inclined to use 32-bits here, rather than 8. Yes, 255 is probably more than enough addresses, but this gains future-proofness and consistency with other counts we send at negligible cost. Either way you can use write_u8() or write_u32() from serialise.c here. > + > + /* Send each address in stable migration format */ > + for_each_addr(a, c->addrs, c->addr_count, 0) { > + struct migrate_addr_v3 migration =3D { > + .addr =3D a->addr.a6, > + .prefix_len =3D htonl(a->prefix_len), > + .flags =3D htonl(flags_to_migration(a->flags)), > + }; > + > + if (write_all_buf(fd, &migration, sizeof(migration))) > + return errno; > + } > + > + /* Send MAC address */ > + if (write_all_buf(fd, c->guest_mac, ETH_ALEN)) > + return errno; > + > + return 0; > +} > + > +/** > + * addrs_target_v3() - Receive addresses on target > + * @c: Execution context > + * @stage: Migration stage, unused > + * @fd: File descriptor for state transfer > + * > + * Receive address entries from the stable migration format and merge on= ly > + * observed addresses into local array. Source sends all addresses for > + * forward compatibility, but target only applies those marked as observ= ed. > + * > + * Return: 0 on success, positive error code on failure > + */ > +static int addrs_target_v3(struct ctx *c, > + const struct migrate_stage *stage, int fd) > +{ > + uint8_t addr_count, i; > + > + (void)stage; > + > + if (read_all_buf(fd, &addr_count, sizeof(addr_count))) > + return errno; read_u8() / read_u32() from serialise.c. > + > + if (addr_count > MAX_GUEST_ADDRS) Print a warning? > + addr_count =3D MAX_GUEST_ADDRS; > + > + /* Read each address from stable migration format */ > + for (i =3D 0; i < addr_count; i++) { > + struct migrate_addr_v3 migration; > + struct guest_addr addr; > + > + if (read_all_buf(fd, &migration, sizeof(migration))) > + return errno; > + > + addr.addr.a6 =3D migration.addr; > + addr.prefix_len =3D ntohl(migration.prefix_len); > + addr.flags =3D flags_from_migration(ntohl(migration.flags)); > + > + if (addr.flags & CONF_ADDR_OBSERVED) { > + fwd_set_addr(c, &addr.addr, addr.flags, > + addr.prefix_len); > + } I'm assuming that sending all the addresses, but only importing the OBSERVED ones is to allow us to change the policy about which addresses are migrated in future. That seems wise. > + } > + > + if (read_all_buf(fd, c->guest_mac, ETH_ALEN)) > + return errno; > + > + return 0; > +} > + > /* Stages for version 2 */ > static const struct migrate_stage stages_v2[] =3D { > { > @@ -146,8 +304,29 @@ static const struct migrate_stage stages_v2[] =3D { > { 0 }, > }; > =20 > +/* Stages for version 3 (all addresses, with flags) */ > +static const struct migrate_stage stages_v3[] =3D { > + { > + .name =3D "addresses", > + .source =3D addrs_source_v3, > + .target =3D addrs_target_v3, > + }, > + { > + .name =3D "prepare flows", > + .source =3D flow_migrate_source_pre, > + .target =3D NULL, > + }, > + { > + .name =3D "transfer flows", > + .source =3D flow_migrate_source, > + .target =3D flow_migrate_target, > + }, > + { 0 }, > +}; > + > /* Supported encoding versions, from latest (most preferred) to oldest */ > static const struct migrate_version versions[] =3D { > + { 3, stages_v3, }, > { 2, stages_v2, }, > /* v1 was released, but not widely used. It had bad endianness for the > * MSS and omitted timestamps, which meant it usually wouldn't work. > --=20 > 2.52.0 >=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 --uAOaL1FzYTqQAZss Content-Type: application/pgp-signature; name=signature.asc -----BEGIN PGP SIGNATURE----- iQIzBAEBCgAdFiEEO+dNsU4E3yXUXRK2zQJF27ox2GcFAmoWa00ACgkQzQJF27ox 2GfHFA//ajpdz4rDYQe/Lf3TtIKtA7KzKWpm4k2QeIRc6lIfUUQKqFCLwaKo+HhW ZgtaKCJ9Iyiln+DcQC/lE4qFshyg8PdKxFcQA9OcJRBMMELOcUc1CnJJa68m2nn4 v/GqovGOjy7AQRcs8uCjj2/mS8TqrgF4AREqLXFnw7mpxXGednILUys8nEeesoKd HVJASjZidqVHup/SsGikM6IEQ4UwZqOKb/3ySTFWmKLI1m6QpQlXT5UGbSLuyDUD CngTkj7gWEfzKeT6SiZBYKDhHwW0pLS7CkkAfy9wkEmxqc+fmVERHFKSyzsIv+Lh AGGz0LMRhtmxUoAV4VYDj9Ao6SVSht8lsvV8WkPH944hS2uidk0TEH5yBSlVgw+W kqAljRp4OiUTAcOXjx0D/VfT0vBfUD+9TqzyTkq56Vd2ieqCRxo27TUMaE5TmtAa ev9dfvShDJNkrN7i942zKTQ9xDzQIH4GqdhNktc5XCixiSKhX1R/4hOYHrClFpNV TeCILBGJo+K+2/OrmK5yCNBGP/rtmDtgthDOQCEPovOsdOiKfdp5bk2d3ZFKKAwE Lz6kCFPhGx+QwabUz/4w7hd3+lDMMyKk1NaaVws9vSsMZ4Yp0ja44MrlxizUV5Oe W+bzXB7WNdLLvSzXaaEYPlsMrsVAtrDqzYhUegXQLPDSUXd2ZFQ= =lkF4 -----END PGP SIGNATURE----- --uAOaL1FzYTqQAZss--