[ovs-dev] [RFC v2 ovn 3/6] ovn-controller: I-P for port binding in runtime_data stage

numans at ovn.org numans at ovn.org
Tue Mar 3 17:20:42 UTC 2020


From: Numan Siddique <numans at ovn.org>

This patch handles the port binding changes incrementally in the runtime_data
stage.

Signed-off-by: Numan Siddique <numans at ovn.org>
---
 controller/binding.c        | 455 ++++++++++++++++++++++++++++++------
 controller/binding.h        |   7 +-
 controller/ovn-controller.c |  50 +++-
 3 files changed, 431 insertions(+), 81 deletions(-)

diff --git a/controller/binding.c b/controller/binding.c
index 38b426bff..236db32c0 100644
--- a/controller/binding.c
+++ b/controller/binding.c
@@ -349,17 +349,6 @@ setup_qos(const char *egress_iface, struct hmap *queue_map)
     netdev_close(netdev_phy);
 }
 
-static void
-update_local_lport_ids(struct sset *local_lport_ids,
-                       const struct sbrec_port_binding *binding_rec)
-{
-        char buf[16];
-        snprintf(buf, sizeof(buf), "%"PRId64"_%"PRId64,
-                 binding_rec->datapath->tunnel_key,
-                 binding_rec->tunnel_key);
-        sset_add(local_lport_ids, buf);
-}
-
 /*
  * Get the encap from the chassis for this port. The interface
  * may have an external_ids:encap-ip=<encap-ip> set; if so we
@@ -490,6 +479,28 @@ consider_localnet_port(const struct sbrec_port_binding *binding_rec,
     ld->localnet_port = binding_rec;
 }
 
+static void
+update_local_lport_ids(struct sset *local_lport_ids,
+                       const struct sbrec_port_binding *binding_rec)
+{
+        char buf[16];
+        snprintf(buf, sizeof(buf), "%"PRId64"_%"PRId64,
+                 binding_rec->datapath->tunnel_key,
+                 binding_rec->tunnel_key);
+        sset_add(local_lport_ids, buf);
+}
+
+static void
+remove_local_lport_ids(const struct sbrec_port_binding *binding_rec,
+                       struct sset *local_lport_ids)
+{
+        char buf[16];
+        snprintf(buf, sizeof(buf), "%"PRId64"_%"PRId64,
+                 binding_rec->datapath->tunnel_key,
+                 binding_rec->tunnel_key);
+        sset_find_and_delete(local_lport_ids, buf);
+}
+
 enum local_binding_type {
     BT_VIF,
     BT_CHILD,
@@ -545,18 +556,21 @@ local_binding_destroy(struct local_binding *lbinding)
     free(lbinding);
 }
 
+static
+void local_binding_delete(struct shash *local_bindings,
+                          struct local_binding *lbinding)
+{
+    shash_find_and_delete(local_bindings, lbinding->name);
+    local_binding_destroy(lbinding);
+}
+
 void
 local_bindings_destroy(struct shash *local_bindings)
 {
     struct shash_node *node, *next;
     SHASH_FOR_EACH_SAFE (node, next, local_bindings) {
         struct local_binding *lbinding = node->data;
-        struct local_binding *c, *n;
-        LIST_FOR_EACH_SAFE (c, n, node, &lbinding->children) {
-            ovs_list_remove(&c->node);
-            free(c->name);
-            free(c);
-        }
+        local_binding_destroy(lbinding);
     }
 
     shash_destroy(local_bindings);
@@ -651,6 +665,22 @@ release_lport(const struct sbrec_port_binding *pb)
     }
 }
 
+static void
+release_local_binding_children(struct local_binding *lbinding)
+{
+    struct local_binding *l;
+    LIST_FOR_EACH (l, node, &lbinding->children) {
+        release_lport(l->pb);
+    }
+}
+
+static void
+release_local_binding(struct local_binding *lbinding)
+{
+    release_local_binding_children(lbinding);
+    release_lport(lbinding->pb);
+}
+
 static void
 consider_port_binding_for_vif(const struct sbrec_port_binding *pb,
                               struct binding_ctx_in *b_ctx_in,
@@ -725,7 +755,6 @@ consider_port_binding(const struct sbrec_port_binding *pb,
                       struct binding_ctx_out *b_ctx_out,
                       struct hmap *qos_map)
 {
-
     bool our_chassis = is_our_chassis(b_ctx_in->chassis_rec, pb,
                                       b_ctx_in->active_tunnels, NULL,
                                       b_ctx_out->local_lports);
@@ -818,6 +847,8 @@ build_local_bindings_from_local_ifaces(struct binding_ctx_in *b_ctx_in,
                     lbinding->pb = pb;
                 }
                 sset_add(b_ctx_out->local_lports, iface_id);
+                smap_replace(b_ctx_out->local_iface_ids, iface_rec->name,
+                             iface_id);
             }
 
             /* Check if this is a tunnel interface. */
