When ovn-monitor-all is set to false ovn-controller sets ovn-installed
on OVS interfaces too early. ovn-controller needs to wait for the
response from the southbound database with the updates to the newly
monitored fields only then can it install flows and label the OVS
interface as installed.

Reported-at: https://redhat.atlassian.net/browse/FDP-2887
Signed-off-by: Jacob Tanenbaum <[email protected]>

---
v9->v10
* added a bool for if the controller is in monitor-all
* removed some code leftover from debugging
* changed argument to if_status_mgr_update to dps_waiting_for_sb
* removed ovs_assert in favor of NULL checking
* removed unrelated new lines

v8->v9
* added the functionality of waiting for sb to update to the incremental
  processor

v7->v8
* removed printing in the system testcases that shouldn't be there and
  caused failure.

v6->v7
* added an sset that holds the uuid's of datapaths that are waiting for
  sb updates
* added back the the state OIF_WAITING_SB_COND to the if_mgr state
  machine.
* no longer hold if the datapath is updated in the local_datapaths
  struct as that is generated each transaction and cannot be relied
  upon.
* removed some leftover logic from previous patch versions

v5->v6
* simplified the logic as requested, Ales saw that we did not need to
  save the seqno if we checked before the engine run.
* removing the extra state from the state machine
* removing some leftover logic that was seen.

v4->v5
* corrected a sanitizer error: used bool update_seqno without
  initializing

v3->v4
* Added state OIF_WAITING_SB_COND to the state machine that manages
  the adding of interfaces. This state waits until the Southbound has
  updated the ovn-controller of relevent information about ports related
  to it
* Addressed several nits

v2->v3
* adding the ld->monitor_updated required the additiona of checking for
  monitor_all in update_sb_monitors. I didn't account for being able to
  toggle on monitor_all

v1->v2
* if_status_mgr_run() will run everytime the conditional seqno is
  changed so it should be safe to only skip when the expected_seqno and
  seqno returned from ovn are strictly not equal, that way we do not
  have to deal with overflow in the seqno. Additionally add a boolean to
  the local_datapath in the event that the seqno wraps around at the
  same time the datapath would go back into the state OIF_INSTALL_FLOWS.
* remove setting the state to itself for OIF_INSTALL_FLOWS in
  if_status_mgr_update()
* added assert(pb) in if_status_mgr_run()
* removed a manual loop looking for the local_datapath and replaced with
  get_local_datapath() in if_status_mgr_run
* remove a few nit spelling errors in the test case

diff --git a/controller/if-status.c b/controller/if-status.c
index ee9337e63..d12ac5515 100644
--- a/controller/if-status.c
+++ b/controller/if-status.c
@@ -18,6 +18,7 @@
 #include "binding.h"
 #include "if-status.h"
 #include "lib/ofctrl-seqno.h"
+#include "local_data.h"
 #include "ovsport.h"
 #include "simap.h"
 
