get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/2194259/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2194259,
    "url": "http://patchwork.ozlabs.org/api/patches/2194259/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/ovn/patch/20260207214852.86991-1-arukomoinikova@k2.cloud/",
    "project": {
        "id": 68,
        "url": "http://patchwork.ozlabs.org/api/projects/68/?format=api",
        "name": "Open Virtual Network development",
        "link_name": "ovn",
        "list_id": "ovs-dev.openvswitch.org",
        "list_email": "ovs-dev@openvswitch.org",
        "web_url": "http://openvswitch.org/",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20260207214852.86991-1-arukomoinikova@k2.cloud>",
    "list_archive_url": null,
    "date": "2026-02-07T21:48:42",
    "name": "[ovs-dev,1/8,v2] ovn-nb, ovn-nbctl: Add Logical Switch Port Health Check support.",
    "commit_ref": null,
    "pull_url": null,
    "state": "changes-requested",
    "archived": false,
    "hash": "d27873007979fa77ca9b54a06481cc44c3367f82",
    "submitter": {
        "id": 89461,
        "url": "http://patchwork.ozlabs.org/api/people/89461/?format=api",
        "name": "Rukomoinikova Aleksandra",
        "email": "ARukomoinikova@k2.cloud"
    },
    "delegate": {
        "id": 94943,
        "url": "http://patchwork.ozlabs.org/api/users/94943/?format=api",
        "username": "dceara",
        "first_name": "Dumitru",
        "last_name": "Ceara",
        "email": "dceara@redhat.com"
    },
    "mbox": "http://patchwork.ozlabs.org/project/ovn/patch/20260207214852.86991-1-arukomoinikova@k2.cloud/mbox/",
    "series": [
        {
            "id": 491397,
            "url": "http://patchwork.ozlabs.org/api/series/491397/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/ovn/list/?series=491397",
            "date": "2026-02-07T21:48:46",
            "name": "[ovs-dev,1/8,v2] ovn-nb, ovn-nbctl: Add Logical Switch Port Health Check support.",
            "version": 2,
            "mbox": "http://patchwork.ozlabs.org/series/491397/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2194259/comments/",
    "check": "warning",
    "checks": "http://patchwork.ozlabs.org/api/patches/2194259/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<ovs-dev-bounces@openvswitch.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "dev@openvswitch.org"
        ],
        "Delivered-To": [
            "patchwork-incoming@legolas.ozlabs.org",
            "ovs-dev@lists.linuxfoundation.org"
        ],
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n unprotected) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256\n header.s=cloudmail header.b=J43gT9dx;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org\n (client-ip=2605:bc80:3010::137; helo=smtp4.osuosl.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org)",
            "smtp4.osuosl.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key)\n header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256 header.s=cloudmail\n header.b=J43gT9dx",
            "smtp1.osuosl.org;\n dmarc=pass (p=none dis=none) header.from=k2.cloud",
            "smtp1.osuosl.org; dkim=pass (1024-bit key,\n unprotected) header.d=k2.cloud header.i=@k2.cloud header.a=rsa-sha256\n header.s=cloudmail header.b=J43gT9dx"
        ],
        "Received": [
            "from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4f7l3M3jHYz1xvW\n\tfor <incoming@patchwork.ozlabs.org>; Sun, 08 Feb 2026 08:49:19 +1100 (AEDT)",
            "from localhost (localhost [127.0.0.1])\n\tby smtp4.osuosl.org (Postfix) with ESMTP id 543D341BFB;\n\tSat,  7 Feb 2026 21:49:13 +0000 (UTC)",
            "from smtp4.osuosl.org ([127.0.0.1])\n by localhost (smtp4.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id S8cnCGUu36bg; Sat,  7 Feb 2026 21:49:06 +0000 (UTC)",
            "from lists.linuxfoundation.org (lf-lists.osuosl.org\n [IPv6:2605:bc80:3010:104::8cd3:938])\n\tby smtp4.osuosl.org (Postfix) with ESMTPS id 902FC41C01;\n\tSat,  7 Feb 2026 21:49:05 +0000 (UTC)",
            "from lf-lists.osuosl.org (localhost [127.0.0.1])\n\tby lists.linuxfoundation.org (Postfix) with ESMTP id 669DBC0780;\n\tSat,  7 Feb 2026 21:49:05 +0000 (UTC)",
            "from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138])\n by lists.linuxfoundation.org (Postfix) with ESMTP id 97D6BC02A4\n for <dev@openvswitch.org>; Sat,  7 Feb 2026 21:49:01 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n by smtp1.osuosl.org (Postfix) with ESMTP id 77B5983330\n for <dev@openvswitch.org>; Sat,  7 Feb 2026 21:49:01 +0000 (UTC)",
            "from smtp1.osuosl.org ([127.0.0.1])\n by localhost (smtp1.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id 6sFXUcsK8_6o for <dev@openvswitch.org>;\n Sat,  7 Feb 2026 21:48:59 +0000 (UTC)",
            "from mail1.k2.cloud (mail1.k2.cloud [109.73.14.252])\n by smtp1.osuosl.org (Postfix) with ESMTPS id DD85380ED6\n for <dev@openvswitch.org>; Sat,  7 Feb 2026 21:48:57 +0000 (UTC)"
        ],
        "X-Virus-Scanned": [
            "amavis at osuosl.org",
            "amavis at osuosl.org"
        ],
        "X-Comment": "SPF check N/A for local connections -\n client-ip=2605:bc80:3010:104::8cd3:938; helo=lists.linuxfoundation.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=<UNKNOWN> ",
        "DKIM-Filter": [
            "OpenDKIM Filter v2.11.0 smtp4.osuosl.org 902FC41C01",
            "OpenDKIM Filter v2.11.0 smtp1.osuosl.org DD85380ED6"
        ],
        "Received-SPF": "Pass (mailfrom) identity=mailfrom; client-ip=109.73.14.252;\n helo=mail1.k2.cloud; envelope-from=arukomoinikova@k2.cloud;\n receiver=<UNKNOWN>",
        "DMARC-Filter": "OpenDMARC Filter v1.4.2 smtp1.osuosl.org DD85380ED6",
        "From": "Alexandra Rukomoinikova <arukomoinikova@k2.cloud>",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=k2.cloud;\n s=cloudmail; t=1770500934;\n bh=rltx91eR4UtHxYQitCzPL37yChgeydWxTjy7s7aLpGw=;\n h=From:To:Cc:Subject:Date;\n b=J43gT9dxDKIrbVzWDT77Ggigax6+3Y09oKE8JR2/4wd3ByARylCvyIZvAgjxpV0W5\n hecbuyaHQHAHkLpgFobE9XVVcR4uedXGh83/TpQYzDOWlV9m/m5tD9l56PQvkMQAZo\n y8pqUJ+8gCruCmMfxEiAJqhxRGBbkPE2czn6lq54=",
        "To": "dev@openvswitch.org",
        "Cc": "Alexandra Rukomoinikova <arukomoinikova@k2.cloud>",
        "Date": "Sun,  8 Feb 2026 00:48:42 +0300",
        "Message-Id": "<20260207214852.86991-1-arukomoinikova@k2.cloud>",
        "MIME-Version": "1.0",
        "Subject": "[ovs-dev] [PATCH ovn 1/8 v2] ovn-nb,\n ovn-nbctl: Add Logical Switch Port Health Check support.",
        "X-BeenThere": "ovs-dev@openvswitch.org",
        "X-Mailman-Version": "2.1.30",
        "Precedence": "list",
        "List-Id": "<ovs-dev.openvswitch.org>",
        "List-Unsubscribe": "<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>",
        "List-Archive": "<http://mail.openvswitch.org/pipermail/ovs-dev/>",
        "List-Post": "<mailto:ovs-dev@openvswitch.org>",
        "List-Help": "<mailto:ovs-dev-request@openvswitch.org?subject=help>",
        "List-Subscribe": "<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=subscribe>",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Errors-To": "ovs-dev-bounces@openvswitch.org",
        "Sender": "\"dev\" <ovs-dev-bounces@openvswitch.org>"
    },
    "content": "Add schema and CLI support for health checks on logical switch\nports by introducing a new health check table and linking it\nfrom logical switch ports. Implement corresponding ovn-nbctl\ncommands to manage LSP health checks. Also extend service\nmonitoring to support the logical-switch-port type.\n\nSigned-off-by: Alexandra Rukomoinikova <arukomoinikova@k2.cloud>\n---\nv1 --> v2: corrected all the comments and made one service monitor bind to only one address\n---\n ovn-nb.ovsschema          |  28 ++-\n ovn-nb.xml                |  53 ++++\n ovn-sb.ovsschema          |   7 +-\n ovn-sb.xml                |  11 +\n tests/ovn-nbctl.at        | 196 +++++++++++++++\n utilities/ovn-nbctl.8.xml |  52 ++++\n utilities/ovn-nbctl.c     | 516 ++++++++++++++++++++++++++++++++++++--\n 7 files changed, 842 insertions(+), 21 deletions(-)",
    "diff": "diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema\nindex 8c2c1d861..538b37456 100644\n--- a/ovn-nb.ovsschema\n+++ b/ovn-nb.ovsschema\n@@ -1,7 +1,7 @@\n {\n     \"name\": \"OVN_Northbound\",\n-    \"version\": \"7.15.0\",\n-    \"cksum\": \"4060410729 43708\",\n+    \"version\": \"7.16.0\",\n+    \"cksum\": \"3492890733 44939\",\n     \"tables\": {\n         \"NB_Global\": {\n             \"columns\": {\n@@ -179,6 +179,11 @@\n                                      \"refType\": \"strong\"},\n                              \"min\": 0,\n                              \"max\": 1}},\n+                \"health_checks\": {\"type\": {\"key\": {\"type\": \"uuid\",\n+                                          \"refTable\": \"Logical_Switch_Port_Health_Check\",\n+                                          \"refType\": \"strong\"},\n+                                 \"min\": 0,\n+                                 \"max\": \"unlimited\"}},\n                 \"external_ids\": {\n                     \"type\": {\"key\": \"string\", \"value\": \"string\",\n                              \"min\": 0, \"max\": \"unlimited\"}}},\n@@ -246,6 +251,25 @@\n                              \"min\": 0, \"max\": \"unlimited\"}}},\n             \"indexes\": [[\"name\"], [\"id\"]],\n             \"isRoot\": true},\n+        \"Logical_Switch_Port_Health_Check\": {\n+            \"columns\": {\n+                \"protocol\": {\n+                    \"type\": {\"key\": {\"type\": \"string\",\n+                             \"enum\": [\"set\", [\"tcp\", \"udp\", \"icmp\"]]},\n+                             \"min\": 0, \"max\": 1}},\n+                \"src_ip\": {\"type\": \"string\"},\n+                \"port\": {\"type\": {\"key\": {\"type\": \"integer\",\n+                                          \"minInteger\": 0,\n+                                          \"maxInteger\": 65535}}},\n+                \"address\": {\"type\": {\"key\": \"string\",\n+                                       \"min\": 0,\n+                                       \"max\": 1}},\n+                \"options\": {\n+                     \"type\": {\"key\": \"string\",\n+                              \"value\": \"string\",\n+                              \"min\": 0,\n+                              \"max\": \"unlimited\"}}},\n+            \"isRoot\": false},\n         \"Forwarding_Group\": {\n             \"columns\": {\n                 \"name\": {\"type\": \"string\"},\ndiff --git a/ovn-nb.xml b/ovn-nb.xml\nindex 1acbf202b..e60edbd8d 100644\n--- a/ovn-nb.xml\n+++ b/ovn-nb.xml\n@@ -2136,6 +2136,11 @@\n         Please see the <ref table=\"Mirror\"/> table.\n     </column>\n \n+    <column name=\"health_checks\">\n+        Health checks configuration for this logical switch port.\n+        Please see the <ref table=\"Logical_Switch_Port_Health_Check\"/> table.\n+    </column>\n+\n     <column name=\"ha_chassis_group\">\n       References a row in the OVN Northbound database's\n       <ref table=\"HA_Chassis_Group\" db=\"OVN_Northbound\"/> table.\n@@ -2192,6 +2197,54 @@\n     </group>\n   </table>\n \n+  <table name=\"Logical_Switch_Port_Health_Check\"\n+         title=\"logical switch port health check\">\n+    <p>\n+      Each row represents health check configuration for logical switch port.\n+      Health checks are used to monitor reachability and health of backend\n+      endpoints associated with logical switch port. Health check can be\n+      configured to use different protocols (TCP, UDP, or ICMP) to verify\n+      availability of target IP addresses.\n+    </p>\n+\n+    <column name=\"protocol\">\n+      Valid protocols are <code>tcp</code>, <code>udp</code>, or\n+      <code>icmp</code>. For <code>tcp</code> and <code>udp</code>\n+      protocols - destination port must be specified.\n+    </column>\n+\n+    <column name=\"src_ip\">\n+      Source IP address used when sending health check probes.\n+    </column>\n+\n+    <column name=\"port\">\n+      Destination port number for TCP and UDP health checks.\n+    </column>\n+\n+    <column name=\"address\">\n+      IP address to monitor for the health check.\n+    </column>\n+\n+    <column name=\"options\" key=\"interval\" type='{\"type\": \"integer\"}'>\n+      The interval, in seconds, between service monitor checks.\n+    </column>\n+\n+    <column name=\"options\" key=\"timeout\" type='{\"type\": \"integer\"}'>\n+      The time, in seconds, after which the service monitor check times\n+      out.\n+    </column>\n+\n+    <column name=\"options\" key=\"success_count\" type='{\"type\": \"integer\"}'>\n+      The number of successful checks after which the service is\n+      considered <code>online</code>.\n+    </column>\n+\n+    <column name=\"options\" key=\"failure_count\" type='{\"type\": \"integer\"}'>\n+      The number of failure checks after which the service is considered\n+    <code>offline</code>.\n+    </column>\n+  </table>\n+\n   <table name=\"Forwarding_Group\" title=\"forwarding group\">\n     <p>\n       Each row represents one forwarding group.\ndiff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema\nindex cf33933da..dd9e32f06 100644\n--- a/ovn-sb.ovsschema\n+++ b/ovn-sb.ovsschema\n@@ -1,7 +1,7 @@\n {\n     \"name\": \"OVN_Southbound\",\n-    \"version\": \"21.7.0\",\n-    \"cksum\": \"1383351379 36646\",\n+    \"version\": \"21.8.0\",\n+    \"cksum\": \"3491605797 36713\",\n     \"tables\": {\n         \"SB_Global\": {\n             \"columns\": {\n@@ -516,7 +516,8 @@\n                 \"type\": {\"type\": {\"key\": {\n                            \"type\": \"string\",\n                            \"enum\": [\"set\", [\"load-balancer\",\n-                                            \"network-function\"]]},\n+                                            \"network-function\",\n+                                            \"logical-switch-port\"]]},\n                              \"min\": 0, \"max\": 1}},\n                 \"ip\": {\"type\": \"string\"},\n                 \"mac\": {\"type\": \"string\"},\ndiff --git a/ovn-sb.xml b/ovn-sb.xml\nindex 00bae26bf..0ec7d6094 100644\n--- a/ovn-sb.xml\n+++ b/ovn-sb.xml\n@@ -5042,6 +5042,8 @@ tcp.flags = RST;\n         icmp, and the health probe is done by injecting an icmp echo request\n         packet into the <code>inport</code> of the Network_Function and then\n         montoring the same packet coming out of the <code>outport</code>.\n+        For <code>type</code> \"logical-switch-port\", supported protocols are\n+        <code>tcp</code>, <code>udp</code> and <code>icmp</code>.\n       </column>\n \n       <column name=\"port\">\n@@ -5124,6 +5126,15 @@ tcp.flags = RST;\n           the service and doesn't expect any reply.  If it receives an ICMP\n           reply, then it considers the service to be <code>offline</code>.\n         </p>\n+\n+        <p>\n+          For ICMP service, <code>ovn-controller</code> sends an ICMP\n+          Echo Request and expects an ICMP Echo Reply to consider service\n+          to be <code>online</code>. If no reply is received or if an ICMP\n+          error message is received, the service is considered\n+          <code>offline</code>.\n+       </p>\n+\n       </column>\n     </group>\n \ndiff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at\nindex dccf30758..177e097fb 100644\n--- a/tests/ovn-nbctl.at\n+++ b/tests/ovn-nbctl.at\n@@ -3499,3 +3499,199 @@ AT_CHECK([ovn-nbctl --may-exist lsp-add-localnet-port ls ln_port net1], [1], [],\n check ovn-nbctl lsp-set-options ln_port network_name=net1\n check ovn-nbctl --may-exist lsp-add-localnet-port ls ln_port net1\n ])\n+\n+dnl ---------------------------------------------------------------------\n+\n+AT_SETUP([ovn-nbctl - Logical Switch Port Health Check])\n+OVN_NBCTL_TEST_START daemon\n+\n+# Create logical switch port\n+AT_CHECK([ovn-nbctl ls-add ls0])\n+AT_CHECK([ovn-nbctl lsp-add ls0 lport0])\n+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\"])\n+\n+# Create IPV4 ICMP health check\n+AT_CHECK([ovn-nbctl lsp-hc-add lport0 icmp 192.168.0.255 192.168.1.10])\n+AT_CHECK([ovn-nbctl lsp-hc-list lport0], [0], [dnl\n+Logical Switch Port lport0:\n+  Protocol      :  icmp\n+  Source IP     :  192.168.0.255\n+  Addresses     :  192.168.1.10\n+])\n+\n+# Check hc attaching to logical switch port\n+hc_icmp_uuid=$(fetch_column nb:logical_switch_port_health_check _uuid src_ip=\"192.168.0.255\")\n+check_column \"$hc_icmp_uuid\" nb:logical_switch_port health_checks\n+\n+# Create IPv4 TCP health check with the specified addresses\n+AT_CHECK([ovn-nbctl lsp-hc-add lport0 tcp 10.0.0.2 80 192.168.1.10])\n+AT_CHECK([ovn-nbctl lsp-hc-list lport0], [0], [dnl\n+Logical Switch Port lport0:\n+  Protocol      :  tcp\n+  Source IP     :  10.0.0.2\n+  Port          :  80\n+  Addresses     :  192.168.1.10\n+\n+  Protocol      :  icmp\n+  Source IP     :  192.168.0.255\n+  Addresses     :  192.168.1.10\n+])\n+hc_tcp_uuid=$(fetch_column nb:logical_switch_port_health_check _uuid src_ip=\"10.0.0.2\")\n+\n+# Create UDP health check with the specified addresses\n+AT_CHECK([ovn-nbctl lsp-hc-add lport0 udp 10.0.0.3 53 192.168.1.11])\n+AT_CHECK([ovn-nbctl lsp-hc-list lport0], [0], [dnl\n+Logical Switch Port lport0:\n+  Protocol      :  tcp\n+  Source IP     :  10.0.0.2\n+  Port          :  80\n+  Addresses     :  192.168.1.10\n+\n+  Protocol      :  udp\n+  Source IP     :  10.0.0.3\n+  Port          :  53\n+  Addresses     :  192.168.1.11\n+\n+  Protocol      :  icmp\n+  Source IP     :  192.168.0.255\n+  Addresses     :  192.168.1.10\n+])\n+hc_udp_uuid=$(fetch_column nb:logical_switch_port_health_check _uuid src_ip=\"10.0.0.3\")\n+\n+check_column \"$hc_icmp_uuid $hc_tcp_uuid $hc_udp_uuid\" nb:logical_switch_port health_checks\n+\n+AT_CHECK([ovn-nbctl lsp-hc-del lport0 $hc_icmp_uuid])\n+# Check hcs detaching to logical switch port\n+check_column \"$hc_tcp_uuid $hc_udp_uuid\" nb:logical_switch_port health_checks\n+\n+AT_CHECK([ovn-nbctl lsp-hc-list lport0], [0], [dnl\n+Logical Switch Port lport0:\n+  Protocol      :  tcp\n+  Source IP     :  10.0.0.2\n+  Port          :  80\n+  Addresses     :  192.168.1.10\n+\n+  Protocol      :  udp\n+  Source IP     :  10.0.0.3\n+  Port          :  53\n+  Addresses     :  192.168.1.11\n+])\n+\n+AT_CHECK([ovn-nbctl lsp-hc-del lport0])\n+check_row_count nb:Logical_Switch_Port_Health_Check 0\n+AT_CHECK([ovn-nbctl lsp-hc-list lport0], [0], [dnl])\n+\n+# Check invalid protocol\n+AT_CHECK([ovn-nbctl lsp-hc-add lport0 stcp 10.0.0.1 50], [1], [], [stderr])\n+AT_CHECK([grep \"Type must be icmp, tcp or udp\" stderr], [0], [ignore])\n+\n+# Check invalid source IP\n+AT_CHECK([ovn-nbctl lsp-hc-add lport0 icmp invalid_ip invalid_ip], [1], [], [stderr])\n+AT_CHECK([grep \"Not a valid IPv4 or IPv6 address\" stderr], [0], [ignore])\n+\n+# Check TCP/UDP non-valid destination port\n+AT_CHECK([ovn-nbctl lsp-hc-add lport0 tcp 10.0.0.1 70000], [1], [], [stderr])\n+AT_CHECK([grep \"port must in range 0...65535\" stderr], [0], [ignore])\n+\n+# Check IP address not configured on port\n+AT_CHECK([ovn-nbctl lsp-hc-add lport0 icmp 10.0.0.1 192.168.99.99], [1], [], [stderr])\n+AT_CHECK([grep \"Address 192.168.99.99 not configured on port\" stderr], [0], [ignore])\n+\n+AT_CHECK([ovn-nbctl lsp-hc-del lport0])\n+\n+# Different source IP, same protocol, port and address - should be allowed\n+AT_CHECK([ovn-nbctl lsp-hc-add lport0 tcp 10.0.0.1 80 192.168.1.10])\n+AT_CHECK([ovn-nbctl lsp-hc-add lport0 tcp 10.0.0.2 80 192.168.1.10], [0], [], [ignore])\n+AT_CHECK([ovn-nbctl lsp-hc-add lport0 tcp 10.0.0.3 80 192.168.1.10], [0], [], [ignore])\n+\n+# Same source IP, different ports, same protocol and address - should be allowed\n+AT_CHECK([ovn-nbctl lsp-hc-add lport0 tcp 10.0.0.1 81 192.168.1.10], [0], [], [ignore])\n+AT_CHECK([ovn-nbctl lsp-hc-add lport0 tcp 10.0.0.1 82 192.168.1.10], [0], [], [ignore])\n+\n+# Same source IP and port, different protocols, same address - should be allowed\n+AT_CHECK([ovn-nbctl lsp-hc-add lport0 udp 10.0.0.1 80 192.168.1.10], [0], [], [ignore])\n+AT_CHECK([ovn-nbctl lsp-hc-add lport0 icmp 10.0.0.1 192.168.1.10], [0], [], [ignore])\n+\n+# Check duplication\n+AT_CHECK([ovn-nbctl lsp-hc-add lport0 tcp 10.0.0.5 90 192.168.1.10])\n+AT_CHECK([ovn-nbctl lsp-hc-add lport0 tcp 10.0.0.5 90 192.168.1.10], [1], [], [stderr])\n+AT_CHECK([grep \"Health check with address 192.168.1.10 already exists on port lport0\" stderr], [0], [ignore])\n+\n+# ICMP - same source IP, different addresses - should be allowed\n+AT_CHECK([ovn-nbctl lsp-hc-del lport0])\n+AT_CHECK([ovn-nbctl lsp-hc-add lport0 icmp 10.0.0.9 192.168.1.10])\n+AT_CHECK([ovn-nbctl lsp-hc-add lport0 icmp 10.0.0.9 192.168.1.11], [0], [], [ignore])\n+\n+# ICMP - different source IP, same address - should be allowed\n+AT_CHECK([ovn-nbctl lsp-hc-add lport0 icmp 10.0.0.10 192.168.1.10], [0], [], [ignore])\n+\n+# Check supported logical switch port type for monitoring\n+AT_CHECK([ovn-nbctl lsp-add ls0 lport1])\n+AT_CHECK([ovn-nbctl lsp-set-type lport1 router])\n+AT_CHECK([ovn-nbctl lsp-hc-add lport1 icmp 10.0.0.1 10.0.0.2], [1], [], [stderr])\n+AT_CHECK([grep \"Health check monitoring supported only for port with vif type\" stderr], [0], [ignore])\n+\n+AT_CHECK([ovn-nbctl lsp-hc-del lport0])\n+\n+# Test IPv6 addresses support: icmp, tcp, udp\n+AT_CHECK([ovn-nbctl lsp-add ls0 lport3])\n+AT_CHECK([ovn-nbctl lsp-set-addresses lport3 \"00:11:22:33:44:57 2001:db8::1\"])\n+AT_CHECK([ovn-nbctl lsp-hc-add lport3 icmp 2001:db8::2 2001:db8::1])\n+AT_CHECK([ovn-nbctl lsp-hc-add lport3 tcp 2001:db8::2 80 2001:db8::1])\n+AT_CHECK([ovn-nbctl lsp-hc-add lport3 udp 2001:db8::2 53 2001:db8::1])\n+AT_CHECK([ovn-nbctl lsp-hc-list lport3], [0], [dnl\n+Logical Switch Port lport3:\n+  Protocol      :  icmp\n+  Source IP     :  2001:db8::2\n+  Addresses     :  2001:db8::1\n+\n+  Protocol      :  tcp\n+  Source IP     :  2001:db8::2\n+  Port          :  80\n+  Addresses     :  2001:db8::1\n+\n+  Protocol      :  udp\n+  Source IP     :  2001:db8::2\n+  Port          :  53\n+  Addresses     :  2001:db8::1\n+])\n+\n+AT_CHECK([ovn-nbctl lsp-hc-del lport3])\n+\n+# Duplicate IPv6 health check - should be disabled\n+AT_CHECK([ovn-nbctl lsp-hc-add lport3 icmp 2001:db8::2 2001:db8::1])\n+AT_CHECK([ovn-nbctl lsp-hc-add lport3 icmp 2001:db8::2 2001:db8::1], [1], [], [stderr])\n+AT_CHECK([grep \"Health check with address 2001:db8::1 already exists on port lport3\" stderr], [0], [ignore])\n+\n+# Check options printing\n+AT_CHECK([ovn-nbctl lsp-hc-add lport0 icmp 10.0.0.4 192.168.1.10 192.168.1.11])\n+AT_CHECK([ovn-nbctl lsp-hc-list lport0], [0], [dnl\n+Logical Switch Port lport0:\n+  Protocol      :  icmp\n+  Source IP     :  10.0.0.4\n+  Addresses     :  192.168.1.10\n+])\n+hc_icmp_uuid=$(fetch_column nb:logical_switch_port_health_check _uuid src_ip=\"10.0.0.4\")\n+\n+AT_CHECK([ovn-nbctl set logical_switch_port_health_check $hc_icmp_uuid options:interval=3])\n+AT_CHECK([ovn-nbctl set logical_switch_port_health_check $hc_icmp_uuid options:timeout=30])\n+AT_CHECK([ovn-nbctl set logical_switch_port_health_check $hc_icmp_uuid options:success_count=1])\n+AT_CHECK([ovn-nbctl set logical_switch_port_health_check $hc_icmp_uuid options:failure_count=2])\n+\n+AT_CHECK([ovn-nbctl lsp-hc-list lport0], [0], [dnl\n+Logical Switch Port lport0:\n+  Protocol      :  icmp\n+  Source IP     :  10.0.0.4\n+  Addresses     :  192.168.1.10\n+  Interval      :  3\n+  Timeout       :  30\n+  Success count :  1\n+  Failure count :  2\n+])\n+\n+AT_CHECK([ovn-nbctl lsp-hc-del lport0])\n+AT_CHECK([ovn-nbctl lsp-hc-del lport3])\n+check_row_count nb:Logical_Switch_Port_Health_Check 0\n+\n+OVN_NBCTL_TEST_STOP \"/terminating with signal 15/d\"\n+AT_CLEANUP\ndiff --git a/utilities/ovn-nbctl.8.xml b/utilities/ovn-nbctl.8.xml\nindex 7df902944..c403fcfb6 100644\n--- a/utilities/ovn-nbctl.8.xml\n+++ b/utilities/ovn-nbctl.8.xml\n@@ -1822,6 +1822,58 @@\n       </dd>\n     </dl>\n \n+    <h2>Health Check commands</h2>\n+    <dl>\n+      <dt><code>lsp-hc-add</code> <var>PORT</var> <var>PROTOCOL</var>\n+      <var>SOURCE_IP</var> [<var>DST_PORT</var>] <var>ADDRESS</var></dt>\n+      <dd>\n+        <p>\n+          Creates a new health check configuration for the logical switch port\n+          <code>PORT</code> with the below mandatory arguments.\n+        </p>\n+\n+        <p>\n+          <var>PROTOCOL</var> specifies the health check protocol -\n+          <code>tcp</code>, <code>udp</code>, or <code>icmp</code>.\n+        </p>\n+\n+        <p>\n+          <var>SOURCE_IP</var> specifies the source IP address used when\n+          sending health check probes.\n+        </p>\n+\n+        <p>\n+          <var>DST_PORT</var> specifies the destination port number for\n+          <code>tcp</code> and <code>udp</code> health checks. This parameter\n+          is ignored for <code>icmp</code> protocol.\n+        </p>\n+\n+        <p>\n+          <var>ADDRESS</var> specifies the IP address to monitor.\n+        </p>\n+\n+        <p>\n+          Additional health check options such as interval, timeout,\n+          success count, and failure count can be configured separately.\n+        </p>\n+      </dd>\n+\n+      <dt><code>lsp-hc-del</code> <var>PORT</var> [<var>HC_UUID</var>]</dt>\n+      <dd>\n+        <p>\n+          Deletes health check configuration for the logical switch port\n+          <code>PORT</code>.\n+        </p>\n+      </dd>\n+\n+    <dt><code>lsp-hc-list</code> <var>PORT</var></dt>\n+    <dd>\n+      Lists all health check configurations for the logical switch port\n+      <code>PORT</code>, including protocol, source IP, destination port,\n+      monitored addresses, and current status.\n+    </dd>\n+    </dl>\n+\n     <h2>Synchronization Commands</h2>\n \n     <dl>\ndiff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c\nindex cdf6b578a..e58001148 100644\n--- a/utilities/ovn-nbctl.c\n+++ b/utilities/ovn-nbctl.c\n@@ -66,6 +66,18 @@ string_ptr(char *ptr)\n     return (ptr) ? ptr : s;\n }\n \n+static char *OVS_WARN_UNUSED_RESULT\n+parse_l4_port_range(const char *arg, uint16_t *port_p)\n+{\n+    int64_t port;\n+    if (!ovs_scan(arg, \"%\"SCNd64, &port)\n+        || port < 0 || port > UINT16_MAX) {\n+        return xasprintf(\"%s: port must in range 0...65535\", arg);\n+    }\n+    *port_p = port;\n+    return NULL;\n+}\n+\n static void\n nbctl_add_base_prerequisites(struct ovsdb_idl *idl,\n                              enum nbctl_wait_type wait_type)\n@@ -544,6 +556,12 @@ MAC_Binding commands:\\n\\\n                                     Delete Static_MAC_Binding entry\\n\\\n   static-mac-binding-list           List all Static_MAC_Binding entries\\n\\\n \\n\\\n+Logical Switch Port Health Check:\\n\\\n+  lsp-hc-add PORT PROTOCOL SOURCE_IP DST_PORT ADDRESS...\\n\\\n+                            add health check monitoring for PORT\\n\\\n+  lsp-hc-del PORT HC_UUID   delete health check monitoring for PORT\\n\\\n+  lsp-hc-list PORT              print health check for PORT\\n\\\n+\\n\\\n %s\\\n %s\\\n \\n\\\n@@ -1464,18 +1482,23 @@ nbctl_pre_lsp_set_addresses(struct ctl_context *ctx)\n                          &nbrec_logical_switch_port_col_dynamic_addresses);\n }\n \n-static char *\n+static bool\n lsp_contains_duplicate_ip(struct lport_addresses *laddrs1,\n                           struct lport_addresses *laddrs2,\n-                          const struct nbrec_logical_switch_port *lsp_test)\n+                          const struct nbrec_logical_switch_port *lsp_test,\n+                          char **error_str)\n {\n     for (size_t i = 0; i < laddrs1->n_ipv4_addrs; i++) {\n         for (size_t j = 0; j < laddrs2->n_ipv4_addrs; j++) {\n             if (laddrs1->ipv4_addrs[i].addr == laddrs2->ipv4_addrs[j].addr) {\n-                return xasprintf(\"duplicate IPv4 address '%s' found on \"\n-                                 \"logical switch port '%s'\",\n-                                 laddrs1->ipv4_addrs[i].addr_s,\n-                                 lsp_test->name);\n+                if (error_str) {\n+                    *error_str = xasprintf(\"duplicate IPv4 address '%s' \"\n+                                           \"found on logical switch \"\n+                                           \"port '%s'\",\n+                                           laddrs1->ipv4_addrs[i].addr_s,\n+                                           lsp_test->name);\n+                }\n+                return true;\n             }\n         }\n     }\n@@ -1484,15 +1507,23 @@ lsp_contains_duplicate_ip(struct lport_addresses *laddrs1,\n         for (size_t j = 0; j < laddrs2->n_ipv6_addrs; j++) {\n             if (IN6_ARE_ADDR_EQUAL(&laddrs1->ipv6_addrs[i].addr,\n                                    &laddrs2->ipv6_addrs[j].addr)) {\n-                return xasprintf(\"duplicate IPv6 address '%s' found on \"\n-                                 \"logical switch port '%s'\",\n-                                 laddrs1->ipv6_addrs[i].addr_s,\n-                                 lsp_test->name);\n+                if (error_str) {\n+                    *error_str = xasprintf(\"duplicate IPv6 address \"\n+                                           \"'%s' found on logical \"\n+                                           \"switch port '%s'\",\n+                                           laddrs1->ipv6_addrs[i].addr_s,\n+                                           lsp_test->name);\n+                }\n+                return true;\n             }\n         }\n     }\n \n-    return NULL;\n+    if (error_str) {\n+        *error_str = NULL;\n+    }\n+\n+    return false;\n }\n \n static char *\n@@ -1500,12 +1531,13 @@ lsp_contains_duplicates(const struct nbrec_logical_switch *ls,\n                         const struct nbrec_logical_switch_port *lsp,\n                         const char *address)\n {\n+    char *error = NULL;\n+    char *sub_error = NULL;\n     struct lport_addresses laddrs;\n     if (!extract_lsp_addresses(address, &laddrs)) {\n         return NULL;\n     }\n \n-    char *sub_error = NULL;\n     for (size_t i = 0; i < ls->n_ports; i++) {\n         struct nbrec_logical_switch_port *lsp_test = ls->ports[i];\n         if (lsp_test == lsp) {\n@@ -1518,10 +1550,11 @@ lsp_contains_duplicates(const struct nbrec_logical_switch *ls,\n                 addr = lsp_test->dynamic_addresses;\n             }\n             if (extract_lsp_addresses(addr, &laddrs_test)) {\n-                sub_error = lsp_contains_duplicate_ip(&laddrs, &laddrs_test,\n-                                                      lsp_test);\n+                bool has_duplicate =\n+                    lsp_contains_duplicate_ip(&laddrs, &laddrs_test,\n+                                              lsp_test, &sub_error);\n                 destroy_lport_addresses(&laddrs_test);\n-                if (sub_error) {\n+                if (has_duplicate) {\n                     goto err_out;\n                 }\n             }\n@@ -1529,7 +1562,6 @@ lsp_contains_duplicates(const struct nbrec_logical_switch *ls,\n     }\n \n err_out: ;\n-    char *error = NULL;\n     if (sub_error) {\n         error = xasprintf(\"Error on switch %s: %s\", ls->name, sub_error);\n         free(sub_error);\n@@ -8677,6 +8709,448 @@ nbctl_lsp_add_misc_port(struct ctl_context *ctx)\n     shash_add(&nbctx->lsp_to_ls_map, lsp_name, ls);\n }\n \n+/* Logical Switch Port Health Check Functions. */\n+enum health_check_protocol {\n+    LSP_ICMP_HEALTH_CHECK,\n+    LSP_TCP_HEALTH_CHECK,\n+    LSP_UDP_HEALTH_CHECK,\n+};\n+\n+static char *\n+lsp_health_check_parse_protocol(const char *type,\n+                                enum health_check_protocol *protocol)\n+{\n+    char *error = NULL;\n+\n+    if (!strcmp(type, \"icmp\")) {\n+        *protocol = LSP_ICMP_HEALTH_CHECK;\n+    } else if (!strcmp(type, \"tcp\")) {\n+        *protocol = LSP_TCP_HEALTH_CHECK;\n+    } else if (!strcmp(type, \"udp\")) {\n+        *protocol = LSP_UDP_HEALTH_CHECK;\n+    } else {\n+        error = xasprintf(\"%s: Type must be icmp, tcp or udp.\", type);\n+    }\n+\n+    return error;\n+}\n+\n+static char *\n+lsp_health_check_parse_dst_port(struct ctl_context *ctx,\n+                                enum health_check_protocol protocol,\n+                                const char *protocol_str,\n+                                uint16_t *destination_port,\n+                                int *target_ip_index)\n+{\n+    char *error;\n+\n+    switch (protocol) {\n+    case LSP_TCP_HEALTH_CHECK:\n+    case LSP_UDP_HEALTH_CHECK:\n+        if (ctx->argc < 5) {\n+            error = xasprintf(\"Destination port required for \"\n+                              \"%s health check.\", protocol_str);\n+            return error;\n+        }\n+\n+        error = parse_l4_port_range(ctx->argv[4], destination_port);\n+        if (error) {\n+            return error;\n+        }\n+\n+        *target_ip_index = 5;\n+        break;\n+\n+    case LSP_ICMP_HEALTH_CHECK:\n+        *target_ip_index = 4;\n+        break;\n+\n+    default:\n+        OVS_NOT_REACHED();\n+    }\n+\n+    if (*target_ip_index == ctx->argc) {\n+        error = xasprintf(\"No addresses specified for health checking.\");\n+        return error;\n+    }\n+\n+    return NULL;\n+}\n+\n+static bool\n+lsp_health_check_get_duplicate_record(\n+    int64_t destination_port, const char *protocol_str,\n+    const char *source_ip_str, const char *target_ip_str,\n+    const struct nbrec_logical_switch_port *lsp)\n+{\n+    for (size_t i = 0; i < lsp->n_health_checks; i++) {\n+        const struct nbrec_logical_switch_port_health_check *lsp_hc_p =\n+            lsp->health_checks[i];\n+\n+        if (!strcmp(lsp_hc_p->src_ip, source_ip_str) &&\n+            !strcmp(lsp_hc_p->protocol, protocol_str)) {\n+\n+            if (strcmp(protocol_str, \"icmp\") &&\n+                lsp_hc_p->port != destination_port) {\n+                continue;\n+            }\n+\n+            if (strcmp(lsp_hc_p->address, target_ip_str) == 0) {\n+                return true;\n+            }\n+        }\n+    }\n+\n+    return false;\n+}\n+\n+static char *\n+lsp_health_check_parse_target_address(\n+    const char *target_ip_str, const char *protocol_str,\n+    const char *source_ip_str, const int64_t destination_port,\n+    const struct nbrec_logical_switch_port *lsp)\n+{\n+    bool ip_found_on_port = false;\n+    char *error = NULL;\n+\n+    struct lport_addresses target_address;\n+    if (!extract_ip_address(target_ip_str, &target_address)) {\n+        error = xasprintf(\"Not a valid IPv4 or IPv6 address %s.\",\n+                          target_ip_str);\n+        return error;\n+    }\n+\n+    struct lport_addresses lsp_address;\n+    for (size_t i = 0; i < lsp->n_addresses; i++) {\n+        if (!extract_lsp_addresses(lsp->addresses[i], &lsp_address)) {\n+            error = xasprintf(\"Error extracting logical switch port address.\");\n+            goto cleanup;\n+        }\n+\n+        if (lsp_contains_duplicate_ip(&target_address,\n+                                      &lsp_address, lsp, NULL)) {\n+            ip_found_on_port = true;\n+        }\n+\n+        destroy_lport_addresses(&lsp_address);\n+\n+        if (ip_found_on_port) {\n+            break;\n+        }\n+    }\n+\n+    if (!ip_found_on_port) {\n+        error = xasprintf(\"Address %s not configured on port %s.\",\n+                          target_ip_str, lsp->name);\n+        goto cleanup;\n+    }\n+\n+    if (lsp_health_check_get_duplicate_record(destination_port,\n+                                              protocol_str,\n+                                              source_ip_str,\n+                                              target_ip_str, lsp)) {\n+        error = xasprintf(\"Health check with address %s already exists \"\n+                          \"on port %s.\", target_ip_str, lsp->name);\n+        goto cleanup;\n+    }\n+\n+cleanup:\n+    destroy_lport_addresses(&target_address);\n+    return error;\n+}\n+\n+static void\n+nbctl_pre_lsp_health_check_add(struct ctl_context *ctx)\n+{\n+    ovsdb_idl_add_column(ctx->idl,\n+        &nbrec_logical_switch_port_col_name);\n+    ovsdb_idl_add_column(ctx->idl,\n+        &nbrec_logical_switch_port_col_addresses);\n+    ovsdb_idl_add_column(ctx->idl,\n+        &nbrec_logical_switch_port_col_health_checks);\n+    ovsdb_idl_add_column(ctx->idl,\n+        &nbrec_logical_switch_port_health_check_col_port);\n+    ovsdb_idl_add_column(ctx->idl,\n+        &nbrec_logical_switch_port_health_check_col_protocol);\n+    ovsdb_idl_add_column(ctx->idl,\n+        &nbrec_logical_switch_port_health_check_col_src_ip);\n+    ovsdb_idl_add_column(ctx->idl,\n+        &nbrec_logical_switch_port_health_check_col_address);\n+}\n+\n+static void\n+nbctl_lsp_health_check_add(struct ctl_context *ctx)\n+{\n+    const struct nbrec_logical_switch_port *lsp = NULL;\n+    const struct nbrec_logical_switch_port_health_check *lsp_hc = NULL;\n+\n+    const char *lsp_port_name = ctx->argv[1];\n+    const char *protocol_type = ctx->argv[2];\n+    const char *src_ip = ctx->argv[3];\n+    char *error = NULL;\n+\n+    error = lsp_by_name_or_uuid(ctx, lsp_port_name, true, &lsp);\n+    if (error) {\n+        ctx->error = error;\n+        return;\n+    }\n+\n+    if (lsp->type && lsp->type[0]) {\n+        ctl_error(ctx, \"%s: Health check monitoring supported only for\"\n+                  \" port with vif type.\", lsp->type);\n+        return;\n+    }\n+\n+    char *validated_src_ip = normalize_addr_str(src_ip);\n+    if (!validated_src_ip) {\n+        ctl_error(ctx, \"%s: Not a valid IPv4 or IPv6 address.\", src_ip);\n+        goto cleanup;\n+    }\n+\n+    enum health_check_protocol protocol;\n+    error = lsp_health_check_parse_protocol(protocol_type, &protocol);\n+    if (error) {\n+        ctx->error = error;\n+        goto cleanup;\n+    }\n+\n+    uint16_t destination_port = 0;\n+    int target_ip_index = 0;\n+    error = lsp_health_check_parse_dst_port(ctx, protocol,\n+                                            protocol_type,\n+                                            &destination_port,\n+                                            &target_ip_index);\n+    if (error) {\n+        ctx->error = error;\n+        goto cleanup;\n+    }\n+\n+    const char *target_address = ctx->argv[target_ip_index];\n+    error = lsp_health_check_parse_target_address(\n+                target_address, protocol_type,\n+                validated_src_ip, destination_port, lsp);\n+    if (error) {\n+        ctx->error = error;\n+        goto cleanup;\n+    }\n+\n+    lsp_hc = nbrec_logical_switch_port_health_check_insert(ctx->txn);\n+    nbrec_logical_switch_port_health_check_set_protocol(lsp_hc,\n+                                                        protocol_type);\n+    nbrec_logical_switch_port_health_check_set_src_ip(lsp_hc,\n+                                                      validated_src_ip);\n+    nbrec_logical_switch_port_health_check_set_port(lsp_hc,\n+                                                    destination_port);\n+\n+    nbrec_logical_switch_port_health_check_set_address(lsp_hc,\n+        target_address);\n+\n+    nbrec_logical_switch_port_update_health_checks_addvalue(lsp, lsp_hc);\n+\n+cleanup:\n+    free(validated_src_ip);\n+}\n+\n+static char * OVS_WARN_UNUSED_RESULT\n+find_logical_switch_port_health_check_by_uuid(\n+    struct ctl_context *ctx,\n+    const char *id,\n+    const struct nbrec_logical_switch_port_health_check **lsp_hc_p)\n+{\n+    const struct nbrec_logical_switch_port_health_check *lsp_hc;\n+    *lsp_hc_p = NULL;\n+\n+    struct uuid lsp_hc_uuid;\n+    bool is_uuid = uuid_from_string(&lsp_hc_uuid, id);\n+\n+    if (!is_uuid) {\n+        return xasprintf(\"%s: Invalid UUID format.\", id);\n+    }\n+\n+    lsp_hc = nbrec_logical_switch_port_health_check_get_for_uuid(\n+                    ctx->idl, &lsp_hc_uuid);\n+\n+    if (!lsp_hc) {\n+        return xasprintf(\"%s: Logical Switch Port Health Check \"\n+                         \"not found.\", id);\n+    }\n+\n+    *lsp_hc_p = lsp_hc;\n+\n+    return NULL;\n+}\n+\n+static void\n+nbctl_pre_lsp_health_check_del(struct ctl_context *ctx)\n+{\n+    ovsdb_idl_add_column(ctx->idl,\n+        &nbrec_logical_switch_port_col_name);\n+    ovsdb_idl_add_column(ctx->idl,\n+        &nbrec_logical_switch_port_col_health_checks);\n+    ovsdb_idl_add_column(ctx->idl,\n+        &nbrec_logical_switch_port_health_check_col_protocol);\n+}\n+\n+static void\n+nbctl_lsp_health_check_del(struct ctl_context *ctx)\n+{\n+    const struct nbrec_logical_switch_port_health_check *lsp_hc = NULL;\n+    const struct nbrec_logical_switch_port *lsp = NULL;\n+    const char *port_id = ctx->argv[1];\n+    const char *hc_uuid = ctx->argv[2];\n+\n+    char *error;\n+    error = lsp_by_name_or_uuid(ctx, port_id, true, &lsp);\n+    if (error) {\n+        ctx->error = error;\n+        return;\n+    }\n+\n+    if (hc_uuid) {\n+        error = find_logical_switch_port_health_check_by_uuid(ctx,\n+                                                              hc_uuid,\n+                                                              &lsp_hc);\n+        if (error) {\n+            ctx->error = error;\n+            return;\n+        }\n+\n+        nbrec_logical_switch_port_update_health_checks_delvalue(lsp, lsp_hc);\n+        nbrec_logical_switch_port_health_check_delete(lsp_hc);\n+        return;\n+    }\n+\n+    for (size_t i = 0; i < lsp->n_health_checks; i++) {\n+        nbrec_logical_switch_port_update_health_checks_delvalue(\n+            lsp, lsp->health_checks[i]);\n+        nbrec_logical_switch_port_health_check_delete(lsp->health_checks[i]);\n+    }\n+}\n+\n+static int\n+lsp_health_check_cmp(const void *lsp_hc_1_, const void *lsp_hc_2_)\n+{\n+    const struct nbrec_logical_switch_port_health_check *const *lsp_hc_1p =\n+        lsp_hc_1_;\n+    const struct nbrec_logical_switch_port_health_check *const *lsp_hc_2p =\n+        lsp_hc_2_;\n+    const struct nbrec_logical_switch_port_health_check *lsp_hc_1 =\n+        *lsp_hc_1p;\n+    const struct nbrec_logical_switch_port_health_check *lsp_hc_2 =\n+        *lsp_hc_2p;\n+\n+    int src_ip_cmp = strcmp(lsp_hc_1->src_ip, lsp_hc_2->src_ip);\n+    if (src_ip_cmp) {\n+        return src_ip_cmp;\n+    }\n+\n+    int protocol_cmp = strcmp(lsp_hc_1->protocol, lsp_hc_2->protocol);\n+    if (protocol_cmp) {\n+        return protocol_cmp;\n+    }\n+\n+    if (strcmp(lsp_hc_1->protocol, \"icmp\")) {\n+        if (lsp_hc_1->port != lsp_hc_2->port) {\n+            return lsp_hc_1->port < lsp_hc_2->port ? -1 : 1;\n+        }\n+    }\n+\n+    int ip_cmp = strcmp(lsp_hc_1->address, lsp_hc_2->address);\n+    if (ip_cmp) {\n+        return ip_cmp;\n+    }\n+\n+    return 0;\n+}\n+\n+static void\n+nbctl_pre_lsp_health_check_list(struct ctl_context *ctx)\n+{\n+    ovsdb_idl_add_column(ctx->idl,\n+        &nbrec_logical_switch_port_col_name);\n+    ovsdb_idl_add_column(ctx->idl,\n+        &nbrec_logical_switch_port_col_health_checks);\n+    ovsdb_idl_add_column(ctx->idl,\n+        &nbrec_logical_switch_port_health_check_col_port);\n+    ovsdb_idl_add_column(ctx->idl,\n+        &nbrec_logical_switch_port_health_check_col_protocol);\n+    ovsdb_idl_add_column(ctx->idl,\n+        &nbrec_logical_switch_port_health_check_col_src_ip);\n+    ovsdb_idl_add_column(ctx->idl,\n+        &nbrec_logical_switch_port_health_check_col_address);\n+}\n+\n+static void\n+nbctl_lsp_health_check_list(struct ctl_context *ctx)\n+{\n+    const struct nbrec_logical_switch_port_health_check **lsp_hcs;\n+    const struct nbrec_logical_switch_port *lsp = NULL;\n+    const char *port = ctx->argv[1];\n+\n+    char *error;\n+    error = lsp_by_name_or_uuid(ctx, port, true, &lsp);\n+    if (error) {\n+        ctx->error = error;\n+        return;\n+    }\n+\n+    if (!lsp->n_health_checks) {\n+        return;\n+    }\n+\n+    lsp_hcs = xmalloc(sizeof *lsp_hcs * lsp->n_health_checks);\n+    for (size_t i = 0; i < lsp->n_health_checks; i++) {\n+        lsp_hcs[i] = lsp->health_checks[i];\n+    }\n+\n+    qsort(lsp_hcs, lsp->n_health_checks,\n+          sizeof *lsp_hcs, lsp_health_check_cmp);\n+\n+    ds_put_format(&ctx->output, \"Logical Switch Port %s:\\n\", port);\n+    for (size_t i = 0; i < lsp->n_health_checks; i++) {\n+        const struct nbrec_logical_switch_port_health_check *hc\n+\n+                                                        = lsp_hcs[i];\n+        ds_put_format(&ctx->output, \"  Protocol      :  %s\\n\",\n+                      hc->protocol);\n+        ds_put_format(&ctx->output, \"  Source IP     :  %s\\n\",\n+                      hc->src_ip);\n+\n+        if (strcmp(hc->protocol, \"icmp\")) {\n+            ds_put_format(&ctx->output, \"  Port          :  %\"PRId64\"\\n\",\n+                          hc->port);\n+        }\n+\n+        ds_put_format(&ctx->output, \"  Addresses     :  \");\n+        ds_put_format(&ctx->output, \"%s\", hc->address);\n+        ds_put_format(&ctx->output, \"\\n\");\n+\n+        int interval = smap_get_int(&hc->options, \"interval\", 0);\n+        int timeout = smap_get_int(&hc->options, \"timeout\", 0);\n+        int success_count = smap_get_int(&hc->options, \"success_count\", 0);\n+        int failure_count = smap_get_int(&hc->options, \"failure_count\", 0);\n+        if (interval) {\n+            ds_put_format(&ctx->output, \"  Interval      :  %d\\n\",\n+                          interval);\n+        }\n+        if (timeout) {\n+            ds_put_format(&ctx->output, \"  Timeout       :  %d\\n\",\n+                          timeout);\n+        }\n+        if (success_count) {\n+            ds_put_format(&ctx->output, \"  Success count :  %d\\n\",\n+                          success_count);\n+        }\n+        if (failure_count) {\n+            ds_put_format(&ctx->output, \"  Failure count :  %d\\n\",\n+                          failure_count);\n+        }\n+        if (i < lsp->n_health_checks - 1) {\n+            ds_put_format(&ctx->output, \"\\n\");\n+        }\n+    }\n+}\n+\n static const struct ctl_table_class tables[NBREC_N_TABLES] = {\n     [NBREC_TABLE_DHCP_OPTIONS].row_ids\n     = {{&nbrec_logical_switch_port_col_name, NULL,\n@@ -9064,6 +9538,16 @@ static const struct ctl_command_syntax nbctl_commands[] = {\n       nbctl_pre_static_mac_binding, nbctl_static_mac_binding_list, NULL,\n       \"\", RO },\n \n+    /* Health Check commands */\n+    {\"lsp-hc-add\", 4, 5, \"PORT TYPE SRC_IP [DST_PORT] ADDRESS\",\n+     nbctl_pre_lsp_health_check_add, nbctl_lsp_health_check_add,\n+     NULL, \"\", RW },\n+    {\"lsp-hc-del\", 1, INT_MAX, \"PORT [HC_UUID]\",\n+     nbctl_pre_lsp_health_check_del, nbctl_lsp_health_check_del,\n+     NULL, \"\", RW },\n+    {\"lsp-hc-list\", 1, 1, \"PORT\", nbctl_pre_lsp_health_check_list,\n+     nbctl_lsp_health_check_list, NULL, \"\", RW },\n+\n     {NULL, 0, 0, NULL, NULL, NULL, NULL, \"\", RO},\n };\n \n",
    "prefixes": [
        "ovs-dev",
        "1/8",
        "v2"
    ]
}