@@ -935,62 +966,6 @@ binding_run(struct binding_ctx_in *b_ctx_in, struct binding_ctx_out *b_ctx_out)
     hmap_destroy(&qos_map);
 }
 
-/* Returns true if port-binding changes potentially require flow changes on
- * the current chassis. Returns false if we are sure there is no impact. */
-bool
-binding_evaluate_port_binding_changes(struct binding_ctx_in *b_ctx_in,
-                                      struct binding_ctx_out *b_ctx_out)
-{
-    if (!b_ctx_in->chassis_rec) {
-        return true;
-    }
-
-    bool changed = false;
-
-    const struct sbrec_port_binding *binding_rec;
-    SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED (binding_rec,
-                                               b_ctx_in->port_binding_table) {
-        /* XXX: currently OVSDB change tracking doesn't support getting old
-         * data when the operation is update, so if a port-binding moved from
-         * this chassis to another, there is no easy way to find out the
-         * change. To workaround this problem, we just makes sure if
-         * any port *related to* this chassis has any change, then trigger
-         * recompute.
-         *
-         * - If a regular VIF is unbound from this chassis, the local ovsdb
-         *   interface table will be updated, which will trigger recompute.
-         *
-         * - If the port is not a regular VIF, always trigger recompute. */
-        if (binding_rec->chassis == b_ctx_in->chassis_rec) {
-            changed = true;
-            break;
-        }
-
-        if (strcmp(binding_rec->type, "")) {
-            changed = true;
-            break;
-        }
-
-        struct local_binding *lbinding = NULL;
-        if (!binding_rec->type[0]) {
-            if (!binding_rec->parent_port || !binding_rec->parent_port[0]) {
-                lbinding = local_binding_find(b_ctx_out->local_bindings,
-                                              binding_rec->logical_port);
-            } else {
-                lbinding = local_binding_find(b_ctx_out->local_bindings,
-                                              binding_rec->parent_port);
-            }
-        }
-
-        if (lbinding) {
-            changed = true;
-            break;
-        }
-    }
-
-    return changed;
-}
-
 /* Returns true if the database is all cleaned up, false if more work is
  * required. */
 bool
@@ -1025,3 +1000,335 @@ binding_cleanup(struct ovsdb_idl_txn *ovnsb_idl_txn,
 
     return !any_changes;
 }