@@ -58,6 +59,11 @@ VLOG_DEFINE_THIS_MODULE(if_status);
 enum if_state {
     OIF_CLAIMED,          /* Newly claimed interface. pb->chassis update not
                              yet initiated. */
+    OIF_WAITING_SB_COND,  /* Waiting for the Southbound database to update
+                           * ovn-controller for a given datapath. We should
+                           * only be waiting in this state when monitor_all
+                           * is false AND it is the first time that we see
+                           * a specific datapath. */
     OIF_INSTALL_FLOWS,    /* Claimed interface with pb->chassis update sent to
                            * SB (but update notification not confirmed, so the
                            * update may be resent in any of the following
@@ -87,6 +93,7 @@ enum if_state {
 
 static const char *if_state_names[] = {
     [OIF_CLAIMED]          = "CLAIMED",
+    [OIF_WAITING_SB_COND]  = "WAITING_SB_COND",
     [OIF_INSTALL_FLOWS]    = "INSTALL_FLOWS",
     [OIF_REM_OLD_OVN_INST] = "REM_OLD_OVN_INST",
     [OIF_MARK_UP]          = "MARK_UP",
@@ -114,7 +121,18 @@ static const char *if_state_names[] = {
  * | |                 |  +--+                                           | | |
  * | |                 |                                                 | | |
  * | |                 | mgr_update(when sb is rw i.e. pb->chassis)      | | |
- * | |                 |            has been updated                     | | |
+ * | |                 V            has been updated                     | | |
+ * | |   +----------------------+                                        | | |
+ * | |   |                      |                                        | | |
+ * | |   |    WAITING_SB_COND   |                                        | | |
+ * | |   |                      |                                        | | |
+ * | |   |                      |                                        | | |
+ * | |   +----------------------+                                        | | |
+ * | |                 |                                                 | | |
+ * | |                 |                                                 | | |
+ * | |                 |   mgr_update(when sb_cond_seqno == expected)    | | |
+ * | |                 |   - request seqno                               | | |
+ * | |                 |                                                 | | |
  * | | release_iface   | - request seqno                                 | | |
  * | |                 |                                                 | | |
  * | |                 V                                                 | | |
@@ -335,6 +353,7 @@ if_status_mgr_claim_iface(struct if_status_mgr *mgr,
 
     switch (iface->state) {
     case OIF_CLAIMED:
+    case OIF_WAITING_SB_COND:
     case OIF_INSTALL_FLOWS:
     case OIF_REM_OLD_OVN_INST:
     case OIF_MARK_UP:
@@ -383,6 +402,7 @@ if_status_mgr_release_iface(struct if_status_mgr *mgr, 
const char *iface_id)
 
     switch (iface->state) {
     case OIF_CLAIMED:
+    case OIF_WAITING_SB_COND:
     case OIF_INSTALL_FLOWS:
         /* Not yet fully installed interfaces:
          * pb->chassis still need to be deleted.
@@ -424,6 +444,7 @@ if_status_mgr_delete_iface(struct if_status_mgr *mgr, const 
char *iface_id,
 
     switch (iface->state) {
     case OIF_CLAIMED:
+    case OIF_WAITING_SB_COND:
     case OIF_INSTALL_FLOWS:
         /* Not yet fully installed interfaces:
          * pb->chassis still need to be deleted.
@@ -500,6 +521,8 @@ if_status_mgr_update(struct if_status_mgr *mgr,
                      const struct sbrec_chassis *chassis_rec,
                      const struct ovsrec_interface_table *iface_table,
                      const struct sbrec_port_binding_table *pb_table,
+                     const struct hmap *local_datapaths,
+                     const struct uuidset *dps_waiting_for_sb,
                      bool ovs_readonly,
                      bool sb_readonly)
 {
@@ -510,6 +533,8 @@ if_status_mgr_update(struct if_status_mgr *mgr,
         return;
     }
 
+    ovs_assert(dps_waiting_for_sb);
+
     struct shash *bindings = &binding_data->bindings;
     struct hmapx_node *node;
 
@@ -622,9 +647,7 @@ if_status_mgr_update(struct if_status_mgr *mgr,
              * in if_status_handle_claims or if_status_mgr_claim_iface
              */
             if (iface->is_vif) {
-                ovs_iface_set_state(mgr, iface, OIF_INSTALL_FLOWS);
-                iface->install_seqno = mgr->iface_seqno + 1;
-                new_ifaces = true;
+                ovs_iface_set_state(mgr, iface, OIF_WAITING_SB_COND);
             } else {
                 ovs_iface_set_state(mgr, iface, OIF_MARK_UP);
             }
@@ -639,6 +662,33 @@ if_status_mgr_update(struct if_status_mgr *mgr,
         }
     }
 
