On Wed, May 27, 2020 at 9:15 PM Dumitru Ceara <dce...@redhat.com> wrote:
> On 5/26/20 2:28 PM, num...@ovn.org wrote: > > From: Numan Siddique <num...@ovn.org> > > > > This patch adds a new data structure - 'struct local_binding' which > represents > > a probable local port binding. A new object of this structure is creared > for > > each interface present in the integration bridge (br-int) with the > > external_ids:iface-id set. This struct has 2 main fields > > - 'struct ovsrec_interface *' and 'struct sbrec_port_binding *'. These > fields > > are updated during port claim and release. > > > > A shash of the local bindings is maintained with the 'iface-id' as the > hash key > > in the runtime data of the incremental processing engine. > > > > This patch helps in the upcoming patch to add incremental processing > support > > for OVS interface and SB port binding changes. > > > > This patch also refactors the port binding code by adding a port binding > function > > for each port binding type. > > > > Acked-by: Mark Michelson <mmich...@redhat.com> > > Signed-off-by: Numan Siddique <num...@ovn.org> > > Hi Numan, > > Maybe I'm wrong but won't your changes revert commit: > > 1cadfb515124 ("ovn-controller: Skip vport bindings done through OVS > external_ids:iface-id.") > > Or at least I don't see the warning being logged anymore. > > It doesn't revert the comment, but it doesn't log the warning anymore. It's because of the way it is refactored now. Lets say you have an ovs interface with external_ids:iface-id=sw0-vir and the logical port 'sw0-vir' is of type 'virtual'. When binding_run() calls build_local_bindings(), it creates a local_binding for sw0-vir and the iface rec is set. Later binding_run() for virtual port binding 'sw0-vir', calls consider_virtual_lport() and it looks for the local_binding for its parent. It never looks for 'sw0-vir' in local bindings. I thought about this warning, but is it worth the lookup in the local bindings shash to see if there is a VIF interface for it ? The VIF will be ignored like any other VIF configured with external_ids:iface-id but with no corresponding port binding row in SB DB. If you want I can put it, but it's a waste of shash lookup for every virtual port binding. A few more comments inline. > > Thanks, > Dumitru > > > --- > > controller/binding.c | 1012 ++++++++++++++++++++++++----------- > > controller/binding.h | 14 +- > > controller/ovn-controller.c | 48 +- > > tests/ovn.at | 36 ++ > > 4 files changed, 754 insertions(+), 356 deletions(-) > > > > diff --git a/controller/binding.c b/controller/binding.c > > index 79dc046d9..2997fcae8 100644 > > --- a/controller/binding.c > > +++ b/controller/binding.c > > @@ -69,47 +69,6 @@ binding_register_ovs_idl(struct ovsdb_idl *ovs_idl) > > ovsdb_idl_add_column(ovs_idl, &ovsrec_qos_col_type); > > } > > > > -static void > > -get_local_iface_ids(const struct ovsrec_bridge *br_int, > > - struct shash *lport_to_iface, > > - struct sset *local_lports, > > - struct sset *egress_ifaces) > > -{ > > - int i; > > - > > - for (i = 0; i < br_int->n_ports; i++) { > > - const struct ovsrec_port *port_rec = br_int->ports[i]; > > - const char *iface_id; > > - int j; > > - > > - if (!strcmp(port_rec->name, br_int->name)) { > > - continue; > > - } > > - > > - for (j = 0; j < port_rec->n_interfaces; j++) { > > - const struct ovsrec_interface *iface_rec; > > - > > - iface_rec = port_rec->interfaces[j]; > > - iface_id = smap_get(&iface_rec->external_ids, "iface-id"); > > - int64_t ofport = iface_rec->n_ofport ? *iface_rec->ofport : > 0; > > - > > - if (iface_id && ofport > 0) { > > - shash_add(lport_to_iface, iface_id, iface_rec); > > - sset_add(local_lports, iface_id); > > - } > > - > > - /* Check if this is a tunnel interface. */ > > - if (smap_get(&iface_rec->options, "remote_ip")) { > > - const char *tunnel_iface > > - = smap_get(&iface_rec->status, > "tunnel_egress_iface"); > > - if (tunnel_iface) { > > - sset_add(egress_ifaces, tunnel_iface); > > - } > > - } > > - } > > - } > > -} > > - > > static void > > add_local_datapath__(struct ovsdb_idl_index > *sbrec_datapath_binding_by_key, > > struct ovsdb_idl_index > *sbrec_port_binding_by_datapath, > > @@ -448,219 +407,6 @@ sbrec_get_port_encap(const struct sbrec_chassis > *chassis_rec, > > return best_encap; > > } > > > > -static bool > > -is_our_chassis(const struct sbrec_chassis *chassis_rec, > > - const struct sbrec_port_binding *binding_rec, > > - const struct sset *active_tunnels, > > - const struct ovsrec_interface *iface_rec, > > - const struct sset *local_lports) > > -{ > > - /* Ports of type "virtual" should never be explicitly bound to an > OVS > > - * port in the integration bridge. If that's the case, ignore the > binding > > - * and log a warning. > > - */ > > - if (iface_rec && !strcmp(binding_rec->type, "virtual")) { > > - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); > > - VLOG_WARN_RL(&rl, > > - "Virtual port %s should not be bound to OVS port > %s", > > - binding_rec->logical_port, iface_rec->name); > > - return false; > > - } > > - > > - 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. */ > > - our_chassis = strcmp(binding_rec->type, "localport"); > > - } 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") || > > - !strcmp(binding_rec->type, "external")) { > > - our_chassis = > ha_chassis_group_contains(binding_rec->ha_chassis_group, > > - chassis_rec) && > > - > ha_chassis_group_is_active(binding_rec->ha_chassis_group, > > - active_tunnels, > chassis_rec); > > - } 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); > > - } > > - > > - return our_chassis; > > -} > > - > > -/* Updates 'binding_rec' and if the port binding is local also updates > the > > - * local datapaths and ports. > > - * Updates and returns the array of local virtual ports that will > require > > - * additional processing. > > - */ > > -static const struct sbrec_port_binding ** > > -consider_local_datapath(const struct sbrec_port_binding *binding_rec, > > - const struct ovsrec_interface *iface_rec, > > - struct binding_ctx_in *b_ctx_in, > > - struct binding_ctx_out *b_ctx_out, > > - struct hmap *qos_map, > > - const struct sbrec_port_binding **vpbs, > > - size_t *n_vpbs, size_t *n_allocated_vpbs) > > -{ > > - bool our_chassis = is_our_chassis(b_ctx_in->chassis_rec, > binding_rec, > > - b_ctx_in->active_tunnels, > iface_rec, > > - b_ctx_out->local_lports); > > - if (iface_rec > > - || (binding_rec->parent_port && binding_rec->parent_port[0] && > > - sset_contains(b_ctx_out->local_lports, > > - binding_rec->parent_port))) { > > - if (binding_rec->parent_port && binding_rec->parent_port[0]) { > > - /* Add child logical port to the set of all local ports. */ > > - sset_add(b_ctx_out->local_lports, > binding_rec->logical_port); > > - } > > - 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, > > - binding_rec->datapath, false, > > - b_ctx_out->local_datapaths); > > - if (iface_rec && qos_map && b_ctx_in->ovs_idl_txn) { > > - get_qos_params(binding_rec, qos_map); > > - } > > - } else if (!strcmp(binding_rec->type, "l2gateway")) { > > - if (our_chassis) { > > - sset_add(b_ctx_out->local_lports, > binding_rec->logical_port); > > - 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, > > - binding_rec->datapath, false, > > - b_ctx_out->local_datapaths); > > - } > > - } else if (!strcmp(binding_rec->type, "chassisredirect")) { > > - if (ha_chassis_group_contains(binding_rec->ha_chassis_group, > > - b_ctx_in->chassis_rec)) { > > - 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, > > - binding_rec->datapath, false, > > - b_ctx_out->local_datapaths); > > - } > > - } else if (!strcmp(binding_rec->type, "l3gateway")) { > > - if (our_chassis) { > > - 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, > > - binding_rec->datapath, true, > > - b_ctx_out->local_datapaths); > > - } > > - } else if (!strcmp(binding_rec->type, "localnet")) { > > - /* Add all localnet ports to local_lports so that we allocate > ct zones > > - * for them. */ > > - sset_add(b_ctx_out->local_lports, binding_rec->logical_port); > > - if (qos_map && b_ctx_in->ovs_idl_txn) { > > - get_qos_params(binding_rec, qos_map); > > - } > > - } else if (!strcmp(binding_rec->type, "external")) { > > - if (ha_chassis_group_contains(binding_rec->ha_chassis_group, > > - b_ctx_in->chassis_rec)) { > > - 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, > > - binding_rec->datapath, false, > > - b_ctx_out->local_datapaths); > > - } > > - } > > - > > - if (our_chassis > > - || !strcmp(binding_rec->type, "patch") > > - || !strcmp(binding_rec->type, "localport") > > - || !strcmp(binding_rec->type, "vtep") > > - || !strcmp(binding_rec->type, "localnet")) { > > - update_local_lport_ids(b_ctx_out->local_lport_ids, binding_rec); > > - } > > - > > - ovs_assert(b_ctx_in->ovnsb_idl_txn); > > - const char *vif_chassis = smap_get(&binding_rec->options, > > - "requested-chassis"); > > - bool can_bind = !vif_chassis || !vif_chassis[0] > > - || !strcmp(vif_chassis, b_ctx_in->chassis_rec->name) > > - || !strcmp(vif_chassis, > b_ctx_in->chassis_rec->hostname); > > - > > - if (can_bind && our_chassis) { > > - if (binding_rec->chassis != b_ctx_in->chassis_rec) { > > - if (binding_rec->chassis) { > > - VLOG_INFO("Changing chassis for lport %s from %s to > %s.", > > - binding_rec->logical_port, > > - binding_rec->chassis->name, > > - b_ctx_in->chassis_rec->name); > > - } else { > > - VLOG_INFO("Claiming lport %s for this chassis.", > > - binding_rec->logical_port); > > - } > > - for (int i = 0; i < binding_rec->n_mac; i++) { > > - VLOG_INFO("%s: Claiming %s", > > - binding_rec->logical_port, > binding_rec->mac[i]); > > - } > > - sbrec_port_binding_set_chassis(binding_rec, > b_ctx_in->chassis_rec); > > - } > > - /* Check if the port encap binding, if any, has changed */ > > - struct sbrec_encap *encap_rec = > > - sbrec_get_port_encap(b_ctx_in->chassis_rec, iface_rec); > > - if (encap_rec && binding_rec->encap != encap_rec) { > > - sbrec_port_binding_set_encap(binding_rec, encap_rec); > > - } > > - } else if (binding_rec->chassis == b_ctx_in->chassis_rec) { > > - if (!strcmp(binding_rec->type, "virtual")) { > > - if (*n_vpbs == *n_allocated_vpbs) { > > - vpbs = x2nrealloc(vpbs, n_allocated_vpbs, sizeof *vpbs); > > - } > > - vpbs[(*n_vpbs)] = binding_rec; > > - (*n_vpbs)++; > > - } else { > > - VLOG_INFO("Releasing lport %s from this chassis.", > > - binding_rec->logical_port); > > - if (binding_rec->encap) { > > - sbrec_port_binding_set_encap(binding_rec, NULL); > > - } > > - sbrec_port_binding_set_chassis(binding_rec, NULL); > > - } > > - } else if (our_chassis) { > > - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); > > - VLOG_INFO_RL(&rl, > > - "Not claiming lport %s, chassis %s " > > - "requested-chassis %s", > > - binding_rec->logical_port, > b_ctx_in->chassis_rec->name, > > - vif_chassis); > > - } > > - > > - return vpbs; > > -} > > - > > -static void > > -consider_local_virtual_port(struct ovsdb_idl_index > *sbrec_port_binding_by_name, > > - const struct sbrec_chassis *chassis_rec, > > - const struct sbrec_port_binding > *binding_rec) > > -{ > > - if (binding_rec->virtual_parent) { > > - const struct sbrec_port_binding *parent = > > - lport_lookup_by_name(sbrec_port_binding_by_name, > > - binding_rec->virtual_parent); > > - if (parent && parent->chassis == chassis_rec) { > > - return; > > - } > > - } > > - > > - /* pinctrl module takes care of binding the ports of type 'virtual'. > > - * Release such ports if their virtual parents are no longer > claimed by > > - * this chassis. > > - */ > > - VLOG_INFO("Releasing lport %s from this chassis.", > > - binding_rec->logical_port); > > - if (binding_rec->encap) { > > - sbrec_port_binding_set_encap(binding_rec, NULL); > > - } > > - sbrec_port_binding_set_chassis(binding_rec, NULL); > > - sbrec_port_binding_set_virtual_parent(binding_rec, NULL); > > -} > > - > > static void > > add_localnet_egress_interface_mappings( > > const struct sbrec_port_binding *port_binding, > > @@ -736,6 +482,588 @@ consider_localnet_port(const struct > sbrec_port_binding *binding_rec, > > ld->localnet_port = binding_rec; > > } > > > > +/* Local bindings. binding.c module binds the logical port (represented > by > > + * Port_Binding rows) and sets the 'chassis' column when it is sees the > > Nit: s/it is sees/it sees > Ack. Done. > > > + * OVS interface row (of type "" or "internal") with the > > + * external_ids:iface-id=<logical_port name> set. > > + * > > + * This module also manages the other port_bindings. > > + * > > + * To better manage the local bindings with the associated OVS > interfaces, > > + * 'struct local_binding' is used. A shash of these local bindings is > > + * maintained with the 'external_ids:iface-id' as the key to the shash. > > + * > > + * struct local_binding has 3 main fields: > > + * - type > > + * - OVS interface row object > > + * - Port_Binding row object > > + * > > + * An instance of 'struct local_binding' can be one of 3 types. > > + * > > + * BT_VIF: Represent a local binding for an OVS interface of > > + * type "" or "internal" with the external_ids:iface-id > > + * set. > > + * > > + * This can be a > > + * * probable local binding - external_ids:iface-id is > > + * set, but the corresponding Port_Binding row is not > > + * created or is not visible to the local > ovn-controller > > + * instance. > > + * > > + * * a local binding - external_ids:iface-id is set and > > + * which is already bound to the corresponding > Port_Binding > > + * row. > > + * > > + * It maintains a list of children > > + * (of type BT_CONTAINER/BT_VIRTUAL) if any. > > + * > > + * BT_CONTAINER: Represents a local binding which has a parent of > type > > + * BT_VIF. Its Port_Binding row's 'parent' column is > set to > > + * its parent's Port_Binding. It shares the OVS > interface row > > + * with the parent. > > + * > > + * BT_VIRTUAL: Represents a local binding which has a parent of type > BT_VIF. > > + * Its Port_Binding type is "virtual" and it shares the OVS > > + * interface row with the parent. > > + * Port_Binding of type "virtual" is claimed by pinctrl > module > > + * when it sees the ARP packet from the parent's VIF. > > + * > > + */ > > +enum local_binding_type { > > + BT_VIF, > > + BT_CONTAINER, > > + BT_VIRTUAL > > +}; > > + > > +struct local_binding { > > + char *name; > > + enum local_binding_type type; > > + const struct ovsrec_interface *iface; > > + const struct sbrec_port_binding *pb; > > + > > + /* shash of 'struct local_binding' representing children. */ > > + struct shash children; > > +}; > > + > > +static struct local_binding * > > +local_binding_create(const char *name, const struct ovsrec_interface > *iface, > > + const struct sbrec_port_binding *pb, > > + enum local_binding_type type) > > +{ > > + struct local_binding *lbinding = xzalloc(sizeof *lbinding); > > + lbinding->name = xstrdup(name); > > + lbinding->type = type; > > + lbinding->pb = pb; > > + lbinding->iface = iface; > > + shash_init(&lbinding->children); > > + return lbinding; > > +} > > + > > +static void > > +local_binding_add(struct shash *local_bindings, struct local_binding > *lbinding) > > +{ > > + shash_add(local_bindings, lbinding->name, lbinding); > > +} > > + > > +static struct local_binding * > > +local_binding_find(struct shash *local_bindings, const char *name) > > +{ > > + return shash_find_data(local_bindings, name); > > +} > > + > > +static void > > +local_binding_destroy(struct local_binding *lbinding) > > +{ > > + local_bindings_destroy(&lbinding->children); > > + > > + free(lbinding->name); > > + free(lbinding); > > +} > > + > > +void > > +local_bindings_init(struct shash *local_bindings) > > +{ > > + shash_init(local_bindings); > > +} > > + > > +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; > > + local_binding_destroy(lbinding); > > + shash_delete(local_bindings, node); > > + } > > + > > + shash_destroy(local_bindings); > > +} > > + > > +static void > > +local_binding_add_child(struct local_binding *lbinding, > > + struct local_binding *child) > > +{ > > + local_binding_add(&lbinding->children, child); > > +} > > + > > +static struct local_binding * > > +local_binding_find_child(struct local_binding *lbinding, > > + const char *child_name) > > +{ > > + return local_binding_find(&lbinding->children, child_name); > > +} > > + > > +static bool > > +is_lport_vif(const struct sbrec_port_binding *pb) > > +{ > > + return !pb->type[0]; > > +} > > + > > +static bool > > +is_lport_container(const struct sbrec_port_binding *pb) > > +{ > > + return !pb->type[0] && pb->parent_port && pb->parent_port[0]; > > Nit: I'd probably replace this with: > return is_lport_vif(pb) && pb->parent_port && pb->parent_port[0]; > > > +} > > + > > +enum en_lport_type { > > + LP_UNKNOWN, > > + LP_VIF, > > + LP_PATCH, > > + LP_L3GATEWAY, > > + LP_LOCALNET, > > + LP_LOCALPORT, > > + LP_L2GATEWAY, > > + LP_VTEP, > > + LP_CHASSISREDIRECT, > > + LP_VIRTUAL, > > + LP_EXTERNAL, > > + LP_REMOTE > > +}; > > + > > +static enum en_lport_type > > +get_lport_type(const struct sbrec_port_binding *pb) > > +{ > > + if (is_lport_vif(pb)) { > > + return LP_VIF; > > + } else if (!strcmp(pb->type, "patch")) { > > + return LP_PATCH; > > + } else if (!strcmp(pb->type, "chassisredirect")) { > > + return LP_CHASSISREDIRECT; > > + } else if (!strcmp(pb->type, "l3gateway")) { > > + return LP_L3GATEWAY; > > + } else if (!strcmp(pb->type, "localnet")) { > > + return LP_LOCALNET; > > + } else if (!strcmp(pb->type, "localport")) { > > + return LP_LOCALPORT; > > + } else if (!strcmp(pb->type, "l2gateway")) { > > + return LP_L2GATEWAY; > > + } else if (!strcmp(pb->type, "virtual")) { > > + return LP_VIRTUAL; > > + } else if (!strcmp(pb->type, "external")) { > > + return LP_EXTERNAL; > > + } else if (!strcmp(pb->type, "remote")) { > > + return LP_REMOTE; > > + } else if (!strcmp(pb->type, "vtep")) { > > + return LP_VTEP; > > + } > > + > > + return LP_UNKNOWN; > > +} > > + > > +static void > > +claim_lport(const struct sbrec_port_binding *pb, > > + const struct sbrec_chassis *chassis_rec, > > + const struct ovsrec_interface *iface_rec) > > +{ > > + if (pb->chassis != chassis_rec) { > > + if (pb->chassis) { > > + VLOG_INFO("Changing chassis for lport %s from %s to %s.", > > + pb->logical_port, pb->chassis->name, > > + chassis_rec->name); > > + } else { > > + VLOG_INFO("Claiming lport %s for this chassis.", > pb->logical_port); > > + } > > + for (int i = 0; i < pb->n_mac; i++) { > > + VLOG_INFO("%s: Claiming %s", pb->logical_port, pb->mac[i]); > > + } > > + > > + sbrec_port_binding_set_chassis(pb, chassis_rec); > > + } > > + > > + /* Check if the port encap binding, if any, has changed */ > > + struct sbrec_encap *encap_rec = > > + sbrec_get_port_encap(chassis_rec, iface_rec); > > + if (encap_rec && pb->encap != encap_rec) { > > + sbrec_port_binding_set_encap(pb, encap_rec); > > + } > > +} > > + > > +static void > > +release_lport(const struct sbrec_port_binding *pb) > > +{ > > + if (!pb) { > > + return; > > + } > > We don't check for NULL pb in claim_lport(). And as far as I can see in > all places where release_lport() is called the pb can't be NULL. I'd > either check for NULL pb in both functions or skip the check completely > as this is a static function and we control the way it's called. > I will remove the check for NULL in release_lport. > > + > > + VLOG_INFO("Releasing lport %s from this chassis.", > pb->logical_port); > > + if (pb->encap) { > > + sbrec_port_binding_set_encap(pb, NULL); > > + } > > + sbrec_port_binding_set_chassis(pb, NULL); > > + > > + if (pb->virtual_parent) { > > + sbrec_port_binding_set_virtual_parent(pb, NULL); > > + } > > +} > > + > > +static bool > > +is_lbinding_set(struct local_binding *lbinding) > > +{ > > + return lbinding && lbinding->pb && lbinding->iface; > > +} > > + > > +static bool > > +is_lbinding_this_chassis(struct local_binding *lbinding, > > + const struct sbrec_chassis *chassis) > > +{ > > + return lbinding && lbinding->pb && lbinding->pb->chassis == chassis; > > +} > > + > > +static bool > > +can_bind_on_this_chassis(const struct sbrec_chassis *chassis_rec, > > + const char *requested_chassis) > > +{ > > + return !requested_chassis || !requested_chassis[0] > > + || !strcmp(requested_chassis, chassis_rec->name) > > + || !strcmp(requested_chassis, chassis_rec->hostname); > > +} > > + > > +static void > > +consider_vif_lport_(const struct sbrec_port_binding *pb, > > + bool can_bind, const char *vif_chassis, > > + struct binding_ctx_in *b_ctx_in, > > + struct binding_ctx_out *b_ctx_out, > > + struct local_binding *lbinding, > > + struct hmap *qos_map) > > +{ > > + bool lbinding_set = is_lbinding_set(lbinding); > > + if (lbinding_set) { > > + if (can_bind) { > > + /* We can claim the lport. */ > > + claim_lport(pb, b_ctx_in->chassis_rec, lbinding->iface); > > + > > + 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, > > + pb->datapath, false, > b_ctx_out->local_datapaths); > > + update_local_lport_ids(b_ctx_out->local_lport_ids, pb); > > + if (lbinding->iface && qos_map && b_ctx_in->ovs_idl_txn) { > > + get_qos_params(pb, qos_map); > > + } > > + } else { > > + /* We could, but can't claim the lport. */ > > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, > 1); > > + VLOG_INFO_RL(&rl, > > + "Not claiming lport %s, chassis %s " > > + "requested-chassis %s", > > + pb->logical_port, > > + b_ctx_in->chassis_rec->name, > > + vif_chassis); > > Indentation: this should be 4 spaces to the left. > I'll align it properly. > > > + } > > + } > > + > > + if (pb->chassis == b_ctx_in->chassis_rec) { > > + /* Release the lport if there is no lbinding. */ > > + if (!lbinding_set || !can_bind) { > > + release_lport(pb); > > + } > > + } > > + > > +} > > + > > +static void > > +consider_vif_lport(const struct sbrec_port_binding *pb, > > + struct binding_ctx_in *b_ctx_in, > > + struct binding_ctx_out *b_ctx_out, > > + struct local_binding *lbinding, > > + struct hmap *qos_map) > > +{ > > + const char *vif_chassis = smap_get(&pb->options, > "requested-chassis"); > > + bool can_bind = can_bind_on_this_chassis(b_ctx_in->chassis_rec, > > + vif_chassis); > > + > > + if (!lbinding) { > > + lbinding = local_binding_find(b_ctx_out->local_bindings, > > + pb->logical_port); > > + } > > + > > + if (lbinding) { > > + lbinding->pb = pb; > > + } > > + > > + consider_vif_lport_(pb, can_bind, vif_chassis, b_ctx_in, > > + b_ctx_out, lbinding, qos_map); > > +} > > + > > +static void > > +consider_container_lport(const struct sbrec_port_binding *pb, > > + struct binding_ctx_in *b_ctx_in, > > + struct binding_ctx_out *b_ctx_out, > > + struct hmap *qos_map) > > +{ > > + struct local_binding *parent_lbinding; > > + parent_lbinding = local_binding_find(b_ctx_out->local_bindings, > > + pb->parent_port); > > + > > + if (parent_lbinding && !parent_lbinding->pb) { > > + parent_lbinding->pb = lport_lookup_by_name( > > + b_ctx_in->sbrec_port_binding_by_name, pb->parent_port); > > + > > + if (parent_lbinding->pb) { > > + /* Its possible that the parent lport is not considered yet. > > + * So call consider_vif_lport() to process it first. */ > > + consider_vif_lport(parent_lbinding->pb, b_ctx_in, b_ctx_out, > > + parent_lbinding, qos_map); > > + } > > + } > > + > > + if (!parent_lbinding || !parent_lbinding->pb) { > > + /* Call release_lport, to release the container lport, if > > + * it was bound earlier. */ > > + if (pb->chassis == b_ctx_in->chassis_rec) { > > + release_lport(pb); > > + } > > + return; > > + } > > + > > + struct local_binding *container_lbinding = > > + local_binding_find_child(parent_lbinding, pb->logical_port); > > + ovs_assert(!container_lbinding); > > + > > + container_lbinding = local_binding_create(pb->logical_port, > > + parent_lbinding->iface, > > + pb, BT_CONTAINER); > > + local_binding_add_child(parent_lbinding, container_lbinding); > > + > > + const char *vif_chassis = smap_get(&parent_lbinding->pb->options, > > + "requested-chassis"); > > + bool can_bind = can_bind_on_this_chassis(b_ctx_in->chassis_rec, > > + vif_chassis); > > + > > + consider_vif_lport_(pb, can_bind, vif_chassis, b_ctx_in, b_ctx_out, > > + container_lbinding, qos_map); > > +} > > + > > +static void > > +consider_virtual_lport(const struct sbrec_port_binding *pb, > > + struct binding_ctx_in *b_ctx_in, > > + struct binding_ctx_out *b_ctx_out, > > + struct hmap *qos_map) > > +{ > > + struct local_binding * parent_lbinding = > > + pb->virtual_parent ? > local_binding_find(b_ctx_out->local_bindings, > > + pb->virtual_parent) > > + : NULL; > > + > > + if (parent_lbinding && !parent_lbinding->pb) { > > + parent_lbinding->pb = lport_lookup_by_name( > > + b_ctx_in->sbrec_port_binding_by_name, pb->virtual_parent); > > + > > + if (parent_lbinding->pb) { > > + /* Its possible that the parent lport is not considered yet. > > + * So call consider_vif_lport() to process it first. */ > > + consider_vif_lport(parent_lbinding->pb, b_ctx_in, b_ctx_out, > > + parent_lbinding, qos_map); > > + } > > + } > > + > > + struct local_binding *virtual_lbinding = NULL; > > + if (is_lbinding_this_chassis(parent_lbinding, > b_ctx_in->chassis_rec)) { > > + virtual_lbinding = > > + local_binding_find_child(parent_lbinding, pb->logical_port); > > + ovs_assert(!virtual_lbinding); > > + virtual_lbinding = local_binding_create(pb->logical_port, > > + parent_lbinding->iface, > > + pb, BT_VIRTUAL); > > + local_binding_add_child(parent_lbinding, virtual_lbinding); > > + } > > + > > + return consider_vif_lport_(pb, true, NULL, b_ctx_in, b_ctx_out, > > + virtual_lbinding, qos_map); > > +} > > + > > +/* Considers either claiming the lport or releasing the lport > > + * for non VIF lports. > > + */ > > +static void > > +consider_nonvif_lport_(const struct sbrec_port_binding *pb, > > + bool our_chassis, > > + bool has_local_l3gateway, > > + struct binding_ctx_in *b_ctx_in, > > + struct binding_ctx_out *b_ctx_out) > > +{ > > + ovs_assert(b_ctx_in->ovnsb_idl_txn); > > + if (our_chassis) { > > + sset_add(b_ctx_out->local_lports, pb->logical_port); > > + 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, > > + pb->datapath, has_local_l3gateway, > > + b_ctx_out->local_datapaths); > > + > > + update_local_lport_ids(b_ctx_out->local_lport_ids, pb); > > + claim_lport(pb, b_ctx_in->chassis_rec, NULL); > > + } else if (pb->chassis == b_ctx_in->chassis_rec) { > > + release_lport(pb); > > + } > > +} > > + > > +static void > > +consider_l2gw_lport(const struct sbrec_port_binding *pb, > > + struct binding_ctx_in *b_ctx_in, > > + struct binding_ctx_out *b_ctx_out) > > +{ > > + const char *chassis_id = smap_get(&pb->options, > "l2gateway-chassis"); > > + bool our_chassis = chassis_id && !strcmp(chassis_id, > > + > b_ctx_in->chassis_rec->name); > > + > > + consider_nonvif_lport_(pb, our_chassis, false, b_ctx_in, b_ctx_out); > > +} > > + > > +static void > > +consider_l3gw_lport(const struct sbrec_port_binding *pb, > > + struct binding_ctx_in *b_ctx_in, > > + struct binding_ctx_out *b_ctx_out) > > +{ > > + const char *chassis_id = smap_get(&pb->options, > "l3gateway-chassis"); > > + bool our_chassis = chassis_id && !strcmp(chassis_id, > > + > b_ctx_in->chassis_rec->name); > > + > > + consider_nonvif_lport_(pb, our_chassis, true, b_ctx_in, b_ctx_out); > > +} > > + > > +static void > > +consider_localnet_lport(const struct sbrec_port_binding *pb, > > + struct binding_ctx_in *b_ctx_in, > > + struct binding_ctx_out *b_ctx_out, > > + struct hmap *qos_map) > > +{ > > + /* Add all localnet ports to local_lports so that we allocate ct > zones > > + * for them. */ > > + sset_add(b_ctx_out->local_lports, pb->logical_port); > > + if (qos_map && b_ctx_in->ovs_idl_txn) { > > + get_qos_params(pb, qos_map); > > + } > > + > > + update_local_lport_ids(b_ctx_out->local_lport_ids, pb); > > +} > > + > > +static void > > +consider_ha_lport(const struct sbrec_port_binding *pb, > > + struct binding_ctx_in *b_ctx_in, > > + struct binding_ctx_out *b_ctx_out) > > +{ > > + bool our_chassis = false; > > + bool is_ha_chassis = ha_chassis_group_contains(pb->ha_chassis_group, > > + > b_ctx_in->chassis_rec); > > + our_chassis = is_ha_chassis && > > + ha_chassis_group_is_active(pb->ha_chassis_group, > > + b_ctx_in->active_tunnels, > > + b_ctx_in->chassis_rec); > > + > > + if (is_ha_chassis && !our_chassis) { > > + /* If the chassis_rec is part of ha_chassis_group associated > with > > + * the port_binding 'pb', we need to add to the local_datapath > > + * in even if its not active. > > + * > > + * If the chassis is active, consider_nonvif_lport_() takes care > > + * of adding the datapath of this 'pb' to local datapaths. > > + * */ > > + 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, > > + pb->datapath, false, > > + b_ctx_out->local_datapaths); > > + } > > + > > + consider_nonvif_lport_(pb, our_chassis, false, b_ctx_in, b_ctx_out); > > +} > > + > > +static void > > +consider_cr_lport(const struct sbrec_port_binding *pb, > > + struct binding_ctx_in *b_ctx_in, > > + struct binding_ctx_out *b_ctx_out) > > +{ > > + consider_ha_lport(pb, b_ctx_in, b_ctx_out); > > +} > > + > > +static void > > +consider_external_lport(const struct sbrec_port_binding *pb, > > + struct binding_ctx_in *b_ctx_in, > > + struct binding_ctx_out *b_ctx_out) > > +{ > > + return consider_ha_lport(pb, b_ctx_in, b_ctx_out); > > +} > > + > > +/* > > + * Builds local_bindings from the OVS interfaces. > > + */ > > +static void > > +build_local_bindings(struct binding_ctx_in *b_ctx_in, > > + struct binding_ctx_out *b_ctx_out) > > +{ > > + int i; > > + for (i = 0; i < b_ctx_in->br_int->n_ports; i++) { > > + const struct ovsrec_port *port_rec = b_ctx_in->br_int->ports[i]; > > + const char *iface_id; > > + int j; > > + > > + if (!strcmp(port_rec->name, b_ctx_in->br_int->name)) { > > + continue; > > + } > > + > > + for (j = 0; j < port_rec->n_interfaces; j++) { > > + const struct ovsrec_interface *iface_rec; > > + > > + iface_rec = port_rec->interfaces[j]; > > + iface_id = smap_get(&iface_rec->external_ids, "iface-id"); > > + int64_t ofport = iface_rec->n_ofport ? *iface_rec->ofport : > 0; > > + > > + if (iface_id && ofport > 0) { > > + struct local_binding *lbinding = > > + local_binding_find(b_ctx_out->local_bindings, > iface_id); > > + if (!lbinding) { > > + lbinding = local_binding_create(iface_id, > iface_rec, NULL, > > + BT_VIF); > > + local_binding_add(b_ctx_out->local_bindings, > lbinding); > > + } else { > > + static struct vlog_rate_limit rl = > > + VLOG_RATE_LIMIT_INIT(1, 5); > > + VLOG_WARN_RL( > > + &rl, > > + "Invalid configuration: iface-id is configured > on " > > + "interfaces : [%s] and [%s]. Ignoring the " > > + "configuration on interface [%s]", > > + lbinding->iface->name, iface_rec->name, > > + iface_rec->name); > > + ovs_assert(lbinding->type == BT_VIF); > > + } > > + > > + sset_add(b_ctx_out->local_lports, iface_id); > > + } > > + > > + /* Check if this is a tunnel interface. */ > > + if (smap_get(&iface_rec->options, "remote_ip")) { > > + const char *tunnel_iface > > + = smap_get(&iface_rec->status, > "tunnel_egress_iface"); > > + if (tunnel_iface) { > > + sset_add(b_ctx_out->egress_ifaces, tunnel_iface); > > + } > > + } > > + } > > + } > > +} > > + > > void > > binding_run(struct binding_ctx_in *b_ctx_in, struct binding_ctx_out > *b_ctx_out) > > { > > @@ -743,106 +1071,135 @@ binding_run(struct binding_ctx_in *b_ctx_in, > struct binding_ctx_out *b_ctx_out) > > return; > > } > > > > - const struct sbrec_port_binding *binding_rec; > > struct shash bridge_mappings = SHASH_INITIALIZER(&bridge_mappings); > > - struct shash lport_to_iface = SHASH_INITIALIZER(&lport_to_iface); > > - struct sset egress_ifaces = SSET_INITIALIZER(&egress_ifaces); > > struct hmap qos_map; > > > > hmap_init(&qos_map); > > if (b_ctx_in->br_int) { > > - get_local_iface_ids(b_ctx_in->br_int, &lport_to_iface, > > - b_ctx_out->local_lports, &egress_ifaces); > > + build_local_bindings(b_ctx_in, b_ctx_out); > > } > > > > - /* Array to store pointers to local virtual ports. It is populated > by > > - * consider_local_datapath. > > - */ > > - const struct sbrec_port_binding **vpbs = NULL; > > - size_t n_vpbs = 0; > > - size_t n_allocated_vpbs = 0; > > + struct hmap *qos_map_ptr = > > + !sset_is_empty(b_ctx_out->egress_ifaces) ? &qos_map : NULL; > > + > > + struct ovs_list localnet_lports = > OVS_LIST_INITIALIZER(&localnet_lports); > > + > > + struct localnet_lport { > > + struct ovs_list list_node; > > + const struct sbrec_port_binding *pb; > > + }; > > > > /* Run through each binding record to see if it is resident on this > > * chassis and update the binding accordingly. This includes both > > - * directly connected logical ports and children of those ports. > > - * Virtual ports are just added to vpbs array and will be processed > > - * later. This is special case for virtual ports is needed in order > to > > - * make sure we update the virtual_parent port bindings first. > > + * directly connected logical ports and children of those ports > > + * (which also includes virtual ports). > > */ > > - SBREC_PORT_BINDING_TABLE_FOR_EACH (binding_rec, > > + const struct sbrec_port_binding *pb; > > + SBREC_PORT_BINDING_TABLE_FOR_EACH (pb, > > b_ctx_in->port_binding_table) { > > - const struct ovsrec_interface *iface_rec > > - = shash_find_data(&lport_to_iface, > binding_rec->logical_port); > > - vpbs = > > - consider_local_datapath(binding_rec, > > - iface_rec, b_ctx_in, b_ctx_out, > > - sset_is_empty(&egress_ifaces) ? > NULL : > > - &qos_map, > > - vpbs, &n_vpbs, &n_allocated_vpbs); > > - } > > - > > - /* Now also update the virtual ports in case their parent ports were > > - * updated above. > > - */ > > - for (size_t i = 0; i < n_vpbs; i++) { > > - > consider_local_virtual_port(b_ctx_in->sbrec_port_binding_by_name, > > - b_ctx_in->chassis_rec, vpbs[i]); > > + enum en_lport_type lport_type = get_lport_type(pb); > > + > > + switch (lport_type) { > > + case LP_PATCH: > > + case LP_LOCALPORT: > > + case LP_VTEP: > > + update_local_lport_ids(b_ctx_out->local_lport_ids, pb); > > + break; > > + > > + case LP_VIF: > > + if (is_lport_container(pb)) { > > + consider_container_lport(pb, b_ctx_in, b_ctx_out, > qos_map_ptr); > > + } else { > > + consider_vif_lport(pb, b_ctx_in, b_ctx_out, NULL, > qos_map_ptr); > > + } > > + break; > > + > > + case LP_VIRTUAL: > > + consider_virtual_lport(pb, b_ctx_in, b_ctx_out, > qos_map_ptr); > > + break; > > + > > + case LP_L2GATEWAY: > > + consider_l2gw_lport(pb, b_ctx_in, b_ctx_out); > > + break; > > + > > + case LP_L3GATEWAY: > > + consider_l3gw_lport(pb, b_ctx_in, b_ctx_out); > > + break; > > + > > + case LP_CHASSISREDIRECT: > > + consider_cr_lport(pb, b_ctx_in, b_ctx_out); > > + break; > > + > > + case LP_EXTERNAL: > > + consider_external_lport(pb, b_ctx_in, b_ctx_out); > > + break; > > + > > + case LP_LOCALNET: { > > + consider_localnet_lport(pb, b_ctx_in, b_ctx_out, > qos_map_ptr); > > + struct localnet_lport *lnet_lport = xmalloc(sizeof > *lnet_lport); > > + lnet_lport->pb = pb; > > + ovs_list_push_back(&localnet_lports, > &lnet_lport->list_node); > > + break; > > + } > > + > > + case LP_REMOTE: > > + /* Nothing to be done for REMOTE type. */ > > + break; > > + > > + case LP_UNKNOWN: { > > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, > 5); > > + VLOG_WARN_RL(&rl, > > + "Unknown port binding type [%s] for port > binding " > > + "[%s]. Does ovn-controller needs update ?", > > + pb->type, pb->logical_port); > > + break; > > + } > > + } > > } > > - free(vpbs); > > > > add_ovs_bridge_mappings(b_ctx_in->ovs_table, b_ctx_in->bridge_table, > > &bridge_mappings); > > > > - /* Run through each binding record to see if it is a localnet port > > + /* Run through each localnet lport list to see if it is a localnet > port > > * on local datapaths discovered from above loop, and update the > > * corresponding local datapath accordingly. */ > > - SBREC_PORT_BINDING_TABLE_FOR_EACH (binding_rec, > > - b_ctx_in->port_binding_table) { > > - if (!strcmp(binding_rec->type, "localnet")) { > > - consider_localnet_port(binding_rec, &bridge_mappings, > > - &egress_ifaces, > b_ctx_out->local_datapaths); > > - } > > + struct localnet_lport *lnet_lport; > > + LIST_FOR_EACH_POP (lnet_lport, list_node, &localnet_lports) { > > + consider_localnet_port(lnet_lport->pb, &bridge_mappings, > > + b_ctx_out->egress_ifaces, > > + b_ctx_out->local_datapaths); > > + free(lnet_lport); > > } > > + > > shash_destroy(&bridge_mappings); > > > > - if (!sset_is_empty(&egress_ifaces) > > + if (!sset_is_empty(b_ctx_out->egress_ifaces) > > && set_noop_qos(b_ctx_in->ovs_idl_txn, b_ctx_in->port_table, > > - b_ctx_in->qos_table, &egress_ifaces)) { > > + b_ctx_in->qos_table, b_ctx_out->egress_ifaces)) > { > > const char *entry; > > - SSET_FOR_EACH (entry, &egress_ifaces) { > > + SSET_FOR_EACH (entry, b_ctx_out->egress_ifaces) { > > setup_qos(entry, &qos_map); > > } > > } > > > > - shash_destroy(&lport_to_iface); > > - sset_destroy(&egress_ifaces); > > destroy_qos_map(&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( > > - const struct sbrec_port_binding_table *pb_table, > > - const struct ovsrec_bridge *br_int, > > - const struct sbrec_chassis *chassis_rec, > > - struct sset *active_tunnels, > > - struct sset *local_lports) > > +binding_evaluate_port_binding_changes(struct binding_ctx_in *b_ctx_in, > > + struct binding_ctx_out *b_ctx_out) > > { > > - if (!chassis_rec) { > > + if (!b_ctx_in->chassis_rec) { > > return true; > > } > > > > bool changed = false; > > > > 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_TABLE_FOR_EACH_TRACKED (binding_rec, pb_table) { > > + 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 > > @@ -854,24 +1211,35 @@ binding_evaluate_port_binding_changes( > > * interface table will be updated, which will trigger > recompute. > > * > > * - If the port is not a regular VIF, always trigger > recompute. */ > > - if (binding_rec->chassis == chassis_rec) { > > + if (binding_rec->chassis == b_ctx_in->chassis_rec) { > > changed = true; > > break; > > } > > > > - const struct ovsrec_interface *iface_rec > > - = shash_find_data(&lport_to_iface, > binding_rec->logical_port); > > - if (is_our_chassis(chassis_rec, binding_rec, active_tunnels, > iface_rec, > > - local_lports) || > > - (strcmp(binding_rec->type, "") && strcmp(binding_rec->type, > > - "remote"))) { > > + if (!strcmp(binding_rec->type, "remote")) { > > + continue; > > + } > > + > > + if (strcmp(binding_rec->type, "")) { > > + changed = true; > > + break; > > + } > > + > > + struct local_binding *lbinding = NULL; > > + 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; > > } > > } > > > > - shash_destroy(&lport_to_iface); > > - sset_destroy(&egress_ifaces); > > return changed; > > } > > > > diff --git a/controller/binding.h b/controller/binding.h > > index d0b8331af..9affc9a96 100644 > > --- a/controller/binding.h > > +++ b/controller/binding.h > > @@ -31,6 +31,8 @@ struct ovsrec_open_vswitch_table; > > struct sbrec_chassis; > > struct sbrec_port_binding_table; > > struct sset; > > +struct sbrec_port_binding; > > +struct shash; > > > > struct binding_ctx_in { > > struct ovsdb_idl_txn *ovnsb_idl_txn; > > @@ -51,8 +53,10 @@ struct binding_ctx_in { > > > > struct binding_ctx_out { > > struct hmap *local_datapaths; > > + struct shash *local_bindings; > > struct sset *local_lports; > > struct sset *local_lport_ids; > > + struct sset *egress_ifaces; > > }; > > > > void binding_register_ovs_idl(struct ovsdb_idl *); > > @@ -60,11 +64,9 @@ 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( > > - const struct sbrec_port_binding_table *, > > - const struct ovsrec_bridge *br_int, > > - const struct sbrec_chassis *, > > - struct sset *active_tunnels, > > - struct sset *local_lports); > > +bool binding_evaluate_port_binding_changes(struct binding_ctx_in *, > > + struct binding_ctx_out *); > > > > +void local_bindings_init(struct shash *local_bindings); > > +void local_bindings_destroy(struct shash *local_bindings); > > #endif /* controller/binding.h */ > > diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c > > index 11fa2840d..6b759966b 100644 > > --- a/controller/ovn-controller.c > > +++ b/controller/ovn-controller.c > > @@ -958,6 +958,9 @@ struct ed_type_runtime_data { > > /* Contains "struct local_datapath" nodes. */ > > struct hmap local_datapaths; > > > > + /* Contains "struct local_binding" nodes. */ > > + struct shash local_bindings; > > + > > /* Contains the name of each logical port resident on the local > > * hypervisor. These logical ports include the VIFs (and their > child > > * logical ports, if any) that belong to VMs running on the > hypervisor, > > @@ -969,6 +972,8 @@ struct ed_type_runtime_data { > > * <datapath-tunnel-key>_<port-tunnel-key> */ > > struct sset local_lport_ids; > > struct sset active_tunnels; > > + > > + struct sset egress_ifaces; > > }; > > > > static void * > > @@ -981,6 +986,8 @@ en_runtime_data_init(struct engine_node *node > OVS_UNUSED, > > sset_init(&data->local_lports); > > sset_init(&data->local_lport_ids); > > sset_init(&data->active_tunnels); > > + sset_init(&data->egress_ifaces); > > + local_bindings_init(&data->local_bindings); > > return data; > > } > > > > @@ -992,6 +999,7 @@ en_runtime_data_cleanup(void *data) > > sset_destroy(&rt_data->local_lports); > > sset_destroy(&rt_data->local_lport_ids); > > sset_destroy(&rt_data->active_tunnels); > > + sset_destroy(&rt_data->egress_ifaces); > > struct local_datapath *cur_node, *next_node; > > HMAP_FOR_EACH_SAFE (cur_node, next_node, hmap_node, > > &rt_data->local_datapaths) { > > @@ -1000,6 +1008,7 @@ en_runtime_data_cleanup(void *data) > > free(cur_node); > > } > > hmap_destroy(&rt_data->local_datapaths); > > + local_bindings_destroy(&rt_data->local_bindings); > > } > > > > static void > > @@ -1072,6 +1081,8 @@ init_binding_ctx(struct engine_node *node, > > b_ctx_out->local_datapaths = &rt_data->local_datapaths; > > b_ctx_out->local_lports = &rt_data->local_lports; > > 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; > > } > > > > static void > > @@ -1095,12 +1106,16 @@ en_runtime_data_run(struct engine_node *node, > void *data) > > free(cur_node); > > } > > hmap_clear(local_datapaths); > > + local_bindings_destroy(&rt_data->local_bindings); > > sset_destroy(local_lports); > > sset_destroy(local_lport_ids); > > sset_destroy(active_tunnels); > > + sset_destroy(&rt_data->egress_ifaces); > > sset_init(local_lports); > > sset_init(local_lport_ids); > > sset_init(active_tunnels); > > + sset_init(&rt_data->egress_ifaces); > > + local_bindings_init(&rt_data->local_bindings); > > } > > > > struct binding_ctx_in b_ctx_in; > > @@ -1129,35 +1144,12 @@ static bool > > runtime_data_sb_port_binding_handler(struct engine_node *node, void > *data) > > { > > struct ed_type_runtime_data *rt_data = data; > > - struct sset *local_lports = &rt_data->local_lports; > > - struct sset *active_tunnels = &rt_data->active_tunnels; > > - > > - struct ovsrec_open_vswitch_table *ovs_table = > > - (struct ovsrec_open_vswitch_table *)EN_OVSDB_GET( > > - engine_get_input("OVS_open_vswitch", node)); > > - struct ovsrec_bridge_table *bridge_table = > > - (struct ovsrec_bridge_table *)EN_OVSDB_GET( > > - engine_get_input("OVS_bridge", node)); > > - const char *chassis_id = chassis_get_id(); > > - const struct ovsrec_bridge *br_int = get_br_int(bridge_table, > ovs_table); > > - > > - ovs_assert(br_int && chassis_id); > > - > > - struct ovsdb_idl_index *sbrec_chassis_by_name = > > - engine_ovsdb_node_get_index( > > - engine_get_input("SB_chassis", node), > > - "name"); > > - > > - const struct sbrec_chassis *chassis > > - = chassis_lookup_by_name(sbrec_chassis_by_name, chassis_id); > > - ovs_assert(chassis); > > - > > - struct sbrec_port_binding_table *pb_table = > > - (struct sbrec_port_binding_table *)EN_OVSDB_GET( > > - engine_get_input("SB_port_binding", node)); > > + 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( > > - pb_table, br_int, chassis, active_tunnels, local_lports); > > + bool changed = binding_evaluate_port_binding_changes(&b_ctx_in, > > + &b_ctx_out); > > > > return !changed; > > } > > diff --git a/tests/ovn.at b/tests/ovn.at > > index 8fa1a7e1b..d008dcb6c 100644 > > --- a/tests/ovn.at > > +++ b/tests/ovn.at > > @@ -8606,6 +8606,42 @@ as hv1 ovs-appctl netdev-dummy/receive vm1 $packet > > # expected packet at VM1 > > OVN_CHECK_PACKETS([hv1/vm1-tx.pcap], [expected1]) > > > > +# Test binding of parent and container ports. > > +ovn-nbctl lsp-set-options vm1 requested-chassis=foo > > + > > +OVS_WAIT_UNTIL([test xdown = x$(ovn-nbctl lsp-get-up vm1)]) > > +OVS_WAIT_UNTIL([test xdown = x$(ovn-nbctl lsp-get-up foo1)]) > > +OVS_WAIT_UNTIL([test xdown = x$(ovn-nbctl lsp-get-up bar1)]) > > + > > +ovn-nbctl clear logical_switch_port vm1 options > > +OVS_WAIT_UNTIL([test xup = x$(ovn-nbctl lsp-get-up vm1)]) > > +OVS_WAIT_UNTIL([test xup = x$(ovn-nbctl lsp-get-up foo1)]) > > +OVS_WAIT_UNTIL([test xup = x$(ovn-nbctl lsp-get-up bar1)]) > > + > > +as hv1 ovs-vsctl set interface vm1 external_ids:iface-id=foo > > +OVS_WAIT_UNTIL([test xdown = x$(ovn-nbctl lsp-get-up vm1)]) > > +OVS_WAIT_UNTIL([test xdown = x$(ovn-nbctl lsp-get-up foo1)]) > > +OVS_WAIT_UNTIL([test xdown = x$(ovn-nbctl lsp-get-up bar1)]) > > + > > +as hv1 ovs-vsctl set interface vm1 external_ids:iface-id=vm1 > > +OVS_WAIT_UNTIL([test xup = x$(ovn-nbctl lsp-get-up vm1)]) > > +OVS_WAIT_UNTIL([test xup = x$(ovn-nbctl lsp-get-up foo1)]) > > +OVS_WAIT_UNTIL([test xup = x$(ovn-nbctl lsp-get-up bar1)]) > > + > > +ovn-nbctl lsp-del vm1 > > +OVS_WAIT_UNTIL([test xdown = x$(ovn-nbctl lsp-get-up foo1)]) > > +OVS_WAIT_UNTIL([test xdown = x$(ovn-nbctl lsp-get-up bar1)]) > > + > > +ovn-nbctl lsp-add mgmt vm1 > > +OVS_WAIT_UNTIL([test xup = x$(ovn-nbctl lsp-get-up vm1)]) > > +OVS_WAIT_UNTIL([test xup = x$(ovn-nbctl lsp-get-up foo1)]) > > +OVS_WAIT_UNTIL([test xup = x$(ovn-nbctl lsp-get-up bar1)]) > > + > > +as hv1 ovs-vsctl del-port vm1 > > +OVS_WAIT_UNTIL([test xdown = x$(ovn-nbctl lsp-get-up vm1)]) > > +OVS_WAIT_UNTIL([test xdown = x$(ovn-nbctl lsp-get-up foo1)]) > > +OVS_WAIT_UNTIL([test xdown = x$(ovn-nbctl lsp-get-up bar1)]) > > + > > OVN_CLEANUP([hv1],[hv2]) > > > > AT_CLEANUP > > > > _______________________________________________ > dev mailing list > d...@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev