This commit introduces the ability to dump a (partial) representation
of the incremental processing graph.  It's currently supported for
ovn-northd and ovn-controller through a command-line argument,
--dump-inc-proc-graph[=<i-p-node>].

If the command line argument is present the binary (ovn-northd or
ovn-controller) just dumps a representation of the incremental
processing graph in DOT format to stdout.  The binary then exits.

If the '<i-p-node>' optional argument value is present the
representation only includes nodes up to (and including) '<i-p-node>'.

The goal of the feature is to make lives of the developers/maintainers
easier when writing or debugging features that require incremental
processing.

Reported-at: https://issues.redhat.com/browse/FDP-2646
Assisted-by: gemini-cli, with model: gemini-3-pro-preview
Signed-off-by: Dumitru Ceara <[email protected]>
---
 build-aux/initial-tab-whitelist  |   1 +
 controller/ovn-controller.c      |  28 ++
 lib/inc-proc-eng.c               |  64 +++-
 lib/inc-proc-eng.h               |  23 +-
 northd/ovn-northd.c              |  25 ++
 tests/automake.mk                |   3 +-
 tests/ovn-inc-proc-graph-dump.at | 513 +++++++++++++++++++++++++++++++
 tests/testsuite.at               |   1 +
 8 files changed, 646 insertions(+), 12 deletions(-)
 create mode 100644 tests/ovn-inc-proc-graph-dump.at

diff --git a/build-aux/initial-tab-whitelist b/build-aux/initial-tab-whitelist
index eb5c1a23a3..2dd02b6579 100644
--- a/build-aux/initial-tab-whitelist
+++ b/build-aux/initial-tab-whitelist
@@ -9,3 +9,4 @@
 ^debian/rules$
 ^\.gitmodules$
 ^utilities/containers/Makefile
+^tests/ovn-inc-proc-graph-dump.at
diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
index 52fc69f31f..5b7652fbf9 100644
--- a/controller/ovn-controller.c
+++ b/controller/ovn-controller.c
@@ -8081,6 +8081,23 @@ loop_done:
     exit(retval);
 }
 
+static void
+inc_proc_graph_dump(const char *end_node)
+{
+    struct ovsdb_idl_loop ovs_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
+        ovsdb_idl_create_unconnected(&ovsrec_idl_class, true));
+    struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
+        ovsdb_idl_create_unconnected(&sbrec_idl_class, true));
+
+    inc_proc_ovn_controller_init(&ovnsb_idl_loop, &ovs_idl_loop,
+                                 NULL, NULL, NULL, NULL, NULL,
+                                 NULL, NULL, NULL, NULL);
+    engine_dump_graph(end_node);
+
+    ovsdb_idl_loop_destroy(&ovs_idl_loop);
+    ovsdb_idl_loop_destroy(&ovnsb_idl_loop);
+}
+
 static char *
 parse_options(int argc, char *argv[])
 {
@@ -8091,6 +8108,7 @@ parse_options(int argc, char *argv[])
         OVN_DAEMON_OPTION_ENUMS,
         SSL_OPTION_ENUMS,
         OPT_ENABLE_DUMMY_VIF_PLUG,
+        OPT_DUMP_INC_PROC_GRAPH,
     };
 
     static struct option long_options[] = {
@@ -8105,6 +8123,8 @@ parse_options(int argc, char *argv[])
         {"chassis", required_argument, NULL, 'n'},
         {"enable-dummy-vif-plug", no_argument, NULL,
          OPT_ENABLE_DUMMY_VIF_PLUG},
+        {"dump-inc-proc-graph", optional_argument, NULL,
+         OPT_DUMP_INC_PROC_GRAPH},
         {NULL, 0, NULL, 0}
     };
     char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
@@ -8173,6 +8193,14 @@ parse_options(int argc, char *argv[])
             vif_plug_dummy_enable();
             break;
 
+        /* --dump-inc-proc-graph[=<i-p-node>]: Whether to dump the I-P engine
+         * graph representation in DOT format to stdout.  Optionally only up
+         * to <i-p-node>.
+         */
+        case OPT_DUMP_INC_PROC_GRAPH:
+            inc_proc_graph_dump(optarg);
+            exit(EXIT_SUCCESS);
+
         case 'n':
             free(cli_system_id);
             cli_system_id = xstrdup(optarg);
diff --git a/lib/inc-proc-eng.c b/lib/inc-proc-eng.c
index bd366cb906..839f6cfcaf 100644
--- a/lib/inc-proc-eng.c
+++ b/lib/inc-proc-eng.c
@@ -32,6 +32,7 @@
 #include "timeval.h"
 #include "unixctl.h"
 #include "vec.h"
+#include "sset.h"
 
 VLOG_DEFINE_THIS_MODULE(inc_proc_eng);
 
@@ -266,24 +267,27 @@ engine_get_input_data(const char *input_name, struct 
engine_node *node)
 }
 
 void
-engine_add_input(struct engine_node *node, struct engine_node *input,
-                 enum engine_input_handler_result (*change_handler)
-                     (struct engine_node *, void *))
+engine_add_input_impl(struct engine_node *node, struct engine_node *input,
+                      enum engine_input_handler_result (*change_handler)
+                          (struct engine_node *, void *),
+                      const char *change_handler_name)
 {
     ovs_assert(node->n_inputs < ENGINE_MAX_INPUT);
     node->inputs[node->n_inputs].node = input;
     node->inputs[node->n_inputs].change_handler = change_handler;
+    node->inputs[node->n_inputs].change_handler_name = change_handler_name;
     node->n_inputs ++;
 }
 
 void
-engine_add_input_with_compute_debug(
+engine_add_input_with_compute_debug_impl(
         struct engine_node *node, struct engine_node *input,
         enum engine_input_handler_result (*change_handler)
             (struct engine_node *, void *),
-        void (*get_compute_failure_info)(struct engine_node *))
+        void (*get_compute_failure_info)(struct engine_node *),
+        const char *change_handler_name)
 {
-    engine_add_input(node, input, change_handler);
+    engine_add_input_impl(node, input, change_handler, change_handler_name);
     node->get_compute_failure_info = get_compute_failure_info;
 }
 
@@ -611,3 +615,51 @@ engine_trigger_recompute(void)
     VLOG_INFO("User triggered force recompute.");
     engine_set_force_recompute_immediate();
 }