+    if (!sb_readonly) {
+        HMAPX_FOR_EACH_SAFE (node,
+                             &mgr->ifaces_per_state[OIF_WAITING_SB_COND]) {
+            struct ovs_iface *iface = node->data;
+            if (local_datapaths) {
+                const struct sbrec_port_binding *pb =
+                    sbrec_port_binding_table_get_for_uuid(pb_table,
+                                                          &iface->pb_uuid);
+                if (!pb) {
+                    continue;
+                }
+                struct local_datapath *ld =
+                    get_local_datapath(local_datapaths,
+                                       pb->datapath->tunnel_key);
+                if (!ld) {
+                    continue;
+                }
+                if (!uuidset_find(dps_waiting_for_sb,
+                        &ld->datapath->header_.uuid)) {
+                    ovs_iface_set_state(mgr, iface, OIF_INSTALL_FLOWS);
+                    iface->install_seqno = mgr->iface_seqno + 1;
+                    new_ifaces = true;
+                }
+            }
+        }
+    }
+
     if (!sb_readonly) {
         HMAPX_FOR_EACH_SAFE (node, &mgr->ifaces_per_state[OIF_UPDATE_PORT]) {
             struct ovs_iface *iface = node->data;
diff --git a/controller/if-status.h b/controller/if-status.h
index d15ca3008..75c7bf71c 100644
--- a/controller/if-status.h
+++ b/controller/if-status.h
@@ -18,6 +18,7 @@
 
 #include "openvswitch/shash.h"
 #include "lib/vswitch-idl.h"
+#include "lib/uuidset.h"
 
 #include "binding.h"
 #include "lport.h"
@@ -43,6 +44,8 @@ void if_status_mgr_update(struct if_status_mgr *, struct 
local_binding_data *,
                           const struct sbrec_chassis *chassis,
                           const struct ovsrec_interface_table *iface_table,
                           const struct sbrec_port_binding_table *pb_table,
+                          const struct hmap *local_datapaths,
+                          const struct uuidset *dps_waiting_for_sb,
                           bool ovs_readonly,
                           bool sb_readonly);
 void if_status_mgr_run(struct if_status_mgr *mgr, struct local_binding_data *,
diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
index 35a5cd0b4..3a8eeb4c0 100644
--- a/controller/ovn-controller.c
+++ b/controller/ovn-controller.c
@@ -170,6 +170,8 @@ static char *unixctl_path;
 struct controller_engine_ctx {
     struct lflow_cache *lflow_cache;
     struct if_status_mgr *if_mgr;
+    const unsigned int *ovnsb_expected_cond_seqno;
+    const bool *sb_monitor_all;
 };
 
 /* Pending packet to be injected into connected OVS. */
@@ -1145,6 +1147,50 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl)
      * track that column which should be addressed in the future. */
 }
 
+struct ed_type_datapaths_updated {
+    struct uuidset waiting_sb_cond_update;
+};
+
+static void *
+en_datapaths_updated_init(struct engine_node *node OVS_UNUSED,
+                          struct engine_arg *arg OVS_UNUSED)
+{
+    struct ed_type_datapaths_updated *data = xzalloc(sizeof *data);
+    *data = (struct ed_type_datapaths_updated) {
+        .waiting_sb_cond_update =
+                UUIDSET_INITIALIZER(&data->waiting_sb_cond_update),
+    };
+    return data;
+}
+
+static void
+en_datapaths_updated_cleanup(void *data)
+{
+    struct ed_type_datapaths_updated *sb_data = data;
+    uuidset_destroy(&sb_data->waiting_sb_cond_update);
+}
+
+static enum engine_node_state
+en_datapaths_updated_run(struct engine_node *node OVS_UNUSED,
+                         void *data)
+{
+    struct controller_engine_ctx *ctrl_ctx = engine_get_context()->client_ctx;
+    struct ovsdb_idl_txn *ovnsb_idl_txn = engine_get_context()->ovnsb_idl_txn;
+    if (!ovnsb_idl_txn) {
+        return EN_UNCHANGED;
+    }
+    struct ovsdb_idl *ovnsb_idl = ovsdb_idl_txn_get_idl(ovnsb_idl_txn);
+    if (*ctrl_ctx->ovnsb_expected_cond_seqno ==
+            ovsdb_idl_get_condition_seqno(ovnsb_idl)) {
+        struct ed_type_datapaths_updated *dp_data = data;
+        if (!uuidset_is_empty(&dp_data->waiting_sb_cond_update)) {
+            uuidset_clear(&dp_data->waiting_sb_cond_update);
+            return EN_UPDATED;
+        }
+    }
+    return EN_UNCHANGED;
+}
+
 struct ed_type_ofctrl_is_connected {
     bool connected;
 };
@@ -1180,6 +1226,41 @@ en_ofctrl_is_connected_run(struct engine_node *node 
OVS_UNUSED, void *data)
     return EN_UNCHANGED;
 }
 
