@@ -580,6 +580,98 @@ binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int,
hmap_destroy(&qos_map);
}
+static bool
+is_our_chassis(const struct chassis_index *chassis_index,
+ struct sset *active_tunnels,
+ const struct sbrec_chassis *chassis_rec,
+ const struct sbrec_port_binding *binding_rec,
+ struct shash *lport_to_iface,
+ struct sset *local_lports)
+{
+ const struct ovsrec_interface *iface_rec
+ = shash_find_data(lport_to_iface, binding_rec->logical_port);
+ struct ovs_list *gateway_chassis = NULL;
+
+ bool our_chassis = false;
+ if (iface_rec
+ || (binding_rec->parent_port && binding_rec->parent_port[0] &&
+ sset_contains(local_lports, binding_rec->parent_port))) {
+ /* This port is in our chassis unless it is a localport. */
+ if (strcmp(binding_rec->type, "localport")) {
+ our_chassis = true;
+ }
+ } else if (!strcmp(binding_rec->type, "l2gateway")) {
+ const char *chassis_id = smap_get(&binding_rec->options,
+ "l2gateway-chassis");
+ our_chassis = chassis_id && !strcmp(chassis_id, chassis_rec->name);
+ } else if (!strcmp(binding_rec->type, "chassisredirect")) {
+ gateway_chassis = gateway_chassis_get_ordered(binding_rec,
+ chassis_index);
+ if (gateway_chassis &&
+ gateway_chassis_contains(gateway_chassis, chassis_rec)) {
+
+ our_chassis = gateway_chassis_is_active(
+ gateway_chassis, chassis_rec, active_tunnels);
+
+ }
+ gateway_chassis_destroy(gateway_chassis);
+ } else if (!strcmp(binding_rec->type, "l3gateway")) {
+ const char *chassis_id = smap_get(&binding_rec->options,
+ "l3gateway-chassis");
+ our_chassis = chassis_id && !strcmp(chassis_id, chassis_rec->name);
+ } else if (!strcmp(binding_rec->type, "localnet")) {
+ our_chassis = false;
+ }
+
+ return our_chassis;
+}
+
+/* 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 controller_ctx *ctx, const struct ovsrec_bridge *br_int,
+ const struct sbrec_chassis *chassis_rec,
+ const struct chassis_index *chassis_index,
+ struct sset *active_tunnels,
+ struct sset *local_lports)
+{
+ if (!chassis_rec) {
+ return true;
+ }
+
+ const struct sbrec_port_binding *binding_rec;
+ struct shash lport_to_iface = SHASH_INITIALIZER(&lport_to_iface);
+ struct sset egress_ifaces = SSET_INITIALIZER(&egress_ifaces);
+ if (br_int) {
+ get_local_iface_ids(br_int, &lport_to_iface, local_lports,
+ &egress_ifaces);
+ }
+ SBREC_PORT_BINDING_FOR_EACH_TRACKED (binding_rec, ctx->ovnsb_idl) {
+ /* 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, we would not know it with this check.
+ * However, if the port is unbound from this chassis, the local ovsdb
+ * interface table will be updated, which will trigger recompute.
+ * If the port is still bound on this chassis, then below check
+ * is_our_chassis() will take care that case. */
+ if (binding_rec->chassis == chassis_rec) {
+ return true;
+ }
+ if (is_our_chassis(chassis_index,
+ active_tunnels, chassis_rec, binding_rec,
+ &lport_to_iface,
+ local_lports)
+ || !strcmp(binding_rec->type, "patch")
+ || !strcmp(binding_rec->type, "localport")
+ || !strcmp(binding_rec->type, "vtep")
+ || !strcmp(binding_rec->type, "localnet")) {
+ return true;
+ }
+ }
+ return false;
+}
+
/* Returns true if the database is all cleaned up, false if more work is
* required. */
bool
@@ -34,5 +34,11 @@ void binding_run(struct controller_ctx *, const struct ovsrec_bridge *br_int,
struct sset *active_tunnels, struct hmap *local_datapaths,
struct sset *local_lports, struct sset *local_lport_ids);
bool binding_cleanup(struct controller_ctx *, const struct sbrec_chassis *);
+bool binding_evaluate_port_binding_changes(
+ struct controller_ctx *ctx, const struct ovsrec_bridge *br_int,
+ const struct sbrec_chassis *chassis_rec,
+ const struct chassis_index *chassis_index,
+ struct sset *active_tunnels,
+ struct sset *local_lports);
#endif /* ovn/binding.h */
@@ -741,6 +741,32 @@ runtime_data_run(struct engine_node *node)
node->changed = true;
}
+static bool
+runtime_data_sb_port_binding_handler(struct engine_node *node)
+{
+ struct controller_ctx *ctx = (struct controller_ctx *)node->context;
+ struct ed_type_runtime_data *data =
+ (struct ed_type_runtime_data *)node->data;
+ struct sset *local_lports = &data->local_lports;
+ struct sset *active_tunnels = &data->active_tunnels;
+ struct chassis_index *chassis_index = &data->chassis_index;
+
+ const char *chassis_id = get_chassis_id(ctx->ovs_idl);
+ const struct ovsrec_bridge *br_int = get_br_int(ctx);
+
+ ovs_assert(br_int && chassis_id);
+ const struct sbrec_chassis *chassis = NULL;
+ chassis = get_chassis(ctx->ovnsb_idl, chassis_id);
+ ovs_assert(chassis);
+
+ bool changed = binding_evaluate_port_binding_changes(
+ ctx, br_int, chassis,
+ chassis_index, active_tunnels,
+ local_lports);
+
+ return !changed;
+}
+
struct ed_type_flow_output {
/* desired flows */
struct ovn_desired_flow_table flow_table;
@@ -970,7 +996,7 @@ main(int argc, char *argv[])
engine_add_input(&en_runtime_data, &en_sb_address_set, NULL);
engine_add_input(&en_runtime_data, &en_sb_port_group, NULL);
engine_add_input(&en_runtime_data, &en_sb_datapath_binding, NULL);
- engine_add_input(&en_runtime_data, &en_sb_port_binding, NULL);
+ engine_add_input(&en_runtime_data, &en_sb_port_binding, runtime_data_sb_port_binding_handler);
engine_add_input(&en_runtime_data, &en_sb_gateway_chassis, NULL);
engine_init(&en_flow_output);
Evaluates change for SB port-binding in runtime_data node. If the port-binding change has no impact for the runtime_data it will not trigger runtime_data change. Signed-off-by: Han Zhou <hzhou8@ebay.com> --- ovn/controller/binding.c | 92 +++++++++++++++++++++++++++++++++++++++++ ovn/controller/binding.h | 6 +++ ovn/controller/ovn-controller.c | 28 ++++++++++++- 3 files changed, 125 insertions(+), 1 deletion(-)