diff mbox series

[ovs-dev,v2] ovn-controller: fixed ovn-installed not always properly added.

Message ID 20220627085202.1187277-1-xsimonar@redhat.com
State Superseded
Delegated to: Dumitru Ceara
Headers show
Series [ovs-dev,v2] ovn-controller: fixed ovn-installed not always properly added. | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_Build_and_Test success github build: passed
ovsrobot/github-robot-_ovn-kubernetes success github build: passed

Commit Message

Xavier Simonart June 27, 2022, 8:52 a.m. UTC
OVN checks whether ovn-installed is already present (in OVS) before updating it.
This might cause ovn-installed related issues in the following case:
- (1) ovn-installed is present
- (2) we claim the interface
- (3) we update ovs, removing ovn-installed and start installing flows
- (4) (next loop), after flows installed, we check if ovn-installed is absent,
  and if yes, we update OVS with ovn-installed.
However, in step4, if OVS is still busy from step 3, ovn-installed is read as
present; hence OVN controller does not update it and move to INSTALLED state.

Note that this does not happen with writing port up in SBDB because Port status
changes will hit I-P.

This patch will require updating the state machine description in the
"controller: avoid recomputes triggered by SBDB Port_Binding updates." patch
when it's merged, as it changes the if-status state-machine.

Signed-off-by: Xavier Simonart <xsimonar@redhat.com>
---
 controller/binding.c   | 35 ++++++++++++++++++++++++++++++++--
 controller/binding.h   |  6 ++++++
 controller/if-status.c | 43 ++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 80 insertions(+), 4 deletions(-)

Comments

Dumitru Ceara June 28, 2022, 12:35 p.m. UTC | #1
On 6/27/22 10:52, Xavier Simonart wrote:
> OVN checks whether ovn-installed is already present (in OVS) before updating it.
> This might cause ovn-installed related issues in the following case:
> - (1) ovn-installed is present
> - (2) we claim the interface
> - (3) we update ovs, removing ovn-installed and start installing flows
> - (4) (next loop), after flows installed, we check if ovn-installed is absent,
>   and if yes, we update OVS with ovn-installed.
> However, in step4, if OVS is still busy from step 3, ovn-installed is read as
> present; hence OVN controller does not update it and move to INSTALLED state.
> 
> Note that this does not happen with writing port up in SBDB because Port status
> changes will hit I-P.
> 
> This patch will require updating the state machine description in the
> "controller: avoid recomputes triggered by SBDB Port_Binding updates." patch
> when it's merged, as it changes the if-status state-machine.
> 
> Signed-off-by: Xavier Simonart <xsimonar@redhat.com>
> ---

Hi Xavier,

I only have a couple tiny style related remarks below.  I think those
can be addressed at apply time if maintainers agree.  Therefore:

Acked-by: Dumitru Ceara <dceara@redhat.com>

Thanks,
Dumitru

