get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 2199657,
    "url": "http://patchwork.ozlabs.org/api/1.2/patches/2199657/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/ovn/patch/20260223174615.65626-1-tiago.reis@luizalabs.com/",
    "project": {
        "id": 68,
        "url": "http://patchwork.ozlabs.org/api/1.2/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": "<20260223174615.65626-1-tiago.reis@luizalabs.com>",
    "list_archive_url": null,
    "date": "2026-02-23T17:46:15",
    "name": "[ovs-dev,v3] ovn-ic: Use dual IC-SB connections to prevent constraint violations.",
    "commit_ref": null,
    "pull_url": null,
    "state": "changes-requested",
    "archived": false,
    "hash": "cd9cc5c240717daf6879d3c3daa0c0e07bf6047e",
    "submitter": {
        "id": 92676,
        "url": "http://patchwork.ozlabs.org/api/1.2/people/92676/?format=api",
        "name": "Tiago Matos",
        "email": "tiago.reis@luizalabs.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/ovn/patch/20260223174615.65626-1-tiago.reis@luizalabs.com/mbox/",
    "series": [
        {
            "id": 493017,
            "url": "http://patchwork.ozlabs.org/api/1.2/series/493017/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/ovn/list/?series=493017",
            "date": "2026-02-23T17:46:15",
            "name": "[ovs-dev,v3] ovn-ic: Use dual IC-SB connections to prevent constraint violations.",
            "version": 3,
            "mbox": "http://patchwork.ozlabs.org/series/493017/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2199657/comments/",
    "check": "success",
    "checks": "http://patchwork.ozlabs.org/api/patches/2199657/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=luizalabs.com header.i=@luizalabs.com\n header.a=rsa-sha256 header.s=google header.b=b+i9hjOZ;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org\n (client-ip=140.211.166.138; helo=smtp1.osuosl.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org)",
            "smtp1.osuosl.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key)\n header.d=luizalabs.com header.i=@luizalabs.com header.a=rsa-sha256\n header.s=google header.b=b+i9hjOZ",
            "smtp1.osuosl.org; dmarc=pass (p=quarantine dis=none)\n header.from=luizalabs.com"
        ],
        "Received": [
            "from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138])\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 4fKSw65hxLz1xv2\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 24 Feb 2026 04:46:45 +1100 (AEDT)",
            "from localhost (localhost [127.0.0.1])\n\tby smtp1.osuosl.org (Postfix) with ESMTP id 8FF77821D1;\n\tMon, 23 Feb 2026 17:46:42 +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 fjL5GhIvLriE; Mon, 23 Feb 2026 17:46:41 +0000 (UTC)",
            "from lists.linuxfoundation.org (lf-lists.osuosl.org\n [IPv6:2605:bc80:3010:104::8cd3:938])\n\tby smtp1.osuosl.org (Postfix) with ESMTPS id 0714D84037;\n\tMon, 23 Feb 2026 17:46:41 +0000 (UTC)",
            "from lf-lists.osuosl.org (localhost [127.0.0.1])\n\tby lists.linuxfoundation.org (Postfix) with ESMTP id DFDEAC0070;\n\tMon, 23 Feb 2026 17:46:40 +0000 (UTC)",
            "from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138])\n by lists.linuxfoundation.org (Postfix) with ESMTP id 0C494C003D\n for <dev@openvswitch.org>; Mon, 23 Feb 2026 17:46:39 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n by smtp1.osuosl.org (Postfix) with ESMTP id EB5D78403B\n for <dev@openvswitch.org>; Mon, 23 Feb 2026 17:46:38 +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 vYR5fV8RzTq2 for <dev@openvswitch.org>;\n Mon, 23 Feb 2026 17:46:37 +0000 (UTC)",
            "from mail-vk1-xa2a.google.com (mail-vk1-xa2a.google.com\n [IPv6:2607:f8b0:4864:20::a2a])\n by smtp1.osuosl.org (Postfix) with ESMTPS id 5C1A18403A\n for <dev@openvswitch.org>; Mon, 23 Feb 2026 17:46:37 +0000 (UTC)",
            "by mail-vk1-xa2a.google.com with SMTP id\n 71dfb90a1353d-5688b9e4e80so4060533e0c.1\n for <dev@openvswitch.org>; Mon, 23 Feb 2026 09:46:37 -0800 (PST)",
            "from state ([2804:10dc:d328:9e00:3256:fff:fe0d:5e27])\n by smtp.gmail.com with ESMTPSA id\n 71dfb90a1353d-568e593a666sm9480880e0c.17.2026.02.23.09.46.33\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Mon, 23 Feb 2026 09:46:34 -0800 (PST)"
        ],
        "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 smtp1.osuosl.org 0714D84037",
            "OpenDKIM Filter v2.11.0 smtp1.osuosl.org 5C1A18403A"
        ],
        "Received-SPF": "Pass (mailfrom) identity=mailfrom;\n client-ip=2607:f8b0:4864:20::a2a; helo=mail-vk1-xa2a.google.com;\n envelope-from=tiago.reis@luizalabs.com; receiver=<UNKNOWN>",
        "DMARC-Filter": "OpenDMARC Filter v1.4.2 smtp1.osuosl.org 5C1A18403A",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=luizalabs.com; s=google; t=1771868796; x=1772473596; darn=openvswitch.org;\n h=content-transfer-encoding:mime-version:message-id:date:subject:cc\n :to:from:from:to:cc:subject:date:message-id:reply-to;\n bh=Cto9RzYQ8AfplRb7wG7aQtBTY819N5PWsBIoziUpb7g=;\n b=b+i9hjOZObTi56Bm5vQwA0TKXPjxYNsoYPNZyBusp8GCtfaQTiC9noMZ0YMY1RID/K\n Heht9UKzHLXR9hywhKgc5BfJoFVeXk8/RlixHQu8n7zWZ68SeAA0zobvE+GMCJo68n2K\n ojQNsRMKQWfuvC0uwcZevFTVlTB8A5owZZVEU=",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20230601; t=1771868796; x=1772473596;\n h=content-transfer-encoding:mime-version:message-id:date:subject:cc\n :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date\n :message-id:reply-to;\n bh=Cto9RzYQ8AfplRb7wG7aQtBTY819N5PWsBIoziUpb7g=;\n b=suBV6JUyRwnbi66WVhHyg6fHBcZjJLzPZTur4NTehWKZ4Rq1Ipvj0luF2VM0BduF5B\n WwJmBqmQzd+4hbV6imtrvqxKGbPv552KBXXZIPh2lKC/l//CigFhqoZA6Ag4YnhWB/J0\n Qw2nE5KrlYdAswPT+liiGGFQfD08c+kvF5i6HdslUcHuj9ydkJe7eG+4c7AA3Tii4y9n\n KtaVod0ZNmyTizp1EyYQUyp4H1WN25BZncxvzqbvm41MvfGasphmttHGuYFRNWYA2MfP\n GWh6zFslLew5Zxrne75HZGywE18oefTLVgn3bHlYQaep+EvRWM03wRPCI4vKih0x0pBA\n 91cg==",
        "X-Gm-Message-State": "AOJu0Yy5pfNxAefLeij4fSkmOQQdaAA5kFCfXM86m3DYV3JVwTQrpEvZ\n IK17l6Oqp1Uzo5HvOFH/N47r8/nTlVzKixuZfAqyddxDU6+sX1ac7OiqJ/zCvANp2xC1tIlfkBO\n 4O6KnYwF66S2fYOfDC0K+W8h5keXNqTiEtO+Jvq3tQKCcyzllbR6WvL3xtq1uBz/I1g==",
        "X-Gm-Gg": "AZuq6aId84neYJiKKSeY32wENiJ+CsDEBBcseKT1OVDMxMudcSRr2gKQH8uPPSJQypJ\n cgzySMsotFsLWHn0Qz3YdjOoD+n+JdjL/GmId6JQ50lQb1zntGogSuw1yR6KsxNm8aDM5XrYcN5\n 2RbI2z1StlSp2Z78fRtXYxGZNu2/e/9QbiVZfZZM8iCIrGEg7mNjZuTFi+r7vZV+saTjV9Zsd2O\n iAWrfF6rzS7ds8rzz5I+VE1aHNuDnndOgjuA7PVHh+OxL6YEYIKU8Q6E6VatBQhOUvVPX3tdD+P\n lEhLYQO0j4VpVEWvscOu8zhY6IQVcdupq5PJRe3FGXPh9eWi7i9fGg/aDH+vOJliSCIfr7Zd2St\n OKxCUsOle8mA+XczFtm0/2abiCnwIozaQvTnxgGWI1zsfmjIbcbKwLNmbraQJvjCwXT7I5og132\n d8zDDjxha/fteUJUsFVnT2u/gJ",
        "X-Received": "by 2002:a05:6122:a20:b0:566:222b:c164 with SMTP id\n 71dfb90a1353d-568e45f46ccmr4228560e0c.4.1771868795424;\n Mon, 23 Feb 2026 09:46:35 -0800 (PST)",
        "To": "dev@openvswitch.org",
        "Date": "Mon, 23 Feb 2026 14:46:15 -0300",
        "Message-ID": "<20260223174615.65626-1-tiago.reis@luizalabs.com>",
        "X-Mailer": "git-send-email 2.53.0",
        "MIME-Version": "1.0",
        "Subject": "[ovs-dev] [PATCH ovn v3] ovn-ic: Use dual IC-SB connections to\n prevent constraint violations.",
        "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>",
        "From": "Tiago Matos via dev <ovs-dev@openvswitch.org>",
        "Reply-To": "Tiago Matos <tiago.reis@luizalabs.com>",
        "Content-Type": "text/plain; charset=\"iso-8859-1\"",
        "Content-Transfer-Encoding": "quoted-printable",
        "Errors-To": "ovs-dev-bounces@openvswitch.org",
        "Sender": "\"dev\" <ovs-dev-bounces@openvswitch.org>"
    },
    "content": "When multiple Availability Zones (AZs) are connected via OVN-IC,\ncertain events trigger all AZs to attempt writing the same data to the\nIC-SB simultaneously. This race condition leads to constraint\nviolations, causing transaction failures and forcing expensive full\nrecomputes.\n\nTo mitigate this, this patch introduces a write-segregation mechanism\nemploying two distinct connections to IC-SB:\n1. Locked Connection: Acquires a lock to handle data that only a\n   single AZ should write (e.g., creating a new datapath_binding for a\n   transit switch/router).\n\n2. Lockless Connections: Used for data that multiple AZs can safely\n   insert concurrently (e.g., creating a new port_binding).\n\nSigned-off-by: Tiago Matos <tiago.reis@luizalabs.com>\n---\n ic/inc-proc-ic.c |   6 +-\n ic/inc-proc-ic.h |   1 +\n ic/ovn-ic.c      | 186 +++++++++++++++++++++++++++++++++++------------\n ic/ovn-ic.h      |   2 +\n 4 files changed, 145 insertions(+), 50 deletions(-)",
    "diff": "diff --git a/ic/inc-proc-ic.c b/ic/inc-proc-ic.c\nindex 995f23433..2c0420292 100644\n--- a/ic/inc-proc-ic.c\n+++ b/ic/inc-proc-ic.c\n@@ -27,6 +27,7 @@\n #include \"openvswitch/vlog.h\"\n #include \"inc-proc-ic.h\"\n #include \"en-ic.h\"\n+#include \"ovn-util.h\"\n #include \"unixctl.h\"\n #include \"util.h\"\n \n@@ -214,7 +215,7 @@ inc_proc_ic_run(struct ic_context *ctx,\n                 struct ic_engine_context *ic_eng_ctx)\n {\n     ovs_assert(ctx->ovnnb_txn && ctx->ovnsb_txn &&\n-               ctx->ovninb_txn && ctx->ovnisb_txn);\n+               ctx->ovninb_txn && ctx->ovnisb_unlocked_txn);\n \n     int64_t start = time_msec();\n     engine_init_run();\n@@ -262,7 +263,8 @@ inc_proc_ic_can_run(struct ic_engine_context *ctx)\n         ctx->nb_idl_duration_ms >= IDL_LOOP_MAX_DURATION_MS ||\n         ctx->sb_idl_duration_ms >= IDL_LOOP_MAX_DURATION_MS ||\n         ctx->inb_idl_duration_ms >= IDL_LOOP_MAX_DURATION_MS ||\n-        ctx->isb_idl_duration_ms >= IDL_LOOP_MAX_DURATION_MS) {\n+        ctx->isb_idl_duration_ms >= IDL_LOOP_MAX_DURATION_MS ||\n+        ctx->isb_unlock_idl_duration_ms >= IDL_LOOP_MAX_DURATION_MS) {\n         return true;\n     }\n \ndiff --git a/ic/inc-proc-ic.h b/ic/inc-proc-ic.h\nindex 9af147fb3..36464564d 100644\n--- a/ic/inc-proc-ic.h\n+++ b/ic/inc-proc-ic.h\n@@ -13,6 +13,7 @@ struct ic_engine_context {\n     uint64_t sb_idl_duration_ms;\n     uint64_t inb_idl_duration_ms;\n     uint64_t isb_idl_duration_ms;\n+    uint64_t isb_unlock_idl_duration_ms;\n     uint32_t backoff_ms;\n };\n \ndiff --git a/ic/ovn-ic.c b/ic/ovn-ic.c\nindex 95d73cb4b..0adf637c8 100644\n--- a/ic/ovn-ic.c\n+++ b/ic/ovn-ic.c\n@@ -115,8 +115,9 @@ az_run(struct ic_context *ctx)\n      * \"ovn-ic-sbctl destroy avail <az>\". */\n     static char *az_name;\n     const struct icsbrec_availability_zone *az;\n-    if (ctx->ovnisb_txn && az_name && strcmp(az_name, nb_global->name)) {\n-        ICSBREC_AVAILABILITY_ZONE_FOR_EACH (az, ctx->ovnisb_idl) {\n+    if (ctx->ovnisb_unlocked_txn && az_name\n+        && strcmp(az_name, nb_global->name)) {\n+        ICSBREC_AVAILABILITY_ZONE_FOR_EACH (az, ctx->ovnisb_unlocked_idl) {\n             /* AZ name update locally need to update az in ISB. */\n             if (nb_global->name[0] && !strcmp(az->name, az_name)) {\n                 icsbrec_availability_zone_set_name(az, nb_global->name);\n@@ -138,11 +139,11 @@ az_run(struct ic_context *ctx)\n         az_name = xstrdup(nb_global->name);\n     }\n \n-    if (ctx->ovnisb_txn) {\n-        ovsdb_idl_txn_add_comment(ctx->ovnisb_txn, \"AZ %s\", az_name);\n+    if (ctx->ovnisb_unlocked_txn) {\n+        ovsdb_idl_txn_add_comment(ctx->ovnisb_unlocked_txn, \"AZ %s\", az_name);\n     }\n \n-    ICSBREC_AVAILABILITY_ZONE_FOR_EACH (az, ctx->ovnisb_idl) {\n+    ICSBREC_AVAILABILITY_ZONE_FOR_EACH (az, ctx->ovnisb_unlocked_idl) {\n         if (!strcmp(az->name, az_name)) {\n             ctx->runned_az = az;\n             return az;\n@@ -150,9 +151,9 @@ az_run(struct ic_context *ctx)\n     }\n \n     /* Create AZ in ISB */\n-    if (ctx->ovnisb_txn) {\n+    if (ctx->ovnisb_unlocked_txn) {\n         VLOG_INFO(\"Register AZ %s to interconnection DB.\", az_name);\n-        az = icsbrec_availability_zone_insert(ctx->ovnisb_txn);\n+        az = icsbrec_availability_zone_insert(ctx->ovnisb_unlocked_txn);\n         icsbrec_availability_zone_set_name(az, az_name);\n         ctx->runned_az = az;\n         return az;\n@@ -195,7 +196,7 @@ enumerate_datapaths(struct ic_context *ctx, struct hmap *dp_tnlids,\n                     struct shash *isb_ts_dps, struct shash *isb_tr_dps)\n {\n     const struct icsbrec_datapath_binding *isb_dp;\n-    ICSBREC_DATAPATH_BINDING_FOR_EACH (isb_dp, ctx->ovnisb_idl) {\n+    ICSBREC_DATAPATH_BINDING_FOR_EACH (isb_dp, ctx->ovnisb_unlocked_idl) {\n         ovn_add_tnlid(dp_tnlids, isb_dp->tunnel_key);\n \n         enum ic_datapath_type dp_type = ic_dp_get_type(isb_dp);\n@@ -209,6 +210,20 @@ enumerate_datapaths(struct ic_context *ctx, struct hmap *dp_tnlids,\n     }\n }\n \n+/*\n+ * Check if the AZ is the leader by checking the lock.\n+ */\n+static bool\n+is_az_leader(struct ovsdb_idl_txn *txn)\n+{\n+    struct ovsdb_idl *idl = ovsdb_idl_txn_get_idl(txn);\n+    if (idl && ovsdb_idl_has_lock(idl)) {\n+        return true;\n+    }\n+\n+    return false;\n+}\n+\n static void\n ts_run(struct ic_context *ctx, struct hmap *dp_tnlids,\n        struct shash *isb_ts_dps)\n@@ -221,7 +236,7 @@ ts_run(struct ic_context *ctx, struct hmap *dp_tnlids,\n \n     if (ic_nb && smap_get_bool(&ic_nb->options, \"vxlan_mode\", false)) {\n         const struct icsbrec_encap *encap;\n-        ICSBREC_ENCAP_FOR_EACH (encap, ctx->ovnisb_idl) {\n+        ICSBREC_ENCAP_FOR_EACH (encap, ctx->ovnisb_unlocked_idl) {\n             if (!strcmp(encap->type, \"vxlan\")) {\n                 vxlan_mode = true;\n                 break;\n@@ -294,7 +309,8 @@ ts_run(struct ic_context *ctx, struct hmap *dp_tnlids,\n     /* Sync TS between INB and ISB.  This is performed after syncing with AZ\n      * SB, to avoid uncommitted ISB datapath tunnel key to be synced back to\n      * AZ. */\n-    if (ctx->ovnisb_txn) {\n+    if (ctx->ovnisb_txn &&\n+        is_az_leader(ctx->ovnisb_txn)) {\n         /* Create ISB Datapath_Binding */\n         ICNBREC_TRANSIT_SWITCH_FOR_EACH (ts, ctx->ovninb_idl) {\n             const struct icsbrec_datapath_binding *isb_dp =\n@@ -383,7 +399,8 @@ tr_run(struct ic_context *ctx, struct hmap *dp_tnlids,\n     /* Sync TR between INB and ISB.  This is performed after syncing with AZ\n      * SB, to avoid uncommitted ISB datapath tunnel key to be synced back to\n      * AZ. */\n-    if (ctx->ovnisb_txn) {\n+    if (ctx->ovnisb_txn &&\n+        is_az_leader(ctx->ovnisb_txn)) {\n         /* Create ISB Datapath_Binding */\n         const struct icnbrec_transit_router *tr;\n         ICNBREC_TRANSIT_ROUTER_FOR_EACH (tr, ctx->ovninb_idl) {\n@@ -488,7 +505,7 @@ sync_sb_gw_to_isb(struct ic_context *ctx,\n     struct icsbrec_encap **isb_encaps =\n         xmalloc(chassis->n_encaps * sizeof *isb_encaps);\n     for (int i = 0; i < chassis->n_encaps; i++) {\n-        isb_encap = icsbrec_encap_insert(ctx->ovnisb_txn);\n+        isb_encap = icsbrec_encap_insert(ctx->ovnisb_unlocked_txn);\n         icsbrec_encap_set_gateway_name(isb_encap,\n                                       chassis->name);\n         icsbrec_encap_set_ip(isb_encap, chassis->encaps[i]->ip);\n@@ -506,14 +523,14 @@ sync_sb_gw_to_isb(struct ic_context *ctx,\n static void\n gateway_run(struct ic_context *ctx)\n {\n-    if (!ctx->ovnisb_txn || !ctx->ovnsb_txn) {\n+    if (!ctx->ovnisb_unlocked_txn || !ctx->ovnsb_txn) {\n         return;\n     }\n \n     struct shash local_gws = SHASH_INITIALIZER(&local_gws);\n     struct shash remote_gws = SHASH_INITIALIZER(&remote_gws);\n     const struct icsbrec_gateway *gw;\n-    ICSBREC_GATEWAY_FOR_EACH (gw, ctx->ovnisb_idl) {\n+    ICSBREC_GATEWAY_FOR_EACH (gw, ctx->ovnisb_unlocked_idl) {\n         if (gw->availability_zone == ctx->runned_az) {\n             shash_add(&local_gws, gw->name, gw);\n         } else {\n@@ -526,7 +543,7 @@ gateway_run(struct ic_context *ctx)\n         if (smap_get_bool(&chassis->other_config, \"is-interconn\", false)) {\n             gw = shash_find_and_delete(&local_gws, chassis->name);\n             if (!gw) {\n-                gw = icsbrec_gateway_insert(ctx->ovnisb_txn);\n+                gw = icsbrec_gateway_insert(ctx->ovnisb_unlocked_txn);\n                 icsbrec_gateway_set_availability_zone(gw, ctx->runned_az);\n                 icsbrec_gateway_set_name(gw, chassis->name);\n                 sync_sb_gw_to_isb(ctx, chassis, gw);\n@@ -980,7 +997,7 @@ create_isb_pb(struct ic_context *ctx, const char *logical_port,\n     }\n \n     const struct icsbrec_port_binding *isb_pb =\n-        icsbrec_port_binding_insert(ctx->ovnisb_txn);\n+        icsbrec_port_binding_insert(ctx->ovnisb_unlocked_txn);\n     icsbrec_port_binding_set_availability_zone(isb_pb, az);\n     icsbrec_port_binding_set_transit_switch(isb_pb, ts_name);\n     icsbrec_port_binding_set_logical_port(isb_pb, logical_port);\n@@ -1068,7 +1085,7 @@ find_lsp_in_sb(struct ic_context *ctx,\n static void\n port_binding_run(struct ic_context *ctx)\n {\n-    if (!ctx->ovnisb_txn || !ctx->ovnnb_txn || !ctx->ovnsb_txn) {\n+    if (!ctx->ovnisb_unlocked_txn || !ctx->ovnnb_txn || !ctx->ovnsb_txn) {\n         return;\n     }\n \n@@ -2252,7 +2269,7 @@ advertise_routes(struct ic_context *ctx,\n                  const char *ts_name,\n                  struct hmap *routes_ad)\n {\n-    ovs_assert(ctx->ovnisb_txn);\n+    ovs_assert(ctx->ovnisb_unlocked_txn);\n     const struct icsbrec_route *isb_route;\n     const struct icsbrec_route *isb_route_key =\n         icsbrec_route_index_init_row(ctx->icsbrec_route_by_ts_az);\n@@ -2294,7 +2311,7 @@ advertise_routes(struct ic_context *ctx,\n     /* Create the missing routes in IC-SB */\n     struct ic_route_info *route_adv;\n     HMAP_FOR_EACH_SAFE (route_adv, node, routes_ad) {\n-        isb_route = icsbrec_route_insert(ctx->ovnisb_txn);\n+        isb_route = icsbrec_route_insert(ctx->ovnisb_unlocked_txn);\n         icsbrec_route_set_transit_switch(isb_route, ts_name);\n         icsbrec_route_set_availability_zone(isb_route, az);\n \n@@ -2526,7 +2543,7 @@ delete_orphan_ic_routes(struct ic_context *ctx,\n static void\n route_run(struct ic_context *ctx)\n {\n-    if (!ctx->ovnisb_txn || !ctx->ovnnb_txn || !ctx->ovnsb_txn) {\n+    if (!ctx->ovnisb_unlocked_txn || !ctx->ovnnb_txn || !ctx->ovnsb_txn) {\n         return;\n     }\n \n@@ -2958,7 +2975,7 @@ destroy_service_monitor_data(struct sync_service_monitor_data *sync_data)\n static void\n sync_service_monitor(struct ic_context *ctx)\n {\n-    if (!ctx->ovnisb_txn || !ctx->ovnsb_txn) {\n+    if (!ctx->ovnisb_unlocked_txn || !ctx->ovnsb_txn) {\n         return;\n     }\n \n@@ -2980,7 +2997,7 @@ sync_service_monitor(struct ic_context *ctx)\n         if (ic_rec) {\n             sbrec_service_monitor_set_status(db_rec, ic_rec->status);\n         } else {\n-            ic_rec = icsbrec_service_monitor_insert(ctx->ovnisb_txn);\n+            ic_rec = icsbrec_service_monitor_insert(ctx->ovnisb_unlocked_txn);\n             icsbrec_service_monitor_set_type(ic_rec, db_rec->type);\n             icsbrec_service_monitor_set_ip(ic_rec, db_rec->ip);\n             icsbrec_service_monitor_set_port(ic_rec, db_rec->port);\n@@ -3085,7 +3102,7 @@ static void\n update_sequence_numbers(struct ic_context *ctx,\n                         struct ovsdb_idl_loop *ic_sb_loop)\n {\n-    if (!ctx->ovnisb_txn || !ctx->ovninb_txn) {\n+    if (!ctx->ovnisb_unlocked_txn || !ctx->ovninb_txn) {\n         return;\n     }\n \n@@ -3095,9 +3112,9 @@ update_sequence_numbers(struct ic_context *ctx,\n         ic_nb = icnbrec_ic_nb_global_insert(ctx->ovninb_txn);\n     }\n     const struct icsbrec_ic_sb_global *ic_sb = icsbrec_ic_sb_global_first(\n-                                               ctx->ovnisb_idl);\n+                                               ctx->ovnisb_unlocked_idl);\n     if (!ic_sb) {\n-        ic_sb = icsbrec_ic_sb_global_insert(ctx->ovnisb_txn);\n+        ic_sb = icsbrec_ic_sb_global_insert(ctx->ovnisb_unlocked_txn);\n     }\n \n     if ((ic_nb->nb_ic_cfg != ic_sb->nb_ic_cfg) &&\n@@ -3107,7 +3124,8 @@ update_sequence_numbers(struct ic_context *ctx,\n             icsbrec_availability_zone_set_nb_ic_cfg(ctx->runned_az, 0);\n         }\n         ic_sb_loop->next_cfg = ic_nb->nb_ic_cfg;\n-        ovsdb_idl_txn_increment(ctx->ovnisb_txn, &ctx->runned_az->header_,\n+        ovsdb_idl_txn_increment(ctx->ovnisb_unlocked_txn,\n+                                &ctx->runned_az->header_,\n             &icsbrec_availability_zone_col_nb_ic_cfg, true);\n         return;\n     }\n@@ -3122,7 +3140,7 @@ update_sequence_numbers(struct ic_context *ctx,\n     }\n \n     const struct icsbrec_availability_zone *other_az;\n-    ICSBREC_AVAILABILITY_ZONE_FOR_EACH (other_az, ctx->ovnisb_idl) {\n+    ICSBREC_AVAILABILITY_ZONE_FOR_EACH (other_az, ctx->ovnisb_unlocked_idl) {\n         if (other_az->nb_ic_cfg != ctx->runned_az->nb_ic_cfg) {\n             return;\n         }\n@@ -3331,6 +3349,7 @@ static void\n update_idl_probe_interval(struct ovsdb_idl *ovn_sb_idl,\n                           struct ovsdb_idl *ovn_nb_idl,\n                           struct ovsdb_idl *ovn_icsb_idl,\n+                          struct ovsdb_idl *ovn_icsb_unlocked_idl,\n                           struct ovsdb_idl *ovn_icnb_idl)\n {\n     const struct nbrec_nb_global *nb = nbrec_nb_global_first(ovn_nb_idl);\n@@ -3349,6 +3368,7 @@ update_idl_probe_interval(struct ovsdb_idl *ovn_sb_idl,\n                                    ic_interval);\n     }\n     set_idl_probe_interval(ovn_icsb_idl, ovn_ic_sb_db, ic_interval);\n+    set_idl_probe_interval(ovn_icsb_unlocked_idl, ovn_ic_sb_db, ic_interval);\n     set_idl_probe_interval(ovn_icnb_idl, ovn_ic_nb_db, ic_interval);\n }\n \n@@ -3389,7 +3409,27 @@ main(int argc, char *argv[])\n         ovsdb_idl_create(ovn_ic_nb_db, &icnbrec_idl_class, true, true));\n     ovsdb_idl_track_add_all(ovninb_idl_loop.idl);\n \n-    /* ovn-ic-sb db. */\n+    /*\n+     * Each ovn-ic instance maintains two connections to the IC-SB database:\n+     * 1. Locked Connection: Competes for a global lock on IC-SB. Used for\n+     * writes that must be performed by only one active instance\n+     * (e.g., inserting a datapath_binding for a transit switch/router).\n+     *\n+     * 2. Unlocked Connection: Does not hold a lock. Used for writes that\n+     * can be safely performed by multiple instances simultaneously\n+     * (e.g., inserting a port_binding).\n+     *\n+     * This segregation prevents constraint violations and a full recompute\n+     * when writing to IC-SB.\n+     */\n+    /* ovn-ic-sb db without lock. */\n+    struct ovsdb_idl_loop ovnisb_unlocked_idl_loop =\n+        OVSDB_IDL_LOOP_INITIALIZER(ovsdb_idl_create(ovn_ic_sb_db,\n+                                                    &icsbrec_idl_class,\n+                                                    true, true));\n+    ovsdb_idl_track_add_all(ovnisb_unlocked_idl_loop.idl);\n+\n+    /* ovn-ic-sb db with lock. */\n     struct ovsdb_idl_loop ovnisb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(\n         ovsdb_idl_create(ovn_ic_sb_db, &icsbrec_idl_class, true, true));\n     ovsdb_idl_track_add_all(ovnisb_idl_loop.idl);\n@@ -3614,41 +3654,41 @@ main(int argc, char *argv[])\n                                   &icnbrec_transit_switch_col_name);\n \n     struct ovsdb_idl_index *icsbrec_port_binding_by_az\n-        = ovsdb_idl_index_create1(ovnisb_idl_loop.idl,\n+        = ovsdb_idl_index_create1(ovnisb_unlocked_idl_loop.idl,\n                                   &icsbrec_port_binding_col_availability_zone);\n \n     struct ovsdb_idl_index *icsbrec_port_binding_by_ts\n-        = ovsdb_idl_index_create1(ovnisb_idl_loop.idl,\n+        = ovsdb_idl_index_create1(ovnisb_unlocked_idl_loop.idl,\n                                   &icsbrec_port_binding_col_transit_switch);\n \n     struct ovsdb_idl_index *icsbrec_port_binding_by_ts_az\n-        = ovsdb_idl_index_create2(ovnisb_idl_loop.idl,\n+        = ovsdb_idl_index_create2(ovnisb_unlocked_idl_loop.idl,\n                                   &icsbrec_port_binding_col_transit_switch,\n                                   &icsbrec_port_binding_col_availability_zone);\n \n     struct ovsdb_idl_index *icsbrec_route_by_az\n-        = ovsdb_idl_index_create1(ovnisb_idl_loop.idl,\n+        = ovsdb_idl_index_create1(ovnisb_unlocked_idl_loop.idl,\n                                   &icsbrec_route_col_availability_zone);\n \n     struct ovsdb_idl_index *icsbrec_route_by_ts\n-        = ovsdb_idl_index_create1(ovnisb_idl_loop.idl,\n+        = ovsdb_idl_index_create1(ovnisb_unlocked_idl_loop.idl,\n                                   &icsbrec_route_col_transit_switch);\n \n     struct ovsdb_idl_index *icsbrec_route_by_ts_az\n-        = ovsdb_idl_index_create2(ovnisb_idl_loop.idl,\n+        = ovsdb_idl_index_create2(ovnisb_unlocked_idl_loop.idl,\n                                   &icsbrec_route_col_transit_switch,\n                                   &icsbrec_route_col_availability_zone);\n \n     struct ovsdb_idl_index *icsbrec_service_monitor_by_source_az\n-        = ovsdb_idl_index_create1(ovnisb_idl_loop.idl,\n+        = ovsdb_idl_index_create1(ovnisb_unlocked_idl_loop.idl,\n             &icsbrec_service_monitor_col_source_availability_zone);\n \n     struct ovsdb_idl_index *icsbrec_service_monitor_by_target_az\n-        = ovsdb_idl_index_create1(ovnisb_idl_loop.idl,\n+        = ovsdb_idl_index_create1(ovnisb_unlocked_idl_loop.idl,\n             &icsbrec_service_monitor_col_target_availability_zone);\n \n     struct ovsdb_idl_index *icsbrec_service_monitor_by_target_az_logical_port\n-        = ovsdb_idl_index_create2(ovnisb_idl_loop.idl,\n+        = ovsdb_idl_index_create2(ovnisb_unlocked_idl_loop.idl,\n             &icsbrec_service_monitor_col_target_availability_zone,\n             &icsbrec_service_monitor_col_logical_port);\n \n@@ -3661,14 +3701,26 @@ main(int argc, char *argv[])\n     unixctl_command_register(\"ic-sb-connection-status\", \"\", 0, 0,\n                              ovn_conn_show, ovnisb_idl_loop.idl);\n \n+    if (!ovsdb_idl_has_lock(ovnisb_idl_loop.idl) &&\n+        !ovsdb_idl_is_lock_contended(ovnisb_idl_loop.idl)) {\n+        /*\n+         * Ensure that only a single ovn-ic has the permission to\n+         * write to IC-SB.\n+         */\n+        VLOG_INFO(\"OVN ISB lock acquired. \"\n+                  \"This ovn-ic instance is now active.\");\n+        ovsdb_idl_set_lock(ovnisb_idl_loop.idl, \"ovn_ic_sb\");\n+    }\n+\n     /* Initialize incremental processing engine for ovn-northd */\n     inc_proc_ic_init(&ovnnb_idl_loop, &ovnsb_idl_loop,\n-                     &ovninb_idl_loop, &ovnisb_idl_loop);\n+                     &ovninb_idl_loop, &ovnisb_unlocked_idl_loop);\n \n     unsigned int ovnnb_cond_seqno = UINT_MAX;\n     unsigned int ovnsb_cond_seqno = UINT_MAX;\n     unsigned int ovninb_cond_seqno = UINT_MAX;\n     unsigned int ovnisb_cond_seqno = UINT_MAX;\n+    unsigned int ovnisb_unlocked_cond_seqno = UINT_MAX;\n \n     /* Main loop. */\n     struct ic_engine_context  eng_ctx = {0};\n@@ -3680,7 +3732,9 @@ main(int argc, char *argv[])\n     while (!exiting) {\n         update_ssl_config();\n         update_idl_probe_interval(ovnsb_idl_loop.idl, ovnnb_idl_loop.idl,\n-                                  ovnisb_idl_loop.idl, ovninb_idl_loop.idl);\n+                                  ovnisb_idl_loop.idl,\n+                                  ovnisb_unlocked_idl_loop.idl,\n+                                  ovninb_idl_loop.idl);\n         memory_run();\n         if (memory_should_report()) {\n             struct simap usage = SIMAP_INITIALIZER(&usage);\n@@ -3754,6 +3808,20 @@ main(int argc, char *argv[])\n                 ovnisb_cond_seqno = new_ovnisb_cond_seqno;\n             }\n \n+            struct ovsdb_idl_txn *ovnisb_unlocked_txn =\n+                run_idl_loop(&ovnisb_unlocked_idl_loop, \"OVN_IC_Southbound\",\n+                             &eng_ctx.isb_unlock_idl_duration_ms);\n+            unsigned int new_ovnisb_unlocked_cond_seqno =\n+                ovsdb_idl_get_condition_seqno(ovnisb_unlocked_idl_loop.idl);\n+            if (new_ovnisb_unlocked_cond_seqno != ovnisb_unlocked_cond_seqno) {\n+                if (!new_ovnisb_unlocked_cond_seqno) {\n+                    VLOG_INFO(\"OVN ISB IDL Unlocked reconnected,\"\n+                              \"force recompute.\");\n+                    inc_proc_ic_force_recompute();\n+                }\n+                ovnisb_unlocked_cond_seqno = new_ovnisb_unlocked_cond_seqno;\n+            }\n+\n             struct ic_context ctx = {\n                 .ovnnb_idl = ovnnb_idl_loop.idl,\n                 .ovnnb_txn = ovnnb_txn,\n@@ -3763,6 +3831,8 @@ main(int argc, char *argv[])\n                 .ovninb_txn = ovninb_txn,\n                 .ovnisb_idl = ovnisb_idl_loop.idl,\n                 .ovnisb_txn = ovnisb_txn,\n+                .ovnisb_unlocked_idl = ovnisb_unlocked_idl_loop.idl,\n+                .ovnisb_unlocked_txn = ovnisb_unlocked_txn,\n                 .nbrec_ls_by_name = nbrec_ls_by_name,\n                 .nbrec_lr_by_name = nbrec_lr_by_name,\n                 .nbrec_lrp_by_name = nbrec_lrp_by_name,\n@@ -3810,15 +3880,17 @@ main(int argc, char *argv[])\n                 ovsdb_idl_has_ever_connected(ctx.ovnnb_idl) &&\n                 ovsdb_idl_has_ever_connected(ctx.ovnsb_idl) &&\n                 ovsdb_idl_has_ever_connected(ctx.ovninb_idl) &&\n-                ovsdb_idl_has_ever_connected(ctx.ovnisb_idl)) {\n+                ovsdb_idl_has_ever_connected(ctx.ovnisb_idl) &&\n+                ovsdb_idl_has_ever_connected(ovnisb_unlocked_idl_loop.idl)) {\n                 if (ctx.ovnnb_txn && ctx.ovnsb_txn && ctx.ovninb_txn &&\n-                    ctx.ovnisb_txn && inc_proc_ic_can_run(&eng_ctx)) {\n+                    ctx.ovnisb_unlocked_txn && inc_proc_ic_can_run(&eng_ctx)) {\n                     ctx.runned_az = az_run(&ctx);\n                     VLOG_DBG(\"Availability zone: %s\", ctx.runned_az ?\n                              ctx.runned_az->name : \"not created yet.\");\n                     if (ctx.runned_az) {\n                         (void) inc_proc_ic_run(&ctx, &eng_ctx);\n-                        update_sequence_numbers(&ctx, &ovnisb_idl_loop);\n+                        update_sequence_numbers(&ctx,\n+                                                &ovnisb_unlocked_idl_loop);\n                     }\n                 } else if (!inc_proc_ic_get_force_recompute()) {\n                     clear_idl_track = false;\n@@ -3842,22 +3914,36 @@ main(int argc, char *argv[])\n                                 \"force recompute next time.\");\n                     inc_proc_ic_force_recompute_immediate();\n                 }\n-\n-                if (!ovsdb_idl_loop_commit_and_wait(&ovnisb_idl_loop)) {\n-                    VLOG_INFO(\"OVNISB commit failed, \"\n+                if (!ovsdb_idl_loop_commit_and_wait(\n+                                          &ovnisb_unlocked_idl_loop)) {\n+                    VLOG_INFO(\"OVNISB Unlocked commit failed, \"\n                                 \"force recompute next time.\");\n                     inc_proc_ic_force_recompute_immediate();\n                 }\n+\n+                /*\n+                 * ovn-ic will only try to recompute a failed transaction from\n+                 * the locked connection IF the AZ has the lock.\n+                 */\n+                if (!ovsdb_idl_loop_commit_and_wait(&ovnisb_idl_loop) &&\n+                    ovsdb_idl_has_lock(ovnisb_idl_loop.idl)) {\n+                    VLOG_INFO(\"OVNISB commit failed, \"\n+                              \"force recompute next time.\");\n+                        inc_proc_ic_force_recompute_immediate();\n+                }\n             } else {\n                 /* Make sure we send any pending requests, e.g., lock. */\n                 int rc1 = ovsdb_idl_loop_commit_and_wait(&ovnnb_idl_loop);\n                 int rc2 = ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);\n                 int rc3 = ovsdb_idl_loop_commit_and_wait(&ovninb_idl_loop);\n                 int rc4 = ovsdb_idl_loop_commit_and_wait(&ovnisb_idl_loop);\n-                if (!rc1 || !rc2 || !rc3 || !rc4) {\n-                    VLOG_DBG(\" a transaction failed in: %s %s %s %s\",\n+                int rc5 =\n+                    ovsdb_idl_loop_commit_and_wait(&ovnisb_unlocked_idl_loop);\n+                                if (!rc1 || !rc2 || !rc3 || !rc4 || !rc5) {\n+                    VLOG_DBG(\" a transaction failed in: %s %s %s %s %s\",\n                             !rc1 ? \"nb\" : \"\", !rc2 ? \"sb\" : \"\",\n-                            !rc3 ? \"ic_nb\" : \"\", !rc4 ? \"ic_sb\" : \"\");\n+                             !rc3 ? \"ic_nb\" : \"\", !rc4 ? \"ic_sb\" : \"\",\n+                             !rc5 ? \"ic_sb_unlocked\" : \"\");\n                     /* A transaction failed. Wake up immediately to give\n                     * opportunity to send the proper transaction\n                     */\n@@ -3885,10 +3971,12 @@ main(int argc, char *argv[])\n             ovsdb_idl_run(ovnsb_idl_loop.idl);\n             ovsdb_idl_run(ovninb_idl_loop.idl);\n             ovsdb_idl_run(ovnisb_idl_loop.idl);\n+            ovsdb_idl_run(ovnisb_unlocked_idl_loop.idl);\n             ovsdb_idl_wait(ovnnb_idl_loop.idl);\n             ovsdb_idl_wait(ovnsb_idl_loop.idl);\n             ovsdb_idl_wait(ovninb_idl_loop.idl);\n             ovsdb_idl_wait(ovnisb_idl_loop.idl);\n+            ovsdb_idl_wait(ovnisb_unlocked_idl_loop.idl);\n \n             /* Force a full recompute next time we become active. */\n             inc_proc_ic_force_recompute_immediate();\n@@ -3899,6 +3987,7 @@ main(int argc, char *argv[])\n             ovsdb_idl_track_clear(ovnsb_idl_loop.idl);\n             ovsdb_idl_track_clear(ovninb_idl_loop.idl);\n             ovsdb_idl_track_clear(ovnisb_idl_loop.idl);\n+            ovsdb_idl_track_clear(ovnisb_unlocked_idl_loop.idl);\n         }\n \n         unixctl_server_run(unixctl);\n@@ -3920,6 +4009,7 @@ main(int argc, char *argv[])\n     ovsdb_idl_loop_destroy(&ovnsb_idl_loop);\n     ovsdb_idl_loop_destroy(&ovninb_idl_loop);\n     ovsdb_idl_loop_destroy(&ovnisb_idl_loop);\n+    ovsdb_idl_loop_destroy(&ovnisb_unlocked_idl_loop);\n     service_stop();\n \n     exit(res);\ndiff --git a/ic/ovn-ic.h b/ic/ovn-ic.h\nindex 7391a19d4..9f52bb0f9 100644\n--- a/ic/ovn-ic.h\n+++ b/ic/ovn-ic.h\n@@ -22,10 +22,12 @@ struct ic_context {\n     struct ovsdb_idl *ovnsb_idl;\n     struct ovsdb_idl *ovninb_idl;\n     struct ovsdb_idl *ovnisb_idl;\n+    struct ovsdb_idl *ovnisb_unlocked_idl;\n     struct ovsdb_idl_txn *ovnnb_txn;\n     struct ovsdb_idl_txn *ovnsb_txn;\n     struct ovsdb_idl_txn *ovninb_txn;\n     struct ovsdb_idl_txn *ovnisb_txn;\n+    struct ovsdb_idl_txn *ovnisb_unlocked_txn;\n     const struct icsbrec_availability_zone *runned_az;\n     struct ovsdb_idl_index *nbrec_ls_by_name;\n     struct ovsdb_idl_index *nbrec_lr_by_name;\n",
    "prefixes": [
        "ovs-dev",
        "v3"
    ]
}