From patchwork Thu Jul 25 14:00:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1964783 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=140.211.166.138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) (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 4WVCFd6G1Jz1yXx for ; Fri, 26 Jul 2024 00:00:21 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id C944C80B73; Thu, 25 Jul 2024 14:00:19 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id DOTtxJ-r7Xoi; Thu, 25 Jul 2024 14:00:18 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=2605:bc80:3010:104::8cd3:938; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 9CF2680B09 Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp1.osuosl.org (Postfix) with ESMTPS id 9CF2680B09; Thu, 25 Jul 2024 14:00:18 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 6A31EC002B; Thu, 25 Jul 2024 14:00:18 +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 7F540C002A for ; Thu, 25 Jul 2024 14:00:17 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 6E64D80B05 for ; Thu, 25 Jul 2024 14:00:17 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id Uqr-q8Rica-E for ; Thu, 25 Jul 2024 14:00:15 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=209.85.208.170; helo=mail-lj1-f170.google.com; envelope-from=frode.nordahl@gmail.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp1.osuosl.org 1F55180AB4 Authentication-Results: smtp1.osuosl.org; dmarc=fail (p=none dis=none) header.from=ubuntu.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 1F55180AB4 Received: from mail-lj1-f170.google.com (mail-lj1-f170.google.com [209.85.208.170]) by smtp1.osuosl.org (Postfix) with ESMTPS id 1F55180AB4 for ; Thu, 25 Jul 2024 14:00:15 +0000 (UTC) Received: by mail-lj1-f170.google.com with SMTP id 38308e7fff4ca-2f032cb782dso2035851fa.3 for ; Thu, 25 Jul 2024 07:00:14 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721916012; x=1722520812; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=h5reV8BLFvUuSiHfSRqHbYU7uBwB6uz5CQW2mKphw2U=; b=XMsycnBAfahl1iFqkNCzkTw8IFv9BNIk5oOuSJSvZ1j64PcBTJHFMGQ+WWRxW8rF6n mav1BzO1XW4R9LiSMJelZ3I2/1MkFtxhWVAXhVB+oNNFF8tIAq9zaXJdNu/3jL6TeBSk Z6ZkXODDhkLuSQBYqpXrXK1P5RNpQ5ZS0w2zXvJyG0PP9c9LqyLX8OO7Nd0iwiYam5gH F1n51lpVIVV2y26yCH2Npb6tjVor0pG/O1/CBvksP151Jc59fyQdaDhvE6ii4bTI7I7O kNwZLRlu/8Wj+6krsHcA5//X4QdWRveZyiNpCZe4JWaiUnFLKFLLepqwHkUCPuYM+9PM HozA== X-Gm-Message-State: AOJu0Yw7j71IQpuf/q3PJtyDW6BuRv7wPN7xNkEUBVeZuz/ppMpL6R7O SJz+7HGKajPtK0uiRvJMsqCME9lppTOjx+Tl8Yg3Lv6OVw2tLXUw8XCkBA== X-Google-Smtp-Source: AGHT+IFFT90ZEI2k5lHRzXcv2s7svJKSDgxAOpAYPXDoTIBP0zL6UkFziKtrsfseq+PihXHnk37TWQ== X-Received: by 2002:a2e:b019:0:b0:2ec:4acf:97dc with SMTP id 38308e7fff4ca-2f03db7d51bmr15170061fa.11.1721916012216; Thu, 25 Jul 2024 07:00:12 -0700 (PDT) Received: from localhost.localdomain ([2001:4643:d087:0:bd05:8094:92b2:c0a]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-2f03cf0e36csm2027211fa.17.2024.07.25.07.00.10 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jul 2024 07:00:10 -0700 (PDT) From: Frode Nordahl To: dev@openvswitch.org Date: Thu, 25 Jul 2024 16:00:03 +0200 Message-ID: <20240725140009.413791-1-fnordahl@ubuntu.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240719020943.380924-1-fnordahl@ubuntu.com> References: <20240719020943.380924-1-fnordahl@ubuntu.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v3 1/7] controller: Move address with port parser to lib. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" We will need parsing of Port_Binding->nat_addresses in other parts of the ovn-controller in subsequent patches. Move extract_addresses_with_port() to the lib/ ovn-util module. Signed-off-by: Frode Nordahl --- controller/pinctrl.c | 67 -------------------------------------------- lib/ovn-util.c | 66 +++++++++++++++++++++++++++++++++++++++++++ lib/ovn-util.h | 4 +++ 3 files changed, 70 insertions(+), 67 deletions(-) diff --git a/controller/pinctrl.c b/controller/pinctrl.c index 6a4299b82..708240e24 100644 --- a/controller/pinctrl.c +++ b/controller/pinctrl.c @@ -6377,73 +6377,6 @@ get_localnet_vifs_l3gwports( sbrec_port_binding_index_destroy_row(target); } - -/* Extracts the mac, IPv4 and IPv6 addresses, and logical port from - * 'addresses' which should be of the format 'MAC [IP1 IP2 ..] - * [is_chassis_resident("LPORT_NAME")]', where IPn should be a valid IPv4 - * or IPv6 address, and stores them in the 'ipv4_addrs' and 'ipv6_addrs' - * fields of 'laddrs'. The logical port name is stored in 'lport'. - * - * Returns true if at least 'MAC' is found in 'address', false otherwise. - * - * The caller must call destroy_lport_addresses() and free(*lport). */ -static bool -extract_addresses_with_port(const char *addresses, - struct lport_addresses *laddrs, - char **lport) -{ - int ofs; - if (!extract_addresses(addresses, laddrs, &ofs)) { - return false; - } else if (!addresses[ofs]) { - return true; - } - - struct lexer lexer; - lexer_init(&lexer, addresses + ofs); - lexer_get(&lexer); - - if (lexer.error || lexer.token.type != LEX_T_ID - || !lexer_match_id(&lexer, "is_chassis_resident")) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); - VLOG_INFO_RL(&rl, "invalid syntax '%s' in address", addresses); - lexer_destroy(&lexer); - return true; - } - - if (!lexer_match(&lexer, LEX_T_LPAREN)) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); - VLOG_INFO_RL(&rl, "Syntax error: expecting '(' after " - "'is_chassis_resident' in address '%s'", addresses); - lexer_destroy(&lexer); - return false; - } - - if (lexer.token.type != LEX_T_STRING) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); - VLOG_INFO_RL(&rl, - "Syntax error: expecting quoted string after " - "'is_chassis_resident' in address '%s'", addresses); - lexer_destroy(&lexer); - return false; - } - - *lport = xstrdup(lexer.token.s); - - lexer_get(&lexer); - if (!lexer_match(&lexer, LEX_T_RPAREN)) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); - VLOG_INFO_RL(&rl, "Syntax error: expecting ')' after quoted string in " - "'is_chassis_resident()' in address '%s'", - addresses); - lexer_destroy(&lexer); - return false; - } - - lexer_destroy(&lexer); - return true; -} - static void consider_nat_address(struct ovsdb_idl_index *sbrec_port_binding_by_name, const char *nat_address, diff --git a/lib/ovn-util.c b/lib/ovn-util.c index 58e941193..c1557f42d 100644 --- a/lib/ovn-util.c +++ b/lib/ovn-util.c @@ -1314,3 +1314,69 @@ ovn_update_swconn_at(struct rconn *swconn, const char *target, return notify; } + +/* Extracts the mac, IPv4 and IPv6 addresses, and logical port from + * 'addresses' which should be of the format 'MAC [IP1 IP2 ..] + * [is_chassis_resident("LPORT_NAME")]', where IPn should be a valid IPv4 + * or IPv6 address, and stores them in the 'ipv4_addrs' and 'ipv6_addrs' + * fields of 'laddrs'. The logical port name is stored in 'lport'. + * + * Returns true if at least 'MAC' is found in 'address', false otherwise. + * + * The caller must call destroy_lport_addresses() and free(*lport). */ +bool +extract_addresses_with_port(const char *addresses, + struct lport_addresses *laddrs, + char **lport) +{ + int ofs; + if (!extract_addresses(addresses, laddrs, &ofs)) { + return false; + } else if (!addresses[ofs]) { + return true; + } + + struct lexer lexer; + lexer_init(&lexer, addresses + ofs); + lexer_get(&lexer); + + if (lexer.error || lexer.token.type != LEX_T_ID + || !lexer_match_id(&lexer, "is_chassis_resident")) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + VLOG_INFO_RL(&rl, "invalid syntax '%s' in address", addresses); + lexer_destroy(&lexer); + return true; + } + + if (!lexer_match(&lexer, LEX_T_LPAREN)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + VLOG_INFO_RL(&rl, "Syntax error: expecting '(' after " + "'is_chassis_resident' in address '%s'", addresses); + lexer_destroy(&lexer); + return false; + } + + if (lexer.token.type != LEX_T_STRING) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + VLOG_INFO_RL(&rl, + "Syntax error: expecting quoted string after " + "'is_chassis_resident' in address '%s'", addresses); + lexer_destroy(&lexer); + return false; + } + + *lport = xstrdup(lexer.token.s); + + lexer_get(&lexer); + if (!lexer_match(&lexer, LEX_T_RPAREN)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + VLOG_INFO_RL(&rl, "Syntax error: expecting ')' after quoted string in " + "'is_chassis_resident()' in address '%s'", + addresses); + lexer_destroy(&lexer); + return false; + } + + lexer_destroy(&lexer); + return true; +} diff --git a/lib/ovn-util.h b/lib/ovn-util.h index f75b821b6..e07c09238 100644 --- a/lib/ovn-util.h +++ b/lib/ovn-util.h @@ -481,4 +481,8 @@ void ovn_exit_args_finish(struct ovn_exit_args *exit_args); bool ovn_update_swconn_at(struct rconn *swconn, const char *target, int probe_interval, const char *where); +bool extract_addresses_with_port(const char *addresses, + struct lport_addresses *laddrs, + char **lport); + #endif /* OVN_UTIL_H */ From patchwork Thu Jul 25 14:00:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1964784 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=140.211.166.137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (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 4WVCFk1Kqgz1yXx for ; Fri, 26 Jul 2024 00:00:26 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 27B9E40987; Thu, 25 Jul 2024 14:00:23 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id OM4oQHyQS1lS; Thu, 25 Jul 2024 14:00:21 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=2605:bc80:3010:104::8cd3:938; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 7599440979 Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp4.osuosl.org (Postfix) with ESMTPS id 7599440979; Thu, 25 Jul 2024 14:00:21 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 477A8C002B; Thu, 25 Jul 2024 14:00:21 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) by lists.linuxfoundation.org (Postfix) with ESMTP id A3C07C0035 for ; Thu, 25 Jul 2024 14:00:19 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 7886B408DD for ; Thu, 25 Jul 2024 14:00:19 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id 7UgjOghu2M8i for ; Thu, 25 Jul 2024 14:00:18 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=209.85.208.181; helo=mail-lj1-f181.google.com; envelope-from=frode.nordahl@gmail.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp4.osuosl.org B270840653 Authentication-Results: smtp4.osuosl.org; dmarc=fail (p=none dis=none) header.from=ubuntu.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org B270840653 Received: from mail-lj1-f181.google.com (mail-lj1-f181.google.com [209.85.208.181]) by smtp4.osuosl.org (Postfix) with ESMTPS id B270840653 for ; Thu, 25 Jul 2024 14:00:17 +0000 (UTC) Received: by mail-lj1-f181.google.com with SMTP id 38308e7fff4ca-2ef27bfd15bso2383741fa.2 for ; Thu, 25 Jul 2024 07:00:17 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721916015; x=1722520815; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=mM8YmxbHe1IoAd5FkcM0RxUiT/jLsRIpBhlu0pfolGM=; b=gdV9D/RqWjsJEkEGWRgsHpNuccAsbwafTXh16dfPcnrebhLdXUDIUWooT+K3Iu1NEA 1wQbwG+qa7cyA5Zd6VXgG0fi5AD6F3NI9AG9D1z8Mi41q0cdDJ3y9EMwuBFTXkGlVoFw 5WtfvYNza917pwOu//+W8pFb1QQnTOIkLqgaSbLlR9Taa4G81FBZMsxvt00e7r3a3xov aX2oo+HXxryA1M6rE22HGdjvWjQc8CB+fU61VCGHvaWwDhQuiyXyJeNS6uS5NpT3W48b 4XwVccYDygdkCjhVjeowkRhnFKLseybeE0UyGS5GmL4pf1elfis4+JlxTZNA+cS959nG a0rA== X-Gm-Message-State: AOJu0Yz3pzukRbv3al1oabR5wKChPlo2/wdXpkOWKzgToeA/4cX5l0qi u/Rz7AQXQRIcuKk1fy6T1m6Zc81LiGj1WkWcZXjzK4vK/lBN9plnZa/qHA== X-Google-Smtp-Source: AGHT+IHEwy7JA66kCaCn/pcrjmljt48cThDfOR7pITkFzNIO1t3zPvAO+inFjFGxn51qfGvqpAMtug== X-Received: by 2002:a2e:9d96:0:b0:2f0:19f5:9d99 with SMTP id 38308e7fff4ca-2f03db8e466mr15193031fa.23.1721916014919; Thu, 25 Jul 2024 07:00:14 -0700 (PDT) Received: from localhost.localdomain ([2001:4643:d087:0:bd05:8094:92b2:c0a]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-2f03cf0e36csm2027211fa.17.2024.07.25.07.00.12 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jul 2024 07:00:12 -0700 (PDT) From: Frode Nordahl To: dev@openvswitch.org Date: Thu, 25 Jul 2024 16:00:04 +0200 Message-ID: <20240725140009.413791-2-fnordahl@ubuntu.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240725140009.413791-1-fnordahl@ubuntu.com> References: <20240719020943.380924-1-fnordahl@ubuntu.com> <20240725140009.413791-1-fnordahl@ubuntu.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v3 2/7] controller: Move LB by dp helpers to lb module. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" In a subsequent patch we need these functions in the route-exchange module. Signed-off-by: Frode Nordahl --- controller/lb.c | 119 +++++++++++++++++++++++++++++++++ controller/lb.h | 19 ++++++ controller/ovn-controller.c | 128 ------------------------------------ 3 files changed, 138 insertions(+), 128 deletions(-) diff --git a/controller/lb.c b/controller/lb.c index 8f9f20ed5..8dd748d64 100644 --- a/controller/lb.c +++ b/controller/lb.c @@ -23,6 +23,7 @@ /* OVN includes */ #include "lb.h" #include "lib/ovn-sb-idl.h" +#include "local_data.h" #include "ovn/lex.h" VLOG_DEFINE_THIS_MODULE(controller_lb); @@ -144,3 +145,121 @@ ovn_controller_lb_find(const struct hmap *ovn_controller_lbs, return NULL; } +static struct load_balancers_by_dp * +load_balancers_by_dp_create(struct hmap *lbs, + const struct sbrec_datapath_binding *dp) +{ + struct load_balancers_by_dp *lbs_by_dp = xzalloc(sizeof *lbs_by_dp); + + lbs_by_dp->dp = dp; + hmap_insert(lbs, &lbs_by_dp->node, hash_uint64(dp->tunnel_key)); + return lbs_by_dp; +} + +static void +load_balancers_by_dp_destroy(struct load_balancers_by_dp *lbs_by_dp) +{ + if (!lbs_by_dp) { + return; + } + + free(lbs_by_dp->dp_lbs); + free(lbs_by_dp); +} + +struct load_balancers_by_dp * +load_balancers_by_dp_find(struct hmap *lbs, + const struct sbrec_datapath_binding *dp) +{ + uint32_t hash = hash_uint64(dp->tunnel_key); + struct load_balancers_by_dp *lbs_by_dp; + + HMAP_FOR_EACH_WITH_HASH (lbs_by_dp, node, hash, lbs) { + if (lbs_by_dp->dp == dp) { + return lbs_by_dp; + } + } + return NULL; +} + +static void +load_balancers_by_dp_add_one(const struct hmap *local_datapaths, + const struct sbrec_datapath_binding *datapath, + const struct sbrec_load_balancer *lb, + struct hmap *lbs) +{ + struct local_datapath *ldp = + get_local_datapath(local_datapaths, datapath->tunnel_key); + + if (!ldp) { + return; + } + + struct load_balancers_by_dp *lbs_by_dp = + load_balancers_by_dp_find(lbs, ldp->datapath); + if (!lbs_by_dp) { + lbs_by_dp = load_balancers_by_dp_create(lbs, ldp->datapath); + } + + if (lbs_by_dp->n_dp_lbs == lbs_by_dp->n_allocated_dp_lbs) { + lbs_by_dp->dp_lbs = x2nrealloc(lbs_by_dp->dp_lbs, + &lbs_by_dp->n_allocated_dp_lbs, + sizeof *lbs_by_dp->dp_lbs); + } + lbs_by_dp->dp_lbs[lbs_by_dp->n_dp_lbs++] = lb; +} + +/* Builds and returns a hmap of 'load_balancers_by_dp', one record for each + * local datapath. + */ +struct hmap * +load_balancers_by_dp_init(const struct hmap *local_datapaths, + const struct sbrec_load_balancer_table *lb_table) +{ + struct hmap *lbs = xmalloc(sizeof *lbs); + hmap_init(lbs); + + const struct sbrec_load_balancer *lb; + SBREC_LOAD_BALANCER_TABLE_FOR_EACH (lb, lb_table) { + for (size_t i = 0; i < lb->n_datapaths; i++) { + load_balancers_by_dp_add_one(local_datapaths, + lb->datapaths[i], lb, lbs); + } + /* datapath_group column is deprecated. */ + for (size_t i = 0; lb->datapath_group + && i < lb->datapath_group->n_datapaths; i++) { + load_balancers_by_dp_add_one(local_datapaths, + lb->datapath_group->datapaths[i], + lb, lbs); + } + for (size_t i = 0; lb->ls_datapath_group + && i < lb->ls_datapath_group->n_datapaths; i++) { + load_balancers_by_dp_add_one(local_datapaths, + lb->ls_datapath_group->datapaths[i], + lb, lbs); + } + for (size_t i = 0; lb->lr_datapath_group + && i < lb->lr_datapath_group->n_datapaths; i++) { + load_balancers_by_dp_add_one(local_datapaths, + lb->lr_datapath_group->datapaths[i], + lb, lbs); + } + } + return lbs; +} + +void +load_balancers_by_dp_cleanup(struct hmap *lbs) +{ + if (!lbs) { + return; + } + + struct load_balancers_by_dp *lbs_by_dp; + + HMAP_FOR_EACH_POP (lbs_by_dp, node, lbs) { + load_balancers_by_dp_destroy(lbs_by_dp); + } + hmap_destroy(lbs); + free(lbs); +} diff --git a/controller/lb.h b/controller/lb.h index 84d51c332..86e6e611b 100644 --- a/controller/lb.h +++ b/controller/lb.h @@ -20,6 +20,7 @@ #include "lib/lb.h" struct sbrec_load_balancer; +struct sbrec_load_balancer_table; struct ovn_controller_lb { struct hmap_node hmap_node; @@ -41,6 +42,15 @@ struct ovn_controller_lb { */ }; +/* Stores the load balancers that are applied to the datapath 'dp'. */ +struct load_balancers_by_dp { + struct hmap_node node; + const struct sbrec_datapath_binding *dp; + const struct sbrec_load_balancer **dp_lbs; + size_t n_allocated_dp_lbs; + size_t n_dp_lbs; +}; + struct ovn_controller_lb *ovn_controller_lb_create( const struct sbrec_load_balancer *, const struct smap *template_vars, @@ -51,5 +61,14 @@ struct ovn_controller_lb *ovn_controller_lb_find( const struct hmap *ovn_controller_lbs, const struct uuid *uuid); +struct hmap *load_balancers_by_dp_init( + const struct hmap *local_datapaths, + const struct sbrec_load_balancer_table *lb_table); +struct load_balancers_by_dp *load_balancers_by_dp_find( + struct hmap *lbs, + const struct sbrec_datapath_binding *dp); +void load_balancers_by_dp_cleanup(struct hmap *lbs); + + #endif /* OVN_CONTROLLER_LB_H */ diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 4e30302ea..805d29c81 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -2357,134 +2357,6 @@ en_mff_ovn_geneve_run(struct engine_node *node, void *data) engine_set_node_state(node, EN_UNCHANGED); } -/* Stores the load balancers that are applied to the datapath 'dp'. */ -struct load_balancers_by_dp { - struct hmap_node node; - const struct sbrec_datapath_binding *dp; - const struct sbrec_load_balancer **dp_lbs; - size_t n_allocated_dp_lbs; - size_t n_dp_lbs; -}; - -static struct load_balancers_by_dp * -load_balancers_by_dp_create(struct hmap *lbs, - const struct sbrec_datapath_binding *dp) -{ - struct load_balancers_by_dp *lbs_by_dp = xzalloc(sizeof *lbs_by_dp); - - lbs_by_dp->dp = dp; - hmap_insert(lbs, &lbs_by_dp->node, hash_uint64(dp->tunnel_key)); - return lbs_by_dp; -} - -static void -load_balancers_by_dp_destroy(struct load_balancers_by_dp *lbs_by_dp) -{ - if (!lbs_by_dp) { - return; - } - - free(lbs_by_dp->dp_lbs); - free(lbs_by_dp); -} - -static struct load_balancers_by_dp * -load_balancers_by_dp_find(struct hmap *lbs, - const struct sbrec_datapath_binding *dp) -{ - uint32_t hash = hash_uint64(dp->tunnel_key); - struct load_balancers_by_dp *lbs_by_dp; - - HMAP_FOR_EACH_WITH_HASH (lbs_by_dp, node, hash, lbs) { - if (lbs_by_dp->dp == dp) { - return lbs_by_dp; - } - } - return NULL; -} - -static void -load_balancers_by_dp_add_one(const struct hmap *local_datapaths, - const struct sbrec_datapath_binding *datapath, - const struct sbrec_load_balancer *lb, - struct hmap *lbs) -{ - struct local_datapath *ldp = - get_local_datapath(local_datapaths, datapath->tunnel_key); - - if (!ldp) { - return; - } - - struct load_balancers_by_dp *lbs_by_dp = - load_balancers_by_dp_find(lbs, ldp->datapath); - if (!lbs_by_dp) { - lbs_by_dp = load_balancers_by_dp_create(lbs, ldp->datapath); - } - - if (lbs_by_dp->n_dp_lbs == lbs_by_dp->n_allocated_dp_lbs) { - lbs_by_dp->dp_lbs = x2nrealloc(lbs_by_dp->dp_lbs, - &lbs_by_dp->n_allocated_dp_lbs, - sizeof *lbs_by_dp->dp_lbs); - } - lbs_by_dp->dp_lbs[lbs_by_dp->n_dp_lbs++] = lb; -} - -/* Builds and returns a hmap of 'load_balancers_by_dp', one record for each - * local datapath. - */ -static struct hmap * -load_balancers_by_dp_init(const struct hmap *local_datapaths, - const struct sbrec_load_balancer_table *lb_table) -{ - struct hmap *lbs = xmalloc(sizeof *lbs); - hmap_init(lbs); - - const struct sbrec_load_balancer *lb; - SBREC_LOAD_BALANCER_TABLE_FOR_EACH (lb, lb_table) { - for (size_t i = 0; i < lb->n_datapaths; i++) { - load_balancers_by_dp_add_one(local_datapaths, - lb->datapaths[i], lb, lbs); - } - /* datapath_group column is deprecated. */ - for (size_t i = 0; lb->datapath_group - && i < lb->datapath_group->n_datapaths; i++) { - load_balancers_by_dp_add_one(local_datapaths, - lb->datapath_group->datapaths[i], - lb, lbs); - } - for (size_t i = 0; lb->ls_datapath_group - && i < lb->ls_datapath_group->n_datapaths; i++) { - load_balancers_by_dp_add_one(local_datapaths, - lb->ls_datapath_group->datapaths[i], - lb, lbs); - } - for (size_t i = 0; lb->lr_datapath_group - && i < lb->lr_datapath_group->n_datapaths; i++) { - load_balancers_by_dp_add_one(local_datapaths, - lb->lr_datapath_group->datapaths[i], - lb, lbs); - } - } - return lbs; -} - -static void -load_balancers_by_dp_cleanup(struct hmap *lbs) -{ - if (!lbs) { - return; - } - - struct load_balancers_by_dp *lbs_by_dp; - - HMAP_FOR_EACH_POP (lbs_by_dp, node, lbs) { - load_balancers_by_dp_destroy(lbs_by_dp); - } - hmap_destroy(lbs); - free(lbs); -} - /* Engine node which is used to handle runtime related data to * load balancers. */ struct ed_type_lb_data { From patchwork Thu Jul 25 14:00:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1964786 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::137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) (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 4WVCFr2n42z1yXx for ; Fri, 26 Jul 2024 00:00:32 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 3CBAB409A1; Thu, 25 Jul 2024 14:00:26 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id saVtC4Itt3zJ; Thu, 25 Jul 2024 14:00:25 +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 smtp4.osuosl.org B83CC40986 Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp4.osuosl.org (Postfix) with ESMTPS id B83CC40986; Thu, 25 Jul 2024 14:00:24 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 6AD1CC002B; Thu, 25 Jul 2024 14:00:24 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id C976FC002A for ; Thu, 25 Jul 2024 14:00:20 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id A1F7460A9D for ; Thu, 25 Jul 2024 14:00:20 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id 2VKccDnsiWTO for ; Thu, 25 Jul 2024 14:00:20 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=209.85.208.173; helo=mail-lj1-f173.google.com; envelope-from=frode.nordahl@gmail.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp3.osuosl.org 70B6160A94 Authentication-Results: smtp3.osuosl.org; dmarc=fail (p=none dis=none) header.from=ubuntu.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 70B6160A94 Received: from mail-lj1-f173.google.com (mail-lj1-f173.google.com [209.85.208.173]) by smtp3.osuosl.org (Postfix) with ESMTPS id 70B6160A94 for ; Thu, 25 Jul 2024 14:00:19 +0000 (UTC) Received: by mail-lj1-f173.google.com with SMTP id 38308e7fff4ca-2f040733086so2680511fa.1 for ; Thu, 25 Jul 2024 07:00:19 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721916016; x=1722520816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=EZjg2tE7g4Aq6L8zX3ki8/Ed4a0ShbPbiSjwbX48gCY=; b=ho5IROYncjcoDAklLsrZEs9cuzPZameC3f36AVPdoGU5q+IHk6pUSjFbrAZyYW2MAP aSNOgfUyTNeXWIubr5w/EDapBi5+vyoRIqsN3Dw3NHJp7bP4CouChuQ26zJJ3Q+9Ydqc l1NDjbyc7iu00dXPGlcjEBnFpsB7nDSGBTxAX6jH98sT/qxLlguenM3h5maSzV+rnCWL ML/m03MUx0ZDJiGPO1AymALK8f2cXx69QB8hyOVEbbJk9GRjodrrO1eMjK4GLB8i0IR1 zMV8hwBXWW/jnJylqGQD3G0bEc2tiZ2D/MYbbjHwDOmK+9pSZkhpZ/IvF7UgOKBcvkQ1 a6DQ== X-Gm-Message-State: AOJu0YypWUOFVOIunUXgWSpFJntMwWCPYsXDAmW6Bv7ICVvc6Cqx7B1Q /wLXbykslO1VovyWwnKTZxjyqElcepjU4ESr+J30Cd9/7hFSGVzNkAVq6Q== X-Google-Smtp-Source: AGHT+IEmE3/gmx1Bytwrx+kTCjw1VLiI10YAhBIygmuqWMmr63/9N2+UgWxPpKPU1t8jmznoqPmTNA== X-Received: by 2002:a2e:bc15:0:b0:2ef:2b38:879c with SMTP id 38308e7fff4ca-2f039c4e94fmr27073731fa.3.1721916016409; Thu, 25 Jul 2024 07:00:16 -0700 (PDT) Received: from localhost.localdomain ([2001:4643:d087:0:bd05:8094:92b2:c0a]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-2f03cf0e36csm2027211fa.17.2024.07.25.07.00.15 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jul 2024 07:00:15 -0700 (PDT) From: Frode Nordahl To: dev@openvswitch.org Date: Thu, 25 Jul 2024 16:00:05 +0200 Message-ID: <20240725140009.413791-3-fnordahl@ubuntu.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240725140009.413791-1-fnordahl@ubuntu.com> References: <20240719020943.380924-1-fnordahl@ubuntu.com> <20240725140009.413791-1-fnordahl@ubuntu.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v3 3/7] ci: Manage host/system level dependencies. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Most dependencies are managed in the `prepare-container` job, but there are some host/system level dependencies. This will be used by a subsequent patch that adds system tests that require the `vrf` kernel module to be loaded. Signed-off-by: Frode Nordahl --- .github/workflows/test.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0342c3dcf..5f8f122fa 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -107,6 +107,11 @@ jobs: - { arch: x86, compiler: gcc, opts: --disable-ssl } steps: + - name: system-level-dependencies + run: | + sudo apt update + sudo apt -y install linux-modules-extra-$(uname -r) + - name: checkout if: github.event_name == 'push' || github.event_name == 'pull_request' uses: actions/checkout@v4 From patchwork Thu Jul 25 14:00:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1964787 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::137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) (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 4WVCFv6Wgwz1yXx for ; Fri, 26 Jul 2024 00:00:35 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 28A2F409A5; Thu, 25 Jul 2024 14:00:34 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id LwLyLI-Tkrdb; Thu, 25 Jul 2024 14:00:28 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=2605:bc80:3010:104::8cd3:938; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 32BA0409AD Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp4.osuosl.org (Postfix) with ESMTPS id 32BA0409AD; Thu, 25 Jul 2024 14:00:28 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id E0038C0035; Thu, 25 Jul 2024 14:00:27 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 3568DC003D for ; Thu, 25 Jul 2024 14:00:25 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id F2D538127D for ; Thu, 25 Jul 2024 14:00:24 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id yiQ8roiu66vk for ; Thu, 25 Jul 2024 14:00:21 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=209.85.208.172; helo=mail-lj1-f172.google.com; envelope-from=frode.nordahl@gmail.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp1.osuosl.org 40C7B80AB4 Authentication-Results: smtp1.osuosl.org; dmarc=fail (p=none dis=none) header.from=ubuntu.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 40C7B80AB4 Received: from mail-lj1-f172.google.com (mail-lj1-f172.google.com [209.85.208.172]) by smtp1.osuosl.org (Postfix) with ESMTPS id 40C7B80AB4 for ; Thu, 25 Jul 2024 14:00:21 +0000 (UTC) Received: by mail-lj1-f172.google.com with SMTP id 38308e7fff4ca-2f01e9f53ebso2262811fa.2 for ; Thu, 25 Jul 2024 07:00:21 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721916019; x=1722520819; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=GUZE7S53PDi+xF+DYvAQiydIIRdSNbID/p+27CgzHHo=; b=Rkw+fUPBK+KiUBh2E/VlqKTQrHLY2CG8OY9yehKOTiRJPoqSTFeyywsl7b9JP6iOIV 5i4APXNTSt8bqJjxESu0q1QHEh4efgRv3Ra6JzZ0ppbScJ2l95jFGwWD1p/8jIW1ayX9 AYbgrid+P2CIb27YN78QhsnddAAduB8rnwEpagsaY2qEQvsTS8pf8nnuexMfIshNiDY2 Y4rre/xzggzSmxjHU1p1narVFfHhXJOyFRbOKt1/jbZfD7NKYdnIGLqTjD21iezADmY4 oc6qK6CL5Q9TpQ6vOaDVU0dfoFbc+NYi8s7yw0upD36LHLZWXH+iRllZEEP1vQdwucTB VNfA== X-Gm-Message-State: AOJu0YxOFp4Rmy9VxIktw47tIx7eAtl8IfA8CF6wXPrfWRDg/VWLeQSj z8DFeFRdFIctowycEhTYXyP6f6vOY+2OhKdBpNyHuNDeug2x/5oBmdRZmA== X-Google-Smtp-Source: AGHT+IH9hGQW0/xOsgsNyIKnZp0ZpRN67x/SbNiVeeAKkeyNFhmW/LCUJ4J2CSpWbqCeMCeYJn8V0Q== X-Received: by 2002:a05:651c:1987:b0:2ef:2ef5:ae98 with SMTP id 38308e7fff4ca-2f039dba26dmr23340911fa.34.1721916017799; Thu, 25 Jul 2024 07:00:17 -0700 (PDT) Received: from localhost.localdomain ([2001:4643:d087:0:bd05:8094:92b2:c0a]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-2f03cf0e36csm2027211fa.17.2024.07.25.07.00.16 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jul 2024 07:00:16 -0700 (PDT) From: Frode Nordahl To: dev@openvswitch.org Date: Thu, 25 Jul 2024 16:00:06 +0200 Message-ID: <20240725140009.413791-4-fnordahl@ubuntu.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240725140009.413791-1-fnordahl@ubuntu.com> References: <20240719020943.380924-1-fnordahl@ubuntu.com> <20240725140009.413791-1-fnordahl@ubuntu.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v3 4/7] controller: Introduce route-exchange-netlink. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Introduce route-exchange-netlink module which implements interface for maintaining VRFs [0] and host routes through Netlink. We want to export host routes to resources such as NAT addresses and LB VIPs to routing protocol suite software running on the same system, which subject to configuration can redistribute routes to external sytems such as one or more Top-of-Rack (ToR) switches. There is a desire to do this without having to (re-)implement routing protocol state machines in OVN, and to accomplish this we make use of Netlink. Netlink was chosen because: * Its ubiquitous nature with availability on any Linux system as as well other platforms. * Presence of a very good Netlink library implementation in our sibling project and library, Open vSwitch. * Popular routing protocol software conveniently already have support for redistributing routes to/from Netlink. * Support for interacting with Virtual Routing and Forwarding domains [0], allowing full isolation between virtual network resources defined within OVN and the hosting system while retaining access to all system network interfaces. It is important to note that the purpose of this integration is generic exchange of control plane information, while allowing to keep the datapath in OVS/OVN, enabling users to leverage its full range of user-, kernel- and mixed- space datapath implementations. 0: https://docs.kernel.org/networking/vrf.html Signed-off-by: Frode Nordahl --- configure.ac | 2 + controller/automake.mk | 7 + controller/route-exchange-netlink-private.h | 243 ++++++++++++++++++ controller/route-exchange-netlink.c | 264 ++++++++++++++++++++ controller/route-exchange-netlink.h | 40 +++ controller/test-route-exchange-netlink.c | 173 +++++++++++++ m4/ovn.m4 | 25 ++ tests/automake.mk | 13 +- tests/ovn-system-route-exchange.at | 16 ++ tests/system-common-macros.at | 12 + tests/system-kmod-testsuite.at | 1 + 11 files changed, 795 insertions(+), 1 deletion(-) create mode 100644 controller/route-exchange-netlink-private.h create mode 100644 controller/route-exchange-netlink.c create mode 100644 controller/route-exchange-netlink.h create mode 100644 controller/test-route-exchange-netlink.c create mode 100644 tests/ovn-system-route-exchange.at diff --git a/configure.ac b/configure.ac index 6a6b0db6a..6f0f485c4 100644 --- a/configure.ac +++ b/configure.ac @@ -87,6 +87,8 @@ OVS_CHECK_WIN32 OVS_CHECK_VISUAL_STUDIO_DDK OVN_CHECK_COVERAGE OVS_CHECK_NDEBUG +OVS_CHECK_NETLINK +OVS_CHECK_LINUX_NETLINK OVS_CHECK_OPENSSL OVN_CHECK_LOGDIR OVN_CHECK_PYTHON3 diff --git a/controller/automake.mk b/controller/automake.mk index ed93cfb3c..006e884dc 100644 --- a/controller/automake.mk +++ b/controller/automake.mk @@ -51,6 +51,13 @@ controller_ovn_controller_SOURCES = \ controller/ct-zone.h \ controller/ct-zone.c +if HAVE_NETLINK +controller_ovn_controller_SOURCES += \ + controller/route-exchange-netlink.h \ + controller/route-exchange-netlink-private.h \ + controller/route-exchange-netlink.c +endif + controller_ovn_controller_LDADD = lib/libovn.la $(OVS_LIBDIR)/libopenvswitch.la man_MANS += controller/ovn-controller.8 EXTRA_DIST += controller/ovn-controller.8.xml diff --git a/controller/route-exchange-netlink-private.h b/controller/route-exchange-netlink-private.h new file mode 100644 index 000000000..4c2559895 --- /dev/null +++ b/controller/route-exchange-netlink-private.h @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2024 Canonical, Ltd. + * Copyright (c) 2011, 2012, 2013, 2014, 2017 Nicira, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ROUTE_EXCHANGE_NETLINK_PRIVATE_H +#define ROUTE_EXCHANGE_NETLINK_PRIVATE_H 1 + +/* + * NOTE(fnordahl): The below code is stolen directly from OVS lib/route-table.c + * with the addition of inlining of function definitions for practical reasons + * and modifications: + * + * struct route_data: + * + * - Add rta_table_id. + * + * route_table_parse(): + * + * - Consider non-standard routing tables and store the table_id. + * + * route_table_dump_one_table(): + * + * - Use uint32_t for table id and pass it to kernel using thee RTA_TABLE + * attribute to allow use of table IDs greater than 256. + * - Use callback with argument instead of hard coded call to static function + * route_table_handle_msg(). + * + * Ideally we would upstream those changes along with export of interesting + * data structures and functions to OVS, but in the interest of time we vendor + * the code here for now. + * + * BEGIN VENDORED CODE FROM OVS lib/route-table.c + */ +struct route_data { + /* Copied from struct rtmsg. */ + unsigned char rtm_dst_len; + bool local; + + /* Extracted from Netlink attributes. */ + struct in6_addr rta_dst; /* 0 if missing. */ + struct in6_addr rta_prefsrc; /* 0 if missing. */ + struct in6_addr rta_gw; + char ifname[IFNAMSIZ]; /* Interface name. */ + uint32_t mark; + uint32_t rta_table_id; /* 0 if missing. */ +}; + +/* A digested version of a route message sent down by the kernel to indicate + * that a route has changed. */ +struct route_table_msg { + bool relevant; /* Should this message be processed? */ + int nlmsg_type; /* e.g. RTM_NEWROUTE, RTM_DELROUTE. */ + struct route_data rd; /* Data parsed from this message. */ +}; + +/* Return RTNLGRP_IPV4_ROUTE or RTNLGRP_IPV6_ROUTE on success, 0 on parse + * error. */ +static inline int +route_table_parse(struct ofpbuf *buf, struct route_table_msg *change) +{ + bool parsed, ipv4 = false; + + static const struct nl_policy policy[] = { + [RTA_DST] = { .type = NL_A_U32, .optional = true }, + [RTA_OIF] = { .type = NL_A_U32, .optional = true }, + [RTA_GATEWAY] = { .type = NL_A_U32, .optional = true }, + [RTA_MARK] = { .type = NL_A_U32, .optional = true }, + [RTA_PREFSRC] = { .type = NL_A_U32, .optional = true }, + [RTA_TABLE] = { .type = NL_A_U32, .optional = true }, + }; + + static const struct nl_policy policy6[] = { + [RTA_DST] = { .type = NL_A_IPV6, .optional = true }, + [RTA_OIF] = { .type = NL_A_U32, .optional = true }, + [RTA_MARK] = { .type = NL_A_U32, .optional = true }, + [RTA_GATEWAY] = { .type = NL_A_IPV6, .optional = true }, + [RTA_PREFSRC] = { .type = NL_A_IPV6, .optional = true }, + [RTA_TABLE] = { .type = NL_A_U32, .optional = true }, + }; + + struct nlattr *attrs[ARRAY_SIZE(policy)]; + const struct rtmsg *rtm; + + rtm = ofpbuf_at(buf, NLMSG_HDRLEN, sizeof *rtm); + + if (rtm->rtm_family == AF_INET) { + parsed = nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct rtmsg), + policy, attrs, ARRAY_SIZE(policy)); + ipv4 = true; + } else if (rtm->rtm_family == AF_INET6) { + parsed = nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct rtmsg), + policy6, attrs, ARRAY_SIZE(policy6)); + } else { + VLOG_DBG_RL(&rl, "received non AF_INET rtnetlink route message"); + return 0; + } + + if (parsed) { + const struct nlmsghdr *nlmsg; + uint32_t table_id; + int rta_oif; /* Output interface index. */ + + nlmsg = buf->data; + + memset(change, 0, sizeof *change); + change->relevant = true; + + if (rtm->rtm_scope == RT_SCOPE_NOWHERE) { + change->relevant = false; + } + + if (rtm->rtm_type != RTN_UNICAST && + rtm->rtm_type != RTN_LOCAL) { + change->relevant = false; + } + + table_id = rtm->rtm_table; + if (attrs[RTA_TABLE]) { + table_id = nl_attr_get_u32(attrs[RTA_TABLE]); + change->rd.rta_table_id = table_id; + } + + change->nlmsg_type = nlmsg->nlmsg_type; + change->rd.rtm_dst_len = rtm->rtm_dst_len + (ipv4 ? 96 : 0); + change->rd.local = rtm->rtm_type == RTN_LOCAL; + if (attrs[RTA_OIF]) { + rta_oif = nl_attr_get_u32(attrs[RTA_OIF]); + + if (!if_indextoname(rta_oif, change->rd.ifname)) { + int error = errno; + + VLOG_DBG_RL(&rl, "Could not find interface name[%u]: %s", + rta_oif, ovs_strerror(error)); + if (error == ENXIO) { + change->relevant = false; + } else { + return 0; + } + } + } + + if (attrs[RTA_DST]) { + if (ipv4) { + ovs_be32 dst; + dst = nl_attr_get_be32(attrs[RTA_DST]); + in6_addr_set_mapped_ipv4(&change->rd.rta_dst, dst); + } else { + change->rd.rta_dst = nl_attr_get_in6_addr(attrs[RTA_DST]); + } + } else if (ipv4) { + in6_addr_set_mapped_ipv4(&change->rd.rta_dst, 0); + } + if (attrs[RTA_PREFSRC]) { + if (ipv4) { + ovs_be32 prefsrc; + prefsrc = nl_attr_get_be32(attrs[RTA_PREFSRC]); + in6_addr_set_mapped_ipv4(&change->rd.rta_prefsrc, prefsrc); + } else { + change->rd.rta_prefsrc = + nl_attr_get_in6_addr(attrs[RTA_PREFSRC]); + } + } + if (attrs[RTA_GATEWAY]) { + if (ipv4) { + ovs_be32 gw; + gw = nl_attr_get_be32(attrs[RTA_GATEWAY]); + in6_addr_set_mapped_ipv4(&change->rd.rta_gw, gw); + } else { + change->rd.rta_gw = nl_attr_get_in6_addr(attrs[RTA_GATEWAY]); + } + } + if (attrs[RTA_MARK]) { + change->rd.mark = nl_attr_get_u32(attrs[RTA_MARK]); + } + } else { + VLOG_DBG_RL(&rl, "received unparseable rtnetlink route message"); + return 0; + } + + /* Success. */ + return ipv4 ? RTNLGRP_IPV4_ROUTE : RTNLGRP_IPV6_ROUTE; +} + +static inline bool +route_table_dump_one_table( + uint32_t id, + void (*handle_msg)(struct route_table_msg *, void *), + void *data) +{ + uint64_t reply_stub[NL_DUMP_BUFSIZE / 8]; + struct ofpbuf request, reply, buf; + struct rtmsg *rq_msg; + bool filtered = true; + struct nl_dump dump; + + ofpbuf_init(&request, 0); + + nl_msg_put_nlmsghdr(&request, 0, RTM_GETROUTE, NLM_F_REQUEST); + + rq_msg = ofpbuf_put_zeros(&request, sizeof *rq_msg); + rq_msg->rtm_family = AF_UNSPEC; + rq_msg->rtm_table = RT_TABLE_UNSPEC; + + nl_msg_put_u32(&request, RTA_TABLE, id); + + nl_dump_start(&dump, NETLINK_ROUTE, &request); + ofpbuf_uninit(&request); + + ofpbuf_use_stub(&buf, reply_stub, sizeof reply_stub); + while (nl_dump_next(&dump, &reply, &buf)) { + struct route_table_msg msg; + + if (route_table_parse(&reply, &msg)) { + struct nlmsghdr *nlmsghdr = nl_msg_nlmsghdr(&reply); + + /* Older kernels do not support filtering. */ + if (!(nlmsghdr->nlmsg_flags & NLM_F_DUMP_FILTERED)) { + filtered = false; + } + (*handle_msg)(&msg, data); + } + } + ofpbuf_uninit(&buf); + nl_dump_done(&dump); + + return filtered; +} +/* END VENDORED CODE */ + +#endif /* route-exchange-netlink-private.h */ diff --git a/controller/route-exchange-netlink.c b/controller/route-exchange-netlink.c new file mode 100644 index 000000000..707676f33 --- /dev/null +++ b/controller/route-exchange-netlink.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2024 Canonical, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include + +#include "netlink-socket.h" +#include "netlink.h" +#include "openvswitch/hmap.h" +#include "openvswitch/ofpbuf.h" +#include "openvswitch/vlog.h" +#include "packets.h" + +#include "route-exchange-netlink.h" + +VLOG_DEFINE_THIS_MODULE(route_exchange_netlink); +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); + +/* Due to inlining of vendored code from OVS lib/route-table.c, we need to + * include this after the above VLOG statements. */ +#include "route-exchange-netlink-private.h" + +#define TABLE_ID_VALID(table_id) (table_id != RT_TABLE_UNSPEC && \ + table_id != RT_TABLE_COMPAT && \ + table_id != RT_TABLE_DEFAULT && \ + table_id != RT_TABLE_MAIN && \ + table_id != RT_TABLE_LOCAL && \ + table_id != RT_TABLE_MAX) + +static int +modify_vrf(uint32_t type, uint32_t flags_arg, + const char *ifname, uint32_t table_id) +{ + uint32_t flags = NLM_F_REQUEST | NLM_F_ACK; + size_t linkinfo_off, infodata_off; + struct ifinfomsg *ifinfo; + struct ofpbuf request; + int err; + + flags |= flags_arg; + + ofpbuf_init(&request, 0); + nl_msg_put_nlmsghdr(&request, 0, type, flags); + ifinfo = ofpbuf_put_zeros(&request, sizeof *ifinfo); + nl_msg_put_string(&request, IFLA_IFNAME, ifname); + if (type == RTM_DELLINK) { + goto out; + } + + ifinfo->ifi_change = ifinfo->ifi_flags = IFF_UP; + linkinfo_off = nl_msg_start_nested(&request, IFLA_LINKINFO); + nl_msg_put_string(&request, IFLA_INFO_KIND, "vrf"); + infodata_off = nl_msg_start_nested(&request, IFLA_INFO_DATA); + nl_msg_put_u32(&request, IFLA_VRF_TABLE, table_id); + nl_msg_end_nested(&request, infodata_off); + nl_msg_end_nested(&request, linkinfo_off); + +out: + err = nl_transact(NETLINK_ROUTE, &request, NULL); + + ofpbuf_uninit(&request); + + return err; +} + +int +re_nl_create_vrf(const char *ifname, uint32_t table_id) +{ + uint32_t flags = NLM_F_CREATE | NLM_F_EXCL; + uint32_t type = RTM_NEWLINK; + + if (!TABLE_ID_VALID(table_id)) { + VLOG_WARN_RL(&rl, + "attempt to create VRF using invalid table id %"PRIu32, + table_id); + return EINVAL; + } + + return modify_vrf(type, flags, ifname, table_id); +} + +int +re_nl_delete_vrf(const char *ifname) +{ + return modify_vrf(RTM_DELLINK, 0, ifname, 0); +} + +static int +modify_route(uint32_t type, uint32_t flags_arg, uint32_t table_id, + struct in6_addr *dst, uint32_t oif) +{ + uint32_t flags = NLM_F_REQUEST | NLM_F_ACK; + bool is_ipv4 = IN6_IS_ADDR_V4MAPPED(dst); + struct ofpbuf request; + struct rtmsg *rt; + int err; + + flags |= flags_arg; + + ofpbuf_init(&request, 0); + nl_msg_put_nlmsghdr(&request, 0, type, flags); + rt = ofpbuf_put_zeros(&request, sizeof *rt); + rt->rtm_family = is_ipv4 ? AF_INET : AF_INET6; + rt->rtm_table = RT_TABLE_UNSPEC; /* RTA_TABLE attribute allows id > 256 */ + if (type == RTM_DELROUTE) { + rt->rtm_scope = RT_SCOPE_NOWHERE; + } else { + rt->rtm_protocol = RTPROT_BOOT; + rt->rtm_scope = RT_SCOPE_UNIVERSE; + rt->rtm_type = RTN_UNICAST; + } + rt->rtm_dst_len = is_ipv4 ? 32 : 128; + + nl_msg_put_u32(&request, RTA_TABLE, table_id); + + if (is_ipv4) { + nl_msg_put_be32(&request, RTA_DST, in6_addr_get_mapped_ipv4(dst)); + } else { + nl_msg_put_in6_addr(&request, RTA_DST, dst); + } + + if (oif) { + nl_msg_put_u32(&request, RTA_OIF, oif); + } + + err = nl_transact(NETLINK_ROUTE, &request, NULL); + ofpbuf_uninit(&request); + + return err; +} + +int +re_nl_add_route(uint32_t table_id, struct in6_addr *dst, const char *ifname) +{ + uint32_t flags = NLM_F_CREATE | NLM_F_EXCL; + uint32_t type = RTM_NEWROUTE; + + if (!TABLE_ID_VALID(table_id)) { + VLOG_WARN_RL(&rl, + "attempt to add route using invalid table id %"PRIu32, + table_id); + return EINVAL; + } + + return modify_route(type, flags, table_id, dst, if_nametoindex(ifname)); +} + +int +re_nl_delete_route(uint32_t table_id, struct in6_addr *dst) +{ + if (!TABLE_ID_VALID(table_id)) { + VLOG_WARN_RL(&rl, + "attempt to delete route using invalid table id %"PRIu32, + table_id); + return EINVAL; + } + + return modify_route(RTM_DELROUTE, 0, table_id, dst, 0); +} + +struct host_route_node { + struct hmap_node hmap_node; + uint32_t table_id; + struct in6_addr addr; +}; + +static uint32_t +host_route_hash(const struct in6_addr *dst) +{ + return hash_bytes(dst->s6_addr, 16, 0); +} + +void +host_route_insert(struct hmap *host_routes, uint32_t table_id, + struct in6_addr *dst) +{ + struct host_route_node *hr = xzalloc(sizeof *hr); + hmap_insert(host_routes, &hr->hmap_node, host_route_hash(dst)); + hr->table_id = table_id; + hr->addr = *dst; +} + +void +host_routes_destroy(struct hmap *host_routes) +{ + struct host_route_node *hr; + HMAP_FOR_EACH_SAFE (hr, hmap_node, host_routes) { + hmap_remove(host_routes, &hr->hmap_node); + free(hr); + } + hmap_destroy(host_routes); +} + +static void +handle_route_msg_delete_host_routes(struct route_table_msg *msg, void *data) +{ + struct route_data *rd = &msg->rd; + struct hmap *host_routes = data; + struct host_route_node *hr; + int err; + + uint32_t hash = host_route_hash(&rd->rta_dst); + HMAP_FOR_EACH_WITH_HASH (hr, hmap_node, hash, host_routes) { + if (ipv6_addr_equals(&hr->addr, &rd->rta_dst)) { + hmap_remove(host_routes, &hr->hmap_node); + free(hr); + return; + } + } + err = re_nl_delete_route(rd->rta_table_id, &rd->rta_dst); + if (err) { + char addr_s[INET6_ADDRSTRLEN + 1]; + VLOG_WARN_RL(&rl, "Delete route table_id=%"PRIu32" dst=%s: %s", + rd->rta_table_id, + ipv6_string_mapped( + addr_s, &rd->rta_dst) ? addr_s : "(invalid)", + ovs_strerror(err)); + } +} + +void +re_nl_sync_routes(uint32_t table_id, const char *ifname, + struct hmap *host_routes) +{ + /* Remove routes from the system that are not in the host_routes hmap and + * remove entries from host_routes hmap that match routes already installed + * in the system. */ + route_table_dump_one_table(table_id, handle_route_msg_delete_host_routes, + host_routes); + + /* Add any remaining routes in the host_routes hmap to the system routing + * table. */ + struct host_route_node *hr; + HMAP_FOR_EACH_SAFE (hr, hmap_node, host_routes) { + int err = re_nl_add_route(table_id, &hr->addr, ifname); + if (err) { + char addr_s[INET6_ADDRSTRLEN + 1]; + VLOG_WARN_RL(&rl, "Add route table_id=%"PRIu32" dst=%s dev=%s: %s", + table_id, ifname, + ipv6_string_mapped( + addr_s, &hr->addr) ? addr_s : "(invalid)", + ovs_strerror(err)); + } + hmap_remove(host_routes, &hr->hmap_node); + free(hr); + } +} diff --git a/controller/route-exchange-netlink.h b/controller/route-exchange-netlink.h new file mode 100644 index 000000000..10a60a60e --- /dev/null +++ b/controller/route-exchange-netlink.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 Canonical + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ROUTE_EXCHANGE_NETLINK_H +#define ROUTE_EXCHANGE_NETLINK_H 1 + +#include + +struct in6_addr; +struct hmap; + +int re_nl_create_vrf(const char *ifname, uint32_t table_id); +int re_nl_delete_vrf(const char *ifname); + +int re_nl_add_route(uint32_t table_id, struct in6_addr *dst, + const char *ifname); +int re_nl_delete_route(uint32_t table_id, struct in6_addr *dst); + +void re_nl_dump(uint32_t table_id); + +void host_route_insert(struct hmap *host_routes, uint32_t table_id, + struct in6_addr *dst); +void host_routes_destroy(struct hmap *); +void re_nl_sync_routes(uint32_t table_id, const char *ifname, + struct hmap *host_routes); + +#endif /* route-exchange-netlink.h */ diff --git a/controller/test-route-exchange-netlink.c b/controller/test-route-exchange-netlink.c new file mode 100644 index 000000000..7097d5182 --- /dev/null +++ b/controller/test-route-exchange-netlink.c @@ -0,0 +1,173 @@ +/* Copyright (c) 2021, Canonical + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include "openvswitch/hmap.h" +#include "openvswitch/types.h" +#include "packets.h" +#include "route-exchange-netlink.h" +#include "tests/ovstest.h" + +#define VRF_IFNAME "ovnvrf42" +#define TABLE_ID 42 + +static void +test_re_nl_sync_routes(struct ovs_cmdl_context *ctx OVS_UNUSED) +{ + struct hmap host_routes = HMAP_INITIALIZER(&host_routes); + struct in6_addr dst4, dst6; + ovs_be32 ip; + int err; + + ipv6_parse("2001:db8:42::100", &dst6); + host_route_insert(&host_routes, TABLE_ID, &dst6); + + ip_parse("172.16.42.100", &ip); + in6_addr_set_mapped_ipv4(&dst4, ip); + host_route_insert(&host_routes, TABLE_ID, &dst4); + + err = re_nl_create_vrf(VRF_IFNAME, TABLE_ID); + ovs_assert(err == 0); + err = re_nl_create_vrf(VRF_IFNAME, TABLE_ID); + ovs_assert(err == EEXIST); + re_nl_sync_routes(TABLE_ID, VRF_IFNAME, &host_routes); + host_routes_destroy(&host_routes); + + err = re_nl_add_route(TABLE_ID, &dst6, VRF_IFNAME); + ovs_assert(err == EEXIST); + err = re_nl_add_route(TABLE_ID, &dst4, VRF_IFNAME); + ovs_assert(err == EEXIST); + + hmap_init(&host_routes); + re_nl_sync_routes(TABLE_ID, VRF_IFNAME, &host_routes); + host_routes_destroy(&host_routes); + + err = re_nl_add_route(TABLE_ID, &dst6, VRF_IFNAME); + ovs_assert(err == 0); + err = re_nl_add_route(TABLE_ID, &dst4, VRF_IFNAME); + ovs_assert(err == 0); + + err = re_nl_delete_vrf(VRF_IFNAME); + ovs_assert(err == 0); +} + +static void +test_re_nl_create_vrf(struct ovs_cmdl_context *ctx OVS_UNUSED) +{ + int err; + + err = re_nl_create_vrf(VRF_IFNAME, TABLE_ID); + ovs_assert(err == 0); + err = re_nl_create_vrf(VRF_IFNAME, TABLE_ID); + ovs_assert(err == EEXIST); + err = re_nl_delete_vrf(VRF_IFNAME); + ovs_assert(err == 0); +} + +static void +test_re_nl_delete_vrf(struct ovs_cmdl_context *ctx OVS_UNUSED) +{ + int err; + + err = re_nl_create_vrf(VRF_IFNAME, TABLE_ID); + ovs_assert(err == 0); + err = re_nl_delete_vrf(VRF_IFNAME); + ovs_assert(err == 0); + err = re_nl_delete_vrf(VRF_IFNAME); + ovs_assert(err == ENODEV); +} + +static void +test_re_nl_add_route(struct ovs_cmdl_context *ctx OVS_UNUSED) +{ + int err; + struct in6_addr dst4, dst6; + ovs_be32 ip; + + ipv6_parse("2001:db8:42::100", &dst6); + ip_parse("172.16.42.100", &ip); + in6_addr_set_mapped_ipv4(&dst4, ip); + + err = re_nl_create_vrf(VRF_IFNAME, TABLE_ID); + ovs_assert(err == 0); + + err = re_nl_add_route(TABLE_ID, &dst6, VRF_IFNAME); + ovs_assert(err == 0); + err = re_nl_add_route(TABLE_ID, &dst4, VRF_IFNAME); + ovs_assert(err == 0); + err = re_nl_add_route(TABLE_ID, &dst6, VRF_IFNAME); + ovs_assert(err == EEXIST); + err = re_nl_add_route(TABLE_ID, &dst4, VRF_IFNAME); + ovs_assert(err == EEXIST); + + err = re_nl_delete_vrf(VRF_IFNAME); + ovs_assert(err == 0); +} + +static void +test_re_nl_delete_route(struct ovs_cmdl_context *ctx OVS_UNUSED) +{ + int err; + struct in6_addr dst4, dst6; + ovs_be32 ip; + + ipv6_parse("2001:db8:42::100", &dst6); + ip_parse("172.16.42.100", &ip); + in6_addr_set_mapped_ipv4(&dst4, ip); + + err = re_nl_create_vrf(VRF_IFNAME, TABLE_ID); + ovs_assert(err == 0); + + err = re_nl_add_route(TABLE_ID, &dst6, VRF_IFNAME); + ovs_assert(err == 0); + err = re_nl_add_route(TABLE_ID, &dst4, VRF_IFNAME); + ovs_assert(err == 0); + + err = re_nl_delete_route(TABLE_ID, &dst6); + ovs_assert(err == 0); + err = re_nl_delete_route(TABLE_ID, &dst4); + ovs_assert(err == 0); + err = re_nl_delete_route(TABLE_ID, &dst6); + ovs_assert(err == ESRCH); + err = re_nl_delete_route(TABLE_ID, &dst4); + ovs_assert(err == ESRCH); + + err = re_nl_delete_vrf(VRF_IFNAME); + ovs_assert(err == 0); +} + +static void +test_route_exchange_netlink_main(int argc, char *argv[]) +{ + set_program_name(argv[0]); + static const struct ovs_cmdl_command commands[] = { + {"sync-routes", NULL, 0, 0, test_re_nl_sync_routes, OVS_RO}, + {"create-vrf", NULL, 0, 0, test_re_nl_create_vrf, OVS_RO}, + {"delete-vrf", NULL, 0, 0, test_re_nl_delete_vrf, OVS_RO}, + {"add-route", NULL, 0, 0, test_re_nl_add_route, OVS_RO}, + {"delete-route", NULL, 0, 0, test_re_nl_delete_route, OVS_RO}, + {NULL, NULL, 0, 0, NULL, OVS_RO}, + }; + struct ovs_cmdl_context ctx; + ctx.argc = argc - 1; + ctx.argv = argv + 1; + ovs_cmdl_run_command(&ctx, commands); +} + +OVSTEST_REGISTER("test-route-exchange-netlink", + test_route_exchange_netlink_main); diff --git a/m4/ovn.m4 b/m4/ovn.m4 index ebe4c9612..e8f30e0ac 100644 --- a/m4/ovn.m4 +++ b/m4/ovn.m4 @@ -576,3 +576,28 @@ AC_DEFUN([OVN_CHECK_UNBOUND], fi AM_CONDITIONAL([HAVE_UNBOUND], [test "$HAVE_UNBOUND" = yes]) AC_SUBST([HAVE_UNBOUND])]) + +dnl Checks for Netlink support. +AC_DEFUN([OVS_CHECK_NETLINK], + [AC_CHECK_HEADER([linux/netlink.h], + [HAVE_NETLINK=yes], + [HAVE_NETLINK=no], + [#include + ]) + AM_CONDITIONAL([HAVE_NETLINK], [test "$HAVE_NETLINK" = yes]) + if test "$HAVE_NETLINK" = yes; then + AC_DEFINE([HAVE_NETLINK], [1], + [Define to 1 if Netlink protocol is available.]) + fi]) + +dnl OVS_CHECK_LINUX_NETLINK +dnl +dnl Configure Linux netlink compat. +AC_DEFUN([OVS_CHECK_LINUX_NETLINK], [ + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([#include ], [ + struct nla_bitfield32 x = { 0 }; + ])], + [AC_DEFINE([HAVE_NLA_BITFIELD32], [1], + [Define to 1 if struct nla_bitfield32 is available.])]) +]) diff --git a/tests/automake.mk b/tests/automake.mk index 3899c9e80..0087bff69 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -55,7 +55,8 @@ SYSTEM_DPDK_TESTSUITE_AT = \ SYSTEM_KMOD_TESTSUITE_AT = \ tests/system-kmod-macros.at \ tests/system-kmod-testsuite.at \ - tests/system-ovn-kmod.at + tests/system-ovn-kmod.at \ + tests/ovn-system-route-exchange.at SYSTEM_USERSPACE_TESTSUITE_AT = \ tests/system-userspace-testsuite.at \ @@ -290,6 +291,11 @@ tests_ovstest_SOURCES = \ lib/test-ovn-features.c \ northd/test-ipam.c +if HAVE_NETLINK +tests_ovstest_SOURCES += \ + controller/test-route-exchange-netlink.c +endif + tests_ovstest_LDADD = $(OVS_LIBDIR)/daemon.lo \ $(OVS_LIBDIR)/libopenvswitch.la lib/libovn.la \ controller/binding.$(OBJEXT) \ @@ -307,6 +313,11 @@ tests_ovstest_LDADD = $(OVS_LIBDIR)/daemon.lo \ controller/vif-plug.$(OBJEXT) \ northd/ipam.$(OBJEXT) +if HAVE_NETLINK +tests_ovstest_LDADD += \ + controller/route-exchange-netlink.$(OBJEXT) +endif + # Python tests. CHECK_PYFILES = \ tests/test-l7.py \ diff --git a/tests/ovn-system-route-exchange.at b/tests/ovn-system-route-exchange.at new file mode 100644 index 000000000..36d7e3d2a --- /dev/null +++ b/tests/ovn-system-route-exchange.at @@ -0,0 +1,16 @@ +# +# System level unit tests for controller/route-exchange-netlink.c module. +# +AT_BANNER([OVN system level unit tests]) + +AT_SETUP([system level unit test -- route-exchange-netlink]) +AT_KEYWORDS([route-exchange]) + +CHECK_VRF() + +AT_CHECK([ovstest test-route-exchange-netlink sync-routes], [0], []) +AT_CHECK([ovstest test-route-exchange-netlink create-vrf], [0], []) +AT_CHECK([ovstest test-route-exchange-netlink delete-vrf], [0], []) +AT_CHECK([ovstest test-route-exchange-netlink add-route], [0], []) +AT_CHECK([ovstest test-route-exchange-netlink delete-route], [0], []) +AT_CLEANUP diff --git a/tests/system-common-macros.at b/tests/system-common-macros.at index 691c271a3..159396a40 100644 --- a/tests/system-common-macros.at +++ b/tests/system-common-macros.at @@ -519,3 +519,15 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/.*error receiving.*/d /failed to query port patch-.*/d /.*terminating with signal 15.*/d"]) ])) + +# CHECK_VRF() +# +# Perform a requirements check for running VRF tests. +# +m4_define([CHECK_VRF], +[ + rc=0 + modprobe vrf || rc=$? + AT_SKIP_IF([test $rc -ne 0]) + on_exit 'modprobe -r vrf' +]) diff --git a/tests/system-kmod-testsuite.at b/tests/system-kmod-testsuite.at index 5ba35babb..16b633ece 100644 --- a/tests/system-kmod-testsuite.at +++ b/tests/system-kmod-testsuite.at @@ -25,3 +25,4 @@ m4_include([tests/system-kmod-macros.at]) m4_include([tests/system-ovn.at]) m4_include([tests/system-ovn-kmod.at]) +m4_include([tests/ovn-system-route-exchange.at]) From patchwork Thu Jul 25 14:00:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1964785 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 4WVCFn3Ww3z1yXx for ; Fri, 26 Jul 2024 00:00:29 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id A184960AA2; Thu, 25 Jul 2024 14:00:27 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id xFWGHpYmcaG9; Thu, 25 Jul 2024 14:00:26 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=2605:bc80:3010:104::8cd3:938; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 5F9A460AAE Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTPS id 5F9A460AAE; Thu, 25 Jul 2024 14:00:26 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 38790C0033; Thu, 25 Jul 2024 14:00:26 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 16079C002A for ; Thu, 25 Jul 2024 14:00:24 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id DC43540986 for ; Thu, 25 Jul 2024 14:00:23 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id lTY7_HZeCq2p for ; Thu, 25 Jul 2024 14:00:23 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=209.85.208.180; helo=mail-lj1-f180.google.com; envelope-from=frode.nordahl@gmail.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp4.osuosl.org 6AB91406AA Authentication-Results: smtp4.osuosl.org; dmarc=fail (p=none dis=none) header.from=ubuntu.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 6AB91406AA Received: from mail-lj1-f180.google.com (mail-lj1-f180.google.com [209.85.208.180]) by smtp4.osuosl.org (Postfix) with ESMTPS id 6AB91406AA for ; Thu, 25 Jul 2024 14:00:21 +0000 (UTC) Received: by mail-lj1-f180.google.com with SMTP id 38308e7fff4ca-2ef2d582e31so2186711fa.2 for ; Thu, 25 Jul 2024 07:00:21 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721916019; x=1722520819; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=RkL0tAuLrKymK7/SSJ5hLv2wbDJrw/SCusjcY7krrsk=; b=tdfBz+gqI/apJ9wAsekk+eLFOPDhoekwdeFmP5rpqZAIWBxpWCHCTsWcyhSOHCMVvf FiIv93MRiJTA10B3keT50JbqCzmGuVEK+P1wH2VU4TnlyEaYJcZ3fXCVSlVKhLfIoBac MO/2KiwToknnBnqOfXYtk8o4cxh2PZ6Ci9A7R8+VPCKFKwzrDJpoV+1G5eHBZN7WYa87 3sDkjKkbYasr+K52FWeUSD6fqD6hA3ubCI8hcdwB8TvOsox2gi4cbw/IP8fY6Z0vQ0x+ NjN6UQsN3pgke2c7klia4XflnQmASgqo9CmqQ+VEDKL64XTLRC3SZp4QpBSAsG+EjnfX W6vA== X-Gm-Message-State: AOJu0Yx+AzTnePKXhQs6N6HG7OCJGm8trrMviwyuLK3coBn3UoZQtSYO 8CjxJ/TL78q/tSCFckMdUZCmRNmv2jmFbYJ6AA4q1Fq71q+7hImOo+YctA== X-Google-Smtp-Source: AGHT+IFq4KH3vCFabxaPvdkhp451+JwYkZsvGGIMGKOC4W8HUN2N1CpUPLADsI5Gehz4YBuqoBhGkg== X-Received: by 2002:a2e:868e:0:b0:2ef:2ed2:25b1 with SMTP id 38308e7fff4ca-2f03db909b0mr14589811fa.20.1721916018734; Thu, 25 Jul 2024 07:00:18 -0700 (PDT) Received: from localhost.localdomain ([2001:4643:d087:0:bd05:8094:92b2:c0a]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-2f03cf0e36csm2027211fa.17.2024.07.25.07.00.17 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jul 2024 07:00:18 -0700 (PDT) From: Frode Nordahl To: dev@openvswitch.org Date: Thu, 25 Jul 2024 16:00:07 +0200 Message-ID: <20240725140009.413791-5-fnordahl@ubuntu.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240725140009.413791-1-fnordahl@ubuntu.com> References: <20240719020943.380924-1-fnordahl@ubuntu.com> <20240725140009.413791-1-fnordahl@ubuntu.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v3 5/7] northd: Allow IPv6 in get_nat_addresses(). X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" While IPv6 and NAT does not ring particularly well together in my mind, it is a supported feature. We need this function to allow them in a subsequent patch adding host route exchange for NAT addresses. Signed-off-by: Frode Nordahl --- northd/northd.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/northd/northd.c b/northd/northd.c index 5b50ea191..d2d557f0b 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -1121,14 +1121,16 @@ destroy_routable_addresses(struct ovn_port_routable_addresses *ra) static char **get_nat_addresses(const struct ovn_port *op, size_t *n, bool routable_only, bool include_lb_ips, - const struct lr_stateful_record *); + const struct lr_stateful_record *, + bool allow_ipv6); static struct ovn_port_routable_addresses get_op_routable_addresses(struct ovn_port *op, const struct lr_stateful_record *lr_stateful_rec) { size_t n; - char **nats = get_nat_addresses(op, &n, true, true, lr_stateful_rec); + char **nats = get_nat_addresses(op, &n, true, true, lr_stateful_rec, + false); if (!nats) { return (struct ovn_port_routable_addresses) { @@ -2416,7 +2418,8 @@ join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table, static char ** get_nat_addresses(const struct ovn_port *op, size_t *n, bool routable_only, bool include_lb_ips, - const struct lr_stateful_record *lr_stateful_rec) + const struct lr_stateful_record *lr_stateful_rec, + bool allow_ipv6) { size_t n_nats = 0; struct eth_addr mac; @@ -2439,6 +2442,7 @@ get_nat_addresses(const struct ovn_port *op, size_t *n, bool routable_only, for (size_t i = 0; i < op->od->nbr->n_nat; i++) { const struct nbrec_nat *nat = op->od->nbr->nat[i]; ovs_be32 ip, mask; + struct in6_addr ip6, mask6; if (routable_only && (!strcmp(nat->type, "snat") || @@ -2449,7 +2453,15 @@ get_nat_addresses(const struct ovn_port *op, size_t *n, bool routable_only, char *error = ip_parse_masked(nat->external_ip, &ip, &mask); if (error || mask != OVS_BE32_MAX) { free(error); - continue; + if (allow_ipv6) { + error = ipv6_parse_masked(nat->external_ip, &ip6, &mask6); + if (error || ipv6_count_cidr_bits(&mask6) != 128) { + free(error); + continue; + } + } else { + continue; + } } /* Not including external IP of NAT rules whose gateway_port is @@ -3783,7 +3795,8 @@ sync_pb_for_lsp(struct ovn_port *op, lr_stateful_table, op->peer->od->index); } nats = get_nat_addresses(op->peer, &n_nats, false, - include_lb_vips, lr_stateful_rec); + include_lb_vips, lr_stateful_rec, + false); } } else if (nat_addresses && (chassis || l3dgw_ports)) { struct lport_addresses laddrs; From patchwork Thu Jul 25 14:00:08 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1964788 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::133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) (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 4WVCFw3jV5z1ydm for ; Fri, 26 Jul 2024 00:00:36 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 9467340F08; Thu, 25 Jul 2024 14:00:34 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id 1Qv1NgQjg6U7; Thu, 25 Jul 2024 14:00:32 +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 smtp2.osuosl.org 2295840EF4 Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTPS id 2295840EF4; Thu, 25 Jul 2024 14:00:31 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id AE86CC0035; Thu, 25 Jul 2024 14:00:30 +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 22D04C0078 for ; Thu, 25 Jul 2024 14:00:26 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 04C43812C9 for ; Thu, 25 Jul 2024 14:00:25 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id 8t0KYRFRwS0Z for ; Thu, 25 Jul 2024 14:00:23 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=209.85.208.181; helo=mail-lj1-f181.google.com; envelope-from=frode.nordahl@gmail.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp1.osuosl.org 32EE781006 Authentication-Results: smtp1.osuosl.org; dmarc=fail (p=none dis=none) header.from=ubuntu.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 32EE781006 Received: from mail-lj1-f181.google.com (mail-lj1-f181.google.com [209.85.208.181]) by smtp1.osuosl.org (Postfix) with ESMTPS id 32EE781006 for ; Thu, 25 Jul 2024 14:00:23 +0000 (UTC) Received: by mail-lj1-f181.google.com with SMTP id 38308e7fff4ca-2ef283c58f4so2043041fa.1 for ; Thu, 25 Jul 2024 07:00:22 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721916020; x=1722520820; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=W+d/D/dSefY9bwAtxyeBE/4E53YFzzF9KA87kSkYikM=; b=DoDXVDzIrggY2IMYEl4LgsDi2Dyf/N2TkwCSTc5KYOOFUNLC47NF/8ZSaNqU/6iMI5 H6uwyIGgKPWZQv7J0V9RCEIbav272AeWv+M9d0Juz0VgXC2KIPuenm4KiQaq/LAAFai2 xScuDKtjBJBuxdGQSsDHy7/FJRvTgqQ7QspNFRQB1/4n46LeEkrgysNcaeHzNe4Cp8TN 6wKYauxcKEkkmSa33kEA1nBWZvDAvT/fIWIlxOCgTwOHWdPRUPst/93pQDrX8dWSmWFP iOe/v/SeX0n0H4zkKfzyA3VR0ilIdesSH8K3hp5cqX8ASPoiq2NSEPDdQSm4cI2J08/n rc6g== X-Gm-Message-State: AOJu0YymhJEROx9vLWdA+em2W5OePJ2d1WGWRsqSAwyxbJCf+EjGiUOK rln8tz7pOGWYL0hioML3Aeb+b4O1wN9/R0Aj8PfFNqB5tDxQ3FmhpbeRIg== X-Google-Smtp-Source: AGHT+IFh74Qj2XUMEwORC0+LlQcWiOBj8CR9GoBnAuziukfYBsMl7ZhrkhkTdknRkI4cTA6x4GIN3w== X-Received: by 2002:a2e:8e88:0:b0:2ef:23ec:9357 with SMTP id 38308e7fff4ca-2f03dae8e6bmr14791231fa.0.1721916020306; Thu, 25 Jul 2024 07:00:20 -0700 (PDT) Received: from localhost.localdomain ([2001:4643:d087:0:bd05:8094:92b2:c0a]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-2f03cf0e36csm2027211fa.17.2024.07.25.07.00.18 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jul 2024 07:00:19 -0700 (PDT) From: Frode Nordahl To: dev@openvswitch.org Date: Thu, 25 Jul 2024 16:00:08 +0200 Message-ID: <20240725140009.413791-6-fnordahl@ubuntu.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240725140009.413791-1-fnordahl@ubuntu.com> References: <20240719020943.380924-1-fnordahl@ubuntu.com> <20240725140009.413791-1-fnordahl@ubuntu.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v3 6/7] northd: Add distributed route exchange options. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Add three new options for Logical Router Ports that control ovn-controller route exchange for NAT addresses and LB VIPs. Load Balancers already have structured data in the Southbound database which the ovn-controller can use directly. NAT addresses are however currently only expressed as specialized rules in the Port_Binding table nat_addresses column on LSP peer records for LRPs, used for (G)ARP processing, as well as logical flow rules for OpenFlow processing. Options considered for how to redistribute these addresses to the ovn-controllers in a structured way: * Introduce even more conditional processing of the lsp nat_addresses column. * Parse ct_dnat records in the Logical_Flow table. * Add column to the Port_Binding table. * Copy the Northbound NAT table over to the Southbound database, similar to what is done with Load Balancers. * Populate Port_Binding table nat_addresses column on LRPs peer record (the proposed approach). The Port_Binding table LRP peer records nat_addresses column is currently unused, populate it with NAT addresses for route exchange, when the redistribute-nat LRP option is set to 'true'. The options are only processed for gateway routers. Signed-off-by: Frode Nordahl --- controller/pinctrl.c | 8 +++++-- northd/northd.c | 28 ++++++++++++++++++++++++ ovn-nb.xml | 45 ++++++++++++++++++++++++++++++++++++++ ovn-sb.xml | 51 +++++++++++++++++++++++++++++++++++++++++++- tests/ovn-northd.at | 42 ++++++++++++++++++++++++++++++++++++ 5 files changed, 171 insertions(+), 3 deletions(-) diff --git a/controller/pinctrl.c b/controller/pinctrl.c index 708240e24..d9ef97ce1 100644 --- a/controller/pinctrl.c +++ b/controller/pinctrl.c @@ -6428,11 +6428,15 @@ get_nat_addresses_and_keys(struct ovsdb_idl_index *sbrec_port_binding_by_name, const struct sbrec_port_binding *pb; pb = lport_lookup_by_name(sbrec_port_binding_by_name, gw_port); - if (!pb) { + if (!pb || !pb->datapath) { continue; } - if (pb->n_nat_addresses) { + /* We only want to consider nat_addresses column for LS datapaths. */ + const char *logical_switch = smap_get(&pb->datapath->external_ids, + "logical-switch"); + + if (pb->n_nat_addresses && logical_switch) { for (int i = 0; i < pb->n_nat_addresses; i++) { consider_nat_address(sbrec_port_binding_by_name, pb->nat_addresses[i], pb, diff --git a/northd/northd.c b/northd/northd.c index d2d557f0b..0c4075847 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -3912,6 +3912,8 @@ sync_pb_for_lrp(struct ovn_port *op, smap_init(&new); const char *chassis_name = smap_get(&op->od->nbr->options, "chassis"); + bool redistribute_nat = smap_get_bool(&op->nbrp->options, + "redistribute-nat", false); if (is_cr_port(op)) { const struct lr_stateful_record *lr_stateful_rec = lr_stateful_table_find_by_index(lr_stateful_table, op->od->index); @@ -3950,6 +3952,28 @@ sync_pb_for_lrp(struct ovn_port *op, } if (chassis_name) { smap_add(&new, "l3gateway-chassis", chassis_name); + if (smap_get_bool(&op->nbrp->options, "maintain-vrf", false)) { + smap_add(&new, "maintain-vrf", "true"); + } + if (redistribute_nat) { + smap_add(&new, "redistribute-nat", "true"); + + size_t n_nats = 0; + char **nats = NULL; + nats = get_nat_addresses(op, &n_nats, false, false, NULL, + true); + sbrec_port_binding_set_nat_addresses(op->sb, + (const char **) nats, + n_nats); + for (size_t i = 0; i < n_nats; i++) { + free(nats[i]); + } + free(nats); + } + if (smap_get_bool(&op->nbrp->options, + "redistribute-lb-vips", false)) { + smap_add(&new, "redistribute-lb-vips", "true"); + } } } @@ -3960,6 +3984,10 @@ sync_pb_for_lrp(struct ovn_port *op, sbrec_port_binding_set_options(op->sb, &new); smap_destroy(&new); + + if (!chassis_name || !redistribute_nat) { + sbrec_port_binding_set_nat_addresses(op->sb, NULL, 0); + } } static void ovn_update_ipv6_options(struct hmap *lr_ports); diff --git a/ovn-nb.xml b/ovn-nb.xml index 0f9a1005a..a2681e3c2 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -3467,6 +3467,51 @@ or option.

+ + +

+ When configured the ovn-controller will redistribute + host routes to Load Balancer VIPs that are local to its chassis and + associated with the LR datapath. + + This option only works on gateway routers (routers that have + set) + when OVN is built on a system with Netlink support. +

+
+ + +

+ When configured the ovn-controller will redistribute + host routes to NAT records associated with logical ports local to + its chassis in relateion to the LR datapath. + + This option only works on gateway routers (routers that have + set) + when OVN is built on a system with Netlink support. +

+
+ + +

+ When configured the ovn-controller will maintain a VRF + in the system for exporting host routes to NAT addresses (see + option) and Load + Balancer VIPs (see + option). + + Route table ID to use can be influenced by setting the + option in the + table. If not set, + ovn-northd will allocate one. + + This option only works on gateway routers (routers that have + set) + when OVN is built on a system with Netlink support. +

+
+ diff --git a/ovn-sb.xml b/ovn-sb.xml index 90f113afd..2ee1ea5e1 100644 --- a/ovn-sb.xml +++ b/ovn-sb.xml @@ -3594,14 +3594,63 @@ tcp.flags = RST; The chassis in which the port resides. + +

+ The value is copied from the column + and when configured the + ovn-controller will redistribute host routes to Load + Balancer VIPs that are local to its chassis and associated with the + LR datapath. +

+
+ + +

+ The value is copied from the column + and when configured the + ovn-controller will redistribute host routes to + records associated with + logical ports local to this chassis in relateion to the LR datapath. +

+
+ + +

+ The value is copied from the column + and when configured the + ovn-controller will maintain a VRF in the system for + exporting host routes to NAT addresses (see + option) and Load + Balancer VIPs (see + option). +

+
+ MAC address of the l3gateway port followed by a list of - SNAT and DNAT external IP addresses. This is used to send gratuitous + SNAT and DNAT external IP addresses. + + Both sides of a LRP-LSP peer relationship have records in the + table. + + When the record is associated with a + record, this is used to send gratuitous ARPs for SNAT and DNAT external IP addresses via localnet. Example: 80:fa:5b:06:72:b7 158.36.44.22 158.36.44.24. This would result in generation of gratuitous ARPs for IP addresses 158.36.44.22 and 158.36.44.24 with a MAC address of 80:fa:5b:06:72:b7. This is used in OVS version 2.8 and later versions. + + When the record is associated with a + record, this is used to redistribute host + routes to records associated + with logical ports local to this chassis in relateion to the LR + datapath.
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index 83f91c05c..e303609ed 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -12459,3 +12459,45 @@ AT_CHECK([ovn-sbctl dump-flows lr | grep lr_in_dnat | ovn_strip_lflows], [0], [d AT_CLEANUP ]) + +OVN_FOR_EACH_NORTHD_NO_HV([ +AT_SETUP([check route-exchange redistribute-nat option]) +ovn_start + +ovn-nbctl lr-add R1 +ovn-nbctl set Logical_Router R1 options:chassis=hv1 +ovn-nbctl lrp-add R1 R1-S1 02:ac:10:01:00:01 172.16.1.1/24 + +ovn-nbctl ls-add S1 +ovn-nbctl lsp-add S1 S1-R1 +ovn-nbctl lsp-set-type S1-R1 router +ovn-nbctl lsp-set-addresses S1-R1 02:ac:10:01:00:01 +ovn-nbctl --wait=sb lsp-set-options S1-R1 \ + router-port=R1-S1 \ + nat-addresses="router" + +ovn-nbctl lr-nat-add R1 snat 172.16.1.1 10.0.0.0/24 +ovn-nbctl lr-nat-add R1 dnat 172.16.1.2 10.0.0.1 +ovn-nbctl --wait=sb sync + +AT_CHECK([dnl +ovn-sbctl get Port_Binding S1-R1 nat_addresses | grep -q 172.16.1.2], [0]) +AT_CHECK([dnl +ovn-sbctl get Port_Binding R1-S1 nat_addresses | grep -q 172.16.1.2], [1]) + +ovn-nbctl --wait=sb lrp-set-options R1-S1 redistribute-nat=true + +AT_CHECK([dnl +ovn-sbctl get Port_Binding S1-R1 nat_addresses | grep -q 172.16.1.2], [0]) +AT_CHECK([dnl +ovn-sbctl get Port_Binding R1-S1 nat_addresses | grep -q 172.16.1.2], [0]) + +ovn-nbctl --wait=sb lrp-set-options R1-S1 redistribute-nat=false + +AT_CHECK([dnl +ovn-sbctl get Port_Binding S1-R1 nat_addresses | grep -q 172.16.1.2], [0]) +AT_CHECK([dnl +ovn-sbctl get Port_Binding R1-S1 nat_addresses | grep -q 172.16.1.2], [1]) + +AT_CLEANUP +]) From patchwork Thu Jul 25 14:00:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1964789 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=140.211.166.137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (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 4WVCG640g1z1yXx for ; Fri, 26 Jul 2024 00:00:46 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id CB18440975; Thu, 25 Jul 2024 14:00:44 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id BOrjvJYi8itb; Thu, 25 Jul 2024 14:00:38 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=2605:bc80:3010:104::8cd3:938; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 38D834099F Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp4.osuosl.org (Postfix) with ESMTPS id 38D834099F; Thu, 25 Jul 2024 14:00:34 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id A16F8C0033; Thu, 25 Jul 2024 14:00:33 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 225C8C0926 for ; Thu, 25 Jul 2024 14:00:31 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 53B6340994 for ; Thu, 25 Jul 2024 14:00:29 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id MnQb9hbM0qCW for ; Thu, 25 Jul 2024 14:00:26 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=209.85.208.171; helo=mail-lj1-f171.google.com; envelope-from=frode.nordahl@gmail.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp4.osuosl.org 57C2240981 Authentication-Results: smtp4.osuosl.org; dmarc=fail (p=none dis=none) header.from=ubuntu.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 57C2240981 Received: from mail-lj1-f171.google.com (mail-lj1-f171.google.com [209.85.208.171]) by smtp4.osuosl.org (Postfix) with ESMTPS id 57C2240981 for ; Thu, 25 Jul 2024 14:00:25 +0000 (UTC) Received: by mail-lj1-f171.google.com with SMTP id 38308e7fff4ca-2ef2cb7d562so2297041fa.3 for ; Thu, 25 Jul 2024 07:00:25 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721916022; x=1722520822; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Ik5W0sXJX5hbCSbIN7X3FRPIoy0DNtNYK9mDAiu4M1c=; b=wI1DeGfeoVJLnUP8lYibhwo5Pswb4sinq0iqzdRWmGiBnRx6UgpZ6cQcfkzFWu21wk /d9POkd50R8L/K6uRPicjrHmhtNBehl+8LBRH8WpJSbPgsBIpcKCqr+0h3E60KHxMDj4 h4eZQBoAd3h+ZaT66XKJRPCLM2lwzWkCTGf3kphplvZlr3VffOvcXw0O4SQl6iMpV/bB H+5MVdLvxRmVJCxQ8MhEAhpapXHuSzu+a1/TEnxMUj1TaQg5WgRUfIz4IezEuFzRKHkj tHlaRx5LzwQYhhysnRODuR26m50rvBd9XCjIU3KAz4+juG8JHJN0b7XHfnik9svzuNHH PZ/w== X-Gm-Message-State: AOJu0YysxQ9h0L/sBnuZiuCpJWvFGsI4NtDnmGROpxCmvFF0uB1gAPS0 eEW6vGUCxckI6+qebNCapVJKfvxRIqul4B04dL/Vx4FPVZm2UElGAJ2HZg== X-Google-Smtp-Source: AGHT+IHL1NCFYcfUJmysmaxwrpGq3Ju8J0PyxEAyC6uPMGHrQk9v0E2Aw6OO9zqhZ2CytY02TJGMqg== X-Received: by 2002:a2e:93c3:0:b0:2ef:284e:1d07 with SMTP id 38308e7fff4ca-2f03db7df5amr16108611fa.13.1721916021928; Thu, 25 Jul 2024 07:00:21 -0700 (PDT) Received: from localhost.localdomain ([2001:4643:d087:0:bd05:8094:92b2:c0a]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-2f03cf0e36csm2027211fa.17.2024.07.25.07.00.20 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jul 2024 07:00:20 -0700 (PDT) From: Frode Nordahl To: dev@openvswitch.org Date: Thu, 25 Jul 2024 16:00:09 +0200 Message-ID: <20240725140009.413791-7-fnordahl@ubuntu.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240725140009.413791-1-fnordahl@ubuntu.com> References: <20240719020943.380924-1-fnordahl@ubuntu.com> <20240725140009.413791-1-fnordahl@ubuntu.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v3 7/7] controller: Introduce route-exchange module. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Introduce route-exchange module that depending on Logical Router Port options maintains a VRF in the system for redistribution of host routes to NAT addresses and LB VIPs attached to local gateway router datapaths. The route-exchange module requires input from both runtime_data and lb_data engine nodes. Consequently it needs its own I-P engine node. TODO: * E2E test together with the bgp-mirror patch. * E2E docs and NEWS items. Signed-off-by: Frode Nordahl --- controller/automake.mk | 9 +- controller/ovn-controller.c | 193 ++++++++++++++++ controller/route-exchange-stub.c | 44 ++++ controller/route-exchange.c | 274 ++++++++++++++++++++++ controller/route-exchange.h | 45 ++++ tests/system-ovn.at | 382 +++++++++++++++++++++++++++++++ 6 files changed, 945 insertions(+), 2 deletions(-) create mode 100644 controller/route-exchange-stub.c create mode 100644 controller/route-exchange.c create mode 100644 controller/route-exchange.h diff --git a/controller/automake.mk b/controller/automake.mk index 006e884dc..3e91e97e6 100644 --- a/controller/automake.mk +++ b/controller/automake.mk @@ -49,13 +49,18 @@ controller_ovn_controller_SOURCES = \ controller/statctrl.h \ controller/statctrl.c \ controller/ct-zone.h \ - controller/ct-zone.c + controller/ct-zone.c \ + controller/route-exchange.h if HAVE_NETLINK controller_ovn_controller_SOURCES += \ controller/route-exchange-netlink.h \ controller/route-exchange-netlink-private.h \ - controller/route-exchange-netlink.c + controller/route-exchange-netlink.c \ + controller/route-exchange.c +else +controller_ovn_controller_SOURCES += \ + controller/route-exchange-stub.c endif controller_ovn_controller_LDADD = lib/libovn.la $(OVS_LIBDIR)/libopenvswitch.la diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 805d29c81..7bc90da31 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -87,6 +87,7 @@ #include "statctrl.h" #include "lib/dns-resolve.h" #include "ct-zone.h" +#include "route-exchange.h" VLOG_DEFINE_THIS_MODULE(main); @@ -4576,6 +4577,14 @@ controller_output_mac_cache_handler(struct engine_node *node, return true; } +static bool +controller_output_route_exchange_handler(struct engine_node *node, + void *data OVS_UNUSED) +{ + engine_set_node_state(node, EN_UPDATED); + return true; +} + /* Handles sbrec_chassis changes. * If a new chassis is added or removed return false, so that * flows are recomputed. For any updates, there is no need for @@ -4599,6 +4608,174 @@ pflow_lflow_output_sb_chassis_handler(struct engine_node *node, return true; } +struct ed_type_route_exchange { + /* Contains struct tracked_datapath entries for local datapaths subject to + * route exchange. */ + struct hmap tracked_re_datapaths; +}; + +static void +en_route_exchange_run(struct engine_node *node, void *data) +{ + struct ed_type_route_exchange *re_data = data; + const struct ovsrec_open_vswitch_table *ovs_table = + EN_OVSDB_GET(engine_get_input("OVS_open_vswitch", node)); + const char *chassis_id = get_ovs_chassis_id(ovs_table); + ovs_assert(chassis_id); + + struct ovsdb_idl_index *sbrec_chassis_by_name = + engine_ovsdb_node_get_index( + engine_get_input("SB_chassis", node), + "name"); + const struct sbrec_chassis *chassis + = chassis_lookup_by_name(sbrec_chassis_by_name, chassis_id); + ovs_assert(chassis); + + struct ovsdb_idl_index *sbrec_port_binding_by_name = + engine_ovsdb_node_get_index( + engine_get_input("SB_port_binding", node), + "name"); + struct ed_type_runtime_data *rt_data = + engine_get_input_data("runtime_data", node); + + const struct sbrec_load_balancer_table *lb_table = + EN_OVSDB_GET(engine_get_input("SB_load_balancer", node)); + struct ed_type_lb_data *lb_data = + engine_get_input_data("lb_data", node); + + struct route_exchange_ctx_in r_ctx_in = { + .sbrec_port_binding_by_name = sbrec_port_binding_by_name, + .lb_table = lb_table, + .chassis_rec = chassis, + .active_tunnels = &rt_data->active_tunnels, + .local_datapaths = &rt_data->local_datapaths, + .local_lbs = &lb_data->local_lbs, + }; + + struct route_exchange_ctx_out r_ctx_out = { + .tracked_re_datapaths = &re_data->tracked_re_datapaths, + }; + + + route_exchange_run(&r_ctx_in, &r_ctx_out); + + engine_set_node_state(node, EN_UPDATED); +} + + +static void * +en_route_exchange_init(struct engine_node *node OVS_UNUSED, + struct engine_arg *arg OVS_UNUSED) +{ + struct ed_type_route_exchange *data = xzalloc(sizeof *data); + + hmap_init(&data->tracked_re_datapaths); + + return data; +} + +static void +en_route_exchange_cleanup(void *data) +{ + struct ed_type_route_exchange *re_data = data; + + tracked_datapaths_destroy(&re_data->tracked_re_datapaths); +} + +static bool +route_exchange_runtime_data_handler(struct engine_node *node, void *data) +{ + struct ed_type_route_exchange *re_data = data; + struct ed_type_runtime_data *rt_data = + engine_get_input_data("runtime_data", node); + + if (!rt_data->tracked) { + return false; + } + + struct tracked_datapath *t_dp; + HMAP_FOR_EACH (t_dp, node, &rt_data->tracked_dp_bindings) { + struct tracked_datapath *re_t_dp = + tracked_datapath_find(&re_data->tracked_re_datapaths, t_dp->dp); + + if (re_t_dp) { + /* Until we get I-P support for route exchange we need to request + * recompute. */ + return false; + } + + struct shash_node *shash_node; + SHASH_FOR_EACH (shash_node, &t_dp->lports) { + struct tracked_lport *lport = shash_node->data; + if (route_exchange_relevant_port(lport->pb)) { + /* Until we get I-P support for route exchange we need to + * request recompute. */ + return false; + } + } + } + + return true; +} + +static bool +route_exchange_lb_data_handler(struct engine_node *node, + void *data) +{ + struct ed_type_route_exchange *re_data = data; + struct ed_type_runtime_data *rt_data = + engine_get_input_data("runtime_data", node); + struct ed_type_lb_data *lb_data = + engine_get_input_data("lb_data", node); + const struct sbrec_load_balancer_table *lb_table = + EN_OVSDB_GET(engine_get_input("SB_load_balancer", node)); + + if (!lb_data->change_tracked) { + return false; + } + + if (!rt_data->tracked) { + return false; + } + + if (hmap_is_empty(&re_data->tracked_re_datapaths)) { + return true; + } + + struct hmap *tracked_dp_bindings = &rt_data->tracked_dp_bindings; + if (hmap_is_empty(tracked_dp_bindings)) { + return true; + } + + struct hmap *lbs = NULL; + + struct tracked_datapath *t_dp; + HMAP_FOR_EACH (t_dp, node, tracked_dp_bindings) { + struct tracked_datapath *re_t_dp = + tracked_datapath_find(&re_data->tracked_re_datapaths, t_dp->dp); + + if (!re_t_dp) { + continue; + } + + if (!lbs) { + lbs = load_balancers_by_dp_init(&rt_data->local_datapaths, + lb_table); + } + + struct load_balancers_by_dp *lbs_by_dp = + load_balancers_by_dp_find(lbs, re_t_dp->dp); + if (lbs_by_dp) { + /* Until we get I-P support for route exchange we need to + * request recompute. */ + load_balancers_by_dp_cleanup(lbs); + return false; + } + } + load_balancers_by_dp_cleanup(lbs); + return true; +} + /* Returns false if the northd internal version stored in SB_Global * and ovn-controller internal version don't match. */ @@ -4885,6 +5062,7 @@ main(int argc, char *argv[]) ENGINE_NODE(if_status_mgr, "if_status_mgr"); ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lb_data, "lb_data"); ENGINE_NODE(mac_cache, "mac_cache"); + ENGINE_NODE(route_exchange, "route_exchange"); #define SB_NODE(NAME, NAME_STR) ENGINE_NODE_SB(NAME, NAME_STR); SB_NODES @@ -4907,6 +5085,17 @@ main(int argc, char *argv[]) engine_add_input(&en_lb_data, &en_runtime_data, lb_data_runtime_data_handler); + engine_add_input(&en_route_exchange, &en_ovs_open_vswitch, NULL); + engine_add_input(&en_route_exchange, &en_sb_chassis, NULL); + engine_add_input(&en_route_exchange, &en_sb_port_binding, + engine_noop_handler); + engine_add_input(&en_route_exchange, &en_runtime_data, + route_exchange_runtime_data_handler); + engine_add_input(&en_route_exchange, &en_sb_load_balancer, + engine_noop_handler); + engine_add_input(&en_route_exchange, &en_lb_data, + route_exchange_lb_data_handler); + engine_add_input(&en_addr_sets, &en_sb_address_set, addr_sets_sb_address_set_handler); engine_add_input(&en_port_groups, &en_sb_port_group, @@ -5081,6 +5270,8 @@ main(int argc, char *argv[]) controller_output_pflow_output_handler); engine_add_input(&en_controller_output, &en_mac_cache, controller_output_mac_cache_handler); + engine_add_input(&en_controller_output, &en_route_exchange, + controller_output_route_exchange_handler); struct engine_arg engine_arg = { .sb_idl = ovnsb_idl_loop.idl, @@ -5770,6 +5961,7 @@ loop_done: ovsdb_idl_loop_commit_and_wait(&ovs_idl_loop); poll_block(); } + route_exchange_cleanup(); } free(ovn_version); @@ -5799,6 +5991,7 @@ loop_done: service_stop(); ovsrcu_exit(); dns_resolve_destroy(); + route_exchange_destroy(); exit(retval); } diff --git a/controller/route-exchange-stub.c b/controller/route-exchange-stub.c new file mode 100644 index 000000000..839cbc077 --- /dev/null +++ b/controller/route-exchange-stub.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024 Canonical + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include "openvswitch/compiler.h" +#include "route-exchange.h" + +bool +route_exchange_relevant_port(const struct sbrec_port_binding *pb OVS_UNUSED) +{ + return false; +} + +void +route_exchange_run(struct route_exchange_ctx_in *r_ctx_in OVS_UNUSED, + struct route_exchange_ctx_out *r_ctx_out OVS_UNUSED) +{ +} + +void +route_exchange_cleanup(void) +{ +} + +void +route_exchange_destroy(void) +{ +} diff --git a/controller/route-exchange.c b/controller/route-exchange.c new file mode 100644 index 000000000..d3b8f0480 --- /dev/null +++ b/controller/route-exchange.c @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2024 Canonical + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include + +#include "openvswitch/vlog.h" + +#include "lib/ovn-sb-idl.h" + +#include "binding.h" +#include "ha-chassis.h" +#include "lb.h" +#include "local_data.h" +#include "route-exchange.h" +#include "route-exchange-netlink.h" + + +VLOG_DEFINE_THIS_MODULE(route_exchange); +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); + +/* While the linux kernel can handle 2^32 routing tables, only so many can fit + * in the corresponding VRF interface name. */ +#define MAX_TABLE_ID 1000000000 + +static struct sset _maintained_vrfs = SSET_INITIALIZER(&_maintained_vrfs); + +bool +route_exchange_relevant_port(const struct sbrec_port_binding *pb) { + return (pb && pb->type && !strcmp(pb->type, "l3gateway") && + (smap_get_bool(&pb->options, "redistribute-lb-vips", false) || + smap_get_bool(&pb->options, "redistribute-nat", false))); +} + +static void +extract_nat_addresses(const struct sbrec_port_binding *pb, + struct route_exchange_ctx_in *r_ctx_in, + uint32_t table_id, struct hmap *host_routes) +{ + if (!pb || !pb->n_nat_addresses) { + return; + } + VLOG_DBG("extract_nat_addresses: considering lport %s", pb->logical_port); + + for (size_t i = 0; i < pb->n_nat_addresses; i++) { + struct lport_addresses *laddrs = xzalloc(sizeof *laddrs); + char *lport = NULL; + + if (!extract_addresses_with_port( + pb->nat_addresses[i], laddrs, &lport)) { + VLOG_DBG("extract_nat_addresses: no addresses"); + goto cleanup; + } + if (lport) { + const struct sbrec_port_binding *lport_pb = lport_lookup_by_name( + r_ctx_in->sbrec_port_binding_by_name, lport); + if (!lport_pb || !lport_pb->chassis) { + VLOG_DBG("extract_nat_addresses: cannot find lport %s", + lport); + goto cleanup; + } + enum en_lport_type lport_pb_type = get_lport_type(lport_pb); + if (((lport_pb_type == LP_VIF || + lport_pb_type == LP_CHASSISREDIRECT) && + lport_pb->chassis != r_ctx_in->chassis_rec) || + !ha_chassis_group_is_active(lport_pb->ha_chassis_group, + r_ctx_in->active_tunnels, + r_ctx_in->chassis_rec)) { + VLOG_DBG("extract_nat_addresses: ignoring non-local lport %s", + lport); + goto cleanup; + } + } + for (size_t j = 0; j < laddrs->n_ipv4_addrs; j++) { + struct in6_addr addr; + in6_addr_set_mapped_ipv4(&addr, laddrs->ipv4_addrs[j].addr); + host_route_insert(host_routes, table_id, &addr); + } + for (size_t j = 0; j < laddrs->n_ipv6_addrs; j++) { + host_route_insert(host_routes, table_id, + &laddrs->ipv6_addrs[j].addr); + } + +cleanup: + destroy_lport_addresses(laddrs); + free(laddrs); + if (lport) { + free(lport); + } + } +} + +static void +extract_lb_vips(const struct sbrec_datapath_binding *dpb, + struct hmap *lbs_by_dp_hmap, + const struct route_exchange_ctx_in *r_ctx_in, + uint32_t table_id, struct hmap *host_routes) +{ + struct load_balancers_by_dp *lbs_by_dp + = load_balancers_by_dp_find(lbs_by_dp_hmap, dpb); + if (!lbs_by_dp) { + return; + } + + for (size_t i = 0; i < lbs_by_dp->n_dp_lbs; i++) { + const struct sbrec_load_balancer *sbrec_lb + = lbs_by_dp->dp_lbs[i]; + + if (!sbrec_lb) { + return; + } + + struct ovn_controller_lb *lb + = ovn_controller_lb_find(r_ctx_in->local_lbs, + &sbrec_lb->header_.uuid); + + if (!lb || !lb->slb) { + return; + } + + VLOG_DBG("considering lb for route leaking: %s", lb->slb->name); + for (i = 0; i < lb->n_vips; i++) { + VLOG_DBG("considering lb for route leaking: %s vip_str=%s", + lb->slb->name, lb->vips[i].vip_str); + host_route_insert(host_routes, table_id, &lb->vips[i].vip); + } + } +} + +void +route_exchange_run(struct route_exchange_ctx_in *r_ctx_in, + struct route_exchange_ctx_out *r_ctx_out) +{ + struct sset old_maintained_vrfs = SSET_INITIALIZER(&old_maintained_vrfs); + sset_swap(&_maintained_vrfs, &old_maintained_vrfs); + struct hmap *lbs_by_dp_hmap + = load_balancers_by_dp_init(r_ctx_in->local_datapaths, + r_ctx_in->lb_table); + + /* Extract all NAT- and LB VIP-addresses associated with lports resident on + * the current chassis to allow full sync of leaked routing tables. */ + const struct local_datapath *ld; + HMAP_FOR_EACH (ld, hmap_node, r_ctx_in->local_datapaths) { + if (!ld->n_peer_ports || ld->is_switch) { + continue; + } + + bool maintain_vrf = false; + bool lbs_sync = false; + struct hmap local_host_routes_for_current_dp + = HMAP_INITIALIZER(&local_host_routes_for_current_dp); + + /* This is a LR datapath, find LRPs with route exchange options. */ + for (size_t i = 0; i < ld->n_peer_ports; i++) { + const struct sbrec_port_binding *local_peer + = ld->peer_ports[i].local; + if (!local_peer || !route_exchange_relevant_port(local_peer)) { + continue; + } + + maintain_vrf |= smap_get_bool(&local_peer->options, + "maintain-vrf", false); + lbs_sync |= smap_get_bool(&local_peer->options, + "redistribute-lb-vips", + false); + if (smap_get_bool(&local_peer->options, + "redistribute-nat", + false)) { + extract_nat_addresses(local_peer, r_ctx_in, + ld->datapath->tunnel_key, + &local_host_routes_for_current_dp); + } + } + + if (lbs_sync) { + extract_lb_vips(ld->datapath, lbs_by_dp_hmap, r_ctx_in, + ld->datapath->tunnel_key, + &local_host_routes_for_current_dp); + } + + /* While tunnel_key would most likely never be negative, the compiler + * has opinions if we don't check before using it in snprintf below. */ + if (ld->datapath->tunnel_key < 0 || + ld->datapath->tunnel_key > MAX_TABLE_ID) { + VLOG_WARN_RL(&rl, + "skip route sync for datapath "UUID_FMT", " + "tunnel_key %"PRIi64" would make VRF interface name " + "overflow.", + UUID_ARGS(&ld->datapath->header_.uuid), + ld->datapath->tunnel_key); + goto out; + } + char vrf_name[IFNAMSIZ + 1]; + snprintf(vrf_name, sizeof vrf_name, "ovnvrf%"PRIi64, + ld->datapath->tunnel_key); + + if (maintain_vrf) { + int error = re_nl_create_vrf(vrf_name, ld->datapath->tunnel_key); + if (error && error != EEXIST) { + VLOG_WARN_RL(&rl, + "Unable to create VRF %s for datapath "UUID_FMT + ": %s.", + vrf_name, UUID_ARGS(&ld->datapath->header_.uuid), + ovs_strerror(error)); + goto out; + } + sset_add(&_maintained_vrfs, vrf_name); + } + if (!hmap_is_empty(&local_host_routes_for_current_dp)) { + tracked_datapath_add(ld->datapath, TRACKED_RESOURCE_NEW, + r_ctx_out->tracked_re_datapaths); + } + re_nl_sync_routes(ld->datapath->tunnel_key, vrf_name, + &local_host_routes_for_current_dp); + +out: + host_routes_destroy(&local_host_routes_for_current_dp); + } + + /* Remove VRFs previously maintained by us not found in the above loop. */ + const char *vrf_name; + SSET_FOR_EACH_SAFE (vrf_name, &old_maintained_vrfs) { + if (!sset_find(&_maintained_vrfs, vrf_name)) { + re_nl_delete_vrf(vrf_name); + } + sset_delete(&old_maintained_vrfs, SSET_NODE_FROM_NAME(vrf_name)); + } + sset_destroy(&old_maintained_vrfs); + + load_balancers_by_dp_cleanup(lbs_by_dp_hmap); +} + +static void +route_exchange_cleanup__(bool cleanup) +{ + const char *vrf_name; + SSET_FOR_EACH_SAFE (vrf_name, &_maintained_vrfs) { + if (cleanup) { + re_nl_delete_vrf(vrf_name); + } else { + sset_delete(&_maintained_vrfs, SSET_NODE_FROM_NAME(vrf_name)); + } + } + if (!cleanup) { + sset_destroy(&_maintained_vrfs); + } +} + +void +route_exchange_cleanup(void) +{ + route_exchange_cleanup__(true); +} + +void +route_exchange_destroy(void) +{ + route_exchange_cleanup__(false); +} diff --git a/controller/route-exchange.h b/controller/route-exchange.h new file mode 100644 index 000000000..de554f9b1 --- /dev/null +++ b/controller/route-exchange.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 Canonical + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ROUTE_EXCHANGE_H +#define ROUTE_EXCHANGE_H 1 + +struct hmap; +struct ovsdb_idl_index; +struct sbrec_chassis; +struct sbrec_port_binding; +struct sset; + +struct route_exchange_ctx_in { + struct ovsdb_idl_index *sbrec_port_binding_by_name; + const struct sbrec_load_balancer_table *lb_table; + const struct sbrec_chassis *chassis_rec; + const struct sset *active_tunnels; + struct hmap *local_datapaths; + struct hmap *local_lbs; +}; + +struct route_exchange_ctx_out { + struct hmap *tracked_re_datapaths; +}; + +bool route_exchange_relevant_port(const struct sbrec_port_binding *pb); +void route_exchange_run(struct route_exchange_ctx_in *, + struct route_exchange_ctx_out *); +void route_exchange_cleanup(void); +void route_exchange_destroy(void); + +#endif /* ROUTE_EXCHANGE_H */ diff --git a/tests/system-ovn.at b/tests/system-ovn.at index ddb3d14e9..2c410d555 100644 --- a/tests/system-ovn.at +++ b/tests/system-ovn.at @@ -13022,3 +13022,385 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d /connection dropped.*/d"]) AT_CLEANUP ]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([route-exchange for LB VIPs with gateway router IPv4]) +AT_KEYWORDS([route-exchange]) + +CHECK_VRF() +CHECK_CONNTRACK() +CHECK_CONNTRACK_NAT() +ovn_start +OVS_TRAFFIC_VSWITCHD_START() +ADD_BR([br-int]) +ADD_BR([br-ext], [set Bridge br-ext fail-mode=standalone]) + +# Set external-ids in br-int needed for ovn-controller +ovs-vsctl \ + -- set Open_vSwitch . external-ids:system-id=hv1 \ + -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ + -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ + -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ + -- set bridge br-int fail-mode=secure other-config:disable-in-band=true + +# Start ovn-controller +start_daemon ovn-controller + +ovn-appctl vlog/set route_exchange +check ovn-nbctl -- lr-add R1 \ + -- set Logical_Router R1 options:requested-tnl-key=1000 + +check ovn-nbctl ls-add sw0 +check ovn-nbctl ls-add public + +check ovn-nbctl --wait=hv sync + +AT_CHECK([ip link | grep -q ovnvrf1000:.*UP], [1]) + +check ovn-nbctl lrp-add R1 rp-sw0 00:00:01:01:02:03 192.168.1.1/24 +check ovn-nbctl -- lrp-add R1 rp-public 00:00:02:01:02:03 172.16.1.1/24 \ + -- lrp-set-options rp-public \ + maintain-vrf=true \ + redistribute-lb-vips=true + +check ovn-nbctl set logical_router R1 options:chassis=hv1 + +check ovn-nbctl lsp-add sw0 sw0-rp -- set Logical_Switch_Port sw0-rp \ + type=router options:router-port=rp-sw0 \ + -- lsp-set-addresses sw0-rp router + +check ovn-nbctl lsp-add public public-rp -- set Logical_Switch_Port public-rp \ + type=router options:router-port=rp-public \ + -- lsp-set-addresses public-rp router + +check ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext + +check ovn-nbctl lsp-add public public1 \ + -- lsp-set-addresses public1 unknown \ + -- lsp-set-type public1 localnet \ + -- lsp-set-options public1 network_name=phynet + +check ovn-nbctl --wait=hv sync + +AT_CHECK([test `ip route show table 1000 | wc -l` -eq 1], [1]) + +# Create a load balancer and associate to R1 +check ovn-nbctl lb-add lb1 172.16.1.150:80 172.16.1.100:80 +check ovn-nbctl lr-lb-add R1 lb1 + +check ovn-nbctl --wait=hv sync + +AT_CHECK([ip link | grep -q ovnvrf1000:.*UP]) +AT_CHECK([test `ip route show table 1000 | wc -l` -eq 1]) +AT_CHECK([ip route show table 1000 | grep -q 172.16.1.150]) + + +OVS_APP_EXIT_AND_WAIT([ovn-controller]) + +# Ensure system resources are cleaned up +AT_CHECK([ip link | grep -q ovnvrf1000:.*UP], [1]) +AT_CHECK([test `ip route show table 1000 | wc -l` -eq 1], [1]) + +as ovn-sb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as ovn-nb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as northd +OVS_APP_EXIT_AND_WAIT([ovn-northd]) + +as +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d +/Failed to acquire.*/d +/connection dropped.*/d"]) +AT_CLEANUP +]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([route-exchange for LB VIPs with gateway router IPv6]) +AT_KEYWORDS([route-exchange]) + +CHECK_VRF() +CHECK_CONNTRACK() +CHECK_CONNTRACK_NAT() +ovn_start +OVS_TRAFFIC_VSWITCHD_START() +ADD_BR([br-int]) +ADD_BR([br-ext], [set Bridge br-ext fail-mode=standalone]) + +# Set external-ids in br-int needed for ovn-controller +ovs-vsctl \ + -- set Open_vSwitch . external-ids:system-id=hv1 \ + -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ + -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ + -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ + -- set bridge br-int fail-mode=secure other-config:disable-in-band=true + +# Start ovn-controller +start_daemon ovn-controller + +ovn-appctl vlog/set route_exchange +check ovn-nbctl -- lr-add R1 \ + -- set Logical_Router R1 options:requested-tnl-key=1001 + +check ovn-nbctl ls-add sw0 +check ovn-nbctl ls-add public + +check ovn-nbctl --wait=hv sync + +AT_CHECK([ip link | grep -q ovnvrf1001:.*UP], [1]) + +check ovn-nbctl lrp-add R1 rp-sw0 00:00:01:01:02:03 2001:db8:100::1/64 +check ovn-nbctl -- lrp-add R1 rp-public 00:00:02:01:02:03 2001:db8:1001::1/64 \ + -- lrp-set-options rp-public \ + maintain-vrf=true \ + redistribute-lb-vips=true + +check ovn-nbctl set logical_router R1 options:chassis=hv1 + +check ovn-nbctl lsp-add sw0 sw0-rp -- set Logical_Switch_Port sw0-rp \ + type=router options:router-port=rp-sw0 \ + -- lsp-set-addresses sw0-rp router + +check ovn-nbctl lsp-add public public-rp -- set Logical_Switch_Port public-rp \ + type=router options:router-port=rp-public \ + -- lsp-set-addresses public-rp router + +check ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext + +check ovn-nbctl lsp-add public public1 \ + -- lsp-set-addresses public1 unknown \ + -- lsp-set-type public1 localnet \ + -- lsp-set-options public1 network_name=phynet + +check ovn-nbctl --wait=hv sync + +AT_CHECK([test `ip -6 route show table 1001 | wc -l` -eq 1], [1]) + +# Create a load balancer and associate to R1 +check ovn-nbctl lb-add lb1 [[2001:db8:1001::150]]:80 [[2001:db8:1001::100]]:80 +check ovn-nbctl lr-lb-add R1 lb1 + +check ovn-nbctl --wait=hv sync + +AT_CHECK([ip link | grep -q ovnvrf1001:.*UP]) +AT_CHECK([test `ip -6 route show table 1001 | wc -l` -eq 1]) +AT_CHECK([ip -6 route show table 1001 | grep -q 2001:db8:1001::150]) + + +OVS_APP_EXIT_AND_WAIT([ovn-controller]) + +# Ensure system resources are cleaned up +AT_CHECK([ip link | grep -q ovnvrf1001:.*UP], [1]) +AT_CHECK([test `ip -6 route show table 1001 | wc -l` -eq 1], [1]) + +as ovn-sb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as ovn-nb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as northd +OVS_APP_EXIT_AND_WAIT([ovn-northd]) + +as +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d +/Failed to acquire.*/d +/connection dropped.*/d"]) +AT_CLEANUP +]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([route-exchange for DNAT and DNAT_AND_SNAT with gateway router IPv4]) +AT_KEYWORDS([route-exchange]) + +CHECK_VRF() +CHECK_CONNTRACK() +CHECK_CONNTRACK_NAT() +ovn_start +OVS_TRAFFIC_VSWITCHD_START() +ADD_BR([br-int]) +ADD_BR([br-ext], [set Bridge br-ext fail-mode=standalone]) + +# Set external-ids in br-int needed for ovn-controller +ovs-vsctl \ + -- set Open_vSwitch . external-ids:system-id=hv1 \ + -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ + -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ + -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ + -- set bridge br-int fail-mode=secure other-config:disable-in-band=true + +# Start ovn-controller +start_daemon ovn-controller + +ovn-appctl vlog/set route_exchange +check ovn-nbctl -- lr-add R1 \ + -- set Logical_Router R1 options:requested-tnl-key=1002 + +check ovn-nbctl ls-add sw0 +check ovn-nbctl ls-add public + +check ovn-nbctl --wait=hv sync + +AT_CHECK([ip link | grep -q ovnvrf1002:.*UP], [1]) + +check ovn-nbctl lrp-add R1 rp-sw0 00:00:01:01:02:03 192.168.1.1/24 +check ovn-nbctl -- lrp-add R1 rp-public 00:00:02:01:02:03 172.16.1.1/24 \ + -- lrp-set-options rp-public \ + maintain-vrf=true \ + redistribute-nat=true + +check ovn-nbctl set logical_router R1 options:chassis=hv1 + +check ovn-nbctl lsp-add sw0 sw0-rp -- set Logical_Switch_Port sw0-rp \ + type=router options:router-port=rp-sw0 \ + -- lsp-set-addresses sw0-rp router + +check ovn-nbctl lsp-add public public-rp -- set Logical_Switch_Port public-rp \ + type=router options:router-port=rp-public \ + -- lsp-set-addresses public-rp router + +check ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext + +check ovn-nbctl lsp-add public public1 \ + -- lsp-set-addresses public1 unknown \ + -- lsp-set-type public1 localnet \ + -- lsp-set-options public1 network_name=phynet + +check ovn-nbctl --wait=hv sync + +AT_CHECK([test `ip route show table 1002 | wc -l` -eq 2], [1]) + +# Create dnat_and_snat, dnat rules in R1 +check ovn-nbctl lr-nat-add R1 dnat_and_snat 172.16.1.10 192.168.1.10 +check ovn-nbctl lr-nat-add R1 dnat 172.16.1.11 192.168.1.11 + +check ovn-nbctl --wait=hv sync + +AT_CHECK([ip link | grep -q ovnvrf1002:.*UP]) +AT_CHECK([test `ip route show table 1002 | wc -l` -eq 2]) +AT_CHECK([ip route show table 1002 | grep -q 172.16.1.10]) +AT_CHECK([ip route show table 1002 | grep -q 172.16.1.11]) + + +OVS_APP_EXIT_AND_WAIT([ovn-controller]) + +# Ensure system resources are cleaned up +AT_CHECK([ip link | grep -q ovnvrf1000:.*UP], [1]) +AT_CHECK([test `ip route show table 1000 | wc -l` -eq 1], [1]) + +as ovn-sb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as ovn-nb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as northd +OVS_APP_EXIT_AND_WAIT([ovn-northd]) + +as +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d +/Failed to acquire.*/d +/connection dropped.*/d"]) +AT_CLEANUP +]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([route-exchange for DNAT and DNAT_AND_SNAT with gateway router IPv6]) +AT_KEYWORDS([route-exchange]) + +CHECK_VRF() +CHECK_CONNTRACK() +CHECK_CONNTRACK_NAT() +ovn_start +OVS_TRAFFIC_VSWITCHD_START() +ADD_BR([br-int]) +ADD_BR([br-ext], [set Bridge br-ext fail-mode=standalone]) + +# Set external-ids in br-int needed for ovn-controller +ovs-vsctl \ + -- set Open_vSwitch . external-ids:system-id=hv1 \ + -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ + -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ + -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ + -- set bridge br-int fail-mode=secure other-config:disable-in-band=true + +# Start ovn-controller +start_daemon ovn-controller + +ovn-appctl vlog/set route_exchange +check ovn-nbctl -- lr-add R1 \ + -- set Logical_Router R1 options:requested-tnl-key=1003 + +check ovn-nbctl ls-add sw0 +check ovn-nbctl ls-add public + +check ovn-nbctl --wait=hv sync + +AT_CHECK([ip link | grep -q ovnvrf1003:.*UP], [1]) + +check ovn-nbctl lrp-add R1 rp-sw0 00:00:01:01:02:03 2001:db8:100::1/64 +check ovn-nbctl -- lrp-add R1 rp-public 00:00:02:01:02:03 2001:db8:1003::1/64 \ + -- lrp-set-options rp-public \ + maintain-vrf=true \ + redistribute-nat=true + +check ovn-nbctl set logical_router R1 options:chassis=hv1 + +check ovn-nbctl lsp-add sw0 sw0-rp -- set Logical_Switch_Port sw0-rp \ + type=router options:router-port=rp-sw0 \ + -- lsp-set-addresses sw0-rp router + +check ovn-nbctl lsp-add public public-rp -- set Logical_Switch_Port public-rp \ + type=router options:router-port=rp-public \ + -- lsp-set-addresses public-rp router + +check ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext + +check ovn-nbctl lsp-add public public1 \ + -- lsp-set-addresses public1 unknown \ + -- lsp-set-type public1 localnet \ + -- lsp-set-options public1 network_name=phynet + +check ovn-nbctl --wait=hv sync + +AT_CHECK([test `ip -6 route show table 1003 | wc -l` -eq 2], [1]) + +# Create dnat_and_snat, dnat rules in R1 +check ovn-nbctl lr-nat-add R1 \ + dnat_and_snat 2001:db8:1003::150 2001:db8:100::100 +check ovn-nbctl lr-nat-add R1 \ + dnat 2001:db8:1003::151 2001:db8:100::100 + +check ovn-nbctl --wait=hv sync + +ovn-nbctl list nat +ovn-sbctl list port-binding + +AT_CHECK([ip link | grep -q ovnvrf1003:.*UP]) +AT_CHECK([test `ip -6 route show table 1003 | wc -l` -eq 2]) +AT_CHECK([ip -6 route show table 1003 | grep -q 2001:db8:1003::150]) +AT_CHECK([ip -6 route show table 1003 | grep -q 2001:db8:1003::151]) + +OVS_APP_EXIT_AND_WAIT([ovn-controller]) + +# Ensure system resources are cleaned up +AT_CHECK([ip link | grep -q ovnvrf1003:.*UP], [1]) +AT_CHECK([test `ip -6 route show table 1003 | wc -l` -eq 2], [1]) + +as ovn-sb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as ovn-nb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as northd +OVS_APP_EXIT_AND_WAIT([ovn-northd]) + +as +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d +/Failed to acquire.*/d +/connection dropped.*/d"]) +AT_CLEANUP +])