From patchwork Mon Nov 17 09:06:53 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rukomoinikova Aleksandra X-Patchwork-Id: 2165505 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=SPsHyueN; dkim-atps=neutral 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 4d922H6Kl9z1xwc for ; Mon, 17 Nov 2025 20:07:35 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 55300406D3; Mon, 17 Nov 2025 09:07:28 +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 cf-FnQgJE_O7; Mon, 17 Nov 2025 09:07:22 +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 smtp2.osuosl.org 7C69340428 Authentication-Results: smtp2.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key, unprotected) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=SPsHyueN Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp2.osuosl.org (Postfix) with ESMTPS id 7C69340428; Mon, 17 Nov 2025 09:07:22 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 2362AC063E; Mon, 17 Nov 2025 09:07:22 +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 CAF05C063D for ; Mon, 17 Nov 2025 09:07:20 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id BCFEA4092F for ; Mon, 17 Nov 2025 09:07:20 +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 KUxfyVZnkUkN for ; Mon, 17 Nov 2025 09:07:20 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=109.73.14.254; helo=mail3.k2.cloud; envelope-from=arukomoinikova@k2.cloud; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp4.osuosl.org 2F2C84091B Authentication-Results: smtp4.osuosl.org; dmarc=pass (p=none dis=none) header.from=k2.cloud DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 2F2C84091B Authentication-Results: smtp4.osuosl.org; dkim=pass (1024-bit key, unprotected) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=SPsHyueN Received: from mail3.k2.cloud (mail3.k2.cloud [109.73.14.254]) by smtp4.osuosl.org (Postfix) with ESMTPS id 2F2C84091B for ; Mon, 17 Nov 2025 09:07:18 +0000 (UTC) From: Alexandra Rukomoinikova DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=k2.cloud; s=cloudmail; t=1763370434; bh=oTbu3fuii7uzza1J8psNpy+439CFgDKE8l5jDmY7b4s=; h=From:To:Cc:Subject:Date; b=SPsHyueNxjVy1wJGa8XU+RP4I3qz901E02pivCViuqSmQdkF3aOk9Hg9RuhBeklW0 urFbdEP6R5QbnlKI1UtPisgGGx9ti/BoiGuNT0Cdb7KPNfr1r9tZtYCoHIHd1mjoay 4HoRN1HKlNV+ppvbmuDYhxt1OxIEgMV1F4ZDOyUk= To: dev@openvswitch.org Cc: Alexandra Rukomoinikova Date: Mon, 17 Nov 2025 12:06:53 +0300 Message-Id: <20251117090712.19708-1-arukomoinikova@k2.cloud> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 1/9] ovn-nb: Add LSP Health Check schema support. 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" Added tables for further implementation of service monitors for logical switch ports: New table: - Logical_Switch_Port_Health_Check: Health check configuration for logical switch port. Modified tables: - Logical_Switch_Port: Add 'health_checks' column referencing health checks configuration. Signed-off-by: Alexandra Rukomoinikova --- ovn-nb.ovsschema | 9 ++++++-- ovn-nb.xml | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema index cbb4f98e7..47da7ae18 100644 --- a/ovn-nb.ovsschema +++ b/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", - "version": "7.14.0", - "cksum": "3428479461 43444", + "version": "7.15.0", + "cksum": "1804537878 43761", "tables": { "NB_Global": { "columns": { @@ -179,6 +179,11 @@ "refType": "strong"}, "min": 0, "max": 1}}, + "health_checks": {"type": {"key": {"type": "uuid", + "refTable": "Logical_Switch_Port_Health_Check", + "refType": "weak"}, + "min": 0, + "max": "unlimited"}}, "external_ids": { "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}, diff --git a/ovn-nb.xml b/ovn-nb.xml index b5fe44e53..9202f0910 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -2115,6 +2115,11 @@ Please see the table. + + Health checks configuration for this logical switch port. + Please see the table. + + References a row in the OVN Northbound database's table. @@ -2171,6 +2176,55 @@ + +

+ Each row represents health check configuration for logical switch port. + Health checks are used to monitor reachability and health of backend + endpoints associated with logical switch port. Health check can be + configured to use different protocols (TCP, UDP, or ICMP) to verify + availability of target IP addresses. +

+ + + Valid protocols are tcp, udp, or + icmp. For tcp and udp + protocols - destination port must be specified. + + + + Source IP address used when sending health check probes. + + + + Destination port number for TCP and UDP health checks. + + + + A set of IP addresses to monitor. If no specific addresses are provided, + health check will use all addresses configured on logical switch port. + + + + The interval, in seconds, between service monitor checks. + + + + The time, in seconds, after which the service monitor check times + out. + + + + The number of successful checks after which the service is + considered online. + + + + The number of failure checks after which the service is considered + offline. + +
+

Each row represents one forwarding group. From patchwork Mon Nov 17 09:06:54 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rukomoinikova Aleksandra X-Patchwork-Id: 2165504 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=XnJTqb7u; dkim-atps=neutral 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 4d922D5x5kz1yHt for ; Mon, 17 Nov 2025 20:07:32 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 4E9C7821C3; Mon, 17 Nov 2025 09:07:29 +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 sn8XBk8X3xbN; Mon, 17 Nov 2025 09:07:23 +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 smtp1.osuosl.org 6173A81E37 Authentication-Results: smtp1.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=XnJTqb7u Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTPS id 6173A81E37; Mon, 17 Nov 2025 09:07:23 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 06EF8C0641; Mon, 17 Nov 2025 09:07:23 +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 B3303C063D for ; Mon, 17 Nov 2025 09:07:21 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 9A51A4092F for ; Mon, 17 Nov 2025 09:07:21 +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 qS4eQiJOpHwb for ; Mon, 17 Nov 2025 09:07:20 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=109.73.14.254; helo=mail3.k2.cloud; envelope-from=arukomoinikova@k2.cloud; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp4.osuosl.org 2F34440922 Authentication-Results: smtp4.osuosl.org; dmarc=pass (p=none dis=none) header.from=k2.cloud DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 2F34440922 Authentication-Results: smtp4.osuosl.org; dkim=pass (1024-bit key, unprotected) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=XnJTqb7u Received: from mail3.k2.cloud (mail3.k2.cloud [109.73.14.254]) by smtp4.osuosl.org (Postfix) with ESMTPS id 2F34440922 for ; Mon, 17 Nov 2025 09:07:18 +0000 (UTC) From: Alexandra Rukomoinikova DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=k2.cloud; s=cloudmail; t=1763370435; bh=BHOb3bbi8wkLu/JU2OkLQUBuwyGYAmwg8yXFaTs18Ts=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=XnJTqb7uhH05Yney68gQpeAqdPN+GvhwtbvkZACp5PRH6VEIp4++4N9r32oFWd1bU r4n5e3vzYQC19Fmc0kvz4FBtEDIi7XO1BPtNd96PxwNscdYYuD3ihVMexhbNk139rM kbhpGonv8WyTRU5lT+m+CRo76QIWZGSSZDYaw4bU= To: dev@openvswitch.org Cc: Alexandra Rukomoinikova Date: Mon, 17 Nov 2025 12:06:54 +0300 Message-Id: <20251117090712.19708-2-arukomoinikova@k2.cloud> In-Reply-To: <20251117090712.19708-1-arukomoinikova@k2.cloud> References: <20251117090712.19708-1-arukomoinikova@k2.cloud> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 2/9] ovn-nbctl: CLI Commands for lsp health check support. 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" Added commands to create, delete, and describe health checks for logical switch ports. Signed-off-by: Alexandra Rukomoinikova --- lib/ovn-util.c | 17 ++ lib/ovn-util.h | 2 + ovn-nb.ovsschema | 21 +- tests/ovn-nbctl.at | 186 ++++++++++++++ utilities/ovn-nbctl.8.xml | 54 ++++ utilities/ovn-nbctl.c | 512 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 791 insertions(+), 1 deletion(-) diff --git a/lib/ovn-util.c b/lib/ovn-util.c index cec029e42..16f7eb2b9 100644 --- a/lib/ovn-util.c +++ b/lib/ovn-util.c @@ -1704,3 +1704,20 @@ is_partial_uuid_match(const struct uuid *uuid, const char *match) s2 = strip_leading_zero(s2); return !strncmp(s1, s2, strlen(s2)); } + +char * +skip_mac_address_from_lsp_address(const char *address_with_mac) +{ + if (!address_with_mac) { + return NULL; + } + const char *ptr = address_with_mac; + while (*ptr == ' ') { + ptr++; + } + ptr += (char) 17; + while (*ptr == ' ') { + ptr++; + } + return (char *) ptr; +} diff --git a/lib/ovn-util.h b/lib/ovn-util.h index 611f80f1e..09e2c8b1f 100644 --- a/lib/ovn-util.h +++ b/lib/ovn-util.h @@ -733,4 +733,6 @@ NEIGH_REDISTRIBUTE_MODES enum neigh_redistribute_mode parse_neigh_dynamic_redistribute(const struct smap *options); +char *skip_mac_address_from_lsp_address(const char *address_with_mac); + #endif /* OVN_UTIL_H */ diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema index 47da7ae18..f59e80c20 100644 --- a/ovn-nb.ovsschema +++ b/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", "version": "7.15.0", - "cksum": "1804537878 43761", + "cksum": "42875815 44684", "tables": { "NB_Global": { "columns": { @@ -247,6 +247,25 @@ "min": 0, "max": "unlimited"}}}, "indexes": [["name"], ["id"]], "isRoot": true}, + "Logical_Switch_Port_Health_Check": { + "columns": { + "protocol": { + "type": {"key": {"type": "string", + "enum": ["set", ["tcp", "udp", "icmp"]]}, + "min": 0, "max": 1}}, + "src_ip": {"type": "string"}, + "port": {"type": {"key": {"type": "integer", + "minInteger": 0, + "maxInteger": 65535}}}, + "addresses": {"type": {"key": "string", + "min": 0, + "max": "unlimited"}}, + "options": { + "type": {"key": "string", + "value": "string", + "min": 0, + "max": "unlimited"}}}, + "isRoot": true}, "Forwarding_Group": { "columns": { "name": {"type": "string"}, diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at index dccf30758..62b89945b 100644 --- a/tests/ovn-nbctl.at +++ b/tests/ovn-nbctl.at @@ -3499,3 +3499,189 @@ AT_CHECK([ovn-nbctl --may-exist lsp-add-localnet-port ls ln_port net1], [1], [], check ovn-nbctl lsp-set-options ln_port network_name=net1 check ovn-nbctl --may-exist lsp-add-localnet-port ls ln_port net1 ]) + +dnl --------------------------------------------------------------------- + +AT_SETUP([ovn-nbctl - Logical Switch Port Health Check]) +OVN_NBCTL_TEST_START daemon + +# Create logical switch port +AT_CHECK([ovn-nbctl ls-add ls0]) +AT_CHECK([ovn-nbctl lsp-add ls0 lport0]) +AT_CHECK([ovn-nbctl lsp-set-addresses lport0 "00:11:22:33:44:55 192.168.1.10" "00:11:22:33:44:56 192.168.1.11"]) + +# Create icmp health check with the specified addresses +AT_CHECK([ovn-nbctl lsp-hc-add lport0 icmp 192.168.0.255 192.168.1.10 192.168.1.11]) +AT_CHECK([ovn-nbctl lsp-hc-list lport0], [0], [dnl +Logical Switch Port lport0: + Protocol : icmp + Source IP : 192.168.0.255 + Addresses : 192.168.1.10, 192.168.1.11 +]) + +# Check hc attaching to logical switch port +hc_icmp_uuid=$(fetch_column nb:logical_switch_port_health_check _uuid src_ip="192.168.0.255") +check_column "$hc_icmp_uuid" nb:logical_switch_port health_checks + +# Create tcp health check with the specified addresses +AT_CHECK([ovn-nbctl lsp-hc-add lport0 tcp 10.0.0.2 80 192.168.1.10]) +AT_CHECK([ovn-nbctl lsp-hc-list lport0], [0], [dnl +Logical Switch Port lport0: + Protocol : tcp + Source IP : 10.0.0.2 + Port : 80 + Addresses : 192.168.1.10 + + Protocol : icmp + Source IP : 192.168.0.255 + Addresses : 192.168.1.10, 192.168.1.11 +]) +hc_tcp_uuid=$(fetch_column nb:logical_switch_port_health_check _uuid src_ip="10.0.0.2") + +# Create udp health check with the specified addresses +AT_CHECK([ovn-nbctl lsp-hc-add lport0 udp 10.0.0.3 53 192.168.1.11]) +AT_CHECK([ovn-nbctl lsp-hc-list lport0], [0], [dnl +Logical Switch Port lport0: + Protocol : tcp + Source IP : 10.0.0.2 + Port : 80 + Addresses : 192.168.1.10 + + Protocol : udp + Source IP : 10.0.0.3 + Port : 53 + Addresses : 192.168.1.11 + + Protocol : icmp + Source IP : 192.168.0.255 + Addresses : 192.168.1.10, 192.168.1.11 +]) +hc_udp_uuid=$(fetch_column nb:logical_switch_port_health_check _uuid src_ip="10.0.0.3") + +check_column "$hc_icmp_uuid $hc_tcp_uuid $hc_udp_uuid" nb:logical_switch_port health_checks + +AT_CHECK([ovn-nbctl lsp-hc-del lport0 $hc_icmp_uuid]) +# Check hcs detaching to logical switch port +check_column "$hc_tcp_uuid $hc_udp_uuid" nb:logical_switch_port health_checks + +AT_CHECK([ovn-nbctl lsp-hc-list lport0], [0], [dnl +Logical Switch Port lport0: + Protocol : tcp + Source IP : 10.0.0.2 + Port : 80 + Addresses : 192.168.1.10 + + Protocol : udp + Source IP : 10.0.0.3 + Port : 53 + Addresses : 192.168.1.11 +]) + +AT_CHECK([ovn-nbctl lsp-hc-del lport0]) +AT_CHECK([ovn-nbctl lsp-hc-list lport0], [0], [dnl]) + +# Create health check without specified addresses +AT_CHECK([ovn-nbctl lsp-hc-add lport0 icmp 10.0.0.4]) +AT_CHECK([ovn-nbctl lsp-hc-list lport0], [0], [dnl +Logical Switch Port lport0: + Protocol : icmp + Source IP : 10.0.0.4 +]) + +# Check invalid protocol +AT_CHECK([ovn-nbctl lsp-hc-add lport0 stcp 10.0.0.1], [1], [], [stderr]) +AT_CHECK([grep "Type must be icmp, tcp or udp" stderr], [0], [ignore]) + +# Check invalid source IP +AT_CHECK([ovn-nbctl lsp-hc-add lport0 icmp invalid_ip], [1], [], [stderr]) +AT_CHECK([grep "Not a valid IPv4 or IPv6 address" stderr], [0], [ignore]) + +# Check TCP/UDP without destination port +AT_CHECK([ovn-nbctl lsp-hc-add lport0 tcp 10.0.0.1], [1], [], [stderr]) +AT_CHECK([grep "Destination port required for tcp health check" stderr], [0], [ignore]) + +# Check invalid destination port +AT_CHECK([ovn-nbctl lsp-hc-add lport0 tcp 10.0.0.1 70000], [1], [], [stderr]) +AT_CHECK([grep "port must in range 0...65535" stderr], [0], [ignore]) + +# Check IP address not configured on port +AT_CHECK([ovn-nbctl lsp-hc-add lport0 icmp 10.0.0.1 192.168.99.99], [1], [], [stderr]) +AT_CHECK([grep "Address 192.168.99.99 not configured on port" stderr], [0], [ignore]) + +# Check Duplicate health check configuration +AT_CHECK([ovn-nbctl lsp-hc-add lport0 icmp 10.0.0.4], [1], [], [stderr]) +AT_CHECK([grep "Health check already exists" stderr], [0], [ignore]) + +AT_CHECK([ovn-nbctl lsp-hc-add lport0 icmp 10.0.0.1 192.168.1.10]) +AT_CHECK([ovn-nbctl lsp-hc-add lport0 icmp 10.0.0.1 192.168.1.10], [1], [], [stderr]) +AT_CHECK([grep "Health check already exists" stderr], [0], [ignore]) + +# Check same protocol with different ports - it's ok +AT_CHECK([ovn-nbctl lsp-hc-add lport0 tcp 10.0.0.1 90 192.168.1.10]) +AT_CHECK([ovn-nbctl lsp-hc-add lport0 tcp 10.0.0.1 443 192.168.1.10], [0], [], [ignore]) + +# Check different protocol with same ports - it's ok +AT_CHECK([ovn-nbctl lsp-hc-add lport0 tcp 10.0.0.1 80 192.168.1.10]) +AT_CHECK([ovn-nbctl lsp-hc-add lport0 udp 10.0.0.1 80 192.168.1.10], [0], [], [ignore]) + +# Check different source ip with same ports and addresses - it's ok +AT_CHECK([ovn-nbctl lsp-hc-add lport0 tcp 10.0.0.1 92 192.168.1.10]) +AT_CHECK([ovn-nbctl lsp-hc-add lport0 tcp 10.0.0.2 92 192.168.1.10], [0], [], [ignore]) + +# Check multipal same addresses +AT_CHECK([ovn-nbctl lsp-hc-add lport0 tcp 10.0.0.1 93 192.168.1.10 192.168.1.11]) +AT_CHECK([ovn-nbctl lsp-hc-add lport0 tcp 10.0.0.1 93 192.168.1.10 192.168.1.11], [1], [], [stderr]) +AT_CHECK([grep "Health check already exists" stderr], [0], [ignore]) + +# Check supported logical switch port type for monitoring +AT_CHECK([ovn-nbctl lsp-add ls0 lport1]) +AT_CHECK([ovn-nbctl lsp-set-type lport1 router]) +AT_CHECK([ovn-nbctl lsp-hc-add lport1 icmp 10.0.0.1], [1], [], [stderr]) +AT_CHECK([grep "Health check monitoring supported only for port with vif type" stderr], [0], [ignore]) + +AT_CHECK([ovn-nbctl lsp-hc-del lport0]) + +# Test IPv6 addresses support +AT_CHECK([ovn-nbctl lsp-add ls0 lport3]) +AT_CHECK([ovn-nbctl lsp-set-addresses lport3 "00:11:22:33:44:57 2001:db8::1"]) +AT_CHECK([ovn-nbctl lsp-hc-add lport3 icmp 2001:db8::2 2001:db8::1]) +AT_CHECK([ovn-nbctl lsp-hc-list lport3], [0], [dnl +Logical Switch Port lport3: + Protocol : icmp + Source IP : 2001:db8::2 + Addresses : 2001:db8::1 +]) + +# Check options printing +AT_CHECK([ovn-nbctl lsp-hc-add lport0 icmp 10.0.0.4 192.168.1.10 192.168.1.11]) +AT_CHECK([ovn-nbctl lsp-hc-list lport0], [0], [dnl +Logical Switch Port lport0: + Protocol : icmp + Source IP : 10.0.0.4 + Addresses : 192.168.1.10, 192.168.1.11 +]) +hc_icmp_uuid=$(fetch_column nb:logical_switch_port_health_check _uuid src_ip="10.0.0.4") + +AT_CHECK([ovn-nbctl set logical_switch_port_health_check $hc_icmp_uuid options:interval=3]) +AT_CHECK([ovn-nbctl set logical_switch_port_health_check $hc_icmp_uuid options:timeout=30]) +AT_CHECK([ovn-nbctl set logical_switch_port_health_check $hc_icmp_uuid options:success_count=1]) +AT_CHECK([ovn-nbctl set logical_switch_port_health_check $hc_icmp_uuid options:failure_count=2]) + +AT_CHECK([ovn-nbctl lsp-hc-list lport0], [0], [dnl +Logical Switch Port lport0: + Protocol : icmp + Source IP : 10.0.0.4 + Addresses : 192.168.1.10, 192.168.1.11 + Interval : 3 + Timeout : 30 + Success count : 1 + Failure count : 2 +]) + +AT_CHECK([ovn-nbctl lsp-hc-del lport0]) +AT_CHECK([ovn-nbctl lsp-hc-del lport3]) +check_row_count nb:Logical_Switch_Port_Health_Check 0 + +OVN_NBCTL_TEST_STOP "/terminating with signal 15/d" +AT_CLEANUP + diff --git a/utilities/ovn-nbctl.8.xml b/utilities/ovn-nbctl.8.xml index 7df902944..efc781d77 100644 --- a/utilities/ovn-nbctl.8.xml +++ b/utilities/ovn-nbctl.8.xml @@ -1822,6 +1822,60 @@ +

Health Check commands

+
+
lsp-hc-add PORT PROTOCOL + SOURCE_IP [DST_PORT] [ADDRESS]...
+
+

+ Creates a new health check configuration for the logical switch port + PORT with the below mandatory arguments. +

+ +

+ PROTOCOL specifies the health check protocol - + tcp, udp, or icmp. +

+ +

+ SOURCE_IP specifies the source IP address used when + sending health check probes. +

+ +

+ DST_PORT specifies the destination port number for + tcp and udp health checks. This parameter + is ignored for icmp protocol. +

+ +

+ ADDRESS specifies one or more IP addresses to monitor. + If no addresses are provided, the health check will monitor all IP + addresses configured on the logical switch port. +

+ +

+ Additional health check options such as interval, timeout, + success count, and failure count can be configured separately. +

+
+ +
lsp-hc-del PORT [HC_UUID]
+
+

+ Deletes health check configuration for the logical switch port + PORT. +

+
+ +
lsp-hc-list PORT
+
+ Lists all health check configurations for the logical switch port + PORT, including protocol, source IP, destination port, + monitored addresses, and current status. +
+
+

Synchronization Commands

diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c index cdf6b578a..b8802ab30 100644 --- a/utilities/ovn-nbctl.c +++ b/utilities/ovn-nbctl.c @@ -66,6 +66,18 @@ string_ptr(char *ptr) return (ptr) ? ptr : s; } +static char *OVS_WARN_UNUSED_RESULT +parse_l4_port_range(const char *arg, int64_t *port_p) +{ + int64_t port; + if (!ovs_scan(arg, "%"SCNd64, &port) + || port < 0 || port > UINT16_MAX) { + return xasprintf("%s: port must in range 0...65535", arg); + } + *port_p = port; + return NULL; +} + static void nbctl_add_base_prerequisites(struct ovsdb_idl *idl, enum nbctl_wait_type wait_type) @@ -544,6 +556,12 @@ MAC_Binding commands:\n\ Delete Static_MAC_Binding entry\n\ static-mac-binding-list List all Static_MAC_Binding entries\n\ \n\ +Logical Switch Port Health Check:\n\ + lsp-hc-add PORT PROTOCOL SOURCE_IP DST_PORT [ADDRESS]...\n\ + add health check monitoring for PORT\n\ + lsp-hc-del PORT HC_UUID delete health check monitoring for PORT\n\ + lsp-hc-list PORT print health check for PORT\n\ +\n\ %s\ %s\ \n\ @@ -8677,6 +8695,490 @@ nbctl_lsp_add_misc_port(struct ctl_context *ctx) shash_add(&nbctx->lsp_to_ls_map, lsp_name, ls); } +/* Logical Switch Port Health Check Functions. */ +enum health_check_protocol { + LSP_ICMP_HEALTH_CHECK, + LSP_TCP_HEALTH_CHECK, + LSP_UDP_HEALTH_CHECK, +}; + +static bool +parse_health_check_protocol(struct ctl_context *ctx, const char *type, + enum health_check_protocol *protocol) +{ + if (!strcmp(type, "icmp")) { + *protocol = LSP_ICMP_HEALTH_CHECK; + return true; + } else if (!strcmp(type, "tcp")) { + *protocol = LSP_TCP_HEALTH_CHECK; + return true; + } else if (!strcmp(type, "udp")) { + *protocol = LSP_UDP_HEALTH_CHECK; + return true; + } else { + ctl_error(ctx, "%s: Type must be icmp, tcp or udp", type); + return false; + } +} + +static void +lsp_health_check_get_duplicate( + int proto, const char *src_ip, + int64_t port, struct sset *addresses, + const struct nbrec_logical_switch_port *lsp, + const struct nbrec_logical_switch_port_health_check **lsp_hc) +{ + *lsp_hc = NULL; + + for (size_t i = 0; i < lsp->n_health_checks; i++) { + const struct nbrec_logical_switch_port_health_check *lsp_hc_p = + lsp->health_checks[i]; + + if (src_ip && strcmp(lsp_hc_p->src_ip, src_ip)) { + continue; + } + + const char *target_proto = + (proto == LSP_ICMP_HEALTH_CHECK) ? "icmp" : + (proto == LSP_TCP_HEALTH_CHECK) ? "tcp" : "udp"; + if (strcmp(lsp_hc_p->protocol, target_proto)) { + continue; + } + + if (proto != LSP_ICMP_HEALTH_CHECK && lsp_hc_p->port != port) { + continue; + } + + if (!addresses || sset_is_empty(addresses)) { + *lsp_hc = lsp_hc_p; + return; + } + + bool addresses_found = true; + for (size_t j = 0; j < lsp_hc_p->n_addresses; j++) { + if (!sset_contains(addresses, lsp_hc_p->addresses[j])) { + addresses_found = false; + break; + } + } + + if (addresses_found) { + *lsp_hc = lsp_hc_p; + return; + } + } +} + +static char ** +_get_lsp_ip_addresses(char **lsp_addresses, + int lsp_n_addresses, + int *lsp_n_ip_addresses) +{ + char **lsp_ip_addresses_p = NULL; + *lsp_n_ip_addresses = 0; + size_t n_capacity = 0; + size_t count = 0; + + for (size_t i = 0; i < lsp_n_addresses; i++) { + char *address_without_mac = + skip_mac_address_from_lsp_address(lsp_addresses[i]); + + if (address_without_mac && address_without_mac[0]) { + if (count == n_capacity) { + lsp_ip_addresses_p = x2nrealloc(lsp_ip_addresses_p, + &n_capacity, + sizeof *lsp_ip_addresses_p); + } + lsp_ip_addresses_p[count] = xstrdup(address_without_mac); + count++; + } + } + + *lsp_n_ip_addresses = count; + return lsp_ip_addresses_p; +} + +static bool +_lsp_contains_ip_address(char **lsp_ip_addresses, + size_t lsp_n_ip_addresses, + char *ip_address) +{ + for (size_t i = 0; i < lsp_n_ip_addresses; i++) { + if (!strcmp(lsp_ip_addresses[i], ip_address)) { + return true; + } + } + + return false; +} + +static char * OVS_WARN_UNUSED_RESULT +find_logical_switch_port_health_check_by_uuid( + struct ctl_context *ctx, + const char *id, + const struct nbrec_logical_switch_port_health_check **lsp_hc_p) +{ + const struct nbrec_logical_switch_port_health_check *lsp_hc; + *lsp_hc_p = NULL; + + struct uuid lsp_hc_uuid; + bool is_uuid = uuid_from_string(&lsp_hc_uuid, id); + + if (!is_uuid) { + return xasprintf("%s: Invalid UUID format", id); + } + + lsp_hc = nbrec_logical_switch_port_health_check_get_for_uuid( + ctx->idl, &lsp_hc_uuid); + + if (!lsp_hc) { + return xasprintf("%s: Logical Switch Port Health Check not found", id); + } + + *lsp_hc_p = lsp_hc; + + return NULL; +} + +static void +nbctl_pre_lsp_health_check_add(struct ctl_context *ctx) +{ + ovsdb_idl_add_column(ctx->idl, + &nbrec_logical_switch_port_col_name); + ovsdb_idl_add_column(ctx->idl, + &nbrec_logical_switch_port_col_addresses); + ovsdb_idl_add_column(ctx->idl, + &nbrec_logical_switch_port_col_health_checks); + ovsdb_idl_add_column(ctx->idl, + &nbrec_logical_switch_port_health_check_col_port); + ovsdb_idl_add_column(ctx->idl, + &nbrec_logical_switch_port_health_check_col_protocol); + ovsdb_idl_add_column(ctx->idl, + &nbrec_logical_switch_port_health_check_col_src_ip); + ovsdb_idl_add_column(ctx->idl, + &nbrec_logical_switch_port_health_check_col_addresses); +} + +static void +nbctl_lsp_health_check_add(struct ctl_context *ctx) +{ + const struct nbrec_logical_switch_port *lsp = NULL; + const struct nbrec_logical_switch_port_health_check *lsp_hc = NULL; + + const char *port = ctx->argv[1]; + const char *type = ctx->argv[2]; + const char *src_ip = ctx->argv[3]; + enum health_check_protocol protocol; + char **lsp_ip_addresses = NULL; + int lsp_n_ip_addresses = 0; + char *validated_src_ip = NULL; + struct sset target_ips; + sset_init(&target_ips); + + char *error; + error = lsp_by_name_or_uuid(ctx, port, true, &lsp); + if (error) { + ctx->error = error; + return; + } + + if (lsp->type[0]) { + ctl_error(ctx, "%s: Health check monitoring supported only for" + " port with vif type", lsp->type); + goto cleanup; + } + + if (!parse_health_check_protocol(ctx, type, &protocol)) { + goto cleanup; + } + + validated_src_ip = normalize_addr_str(src_ip); + if (!validated_src_ip) { + ctl_error(ctx, "%s: Not a valid IPv4 or IPv6 address", + ctx->argv[3]); + goto cleanup; + } + + int64_t destination_port = 0; + if (protocol == LSP_TCP_HEALTH_CHECK || + protocol == LSP_UDP_HEALTH_CHECK) { + if (ctx->argc < 5) { + ctl_error(ctx, "Destination port required for %s health check", + type); + goto cleanup; + } + + error = parse_l4_port_range(ctx->argv[4], &destination_port); + if (error) { + ctx->error = error; + goto cleanup; + } + } + + size_t target_ips_start_index; + if (protocol == LSP_ICMP_HEALTH_CHECK) { + target_ips_start_index = 4; + } else { + target_ips_start_index = 5; + } + + if (ctx->argc > target_ips_start_index) { + lsp_ip_addresses = _get_lsp_ip_addresses(lsp->addresses, + lsp->n_addresses, + &lsp_n_ip_addresses); + + for (int i = target_ips_start_index; i < ctx->argc; i++) { + char *ip_addr = ctx->argv[i]; + + char *validated_ip = normalize_addr_str(ip_addr); + if (!validated_ip) { + free(validated_ip); + ctl_error(ctx, "%s: Not a valid IPv4 or IPv6 address", + ip_addr); + goto cleanup; + } + + if (!_lsp_contains_ip_address(lsp_ip_addresses, + lsp_n_ip_addresses, + ip_addr)) { + free(validated_ip); + ctl_error(ctx, "%s: Address %s not configured on port", + lsp->name, ip_addr); + goto cleanup; + } + + sset_add(&target_ips, validated_ip); + free(validated_ip); + } + } + + lsp_health_check_get_duplicate(protocol, + src_ip, + destination_port, + &target_ips, + lsp, + &lsp_hc); + + if (lsp_hc) { + ctl_error(ctx, "Health check already exists"); + goto cleanup; + } + + lsp_hc = nbrec_logical_switch_port_health_check_insert(ctx->txn); + nbrec_logical_switch_port_health_check_set_protocol(lsp_hc, type); + nbrec_logical_switch_port_health_check_set_src_ip(lsp_hc, src_ip); + nbrec_logical_switch_port_health_check_set_port(lsp_hc, destination_port); + + if (ctx->argc > target_ips_start_index) { + size_t num_target_ips = ctx->argc - target_ips_start_index; + nbrec_logical_switch_port_health_check_set_addresses( + lsp_hc, (const char **) ctx->argv + target_ips_start_index, + num_target_ips); + } else { + nbrec_logical_switch_port_health_check_set_addresses(lsp_hc, NULL, 0); + } + + nbrec_logical_switch_port_update_health_checks_addvalue(lsp, lsp_hc); + +cleanup: + if (lsp_ip_addresses) { + for (size_t i = 0; i < lsp_n_ip_addresses; i++) { + free(lsp_ip_addresses[i]); + } + free(lsp_ip_addresses); + } + sset_destroy(&target_ips); + free(validated_src_ip); +} + +static void +nbctl_pre_lsp_health_check_del(struct ctl_context *ctx) +{ + ovsdb_idl_add_column(ctx->idl, + &nbrec_logical_switch_port_col_name); + ovsdb_idl_add_column(ctx->idl, + &nbrec_logical_switch_port_col_health_checks); + ovsdb_idl_add_column(ctx->idl, + &nbrec_logical_switch_port_health_check_col_protocol); +} + +static void +nbctl_lsp_health_check_del(struct ctl_context *ctx) +{ + const struct nbrec_logical_switch_port_health_check *lsp_hc = NULL; + const struct nbrec_logical_switch_port *lsp = NULL; + const char *port_id = ctx->argv[1]; + const char *hc_uuid = ctx->argv[2]; + + char *error; + error = lsp_by_name_or_uuid(ctx, port_id, true, &lsp); + if (error) { + ctx->error = error; + return; + } + + if (!lsp) { + ctl_error(ctx, "Logical Switch Port with id %s not found", + port_id); + return; + } + + if (hc_uuid) { + error = find_logical_switch_port_health_check_by_uuid(ctx, + hc_uuid, + &lsp_hc); + if (error) { + ctx->error = error; + return; + } + + nbrec_logical_switch_port_update_health_checks_delvalue(lsp, lsp_hc); + nbrec_logical_switch_port_health_check_delete(lsp_hc); + return; + } + + for (size_t i = 0; i < lsp->n_health_checks; i++) { + nbrec_logical_switch_port_update_health_checks_delvalue( + lsp, lsp->health_checks[i]); + nbrec_logical_switch_port_health_check_delete(lsp->health_checks[i]); + } +} + +static int +cmp_lsp_hc(const void *lsp_hc_1_, const void *lsp_hc_2_) +{ + const struct nbrec_logical_switch_port_health_check *const *lsp_hc_1p = + lsp_hc_1_; + const struct nbrec_logical_switch_port_health_check *const *lsp_hc_2p = + lsp_hc_2_; + const struct nbrec_logical_switch_port_health_check *lsp_hc_1 = + *lsp_hc_1p; + const struct nbrec_logical_switch_port_health_check *lsp_hc_2 = + *lsp_hc_2p; + + int src_ip_cmp = strcmp(lsp_hc_1->src_ip, lsp_hc_2->src_ip); + if (src_ip_cmp) { + return src_ip_cmp; + } + + int protocol_cmp = strcmp(lsp_hc_1->protocol, lsp_hc_2->protocol); + if (protocol_cmp != 0) { + return protocol_cmp; + } + + if (strcmp(lsp_hc_1->protocol, "icmp") != 0) { + if (lsp_hc_1->port != lsp_hc_2->port) { + return lsp_hc_1->port < lsp_hc_2->port ? -1 : 1; + } + } + + if (lsp_hc_1->n_addresses != lsp_hc_2->n_addresses) { + return lsp_hc_1->n_addresses < lsp_hc_2->n_addresses ? -1 : 1; + } + + size_t min_n_addresses = lsp_hc_1->n_addresses < lsp_hc_2->n_addresses ? + lsp_hc_1->n_addresses : lsp_hc_2->n_addresses; + + for (size_t i = 0; i < min_n_addresses; i++) { + int ip_cmp = strcmp(lsp_hc_1->addresses[i], lsp_hc_2->addresses[i]); + if (ip_cmp) { + return ip_cmp; + } + } + + return 0; +} + +static void +nbctl_pre_lsp_health_check_list(struct ctl_context *ctx) +{ + ovsdb_idl_add_column(ctx->idl, + &nbrec_logical_switch_port_col_name); + ovsdb_idl_add_column(ctx->idl, + &nbrec_logical_switch_port_col_health_checks); + ovsdb_idl_add_column(ctx->idl, + &nbrec_logical_switch_port_health_check_col_port); + ovsdb_idl_add_column(ctx->idl, + &nbrec_logical_switch_port_health_check_col_protocol); + ovsdb_idl_add_column(ctx->idl, + &nbrec_logical_switch_port_health_check_col_src_ip); + ovsdb_idl_add_column(ctx->idl, + &nbrec_logical_switch_port_health_check_col_addresses); +} + +static void +nbctl_lsp_health_check_list(struct ctl_context *ctx) +{ + const struct nbrec_logical_switch_port_health_check **lsp_hcs; + const struct nbrec_logical_switch_port *lsp = NULL; + const char *port = ctx->argv[1]; + + char *error; + error = lsp_by_name_or_uuid(ctx, port, true, &lsp); + if (error) { + ctx->error = error; + return; + } + + if (!lsp->n_health_checks) { + return; + } + + lsp_hcs = xmalloc(sizeof *lsp_hcs * lsp->n_health_checks); + for (size_t i = 0; i < lsp->n_health_checks; i++) { + lsp_hcs[i] = lsp->health_checks[i]; + } + + qsort(lsp_hcs, lsp->n_health_checks, sizeof *lsp_hcs, cmp_lsp_hc); + + ds_put_format(&ctx->output, "Logical Switch Port %s:\n", port); + for (size_t i = 0; i < lsp->n_health_checks; i++) { + const struct nbrec_logical_switch_port_health_check *hc + = lsp_hcs[i]; + ds_put_format(&ctx->output, " Protocol : %s\n", + hc->protocol); + ds_put_format(&ctx->output, " Source IP : %s\n", + hc->src_ip); + if (strcmp(hc->protocol, "icmp")) { + ds_put_format(&ctx->output, " Port : %"PRId64"\n", + hc->port); + } + if (hc->n_addresses) { + ds_put_format(&ctx->output, " Addresses : "); + for (size_t j = 0; j < hc->n_addresses; j++) { + if (j > 0) { + ds_put_format(&ctx->output, ", "); + } + ds_put_format(&ctx->output, "%s", hc->addresses[j]); + } + ds_put_format(&ctx->output, "\n"); + } + int interval = smap_get_int(&hc->options, "interval", 0); + int timeout = smap_get_int(&hc->options, "timeout", 0); + int success_count = smap_get_int(&hc->options, "success_count", 0); + int failure_count = smap_get_int(&hc->options, "failure_count", 0); + if (interval) { + ds_put_format(&ctx->output, " Interval : %d\n", + interval); + } + if (timeout) { + ds_put_format(&ctx->output, " Timeout : %d\n", + timeout); + } + if (success_count) { + ds_put_format(&ctx->output, " Success count : %d\n", + success_count); + } + if (failure_count) { + ds_put_format(&ctx->output, " Failure count : %d\n", + failure_count); + } + if (i < lsp->n_health_checks - 1) { + ds_put_format(&ctx->output, "\n"); + } + } +} + static const struct ctl_table_class tables[NBREC_N_TABLES] = { [NBREC_TABLE_DHCP_OPTIONS].row_ids = {{&nbrec_logical_switch_port_col_name, NULL, @@ -9064,6 +9566,16 @@ static const struct ctl_command_syntax nbctl_commands[] = { nbctl_pre_static_mac_binding, nbctl_static_mac_binding_list, NULL, "", RO }, + /* Health Check commands */ + {"lsp-hc-add", 2, INT_MAX, "PORT TYPE SRC_IP [DST_PORT] [ADDRESS]", + nbctl_pre_lsp_health_check_add, nbctl_lsp_health_check_add, + NULL, "", RW }, + {"lsp-hc-del", 1, INT_MAX, "PORT [HC_UUID]", + nbctl_pre_lsp_health_check_del, nbctl_lsp_health_check_del, + NULL, "", RW }, + {"lsp-hc-list", 1, 1, "PORT", nbctl_pre_lsp_health_check_list, + nbctl_lsp_health_check_list, NULL, "", RW }, + {NULL, 0, 0, NULL, NULL, NULL, NULL, "", RO}, }; From patchwork Mon Nov 17 09:06:55 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rukomoinikova Aleksandra X-Patchwork-Id: 2165507 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=ZFKUKcWg; dkim-atps=neutral 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 4d922M2ck2z1yHt for ; Mon, 17 Nov 2025 20:07:39 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id DB8C840EC6; Mon, 17 Nov 2025 09:07:37 +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 9RtUWqjlKI2y; Mon, 17 Nov 2025 09:07: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 smtp4.osuosl.org A74504091B Authentication-Results: smtp4.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=ZFKUKcWg Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp4.osuosl.org (Postfix) with ESMTPS id A74504091B; Mon, 17 Nov 2025 09:07:27 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 59E7DC063F; Mon, 17 Nov 2025 09:07:27 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 4B32CC063F for ; Mon, 17 Nov 2025 09:07:25 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 3DD52606BE for ; Mon, 17 Nov 2025 09:07:25 +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 58I0WLVQFRLQ for ; Mon, 17 Nov 2025 09:07:20 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=109.73.14.254; helo=mail3.k2.cloud; envelope-from=arukomoinikova@k2.cloud; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp3.osuosl.org 7FB2460A8D Authentication-Results: smtp3.osuosl.org; dmarc=pass (p=none dis=none) header.from=k2.cloud DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 7FB2460A8D Authentication-Results: smtp3.osuosl.org; dkim=pass (1024-bit key, unprotected) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=ZFKUKcWg Received: from mail3.k2.cloud (mail3.k2.cloud [109.73.14.254]) by smtp3.osuosl.org (Postfix) with ESMTPS id 7FB2460A8D for ; Mon, 17 Nov 2025 09:07:19 +0000 (UTC) From: Alexandra Rukomoinikova DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=k2.cloud; s=cloudmail; t=1763370437; bh=QEjb6SK3EivGJayG7lr6TDt4vkL4VH08IgboU3wlI+8=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=ZFKUKcWgw/SolFv6cKVE5ACeZdp+9paSPwi8QB7SACWyNjUZlDybB4OC5EVx1HUnN +JYYsFFiM2nIxlNi4RqiBSUWANT7kX9DT6V+UCxZTe9QCzXULBKGZDo0ZG+OTac/fX OpCeJ1gJ6Bc6EplOh/BdeMw2/jT4GQi6Tn6Xfmk0= To: dev@openvswitch.org Cc: Alexandra Rukomoinikova Date: Mon, 17 Nov 2025 12:06:55 +0300 Message-Id: <20251117090712.19708-3-arukomoinikova@k2.cloud> In-Reply-To: <20251117090712.19708-1-arukomoinikova@k2.cloud> References: <20251117090712.19708-1-arukomoinikova@k2.cloud> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 3/9] ovn-sb: ICMP protocol Service Monitor support. 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" The list of supported protocols for Service_Monitor table has been expanded to support ICMP protocol. Also, added column that determines the type of service monitor (load balancer or lsp). Modified tables: - Service_Monitor: Add 'type' column referencing type of monitoring (logical switch port, load_balancer) Add 'icmp' to supported protocols. Signed-off-by: Alexandra Rukomoinikova --- ovn-sb.ovsschema | 7 ++++--- ovn-sb.xml | 11 +++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema index cf33933da..dd9e32f06 100644 --- a/ovn-sb.ovsschema +++ b/ovn-sb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Southbound", - "version": "21.7.0", - "cksum": "1383351379 36646", + "version": "21.8.0", + "cksum": "3491605797 36713", "tables": { "SB_Global": { "columns": { @@ -516,7 +516,8 @@ "type": {"type": {"key": { "type": "string", "enum": ["set", ["load-balancer", - "network-function"]]}, + "network-function", + "logical-switch-port"]]}, "min": 0, "max": 1}}, "ip": {"type": "string"}, "mac": {"type": "string"}, diff --git a/ovn-sb.xml b/ovn-sb.xml index 623aaeffd..82a212e79 100644 --- a/ovn-sb.xml +++ b/ovn-sb.xml @@ -5027,6 +5027,8 @@ tcp.flags = RST; icmp, and the health probe is done by injecting an icmp echo request packet into the inport of the Network_Function and then montoring the same packet coming out of the outport. + For type "logical-switch-port", supported protocols are + tcp, udp and icmp. @@ -5109,6 +5111,15 @@ tcp.flags = RST; the service and doesn't expect any reply. If it receives an ICMP reply, then it considers the service to be offline.

+ +

+ For ICMP service, ovn-controller sends an ICMP + Echo Request and expects an ICMP Echo Reply to consider service + to be online. If no reply is received or if an ICMP + error message is received, the service is considered + offline. +

+
From patchwork Mon Nov 17 09:06:56 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rukomoinikova Aleksandra X-Patchwork-Id: 2165503 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=DK6JvJAk; dkim-atps=neutral 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 4d922D10dyz1xwc for ; Mon, 17 Nov 2025 20:07:31 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 1848540497; Mon, 17 Nov 2025 09:07:27 +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 ss8d0HFmNn47; Mon, 17 Nov 2025 09:07: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 smtp2.osuosl.org 764564045D Authentication-Results: smtp2.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=DK6JvJAk Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTPS id 764564045D; Mon, 17 Nov 2025 09:07:24 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 5CFD5C0645; Mon, 17 Nov 2025 09:07:24 +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 F211BC063E for ; Mon, 17 Nov 2025 09:07:22 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id DEF0040939 for ; Mon, 17 Nov 2025 09:07:22 +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 ZCcPl68HAVK0 for ; Mon, 17 Nov 2025 09:07:21 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=109.73.14.254; helo=mail3.k2.cloud; envelope-from=arukomoinikova@k2.cloud; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp4.osuosl.org E89AC4091B Authentication-Results: smtp4.osuosl.org; dmarc=pass (p=none dis=none) header.from=k2.cloud DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org E89AC4091B Authentication-Results: smtp4.osuosl.org; dkim=pass (1024-bit key) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=DK6JvJAk Received: from mail3.k2.cloud (mail3.k2.cloud [109.73.14.254]) by smtp4.osuosl.org (Postfix) with ESMTPS id E89AC4091B for ; Mon, 17 Nov 2025 09:07:20 +0000 (UTC) From: Alexandra Rukomoinikova DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=k2.cloud; s=cloudmail; t=1763370438; bh=qcYCIhuB4QlG9dDU6rz4BMB01BZeKnrwQlQqtYe8Ri8=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=DK6JvJAk5G7GddAn6OOqtmptgELs5CLEgDTORbj/JlgPDq6SdX8AQ0qt31hhA7gET 2mMjN9ogHy3rBhiQlKCQrSYqNbYl9vaETuz2TOk9/ObdgW09/2zUIKfAvx2Ozwy4F6 AW+Y3TblahHxHqPO28h07GTcG5YI/tdFz6LQaMbg= To: dev@openvswitch.org Cc: Alexandra Rukomoinikova Date: Mon, 17 Nov 2025 12:06:56 +0300 Message-Id: <20251117090712.19708-4-arukomoinikova@k2.cloud> In-Reply-To: <20251117090712.19708-1-arukomoinikova@k2.cloud> References: <20251117090712.19708-1-arukomoinikova@k2.cloud> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 4/9] northd: Remove duplicate code. 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" Signed-off-by: Alexandra Rukomoinikova --- northd/en-northd.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/northd/en-northd.c b/northd/en-northd.c index 77cce8c9c..6815e6e39 100644 --- a/northd/en-northd.c +++ b/northd/en-northd.c @@ -82,10 +82,6 @@ northd_get_input_data(struct engine_node *node, EN_OVSDB_GET(engine_get_input("NB_network_function", node)); input_data->nbrec_network_function_group_table = EN_OVSDB_GET(engine_get_input("NB_network_function_group", node)); - input_data->sbrec_service_monitor_by_learned_type = - engine_ovsdb_node_get_index( - engine_get_input("SB_service_monitor", node), - "sbrec_service_monitor_by_learned_type"); input_data->sbrec_port_binding_table = EN_OVSDB_GET(engine_get_input("SB_port_binding", node)); From patchwork Mon Nov 17 09:06:57 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Rukomoinikova Aleksandra X-Patchwork-Id: 2165506 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=WaB1uPqY; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.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 4d922L31Vmz1xwc for ; Mon, 17 Nov 2025 20:07:38 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 38CD04072E; Mon, 17 Nov 2025 09:07:35 +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 ih2i6vvuJ4jO; Mon, 17 Nov 2025 09:07:27 +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 smtp2.osuosl.org 868014069D Authentication-Results: smtp2.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=WaB1uPqY Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp2.osuosl.org (Postfix) with ESMTPS id 868014069D; Mon, 17 Nov 2025 09:07:26 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 6499FC063E; Mon, 17 Nov 2025 09:07:26 +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 E4FD1C063E for ; Mon, 17 Nov 2025 09:07:24 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id B1FEC60C05 for ; Mon, 17 Nov 2025 09:07:24 +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 6r8VYZ4CY-2m for ; Mon, 17 Nov 2025 09:07:22 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=109.73.14.254; helo=mail3.k2.cloud; envelope-from=arukomoinikova@k2.cloud; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp3.osuosl.org 23E17606BE Authentication-Results: smtp3.osuosl.org; dmarc=pass (p=none dis=none) header.from=k2.cloud DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 23E17606BE Authentication-Results: smtp3.osuosl.org; dkim=pass (1024-bit key) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=WaB1uPqY Received: from mail3.k2.cloud (mail3.k2.cloud [109.73.14.254]) by smtp3.osuosl.org (Postfix) with ESMTPS id 23E17606BE for ; Mon, 17 Nov 2025 09:07:22 +0000 (UTC) From: Alexandra Rukomoinikova DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=k2.cloud; s=cloudmail; t=1763370439; bh=Gbh3kxtgqh5fVAe3Vco87vMJ6Z25vzvguek3NVzeIa4=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=WaB1uPqYNN/cZ1HZ1Y8uYMwsC/eNgbcSw9Y6jLyV5A1TnWFAkPlE66YqzEtI7B2S/ nD5gXnS11DRIc7xsJMcgvrA1mbyCcmFT+yz2CWenptVJRxnNAiTvGkWDZ/m/9Yjmbq l4M5q+V0JIfVMuj3Zlf+YS/oFStk1SHcHwTOp2p0= To: dev@openvswitch.org Cc: Alexandra Rukomoinikova Date: Mon, 17 Nov 2025 12:06:57 +0300 Message-Id: <20251117090712.19708-5-arukomoinikova@k2.cloud> In-Reply-To: <20251117090712.19708-1-arukomoinikova@k2.cloud> References: <20251117090712.19708-1-arukomoinikova@k2.cloud> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 5/9] northd, pinctrl: Add health monitoring for logical switch ports. 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 support for health check monitoring on logical switch ports via new NB table Logical_Switch_Port_Health_Check. Supports ICMP/TCP/UDP probes with configurable source IP and options. - Extend service monitor for LSP monitoring type - Add ICMP probe handling with sequence validation - Generate necessary ARP/ND responses for health checks Signed-off-by: Alexandra Rukomoinikova --- controller/pinctrl.c | 88 +++++++---- northd/en-northd.c | 2 + northd/inc-proc-northd.c | 5 +- northd/northd.c | 310 ++++++++++++++++++++++++++++++++------- northd/northd.h | 3 + tests/ovn-northd.at | 134 +++++++++++++++++ tests/system-ovn.at | 69 +++++++++ 7 files changed, 525 insertions(+), 86 deletions(-) diff --git a/controller/pinctrl.c b/controller/pinctrl.c index 2fb2dcded..3faba9b8e 100644 --- a/controller/pinctrl.c +++ b/controller/pinctrl.c @@ -6857,6 +6857,8 @@ enum svc_monitor_type { SVC_MON_TYPE_LB, /* network function */ SVC_MON_TYPE_NF, + /* logical switch port */ + SVC_MON_TYPE_LSP, }; /* Service monitor health checks. */ @@ -6981,20 +6983,26 @@ sync_svc_monitors(struct ovsdb_idl_txn *ovnsb_idl_txn, const struct sbrec_service_monitor *sb_svc_mon; SBREC_SERVICE_MONITOR_TABLE_FOR_EACH (sb_svc_mon, svc_mon_table) { enum svc_monitor_type mon_type; - if (sb_svc_mon->type && !strcmp(sb_svc_mon->type, - "network-function")) { + enum svc_monitor_protocol protocol; + + if (sb_svc_mon->type && + !strcmp(sb_svc_mon->type, "network-function")) { mon_type = SVC_MON_TYPE_NF; + } else if (sb_svc_mon->type && + !strcmp(sb_svc_mon->type, "logical-switch-port")) { + mon_type = SVC_MON_TYPE_LSP; } else { mon_type = SVC_MON_TYPE_LB; } - enum svc_monitor_protocol protocol; if (!strcmp(sb_svc_mon->protocol, "udp")) { - protocol = SVC_MON_PROTO_UDP; + protocol = (mon_type == SVC_MON_TYPE_NF) ? + SVC_MON_PROTO_ICMP : SVC_MON_PROTO_UDP; } else if (!strcmp(sb_svc_mon->protocol, "icmp")) { protocol = SVC_MON_PROTO_ICMP; } else { - protocol = SVC_MON_PROTO_TCP; + protocol = (mon_type == SVC_MON_TYPE_NF) ? + SVC_MON_PROTO_ICMP : SVC_MON_PROTO_TCP; } const struct sbrec_port_binding *pb @@ -7031,9 +7039,6 @@ sync_svc_monitors(struct ovsdb_idl_txn *ovnsb_idl_txn, bool mac_found = false; if (mon_type == SVC_MON_TYPE_NF) { - if (protocol != SVC_MON_PROTO_ICMP) { - continue; - } input_pb = lport_lookup_by_name(sbrec_port_binding_by_name, sb_svc_mon->logical_input_port); if (!input_pb) { @@ -7048,11 +7053,6 @@ sync_svc_monitors(struct ovsdb_idl_txn *ovnsb_idl_txn, } } } else { - if (protocol != SVC_MON_PROTO_TCP && - protocol != SVC_MON_PROTO_UDP) { - continue; - } - for (size_t i = 0; i < pb->n_mac && !mac_found; i++) { struct lport_addresses laddrs; @@ -8011,6 +8011,7 @@ static void svc_monitor_send_icmp_health_check__(struct rconn *swconn, struct svc_monitor *svc_mon) { + bool svc_mon_nf = (svc_mon->type == SVC_MON_TYPE_NF) ? true : false; uint64_t packet_stub[128 / 8]; struct dp_packet packet; dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub); @@ -8057,7 +8058,8 @@ svc_monitor_send_icmp_health_check__(struct rconn *swconn, struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub); enum ofp_version version = rconn_get_version(swconn); put_load(svc_mon->dp_key, MFF_LOG_DATAPATH, 0, 64, &ofpacts); - put_load(svc_mon->input_port_key, MFF_LOG_OUTPORT, 0, 32, &ofpacts); + put_load(svc_mon_nf ? svc_mon->input_port_key : svc_mon->port_key, + MFF_LOG_OUTPORT, 0, 32, &ofpacts); put_load(1, MFF_LOG_FLAGS, MLF_LOCAL_ONLY, 1, &ofpacts); struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts); resubmit->in_port = OFPP_CONTROLLER; @@ -8335,6 +8337,7 @@ pinctrl_handle_svc_check(struct rconn *swconn, const struct flow *ip_flow, "not found"); return; } + pinctrl_handle_tcp_svc_check(swconn, pkt_in, svc_mon); } else { const char *end = @@ -8347,48 +8350,69 @@ pinctrl_handle_svc_check(struct rconn *swconn, const struct flow *ip_flow, return; } - /* Handle ICMP ECHO REQUEST probes for Network Function services */ + /* Handle ICMP ECHO REQUEST probes for Network Function and + * Logical Switch Port services */ if (in_eth->eth_type == htons(ETH_TYPE_IP)) { struct icmp_header *ih = l4h; /* It's ICMP packet. */ - if (ih->icmp_type == ICMP4_ECHO_REQUEST && ih->icmp_code == 0) { - uint32_t hash = hash_bytes(&dst_ip_addr, sizeof dst_ip_addr, - hash_3words(dp_key, port_key, 0)); - struct svc_monitor *svc_mon = - pinctrl_find_svc_monitor(dp_key, port_key, &dst_ip_addr, 0, + if ((ih->icmp_type == ICMP4_ECHO_REQUEST || + ih->icmp_type == ICMP4_ECHO_REPLY) && ih->icmp_code == 0) { + uint32_t hash = + hash_bytes(&ip_addr, sizeof ip_addr, + hash_3words(dp_key, port_key, + ntohs(ip_flow->tp_src))); + + struct svc_monitor *svc_mon = + pinctrl_find_svc_monitor(dp_key, port_key, + ih->icmp_type == + ICMP4_ECHO_REQUEST ? + &dst_ip_addr : &ip_addr, 0, SVC_MON_PROTO_ICMP, hash); if (!svc_mon) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT( - 1, 5); + static struct vlog_rate_limit rl + = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "handle service check: Service monitor " "not found for ICMP request"); return; } - if (svc_mon->type == SVC_MON_TYPE_NF) { - pinctrl_handle_icmp_svc_check(pkt_in, svc_mon); - } + + /* Type validation done during creation - + * asserts on unsupported types. */ + ovs_assert(svc_mon->type != SVC_MON_TYPE_NF || + svc_mon->type != SVC_MON_TYPE_LSP); + + pinctrl_handle_icmp_svc_check(pkt_in, svc_mon); + return; } } else if (in_eth->eth_type == htons(ETH_TYPE_IPV6)) { struct icmp6_data_header *ih6 = l4h; /* It's ICMPv6 packet. */ - if (ih6->icmp6_base.icmp6_type == ICMP6_ECHO_REQUEST && + if ((ih6->icmp6_base.icmp6_type == ICMP6_ECHO_REQUEST || + ih6->icmp6_base.icmp6_type == ICMP6_ECHO_REPLY) && ih6->icmp6_base.icmp6_code == 0) { uint32_t hash = hash_bytes(&dst_ip_addr, sizeof dst_ip_addr, hash_3words(dp_key, port_key, 0)); struct svc_monitor *svc_mon = - pinctrl_find_svc_monitor(dp_key, port_key, &dst_ip_addr, 0, + pinctrl_find_svc_monitor(dp_key, port_key, + ih6->icmp6_base.icmp6_type == + ICMP6_ECHO_REQUEST ? + &dst_ip_addr : &ip_addr, 0, SVC_MON_PROTO_ICMP, hash); if (!svc_mon) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT( - 1, 5); + static struct vlog_rate_limit rl = + VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "handle service check: Service monitor " "not found for ICMPv6 request"); return; } - if (svc_mon->type == SVC_MON_TYPE_NF) { - pinctrl_handle_icmp_svc_check(pkt_in, svc_mon); - } + + /* Type validation done during creation + * - asserts on unsupported types. */ + ovs_assert(svc_mon->type != SVC_MON_TYPE_NF || + svc_mon->type != SVC_MON_TYPE_LSP); + + pinctrl_handle_icmp_svc_check(pkt_in, svc_mon); return; } } diff --git a/northd/en-northd.c b/northd/en-northd.c index 6815e6e39..9b37f3eee 100644 --- a/northd/en-northd.c +++ b/northd/en-northd.c @@ -82,6 +82,8 @@ northd_get_input_data(struct engine_node *node, EN_OVSDB_GET(engine_get_input("NB_network_function", node)); input_data->nbrec_network_function_group_table = EN_OVSDB_GET(engine_get_input("NB_network_function_group", node)); + input_data->nbrec_lsp_hc_table = EN_OVSDB_GET(engine_get_input( + "NB_logical_switch_port_health_check", node)); input_data->sbrec_port_binding_table = EN_OVSDB_GET(engine_get_input("SB_port_binding", node)); diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c index 94199de12..5c41fd3ac 100644 --- a/northd/inc-proc-northd.c +++ b/northd/inc-proc-northd.c @@ -74,7 +74,8 @@ static unixctl_cb_func chassis_features_list; NB_NODE(chassis_template_var) \ NB_NODE(sampling_app) \ NB_NODE(network_function) \ - NB_NODE(network_function_group) + NB_NODE(network_function_group) \ + NB_NODE(logical_switch_port_health_check) enum nb_engine_node { #define NB_NODE(NAME) NB_##NAME, @@ -254,6 +255,8 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, engine_add_input(&en_northd, &en_nb_chassis_template_var, NULL); engine_add_input(&en_northd, &en_nb_network_function, NULL); engine_add_input(&en_northd, &en_nb_network_function_group, NULL); + engine_add_input(&en_northd, &en_nb_logical_switch_port_health_check, + NULL); engine_add_input(&en_northd, &en_sb_chassis, NULL); engine_add_input(&en_northd, &en_sb_mirror, NULL); diff --git a/northd/northd.c b/northd/northd.c index cdf12ec86..a9c700bb2 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -3027,14 +3027,14 @@ get_service_mon(const struct hmap *local_svc_monitors_map, return NULL; } -static void +static inline void set_service_mon_options(const struct sbrec_service_monitor *sbrec_mon, - const struct smap *nb_hc_options, + const struct smap *options, const char *target_az_name) { struct smap sb_svc_options = SMAP_INITIALIZER(&sb_svc_options); - smap_clone(&sb_svc_options, nb_hc_options); + smap_clone(&sb_svc_options, options); if (target_az_name) { smap_add(&sb_svc_options, "az-name", target_az_name); } @@ -3042,6 +3042,40 @@ set_service_mon_options(const struct sbrec_service_monitor *sbrec_mon, smap_destroy(&sb_svc_options); } +static inline void +configure_service_mon_rec(const struct sbrec_service_monitor *sbrec_mon, + const char *src_ip, + const char *target_az_name, + const char *svc_monitor_mac, + const struct eth_addr *svc_monitor_mac_ea, + const struct smap *options) +{ + set_service_mon_options(sbrec_mon, options, target_az_name); + + struct eth_addr ea; + if (!sbrec_mon->src_mac || + !eth_addr_from_string(sbrec_mon->src_mac, &ea) || + !eth_addr_equals(ea, *svc_monitor_mac_ea)) { + sbrec_service_monitor_set_src_mac(sbrec_mon, svc_monitor_mac); + } + + if (!sbrec_mon->src_ip || + strcmp(sbrec_mon->src_ip, src_ip)) { + sbrec_service_monitor_set_src_ip(sbrec_mon, src_ip); + } +} + +static inline void +update_status_to_service_mon(const struct sbrec_service_monitor *sbrec_mon, + const struct ovn_port *op, + bool remote_backend) +{ + if (!remote_backend && (!op->sb->n_up || !op->sb->up[0]) && + sbrec_mon->status && !strcmp(sbrec_mon->status, "online")) { + sbrec_service_monitor_set_status(sbrec_mon, "offline"); + } +} + static struct service_monitor_info * create_or_get_service_mon(struct ovsdb_idl_txn *ovnsb_txn, struct hmap *local_svc_monitors_map, @@ -3055,7 +3089,8 @@ create_or_get_service_mon(struct ovsdb_idl_txn *ovnsb_txn, struct service_monitor_info *mon_info = get_service_mon(local_svc_monitors_map, ic_learned_svc_monitors_map, - ip, logical_port, service_port, protocol); + ip, logical_port, + service_port, protocol); if (mon_info) { if (chassis_name && strcmp(mon_info->sbrec_mon->chassis_name, @@ -3191,6 +3226,33 @@ ovn_nf_svc_create(struct ovsdb_idl_txn *ovnsb_txn, mon_info->required = true; } +static inline bool +check_svc_port_available(const char *logical_port, + const bool remote_backend, + struct hmap *ls_ports, + struct sset *svc_monitor_lsps, + struct ovn_port **op, + char **chassis_name) +{ + sset_add(svc_monitor_lsps, logical_port); + + struct ovn_port *op_p = ovn_port_find(ls_ports, logical_port); + + if (!remote_backend && + (!op_p || !lsp_is_enabled(op_p->nbsp))) { + return false; + } + + if (!remote_backend && + op_p->sb && op_p->sb->chassis) { + *chassis_name = op_p->sb->chassis->name; + } + + *op = op_p; + + return true; +} + static void ovn_lb_svc_create(struct ovsdb_idl_txn *ovnsb_txn, const struct ovn_northd_lb *lb, @@ -3214,30 +3276,26 @@ ovn_lb_svc_create(struct ovsdb_idl_txn *ovnsb_txn, vector_get_ptr(&lb_vip->backends, j); struct ovn_northd_lb_backend *backend_nb = &lb_vip_nb->backends_nb[j]; + const char *protocol = lb->nlb->protocol; + struct ovn_port *op = NULL; + char *chassis_name = NULL; if (!backend_nb->health_check) { continue; } - sset_add(svc_monitor_lsps, backend_nb->logical_port); - struct ovn_port *op = ovn_port_find(ls_ports, - backend_nb->logical_port); - - if (!backend_nb->remote_backend && - (!op || !lsp_is_enabled(op->nbsp))) { - continue; + if (!check_svc_port_available(backend_nb->logical_port, + backend_nb->remote_backend, + ls_ports, + svc_monitor_lsps, + &op, &chassis_name)) { + continue; } - const char *protocol = lb->nlb->protocol; if (!protocol || !protocol[0]) { protocol = "tcp"; } - const char *chassis_name = NULL; - if (!backend_nb->remote_backend && op->sb->chassis) { - chassis_name = op->sb->chassis->name; - } - struct service_monitor_info *mon_info = create_or_get_service_mon(ovnsb_txn, local_svc_monitors_map, @@ -3251,38 +3309,115 @@ ovn_lb_svc_create(struct ovsdb_idl_txn *ovnsb_txn, chassis_name, backend_nb->remote_backend); ovs_assert(mon_info); - set_service_mon_options(mon_info->sbrec_mon, - &lb_vip_nb->lb_health_check->options, - backend_nb->az_name); - struct eth_addr ea; - if (!mon_info->sbrec_mon->src_mac || - !eth_addr_from_string(mon_info->sbrec_mon->src_mac, &ea) || - !eth_addr_equals(ea, *svc_monitor_mac_ea)) { - sbrec_service_monitor_set_src_mac(mon_info->sbrec_mon, - svc_monitor_mac); - } - if (!mon_info->sbrec_mon->src_ip || - strcmp(mon_info->sbrec_mon->src_ip, - backend_nb->svc_mon_src_ip)) { - sbrec_service_monitor_set_src_ip( - mon_info->sbrec_mon, - backend_nb->svc_mon_src_ip); - } + configure_service_mon_rec(mon_info->sbrec_mon, + backend_nb->svc_mon_src_ip, + backend_nb->az_name, + svc_monitor_mac, + svc_monitor_mac_ea, + &lb_vip_nb->lb_health_check->options); - if (!backend_nb->remote_backend && - (!op->sb->n_up || !op->sb->up[0]) - && mon_info->sbrec_mon->status - && !strcmp(mon_info->sbrec_mon->status, "online")) { - sbrec_service_monitor_set_status(mon_info->sbrec_mon, - "offline"); - } + update_status_to_service_mon(mon_info->sbrec_mon, + op, backend_nb->remote_backend); mon_info->required = true; } } } +static void +ovn_lsp_svc_monitor_add_address(struct ovsdb_idl_txn *ovnsb_txn, + struct nbrec_logical_switch_port_health_check *lsp_hc, + const struct ovn_port *op, + const char *address, + const char *svc_monitor_mac, + const struct eth_addr *svc_monitor_mac_ea, + struct hmap *local_svc_monitors_map) +{ + struct service_monitor_info *mon_info = + create_or_get_service_mon(ovnsb_txn, + local_svc_monitors_map, + NULL, + "logical-switch-port", + address, + op->key, + NULL, + lsp_hc->port, + lsp_hc->protocol, + (op->sb && op->sb->chassis) ? + op->sb->chassis->name : NULL, + false); + + ovs_assert(mon_info); + + configure_service_mon_rec(mon_info->sbrec_mon, + lsp_hc->src_ip, + NULL, + svc_monitor_mac, + svc_monitor_mac_ea, + &lsp_hc->options); + + update_status_to_service_mon(mon_info->sbrec_mon, op, false); + + mon_info->required = true; +} + +static void +ovn_lsp_svc_create_record(struct ovsdb_idl_txn *ovnsb_txn, + struct nbrec_logical_switch_port_health_check *lsp_hc, + const struct ovn_port *op, + const char *svc_monitor_mac, + const struct eth_addr *svc_monitor_mac_ea, + struct hmap *local_monitor_map) +{ + if (!lsp_hc->n_addresses) { + for (size_t i = 0; i < op->n_lsp_addrs; i++) { + for (size_t j = 0; j < op->lsp_addrs[i].n_ipv4_addrs; j++) { + ovn_lsp_svc_monitor_add_address( + ovnsb_txn, lsp_hc, op, + op->lsp_addrs[i].ipv4_addrs[j].addr_s, + svc_monitor_mac, svc_monitor_mac_ea, + local_monitor_map); + } + for (size_t j = 0; j < op->lsp_addrs[i].n_ipv6_addrs; j++) { + ovn_lsp_svc_monitor_add_address( + ovnsb_txn, lsp_hc, op, + op->lsp_addrs[i].ipv6_addrs[j].addr_s, + svc_monitor_mac, svc_monitor_mac_ea, + local_monitor_map); + } + } + } else { + for (size_t j = 0; j < lsp_hc->n_addresses; j++) { + ovn_lsp_svc_monitor_add_address( + ovnsb_txn, lsp_hc, op, + lsp_hc->addresses[j], + svc_monitor_mac, svc_monitor_mac_ea, + local_monitor_map); + } + } +} + +static void +ovn_lsp_svc_monitors_process_port(struct ovsdb_idl_txn *ovnsb_txn, + const struct ovn_port *op, + const char *svc_monitor_mac, + const struct eth_addr *svc_monitor_mac_ea, + struct hmap *local_monitor_map, + struct sset *svc_monitor_lsps) +{ + sset_add(svc_monitor_lsps, op->key); + + for (size_t i = 0; i < op->nbsp->n_health_checks; i++) { + ovn_lsp_svc_create_record(ovnsb_txn, + op->nbsp->health_checks[i], + op, + svc_monitor_mac, + svc_monitor_mac_ea, + local_monitor_map); + } +} + static bool build_lb_vip_actions(const struct ovn_northd_lb *lb, const struct ovn_lb_vip *lb_vip, @@ -3491,7 +3626,7 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups, } static void -build_svcs( +build_svc_monitors_data( struct ovsdb_idl_txn *ovnsb_txn, struct ovsdb_idl_index *sbrec_service_monitor_by_learned_type, const char *svc_monitor_mac, @@ -3503,7 +3638,8 @@ build_svcs( const struct nbrec_network_function_table *nbrec_network_function_table, struct sset *svc_monitor_lsps, struct hmap *local_svc_monitors_map, - struct hmap *ic_learned_svc_monitors_map) + struct hmap *ic_learned_svc_monitors_map, + struct hmapx *monitored_ports_map) { const struct sbrec_service_monitor *sbrec_mon; struct sbrec_service_monitor *key = @@ -3512,6 +3648,11 @@ build_svcs( sbrec_service_monitor_index_set_ic_learned(key, false); + /* Hash only the IP, port, and logical port. + * This is necessary because two service monitors with the same IP and + * logical port will have different `port` values + * (e.g., an ICMP monitor defaults its port to 0). + */ SBREC_SERVICE_MONITOR_FOR_EACH_EQUAL (sbrec_mon, key, sbrec_service_monitor_by_learned_type) { uint32_t hash = sbrec_mon->port; @@ -3553,6 +3694,18 @@ build_svcs( } } + struct hmapx_node *hmapx_node; + const struct ovn_port *op; + HMAPX_FOR_EACH (hmapx_node, monitored_ports_map) { + op = hmapx_node->data; + ovn_lsp_svc_monitors_process_port(ovnsb_txn, + op, + svc_monitor_mac, + svc_monitor_mac_ea, + local_svc_monitors_map, + svc_monitor_lsps); + } + struct service_monitor_info *mon_info; HMAP_FOR_EACH_SAFE (mon_info, hmap_node, local_svc_monitors_map) { if (!mon_info->required) { @@ -4017,6 +4170,16 @@ ovn_port_allocate_key(struct ovn_port *op) return true; } +static inline void +add_monitored_port(struct ovn_port *op, struct hmapx *monitored_ports_map) +{ + if (op->nbsp && + op->nbsp->n_health_checks && + lsp_is_enabled(op->nbsp)) { + hmapx_add(monitored_ports_map, op); + } +} + /* Updates the southbound Port_Binding table so that it contains the logical * switch ports specified by the northbound database. * @@ -4033,7 +4196,8 @@ build_ports(struct ovsdb_idl_txn *ovnsb_txn, struct ovsdb_idl_index *sbrec_chassis_by_hostname, struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name, struct hmap *ls_datapaths, struct hmap *lr_datapaths, - struct hmap *ls_ports, struct hmap *lr_ports) + struct hmap *ls_ports, struct hmap *lr_ports, + struct hmapx *monitored_ports_map) { struct ovs_list sb_only, nb_only, both; /* XXX: Add tag_alloc_table and queue_id_bitmap as part of northd_data @@ -4109,6 +4273,7 @@ build_ports(struct ovsdb_idl_txn *ovnsb_txn, &active_ha_chassis_grps); op->od->is_transit_router |= is_transit_router_port(op); ovs_list_remove(&op->list); + add_monitored_port(op, monitored_ports_map); } /* Add southbound record for each unmatched northbound record. */ @@ -4122,6 +4287,7 @@ build_ports(struct ovsdb_idl_txn *ovnsb_txn, &active_ha_chassis_grps); sbrec_port_binding_set_logical_port(op->sb, op->key); op->od->is_transit_router |= is_transit_router_port(op); + add_monitored_port(op, monitored_ports_map); ovs_list_remove(&op->list); } @@ -15250,6 +15416,34 @@ build_arp_resolve_flows_for_lsp( } } +static void +build_arp_nd_lflow_for_lsp_svc_hc(struct ovn_port *op, + const char *svc_monitor_mac, + struct lflow_table *lflows, + struct ds *match, + struct ds *actions) +{ + const struct nbrec_logical_switch_port *nbsp = op->nbsp; + for (size_t i = 0; i < nbsp->n_health_checks; i++) { + struct nbrec_logical_switch_port_health_check *lsp_hc = + nbsp->health_checks[i]; + ds_clear(match); + ds_clear(actions); + + bool is_ipv4 = strchr(lsp_hc->src_ip, '.') ? true : false; + + build_arp_nd_service_monitor_lflow(svc_monitor_mac, + lsp_hc->src_ip, actions, match, is_ipv4); + + ovn_lflow_add_with_hint(lflows, + op->od, + S_SWITCH_IN_ARP_ND_RSP, 110, + ds_cstr(match), ds_cstr(actions), + &op->nbsp->header_, + op->lflow_ref); + } +} + #define ICMP4_NEED_FRAG_FORMAT \ "icmp4_error {" \ "%s" \ @@ -18668,6 +18862,7 @@ build_lswitch_and_lrouter_iterate_by_lsp(struct ovn_port *op, const struct shash *meter_groups, struct ds *match, struct ds *actions, + const char *svc_monitor_mac, struct lflow_table *lflows) { ovs_assert(op->nbsp); @@ -18691,6 +18886,10 @@ build_lswitch_and_lrouter_iterate_by_lsp(struct ovn_port *op, /* Build Logical Router Flows. */ build_arp_resolve_flows_for_lsp(op, lflows, lr_ports, match, actions); + if (op->nbsp->n_health_checks) { + build_arp_nd_lflow_for_lsp_svc_hc(op, svc_monitor_mac, lflows, + match, actions); + } } /* Helper function to combine all lflow generation which is iterated by logical @@ -18794,11 +18993,8 @@ build_lflows_thread(void *arg) return NULL; } build_lswitch_and_lrouter_iterate_by_lsp(op, lsi->ls_ports, - lsi->lr_ports, - lsi->meter_groups, - &lsi->match, - &lsi->actions, - lsi->lflows); + lsi->lr_ports, lsi->meter_groups, &lsi->match, + &lsi->actions, lsi->svc_monitor_mac, lsi->lflows); build_lbnat_lflows_iterate_by_lsp( op, lsi->lr_stateful_table, &lsi->match, &lsi->actions, lsi->lflows); @@ -19065,6 +19261,7 @@ build_lswitch_and_lrouter_flows( lsi.meter_groups, &lsi.match, &lsi.actions, + lsi.svc_monitor_mac, lsi.lflows); build_lbnat_lflows_iterate_by_lsp(op, lsi.lr_stateful_table, &lsi.match, @@ -19376,6 +19573,7 @@ lflow_handle_northd_port_changes(struct ovsdb_idl_txn *ovnsb_txn, lflow_input->lr_ports, lflow_input->meter_groups, &match, &actions, + lflow_input->svc_monitor_mac, lflows); /* Sync the new flows to SB. */ bool handled = lflow_ref_sync_lflows( @@ -19435,7 +19633,9 @@ lflow_handle_northd_port_changes(struct ovsdb_idl_txn *ovnsb_txn, build_lswitch_and_lrouter_iterate_by_lsp(op, lflow_input->ls_ports, lflow_input->lr_ports, lflow_input->meter_groups, - &match, &actions, lflows); + &match, &actions, + lflow_input->svc_monitor_mac, + lflows); /* Sync the newly added flows to SB. */ bool handled = lflow_ref_sync_lflows( @@ -20101,6 +20301,7 @@ northd_init(struct northd_data *data) hmap_init(&data->lb_group_datapaths_map); sset_init(&data->svc_monitor_lsps); hmap_init(&data->local_svc_monitors_map); + hmapx_init(&data->monitored_ports_map); init_northd_tracked_data(data); } @@ -20186,6 +20387,7 @@ northd_destroy(struct northd_data *data) &data->ls_ports, &data->lr_ports); sset_destroy(&data->svc_monitor_lsps); + hmapx_destroy(&data->monitored_ports_map); destroy_northd_tracked_data(data); } @@ -20291,11 +20493,12 @@ ovnnb_db_run(struct northd_input *input_data, input_data->sbrec_chassis_by_hostname, input_data->sbrec_ha_chassis_grp_by_name, &data->ls_datapaths.datapaths, &data->lr_datapaths.datapaths, - &data->ls_ports, &data->lr_ports); + &data->ls_ports, &data->lr_ports, + &data->monitored_ports_map); build_lb_port_related_data(&data->lr_datapaths, &data->ls_datapaths, &data->lb_datapaths_map, &data->lb_group_datapaths_map); - build_svcs(ovnsb_txn, + build_svc_monitors_data(ovnsb_txn, input_data->sbrec_service_monitor_by_learned_type, input_data->svc_monitor_mac, &input_data->svc_monitor_mac_ea, @@ -20305,7 +20508,8 @@ ovnnb_db_run(struct northd_input *input_data, &data->ls_ports, &data->lb_datapaths_map, input_data->nbrec_network_function_table, &data->svc_monitor_lsps, &data->local_svc_monitors_map, - input_data->ic_learned_svc_monitors_map); + input_data->ic_learned_svc_monitors_map, + &data->monitored_ports_map); build_lb_count_dps(&data->lb_datapaths_map); build_network_function_active( input_data->nbrec_network_function_group_table, diff --git a/northd/northd.h b/northd/northd.h index 32134d36e..e16f5cbfe 100644 --- a/northd/northd.h +++ b/northd/northd.h @@ -41,6 +41,8 @@ struct northd_input { const struct nbrec_network_function_table *nbrec_network_function_table; const struct nbrec_network_function_group_table *nbrec_network_function_group_table; + const struct nbrec_logical_switch_port_health_check_table + *nbrec_lsp_hc_table; /* Southbound table references */ const struct sbrec_port_binding_table *sbrec_port_binding_table; @@ -202,6 +204,7 @@ struct northd_data { struct hmap lb_group_datapaths_map; struct sset svc_monitor_lsps; struct hmap local_svc_monitors_map; + struct hmapx monitored_ports_map; /* Change tracking data. */ struct northd_tracked_data trk_data; diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index 448bc66ae..409dcb7d5 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -18558,3 +18558,137 @@ check_row_count Advertised_MAC_Binding 0 AT_CLEANUP ]) + +OVN_FOR_EACH_NORTHD_NO_HV([ +AT_SETUP([Logical Switch Port Health Check - lflow/service monitor synchronization]) +ovn_start + +check ovn-nbctl ls-add ls1 +check ovn-nbctl lsp-add ls1 lport1 -- \ + lsp-set-addresses lport1 "f0:00:0f:01:02:04 192.168.0.10" "f0:00:0f:01:02:06 192.168.0.11" + +check ovn-nbctl lsp-add ls1 lport2 -- \ + lsp-set-addresses lport2 "f0:00:0f:01:02:08 192.168.0.12" + +check ovn-nbctl set NB_Global . options:svc_monitor_mac="11:11:11:11:11:11" + +# Сreate a service monitor for all addresses on one of lsp. +check ovn-nbctl lsp-hc-add lport1 icmp 192.168.0.255 +check_row_count nb:Logical_Switch_Port_Health_Check 1 +lport1_uuid1=$(fetch_column nb:Logical_Switch_Port_Health_Check _uuid protocol=icmp) + +# Check lflow and service monitor synchronization +AT_CHECK([ovn-sbctl lflow-list ls1 | grep 'ls_in_arp_rsp'| grep "priority=110" | ovn_strip_lflows], [0], [dnl + table=??(ls_in_arp_rsp ), priority=110 , match=(arp.tpa == 192.168.0.255 && arp.op == 1), action=(eth.dst = eth.src; eth.src = 11:11:11:11:11:11; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = 11:11:11:11:11:11; arp.tpa = arp.spa; arp.spa = 192.168.0.255; outport = inport; flags.loopback = 1; output;) +]) + +check_row_count sb:Service_Monitor 2 +check_column "false false" sb:Service_Monitor ic_learned logical_port=lport1 +check_column "false false" sb:Service_Monitor remote logical_port=lport1 +check_column "192.168.0.10 192.168.0.11" sb:Service_Monitor ip logical_port=lport1 +check_column "icmp icmp" sb:Service_Monitor protocol logical_port=lport1 +check_column "192.168.0.255 192.168.0.255" sb:Service_Monitor src_ip logical_port=lport1 +check_column "0 0" sb:Service_Monitor port logical_port=lport1 +check_column "logical-switch-port logical-switch-port" sb:Service_Monitor type logical_port=lport1 +check_column "11:11:11:11:11:11 11:11:11:11:11:11" sb:Service_Monitor src_mac logical_port=lport1 + +# Сreate one more service monitor for all addresses on one of lsp. +check ovn-nbctl lsp-hc-add lport1 tcp 192.168.0.254 80 +check_row_count nb:Logical_Switch_Port_Health_Check 2 +lport1_uuid2=$(fetch_column nb:Logical_Switch_Port_Health_Check _uuid protocol=tcp) + +# Check that 2 records (2 addresses) have been created for each protocol. +check_row_count sb:Service_Monitor 4 + +AT_CHECK([ovn-sbctl lflow-list ls1 | grep 'ls_in_arp_rsp'| grep "priority=110" | ovn_strip_lflows], [0], [dnl + table=??(ls_in_arp_rsp ), priority=110 , match=(arp.tpa == 192.168.0.254 && arp.op == 1), action=(eth.dst = eth.src; eth.src = 11:11:11:11:11:11; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = 11:11:11:11:11:11; arp.tpa = arp.spa; arp.spa = 192.168.0.254; outport = inport; flags.loopback = 1; output;) + table=??(ls_in_arp_rsp ), priority=110 , match=(arp.tpa == 192.168.0.255 && arp.op == 1), action=(eth.dst = eth.src; eth.src = 11:11:11:11:11:11; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = 11:11:11:11:11:11; arp.tpa = arp.spa; arp.spa = 192.168.0.255; outport = inport; flags.loopback = 1; output;) +]) + +# Change addresses on lport - addresses for service monitors should be changed +check ovn-nbctl lsp-set-addresses lport1 "f0:00:0f:01:02:04 192.168.0.20" + +check_row_count sb:Service_Monitor 2 +check_column "false false" sb:Service_Monitor ic_learned logical_port=lport1 +check_column "false false " sb:Service_Monitor remote logical_port=lport1 +check_column "192.168.0.20 192.168.0.20" sb:Service_Monitor ip logical_port=lport1 +check_column "icmp tcp" sb:Service_Monitor protocol logical_port=lport1 +check_column "192.168.0.255 192.168.0.254" sb:Service_Monitor src_ip logical_port=lport1 +check_column "0 80" sb:Service_Monitor port logical_port=lport1 +check_column "logical-switch-port logical-switch-port" sb:Service_Monitor type logical_port=lport1 +check_column "11:11:11:11:11:11 11:11:11:11:11:11" sb:Service_Monitor src_mac logical_port=lport1 + +# Check options propogations +hc_lport1_uuid=$(fetch_column nb:logical_switch_port_health_check _uuid src_ip="192.168.0.255") + +check ovn-nbctl set logical_switch_port_health_check $hc_lport1_uuid options:interval=3 +check ovn-nbctl set logical_switch_port_health_check $hc_lport1_uuid options:timeout=30 +check ovn-nbctl set logical_switch_port_health_check $hc_lport1_uuid options:success_count=1 +check ovn-nbctl set logical_switch_port_health_check $hc_lport1_uuid options:failure_count=2 + + +sm_lport1_uuid=$(fetch_column sb:service_monitor _uuid protocol=icmp) + +AT_CHECK([ovn-sbctl get Service_Monitor $sm_lport1_uuid options:interval], +[0], ["3" +]) +AT_CHECK([ovn-sbctl get Service_Monitor $sm_lport1_uuid options:failure_count], +[0], ["2" +]) +AT_CHECK([ovn-sbctl get Service_Monitor $sm_lport1_uuid options:success_count], +[0], ["1" +]) +AT_CHECK([ovn-sbctl get Service_Monitor $sm_lport1_uuid options:timeout], +[0], ["30" +]) + +ovn-nbctl list logical_switch_port + +check ovn-nbctl lsp-hc-del lport1 + +check_row_count nb:Logical_Switch_Port_Health_Check 0 + +# Change the service monitor to monitor only one address. +check ovn-nbctl lsp-hc-add lport1 icmp 192.168.0.255 192.168.0.20 +check_row_count nb:Logical_Switch_Port_Health_Check 1 +lport1_uuid3=$(fetch_column nb:Logical_Switch_Port_Health_Check _uuid protocol=icmp) + +check_row_count sb:Service_Monitor 1 + +AT_CHECK([ovn-sbctl lflow-list ls1 | grep 'ls_in_arp_rsp'| grep "priority=110" | ovn_strip_lflows], [0], [dnl + table=??(ls_in_arp_rsp ), priority=110 , match=(arp.tpa == 192.168.0.255 && arp.op == 1), action=(eth.dst = eth.src; eth.src = 11:11:11:11:11:11; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = 11:11:11:11:11:11; arp.tpa = arp.spa; arp.spa = 192.168.0.255; outport = inport; flags.loopback = 1; output;) +]) + +check_column "false" sb:Service_Monitor ic_learned logical_port=lport1 +check_column "false" sb:Service_Monitor remote logical_port=lport1 +check_column "192.168.0.20" sb:Service_Monitor ip logical_port=lport1 +check_column "icmp" sb:Service_Monitor protocol logical_port=lport1 +check_column "192.168.0.255" sb:Service_Monitor src_ip logical_port=lport1 +check_column "0" sb:Service_Monitor port logical_port=lport1 +check_column "logical-switch-port" sb:Service_Monitor type logical_port=lport1 +check_column "11:11:11:11:11:11" sb:Service_Monitor src_mac logical_port=lport1 + +# Create one more monitor +check ovn-nbctl lsp-hc-add lport2 icmp 192.168.0.255 192.168.0.12 +lport1_uuid4=$(fetch_column nb:Logical_Switch_Port_Health_Check _uuid addresses="192.168.0.12") +check_row_count nb:Logical_Switch_Port_Health_Check 2 + +check_row_count sb:Service_Monitor 2 + +# One record for arp replay +AT_CHECK([ovn-sbctl lflow-list ls1 | grep 'ls_in_arp_rsp'| grep "priority=110" | ovn_strip_lflows], [0], [dnl + table=??(ls_in_arp_rsp ), priority=110 , match=(arp.tpa == 192.168.0.255 && arp.op == 1), action=(eth.dst = eth.src; eth.src = 11:11:11:11:11:11; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = 11:11:11:11:11:11; arp.tpa = arp.spa; arp.spa = 192.168.0.255; outport = inport; flags.loopback = 1; output;) +]) + +ovn-nbctl list logical_switch_port_health_check + +check ovn-nbctl lsp-hc-del lport1 +check ovn-nbctl lsp-hc-del lport2 +check_row_count nb:Logical_Switch_Port_Health_Check 0 +check_row_count sb:Service_Monitor 0 + +AT_CHECK([ovn-sbctl lflow-list ls1 | grep 'ls_in_arp_rsp'| grep "priority=110" | ovn_strip_lflows], [0], []) + +AT_CLEANUP +]) + diff --git a/tests/system-ovn.at b/tests/system-ovn.at index 76f73d96e..6dd12787a 100644 --- a/tests/system-ovn.at +++ b/tests/system-ovn.at @@ -19283,3 +19283,72 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/.*error receiving.*/d /.*terminating with signal 15.*/d"]) AT_CLEANUP ]) + +OVN_FOR_EACH_NORTHD_NO_HV([ +AT_SETUP([Logical Switch Port Health Check]) + +ovn_start +OVS_TRAFFIC_VSWITCHD_START() +ADD_BR([br-int]) + +# 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 + +check ovn-nbctl ls-add ls1 + +ADD_NAMESPACES(lport) +ADD_VETH(lport, lport, br-int, "192.168.0.10", "f0:00:0f:01:02:04", \ + "192.168.0.1") +NS_EXEC([lport], [ip r del default via 192.168.0.1 dev lport]) +NS_EXEC([lport], [ip r add default dev lport]) + +check ovn-nbctl lsp-add ls1 lport -- \ + lsp-set-addresses lport "f0:00:0f:01:02:04 192.168.0.10" + +check ovn-nbctl --wait=hv sync + +check ovn-nbctl lsp-hc-add lport icmp 192.168.0.255 +lport1_uuid1=$(fetch_column nb:Logical_Switch_Port_Health_Check _uuid protocol=icmp) + +check_row_count sb:Service_Monitor 1 + +NETNS_START_TCPDUMP([lport], [-n -c 2 -i lport], [lport]) +OVS_WAIT_UNTIL([ + total_queries=`grep "ICMP" -c lport.tcpdump` + test "${total_queries}" = "2" +]) + +# Wait until the services are set to online. +wait_row_count Service_Monitor 1 status=online + +# Create one more health check on logical switch port +NETNS_DAEMONIZE([lport], [nc -l -k 192.168.0.10 4041], [lport_tcp.pid]) + +check ovn-nbctl lsp-hc-add lport tcp 192.168.0.255 4041 +lport1_uuid2=$(fetch_column nb:Logical_Switch_Port_Health_Check _uuid protocol=tcp) + +check_row_count sb:Service_Monitor 2 + +# Wait until the services are set to online. +wait_row_count Service_Monitor 2 status=online + +NETNS_DAEMONIZE([lport], [nc -ulp 4042], [lport_udp.pid]) + +check ovn-nbctl lsp-hc-add lport udp 192.168.0.255 4042 +lport1_uuid3=$(fetch_column nb:Logical_Switch_Port_Health_Check _uuid protocol=udp) + +check_row_count sb:Service_Monitor 3 +# Wait until the services are set to online. +wait_row_count Service_Monitor 3 status=online + +AT_CLEANUP +]) + From patchwork Mon Nov 17 09:06:58 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rukomoinikova Aleksandra X-Patchwork-Id: 2165510 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=Xgzm/4fQ; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::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 4d922W3PPZz1xwc for ; Mon, 17 Nov 2025 20:07:47 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 07384821EC; Mon, 17 Nov 2025 09:07:43 +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 LNs2bparaoRP; Mon, 17 Nov 2025 09:07:39 +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 smtp1.osuosl.org CADB7821DF Authentication-Results: smtp1.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=Xgzm/4fQ Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTPS id CADB7821DF; Mon, 17 Nov 2025 09:07:30 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id A16A8C0641; Mon, 17 Nov 2025 09:07:30 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 782DFC063F for ; Mon, 17 Nov 2025 09:07:29 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 2289D60D4E for ; Mon, 17 Nov 2025 09:07:29 +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 j2ObS5lzDx8h for ; Mon, 17 Nov 2025 09:07:23 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=109.73.14.254; helo=mail3.k2.cloud; envelope-from=arukomoinikova@k2.cloud; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp3.osuosl.org A6FE760BDE Authentication-Results: smtp3.osuosl.org; dmarc=pass (p=none dis=none) header.from=k2.cloud DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org A6FE760BDE Authentication-Results: smtp3.osuosl.org; dkim=pass (1024-bit key) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=Xgzm/4fQ Received: from mail3.k2.cloud (mail3.k2.cloud [109.73.14.254]) by smtp3.osuosl.org (Postfix) with ESMTPS id A6FE760BDE for ; Mon, 17 Nov 2025 09:07:22 +0000 (UTC) From: Alexandra Rukomoinikova DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=k2.cloud; s=cloudmail; t=1763370440; bh=y2+gvNYyaSsBiWbctqtC8CDfGxwS2x4qcq+QLPQ+B2Y=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=Xgzm/4fQPHKORYvkaFFUKeAx79317wxm6BShcy6jk4IbYyOjqALxOm9iaPJ+ZeUYc QvQqGrLeIPjTu3dcM6CoUHMjB8wvNqdou+RsbnPf48i0US7NbD8P8sKvEbegl4Ww5j 3oFyNF1VbDWcaKV7mx+wf30k2gYkOSfrUjw0s35k= To: dev@openvswitch.org Cc: Alexandra Rukomoinikova Date: Mon, 17 Nov 2025 12:06:58 +0300 Message-Id: <20251117090712.19708-6-arukomoinikova@k2.cloud> In-Reply-To: <20251117090712.19708-1-arukomoinikova@k2.cloud> References: <20251117090712.19708-1-arukomoinikova@k2.cloud> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 6/9] ovn-controller: Add monitor condition for Service Monitors. 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" Use conditional monitor for Service Monitors. Signed-off-by: Alexandra Rukomoinikova --- controller/ovn-controller.c | 11 ++++++++ tests/ovn-controller.at | 55 +++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 14b9b9e28..9b7932e04 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -268,6 +268,7 @@ update_sb_monitors(struct ovsdb_idl *ovnsb_idl, struct ovsdb_idl_condition ar = OVSDB_IDL_CONDITION_INIT(&ar); struct ovsdb_idl_condition lr = OVSDB_IDL_CONDITION_INIT(&lr); struct ovsdb_idl_condition amb = OVSDB_IDL_CONDITION_INIT(&amb); + struct ovsdb_idl_condition sm = OVSDB_IDL_CONDITION_INIT(&sm); /* Always monitor all logical datapath groups. Otherwise, DPG updates may * be received *after* the lflows using it are seen by ovn-controller. @@ -303,6 +304,7 @@ update_sb_monitors(struct ovsdb_idl *ovnsb_idl, ovsdb_idl_condition_add_clause_true(&nh); ovsdb_idl_condition_add_clause_true(&ar); ovsdb_idl_condition_add_clause_true(&amb); + ovsdb_idl_condition_add_clause_true(&sm); goto out; } @@ -344,6 +346,10 @@ update_sb_monitors(struct ovsdb_idl *ovnsb_idl, sbrec_chassis_template_var_add_clause_chassis(&tv, OVSDB_F_EQ, chassis->name); + + sbrec_service_monitor_add_clause_chassis_name(&sm, OVSDB_F_EQ, + chassis->name); + } else { /* During initialization, we monitor all records in Chassis_Private so * that we don't try to recreate existing ones. */ @@ -373,6 +379,9 @@ update_sb_monitors(struct ovsdb_idl *ovnsb_idl, name = n->name; /* Skip the VIFs we bound already, we should have a local datapath * for those. */ + /* Always monitor service monitors that relate to local ports. */ + sbrec_service_monitor_add_clause_logical_port(&sm, + OVSDB_F_EQ, name); const struct sbrec_port_binding *local_pb = local_binding_get_primary_pb(local_bindings, name); if (local_pb && get_lport_type(local_pb) == LP_VIF && @@ -436,6 +445,7 @@ out:; sb_table_set_opt_mon_condition(ovnsb_idl, learned_route, &lr), sb_table_set_opt_mon_condition(ovnsb_idl, advertised_mac_binding, &amb), + sb_table_set_opt_mon_condition(ovnsb_idl, service_monitor, &sm), }; unsigned int expected_cond_seqno = 0; @@ -459,6 +469,7 @@ out:; ovsdb_idl_condition_destroy(&ar); ovsdb_idl_condition_destroy(&lr); ovsdb_idl_condition_destroy(&amb); + ovsdb_idl_condition_destroy(&sm); return expected_cond_seqno; } diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at index 6ecf50358..e3717a490 100644 --- a/tests/ovn-controller.at +++ b/tests/ovn-controller.at @@ -3851,3 +3851,58 @@ OVN_CLEANUP([hv1], [hv2 /already has encap ip.*cannot duplicate on/d]) AT_CLEANUP ]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([ovn-controller - Service Monitor conditional monitoring]) +AT_KEYWORDS([ovn]) +ovn_start + +net_add n1 +sim_add hv1 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 + +check ovn-nbctl ls-add ls1 -- lsp-add ls1 lsp1 -- \ + lsp-set-addresses lsp1 "50:54:00:00:00:03 10.0.0.1" + +as hv1 +check ovs-vsctl \ + -- add-port br-int vif1 \ + -- set Interface vif1 external_ids:iface-id=lsp1 + +sim_add hv2 +as hv2 +check ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.12 + +AT_SKIP_IF([ovs-vsctl get Open_vSwitch . external_ids:ovn-monitor-all | grep -q "true"]) + +check ovn-nbctl ls-add ls2 -- lsp-add ls1 lsp2 -- \ + lsp-set-addresses lsp2 "50:54:00:00:00:04 10.0.0.2" + +as hv2 +check ovs-vsctl \ + -- add-port br-int vif2 \ + -- set Interface vif2 external_ids:iface-id=lsp2 + +# Enable debug for check the received messages. +as hv1 ovn-appctl -t ovn-controller vlog/set dbg +as hv2 ovn-appctl -t ovn-controller vlog/set dbg + +check ovn-nbctl lsp-hc-add lsp1 icmp 10.0.0.255 +check ovn-nbctl lsp-hc-add lsp2 icmp 10.0.0.255 + +check_row_count sb:Service_Monitor 2 + +AT_CHECK([grep -c 'Service_Monitor' hv1/ovn-controller.log], [0], [dnl +1 +]) + +AT_CHECK([grep -c 'Service_Monitor' hv2/ovn-controller.log], [0], [dnl +1 +]) + +OVN_CLEANUP([hv1],[hv2]) +AT_CLEANUP +]) + From patchwork Mon Nov 17 09:06:59 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rukomoinikova Aleksandra X-Patchwork-Id: 2165509 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=BtyRihOH; dkim-atps=neutral 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 4d922T3JBKz1xwc for ; Mon, 17 Nov 2025 20:07:45 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id A4837822AB; Mon, 17 Nov 2025 09:07:40 +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 dlP4RQMHd2Rl; Mon, 17 Nov 2025 09:07:35 +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 D43EA8218C Authentication-Results: smtp1.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=BtyRihOH Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp1.osuosl.org (Postfix) with ESMTPS id D43EA8218C; Mon, 17 Nov 2025 09:07:28 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 75FEBC0645; Mon, 17 Nov 2025 09:07:28 +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 BEE2FC063E for ; Mon, 17 Nov 2025 09:07:26 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 9C99240AD6 for ; Mon, 17 Nov 2025 09:07: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 ujchIbheDOOI for ; Mon, 17 Nov 2025 09:07:25 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=109.73.14.254; helo=mail3.k2.cloud; envelope-from=arukomoinikova@k2.cloud; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp4.osuosl.org 8B17240A1D Authentication-Results: smtp4.osuosl.org; dmarc=pass (p=none dis=none) header.from=k2.cloud DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 8B17240A1D Authentication-Results: smtp4.osuosl.org; dkim=pass (1024-bit key) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=BtyRihOH Received: from mail3.k2.cloud (mail3.k2.cloud [109.73.14.254]) by smtp4.osuosl.org (Postfix) with ESMTPS id 8B17240A1D for ; Mon, 17 Nov 2025 09:07:23 +0000 (UTC) From: Alexandra Rukomoinikova DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=k2.cloud; s=cloudmail; t=1763370441; bh=0CKt0sQSAPfVPV/Ri1CXRZFWA99bJ13ebR1qyd24+BE=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=BtyRihOHQ3d/l3z0oKbBrws9tO7g1+UEG9EW3q4MtDgdE+79NHkzxS5iMqNQONZej S/eCj2Qul6Z+q/vyYKusd+n3+eWoSvMRl4lfrLwnCwpuxjm0OgPt2EnMji5Z+QprnF RkWV+nAWfCkpWIFhW7kNLR7zadakDVU+Ih456w/U= To: dev@openvswitch.org Cc: Alexandra Rukomoinikova Date: Mon, 17 Nov 2025 12:06:59 +0300 Message-Id: <20251117090712.19708-7-arukomoinikova@k2.cloud> In-Reply-To: <20251117090712.19708-1-arukomoinikova@k2.cloud> References: <20251117090712.19708-1-arukomoinikova@k2.cloud> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 7/9] northd: Skip service health checks for remote ports. 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" Service monitor should only health check locally attached ports. Exclude remote backends from health check monitoring as they cannot be verified from the current chassis. Signed-off-by: Alexandra Rukomoinikova --- northd/northd.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/northd/northd.c b/northd/northd.c index a9c700bb2..7598e01b0 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -3067,10 +3067,9 @@ configure_service_mon_rec(const struct sbrec_service_monitor *sbrec_mon, static inline void update_status_to_service_mon(const struct sbrec_service_monitor *sbrec_mon, - const struct ovn_port *op, - bool remote_backend) + const struct ovn_port *op) { - if (!remote_backend && (!op->sb->n_up || !op->sb->up[0]) && + if ((!op->sb->n_up || !op->sb->up[0]) && sbrec_mon->status && !strcmp(sbrec_mon->status, "online")) { sbrec_service_monitor_set_status(sbrec_mon, "offline"); } @@ -3228,7 +3227,6 @@ ovn_nf_svc_create(struct ovsdb_idl_txn *ovnsb_txn, static inline bool check_svc_port_available(const char *logical_port, - const bool remote_backend, struct hmap *ls_ports, struct sset *svc_monitor_lsps, struct ovn_port **op, @@ -3238,13 +3236,11 @@ check_svc_port_available(const char *logical_port, struct ovn_port *op_p = ovn_port_find(ls_ports, logical_port); - if (!remote_backend && - (!op_p || !lsp_is_enabled(op_p->nbsp))) { + if (!op_p || !lsp_is_enabled(op_p->nbsp)) { return false; } - if (!remote_backend && - op_p->sb && op_p->sb->chassis) { + if (op_p->sb && op_p->sb->chassis) { *chassis_name = op_p->sb->chassis->name; } @@ -3284,8 +3280,8 @@ ovn_lb_svc_create(struct ovsdb_idl_txn *ovnsb_txn, continue; } - if (!check_svc_port_available(backend_nb->logical_port, - backend_nb->remote_backend, + if (!backend_nb->remote_backend && + !check_svc_port_available(backend_nb->logical_port, ls_ports, svc_monitor_lsps, &op, &chassis_name)) { @@ -3317,8 +3313,9 @@ ovn_lb_svc_create(struct ovsdb_idl_txn *ovnsb_txn, svc_monitor_mac_ea, &lb_vip_nb->lb_health_check->options); - update_status_to_service_mon(mon_info->sbrec_mon, - op, backend_nb->remote_backend); + if (!backend_nb->remote_backend) { + update_status_to_service_mon(mon_info->sbrec_mon, op); + } mon_info->required = true; } @@ -3357,7 +3354,7 @@ ovn_lsp_svc_monitor_add_address(struct ovsdb_idl_txn *ovnsb_txn, svc_monitor_mac_ea, &lsp_hc->options); - update_status_to_service_mon(mon_info->sbrec_mon, op, false); + update_status_to_service_mon(mon_info->sbrec_mon, op); mon_info->required = true; } From patchwork Mon Nov 17 09:07:00 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rukomoinikova Aleksandra X-Patchwork-Id: 2165508 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=JfW6kz/6; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::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 4d922R27mvz1xwc for ; Mon, 17 Nov 2025 20:07:43 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 0404B82298; Mon, 17 Nov 2025 09:07:40 +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 Lhhv3NAXrwYt; Mon, 17 Nov 2025 09:07:36 +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 smtp1.osuosl.org CDFC3821CD Authentication-Results: smtp1.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=JfW6kz/6 Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTPS id CDFC3821CD; Mon, 17 Nov 2025 09:07:29 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id A79F8C063F; Mon, 17 Nov 2025 09:07:29 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 13BECC063D for ; Mon, 17 Nov 2025 09:07:28 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id E1915406CD for ; Mon, 17 Nov 2025 09:07:27 +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 NeVxjyn2dtbg for ; Mon, 17 Nov 2025 09:07:27 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=109.73.14.254; helo=mail3.k2.cloud; envelope-from=arukomoinikova@k2.cloud; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp2.osuosl.org 12E9D4047C Authentication-Results: smtp2.osuosl.org; dmarc=pass (p=none dis=none) header.from=k2.cloud DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 12E9D4047C Authentication-Results: smtp2.osuosl.org; dkim=pass (1024-bit key) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=JfW6kz/6 Received: from mail3.k2.cloud (mail3.k2.cloud [109.73.14.254]) by smtp2.osuosl.org (Postfix) with ESMTPS id 12E9D4047C for ; Mon, 17 Nov 2025 09:07:24 +0000 (UTC) From: Alexandra Rukomoinikova DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=k2.cloud; s=cloudmail; t=1763370442; bh=ZDqf9wSuYiUwQ7fS3uvE4qsVPHKpCSOtZzrbpU0XbCM=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=JfW6kz/6BFy1jgGHp+xqKXT1rm8/3ZdyY7T0OYYl1jeTSLMCbg1ytTGpGHAPwtB4h abdordqql8AYXM3lYvyWeUO3UPs1DwttXMMjCYJ1g17PFza0rXdIbWvF1TyzVno3Pe 9QdZd8OhGt7wk8oURVK8SVZmLsR77dSlK54Bzlqc= To: dev@openvswitch.org Cc: Alexandra Rukomoinikova Date: Mon, 17 Nov 2025 12:07:00 +0300 Message-Id: <20251117090712.19708-8-arukomoinikova@k2.cloud> In-Reply-To: <20251117090712.19708-1-arukomoinikova@k2.cloud> References: <20251117090712.19708-1-arukomoinikova@k2.cloud> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 8/9] northd: Refactor SB sync to use engine data structure. 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" Signed-off-by: Alexandra Rukomoinikova --- northd/en-sync-from-sb.c | 28 +++++++++++++++++++--------- northd/en-sync-from-sb.h | 6 ++++++ northd/northd.c | 29 +++++++++++++++++------------ northd/northd.h | 7 +++---- 4 files changed, 45 insertions(+), 25 deletions(-) diff --git a/northd/en-sync-from-sb.c b/northd/en-sync-from-sb.c index dde0e9f55..6d4ff3e39 100644 --- a/northd/en-sync-from-sb.c +++ b/northd/en-sync-from-sb.c @@ -40,23 +40,33 @@ void * en_sync_from_sb_init(struct engine_node *node OVS_UNUSED, struct engine_arg *arg OVS_UNUSED) { - return NULL; + struct en_sync_from_sb_data *data = xmalloc(sizeof *data); + return data; +} + +static void +en_sync_from_sb_get_input_data(struct engine_node *node, + struct en_sync_from_sb_data *data) +{ + data->sb_pb_table = + EN_OVSDB_GET(engine_get_input("SB_port_binding", node)); + data->sb_ha_ch_grp_table = + EN_OVSDB_GET(engine_get_input("SB_ha_chassis_group", node)); } enum engine_node_state -en_sync_from_sb_run(struct engine_node *node, void *data OVS_UNUSED) +en_sync_from_sb_run(struct engine_node *node, void *data_) { + struct en_sync_from_sb_data *data = + (struct en_sync_from_sb_data *) data_; const struct engine_context *eng_ctx = engine_get_context(); - struct northd_data *nd = engine_get_input_data("northd", node); + struct northd_data *northd_data = engine_get_input_data("northd", node); + + en_sync_from_sb_get_input_data(node, data); - const struct sbrec_port_binding_table *sb_pb_table = - EN_OVSDB_GET(engine_get_input("SB_port_binding", node)); - const struct sbrec_ha_chassis_group_table *sb_ha_ch_grp_table = - EN_OVSDB_GET(engine_get_input("SB_ha_chassis_group", node)); stopwatch_start(OVNSB_DB_RUN_STOPWATCH_NAME, time_msec()); ovnsb_db_run(eng_ctx->ovnsb_idl_txn, - sb_pb_table, sb_ha_ch_grp_table, - &nd->ls_ports, &nd->lr_ports); + data, northd_data); stopwatch_stop(OVNSB_DB_RUN_STOPWATCH_NAME, time_msec()); return EN_UNCHANGED; diff --git a/northd/en-sync-from-sb.h b/northd/en-sync-from-sb.h index 0ad07853a..bea248c45 100644 --- a/northd/en-sync-from-sb.h +++ b/northd/en-sync-from-sb.h @@ -3,6 +3,12 @@ #include "lib/inc-proc-eng.h" +struct en_sync_from_sb_data { + /* Southbound table references */ + const struct sbrec_port_binding_table *sb_pb_table; + const struct sbrec_ha_chassis_group_table *sb_ha_ch_grp_table; +}; + void *en_sync_from_sb_init(struct engine_node *, struct engine_arg *); enum engine_node_state en_sync_from_sb_run(struct engine_node *, void *data); void en_sync_from_sb_cleanup(void *data); diff --git a/northd/northd.c b/northd/northd.c index 7598e01b0..4c8befb21 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -54,6 +54,7 @@ #include "en-sampling-app.h" #include "en-datapath-logical-switch.h" #include "en-datapath-logical-router.h" +#include "en-sync-from-sb.h" #include "lib/ovn-parallel-hmap.h" #include "ovn/actions.h" #include "ovn/features.h" @@ -2406,7 +2407,7 @@ op_get_name(const struct ovn_port *op) } static void -ovn_update_ipv6_prefix(struct hmap *lr_ports) +ovn_update_ipv6_prefix(const struct hmap *lr_ports) { const struct ovn_port *op; HMAP_FOR_EACH (op, key_node, lr_ports) { @@ -20731,10 +20732,11 @@ handle_cr_port_binding_changes(const struct sbrec_port_binding *sb, * this column is not empty, it means we need to set the corresponding logical * port as 'up' in the northbound DB. */ static void -handle_port_binding_changes(const struct sbrec_port_binding_table *sb_pb_table, +handle_port_binding_changes( + const struct sbrec_port_binding_table *sb_pb_table, const struct sbrec_ha_chassis_group_table *sb_ha_ch_grp_table, - struct hmap *ls_ports, - struct hmap *lr_ports, + const struct hmap *ls_ports, + const struct hmap *lr_ports, struct shash *ha_ref_chassis_map) { struct hmapx lr_groups = HMAPX_INITIALIZER(&lr_groups); @@ -20810,23 +20812,26 @@ handle_port_binding_changes(const struct sbrec_port_binding_table *sb_pb_table, /* Handle a fairly small set of changes in the southbound database. */ void ovnsb_db_run(struct ovsdb_idl_txn *ovnsb_txn, - const struct sbrec_port_binding_table *sb_pb_table, - const struct sbrec_ha_chassis_group_table *sb_ha_ch_grp_table, - struct hmap *ls_ports, - struct hmap *lr_ports) + const struct en_sync_from_sb_data *sync_from_sb_data, + const struct northd_data *northd_data) { if (!ovsdb_idl_has_ever_connected(ovsdb_idl_txn_get_idl(ovnsb_txn))) { return; } struct shash ha_ref_chassis_map = SHASH_INITIALIZER(&ha_ref_chassis_map); - handle_port_binding_changes(sb_pb_table, sb_ha_ch_grp_table, - ls_ports, lr_ports, &ha_ref_chassis_map); - update_sb_ha_group_ref_chassis(sb_ha_ch_grp_table, &ha_ref_chassis_map); + handle_port_binding_changes(sync_from_sb_data->sb_pb_table, + sync_from_sb_data->sb_ha_ch_grp_table, + &northd_data->ls_ports, + &northd_data->lr_ports, + &ha_ref_chassis_map); + + update_sb_ha_group_ref_chassis(sync_from_sb_data->sb_ha_ch_grp_table, + &ha_ref_chassis_map); shash_destroy(&ha_ref_chassis_map); - ovn_update_ipv6_prefix(lr_ports); + ovn_update_ipv6_prefix(&northd_data->lr_ports); } const struct ovn_datapath * diff --git a/northd/northd.h b/northd/northd.h index e16f5cbfe..bc3f6a142 100644 --- a/northd/northd.h +++ b/northd/northd.h @@ -21,6 +21,7 @@ #include "lib/ovs-atomic.h" #include "lib/sset.h" #include "northd/en-port-group.h" +#include "northd/en-sync-from-sb.h" #include "northd/ipam.h" #include "northd/lb.h" #include "openvswitch/hmap.h" @@ -887,10 +888,8 @@ void ovnnb_db_run(struct northd_input *input_data, struct northd_data *data, struct ovsdb_idl_txn *ovnsb_txn); void ovnsb_db_run(struct ovsdb_idl_txn *ovnsb_txn, - const struct sbrec_port_binding_table *, - const struct sbrec_ha_chassis_group_table *, - struct hmap *ls_ports, - struct hmap *lr_ports); + const struct en_sync_from_sb_data *sync_from_sb_data, + const struct northd_data *northd_data); bool northd_handle_ls_changes(struct ovsdb_idl_txn *, const struct northd_input *, struct northd_data *); From patchwork Mon Nov 17 09:07:01 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rukomoinikova Aleksandra X-Patchwork-Id: 2165511 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=lYtle0ZP; dkim-atps=neutral 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 4d922b6cBZz1xwc for ; Mon, 17 Nov 2025 20:07:51 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 7421741116; Mon, 17 Nov 2025 09:07:50 +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 789aReNrQaji; Mon, 17 Nov 2025 09:07:44 +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 64E0A40D1A Authentication-Results: smtp4.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=lYtle0ZP Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp4.osuosl.org (Postfix) with ESMTPS id 64E0A40D1A; Mon, 17 Nov 2025 09:07:33 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 58A5DC063F; Mon, 17 Nov 2025 09:07:33 +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 20A01C0645 for ; Mon, 17 Nov 2025 09:07:32 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 8426D821EE for ; Mon, 17 Nov 2025 09:07:31 +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 4gNuqekmZwnQ for ; Mon, 17 Nov 2025 09:07:29 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=109.73.14.254; helo=mail3.k2.cloud; envelope-from=arukomoinikova@k2.cloud; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp1.osuosl.org EAAB181F1F Authentication-Results: smtp1.osuosl.org; dmarc=pass (p=none dis=none) header.from=k2.cloud DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org EAAB181F1F Authentication-Results: smtp1.osuosl.org; dkim=pass (1024-bit key) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail header.b=lYtle0ZP Received: from mail3.k2.cloud (mail3.k2.cloud [109.73.14.254]) by smtp1.osuosl.org (Postfix) with ESMTPS id EAAB181F1F for ; Mon, 17 Nov 2025 09:07:25 +0000 (UTC) From: Alexandra Rukomoinikova DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=k2.cloud; s=cloudmail; t=1763370443; bh=YudlDNKd+sIVJL9Y7uy4t81ex2Lp6GDCe7Q2xIRNwts=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=lYtle0ZPijAfhvGttqKNODlJMvakwlZF2XQymNNNVY6WQjFF19ydW3+QYF+M/Za5q Rbxznqw6gupiLbW+IUlCMWo2a1q1ZiaQ/C08d/nUPA2pO1lAT9FB4zi0MoWX/b9mOJ XDxRVm+3HNdJLe4NeY8dGekomWWkF8KStN2ytAwE= To: dev@openvswitch.org Cc: Alexandra Rukomoinikova Date: Mon, 17 Nov 2025 12:07:01 +0300 Message-Id: <20251117090712.19708-9-arukomoinikova@k2.cloud> In-Reply-To: <20251117090712.19708-1-arukomoinikova@k2.cloud> References: <20251117090712.19708-1-arukomoinikova@k2.cloud> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 9/9] northd: Synchronize service monitor status from SB to NB. 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" This commit implements synchronization of health check for logical switch port status from SB Service_Monitor table to NB Logical_Switch_Port_Health_Check table. Signed-off-by: Alexandra Rukomoinikova --- northd/en-sync-from-sb.c | 4 ++++ northd/en-sync-from-sb.h | 3 +++ northd/inc-proc-northd.c | 8 +++++++ northd/northd.c | 45 ++++++++++++++++++++++++++++++++++++++++ ovn-nb.ovsschema | 8 +++++-- ovn-nb.xml | 5 +++++ tests/system-ovn.at | 20 +++++++++++++++--- 7 files changed, 88 insertions(+), 5 deletions(-) diff --git a/northd/en-sync-from-sb.c b/northd/en-sync-from-sb.c index 6d4ff3e39..11f3886dc 100644 --- a/northd/en-sync-from-sb.c +++ b/northd/en-sync-from-sb.c @@ -52,6 +52,10 @@ en_sync_from_sb_get_input_data(struct engine_node *node, EN_OVSDB_GET(engine_get_input("SB_port_binding", node)); data->sb_ha_ch_grp_table = EN_OVSDB_GET(engine_get_input("SB_ha_chassis_group", node)); + data->sbrec_service_monitor_by_service_type = + engine_ovsdb_node_get_index( + engine_get_input("SB_service_monitor", node), + "sbrec_service_monitor_by_service_type"); } enum engine_node_state diff --git a/northd/en-sync-from-sb.h b/northd/en-sync-from-sb.h index bea248c45..177d75de0 100644 --- a/northd/en-sync-from-sb.h +++ b/northd/en-sync-from-sb.h @@ -7,6 +7,9 @@ struct en_sync_from_sb_data { /* Southbound table references */ const struct sbrec_port_binding_table *sb_pb_table; const struct sbrec_ha_chassis_group_table *sb_ha_ch_grp_table; + + /* Indexes */ + struct ovsdb_idl_index *sbrec_service_monitor_by_service_type; }; void *en_sync_from_sb_init(struct engine_node *, struct engine_arg *); diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c index 5c41fd3ac..cebd4e29d 100644 --- a/northd/inc-proc-northd.c +++ b/northd/inc-proc-northd.c @@ -465,6 +465,7 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, sync_from_sb_northd_handler); engine_add_input(&en_sync_from_sb, &en_sb_port_binding, NULL); engine_add_input(&en_sync_from_sb, &en_sb_ha_chassis_group, NULL); + engine_add_input(&en_sync_from_sb, &en_sb_service_monitor, NULL); engine_add_input(&en_northd_output, &en_acl_id, NULL); engine_add_input(&en_northd_output, &en_sync_from_sb, NULL); @@ -580,6 +581,13 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, "sbrec_service_monitor_by_learned_type", sbrec_service_monitor_by_learned_type); + struct ovsdb_idl_index *sbrec_service_monitor_by_service_type + = ovsdb_idl_index_create1(sb->idl, + &sbrec_service_monitor_col_type); + engine_ovsdb_node_add_index(&en_sb_service_monitor, + "sbrec_service_monitor_by_service_type", + sbrec_service_monitor_by_service_type); + struct ed_type_global_config *global_config = engine_get_internal_data(&en_global_config); unixctl_command_register("debug/chassis-features-list", "", 0, 0, diff --git a/northd/northd.c b/northd/northd.c index 4c8befb21..7015ac68c 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -20809,6 +20809,46 @@ handle_port_binding_changes( hmapx_destroy(&lr_groups); } +static void +handle_service_monitor_changes( + struct ovsdb_idl_index *sbrec_service_monitor_by_service_type, + const struct hmap *ls_ports) +{ + const struct sbrec_service_monitor *sbrec_mon; + struct sbrec_service_monitor *key = + sbrec_service_monitor_index_init_row( + sbrec_service_monitor_by_service_type); + + sbrec_service_monitor_set_type(key, "logical-switch-port"); + + SBREC_SERVICE_MONITOR_FOR_EACH_EQUAL (sbrec_mon, key, + sbrec_service_monitor_by_service_type) { + + struct ovn_port *op = ovn_port_find(ls_ports, sbrec_mon->logical_port); + if (!op) { + continue; + } + + ovs_assert(op->nbsp && op->nbsp->n_health_checks); + + for (size_t i = 0; i < op->nbsp->n_health_checks; i++) { + const struct nbrec_logical_switch_port_health_check *lsp_hc = + op->nbsp->health_checks[i]; + + const char *desired_status = sbrec_mon->status; + if (desired_status) { + if (!lsp_hc->status || + strcmp(lsp_hc->status, desired_status)) { + nbrec_logical_switch_port_health_check_set_status( + lsp_hc, sbrec_mon->status); + } + } + } + } + + sbrec_service_monitor_index_destroy_row(key); +} + /* Handle a fairly small set of changes in the southbound database. */ void ovnsb_db_run(struct ovsdb_idl_txn *ovnsb_txn, @@ -20826,6 +20866,11 @@ ovnsb_db_run(struct ovsdb_idl_txn *ovnsb_txn, &northd_data->lr_ports, &ha_ref_chassis_map); + handle_service_monitor_changes( + sync_from_sb_data->sbrec_service_monitor_by_service_type, + &northd_data->ls_ports); + + update_sb_ha_group_ref_chassis(sync_from_sb_data->sb_ha_ch_grp_table, &ha_ref_chassis_map); diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema index f59e80c20..18af0744f 100644 --- a/ovn-nb.ovsschema +++ b/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", - "version": "7.15.0", - "cksum": "42875815 44684", + "version": "7.16.0", + "cksum": "1566377856 44897", "tables": { "NB_Global": { "columns": { @@ -260,6 +260,10 @@ "addresses": {"type": {"key": "string", "min": 0, "max": "unlimited"}}, + "status": { + "type": {"key": {"type": "string", + "enum": ["set", ["online", "offline", "error"]]}, + "min": 0, "max": 1}}, "options": { "type": {"key": "string", "value": "string", diff --git a/ovn-nb.xml b/ovn-nb.xml index 9202f0910..1fd7e7250 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -2205,6 +2205,11 @@ health check will use all addresses configured on logical switch port. + + Health status synchronized from the status field of + corresponding service monitor in the southbound database. + + The interval, in seconds, between service monitor checks. diff --git a/tests/system-ovn.at b/tests/system-ovn.at index 6dd12787a..1dcd087e9 100644 --- a/tests/system-ovn.at +++ b/tests/system-ovn.at @@ -19329,26 +19329,40 @@ OVS_WAIT_UNTIL([ # Wait until the services are set to online. wait_row_count Service_Monitor 1 status=online -# Create one more health check on logical switch port -NETNS_DAEMONIZE([lport], [nc -l -k 192.168.0.10 4041], [lport_tcp.pid]) +# Check status +check_column "online" nb:Logical_Switch_Port_Health_Check status protocol=icmp +# Check tcp monitor check ovn-nbctl lsp-hc-add lport tcp 192.168.0.255 4041 lport1_uuid2=$(fetch_column nb:Logical_Switch_Port_Health_Check _uuid protocol=tcp) check_row_count sb:Service_Monitor 2 +ovn-sbctl list service_monitor + +check_column "offline" nb:Logical_Switch_Port_Health_Check status protocol=tcp + +# Create one more health check on logical switch port +NETNS_DAEMONIZE([lport], [nc -l -k 192.168.0.10 4041], [lport_tcp.pid]) + # Wait until the services are set to online. wait_row_count Service_Monitor 2 status=online -NETNS_DAEMONIZE([lport], [nc -ulp 4042], [lport_udp.pid]) +check_column "online" nb:Logical_Switch_Port_Health_Check status protocol=tcp check ovn-nbctl lsp-hc-add lport udp 192.168.0.255 4042 lport1_uuid3=$(fetch_column nb:Logical_Switch_Port_Health_Check _uuid protocol=udp) +check_column "offline" nb:Logical_Switch_Port_Health_Check status protocol=udp + +NETNS_DAEMONIZE([lport], [nc -ulp 4042], [lport_udp.pid]) + check_row_count sb:Service_Monitor 3 # Wait until the services are set to online. wait_row_count Service_Monitor 3 status=online +check_column "online" nb:Logical_Switch_Port_Health_Check status protocol=udp + AT_CLEANUP ])