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=E9y9mmHz; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by passt.top (Postfix) with ESMTPS id BF1725A026D for ; Tue, 17 Feb 2026 23:18:40 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1771366719; 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=XJ6NldC+dYx0TkHxqMFrVS6+BbnKjK2NUh9OOBzDegk=; b=E9y9mmHzANKvfBW+Le8wHgN82YDkxPq9m0fmmjPNYRtSnRodb6L0o+RN7CHbUDgMon2udv Btm8rTiJIKMWM5F6nG0xvh/YqZeU2dNMmMnYQMtSkuKEQX5r8iu01Pgx/69yNRGKkMkjOZ A41DhS23IfKPUu3CumaN9st87O5TfZo= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-339-mukX_SF4NMiYePCU4XYzQQ-1; Tue, 17 Feb 2026 17:18:36 -0500 X-MC-Unique: mukX_SF4NMiYePCU4XYzQQ-1 X-Mimecast-MFC-AGG-ID: mukX_SF4NMiYePCU4XYzQQ_1771366715 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 62B341955BF9; Tue, 17 Feb 2026 22:18:35 +0000 (UTC) Received: from jmaloy-thinkpadp16vgen1.rmtcaqc.csb (unknown [10.22.80.48]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 7ED321800348; Tue, 17 Feb 2026 22:18:34 +0000 (UTC) From: Jon Maloy To: sbrivio@redhat.com, dgibson@redhat.com, david@gibson.dropbear.id.au, jmaloy@redhat.com, passt-dev@passt.top Subject: [PATCH v4 12/12] migrate: Update protocol to v3 for multi-address support Date: Tue, 17 Feb 2026 17:18:14 -0500 Message-ID: <20260217221814.4053583-13-jmaloy@redhat.com> In-Reply-To: <20260217221814.4053583-1-jmaloy@redhat.com> References: <20260217221814.4053583-1-jmaloy@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: qO2AccZPkSX0mZY5OtgDeZ_--eYSRqrQhbDMR6q-oyc_1771366715 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit content-type: text/plain; charset="US-ASCII"; x-default=true Message-ID-Hash: CK4R7JH5CWEPLFKATN2QV7AWICAHWXWY X-Message-ID-Hash: CK4R7JH5CWEPLFKATN2QV7AWICAHWXWY 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 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 transferrable addresses variable --- migrate.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/migrate.c b/migrate.c index f937793..13a5d6f 100644 --- a/migrate.c +++ b/migrate.c @@ -124,6 +124,108 @@ 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 with their flags. The receiver can filter + * based on flags as needed. This provides forward compatibility if + * future versions need different address types. + * + * 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; + + (void)stage; + + /* Send count, then all addresses with flags, then MAC */ + if (write_all_buf(fd, &addr_count, sizeof(addr_count))) + return errno; + + if (addr_count && write_all_buf(fd, c->addrs, + addr_count * sizeof(c->addrs[0]))) + return errno; + + if (write_all_buf(fd, c->guest_mac, ETH_ALEN)) + return errno; + + return 0; +} + +/** + * migrate_merge_addr() - Merge migrated address into local array + * @c: Execution context + * @addr: Address entry from migration source + * + * If the address already exists locally, merge the flags (preserving + * local flags and adding migrated ones). Otherwise add as new entry. + */ +static void migrate_merge_addr(struct ctx *c, + const struct inany_addr_entry *addr) +{ + struct inany_addr_entry *e; + + if (inany_is_unspecified(&addr->addr)) + return; + + /* Check if address already exists, merge flags */ + for_each_addr(e, c, 0) { + if (inany_equals(&e->addr, &addr->addr)) { + e->flags |= addr->flags; + return; + } + } + + /* Add new entry if there's room */ + if (c->addr_count < INANY_MAX_ADDRS) + c->addrs[c->addr_count++] = *addr; +} + +/** + * addrs_target_v3() - Receive addresses on target + * @c: Execution context + * @stage: Migration stage, unused + * @fd: File descriptor for state transfer + * + * Receive all address entries and merge only observed addresses into local + * array. Source sends all addresses for forward compatibility, but target + * only applies those marked as observed by guest traffic. + * + * Return: 0 on success, positive error code on failure + */ +static int addrs_target_v3(struct ctx *c, + const struct migrate_stage *stage, int fd) +{ + struct inany_addr_entry addrs[INANY_MAX_ADDRS]; + uint8_t addr_count, i; + + (void)stage; + + if (read_all_buf(fd, &addr_count, sizeof(addr_count))) + return errno; + + if (addr_count > INANY_MAX_ADDRS) + addr_count = INANY_MAX_ADDRS; + + if (addr_count && read_all_buf(fd, addrs, addr_count * sizeof(addrs[0]))) + return errno; + + if (read_all_buf(fd, c->guest_mac, ETH_ALEN)) + return errno; + + for (i = 0; i < addr_count; i++) + if (addrs[i].flags & CONF_ADDR_OBSERVED) + migrate_merge_addr(c, &addrs[i]); + + return 0; +} + /* Stages for version 2 */ static const struct migrate_stage stages_v2[] = { { @@ -144,8 +246,29 @@ static const struct migrate_stage stages_v2[] = { { 0 }, }; +/* Stages for version 3 (multiple observed IPv4 addresses) */ +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. -- 2.52.0