+
+static void
+engine_dump_node(struct engine_node *node, struct sset *visited_nodes)
+{
+    if (sset_contains(visited_nodes, node->name)) {
+        return;
+    }
+    sset_add(visited_nodes, node->name);
+
+    printf("\t%s [style=filled, shape=box, fillcolor=white, "
+           "label=\"%s\"];\n",
+           node->name, node->name);
+    for (size_t i = 0; i < node->n_inputs; i++) {
+        const char *label = node->inputs[i].change_handler
+                            ? node->inputs[i].change_handler_name
+                            : NULL;
+
+        printf("\t%s -> %s [label=\"%s\"];\n",
+               node->inputs[i].node->name, node->name,
+               label ? label : "");
+
+        engine_dump_node(node->inputs[i].node, visited_nodes);
+    }
+}
+
+void
+engine_dump_graph(const char *node_name)
+{
+    printf("digraph \"Incremental-Processing-Engine\" {\n");
+    printf("\trankdir=LR;\n");
+
+    struct sset visited_nodes = SSET_INITIALIZER(&visited_nodes);
+    struct engine_node *node;
+    VECTOR_FOR_EACH (&engine_nodes, node) {
+        if (node_name && strcmp(node->name, node_name)) {
+            continue;
+        }
+
+        engine_dump_node(node, &visited_nodes);
+
+        if (node_name) {
+            break;
+        }
+    }
+
+    sset_destroy(&visited_nodes);
+    printf("}\n");
+}
diff --git a/lib/inc-proc-eng.h b/lib/inc-proc-eng.h
index 6a9e39efe6..02eeb46fe8 100644
--- a/lib/inc-proc-eng.h
+++ b/lib/inc-proc-eng.h
@@ -209,6 +209,7 @@ struct engine_node_input {
      * handler needs to use the txn pointers returned by engine_get_context(),
      * and the pointers are NULL, the change handler MUST return EN_UNHANDLED.
      */
+    const char *change_handler_name;
     enum engine_input_handler_result (*change_handler)
         (struct engine_node *node, void *data);
 };
@@ -315,14 +316,24 @@ void *engine_get_input_data(const char *input_name, 
struct engine_node *);
  * which can be NULL. If the change_handler is NULL, the engine will not
  * be able to process the change incrementally, and will fall back to call
  * the run method to recompute. */
-void engine_add_input(struct engine_node *node, struct engine_node *input,
-                      enum engine_input_handler_result (*change_handler)
-                          (struct engine_node *, void *));
-void engine_add_input_with_compute_debug(
+void engine_add_input_impl(struct engine_node *node, struct engine_node *input,
+                           enum engine_input_handler_result (*change_handler)
+                               (struct engine_node *, void *),
+                           const char *change_handler_name);
+#define engine_add_input(node, input, change_handler) \
+    engine_add_input_impl(node, input, change_handler, #change_handler)
+
+void engine_add_input_with_compute_debug_impl(
         struct engine_node *node, struct engine_node *input,
         enum engine_input_handler_result (*change_handler)
             (struct engine_node *, void *),
-        void (*get_compute_failure_info)(struct engine_node *));
+        void (*get_compute_failure_info)(struct engine_node *),
+        const char *change_handler_name);
+#define engine_add_input_with_compute_debug(node, input, change_handler, \
+                                            get_failure_info) \
+    engine_add_input_with_compute_debug_impl(node, input, change_handler, \
+                                             get_failure_info,            \
+                                             #change_handler)
 
 /* Force the engine to recompute everything. It is used
  * in circumstances when we are not sure there is change or not, or
@@ -330,6 +341,8 @@ void engine_add_input_with_compute_debug(
  * iteration, and the change can't be tracked across iterations. */
 void engine_set_force_recompute(void);
 
+void engine_dump_graph(const char *node_name);
+
 /* Same as "engine_set_force_recompute()", but the poll_loop is woken up
  * immediately and the next engine run is not delayed. */
 void engine_set_force_recompute_immediate(void);
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index 52a3c78832..f718c81afb 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -590,6 +590,20 @@ update_sequence_numbers(int64_t loop_start_time,
         nbrec_nb_global_set_hv_cfg_timestamp(nb, hv_cfg_ts);
     }
 }
+
+static void inc_proc_graph_dump(const char *end_node)
+{
+    struct ovsdb_idl_loop ovnnb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
+        ovsdb_idl_create_unconnected(&nbrec_idl_class, true));
+    struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
+        ovsdb_idl_create_unconnected(&sbrec_idl_class, true));
+
+    inc_proc_northd_init(&ovnnb_idl_loop, &ovnsb_idl_loop);
+    engine_dump_graph(end_node);
+
+    ovsdb_idl_loop_destroy(&ovnnb_idl_loop);
+    ovsdb_idl_loop_destroy(&ovnsb_idl_loop);
+}
 
 static void
 usage(void)
@@ -625,6 +639,7 @@ parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED,
         SSL_OPTION_ENUMS,
         OPT_DRY_RUN,
         OPT_N_THREADS,
+        OPT_DUMP_INC_PROC_GRAPH,
     };
     static const struct option long_options[] = {
         {"ovnsb-db", required_argument, NULL, 'd'},
@@ -635,6 +650,8 @@ parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED,
         {"version", no_argument, NULL, 'V'},
         {"dry-run", no_argument, NULL, OPT_DRY_RUN},
         {"n-threads", required_argument, NULL, OPT_N_THREADS},
+        {"dump-inc-proc-graph", optional_argument, NULL,
+         OPT_DUMP_INC_PROC_GRAPH},
         OVN_DAEMON_LONG_OPTIONS,
         VLOG_LONG_OPTIONS,
         STREAM_SSL_LONG_OPTIONS,
@@ -727,6 +744,14 @@ parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED,
             *paused = true;
             break;
 
+        /* --dump-inc-proc-graph[=<i-p-node>]: Whether to dump the I-P engine
+         * graph representation in DOT format to stdout.  Optionally only up
+         * to <i-p-node>.
+         */
+        case OPT_DUMP_INC_PROC_GRAPH:
+            inc_proc_graph_dump(optarg);
+            exit(EXIT_SUCCESS);
+
         default:
             break;
         }
diff --git a/tests/automake.mk b/tests/automake.mk
index 8ae3105478..18472d9cc0 100644
--- a/tests/automake.mk
+++ b/tests/automake.mk
@@ -47,7 +47,8 @@ TESTSUITE_AT = \
        tests/ovn-ipsec.at \
        tests/ovn-vif-plug.at \
        tests/ovn-util.at \
-       tests/ovn-br-controller.at
+       tests/ovn-br-controller.at \
+       tests/ovn-inc-proc-graph-dump.at
 
 SYSTEM_DPDK_TESTSUITE_AT = \
        tests/system-dpdk-testsuite.at \
