On 4/30/26 10:44 PM, Jacob Tanenbaum wrote:
> 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]>
> 
> ---

Hi Jacob,

Thanks for this new version!  Overall it looks ok to me, but I have some
comments about some things that I think should be addressed in v10
before we merge this.

> 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..aa789c63c 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 *waiting_sb_update,

At this point, the argument name is too vague, these are datapaths but
it's hard to tell from the argument name.  Maybe 'dps_waiting_for_sb'.

Also, I think we should never call this function with a NULL
'waiting_sb_update' argument.  Maybe an "ovs_assert(dps_waiting_for_sb)"
just in the beginning of the function?

>                       bool ovs_readonly,
>                       bool sb_readonly)
>  {
> @@ -622,9 +645,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 +660,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);
> +                ovs_assert(pb);

As mentioned in the review of v8, we should probably change this to a
graceful NULL check.

> +                struct local_datapath *ld =
> +                    get_local_datapath(local_datapaths,
> +                                       pb->datapath->tunnel_key);
> +                if (!ld) {
> +                    continue;
> +                }
> +                if (waiting_sb_update &&

As mentioned above, we'd never have a NULL uuidset here so we can skip
this part of the condition.

> +                    !uuidset_find(waiting_sb_update,
> +                        &ld->datapath->header_.uuid)) {
> +                    ovs_iface_set_state(mgr, iface, OIF_INSTALL_FLOWS);
> +                    iface->install_seqno = mgr->iface_seqno + 1;
> +                    new_ifaces = true;
> +                }
> +

Unnecessary empty line.

> +            }
> +        }
> +    }
> +
>      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..8c057bf6b 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 *waiting_sb_update,
>                            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..91c659718 100644
> --- a/controller/ovn-controller.c
> +++ b/controller/ovn-controller.c
> @@ -170,6 +170,7 @@ static char *unixctl_path;
>  struct controller_engine_ctx {
>      struct lflow_cache *lflow_cache;
>      struct if_status_mgr *if_mgr;
> +    unsigned int *ovnsb_expected_cond_seqno;

Nit: const unsigned int *

>  };
>  
>  /* Pending packet to be injected into connected OVS. */
> @@ -1145,10 +1146,51 @@ 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);
> +    uuidset_init(&data->waiting_sb_cond_update);

Nit: I'd do:

    struct ed_type_datapaths_updated *data = xmalloc(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);
> +}
> +
>  struct ed_type_ofctrl_is_connected {
>      bool connected;
>  };

I guess the en_datapaths_updated_run() function definition should've
been inserted above this struct definition.

>  
> +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_UNCHANGED;
> +        }
> +    }
> +    return EN_UNCHANGED;

It's kind of weird that this always returns EN_UNCHANGED.

> +}
> +
>  static void *
>  en_ofctrl_is_connected_init(struct engine_node *node OVS_UNUSED,
>                              struct engine_arg *arg OVS_UNUSED)
> @@ -1180,6 +1222,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)

Please add the parenthesis just after the function name.  Also, we
always add a new line between function return type and function name
when defining a function, i.e.:

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;
> @@ -1512,6 +1589,7 @@ en_runtime_data_clear_tracked_data(void *data_)
>  }
>  
>  static void *
> +

Please remove this unrelated newline.

>  en_runtime_data_init(struct engine_node *node OVS_UNUSED,
>                       struct engine_arg *arg OVS_UNUSED)
>  {
> @@ -6745,6 +6823,50 @@ evpn_arp_vtep_binding_handler(struct engine_node 
> *node, void *data OVS_UNUSED)
>      return EN_UNHANDLED;
>  }
>  

Please move the handler definition where we define the rest of the node
functions, i.e., just after en_datapaths_updated_run().

> +static enum engine_input_handler_result
> +new_datapaths_handler(struct engine_node *node,
> +                                    void *data)

void *data should be indented the same as the previous argument above.

> +{
> +    struct ed_type_datapaths_updated *dp_data = data;
> +    struct ed_type_runtime_data *rt_data =
> +        engine_get_input_data("runtime_data", node);
> +
> +    enum engine_input_handler_result status = EN_HANDLED_UNCHANGED;
> +    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);

Shouldn't we make this conditional too, i.e., only if
ovnsb_expected_cond_seqno is not the right one?  In the monitor-all case
there's no need to move these to waiting_sb_cond_update, right?

> +            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 (ovnsb_idl_txn) {

We checked !ovnsb_idl_txn just above, we can remove this one from here.

> +        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 +6989,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 +7013,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);

Let's group this one together with the handler for en_runtime data
below.  We try to group all dependencies for each node.

>      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 +7101,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,
> +                    new_datapaths_handler);

The (I guess undocumented) convention for handler function names is
<NODE-NAME>_<INPUT-NODE-NAME>_handler() so in this case:

datapaths_updated_runtime_data_handler()

Also, nit, indentation: you need one more space before the handler name.

> +
>      engine_add_input(&en_northd_options, &en_sb_sb_global,
>                       en_northd_options_sb_sb_global_handler);
>  
> @@ -7163,6 +7292,7 @@ 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, NULL);

We shouldn't use a NULL handler for inputs of "en_controller_output"
(the final node of the DAG).  Instead we should use a handler like the
ones we add for other nodes (e.g.,
controller_output_route_exchange_handler()).

>  
>      struct engine_arg engine_arg = {
>          .sb_idl = sb_idl_loop->idl,
> @@ -7556,6 +7686,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);
> @@ -7659,6 +7791,7 @@ main(int argc, char *argv[])
>      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,
>      };
>      struct if_status_mgr *if_mgr = ctrl_engine_ctx.if_mgr;
>  
> @@ -7915,6 +8048,7 @@ main(int argc, char *argv[])
>  
>                      bool recompute_allowed = (ovnsb_idl_txn &&
>                                                !ofctrl_has_backlog());
> +

Please remove this unrelated newline.

>                      engine_run(recompute_allowed);
>                      tracked_acl_ids = engine_get_data(&en_acl_id);
>  
> @@ -8085,11 +8219,23 @@ main(int argc, char *argv[])
>                          runtime_data ? &runtime_data->lbinding_data : NULL;
>                      stopwatch_start(IF_STATUS_MGR_UPDATE_STOPWATCH_NAME,
>                                      time_msec());
> +                    if (sb_monitor_all && dp_updated_data) {
> +                        uuidset_clear(
> +                            &dp_updated_data->waiting_sb_cond_update);
> +                    }

See my comment about the monitor-all case above, if you check the cond
seqno in the handler you don't need this clear anymore.

Also, it's very awkward to clear node-internal data outside the
incremental processing engine.

> +
> +                    struct uuidset *waiting_sb_cond_update = dp_updated_data 
> ?

const struct uuidset *?

OTOH, dp_updated_data is always non-NULL, I'd just pass
&dp_updated_data->waiting_sb_cond_update to if_status_mgr_update().

> +                        &dp_updated_data->waiting_sb_cond_update
> +                        : NULL;
>                      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,
> +                                         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..9dc7555ba 100644
> --- a/tests/ovn-controller.at
> +++ b/tests/ovn-controller.at
> @@ -3944,3 +3944,69 @@ 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
> +        as hv1 ovs-ofctl dump-flows br-int > output

Leftover from debugging?

> +        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
> +        as hv1 ovs-ofctl dump-flows br-int > output

Leftover from debugging?

> +        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..036d44891 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="new_datapaths_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=""]];
>  }
>  ])
>  AT_CLEANUP

Regards,
Dumitru

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

Reply via email to