+struct ed_type_sb_cond_seqno {
+    unsigned int last_sb_cond_seqno;
+};
+
+static void *
+en_sb_cond_seqno_init(struct engine_node *node OVS_UNUSED,
+                      struct engine_arg *arg OVS_UNUSED)
+{
+    struct ed_type_sb_cond_seqno *data = xzalloc(sizeof *data);
+    return data;
+}
+
+static void en_sb_cond_seqno_cleanup(void *data OVS_UNUSED)
+{
+}
+
+static enum engine_node_state
+en_sb_cond_seqno_run(struct engine_node *node OVS_UNUSED, void *data)
+{
+    struct ed_type_sb_cond_seqno *sb_seqno_data = data;
+    struct ovsdb_idl_txn *ovnsb_idl_txn = engine_get_context()->ovnsb_idl_txn;
+    if (!ovnsb_idl_txn) {
+        return EN_UNCHANGED;
+    }
+
+    unsigned int curr_seqno =
+        ovsdb_idl_get_condition_seqno(ovsdb_idl_txn_get_idl(ovnsb_idl_txn));
+
+    if (sb_seqno_data->last_sb_cond_seqno != curr_seqno) {
+        sb_seqno_data->last_sb_cond_seqno = curr_seqno;
+        return EN_UPDATED;
+    }
+    return EN_UNCHANGED;
+}
+
 struct ed_type_if_status_mgr {
     const struct if_status_mgr *manager;
     const struct ovsrec_interface_table *iface_table;
@@ -5204,6 +5285,15 @@ controller_output_acl_id_handler(struct engine_node 
*node OVS_UNUSED,
     return EN_HANDLED_UPDATED;
 }
 
+static enum engine_input_handler_result
+controlller_output_datapaths_updated_handler(
+                                struct engine_node *node OVS_UNUSED,
+                                void *data OVS_UNUSED)
+{
+    return EN_HANDLED_UPDATED;
+}
+
+
 static enum engine_input_handler_result
 controller_output_route_exchange_handler(struct engine_node *node OVS_UNUSED,
                                          void *data OVS_UNUSED)
@@ -6745,6 +6835,56 @@ evpn_arp_vtep_binding_handler(struct engine_node *node, 
void *data OVS_UNUSED)
     return EN_UNHANDLED;
 }
 