>  controller/binding.c   | 35 ++++++++++++++++++++++++++++++++--
>  controller/binding.h   |  6 ++++++
>  controller/if-status.c | 43 ++++++++++++++++++++++++++++++++++++++++--
>  3 files changed, 80 insertions(+), 4 deletions(-)
> 
> diff --git a/controller/binding.c b/controller/binding.c
> index 2279570f9..157c381cf 100644
> --- a/controller/binding.c
> +++ b/controller/binding.c
> @@ -643,6 +643,19 @@ local_binding_get_lport_ofport(const struct shash *local_bindings,
>              u16_to_ofp(lbinding->iface->ofport[0]) : 0;
>  }
>  
> +bool
> +local_binding_is_ovn_installed(struct shash *local_bindings,
> +                               const char *pb_name)
> +{
> +    struct local_binding *lbinding =
> +        local_binding_find(local_bindings, pb_name);
> +    if (lbinding && lbinding->iface) {
> +        return smap_get_bool(&lbinding->iface->external_ids,
> +                             OVN_INSTALLED_EXT_ID, false);
> +    }
> +    return false;
> +}
> +
>  bool
>  local_binding_is_up(struct shash *local_bindings, const char *pb_name)
>  {
> @@ -715,6 +728,22 @@ local_binding_set_up(struct shash *local_bindings, const char *pb_name,
>      }
>  }
>  
> +void
> +local_binding_remove_ovn_installed(struct shash *local_bindings,
> +                                   const char *pb_name, bool ovs_readonly)
> +{

Nit: we could avoid the shash lookup if we return if ovs_readonly ==
true here.

> +    struct local_binding *lbinding =
> +        local_binding_find(local_bindings, pb_name);
> +
> +    if (!ovs_readonly && lbinding && lbinding->iface
> +            && smap_get_bool(&lbinding->iface->external_ids,
> +                             OVN_INSTALLED_EXT_ID, false)) {
> +        VLOG_INFO("Removing lport %s ovn-installed in OVS", pb_name);
> +        ovsrec_interface_update_external_ids_delkey(lbinding->iface,
> +                                                    OVN_INSTALLED_EXT_ID);
> +    }
> +}
> +
>  void
>  local_binding_set_down(struct shash *local_bindings, const char *pb_name,
>                         const struct sbrec_chassis *chassis_rec,
> @@ -1297,9 +1326,11 @@ consider_vif_lport_(const struct sbrec_port_binding *pb,
>              const char *requested_chassis_option = smap_get(
>                  &pb->options, "requested-chassis");
>              VLOG_INFO_RL(&rl,
> -                "Not claiming lport %s, chassis %s requested-chassis %s",
> +                "Not claiming lport %s, chassis %s requested-chassis %s "
> +                "pb->chassis %s",
>                  pb->logical_port, b_ctx_in->chassis_rec->name,
> -                requested_chassis_option ? requested_chassis_option : "[]");
> +                requested_chassis_option ? requested_chassis_option : "[]",
> +                pb->chassis ? pb->chassis->name: "");
>          }
>      }
>  
> diff --git a/controller/binding.h b/controller/binding.h
> index 1fed06674..445bdd9f2 100644
> --- a/controller/binding.h
> +++ b/controller/binding.h
> @@ -152,6 +152,12 @@ ofp_port_t local_binding_get_lport_ofport(const struct shash *local_bindings,
>                                            const char *pb_name);
>  
>  bool local_binding_is_up(struct shash *local_bindings, const char *pb_name);
> +bool local_binding_is_ovn_installed(struct shash *local_bindings,
> +                                    const char *pb_name);
> +void local_binding_remove_ovn_installed(struct shash *local_bindings,
> +                                        const char *pb_name,
> +                                        bool ovs_readonly);
> +
>  bool local_binding_is_down(struct shash *local_bindings, const char *pb_name);
>  void local_binding_set_up(struct shash *local_bindings, const char *pb_name,
>                            const struct sbrec_chassis *chassis_rec,
> diff --git a/controller/if-status.c b/controller/if-status.c
> index ad61844d8..fe544c6ec 100644
> --- a/controller/if-status.c
> +++ b/controller/if-status.c
> @@ -57,6 +57,9 @@ enum if_state {
>      OIF_INSTALL_FLOWS, /* Already claimed interface for which flows are still
>                          * being installed.
>                          */
> +    OIF_REMOVE_OVN_INST,/* Interface with flows successfully installed in OVS,
> +                         * but with ovn-installed still in OVSDB.
> +                         */

Nit: indentation and missing space after ','.

>      OIF_MARK_UP,       /* Interface with flows successfully installed in OVS
>                          * but not yet marked "up" in the binding module (in
>                          * SB and OVS databases).
> @@ -73,6 +76,7 @@ enum if_state {
>  static const char *if_state_names[] = {
>      [OIF_CLAIMED]       = "CLAIMED",
>      [OIF_INSTALL_FLOWS] = "INSTALL_FLOWS",
> +    [OIF_REMOVE_OVN_INST] = "REMOVE_OVN_INST",

I know one often prefers the misaligned '=' over re-indenting all the
existing assignments but because we only have 6 lines here I think I'd
re-align all of them.  But it's personal preference, it's fine to leave
it as-is too.

>      [OIF_MARK_UP]       = "MARK_UP",
>      [OIF_MARK_DOWN]     = "MARK_DOWN",
>      [OIF_INSTALLED]     = "INSTALLED",
> @@ -169,6 +173,7 @@ if_status_mgr_claim_iface(struct if_status_mgr *mgr, const char *iface_id)
>      switch (iface->state) {
>      case OIF_CLAIMED:
>      case OIF_INSTALL_FLOWS:
> +    case OIF_REMOVE_OVN_INST:
>      case OIF_MARK_UP:
>          /* Nothing to do here. */
>          break;
> @@ -199,6 +204,7 @@ if_status_mgr_release_iface(struct if_status_mgr *mgr, const char *iface_id)
>          /* Not yet fully installed interfaces can be safely deleted. */
>          ovs_iface_destroy(mgr, iface);
>          break;
> +    case OIF_REMOVE_OVN_INST:
>      case OIF_MARK_UP:
>      case OIF_INSTALLED:
>          /* Properly mark interfaces "down" if their flows were already
> @@ -230,6 +236,7 @@ if_status_mgr_delete_iface(struct if_status_mgr *mgr, const char *iface_id)
>          /* Not yet fully installed interfaces can be safely deleted. */
>          ovs_iface_destroy(mgr, iface);
>          break;
> +    case OIF_REMOVE_OVN_INST:
>      case OIF_MARK_UP:
>      case OIF_INSTALLED:
>          /* Properly mark interfaces "down" if their flows were already
> @@ -257,6 +264,17 @@ if_status_mgr_update(struct if_status_mgr *mgr,
>      struct shash *bindings = &binding_data->bindings;
>      struct hmapx_node *node;
>  
> +    /* Move all interfaces that have been confirmed without ovn-installed,
> +     * from OIF_REMOVE_OVN_INST to OIF_MARK_UP.
> +     */
> +    HMAPX_FOR_EACH_SAFE (node, &mgr->ifaces_per_state[OIF_REMOVE_OVN_INST]) {
> +        struct ovs_iface *iface = node->data;
> +
> +        if (!local_binding_is_ovn_installed(bindings, iface->id)) {
> +            ovs_iface_set_state(mgr, iface, OIF_MARK_UP);
> +        }
> +    }
> +
>      /* Move all interfaces that have been confirmed "up" by the binding module,
>       * from OIF_MARK_UP to OIF_INSTALLED.
>       */
> @@ -325,7 +343,19 @@ if_status_mgr_run(struct if_status_mgr *mgr,
>                                            iface->install_seqno)) {
>              continue;
>          }
> -        ovs_iface_set_state(mgr, iface, OIF_MARK_UP);
> +        /* Wait for ovn-installed to be absent before moving to MARK_UP state.
> +         * Most of the times ovn-installed is already absent and hence we will
> +         * not have to wait.
> +         * If there is no binding_data, we can't determine if ovn-installed is
> +         * present or not; hence also go to the OIF_REMOVE_OVN_INST state.
> +         */
> +        if (!binding_data ||
> +            local_binding_is_ovn_installed(&binding_data->bindings,
> +                                           iface->id)) {
> +            ovs_iface_set_state(mgr, iface, OIF_REMOVE_OVN_INST);
> +        } else {
> +            ovs_iface_set_state(mgr, iface, OIF_MARK_UP);
> +        }
>      }
>      ofctrl_acked_seqnos_destroy(acked_seqnos);
>  
> @@ -412,7 +442,16 @@ if_status_mgr_update_bindings(struct if_status_mgr *mgr,
>                                 sb_readonly, ovs_readonly);
>      }
>  
> -    /* Notifiy the binding module to set "up" all bindings that have had
> +    /* Notify the binding module to remove "ovn-installed" for all bindings
> +     * in the OIF_REMOVE_OVN_INST state.
> +     */
> +    HMAPX_FOR_EACH (node, &mgr->ifaces_per_state[OIF_REMOVE_OVN_INST]) {
> +        struct ovs_iface *iface = node->data;
> +
> +        local_binding_remove_ovn_installed(bindings, iface->id, ovs_readonly);
> +    }
> +
> +    /* Notify the binding module to set "up" all bindings that have had
>       * their flows installed but are not yet marked "up" in the binding
>       * module.
>       */
Dumitru Ceara Sept. 30, 2022, 7:55 a.m. UTC | #2
On 6/28/22 14:35, Dumitru Ceara wrote:
> On 6/27/22 10:52, Xavier Simonart wrote:
>> OVN checks whether ovn-installed is already present (in OVS) before updating it.
>> This might cause ovn-installed related issues in the following case:
>> - (1) ovn-installed is present
>> - (2) we claim the interface
>> - (3) we update ovs, removing ovn-installed and start installing flows
>> - (4) (next loop), after flows installed, we check if ovn-installed is absent,
>>   and if yes, we update OVS with ovn-installed.
>> However, in step4, if OVS is still busy from step 3, ovn-installed is read as
>> present; hence OVN controller does not update it and move to INSTALLED state.
>>
>> Note that this does not happen with writing port up in SBDB because Port status
>> changes will hit I-P.
>>
>> This patch will require updating the state machine description in the
>> "controller: avoid recomputes triggered by SBDB Port_Binding updates." patch
>> when it's merged, as it changes the if-status state-machine.
>>
>> Signed-off-by: Xavier Simonart <xsimonar@redhat.com>
>> ---
> Hi Xavier,
> 
> I only have a couple tiny style related remarks below.  I think those
> can be addressed at apply time if maintainers agree.  Therefore:
> 
> Acked-by: Dumitru Ceara <dceara@redhat.com>
> 