+
+static void
+add_local_datapath_peer_port(const struct sbrec_port_binding *pb,
+                             struct binding_ctx_in *b_ctx_in,
+                             struct binding_ctx_out *b_ctx_out,
+                             struct local_datapath *ld)
+{
+    bool present = false;
+    for (size_t i = 0; i < ld->n_peer_ports; i++) {
+        if (ld->peer_ports[i].local == pb) {
+            present = true;
+            break;
+        }
+    }
+
+    const char *peer_name = smap_get(&pb->options, "peer");
+    if (strcmp(pb->type, "patch") || !peer_name) {
+        return;
+    }
+
+    const struct sbrec_port_binding *peer;
+    peer = lport_lookup_by_name(b_ctx_in->sbrec_port_binding_by_name,
+                                peer_name);
+
+    if (!peer || !peer->datapath) {
+        return;
+    }
+
+    if (!present) {
+        ld->n_peer_ports++;
+        if (ld->n_peer_ports > ld->n_allocated_peer_ports) {
+            ld->peer_ports =
+                x2nrealloc(ld->peer_ports,
+                           &ld->n_allocated_peer_ports,
+                           sizeof *ld->peer_ports);
+        }
+        ld->peer_ports[ld->n_peer_ports - 1].local = pb;
+        ld->peer_ports[ld->n_peer_ports - 1].remote = peer;
+    }
+
+    struct local_datapath *peer_ld =
+        get_local_datapath(b_ctx_out->local_datapaths, peer->datapath->tunnel_key);
+    if (!peer_ld) {
+        add_local_datapath__(b_ctx_in->sbrec_datapath_binding_by_key,
+                             b_ctx_in->sbrec_port_binding_by_datapath,
+                             b_ctx_in->sbrec_port_binding_by_name,
+                             peer->datapath, false,
+                             1, b_ctx_out->local_datapaths);
+        return;
+    }
+
+    for (size_t i = 0; i < peer_ld->n_peer_ports; i++) {
+        if (peer_ld->peer_ports[i].local == peer) {
+            return;
+        }
+    }
+
+    peer_ld->n_peer_ports++;
+    if (peer_ld->n_peer_ports > peer_ld->n_allocated_peer_ports) {
+        peer_ld->peer_ports =
+            x2nrealloc(peer_ld->peer_ports,
+                        &peer_ld->n_allocated_peer_ports,
+                        sizeof *peer_ld->peer_ports);
+    }
+    peer_ld->peer_ports[peer_ld->n_peer_ports - 1].local = peer;
+    peer_ld->peer_ports[peer_ld->n_peer_ports - 1].remote = pb;
+}
+
+static void
+remove_local_datapath_peer_port(const struct sbrec_port_binding *pb,
+                                struct local_datapath *ld,
+                                struct hmap *local_datapaths)
+{
+    size_t i =0;
+    for (i = 0; i < ld->n_peer_ports; i++) {
+        if (ld->peer_ports[i].local == pb) {
+            break;
+        }
+    }
+
+    if (i == ld->n_peer_ports) {
+        return;
+    }
+
+    const struct sbrec_port_binding *peer = ld->peer_ports[i].remote;
+
+    ld->peer_ports[i].local = ld->peer_ports[ld->n_peer_ports - 1].local;
+    ld->peer_ports[i].remote = ld->peer_ports[ld->n_peer_ports - 1].remote;
+    ld->n_peer_ports--;
+
+    struct local_datapath *peer_ld =
+        get_local_datapath(local_datapaths, peer->datapath->tunnel_key);
+    if (peer_ld) {
+        remove_local_datapath_peer_port(peer, peer_ld, local_datapaths);
+    }
+}
+
+static void
+update_local_datapath_for_pb(const struct sbrec_port_binding *pb,
+                             struct binding_ctx_in *b_ctx_in,
+                             struct binding_ctx_out *b_ctx_out,
+                             struct local_datapath *ld)
+{
+    if (!strcmp(pb->type, "patch")) {
+        add_local_datapath_peer_port(pb, b_ctx_in, b_ctx_out, ld);
+    } else if (!strcmp(pb->type, "localnet")) {
+        struct shash bridge_mappings = SHASH_INITIALIZER(&bridge_mappings);
+        add_ovs_bridge_mappings(b_ctx_in->ovs_table, b_ctx_in->bridge_table,
+                                &bridge_mappings);
+        consider_localnet_port(pb, &bridge_mappings, b_ctx_out->egress_ifaces,
+                               b_ctx_out->local_datapaths);
+        shash_destroy(&bridge_mappings);
+    } else if (!strcmp(pb->type, "l3gateway")) {
+        const char *chassis_id = smap_get(&pb->options,
+                                          "l3gateway-chassis");
+        if (chassis_id && !strcmp(chassis_id, b_ctx_in->chassis_rec->name)) {
+            ld->has_local_l3gateway = true;
+        }
+    }
+
+    if (!strcmp(pb->type, "patch") ||
+        !strcmp(pb->type, "localport") ||
+        !strcmp(pb->type, "vtep")) {
+        update_local_lport_ids(b_ctx_out->local_lport_ids, pb);
+    }
+}
+
+static void
+remove_pb_from_local_datapath(const struct sbrec_port_binding *pb,
+                              const struct sbrec_chassis *chassis_rec,
+                              struct binding_ctx_out *b_ctx_out,
+                              struct local_datapath *ld)
+{
+    remove_local_lport_ids(pb, b_ctx_out->local_lport_ids);
+    if (!strcmp(pb->type, "patch") ||
+        !strcmp(pb->type, "l3gateway")) {
+        remove_local_datapath_peer_port(pb, ld, b_ctx_out->local_datapaths);
+    } else if (!strcmp(pb->type, "localnet")) {
+        if (ld->localnet_port && !strcmp(ld->localnet_port->logical_port,
+                                         pb->logical_port)) {
+            ld->localnet_port = NULL;
+        }
+    } else if (!strcmp(pb->type, "l3gateway")) {
+        const char *chassis_id = smap_get(&pb->options,
+                                          "l3gateway-chassis");
+        if (chassis_id && !strcmp(chassis_id, chassis_rec->name)) {
+            ld->has_local_l3gateway = false;
+        }
+    }
+}
+
+bool
+binding_handle_ovs_interface_changes(struct binding_ctx_in *b_ctx_in,
+                                     struct binding_ctx_out *b_ctx_out)
+{
+    if (!b_ctx_in->chassis_rec) {
+        return false;
+    }
+
+    bool handled = true;
+    struct hmap qos_map = HMAP_INITIALIZER(&qos_map);
+    struct hmap *qos_map_ptr =
+        sset_is_empty(b_ctx_out->egress_ifaces) ? NULL : &qos_map;
+
+    const struct ovsrec_interface *iface_rec;
+    OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, b_ctx_in->iface_table) {
+        const char *iface_id = smap_get(&iface_rec->external_ids, "iface-id");
+        const char *old_iface_id = smap_get(b_ctx_out->local_iface_ids,
+                                            iface_rec->name);
+        if (iface_rec->type && iface_rec->type[0]) {
+            handled = false;
+            goto out;
+        }
+
+        struct local_binding *lbinding = NULL;
+        struct local_binding *claim_lbinding = NULL;
+        const char *cleared_iface_id = NULL;
+        int64_t ofport = iface_rec->n_ofport ? *iface_rec->ofport : 0;
+        if (!ovsrec_interface_is_deleted(iface_rec)) {
+            if (iface_id) {
+                /* Check if iface_id is changed. If so we need to
+                 * release the old port binding and associate this
+                 * inteface to new port binding. */
+                if (old_iface_id && strcmp(iface_id, old_iface_id)) {
+                    cleared_iface_id = old_iface_id;
+                }
+            } else if (old_iface_id) {
+                cleared_iface_id = old_iface_id;
+            }
+        } else {
+            cleared_iface_id = iface_id;
+            iface_id = NULL;
+        }
+
+        if (cleared_iface_id) {
+            lbinding = local_binding_find(b_ctx_out->local_bindings,
+                                          cleared_iface_id);
+            if (lbinding && lbinding->pb &&
+                lbinding->pb->chassis == b_ctx_in->chassis_rec) {
+                release_local_binding(lbinding);
+                struct local_datapath *ld =
+                    get_local_datapath(b_ctx_out->local_datapaths,
+                                       lbinding->pb->datapath->tunnel_key);
+                if (ld) {
+                    remove_pb_from_local_datapath(lbinding->pb, b_ctx_in->chassis_rec,
+                                                  b_ctx_out, ld);
+                }
+                local_binding_delete(b_ctx_out->local_bindings, lbinding);
+            }
+
+            sset_find_and_delete(b_ctx_out->local_lports, cleared_iface_id);
+            smap_remove(b_ctx_out->local_iface_ids, iface_rec->name);
+        }
+
+        if (iface_id && ofport > 0) {
+            sset_add(b_ctx_out->local_lports, iface_id);
+            smap_replace(b_ctx_out->local_iface_ids, iface_rec->name,
+                             iface_id);
+            claim_lbinding =
+                local_binding_find(b_ctx_out->local_bindings, iface_id);
+            if (!claim_lbinding) {
+                claim_lbinding = local_binding_create(iface_id, iface_rec,
+                                                      NULL, BT_VIF);
+                local_binding_add(b_ctx_out->local_bindings, claim_lbinding);
+            } else {
+                claim_lbinding->iface = iface_rec;
+            }
+
+            if (!claim_lbinding->pb ||
+                strcmp(claim_lbinding->name,
+                       claim_lbinding->pb->logical_port)) {
+                claim_lbinding->pb =
+                    lport_lookup_by_name(b_ctx_in->sbrec_port_binding_by_name,
+                                         claim_lbinding->name);
+            }
+
+            if (claim_lbinding->pb) {
+                consider_port_binding_for_vif(claim_lbinding->pb, b_ctx_in,
+                                              BT_VIF, claim_lbinding,
+                                              b_ctx_out, qos_map_ptr);
+            }
+        }
+    }
+
+    if (qos_map_ptr && set_noop_qos(b_ctx_in->ovs_idl_txn, b_ctx_in->port_table,
+                                    b_ctx_in->qos_table, b_ctx_out->egress_ifaces)) {
+        const char *entry;
+        SSET_FOR_EACH (entry, b_ctx_out->egress_ifaces) {
+            setup_qos(entry, &qos_map);
+        }
+    }
+
+    hmap_destroy(&qos_map);
+out:
+    return handled;
+}
+
+bool
+binding_handle_port_binding_changes(struct binding_ctx_in *b_ctx_in,
+                                    struct binding_ctx_out *b_ctx_out)
+{
+    if (!b_ctx_in->chassis_rec) {
+        return false;
+    }
+
+    bool handled = true;
+    struct hmap qos_map = HMAP_INITIALIZER(&qos_map);
+    struct hmap *qos_map_ptr =
+        sset_is_empty(b_ctx_out->egress_ifaces) ? NULL : &qos_map;
+
+    const struct sbrec_port_binding *pb;
+    SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED (pb, b_ctx_in->port_binding_table) {
+        bool consider_for_vif = false;
+        struct local_binding *lbinding = NULL;
+        enum local_binding_type binding_type = BT_VIF;
+        bool is_deleted = sbrec_port_binding_is_deleted(pb);
+        if (!pb->type[0]) {
+            if (!pb->parent_port || !pb->parent_port[0]) {
+                lbinding = local_binding_find(b_ctx_out->local_bindings,
+                                              pb->logical_port);
+            } else {
+                lbinding = local_binding_find(b_ctx_out->local_bindings,
+                                              pb->parent_port);
+                binding_type = BT_CHILD;
+            }
+
+            consider_for_vif = true;
+        } else if (!strcmp(pb->type, "virtual") &&
+                   pb->virtual_parent && pb->virtual_parent[0]) {
+            lbinding = local_binding_find(b_ctx_out->local_bindings,
+                                          pb->virtual_parent);
+            consider_for_vif = true;
+            binding_type = BT_VIRTUAL;
+        }
+
+        if (is_deleted) {
+            if (lbinding) {
+                lbinding->pb = NULL;
+
+                if (binding_type == BT_VIF) {
+                    release_local_binding_children(lbinding);
+                }
+            }
+
+            struct local_datapath *ld =
+                get_local_datapath(b_ctx_out->local_datapaths,
+                                   pb->datapath->tunnel_key);
+            if (ld) {
+                remove_pb_from_local_datapath(pb, b_ctx_in->chassis_rec, b_ctx_out, ld);
+            }
+        } else {
+            if (consider_for_vif) {
+                if (lbinding) {
+                    lbinding->pb = pb;
+                    consider_port_binding_for_vif(pb, b_ctx_in, binding_type,
+                                                  lbinding, b_ctx_out,
+                                                  qos_map_ptr);
+                }
+            } else {
+                consider_port_binding(pb, b_ctx_in, b_ctx_out, qos_map_ptr);
+                struct local_datapath *ld =
+                    get_local_datapath(b_ctx_out->local_datapaths,
+                                       pb->datapath->tunnel_key);
+                if (ld) {
+                    update_local_datapath_for_pb(pb, b_ctx_in, b_ctx_out, ld);
+                }
+            }
+        }
+    }
+
+    return handled;
+}
diff --git a/controller/binding.h b/controller/binding.h
index 6bee1d12e..95ca0367d 100644
--- a/controller/binding.h
+++ b/controller/binding.h
@@ -56,6 +56,7 @@ struct binding_ctx_out {
     struct sset *local_lports;
     struct sset *local_lport_ids;
     struct sset *egress_ifaces;
+    struct smap *local_iface_ids;
 };
 
 void binding_register_ovs_idl(struct ovsdb_idl *);