+static enum engine_input_handler_result
+datapaths_updated_runtime_data_handler(struct engine_node *node,
+                                       void *data)
+{
+    enum engine_input_handler_result status = EN_HANDLED_UNCHANGED;
+    struct ed_type_datapaths_updated *dp_data = data;
+    struct ed_type_runtime_data *rt_data =
+        engine_get_input_data("runtime_data", node);
+    struct controller_engine_ctx *ctrl_ctx = engine_get_context()->client_ctx;
+    if (*ctrl_ctx->sb_monitor_all) {
+        if (!uuidset_is_empty(&dp_data->waiting_sb_cond_update)) {
+            uuidset_clear(&dp_data->waiting_sb_cond_update);
+            status = EN_HANDLED_UPDATED;
+        }
+        return status;
+    }
+
+    struct tracked_datapath *tdp;
+    HMAP_FOR_EACH_SAFE (tdp, node, &rt_data->tracked_dp_bindings) {
+        if (tdp->tracked_type == TRACKED_RESOURCE_NEW) {
+            uuidset_insert(&dp_data->waiting_sb_cond_update,
+                           &tdp->dp->header_.uuid);
+            status = EN_HANDLED_UPDATED;
+        }
+    }
+    return status;
+}
+
+static enum engine_input_handler_result
+datapaths_update_sb_cond_handler(struct engine_node *node OVS_UNUSED,
+                                 void *data)
+{
+    struct controller_engine_ctx *ctrl_ctx = engine_get_context()->client_ctx;
+    struct ovsdb_idl_txn *ovnsb_idl_txn = engine_get_context()->ovnsb_idl_txn;
+    if (!ovnsb_idl_txn) {
+        return EN_HANDLED_UNCHANGED;
+    }
+    struct ovsdb_idl *ovnsb_idl = ovsdb_idl_txn_get_idl(ovnsb_idl_txn);
+    if (*ctrl_ctx->ovnsb_expected_cond_seqno ==
+        ovsdb_idl_get_condition_seqno(ovnsb_idl)) {
+        struct ed_type_datapaths_updated *dp_data = data;
+
+        if (!uuidset_is_empty(&dp_data->waiting_sb_cond_update)) {
+            uuidset_clear(&dp_data->waiting_sb_cond_update);
+            return EN_HANDLED_UPDATED;
+        }
+    }
+    return EN_HANDLED_UNCHANGED;
+}
+
 /* Define engine node functions for nodes that represent SB tables.
  *
  * en_sb_<TABLE_NAME>_run()
@@ -6867,6 +7007,8 @@ static ENGINE_NODE(neighbor_exchange_status);
 static ENGINE_NODE(evpn_vtep_binding, CLEAR_TRACKED_DATA);
 static ENGINE_NODE(evpn_fdb, CLEAR_TRACKED_DATA);
 static ENGINE_NODE(evpn_arp, CLEAR_TRACKED_DATA);
+static ENGINE_NODE(datapaths_updated);
+static ENGINE_NODE(sb_cond_seqno);
 
 static void
 inc_proc_ovn_controller_init(
@@ -6889,6 +7031,8 @@ inc_proc_ovn_controller_init(
     engine_add_input(&en_template_vars, &en_sb_chassis_template_var,
                      template_vars_sb_chassis_template_var_handler);
 
+    engine_add_input(&en_datapaths_updated, &en_sb_cond_seqno,
+                     datapaths_update_sb_cond_handler);
     engine_add_input(&en_lb_data, &en_sb_load_balancer,
                      lb_data_sb_load_balancer_handler);
     engine_add_input(&en_lb_data, &en_template_vars,
@@ -6975,6 +7119,9 @@ inc_proc_ovn_controller_init(
     engine_add_input(&en_pflow_output, &en_sb_sb_global,
                      pflow_output_debug_handler);
 
+    engine_add_input(&en_datapaths_updated, &en_runtime_data,
+                     datapaths_updated_runtime_data_handler);
+
     engine_add_input(&en_northd_options, &en_sb_sb_global,
                      en_northd_options_sb_sb_global_handler);
 
@@ -7163,6 +7310,8 @@ inc_proc_ovn_controller_init(
     engine_add_input(&en_acl_id, &en_sb_acl_id, NULL);
     engine_add_input(&en_controller_output, &en_acl_id,
                      controller_output_acl_id_handler);
+    engine_add_input(&en_controller_output, &en_datapaths_updated,
+                     controlller_output_datapaths_updated_handler);
 
     struct engine_arg engine_arg = {
         .sb_idl = sb_idl_loop->idl,
@@ -7556,6 +7705,8 @@ main(int argc, char *argv[])
         engine_get_internal_data(&en_evpn_fdb);
     struct ed_type_evpn_arp *earp_data =
         engine_get_internal_data(&en_evpn_arp);
+    struct ed_type_datapaths_updated *dp_updated_data =
+        engine_get_internal_data(&en_datapaths_updated);
 
     ofctrl_init(&lflow_output_data->group_table,
                 &lflow_output_data->meter_table);
@@ -7655,10 +7806,13 @@ main(int argc, char *argv[])
     unsigned int ovs_cond_seqno = UINT_MAX;
     unsigned int ovnsb_cond_seqno = UINT_MAX;
     unsigned int ovnsb_expected_cond_seqno = UINT_MAX;
+    bool sb_monitor_all = false;
 
     struct controller_engine_ctx ctrl_engine_ctx = {
         .lflow_cache = lflow_cache_create(),
         .if_mgr = if_status_mgr_create(),
+        .ovnsb_expected_cond_seqno = &ovnsb_expected_cond_seqno,
+        .sb_monitor_all = &sb_monitor_all,
     };
     struct if_status_mgr *if_mgr = ctrl_engine_ctx.if_mgr;
 
@@ -7673,7 +7827,6 @@ main(int argc, char *argv[])
     /* Main loop. */
     int ovnsb_txn_status = 1;
     int ovs_txn_status = 1;