Hi Xavier,

Unfortunately it seems this patch needs a rebase.  Would it be possible
for you to do that and also address the comments I had earlier in a new
revision?

Thanks,
Dumitru
diff mbox series

Patch

diff --git a/controller/binding.c b/controller/binding.c
index 2279570f9..157c381cf 100644
--- a/controller/binding.c
+++ b/controller/binding.c
@@ -643,6 +643,19 @@  local_binding_get_lport_ofport(const struct shash *local_bindings,
             u16_to_ofp(lbinding->iface->ofport[0]) : 0;
 }
 
+bool
+local_binding_is_ovn_installed(struct shash *local_bindings,
+                               const char *pb_name)
+{
+    struct local_binding *lbinding =
+        local_binding_find(local_bindings, pb_name);
+    if (lbinding && lbinding->iface) {
+        return smap_get_bool(&lbinding->iface->external_ids,
+                             OVN_INSTALLED_EXT_ID, false);
+    }
+    return false;
+}
+
 bool
 local_binding_is_up(struct shash *local_bindings, const char *pb_name)
 {
@@ -715,6 +728,22 @@  local_binding_set_up(struct shash *local_bindings, const char *pb_name,
     }
 }
 
+void
+local_binding_remove_ovn_installed(struct shash *local_bindings,
+                                   const char *pb_name, bool ovs_readonly)
+{
+    struct local_binding *lbinding =
+        local_binding_find(local_bindings, pb_name);
+
+    if (!ovs_readonly && lbinding && lbinding->iface
+            && smap_get_bool(&lbinding->iface->external_ids,
+                             OVN_INSTALLED_EXT_ID, false)) {
+        VLOG_INFO("Removing lport %s ovn-installed in OVS", pb_name);
+        ovsrec_interface_update_external_ids_delkey(lbinding->iface,
+                                                    OVN_INSTALLED_EXT_ID);
+    }
+}
+
 void
 local_binding_set_down(struct shash *local_bindings, const char *pb_name,
                        const struct sbrec_chassis *chassis_rec,
@@ -1297,9 +1326,11 @@  consider_vif_lport_(const struct sbrec_port_binding *pb,
             const char *requested_chassis_option = smap_get(
                 &pb->options, "requested-chassis");
             VLOG_INFO_RL(&rl,
-                "Not claiming lport %s, chassis %s requested-chassis %s",
+                "Not claiming lport %s, chassis %s requested-chassis %s "
+                "pb->chassis %s",
                 pb->logical_port, b_ctx_in->chassis_rec->name,
-                requested_chassis_option ? requested_chassis_option : "[]");
+                requested_chassis_option ? requested_chassis_option : "[]",
+                pb->chassis ? pb->chassis->name: "");
         }
     }
 
