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=Vy/dNwdm; 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 910DB5A0272 for ; Thu, 02 Apr 2026 23:55:34 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1775166933; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=KwNFYd51boDfeoZKFxL+K38jPy+XTn0Smvs9uE9kreQ=; b=Vy/dNwdmjaowxpiiSpLnAo8UnMbD+N5MSJgByZgib9ZKIiOKYPWAmX/V87T+IgOU5i7mCE 4nUJiC8qvNLtjCsxLX4spby1lskkW3gSqBWusdR2g30h/PaCxRKwas0qv7V7myZg2+Jfh4 Yq3RHLbfEcLf16N7UkPeetgt7Zk4oHc= Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-642-Xuz_h6JkMcuaibbL-8dwpg-1; Thu, 02 Apr 2026 17:55:32 -0400 X-MC-Unique: Xuz_h6JkMcuaibbL-8dwpg-1 X-Mimecast-MFC-AGG-ID: Xuz_h6JkMcuaibbL-8dwpg_1775166931 Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-43d022974acso1333156f8f.2 for ; Thu, 02 Apr 2026 14:55:31 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775166930; x=1775771730; h=date:content-transfer-encoding:mime-version:organization:references :in-reply-to:message-id:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=KwNFYd51boDfeoZKFxL+K38jPy+XTn0Smvs9uE9kreQ=; b=n3XMSl2h9wHdjvetDas7k116l0goRPnRzYYJJVHMwGuZUgeGe6h/rKCBU4TGRFvdct miyPawSxLiuiNDUSUtRNT/yXWjTd+h6iHfCbhoX/WUDvv56YjphcYeIrRFNq5BjGwEcd WfLRvb1A+9hgI5QBe8WwZHauF6/z3mNsV4f0FTrvIX7x8cLszQ39Xk2HgoF7ERnjy4Az Xaf9FpPwegRgcFix92iRV7oAAHtlJFRk0NYYcbvmFWxsEMor0gXOLifZzaz7sloRemHj CjytOIwZRWEg1UzrAOTQ7H9vGeLLRHCvamTgm4rBq5dzm71EhrpUvgkOLkOpMFgFEsuP L6nA== X-Forwarded-Encrypted: i=1; AJvYcCUnARQR9nJYLoZhI0yPOZKJjOuROFZq8sx4bRWgsQruuFLIBJn8+Xl/Wfg238kgh8GDaKF06IG24cI=@passt.top X-Gm-Message-State: AOJu0YwwTv+3kXnN5EfQ6yT/W3ho7AcjeB6sEscjyvpc/AFKfHGEXCq8 GZypxVMLbaU4hGgza7ksTTNGpaSqZIMd//qa9UogiLTMXuDN+YGR1eXODK2y29Yqm0DEaMHAO+c DuQgZYcchYjxpqAEWa5ZmQt4vB56blVojEux+iOA2AUbnex7RincZrQ== X-Gm-Gg: AeBDievr+HEfAGVfgMaJSyDU1C16T5ho61dGQqSEPrq7JifmSmxw671ni2q8rRbqMty TOVD4/Z3KybrpyjmM9Eegw1Y/N02fppdRgWYfwp9JaMCfcAevSfRl4pBfBdPMcumJMZ9jGdf9Wk kh4dbTjYJpDWIyeWI6nd4hZOfghj3WKxzbmPXu3iMcdfjbylOsLAYRHoj2JZJ2NOAoNcIyOVFZJ x+SEW9js/F+LanN9oxZQsMIRqgLbnffgMiw+AmmTxcDz+RA2lyP0n8MfFC0Rs24psy0bwqJn5ea IzqqwckcOF5D+22Ap0HGP8bFPq5CBdKM7HeQN3Efoy4bau2X34O+2d+pYjV8H2ovzZNkyMthEEe m4yyuWIn1IS95B+iFqSszhXB8yq3jUzc7w9rAO092GT/F5Ck8Hw== X-Received: by 2002:a05:6000:420f:b0:43b:4a2c:ff4 with SMTP id ffacd0b85a97d-43d292d3a09mr1045909f8f.33.1775166930455; Thu, 02 Apr 2026 14:55:30 -0700 (PDT) X-Received: by 2002:a05:6000:420f:b0:43b:4a2c:ff4 with SMTP id ffacd0b85a97d-43d292d3a09mr1045865f8f.33.1775166929897; Thu, 02 Apr 2026 14:55:29 -0700 (PDT) Received: from maya.myfinge.rs (ifcgrfdd.trafficplex.cloud. [176.103.220.4]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43d1e2a6f1esm11219179f8f.2.2026.04.02.14.55.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 02 Apr 2026 14:55:29 -0700 (PDT) From: Stefano Brivio To: Jon Maloy Subject: Re: [PATCH v6 10/13] migrate: Update protocol to v3 for multi-address support Message-ID: <20260402235524.38bd747f@elisabeth> In-Reply-To: <20260322004333.365713-11-jmaloy@redhat.com> References: <20260322004333.365713-1-jmaloy@redhat.com> <20260322004333.365713-11-jmaloy@redhat.com> Organization: Red Hat X-Mailer: Claws Mail 4.2.0 (GTK 3.24.49; x86_64-pc-linux-gnu) MIME-Version: 1.0 Date: Thu, 02 Apr 2026 23:55:27 +0200 (CEST) X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 8BP-AVnh4gnnvcf2-deR0VvPKgSM9xYtVMUOS8K84zk_1775166931 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Message-ID-Hash: XYZSEUEGJLWVZ6BARGGMMHJTYQH4MNPS X-Message-ID-Hash: XYZSEUEGJLWVZ6BARGGMMHJTYQH4MNPS X-MailFrom: sbrivio@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 CC: david@gibson.dropbear.id.au, 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: On Sat, 21 Mar 2026 20:43:30 -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. > > Signed-off-by: Jon Maloy > > --- > v4: - Broke out as separate commit > - Made number of transferable addresses variable > > v6: - Separated internal and wire transfer format > --- > migrate.c | 178 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 178 insertions(+) > > diff --git a/migrate.c b/migrate.c > index a92301b..7b9a2f6 100644 > --- a/migrate.c > +++ b/migrate.c > @@ -44,6 +44,71 @@ struct migrate_seen_addrs_v2 { > unsigned char mac[ETH_ALEN]; > } __attribute__((packed)); > > +/** > + * Wire format flags for address migration (v3) "Wire format" is perfectly clear to me but I'm afraid it's not really that much of a universal term. What about "Migration format" or "Stable format"? > + * 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 - Wire format for a single address entry > + * @addr: IPv6 or IPv4-mapped address (16 bytes) > + * @prefix_len: Prefix length > + * @flags: MIGRATE_ADDR_* flags (wire format) > + */ > +struct migrate_addr_v3 { > + struct in6_addr addr; > + uint8_t prefix_len; > + uint8_t flags; > +} __attribute__((__packed__)); > + > +/** > + * flags_to_wire() - Convert internal flags to stable wire format > + * @flags: Internal CONF_ADDR_* flags > + * > + * Return: Wire format MIGRATE_ADDR_* flags > + */ > +static uint8_t flags_to_wire(uint8_t flags) > +{ > + uint8_t wire = 0; > + > + if (flags & CONF_ADDR_USER) > + wire |= MIGRATE_ADDR_USER; > + if (flags & CONF_ADDR_HOST) > + wire |= MIGRATE_ADDR_HOST; > + if (flags & CONF_ADDR_LINKLOCAL) > + wire |= MIGRATE_ADDR_LINKLOCAL; > + if (flags & CONF_ADDR_OBSERVED) > + wire |= MIGRATE_ADDR_OBSERVED; > + > + return wire; > +} > + > +/** > + * flags_from_wire() - Convert wire format flags to internal format > + * @wire: Wire format MIGRATE_ADDR_* flags > + * > + * Return: Internal CONF_ADDR_* flags > + */ > +static uint8_t flags_from_wire(uint8_t wire) > +{ > + uint8_t flags = 0; > + > + if (wire & MIGRATE_ADDR_USER) > + flags |= CONF_ADDR_USER; > + if (wire & MIGRATE_ADDR_HOST) > + flags |= CONF_ADDR_HOST; > + if (wire & MIGRATE_ADDR_LINKLOCAL) > + flags |= CONF_ADDR_LINKLOCAL; > + if (wire & MIGRATE_ADDR_OBSERVED) > + flags |= CONF_ADDR_OBSERVED; > + > + return flags; > +} > + > /** > * seen_addrs_source_v2() - Copy and send guest observed addresses from source > * @c: Execution context > @@ -126,6 +191,98 @@ static int seen_addrs_target_v2(struct ctx *c, > return 0; > } > > +/** > + * 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 wire format. Each field is > + * serialized explicitly to avoid coupling the wire format to internal Nit, for consistency: "serialised". > + * 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 = 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; > + > + /* Send each address in stable wire format */ > + for_each_addr(a, c, 0) { > + struct migrate_addr_v3 wire = { > + .addr = a->addr.a6, > + .prefix_len = a->prefix_len, > + .flags = flags_to_wire(a->flags), > + }; > + > + if (write_all_buf(fd, &wire, sizeof(wire))) > + return errno; > + } > + > + /* Send MAC */ Nit: it's a MAC _address_, not a control... something. > + 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 wire format and merge only > + * observed addresses into local array. Source sends all addresses for > + * forward compatibility, but target only applies those marked as observed. > + * > + * 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; > + > + if (addr_count > MAX_GUEST_ADDRS) > + addr_count = MAX_GUEST_ADDRS; > + > + /* Read each address from stable wire format */ > + for (i = 0; i < addr_count; i++) { > + struct migrate_addr_v3 wire; > + struct guest_addr addr; > + > + if (read_all_buf(fd, &wire, sizeof(wire))) > + return errno; > + > + addr.addr.a6 = wire.addr; > + addr.prefix_len = wire.prefix_len; > + addr.flags = flags_from_wire(wire.flags); > + > + if (addr.flags & CONF_ADDR_OBSERVED) > + fwd_set_addr(c, &addr.addr, addr.flags, > + addr.prefix_len); Nit: curly brackets for coding style. > + } > + > + 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[] = { > { > @@ -146,8 +303,29 @@ static const struct migrate_stage stages_v2[] = { > { 0 }, > }; > > +/* Stages for version 3 (multiple observed IPv4 addresses) */ It's not just observed (anymore), and it's not just IPv4 addresses. Maybe this should actually state "(all addresses, with flags)"? > +static const struct migrate_stage stages_v3[] = { > + { > + .name = "addresses", > + .source = addrs_source_v3, > + .target = addrs_target_v3, > + }, > + { > + .name = "prepare flows", > + .source = flow_migrate_source_pre, > + .target = NULL, > + }, > + { > + .name = "transfer flows", > + .source = flow_migrate_source, > + .target = flow_migrate_target, > + }, > + { 0 }, > +}; > + > /* Supported encoding versions, from latest (most preferred) to oldest */ > static const struct migrate_version versions[] = { > + { 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. -- Stefano