@@ -63,10 +64,12 @@ void binding_run(struct binding_ctx_in *, struct binding_ctx_out *);
 bool binding_cleanup(struct ovsdb_idl_txn *ovnsb_idl_txn,
                      const struct sbrec_port_binding_table *,
                      const struct sbrec_chassis *);
-bool binding_evaluate_port_binding_changes(struct binding_ctx_in *,
-                                           struct binding_ctx_out *);
 void local_bindings_destroy(struct shash *local_bindings);
 void binding_add_vport_to_local_bindings(
     struct shash *local_bindings, const struct sbrec_port_binding *parent,
     const struct sbrec_port_binding *vport);
+bool binding_handle_ovs_interface_changes(struct binding_ctx_in *,
+                                          struct binding_ctx_out *);
+bool binding_handle_port_binding_changes(struct binding_ctx_in *,
+                                         struct binding_ctx_out *);
 #endif /* controller/binding.h */
diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
index 8cc27cebf..8502b17ed 100644
--- a/controller/ovn-controller.c
+++ b/controller/ovn-controller.c
@@ -753,6 +753,7 @@ enum sb_engine_node {
     OVS_NODE(open_vswitch, "open_vswitch") \
     OVS_NODE(bridge, "bridge") \
     OVS_NODE(port, "port") \
+    OVS_NODE(interface, "interface") \
     OVS_NODE(qos, "qos")
 
 enum ovs_engine_node {
@@ -974,6 +975,7 @@ struct ed_type_runtime_data {
     struct sset active_tunnels;
 
     struct sset egress_ifaces;
+    struct smap local_iface_ids;
 };
 
 static void *
@@ -988,6 +990,7 @@ en_runtime_data_init(struct engine_node *node OVS_UNUSED,
     sset_init(&data->active_tunnels);
     sset_init(&data->egress_ifaces);
     shash_init(&data->local_bindings);
+    smap_init(&data->local_iface_ids);
     return data;
 }
 
@@ -1000,6 +1003,7 @@ en_runtime_data_cleanup(void *data)
     sset_destroy(&rt_data->local_lport_ids);
     sset_destroy(&rt_data->active_tunnels);
     sset_init(&rt_data->egress_ifaces);
+    smap_destroy(&rt_data->local_iface_ids);
     struct local_datapath *cur_node, *next_node;
     HMAP_FOR_EACH_SAFE (cur_node, next_node, hmap_node,
                         &rt_data->local_datapaths) {
@@ -1041,6 +1045,10 @@ init_binding_ctx(struct engine_node *node,
         (struct ovsrec_port_table *)EN_OVSDB_GET(
             engine_get_input("OVS_port", node));
 
+    struct ovsrec_interface_table *iface_table =
+        (struct ovsrec_interface_table *)EN_OVSDB_GET(
+            engine_get_input("OVS_interface", node));
+
     struct ovsrec_qos_table *qos_table =
         (struct ovsrec_qos_table *)EN_OVSDB_GET(
             engine_get_input("OVS_qos", node));
@@ -1070,6 +1078,7 @@ init_binding_ctx(struct engine_node *node,
     b_ctx_in->sbrec_port_binding_by_datapath = sbrec_port_binding_by_datapath;
     b_ctx_in->sbrec_port_binding_by_name = sbrec_port_binding_by_name;
     b_ctx_in->port_table = port_table;
+    b_ctx_in->iface_table = iface_table;
     b_ctx_in->qos_table = qos_table;
     b_ctx_in->port_binding_table = pb_table;
     b_ctx_in->br_int = br_int;
@@ -1083,6 +1092,7 @@ init_binding_ctx(struct engine_node *node,
     b_ctx_out->local_lport_ids = &rt_data->local_lport_ids;
     b_ctx_out->egress_ifaces = &rt_data->egress_ifaces;
     b_ctx_out->local_bindings = &rt_data->local_bindings;
+    b_ctx_out->local_iface_ids = &rt_data->local_iface_ids;
 }
 
 static void
@@ -1110,10 +1120,12 @@ en_runtime_data_run(struct engine_node *node, void *data)
         sset_destroy(local_lport_ids);
         sset_destroy(active_tunnels);
         sset_destroy(&rt_data->egress_ifaces);
+        smap_destroy(&rt_data->local_iface_ids);
         sset_init(local_lports);
         sset_init(local_lport_ids);
         sset_init(active_tunnels);
         sset_init(&rt_data->egress_ifaces);
+        smap_init(&rt_data->local_iface_ids);
     }
 
     struct binding_ctx_in b_ctx_in;
@@ -1139,17 +1151,42 @@ en_runtime_data_run(struct engine_node *node, void *data)
 }
 
 static bool
-runtime_data_sb_port_binding_handler(struct engine_node *node, void *data)
+runtime_data_ovs_interface_handler(struct engine_node *node, void *data)
 {
+    if (!engine_get_context()->ovnsb_idl_txn) {
+        return false;
+    }
+
     struct ed_type_runtime_data *rt_data = data;
     struct binding_ctx_in b_ctx_in;
     struct binding_ctx_out b_ctx_out;
     init_binding_ctx(node, rt_data, &b_ctx_in, &b_ctx_out);
 
-    bool changed = binding_evaluate_port_binding_changes(&b_ctx_in,
-                                                         &b_ctx_out);
+    engine_set_node_state(node, EN_UPDATED);
+    return binding_handle_ovs_interface_changes(&b_ctx_in, &b_ctx_out);
+}
+
+static bool
+runtime_data_noop_handler(struct engine_node *node OVS_UNUSED,
+                          void *data OVS_UNUSED)
+{
+    return true;
+}
+
+static bool
+runtime_data_sb_port_binding_handler(struct engine_node *node, void *data)
+{
+    if (!engine_get_context()->ovnsb_idl_txn) {
+        return false;
+    }
 
-    return !changed;
+    struct ed_type_runtime_data *rt_data = data;
+    struct binding_ctx_in b_ctx_in;
+    struct binding_ctx_out b_ctx_out;
+    init_binding_ctx(node, rt_data, &b_ctx_in, &b_ctx_out);
+
+    engine_set_node_state(node, EN_UPDATED);
+    return binding_handle_port_binding_changes(&b_ctx_in, &b_ctx_out);
 }
 
 /* Connection tracking zones. */
@@ -1891,7 +1928,10 @@ main(int argc, char *argv[])
 
     engine_add_input(&en_runtime_data, &en_ovs_open_vswitch, NULL);
     engine_add_input(&en_runtime_data, &en_ovs_bridge, NULL);
-    engine_add_input(&en_runtime_data, &en_ovs_port, NULL);
+    engine_add_input(&en_runtime_data, &en_ovs_port,
+                     runtime_data_noop_handler);
+    engine_add_input(&en_runtime_data, &en_ovs_interface,
+                     runtime_data_ovs_interface_handler);
     engine_add_input(&en_runtime_data, &en_ovs_qos, NULL);
 
     engine_add_input(&en_runtime_data, &en_sb_chassis, NULL);
-- 
2.24.1



More information about the dev mailing list