From patchwork Fri Feb 16 06:52:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Han Zhou X-Patchwork-Id: 1899888 X-Patchwork-Delegate: dceara@redhat.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4TbjL86TGqz23hR for ; Fri, 16 Feb 2024 17:52:47 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 728D4610FF; Fri, 16 Feb 2024 06:52:44 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ysQbdUpqyyzZ; Fri, 16 Feb 2024 06:52:43 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=140.211.9.56; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 30F65606F3 Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp3.osuosl.org (Postfix) with ESMTPS id 30F65606F3; Fri, 16 Feb 2024 06:52:43 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 06392C0072; Fri, 16 Feb 2024 06:52:43 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 70561C0037 for ; Fri, 16 Feb 2024 06:52:42 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 59D06820EE for ; Fri, 16 Feb 2024 06:52:42 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id cG-wUC_OQmQN for ; Fri, 16 Feb 2024 06:52:41 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=217.70.183.198; helo=relay6-d.mail.gandi.net; envelope-from=hzhou@ovn.org; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp1.osuosl.org 1F4E081FAB Authentication-Results: smtp1.osuosl.org; dmarc=none (p=none dis=none) header.from=ovn.org DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 1F4E081FAB Received: from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net [217.70.183.198]) by smtp1.osuosl.org (Postfix) with ESMTPS id 1F4E081FAB for ; Fri, 16 Feb 2024 06:52:40 +0000 (UTC) Received: by mail.gandi.net (Postfix) with ESMTPSA id 21D05C0004; Fri, 16 Feb 2024 06:52:36 +0000 (UTC) From: Han Zhou To: dev@openvswitch.org Date: Thu, 15 Feb 2024 22:52:30 -0800 Message-Id: <20240216065230.2350314-1-hzhou@ovn.org> X-Mailer: git-send-email 2.38.1 MIME-Version: 1.0 X-GND-Sasl: hzhou@ovn.org Subject: [ovs-dev] [PATCH ovn] encaps: Support backward compatibility for tunnel chassis id change. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" In commit 41eefcb2807d, the format of external_ids:ovn-chassis-id for tunnels was modified to include the local encapsulation IP. This change can lead to the recreation of tunnels during an upgrade, potentially disrupting the dataplane temporarily, especially in large-scale environments. This patch resolves the issue by recognizing the previous format. Thus, if the only modification is to the ID format, the tunnel will not be recreated. Instead, the external_ids will be updated directly. This approach ensures that the upgrade process is non-disruptive. Fixes: 41eefcb2807d ("encaps: Create separate tunnels for multiple local encap IPs.") Signed-off-by: Han Zhou Acked-by: Dumitru Ceara --- controller/encaps.c | 83 ++++++++++++++++++++++++++++++++--------- tests/ovn-controller.at | 44 ++++++++++++++++++++++ 2 files changed, 110 insertions(+), 17 deletions(-) diff --git a/controller/encaps.c b/controller/encaps.c index 28237f6191c8..1d0d47523e77 100644 --- a/controller/encaps.c +++ b/controller/encaps.c @@ -104,40 +104,62 @@ encaps_tunnel_id_create(const char *chassis_id, const char *remote_encap_ip, '%', local_encap_ip); } +/* + * The older version of encaps_tunnel_id_create, which doesn't include + * local_encap_ip in the ID. This is used for backward compatibility support. + */ +static char * +encaps_tunnel_id_create_old(const char *chassis_id, + const char *remote_encap_ip) +{ + return xasprintf("%s%c%s", chassis_id, '@', remote_encap_ip); +} + /* * Parses a 'tunnel_id' of the form @%. * If the 'chassis_id' argument is not NULL the function will allocate memory * and store the chassis_name part of the tunnel-id at '*chassis_id'. * Same for remote_encap_ip and local_encap_ip. + * + * The old form @ is also supported for backward + * compatibility during upgrade. */ bool encaps_tunnel_id_parse(const char *tunnel_id, char **chassis_id, char **remote_encap_ip, char **local_encap_ip) { - /* Find the @. Fail if there is no @ or if any part is empty. */ - const char *d = strchr(tunnel_id, '@'); - if (d == tunnel_id || !d || !d[1]) { - return false; + char *tokstr = xstrdup(tunnel_id); + char *saveptr = NULL; + bool ret = false; + + char *token_chassis = strtok_r(tokstr, "@", &saveptr); + if (!token_chassis) { + goto out; } - /* Find the %. Fail if there is no % or if any part is empty. */ - const char *d2 = strchr(d + 1, '%'); - if (d2 == d + 1 || !d2 || !d2[1]) { - return false; + char *token_remote_ip = strtok_r(NULL, "%", &saveptr); + if (!token_remote_ip) { + goto out; } + char *token_local_ip = strtok_r(NULL, "", &saveptr); + if (chassis_id) { - *chassis_id = xmemdup0(tunnel_id, d - tunnel_id); + *chassis_id = xstrdup(token_chassis); } - if (remote_encap_ip) { - *remote_encap_ip = xmemdup0(d + 1, d2 - (d + 1)); + *remote_encap_ip = xstrdup(token_remote_ip); } - if (local_encap_ip) { - *local_encap_ip = xstrdup(d2 + 1); + /* To support backward compatibility during upgrade, ignore local ip if + * it is not encoded in the tunnel id yet. */ + *local_encap_ip = token_local_ip ? xstrdup(token_local_ip) : NULL; } - return true; + + ret = true; +out: + free(tokstr); + return ret; } /* @@ -145,6 +167,10 @@ encaps_tunnel_id_parse(const char *tunnel_id, char **chassis_id, * @% * contains 'chassis_id' and, if specified, the given 'remote_encap_ip' and * 'local_encap_ip'. Returns false otherwise. + * + * The old format @ is also supported for backward + * compatibility during upgrade, and the local_encap_ip matching is ignored in + * that case. */ bool encaps_tunnel_id_match(const char *tunnel_id, const char *chassis_id, @@ -166,8 +192,10 @@ encaps_tunnel_id_match(const char *tunnel_id, const char *chassis_id, } char *token_local_ip = strtok_r(NULL, "", &saveptr); - if (local_encap_ip && - (!token_local_ip || strcmp(token_local_ip, local_encap_ip))) { + if (!token_local_ip) { + /* It is old format. To support backward compatibility during upgrade, + * just ignore local_ip. */ + } else if (local_encap_ip && strcmp(token_local_ip, local_encap_ip)) { goto out; } @@ -189,6 +217,7 @@ tunnel_add(struct tunnel_ctx *tc, const struct sbrec_sb_global *sbg, const char *dst_port = smap_get(&encap->options, "dst_port"); const char *csum = smap_get(&encap->options, "csum"); char *tunnel_entry_id = NULL; + char *tunnel_entry_id_old = NULL; /* * Since a chassis may have multiple encap-ip, we can't just add the @@ -198,6 +227,8 @@ tunnel_add(struct tunnel_ctx *tc, const struct sbrec_sb_global *sbg, */ tunnel_entry_id = encaps_tunnel_id_create(new_chassis_id, encap->ip, local_ip); + tunnel_entry_id_old = encaps_tunnel_id_create_old(new_chassis_id, + encap->ip); if (csum && (!strcmp(csum, "true") || !strcmp(csum, "false"))) { smap_add(&options, "csum", csum); } @@ -269,11 +300,28 @@ tunnel_add(struct tunnel_ctx *tc, const struct sbrec_sb_global *sbg, * it). */ struct tunnel_node *tunnel = shash_find_data(&tc->tunnel, tunnel_entry_id); + bool old_id_format = false; + if (!tunnel) { + tunnel = shash_find_data(&tc->tunnel, tunnel_entry_id_old); + old_id_format = true; + } if (tunnel && tunnel->port->n_interfaces == 1 && !strcmp(tunnel->port->interfaces[0]->type, encap->type) && smap_equal(&tunnel->port->interfaces[0]->options, &options)) { - shash_find_and_delete(&tc->tunnel, tunnel_entry_id); + if (old_id_format) { + /* We must be upgrading from an older version. We can reuse the + * existing tunnel, but needs to update the tunnel's ID to the new + * format. */ + ovsrec_port_update_external_ids_setkey(tunnel->port, OVN_TUNNEL_ID, + tunnel_entry_id); + ovsrec_interface_update_external_ids_setkey( + tunnel->port->interfaces[0], OVN_TUNNEL_ID, tunnel_entry_id); + + shash_find_and_delete(&tc->tunnel, tunnel_entry_id_old); + } else { + shash_find_and_delete(&tc->tunnel, tunnel_entry_id); + } free(tunnel); goto exit; } @@ -306,6 +354,7 @@ tunnel_add(struct tunnel_ctx *tc, const struct sbrec_sb_global *sbg, exit: free(tunnel_entry_id); + free(tunnel_entry_id_old); smap_destroy(&options); } diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at index f77e032d4839..0b60806089cf 100644 --- a/tests/ovn-controller.at +++ b/tests/ovn-controller.at @@ -2732,3 +2732,47 @@ OVS_WAIT_FOR_OUTPUT([ovn-appctl -t ovn-controller connection-status], [0], [conn OVN_CLEANUP([hv1]) AT_CLEANUP + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([ovn-controller - tunnel chassis id backward compatibility]) + +ovn_start + +net_add n1 +sim_add hv1 +as hv1 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 + +ovn-nbctl --wait=sb sync +wait_row_count Chassis 1 name=hv1 + +ovn-sbctl chassis-add fakechassis geneve 192.168.0.2 +fakech_tunnel=ovn-fakech-0 +OVS_WAIT_UNTIL([ovs-vsctl list port $fakech_tunnel]) +port_uuid=$(ovs-vsctl get port $fakech_tunnel _uuid) + +AT_CHECK([ovs-vsctl get port $fakech_tunnel external_ids:ovn-chassis-id], [0], [dnl +"fakechassis@192.168.0.2%192.168.0.1" +]) + +# Stop ovn-controller without deleting tunnel +ovs-appctl --timeout=10 -t ovn-controller exit --restart + +# Change the tunnel external id to the old format, and then start +# ovn-controller, pretending we are upgrading from an older version. +ovs-vsctl set port $fakech_tunnel external_ids:ovn-chassis-id=fakechassis@192.168.0.2 +AT_CHECK([ovs-vsctl get port $fakech_tunnel external_ids:ovn-chassis-id], [0], [dnl +"fakechassis@192.168.0.2" +]) + +start_daemon ovn-controller + +# The tunnel id should be updated to the new format but the tunnel's uuid +# should kept the same (no recreation). +OVS_WAIT_UNTIL([test x$(ovs-vsctl get port $fakech_tunnel external_ids:ovn-chassis-id) = x\"fakechassis@192.168.0.2%192.168.0.1\"]) +AT_CHECK([test x"$port_uuid"=$(ovs-vsctl get port $fakech_tunnel _uuid)]) + +OVN_CLEANUP([hv1]) +AT_CLEANUP +])