diff --git a/tests/ovn-inc-proc-graph-dump.at b/tests/ovn-inc-proc-graph-dump.at
new file mode 100644
index 0000000000..1775cf5d5e
--- /dev/null
+++ b/tests/ovn-inc-proc-graph-dump.at
@@ -0,0 +1,513 @@
+AT_BANNER([OVN Incremental Processing Engine Graph Dump])
+
+AT_SETUP([northd: dump full incremental processing graph])
+AT_KEYWORDS([inc-proc-graph])
+AT_CHECK([ovn-northd --dump-inc-proc-graph], [0], [dnl
+digraph "Incremental-Processing-Engine" {
+       rankdir=LR;
+       NB_acl [[style=filled, shape=box, fillcolor=white, label="NB_acl"]];
+       SB_acl_id [[style=filled, shape=box, fillcolor=white, 
label="SB_acl_id"]];
+       acl_id [[style=filled, shape=box, fillcolor=white, label="acl_id"]];
+       NB_acl -> acl_id [[label=""]];
+       SB_acl_id -> acl_id [[label=""]];
+       NB_mirror [[style=filled, shape=box, fillcolor=white, 
label="NB_mirror"]];
+       NB_mirror_rule [[style=filled, shape=box, fillcolor=white, 
label="NB_mirror_rule"]];
+       NB_static_mac_binding [[style=filled, shape=box, fillcolor=white, 
label="NB_static_mac_binding"]];
+       NB_chassis_template_var [[style=filled, shape=box, fillcolor=white, 
label="NB_chassis_template_var"]];
+       NB_network_function [[style=filled, shape=box, fillcolor=white, 
label="NB_network_function"]];
+       NB_network_function_group [[style=filled, shape=box, fillcolor=white, 
label="NB_network_function_group"]];
+       SB_chassis [[style=filled, shape=box, fillcolor=white, 
label="SB_chassis"]];
+       SB_mirror [[style=filled, shape=box, fillcolor=white, 
label="SB_mirror"]];
+       SB_meter [[style=filled, shape=box, fillcolor=white, label="SB_meter"]];
+       SB_dns [[style=filled, shape=box, fillcolor=white, label="SB_dns"]];
+       SB_ha_chassis_group [[style=filled, shape=box, fillcolor=white, 
label="SB_ha_chassis_group"]];
+       SB_service_monitor [[style=filled, shape=box, fillcolor=white, 
label="SB_service_monitor"]];
+       SB_static_mac_binding [[style=filled, shape=box, fillcolor=white, 
label="SB_static_mac_binding"]];
+       SB_chassis_template_var [[style=filled, shape=box, fillcolor=white, 
label="SB_chassis_template_var"]];
+       ic_learned_svc_monitors [[style=filled, shape=box, fillcolor=white, 
label="ic_learned_svc_monitors"]];
+       SB_service_monitor -> ic_learned_svc_monitors [[label=""]];
+       SB_fdb [[style=filled, shape=box, fillcolor=white, label="SB_fdb"]];
+       NB_nb_global [[style=filled, shape=box, fillcolor=white, 
label="NB_nb_global"]];
+       NB_logical_switch [[style=filled, shape=box, fillcolor=white, 
label="NB_logical_switch"]];
+       SB_sb_global [[style=filled, shape=box, fillcolor=white, 
label="SB_sb_global"]];
+       NB_sampling_app [[style=filled, shape=box, fillcolor=white, 
label="NB_sampling_app"]];
+       sampling_app [[style=filled, shape=box, fillcolor=white, 
label="sampling_app"]];
+       NB_sampling_app -> sampling_app [[label=""]];
+       global_config [[style=filled, shape=box, fillcolor=white, 
label="global_config"]];
+       NB_nb_global -> global_config 
[[label="global_config_nb_global_handler"]];
+       NB_logical_switch -> global_config 
[[label="global_config_nb_logical_switch_handler"]];
+       SB_sb_global -> global_config 
[[label="global_config_sb_global_handler"]];
+       SB_chassis -> global_config 
[[label="global_config_sb_chassis_handler"]];
+       sampling_app -> global_config [[label=""]];
+       SB_mac_binding [[style=filled, shape=box, fillcolor=white, 
label="SB_mac_binding"]];
+       SB_port_binding [[style=filled, shape=box, fillcolor=white, 
label="SB_port_binding"]];
+       SB_datapath_binding [[style=filled, shape=box, fillcolor=white, 
label="SB_datapath_binding"]];
+       datapath_logical_switch [[style=filled, shape=box, fillcolor=white, 
label="datapath_logical_switch"]];
+       NB_logical_switch -> datapath_logical_switch 
[[label="datapath_logical_switch_handler"]];
+       global_config -> datapath_logical_switch 
[[label="datapath_logical_switch_handler"]];
+       NB_logical_router [[style=filled, shape=box, fillcolor=white, 
label="NB_logical_router"]];
+       datapath_logical_router [[style=filled, shape=box, fillcolor=white, 
label="datapath_logical_router"]];
+       NB_logical_router -> datapath_logical_router 
[[label="en_datapath_logical_router_logical_router_handler"]];
+       datapath_sync [[style=filled, shape=box, fillcolor=white, 
label="datapath_sync"]];
+       global_config -> datapath_sync 
[[label="datapath_sync_global_config_handler"]];
+       SB_datapath_binding -> datapath_sync 
[[label="datapath_sync_sb_datapath_binding"]];
+       datapath_logical_switch -> datapath_sync 
[[label="datapath_sync_logical_switch_handler"]];
+       datapath_logical_router -> datapath_sync 
[[label="datapath_sync_logical_router_handler"]];
+       datapath_synced_logical_switch [[style=filled, shape=box, 
fillcolor=white, label="datapath_synced_logical_switch"]];
+       datapath_sync -> datapath_synced_logical_switch 
[[label="en_datapath_synced_logical_switch_datapath_sync_handler"]];
+       datapath_synced_logical_router [[style=filled, shape=box, 
fillcolor=white, label="datapath_synced_logical_router"]];
+       datapath_sync -> datapath_synced_logical_router 
[[label="en_datapath_synced_logical_router_datapath_sync_handler"]];
+       NB_load_balancer [[style=filled, shape=box, fillcolor=white, 
label="NB_load_balancer"]];
+       NB_load_balancer_group [[style=filled, shape=box, fillcolor=white, 
label="NB_load_balancer_group"]];
+       lb_data [[style=filled, shape=box, fillcolor=white, label="lb_data"]];
+       NB_load_balancer -> lb_data [[label="lb_data_load_balancer_handler"]];
+       NB_load_balancer_group -> lb_data 
[[label="lb_data_load_balancer_group_handler"]];
+       datapath_synced_logical_switch -> lb_data 
[[label="lb_data_synced_logical_switch_handler"]];
+       datapath_synced_logical_router -> lb_data 
[[label="lb_data_synced_logical_router_handler"]];
+       NB_port_group [[style=filled, shape=box, fillcolor=white, 
label="NB_port_group"]];
+       SB_ip_multicast [[style=filled, shape=box, fillcolor=white, 
label="SB_ip_multicast"]];
+       northd [[style=filled, shape=box, fillcolor=white, label="northd"]];
+       NB_mirror -> northd [[label=""]];
+       NB_mirror_rule -> northd [[label=""]];
+       NB_static_mac_binding -> northd [[label=""]];
+       NB_chassis_template_var -> northd [[label=""]];
+       NB_network_function -> northd [[label=""]];
+       NB_network_function_group -> northd [[label=""]];
+       SB_chassis -> northd [[label=""]];
+       SB_mirror -> northd [[label=""]];
+       SB_meter -> northd [[label=""]];
+       SB_dns -> northd [[label=""]];
+       SB_ha_chassis_group -> northd [[label=""]];
+       SB_service_monitor -> northd [[label=""]];
+       SB_static_mac_binding -> northd [[label=""]];
+       SB_chassis_template_var -> northd [[label=""]];
+       ic_learned_svc_monitors -> northd [[label=""]];
+       SB_fdb -> northd [[label="northd_sb_fdb_change_handler"]];
+       global_config -> northd [[label="northd_global_config_handler"]];
+       SB_mac_binding -> northd [[label="engine_noop_handler"]];
+       SB_port_binding -> northd [[label="northd_sb_port_binding_handler"]];
+       datapath_synced_logical_switch -> northd 
[[label="northd_nb_logical_switch_handler"]];
+       datapath_synced_logical_router -> northd 
[[label="northd_nb_logical_router_handler"]];
+       lb_data -> northd [[label="northd_lb_data_handler"]];
+       NB_port_group -> northd [[label="northd_nb_port_group_handler"]];
+       SB_ip_multicast -> northd [[label="engine_noop_handler"]];
+       sync_from_sb [[style=filled, shape=box, fillcolor=white, 
label="sync_from_sb"]];
+       northd -> sync_from_sb [[label="sync_from_sb_northd_handler"]];
+       SB_port_binding -> sync_from_sb [[label=""]];
+       SB_ha_chassis_group -> sync_from_sb [[label=""]];
+       lr_nat [[style=filled, shape=box, fillcolor=white, label="lr_nat"]];
+       northd -> lr_nat [[label="lr_nat_northd_handler"]];
+       lr_stateful [[style=filled, shape=box, fillcolor=white, 
label="lr_stateful"]];
+       northd -> lr_stateful [[label="lr_stateful_northd_handler"]];
+       lr_nat -> lr_stateful [[label="lr_stateful_lr_nat_handler"]];
+       lb_data -> lr_stateful [[label="lr_stateful_lb_data_handler"]];
+       SB_address_set [[style=filled, shape=box, fillcolor=white, 
label="SB_address_set"]];
+       NB_address_set [[style=filled, shape=box, fillcolor=white, 
label="NB_address_set"]];
+       sync_to_sb_addr_set [[style=filled, shape=box, fillcolor=white, 
label="sync_to_sb_addr_set"]];
+       northd -> sync_to_sb_addr_set [[label=""]];
+       lr_stateful -> sync_to_sb_addr_set [[label=""]];
+       SB_address_set -> sync_to_sb_addr_set [[label=""]];
+       NB_address_set -> sync_to_sb_addr_set 
[[label="sync_to_sb_addr_set_nb_address_set_handler"]];
+       NB_port_group -> sync_to_sb_addr_set 
[[label="sync_to_sb_addr_set_nb_port_group_handler"]];
+       global_config -> sync_to_sb_addr_set 
[[label="node_global_config_handler"]];
+       SB_port_group [[style=filled, shape=box, fillcolor=white, 
label="SB_port_group"]];
+       port_group [[style=filled, shape=box, fillcolor=white, 
label="port_group"]];
+       NB_port_group -> port_group 
[[label="port_group_nb_port_group_handler"]];
+       SB_port_group -> port_group [[label=""]];
+       northd -> port_group [[label="engine_noop_handler"]];
+       NB_meter [[style=filled, shape=box, fillcolor=white, label="NB_meter"]];
+       sync_meters [[style=filled, shape=box, fillcolor=white, 
label="sync_meters"]];
+       NB_acl -> sync_meters [[label="sync_meters_nb_acl_handler"]];
+       NB_meter -> sync_meters [[label=""]];
+       SB_meter -> sync_meters [[label=""]];
+       SB_load_balancer [[style=filled, shape=box, fillcolor=white, 
label="SB_load_balancer"]];
+       SB_logical_dp_group [[style=filled, shape=box, fillcolor=white, 
label="SB_logical_dp_group"]];
+       sync_to_sb_lb [[style=filled, shape=box, fillcolor=white, 
label="sync_to_sb_lb"]];
+       global_config -> sync_to_sb_lb [[label="node_global_config_handler"]];
+       northd -> sync_to_sb_lb [[label="sync_to_sb_lb_northd_handler"]];
+       SB_load_balancer -> sync_to_sb_lb 
[[label="sync_to_sb_lb_sb_load_balancer"]];
+       SB_logical_dp_group -> sync_to_sb_lb [[label=""]];
+       sync_to_sb_pb [[style=filled, shape=box, fillcolor=white, 
label="sync_to_sb_pb"]];
+       northd -> sync_to_sb_pb [[label="sync_to_sb_pb_northd_handler"]];
+       lr_stateful -> sync_to_sb_pb 
[[label="sync_to_sb_pb_lr_stateful_handler"]];
+       sync_to_sb [[style=filled, shape=box, fillcolor=white, 
label="sync_to_sb"]];
+       sync_to_sb_addr_set -> sync_to_sb [[label=""]];
+       port_group -> sync_to_sb [[label=""]];
+       sync_meters -> sync_to_sb [[label=""]];
+       sync_to_sb_lb -> sync_to_sb [[label=""]];
+       sync_to_sb_pb -> sync_to_sb [[label=""]];
+       SB_logical_flow [[style=filled, shape=box, fillcolor=white, 
label="SB_logical_flow"]];
+       SB_multicast_group [[style=filled, shape=box, fillcolor=white, 
label="SB_multicast_group"]];
+       NB_bfd [[style=filled, shape=box, fillcolor=white, label="NB_bfd"]];
+       SB_bfd [[style=filled, shape=box, fillcolor=white, label="SB_bfd"]];
+       bfd [[style=filled, shape=box, fillcolor=white, label="bfd"]];
+       NB_bfd -> bfd [[label=""]];
+       SB_bfd -> bfd [[label=""]];
+       routes [[style=filled, shape=box, fillcolor=white, label="routes"]];
+       bfd -> routes [[label=""]];
+       northd -> routes [[label="routes_northd_change_handler"]];
+       route_policies [[style=filled, shape=box, fillcolor=white, 
label="route_policies"]];
+       bfd -> route_policies [[label=""]];
+       northd -> route_policies 
[[label="route_policies_northd_change_handler"]];
+       bfd_sync [[style=filled, shape=box, fillcolor=white, label="bfd_sync"]];
+       bfd -> bfd_sync [[label=""]];
+       NB_bfd -> bfd_sync [[label=""]];
+       routes -> bfd_sync [[label=""]];
+       route_policies -> bfd_sync [[label=""]];
+       northd -> bfd_sync [[label="bfd_sync_northd_change_handler"]];
+       SB_learned_route [[style=filled, shape=box, fillcolor=white, 
label="SB_learned_route"]];
+       learned_route_sync [[style=filled, shape=box, fillcolor=white, 
label="learned_route_sync"]];
+       SB_learned_route -> learned_route_sync 
[[label="learned_route_sync_sb_learned_route_change_handler"]];
+       northd -> learned_route_sync 
[[label="learned_route_sync_northd_change_handler"]];
+       group_ecmp_route [[style=filled, shape=box, fillcolor=white, 
label="group_ecmp_route"]];
+       routes -> group_ecmp_route [[label=""]];
+       learned_route_sync -> group_ecmp_route 
[[label="group_ecmp_route_learned_route_change_handler"]];
+       ls_stateful [[style=filled, shape=box, fillcolor=white, 
label="ls_stateful"]];
+       northd -> ls_stateful [[label="ls_stateful_northd_handler"]];
+       port_group -> ls_stateful [[label="ls_stateful_port_group_handler"]];
+       NB_acl -> ls_stateful [[label="ls_stateful_acl_handler"]];
+       SB_igmp_group [[style=filled, shape=box, fillcolor=white, 
label="SB_igmp_group"]];
+       multicast_igmp [[style=filled, shape=box, fillcolor=white, 
label="multicast_igmp"]];
+       northd -> multicast_igmp [[label="multicast_igmp_northd_handler"]];
+       SB_multicast_group -> multicast_igmp [[label=""]];
+       SB_igmp_group -> multicast_igmp [[label=""]];
+       lflow [[style=filled, shape=box, fillcolor=white, label="lflow"]];
+       sync_meters -> lflow [[label=""]];
+       SB_logical_flow -> lflow [[label=""]];
+       SB_multicast_group -> lflow [[label=""]];
+       SB_logical_dp_group -> lflow [[label=""]];
+       bfd_sync -> lflow [[label=""]];
+       route_policies -> lflow [[label=""]];
+       routes -> lflow [[label=""]];
+       group_ecmp_route -> lflow 
[[label="lflow_group_ecmp_route_change_handler"]];
+       global_config -> lflow [[label="node_global_config_handler"]];
+       sampling_app -> lflow [[label=""]];
+       northd -> lflow [[label="lflow_northd_handler"]];
+       port_group -> lflow [[label="engine_noop_handler"]];
+       lr_stateful -> lflow [[label="lflow_lr_stateful_handler"]];
+       ls_stateful -> lflow [[label="lflow_ls_stateful_handler"]];
+       multicast_igmp -> lflow [[label="lflow_multicast_igmp_handler"]];
+       SB_acl_id -> lflow [[label=""]];
+       ic_learned_svc_monitors -> lflow 
[[label="lflow_ic_learned_svc_mons_handler"]];
+       mac_binding_aging_waker [[style=filled, shape=box, fillcolor=white, 
label="mac_binding_aging_waker"]];
+       mac_binding_aging [[style=filled, shape=box, fillcolor=white, 
label="mac_binding_aging"]];
+       SB_mac_binding -> mac_binding_aging [[label=""]];
+       northd -> mac_binding_aging [[label=""]];
+       mac_binding_aging_waker -> mac_binding_aging [[label=""]];
+       global_config -> mac_binding_aging 
[[label="node_global_config_handler"]];
+       fdb_aging_waker [[style=filled, shape=box, fillcolor=white, 
label="fdb_aging_waker"]];
+       fdb_aging [[style=filled, shape=box, fillcolor=white, 
label="fdb_aging"]];
+       SB_fdb -> fdb_aging [[label=""]];
+       northd -> fdb_aging [[label=""]];
+       fdb_aging_waker -> fdb_aging [[label=""]];
+       global_config -> fdb_aging [[label="node_global_config_handler"]];
+       SB_ecmp_nexthop [[style=filled, shape=box, fillcolor=white, 
label="SB_ecmp_nexthop"]];
+       ecmp_nexthop [[style=filled, shape=box, fillcolor=white, 
label="ecmp_nexthop"]];
+       global_config -> ecmp_nexthop [[label=""]];
+       routes -> ecmp_nexthop [[label=""]];
+       SB_ecmp_nexthop -> ecmp_nexthop [[label=""]];
+       SB_port_binding -> ecmp_nexthop [[label=""]];
+       SB_mac_binding -> ecmp_nexthop 
[[label="ecmp_nexthop_mac_binding_handler"]];
+       dynamic_routes [[style=filled, shape=box, fillcolor=white, 
label="dynamic_routes"]];
+       lr_stateful -> dynamic_routes [[label=""]];
+       northd -> dynamic_routes [[label="engine_noop_handler"]];
+       SB_advertised_route [[style=filled, shape=box, fillcolor=white, 
label="SB_advertised_route"]];
+       advertised_route_sync [[style=filled, shape=box, fillcolor=white, 
label="advertised_route_sync"]];
+       routes -> advertised_route_sync [[label=""]];
+       dynamic_routes -> advertised_route_sync [[label=""]];
+       SB_advertised_route -> advertised_route_sync [[label=""]];
+       lr_stateful -> advertised_route_sync 
[[label="advertised_route_sync_lr_stateful_change_handler"]];
+       northd -> advertised_route_sync 
[[label="advertised_route_sync_northd_change_handler"]];
+       SB_advertised_mac_binding [[style=filled, shape=box, fillcolor=white, 
label="SB_advertised_mac_binding"]];
+       advertised_mac_binding_sync [[style=filled, shape=box, fillcolor=white, 
label="advertised_mac_binding_sync"]];
+       SB_port_binding -> advertised_mac_binding_sync [[label=""]];
+       SB_advertised_mac_binding -> advertised_mac_binding_sync [[label=""]];
+       northd -> advertised_mac_binding_sync [[label="engine_noop_handler"]];
+       northd_output [[style=filled, shape=box, fillcolor=white, 
label="northd_output"]];
+       acl_id -> northd_output [[label=""]];
+       sync_from_sb -> northd_output [[label=""]];
+       sync_to_sb -> northd_output 
[[label="northd_output_sync_to_sb_handler"]];
+       lflow -> northd_output [[label="northd_output_lflow_handler"]];
+       mac_binding_aging -> northd_output 
[[label="northd_output_mac_binding_aging_handler"]];
+       fdb_aging -> northd_output [[label="northd_output_fdb_aging_handler"]];
+       ecmp_nexthop -> northd_output 
[[label="northd_output_ecmp_nexthop_handler"]];
+       acl_id -> northd_output [[label="northd_output_acl_id_handler"]];
+       advertised_route_sync -> northd_output 
[[label="northd_output_advertised_route_sync_handler"]];
+       advertised_mac_binding_sync -> northd_output 
[[label="northd_output_advertised_mac_binding_sync_handler"]];
+}
+])
+AT_CLEANUP
+
+AT_SETUP([northd: dump partial incremental processing graph (up to 
datapath_sync)])
+AT_KEYWORDS([inc-proc-graph])
+AT_CHECK([ovn-northd --dump-inc-proc-graph=datapath_sync], [0], [dnl
+digraph "Incremental-Processing-Engine" {
+       rankdir=LR;
+       datapath_sync [[style=filled, shape=box, fillcolor=white, 
label="datapath_sync"]];
+       global_config -> datapath_sync 
[[label="datapath_sync_global_config_handler"]];
+       global_config [[style=filled, shape=box, fillcolor=white, 
label="global_config"]];
+       NB_nb_global -> global_config 
[[label="global_config_nb_global_handler"]];
+       NB_nb_global [[style=filled, shape=box, fillcolor=white, 
label="NB_nb_global"]];
+       NB_logical_switch -> global_config 
[[label="global_config_nb_logical_switch_handler"]];
+       NB_logical_switch [[style=filled, shape=box, fillcolor=white, 
label="NB_logical_switch"]];
+       SB_sb_global -> global_config 
[[label="global_config_sb_global_handler"]];
+       SB_sb_global [[style=filled, shape=box, fillcolor=white, 
label="SB_sb_global"]];
+       SB_chassis -> global_config 
[[label="global_config_sb_chassis_handler"]];
+       SB_chassis [[style=filled, shape=box, fillcolor=white, 
label="SB_chassis"]];
+       sampling_app -> global_config [[label=""]];
+       sampling_app [[style=filled, shape=box, fillcolor=white, 
label="sampling_app"]];
+       NB_sampling_app -> sampling_app [[label=""]];
+       NB_sampling_app [[style=filled, shape=box, fillcolor=white, 
label="NB_sampling_app"]];
+       SB_datapath_binding -> datapath_sync 
[[label="datapath_sync_sb_datapath_binding"]];
+       SB_datapath_binding [[style=filled, shape=box, fillcolor=white, 
label="SB_datapath_binding"]];
+       datapath_logical_switch -> datapath_sync 
[[label="datapath_sync_logical_switch_handler"]];
+       datapath_logical_switch [[style=filled, shape=box, fillcolor=white, 
label="datapath_logical_switch"]];
+       NB_logical_switch -> datapath_logical_switch 
[[label="datapath_logical_switch_handler"]];
+       global_config -> datapath_logical_switch 
[[label="datapath_logical_switch_handler"]];
+       datapath_logical_router -> datapath_sync 
[[label="datapath_sync_logical_router_handler"]];
+       datapath_logical_router [[style=filled, shape=box, fillcolor=white, 
label="datapath_logical_router"]];
+       NB_logical_router -> datapath_logical_router 
[[label="en_datapath_logical_router_logical_router_handler"]];
+       NB_logical_router [[style=filled, shape=box, fillcolor=white, 
label="NB_logical_router"]];
+}
+])
+AT_CLEANUP
+
+AT_SETUP([controller: dump full incremental processing graph])
+AT_KEYWORDS([inc-proc-graph])
+AT_CHECK([ovn-controller --dump-inc-proc-graph], [0], [dnl
+digraph "Incremental-Processing-Engine" {
+       rankdir=LR;
+       SB_dns [[style=filled, shape=box, fillcolor=white, label="SB_dns"]];
+       dns_cache [[style=filled, shape=box, fillcolor=white, 
label="dns_cache"]];
+       SB_dns -> dns_cache [[label="dns_cache_sb_dns_handler"]];
+       SB_sb_global [[style=filled, shape=box, fillcolor=white, 
label="SB_sb_global"]];
+       northd_options [[style=filled, shape=box, fillcolor=white, 
label="northd_options"]];
+       SB_sb_global -> northd_options 
[[label="en_northd_options_sb_sb_global_handler"]];
+       SB_dhcp_options [[style=filled, shape=box, fillcolor=white, 
label="SB_dhcp_options"]];
+       SB_dhcpv6_options [[style=filled, shape=box, fillcolor=white, 
label="SB_dhcpv6_options"]];
+       dhcp_options [[style=filled, shape=box, fillcolor=white, 
label="dhcp_options"]];
+       SB_dhcp_options -> dhcp_options [[label=""]];
+       SB_dhcpv6_options -> dhcp_options [[label=""]];
+       SB_address_set [[style=filled, shape=box, fillcolor=white, 
label="SB_address_set"]];
+       addr_sets [[style=filled, shape=box, fillcolor=white, 
label="addr_sets"]];
+       SB_address_set -> addr_sets 
[[label="addr_sets_sb_address_set_handler"]];
+       SB_port_group [[style=filled, shape=box, fillcolor=white, 
label="SB_port_group"]];
+       ofctrl_is_connected [[style=filled, shape=box, fillcolor=white, 
label="ofctrl_is_connected"]];
+       OVS_open_vswitch [[style=filled, shape=box, fillcolor=white, 
label="OVS_open_vswitch"]];
+       OVS_bridge [[style=filled, shape=box, fillcolor=white, 
label="OVS_bridge"]];
+       OVS_qos [[style=filled, shape=box, fillcolor=white, label="OVS_qos"]];
+       OVS_queue [[style=filled, shape=box, fillcolor=white, 
label="OVS_queue"]];
+       SB_chassis [[style=filled, shape=box, fillcolor=white, 
label="SB_chassis"]];
+       SB_datapath_binding [[style=filled, shape=box, fillcolor=white, 
label="SB_datapath_binding"]];
+       SB_port_binding [[style=filled, shape=box, fillcolor=white, 
label="SB_port_binding"]];
+       postponed_ports [[style=filled, shape=box, fillcolor=white, 
label="postponed_ports"]];
+       sb_ro [[style=filled, shape=box, fillcolor=white, label="sb_ro"]];
+       OVS_port [[style=filled, shape=box, fillcolor=white, label="OVS_port"]];
+       OVS_interface [[style=filled, shape=box, fillcolor=white, 
label="OVS_interface"]];
+       ovs_interface_shadow [[style=filled, shape=box, fillcolor=white, 
label="ovs_interface_shadow"]];
+       OVS_interface -> ovs_interface_shadow 
[[label="ovs_interface_shadow_ovs_interface_handler"]];
+       runtime_data [[style=filled, shape=box, fillcolor=white, 
label="runtime_data"]];
+       ofctrl_is_connected -> runtime_data [[label=""]];
+       OVS_open_vswitch -> runtime_data [[label=""]];
+       OVS_bridge -> runtime_data [[label=""]];
+       OVS_qos -> runtime_data [[label=""]];
+       OVS_queue -> runtime_data [[label=""]];
+       SB_chassis -> runtime_data [[label=""]];
+       SB_datapath_binding -> runtime_data 
[[label="runtime_data_sb_datapath_binding_handler"]];
+       SB_port_binding -> runtime_data 
[[label="runtime_data_sb_port_binding_handler"]];
+       postponed_ports -> runtime_data 
[[label="runtime_data_sb_port_binding_handler"]];
+       sb_ro -> runtime_data [[label="runtime_data_sb_ro_handler"]];
+       OVS_port -> runtime_data [[label="engine_noop_handler"]];
+       ovs_interface_shadow -> runtime_data 
[[label="runtime_data_ovs_interface_shadow_handler"]];
+       port_groups [[style=filled, shape=box, fillcolor=white, 
label="port_groups"]];
+       SB_port_group -> port_groups 
[[label="port_groups_sb_port_group_handler"]];
+       runtime_data -> port_groups 
[[label="port_groups_runtime_data_handler"]];
+       SB_chassis_template_var [[style=filled, shape=box, fillcolor=white, 
label="SB_chassis_template_var"]];
+       template_vars [[style=filled, shape=box, fillcolor=white, 
label="template_vars"]];
+       OVS_open_vswitch -> template_vars [[label=""]];
+       SB_chassis -> template_vars [[label=""]];
+       SB_chassis_template_var -> template_vars 
[[label="template_vars_sb_chassis_template_var_handler"]];
+       non_vif_data [[style=filled, shape=box, fillcolor=white, 
label="non_vif_data"]];
+       OVS_open_vswitch -> non_vif_data [[label=""]];
+       OVS_bridge -> non_vif_data [[label=""]];
+       SB_chassis -> non_vif_data [[label=""]];
+       OVS_interface -> non_vif_data 
[[label="non_vif_data_ovs_iface_handler"]];
+       SB_multicast_group [[style=filled, shape=box, fillcolor=white, 
label="SB_multicast_group"]];
+       OVS_flow_sample_collector_set [[style=filled, shape=box, 
fillcolor=white, label="OVS_flow_sample_collector_set"]];
+       SB_mac_binding [[style=filled, shape=box, fillcolor=white, 
label="SB_mac_binding"]];
+       SB_static_mac_binding [[style=filled, shape=box, fillcolor=white, 
label="SB_static_mac_binding"]];
+       SB_logical_flow [[style=filled, shape=box, fillcolor=white, 
label="SB_logical_flow"]];
+       SB_logical_dp_group [[style=filled, shape=box, fillcolor=white, 
label="SB_logical_dp_group"]];
+       SB_load_balancer [[style=filled, shape=box, fillcolor=white, 
label="SB_load_balancer"]];
+       lb_data [[style=filled, shape=box, fillcolor=white, label="lb_data"]];
+       SB_load_balancer -> lb_data 
[[label="lb_data_sb_load_balancer_handler"]];
+       template_vars -> lb_data [[label="lb_data_template_var_handler"]];
+       runtime_data -> lb_data [[label="lb_data_runtime_data_handler"]];
+       SB_fdb [[style=filled, shape=box, fillcolor=white, label="SB_fdb"]];
+       SB_meter [[style=filled, shape=box, fillcolor=white, label="SB_meter"]];
+       lflow_output [[style=filled, shape=box, fillcolor=white, 
label="lflow_output"]];
+       northd_options -> lflow_output [[label=""]];
+       dhcp_options -> lflow_output [[label=""]];
+       addr_sets -> lflow_output [[label="lflow_output_addr_sets_handler"]];
+       port_groups -> lflow_output 
[[label="lflow_output_port_groups_handler"]];
+       template_vars -> lflow_output 
[[label="lflow_output_template_vars_handler"]];
+       runtime_data -> lflow_output 
[[label="lflow_output_runtime_data_handler"]];
+       non_vif_data -> lflow_output [[label=""]];
+       SB_multicast_group -> lflow_output 
[[label="lflow_output_sb_multicast_group_handler"]];
+       SB_chassis -> lflow_output 
[[label="pflow_lflow_output_sb_chassis_handler"]];
+       SB_port_binding -> lflow_output 
[[label="lflow_output_sb_port_binding_handler"]];
+       OVS_open_vswitch -> lflow_output [[label=""]];
+       OVS_bridge -> lflow_output [[label=""]];
+       OVS_flow_sample_collector_set -> lflow_output 
[[label="lflow_output_flow_sample_collector_set_handler"]];
+       SB_mac_binding -> lflow_output 
[[label="lflow_output_sb_mac_binding_handler"]];
+       SB_static_mac_binding -> lflow_output 
[[label="lflow_output_sb_static_mac_binding_handler"]];
+       SB_logical_flow -> lflow_output 
[[label="lflow_output_sb_logical_flow_handler"]];
+       SB_logical_dp_group -> lflow_output [[label="engine_noop_handler"]];
+       lb_data -> lflow_output [[label="lflow_output_lb_data_handler"]];
+       SB_fdb -> lflow_output [[label="lflow_output_sb_fdb_handler"]];
+       SB_meter -> lflow_output [[label="lflow_output_sb_meter_handler"]];
+       ct_zones [[style=filled, shape=box, fillcolor=white, label="ct_zones"]];
+       OVS_open_vswitch -> ct_zones [[label=""]];
+       OVS_bridge -> ct_zones [[label=""]];
+       SB_datapath_binding -> ct_zones 
[[label="ct_zones_datapath_binding_handler"]];
+       runtime_data -> ct_zones [[label="ct_zones_runtime_data_handler"]];
+       if_status_mgr [[style=filled, shape=box, fillcolor=white, 
label="if_status_mgr"]];
+       OVS_interface -> if_status_mgr 
[[label="if_status_mgr_ovs_interface_handler"]];
+       activated_ports [[style=filled, shape=box, fillcolor=white, 
label="activated_ports"]];
+       SB_encap [[style=filled, shape=box, fillcolor=white, label="SB_encap"]];
+       mff_ovn_geneve [[style=filled, shape=box, fillcolor=white, 
label="mff_ovn_geneve"]];
+       SB_advertised_mac_binding [[style=filled, shape=box, fillcolor=white, 
label="SB_advertised_mac_binding"]];
+       neighbor [[style=filled, shape=box, fillcolor=white, label="neighbor"]];
+       OVS_open_vswitch -> neighbor [[label=""]];
+       SB_chassis -> neighbor [[label=""]];
+       SB_advertised_mac_binding -> neighbor [[label=""]];
+       runtime_data -> neighbor [[label="neighbor_runtime_data_handler"]];
+       SB_datapath_binding -> neighbor 
[[label="neighbor_sb_datapath_binding_handler"]];
+       SB_port_binding -> neighbor 
[[label="neighbor_sb_port_binding_handler"]];
+       host_if_monitor [[style=filled, shape=box, fillcolor=white, 
label="host_if_monitor"]];
+       neighbor_table_notify [[style=filled, shape=box, fillcolor=white, 
label="neighbor_table_notify"]];
+       neighbor_exchange_status [[style=filled, shape=box, fillcolor=white, 
label="neighbor_exchange_status"]];
+       neighbor_exchange [[style=filled, shape=box, fillcolor=white, 
label="neighbor_exchange"]];
+       neighbor -> neighbor_exchange [[label=""]];
+       host_if_monitor -> neighbor_exchange [[label=""]];
+       neighbor_table_notify -> neighbor_exchange [[label=""]];
+       neighbor_exchange_status -> neighbor_exchange [[label=""]];
+       evpn_vtep_binding [[style=filled, shape=box, fillcolor=white, 
label="evpn_vtep_binding"]];
+       OVS_open_vswitch -> evpn_vtep_binding [[label=""]];
+       OVS_bridge -> evpn_vtep_binding [[label=""]];
+       neighbor_exchange -> evpn_vtep_binding [[label=""]];
+       runtime_data -> evpn_vtep_binding [[label="engine_noop_handler"]];
+       OVS_interface -> evpn_vtep_binding 
[[label="evpn_vtep_binding_ovs_interface_handler"]];
+       SB_datapath_binding -> evpn_vtep_binding 
[[label="evpn_vtep_binding_datapath_binding_handler"]];
+       evpn_fdb [[style=filled, shape=box, fillcolor=white, label="evpn_fdb"]];
+       neighbor_exchange -> evpn_fdb [[label=""]];
+       evpn_vtep_binding -> evpn_fdb [[label="evpn_fdb_vtep_binding_handler"]];
+       evpn_arp [[style=filled, shape=box, fillcolor=white, label="evpn_arp"]];
+       neighbor_exchange -> evpn_arp [[label=""]];
+       evpn_vtep_binding -> evpn_arp [[label="evpn_arp_vtep_binding_handler"]];
+       pflow_output [[style=filled, shape=box, fillcolor=white, 
label="pflow_output"]];
+       non_vif_data -> pflow_output [[label=""]];
+       northd_options -> pflow_output [[label=""]];
+       ct_zones -> pflow_output [[label="pflow_output_ct_zones_handler"]];
+       SB_chassis -> pflow_output 
[[label="pflow_lflow_output_sb_chassis_handler"]];
+       if_status_mgr -> pflow_output 
[[label="pflow_output_if_status_mgr_handler"]];
+       SB_port_binding -> pflow_output 
[[label="pflow_output_sb_port_binding_handler"]];
+       SB_multicast_group -> pflow_output 
[[label="pflow_output_sb_multicast_group_handler"]];
+       SB_datapath_binding -> pflow_output [[label="engine_noop_handler"]];
+       activated_ports -> pflow_output 
[[label="pflow_output_activated_ports_handler"]];
+       runtime_data -> pflow_output 
[[label="pflow_output_runtime_data_handler"]];
+       SB_encap -> pflow_output [[label=""]];
+       mff_ovn_geneve -> pflow_output [[label=""]];
+       OVS_open_vswitch -> pflow_output [[label=""]];
+       OVS_bridge -> pflow_output [[label=""]];
+       OVS_flow_sample_collector_set -> pflow_output 
[[label="pflow_output_debug_handler"]];
+       SB_sb_global -> pflow_output [[label="pflow_output_debug_handler"]];
+       evpn_vtep_binding -> pflow_output 
[[label="pflow_output_evpn_binding_handler"]];
+       evpn_fdb -> pflow_output [[label="pflow_output_fdb_handler"]];
+       evpn_arp -> pflow_output [[label="pflow_output_arp_handler"]];
+       mac_cache [[style=filled, shape=box, fillcolor=white, 
label="mac_cache"]];
+       runtime_data -> mac_cache [[label="mac_cache_runtime_data_handler"]];
+       SB_mac_binding -> mac_cache 
[[label="mac_cache_sb_mac_binding_handler"]];
+       SB_fdb -> mac_cache [[label="mac_cache_sb_fdb_handler"]];
+       SB_datapath_binding -> mac_cache 
[[label="mac_cache_sb_datapath_binding_handler"]];
+       SB_port_binding -> mac_cache [[label="engine_noop_handler"]];
+       SB_ha_chassis_group [[style=filled, shape=box, fillcolor=white, 
label="SB_ha_chassis_group"]];
+       bfd_chassis [[style=filled, shape=box, fillcolor=white, 
label="bfd_chassis"]];
+       OVS_open_vswitch -> bfd_chassis [[label=""]];
+       SB_chassis -> bfd_chassis [[label=""]];
+       SB_ha_chassis_group -> bfd_chassis [[label=""]];
+       SB_advertised_route [[style=filled, shape=box, fillcolor=white, 
label="SB_advertised_route"]];
+       route [[style=filled, shape=box, fillcolor=white, label="route"]];
+       OVS_open_vswitch -> route [[label=""]];
+       SB_chassis -> route [[label=""]];
+       SB_port_binding -> route [[label="route_sb_port_binding_data_handler"]];
+       runtime_data -> route [[label="route_runtime_data_handler"]];
+       SB_advertised_route -> route 
[[label="route_sb_advertised_route_data_handler"]];
+       SB_learned_route [[style=filled, shape=box, fillcolor=white, 
label="SB_learned_route"]];
+       route_table_notify [[style=filled, shape=box, fillcolor=white, 
label="route_table_notify"]];
+       route_exchange_status [[style=filled, shape=box, fillcolor=white, 
label="route_exchange_status"]];
+       route_exchange [[style=filled, shape=box, fillcolor=white, 
label="route_exchange"]];
+       route -> route_exchange [[label=""]];
+       SB_learned_route -> route_exchange [[label="engine_noop_handler"]];
+       SB_port_binding -> route_exchange [[label="engine_noop_handler"]];
+       route_table_notify -> route_exchange [[label=""]];
+       route_exchange_status -> route_exchange [[label=""]];
+       sb_ro -> route_exchange [[label="route_exchange_sb_ro_handler"]];
+       garp_rarp [[style=filled, shape=box, fillcolor=white, 
label="garp_rarp"]];
+       OVS_open_vswitch -> garp_rarp [[label=""]];
+       SB_chassis -> garp_rarp [[label=""]];
+       SB_port_binding -> garp_rarp 
[[label="garp_rarp_sb_port_binding_handler"]];
+       SB_datapath_binding -> garp_rarp 
[[label="garp_rarp_sb_datapath_binding_handler"]];
+       SB_mac_binding -> garp_rarp [[label="engine_noop_handler"]];
+       runtime_data -> garp_rarp [[label="garp_rarp_runtime_data_handler"]];
+       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=""]];
+       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"]];
+       pflow_output -> controller_output 
[[label="controller_output_pflow_output_handler"]];
+       mac_cache -> controller_output 
[[label="controller_output_mac_cache_handler"]];
+       bfd_chassis -> controller_output 
[[label="controller_output_bfd_chassis_handler"]];
+       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"]];
+}
+])
+AT_CLEANUP
+
+AT_SETUP([controller: dump partial incremental processing graph (up to 
runtime_data)])
+AT_KEYWORDS([inc-proc-graph])
+AT_CHECK([ovn-controller --dump-inc-proc-graph=runtime_data], [0], [dnl
+digraph "Incremental-Processing-Engine" {
+       rankdir=LR;
+       runtime_data [[style=filled, shape=box, fillcolor=white, 
label="runtime_data"]];
+       ofctrl_is_connected -> runtime_data [[label=""]];
+       ofctrl_is_connected [[style=filled, shape=box, fillcolor=white, 
label="ofctrl_is_connected"]];
+       OVS_open_vswitch -> runtime_data [[label=""]];
+       OVS_open_vswitch [[style=filled, shape=box, fillcolor=white, 
label="OVS_open_vswitch"]];
+       OVS_bridge -> runtime_data [[label=""]];
+       OVS_bridge [[style=filled, shape=box, fillcolor=white, 
label="OVS_bridge"]];
+       OVS_qos -> runtime_data [[label=""]];
+       OVS_qos [[style=filled, shape=box, fillcolor=white, label="OVS_qos"]];
+       OVS_queue -> runtime_data [[label=""]];
+       OVS_queue [[style=filled, shape=box, fillcolor=white, 
label="OVS_queue"]];
+       SB_chassis -> runtime_data [[label=""]];
+       SB_chassis [[style=filled, shape=box, fillcolor=white, 
label="SB_chassis"]];
+       SB_datapath_binding -> runtime_data 
[[label="runtime_data_sb_datapath_binding_handler"]];
+       SB_datapath_binding [[style=filled, shape=box, fillcolor=white, 
label="SB_datapath_binding"]];
+       SB_port_binding -> runtime_data 
[[label="runtime_data_sb_port_binding_handler"]];
+       SB_port_binding [[style=filled, shape=box, fillcolor=white, 
label="SB_port_binding"]];
+       postponed_ports -> runtime_data 
[[label="runtime_data_sb_port_binding_handler"]];
+       postponed_ports [[style=filled, shape=box, fillcolor=white, 
label="postponed_ports"]];
+       sb_ro -> runtime_data [[label="runtime_data_sb_ro_handler"]];
+       sb_ro [[style=filled, shape=box, fillcolor=white, label="sb_ro"]];
+       OVS_port -> runtime_data [[label="engine_noop_handler"]];
+       OVS_port [[style=filled, shape=box, fillcolor=white, label="OVS_port"]];
+       ovs_interface_shadow -> runtime_data 
[[label="runtime_data_ovs_interface_shadow_handler"]];
+       ovs_interface_shadow [[style=filled, shape=box, fillcolor=white, 
label="ovs_interface_shadow"]];
+       OVS_interface -> ovs_interface_shadow 
[[label="ovs_interface_shadow_ovs_interface_handler"]];
+       OVS_interface [[style=filled, shape=box, fillcolor=white, 
label="OVS_interface"]];
+}
+])
+AT_CLEANUP
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 5f5eabb42a..6216ac761d 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -42,3 +42,4 @@ m4_include([tests/ovn-ipsec.at])
 m4_include([tests/ovn-vif-plug.at])
 m4_include([tests/ovn-util.at])
 m4_include([tests/ovn-br-controller.at])
+m4_include([tests/ovn-inc-proc-graph-dump.at])
-- 
2.51.1

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

Reply via email to