-    bool sb_monitor_all = false;
     struct tracked_acl_ids *tracked_acl_ids = NULL;
     while (!exit_args.exiting) {
         ovsrcu_quiesce_end();
@@ -8085,11 +8238,17 @@ main(int argc, char *argv[])
                         runtime_data ? &runtime_data->lbinding_data : NULL;
                     stopwatch_start(IF_STATUS_MGR_UPDATE_STOPWATCH_NAME,
                                     time_msec());
+
                     if_status_mgr_update(if_mgr, binding_data, chassis,
                                          ovsrec_interface_table_get(
                                                     ovs_idl_loop.idl),
                                          sbrec_port_binding_table_get(
                                                     ovnsb_idl_loop.idl),
+                                         runtime_data ?
+                                               &runtime_data->local_datapaths
+                                               : NULL,
+                                         &dp_updated_data->
+                                            waiting_sb_cond_update,
                                          !ovs_idl_txn,
                                          !ovnsb_idl_txn);
                     stopwatch_stop(IF_STATUS_MGR_UPDATE_STOPWATCH_NAME,
diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at
index c98de9bc4..f196213f0 100644
--- a/tests/ovn-controller.at
+++ b/tests/ovn-controller.at
@@ -3944,3 +3944,67 @@ OVN_CLEANUP([hv1], [hv2
 /already has encap ip.*cannot duplicate on/d])
 AT_CLEANUP
 ])
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([ovn-installed])
+ovn_start
+
+net_add n1
+sim_add hv1
+
+as hv1
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+ovn-appctl vlog/set dbg
+ovs-vsctl add-port br-int vif1 -- \
+    set Interface vif1 external-ids:iface-id=lsp1
+
+check ovn-nbctl ls-add ls1
+sleep_controller hv1
+check ovn-nbctl --wait=sb lsp-add ls1 lsp1 -- \
+                          lsp-set-addresses lsp1 "f0:00:00:00:00:01 10.0.0.1"
+
+sleep_sb
+wake_up_controller hv1
+
+# Wait for pflow for lsp1
+OVS_WAIT_UNTIL([
+    ofport=$(as hv1 ovs-vsctl --bare --columns ofport find Interface name=vif1)
+    echo "vif1 port=$ofport"
+    test -n "$ofport" && test 1 -le $(as hv1 ovs-ofctl dump-flows br-int | 
grep -c in_port=$ofport)
+])
+
+# If ovn-installed in ovs, all flows should be installed.
+# In that case, there should be at least one flow with lsp1 address.
+OVS_WAIT_UNTIL([
+    ovn_installed=$(as hv1 ovs-vsctl get Interface vif1 
external_ids:ovn-installed)
+    echo $ovn_installed
+    flow_count=$(as hv1 ovs-ofctl dump-flows br-int | grep -Fc "10.0.0.1")
+    # for the monitor-all=true case the flow gets installed because 
ovn-controller is monitoring all
+    # tables in OVN_SOUTHBOUND.
+    if test -n "$ovn_installed"; then
+        test $flow_count -ge 1
+    else
+        true
+    fi
+])
+
+wake_up_sb
+# After the southbound db has woken up and can send the update to the
+# ovn-controller not monitoring all tables in the southbound db it
+# should be able to install the interface.
+OVS_WAIT_UNTIL([
+    ovn_installed=$(as hv1 ovs-vsctl get Interface vif1 
external_ids:ovn-installed)
+    flow_count=$(as hv1 ovs-ofctl dump-flows br-int | grep -Fc "10.0.0.1")
+    echo "installed=$ovn_installed, count=$flow_count"
+    if test -n "$ovn_installed"; then
+        test $flow_count -ge 1
+    else
+        false
+    fi
+])
+wait_for_ports_up
+
+OVN_CLEANUP([hv1])
+AT_CLEANUP
+])
diff --git a/tests/ovn-inc-proc-graph-dump.at b/tests/ovn-inc-proc-graph-dump.at
index 178310978..bd82f0015 100644
--- a/tests/ovn-inc-proc-graph-dump.at
+++ b/tests/ovn-inc-proc-graph-dump.at
@@ -478,6 +478,10 @@ digraph "Incremental-Processing-Engine" {
        SB_acl_id [[style=filled, shape=box, fillcolor=white, 
label="SB_acl_id"]];
        acl_id [[style=filled, shape=box, fillcolor=white, label="acl_id"]];
        SB_acl_id -> acl_id [[label=""]];
+       sb_cond_seqno [[style=filled, shape=box, fillcolor=white, 
label="sb_cond_seqno"]];
+       datapaths_updated [[style=filled, shape=box, fillcolor=white, 
label="datapaths_updated"]];
+       sb_cond_seqno -> datapaths_updated 
[[label="datapaths_update_sb_cond_handler"]];
+       runtime_data -> datapaths_updated 
[[label="datapaths_updated_runtime_data_handler"]];
        controller_output [[style=filled, shape=box, fillcolor=white, 
label="controller_output"]];
        dns_cache -> controller_output [[label=""]];
        lflow_output -> controller_output 
[[label="controller_output_lflow_output_handler"]];
@@ -487,6 +491,7 @@ digraph "Incremental-Processing-Engine" {
        route_exchange -> controller_output 
[[label="controller_output_route_exchange_handler"]];
        garp_rarp -> controller_output 
[[label="controller_output_garp_rarp_handler"]];
        acl_id -> controller_output 
[[label="controller_output_acl_id_handler"]];
+       datapaths_updated -> controller_output 
[[label="controlller_output_datapaths_updated_handler"]];
 }
 ])
 AT_CLEANUP
-- 
2.54.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to