diff --git a/controller/binding.h b/controller/binding.h
index 1fed06674..445bdd9f2 100644
--- a/controller/binding.h
+++ b/controller/binding.h
@@ -152,6 +152,12 @@  ofp_port_t local_binding_get_lport_ofport(const struct shash *local_bindings,
                                           const char *pb_name);
 
 bool local_binding_is_up(struct shash *local_bindings, const char *pb_name);
+bool local_binding_is_ovn_installed(struct shash *local_bindings,
+                                    const char *pb_name);
+void local_binding_remove_ovn_installed(struct shash *local_bindings,
+                                        const char *pb_name,
+                                        bool ovs_readonly);
+
 bool local_binding_is_down(struct shash *local_bindings, const char *pb_name);
 void local_binding_set_up(struct shash *local_bindings, const char *pb_name,
                           const struct sbrec_chassis *chassis_rec,
diff --git a/controller/if-status.c b/controller/if-status.c
index ad61844d8..fe544c6ec 100644
--- a/controller/if-status.c
+++ b/controller/if-status.c
@@ -57,6 +57,9 @@  enum if_state {
     OIF_INSTALL_FLOWS, /* Already claimed interface for which flows are still
                         * being installed.
                         */
+    OIF_REMOVE_OVN_INST,/* Interface with flows successfully installed in OVS,
+                         * but with ovn-installed still in OVSDB.
+                         */
     OIF_MARK_UP,       /* Interface with flows successfully installed in OVS
                         * but not yet marked "up" in the binding module (in
                         * SB and OVS databases).
@@ -73,6 +76,7 @@  enum if_state {
 static const char *if_state_names[] = {
     [OIF_CLAIMED]       = "CLAIMED",
     [OIF_INSTALL_FLOWS] = "INSTALL_FLOWS",
+    [OIF_REMOVE_OVN_INST] = "REMOVE_OVN_INST",
     [OIF_MARK_UP]       = "MARK_UP",
     [OIF_MARK_DOWN]     = "MARK_DOWN",
     [OIF_INSTALLED]     = "INSTALLED",
@@ -169,6 +173,7 @@  if_status_mgr_claim_iface(struct if_status_mgr *mgr, const char *iface_id)
     switch (iface->state) {
     case OIF_CLAIMED:
     case OIF_INSTALL_FLOWS:
+    case OIF_REMOVE_OVN_INST:
     case OIF_MARK_UP:
         /* Nothing to do here. */
         break;
@@ -199,6 +204,7 @@  if_status_mgr_release_iface(struct if_status_mgr *mgr, const char *iface_id)
         /* Not yet fully installed interfaces can be safely deleted. */
         ovs_iface_destroy(mgr, iface);
         break;
+    case OIF_REMOVE_OVN_INST:
     case OIF_MARK_UP:
     case OIF_INSTALLED:
         /* Properly mark interfaces "down" if their flows were already
@@ -230,6 +236,7 @@  if_status_mgr_delete_iface(struct if_status_mgr *mgr, const char *iface_id)
         /* Not yet fully installed interfaces can be safely deleted. */
         ovs_iface_destroy(mgr, iface);
         break;
+    case OIF_REMOVE_OVN_INST:
     case OIF_MARK_UP:
     case OIF_INSTALLED:
         /* Properly mark interfaces "down" if their flows were already
@@ -257,6 +264,17 @@  if_status_mgr_update(struct if_status_mgr *mgr,
     struct shash *bindings = &binding_data->bindings;
     struct hmapx_node *node;
 
+    /* Move all interfaces that have been confirmed without ovn-installed,
+     * from OIF_REMOVE_OVN_INST to OIF_MARK_UP.
+     */
+    HMAPX_FOR_EACH_SAFE (node, &mgr->ifaces_per_state[OIF_REMOVE_OVN_INST]) {
+        struct ovs_iface *iface = node->data;
+
+        if (!local_binding_is_ovn_installed(bindings, iface->id)) {
+            ovs_iface_set_state(mgr, iface, OIF_MARK_UP);
+        }
+    }
+
     /* Move all interfaces that have been confirmed "up" by the binding module,
      * from OIF_MARK_UP to OIF_INSTALLED.
      */
@@ -325,7 +343,19 @@  if_status_mgr_run(struct if_status_mgr *mgr,
                                           iface->install_seqno)) {
             continue;
         }
-        ovs_iface_set_state(mgr, iface, OIF_MARK_UP);
+        /* Wait for ovn-installed to be absent before moving to MARK_UP state.
+         * Most of the times ovn-installed is already absent and hence we will
+         * not have to wait.
+         * If there is no binding_data, we can't determine if ovn-installed is
+         * present or not; hence also go to the OIF_REMOVE_OVN_INST state.
+         */
+        if (!binding_data ||
+            local_binding_is_ovn_installed(&binding_data->bindings,
+                                           iface->id)) {
+            ovs_iface_set_state(mgr, iface, OIF_REMOVE_OVN_INST);
+        } else {
+            ovs_iface_set_state(mgr, iface, OIF_MARK_UP);
+        }
     }
     ofctrl_acked_seqnos_destroy(acked_seqnos);
 
@@ -412,7 +442,16 @@  if_status_mgr_update_bindings(struct if_status_mgr *mgr,
                                sb_readonly, ovs_readonly);
     }
 
-    /* Notifiy the binding module to set "up" all bindings that have had
+    /* Notify the binding module to remove "ovn-installed" for all bindings
+     * in the OIF_REMOVE_OVN_INST state.
+     */
+    HMAPX_FOR_EACH (node, &mgr->ifaces_per_state[OIF_REMOVE_OVN_INST]) {
+        struct ovs_iface *iface = node->data;
+
+        local_binding_remove_ovn_installed(bindings, iface->id, ovs_readonly);
+    }
+
+    /* Notify the binding module to set "up" all bindings that have had
      * their flows installed but are not yet marked "up" in the binding
      * module.
      */