Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.1/patches/2231563/?format=api
{ "id": 2231563, "url": "http://patchwork.ozlabs.org/api/1.1/patches/2231563/?format=api", "web_url": "http://patchwork.ozlabs.org/project/ovn/patch/20260430204458.3802850-1-jtanenba@redhat.com/", "project": { "id": 68, "url": "http://patchwork.ozlabs.org/api/1.1/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": "" }, "msgid": "<20260430204458.3802850-1-jtanenba@redhat.com>", "date": "2026-04-30T20:44:58", "name": "[ovs-dev,v9] ovn-controller: Port up/ovn-installed reported too early.", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "63649c041a83b2c862c6e6c3615991a9bcf1341f", "submitter": { "id": 88238, "url": "http://patchwork.ozlabs.org/api/1.1/people/88238/?format=api", "name": "Jacob Tanenbaum", "email": "jtanenba@redhat.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/ovn/patch/20260430204458.3802850-1-jtanenba@redhat.com/mbox/", "series": [ { "id": 502382, "url": "http://patchwork.ozlabs.org/api/1.1/series/502382/?format=api", "web_url": "http://patchwork.ozlabs.org/project/ovn/list/?series=502382", "date": "2026-04-30T20:44:58", "name": "[ovs-dev,v9] ovn-controller: Port up/ovn-installed reported too early.", "version": 9, "mbox": "http://patchwork.ozlabs.org/series/502382/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2231563/comments/", "check": "success", "checks": "http://patchwork.ozlabs.org/api/patches/2231563/checks/", "tags": {}, "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=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=AgHdas9r;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org\n (client-ip=2605:bc80:3010::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 unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=AgHdas9r", "smtp2.osuosl.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com", "smtp2.osuosl.org;\n dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com\n header.a=rsa-sha256 header.s=mimecast20190719 header.b=AgHdas9r" ], "Received": [ "from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::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 4g65lk2xzQz1y1d\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 01 May 2026 06:45:22 +1000 (AEST)", "from localhost (localhost [127.0.0.1])\n\tby smtp1.osuosl.org (Postfix) with ESMTP id 8AADD82718;\n\tThu, 30 Apr 2026 20:45:14 +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 Wo5i_sp3_nhr; Thu, 30 Apr 2026 20:45:12 +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 5B52F82356;\n\tThu, 30 Apr 2026 20:45:12 +0000 (UTC)", "from lf-lists.osuosl.org (localhost [127.0.0.1])\n\tby lists.linuxfoundation.org (Postfix) with ESMTP id 1D96FC04E8;\n\tThu, 30 Apr 2026 20:45:12 +0000 (UTC)", "from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n by lists.linuxfoundation.org (Postfix) with ESMTP id B367EC04E7\n for <dev@openvswitch.org>; Thu, 30 Apr 2026 20:45:10 +0000 (UTC)", "from localhost (localhost [127.0.0.1])\n by smtp2.osuosl.org (Postfix) with ESMTP id 92044404F9\n for <dev@openvswitch.org>; Thu, 30 Apr 2026 20:45:10 +0000 (UTC)", "from smtp2.osuosl.org ([127.0.0.1])\n by localhost (smtp2.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id k4IQ00kOiDTL for <dev@openvswitch.org>;\n Thu, 30 Apr 2026 20:45:09 +0000 (UTC)", "from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.133.124])\n by smtp2.osuosl.org (Postfix) with ESMTPS id 1E68A40DE8\n for <dev@openvswitch.org>; Thu, 30 Apr 2026 20:45:07 +0000 (UTC)", "from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-424-KscdPEDqN0udgfobXF88Uw-1; Thu,\n 30 Apr 2026 16:45:04 -0400", "from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id 9A8E9195609F\n for <dev@openvswitch.org>; Thu, 30 Apr 2026 20:45:03 +0000 (UTC)", "from jtanenba-thinkpadp16vgen1.boston.csb (unknown [10.22.89.21])\n by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id C42D31953944; Thu, 30 Apr 2026 20:45:01 +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 smtp1.osuosl.org 5B52F82356", "OpenDKIM Filter v2.11.0 smtp2.osuosl.org 1E68A40DE8" ], "Received-SPF": "Pass (mailfrom) identity=mailfrom; client-ip=170.10.133.124;\n helo=us-smtp-delivery-124.mimecast.com; envelope-from=jtanenba@redhat.com;\n receiver=<UNKNOWN>", "DMARC-Filter": "OpenDMARC Filter v1.4.2 smtp2.osuosl.org 1E68A40DE8", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1777581906;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding;\n bh=TIdvvBljAk6OiOzY2sgb6fT4+L572Co9r92klVMWLz4=;\n b=AgHdas9rf343LawTAEdmfddZZ8Abmcv2Bj3xqlNGZkTkImucTfyrn5jNtQa0RVuivXQ1IZ\n 8PJQzERDG/ruZE+K5O8sH+YFAhD1Qy0Pc7+eZ5IC4MNguJeWypqGS/QrbkF9IOOB3llKzw\n 5c9GjpfThssnzniEQVTAcQfcrXC4urQ=", "X-MC-Unique": "KscdPEDqN0udgfobXF88Uw-1", "X-Mimecast-MFC-AGG-ID": "KscdPEDqN0udgfobXF88Uw_1777581903", "To": "dev@openvswitch.org", "Date": "Thu, 30 Apr 2026 16:44:58 -0400", "Message-ID": "<20260430204458.3802850-1-jtanenba@redhat.com>", "MIME-Version": "1.0", "X-Scanned-By": "MIMEDefang 3.0 on 10.30.177.17", "X-Mimecast-Spam-Score": "0", "X-Mimecast-MFC-PROC-ID": "6vrap2g_R98IuRSBtbiYZ78r_PMsvlusXpY8807jmUA_1777581903", "X-Mimecast-Originator": "redhat.com", "Subject": "[ovs-dev] [Patch ovn v9] ovn-controller: Port up/ovn-installed\n reported too early.", "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": "Jacob Tanenbaum via dev <ovs-dev@openvswitch.org>", "Reply-To": "Jacob Tanenbaum <jtanenba@redhat.com>", "Cc": "dceara@redhat.com", "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": "When ovn-monitor-all is set to false ovn-controller sets ovn-installed\non OVS interfaces too early. ovn-controller needs to wait for the\nresponse from the southbound database with the updates to the newly\nmonitored fields only then can it install flows and label the OVS\ninterface as installed.\n\nReported-at: https://redhat.atlassian.net/browse/FDP-2887\nSigned-off-by: Jacob Tanenbaum <jtanenba@redhat.com>\n\n---\nv8->v9\n* added the functionality of waiting for sb to update to the incremental\n processor\n\nv7->v8\n* removed printing in the system testcases that shouldn't be there and\n caused failure.\n\nv6->v7\n* added an sset that holds the uuid's of datapaths that are waiting for\n sb updates\n* added back the the state OIF_WAITING_SB_COND to the if_mgr state\n machine.\n* no longer hold if the datapath is updated in the local_datapaths\n struct as that is generated each transaction and cannot be relied\n upon.\n* removed some leftover logic from previous patch versions\n\nv5->v6\n* simplified the logic as requested, Ales saw that we did not need to\n save the seqno if we checked before the engine run.\n* removing the extra state from the state machine\n* removing some leftover logic that was seen.\n\nv4->v5\n* corrected a sanitizer error: used bool update_seqno without\n initializing\n\nv3->v4\n* Added state OIF_WAITING_SB_COND to the state machine that manages\n the adding of interfaces. This state waits until the Southbound has\n updated the ovn-controller of relevent information about ports related\n to it\n* Addressed several nits\n\nv2->v3\n* adding the ld->monitor_updated required the additiona of checking for\n monitor_all in update_sb_monitors. I didn't account for being able to\n toggle on monitor_all\n\nv1->v2\n* if_status_mgr_run() will run everytime the conditional seqno is\n changed so it should be safe to only skip when the expected_seqno and\n seqno returned from ovn are strictly not equal, that way we do not\n have to deal with overflow in the seqno. Additionally add a boolean to\n the local_datapath in the event that the seqno wraps around at the\n same time the datapath would go back into the state OIF_INSTALL_FLOWS.\n* remove setting the state to itself for OIF_INSTALL_FLOWS in\n if_status_mgr_update()\n* added assert(pb) in if_status_mgr_run()\n* removed a manual loop looking for the local_datapath and replaced with\n get_local_datapath() in if_status_mgr_run\n* remove a few nit spelling errors in the test case", "diff": "diff --git a/controller/if-status.c b/controller/if-status.c\nindex ee9337e63..aa789c63c 100644\n--- a/controller/if-status.c\n+++ b/controller/if-status.c\n@@ -18,6 +18,7 @@\n #include \"binding.h\"\n #include \"if-status.h\"\n #include \"lib/ofctrl-seqno.h\"\n+#include \"local_data.h\"\n #include \"ovsport.h\"\n #include \"simap.h\"\n \n@@ -58,6 +59,11 @@ VLOG_DEFINE_THIS_MODULE(if_status);\n enum if_state {\n OIF_CLAIMED, /* Newly claimed interface. pb->chassis update not\n yet initiated. */\n+ OIF_WAITING_SB_COND, /* Waiting for the Southbound database to update\n+ * ovn-controller for a given datapath. We should\n+ * only be waiting in this state when monitor_all\n+ * is false AND it is the first time that we see\n+ * a specific datapath. */\n OIF_INSTALL_FLOWS, /* Claimed interface with pb->chassis update sent to\n * SB (but update notification not confirmed, so the\n * update may be resent in any of the following\n@@ -87,6 +93,7 @@ enum if_state {\n \n static const char *if_state_names[] = {\n [OIF_CLAIMED] = \"CLAIMED\",\n+ [OIF_WAITING_SB_COND] = \"WAITING_SB_COND\",\n [OIF_INSTALL_FLOWS] = \"INSTALL_FLOWS\",\n [OIF_REM_OLD_OVN_INST] = \"REM_OLD_OVN_INST\",\n [OIF_MARK_UP] = \"MARK_UP\",\n@@ -114,7 +121,18 @@ static const char *if_state_names[] = {\n * | | | +--+ | | |\n * | | | | | |\n * | | | mgr_update(when sb is rw i.e. pb->chassis) | | |\n- * | | | has been updated | | |\n+ * | | V has been updated | | |\n+ * | | +----------------------+ | | |\n+ * | | | | | | |\n+ * | | | WAITING_SB_COND | | | |\n+ * | | | | | | |\n+ * | | | | | | |\n+ * | | +----------------------+ | | |\n+ * | | | | | |\n+ * | | | | | |\n+ * | | | mgr_update(when sb_cond_seqno == expected) | | |\n+ * | | | - request seqno | | |\n+ * | | | | | |\n * | | release_iface | - request seqno | | |\n * | | | | | |\n * | | V | | |\n@@ -335,6 +353,7 @@ if_status_mgr_claim_iface(struct if_status_mgr *mgr,\n \n switch (iface->state) {\n case OIF_CLAIMED:\n+ case OIF_WAITING_SB_COND:\n case OIF_INSTALL_FLOWS:\n case OIF_REM_OLD_OVN_INST:\n case OIF_MARK_UP:\n@@ -383,6 +402,7 @@ if_status_mgr_release_iface(struct if_status_mgr *mgr, const char *iface_id)\n \n switch (iface->state) {\n case OIF_CLAIMED:\n+ case OIF_WAITING_SB_COND:\n case OIF_INSTALL_FLOWS:\n /* Not yet fully installed interfaces:\n * pb->chassis still need to be deleted.\n@@ -424,6 +444,7 @@ if_status_mgr_delete_iface(struct if_status_mgr *mgr, const char *iface_id,\n \n switch (iface->state) {\n case OIF_CLAIMED:\n+ case OIF_WAITING_SB_COND:\n case OIF_INSTALL_FLOWS:\n /* Not yet fully installed interfaces:\n * pb->chassis still need to be deleted.\n@@ -500,6 +521,8 @@ if_status_mgr_update(struct if_status_mgr *mgr,\n const struct sbrec_chassis *chassis_rec,\n const struct ovsrec_interface_table *iface_table,\n const struct sbrec_port_binding_table *pb_table,\n+ const struct hmap *local_datapaths,\n+ const struct uuidset *waiting_sb_update,\n bool ovs_readonly,\n bool sb_readonly)\n {\n@@ -622,9 +645,7 @@ if_status_mgr_update(struct if_status_mgr *mgr,\n * in if_status_handle_claims or if_status_mgr_claim_iface\n */\n if (iface->is_vif) {\n- ovs_iface_set_state(mgr, iface, OIF_INSTALL_FLOWS);\n- iface->install_seqno = mgr->iface_seqno + 1;\n- new_ifaces = true;\n+ ovs_iface_set_state(mgr, iface, OIF_WAITING_SB_COND);\n } else {\n ovs_iface_set_state(mgr, iface, OIF_MARK_UP);\n }\n@@ -639,6 +660,33 @@ if_status_mgr_update(struct if_status_mgr *mgr,\n }\n }\n \n+ if (!sb_readonly) {\n+ HMAPX_FOR_EACH_SAFE (node,\n+ &mgr->ifaces_per_state[OIF_WAITING_SB_COND]) {\n+ struct ovs_iface *iface = node->data;\n+ if (local_datapaths) {\n+ const struct sbrec_port_binding *pb =\n+ sbrec_port_binding_table_get_for_uuid(pb_table,\n+ &iface->pb_uuid);\n+ ovs_assert(pb);\n+ struct local_datapath *ld =\n+ get_local_datapath(local_datapaths,\n+ pb->datapath->tunnel_key);\n+ if (!ld) {\n+ continue;\n+ }\n+ if (waiting_sb_update &&\n+ !uuidset_find(waiting_sb_update,\n+ &ld->datapath->header_.uuid)) {\n+ ovs_iface_set_state(mgr, iface, OIF_INSTALL_FLOWS);\n+ iface->install_seqno = mgr->iface_seqno + 1;\n+ new_ifaces = true;\n+ }\n+\n+ }\n+ }\n+ }\n+\n if (!sb_readonly) {\n HMAPX_FOR_EACH_SAFE (node, &mgr->ifaces_per_state[OIF_UPDATE_PORT]) {\n struct ovs_iface *iface = node->data;\ndiff --git a/controller/if-status.h b/controller/if-status.h\nindex d15ca3008..8c057bf6b 100644\n--- a/controller/if-status.h\n+++ b/controller/if-status.h\n@@ -18,6 +18,7 @@\n \n #include \"openvswitch/shash.h\"\n #include \"lib/vswitch-idl.h\"\n+#include \"lib/uuidset.h\"\n \n #include \"binding.h\"\n #include \"lport.h\"\n@@ -43,6 +44,8 @@ void if_status_mgr_update(struct if_status_mgr *, struct local_binding_data *,\n const struct sbrec_chassis *chassis,\n const struct ovsrec_interface_table *iface_table,\n const struct sbrec_port_binding_table *pb_table,\n+ const struct hmap *local_datapaths,\n+ const struct uuidset *waiting_sb_update,\n bool ovs_readonly,\n bool sb_readonly);\n void if_status_mgr_run(struct if_status_mgr *mgr, struct local_binding_data *,\ndiff --git a/controller/ovn-controller.c b/controller/ovn-controller.c\nindex 35a5cd0b4..91c659718 100644\n--- a/controller/ovn-controller.c\n+++ b/controller/ovn-controller.c\n@@ -170,6 +170,7 @@ static char *unixctl_path;\n struct controller_engine_ctx {\n struct lflow_cache *lflow_cache;\n struct if_status_mgr *if_mgr;\n+ unsigned int *ovnsb_expected_cond_seqno;\n };\n \n /* Pending packet to be injected into connected OVS. */\n@@ -1145,10 +1146,51 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl)\n * track that column which should be addressed in the future. */\n }\n \n+struct ed_type_datapaths_updated {\n+ struct uuidset waiting_sb_cond_update;\n+};\n+\n+static void *\n+en_datapaths_updated_init(struct engine_node *node OVS_UNUSED,\n+ struct engine_arg *arg OVS_UNUSED)\n+{\n+ struct ed_type_datapaths_updated *data = xzalloc(sizeof *data);\n+ uuidset_init(&data->waiting_sb_cond_update);\n+ return data;\n+}\n+\n+static void\n+en_datapaths_updated_cleanup(void *data)\n+{\n+ struct ed_type_datapaths_updated *sb_data = data;\n+ uuidset_destroy(&sb_data->waiting_sb_cond_update);\n+}\n+\n struct ed_type_ofctrl_is_connected {\n bool connected;\n };\n \n+static enum engine_node_state\n+en_datapaths_updated_run(struct engine_node *node OVS_UNUSED,\n+ void *data)\n+{\n+ struct controller_engine_ctx *ctrl_ctx = engine_get_context()->client_ctx;\n+ struct ovsdb_idl_txn *ovnsb_idl_txn = engine_get_context()->ovnsb_idl_txn;\n+ if (!ovnsb_idl_txn) {\n+ return EN_UNCHANGED;\n+ }\n+ struct ovsdb_idl *ovnsb_idl = ovsdb_idl_txn_get_idl(ovnsb_idl_txn);\n+ if (*ctrl_ctx->ovnsb_expected_cond_seqno ==\n+ ovsdb_idl_get_condition_seqno(ovnsb_idl)) {\n+ struct ed_type_datapaths_updated *dp_data = data;\n+ if (!uuidset_is_empty(&dp_data->waiting_sb_cond_update)) {\n+ uuidset_clear(&dp_data->waiting_sb_cond_update);\n+ return EN_UNCHANGED;\n+ }\n+ }\n+ return EN_UNCHANGED;\n+}\n+\n static void *\n en_ofctrl_is_connected_init(struct engine_node *node OVS_UNUSED,\n struct engine_arg *arg OVS_UNUSED)\n@@ -1180,6 +1222,41 @@ en_ofctrl_is_connected_run(struct engine_node *node OVS_UNUSED, void *data)\n return EN_UNCHANGED;\n }\n \n+struct ed_type_sb_cond_seqno {\n+ unsigned int last_sb_cond_seqno;\n+};\n+\n+static void *\n+en_sb_cond_seqno_init(struct engine_node *node OVS_UNUSED,\n+ struct engine_arg *arg OVS_UNUSED)\n+{\n+ struct ed_type_sb_cond_seqno *data = xzalloc(sizeof *data);\n+ return data;\n+}\n+\n+static void en_sb_cond_seqno_cleanup (void *data OVS_UNUSED)\n+{\n+}\n+\n+static enum engine_node_state\n+en_sb_cond_seqno_run(struct engine_node *node OVS_UNUSED, void *data)\n+{\n+ struct ed_type_sb_cond_seqno *sb_seqno_data = data;\n+ struct ovsdb_idl_txn *ovnsb_idl_txn = engine_get_context()->ovnsb_idl_txn;\n+ if (!ovnsb_idl_txn) {\n+ return EN_UNCHANGED;\n+ }\n+\n+ unsigned int curr_seqno =\n+ ovsdb_idl_get_condition_seqno(ovsdb_idl_txn_get_idl(ovnsb_idl_txn));\n+\n+ if (sb_seqno_data->last_sb_cond_seqno != curr_seqno) {\n+ sb_seqno_data->last_sb_cond_seqno = curr_seqno;\n+ return EN_UPDATED;\n+ }\n+ return EN_UNCHANGED;\n+}\n+\n struct ed_type_if_status_mgr {\n const struct if_status_mgr *manager;\n const struct ovsrec_interface_table *iface_table;\n@@ -1512,6 +1589,7 @@ en_runtime_data_clear_tracked_data(void *data_)\n }\n \n static void *\n+\n en_runtime_data_init(struct engine_node *node OVS_UNUSED,\n struct engine_arg *arg OVS_UNUSED)\n {\n@@ -6745,6 +6823,50 @@ evpn_arp_vtep_binding_handler(struct engine_node *node, void *data OVS_UNUSED)\n return EN_UNHANDLED;\n }\n \n+static enum engine_input_handler_result\n+new_datapaths_handler(struct engine_node *node,\n+ void *data)\n+{\n+ struct ed_type_datapaths_updated *dp_data = data;\n+ struct ed_type_runtime_data *rt_data =\n+ engine_get_input_data(\"runtime_data\", node);\n+\n+ enum engine_input_handler_result status = EN_HANDLED_UNCHANGED;\n+ struct tracked_datapath *tdp;\n+ HMAP_FOR_EACH_SAFE (tdp, node, &rt_data->tracked_dp_bindings) {\n+ if (tdp->tracked_type == TRACKED_RESOURCE_NEW) {\n+ uuidset_insert(&dp_data->waiting_sb_cond_update,\n+ &tdp->dp->header_.uuid);\n+ status = EN_HANDLED_UPDATED;\n+ }\n+ }\n+ return status;\n+}\n+\n+static enum engine_input_handler_result\n+datapaths_update_sb_cond_handler(struct engine_node *node OVS_UNUSED,\n+ void *data)\n+{\n+ struct controller_engine_ctx *ctrl_ctx = engine_get_context()->client_ctx;\n+ struct ovsdb_idl_txn *ovnsb_idl_txn = engine_get_context()->ovnsb_idl_txn;\n+ if (!ovnsb_idl_txn) {\n+ return EN_HANDLED_UNCHANGED;\n+ }\n+ struct ovsdb_idl *ovnsb_idl = ovsdb_idl_txn_get_idl(ovnsb_idl_txn);\n+ if (ovnsb_idl_txn) {\n+ if (*ctrl_ctx->ovnsb_expected_cond_seqno ==\n+ ovsdb_idl_get_condition_seqno(ovnsb_idl)) {\n+ struct ed_type_datapaths_updated *dp_data = data;\n+\n+ if (!uuidset_is_empty(&dp_data->waiting_sb_cond_update)) {\n+ uuidset_clear(&dp_data->waiting_sb_cond_update);\n+ return EN_HANDLED_UPDATED;\n+ }\n+ }\n+ }\n+ return EN_HANDLED_UNCHANGED;\n+}\n+\n /* Define engine node functions for nodes that represent SB tables.\n *\n * en_sb_<TABLE_NAME>_run()\n@@ -6867,6 +6989,8 @@ static ENGINE_NODE(neighbor_exchange_status);\n static ENGINE_NODE(evpn_vtep_binding, CLEAR_TRACKED_DATA);\n static ENGINE_NODE(evpn_fdb, CLEAR_TRACKED_DATA);\n static ENGINE_NODE(evpn_arp, CLEAR_TRACKED_DATA);\n+static ENGINE_NODE(datapaths_updated);\n+static ENGINE_NODE(sb_cond_seqno);\n \n static void\n inc_proc_ovn_controller_init(\n@@ -6889,6 +7013,8 @@ inc_proc_ovn_controller_init(\n engine_add_input(&en_template_vars, &en_sb_chassis_template_var,\n template_vars_sb_chassis_template_var_handler);\n \n+ engine_add_input(&en_datapaths_updated, &en_sb_cond_seqno,\n+ datapaths_update_sb_cond_handler);\n engine_add_input(&en_lb_data, &en_sb_load_balancer,\n lb_data_sb_load_balancer_handler);\n engine_add_input(&en_lb_data, &en_template_vars,\n@@ -6975,6 +7101,9 @@ inc_proc_ovn_controller_init(\n engine_add_input(&en_pflow_output, &en_sb_sb_global,\n pflow_output_debug_handler);\n \n+ engine_add_input(&en_datapaths_updated, &en_runtime_data,\n+ new_datapaths_handler);\n+\n engine_add_input(&en_northd_options, &en_sb_sb_global,\n en_northd_options_sb_sb_global_handler);\n \n@@ -7163,6 +7292,7 @@ inc_proc_ovn_controller_init(\n engine_add_input(&en_acl_id, &en_sb_acl_id, NULL);\n engine_add_input(&en_controller_output, &en_acl_id,\n controller_output_acl_id_handler);\n+ engine_add_input(&en_controller_output, &en_datapaths_updated, NULL);\n \n struct engine_arg engine_arg = {\n .sb_idl = sb_idl_loop->idl,\n@@ -7556,6 +7686,8 @@ main(int argc, char *argv[])\n engine_get_internal_data(&en_evpn_fdb);\n struct ed_type_evpn_arp *earp_data =\n engine_get_internal_data(&en_evpn_arp);\n+ struct ed_type_datapaths_updated *dp_updated_data =\n+ engine_get_internal_data(&en_datapaths_updated);\n \n ofctrl_init(&lflow_output_data->group_table,\n &lflow_output_data->meter_table);\n@@ -7659,6 +7791,7 @@ main(int argc, char *argv[])\n struct controller_engine_ctx ctrl_engine_ctx = {\n .lflow_cache = lflow_cache_create(),\n .if_mgr = if_status_mgr_create(),\n+ .ovnsb_expected_cond_seqno = &ovnsb_expected_cond_seqno,\n };\n struct if_status_mgr *if_mgr = ctrl_engine_ctx.if_mgr;\n \n@@ -7915,6 +8048,7 @@ main(int argc, char *argv[])\n \n bool recompute_allowed = (ovnsb_idl_txn &&\n !ofctrl_has_backlog());\n+\n engine_run(recompute_allowed);\n tracked_acl_ids = engine_get_data(&en_acl_id);\n \n@@ -8085,11 +8219,23 @@ main(int argc, char *argv[])\n runtime_data ? &runtime_data->lbinding_data : NULL;\n stopwatch_start(IF_STATUS_MGR_UPDATE_STOPWATCH_NAME,\n time_msec());\n+ if (sb_monitor_all && dp_updated_data) {\n+ uuidset_clear(\n+ &dp_updated_data->waiting_sb_cond_update);\n+ }\n+\n+ struct uuidset *waiting_sb_cond_update = dp_updated_data ?\n+ &dp_updated_data->waiting_sb_cond_update\n+ : NULL;\n if_status_mgr_update(if_mgr, binding_data, chassis,\n ovsrec_interface_table_get(\n ovs_idl_loop.idl),\n sbrec_port_binding_table_get(\n ovnsb_idl_loop.idl),\n+ runtime_data ?\n+ &runtime_data->local_datapaths\n+ : NULL,\n+ waiting_sb_cond_update,\n !ovs_idl_txn,\n !ovnsb_idl_txn);\n stopwatch_stop(IF_STATUS_MGR_UPDATE_STOPWATCH_NAME,\ndiff --git a/tests/ovn-controller.at b/tests/ovn-controller.at\nindex c98de9bc4..9dc7555ba 100644\n--- a/tests/ovn-controller.at\n+++ b/tests/ovn-controller.at\n@@ -3944,3 +3944,69 @@ OVN_CLEANUP([hv1], [hv2\n /already has encap ip.*cannot duplicate on/d])\n AT_CLEANUP\n ])\n+\n+OVN_FOR_EACH_NORTHD([\n+AT_SETUP([ovn-installed])\n+ovn_start\n+\n+net_add n1\n+sim_add hv1\n+\n+as hv1\n+ovs-vsctl add-br br-phys\n+ovn_attach n1 br-phys 192.168.0.1\n+ovn-appctl vlog/set dbg\n+ovs-vsctl add-port br-int vif1 -- \\\n+ set Interface vif1 external-ids:iface-id=lsp1\n+\n+check ovn-nbctl ls-add ls1\n+sleep_controller hv1\n+check ovn-nbctl --wait=sb lsp-add ls1 lsp1 -- \\\n+ lsp-set-addresses lsp1 \"f0:00:00:00:00:01 10.0.0.1\"\n+\n+sleep_sb\n+wake_up_controller hv1\n+\n+# Wait for pflow for lsp1\n+OVS_WAIT_UNTIL([\n+ ofport=$(as hv1 ovs-vsctl --bare --columns ofport find Interface name=vif1)\n+ echo \"vif1 port=$ofport\"\n+ test -n \"$ofport\" && test 1 -le $(as hv1 ovs-ofctl dump-flows br-int | grep -c in_port=$ofport)\n+])\n+\n+# If ovn-installed in ovs, all flows should be installed.\n+# In that case, there should be at least one flow with lsp1 address.\n+OVS_WAIT_UNTIL([\n+ ovn_installed=$(as hv1 ovs-vsctl get Interface vif1 external_ids:ovn-installed)\n+ echo $ovn_installed\n+ flow_count=$(as hv1 ovs-ofctl dump-flows br-int | grep -Fc \"10.0.0.1\")\n+ # for the monitor-all=true case the flow gets installed because ovn-controller is monitoring all\n+ # tables in OVN_SOUTHBOUND.\n+ if test -n \"$ovn_installed\"; then\n+ as hv1 ovs-ofctl dump-flows br-int > output\n+ test $flow_count -ge 1\n+ else\n+ true\n+ fi\n+])\n+\n+wake_up_sb\n+# After the southbound db has woken up and can send the update to the\n+# ovn-controller not monitoring all tables in the southbound db it\n+# should be able to install the interface.\n+OVS_WAIT_UNTIL([\n+ ovn_installed=$(as hv1 ovs-vsctl get Interface vif1 external_ids:ovn-installed)\n+ flow_count=$(as hv1 ovs-ofctl dump-flows br-int | grep -Fc \"10.0.0.1\")\n+ echo \"installed=$ovn_installed, count=$flow_count\"\n+ if test -n \"$ovn_installed\"; then\n+ as hv1 ovs-ofctl dump-flows br-int > output\n+ test $flow_count -ge 1\n+ else\n+ false\n+ fi\n+])\n+wait_for_ports_up\n+\n+OVN_CLEANUP([hv1])\n+AT_CLEANUP\n+])\ndiff --git a/tests/ovn-inc-proc-graph-dump.at b/tests/ovn-inc-proc-graph-dump.at\nindex 178310978..036d44891 100644\n--- a/tests/ovn-inc-proc-graph-dump.at\n+++ b/tests/ovn-inc-proc-graph-dump.at\n@@ -478,6 +478,10 @@ digraph \"Incremental-Processing-Engine\" {\n \tSB_acl_id [[style=filled, shape=box, fillcolor=white, label=\"SB_acl_id\"]];\n \tacl_id [[style=filled, shape=box, fillcolor=white, label=\"acl_id\"]];\n \tSB_acl_id -> acl_id [[label=\"\"]];\n+\tsb_cond_seqno [[style=filled, shape=box, fillcolor=white, label=\"sb_cond_seqno\"]];\n+\tdatapaths_updated [[style=filled, shape=box, fillcolor=white, label=\"datapaths_updated\"]];\n+\tsb_cond_seqno -> datapaths_updated [[label=\"datapaths_update_sb_cond_handler\"]];\n+\truntime_data -> datapaths_updated [[label=\"new_datapaths_handler\"]];\n \tcontroller_output [[style=filled, shape=box, fillcolor=white, label=\"controller_output\"]];\n \tdns_cache -> controller_output [[label=\"\"]];\n \tlflow_output -> controller_output [[label=\"controller_output_lflow_output_handler\"]];\n@@ -487,6 +491,7 @@ digraph \"Incremental-Processing-Engine\" {\n \troute_exchange -> controller_output [[label=\"controller_output_route_exchange_handler\"]];\n \tgarp_rarp -> controller_output [[label=\"controller_output_garp_rarp_handler\"]];\n \tacl_id -> controller_output [[label=\"controller_output_acl_id_handler\"]];\n+\tdatapaths_updated -> controller_output [[label=\"\"]];\n }\n ])\n AT_CLEANUP\n", "prefixes": [ "ovs-dev", "v9" ] }