Message ID | 20210716114603.1896002-1-numans@ovn.org |
---|---|
State | Changes Requested |
Delegated to: | Han Zhou |
Headers | show |
Series | pflow_output and ct_zone engine improvements. | expand |
Context | Check | Description |
---|---|---|
ovsrobot/apply-robot | success | apply and check: success |
Thanks Numan. The commit title has a typo: s/plow/pflow. On Fri, Jul 16, 2021 at 4:55 AM <numans@ovn.org> wrote: > > From: Numan Siddique <numans@ovn.org> > > physical_run() maintains a local copy of local vif to ofports > in a simap along with the chassis tunnel information. This patch > removes this from the physical module and now stores it in the > runtime_data engine node. This makes it easier to handle runtime > data changes in pflow_output engine. > > The newly added handler pflow_output_runtime_data_handler() returns > false if a datapath is added or removed from the local_datapaths > and handles the logical port claims and releases incrementally. > > Signed-off-by: Numan Siddique <numans@ovn.org> > --- > controller/binding.c | 39 ++-- > controller/binding.h | 23 +++ > controller/ldata.c | 169 ++++++++++++++++ > controller/ldata.h | 44 +++++ > controller/lflow.c | 5 +- > controller/lflow.h | 1 + > controller/ovn-controller.c | 68 ++++++- > controller/ovn-controller.h | 8 - > controller/physical.c | 382 +++++++++--------------------------- > controller/physical.h | 13 +- > 10 files changed, 422 insertions(+), 330 deletions(-) > > diff --git a/controller/binding.c b/controller/binding.c > index 0fd951ad7..b50139726 100644 > --- a/controller/binding.c > +++ b/controller/binding.c > @@ -546,23 +546,6 @@ update_active_pb_ras_pd(const struct sbrec_port_binding *pb, > } > } > > -/* Corresponds to each Port_Binding.type. */ > -enum en_lport_type { > - LP_UNKNOWN, > - LP_VIF, > - LP_CONTAINER, > - LP_PATCH, > - LP_L3GATEWAY, > - LP_LOCALNET, > - LP_LOCALPORT, > - LP_L2GATEWAY, > - LP_VTEP, > - LP_CHASSISREDIRECT, > - LP_VIRTUAL, > - LP_EXTERNAL, > - LP_REMOTE > -}; > - > /* Local bindings. binding.c module binds the logical port (represented by > * Port_Binding rows) and sets the 'chassis' column when it sees the > * OVS interface row (of type "" or "internal") with the > @@ -616,7 +599,7 @@ static struct local_binding *local_binding_create( > static void local_binding_add(struct shash *local_bindings, > struct local_binding *); > static struct local_binding *local_binding_find( > - struct shash *local_bindings, const char *name); > + const struct shash *local_bindings, const char *name); > static void local_binding_destroy(struct local_binding *, > struct shash *binding_lports); > static void local_binding_delete(struct local_binding *, > @@ -701,7 +684,8 @@ local_binding_data_destroy(struct local_binding_data *lbinding_data) > } > > const struct sbrec_port_binding * > -local_binding_get_primary_pb(struct shash *local_bindings, const char *pb_name) > +local_binding_get_primary_pb(struct shash *local_bindings, > + const char *pb_name) > { > struct local_binding *lbinding = > local_binding_find(local_bindings, pb_name); > @@ -710,6 +694,19 @@ local_binding_get_primary_pb(struct shash *local_bindings, const char *pb_name) > return b_lport ? b_lport->pb : NULL; > } > > +ofp_port_t > +local_binding_get_lport_ofport(const struct shash *local_bindings, > + const char *pb_name) > +{ > + struct local_binding *lbinding = > + local_binding_find(local_bindings, pb_name); > + struct binding_lport *b_lport = > + local_binding_get_primary_or_localport_lport(lbinding); > + > + return (b_lport && lbinding->iface && lbinding->iface->n_ofport) ? > + u16_to_ofp(lbinding->iface->ofport[0]) : 0; > +} > + > bool > local_binding_is_up(struct shash *local_bindings, const char *pb_name) > { > @@ -871,7 +868,7 @@ is_lport_vif(const struct sbrec_port_binding *pb) > return !pb->type[0]; > } > > -static enum en_lport_type > +enum en_lport_type > get_lport_type(const struct sbrec_port_binding *pb) > { > if (is_lport_vif(pb)) { > @@ -2555,7 +2552,7 @@ local_binding_create(const char *name, const struct ovsrec_interface *iface) > } > > static struct local_binding * > -local_binding_find(struct shash *local_bindings, const char *name) > +local_binding_find(const struct shash *local_bindings, const char *name) > { > return shash_find_data(local_bindings, name); > } > diff --git a/controller/binding.h b/controller/binding.h > index b1717bd2b..f1abc4b9c 100644 > --- a/controller/binding.h > +++ b/controller/binding.h > @@ -114,6 +114,9 @@ void local_binding_data_destroy(struct local_binding_data *); > > const struct sbrec_port_binding *local_binding_get_primary_pb( > struct shash *local_bindings, const char *pb_name); > +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_down(struct shash *local_bindings, const char *pb_name); > void local_binding_set_up(struct shash *local_bindings, const char *pb_name, > @@ -134,4 +137,24 @@ bool binding_handle_port_binding_changes(struct binding_ctx_in *, > void binding_tracked_dp_destroy(struct hmap *tracked_datapaths); > > void binding_dump_local_bindings(struct local_binding_data *, struct ds *); > + > +/* Corresponds to each Port_Binding.type. */ > +enum en_lport_type { > + LP_UNKNOWN, > + LP_VIF, > + LP_CONTAINER, > + LP_PATCH, > + LP_L3GATEWAY, > + LP_LOCALNET, > + LP_LOCALPORT, > + LP_L2GATEWAY, > + LP_VTEP, > + LP_CHASSISREDIRECT, > + LP_VIRTUAL, > + LP_EXTERNAL, > + LP_REMOTE > +}; > + > +enum en_lport_type get_lport_type(const struct sbrec_port_binding *); > + > #endif /* controller/binding.h */ > diff --git a/controller/ldata.c b/controller/ldata.c > index a6df9b1da..f55905551 100644 > --- a/controller/ldata.c > +++ b/controller/ldata.c > @@ -18,10 +18,13 @@ > /* OVS includes. */ > #include "include/openvswitch/json.h" > #include "lib/hmapx.h" > +#include "lib/flow.h" > #include "lib/util.h" > +#include "lib/vswitch-idl.h" > #include "openvswitch/vlog.h" > > /* OVN includes. */ > +#include "encaps.h" > #include "ldata.h" > #include "lport.h" > #include "lib/ovn-util.h" > @@ -275,6 +278,172 @@ tracked_datapaths_destroy(struct hmap *tracked_datapaths) > hmap_destroy(tracked_datapaths); > } > > +/* Iterates the br_int ports and build the simap of patch to ofports > + * and chassis tunnels. */ > +void > +ldata_run(const struct ovsrec_bridge *br_int, > + const struct sbrec_chassis *chassis_rec, > + struct local_nonvif_data *nonvif_data) > +{ > + for (int i = 0; i < br_int->n_ports; i++) { > + const struct ovsrec_port *port_rec = br_int->ports[i]; > + if (!strcmp(port_rec->name, br_int->name)) { > + continue; > + } > + > + const char *tunnel_id = smap_get(&port_rec->external_ids, > + "ovn-chassis-id"); > + if (tunnel_id && encaps_tunnel_id_match(tunnel_id, > + chassis_rec->name, > + NULL)) { > + continue; > + } > + > + const char *localnet = smap_get(&port_rec->external_ids, > + "ovn-localnet-port"); > + const char *l2gateway = smap_get(&port_rec->external_ids, > + "ovn-l2gateway-port"); > + > + for (int j = 0; j < port_rec->n_interfaces; j++) { > + const struct ovsrec_interface *iface_rec = port_rec->interfaces[j]; > + > + /* Get OpenFlow port number. */ > + if (!iface_rec->n_ofport) { > + continue; > + } > + int64_t ofport = iface_rec->ofport[0]; > + if (ofport < 1 || ofport > ofp_to_u16(OFPP_MAX)) { > + continue; > + } > + > + bool is_patch = !strcmp(iface_rec->type, "patch"); > + if (is_patch && localnet) { > + simap_put(&nonvif_data->patch_ofports, localnet, ofport); > + break; > + } else if (is_patch && l2gateway) { > + /* L2 gateway patch ports can be handled just like VIFs. */ > + simap_put(&nonvif_data->patch_ofports, l2gateway, ofport); > + break; > + } else if (tunnel_id) { > + enum chassis_tunnel_type tunnel_type; > + if (!strcmp(iface_rec->type, "geneve")) { > + tunnel_type = GENEVE; > + } else if (!strcmp(iface_rec->type, "stt")) { > + tunnel_type = STT; > + } else if (!strcmp(iface_rec->type, "vxlan")) { > + tunnel_type = VXLAN; > + } else { > + continue; > + } > + > + /* We split the tunnel_id to get the chassis-id > + * and hash the tunnel list on the chassis-id. The > + * reason to use the chassis-id alone is because > + * there might be cases (multicast, gateway chassis) > + * where we need to tunnel to the chassis, but won't > + * have the encap-ip specifically. > + */ > + char *hash_id = NULL; > + char *ip = NULL; > + > + if (!encaps_tunnel_id_parse(tunnel_id, &hash_id, &ip)) { > + continue; > + } > + struct chassis_tunnel *tun = xmalloc(sizeof *tun); > + hmap_insert(&nonvif_data->chassis_tunnels, &tun->hmap_node, > + hash_string(hash_id, 0)); > + tun->chassis_id = xstrdup(tunnel_id); > + tun->ofport = u16_to_ofp(ofport); > + tun->type = tunnel_type; > + > + free(hash_id); > + free(ip); > + break; > + } > + } > + } > +} > + > +bool > +ldata_handle_ovs_iface_changes( > + const struct ovsrec_interface_table *iface_table) > +{ > + const struct ovsrec_interface *iface_rec; > + OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, iface_table) { > + if (!strcmp(iface_rec->type, "geneve") || > + !strcmp(iface_rec->type, "patch") || > + !strcmp(iface_rec->type, "vxlan") || > + !strcmp(iface_rec->type, "stt")) { > + return false; > + } > + } > + > + return true; > +} > + > +bool > +get_chassis_tunnel_ofport(const struct hmap *chassis_tunnels, > + const char *chassis_name, char *encap_ip, > + ofp_port_t *ofport) > +{ > + struct chassis_tunnel *tun = NULL; > + tun = chassis_tunnel_find(chassis_tunnels, chassis_name, encap_ip); > + if (!tun) { > + return false; > + } > + > + *ofport = tun->ofport; > + return true; > +} > + > +void > +local_nonvif_data_init(struct local_nonvif_data *nonvif_data) > +{ > + simap_init(&nonvif_data->patch_ofports); > + hmap_init(&nonvif_data->chassis_tunnels); > +} > + > +void > +local_nonvif_data_destroy(struct local_nonvif_data *nonvif_data) > +{ > + simap_destroy(&nonvif_data->patch_ofports); > + struct chassis_tunnel *tun; > + HMAP_FOR_EACH_POP (tun, hmap_node, &nonvif_data->chassis_tunnels) { > + free(tun->chassis_id); > + free(tun); > + } > + hmap_destroy(&nonvif_data->chassis_tunnels); > +} > + > + > +/* > + * This function looks up the list of tunnel ports (provided by > + * ovn-chassis-id ports) and returns the tunnel for the given chassid-id and > + * encap-ip. The ovn-chassis-id is formed using the chassis-id and encap-ip. > + * The list is hashed using the chassis-id. If the encap-ip is not specified, > + * it means we'll just return a tunnel for that chassis-id, i.e. we just check > + * for chassis-id and if there is a match, we'll return the tunnel. > + * If encap-ip is also provided we use both chassis-id and encap-ip to do > + * a more specific lookup. > + */ > +struct chassis_tunnel * > +chassis_tunnel_find(const struct hmap *chassis_tunnels, const char *chassis_id, > + char *encap_ip) > +{ > + /* > + * If the specific encap_ip is given, look for the chassisid_ip entry, > + * else return the 1st found entry for the chassis. > + */ > + struct chassis_tunnel *tun = NULL; > + HMAP_FOR_EACH_WITH_HASH (tun, hmap_node, hash_string(chassis_id, 0), > + chassis_tunnels) { > + if (encaps_tunnel_id_match(tun->chassis_id, chassis_id, encap_ip)) { > + return tun; > + } > + } > + return NULL; > +} > + > /* static functions. */ > static struct local_datapath * > local_datapath_add__(struct hmap *local_datapaths, > diff --git a/controller/ldata.h b/controller/ldata.h > index 16ad43c8f..91624d0b4 100644 > --- a/controller/ldata.h > +++ b/controller/ldata.h > @@ -19,10 +19,14 @@ > /* OVS includes. */ > #include "include/openvswitch/shash.h" > #include "lib/smap.h" > +#include "lib/simap.h" > > struct sbrec_datapath_binding; > struct sbrec_port_binding; > +struct sbrec_chassis; > struct ovsdb_idl_index; > +struct ovsrec_bridge; > +struct ovsrec_interface_table; > > /* A logical datapath that has some relevance to this hypervisor. A logical > * datapath D is relevant to hypervisor H if: > @@ -117,4 +121,44 @@ void tracked_datapath_lport_add(const struct sbrec_port_binding *, > struct hmap *tracked_datapaths); > void tracked_datapaths_destroy(struct hmap *tracked_datapaths); > > +/* Must be a bit-field ordered from most-preferred (higher number) to > + * least-preferred (lower number). */ > +enum chassis_tunnel_type { > + GENEVE = 1 << 2, > + STT = 1 << 1, > + VXLAN = 1 << 0 > +}; > + > +/* Maps from a chassis to the OpenFlow port number of the tunnel that can be > + * used to reach that chassis. */ > +struct chassis_tunnel { > + struct hmap_node hmap_node; > + char *chassis_id; > + ofp_port_t ofport; > + enum chassis_tunnel_type type; > +}; > + > +struct local_nonvif_data { > + struct simap patch_ofports; /* simap of patch ovs ports. */ > + struct hmap chassis_tunnels; /* hmap of 'struct chassis_tunnel' from the > + * tunnel OVS ports. */ > +}; > + > +void ldata_run(const struct ovsrec_bridge *br_int, > + const struct sbrec_chassis *, > + struct local_nonvif_data *nonvif_data); > + > +bool ldata_handle_ovs_iface_changes(const struct ovsrec_interface_table *); > + > +struct chassis_tunnel *chassis_tunnel_find(const struct hmap *chassis_tunnels, > + const char *chassis_id, > + char *encap_ip); > + > +bool get_chassis_tunnel_ofport(const struct hmap *chassis_tunnels, > + const char *chassis_name, char *encap_ip, > + ofp_port_t *ofport); > + > +void local_nonvif_data_init(struct local_nonvif_data *nonvif_data); > +void local_nonvif_data_destroy(struct local_nonvif_data *nonvif_data); > + > #endif /* controller/ldata.h */ > diff --git a/controller/lflow.c b/controller/lflow.c > index d1f32077b..4ac671e40 100644 > --- a/controller/lflow.c > +++ b/controller/lflow.c > @@ -58,6 +58,7 @@ struct lookup_port_aux { > const struct sbrec_datapath_binding *dp; > const struct sbrec_logical_flow *lflow; > struct lflow_resource_ref *lfrr; > + const struct hmap *chassis_tunnels; > }; > > struct condition_aux { > @@ -145,7 +146,8 @@ tunnel_ofport_cb(const void *aux_, const char *port_name, ofp_port_t *ofport) > return false; > } > > - if (!get_tunnel_ofport(pb->chassis->name, NULL, ofport)) { > + if (!get_chassis_tunnel_ofport(aux->chassis_tunnels, pb->chassis->name, > + NULL, ofport)) { > return false; > } > > @@ -591,6 +593,7 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow, > .dp = dp, > .lflow = lflow, > .lfrr = l_ctx_out->lfrr, > + .chassis_tunnels = l_ctx_in->chassis_tunnels, > }; > > /* Encode OVN logical actions into OpenFlow. */ > diff --git a/controller/lflow.h b/controller/lflow.h > index c17ff6dd4..e7dd31289 100644 > --- a/controller/lflow.h > +++ b/controller/lflow.h > @@ -146,6 +146,7 @@ struct lflow_ctx_in { > const struct shash *port_groups; > const struct sset *active_tunnels; > const struct sset *related_lport_ids; > + const struct hmap *chassis_tunnels; > }; > > struct lflow_ctx_out { > diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c > index 8f620e4ad..69d135046 100644 > --- a/controller/ovn-controller.c > +++ b/controller/ovn-controller.c > @@ -1039,6 +1039,11 @@ struct ed_type_runtime_data { > struct related_lports related_lports; > struct sset active_tunnels; > > + /* Non VIF OVS interface information (mainly patch OVS interfacs > + * and tunnel interfaces) that are relevant to the local > + * chassis (generated by ldata_run()). */ > + struct local_nonvif_data nonvif_data; > + I don't see a benefit of adding this to runtime_data. It is unrelated to the other data in the current runtime_data node. Now if we combine it to runtime_data, it means we are coupling those data unnecessarily, which leads to unflexible handler implementation. An example is that now recompute of nonvif_data would trigger recompute of runtime_data, which would trigger recompute of lflow_output. In fact, this can be just in a separate engine node, only as input to pflow_output. Would that be more straightforward and efficient? As to the code organization, I think now I understand why you added the new module ldata.c (suppose it is going to be renamed to local_data.c to be more clear). Although it is not harmful to have that new module, it seems not quite necessary to me, either. The original localvif_to_ofport data is now split into two parts, VIF related and nonVIF related. I don't see benefit of keeping these two parts in the same file. It is reasonable to combine the VIF related data in runtime_data (which could be renamed, because the name was vague), to avoid maintaining redundant data. I think it is ok to stay in binding.c. For the nonVIF part, I think the new engine node can be defined in ovn-controller.c and implemented in physical.c because that data is used by physical flow processing only. I don't have a strong argument for this - maybe just less change is needed for this series (and so the change history would be easier to follow). > /* runtime data engine private data. */ > struct sset egress_ifaces; > struct smap local_iface_ids; > @@ -1139,6 +1144,7 @@ en_runtime_data_init(struct engine_node *node OVS_UNUSED, > local_binding_data_init(&data->lbinding_data); > shash_init(&data->local_active_ports_ipv6_pd); > shash_init(&data->local_active_ports_ras); > + local_nonvif_data_init(&data->nonvif_data); > > /* Init the tracked data. */ > hmap_init(&data->tracked_dp_bindings); > @@ -1160,6 +1166,7 @@ en_runtime_data_cleanup(void *data) > shash_destroy_free_data(&rt_data->local_active_ports_ipv6_pd); > shash_destroy_free_data(&rt_data->local_active_ports_ras); > local_binding_data_destroy(&rt_data->lbinding_data); > + local_nonvif_data_destroy(&rt_data->nonvif_data); > } > > static void > @@ -1272,6 +1279,7 @@ en_runtime_data_run(struct engine_node *node, void *data) > shash_clear_free_data(local_active_ipv6_pd); > shash_clear_free_data(local_active_ras); > local_binding_data_destroy(&rt_data->lbinding_data); > + local_nonvif_data_destroy(&rt_data->nonvif_data); > sset_destroy(local_lports); > related_lports_destroy(&rt_data->related_lports); > sset_destroy(active_tunnels); > @@ -1284,6 +1292,7 @@ en_runtime_data_run(struct engine_node *node, void *data) > sset_init(&rt_data->egress_ifaces); > smap_init(&rt_data->local_iface_ids); > local_binding_data_init(&rt_data->lbinding_data); > + local_nonvif_data_init(&rt_data->nonvif_data); > } > > struct binding_ctx_in b_ctx_in; > @@ -1303,6 +1312,7 @@ en_runtime_data_run(struct engine_node *node, void *data) > bfd_calculate_active_tunnels(b_ctx_in.br_int, active_tunnels); > } > > + ldata_run(b_ctx_in.br_int, b_ctx_in.chassis_rec, &rt_data->nonvif_data); > binding_run(&b_ctx_in, &b_ctx_out); > > engine_set_node_state(node, EN_UPDATED); > @@ -1318,6 +1328,10 @@ runtime_data_ovs_interface_handler(struct engine_node *node, void *data) > rt_data->tracked = true; > b_ctx_out.tracked_dp_bindings = &rt_data->tracked_dp_bindings; > > + if (!ldata_handle_ovs_iface_changes(b_ctx_in.iface_table)) { > + return false; > + } > + This is the performance problem I mentioned above. Before this change, tunnel/patch interface changes only triggered physical_run(), now it would trigger lflow_run(). > if (!binding_handle_ovs_interface_changes(&b_ctx_in, &b_ctx_out)) { > return false; > } > @@ -2060,6 +2074,7 @@ init_lflow_ctx(struct engine_node *node, > l_ctx_in->port_groups = port_groups; > l_ctx_in->active_tunnels = &rt_data->active_tunnels; > l_ctx_in->related_lport_ids = &rt_data->related_lports.lport_ids; > + l_ctx_in->chassis_tunnels = &rt_data->nonvif_data.chassis_tunnels; > > l_ctx_out->flow_table = &fo->flow_table; > l_ctx_out->group_table = &fo->group_table; > @@ -2527,6 +2542,7 @@ static void init_physical_ctx(struct engine_node *node, > p_ctx->ct_zones = ct_zones; > p_ctx->mff_ovn_geneve = ed_mff_ovn_geneve->mff_ovn_geneve; > p_ctx->local_bindings = &rt_data->lbinding_data.bindings; > + p_ctx->nonvif_data = &rt_data->nonvif_data; > } > > static void * > @@ -2583,7 +2599,11 @@ pflow_output_sb_port_binding_handler(struct engine_node *node, > * only. flow_output runtime data handler takes care of processing > * logical flows for any port binding changes. > */ > - physical_handle_port_binding_changes(&p_ctx, &pfo->flow_table); > + const struct sbrec_port_binding *pb; > + SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED (pb, p_ctx.port_binding_table) { > + bool removed = sbrec_port_binding_is_deleted(pb); > + physical_handle_flows_for_lport(pb, removed, &p_ctx, &pfo->flow_table); > + } nit: I think it is better to keep the interface physical_handle_port_binding_changes() and hide this loop details in the physical.c module. Thanks, Han > > engine_set_node_state(node, EN_UPDATED); > return true; > @@ -2613,13 +2633,55 @@ pflow_output_ovs_iface_handler(struct engine_node *node OVS_UNUSED, > struct ed_type_runtime_data *rt_data = > engine_get_input_data("runtime_data", node); > > + struct physical_ctx p_ctx; > + init_physical_ctx(node, rt_data, &p_ctx); > + > + engine_set_node_state(node, EN_UPDATED); > + return physical_handle_ovs_iface_changes(&p_ctx); > +} > + > +static bool > +pflow_output_runtime_data_handler(struct engine_node *node, void *data) > +{ > + struct ed_type_runtime_data *rt_data = > + engine_get_input_data("runtime_data", node); > + > + /* There is no tracked data. Fall back to full recompute of > + * pflow_output. */ > + if (!rt_data->tracked) { > + return false; > + } > + > + struct hmap *tracked_dp_bindings = &rt_data->tracked_dp_bindings; > + if (hmap_is_empty(tracked_dp_bindings)) { > + return true; > + } > + > struct ed_type_pflow_output *pfo = data; > > struct physical_ctx p_ctx; > init_physical_ctx(node, rt_data, &p_ctx); > > + struct tracked_datapath *tdp; > + HMAP_FOR_EACH (tdp, node, tracked_dp_bindings) { > + if (tdp->tracked_type != TRACKED_RESOURCE_UPDATED) { > + /* Fall back to full recompute when a local datapath > + * is added or deleted. */ > + return false; > + } > + > + struct shash_node *shash_node; > + SHASH_FOR_EACH (shash_node, &tdp->lports) { > + struct tracked_lport *lport = shash_node->data; > + bool removed = > + lport->tracked_type == TRACKED_RESOURCE_REMOVED ? true: false; > + physical_handle_flows_for_lport(lport->pb, removed, &p_ctx, > + &pfo->flow_table); > + } > + } > + > engine_set_node_state(node, EN_UPDATED); > - return physical_handle_ovs_iface_changes(&p_ctx, &pfo->flow_table); > + return true; > } > > static void * > @@ -2914,7 +2976,7 @@ main(int argc, char *argv[]) > pflow_output_sb_multicast_group_handler); > > engine_add_input(&en_pflow_output, &en_runtime_data, > - NULL); > + pflow_output_runtime_data_handler); > engine_add_input(&en_pflow_output, &en_sb_encap, NULL); > engine_add_input(&en_pflow_output, &en_mff_ovn_geneve, NULL); > engine_add_input(&en_pflow_output, &en_ovs_open_vswitch, NULL); > diff --git a/controller/ovn-controller.h b/controller/ovn-controller.h > index 578588305..78a53312f 100644 > --- a/controller/ovn-controller.h > +++ b/controller/ovn-controller.h > @@ -45,14 +45,6 @@ const struct ovsrec_bridge *get_bridge(const struct ovsrec_bridge_table *, > > struct sbrec_encap *preferred_encap(const struct sbrec_chassis *); > > -/* Must be a bit-field ordered from most-preferred (higher number) to > - * least-preferred (lower number). */ > -enum chassis_tunnel_type { > - GENEVE = 1 << 2, > - STT = 1 << 1, > - VXLAN = 1 << 0 > -}; > - > uint32_t get_tunnel_type(const char *name); > > struct pb_ld_binding { > diff --git a/controller/physical.c b/controller/physical.c > index b244ff1c2..87080d001 100644 > --- a/controller/physical.c > +++ b/controller/physical.c > @@ -86,46 +86,6 @@ physical_register_ovs_idl(struct ovsdb_idl *ovs_idl) > ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_external_ids); > } > > -static struct simap localvif_to_ofport = > - SIMAP_INITIALIZER(&localvif_to_ofport); > -static struct hmap tunnels = HMAP_INITIALIZER(&tunnels); > - > -/* Maps from a chassis to the OpenFlow port number of the tunnel that can be > - * used to reach that chassis. */ > -struct chassis_tunnel { > - struct hmap_node hmap_node; > - char *chassis_id; > - ofp_port_t ofport; > - enum chassis_tunnel_type type; > -}; > - > -/* > - * This function looks up the list of tunnel ports (provided by > - * ovn-chassis-id ports) and returns the tunnel for the given chassid-id and > - * encap-ip. The ovn-chassis-id is formed using the chassis-id and encap-ip. > - * The list is hashed using the chassis-id. If the encap-ip is not specified, > - * it means we'll just return a tunnel for that chassis-id, i.e. we just check > - * for chassis-id and if there is a match, we'll return the tunnel. > - * If encap-ip is also provided we use both chassis-id and encap-ip to do > - * a more specific lookup. > - */ > -static struct chassis_tunnel * > -chassis_tunnel_find(const char *chassis_id, char *encap_ip) > -{ > - /* > - * If the specific encap_ip is given, look for the chassisid_ip entry, > - * else return the 1st found entry for the chassis. > - */ > - struct chassis_tunnel *tun = NULL; > - HMAP_FOR_EACH_WITH_HASH (tun, hmap_node, hash_string(chassis_id, 0), > - &tunnels) { > - if (encaps_tunnel_id_match(tun->chassis_id, chassis_id, encap_ip)) { > - return tun; > - } > - } > - return NULL; > -} > - > static void > put_load(uint64_t value, enum mf_field_id dst, int ofs, int n_bits, > struct ofpbuf *ofpacts) > @@ -166,17 +126,18 @@ put_resubmit(uint8_t table_id, struct ofpbuf *ofpacts) > * from the associated encap. > */ > static struct chassis_tunnel * > -get_port_binding_tun(const struct sbrec_port_binding *binding) > +get_port_binding_tun(const struct sbrec_port_binding *binding, > + const struct hmap *chassis_tunnels) > { > struct sbrec_encap *encap = binding->encap; > struct sbrec_chassis *chassis = binding->chassis; > struct chassis_tunnel *tun = NULL; > > if (encap) { > - tun = chassis_tunnel_find(chassis->name, encap->ip); > + tun = chassis_tunnel_find(chassis_tunnels, chassis->name, encap->ip); > } > if (!tun) { > - tun = chassis_tunnel_find(chassis->name, NULL); > + tun = chassis_tunnel_find(chassis_tunnels, chassis->name, NULL); > } > return tun; > } > @@ -325,12 +286,13 @@ put_remote_port_redirect_overlay(const struct > uint32_t port_key, > struct match *match, > struct ofpbuf *ofpacts_p, > + const struct hmap *chassis_tunnels, > struct ovn_desired_flow_table *flow_table) > { > if (!is_ha_remote) { > /* Setup encapsulation */ > const struct chassis_tunnel *rem_tun = > - get_port_binding_tun(binding); > + get_port_binding_tun(binding, chassis_tunnels); > if (!rem_tun) { > return; > } > @@ -348,10 +310,10 @@ put_remote_port_redirect_overlay(const struct > continue; > } > if (!tun) { > - tun = chassis_tunnel_find(ch->name, NULL); > + tun = chassis_tunnel_find(chassis_tunnels, ch->name, NULL); > } else { > struct chassis_tunnel *chassis_tunnel = > - chassis_tunnel_find(ch->name, NULL); > + chassis_tunnel_find(chassis_tunnels, ch->name, NULL); > if (chassis_tunnel && > tun->type != chassis_tunnel->type) { > static struct vlog_rate_limit rl = > @@ -385,7 +347,7 @@ put_remote_port_redirect_overlay(const struct > if (!ch) { > continue; > } > - tun = chassis_tunnel_find(ch->name, NULL); > + tun = chassis_tunnel_find(chassis_tunnels, ch->name, NULL); > if (!tun) { > continue; > } > @@ -925,6 +887,9 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, > const struct simap *ct_zones, > const struct sset *active_tunnels, > const struct hmap *local_datapaths, > + const struct shash *local_bindings, > + const struct simap *patch_ofports, > + const struct hmap *chassis_tunnels, > const struct sbrec_port_binding *binding, > const struct sbrec_chassis *chassis, > struct ovn_desired_flow_table *flow_table, > @@ -1081,17 +1046,25 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, > if (!binding->tag) { > goto out; > } > - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, > - binding->parent_port)); > + ofport = local_binding_get_lport_ofport(local_bindings, > + binding->parent_port); > if (ofport) { > tag = *binding->tag; > nested_container = true; > parent_port = lport_lookup_by_name( > sbrec_port_binding_by_name, binding->parent_port); > } > - } else { > - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, > + } else if (!strcmp(binding->type, "localnet") > + || !strcmp(binding->type, "l2gateway")) { > + > + ofport = u16_to_ofp(simap_get(patch_ofports, > binding->logical_port)); > + if (ofport && binding->tag) { > + tag = *binding->tag; > + } > + } else { > + ofport = local_binding_get_lport_ofport(local_bindings, > + binding->logical_port); > const char *requested_chassis = smap_get(&binding->options, > "requested-chassis"); > if (ofport && requested_chassis && requested_chassis[0] && > @@ -1102,12 +1075,6 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, > */ > ofport = 0; > } > - > - if ((!strcmp(binding->type, "localnet") > - || !strcmp(binding->type, "l2gateway")) > - && ofport && binding->tag) { > - tag = *binding->tag; > - } > } > > bool is_ha_remote = false; > @@ -1118,7 +1085,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, > /* It is remote port, may be reached by tunnel or localnet port */ > is_remote = true; > if (localnet_port) { > - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, > + ofport = u16_to_ofp(simap_get(patch_ofports, > localnet_port->logical_port)); > if (!ofport) { > goto out; > @@ -1129,7 +1096,8 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, > if (!binding->chassis) { > goto out; > } > - tun = chassis_tunnel_find(binding->chassis->name, NULL); > + tun = chassis_tunnel_find(chassis_tunnels, > + binding->chassis->name, NULL); > if (!tun) { > goto out; > } > @@ -1383,7 +1351,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, > put_remote_port_redirect_overlay(binding, is_ha_remote, > ha_ch_ordered, mff_ovn_geneve, > tun, port_key, &match, ofpacts_p, > - flow_table); > + chassis_tunnels, flow_table); > } > } > out: > @@ -1396,8 +1364,11 @@ static void > consider_mc_group(enum mf_field_id mff_ovn_geneve, > const struct simap *ct_zones, > const struct hmap *local_datapaths, > + struct shash *local_bindings, > + struct simap *patch_ofports, > const struct sbrec_chassis *chassis, > const struct sbrec_multicast_group *mc, > + const struct hmap *chassis_tunnels, > struct ovn_desired_flow_table *flow_table) > { > uint32_t dp_key = mc->datapath->tunnel_key; > @@ -1444,19 +1415,21 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve, > put_load(zone_id, MFF_LOG_CT_ZONE, 0, 32, &ofpacts); > } > > + const char *lport_name = (port->parent_port && *port->parent_port) ? > + port->parent_port : port->logical_port; > + > if (!strcmp(port->type, "patch")) { > put_load(port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, > &remote_ofpacts); > put_resubmit(OFTABLE_CHECK_LOOPBACK, &remote_ofpacts); > - } else if (simap_contains(&localvif_to_ofport, > - (port->parent_port && *port->parent_port) > - ? port->parent_port : port->logical_port) > + } else if (local_binding_get_primary_pb(local_bindings, lport_name) > + || simap_contains(patch_ofports, port->logical_port) > || (!strcmp(port->type, "l3gateway") > && port->chassis == chassis)) { > put_load(port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, &ofpacts); > put_resubmit(OFTABLE_CHECK_LOOPBACK, &ofpacts); > - } else if (port->chassis && !get_localnet_port(local_datapaths, > - mc->datapath->tunnel_key)) { > + } else if (port->chassis && !get_localnet_port( > + local_datapaths, mc->datapath->tunnel_key)) { > /* Add remote chassis only when localnet port not exist, > * otherwise multicast will reach remote ports through localnet > * port. */ > @@ -1497,7 +1470,7 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve, > const struct chassis_tunnel *prev = NULL; > SSET_FOR_EACH (chassis_name, &remote_chassis) { > const struct chassis_tunnel *tun > - = chassis_tunnel_find(chassis_name, NULL); > + = chassis_tunnel_find(chassis_tunnels, chassis_name, NULL); > if (!tun) { > continue; > } > @@ -1524,41 +1497,50 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve, > sset_destroy(&remote_chassis); > } > > -/* Replaces 'old' by 'new' (destroying 'new'). Returns true if 'old' and 'new' > - * contained different data, false if they were the same. */ > -static bool > -update_ofports(struct simap *old, struct simap *new) > -{ > - bool changed = !simap_equal(old, new); > - simap_swap(old, new); > - simap_destroy(new); > - return changed; > -} > - > void > -physical_handle_port_binding_changes(struct physical_ctx *p_ctx, > - struct ovn_desired_flow_table *flow_table) > +physical_handle_flows_for_lport(const struct sbrec_port_binding *pb, > + bool removed, struct physical_ctx *p_ctx, > + struct ovn_desired_flow_table *flow_table) > { > - const struct sbrec_port_binding *binding; > - struct ofpbuf ofpacts; > - ofpbuf_init(&ofpacts, 0); > - SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED (binding, > - p_ctx->port_binding_table) { > - if (sbrec_port_binding_is_deleted(binding)) { > - ofctrl_remove_flows(flow_table, &binding->header_.uuid); > - } else { > - if (!sbrec_port_binding_is_new(binding)) { > - ofctrl_remove_flows(flow_table, &binding->header_.uuid); > - } > + ofctrl_remove_flows(flow_table, &pb->header_.uuid); > + > + if (!strcmp(pb->type, "external")) { > + /* External lports have a dependency on the localnet port. > + * We need to remove the flows of the localnet port as well > + * and re-consider adding the flows for it. > + */ > + struct local_datapath *ldp = > + get_local_datapath(p_ctx->local_datapaths, > + pb->datapath->tunnel_key); > + if (ldp && ldp->localnet_port) { > + struct ofpbuf ofpacts; > + ofctrl_remove_flows(flow_table, &ldp->localnet_port->header_.uuid); > + ofpbuf_init(&ofpacts, 0); > consider_port_binding(p_ctx->sbrec_port_binding_by_name, > p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > p_ctx->active_tunnels, > p_ctx->local_datapaths, > - binding, p_ctx->chassis, > + p_ctx->local_bindings, > + &p_ctx->nonvif_data->patch_ofports, > + &p_ctx->nonvif_data->chassis_tunnels, > + ldp->localnet_port, p_ctx->chassis, > flow_table, &ofpacts); > + ofpbuf_uninit(&ofpacts); > } > } > - ofpbuf_uninit(&ofpacts); > + > + if (!removed) { > + struct ofpbuf ofpacts; > + ofpbuf_init(&ofpacts, 0); > + consider_port_binding(p_ctx->sbrec_port_binding_by_name, > + p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > + p_ctx->active_tunnels, p_ctx->local_datapaths, > + p_ctx->local_bindings, > + &p_ctx->nonvif_data->patch_ofports, > + &p_ctx->nonvif_data->chassis_tunnels, pb, > + p_ctx->chassis, flow_table, &ofpacts); > + ofpbuf_uninit(&ofpacts); > + } > } > > void > @@ -1574,8 +1556,11 @@ physical_handle_mc_group_changes(struct physical_ctx *p_ctx, > ofctrl_remove_flows(flow_table, &mc->header_.uuid); > } > consider_mc_group(p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > - p_ctx->local_datapaths, > - p_ctx->chassis, mc, flow_table); > + p_ctx->local_datapaths, p_ctx->local_bindings, > + &p_ctx->nonvif_data->patch_ofports, > + p_ctx->chassis, mc, > + &p_ctx->nonvif_data->chassis_tunnels, > + flow_table); > } > } > } > @@ -1591,135 +1576,6 @@ physical_run(struct physical_ctx *p_ctx, > uuid_generate(hc_uuid); > } > > - /* This bool tracks physical mapping changes. */ > - bool physical_map_changed = false; > - > - struct simap new_localvif_to_ofport = > - SIMAP_INITIALIZER(&new_localvif_to_ofport); > - struct simap new_tunnel_to_ofport = > - SIMAP_INITIALIZER(&new_tunnel_to_ofport); > - for (int i = 0; i < p_ctx->br_int->n_ports; i++) { > - const struct ovsrec_port *port_rec = p_ctx->br_int->ports[i]; > - if (!strcmp(port_rec->name, p_ctx->br_int->name)) { > - continue; > - } > - > - const char *tunnel_id = smap_get(&port_rec->external_ids, > - "ovn-chassis-id"); > - if (tunnel_id && encaps_tunnel_id_match(tunnel_id, > - p_ctx->chassis->name, > - NULL)) { > - continue; > - } > - > - const char *localnet = smap_get(&port_rec->external_ids, > - "ovn-localnet-port"); > - const char *l2gateway = smap_get(&port_rec->external_ids, > - "ovn-l2gateway-port"); > - > - for (int j = 0; j < port_rec->n_interfaces; j++) { > - const struct ovsrec_interface *iface_rec = port_rec->interfaces[j]; > - > - /* Get OpenFlow port number. */ > - if (!iface_rec->n_ofport) { > - continue; > - } > - int64_t ofport = iface_rec->ofport[0]; > - if (ofport < 1 || ofport > ofp_to_u16(OFPP_MAX)) { > - continue; > - } > - > - /* Record as patch to local net, logical patch port, chassis, or > - * local logical port. */ > - bool is_patch = !strcmp(iface_rec->type, "patch"); > - if (is_patch && localnet) { > - /* localnet patch ports can be handled just like VIFs. */ > - simap_put(&new_localvif_to_ofport, localnet, ofport); > - break; > - } else if (is_patch && l2gateway) { > - /* L2 gateway patch ports can be handled just like VIFs. */ > - simap_put(&new_localvif_to_ofport, l2gateway, ofport); > - break; > - } else if (tunnel_id) { > - enum chassis_tunnel_type tunnel_type; > - if (!strcmp(iface_rec->type, "geneve")) { > - tunnel_type = GENEVE; > - if (!p_ctx->mff_ovn_geneve) { > - continue; > - } > - } else if (!strcmp(iface_rec->type, "stt")) { > - tunnel_type = STT; > - } else if (!strcmp(iface_rec->type, "vxlan")) { > - tunnel_type = VXLAN; > - } else { > - continue; > - } > - > - simap_put(&new_tunnel_to_ofport, tunnel_id, ofport); > - /* > - * We split the tunnel_id to get the chassis-id > - * and hash the tunnel list on the chassis-id. The > - * reason to use the chassis-id alone is because > - * there might be cases (multicast, gateway chassis) > - * where we need to tunnel to the chassis, but won't > - * have the encap-ip specifically. > - */ > - char *hash_id = NULL; > - char *ip = NULL; > - > - if (!encaps_tunnel_id_parse(tunnel_id, &hash_id, &ip)) { > - continue; > - } > - struct chassis_tunnel *tun = chassis_tunnel_find(hash_id, ip); > - if (tun) { > - /* If the tunnel's ofport has changed, update. */ > - if (tun->ofport != u16_to_ofp(ofport) || > - tun->type != tunnel_type) { > - tun->ofport = u16_to_ofp(ofport); > - tun->type = tunnel_type; > - physical_map_changed = true; > - } > - } else { > - tun = xmalloc(sizeof *tun); > - hmap_insert(&tunnels, &tun->hmap_node, > - hash_string(hash_id, 0)); > - tun->chassis_id = xstrdup(tunnel_id); > - tun->ofport = u16_to_ofp(ofport); > - tun->type = tunnel_type; > - physical_map_changed = true; > - } > - free(hash_id); > - free(ip); > - break; > - } else { > - const char *iface_id = smap_get(&iface_rec->external_ids, > - "iface-id"); > - if (iface_id) { > - simap_put(&new_localvif_to_ofport, iface_id, ofport); > - } > - } > - } > - } > - > - /* Remove tunnels that are no longer here. */ > - struct chassis_tunnel *tun, *tun_next; > - HMAP_FOR_EACH_SAFE (tun, tun_next, hmap_node, &tunnels) { > - if (!simap_find(&new_tunnel_to_ofport, tun->chassis_id)) { > - hmap_remove(&tunnels, &tun->hmap_node); > - physical_map_changed = true; > - free(tun->chassis_id); > - free(tun); > - } > - } > - > - /* Capture changed or removed openflow ports. */ > - physical_map_changed |= update_ofports(&localvif_to_ofport, > - &new_localvif_to_ofport); > - if (physical_map_changed) { > - /* Reprocess logical flow table immediately. */ > - poll_immediate_wake(); > - } > - > struct ofpbuf ofpacts; > ofpbuf_init(&ofpacts, 0); > > @@ -1733,16 +1589,20 @@ physical_run(struct physical_ctx *p_ctx, > consider_port_binding(p_ctx->sbrec_port_binding_by_name, > p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > p_ctx->active_tunnels, p_ctx->local_datapaths, > - binding, p_ctx->chassis, > - flow_table, &ofpacts); > + p_ctx->local_bindings, > + &p_ctx->nonvif_data->patch_ofports, > + &p_ctx->nonvif_data->chassis_tunnels, binding, > + p_ctx->chassis, flow_table, &ofpacts); > } > > /* Handle output to multicast groups, in tables 32 and 33. */ > const struct sbrec_multicast_group *mc; > SBREC_MULTICAST_GROUP_TABLE_FOR_EACH (mc, p_ctx->mc_group_table) { > consider_mc_group(p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > - p_ctx->local_datapaths, p_ctx->chassis, > - mc, flow_table); > + p_ctx->local_datapaths, p_ctx->local_bindings, > + &p_ctx->nonvif_data->patch_ofports, p_ctx->chassis, > + mc, &p_ctx->nonvif_data->chassis_tunnels, > + flow_table); > } > > /* Table 0, priority 100. > @@ -1757,7 +1617,8 @@ physical_run(struct physical_ctx *p_ctx, > * We set MFF_LOG_DATAPATH, MFF_LOG_INPORT, and MFF_LOG_OUTPORT from the > * tunnel key data where possible, then resubmit to table 33 to handle > * packets to the local hypervisor. */ > - HMAP_FOR_EACH (tun, hmap_node, &tunnels) { > + struct chassis_tunnel *tun; > + HMAP_FOR_EACH (tun, hmap_node, &p_ctx->nonvif_data->chassis_tunnels) { > struct match match = MATCH_CATCHALL_INITIALIZER; > match_set_in_port(&match, tun->ofport); > > @@ -1788,7 +1649,7 @@ physical_run(struct physical_ctx *p_ctx, > } > > /* Handle ramp switch encapsulations. */ > - HMAP_FOR_EACH (tun, hmap_node, &tunnels) { > + HMAP_FOR_EACH (tun, hmap_node, &p_ctx->nonvif_data->chassis_tunnels) { > if (tun->type != VXLAN) { > continue; > } > @@ -1925,13 +1786,10 @@ physical_run(struct physical_ctx *p_ctx, > &ofpacts, hc_uuid); > > ofpbuf_uninit(&ofpacts); > - > - simap_destroy(&new_tunnel_to_ofport); > } > > bool > -physical_handle_ovs_iface_changes(struct physical_ctx *p_ctx, > - struct ovn_desired_flow_table *flow_table) > +physical_handle_ovs_iface_changes(struct physical_ctx *p_ctx) > { > const struct ovsrec_interface *iface_rec; > OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, p_ctx->iface_table) { > @@ -1943,64 +1801,6 @@ physical_handle_ovs_iface_changes(struct physical_ctx *p_ctx, > } > } > > - struct ofpbuf ofpacts; > - ofpbuf_init(&ofpacts, 0); > - > - OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, p_ctx->iface_table) { > - const char *iface_id = smap_get(&iface_rec->external_ids, "iface-id"); > - if (!iface_id) { > - continue; > - } > - > - const struct sbrec_port_binding *lb_pb = > - local_binding_get_primary_pb(p_ctx->local_bindings, iface_id); > - if (!lb_pb) { > - /* For regular VIFs (e.g. lsp) the upcoming port-binding update > - * will remove lfows related to the unclaimed ovs port. > - * Localport is a special case and it needs to be managed here > - * since the port is not binded and otherwise the related lfows > - * will not be cleared removing the ovs port. > - */ > - lb_pb = lport_lookup_by_name(p_ctx->sbrec_port_binding_by_name, > - iface_id); > - if (!lb_pb || strcmp(lb_pb->type, "localport")) { > - continue; > - } > - } > - > - int64_t ofport = iface_rec->n_ofport ? *iface_rec->ofport : 0; > - if (ovsrec_interface_is_deleted(iface_rec)) { > - ofctrl_remove_flows(flow_table, &lb_pb->header_.uuid); > - simap_find_and_delete(&localvif_to_ofport, iface_id); > - } else { > - if (!ovsrec_interface_is_new(iface_rec)) { > - ofctrl_remove_flows(flow_table, &lb_pb->header_.uuid); > - } > - > - simap_put(&localvif_to_ofport, iface_id, ofport); > - consider_port_binding(p_ctx->sbrec_port_binding_by_name, > - p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > - p_ctx->active_tunnels, > - p_ctx->local_datapaths, > - lb_pb, p_ctx->chassis, > - flow_table, &ofpacts); > - } > - } > - > - ofpbuf_uninit(&ofpacts); > - return true; > -} > - > -bool > -get_tunnel_ofport(const char *chassis_name, char *encap_ip, ofp_port_t *ofport) > -{ > - struct chassis_tunnel *tun = NULL; > - tun = chassis_tunnel_find(chassis_name, encap_ip); > - if (!tun) { > - return false; > - } > - > - *ofport = tun->ofport; > return true; > } > > diff --git a/controller/physical.h b/controller/physical.h > index feab41df4..3fdc20005 100644 > --- a/controller/physical.h > +++ b/controller/physical.h > @@ -34,6 +34,7 @@ struct simap; > struct sbrec_multicast_group_table; > struct sbrec_port_binding_table; > struct sset; > +struct local_nonvif_data; > > /* OVN Geneve option information. > * > @@ -56,18 +57,18 @@ struct physical_ctx { > const struct simap *ct_zones; > enum mf_field_id mff_ovn_geneve; > struct shash *local_bindings; > + struct local_nonvif_data *nonvif_data; > }; > > void physical_register_ovs_idl(struct ovsdb_idl *); > void physical_run(struct physical_ctx *, > struct ovn_desired_flow_table *); > void physical_clear_unassoc_flows_with_db(struct ovn_desired_flow_table *); > -void physical_handle_port_binding_changes(struct physical_ctx *, > - struct ovn_desired_flow_table *); > void physical_handle_mc_group_changes(struct physical_ctx *, > struct ovn_desired_flow_table *); > -bool physical_handle_ovs_iface_changes(struct physical_ctx *, > - struct ovn_desired_flow_table *); > -bool get_tunnel_ofport(const char *chassis_name, char *encap_ip, > - ofp_port_t *ofport); > +bool physical_handle_ovs_iface_changes(struct physical_ctx *); > +void physical_handle_flows_for_lport(const struct sbrec_port_binding *, > + bool removed, > + struct physical_ctx *, > + struct ovn_desired_flow_table *); > #endif /* controller/physical.h */ > -- > 2.31.1 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
On Tue, Jul 27, 2021 at 3:36 AM Han Zhou <hzhou@ovn.org> wrote: > > Thanks Numan. The commit title has a typo: s/plow/pflow. > > On Fri, Jul 16, 2021 at 4:55 AM <numans@ovn.org> wrote: > > > > From: Numan Siddique <numans@ovn.org> > > > > physical_run() maintains a local copy of local vif to ofports > > in a simap along with the chassis tunnel information. This patch > > removes this from the physical module and now stores it in the > > runtime_data engine node. This makes it easier to handle runtime > > data changes in pflow_output engine. > > > > The newly added handler pflow_output_runtime_data_handler() returns > > false if a datapath is added or removed from the local_datapaths > > and handles the logical port claims and releases incrementally. > > > > Signed-off-by: Numan Siddique <numans@ovn.org> > > --- > > controller/binding.c | 39 ++-- > > controller/binding.h | 23 +++ > > controller/ldata.c | 169 ++++++++++++++++ > > controller/ldata.h | 44 +++++ > > controller/lflow.c | 5 +- > > controller/lflow.h | 1 + > > controller/ovn-controller.c | 68 ++++++- > > controller/ovn-controller.h | 8 - > > controller/physical.c | 382 +++++++++--------------------------- > > controller/physical.h | 13 +- > > 10 files changed, 422 insertions(+), 330 deletions(-) > > > > diff --git a/controller/binding.c b/controller/binding.c > > index 0fd951ad7..b50139726 100644 > > --- a/controller/binding.c > > +++ b/controller/binding.c > > @@ -546,23 +546,6 @@ update_active_pb_ras_pd(const struct > sbrec_port_binding *pb, > > } > > } > > > > -/* Corresponds to each Port_Binding.type. */ > > -enum en_lport_type { > > - LP_UNKNOWN, > > - LP_VIF, > > - LP_CONTAINER, > > - LP_PATCH, > > - LP_L3GATEWAY, > > - LP_LOCALNET, > > - LP_LOCALPORT, > > - LP_L2GATEWAY, > > - LP_VTEP, > > - LP_CHASSISREDIRECT, > > - LP_VIRTUAL, > > - LP_EXTERNAL, > > - LP_REMOTE > > -}; > > - > > /* Local bindings. binding.c module binds the logical port (represented > by > > * Port_Binding rows) and sets the 'chassis' column when it sees the > > * OVS interface row (of type "" or "internal") with the > > @@ -616,7 +599,7 @@ static struct local_binding *local_binding_create( > > static void local_binding_add(struct shash *local_bindings, > > struct local_binding *); > > static struct local_binding *local_binding_find( > > - struct shash *local_bindings, const char *name); > > + const struct shash *local_bindings, const char *name); > > static void local_binding_destroy(struct local_binding *, > > struct shash *binding_lports); > > static void local_binding_delete(struct local_binding *, > > @@ -701,7 +684,8 @@ local_binding_data_destroy(struct local_binding_data > *lbinding_data) > > } > > > > const struct sbrec_port_binding * > > -local_binding_get_primary_pb(struct shash *local_bindings, const char > *pb_name) > > +local_binding_get_primary_pb(struct shash *local_bindings, > > + const char *pb_name) > > { > > struct local_binding *lbinding = > > local_binding_find(local_bindings, pb_name); > > @@ -710,6 +694,19 @@ local_binding_get_primary_pb(struct shash > *local_bindings, const char *pb_name) > > return b_lport ? b_lport->pb : NULL; > > } > > > > +ofp_port_t > > +local_binding_get_lport_ofport(const struct shash *local_bindings, > > + const char *pb_name) > > +{ > > + struct local_binding *lbinding = > > + local_binding_find(local_bindings, pb_name); > > + struct binding_lport *b_lport = > > + local_binding_get_primary_or_localport_lport(lbinding); > > + > > + return (b_lport && lbinding->iface && lbinding->iface->n_ofport) ? > > + u16_to_ofp(lbinding->iface->ofport[0]) : 0; > > +} > > + > > bool > > local_binding_is_up(struct shash *local_bindings, const char *pb_name) > > { > > @@ -871,7 +868,7 @@ is_lport_vif(const struct sbrec_port_binding *pb) > > return !pb->type[0]; > > } > > > > -static enum en_lport_type > > +enum en_lport_type > > get_lport_type(const struct sbrec_port_binding *pb) > > { > > if (is_lport_vif(pb)) { > > @@ -2555,7 +2552,7 @@ local_binding_create(const char *name, const struct > ovsrec_interface *iface) > > } > > > > static struct local_binding * > > -local_binding_find(struct shash *local_bindings, const char *name) > > +local_binding_find(const struct shash *local_bindings, const char *name) > > { > > return shash_find_data(local_bindings, name); > > } > > diff --git a/controller/binding.h b/controller/binding.h > > index b1717bd2b..f1abc4b9c 100644 > > --- a/controller/binding.h > > +++ b/controller/binding.h > > @@ -114,6 +114,9 @@ void local_binding_data_destroy(struct > local_binding_data *); > > > > const struct sbrec_port_binding *local_binding_get_primary_pb( > > struct shash *local_bindings, const char *pb_name); > > +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_down(struct shash *local_bindings, const char > *pb_name); > > void local_binding_set_up(struct shash *local_bindings, const char > *pb_name, > > @@ -134,4 +137,24 @@ bool binding_handle_port_binding_changes(struct > binding_ctx_in *, > > void binding_tracked_dp_destroy(struct hmap *tracked_datapaths); > > > > void binding_dump_local_bindings(struct local_binding_data *, struct ds > *); > > + > > +/* Corresponds to each Port_Binding.type. */ > > +enum en_lport_type { > > + LP_UNKNOWN, > > + LP_VIF, > > + LP_CONTAINER, > > + LP_PATCH, > > + LP_L3GATEWAY, > > + LP_LOCALNET, > > + LP_LOCALPORT, > > + LP_L2GATEWAY, > > + LP_VTEP, > > + LP_CHASSISREDIRECT, > > + LP_VIRTUAL, > > + LP_EXTERNAL, > > + LP_REMOTE > > +}; > > + > > +enum en_lport_type get_lport_type(const struct sbrec_port_binding *); > > + > > #endif /* controller/binding.h */ > > diff --git a/controller/ldata.c b/controller/ldata.c > > index a6df9b1da..f55905551 100644 > > --- a/controller/ldata.c > > +++ b/controller/ldata.c > > @@ -18,10 +18,13 @@ > > /* OVS includes. */ > > #include "include/openvswitch/json.h" > > #include "lib/hmapx.h" > > +#include "lib/flow.h" > > #include "lib/util.h" > > +#include "lib/vswitch-idl.h" > > #include "openvswitch/vlog.h" > > > > /* OVN includes. */ > > +#include "encaps.h" > > #include "ldata.h" > > #include "lport.h" > > #include "lib/ovn-util.h" > > @@ -275,6 +278,172 @@ tracked_datapaths_destroy(struct hmap > *tracked_datapaths) > > hmap_destroy(tracked_datapaths); > > } > > > > +/* Iterates the br_int ports and build the simap of patch to ofports > > + * and chassis tunnels. */ > > +void > > +ldata_run(const struct ovsrec_bridge *br_int, > > + const struct sbrec_chassis *chassis_rec, > > + struct local_nonvif_data *nonvif_data) > > +{ > > + for (int i = 0; i < br_int->n_ports; i++) { > > + const struct ovsrec_port *port_rec = br_int->ports[i]; > > + if (!strcmp(port_rec->name, br_int->name)) { > > + continue; > > + } > > + > > + const char *tunnel_id = smap_get(&port_rec->external_ids, > > + "ovn-chassis-id"); > > + if (tunnel_id && encaps_tunnel_id_match(tunnel_id, > > + chassis_rec->name, > > + NULL)) { > > + continue; > > + } > > + > > + const char *localnet = smap_get(&port_rec->external_ids, > > + "ovn-localnet-port"); > > + const char *l2gateway = smap_get(&port_rec->external_ids, > > + "ovn-l2gateway-port"); > > + > > + for (int j = 0; j < port_rec->n_interfaces; j++) { > > + const struct ovsrec_interface *iface_rec = > port_rec->interfaces[j]; > > + > > + /* Get OpenFlow port number. */ > > + if (!iface_rec->n_ofport) { > > + continue; > > + } > > + int64_t ofport = iface_rec->ofport[0]; > > + if (ofport < 1 || ofport > ofp_to_u16(OFPP_MAX)) { > > + continue; > > + } > > + > > + bool is_patch = !strcmp(iface_rec->type, "patch"); > > + if (is_patch && localnet) { > > + simap_put(&nonvif_data->patch_ofports, localnet, ofport); > > + break; > > + } else if (is_patch && l2gateway) { > > + /* L2 gateway patch ports can be handled just like VIFs. > */ > > + simap_put(&nonvif_data->patch_ofports, l2gateway, > ofport); > > + break; > > + } else if (tunnel_id) { > > + enum chassis_tunnel_type tunnel_type; > > + if (!strcmp(iface_rec->type, "geneve")) { > > + tunnel_type = GENEVE; > > + } else if (!strcmp(iface_rec->type, "stt")) { > > + tunnel_type = STT; > > + } else if (!strcmp(iface_rec->type, "vxlan")) { > > + tunnel_type = VXLAN; > > + } else { > > + continue; > > + } > > + > > + /* We split the tunnel_id to get the chassis-id > > + * and hash the tunnel list on the chassis-id. The > > + * reason to use the chassis-id alone is because > > + * there might be cases (multicast, gateway chassis) > > + * where we need to tunnel to the chassis, but won't > > + * have the encap-ip specifically. > > + */ > > + char *hash_id = NULL; > > + char *ip = NULL; > > + > > + if (!encaps_tunnel_id_parse(tunnel_id, &hash_id, &ip)) { > > + continue; > > + } > > + struct chassis_tunnel *tun = xmalloc(sizeof *tun); > > + hmap_insert(&nonvif_data->chassis_tunnels, > &tun->hmap_node, > > + hash_string(hash_id, 0)); > > + tun->chassis_id = xstrdup(tunnel_id); > > + tun->ofport = u16_to_ofp(ofport); > > + tun->type = tunnel_type; > > + > > + free(hash_id); > > + free(ip); > > + break; > > + } > > + } > > + } > > +} > > + > > +bool > > +ldata_handle_ovs_iface_changes( > > + const struct ovsrec_interface_table *iface_table) > > +{ > > + const struct ovsrec_interface *iface_rec; > > + OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, iface_table) { > > + if (!strcmp(iface_rec->type, "geneve") || > > + !strcmp(iface_rec->type, "patch") || > > + !strcmp(iface_rec->type, "vxlan") || > > + !strcmp(iface_rec->type, "stt")) { > > + return false; > > + } > > + } > > + > > + return true; > > +} > > + > > +bool > > +get_chassis_tunnel_ofport(const struct hmap *chassis_tunnels, > > + const char *chassis_name, char *encap_ip, > > + ofp_port_t *ofport) > > +{ > > + struct chassis_tunnel *tun = NULL; > > + tun = chassis_tunnel_find(chassis_tunnels, chassis_name, encap_ip); > > + if (!tun) { > > + return false; > > + } > > + > > + *ofport = tun->ofport; > > + return true; > > +} > > + > > +void > > +local_nonvif_data_init(struct local_nonvif_data *nonvif_data) > > +{ > > + simap_init(&nonvif_data->patch_ofports); > > + hmap_init(&nonvif_data->chassis_tunnels); > > +} > > + > > +void > > +local_nonvif_data_destroy(struct local_nonvif_data *nonvif_data) > > +{ > > + simap_destroy(&nonvif_data->patch_ofports); > > + struct chassis_tunnel *tun; > > + HMAP_FOR_EACH_POP (tun, hmap_node, &nonvif_data->chassis_tunnels) { > > + free(tun->chassis_id); > > + free(tun); > > + } > > + hmap_destroy(&nonvif_data->chassis_tunnels); > > +} > > + > > + > > +/* > > + * This function looks up the list of tunnel ports (provided by > > + * ovn-chassis-id ports) and returns the tunnel for the given chassid-id > and > > + * encap-ip. The ovn-chassis-id is formed using the chassis-id and > encap-ip. > > + * The list is hashed using the chassis-id. If the encap-ip is not > specified, > > + * it means we'll just return a tunnel for that chassis-id, i.e. we just > check > > + * for chassis-id and if there is a match, we'll return the tunnel. > > + * If encap-ip is also provided we use both chassis-id and encap-ip to do > > + * a more specific lookup. > > + */ > > +struct chassis_tunnel * > > +chassis_tunnel_find(const struct hmap *chassis_tunnels, const char > *chassis_id, > > + char *encap_ip) > > +{ > > + /* > > + * If the specific encap_ip is given, look for the chassisid_ip > entry, > > + * else return the 1st found entry for the chassis. > > + */ > > + struct chassis_tunnel *tun = NULL; > > + HMAP_FOR_EACH_WITH_HASH (tun, hmap_node, hash_string(chassis_id, 0), > > + chassis_tunnels) { > > + if (encaps_tunnel_id_match(tun->chassis_id, chassis_id, > encap_ip)) { > > + return tun; > > + } > > + } > > + return NULL; > > +} > > + > > /* static functions. */ > > static struct local_datapath * > > local_datapath_add__(struct hmap *local_datapaths, > > diff --git a/controller/ldata.h b/controller/ldata.h > > index 16ad43c8f..91624d0b4 100644 > > --- a/controller/ldata.h > > +++ b/controller/ldata.h > > @@ -19,10 +19,14 @@ > > /* OVS includes. */ > > #include "include/openvswitch/shash.h" > > #include "lib/smap.h" > > +#include "lib/simap.h" > > > > struct sbrec_datapath_binding; > > struct sbrec_port_binding; > > +struct sbrec_chassis; > > struct ovsdb_idl_index; > > +struct ovsrec_bridge; > > +struct ovsrec_interface_table; > > > > /* A logical datapath that has some relevance to this hypervisor. A > logical > > * datapath D is relevant to hypervisor H if: > > @@ -117,4 +121,44 @@ void tracked_datapath_lport_add(const struct > sbrec_port_binding *, > > struct hmap *tracked_datapaths); > > void tracked_datapaths_destroy(struct hmap *tracked_datapaths); > > > > +/* Must be a bit-field ordered from most-preferred (higher number) to > > + * least-preferred (lower number). */ > > +enum chassis_tunnel_type { > > + GENEVE = 1 << 2, > > + STT = 1 << 1, > > + VXLAN = 1 << 0 > > +}; > > + > > +/* Maps from a chassis to the OpenFlow port number of the tunnel that > can be > > + * used to reach that chassis. */ > > +struct chassis_tunnel { > > + struct hmap_node hmap_node; > > + char *chassis_id; > > + ofp_port_t ofport; > > + enum chassis_tunnel_type type; > > +}; > > + > > +struct local_nonvif_data { > > + struct simap patch_ofports; /* simap of patch ovs ports. */ > > + struct hmap chassis_tunnels; /* hmap of 'struct chassis_tunnel' from > the > > + * tunnel OVS ports. */ > > +}; > > + > > +void ldata_run(const struct ovsrec_bridge *br_int, > > + const struct sbrec_chassis *, > > + struct local_nonvif_data *nonvif_data); > > + > > +bool ldata_handle_ovs_iface_changes(const struct ovsrec_interface_table > *); > > + > > +struct chassis_tunnel *chassis_tunnel_find(const struct hmap > *chassis_tunnels, > > + const char *chassis_id, > > + char *encap_ip); > > + > > +bool get_chassis_tunnel_ofport(const struct hmap *chassis_tunnels, > > + const char *chassis_name, char *encap_ip, > > + ofp_port_t *ofport); > > + > > +void local_nonvif_data_init(struct local_nonvif_data *nonvif_data); > > +void local_nonvif_data_destroy(struct local_nonvif_data *nonvif_data); > > + > > #endif /* controller/ldata.h */ > > diff --git a/controller/lflow.c b/controller/lflow.c > > index d1f32077b..4ac671e40 100644 > > --- a/controller/lflow.c > > +++ b/controller/lflow.c > > @@ -58,6 +58,7 @@ struct lookup_port_aux { > > const struct sbrec_datapath_binding *dp; > > const struct sbrec_logical_flow *lflow; > > struct lflow_resource_ref *lfrr; > > + const struct hmap *chassis_tunnels; > > }; > > > > struct condition_aux { > > @@ -145,7 +146,8 @@ tunnel_ofport_cb(const void *aux_, const char > *port_name, ofp_port_t *ofport) > > return false; > > } > > > > - if (!get_tunnel_ofport(pb->chassis->name, NULL, ofport)) { > > + if (!get_chassis_tunnel_ofport(aux->chassis_tunnels, > pb->chassis->name, > > + NULL, ofport)) { > > return false; > > } > > > > @@ -591,6 +593,7 @@ add_matches_to_flow_table(const struct > sbrec_logical_flow *lflow, > > .dp = dp, > > .lflow = lflow, > > .lfrr = l_ctx_out->lfrr, > > + .chassis_tunnels = l_ctx_in->chassis_tunnels, > > }; > > > > /* Encode OVN logical actions into OpenFlow. */ > > diff --git a/controller/lflow.h b/controller/lflow.h > > index c17ff6dd4..e7dd31289 100644 > > --- a/controller/lflow.h > > +++ b/controller/lflow.h > > @@ -146,6 +146,7 @@ struct lflow_ctx_in { > > const struct shash *port_groups; > > const struct sset *active_tunnels; > > const struct sset *related_lport_ids; > > + const struct hmap *chassis_tunnels; > > }; > > > > struct lflow_ctx_out { > > diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c > > index 8f620e4ad..69d135046 100644 > > --- a/controller/ovn-controller.c > > +++ b/controller/ovn-controller.c > > @@ -1039,6 +1039,11 @@ struct ed_type_runtime_data { > > struct related_lports related_lports; > > struct sset active_tunnels; > > > > + /* Non VIF OVS interface information (mainly patch OVS interfacs > > + * and tunnel interfaces) that are relevant to the local > > + * chassis (generated by ldata_run()). */ > > + struct local_nonvif_data nonvif_data; > > + > I don't see a benefit of adding this to runtime_data. It is unrelated to > the other data in the current runtime_data node. Now if we combine it to > runtime_data, it means we are coupling those data unnecessarily, which > leads to unflexible handler implementation. An example is that now > recompute of nonvif_data would trigger recompute of runtime_data, which > would trigger recompute of lflow_output. In fact, this can be just in a > separate engine node, only as input to pflow_output. Would that be more > straightforward and efficient? Hi Han, Thanks for the review comments. I see your point. I'll explore if we can add a new engine node for this. My understanding of engine processing is this and runtime data engine in particular is this: 1. The first level of engine nodes would handle the db changes and generates/transforms the data which we can probably call - runtime_data. This was the motivation for me to add the nonvif_data in the runtime data engine. Perhaps we need to further divide the runtime_data engine or rename it so that we only store the VIF related data in this. 2. And the flow output engines ideally would use the runtime data for flow generation. 3. Ideally I'd think (or prefer) to engine nodes one or two level down to not access any db changes at all. For example, lfow_output or pflow_output engine handles should not call IDL TRACKED loops. Maybe we could try to achieve follow up patches if that makes sense. > > As to the code organization, I think now I understand why you added the new > module ldata.c (suppose it is going to be renamed to local_data.c to be > more clear). Although it is not harmful to have that new module, it seems > not quite necessary to me, either. The original localvif_to_ofport data is > now split into two parts, VIF related and nonVIF related. I don't see > benefit of keeping these two parts in the same file. It is reasonable to > combine the VIF related data in runtime_data (which could be renamed, > because the name was vague), to avoid maintaining redundant data. I think > it is ok to stay in binding.c. For the nonVIF part, I think the new engine > node can be defined in ovn-controller.c and implemented in physical.c > because that data is used by physical flow processing only. I don't have a > strong argument for this - maybe just less change is needed for this series > (and so the change history would be easier to follow). I'll explore and see if this can be separated. Although I think having a separate file local_data.c would uncomplicate the binding.c a bit. > > > > /* runtime data engine private data. */ > > struct sset egress_ifaces; > > struct smap local_iface_ids; > > @@ -1139,6 +1144,7 @@ en_runtime_data_init(struct engine_node *node > OVS_UNUSED, > > local_binding_data_init(&data->lbinding_data); > > shash_init(&data->local_active_ports_ipv6_pd); > > shash_init(&data->local_active_ports_ras); > > + local_nonvif_data_init(&data->nonvif_data); > > > > /* Init the tracked data. */ > > hmap_init(&data->tracked_dp_bindings); > > @@ -1160,6 +1166,7 @@ en_runtime_data_cleanup(void *data) > > shash_destroy_free_data(&rt_data->local_active_ports_ipv6_pd); > > shash_destroy_free_data(&rt_data->local_active_ports_ras); > > local_binding_data_destroy(&rt_data->lbinding_data); > > + local_nonvif_data_destroy(&rt_data->nonvif_data); > > } > > > > static void > > @@ -1272,6 +1279,7 @@ en_runtime_data_run(struct engine_node *node, void > *data) > > shash_clear_free_data(local_active_ipv6_pd); > > shash_clear_free_data(local_active_ras); > > local_binding_data_destroy(&rt_data->lbinding_data); > > + local_nonvif_data_destroy(&rt_data->nonvif_data); > > sset_destroy(local_lports); > > related_lports_destroy(&rt_data->related_lports); > > sset_destroy(active_tunnels); > > @@ -1284,6 +1292,7 @@ en_runtime_data_run(struct engine_node *node, void > *data) > > sset_init(&rt_data->egress_ifaces); > > smap_init(&rt_data->local_iface_ids); > > local_binding_data_init(&rt_data->lbinding_data); > > + local_nonvif_data_init(&rt_data->nonvif_data); > > } > > > > struct binding_ctx_in b_ctx_in; > > @@ -1303,6 +1312,7 @@ en_runtime_data_run(struct engine_node *node, void > *data) > > bfd_calculate_active_tunnels(b_ctx_in.br_int, active_tunnels); > > } > > > > + ldata_run(b_ctx_in.br_int, b_ctx_in.chassis_rec, > &rt_data->nonvif_data); > > binding_run(&b_ctx_in, &b_ctx_out); > > > > engine_set_node_state(node, EN_UPDATED); > > @@ -1318,6 +1328,10 @@ runtime_data_ovs_interface_handler(struct > engine_node *node, void *data) > > rt_data->tracked = true; > > b_ctx_out.tracked_dp_bindings = &rt_data->tracked_dp_bindings; > > > > + if (!ldata_handle_ovs_iface_changes(b_ctx_in.iface_table)) { > > + return false; > > + } > > + > > This is the performance problem I mentioned above. Before this change, > tunnel/patch interface changes only triggered physical_run(), now it would > trigger lflow_run(). Actually that's not the case. Any change to tunnel/patch OVS interfaces results in the function binding_handle_ovs_interface_changes() to return false and hence lflow_run() would be called - https://github.com/ovn-org/ovn/blob/master/controller/binding.c#L2198 > > > if (!binding_handle_ovs_interface_changes(&b_ctx_in, &b_ctx_out)) { > > return false; > > } > > @@ -2060,6 +2074,7 @@ init_lflow_ctx(struct engine_node *node, > > l_ctx_in->port_groups = port_groups; > > l_ctx_in->active_tunnels = &rt_data->active_tunnels; > > l_ctx_in->related_lport_ids = &rt_data->related_lports.lport_ids; > > + l_ctx_in->chassis_tunnels = &rt_data->nonvif_data.chassis_tunnels; > > > > l_ctx_out->flow_table = &fo->flow_table; > > l_ctx_out->group_table = &fo->group_table; > > @@ -2527,6 +2542,7 @@ static void init_physical_ctx(struct engine_node > *node, > > p_ctx->ct_zones = ct_zones; > > p_ctx->mff_ovn_geneve = ed_mff_ovn_geneve->mff_ovn_geneve; > > p_ctx->local_bindings = &rt_data->lbinding_data.bindings; > > + p_ctx->nonvif_data = &rt_data->nonvif_data; > > } > > > > static void * > > @@ -2583,7 +2599,11 @@ pflow_output_sb_port_binding_handler(struct > engine_node *node, > > * only. flow_output runtime data handler takes care of processing > > * logical flows for any port binding changes. > > */ > > - physical_handle_port_binding_changes(&p_ctx, &pfo->flow_table); > > + const struct sbrec_port_binding *pb; > > + SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED (pb, > p_ctx.port_binding_table) { > > + bool removed = sbrec_port_binding_is_deleted(pb); > > + physical_handle_flows_for_lport(pb, removed, &p_ctx, > &pfo->flow_table); > > + } > > nit: I think it is better to keep the interface > physical_handle_port_binding_changes() and hide this loop details in the > physical.c module. Ack. Thanks Numan > > Thanks, > Han > > > > > engine_set_node_state(node, EN_UPDATED); > > return true; > > @@ -2613,13 +2633,55 @@ pflow_output_ovs_iface_handler(struct engine_node > *node OVS_UNUSED, > > struct ed_type_runtime_data *rt_data = > > engine_get_input_data("runtime_data", node); > > > > + struct physical_ctx p_ctx; > > + init_physical_ctx(node, rt_data, &p_ctx); > > + > > + engine_set_node_state(node, EN_UPDATED); > > + return physical_handle_ovs_iface_changes(&p_ctx); > > +} > > + > > +static bool > > +pflow_output_runtime_data_handler(struct engine_node *node, void *data) > > +{ > > + struct ed_type_runtime_data *rt_data = > > + engine_get_input_data("runtime_data", node); > > + > > + /* There is no tracked data. Fall back to full recompute of > > + * pflow_output. */ > > + if (!rt_data->tracked) { > > + return false; > > + } > > + > > + struct hmap *tracked_dp_bindings = &rt_data->tracked_dp_bindings; > > + if (hmap_is_empty(tracked_dp_bindings)) { > > + return true; > > + } > > + > > struct ed_type_pflow_output *pfo = data; > > > > struct physical_ctx p_ctx; > > init_physical_ctx(node, rt_data, &p_ctx); > > > > + struct tracked_datapath *tdp; > > + HMAP_FOR_EACH (tdp, node, tracked_dp_bindings) { > > + if (tdp->tracked_type != TRACKED_RESOURCE_UPDATED) { > > + /* Fall back to full recompute when a local datapath > > + * is added or deleted. */ > > + return false; > > + } > > + > > + struct shash_node *shash_node; > > + SHASH_FOR_EACH (shash_node, &tdp->lports) { > > + struct tracked_lport *lport = shash_node->data; > > + bool removed = > > + lport->tracked_type == TRACKED_RESOURCE_REMOVED ? true: > false; > > + physical_handle_flows_for_lport(lport->pb, removed, &p_ctx, > > + &pfo->flow_table); > > + } > > + } > > + > > engine_set_node_state(node, EN_UPDATED); > > - return physical_handle_ovs_iface_changes(&p_ctx, &pfo->flow_table); > > + return true; > > } > > > > static void * > > @@ -2914,7 +2976,7 @@ main(int argc, char *argv[]) > > pflow_output_sb_multicast_group_handler); > > > > engine_add_input(&en_pflow_output, &en_runtime_data, > > - NULL); > > + pflow_output_runtime_data_handler); > > engine_add_input(&en_pflow_output, &en_sb_encap, NULL); > > engine_add_input(&en_pflow_output, &en_mff_ovn_geneve, NULL); > > engine_add_input(&en_pflow_output, &en_ovs_open_vswitch, NULL); > > diff --git a/controller/ovn-controller.h b/controller/ovn-controller.h > > index 578588305..78a53312f 100644 > > --- a/controller/ovn-controller.h > > +++ b/controller/ovn-controller.h > > @@ -45,14 +45,6 @@ const struct ovsrec_bridge *get_bridge(const struct > ovsrec_bridge_table *, > > > > struct sbrec_encap *preferred_encap(const struct sbrec_chassis *); > > > > -/* Must be a bit-field ordered from most-preferred (higher number) to > > - * least-preferred (lower number). */ > > -enum chassis_tunnel_type { > > - GENEVE = 1 << 2, > > - STT = 1 << 1, > > - VXLAN = 1 << 0 > > -}; > > - > > uint32_t get_tunnel_type(const char *name); > > > > struct pb_ld_binding { > > diff --git a/controller/physical.c b/controller/physical.c > > index b244ff1c2..87080d001 100644 > > --- a/controller/physical.c > > +++ b/controller/physical.c > > @@ -86,46 +86,6 @@ physical_register_ovs_idl(struct ovsdb_idl *ovs_idl) > > ovsdb_idl_track_add_column(ovs_idl, > &ovsrec_interface_col_external_ids); > > } > > > > -static struct simap localvif_to_ofport = > > - SIMAP_INITIALIZER(&localvif_to_ofport); > > -static struct hmap tunnels = HMAP_INITIALIZER(&tunnels); > > - > > -/* Maps from a chassis to the OpenFlow port number of the tunnel that > can be > > - * used to reach that chassis. */ > > -struct chassis_tunnel { > > - struct hmap_node hmap_node; > > - char *chassis_id; > > - ofp_port_t ofport; > > - enum chassis_tunnel_type type; > > -}; > > - > > -/* > > - * This function looks up the list of tunnel ports (provided by > > - * ovn-chassis-id ports) and returns the tunnel for the given chassid-id > and > > - * encap-ip. The ovn-chassis-id is formed using the chassis-id and > encap-ip. > > - * The list is hashed using the chassis-id. If the encap-ip is not > specified, > > - * it means we'll just return a tunnel for that chassis-id, i.e. we just > check > > - * for chassis-id and if there is a match, we'll return the tunnel. > > - * If encap-ip is also provided we use both chassis-id and encap-ip to do > > - * a more specific lookup. > > - */ > > -static struct chassis_tunnel * > > -chassis_tunnel_find(const char *chassis_id, char *encap_ip) > > -{ > > - /* > > - * If the specific encap_ip is given, look for the chassisid_ip > entry, > > - * else return the 1st found entry for the chassis. > > - */ > > - struct chassis_tunnel *tun = NULL; > > - HMAP_FOR_EACH_WITH_HASH (tun, hmap_node, hash_string(chassis_id, 0), > > - &tunnels) { > > - if (encaps_tunnel_id_match(tun->chassis_id, chassis_id, > encap_ip)) { > > - return tun; > > - } > > - } > > - return NULL; > > -} > > - > > static void > > put_load(uint64_t value, enum mf_field_id dst, int ofs, int n_bits, > > struct ofpbuf *ofpacts) > > @@ -166,17 +126,18 @@ put_resubmit(uint8_t table_id, struct ofpbuf > *ofpacts) > > * from the associated encap. > > */ > > static struct chassis_tunnel * > > -get_port_binding_tun(const struct sbrec_port_binding *binding) > > +get_port_binding_tun(const struct sbrec_port_binding *binding, > > + const struct hmap *chassis_tunnels) > > { > > struct sbrec_encap *encap = binding->encap; > > struct sbrec_chassis *chassis = binding->chassis; > > struct chassis_tunnel *tun = NULL; > > > > if (encap) { > > - tun = chassis_tunnel_find(chassis->name, encap->ip); > > + tun = chassis_tunnel_find(chassis_tunnels, chassis->name, > encap->ip); > > } > > if (!tun) { > > - tun = chassis_tunnel_find(chassis->name, NULL); > > + tun = chassis_tunnel_find(chassis_tunnels, chassis->name, NULL); > > } > > return tun; > > } > > @@ -325,12 +286,13 @@ put_remote_port_redirect_overlay(const struct > > uint32_t port_key, > > struct match *match, > > struct ofpbuf *ofpacts_p, > > + const struct hmap *chassis_tunnels, > > struct ovn_desired_flow_table > *flow_table) > > { > > if (!is_ha_remote) { > > /* Setup encapsulation */ > > const struct chassis_tunnel *rem_tun = > > - get_port_binding_tun(binding); > > + get_port_binding_tun(binding, chassis_tunnels); > > if (!rem_tun) { > > return; > > } > > @@ -348,10 +310,10 @@ put_remote_port_redirect_overlay(const struct > > continue; > > } > > if (!tun) { > > - tun = chassis_tunnel_find(ch->name, NULL); > > + tun = chassis_tunnel_find(chassis_tunnels, ch->name, > NULL); > > } else { > > struct chassis_tunnel *chassis_tunnel = > > - chassis_tunnel_find(ch->name, > NULL); > > + chassis_tunnel_find(chassis_tunnels, ch->name, NULL); > > if (chassis_tunnel && > > tun->type != chassis_tunnel->type) { > > static struct vlog_rate_limit rl = > > @@ -385,7 +347,7 @@ put_remote_port_redirect_overlay(const struct > > if (!ch) { > > continue; > > } > > - tun = chassis_tunnel_find(ch->name, NULL); > > + tun = chassis_tunnel_find(chassis_tunnels, ch->name, NULL); > > if (!tun) { > > continue; > > } > > @@ -925,6 +887,9 @@ consider_port_binding(struct ovsdb_idl_index > *sbrec_port_binding_by_name, > > const struct simap *ct_zones, > > const struct sset *active_tunnels, > > const struct hmap *local_datapaths, > > + const struct shash *local_bindings, > > + const struct simap *patch_ofports, > > + const struct hmap *chassis_tunnels, > > const struct sbrec_port_binding *binding, > > const struct sbrec_chassis *chassis, > > struct ovn_desired_flow_table *flow_table, > > @@ -1081,17 +1046,25 @@ consider_port_binding(struct ovsdb_idl_index > *sbrec_port_binding_by_name, > > if (!binding->tag) { > > goto out; > > } > > - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, > > - binding->parent_port)); > > + ofport = local_binding_get_lport_ofport(local_bindings, > > + binding->parent_port); > > if (ofport) { > > tag = *binding->tag; > > nested_container = true; > > parent_port = lport_lookup_by_name( > > sbrec_port_binding_by_name, binding->parent_port); > > } > > - } else { > > - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, > > + } else if (!strcmp(binding->type, "localnet") > > + || !strcmp(binding->type, "l2gateway")) { > > + > > + ofport = u16_to_ofp(simap_get(patch_ofports, > > binding->logical_port)); > > + if (ofport && binding->tag) { > > + tag = *binding->tag; > > + } > > + } else { > > + ofport = local_binding_get_lport_ofport(local_bindings, > > + binding->logical_port); > > const char *requested_chassis = smap_get(&binding->options, > > "requested-chassis"); > > if (ofport && requested_chassis && requested_chassis[0] && > > @@ -1102,12 +1075,6 @@ consider_port_binding(struct ovsdb_idl_index > *sbrec_port_binding_by_name, > > */ > > ofport = 0; > > } > > - > > - if ((!strcmp(binding->type, "localnet") > > - || !strcmp(binding->type, "l2gateway")) > > - && ofport && binding->tag) { > > - tag = *binding->tag; > > - } > > } > > > > bool is_ha_remote = false; > > @@ -1118,7 +1085,7 @@ consider_port_binding(struct ovsdb_idl_index > *sbrec_port_binding_by_name, > > /* It is remote port, may be reached by tunnel or localnet port > */ > > is_remote = true; > > if (localnet_port) { > > - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, > > + ofport = u16_to_ofp(simap_get(patch_ofports, > > localnet_port->logical_port)); > > if (!ofport) { > > goto out; > > @@ -1129,7 +1096,8 @@ consider_port_binding(struct ovsdb_idl_index > *sbrec_port_binding_by_name, > > if (!binding->chassis) { > > goto out; > > } > > - tun = chassis_tunnel_find(binding->chassis->name, NULL); > > + tun = chassis_tunnel_find(chassis_tunnels, > > + binding->chassis->name, NULL); > > if (!tun) { > > goto out; > > } > > @@ -1383,7 +1351,7 @@ consider_port_binding(struct ovsdb_idl_index > *sbrec_port_binding_by_name, > > put_remote_port_redirect_overlay(binding, is_ha_remote, > > ha_ch_ordered, > mff_ovn_geneve, > > tun, port_key, &match, > ofpacts_p, > > - flow_table); > > + chassis_tunnels, > flow_table); > > } > > } > > out: > > @@ -1396,8 +1364,11 @@ static void > > consider_mc_group(enum mf_field_id mff_ovn_geneve, > > const struct simap *ct_zones, > > const struct hmap *local_datapaths, > > + struct shash *local_bindings, > > + struct simap *patch_ofports, > > const struct sbrec_chassis *chassis, > > const struct sbrec_multicast_group *mc, > > + const struct hmap *chassis_tunnels, > > struct ovn_desired_flow_table *flow_table) > > { > > uint32_t dp_key = mc->datapath->tunnel_key; > > @@ -1444,19 +1415,21 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve, > > put_load(zone_id, MFF_LOG_CT_ZONE, 0, 32, &ofpacts); > > } > > > > + const char *lport_name = (port->parent_port && > *port->parent_port) ? > > + port->parent_port : port->logical_port; > > + > > if (!strcmp(port->type, "patch")) { > > put_load(port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, > > &remote_ofpacts); > > put_resubmit(OFTABLE_CHECK_LOOPBACK, &remote_ofpacts); > > - } else if (simap_contains(&localvif_to_ofport, > > - (port->parent_port && *port->parent_port) > > - ? port->parent_port : port->logical_port) > > + } else if (local_binding_get_primary_pb(local_bindings, > lport_name) > > + || simap_contains(patch_ofports, port->logical_port) > > || (!strcmp(port->type, "l3gateway") > > && port->chassis == chassis)) { > > put_load(port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, &ofpacts); > > put_resubmit(OFTABLE_CHECK_LOOPBACK, &ofpacts); > > - } else if (port->chassis && !get_localnet_port(local_datapaths, > > - mc->datapath->tunnel_key)) { > > + } else if (port->chassis && !get_localnet_port( > > + local_datapaths, mc->datapath->tunnel_key)) { > > /* Add remote chassis only when localnet port not exist, > > * otherwise multicast will reach remote ports through > localnet > > * port. */ > > @@ -1497,7 +1470,7 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve, > > const struct chassis_tunnel *prev = NULL; > > SSET_FOR_EACH (chassis_name, &remote_chassis) { > > const struct chassis_tunnel *tun > > - = chassis_tunnel_find(chassis_name, NULL); > > + = chassis_tunnel_find(chassis_tunnels, chassis_name, > NULL); > > if (!tun) { > > continue; > > } > > @@ -1524,41 +1497,50 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve, > > sset_destroy(&remote_chassis); > > } > > > > -/* Replaces 'old' by 'new' (destroying 'new'). Returns true if 'old' > and 'new' > > - * contained different data, false if they were the same. */ > > -static bool > > -update_ofports(struct simap *old, struct simap *new) > > -{ > > - bool changed = !simap_equal(old, new); > > - simap_swap(old, new); > > - simap_destroy(new); > > - return changed; > > -} > > - > > void > > -physical_handle_port_binding_changes(struct physical_ctx *p_ctx, > > - struct ovn_desired_flow_table > *flow_table) > > +physical_handle_flows_for_lport(const struct sbrec_port_binding *pb, > > + bool removed, struct physical_ctx *p_ctx, > > + struct ovn_desired_flow_table > *flow_table) > > { > > - const struct sbrec_port_binding *binding; > > - struct ofpbuf ofpacts; > > - ofpbuf_init(&ofpacts, 0); > > - SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED (binding, > > - > p_ctx->port_binding_table) { > > - if (sbrec_port_binding_is_deleted(binding)) { > > - ofctrl_remove_flows(flow_table, &binding->header_.uuid); > > - } else { > > - if (!sbrec_port_binding_is_new(binding)) { > > - ofctrl_remove_flows(flow_table, &binding->header_.uuid); > > - } > > + ofctrl_remove_flows(flow_table, &pb->header_.uuid); > > + > > + if (!strcmp(pb->type, "external")) { > > + /* External lports have a dependency on the localnet port. > > + * We need to remove the flows of the localnet port as well > > + * and re-consider adding the flows for it. > > + */ > > + struct local_datapath *ldp = > > + get_local_datapath(p_ctx->local_datapaths, > > + pb->datapath->tunnel_key); > > + if (ldp && ldp->localnet_port) { > > + struct ofpbuf ofpacts; > > + ofctrl_remove_flows(flow_table, > &ldp->localnet_port->header_.uuid); > > + ofpbuf_init(&ofpacts, 0); > > consider_port_binding(p_ctx->sbrec_port_binding_by_name, > > p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > > p_ctx->active_tunnels, > > p_ctx->local_datapaths, > > - binding, p_ctx->chassis, > > + p_ctx->local_bindings, > > + &p_ctx->nonvif_data->patch_ofports, > > + &p_ctx->nonvif_data->chassis_tunnels, > > + ldp->localnet_port, p_ctx->chassis, > > flow_table, &ofpacts); > > + ofpbuf_uninit(&ofpacts); > > } > > } > > - ofpbuf_uninit(&ofpacts); > > + > > + if (!removed) { > > + struct ofpbuf ofpacts; > > + ofpbuf_init(&ofpacts, 0); > > + consider_port_binding(p_ctx->sbrec_port_binding_by_name, > > + p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > > + p_ctx->active_tunnels, > p_ctx->local_datapaths, > > + p_ctx->local_bindings, > > + &p_ctx->nonvif_data->patch_ofports, > > + &p_ctx->nonvif_data->chassis_tunnels, pb, > > + p_ctx->chassis, flow_table, &ofpacts); > > + ofpbuf_uninit(&ofpacts); > > + } > > } > > > > void > > @@ -1574,8 +1556,11 @@ physical_handle_mc_group_changes(struct > physical_ctx *p_ctx, > > ofctrl_remove_flows(flow_table, &mc->header_.uuid); > > } > > consider_mc_group(p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > > - p_ctx->local_datapaths, > > - p_ctx->chassis, mc, flow_table); > > + p_ctx->local_datapaths, > p_ctx->local_bindings, > > + &p_ctx->nonvif_data->patch_ofports, > > + p_ctx->chassis, mc, > > + &p_ctx->nonvif_data->chassis_tunnels, > > + flow_table); > > } > > } > > } > > @@ -1591,135 +1576,6 @@ physical_run(struct physical_ctx *p_ctx, > > uuid_generate(hc_uuid); > > } > > > > - /* This bool tracks physical mapping changes. */ > > - bool physical_map_changed = false; > > - > > - struct simap new_localvif_to_ofport = > > - SIMAP_INITIALIZER(&new_localvif_to_ofport); > > - struct simap new_tunnel_to_ofport = > > - SIMAP_INITIALIZER(&new_tunnel_to_ofport); > > - for (int i = 0; i < p_ctx->br_int->n_ports; i++) { > > - const struct ovsrec_port *port_rec = p_ctx->br_int->ports[i]; > > - if (!strcmp(port_rec->name, p_ctx->br_int->name)) { > > - continue; > > - } > > - > > - const char *tunnel_id = smap_get(&port_rec->external_ids, > > - "ovn-chassis-id"); > > - if (tunnel_id && encaps_tunnel_id_match(tunnel_id, > > - p_ctx->chassis->name, > > - NULL)) { > > - continue; > > - } > > - > > - const char *localnet = smap_get(&port_rec->external_ids, > > - "ovn-localnet-port"); > > - const char *l2gateway = smap_get(&port_rec->external_ids, > > - "ovn-l2gateway-port"); > > - > > - for (int j = 0; j < port_rec->n_interfaces; j++) { > > - const struct ovsrec_interface *iface_rec = > port_rec->interfaces[j]; > > - > > - /* Get OpenFlow port number. */ > > - if (!iface_rec->n_ofport) { > > - continue; > > - } > > - int64_t ofport = iface_rec->ofport[0]; > > - if (ofport < 1 || ofport > ofp_to_u16(OFPP_MAX)) { > > - continue; > > - } > > - > > - /* Record as patch to local net, logical patch port, > chassis, or > > - * local logical port. */ > > - bool is_patch = !strcmp(iface_rec->type, "patch"); > > - if (is_patch && localnet) { > > - /* localnet patch ports can be handled just like VIFs. */ > > - simap_put(&new_localvif_to_ofport, localnet, ofport); > > - break; > > - } else if (is_patch && l2gateway) { > > - /* L2 gateway patch ports can be handled just like VIFs. > */ > > - simap_put(&new_localvif_to_ofport, l2gateway, ofport); > > - break; > > - } else if (tunnel_id) { > > - enum chassis_tunnel_type tunnel_type; > > - if (!strcmp(iface_rec->type, "geneve")) { > > - tunnel_type = GENEVE; > > - if (!p_ctx->mff_ovn_geneve) { > > - continue; > > - } > > - } else if (!strcmp(iface_rec->type, "stt")) { > > - tunnel_type = STT; > > - } else if (!strcmp(iface_rec->type, "vxlan")) { > > - tunnel_type = VXLAN; > > - } else { > > - continue; > > - } > > - > > - simap_put(&new_tunnel_to_ofport, tunnel_id, ofport); > > - /* > > - * We split the tunnel_id to get the chassis-id > > - * and hash the tunnel list on the chassis-id. The > > - * reason to use the chassis-id alone is because > > - * there might be cases (multicast, gateway chassis) > > - * where we need to tunnel to the chassis, but won't > > - * have the encap-ip specifically. > > - */ > > - char *hash_id = NULL; > > - char *ip = NULL; > > - > > - if (!encaps_tunnel_id_parse(tunnel_id, &hash_id, &ip)) { > > - continue; > > - } > > - struct chassis_tunnel *tun = > chassis_tunnel_find(hash_id, ip); > > - if (tun) { > > - /* If the tunnel's ofport has changed, update. */ > > - if (tun->ofport != u16_to_ofp(ofport) || > > - tun->type != tunnel_type) { > > - tun->ofport = u16_to_ofp(ofport); > > - tun->type = tunnel_type; > > - physical_map_changed = true; > > - } > > - } else { > > - tun = xmalloc(sizeof *tun); > > - hmap_insert(&tunnels, &tun->hmap_node, > > - hash_string(hash_id, 0)); > > - tun->chassis_id = xstrdup(tunnel_id); > > - tun->ofport = u16_to_ofp(ofport); > > - tun->type = tunnel_type; > > - physical_map_changed = true; > > - } > > - free(hash_id); > > - free(ip); > > - break; > > - } else { > > - const char *iface_id = smap_get(&iface_rec->external_ids, > > - "iface-id"); > > - if (iface_id) { > > - simap_put(&new_localvif_to_ofport, iface_id, ofport); > > - } > > - } > > - } > > - } > > - > > - /* Remove tunnels that are no longer here. */ > > - struct chassis_tunnel *tun, *tun_next; > > - HMAP_FOR_EACH_SAFE (tun, tun_next, hmap_node, &tunnels) { > > - if (!simap_find(&new_tunnel_to_ofport, tun->chassis_id)) { > > - hmap_remove(&tunnels, &tun->hmap_node); > > - physical_map_changed = true; > > - free(tun->chassis_id); > > - free(tun); > > - } > > - } > > - > > - /* Capture changed or removed openflow ports. */ > > - physical_map_changed |= update_ofports(&localvif_to_ofport, > > - &new_localvif_to_ofport); > > - if (physical_map_changed) { > > - /* Reprocess logical flow table immediately. */ > > - poll_immediate_wake(); > > - } > > - > > struct ofpbuf ofpacts; > > ofpbuf_init(&ofpacts, 0); > > > > @@ -1733,16 +1589,20 @@ physical_run(struct physical_ctx *p_ctx, > > consider_port_binding(p_ctx->sbrec_port_binding_by_name, > > p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > > p_ctx->active_tunnels, > p_ctx->local_datapaths, > > - binding, p_ctx->chassis, > > - flow_table, &ofpacts); > > + p_ctx->local_bindings, > > + &p_ctx->nonvif_data->patch_ofports, > > + &p_ctx->nonvif_data->chassis_tunnels, > binding, > > + p_ctx->chassis, flow_table, &ofpacts); > > } > > > > /* Handle output to multicast groups, in tables 32 and 33. */ > > const struct sbrec_multicast_group *mc; > > SBREC_MULTICAST_GROUP_TABLE_FOR_EACH (mc, p_ctx->mc_group_table) { > > consider_mc_group(p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > > - p_ctx->local_datapaths, p_ctx->chassis, > > - mc, flow_table); > > + p_ctx->local_datapaths, p_ctx->local_bindings, > > + &p_ctx->nonvif_data->patch_ofports, > p_ctx->chassis, > > + mc, &p_ctx->nonvif_data->chassis_tunnels, > > + flow_table); > > } > > > > /* Table 0, priority 100. > > @@ -1757,7 +1617,8 @@ physical_run(struct physical_ctx *p_ctx, > > * We set MFF_LOG_DATAPATH, MFF_LOG_INPORT, and MFF_LOG_OUTPORT from > the > > * tunnel key data where possible, then resubmit to table 33 to > handle > > * packets to the local hypervisor. */ > > - HMAP_FOR_EACH (tun, hmap_node, &tunnels) { > > + struct chassis_tunnel *tun; > > + HMAP_FOR_EACH (tun, hmap_node, &p_ctx->nonvif_data->chassis_tunnels) > { > > struct match match = MATCH_CATCHALL_INITIALIZER; > > match_set_in_port(&match, tun->ofport); > > > > @@ -1788,7 +1649,7 @@ physical_run(struct physical_ctx *p_ctx, > > } > > > > /* Handle ramp switch encapsulations. */ > > - HMAP_FOR_EACH (tun, hmap_node, &tunnels) { > > + HMAP_FOR_EACH (tun, hmap_node, &p_ctx->nonvif_data->chassis_tunnels) > { > > if (tun->type != VXLAN) { > > continue; > > } > > @@ -1925,13 +1786,10 @@ physical_run(struct physical_ctx *p_ctx, > > &ofpacts, hc_uuid); > > > > ofpbuf_uninit(&ofpacts); > > - > > - simap_destroy(&new_tunnel_to_ofport); > > } > > > > bool > > -physical_handle_ovs_iface_changes(struct physical_ctx *p_ctx, > > - struct ovn_desired_flow_table > *flow_table) > > +physical_handle_ovs_iface_changes(struct physical_ctx *p_ctx) > > { > > const struct ovsrec_interface *iface_rec; > > OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, > p_ctx->iface_table) { > > @@ -1943,64 +1801,6 @@ physical_handle_ovs_iface_changes(struct > physical_ctx *p_ctx, > > } > > } > > > > - struct ofpbuf ofpacts; > > - ofpbuf_init(&ofpacts, 0); > > - > > - OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, > p_ctx->iface_table) { > > - const char *iface_id = smap_get(&iface_rec->external_ids, > "iface-id"); > > - if (!iface_id) { > > - continue; > > - } > > - > > - const struct sbrec_port_binding *lb_pb = > > - local_binding_get_primary_pb(p_ctx->local_bindings, > iface_id); > > - if (!lb_pb) { > > - /* For regular VIFs (e.g. lsp) the upcoming port-binding > update > > - * will remove lfows related to the unclaimed ovs port. > > - * Localport is a special case and it needs to be managed > here > > - * since the port is not binded and otherwise the related > lfows > > - * will not be cleared removing the ovs port. > > - */ > > - lb_pb = > lport_lookup_by_name(p_ctx->sbrec_port_binding_by_name, > > - iface_id); > > - if (!lb_pb || strcmp(lb_pb->type, "localport")) { > > - continue; > > - } > > - } > > - > > - int64_t ofport = iface_rec->n_ofport ? *iface_rec->ofport : 0; > > - if (ovsrec_interface_is_deleted(iface_rec)) { > > - ofctrl_remove_flows(flow_table, &lb_pb->header_.uuid); > > - simap_find_and_delete(&localvif_to_ofport, iface_id); > > - } else { > > - if (!ovsrec_interface_is_new(iface_rec)) { > > - ofctrl_remove_flows(flow_table, &lb_pb->header_.uuid); > > - } > > - > > - simap_put(&localvif_to_ofport, iface_id, ofport); > > - consider_port_binding(p_ctx->sbrec_port_binding_by_name, > > - p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > > - p_ctx->active_tunnels, > > - p_ctx->local_datapaths, > > - lb_pb, p_ctx->chassis, > > - flow_table, &ofpacts); > > - } > > - } > > - > > - ofpbuf_uninit(&ofpacts); > > - return true; > > -} > > - > > -bool > > -get_tunnel_ofport(const char *chassis_name, char *encap_ip, ofp_port_t > *ofport) > > -{ > > - struct chassis_tunnel *tun = NULL; > > - tun = chassis_tunnel_find(chassis_name, encap_ip); > > - if (!tun) { > > - return false; > > - } > > - > > - *ofport = tun->ofport; > > return true; > > } > > > > diff --git a/controller/physical.h b/controller/physical.h > > index feab41df4..3fdc20005 100644 > > --- a/controller/physical.h > > +++ b/controller/physical.h > > @@ -34,6 +34,7 @@ struct simap; > > struct sbrec_multicast_group_table; > > struct sbrec_port_binding_table; > > struct sset; > > +struct local_nonvif_data; > > > > /* OVN Geneve option information. > > * > > @@ -56,18 +57,18 @@ struct physical_ctx { > > const struct simap *ct_zones; > > enum mf_field_id mff_ovn_geneve; > > struct shash *local_bindings; > > + struct local_nonvif_data *nonvif_data; > > }; > > > > void physical_register_ovs_idl(struct ovsdb_idl *); > > void physical_run(struct physical_ctx *, > > struct ovn_desired_flow_table *); > > void physical_clear_unassoc_flows_with_db(struct ovn_desired_flow_table > *); > > -void physical_handle_port_binding_changes(struct physical_ctx *, > > - struct ovn_desired_flow_table > *); > > void physical_handle_mc_group_changes(struct physical_ctx *, > > struct ovn_desired_flow_table *); > > -bool physical_handle_ovs_iface_changes(struct physical_ctx *, > > - struct ovn_desired_flow_table *); > > -bool get_tunnel_ofport(const char *chassis_name, char *encap_ip, > > - ofp_port_t *ofport); > > +bool physical_handle_ovs_iface_changes(struct physical_ctx *); > > +void physical_handle_flows_for_lport(const struct sbrec_port_binding *, > > + bool removed, > > + struct physical_ctx *, > > + struct ovn_desired_flow_table *); > > #endif /* controller/physical.h */ > > -- > > 2.31.1 > > > > _______________________________________________ > > dev mailing list > > dev@openvswitch.org > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > _______________________________________________ > dev mailing list > dev@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev >
On Tue, Jul 27, 2021 at 11:43 AM Numan Siddique <numans@ovn.org> wrote: > > On Tue, Jul 27, 2021 at 3:36 AM Han Zhou <hzhou@ovn.org> wrote: > > > > Thanks Numan. The commit title has a typo: s/plow/pflow. > > > > On Fri, Jul 16, 2021 at 4:55 AM <numans@ovn.org> wrote: > > > > > > From: Numan Siddique <numans@ovn.org> > > > > > > physical_run() maintains a local copy of local vif to ofports > > > in a simap along with the chassis tunnel information. This patch > > > removes this from the physical module and now stores it in the > > > runtime_data engine node. This makes it easier to handle runtime > > > data changes in pflow_output engine. > > > > > > The newly added handler pflow_output_runtime_data_handler() returns > > > false if a datapath is added or removed from the local_datapaths > > > and handles the logical port claims and releases incrementally. > > > > > > Signed-off-by: Numan Siddique <numans@ovn.org> > > > --- > > > controller/binding.c | 39 ++-- > > > controller/binding.h | 23 +++ > > > controller/ldata.c | 169 ++++++++++++++++ > > > controller/ldata.h | 44 +++++ > > > controller/lflow.c | 5 +- > > > controller/lflow.h | 1 + > > > controller/ovn-controller.c | 68 ++++++- > > > controller/ovn-controller.h | 8 - > > > controller/physical.c | 382 +++++++++--------------------------- > > > controller/physical.h | 13 +- > > > 10 files changed, 422 insertions(+), 330 deletions(-) > > > > > > diff --git a/controller/binding.c b/controller/binding.c > > > index 0fd951ad7..b50139726 100644 > > > --- a/controller/binding.c > > > +++ b/controller/binding.c > > > @@ -546,23 +546,6 @@ update_active_pb_ras_pd(const struct > > sbrec_port_binding *pb, > > > } > > > } > > > > > > -/* Corresponds to each Port_Binding.type. */ > > > -enum en_lport_type { > > > - LP_UNKNOWN, > > > - LP_VIF, > > > - LP_CONTAINER, > > > - LP_PATCH, > > > - LP_L3GATEWAY, > > > - LP_LOCALNET, > > > - LP_LOCALPORT, > > > - LP_L2GATEWAY, > > > - LP_VTEP, > > > - LP_CHASSISREDIRECT, > > > - LP_VIRTUAL, > > > - LP_EXTERNAL, > > > - LP_REMOTE > > > -}; > > > - > > > /* Local bindings. binding.c module binds the logical port (represented > > by > > > * Port_Binding rows) and sets the 'chassis' column when it sees the > > > * OVS interface row (of type "" or "internal") with the > > > @@ -616,7 +599,7 @@ static struct local_binding *local_binding_create( > > > static void local_binding_add(struct shash *local_bindings, > > > struct local_binding *); > > > static struct local_binding *local_binding_find( > > > - struct shash *local_bindings, const char *name); > > > + const struct shash *local_bindings, const char *name); > > > static void local_binding_destroy(struct local_binding *, > > > struct shash *binding_lports); > > > static void local_binding_delete(struct local_binding *, > > > @@ -701,7 +684,8 @@ local_binding_data_destroy(struct local_binding_data > > *lbinding_data) > > > } > > > > > > const struct sbrec_port_binding * > > > -local_binding_get_primary_pb(struct shash *local_bindings, const char > > *pb_name) > > > +local_binding_get_primary_pb(struct shash *local_bindings, > > > + const char *pb_name) > > > { > > > struct local_binding *lbinding = > > > local_binding_find(local_bindings, pb_name); > > > @@ -710,6 +694,19 @@ local_binding_get_primary_pb(struct shash > > *local_bindings, const char *pb_name) > > > return b_lport ? b_lport->pb : NULL; > > > } > > > > > > +ofp_port_t > > > +local_binding_get_lport_ofport(const struct shash *local_bindings, > > > + const char *pb_name) > > > +{ > > > + struct local_binding *lbinding = > > > + local_binding_find(local_bindings, pb_name); > > > + struct binding_lport *b_lport = > > > + local_binding_get_primary_or_localport_lport(lbinding); > > > + > > > + return (b_lport && lbinding->iface && lbinding->iface->n_ofport) ? > > > + u16_to_ofp(lbinding->iface->ofport[0]) : 0; > > > +} > > > + > > > bool > > > local_binding_is_up(struct shash *local_bindings, const char *pb_name) > > > { > > > @@ -871,7 +868,7 @@ is_lport_vif(const struct sbrec_port_binding *pb) > > > return !pb->type[0]; > > > } > > > > > > -static enum en_lport_type > > > +enum en_lport_type > > > get_lport_type(const struct sbrec_port_binding *pb) > > > { > > > if (is_lport_vif(pb)) { > > > @@ -2555,7 +2552,7 @@ local_binding_create(const char *name, const struct > > ovsrec_interface *iface) > > > } > > > > > > static struct local_binding * > > > -local_binding_find(struct shash *local_bindings, const char *name) > > > +local_binding_find(const struct shash *local_bindings, const char *name) > > > { > > > return shash_find_data(local_bindings, name); > > > } > > > diff --git a/controller/binding.h b/controller/binding.h > > > index b1717bd2b..f1abc4b9c 100644 > > > --- a/controller/binding.h > > > +++ b/controller/binding.h > > > @@ -114,6 +114,9 @@ void local_binding_data_destroy(struct > > local_binding_data *); > > > > > > const struct sbrec_port_binding *local_binding_get_primary_pb( > > > struct shash *local_bindings, const char *pb_name); > > > +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_down(struct shash *local_bindings, const char > > *pb_name); > > > void local_binding_set_up(struct shash *local_bindings, const char > > *pb_name, > > > @@ -134,4 +137,24 @@ bool binding_handle_port_binding_changes(struct > > binding_ctx_in *, > > > void binding_tracked_dp_destroy(struct hmap *tracked_datapaths); > > > > > > void binding_dump_local_bindings(struct local_binding_data *, struct ds > > *); > > > + > > > +/* Corresponds to each Port_Binding.type. */ > > > +enum en_lport_type { > > > + LP_UNKNOWN, > > > + LP_VIF, > > > + LP_CONTAINER, > > > + LP_PATCH, > > > + LP_L3GATEWAY, > > > + LP_LOCALNET, > > > + LP_LOCALPORT, > > > + LP_L2GATEWAY, > > > + LP_VTEP, > > > + LP_CHASSISREDIRECT, > > > + LP_VIRTUAL, > > > + LP_EXTERNAL, > > > + LP_REMOTE > > > +}; > > > + > > > +enum en_lport_type get_lport_type(const struct sbrec_port_binding *); > > > + > > > #endif /* controller/binding.h */ > > > diff --git a/controller/ldata.c b/controller/ldata.c > > > index a6df9b1da..f55905551 100644 > > > --- a/controller/ldata.c > > > +++ b/controller/ldata.c > > > @@ -18,10 +18,13 @@ > > > /* OVS includes. */ > > > #include "include/openvswitch/json.h" > > > #include "lib/hmapx.h" > > > +#include "lib/flow.h" > > > #include "lib/util.h" > > > +#include "lib/vswitch-idl.h" > > > #include "openvswitch/vlog.h" > > > > > > /* OVN includes. */ > > > +#include "encaps.h" > > > #include "ldata.h" > > > #include "lport.h" > > > #include "lib/ovn-util.h" > > > @@ -275,6 +278,172 @@ tracked_datapaths_destroy(struct hmap > > *tracked_datapaths) > > > hmap_destroy(tracked_datapaths); > > > } > > > > > > +/* Iterates the br_int ports and build the simap of patch to ofports > > > + * and chassis tunnels. */ > > > +void > > > +ldata_run(const struct ovsrec_bridge *br_int, > > > + const struct sbrec_chassis *chassis_rec, > > > + struct local_nonvif_data *nonvif_data) > > > +{ > > > + for (int i = 0; i < br_int->n_ports; i++) { > > > + const struct ovsrec_port *port_rec = br_int->ports[i]; > > > + if (!strcmp(port_rec->name, br_int->name)) { > > > + continue; > > > + } > > > + > > > + const char *tunnel_id = smap_get(&port_rec->external_ids, > > > + "ovn-chassis-id"); > > > + if (tunnel_id && encaps_tunnel_id_match(tunnel_id, > > > + chassis_rec->name, > > > + NULL)) { > > > + continue; > > > + } > > > + > > > + const char *localnet = smap_get(&port_rec->external_ids, > > > + "ovn-localnet-port"); > > > + const char *l2gateway = smap_get(&port_rec->external_ids, > > > + "ovn-l2gateway-port"); > > > + > > > + for (int j = 0; j < port_rec->n_interfaces; j++) { > > > + const struct ovsrec_interface *iface_rec = > > port_rec->interfaces[j]; > > > + > > > + /* Get OpenFlow port number. */ > > > + if (!iface_rec->n_ofport) { > > > + continue; > > > + } > > > + int64_t ofport = iface_rec->ofport[0]; > > > + if (ofport < 1 || ofport > ofp_to_u16(OFPP_MAX)) { > > > + continue; > > > + } > > > + > > > + bool is_patch = !strcmp(iface_rec->type, "patch"); > > > + if (is_patch && localnet) { > > > + simap_put(&nonvif_data->patch_ofports, localnet, ofport); > > > + break; > > > + } else if (is_patch && l2gateway) { > > > + /* L2 gateway patch ports can be handled just like VIFs. > > */ > > > + simap_put(&nonvif_data->patch_ofports, l2gateway, > > ofport); > > > + break; > > > + } else if (tunnel_id) { > > > + enum chassis_tunnel_type tunnel_type; > > > + if (!strcmp(iface_rec->type, "geneve")) { > > > + tunnel_type = GENEVE; > > > + } else if (!strcmp(iface_rec->type, "stt")) { > > > + tunnel_type = STT; > > > + } else if (!strcmp(iface_rec->type, "vxlan")) { > > > + tunnel_type = VXLAN; > > > + } else { > > > + continue; > > > + } > > > + > > > + /* We split the tunnel_id to get the chassis-id > > > + * and hash the tunnel list on the chassis-id. The > > > + * reason to use the chassis-id alone is because > > > + * there might be cases (multicast, gateway chassis) > > > + * where we need to tunnel to the chassis, but won't > > > + * have the encap-ip specifically. > > > + */ > > > + char *hash_id = NULL; > > > + char *ip = NULL; > > > + > > > + if (!encaps_tunnel_id_parse(tunnel_id, &hash_id, &ip)) { > > > + continue; > > > + } > > > + struct chassis_tunnel *tun = xmalloc(sizeof *tun); > > > + hmap_insert(&nonvif_data->chassis_tunnels, > > &tun->hmap_node, > > > + hash_string(hash_id, 0)); > > > + tun->chassis_id = xstrdup(tunnel_id); > > > + tun->ofport = u16_to_ofp(ofport); > > > + tun->type = tunnel_type; > > > + > > > + free(hash_id); > > > + free(ip); > > > + break; > > > + } > > > + } > > > + } > > > +} > > > + > > > +bool > > > +ldata_handle_ovs_iface_changes( > > > + const struct ovsrec_interface_table *iface_table) > > > +{ > > > + const struct ovsrec_interface *iface_rec; > > > + OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, iface_table) { > > > + if (!strcmp(iface_rec->type, "geneve") || > > > + !strcmp(iface_rec->type, "patch") || > > > + !strcmp(iface_rec->type, "vxlan") || > > > + !strcmp(iface_rec->type, "stt")) { > > > + return false; > > > + } > > > + } > > > + > > > + return true; > > > +} > > > + > > > +bool > > > +get_chassis_tunnel_ofport(const struct hmap *chassis_tunnels, > > > + const char *chassis_name, char *encap_ip, > > > + ofp_port_t *ofport) > > > +{ > > > + struct chassis_tunnel *tun = NULL; > > > + tun = chassis_tunnel_find(chassis_tunnels, chassis_name, encap_ip); > > > + if (!tun) { > > > + return false; > > > + } > > > + > > > + *ofport = tun->ofport; > > > + return true; > > > +} > > > + > > > +void > > > +local_nonvif_data_init(struct local_nonvif_data *nonvif_data) > > > +{ > > > + simap_init(&nonvif_data->patch_ofports); > > > + hmap_init(&nonvif_data->chassis_tunnels); > > > +} > > > + > > > +void > > > +local_nonvif_data_destroy(struct local_nonvif_data *nonvif_data) > > > +{ > > > + simap_destroy(&nonvif_data->patch_ofports); > > > + struct chassis_tunnel *tun; > > > + HMAP_FOR_EACH_POP (tun, hmap_node, &nonvif_data->chassis_tunnels) { > > > + free(tun->chassis_id); > > > + free(tun); > > > + } > > > + hmap_destroy(&nonvif_data->chassis_tunnels); > > > +} > > > + > > > + > > > +/* > > > + * This function looks up the list of tunnel ports (provided by > > > + * ovn-chassis-id ports) and returns the tunnel for the given chassid-id > > and > > > + * encap-ip. The ovn-chassis-id is formed using the chassis-id and > > encap-ip. > > > + * The list is hashed using the chassis-id. If the encap-ip is not > > specified, > > > + * it means we'll just return a tunnel for that chassis-id, i.e. we just > > check > > > + * for chassis-id and if there is a match, we'll return the tunnel. > > > + * If encap-ip is also provided we use both chassis-id and encap-ip to do > > > + * a more specific lookup. > > > + */ > > > +struct chassis_tunnel * > > > +chassis_tunnel_find(const struct hmap *chassis_tunnels, const char > > *chassis_id, > > > + char *encap_ip) > > > +{ > > > + /* > > > + * If the specific encap_ip is given, look for the chassisid_ip > > entry, > > > + * else return the 1st found entry for the chassis. > > > + */ > > > + struct chassis_tunnel *tun = NULL; > > > + HMAP_FOR_EACH_WITH_HASH (tun, hmap_node, hash_string(chassis_id, 0), > > > + chassis_tunnels) { > > > + if (encaps_tunnel_id_match(tun->chassis_id, chassis_id, > > encap_ip)) { > > > + return tun; > > > + } > > > + } > > > + return NULL; > > > +} > > > + > > > /* static functions. */ > > > static struct local_datapath * > > > local_datapath_add__(struct hmap *local_datapaths, > > > diff --git a/controller/ldata.h b/controller/ldata.h > > > index 16ad43c8f..91624d0b4 100644 > > > --- a/controller/ldata.h > > > +++ b/controller/ldata.h > > > @@ -19,10 +19,14 @@ > > > /* OVS includes. */ > > > #include "include/openvswitch/shash.h" > > > #include "lib/smap.h" > > > +#include "lib/simap.h" > > > > > > struct sbrec_datapath_binding; > > > struct sbrec_port_binding; > > > +struct sbrec_chassis; > > > struct ovsdb_idl_index; > > > +struct ovsrec_bridge; > > > +struct ovsrec_interface_table; > > > > > > /* A logical datapath that has some relevance to this hypervisor. A > > logical > > > * datapath D is relevant to hypervisor H if: > > > @@ -117,4 +121,44 @@ void tracked_datapath_lport_add(const struct > > sbrec_port_binding *, > > > struct hmap *tracked_datapaths); > > > void tracked_datapaths_destroy(struct hmap *tracked_datapaths); > > > > > > +/* Must be a bit-field ordered from most-preferred (higher number) to > > > + * least-preferred (lower number). */ > > > +enum chassis_tunnel_type { > > > + GENEVE = 1 << 2, > > > + STT = 1 << 1, > > > + VXLAN = 1 << 0 > > > +}; > > > + > > > +/* Maps from a chassis to the OpenFlow port number of the tunnel that > > can be > > > + * used to reach that chassis. */ > > > +struct chassis_tunnel { > > > + struct hmap_node hmap_node; > > > + char *chassis_id; > > > + ofp_port_t ofport; > > > + enum chassis_tunnel_type type; > > > +}; > > > + > > > +struct local_nonvif_data { > > > + struct simap patch_ofports; /* simap of patch ovs ports. */ > > > + struct hmap chassis_tunnels; /* hmap of 'struct chassis_tunnel' from > > the > > > + * tunnel OVS ports. */ > > > +}; > > > + > > > +void ldata_run(const struct ovsrec_bridge *br_int, > > > + const struct sbrec_chassis *, > > > + struct local_nonvif_data *nonvif_data); > > > + > > > +bool ldata_handle_ovs_iface_changes(const struct ovsrec_interface_table > > *); > > > + > > > +struct chassis_tunnel *chassis_tunnel_find(const struct hmap > > *chassis_tunnels, > > > + const char *chassis_id, > > > + char *encap_ip); > > > + > > > +bool get_chassis_tunnel_ofport(const struct hmap *chassis_tunnels, > > > + const char *chassis_name, char *encap_ip, > > > + ofp_port_t *ofport); > > > + > > > +void local_nonvif_data_init(struct local_nonvif_data *nonvif_data); > > > +void local_nonvif_data_destroy(struct local_nonvif_data *nonvif_data); > > > + > > > #endif /* controller/ldata.h */ > > > diff --git a/controller/lflow.c b/controller/lflow.c > > > index d1f32077b..4ac671e40 100644 > > > --- a/controller/lflow.c > > > +++ b/controller/lflow.c > > > @@ -58,6 +58,7 @@ struct lookup_port_aux { > > > const struct sbrec_datapath_binding *dp; > > > const struct sbrec_logical_flow *lflow; > > > struct lflow_resource_ref *lfrr; > > > + const struct hmap *chassis_tunnels; > > > }; > > > > > > struct condition_aux { > > > @@ -145,7 +146,8 @@ tunnel_ofport_cb(const void *aux_, const char > > *port_name, ofp_port_t *ofport) > > > return false; > > > } > > > > > > - if (!get_tunnel_ofport(pb->chassis->name, NULL, ofport)) { > > > + if (!get_chassis_tunnel_ofport(aux->chassis_tunnels, > > pb->chassis->name, > > > + NULL, ofport)) { > > > return false; > > > } > > > > > > @@ -591,6 +593,7 @@ add_matches_to_flow_table(const struct > > sbrec_logical_flow *lflow, > > > .dp = dp, > > > .lflow = lflow, > > > .lfrr = l_ctx_out->lfrr, > > > + .chassis_tunnels = l_ctx_in->chassis_tunnels, > > > }; > > > > > > /* Encode OVN logical actions into OpenFlow. */ > > > diff --git a/controller/lflow.h b/controller/lflow.h > > > index c17ff6dd4..e7dd31289 100644 > > > --- a/controller/lflow.h > > > +++ b/controller/lflow.h > > > @@ -146,6 +146,7 @@ struct lflow_ctx_in { > > > const struct shash *port_groups; > > > const struct sset *active_tunnels; > > > const struct sset *related_lport_ids; > > > + const struct hmap *chassis_tunnels; > > > }; > > > > > > struct lflow_ctx_out { > > > diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c > > > index 8f620e4ad..69d135046 100644 > > > --- a/controller/ovn-controller.c > > > +++ b/controller/ovn-controller.c > > > @@ -1039,6 +1039,11 @@ struct ed_type_runtime_data { > > > struct related_lports related_lports; > > > struct sset active_tunnels; > > > > > > + /* Non VIF OVS interface information (mainly patch OVS interfacs > > > + * and tunnel interfaces) that are relevant to the local > > > + * chassis (generated by ldata_run()). */ > > > + struct local_nonvif_data nonvif_data; > > > + > > I don't see a benefit of adding this to runtime_data. It is unrelated to > > the other data in the current runtime_data node. Now if we combine it to > > runtime_data, it means we are coupling those data unnecessarily, which > > leads to unflexible handler implementation. An example is that now > > recompute of nonvif_data would trigger recompute of runtime_data, which > > would trigger recompute of lflow_output. In fact, this can be just in a > > separate engine node, only as input to pflow_output. Would that be more > > straightforward and efficient? > > Hi Han, > > Thanks for the review comments. > > I see your point. I'll explore if we can add a new engine node for this. > > My understanding of engine processing is this and runtime data engine > in particular is this: > > 1. The first level of engine nodes would handle the db changes and > generates/transforms the data > which we can probably call - runtime_data. This was the > motivation for me to add the nonvif_data > in the runtime data engine. Perhaps we need to further divide > the runtime_data engine or rename it > so that we only store the VIF related data in this. Hi Numan, it seems we had different models for I-P engine nodes in our minds. Sorry that I didn't document these thoughts initially for the I-P engine. I don't think we should restrict the engine nodes in such layers. It should be flexible enough based on the real computation dependencies - just thinking about how DDlog programs would be written. I am not against the idea of a separate encapsulation layer for OVSDB IDL, but runtime_data was not for that purpose. Initially the I-P engine was very coarse grained, so I just created a big "runtime_data" node trying to contain all the intermediate data, just enough to support the first version of I-P for the most frequent changes. Now that we are making the I-P engine more and more fine-grained, we definitely cannot simply put everything in a single node. The current runtime_data may be renamed to binding_data, or be further split if necessary, and we don't need to put more data into it unless it is tightly related to the bindings handling. > 2. And the flow output engines ideally would use the runtime data for > flow generation. The output nodes should only depend on whatever data that is necessary for flow computation. What you said is true if "runtime data" here contains everything that is needed for flow computation, but it should never be a goal to keep all these data in a single I-P engine node, because that would not really benefit from the I-P engine. > 3. Ideally I'd think (or prefer) to engine nodes one or two level > down to not access any db changes at all. > For example, lfow_output or pflow_output engine handles should > not call IDL TRACKED loops. > > Maybe we could try to achieve follow up patches if that makes sense. > Encapsulating IDL to a separate layer may be reasonable, if it provides values, but I think it is another topic. I don't think it changes the I-P model. Thanks, Han > > > > > > As to the code organization, I think now I understand why you added the new > > module ldata.c (suppose it is going to be renamed to local_data.c to be > > more clear). Although it is not harmful to have that new module, it seems > > not quite necessary to me, either. The original localvif_to_ofport data is > > now split into two parts, VIF related and nonVIF related. I don't see > > benefit of keeping these two parts in the same file. It is reasonable to > > combine the VIF related data in runtime_data (which could be renamed, > > because the name was vague), to avoid maintaining redundant data. I think > > it is ok to stay in binding.c. For the nonVIF part, I think the new engine > > node can be defined in ovn-controller.c and implemented in physical.c > > because that data is used by physical flow processing only. I don't have a > > strong argument for this - maybe just less change is needed for this series > > (and so the change history would be easier to follow). > > I'll explore and see if this can be separated. Although I think > having a separate file local_data.c would uncomplicate the binding.c a > bit. > > > > > > > > > /* runtime data engine private data. */ > > > struct sset egress_ifaces; > > > struct smap local_iface_ids; > > > @@ -1139,6 +1144,7 @@ en_runtime_data_init(struct engine_node *node > > OVS_UNUSED, > > > local_binding_data_init(&data->lbinding_data); > > > shash_init(&data->local_active_ports_ipv6_pd); > > > shash_init(&data->local_active_ports_ras); > > > + local_nonvif_data_init(&data->nonvif_data); > > > > > > /* Init the tracked data. */ > > > hmap_init(&data->tracked_dp_bindings); > > > @@ -1160,6 +1166,7 @@ en_runtime_data_cleanup(void *data) > > > shash_destroy_free_data(&rt_data->local_active_ports_ipv6_pd); > > > shash_destroy_free_data(&rt_data->local_active_ports_ras); > > > local_binding_data_destroy(&rt_data->lbinding_data); > > > + local_nonvif_data_destroy(&rt_data->nonvif_data); > > > } > > > > > > static void > > > @@ -1272,6 +1279,7 @@ en_runtime_data_run(struct engine_node *node, void > > *data) > > > shash_clear_free_data(local_active_ipv6_pd); > > > shash_clear_free_data(local_active_ras); > > > local_binding_data_destroy(&rt_data->lbinding_data); > > > + local_nonvif_data_destroy(&rt_data->nonvif_data); > > > sset_destroy(local_lports); > > > related_lports_destroy(&rt_data->related_lports); > > > sset_destroy(active_tunnels); > > > @@ -1284,6 +1292,7 @@ en_runtime_data_run(struct engine_node *node, void > > *data) > > > sset_init(&rt_data->egress_ifaces); > > > smap_init(&rt_data->local_iface_ids); > > > local_binding_data_init(&rt_data->lbinding_data); > > > + local_nonvif_data_init(&rt_data->nonvif_data); > > > } > > > > > > struct binding_ctx_in b_ctx_in; > > > @@ -1303,6 +1312,7 @@ en_runtime_data_run(struct engine_node *node, void > > *data) > > > bfd_calculate_active_tunnels(b_ctx_in.br_int, active_tunnels); > > > } > > > > > > + ldata_run(b_ctx_in.br_int, b_ctx_in.chassis_rec, > > &rt_data->nonvif_data); > > > binding_run(&b_ctx_in, &b_ctx_out); > > > > > > engine_set_node_state(node, EN_UPDATED); > > > @@ -1318,6 +1328,10 @@ runtime_data_ovs_interface_handler(struct > > engine_node *node, void *data) > > > rt_data->tracked = true; > > > b_ctx_out.tracked_dp_bindings = &rt_data->tracked_dp_bindings; > > > > > > + if (!ldata_handle_ovs_iface_changes(b_ctx_in.iface_table)) { > > > + return false; > > > + } > > > + > > > > This is the performance problem I mentioned above. Before this change, > > tunnel/patch interface changes only triggered physical_run(), now it would > > trigger lflow_run(). > > Actually that's not the case. Any change to tunnel/patch OVS interfaces results > in the function binding_handle_ovs_interface_changes() to return false and hence > lflow_run() would be called - > https://github.com/ovn-org/ovn/blob/master/controller/binding.c#L2198 > > > > > > > > if (!binding_handle_ovs_interface_changes(&b_ctx_in, &b_ctx_out)) { > > > return false; > > > } > > > @@ -2060,6 +2074,7 @@ init_lflow_ctx(struct engine_node *node, > > > l_ctx_in->port_groups = port_groups; > > > l_ctx_in->active_tunnels = &rt_data->active_tunnels; > > > l_ctx_in->related_lport_ids = &rt_data->related_lports.lport_ids; > > > + l_ctx_in->chassis_tunnels = &rt_data->nonvif_data.chassis_tunnels; > > > > > > l_ctx_out->flow_table = &fo->flow_table; > > > l_ctx_out->group_table = &fo->group_table; > > > @@ -2527,6 +2542,7 @@ static void init_physical_ctx(struct engine_node > > *node, > > > p_ctx->ct_zones = ct_zones; > > > p_ctx->mff_ovn_geneve = ed_mff_ovn_geneve->mff_ovn_geneve; > > > p_ctx->local_bindings = &rt_data->lbinding_data.bindings; > > > + p_ctx->nonvif_data = &rt_data->nonvif_data; > > > } > > > > > > static void * > > > @@ -2583,7 +2599,11 @@ pflow_output_sb_port_binding_handler(struct > > engine_node *node, > > > * only. flow_output runtime data handler takes care of processing > > > * logical flows for any port binding changes. > > > */ > > > - physical_handle_port_binding_changes(&p_ctx, &pfo->flow_table); > > > + const struct sbrec_port_binding *pb; > > > + SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED (pb, > > p_ctx.port_binding_table) { > > > + bool removed = sbrec_port_binding_is_deleted(pb); > > > + physical_handle_flows_for_lport(pb, removed, &p_ctx, > > &pfo->flow_table); > > > + } > > > > nit: I think it is better to keep the interface > > physical_handle_port_binding_changes() and hide this loop details in the > > physical.c module. > > Ack. > > Thanks > Numan > > > > > Thanks, > > Han > > > > > > > > engine_set_node_state(node, EN_UPDATED); > > > return true; > > > @@ -2613,13 +2633,55 @@ pflow_output_ovs_iface_handler(struct engine_node > > *node OVS_UNUSED, > > > struct ed_type_runtime_data *rt_data = > > > engine_get_input_data("runtime_data", node); > > > > > > + struct physical_ctx p_ctx; > > > + init_physical_ctx(node, rt_data, &p_ctx); > > > + > > > + engine_set_node_state(node, EN_UPDATED); > > > + return physical_handle_ovs_iface_changes(&p_ctx); > > > +} > > > + > > > +static bool > > > +pflow_output_runtime_data_handler(struct engine_node *node, void *data) > > > +{ > > > + struct ed_type_runtime_data *rt_data = > > > + engine_get_input_data("runtime_data", node); > > > + > > > + /* There is no tracked data. Fall back to full recompute of > > > + * pflow_output. */ > > > + if (!rt_data->tracked) { > > > + return false; > > > + } > > > + > > > + struct hmap *tracked_dp_bindings = &rt_data->tracked_dp_bindings; > > > + if (hmap_is_empty(tracked_dp_bindings)) { > > > + return true; > > > + } > > > + > > > struct ed_type_pflow_output *pfo = data; > > > > > > struct physical_ctx p_ctx; > > > init_physical_ctx(node, rt_data, &p_ctx); > > > > > > + struct tracked_datapath *tdp; > > > + HMAP_FOR_EACH (tdp, node, tracked_dp_bindings) { > > > + if (tdp->tracked_type != TRACKED_RESOURCE_UPDATED) { > > > + /* Fall back to full recompute when a local datapath > > > + * is added or deleted. */ > > > + return false; > > > + } > > > + > > > + struct shash_node *shash_node; > > > + SHASH_FOR_EACH (shash_node, &tdp->lports) { > > > + struct tracked_lport *lport = shash_node->data; > > > + bool removed = > > > + lport->tracked_type == TRACKED_RESOURCE_REMOVED ? true: > > false; > > > + physical_handle_flows_for_lport(lport->pb, removed, &p_ctx, > > > + &pfo->flow_table); > > > + } > > > + } > > > + > > > engine_set_node_state(node, EN_UPDATED); > > > - return physical_handle_ovs_iface_changes(&p_ctx, &pfo->flow_table); > > > + return true; > > > } > > > > > > static void * > > > @@ -2914,7 +2976,7 @@ main(int argc, char *argv[]) > > > pflow_output_sb_multicast_group_handler); > > > > > > engine_add_input(&en_pflow_output, &en_runtime_data, > > > - NULL); > > > + pflow_output_runtime_data_handler); > > > engine_add_input(&en_pflow_output, &en_sb_encap, NULL); > > > engine_add_input(&en_pflow_output, &en_mff_ovn_geneve, NULL); > > > engine_add_input(&en_pflow_output, &en_ovs_open_vswitch, NULL); > > > diff --git a/controller/ovn-controller.h b/controller/ovn-controller.h > > > index 578588305..78a53312f 100644 > > > --- a/controller/ovn-controller.h > > > +++ b/controller/ovn-controller.h > > > @@ -45,14 +45,6 @@ const struct ovsrec_bridge *get_bridge(const struct > > ovsrec_bridge_table *, > > > > > > struct sbrec_encap *preferred_encap(const struct sbrec_chassis *); > > > > > > -/* Must be a bit-field ordered from most-preferred (higher number) to > > > - * least-preferred (lower number). */ > > > -enum chassis_tunnel_type { > > > - GENEVE = 1 << 2, > > > - STT = 1 << 1, > > > - VXLAN = 1 << 0 > > > -}; > > > - > > > uint32_t get_tunnel_type(const char *name); > > > > > > struct pb_ld_binding { > > > diff --git a/controller/physical.c b/controller/physical.c > > > index b244ff1c2..87080d001 100644 > > > --- a/controller/physical.c > > > +++ b/controller/physical.c > > > @@ -86,46 +86,6 @@ physical_register_ovs_idl(struct ovsdb_idl *ovs_idl) > > > ovsdb_idl_track_add_column(ovs_idl, > > &ovsrec_interface_col_external_ids); > > > } > > > > > > -static struct simap localvif_to_ofport = > > > - SIMAP_INITIALIZER(&localvif_to_ofport); > > > -static struct hmap tunnels = HMAP_INITIALIZER(&tunnels); > > > - > > > -/* Maps from a chassis to the OpenFlow port number of the tunnel that > > can be > > > - * used to reach that chassis. */ > > > -struct chassis_tunnel { > > > - struct hmap_node hmap_node; > > > - char *chassis_id; > > > - ofp_port_t ofport; > > > - enum chassis_tunnel_type type; > > > -}; > > > - > > > -/* > > > - * This function looks up the list of tunnel ports (provided by > > > - * ovn-chassis-id ports) and returns the tunnel for the given chassid-id > > and > > > - * encap-ip. The ovn-chassis-id is formed using the chassis-id and > > encap-ip. > > > - * The list is hashed using the chassis-id. If the encap-ip is not > > specified, > > > - * it means we'll just return a tunnel for that chassis-id, i.e. we just > > check > > > - * for chassis-id and if there is a match, we'll return the tunnel. > > > - * If encap-ip is also provided we use both chassis-id and encap-ip to do > > > - * a more specific lookup. > > > - */ > > > -static struct chassis_tunnel * > > > -chassis_tunnel_find(const char *chassis_id, char *encap_ip) > > > -{ > > > - /* > > > - * If the specific encap_ip is given, look for the chassisid_ip > > entry, > > > - * else return the 1st found entry for the chassis. > > > - */ > > > - struct chassis_tunnel *tun = NULL; > > > - HMAP_FOR_EACH_WITH_HASH (tun, hmap_node, hash_string(chassis_id, 0), > > > - &tunnels) { > > > - if (encaps_tunnel_id_match(tun->chassis_id, chassis_id, > > encap_ip)) { > > > - return tun; > > > - } > > > - } > > > - return NULL; > > > -} > > > - > > > static void > > > put_load(uint64_t value, enum mf_field_id dst, int ofs, int n_bits, > > > struct ofpbuf *ofpacts) > > > @@ -166,17 +126,18 @@ put_resubmit(uint8_t table_id, struct ofpbuf > > *ofpacts) > > > * from the associated encap. > > > */ > > > static struct chassis_tunnel * > > > -get_port_binding_tun(const struct sbrec_port_binding *binding) > > > +get_port_binding_tun(const struct sbrec_port_binding *binding, > > > + const struct hmap *chassis_tunnels) > > > { > > > struct sbrec_encap *encap = binding->encap; > > > struct sbrec_chassis *chassis = binding->chassis; > > > struct chassis_tunnel *tun = NULL; > > > > > > if (encap) { > > > - tun = chassis_tunnel_find(chassis->name, encap->ip); > > > + tun = chassis_tunnel_find(chassis_tunnels, chassis->name, > > encap->ip); > > > } > > > if (!tun) { > > > - tun = chassis_tunnel_find(chassis->name, NULL); > > > + tun = chassis_tunnel_find(chassis_tunnels, chassis->name, NULL); > > > } > > > return tun; > > > } > > > @@ -325,12 +286,13 @@ put_remote_port_redirect_overlay(const struct > > > uint32_t port_key, > > > struct match *match, > > > struct ofpbuf *ofpacts_p, > > > + const struct hmap *chassis_tunnels, > > > struct ovn_desired_flow_table > > *flow_table) > > > { > > > if (!is_ha_remote) { > > > /* Setup encapsulation */ > > > const struct chassis_tunnel *rem_tun = > > > - get_port_binding_tun(binding); > > > + get_port_binding_tun(binding, chassis_tunnels); > > > if (!rem_tun) { > > > return; > > > } > > > @@ -348,10 +310,10 @@ put_remote_port_redirect_overlay(const struct > > > continue; > > > } > > > if (!tun) { > > > - tun = chassis_tunnel_find(ch->name, NULL); > > > + tun = chassis_tunnel_find(chassis_tunnels, ch->name, > > NULL); > > > } else { > > > struct chassis_tunnel *chassis_tunnel = > > > - chassis_tunnel_find(ch->name, > > NULL); > > > + chassis_tunnel_find(chassis_tunnels, ch->name, NULL); > > > if (chassis_tunnel && > > > tun->type != chassis_tunnel->type) { > > > static struct vlog_rate_limit rl = > > > @@ -385,7 +347,7 @@ put_remote_port_redirect_overlay(const struct > > > if (!ch) { > > > continue; > > > } > > > - tun = chassis_tunnel_find(ch->name, NULL); > > > + tun = chassis_tunnel_find(chassis_tunnels, ch->name, NULL); > > > if (!tun) { > > > continue; > > > } > > > @@ -925,6 +887,9 @@ consider_port_binding(struct ovsdb_idl_index > > *sbrec_port_binding_by_name, > > > const struct simap *ct_zones, > > > const struct sset *active_tunnels, > > > const struct hmap *local_datapaths, > > > + const struct shash *local_bindings, > > > + const struct simap *patch_ofports, > > > + const struct hmap *chassis_tunnels, > > > const struct sbrec_port_binding *binding, > > > const struct sbrec_chassis *chassis, > > > struct ovn_desired_flow_table *flow_table, > > > @@ -1081,17 +1046,25 @@ consider_port_binding(struct ovsdb_idl_index > > *sbrec_port_binding_by_name, > > > if (!binding->tag) { > > > goto out; > > > } > > > - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, > > > - binding->parent_port)); > > > + ofport = local_binding_get_lport_ofport(local_bindings, > > > + binding->parent_port); > > > if (ofport) { > > > tag = *binding->tag; > > > nested_container = true; > > > parent_port = lport_lookup_by_name( > > > sbrec_port_binding_by_name, binding->parent_port); > > > } > > > - } else { > > > - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, > > > + } else if (!strcmp(binding->type, "localnet") > > > + || !strcmp(binding->type, "l2gateway")) { > > > + > > > + ofport = u16_to_ofp(simap_get(patch_ofports, > > > binding->logical_port)); > > > + if (ofport && binding->tag) { > > > + tag = *binding->tag; > > > + } > > > + } else { > > > + ofport = local_binding_get_lport_ofport(local_bindings, > > > + binding->logical_port); > > > const char *requested_chassis = smap_get(&binding->options, > > > "requested-chassis"); > > > if (ofport && requested_chassis && requested_chassis[0] && > > > @@ -1102,12 +1075,6 @@ consider_port_binding(struct ovsdb_idl_index > > *sbrec_port_binding_by_name, > > > */ > > > ofport = 0; > > > } > > > - > > > - if ((!strcmp(binding->type, "localnet") > > > - || !strcmp(binding->type, "l2gateway")) > > > - && ofport && binding->tag) { > > > - tag = *binding->tag; > > > - } > > > } > > > > > > bool is_ha_remote = false; > > > @@ -1118,7 +1085,7 @@ consider_port_binding(struct ovsdb_idl_index > > *sbrec_port_binding_by_name, > > > /* It is remote port, may be reached by tunnel or localnet port > > */ > > > is_remote = true; > > > if (localnet_port) { > > > - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, > > > + ofport = u16_to_ofp(simap_get(patch_ofports, > > > localnet_port->logical_port)); > > > if (!ofport) { > > > goto out; > > > @@ -1129,7 +1096,8 @@ consider_port_binding(struct ovsdb_idl_index > > *sbrec_port_binding_by_name, > > > if (!binding->chassis) { > > > goto out; > > > } > > > - tun = chassis_tunnel_find(binding->chassis->name, NULL); > > > + tun = chassis_tunnel_find(chassis_tunnels, > > > + binding->chassis->name, NULL); > > > if (!tun) { > > > goto out; > > > } > > > @@ -1383,7 +1351,7 @@ consider_port_binding(struct ovsdb_idl_index > > *sbrec_port_binding_by_name, > > > put_remote_port_redirect_overlay(binding, is_ha_remote, > > > ha_ch_ordered, > > mff_ovn_geneve, > > > tun, port_key, &match, > > ofpacts_p, > > > - flow_table); > > > + chassis_tunnels, > > flow_table); > > > } > > > } > > > out: > > > @@ -1396,8 +1364,11 @@ static void > > > consider_mc_group(enum mf_field_id mff_ovn_geneve, > > > const struct simap *ct_zones, > > > const struct hmap *local_datapaths, > > > + struct shash *local_bindings, > > > + struct simap *patch_ofports, > > > const struct sbrec_chassis *chassis, > > > const struct sbrec_multicast_group *mc, > > > + const struct hmap *chassis_tunnels, > > > struct ovn_desired_flow_table *flow_table) > > > { > > > uint32_t dp_key = mc->datapath->tunnel_key; > > > @@ -1444,19 +1415,21 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve, > > > put_load(zone_id, MFF_LOG_CT_ZONE, 0, 32, &ofpacts); > > > } > > > > > > + const char *lport_name = (port->parent_port && > > *port->parent_port) ? > > > + port->parent_port : port->logical_port; > > > + > > > if (!strcmp(port->type, "patch")) { > > > put_load(port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, > > > &remote_ofpacts); > > > put_resubmit(OFTABLE_CHECK_LOOPBACK, &remote_ofpacts); > > > - } else if (simap_contains(&localvif_to_ofport, > > > - (port->parent_port && *port->parent_port) > > > - ? port->parent_port : port->logical_port) > > > + } else if (local_binding_get_primary_pb(local_bindings, > > lport_name) > > > + || simap_contains(patch_ofports, port->logical_port) > > > || (!strcmp(port->type, "l3gateway") > > > && port->chassis == chassis)) { > > > put_load(port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, &ofpacts); > > > put_resubmit(OFTABLE_CHECK_LOOPBACK, &ofpacts); > > > - } else if (port->chassis && !get_localnet_port(local_datapaths, > > > - mc->datapath->tunnel_key)) { > > > + } else if (port->chassis && !get_localnet_port( > > > + local_datapaths, mc->datapath->tunnel_key)) { > > > /* Add remote chassis only when localnet port not exist, > > > * otherwise multicast will reach remote ports through > > localnet > > > * port. */ > > > @@ -1497,7 +1470,7 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve, > > > const struct chassis_tunnel *prev = NULL; > > > SSET_FOR_EACH (chassis_name, &remote_chassis) { > > > const struct chassis_tunnel *tun > > > - = chassis_tunnel_find(chassis_name, NULL); > > > + = chassis_tunnel_find(chassis_tunnels, chassis_name, > > NULL); > > > if (!tun) { > > > continue; > > > } > > > @@ -1524,41 +1497,50 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve, > > > sset_destroy(&remote_chassis); > > > } > > > > > > -/* Replaces 'old' by 'new' (destroying 'new'). Returns true if 'old' > > and 'new' > > > - * contained different data, false if they were the same. */ > > > -static bool > > > -update_ofports(struct simap *old, struct simap *new) > > > -{ > > > - bool changed = !simap_equal(old, new); > > > - simap_swap(old, new); > > > - simap_destroy(new); > > > - return changed; > > > -} > > > - > > > void > > > -physical_handle_port_binding_changes(struct physical_ctx *p_ctx, > > > - struct ovn_desired_flow_table > > *flow_table) > > > +physical_handle_flows_for_lport(const struct sbrec_port_binding *pb, > > > + bool removed, struct physical_ctx *p_ctx, > > > + struct ovn_desired_flow_table > > *flow_table) > > > { > > > - const struct sbrec_port_binding *binding; > > > - struct ofpbuf ofpacts; > > > - ofpbuf_init(&ofpacts, 0); > > > - SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED (binding, > > > - > > p_ctx->port_binding_table) { > > > - if (sbrec_port_binding_is_deleted(binding)) { > > > - ofctrl_remove_flows(flow_table, &binding->header_.uuid); > > > - } else { > > > - if (!sbrec_port_binding_is_new(binding)) { > > > - ofctrl_remove_flows(flow_table, &binding->header_.uuid); > > > - } > > > + ofctrl_remove_flows(flow_table, &pb->header_.uuid); > > > + > > > + if (!strcmp(pb->type, "external")) { > > > + /* External lports have a dependency on the localnet port. > > > + * We need to remove the flows of the localnet port as well > > > + * and re-consider adding the flows for it. > > > + */ > > > + struct local_datapath *ldp = > > > + get_local_datapath(p_ctx->local_datapaths, > > > + pb->datapath->tunnel_key); > > > + if (ldp && ldp->localnet_port) { > > > + struct ofpbuf ofpacts; > > > + ofctrl_remove_flows(flow_table, > > &ldp->localnet_port->header_.uuid); > > > + ofpbuf_init(&ofpacts, 0); > > > consider_port_binding(p_ctx->sbrec_port_binding_by_name, > > > p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > > > p_ctx->active_tunnels, > > > p_ctx->local_datapaths, > > > - binding, p_ctx->chassis, > > > + p_ctx->local_bindings, > > > + &p_ctx->nonvif_data->patch_ofports, > > > + &p_ctx->nonvif_data->chassis_tunnels, > > > + ldp->localnet_port, p_ctx->chassis, > > > flow_table, &ofpacts); > > > + ofpbuf_uninit(&ofpacts); > > > } > > > } > > > - ofpbuf_uninit(&ofpacts); > > > + > > > + if (!removed) { > > > + struct ofpbuf ofpacts; > > > + ofpbuf_init(&ofpacts, 0); > > > + consider_port_binding(p_ctx->sbrec_port_binding_by_name, > > > + p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > > > + p_ctx->active_tunnels, > > p_ctx->local_datapaths, > > > + p_ctx->local_bindings, > > > + &p_ctx->nonvif_data->patch_ofports, > > > + &p_ctx->nonvif_data->chassis_tunnels, pb, > > > + p_ctx->chassis, flow_table, &ofpacts); > > > + ofpbuf_uninit(&ofpacts); > > > + } > > > } > > > > > > void > > > @@ -1574,8 +1556,11 @@ physical_handle_mc_group_changes(struct > > physical_ctx *p_ctx, > > > ofctrl_remove_flows(flow_table, &mc->header_.uuid); > > > } > > > consider_mc_group(p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > > > - p_ctx->local_datapaths, > > > - p_ctx->chassis, mc, flow_table); > > > + p_ctx->local_datapaths, > > p_ctx->local_bindings, > > > + &p_ctx->nonvif_data->patch_ofports, > > > + p_ctx->chassis, mc, > > > + &p_ctx->nonvif_data->chassis_tunnels, > > > + flow_table); > > > } > > > } > > > } > > > @@ -1591,135 +1576,6 @@ physical_run(struct physical_ctx *p_ctx, > > > uuid_generate(hc_uuid); > > > } > > > > > > - /* This bool tracks physical mapping changes. */ > > > - bool physical_map_changed = false; > > > - > > > - struct simap new_localvif_to_ofport = > > > - SIMAP_INITIALIZER(&new_localvif_to_ofport); > > > - struct simap new_tunnel_to_ofport = > > > - SIMAP_INITIALIZER(&new_tunnel_to_ofport); > > > - for (int i = 0; i < p_ctx->br_int->n_ports; i++) { > > > - const struct ovsrec_port *port_rec = p_ctx->br_int->ports[i]; > > > - if (!strcmp(port_rec->name, p_ctx->br_int->name)) { > > > - continue; > > > - } > > > - > > > - const char *tunnel_id = smap_get(&port_rec->external_ids, > > > - "ovn-chassis-id"); > > > - if (tunnel_id && encaps_tunnel_id_match(tunnel_id, > > > - p_ctx->chassis->name, > > > - NULL)) { > > > - continue; > > > - } > > > - > > > - const char *localnet = smap_get(&port_rec->external_ids, > > > - "ovn-localnet-port"); > > > - const char *l2gateway = smap_get(&port_rec->external_ids, > > > - "ovn-l2gateway-port"); > > > - > > > - for (int j = 0; j < port_rec->n_interfaces; j++) { > > > - const struct ovsrec_interface *iface_rec = > > port_rec->interfaces[j]; > > > - > > > - /* Get OpenFlow port number. */ > > > - if (!iface_rec->n_ofport) { > > > - continue; > > > - } > > > - int64_t ofport = iface_rec->ofport[0]; > > > - if (ofport < 1 || ofport > ofp_to_u16(OFPP_MAX)) { > > > - continue; > > > - } > > > - > > > - /* Record as patch to local net, logical patch port, > > chassis, or > > > - * local logical port. */ > > > - bool is_patch = !strcmp(iface_rec->type, "patch"); > > > - if (is_patch && localnet) { > > > - /* localnet patch ports can be handled just like VIFs. */ > > > - simap_put(&new_localvif_to_ofport, localnet, ofport); > > > - break; > > > - } else if (is_patch && l2gateway) { > > > - /* L2 gateway patch ports can be handled just like VIFs. > > */ > > > - simap_put(&new_localvif_to_ofport, l2gateway, ofport); > > > - break; > > > - } else if (tunnel_id) { > > > - enum chassis_tunnel_type tunnel_type; > > > - if (!strcmp(iface_rec->type, "geneve")) { > > > - tunnel_type = GENEVE; > > > - if (!p_ctx->mff_ovn_geneve) { > > > - continue; > > > - } > > > - } else if (!strcmp(iface_rec->type, "stt")) { > > > - tunnel_type = STT; > > > - } else if (!strcmp(iface_rec->type, "vxlan")) { > > > - tunnel_type = VXLAN; > > > - } else { > > > - continue; > > > - } > > > - > > > - simap_put(&new_tunnel_to_ofport, tunnel_id, ofport); > > > - /* > > > - * We split the tunnel_id to get the chassis-id > > > - * and hash the tunnel list on the chassis-id. The > > > - * reason to use the chassis-id alone is because > > > - * there might be cases (multicast, gateway chassis) > > > - * where we need to tunnel to the chassis, but won't > > > - * have the encap-ip specifically. > > > - */ > > > - char *hash_id = NULL; > > > - char *ip = NULL; > > > - > > > - if (!encaps_tunnel_id_parse(tunnel_id, &hash_id, &ip)) { > > > - continue; > > > - } > > > - struct chassis_tunnel *tun = > > chassis_tunnel_find(hash_id, ip); > > > - if (tun) { > > > - /* If the tunnel's ofport has changed, update. */ > > > - if (tun->ofport != u16_to_ofp(ofport) || > > > - tun->type != tunnel_type) { > > > - tun->ofport = u16_to_ofp(ofport); > > > - tun->type = tunnel_type; > > > - physical_map_changed = true; > > > - } > > > - } else { > > > - tun = xmalloc(sizeof *tun); > > > - hmap_insert(&tunnels, &tun->hmap_node, > > > - hash_string(hash_id, 0)); > > > - tun->chassis_id = xstrdup(tunnel_id); > > > - tun->ofport = u16_to_ofp(ofport); > > > - tun->type = tunnel_type; > > > - physical_map_changed = true; > > > - } > > > - free(hash_id); > > > - free(ip); > > > - break; > > > - } else { > > > - const char *iface_id = smap_get(&iface_rec->external_ids, > > > - "iface-id"); > > > - if (iface_id) { > > > - simap_put(&new_localvif_to_ofport, iface_id, ofport); > > > - } > > > - } > > > - } > > > - } > > > - > > > - /* Remove tunnels that are no longer here. */ > > > - struct chassis_tunnel *tun, *tun_next; > > > - HMAP_FOR_EACH_SAFE (tun, tun_next, hmap_node, &tunnels) { > > > - if (!simap_find(&new_tunnel_to_ofport, tun->chassis_id)) { > > > - hmap_remove(&tunnels, &tun->hmap_node); > > > - physical_map_changed = true; > > > - free(tun->chassis_id); > > > - free(tun); > > > - } > > > - } > > > - > > > - /* Capture changed or removed openflow ports. */ > > > - physical_map_changed |= update_ofports(&localvif_to_ofport, > > > - &new_localvif_to_ofport); > > > - if (physical_map_changed) { > > > - /* Reprocess logical flow table immediately. */ > > > - poll_immediate_wake(); > > > - } > > > - > > > struct ofpbuf ofpacts; > > > ofpbuf_init(&ofpacts, 0); > > > > > > @@ -1733,16 +1589,20 @@ physical_run(struct physical_ctx *p_ctx, > > > consider_port_binding(p_ctx->sbrec_port_binding_by_name, > > > p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > > > p_ctx->active_tunnels, > > p_ctx->local_datapaths, > > > - binding, p_ctx->chassis, > > > - flow_table, &ofpacts); > > > + p_ctx->local_bindings, > > > + &p_ctx->nonvif_data->patch_ofports, > > > + &p_ctx->nonvif_data->chassis_tunnels, > > binding, > > > + p_ctx->chassis, flow_table, &ofpacts); > > > } > > > > > > /* Handle output to multicast groups, in tables 32 and 33. */ > > > const struct sbrec_multicast_group *mc; > > > SBREC_MULTICAST_GROUP_TABLE_FOR_EACH (mc, p_ctx->mc_group_table) { > > > consider_mc_group(p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > > > - p_ctx->local_datapaths, p_ctx->chassis, > > > - mc, flow_table); > > > + p_ctx->local_datapaths, p_ctx->local_bindings, > > > + &p_ctx->nonvif_data->patch_ofports, > > p_ctx->chassis, > > > + mc, &p_ctx->nonvif_data->chassis_tunnels, > > > + flow_table); > > > } > > > > > > /* Table 0, priority 100. > > > @@ -1757,7 +1617,8 @@ physical_run(struct physical_ctx *p_ctx, > > > * We set MFF_LOG_DATAPATH, MFF_LOG_INPORT, and MFF_LOG_OUTPORT from > > the > > > * tunnel key data where possible, then resubmit to table 33 to > > handle > > > * packets to the local hypervisor. */ > > > - HMAP_FOR_EACH (tun, hmap_node, &tunnels) { > > > + struct chassis_tunnel *tun; > > > + HMAP_FOR_EACH (tun, hmap_node, &p_ctx->nonvif_data->chassis_tunnels) > > { > > > struct match match = MATCH_CATCHALL_INITIALIZER; > > > match_set_in_port(&match, tun->ofport); > > > > > > @@ -1788,7 +1649,7 @@ physical_run(struct physical_ctx *p_ctx, > > > } > > > > > > /* Handle ramp switch encapsulations. */ > > > - HMAP_FOR_EACH (tun, hmap_node, &tunnels) { > > > + HMAP_FOR_EACH (tun, hmap_node, &p_ctx->nonvif_data->chassis_tunnels) > > { > > > if (tun->type != VXLAN) { > > > continue; > > > } > > > @@ -1925,13 +1786,10 @@ physical_run(struct physical_ctx *p_ctx, > > > &ofpacts, hc_uuid); > > > > > > ofpbuf_uninit(&ofpacts); > > > - > > > - simap_destroy(&new_tunnel_to_ofport); > > > } > > > > > > bool > > > -physical_handle_ovs_iface_changes(struct physical_ctx *p_ctx, > > > - struct ovn_desired_flow_table > > *flow_table) > > > +physical_handle_ovs_iface_changes(struct physical_ctx *p_ctx) > > > { > > > const struct ovsrec_interface *iface_rec; > > > OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, > > p_ctx->iface_table) { > > > @@ -1943,64 +1801,6 @@ physical_handle_ovs_iface_changes(struct > > physical_ctx *p_ctx, > > > } > > > } > > > > > > - struct ofpbuf ofpacts; > > > - ofpbuf_init(&ofpacts, 0); > > > - > > > - OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, > > p_ctx->iface_table) { > > > - const char *iface_id = smap_get(&iface_rec->external_ids, > > "iface-id"); > > > - if (!iface_id) { > > > - continue; > > > - } > > > - > > > - const struct sbrec_port_binding *lb_pb = > > > - local_binding_get_primary_pb(p_ctx->local_bindings, > > iface_id); > > > - if (!lb_pb) { > > > - /* For regular VIFs (e.g. lsp) the upcoming port-binding > > update > > > - * will remove lfows related to the unclaimed ovs port. > > > - * Localport is a special case and it needs to be managed > > here > > > - * since the port is not binded and otherwise the related > > lfows > > > - * will not be cleared removing the ovs port. > > > - */ > > > - lb_pb = > > lport_lookup_by_name(p_ctx->sbrec_port_binding_by_name, > > > - iface_id); > > > - if (!lb_pb || strcmp(lb_pb->type, "localport")) { > > > - continue; > > > - } > > > - } > > > - > > > - int64_t ofport = iface_rec->n_ofport ? *iface_rec->ofport : 0; > > > - if (ovsrec_interface_is_deleted(iface_rec)) { > > > - ofctrl_remove_flows(flow_table, &lb_pb->header_.uuid); > > > - simap_find_and_delete(&localvif_to_ofport, iface_id); > > > - } else { > > > - if (!ovsrec_interface_is_new(iface_rec)) { > > > - ofctrl_remove_flows(flow_table, &lb_pb->header_.uuid); > > > - } > > > - > > > - simap_put(&localvif_to_ofport, iface_id, ofport); > > > - consider_port_binding(p_ctx->sbrec_port_binding_by_name, > > > - p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > > > - p_ctx->active_tunnels, > > > - p_ctx->local_datapaths, > > > - lb_pb, p_ctx->chassis, > > > - flow_table, &ofpacts); > > > - } > > > - } > > > - > > > - ofpbuf_uninit(&ofpacts); > > > - return true; > > > -} > > > - > > > -bool > > > -get_tunnel_ofport(const char *chassis_name, char *encap_ip, ofp_port_t > > *ofport) > > > -{ > > > - struct chassis_tunnel *tun = NULL; > > > - tun = chassis_tunnel_find(chassis_name, encap_ip); > > > - if (!tun) { > > > - return false; > > > - } > > > - > > > - *ofport = tun->ofport; > > > return true; > > > } > > > > > > diff --git a/controller/physical.h b/controller/physical.h > > > index feab41df4..3fdc20005 100644 > > > --- a/controller/physical.h > > > +++ b/controller/physical.h > > > @@ -34,6 +34,7 @@ struct simap; > > > struct sbrec_multicast_group_table; > > > struct sbrec_port_binding_table; > > > struct sset; > > > +struct local_nonvif_data; > > > > > > /* OVN Geneve option information. > > > * > > > @@ -56,18 +57,18 @@ struct physical_ctx { > > > const struct simap *ct_zones; > > > enum mf_field_id mff_ovn_geneve; > > > struct shash *local_bindings; > > > + struct local_nonvif_data *nonvif_data; > > > }; > > > > > > void physical_register_ovs_idl(struct ovsdb_idl *); > > > void physical_run(struct physical_ctx *, > > > struct ovn_desired_flow_table *); > > > void physical_clear_unassoc_flows_with_db(struct ovn_desired_flow_table > > *); > > > -void physical_handle_port_binding_changes(struct physical_ctx *, > > > - struct ovn_desired_flow_table > > *); > > > void physical_handle_mc_group_changes(struct physical_ctx *, > > > struct ovn_desired_flow_table *); > > > -bool physical_handle_ovs_iface_changes(struct physical_ctx *, > > > - struct ovn_desired_flow_table *); > > > -bool get_tunnel_ofport(const char *chassis_name, char *encap_ip, > > > - ofp_port_t *ofport); > > > +bool physical_handle_ovs_iface_changes(struct physical_ctx *); > > > +void physical_handle_flows_for_lport(const struct sbrec_port_binding *, > > > + bool removed, > > > + struct physical_ctx *, > > > + struct ovn_desired_flow_table *); > > > #endif /* controller/physical.h */ > > > -- > > > 2.31.1 > > > > > > _______________________________________________ > > > dev mailing list > > > dev@openvswitch.org > > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > _______________________________________________ > > dev mailing list > > dev@openvswitch.org > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > >
On Tue, Jul 27, 2021 at 4:00 PM Han Zhou <hzhou@ovn.org> wrote: > > On Tue, Jul 27, 2021 at 11:43 AM Numan Siddique <numans@ovn.org> wrote: > > > > On Tue, Jul 27, 2021 at 3:36 AM Han Zhou <hzhou@ovn.org> wrote: > > > > > > Thanks Numan. The commit title has a typo: s/plow/pflow. > > > > > > On Fri, Jul 16, 2021 at 4:55 AM <numans@ovn.org> wrote: > > > > > > > > From: Numan Siddique <numans@ovn.org> > > > > > > > > physical_run() maintains a local copy of local vif to ofports > > > > in a simap along with the chassis tunnel information. This patch > > > > removes this from the physical module and now stores it in the > > > > runtime_data engine node. This makes it easier to handle runtime > > > > data changes in pflow_output engine. > > > > > > > > The newly added handler pflow_output_runtime_data_handler() returns > > > > false if a datapath is added or removed from the local_datapaths > > > > and handles the logical port claims and releases incrementally. > > > > > > > > Signed-off-by: Numan Siddique <numans@ovn.org> > > > > --- > > > > controller/binding.c | 39 ++-- > > > > controller/binding.h | 23 +++ > > > > controller/ldata.c | 169 ++++++++++++++++ > > > > controller/ldata.h | 44 +++++ > > > > controller/lflow.c | 5 +- > > > > controller/lflow.h | 1 + > > > > controller/ovn-controller.c | 68 ++++++- > > > > controller/ovn-controller.h | 8 - > > > > controller/physical.c | 382 > +++++++++--------------------------- > > > > controller/physical.h | 13 +- > > > > 10 files changed, 422 insertions(+), 330 deletions(-) > > > > > > > > diff --git a/controller/binding.c b/controller/binding.c > > > > index 0fd951ad7..b50139726 100644 > > > > --- a/controller/binding.c > > > > +++ b/controller/binding.c > > > > @@ -546,23 +546,6 @@ update_active_pb_ras_pd(const struct > > > sbrec_port_binding *pb, > > > > } > > > > } > > > > > > > > -/* Corresponds to each Port_Binding.type. */ > > > > -enum en_lport_type { > > > > - LP_UNKNOWN, > > > > - LP_VIF, > > > > - LP_CONTAINER, > > > > - LP_PATCH, > > > > - LP_L3GATEWAY, > > > > - LP_LOCALNET, > > > > - LP_LOCALPORT, > > > > - LP_L2GATEWAY, > > > > - LP_VTEP, > > > > - LP_CHASSISREDIRECT, > > > > - LP_VIRTUAL, > > > > - LP_EXTERNAL, > > > > - LP_REMOTE > > > > -}; > > > > - > > > > /* Local bindings. binding.c module binds the logical port > (represented > > > by > > > > * Port_Binding rows) and sets the 'chassis' column when it sees the > > > > * OVS interface row (of type "" or "internal") with the > > > > @@ -616,7 +599,7 @@ static struct local_binding *local_binding_create( > > > > static void local_binding_add(struct shash *local_bindings, > > > > struct local_binding *); > > > > static struct local_binding *local_binding_find( > > > > - struct shash *local_bindings, const char *name); > > > > + const struct shash *local_bindings, const char *name); > > > > static void local_binding_destroy(struct local_binding *, > > > > struct shash *binding_lports); > > > > static void local_binding_delete(struct local_binding *, > > > > @@ -701,7 +684,8 @@ local_binding_data_destroy(struct > local_binding_data > > > *lbinding_data) > > > > } > > > > > > > > const struct sbrec_port_binding * > > > > -local_binding_get_primary_pb(struct shash *local_bindings, const char > > > *pb_name) > > > > +local_binding_get_primary_pb(struct shash *local_bindings, > > > > + const char *pb_name) > > > > { > > > > struct local_binding *lbinding = > > > > local_binding_find(local_bindings, pb_name); > > > > @@ -710,6 +694,19 @@ local_binding_get_primary_pb(struct shash > > > *local_bindings, const char *pb_name) > > > > return b_lport ? b_lport->pb : NULL; > > > > } > > > > > > > > +ofp_port_t > > > > +local_binding_get_lport_ofport(const struct shash *local_bindings, > > > > + const char *pb_name) > > > > +{ > > > > + struct local_binding *lbinding = > > > > + local_binding_find(local_bindings, pb_name); > > > > + struct binding_lport *b_lport = > > > > + local_binding_get_primary_or_localport_lport(lbinding); > > > > + > > > > + return (b_lport && lbinding->iface && lbinding->iface->n_ofport) > ? > > > > + u16_to_ofp(lbinding->iface->ofport[0]) : 0; > > > > +} > > > > + > > > > bool > > > > local_binding_is_up(struct shash *local_bindings, const char > *pb_name) > > > > { > > > > @@ -871,7 +868,7 @@ is_lport_vif(const struct sbrec_port_binding *pb) > > > > return !pb->type[0]; > > > > } > > > > > > > > -static enum en_lport_type > > > > +enum en_lport_type > > > > get_lport_type(const struct sbrec_port_binding *pb) > > > > { > > > > if (is_lport_vif(pb)) { > > > > @@ -2555,7 +2552,7 @@ local_binding_create(const char *name, const > struct > > > ovsrec_interface *iface) > > > > } > > > > > > > > static struct local_binding * > > > > -local_binding_find(struct shash *local_bindings, const char *name) > > > > +local_binding_find(const struct shash *local_bindings, const char > *name) > > > > { > > > > return shash_find_data(local_bindings, name); > > > > } > > > > diff --git a/controller/binding.h b/controller/binding.h > > > > index b1717bd2b..f1abc4b9c 100644 > > > > --- a/controller/binding.h > > > > +++ b/controller/binding.h > > > > @@ -114,6 +114,9 @@ void local_binding_data_destroy(struct > > > local_binding_data *); > > > > > > > > const struct sbrec_port_binding *local_binding_get_primary_pb( > > > > struct shash *local_bindings, const char *pb_name); > > > > +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_down(struct shash *local_bindings, const char > > > *pb_name); > > > > void local_binding_set_up(struct shash *local_bindings, const char > > > *pb_name, > > > > @@ -134,4 +137,24 @@ bool binding_handle_port_binding_changes(struct > > > binding_ctx_in *, > > > > void binding_tracked_dp_destroy(struct hmap *tracked_datapaths); > > > > > > > > void binding_dump_local_bindings(struct local_binding_data *, struct > ds > > > *); > > > > + > > > > +/* Corresponds to each Port_Binding.type. */ > > > > +enum en_lport_type { > > > > + LP_UNKNOWN, > > > > + LP_VIF, > > > > + LP_CONTAINER, > > > > + LP_PATCH, > > > > + LP_L3GATEWAY, > > > > + LP_LOCALNET, > > > > + LP_LOCALPORT, > > > > + LP_L2GATEWAY, > > > > + LP_VTEP, > > > > + LP_CHASSISREDIRECT, > > > > + LP_VIRTUAL, > > > > + LP_EXTERNAL, > > > > + LP_REMOTE > > > > +}; > > > > + > > > > +enum en_lport_type get_lport_type(const struct sbrec_port_binding *); > > > > + > > > > #endif /* controller/binding.h */ > > > > diff --git a/controller/ldata.c b/controller/ldata.c > > > > index a6df9b1da..f55905551 100644 > > > > --- a/controller/ldata.c > > > > +++ b/controller/ldata.c > > > > @@ -18,10 +18,13 @@ > > > > /* OVS includes. */ > > > > #include "include/openvswitch/json.h" > > > > #include "lib/hmapx.h" > > > > +#include "lib/flow.h" > > > > #include "lib/util.h" > > > > +#include "lib/vswitch-idl.h" > > > > #include "openvswitch/vlog.h" > > > > > > > > /* OVN includes. */ > > > > +#include "encaps.h" > > > > #include "ldata.h" > > > > #include "lport.h" > > > > #include "lib/ovn-util.h" > > > > @@ -275,6 +278,172 @@ tracked_datapaths_destroy(struct hmap > > > *tracked_datapaths) > > > > hmap_destroy(tracked_datapaths); > > > > } > > > > > > > > +/* Iterates the br_int ports and build the simap of patch to ofports > > > > + * and chassis tunnels. */ > > > > +void > > > > +ldata_run(const struct ovsrec_bridge *br_int, > > > > + const struct sbrec_chassis *chassis_rec, > > > > + struct local_nonvif_data *nonvif_data) > > > > +{ > > > > + for (int i = 0; i < br_int->n_ports; i++) { > > > > + const struct ovsrec_port *port_rec = br_int->ports[i]; > > > > + if (!strcmp(port_rec->name, br_int->name)) { > > > > + continue; > > > > + } > > > > + > > > > + const char *tunnel_id = smap_get(&port_rec->external_ids, > > > > + "ovn-chassis-id"); > > > > + if (tunnel_id && encaps_tunnel_id_match(tunnel_id, > > > > + chassis_rec->name, > > > > + NULL)) { > > > > + continue; > > > > + } > > > > + > > > > + const char *localnet = smap_get(&port_rec->external_ids, > > > > + "ovn-localnet-port"); > > > > + const char *l2gateway = smap_get(&port_rec->external_ids, > > > > + "ovn-l2gateway-port"); > > > > + > > > > + for (int j = 0; j < port_rec->n_interfaces; j++) { > > > > + const struct ovsrec_interface *iface_rec = > > > port_rec->interfaces[j]; > > > > + > > > > + /* Get OpenFlow port number. */ > > > > + if (!iface_rec->n_ofport) { > > > > + continue; > > > > + } > > > > + int64_t ofport = iface_rec->ofport[0]; > > > > + if (ofport < 1 || ofport > ofp_to_u16(OFPP_MAX)) { > > > > + continue; > > > > + } > > > > + > > > > + bool is_patch = !strcmp(iface_rec->type, "patch"); > > > > + if (is_patch && localnet) { > > > > + simap_put(&nonvif_data->patch_ofports, localnet, > ofport); > > > > + break; > > > > + } else if (is_patch && l2gateway) { > > > > + /* L2 gateway patch ports can be handled just like > VIFs. > > > */ > > > > + simap_put(&nonvif_data->patch_ofports, l2gateway, > > > ofport); > > > > + break; > > > > + } else if (tunnel_id) { > > > > + enum chassis_tunnel_type tunnel_type; > > > > + if (!strcmp(iface_rec->type, "geneve")) { > > > > + tunnel_type = GENEVE; > > > > + } else if (!strcmp(iface_rec->type, "stt")) { > > > > + tunnel_type = STT; > > > > + } else if (!strcmp(iface_rec->type, "vxlan")) { > > > > + tunnel_type = VXLAN; > > > > + } else { > > > > + continue; > > > > + } > > > > + > > > > + /* We split the tunnel_id to get the chassis-id > > > > + * and hash the tunnel list on the chassis-id. The > > > > + * reason to use the chassis-id alone is because > > > > + * there might be cases (multicast, gateway chassis) > > > > + * where we need to tunnel to the chassis, but won't > > > > + * have the encap-ip specifically. > > > > + */ > > > > + char *hash_id = NULL; > > > > + char *ip = NULL; > > > > + > > > > + if (!encaps_tunnel_id_parse(tunnel_id, &hash_id, > &ip)) { > > > > + continue; > > > > + } > > > > + struct chassis_tunnel *tun = xmalloc(sizeof *tun); > > > > + hmap_insert(&nonvif_data->chassis_tunnels, > > > &tun->hmap_node, > > > > + hash_string(hash_id, 0)); > > > > + tun->chassis_id = xstrdup(tunnel_id); > > > > + tun->ofport = u16_to_ofp(ofport); > > > > + tun->type = tunnel_type; > > > > + > > > > + free(hash_id); > > > > + free(ip); > > > > + break; > > > > + } > > > > + } > > > > + } > > > > +} > > > > + > > > > +bool > > > > +ldata_handle_ovs_iface_changes( > > > > + const struct ovsrec_interface_table *iface_table) > > > > +{ > > > > + const struct ovsrec_interface *iface_rec; > > > > + OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, iface_table) > { > > > > + if (!strcmp(iface_rec->type, "geneve") || > > > > + !strcmp(iface_rec->type, "patch") || > > > > + !strcmp(iface_rec->type, "vxlan") || > > > > + !strcmp(iface_rec->type, "stt")) { > > > > + return false; > > > > + } > > > > + } > > > > + > > > > + return true; > > > > +} > > > > + > > > > +bool > > > > +get_chassis_tunnel_ofport(const struct hmap *chassis_tunnels, > > > > + const char *chassis_name, char *encap_ip, > > > > + ofp_port_t *ofport) > > > > +{ > > > > + struct chassis_tunnel *tun = NULL; > > > > + tun = chassis_tunnel_find(chassis_tunnels, chassis_name, > encap_ip); > > > > + if (!tun) { > > > > + return false; > > > > + } > > > > + > > > > + *ofport = tun->ofport; > > > > + return true; > > > > +} > > > > + > > > > +void > > > > +local_nonvif_data_init(struct local_nonvif_data *nonvif_data) > > > > +{ > > > > + simap_init(&nonvif_data->patch_ofports); > > > > + hmap_init(&nonvif_data->chassis_tunnels); > > > > +} > > > > + > > > > +void > > > > +local_nonvif_data_destroy(struct local_nonvif_data *nonvif_data) > > > > +{ > > > > + simap_destroy(&nonvif_data->patch_ofports); > > > > + struct chassis_tunnel *tun; > > > > + HMAP_FOR_EACH_POP (tun, hmap_node, > &nonvif_data->chassis_tunnels) { > > > > + free(tun->chassis_id); > > > > + free(tun); > > > > + } > > > > + hmap_destroy(&nonvif_data->chassis_tunnels); > > > > +} > > > > + > > > > + > > > > +/* > > > > + * This function looks up the list of tunnel ports (provided by > > > > + * ovn-chassis-id ports) and returns the tunnel for the given > chassid-id > > > and > > > > + * encap-ip. The ovn-chassis-id is formed using the chassis-id and > > > encap-ip. > > > > + * The list is hashed using the chassis-id. If the encap-ip is not > > > specified, > > > > + * it means we'll just return a tunnel for that chassis-id, i.e. we > just > > > check > > > > + * for chassis-id and if there is a match, we'll return the tunnel. > > > > + * If encap-ip is also provided we use both chassis-id and encap-ip > to do > > > > + * a more specific lookup. > > > > + */ > > > > +struct chassis_tunnel * > > > > +chassis_tunnel_find(const struct hmap *chassis_tunnels, const char > > > *chassis_id, > > > > + char *encap_ip) > > > > +{ > > > > + /* > > > > + * If the specific encap_ip is given, look for the chassisid_ip > > > entry, > > > > + * else return the 1st found entry for the chassis. > > > > + */ > > > > + struct chassis_tunnel *tun = NULL; > > > > + HMAP_FOR_EACH_WITH_HASH (tun, hmap_node, hash_string(chassis_id, > 0), > > > > + chassis_tunnels) { > > > > + if (encaps_tunnel_id_match(tun->chassis_id, chassis_id, > > > encap_ip)) { > > > > + return tun; > > > > + } > > > > + } > > > > + return NULL; > > > > +} > > > > + > > > > /* static functions. */ > > > > static struct local_datapath * > > > > local_datapath_add__(struct hmap *local_datapaths, > > > > diff --git a/controller/ldata.h b/controller/ldata.h > > > > index 16ad43c8f..91624d0b4 100644 > > > > --- a/controller/ldata.h > > > > +++ b/controller/ldata.h > > > > @@ -19,10 +19,14 @@ > > > > /* OVS includes. */ > > > > #include "include/openvswitch/shash.h" > > > > #include "lib/smap.h" > > > > +#include "lib/simap.h" > > > > > > > > struct sbrec_datapath_binding; > > > > struct sbrec_port_binding; > > > > +struct sbrec_chassis; > > > > struct ovsdb_idl_index; > > > > +struct ovsrec_bridge; > > > > +struct ovsrec_interface_table; > > > > > > > > /* A logical datapath that has some relevance to this hypervisor. A > > > logical > > > > * datapath D is relevant to hypervisor H if: > > > > @@ -117,4 +121,44 @@ void tracked_datapath_lport_add(const struct > > > sbrec_port_binding *, > > > > struct hmap *tracked_datapaths); > > > > void tracked_datapaths_destroy(struct hmap *tracked_datapaths); > > > > > > > > +/* Must be a bit-field ordered from most-preferred (higher number) to > > > > + * least-preferred (lower number). */ > > > > +enum chassis_tunnel_type { > > > > + GENEVE = 1 << 2, > > > > + STT = 1 << 1, > > > > + VXLAN = 1 << 0 > > > > +}; > > > > + > > > > +/* Maps from a chassis to the OpenFlow port number of the tunnel that > > > can be > > > > + * used to reach that chassis. */ > > > > +struct chassis_tunnel { > > > > + struct hmap_node hmap_node; > > > > + char *chassis_id; > > > > + ofp_port_t ofport; > > > > + enum chassis_tunnel_type type; > > > > +}; > > > > + > > > > +struct local_nonvif_data { > > > > + struct simap patch_ofports; /* simap of patch ovs ports. */ > > > > + struct hmap chassis_tunnels; /* hmap of 'struct chassis_tunnel' > from > > > the > > > > + * tunnel OVS ports. */ > > > > +}; > > > > + > > > > +void ldata_run(const struct ovsrec_bridge *br_int, > > > > + const struct sbrec_chassis *, > > > > + struct local_nonvif_data *nonvif_data); > > > > + > > > > +bool ldata_handle_ovs_iface_changes(const struct > ovsrec_interface_table > > > *); > > > > + > > > > +struct chassis_tunnel *chassis_tunnel_find(const struct hmap > > > *chassis_tunnels, > > > > + const char *chassis_id, > > > > + char *encap_ip); > > > > + > > > > +bool get_chassis_tunnel_ofport(const struct hmap *chassis_tunnels, > > > > + const char *chassis_name, char > *encap_ip, > > > > + ofp_port_t *ofport); > > > > + > > > > +void local_nonvif_data_init(struct local_nonvif_data *nonvif_data); > > > > +void local_nonvif_data_destroy(struct local_nonvif_data > *nonvif_data); > > > > + > > > > #endif /* controller/ldata.h */ > > > > diff --git a/controller/lflow.c b/controller/lflow.c > > > > index d1f32077b..4ac671e40 100644 > > > > --- a/controller/lflow.c > > > > +++ b/controller/lflow.c > > > > @@ -58,6 +58,7 @@ struct lookup_port_aux { > > > > const struct sbrec_datapath_binding *dp; > > > > const struct sbrec_logical_flow *lflow; > > > > struct lflow_resource_ref *lfrr; > > > > + const struct hmap *chassis_tunnels; > > > > }; > > > > > > > > struct condition_aux { > > > > @@ -145,7 +146,8 @@ tunnel_ofport_cb(const void *aux_, const char > > > *port_name, ofp_port_t *ofport) > > > > return false; > > > > } > > > > > > > > - if (!get_tunnel_ofport(pb->chassis->name, NULL, ofport)) { > > > > + if (!get_chassis_tunnel_ofport(aux->chassis_tunnels, > > > pb->chassis->name, > > > > + NULL, ofport)) { > > > > return false; > > > > } > > > > > > > > @@ -591,6 +593,7 @@ add_matches_to_flow_table(const struct > > > sbrec_logical_flow *lflow, > > > > .dp = dp, > > > > .lflow = lflow, > > > > .lfrr = l_ctx_out->lfrr, > > > > + .chassis_tunnels = l_ctx_in->chassis_tunnels, > > > > }; > > > > > > > > /* Encode OVN logical actions into OpenFlow. */ > > > > diff --git a/controller/lflow.h b/controller/lflow.h > > > > index c17ff6dd4..e7dd31289 100644 > > > > --- a/controller/lflow.h > > > > +++ b/controller/lflow.h > > > > @@ -146,6 +146,7 @@ struct lflow_ctx_in { > > > > const struct shash *port_groups; > > > > const struct sset *active_tunnels; > > > > const struct sset *related_lport_ids; > > > > + const struct hmap *chassis_tunnels; > > > > }; > > > > > > > > struct lflow_ctx_out { > > > > diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c > > > > index 8f620e4ad..69d135046 100644 > > > > --- a/controller/ovn-controller.c > > > > +++ b/controller/ovn-controller.c > > > > @@ -1039,6 +1039,11 @@ struct ed_type_runtime_data { > > > > struct related_lports related_lports; > > > > struct sset active_tunnels; > > > > > > > > + /* Non VIF OVS interface information (mainly patch OVS interfacs > > > > + * and tunnel interfaces) that are relevant to the local > > > > + * chassis (generated by ldata_run()). */ > > > > + struct local_nonvif_data nonvif_data; > > > > + > > > I don't see a benefit of adding this to runtime_data. It is unrelated to > > > the other data in the current runtime_data node. Now if we combine it to > > > runtime_data, it means we are coupling those data unnecessarily, which > > > leads to unflexible handler implementation. An example is that now > > > recompute of nonvif_data would trigger recompute of runtime_data, which > > > would trigger recompute of lflow_output. In fact, this can be just in a > > > separate engine node, only as input to pflow_output. Would that be more > > > straightforward and efficient? > > > > Hi Han, > > > > Thanks for the review comments. > > > > I see your point. I'll explore if we can add a new engine node for this. > > > > My understanding of engine processing is this and runtime data engine > > in particular is this: > > > > 1. The first level of engine nodes would handle the db changes and > > generates/transforms the data > > which we can probably call - runtime_data. This was the > > motivation for me to add the nonvif_data > > in the runtime data engine. Perhaps we need to further divide > > the runtime_data engine or rename it > > so that we only store the VIF related data in this. > > Hi Numan, it seems we had different models for I-P engine nodes in our > minds. Sorry that I didn't document these thoughts initially for the I-P > engine. I don't think we should restrict the engine nodes in such layers. > It should be flexible enough based on the real computation dependencies - > just thinking about how DDlog programs would be written. I am not against > the idea of a separate encapsulation layer for OVSDB IDL, but runtime_data > was not for that purpose. Initially the I-P engine was very coarse grained, > so I just created a big "runtime_data" node trying to contain all the > intermediate data, just enough to support the first version of I-P for the > most frequent changes. Now that we are making the I-P engine more and more > fine-grained, we definitely cannot simply put everything in a single node. > The current runtime_data may be renamed to binding_data, or be further > split if necessary, and we don't need to put more data into it unless it is > tightly related to the bindings handling. Thanks for the explanation. I'd agree renaming the current runtime_data to binding_data. Probably a patch later for that. Since we are discussing I-P, I'd like to bring up another case. Presently we abort the engine if a recompute needs to be done but recompute is not allowed due to an sb txn is in progress or due to ofctrl_can_put() returns false. We have engine nodes like ct_zone which does not have handlers for many inputs and it has to recompute. And suppose if engine aborts due to the reason I mentioned, then in the next engine run, we do a full recomputation of all engine nodes whereas only recompute of ct_zones (and perhaps pflow_output) was required. In our scale testing we noticed that this recomputation of all the engine nodes is costing a bit. I think we should address this. And probably we can separate out db transactions from the engine and can be done separately. The binding module will not set sbrec_port_binding_set_chassis() for example. Any thoughts on this ? Thanks Numan > > > 2. And the flow output engines ideally would use the runtime data for > > flow generation. > > The output nodes should only depend on whatever data that is necessary for > flow computation. What you said is true if "runtime data" here contains > everything that is needed for flow computation, but it should never be a > goal to keep all these data in a single I-P engine node, because that would > not really benefit from the I-P engine. > > > 3. Ideally I'd think (or prefer) to engine nodes one or two level > > down to not access any db changes at all. > > For example, lfow_output or pflow_output engine handles should > > not call IDL TRACKED loops. > > > > Maybe we could try to achieve follow up patches if that makes sense. > > > Encapsulating IDL to a separate layer may be reasonable, if it provides > values, but I think it is another topic. I don't think it changes the I-P > model. > > Thanks, > Han > > > > > > > > > > > > As to the code organization, I think now I understand why you added the > new > > > module ldata.c (suppose it is going to be renamed to local_data.c to be > > > more clear). Although it is not harmful to have that new module, it > seems > > > not quite necessary to me, either. The original localvif_to_ofport data > is > > > now split into two parts, VIF related and nonVIF related. I don't see > > > benefit of keeping these two parts in the same file. It is reasonable to > > > combine the VIF related data in runtime_data (which could be renamed, > > > because the name was vague), to avoid maintaining redundant data. I > think > > > it is ok to stay in binding.c. For the nonVIF part, I think the new > engine > > > node can be defined in ovn-controller.c and implemented in physical.c > > > because that data is used by physical flow processing only. I don't > have a > > > strong argument for this - maybe just less change is needed for this > series > > > (and so the change history would be easier to follow). > > > > I'll explore and see if this can be separated. Although I think > > having a separate file local_data.c would uncomplicate the binding.c a > > bit. > > > > > > > > > > > > > > /* runtime data engine private data. */ > > > > struct sset egress_ifaces; > > > > struct smap local_iface_ids; > > > > @@ -1139,6 +1144,7 @@ en_runtime_data_init(struct engine_node *node > > > OVS_UNUSED, > > > > local_binding_data_init(&data->lbinding_data); > > > > shash_init(&data->local_active_ports_ipv6_pd); > > > > shash_init(&data->local_active_ports_ras); > > > > + local_nonvif_data_init(&data->nonvif_data); > > > > > > > > /* Init the tracked data. */ > > > > hmap_init(&data->tracked_dp_bindings); > > > > @@ -1160,6 +1166,7 @@ en_runtime_data_cleanup(void *data) > > > > shash_destroy_free_data(&rt_data->local_active_ports_ipv6_pd); > > > > shash_destroy_free_data(&rt_data->local_active_ports_ras); > > > > local_binding_data_destroy(&rt_data->lbinding_data); > > > > + local_nonvif_data_destroy(&rt_data->nonvif_data); > > > > } > > > > > > > > static void > > > > @@ -1272,6 +1279,7 @@ en_runtime_data_run(struct engine_node *node, > void > > > *data) > > > > shash_clear_free_data(local_active_ipv6_pd); > > > > shash_clear_free_data(local_active_ras); > > > > local_binding_data_destroy(&rt_data->lbinding_data); > > > > + local_nonvif_data_destroy(&rt_data->nonvif_data); > > > > sset_destroy(local_lports); > > > > related_lports_destroy(&rt_data->related_lports); > > > > sset_destroy(active_tunnels); > > > > @@ -1284,6 +1292,7 @@ en_runtime_data_run(struct engine_node *node, > void > > > *data) > > > > sset_init(&rt_data->egress_ifaces); > > > > smap_init(&rt_data->local_iface_ids); > > > > local_binding_data_init(&rt_data->lbinding_data); > > > > + local_nonvif_data_init(&rt_data->nonvif_data); > > > > } > > > > > > > > struct binding_ctx_in b_ctx_in; > > > > @@ -1303,6 +1312,7 @@ en_runtime_data_run(struct engine_node *node, > void > > > *data) > > > > bfd_calculate_active_tunnels(b_ctx_in.br_int, > active_tunnels); > > > > } > > > > > > > > + ldata_run(b_ctx_in.br_int, b_ctx_in.chassis_rec, > > > &rt_data->nonvif_data); > > > > binding_run(&b_ctx_in, &b_ctx_out); > > > > > > > > engine_set_node_state(node, EN_UPDATED); > > > > @@ -1318,6 +1328,10 @@ runtime_data_ovs_interface_handler(struct > > > engine_node *node, void *data) > > > > rt_data->tracked = true; > > > > b_ctx_out.tracked_dp_bindings = &rt_data->tracked_dp_bindings; > > > > > > > > + if (!ldata_handle_ovs_iface_changes(b_ctx_in.iface_table)) { > > > > + return false; > > > > + } > > > > + > > > > > > This is the performance problem I mentioned above. Before this change, > > > tunnel/patch interface changes only triggered physical_run(), now it > would > > > trigger lflow_run(). > > > > Actually that's not the case. Any change to tunnel/patch OVS interfaces > results > > in the function binding_handle_ovs_interface_changes() to return false > and hence > > lflow_run() would be called - > > https://github.com/ovn-org/ovn/blob/master/controller/binding.c#L2198 > > > > > > > > > > > > > if (!binding_handle_ovs_interface_changes(&b_ctx_in, > &b_ctx_out)) { > > > > return false; > > > > } > > > > @@ -2060,6 +2074,7 @@ init_lflow_ctx(struct engine_node *node, > > > > l_ctx_in->port_groups = port_groups; > > > > l_ctx_in->active_tunnels = &rt_data->active_tunnels; > > > > l_ctx_in->related_lport_ids = &rt_data->related_lports.lport_ids; > > > > + l_ctx_in->chassis_tunnels = > &rt_data->nonvif_data.chassis_tunnels; > > > > > > > > l_ctx_out->flow_table = &fo->flow_table; > > > > l_ctx_out->group_table = &fo->group_table; > > > > @@ -2527,6 +2542,7 @@ static void init_physical_ctx(struct engine_node > > > *node, > > > > p_ctx->ct_zones = ct_zones; > > > > p_ctx->mff_ovn_geneve = ed_mff_ovn_geneve->mff_ovn_geneve; > > > > p_ctx->local_bindings = &rt_data->lbinding_data.bindings; > > > > + p_ctx->nonvif_data = &rt_data->nonvif_data; > > > > } > > > > > > > > static void * > > > > @@ -2583,7 +2599,11 @@ pflow_output_sb_port_binding_handler(struct > > > engine_node *node, > > > > * only. flow_output runtime data handler takes care of > processing > > > > * logical flows for any port binding changes. > > > > */ > > > > - physical_handle_port_binding_changes(&p_ctx, &pfo->flow_table); > > > > + const struct sbrec_port_binding *pb; > > > > + SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED (pb, > > > p_ctx.port_binding_table) { > > > > + bool removed = sbrec_port_binding_is_deleted(pb); > > > > + physical_handle_flows_for_lport(pb, removed, &p_ctx, > > > &pfo->flow_table); > > > > + } > > > > > > nit: I think it is better to keep the interface > > > physical_handle_port_binding_changes() and hide this loop details in the > > > physical.c module. > > > > Ack. > > > > Thanks > > Numan > > > > > > > > Thanks, > > > Han > > > > > > > > > > > engine_set_node_state(node, EN_UPDATED); > > > > return true; > > > > @@ -2613,13 +2633,55 @@ pflow_output_ovs_iface_handler(struct > engine_node > > > *node OVS_UNUSED, > > > > struct ed_type_runtime_data *rt_data = > > > > engine_get_input_data("runtime_data", node); > > > > > > > > + struct physical_ctx p_ctx; > > > > + init_physical_ctx(node, rt_data, &p_ctx); > > > > + > > > > + engine_set_node_state(node, EN_UPDATED); > > > > + return physical_handle_ovs_iface_changes(&p_ctx); > > > > +} > > > > + > > > > +static bool > > > > +pflow_output_runtime_data_handler(struct engine_node *node, void > *data) > > > > +{ > > > > + struct ed_type_runtime_data *rt_data = > > > > + engine_get_input_data("runtime_data", node); > > > > + > > > > + /* There is no tracked data. Fall back to full recompute of > > > > + * pflow_output. */ > > > > + if (!rt_data->tracked) { > > > > + return false; > > > > + } > > > > + > > > > + struct hmap *tracked_dp_bindings = &rt_data->tracked_dp_bindings; > > > > + if (hmap_is_empty(tracked_dp_bindings)) { > > > > + return true; > > > > + } > > > > + > > > > struct ed_type_pflow_output *pfo = data; > > > > > > > > struct physical_ctx p_ctx; > > > > init_physical_ctx(node, rt_data, &p_ctx); > > > > > > > > + struct tracked_datapath *tdp; > > > > + HMAP_FOR_EACH (tdp, node, tracked_dp_bindings) { > > > > + if (tdp->tracked_type != TRACKED_RESOURCE_UPDATED) { > > > > + /* Fall back to full recompute when a local datapath > > > > + * is added or deleted. */ > > > > + return false; > > > > + } > > > > + > > > > + struct shash_node *shash_node; > > > > + SHASH_FOR_EACH (shash_node, &tdp->lports) { > > > > + struct tracked_lport *lport = shash_node->data; > > > > + bool removed = > > > > + lport->tracked_type == TRACKED_RESOURCE_REMOVED ? > true: > > > false; > > > > + physical_handle_flows_for_lport(lport->pb, removed, > &p_ctx, > > > > + &pfo->flow_table); > > > > + } > > > > + } > > > > + > > > > engine_set_node_state(node, EN_UPDATED); > > > > - return physical_handle_ovs_iface_changes(&p_ctx, > &pfo->flow_table); > > > > + return true; > > > > } > > > > > > > > static void * > > > > @@ -2914,7 +2976,7 @@ main(int argc, char *argv[]) > > > > pflow_output_sb_multicast_group_handler); > > > > > > > > engine_add_input(&en_pflow_output, &en_runtime_data, > > > > - NULL); > > > > + pflow_output_runtime_data_handler); > > > > engine_add_input(&en_pflow_output, &en_sb_encap, NULL); > > > > engine_add_input(&en_pflow_output, &en_mff_ovn_geneve, NULL); > > > > engine_add_input(&en_pflow_output, &en_ovs_open_vswitch, NULL); > > > > diff --git a/controller/ovn-controller.h b/controller/ovn-controller.h > > > > index 578588305..78a53312f 100644 > > > > --- a/controller/ovn-controller.h > > > > +++ b/controller/ovn-controller.h > > > > @@ -45,14 +45,6 @@ const struct ovsrec_bridge *get_bridge(const struct > > > ovsrec_bridge_table *, > > > > > > > > struct sbrec_encap *preferred_encap(const struct sbrec_chassis *); > > > > > > > > -/* Must be a bit-field ordered from most-preferred (higher number) to > > > > - * least-preferred (lower number). */ > > > > -enum chassis_tunnel_type { > > > > - GENEVE = 1 << 2, > > > > - STT = 1 << 1, > > > > - VXLAN = 1 << 0 > > > > -}; > > > > - > > > > uint32_t get_tunnel_type(const char *name); > > > > > > > > struct pb_ld_binding { > > > > diff --git a/controller/physical.c b/controller/physical.c > > > > index b244ff1c2..87080d001 100644 > > > > --- a/controller/physical.c > > > > +++ b/controller/physical.c > > > > @@ -86,46 +86,6 @@ physical_register_ovs_idl(struct ovsdb_idl > *ovs_idl) > > > > ovsdb_idl_track_add_column(ovs_idl, > > > &ovsrec_interface_col_external_ids); > > > > } > > > > > > > > -static struct simap localvif_to_ofport = > > > > - SIMAP_INITIALIZER(&localvif_to_ofport); > > > > -static struct hmap tunnels = HMAP_INITIALIZER(&tunnels); > > > > - > > > > -/* Maps from a chassis to the OpenFlow port number of the tunnel that > > > can be > > > > - * used to reach that chassis. */ > > > > -struct chassis_tunnel { > > > > - struct hmap_node hmap_node; > > > > - char *chassis_id; > > > > - ofp_port_t ofport; > > > > - enum chassis_tunnel_type type; > > > > -}; > > > > - > > > > -/* > > > > - * This function looks up the list of tunnel ports (provided by > > > > - * ovn-chassis-id ports) and returns the tunnel for the given > chassid-id > > > and > > > > - * encap-ip. The ovn-chassis-id is formed using the chassis-id and > > > encap-ip. > > > > - * The list is hashed using the chassis-id. If the encap-ip is not > > > specified, > > > > - * it means we'll just return a tunnel for that chassis-id, i.e. we > just > > > check > > > > - * for chassis-id and if there is a match, we'll return the tunnel. > > > > - * If encap-ip is also provided we use both chassis-id and encap-ip > to do > > > > - * a more specific lookup. > > > > - */ > > > > -static struct chassis_tunnel * > > > > -chassis_tunnel_find(const char *chassis_id, char *encap_ip) > > > > -{ > > > > - /* > > > > - * If the specific encap_ip is given, look for the chassisid_ip > > > entry, > > > > - * else return the 1st found entry for the chassis. > > > > - */ > > > > - struct chassis_tunnel *tun = NULL; > > > > - HMAP_FOR_EACH_WITH_HASH (tun, hmap_node, hash_string(chassis_id, > 0), > > > > - &tunnels) { > > > > - if (encaps_tunnel_id_match(tun->chassis_id, chassis_id, > > > encap_ip)) { > > > > - return tun; > > > > - } > > > > - } > > > > - return NULL; > > > > -} > > > > - > > > > static void > > > > put_load(uint64_t value, enum mf_field_id dst, int ofs, int n_bits, > > > > struct ofpbuf *ofpacts) > > > > @@ -166,17 +126,18 @@ put_resubmit(uint8_t table_id, struct ofpbuf > > > *ofpacts) > > > > * from the associated encap. > > > > */ > > > > static struct chassis_tunnel * > > > > -get_port_binding_tun(const struct sbrec_port_binding *binding) > > > > +get_port_binding_tun(const struct sbrec_port_binding *binding, > > > > + const struct hmap *chassis_tunnels) > > > > { > > > > struct sbrec_encap *encap = binding->encap; > > > > struct sbrec_chassis *chassis = binding->chassis; > > > > struct chassis_tunnel *tun = NULL; > > > > > > > > if (encap) { > > > > - tun = chassis_tunnel_find(chassis->name, encap->ip); > > > > + tun = chassis_tunnel_find(chassis_tunnels, chassis->name, > > > encap->ip); > > > > } > > > > if (!tun) { > > > > - tun = chassis_tunnel_find(chassis->name, NULL); > > > > + tun = chassis_tunnel_find(chassis_tunnels, chassis->name, > NULL); > > > > } > > > > return tun; > > > > } > > > > @@ -325,12 +286,13 @@ put_remote_port_redirect_overlay(const struct > > > > uint32_t port_key, > > > > struct match *match, > > > > struct ofpbuf *ofpacts_p, > > > > + const struct hmap *chassis_tunnels, > > > > struct ovn_desired_flow_table > > > *flow_table) > > > > { > > > > if (!is_ha_remote) { > > > > /* Setup encapsulation */ > > > > const struct chassis_tunnel *rem_tun = > > > > - get_port_binding_tun(binding); > > > > + get_port_binding_tun(binding, chassis_tunnels); > > > > if (!rem_tun) { > > > > return; > > > > } > > > > @@ -348,10 +310,10 @@ put_remote_port_redirect_overlay(const struct > > > > continue; > > > > } > > > > if (!tun) { > > > > - tun = chassis_tunnel_find(ch->name, NULL); > > > > + tun = chassis_tunnel_find(chassis_tunnels, ch->name, > > > NULL); > > > > } else { > > > > struct chassis_tunnel *chassis_tunnel = > > > > - chassis_tunnel_find(ch->name, > > > NULL); > > > > + chassis_tunnel_find(chassis_tunnels, ch->name, > NULL); > > > > if (chassis_tunnel && > > > > tun->type != chassis_tunnel->type) { > > > > static struct vlog_rate_limit rl = > > > > @@ -385,7 +347,7 @@ put_remote_port_redirect_overlay(const struct > > > > if (!ch) { > > > > continue; > > > > } > > > > - tun = chassis_tunnel_find(ch->name, NULL); > > > > + tun = chassis_tunnel_find(chassis_tunnels, ch->name, > NULL); > > > > if (!tun) { > > > > continue; > > > > } > > > > @@ -925,6 +887,9 @@ consider_port_binding(struct ovsdb_idl_index > > > *sbrec_port_binding_by_name, > > > > const struct simap *ct_zones, > > > > const struct sset *active_tunnels, > > > > const struct hmap *local_datapaths, > > > > + const struct shash *local_bindings, > > > > + const struct simap *patch_ofports, > > > > + const struct hmap *chassis_tunnels, > > > > const struct sbrec_port_binding *binding, > > > > const struct sbrec_chassis *chassis, > > > > struct ovn_desired_flow_table *flow_table, > > > > @@ -1081,17 +1046,25 @@ consider_port_binding(struct ovsdb_idl_index > > > *sbrec_port_binding_by_name, > > > > if (!binding->tag) { > > > > goto out; > > > > } > > > > - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, > > > > - binding->parent_port)); > > > > + ofport = local_binding_get_lport_ofport(local_bindings, > > > > + > binding->parent_port); > > > > if (ofport) { > > > > tag = *binding->tag; > > > > nested_container = true; > > > > parent_port = lport_lookup_by_name( > > > > sbrec_port_binding_by_name, binding->parent_port); > > > > } > > > > - } else { > > > > - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, > > > > + } else if (!strcmp(binding->type, "localnet") > > > > + || !strcmp(binding->type, "l2gateway")) { > > > > + > > > > + ofport = u16_to_ofp(simap_get(patch_ofports, > > > > binding->logical_port)); > > > > + if (ofport && binding->tag) { > > > > + tag = *binding->tag; > > > > + } > > > > + } else { > > > > + ofport = local_binding_get_lport_ofport(local_bindings, > > > > + > binding->logical_port); > > > > const char *requested_chassis = smap_get(&binding->options, > > > > > "requested-chassis"); > > > > if (ofport && requested_chassis && requested_chassis[0] && > > > > @@ -1102,12 +1075,6 @@ consider_port_binding(struct ovsdb_idl_index > > > *sbrec_port_binding_by_name, > > > > */ > > > > ofport = 0; > > > > } > > > > - > > > > - if ((!strcmp(binding->type, "localnet") > > > > - || !strcmp(binding->type, "l2gateway")) > > > > - && ofport && binding->tag) { > > > > - tag = *binding->tag; > > > > - } > > > > } > > > > > > > > bool is_ha_remote = false; > > > > @@ -1118,7 +1085,7 @@ consider_port_binding(struct ovsdb_idl_index > > > *sbrec_port_binding_by_name, > > > > /* It is remote port, may be reached by tunnel or localnet > port > > > */ > > > > is_remote = true; > > > > if (localnet_port) { > > > > - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, > > > > + ofport = u16_to_ofp(simap_get(patch_ofports, > > > > > localnet_port->logical_port)); > > > > if (!ofport) { > > > > goto out; > > > > @@ -1129,7 +1096,8 @@ consider_port_binding(struct ovsdb_idl_index > > > *sbrec_port_binding_by_name, > > > > if (!binding->chassis) { > > > > goto out; > > > > } > > > > - tun = chassis_tunnel_find(binding->chassis->name, > NULL); > > > > + tun = chassis_tunnel_find(chassis_tunnels, > > > > + binding->chassis->name, > NULL); > > > > if (!tun) { > > > > goto out; > > > > } > > > > @@ -1383,7 +1351,7 @@ consider_port_binding(struct ovsdb_idl_index > > > *sbrec_port_binding_by_name, > > > > put_remote_port_redirect_overlay(binding, is_ha_remote, > > > > ha_ch_ordered, > > > mff_ovn_geneve, > > > > tun, port_key, &match, > > > ofpacts_p, > > > > - flow_table); > > > > + chassis_tunnels, > > > flow_table); > > > > } > > > > } > > > > out: > > > > @@ -1396,8 +1364,11 @@ static void > > > > consider_mc_group(enum mf_field_id mff_ovn_geneve, > > > > const struct simap *ct_zones, > > > > const struct hmap *local_datapaths, > > > > + struct shash *local_bindings, > > > > + struct simap *patch_ofports, > > > > const struct sbrec_chassis *chassis, > > > > const struct sbrec_multicast_group *mc, > > > > + const struct hmap *chassis_tunnels, > > > > struct ovn_desired_flow_table *flow_table) > > > > { > > > > uint32_t dp_key = mc->datapath->tunnel_key; > > > > @@ -1444,19 +1415,21 @@ consider_mc_group(enum mf_field_id > mff_ovn_geneve, > > > > put_load(zone_id, MFF_LOG_CT_ZONE, 0, 32, &ofpacts); > > > > } > > > > > > > > + const char *lport_name = (port->parent_port && > > > *port->parent_port) ? > > > > + port->parent_port : > port->logical_port; > > > > + > > > > if (!strcmp(port->type, "patch")) { > > > > put_load(port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, > > > > &remote_ofpacts); > > > > put_resubmit(OFTABLE_CHECK_LOOPBACK, &remote_ofpacts); > > > > - } else if (simap_contains(&localvif_to_ofport, > > > > - (port->parent_port && *port->parent_port) > > > > - ? port->parent_port : port->logical_port) > > > > + } else if (local_binding_get_primary_pb(local_bindings, > > > lport_name) > > > > + || simap_contains(patch_ofports, > port->logical_port) > > > > || (!strcmp(port->type, "l3gateway") > > > > && port->chassis == chassis)) { > > > > put_load(port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, > &ofpacts); > > > > put_resubmit(OFTABLE_CHECK_LOOPBACK, &ofpacts); > > > > - } else if (port->chassis && > !get_localnet_port(local_datapaths, > > > > - mc->datapath->tunnel_key)) { > > > > + } else if (port->chassis && !get_localnet_port( > > > > + local_datapaths, mc->datapath->tunnel_key)) { > > > > /* Add remote chassis only when localnet port not exist, > > > > * otherwise multicast will reach remote ports through > > > localnet > > > > * port. */ > > > > @@ -1497,7 +1470,7 @@ consider_mc_group(enum mf_field_id > mff_ovn_geneve, > > > > const struct chassis_tunnel *prev = NULL; > > > > SSET_FOR_EACH (chassis_name, &remote_chassis) { > > > > const struct chassis_tunnel *tun > > > > - = chassis_tunnel_find(chassis_name, NULL); > > > > + = chassis_tunnel_find(chassis_tunnels, chassis_name, > > > NULL); > > > > if (!tun) { > > > > continue; > > > > } > > > > @@ -1524,41 +1497,50 @@ consider_mc_group(enum mf_field_id > mff_ovn_geneve, > > > > sset_destroy(&remote_chassis); > > > > } > > > > > > > > -/* Replaces 'old' by 'new' (destroying 'new'). Returns true if 'old' > > > and 'new' > > > > - * contained different data, false if they were the same. */ > > > > -static bool > > > > -update_ofports(struct simap *old, struct simap *new) > > > > -{ > > > > - bool changed = !simap_equal(old, new); > > > > - simap_swap(old, new); > > > > - simap_destroy(new); > > > > - return changed; > > > > -} > > > > - > > > > void > > > > -physical_handle_port_binding_changes(struct physical_ctx *p_ctx, > > > > - struct ovn_desired_flow_table > > > *flow_table) > > > > +physical_handle_flows_for_lport(const struct sbrec_port_binding *pb, > > > > + bool removed, struct physical_ctx > *p_ctx, > > > > + struct ovn_desired_flow_table > > > *flow_table) > > > > { > > > > - const struct sbrec_port_binding *binding; > > > > - struct ofpbuf ofpacts; > > > > - ofpbuf_init(&ofpacts, 0); > > > > - SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED (binding, > > > > - > > > p_ctx->port_binding_table) { > > > > - if (sbrec_port_binding_is_deleted(binding)) { > > > > - ofctrl_remove_flows(flow_table, &binding->header_.uuid); > > > > - } else { > > > > - if (!sbrec_port_binding_is_new(binding)) { > > > > - ofctrl_remove_flows(flow_table, > &binding->header_.uuid); > > > > - } > > > > + ofctrl_remove_flows(flow_table, &pb->header_.uuid); > > > > + > > > > + if (!strcmp(pb->type, "external")) { > > > > + /* External lports have a dependency on the localnet port. > > > > + * We need to remove the flows of the localnet port as well > > > > + * and re-consider adding the flows for it. > > > > + */ > > > > + struct local_datapath *ldp = > > > > + get_local_datapath(p_ctx->local_datapaths, > > > > + pb->datapath->tunnel_key); > > > > + if (ldp && ldp->localnet_port) { > > > > + struct ofpbuf ofpacts; > > > > + ofctrl_remove_flows(flow_table, > > > &ldp->localnet_port->header_.uuid); > > > > + ofpbuf_init(&ofpacts, 0); > > > > consider_port_binding(p_ctx->sbrec_port_binding_by_name, > > > > p_ctx->mff_ovn_geneve, > p_ctx->ct_zones, > > > > p_ctx->active_tunnels, > > > > p_ctx->local_datapaths, > > > > - binding, p_ctx->chassis, > > > > + p_ctx->local_bindings, > > > > + &p_ctx->nonvif_data->patch_ofports, > > > > + > &p_ctx->nonvif_data->chassis_tunnels, > > > > + ldp->localnet_port, p_ctx->chassis, > > > > flow_table, &ofpacts); > > > > + ofpbuf_uninit(&ofpacts); > > > > } > > > > } > > > > - ofpbuf_uninit(&ofpacts); > > > > + > > > > + if (!removed) { > > > > + struct ofpbuf ofpacts; > > > > + ofpbuf_init(&ofpacts, 0); > > > > + consider_port_binding(p_ctx->sbrec_port_binding_by_name, > > > > + p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > > > > + p_ctx->active_tunnels, > > > p_ctx->local_datapaths, > > > > + p_ctx->local_bindings, > > > > + &p_ctx->nonvif_data->patch_ofports, > > > > + &p_ctx->nonvif_data->chassis_tunnels, > pb, > > > > + p_ctx->chassis, flow_table, &ofpacts); > > > > + ofpbuf_uninit(&ofpacts); > > > > + } > > > > } > > > > > > > > void > > > > @@ -1574,8 +1556,11 @@ physical_handle_mc_group_changes(struct > > > physical_ctx *p_ctx, > > > > ofctrl_remove_flows(flow_table, &mc->header_.uuid); > > > > } > > > > consider_mc_group(p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > > > > - p_ctx->local_datapaths, > > > > - p_ctx->chassis, mc, flow_table); > > > > + p_ctx->local_datapaths, > > > p_ctx->local_bindings, > > > > + &p_ctx->nonvif_data->patch_ofports, > > > > + p_ctx->chassis, mc, > > > > + &p_ctx->nonvif_data->chassis_tunnels, > > > > + flow_table); > > > > } > > > > } > > > > } > > > > @@ -1591,135 +1576,6 @@ physical_run(struct physical_ctx *p_ctx, > > > > uuid_generate(hc_uuid); > > > > } > > > > > > > > - /* This bool tracks physical mapping changes. */ > > > > - bool physical_map_changed = false; > > > > - > > > > - struct simap new_localvif_to_ofport = > > > > - SIMAP_INITIALIZER(&new_localvif_to_ofport); > > > > - struct simap new_tunnel_to_ofport = > > > > - SIMAP_INITIALIZER(&new_tunnel_to_ofport); > > > > - for (int i = 0; i < p_ctx->br_int->n_ports; i++) { > > > > - const struct ovsrec_port *port_rec = p_ctx->br_int->ports[i]; > > > > - if (!strcmp(port_rec->name, p_ctx->br_int->name)) { > > > > - continue; > > > > - } > > > > - > > > > - const char *tunnel_id = smap_get(&port_rec->external_ids, > > > > - "ovn-chassis-id"); > > > > - if (tunnel_id && encaps_tunnel_id_match(tunnel_id, > > > > - p_ctx->chassis->name, > > > > - NULL)) { > > > > - continue; > > > > - } > > > > - > > > > - const char *localnet = smap_get(&port_rec->external_ids, > > > > - "ovn-localnet-port"); > > > > - const char *l2gateway = smap_get(&port_rec->external_ids, > > > > - "ovn-l2gateway-port"); > > > > - > > > > - for (int j = 0; j < port_rec->n_interfaces; j++) { > > > > - const struct ovsrec_interface *iface_rec = > > > port_rec->interfaces[j]; > > > > - > > > > - /* Get OpenFlow port number. */ > > > > - if (!iface_rec->n_ofport) { > > > > - continue; > > > > - } > > > > - int64_t ofport = iface_rec->ofport[0]; > > > > - if (ofport < 1 || ofport > ofp_to_u16(OFPP_MAX)) { > > > > - continue; > > > > - } > > > > - > > > > - /* Record as patch to local net, logical patch port, > > > chassis, or > > > > - * local logical port. */ > > > > - bool is_patch = !strcmp(iface_rec->type, "patch"); > > > > - if (is_patch && localnet) { > > > > - /* localnet patch ports can be handled just like > VIFs. */ > > > > - simap_put(&new_localvif_to_ofport, localnet, ofport); > > > > - break; > > > > - } else if (is_patch && l2gateway) { > > > > - /* L2 gateway patch ports can be handled just like > VIFs. > > > */ > > > > - simap_put(&new_localvif_to_ofport, l2gateway, > ofport); > > > > - break; > > > > - } else if (tunnel_id) { > > > > - enum chassis_tunnel_type tunnel_type; > > > > - if (!strcmp(iface_rec->type, "geneve")) { > > > > - tunnel_type = GENEVE; > > > > - if (!p_ctx->mff_ovn_geneve) { > > > > - continue; > > > > - } > > > > - } else if (!strcmp(iface_rec->type, "stt")) { > > > > - tunnel_type = STT; > > > > - } else if (!strcmp(iface_rec->type, "vxlan")) { > > > > - tunnel_type = VXLAN; > > > > - } else { > > > > - continue; > > > > - } > > > > - > > > > - simap_put(&new_tunnel_to_ofport, tunnel_id, ofport); > > > > - /* > > > > - * We split the tunnel_id to get the chassis-id > > > > - * and hash the tunnel list on the chassis-id. The > > > > - * reason to use the chassis-id alone is because > > > > - * there might be cases (multicast, gateway chassis) > > > > - * where we need to tunnel to the chassis, but won't > > > > - * have the encap-ip specifically. > > > > - */ > > > > - char *hash_id = NULL; > > > > - char *ip = NULL; > > > > - > > > > - if (!encaps_tunnel_id_parse(tunnel_id, &hash_id, > &ip)) { > > > > - continue; > > > > - } > > > > - struct chassis_tunnel *tun = > > > chassis_tunnel_find(hash_id, ip); > > > > - if (tun) { > > > > - /* If the tunnel's ofport has changed, update. */ > > > > - if (tun->ofport != u16_to_ofp(ofport) || > > > > - tun->type != tunnel_type) { > > > > - tun->ofport = u16_to_ofp(ofport); > > > > - tun->type = tunnel_type; > > > > - physical_map_changed = true; > > > > - } > > > > - } else { > > > > - tun = xmalloc(sizeof *tun); > > > > - hmap_insert(&tunnels, &tun->hmap_node, > > > > - hash_string(hash_id, 0)); > > > > - tun->chassis_id = xstrdup(tunnel_id); > > > > - tun->ofport = u16_to_ofp(ofport); > > > > - tun->type = tunnel_type; > > > > - physical_map_changed = true; > > > > - } > > > > - free(hash_id); > > > > - free(ip); > > > > - break; > > > > - } else { > > > > - const char *iface_id = > smap_get(&iface_rec->external_ids, > > > > - "iface-id"); > > > > - if (iface_id) { > > > > - simap_put(&new_localvif_to_ofport, iface_id, > ofport); > > > > - } > > > > - } > > > > - } > > > > - } > > > > - > > > > - /* Remove tunnels that are no longer here. */ > > > > - struct chassis_tunnel *tun, *tun_next; > > > > - HMAP_FOR_EACH_SAFE (tun, tun_next, hmap_node, &tunnels) { > > > > - if (!simap_find(&new_tunnel_to_ofport, tun->chassis_id)) { > > > > - hmap_remove(&tunnels, &tun->hmap_node); > > > > - physical_map_changed = true; > > > > - free(tun->chassis_id); > > > > - free(tun); > > > > - } > > > > - } > > > > - > > > > - /* Capture changed or removed openflow ports. */ > > > > - physical_map_changed |= update_ofports(&localvif_to_ofport, > > > > - &new_localvif_to_ofport); > > > > - if (physical_map_changed) { > > > > - /* Reprocess logical flow table immediately. */ > > > > - poll_immediate_wake(); > > > > - } > > > > - > > > > struct ofpbuf ofpacts; > > > > ofpbuf_init(&ofpacts, 0); > > > > > > > > @@ -1733,16 +1589,20 @@ physical_run(struct physical_ctx *p_ctx, > > > > consider_port_binding(p_ctx->sbrec_port_binding_by_name, > > > > p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > > > > p_ctx->active_tunnels, > > > p_ctx->local_datapaths, > > > > - binding, p_ctx->chassis, > > > > - flow_table, &ofpacts); > > > > + p_ctx->local_bindings, > > > > + &p_ctx->nonvif_data->patch_ofports, > > > > + &p_ctx->nonvif_data->chassis_tunnels, > > > binding, > > > > + p_ctx->chassis, flow_table, &ofpacts); > > > > } > > > > > > > > /* Handle output to multicast groups, in tables 32 and 33. */ > > > > const struct sbrec_multicast_group *mc; > > > > SBREC_MULTICAST_GROUP_TABLE_FOR_EACH (mc, p_ctx->mc_group_table) > { > > > > consider_mc_group(p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > > > > - p_ctx->local_datapaths, p_ctx->chassis, > > > > - mc, flow_table); > > > > + p_ctx->local_datapaths, > p_ctx->local_bindings, > > > > + &p_ctx->nonvif_data->patch_ofports, > > > p_ctx->chassis, > > > > + mc, &p_ctx->nonvif_data->chassis_tunnels, > > > > + flow_table); > > > > } > > > > > > > > /* Table 0, priority 100. > > > > @@ -1757,7 +1617,8 @@ physical_run(struct physical_ctx *p_ctx, > > > > * We set MFF_LOG_DATAPATH, MFF_LOG_INPORT, and MFF_LOG_OUTPORT > from > > > the > > > > * tunnel key data where possible, then resubmit to table 33 to > > > handle > > > > * packets to the local hypervisor. */ > > > > - HMAP_FOR_EACH (tun, hmap_node, &tunnels) { > > > > + struct chassis_tunnel *tun; > > > > + HMAP_FOR_EACH (tun, hmap_node, > &p_ctx->nonvif_data->chassis_tunnels) > > > { > > > > struct match match = MATCH_CATCHALL_INITIALIZER; > > > > match_set_in_port(&match, tun->ofport); > > > > > > > > @@ -1788,7 +1649,7 @@ physical_run(struct physical_ctx *p_ctx, > > > > } > > > > > > > > /* Handle ramp switch encapsulations. */ > > > > - HMAP_FOR_EACH (tun, hmap_node, &tunnels) { > > > > + HMAP_FOR_EACH (tun, hmap_node, > &p_ctx->nonvif_data->chassis_tunnels) > > > { > > > > if (tun->type != VXLAN) { > > > > continue; > > > > } > > > > @@ -1925,13 +1786,10 @@ physical_run(struct physical_ctx *p_ctx, > > > > &ofpacts, hc_uuid); > > > > > > > > ofpbuf_uninit(&ofpacts); > > > > - > > > > - simap_destroy(&new_tunnel_to_ofport); > > > > } > > > > > > > > bool > > > > -physical_handle_ovs_iface_changes(struct physical_ctx *p_ctx, > > > > - struct ovn_desired_flow_table > > > *flow_table) > > > > +physical_handle_ovs_iface_changes(struct physical_ctx *p_ctx) > > > > { > > > > const struct ovsrec_interface *iface_rec; > > > > OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, > > > p_ctx->iface_table) { > > > > @@ -1943,64 +1801,6 @@ physical_handle_ovs_iface_changes(struct > > > physical_ctx *p_ctx, > > > > } > > > > } > > > > > > > > - struct ofpbuf ofpacts; > > > > - ofpbuf_init(&ofpacts, 0); > > > > - > > > > - OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, > > > p_ctx->iface_table) { > > > > - const char *iface_id = smap_get(&iface_rec->external_ids, > > > "iface-id"); > > > > - if (!iface_id) { > > > > - continue; > > > > - } > > > > - > > > > - const struct sbrec_port_binding *lb_pb = > > > > - local_binding_get_primary_pb(p_ctx->local_bindings, > > > iface_id); > > > > - if (!lb_pb) { > > > > - /* For regular VIFs (e.g. lsp) the upcoming port-binding > > > update > > > > - * will remove lfows related to the unclaimed ovs port. > > > > - * Localport is a special case and it needs to be managed > > > here > > > > - * since the port is not binded and otherwise the related > > > lfows > > > > - * will not be cleared removing the ovs port. > > > > - */ > > > > - lb_pb = > > > lport_lookup_by_name(p_ctx->sbrec_port_binding_by_name, > > > > - iface_id); > > > > - if (!lb_pb || strcmp(lb_pb->type, "localport")) { > > > > - continue; > > > > - } > > > > - } > > > > - > > > > - int64_t ofport = iface_rec->n_ofport ? *iface_rec->ofport : > 0; > > > > - if (ovsrec_interface_is_deleted(iface_rec)) { > > > > - ofctrl_remove_flows(flow_table, &lb_pb->header_.uuid); > > > > - simap_find_and_delete(&localvif_to_ofport, iface_id); > > > > - } else { > > > > - if (!ovsrec_interface_is_new(iface_rec)) { > > > > - ofctrl_remove_flows(flow_table, > &lb_pb->header_.uuid); > > > > - } > > > > - > > > > - simap_put(&localvif_to_ofport, iface_id, ofport); > > > > - consider_port_binding(p_ctx->sbrec_port_binding_by_name, > > > > - p_ctx->mff_ovn_geneve, > p_ctx->ct_zones, > > > > - p_ctx->active_tunnels, > > > > - p_ctx->local_datapaths, > > > > - lb_pb, p_ctx->chassis, > > > > - flow_table, &ofpacts); > > > > - } > > > > - } > > > > - > > > > - ofpbuf_uninit(&ofpacts); > > > > - return true; > > > > -} > > > > - > > > > -bool > > > > -get_tunnel_ofport(const char *chassis_name, char *encap_ip, > ofp_port_t > > > *ofport) > > > > -{ > > > > - struct chassis_tunnel *tun = NULL; > > > > - tun = chassis_tunnel_find(chassis_name, encap_ip); > > > > - if (!tun) { > > > > - return false; > > > > - } > > > > - > > > > - *ofport = tun->ofport; > > > > return true; > > > > } > > > > > > > > diff --git a/controller/physical.h b/controller/physical.h > > > > index feab41df4..3fdc20005 100644 > > > > --- a/controller/physical.h > > > > +++ b/controller/physical.h > > > > @@ -34,6 +34,7 @@ struct simap; > > > > struct sbrec_multicast_group_table; > > > > struct sbrec_port_binding_table; > > > > struct sset; > > > > +struct local_nonvif_data; > > > > > > > > /* OVN Geneve option information. > > > > * > > > > @@ -56,18 +57,18 @@ struct physical_ctx { > > > > const struct simap *ct_zones; > > > > enum mf_field_id mff_ovn_geneve; > > > > struct shash *local_bindings; > > > > + struct local_nonvif_data *nonvif_data; > > > > }; > > > > > > > > void physical_register_ovs_idl(struct ovsdb_idl *); > > > > void physical_run(struct physical_ctx *, > > > > struct ovn_desired_flow_table *); > > > > void physical_clear_unassoc_flows_with_db(struct > ovn_desired_flow_table > > > *); > > > > -void physical_handle_port_binding_changes(struct physical_ctx *, > > > > - struct > ovn_desired_flow_table > > > *); > > > > void physical_handle_mc_group_changes(struct physical_ctx *, > > > > struct ovn_desired_flow_table > *); > > > > -bool physical_handle_ovs_iface_changes(struct physical_ctx *, > > > > - struct ovn_desired_flow_table > *); > > > > -bool get_tunnel_ofport(const char *chassis_name, char *encap_ip, > > > > - ofp_port_t *ofport); > > > > +bool physical_handle_ovs_iface_changes(struct physical_ctx *); > > > > +void physical_handle_flows_for_lport(const struct sbrec_port_binding > *, > > > > + bool removed, > > > > + struct physical_ctx *, > > > > + struct ovn_desired_flow_table > *); > > > > #endif /* controller/physical.h */ > > > > -- > > > > 2.31.1 > > > > > > > > _______________________________________________ > > > > dev mailing list > > > > dev@openvswitch.org > > > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > > _______________________________________________ > > > dev mailing list > > > dev@openvswitch.org > > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > > > _______________________________________________ > dev mailing list > dev@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev >
On Tue, Jul 27, 2021 at 3:03 PM Numan Siddique <numans@ovn.org> wrote: > > On Tue, Jul 27, 2021 at 4:00 PM Han Zhou <hzhou@ovn.org> wrote: > > > > On Tue, Jul 27, 2021 at 11:43 AM Numan Siddique <numans@ovn.org> wrote: > > > > > > On Tue, Jul 27, 2021 at 3:36 AM Han Zhou <hzhou@ovn.org> wrote: > > > > > > > > Thanks Numan. The commit title has a typo: s/plow/pflow. > > > > > > > > On Fri, Jul 16, 2021 at 4:55 AM <numans@ovn.org> wrote: > > > > > > > > > > From: Numan Siddique <numans@ovn.org> > > > > > > > > > > physical_run() maintains a local copy of local vif to ofports > > > > > in a simap along with the chassis tunnel information. This patch > > > > > removes this from the physical module and now stores it in the > > > > > runtime_data engine node. This makes it easier to handle runtime > > > > > data changes in pflow_output engine. > > > > > > > > > > The newly added handler pflow_output_runtime_data_handler() returns > > > > > false if a datapath is added or removed from the local_datapaths > > > > > and handles the logical port claims and releases incrementally. > > > > > > > > > > Signed-off-by: Numan Siddique <numans@ovn.org> > > > > > --- > > > > > controller/binding.c | 39 ++-- > > > > > controller/binding.h | 23 +++ > > > > > controller/ldata.c | 169 ++++++++++++++++ > > > > > controller/ldata.h | 44 +++++ > > > > > controller/lflow.c | 5 +- > > > > > controller/lflow.h | 1 + > > > > > controller/ovn-controller.c | 68 ++++++- > > > > > controller/ovn-controller.h | 8 - > > > > > controller/physical.c | 382 > > +++++++++--------------------------- > > > > > controller/physical.h | 13 +- > > > > > 10 files changed, 422 insertions(+), 330 deletions(-) > > > > > > > > > > diff --git a/controller/binding.c b/controller/binding.c > > > > > index 0fd951ad7..b50139726 100644 > > > > > --- a/controller/binding.c > > > > > +++ b/controller/binding.c > > > > > @@ -546,23 +546,6 @@ update_active_pb_ras_pd(const struct > > > > sbrec_port_binding *pb, > > > > > } > > > > > } > > > > > > > > > > -/* Corresponds to each Port_Binding.type. */ > > > > > -enum en_lport_type { > > > > > - LP_UNKNOWN, > > > > > - LP_VIF, > > > > > - LP_CONTAINER, > > > > > - LP_PATCH, > > > > > - LP_L3GATEWAY, > > > > > - LP_LOCALNET, > > > > > - LP_LOCALPORT, > > > > > - LP_L2GATEWAY, > > > > > - LP_VTEP, > > > > > - LP_CHASSISREDIRECT, > > > > > - LP_VIRTUAL, > > > > > - LP_EXTERNAL, > > > > > - LP_REMOTE > > > > > -}; > > > > > - > > > > > /* Local bindings. binding.c module binds the logical port > > (represented > > > > by > > > > > * Port_Binding rows) and sets the 'chassis' column when it sees the > > > > > * OVS interface row (of type "" or "internal") with the > > > > > @@ -616,7 +599,7 @@ static struct local_binding *local_binding_create( > > > > > static void local_binding_add(struct shash *local_bindings, > > > > > struct local_binding *); > > > > > static struct local_binding *local_binding_find( > > > > > - struct shash *local_bindings, const char *name); > > > > > + const struct shash *local_bindings, const char *name); > > > > > static void local_binding_destroy(struct local_binding *, > > > > > struct shash *binding_lports); > > > > > static void local_binding_delete(struct local_binding *, > > > > > @@ -701,7 +684,8 @@ local_binding_data_destroy(struct > > local_binding_data > > > > *lbinding_data) > > > > > } > > > > > > > > > > const struct sbrec_port_binding * > > > > > -local_binding_get_primary_pb(struct shash *local_bindings, const char > > > > *pb_name) > > > > > +local_binding_get_primary_pb(struct shash *local_bindings, > > > > > + const char *pb_name) > > > > > { > > > > > struct local_binding *lbinding = > > > > > local_binding_find(local_bindings, pb_name); > > > > > @@ -710,6 +694,19 @@ local_binding_get_primary_pb(struct shash > > > > *local_bindings, const char *pb_name) > > > > > return b_lport ? b_lport->pb : NULL; > > > > > } > > > > > > > > > > +ofp_port_t > > > > > +local_binding_get_lport_ofport(const struct shash *local_bindings, > > > > > + const char *pb_name) > > > > > +{ > > > > > + struct local_binding *lbinding = > > > > > + local_binding_find(local_bindings, pb_name); > > > > > + struct binding_lport *b_lport = > > > > > + local_binding_get_primary_or_localport_lport(lbinding); > > > > > + > > > > > + return (b_lport && lbinding->iface && lbinding->iface->n_ofport) > > ? > > > > > + u16_to_ofp(lbinding->iface->ofport[0]) : 0; > > > > > +} > > > > > + > > > > > bool > > > > > local_binding_is_up(struct shash *local_bindings, const char > > *pb_name) > > > > > { > > > > > @@ -871,7 +868,7 @@ is_lport_vif(const struct sbrec_port_binding *pb) > > > > > return !pb->type[0]; > > > > > } > > > > > > > > > > -static enum en_lport_type > > > > > +enum en_lport_type > > > > > get_lport_type(const struct sbrec_port_binding *pb) > > > > > { > > > > > if (is_lport_vif(pb)) { > > > > > @@ -2555,7 +2552,7 @@ local_binding_create(const char *name, const > > struct > > > > ovsrec_interface *iface) > > > > > } > > > > > > > > > > static struct local_binding * > > > > > -local_binding_find(struct shash *local_bindings, const char *name) > > > > > +local_binding_find(const struct shash *local_bindings, const char > > *name) > > > > > { > > > > > return shash_find_data(local_bindings, name); > > > > > } > > > > > diff --git a/controller/binding.h b/controller/binding.h > > > > > index b1717bd2b..f1abc4b9c 100644 > > > > > --- a/controller/binding.h > > > > > +++ b/controller/binding.h > > > > > @@ -114,6 +114,9 @@ void local_binding_data_destroy(struct > > > > local_binding_data *); > > > > > > > > > > const struct sbrec_port_binding *local_binding_get_primary_pb( > > > > > struct shash *local_bindings, const char *pb_name); > > > > > +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_down(struct shash *local_bindings, const char > > > > *pb_name); > > > > > void local_binding_set_up(struct shash *local_bindings, const char > > > > *pb_name, > > > > > @@ -134,4 +137,24 @@ bool binding_handle_port_binding_changes(struct > > > > binding_ctx_in *, > > > > > void binding_tracked_dp_destroy(struct hmap *tracked_datapaths); > > > > > > > > > > void binding_dump_local_bindings(struct local_binding_data *, struct > > ds > > > > *); > > > > > + > > > > > +/* Corresponds to each Port_Binding.type. */ > > > > > +enum en_lport_type { > > > > > + LP_UNKNOWN, > > > > > + LP_VIF, > > > > > + LP_CONTAINER, > > > > > + LP_PATCH, > > > > > + LP_L3GATEWAY, > > > > > + LP_LOCALNET, > > > > > + LP_LOCALPORT, > > > > > + LP_L2GATEWAY, > > > > > + LP_VTEP, > > > > > + LP_CHASSISREDIRECT, > > > > > + LP_VIRTUAL, > > > > > + LP_EXTERNAL, > > > > > + LP_REMOTE > > > > > +}; > > > > > + > > > > > +enum en_lport_type get_lport_type(const struct sbrec_port_binding *); > > > > > + > > > > > #endif /* controller/binding.h */ > > > > > diff --git a/controller/ldata.c b/controller/ldata.c > > > > > index a6df9b1da..f55905551 100644 > > > > > --- a/controller/ldata.c > > > > > +++ b/controller/ldata.c > > > > > @@ -18,10 +18,13 @@ > > > > > /* OVS includes. */ > > > > > #include "include/openvswitch/json.h" > > > > > #include "lib/hmapx.h" > > > > > +#include "lib/flow.h" > > > > > #include "lib/util.h" > > > > > +#include "lib/vswitch-idl.h" > > > > > #include "openvswitch/vlog.h" > > > > > > > > > > /* OVN includes. */ > > > > > +#include "encaps.h" > > > > > #include "ldata.h" > > > > > #include "lport.h" > > > > > #include "lib/ovn-util.h" > > > > > @@ -275,6 +278,172 @@ tracked_datapaths_destroy(struct hmap > > > > *tracked_datapaths) > > > > > hmap_destroy(tracked_datapaths); > > > > > } > > > > > > > > > > +/* Iterates the br_int ports and build the simap of patch to ofports > > > > > + * and chassis tunnels. */ > > > > > +void > > > > > +ldata_run(const struct ovsrec_bridge *br_int, > > > > > + const struct sbrec_chassis *chassis_rec, > > > > > + struct local_nonvif_data *nonvif_data) > > > > > +{ > > > > > + for (int i = 0; i < br_int->n_ports; i++) { > > > > > + const struct ovsrec_port *port_rec = br_int->ports[i]; > > > > > + if (!strcmp(port_rec->name, br_int->name)) { > > > > > + continue; > > > > > + } > > > > > + > > > > > + const char *tunnel_id = smap_get(&port_rec->external_ids, > > > > > + "ovn-chassis-id"); > > > > > + if (tunnel_id && encaps_tunnel_id_match(tunnel_id, > > > > > + chassis_rec->name, > > > > > + NULL)) { > > > > > + continue; > > > > > + } > > > > > + > > > > > + const char *localnet = smap_get(&port_rec->external_ids, > > > > > + "ovn-localnet-port"); > > > > > + const char *l2gateway = smap_get(&port_rec->external_ids, > > > > > + "ovn-l2gateway-port"); > > > > > + > > > > > + for (int j = 0; j < port_rec->n_interfaces; j++) { > > > > > + const struct ovsrec_interface *iface_rec = > > > > port_rec->interfaces[j]; > > > > > + > > > > > + /* Get OpenFlow port number. */ > > > > > + if (!iface_rec->n_ofport) { > > > > > + continue; > > > > > + } > > > > > + int64_t ofport = iface_rec->ofport[0]; > > > > > + if (ofport < 1 || ofport > ofp_to_u16(OFPP_MAX)) { > > > > > + continue; > > > > > + } > > > > > + > > > > > + bool is_patch = !strcmp(iface_rec->type, "patch"); > > > > > + if (is_patch && localnet) { > > > > > + simap_put(&nonvif_data->patch_ofports, localnet, > > ofport); > > > > > + break; > > > > > + } else if (is_patch && l2gateway) { > > > > > + /* L2 gateway patch ports can be handled just like > > VIFs. > > > > */ > > > > > + simap_put(&nonvif_data->patch_ofports, l2gateway, > > > > ofport); > > > > > + break; > > > > > + } else if (tunnel_id) { > > > > > + enum chassis_tunnel_type tunnel_type; > > > > > + if (!strcmp(iface_rec->type, "geneve")) { > > > > > + tunnel_type = GENEVE; > > > > > + } else if (!strcmp(iface_rec->type, "stt")) { > > > > > + tunnel_type = STT; > > > > > + } else if (!strcmp(iface_rec->type, "vxlan")) { > > > > > + tunnel_type = VXLAN; > > > > > + } else { > > > > > + continue; > > > > > + } > > > > > + > > > > > + /* We split the tunnel_id to get the chassis-id > > > > > + * and hash the tunnel list on the chassis-id. The > > > > > + * reason to use the chassis-id alone is because > > > > > + * there might be cases (multicast, gateway chassis) > > > > > + * where we need to tunnel to the chassis, but won't > > > > > + * have the encap-ip specifically. > > > > > + */ > > > > > + char *hash_id = NULL; > > > > > + char *ip = NULL; > > > > > + > > > > > + if (!encaps_tunnel_id_parse(tunnel_id, &hash_id, > > &ip)) { > > > > > + continue; > > > > > + } > > > > > + struct chassis_tunnel *tun = xmalloc(sizeof *tun); > > > > > + hmap_insert(&nonvif_data->chassis_tunnels, > > > > &tun->hmap_node, > > > > > + hash_string(hash_id, 0)); > > > > > + tun->chassis_id = xstrdup(tunnel_id); > > > > > + tun->ofport = u16_to_ofp(ofport); > > > > > + tun->type = tunnel_type; > > > > > + > > > > > + free(hash_id); > > > > > + free(ip); > > > > > + break; > > > > > + } > > > > > + } > > > > > + } > > > > > +} > > > > > + > > > > > +bool > > > > > +ldata_handle_ovs_iface_changes( > > > > > + const struct ovsrec_interface_table *iface_table) > > > > > +{ > > > > > + const struct ovsrec_interface *iface_rec; > > > > > + OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, iface_table) > > { > > > > > + if (!strcmp(iface_rec->type, "geneve") || > > > > > + !strcmp(iface_rec->type, "patch") || > > > > > + !strcmp(iface_rec->type, "vxlan") || > > > > > + !strcmp(iface_rec->type, "stt")) { > > > > > + return false; > > > > > + } > > > > > + } > > > > > + > > > > > + return true; > > > > > +} > > > > > + > > > > > +bool > > > > > +get_chassis_tunnel_ofport(const struct hmap *chassis_tunnels, > > > > > + const char *chassis_name, char *encap_ip, > > > > > + ofp_port_t *ofport) > > > > > +{ > > > > > + struct chassis_tunnel *tun = NULL; > > > > > + tun = chassis_tunnel_find(chassis_tunnels, chassis_name, > > encap_ip); > > > > > + if (!tun) { > > > > > + return false; > > > > > + } > > > > > + > > > > > + *ofport = tun->ofport; > > > > > + return true; > > > > > +} > > > > > + > > > > > +void > > > > > +local_nonvif_data_init(struct local_nonvif_data *nonvif_data) > > > > > +{ > > > > > + simap_init(&nonvif_data->patch_ofports); > > > > > + hmap_init(&nonvif_data->chassis_tunnels); > > > > > +} > > > > > + > > > > > +void > > > > > +local_nonvif_data_destroy(struct local_nonvif_data *nonvif_data) > > > > > +{ > > > > > + simap_destroy(&nonvif_data->patch_ofports); > > > > > + struct chassis_tunnel *tun; > > > > > + HMAP_FOR_EACH_POP (tun, hmap_node, > > &nonvif_data->chassis_tunnels) { > > > > > + free(tun->chassis_id); > > > > > + free(tun); > > > > > + } > > > > > + hmap_destroy(&nonvif_data->chassis_tunnels); > > > > > +} > > > > > + > > > > > + > > > > > +/* > > > > > + * This function looks up the list of tunnel ports (provided by > > > > > + * ovn-chassis-id ports) and returns the tunnel for the given > > chassid-id > > > > and > > > > > + * encap-ip. The ovn-chassis-id is formed using the chassis-id and > > > > encap-ip. > > > > > + * The list is hashed using the chassis-id. If the encap-ip is not > > > > specified, > > > > > + * it means we'll just return a tunnel for that chassis-id, i.e. we > > just > > > > check > > > > > + * for chassis-id and if there is a match, we'll return the tunnel. > > > > > + * If encap-ip is also provided we use both chassis-id and encap-ip > > to do > > > > > + * a more specific lookup. > > > > > + */ > > > > > +struct chassis_tunnel * > > > > > +chassis_tunnel_find(const struct hmap *chassis_tunnels, const char > > > > *chassis_id, > > > > > + char *encap_ip) > > > > > +{ > > > > > + /* > > > > > + * If the specific encap_ip is given, look for the chassisid_ip > > > > entry, > > > > > + * else return the 1st found entry for the chassis. > > > > > + */ > > > > > + struct chassis_tunnel *tun = NULL; > > > > > + HMAP_FOR_EACH_WITH_HASH (tun, hmap_node, hash_string(chassis_id, > > 0), > > > > > + chassis_tunnels) { > > > > > + if (encaps_tunnel_id_match(tun->chassis_id, chassis_id, > > > > encap_ip)) { > > > > > + return tun; > > > > > + } > > > > > + } > > > > > + return NULL; > > > > > +} > > > > > + > > > > > /* static functions. */ > > > > > static struct local_datapath * > > > > > local_datapath_add__(struct hmap *local_datapaths, > > > > > diff --git a/controller/ldata.h b/controller/ldata.h > > > > > index 16ad43c8f..91624d0b4 100644 > > > > > --- a/controller/ldata.h > > > > > +++ b/controller/ldata.h > > > > > @@ -19,10 +19,14 @@ > > > > > /* OVS includes. */ > > > > > #include "include/openvswitch/shash.h" > > > > > #include "lib/smap.h" > > > > > +#include "lib/simap.h" > > > > > > > > > > struct sbrec_datapath_binding; > > > > > struct sbrec_port_binding; > > > > > +struct sbrec_chassis; > > > > > struct ovsdb_idl_index; > > > > > +struct ovsrec_bridge; > > > > > +struct ovsrec_interface_table; > > > > > > > > > > /* A logical datapath that has some relevance to this hypervisor. A > > > > logical > > > > > * datapath D is relevant to hypervisor H if: > > > > > @@ -117,4 +121,44 @@ void tracked_datapath_lport_add(const struct > > > > sbrec_port_binding *, > > > > > struct hmap *tracked_datapaths); > > > > > void tracked_datapaths_destroy(struct hmap *tracked_datapaths); > > > > > > > > > > +/* Must be a bit-field ordered from most-preferred (higher number) to > > > > > + * least-preferred (lower number). */ > > > > > +enum chassis_tunnel_type { > > > > > + GENEVE = 1 << 2, > > > > > + STT = 1 << 1, > > > > > + VXLAN = 1 << 0 > > > > > +}; > > > > > + > > > > > +/* Maps from a chassis to the OpenFlow port number of the tunnel that > > > > can be > > > > > + * used to reach that chassis. */ > > > > > +struct chassis_tunnel { > > > > > + struct hmap_node hmap_node; > > > > > + char *chassis_id; > > > > > + ofp_port_t ofport; > > > > > + enum chassis_tunnel_type type; > > > > > +}; > > > > > + > > > > > +struct local_nonvif_data { > > > > > + struct simap patch_ofports; /* simap of patch ovs ports. */ > > > > > + struct hmap chassis_tunnels; /* hmap of 'struct chassis_tunnel' > > from > > > > the > > > > > + * tunnel OVS ports. */ > > > > > +}; > > > > > + > > > > > +void ldata_run(const struct ovsrec_bridge *br_int, > > > > > + const struct sbrec_chassis *, > > > > > + struct local_nonvif_data *nonvif_data); > > > > > + > > > > > +bool ldata_handle_ovs_iface_changes(const struct > > ovsrec_interface_table > > > > *); > > > > > + > > > > > +struct chassis_tunnel *chassis_tunnel_find(const struct hmap > > > > *chassis_tunnels, > > > > > + const char *chassis_id, > > > > > + char *encap_ip); > > > > > + > > > > > +bool get_chassis_tunnel_ofport(const struct hmap *chassis_tunnels, > > > > > + const char *chassis_name, char > > *encap_ip, > > > > > + ofp_port_t *ofport); > > > > > + > > > > > +void local_nonvif_data_init(struct local_nonvif_data *nonvif_data); > > > > > +void local_nonvif_data_destroy(struct local_nonvif_data > > *nonvif_data); > > > > > + > > > > > #endif /* controller/ldata.h */ > > > > > diff --git a/controller/lflow.c b/controller/lflow.c > > > > > index d1f32077b..4ac671e40 100644 > > > > > --- a/controller/lflow.c > > > > > +++ b/controller/lflow.c > > > > > @@ -58,6 +58,7 @@ struct lookup_port_aux { > > > > > const struct sbrec_datapath_binding *dp; > > > > > const struct sbrec_logical_flow *lflow; > > > > > struct lflow_resource_ref *lfrr; > > > > > + const struct hmap *chassis_tunnels; > > > > > }; > > > > > > > > > > struct condition_aux { > > > > > @@ -145,7 +146,8 @@ tunnel_ofport_cb(const void *aux_, const char > > > > *port_name, ofp_port_t *ofport) > > > > > return false; > > > > > } > > > > > > > > > > - if (!get_tunnel_ofport(pb->chassis->name, NULL, ofport)) { > > > > > + if (!get_chassis_tunnel_ofport(aux->chassis_tunnels, > > > > pb->chassis->name, > > > > > + NULL, ofport)) { > > > > > return false; > > > > > } > > > > > > > > > > @@ -591,6 +593,7 @@ add_matches_to_flow_table(const struct > > > > sbrec_logical_flow *lflow, > > > > > .dp = dp, > > > > > .lflow = lflow, > > > > > .lfrr = l_ctx_out->lfrr, > > > > > + .chassis_tunnels = l_ctx_in->chassis_tunnels, > > > > > }; > > > > > > > > > > /* Encode OVN logical actions into OpenFlow. */ > > > > > diff --git a/controller/lflow.h b/controller/lflow.h > > > > > index c17ff6dd4..e7dd31289 100644 > > > > > --- a/controller/lflow.h > > > > > +++ b/controller/lflow.h > > > > > @@ -146,6 +146,7 @@ struct lflow_ctx_in { > > > > > const struct shash *port_groups; > > > > > const struct sset *active_tunnels; > > > > > const struct sset *related_lport_ids; > > > > > + const struct hmap *chassis_tunnels; > > > > > }; > > > > > > > > > > struct lflow_ctx_out { > > > > > diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c > > > > > index 8f620e4ad..69d135046 100644 > > > > > --- a/controller/ovn-controller.c > > > > > +++ b/controller/ovn-controller.c > > > > > @@ -1039,6 +1039,11 @@ struct ed_type_runtime_data { > > > > > struct related_lports related_lports; > > > > > struct sset active_tunnels; > > > > > > > > > > + /* Non VIF OVS interface information (mainly patch OVS interfacs > > > > > + * and tunnel interfaces) that are relevant to the local > > > > > + * chassis (generated by ldata_run()). */ > > > > > + struct local_nonvif_data nonvif_data; > > > > > + > > > > I don't see a benefit of adding this to runtime_data. It is unrelated to > > > > the other data in the current runtime_data node. Now if we combine it to > > > > runtime_data, it means we are coupling those data unnecessarily, which > > > > leads to unflexible handler implementation. An example is that now > > > > recompute of nonvif_data would trigger recompute of runtime_data, which > > > > would trigger recompute of lflow_output. In fact, this can be just in a > > > > separate engine node, only as input to pflow_output. Would that be more > > > > straightforward and efficient? > > > > > > Hi Han, > > > > > > Thanks for the review comments. > > > > > > I see your point. I'll explore if we can add a new engine node for this. > > > > > > My understanding of engine processing is this and runtime data engine > > > in particular is this: > > > > > > 1. The first level of engine nodes would handle the db changes and > > > generates/transforms the data > > > which we can probably call - runtime_data. This was the > > > motivation for me to add the nonvif_data > > > in the runtime data engine. Perhaps we need to further divide > > > the runtime_data engine or rename it > > > so that we only store the VIF related data in this. > > > > Hi Numan, it seems we had different models for I-P engine nodes in our > > minds. Sorry that I didn't document these thoughts initially for the I-P > > engine. I don't think we should restrict the engine nodes in such layers. > > It should be flexible enough based on the real computation dependencies - > > just thinking about how DDlog programs would be written. I am not against > > the idea of a separate encapsulation layer for OVSDB IDL, but runtime_data > > was not for that purpose. Initially the I-P engine was very coarse grained, > > so I just created a big "runtime_data" node trying to contain all the > > intermediate data, just enough to support the first version of I-P for the > > most frequent changes. Now that we are making the I-P engine more and more > > fine-grained, we definitely cannot simply put everything in a single node. > > The current runtime_data may be renamed to binding_data, or be further > > split if necessary, and we don't need to put more data into it unless it is > > tightly related to the bindings handling. > > Thanks for the explanation. I'd agree renaming the current > runtime_data to binding_data. > > Probably a patch later for that. > > Since we are discussing I-P, I'd like to bring up another case. > > Presently we abort the engine if a recompute needs to be done but > recompute is not allowed > due to an sb txn is in progress or due to ofctrl_can_put() returns > false. We have engine nodes > like ct_zone which does not have handlers for many inputs and it has > to recompute. > And suppose if engine aborts due to the reason I mentioned, then in > the next engine run, we do > a full recomputation of all engine nodes whereas only recompute of > ct_zones (and perhaps pflow_output) > was required. In our scale testing we noticed that this recomputation > of all the engine nodes is costing > a bit. > Aha, I just debugged a problem and noticed a similar issue yesterday! It is on the same ct_zones node, but the trigger was not because of sb txn, but the ofctrl_can_put() == false (i.e. there are inflight messages). I think an easy solution is to apply the abort-if-recompute strategy only for certain nodes that either require high cost of recompute (i.e. lflow_output) or require DB txn. This way, recompute in ct_zones node should always be allowed and wouldn't abort and trigger next full recompute for the whole engine. A property can be added to engine_node for this purpose. > I think we should address this. And probably we can separate out db > transactions from the engine > and can be done separately. The binding module will not set > sbrec_port_binding_set_chassis() > for example. > This may be worth exploring, too. There may be benefits more than just the scenario above. However, it cannot solve the scenario I encountered yesterday, which was not triggered by the SB txn but in-flight OF messages. > Any thoughts on this ? > > Thanks > Numan > > > > > > 2. And the flow output engines ideally would use the runtime data for > > > flow generation. > > > > The output nodes should only depend on whatever data that is necessary for > > flow computation. What you said is true if "runtime data" here contains > > everything that is needed for flow computation, but it should never be a > > goal to keep all these data in a single I-P engine node, because that would > > not really benefit from the I-P engine. > > > > > 3. Ideally I'd think (or prefer) to engine nodes one or two level > > > down to not access any db changes at all. > > > For example, lfow_output or pflow_output engine handles should > > > not call IDL TRACKED loops. > > > > > > Maybe we could try to achieve follow up patches if that makes sense. > > > > > Encapsulating IDL to a separate layer may be reasonable, if it provides > > values, but I think it is another topic. I don't think it changes the I-P > > model. > > > > Thanks, > > Han > > > > > > > > > > > > > > > > > > As to the code organization, I think now I understand why you added the > > new > > > > module ldata.c (suppose it is going to be renamed to local_data.c to be > > > > more clear). Although it is not harmful to have that new module, it > > seems > > > > not quite necessary to me, either. The original localvif_to_ofport data > > is > > > > now split into two parts, VIF related and nonVIF related. I don't see > > > > benefit of keeping these two parts in the same file. It is reasonable to > > > > combine the VIF related data in runtime_data (which could be renamed, > > > > because the name was vague), to avoid maintaining redundant data. I > > think > > > > it is ok to stay in binding.c. For the nonVIF part, I think the new > > engine > > > > node can be defined in ovn-controller.c and implemented in physical.c > > > > because that data is used by physical flow processing only. I don't > > have a > > > > strong argument for this - maybe just less change is needed for this > > series > > > > (and so the change history would be easier to follow). > > > > > > I'll explore and see if this can be separated. Although I think > > > having a separate file local_data.c would uncomplicate the binding.c a > > > bit. > > > > > > > > > > > > > > > > > > > /* runtime data engine private data. */ > > > > > struct sset egress_ifaces; > > > > > struct smap local_iface_ids; > > > > > @@ -1139,6 +1144,7 @@ en_runtime_data_init(struct engine_node *node > > > > OVS_UNUSED, > > > > > local_binding_data_init(&data->lbinding_data); > > > > > shash_init(&data->local_active_ports_ipv6_pd); > > > > > shash_init(&data->local_active_ports_ras); > > > > > + local_nonvif_data_init(&data->nonvif_data); > > > > > > > > > > /* Init the tracked data. */ > > > > > hmap_init(&data->tracked_dp_bindings); > > > > > @@ -1160,6 +1166,7 @@ en_runtime_data_cleanup(void *data) > > > > > shash_destroy_free_data(&rt_data->local_active_ports_ipv6_pd); > > > > > shash_destroy_free_data(&rt_data->local_active_ports_ras); > > > > > local_binding_data_destroy(&rt_data->lbinding_data); > > > > > + local_nonvif_data_destroy(&rt_data->nonvif_data); > > > > > } > > > > > > > > > > static void > > > > > @@ -1272,6 +1279,7 @@ en_runtime_data_run(struct engine_node *node, > > void > > > > *data) > > > > > shash_clear_free_data(local_active_ipv6_pd); > > > > > shash_clear_free_data(local_active_ras); > > > > > local_binding_data_destroy(&rt_data->lbinding_data); > > > > > + local_nonvif_data_destroy(&rt_data->nonvif_data); > > > > > sset_destroy(local_lports); > > > > > related_lports_destroy(&rt_data->related_lports); > > > > > sset_destroy(active_tunnels); > > > > > @@ -1284,6 +1292,7 @@ en_runtime_data_run(struct engine_node *node, > > void > > > > *data) > > > > > sset_init(&rt_data->egress_ifaces); > > > > > smap_init(&rt_data->local_iface_ids); > > > > > local_binding_data_init(&rt_data->lbinding_data); > > > > > + local_nonvif_data_init(&rt_data->nonvif_data); > > > > > } > > > > > > > > > > struct binding_ctx_in b_ctx_in; > > > > > @@ -1303,6 +1312,7 @@ en_runtime_data_run(struct engine_node *node, > > void > > > > *data) > > > > > bfd_calculate_active_tunnels(b_ctx_in.br_int, > > active_tunnels); > > > > > } > > > > > > > > > > + ldata_run(b_ctx_in.br_int, b_ctx_in.chassis_rec, > > > > &rt_data->nonvif_data); > > > > > binding_run(&b_ctx_in, &b_ctx_out); > > > > > > > > > > engine_set_node_state(node, EN_UPDATED); > > > > > @@ -1318,6 +1328,10 @@ runtime_data_ovs_interface_handler(struct > > > > engine_node *node, void *data) > > > > > rt_data->tracked = true; > > > > > b_ctx_out.tracked_dp_bindings = &rt_data->tracked_dp_bindings; > > > > > > > > > > + if (!ldata_handle_ovs_iface_changes(b_ctx_in.iface_table)) { > > > > > + return false; > > > > > + } > > > > > + > > > > > > > > This is the performance problem I mentioned above. Before this change, > > > > tunnel/patch interface changes only triggered physical_run(), now it > > would > > > > trigger lflow_run(). > > > > > > Actually that's not the case. Any change to tunnel/patch OVS interfaces > > results > > > in the function binding_handle_ovs_interface_changes() to return false > > and hence > > > lflow_run() would be called - > > > https://github.com/ovn-org/ovn/blob/master/controller/binding.c#L2198 > > > > > > > > > > > > > > > > > > if (!binding_handle_ovs_interface_changes(&b_ctx_in, > > &b_ctx_out)) { > > > > > return false; > > > > > } > > > > > @@ -2060,6 +2074,7 @@ init_lflow_ctx(struct engine_node *node, > > > > > l_ctx_in->port_groups = port_groups; > > > > > l_ctx_in->active_tunnels = &rt_data->active_tunnels; > > > > > l_ctx_in->related_lport_ids = &rt_data->related_lports.lport_ids; > > > > > + l_ctx_in->chassis_tunnels = > > &rt_data->nonvif_data.chassis_tunnels; > > > > > > > > > > l_ctx_out->flow_table = &fo->flow_table; > > > > > l_ctx_out->group_table = &fo->group_table; > > > > > @@ -2527,6 +2542,7 @@ static void init_physical_ctx(struct engine_node > > > > *node, > > > > > p_ctx->ct_zones = ct_zones; > > > > > p_ctx->mff_ovn_geneve = ed_mff_ovn_geneve->mff_ovn_geneve; > > > > > p_ctx->local_bindings = &rt_data->lbinding_data.bindings; > > > > > + p_ctx->nonvif_data = &rt_data->nonvif_data; > > > > > } > > > > > > > > > > static void * > > > > > @@ -2583,7 +2599,11 @@ pflow_output_sb_port_binding_handler(struct > > > > engine_node *node, > > > > > * only. flow_output runtime data handler takes care of > > processing > > > > > * logical flows for any port binding changes. > > > > > */ > > > > > - physical_handle_port_binding_changes(&p_ctx, &pfo->flow_table); > > > > > + const struct sbrec_port_binding *pb; > > > > > + SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED (pb, > > > > p_ctx.port_binding_table) { > > > > > + bool removed = sbrec_port_binding_is_deleted(pb); > > > > > + physical_handle_flows_for_lport(pb, removed, &p_ctx, > > > > &pfo->flow_table); > > > > > + } > > > > > > > > nit: I think it is better to keep the interface > > > > physical_handle_port_binding_changes() and hide this loop details in the > > > > physical.c module. > > > > > > Ack. > > > > > > Thanks > > > Numan > > > > > > > > > > > Thanks, > > > > Han > > > > > > > > > > > > > > engine_set_node_state(node, EN_UPDATED); > > > > > return true; > > > > > @@ -2613,13 +2633,55 @@ pflow_output_ovs_iface_handler(struct > > engine_node > > > > *node OVS_UNUSED, > > > > > struct ed_type_runtime_data *rt_data = > > > > > engine_get_input_data("runtime_data", node); > > > > > > > > > > + struct physical_ctx p_ctx; > > > > > + init_physical_ctx(node, rt_data, &p_ctx); > > > > > + > > > > > + engine_set_node_state(node, EN_UPDATED); > > > > > + return physical_handle_ovs_iface_changes(&p_ctx); > > > > > +} > > > > > + > > > > > +static bool > > > > > +pflow_output_runtime_data_handler(struct engine_node *node, void > > *data) > > > > > +{ > > > > > + struct ed_type_runtime_data *rt_data = > > > > > + engine_get_input_data("runtime_data", node); > > > > > + > > > > > + /* There is no tracked data. Fall back to full recompute of > > > > > + * pflow_output. */ > > > > > + if (!rt_data->tracked) { > > > > > + return false; > > > > > + } > > > > > + > > > > > + struct hmap *tracked_dp_bindings = &rt_data->tracked_dp_bindings; > > > > > + if (hmap_is_empty(tracked_dp_bindings)) { > > > > > + return true; > > > > > + } > > > > > + > > > > > struct ed_type_pflow_output *pfo = data; > > > > > > > > > > struct physical_ctx p_ctx; > > > > > init_physical_ctx(node, rt_data, &p_ctx); > > > > > > > > > > + struct tracked_datapath *tdp; > > > > > + HMAP_FOR_EACH (tdp, node, tracked_dp_bindings) { > > > > > + if (tdp->tracked_type != TRACKED_RESOURCE_UPDATED) { > > > > > + /* Fall back to full recompute when a local datapath > > > > > + * is added or deleted. */ > > > > > + return false; > > > > > + } > > > > > + > > > > > + struct shash_node *shash_node; > > > > > + SHASH_FOR_EACH (shash_node, &tdp->lports) { > > > > > + struct tracked_lport *lport = shash_node->data; > > > > > + bool removed = > > > > > + lport->tracked_type == TRACKED_RESOURCE_REMOVED ? > > true: > > > > false; > > > > > + physical_handle_flows_for_lport(lport->pb, removed, > > &p_ctx, > > > > > + &pfo->flow_table); > > > > > + } > > > > > + } > > > > > + > > > > > engine_set_node_state(node, EN_UPDATED); > > > > > - return physical_handle_ovs_iface_changes(&p_ctx, > > &pfo->flow_table); > > > > > + return true; > > > > > } > > > > > > > > > > static void * > > > > > @@ -2914,7 +2976,7 @@ main(int argc, char *argv[]) > > > > > pflow_output_sb_multicast_group_handler); > > > > > > > > > > engine_add_input(&en_pflow_output, &en_runtime_data, > > > > > - NULL); > > > > > + pflow_output_runtime_data_handler); > > > > > engine_add_input(&en_pflow_output, &en_sb_encap, NULL); > > > > > engine_add_input(&en_pflow_output, &en_mff_ovn_geneve, NULL); > > > > > engine_add_input(&en_pflow_output, &en_ovs_open_vswitch, NULL); > > > > > diff --git a/controller/ovn-controller.h b/controller/ovn-controller.h > > > > > index 578588305..78a53312f 100644 > > > > > --- a/controller/ovn-controller.h > > > > > +++ b/controller/ovn-controller.h > > > > > @@ -45,14 +45,6 @@ const struct ovsrec_bridge *get_bridge(const struct > > > > ovsrec_bridge_table *, > > > > > > > > > > struct sbrec_encap *preferred_encap(const struct sbrec_chassis *); > > > > > > > > > > -/* Must be a bit-field ordered from most-preferred (higher number) to > > > > > - * least-preferred (lower number). */ > > > > > -enum chassis_tunnel_type { > > > > > - GENEVE = 1 << 2, > > > > > - STT = 1 << 1, > > > > > - VXLAN = 1 << 0 > > > > > -}; > > > > > - > > > > > uint32_t get_tunnel_type(const char *name); > > > > > > > > > > struct pb_ld_binding { > > > > > diff --git a/controller/physical.c b/controller/physical.c > > > > > index b244ff1c2..87080d001 100644 > > > > > --- a/controller/physical.c > > > > > +++ b/controller/physical.c > > > > > @@ -86,46 +86,6 @@ physical_register_ovs_idl(struct ovsdb_idl > > *ovs_idl) > > > > > ovsdb_idl_track_add_column(ovs_idl, > > > > &ovsrec_interface_col_external_ids); > > > > > } > > > > > > > > > > -static struct simap localvif_to_ofport = > > > > > - SIMAP_INITIALIZER(&localvif_to_ofport); > > > > > -static struct hmap tunnels = HMAP_INITIALIZER(&tunnels); > > > > > - > > > > > -/* Maps from a chassis to the OpenFlow port number of the tunnel that > > > > can be > > > > > - * used to reach that chassis. */ > > > > > -struct chassis_tunnel { > > > > > - struct hmap_node hmap_node; > > > > > - char *chassis_id; > > > > > - ofp_port_t ofport; > > > > > - enum chassis_tunnel_type type; > > > > > -}; > > > > > - > > > > > -/* > > > > > - * This function looks up the list of tunnel ports (provided by > > > > > - * ovn-chassis-id ports) and returns the tunnel for the given > > chassid-id > > > > and > > > > > - * encap-ip. The ovn-chassis-id is formed using the chassis-id and > > > > encap-ip. > > > > > - * The list is hashed using the chassis-id. If the encap-ip is not > > > > specified, > > > > > - * it means we'll just return a tunnel for that chassis-id, i.e. we > > just > > > > check > > > > > - * for chassis-id and if there is a match, we'll return the tunnel. > > > > > - * If encap-ip is also provided we use both chassis-id and encap-ip > > to do > > > > > - * a more specific lookup. > > > > > - */ > > > > > -static struct chassis_tunnel * > > > > > -chassis_tunnel_find(const char *chassis_id, char *encap_ip) > > > > > -{ > > > > > - /* > > > > > - * If the specific encap_ip is given, look for the chassisid_ip > > > > entry, > > > > > - * else return the 1st found entry for the chassis. > > > > > - */ > > > > > - struct chassis_tunnel *tun = NULL; > > > > > - HMAP_FOR_EACH_WITH_HASH (tun, hmap_node, hash_string(chassis_id, > > 0), > > > > > - &tunnels) { > > > > > - if (encaps_tunnel_id_match(tun->chassis_id, chassis_id, > > > > encap_ip)) { > > > > > - return tun; > > > > > - } > > > > > - } > > > > > - return NULL; > > > > > -} > > > > > - > > > > > static void > > > > > put_load(uint64_t value, enum mf_field_id dst, int ofs, int n_bits, > > > > > struct ofpbuf *ofpacts) > > > > > @@ -166,17 +126,18 @@ put_resubmit(uint8_t table_id, struct ofpbuf > > > > *ofpacts) > > > > > * from the associated encap. > > > > > */ > > > > > static struct chassis_tunnel * > > > > > -get_port_binding_tun(const struct sbrec_port_binding *binding) > > > > > +get_port_binding_tun(const struct sbrec_port_binding *binding, > > > > > + const struct hmap *chassis_tunnels) > > > > > { > > > > > struct sbrec_encap *encap = binding->encap; > > > > > struct sbrec_chassis *chassis = binding->chassis; > > > > > struct chassis_tunnel *tun = NULL; > > > > > > > > > > if (encap) { > > > > > - tun = chassis_tunnel_find(chassis->name, encap->ip); > > > > > + tun = chassis_tunnel_find(chassis_tunnels, chassis->name, > > > > encap->ip); > > > > > } > > > > > if (!tun) { > > > > > - tun = chassis_tunnel_find(chassis->name, NULL); > > > > > + tun = chassis_tunnel_find(chassis_tunnels, chassis->name, > > NULL); > > > > > } > > > > > return tun; > > > > > } > > > > > @@ -325,12 +286,13 @@ put_remote_port_redirect_overlay(const struct > > > > > uint32_t port_key, > > > > > struct match *match, > > > > > struct ofpbuf *ofpacts_p, > > > > > + const struct hmap *chassis_tunnels, > > > > > struct ovn_desired_flow_table > > > > *flow_table) > > > > > { > > > > > if (!is_ha_remote) { > > > > > /* Setup encapsulation */ > > > > > const struct chassis_tunnel *rem_tun = > > > > > - get_port_binding_tun(binding); > > > > > + get_port_binding_tun(binding, chassis_tunnels); > > > > > if (!rem_tun) { > > > > > return; > > > > > } > > > > > @@ -348,10 +310,10 @@ put_remote_port_redirect_overlay(const struct > > > > > continue; > > > > > } > > > > > if (!tun) { > > > > > - tun = chassis_tunnel_find(ch->name, NULL); > > > > > + tun = chassis_tunnel_find(chassis_tunnels, ch->name, > > > > NULL); > > > > > } else { > > > > > struct chassis_tunnel *chassis_tunnel = > > > > > - chassis_tunnel_find(ch->name, > > > > NULL); > > > > > + chassis_tunnel_find(chassis_tunnels, ch->name, > > NULL); > > > > > if (chassis_tunnel && > > > > > tun->type != chassis_tunnel->type) { > > > > > static struct vlog_rate_limit rl = > > > > > @@ -385,7 +347,7 @@ put_remote_port_redirect_overlay(const struct > > > > > if (!ch) { > > > > > continue; > > > > > } > > > > > - tun = chassis_tunnel_find(ch->name, NULL); > > > > > + tun = chassis_tunnel_find(chassis_tunnels, ch->name, > > NULL); > > > > > if (!tun) { > > > > > continue; > > > > > } > > > > > @@ -925,6 +887,9 @@ consider_port_binding(struct ovsdb_idl_index > > > > *sbrec_port_binding_by_name, > > > > > const struct simap *ct_zones, > > > > > const struct sset *active_tunnels, > > > > > const struct hmap *local_datapaths, > > > > > + const struct shash *local_bindings, > > > > > + const struct simap *patch_ofports, > > > > > + const struct hmap *chassis_tunnels, > > > > > const struct sbrec_port_binding *binding, > > > > > const struct sbrec_chassis *chassis, > > > > > struct ovn_desired_flow_table *flow_table, > > > > > @@ -1081,17 +1046,25 @@ consider_port_binding(struct ovsdb_idl_index > > > > *sbrec_port_binding_by_name, > > > > > if (!binding->tag) { > > > > > goto out; > > > > > } > > > > > - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, > > > > > - binding->parent_port)); > > > > > + ofport = local_binding_get_lport_ofport(local_bindings, > > > > > + > > binding->parent_port); > > > > > if (ofport) { > > > > > tag = *binding->tag; > > > > > nested_container = true; > > > > > parent_port = lport_lookup_by_name( > > > > > sbrec_port_binding_by_name, binding->parent_port); > > > > > } > > > > > - } else { > > > > > - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, > > > > > + } else if (!strcmp(binding->type, "localnet") > > > > > + || !strcmp(binding->type, "l2gateway")) { > > > > > + > > > > > + ofport = u16_to_ofp(simap_get(patch_ofports, > > > > > binding->logical_port)); > > > > > + if (ofport && binding->tag) { > > > > > + tag = *binding->tag; > > > > > + } > > > > > + } else { > > > > > + ofport = local_binding_get_lport_ofport(local_bindings, > > > > > + > > binding->logical_port); > > > > > const char *requested_chassis = smap_get(&binding->options, > > > > > > > "requested-chassis"); > > > > > if (ofport && requested_chassis && requested_chassis[0] && > > > > > @@ -1102,12 +1075,6 @@ consider_port_binding(struct ovsdb_idl_index > > > > *sbrec_port_binding_by_name, > > > > > */ > > > > > ofport = 0; > > > > > } > > > > > - > > > > > - if ((!strcmp(binding->type, "localnet") > > > > > - || !strcmp(binding->type, "l2gateway")) > > > > > - && ofport && binding->tag) { > > > > > - tag = *binding->tag; > > > > > - } > > > > > } > > > > > > > > > > bool is_ha_remote = false; > > > > > @@ -1118,7 +1085,7 @@ consider_port_binding(struct ovsdb_idl_index > > > > *sbrec_port_binding_by_name, > > > > > /* It is remote port, may be reached by tunnel or localnet > > port > > > > */ > > > > > is_remote = true; > > > > > if (localnet_port) { > > > > > - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, > > > > > + ofport = u16_to_ofp(simap_get(patch_ofports, > > > > > > > localnet_port->logical_port)); > > > > > if (!ofport) { > > > > > goto out; > > > > > @@ -1129,7 +1096,8 @@ consider_port_binding(struct ovsdb_idl_index > > > > *sbrec_port_binding_by_name, > > > > > if (!binding->chassis) { > > > > > goto out; > > > > > } > > > > > - tun = chassis_tunnel_find(binding->chassis->name, > > NULL); > > > > > + tun = chassis_tunnel_find(chassis_tunnels, > > > > > + binding->chassis->name, > > NULL); > > > > > if (!tun) { > > > > > goto out; > > > > > } > > > > > @@ -1383,7 +1351,7 @@ consider_port_binding(struct ovsdb_idl_index > > > > *sbrec_port_binding_by_name, > > > > > put_remote_port_redirect_overlay(binding, is_ha_remote, > > > > > ha_ch_ordered, > > > > mff_ovn_geneve, > > > > > tun, port_key, &match, > > > > ofpacts_p, > > > > > - flow_table); > > > > > + chassis_tunnels, > > > > flow_table); > > > > > } > > > > > } > > > > > out: > > > > > @@ -1396,8 +1364,11 @@ static void > > > > > consider_mc_group(enum mf_field_id mff_ovn_geneve, > > > > > const struct simap *ct_zones, > > > > > const struct hmap *local_datapaths, > > > > > + struct shash *local_bindings, > > > > > + struct simap *patch_ofports, > > > > > const struct sbrec_chassis *chassis, > > > > > const struct sbrec_multicast_group *mc, > > > > > + const struct hmap *chassis_tunnels, > > > > > struct ovn_desired_flow_table *flow_table) > > > > > { > > > > > uint32_t dp_key = mc->datapath->tunnel_key; > > > > > @@ -1444,19 +1415,21 @@ consider_mc_group(enum mf_field_id > > mff_ovn_geneve, > > > > > put_load(zone_id, MFF_LOG_CT_ZONE, 0, 32, &ofpacts); > > > > > } > > > > > > > > > > + const char *lport_name = (port->parent_port && > > > > *port->parent_port) ? > > > > > + port->parent_port : > > port->logical_port; > > > > > + > > > > > if (!strcmp(port->type, "patch")) { > > > > > put_load(port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, > > > > > &remote_ofpacts); > > > > > put_resubmit(OFTABLE_CHECK_LOOPBACK, &remote_ofpacts); > > > > > - } else if (simap_contains(&localvif_to_ofport, > > > > > - (port->parent_port && *port->parent_port) > > > > > - ? port->parent_port : port->logical_port) > > > > > + } else if (local_binding_get_primary_pb(local_bindings, > > > > lport_name) > > > > > + || simap_contains(patch_ofports, > > port->logical_port) > > > > > || (!strcmp(port->type, "l3gateway") > > > > > && port->chassis == chassis)) { > > > > > put_load(port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, > > &ofpacts); > > > > > put_resubmit(OFTABLE_CHECK_LOOPBACK, &ofpacts); > > > > > - } else if (port->chassis && > > !get_localnet_port(local_datapaths, > > > > > - mc->datapath->tunnel_key)) { > > > > > + } else if (port->chassis && !get_localnet_port( > > > > > + local_datapaths, mc->datapath->tunnel_key)) { > > > > > /* Add remote chassis only when localnet port not exist, > > > > > * otherwise multicast will reach remote ports through > > > > localnet > > > > > * port. */ > > > > > @@ -1497,7 +1470,7 @@ consider_mc_group(enum mf_field_id > > mff_ovn_geneve, > > > > > const struct chassis_tunnel *prev = NULL; > > > > > SSET_FOR_EACH (chassis_name, &remote_chassis) { > > > > > const struct chassis_tunnel *tun > > > > > - = chassis_tunnel_find(chassis_name, NULL); > > > > > + = chassis_tunnel_find(chassis_tunnels, chassis_name, > > > > NULL); > > > > > if (!tun) { > > > > > continue; > > > > > } > > > > > @@ -1524,41 +1497,50 @@ consider_mc_group(enum mf_field_id > > mff_ovn_geneve, > > > > > sset_destroy(&remote_chassis); > > > > > } > > > > > > > > > > -/* Replaces 'old' by 'new' (destroying 'new'). Returns true if 'old' > > > > and 'new' > > > > > - * contained different data, false if they were the same. */ > > > > > -static bool > > > > > -update_ofports(struct simap *old, struct simap *new) > > > > > -{ > > > > > - bool changed = !simap_equal(old, new); > > > > > - simap_swap(old, new); > > > > > - simap_destroy(new); > > > > > - return changed; > > > > > -} > > > > > - > > > > > void > > > > > -physical_handle_port_binding_changes(struct physical_ctx *p_ctx, > > > > > - struct ovn_desired_flow_table > > > > *flow_table) > > > > > +physical_handle_flows_for_lport(const struct sbrec_port_binding *pb, > > > > > + bool removed, struct physical_ctx > > *p_ctx, > > > > > + struct ovn_desired_flow_table > > > > *flow_table) > > > > > { > > > > > - const struct sbrec_port_binding *binding; > > > > > - struct ofpbuf ofpacts; > > > > > - ofpbuf_init(&ofpacts, 0); > > > > > - SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED (binding, > > > > > - > > > > p_ctx->port_binding_table) { > > > > > - if (sbrec_port_binding_is_deleted(binding)) { > > > > > - ofctrl_remove_flows(flow_table, &binding->header_.uuid); > > > > > - } else { > > > > > - if (!sbrec_port_binding_is_new(binding)) { > > > > > - ofctrl_remove_flows(flow_table, > > &binding->header_.uuid); > > > > > - } > > > > > + ofctrl_remove_flows(flow_table, &pb->header_.uuid); > > > > > + > > > > > + if (!strcmp(pb->type, "external")) { > > > > > + /* External lports have a dependency on the localnet port. > > > > > + * We need to remove the flows of the localnet port as well > > > > > + * and re-consider adding the flows for it. > > > > > + */ > > > > > + struct local_datapath *ldp = > > > > > + get_local_datapath(p_ctx->local_datapaths, > > > > > + pb->datapath->tunnel_key); > > > > > + if (ldp && ldp->localnet_port) { > > > > > + struct ofpbuf ofpacts; > > > > > + ofctrl_remove_flows(flow_table, > > > > &ldp->localnet_port->header_.uuid); > > > > > + ofpbuf_init(&ofpacts, 0); > > > > > consider_port_binding(p_ctx->sbrec_port_binding_by_name, > > > > > p_ctx->mff_ovn_geneve, > > p_ctx->ct_zones, > > > > > p_ctx->active_tunnels, > > > > > p_ctx->local_datapaths, > > > > > - binding, p_ctx->chassis, > > > > > + p_ctx->local_bindings, > > > > > + &p_ctx->nonvif_data->patch_ofports, > > > > > + > > &p_ctx->nonvif_data->chassis_tunnels, > > > > > + ldp->localnet_port, p_ctx->chassis, > > > > > flow_table, &ofpacts); > > > > > + ofpbuf_uninit(&ofpacts); > > > > > } > > > > > } > > > > > - ofpbuf_uninit(&ofpacts); > > > > > + > > > > > + if (!removed) { > > > > > + struct ofpbuf ofpacts; > > > > > + ofpbuf_init(&ofpacts, 0); > > > > > + consider_port_binding(p_ctx->sbrec_port_binding_by_name, > > > > > + p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > > > > > + p_ctx->active_tunnels, > > > > p_ctx->local_datapaths, > > > > > + p_ctx->local_bindings, > > > > > + &p_ctx->nonvif_data->patch_ofports, > > > > > + &p_ctx->nonvif_data->chassis_tunnels, > > pb, > > > > > + p_ctx->chassis, flow_table, &ofpacts); > > > > > + ofpbuf_uninit(&ofpacts); > > > > > + } > > > > > } > > > > > > > > > > void > > > > > @@ -1574,8 +1556,11 @@ physical_handle_mc_group_changes(struct > > > > physical_ctx *p_ctx, > > > > > ofctrl_remove_flows(flow_table, &mc->header_.uuid); > > > > > } > > > > > consider_mc_group(p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > > > > > - p_ctx->local_datapaths, > > > > > - p_ctx->chassis, mc, flow_table); > > > > > + p_ctx->local_datapaths, > > > > p_ctx->local_bindings, > > > > > + &p_ctx->nonvif_data->patch_ofports, > > > > > + p_ctx->chassis, mc, > > > > > + &p_ctx->nonvif_data->chassis_tunnels, > > > > > + flow_table); > > > > > } > > > > > } > > > > > } > > > > > @@ -1591,135 +1576,6 @@ physical_run(struct physical_ctx *p_ctx, > > > > > uuid_generate(hc_uuid); > > > > > } > > > > > > > > > > - /* This bool tracks physical mapping changes. */ > > > > > - bool physical_map_changed = false; > > > > > - > > > > > - struct simap new_localvif_to_ofport = > > > > > - SIMAP_INITIALIZER(&new_localvif_to_ofport); > > > > > - struct simap new_tunnel_to_ofport = > > > > > - SIMAP_INITIALIZER(&new_tunnel_to_ofport); > > > > > - for (int i = 0; i < p_ctx->br_int->n_ports; i++) { > > > > > - const struct ovsrec_port *port_rec = p_ctx->br_int->ports[i]; > > > > > - if (!strcmp(port_rec->name, p_ctx->br_int->name)) { > > > > > - continue; > > > > > - } > > > > > - > > > > > - const char *tunnel_id = smap_get(&port_rec->external_ids, > > > > > - "ovn-chassis-id"); > > > > > - if (tunnel_id && encaps_tunnel_id_match(tunnel_id, > > > > > - p_ctx->chassis->name, > > > > > - NULL)) { > > > > > - continue; > > > > > - } > > > > > - > > > > > - const char *localnet = smap_get(&port_rec->external_ids, > > > > > - "ovn-localnet-port"); > > > > > - const char *l2gateway = smap_get(&port_rec->external_ids, > > > > > - "ovn-l2gateway-port"); > > > > > - > > > > > - for (int j = 0; j < port_rec->n_interfaces; j++) { > > > > > - const struct ovsrec_interface *iface_rec = > > > > port_rec->interfaces[j]; > > > > > - > > > > > - /* Get OpenFlow port number. */ > > > > > - if (!iface_rec->n_ofport) { > > > > > - continue; > > > > > - } > > > > > - int64_t ofport = iface_rec->ofport[0]; > > > > > - if (ofport < 1 || ofport > ofp_to_u16(OFPP_MAX)) { > > > > > - continue; > > > > > - } > > > > > - > > > > > - /* Record as patch to local net, logical patch port, > > > > chassis, or > > > > > - * local logical port. */ > > > > > - bool is_patch = !strcmp(iface_rec->type, "patch"); > > > > > - if (is_patch && localnet) { > > > > > - /* localnet patch ports can be handled just like > > VIFs. */ > > > > > - simap_put(&new_localvif_to_ofport, localnet, ofport); > > > > > - break; > > > > > - } else if (is_patch && l2gateway) { > > > > > - /* L2 gateway patch ports can be handled just like > > VIFs. > > > > */ > > > > > - simap_put(&new_localvif_to_ofport, l2gateway, > > ofport); > > > > > - break; > > > > > - } else if (tunnel_id) { > > > > > - enum chassis_tunnel_type tunnel_type; > > > > > - if (!strcmp(iface_rec->type, "geneve")) { > > > > > - tunnel_type = GENEVE; > > > > > - if (!p_ctx->mff_ovn_geneve) { > > > > > - continue; > > > > > - } > > > > > - } else if (!strcmp(iface_rec->type, "stt")) { > > > > > - tunnel_type = STT; > > > > > - } else if (!strcmp(iface_rec->type, "vxlan")) { > > > > > - tunnel_type = VXLAN; > > > > > - } else { > > > > > - continue; > > > > > - } > > > > > - > > > > > - simap_put(&new_tunnel_to_ofport, tunnel_id, ofport); > > > > > - /* > > > > > - * We split the tunnel_id to get the chassis-id > > > > > - * and hash the tunnel list on the chassis-id. The > > > > > - * reason to use the chassis-id alone is because > > > > > - * there might be cases (multicast, gateway chassis) > > > > > - * where we need to tunnel to the chassis, but won't > > > > > - * have the encap-ip specifically. > > > > > - */ > > > > > - char *hash_id = NULL; > > > > > - char *ip = NULL; > > > > > - > > > > > - if (!encaps_tunnel_id_parse(tunnel_id, &hash_id, > > &ip)) { > > > > > - continue; > > > > > - } > > > > > - struct chassis_tunnel *tun = > > > > chassis_tunnel_find(hash_id, ip); > > > > > - if (tun) { > > > > > - /* If the tunnel's ofport has changed, update. */ > > > > > - if (tun->ofport != u16_to_ofp(ofport) || > > > > > - tun->type != tunnel_type) { > > > > > - tun->ofport = u16_to_ofp(ofport); > > > > > - tun->type = tunnel_type; > > > > > - physical_map_changed = true; > > > > > - } > > > > > - } else { > > > > > - tun = xmalloc(sizeof *tun); > > > > > - hmap_insert(&tunnels, &tun->hmap_node, > > > > > - hash_string(hash_id, 0)); > > > > > - tun->chassis_id = xstrdup(tunnel_id); > > > > > - tun->ofport = u16_to_ofp(ofport); > > > > > - tun->type = tunnel_type; > > > > > - physical_map_changed = true; > > > > > - } > > > > > - free(hash_id); > > > > > - free(ip); > > > > > - break; > > > > > - } else { > > > > > - const char *iface_id = > > smap_get(&iface_rec->external_ids, > > > > > - "iface-id"); > > > > > - if (iface_id) { > > > > > - simap_put(&new_localvif_to_ofport, iface_id, > > ofport); > > > > > - } > > > > > - } > > > > > - } > > > > > - } > > > > > - > > > > > - /* Remove tunnels that are no longer here. */ > > > > > - struct chassis_tunnel *tun, *tun_next; > > > > > - HMAP_FOR_EACH_SAFE (tun, tun_next, hmap_node, &tunnels) { > > > > > - if (!simap_find(&new_tunnel_to_ofport, tun->chassis_id)) { > > > > > - hmap_remove(&tunnels, &tun->hmap_node); > > > > > - physical_map_changed = true; > > > > > - free(tun->chassis_id); > > > > > - free(tun); > > > > > - } > > > > > - } > > > > > - > > > > > - /* Capture changed or removed openflow ports. */ > > > > > - physical_map_changed |= update_ofports(&localvif_to_ofport, > > > > > - &new_localvif_to_ofport); > > > > > - if (physical_map_changed) { > > > > > - /* Reprocess logical flow table immediately. */ > > > > > - poll_immediate_wake(); > > > > > - } > > > > > - > > > > > struct ofpbuf ofpacts; > > > > > ofpbuf_init(&ofpacts, 0); > > > > > > > > > > @@ -1733,16 +1589,20 @@ physical_run(struct physical_ctx *p_ctx, > > > > > consider_port_binding(p_ctx->sbrec_port_binding_by_name, > > > > > p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > > > > > p_ctx->active_tunnels, > > > > p_ctx->local_datapaths, > > > > > - binding, p_ctx->chassis, > > > > > - flow_table, &ofpacts); > > > > > + p_ctx->local_bindings, > > > > > + &p_ctx->nonvif_data->patch_ofports, > > > > > + &p_ctx->nonvif_data->chassis_tunnels, > > > > binding, > > > > > + p_ctx->chassis, flow_table, &ofpacts); > > > > > } > > > > > > > > > > /* Handle output to multicast groups, in tables 32 and 33. */ > > > > > const struct sbrec_multicast_group *mc; > > > > > SBREC_MULTICAST_GROUP_TABLE_FOR_EACH (mc, p_ctx->mc_group_table) > > { > > > > > consider_mc_group(p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > > > > > - p_ctx->local_datapaths, p_ctx->chassis, > > > > > - mc, flow_table); > > > > > + p_ctx->local_datapaths, > > p_ctx->local_bindings, > > > > > + &p_ctx->nonvif_data->patch_ofports, > > > > p_ctx->chassis, > > > > > + mc, &p_ctx->nonvif_data->chassis_tunnels, > > > > > + flow_table); > > > > > } > > > > > > > > > > /* Table 0, priority 100. > > > > > @@ -1757,7 +1617,8 @@ physical_run(struct physical_ctx *p_ctx, > > > > > * We set MFF_LOG_DATAPATH, MFF_LOG_INPORT, and MFF_LOG_OUTPORT > > from > > > > the > > > > > * tunnel key data where possible, then resubmit to table 33 to > > > > handle > > > > > * packets to the local hypervisor. */ > > > > > - HMAP_FOR_EACH (tun, hmap_node, &tunnels) { > > > > > + struct chassis_tunnel *tun; > > > > > + HMAP_FOR_EACH (tun, hmap_node, > > &p_ctx->nonvif_data->chassis_tunnels) > > > > { > > > > > struct match match = MATCH_CATCHALL_INITIALIZER; > > > > > match_set_in_port(&match, tun->ofport); > > > > > > > > > > @@ -1788,7 +1649,7 @@ physical_run(struct physical_ctx *p_ctx, > > > > > } > > > > > > > > > > /* Handle ramp switch encapsulations. */ > > > > > - HMAP_FOR_EACH (tun, hmap_node, &tunnels) { > > > > > + HMAP_FOR_EACH (tun, hmap_node, > > &p_ctx->nonvif_data->chassis_tunnels) > > > > { > > > > > if (tun->type != VXLAN) { > > > > > continue; > > > > > } > > > > > @@ -1925,13 +1786,10 @@ physical_run(struct physical_ctx *p_ctx, > > > > > &ofpacts, hc_uuid); > > > > > > > > > > ofpbuf_uninit(&ofpacts); > > > > > - > > > > > - simap_destroy(&new_tunnel_to_ofport); > > > > > } > > > > > > > > > > bool > > > > > -physical_handle_ovs_iface_changes(struct physical_ctx *p_ctx, > > > > > - struct ovn_desired_flow_table > > > > *flow_table) > > > > > +physical_handle_ovs_iface_changes(struct physical_ctx *p_ctx) > > > > > { > > > > > const struct ovsrec_interface *iface_rec; > > > > > OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, > > > > p_ctx->iface_table) { > > > > > @@ -1943,64 +1801,6 @@ physical_handle_ovs_iface_changes(struct > > > > physical_ctx *p_ctx, > > > > > } > > > > > } > > > > > > > > > > - struct ofpbuf ofpacts; > > > > > - ofpbuf_init(&ofpacts, 0); > > > > > - > > > > > - OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, > > > > p_ctx->iface_table) { > > > > > - const char *iface_id = smap_get(&iface_rec->external_ids, > > > > "iface-id"); > > > > > - if (!iface_id) { > > > > > - continue; > > > > > - } > > > > > - > > > > > - const struct sbrec_port_binding *lb_pb = > > > > > - local_binding_get_primary_pb(p_ctx->local_bindings, > > > > iface_id); > > > > > - if (!lb_pb) { > > > > > - /* For regular VIFs (e.g. lsp) the upcoming port-binding > > > > update > > > > > - * will remove lfows related to the unclaimed ovs port. > > > > > - * Localport is a special case and it needs to be managed > > > > here > > > > > - * since the port is not binded and otherwise the related > > > > lfows > > > > > - * will not be cleared removing the ovs port. > > > > > - */ > > > > > - lb_pb = > > > > lport_lookup_by_name(p_ctx->sbrec_port_binding_by_name, > > > > > - iface_id); > > > > > - if (!lb_pb || strcmp(lb_pb->type, "localport")) { > > > > > - continue; > > > > > - } > > > > > - } > > > > > - > > > > > - int64_t ofport = iface_rec->n_ofport ? *iface_rec->ofport : > > 0; > > > > > - if (ovsrec_interface_is_deleted(iface_rec)) { > > > > > - ofctrl_remove_flows(flow_table, &lb_pb->header_.uuid); > > > > > - simap_find_and_delete(&localvif_to_ofport, iface_id); > > > > > - } else { > > > > > - if (!ovsrec_interface_is_new(iface_rec)) { > > > > > - ofctrl_remove_flows(flow_table, > > &lb_pb->header_.uuid); > > > > > - } > > > > > - > > > > > - simap_put(&localvif_to_ofport, iface_id, ofport); > > > > > - consider_port_binding(p_ctx->sbrec_port_binding_by_name, > > > > > - p_ctx->mff_ovn_geneve, > > p_ctx->ct_zones, > > > > > - p_ctx->active_tunnels, > > > > > - p_ctx->local_datapaths, > > > > > - lb_pb, p_ctx->chassis, > > > > > - flow_table, &ofpacts); > > > > > - } > > > > > - } > > > > > - > > > > > - ofpbuf_uninit(&ofpacts); > > > > > - return true; > > > > > -} > > > > > - > > > > > -bool > > > > > -get_tunnel_ofport(const char *chassis_name, char *encap_ip, > > ofp_port_t > > > > *ofport) > > > > > -{ > > > > > - struct chassis_tunnel *tun = NULL; > > > > > - tun = chassis_tunnel_find(chassis_name, encap_ip); > > > > > - if (!tun) { > > > > > - return false; > > > > > - } > > > > > - > > > > > - *ofport = tun->ofport; > > > > > return true; > > > > > } > > > > > > > > > > diff --git a/controller/physical.h b/controller/physical.h > > > > > index feab41df4..3fdc20005 100644 > > > > > --- a/controller/physical.h > > > > > +++ b/controller/physical.h > > > > > @@ -34,6 +34,7 @@ struct simap; > > > > > struct sbrec_multicast_group_table; > > > > > struct sbrec_port_binding_table; > > > > > struct sset; > > > > > +struct local_nonvif_data; > > > > > > > > > > /* OVN Geneve option information. > > > > > * > > > > > @@ -56,18 +57,18 @@ struct physical_ctx { > > > > > const struct simap *ct_zones; > > > > > enum mf_field_id mff_ovn_geneve; > > > > > struct shash *local_bindings; > > > > > + struct local_nonvif_data *nonvif_data; > > > > > }; > > > > > > > > > > void physical_register_ovs_idl(struct ovsdb_idl *); > > > > > void physical_run(struct physical_ctx *, > > > > > struct ovn_desired_flow_table *); > > > > > void physical_clear_unassoc_flows_with_db(struct > > ovn_desired_flow_table > > > > *); > > > > > -void physical_handle_port_binding_changes(struct physical_ctx *, > > > > > - struct > > ovn_desired_flow_table > > > > *); > > > > > void physical_handle_mc_group_changes(struct physical_ctx *, > > > > > struct ovn_desired_flow_table > > *); > > > > > -bool physical_handle_ovs_iface_changes(struct physical_ctx *, > > > > > - struct ovn_desired_flow_table > > *); > > > > > -bool get_tunnel_ofport(const char *chassis_name, char *encap_ip, > > > > > - ofp_port_t *ofport); > > > > > +bool physical_handle_ovs_iface_changes(struct physical_ctx *); > > > > > +void physical_handle_flows_for_lport(const struct sbrec_port_binding > > *, > > > > > + bool removed, > > > > > + struct physical_ctx *, > > > > > + struct ovn_desired_flow_table > > *); > > > > > #endif /* controller/physical.h */ > > > > > -- > > > > > 2.31.1 > > > > > > > > > > _______________________________________________ > > > > > dev mailing list > > > > > dev@openvswitch.org > > > > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > > > _______________________________________________ > > > > dev mailing list > > > > dev@openvswitch.org > > > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > > > > > _______________________________________________ > > dev mailing list > > dev@openvswitch.org > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > >
On Tue, Jul 27, 2021 at 7:11 PM Han Zhou <hzhou@ovn.org> wrote: > > On Tue, Jul 27, 2021 at 3:03 PM Numan Siddique <numans@ovn.org> wrote: > > > > On Tue, Jul 27, 2021 at 4:00 PM Han Zhou <hzhou@ovn.org> wrote: > > > > > > On Tue, Jul 27, 2021 at 11:43 AM Numan Siddique <numans@ovn.org> wrote: > > > > > > > > On Tue, Jul 27, 2021 at 3:36 AM Han Zhou <hzhou@ovn.org> wrote: > > > > > > > > > > Thanks Numan. The commit title has a typo: s/plow/pflow. > > > > > > > > > > On Fri, Jul 16, 2021 at 4:55 AM <numans@ovn.org> wrote: > > > > > > > > > > > > From: Numan Siddique <numans@ovn.org> > > > > > > > > > > > > physical_run() maintains a local copy of local vif to ofports > > > > > > in a simap along with the chassis tunnel information. This patch > > > > > > removes this from the physical module and now stores it in the > > > > > > runtime_data engine node. This makes it easier to handle runtime > > > > > > data changes in pflow_output engine. > > > > > > > > > > > > The newly added handler pflow_output_runtime_data_handler() > returns > > > > > > false if a datapath is added or removed from the local_datapaths > > > > > > and handles the logical port claims and releases incrementally. > > > > > > > > > > > > Signed-off-by: Numan Siddique <numans@ovn.org> > > > > > > --- > > > > > > controller/binding.c | 39 ++-- > > > > > > controller/binding.h | 23 +++ > > > > > > controller/ldata.c | 169 ++++++++++++++++ > > > > > > controller/ldata.h | 44 +++++ > > > > > > controller/lflow.c | 5 +- > > > > > > controller/lflow.h | 1 + > > > > > > controller/ovn-controller.c | 68 ++++++- > > > > > > controller/ovn-controller.h | 8 - > > > > > > controller/physical.c | 382 > > > +++++++++--------------------------- > > > > > > controller/physical.h | 13 +- > > > > > > 10 files changed, 422 insertions(+), 330 deletions(-) > > > > > > > > > > > > diff --git a/controller/binding.c b/controller/binding.c > > > > > > index 0fd951ad7..b50139726 100644 > > > > > > --- a/controller/binding.c > > > > > > +++ b/controller/binding.c > > > > > > @@ -546,23 +546,6 @@ update_active_pb_ras_pd(const struct > > > > > sbrec_port_binding *pb, > > > > > > } > > > > > > } > > > > > > > > > > > > -/* Corresponds to each Port_Binding.type. */ > > > > > > -enum en_lport_type { > > > > > > - LP_UNKNOWN, > > > > > > - LP_VIF, > > > > > > - LP_CONTAINER, > > > > > > - LP_PATCH, > > > > > > - LP_L3GATEWAY, > > > > > > - LP_LOCALNET, > > > > > > - LP_LOCALPORT, > > > > > > - LP_L2GATEWAY, > > > > > > - LP_VTEP, > > > > > > - LP_CHASSISREDIRECT, > > > > > > - LP_VIRTUAL, > > > > > > - LP_EXTERNAL, > > > > > > - LP_REMOTE > > > > > > -}; > > > > > > - > > > > > > /* Local bindings. binding.c module binds the logical port > > > (represented > > > > > by > > > > > > * Port_Binding rows) and sets the 'chassis' column when it sees > the > > > > > > * OVS interface row (of type "" or "internal") with the > > > > > > @@ -616,7 +599,7 @@ static struct local_binding > *local_binding_create( > > > > > > static void local_binding_add(struct shash *local_bindings, > > > > > > struct local_binding *); > > > > > > static struct local_binding *local_binding_find( > > > > > > - struct shash *local_bindings, const char *name); > > > > > > + const struct shash *local_bindings, const char *name); > > > > > > static void local_binding_destroy(struct local_binding *, > > > > > > struct shash *binding_lports); > > > > > > static void local_binding_delete(struct local_binding *, > > > > > > @@ -701,7 +684,8 @@ local_binding_data_destroy(struct > > > local_binding_data > > > > > *lbinding_data) > > > > > > } > > > > > > > > > > > > const struct sbrec_port_binding * > > > > > > -local_binding_get_primary_pb(struct shash *local_bindings, const > char > > > > > *pb_name) > > > > > > +local_binding_get_primary_pb(struct shash *local_bindings, > > > > > > + const char *pb_name) > > > > > > { > > > > > > struct local_binding *lbinding = > > > > > > local_binding_find(local_bindings, pb_name); > > > > > > @@ -710,6 +694,19 @@ local_binding_get_primary_pb(struct shash > > > > > *local_bindings, const char *pb_name) > > > > > > return b_lport ? b_lport->pb : NULL; > > > > > > } > > > > > > > > > > > > +ofp_port_t > > > > > > +local_binding_get_lport_ofport(const struct shash > *local_bindings, > > > > > > + const char *pb_name) > > > > > > +{ > > > > > > + struct local_binding *lbinding = > > > > > > + local_binding_find(local_bindings, pb_name); > > > > > > + struct binding_lport *b_lport = > > > > > > + local_binding_get_primary_or_localport_lport(lbinding); > > > > > > + > > > > > > + return (b_lport && lbinding->iface && > lbinding->iface->n_ofport) > > > ? > > > > > > + u16_to_ofp(lbinding->iface->ofport[0]) : 0; > > > > > > +} > > > > > > + > > > > > > bool > > > > > > local_binding_is_up(struct shash *local_bindings, const char > > > *pb_name) > > > > > > { > > > > > > @@ -871,7 +868,7 @@ is_lport_vif(const struct sbrec_port_binding > *pb) > > > > > > return !pb->type[0]; > > > > > > } > > > > > > > > > > > > -static enum en_lport_type > > > > > > +enum en_lport_type > > > > > > get_lport_type(const struct sbrec_port_binding *pb) > > > > > > { > > > > > > if (is_lport_vif(pb)) { > > > > > > @@ -2555,7 +2552,7 @@ local_binding_create(const char *name, const > > > struct > > > > > ovsrec_interface *iface) > > > > > > } > > > > > > > > > > > > static struct local_binding * > > > > > > -local_binding_find(struct shash *local_bindings, const char > *name) > > > > > > +local_binding_find(const struct shash *local_bindings, const char > > > *name) > > > > > > { > > > > > > return shash_find_data(local_bindings, name); > > > > > > } > > > > > > diff --git a/controller/binding.h b/controller/binding.h > > > > > > index b1717bd2b..f1abc4b9c 100644 > > > > > > --- a/controller/binding.h > > > > > > +++ b/controller/binding.h > > > > > > @@ -114,6 +114,9 @@ void local_binding_data_destroy(struct > > > > > local_binding_data *); > > > > > > > > > > > > const struct sbrec_port_binding *local_binding_get_primary_pb( > > > > > > struct shash *local_bindings, const char *pb_name); > > > > > > +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_down(struct shash *local_bindings, const > char > > > > > *pb_name); > > > > > > void local_binding_set_up(struct shash *local_bindings, const > char > > > > > *pb_name, > > > > > > @@ -134,4 +137,24 @@ bool > binding_handle_port_binding_changes(struct > > > > > binding_ctx_in *, > > > > > > void binding_tracked_dp_destroy(struct hmap *tracked_datapaths); > > > > > > > > > > > > void binding_dump_local_bindings(struct local_binding_data *, > struct > > > ds > > > > > *); > > > > > > + > > > > > > +/* Corresponds to each Port_Binding.type. */ > > > > > > +enum en_lport_type { > > > > > > + LP_UNKNOWN, > > > > > > + LP_VIF, > > > > > > + LP_CONTAINER, > > > > > > + LP_PATCH, > > > > > > + LP_L3GATEWAY, > > > > > > + LP_LOCALNET, > > > > > > + LP_LOCALPORT, > > > > > > + LP_L2GATEWAY, > > > > > > + LP_VTEP, > > > > > > + LP_CHASSISREDIRECT, > > > > > > + LP_VIRTUAL, > > > > > > + LP_EXTERNAL, > > > > > > + LP_REMOTE > > > > > > +}; > > > > > > + > > > > > > +enum en_lport_type get_lport_type(const struct > sbrec_port_binding *); > > > > > > + > > > > > > #endif /* controller/binding.h */ > > > > > > diff --git a/controller/ldata.c b/controller/ldata.c > > > > > > index a6df9b1da..f55905551 100644 > > > > > > --- a/controller/ldata.c > > > > > > +++ b/controller/ldata.c > > > > > > @@ -18,10 +18,13 @@ > > > > > > /* OVS includes. */ > > > > > > #include "include/openvswitch/json.h" > > > > > > #include "lib/hmapx.h" > > > > > > +#include "lib/flow.h" > > > > > > #include "lib/util.h" > > > > > > +#include "lib/vswitch-idl.h" > > > > > > #include "openvswitch/vlog.h" > > > > > > > > > > > > /* OVN includes. */ > > > > > > +#include "encaps.h" > > > > > > #include "ldata.h" > > > > > > #include "lport.h" > > > > > > #include "lib/ovn-util.h" > > > > > > @@ -275,6 +278,172 @@ tracked_datapaths_destroy(struct hmap > > > > > *tracked_datapaths) > > > > > > hmap_destroy(tracked_datapaths); > > > > > > } > > > > > > > > > > > > +/* Iterates the br_int ports and build the simap of patch to > ofports > > > > > > + * and chassis tunnels. */ > > > > > > +void > > > > > > +ldata_run(const struct ovsrec_bridge *br_int, > > > > > > + const struct sbrec_chassis *chassis_rec, > > > > > > + struct local_nonvif_data *nonvif_data) > > > > > > +{ > > > > > > + for (int i = 0; i < br_int->n_ports; i++) { > > > > > > + const struct ovsrec_port *port_rec = br_int->ports[i]; > > > > > > + if (!strcmp(port_rec->name, br_int->name)) { > > > > > > + continue; > > > > > > + } > > > > > > + > > > > > > + const char *tunnel_id = smap_get(&port_rec->external_ids, > > > > > > + "ovn-chassis-id"); > > > > > > + if (tunnel_id && encaps_tunnel_id_match(tunnel_id, > > > > > > + > chassis_rec->name, > > > > > > + NULL)) { > > > > > > + continue; > > > > > > + } > > > > > > + > > > > > > + const char *localnet = smap_get(&port_rec->external_ids, > > > > > > + "ovn-localnet-port"); > > > > > > + const char *l2gateway = smap_get(&port_rec->external_ids, > > > > > > + "ovn-l2gateway-port"); > > > > > > + > > > > > > + for (int j = 0; j < port_rec->n_interfaces; j++) { > > > > > > + const struct ovsrec_interface *iface_rec = > > > > > port_rec->interfaces[j]; > > > > > > + > > > > > > + /* Get OpenFlow port number. */ > > > > > > + if (!iface_rec->n_ofport) { > > > > > > + continue; > > > > > > + } > > > > > > + int64_t ofport = iface_rec->ofport[0]; > > > > > > + if (ofport < 1 || ofport > ofp_to_u16(OFPP_MAX)) { > > > > > > + continue; > > > > > > + } > > > > > > + > > > > > > + bool is_patch = !strcmp(iface_rec->type, "patch"); > > > > > > + if (is_patch && localnet) { > > > > > > + simap_put(&nonvif_data->patch_ofports, localnet, > > > ofport); > > > > > > + break; > > > > > > + } else if (is_patch && l2gateway) { > > > > > > + /* L2 gateway patch ports can be handled just > like > > > VIFs. > > > > > */ > > > > > > + simap_put(&nonvif_data->patch_ofports, l2gateway, > > > > > ofport); > > > > > > + break; > > > > > > + } else if (tunnel_id) { > > > > > > + enum chassis_tunnel_type tunnel_type; > > > > > > + if (!strcmp(iface_rec->type, "geneve")) { > > > > > > + tunnel_type = GENEVE; > > > > > > + } else if (!strcmp(iface_rec->type, "stt")) { > > > > > > + tunnel_type = STT; > > > > > > + } else if (!strcmp(iface_rec->type, "vxlan")) { > > > > > > + tunnel_type = VXLAN; > > > > > > + } else { > > > > > > + continue; > > > > > > + } > > > > > > + > > > > > > + /* We split the tunnel_id to get the chassis-id > > > > > > + * and hash the tunnel list on the chassis-id. > The > > > > > > + * reason to use the chassis-id alone is because > > > > > > + * there might be cases (multicast, gateway > chassis) > > > > > > + * where we need to tunnel to the chassis, but > won't > > > > > > + * have the encap-ip specifically. > > > > > > + */ > > > > > > + char *hash_id = NULL; > > > > > > + char *ip = NULL; > > > > > > + > > > > > > + if (!encaps_tunnel_id_parse(tunnel_id, &hash_id, > > > &ip)) { > > > > > > + continue; > > > > > > + } > > > > > > + struct chassis_tunnel *tun = xmalloc(sizeof > *tun); > > > > > > + hmap_insert(&nonvif_data->chassis_tunnels, > > > > > &tun->hmap_node, > > > > > > + hash_string(hash_id, 0)); > > > > > > + tun->chassis_id = xstrdup(tunnel_id); > > > > > > + tun->ofport = u16_to_ofp(ofport); > > > > > > + tun->type = tunnel_type; > > > > > > + > > > > > > + free(hash_id); > > > > > > + free(ip); > > > > > > + break; > > > > > > + } > > > > > > + } > > > > > > + } > > > > > > +} > > > > > > + > > > > > > +bool > > > > > > +ldata_handle_ovs_iface_changes( > > > > > > + const struct ovsrec_interface_table *iface_table) > > > > > > +{ > > > > > > + const struct ovsrec_interface *iface_rec; > > > > > > + OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, > iface_table) > > > { > > > > > > + if (!strcmp(iface_rec->type, "geneve") || > > > > > > + !strcmp(iface_rec->type, "patch") || > > > > > > + !strcmp(iface_rec->type, "vxlan") || > > > > > > + !strcmp(iface_rec->type, "stt")) { > > > > > > + return false; > > > > > > + } > > > > > > + } > > > > > > + > > > > > > + return true; > > > > > > +} > > > > > > + > > > > > > +bool > > > > > > +get_chassis_tunnel_ofport(const struct hmap *chassis_tunnels, > > > > > > + const char *chassis_name, char > *encap_ip, > > > > > > + ofp_port_t *ofport) > > > > > > +{ > > > > > > + struct chassis_tunnel *tun = NULL; > > > > > > + tun = chassis_tunnel_find(chassis_tunnels, chassis_name, > > > encap_ip); > > > > > > + if (!tun) { > > > > > > + return false; > > > > > > + } > > > > > > + > > > > > > + *ofport = tun->ofport; > > > > > > + return true; > > > > > > +} > > > > > > + > > > > > > +void > > > > > > +local_nonvif_data_init(struct local_nonvif_data *nonvif_data) > > > > > > +{ > > > > > > + simap_init(&nonvif_data->patch_ofports); > > > > > > + hmap_init(&nonvif_data->chassis_tunnels); > > > > > > +} > > > > > > + > > > > > > +void > > > > > > +local_nonvif_data_destroy(struct local_nonvif_data *nonvif_data) > > > > > > +{ > > > > > > + simap_destroy(&nonvif_data->patch_ofports); > > > > > > + struct chassis_tunnel *tun; > > > > > > + HMAP_FOR_EACH_POP (tun, hmap_node, > > > &nonvif_data->chassis_tunnels) { > > > > > > + free(tun->chassis_id); > > > > > > + free(tun); > > > > > > + } > > > > > > + hmap_destroy(&nonvif_data->chassis_tunnels); > > > > > > +} > > > > > > + > > > > > > + > > > > > > +/* > > > > > > + * This function looks up the list of tunnel ports (provided by > > > > > > + * ovn-chassis-id ports) and returns the tunnel for the given > > > chassid-id > > > > > and > > > > > > + * encap-ip. The ovn-chassis-id is formed using the chassis-id > and > > > > > encap-ip. > > > > > > + * The list is hashed using the chassis-id. If the encap-ip is > not > > > > > specified, > > > > > > + * it means we'll just return a tunnel for that chassis-id, i.e. > we > > > just > > > > > check > > > > > > + * for chassis-id and if there is a match, we'll return the > tunnel. > > > > > > + * If encap-ip is also provided we use both chassis-id and > encap-ip > > > to do > > > > > > + * a more specific lookup. > > > > > > + */ > > > > > > +struct chassis_tunnel * > > > > > > +chassis_tunnel_find(const struct hmap *chassis_tunnels, const > char > > > > > *chassis_id, > > > > > > + char *encap_ip) > > > > > > +{ > > > > > > + /* > > > > > > + * If the specific encap_ip is given, look for the > chassisid_ip > > > > > entry, > > > > > > + * else return the 1st found entry for the chassis. > > > > > > + */ > > > > > > + struct chassis_tunnel *tun = NULL; > > > > > > + HMAP_FOR_EACH_WITH_HASH (tun, hmap_node, > hash_string(chassis_id, > > > 0), > > > > > > + chassis_tunnels) { > > > > > > + if (encaps_tunnel_id_match(tun->chassis_id, chassis_id, > > > > > encap_ip)) { > > > > > > + return tun; > > > > > > + } > > > > > > + } > > > > > > + return NULL; > > > > > > +} > > > > > > + > > > > > > /* static functions. */ > > > > > > static struct local_datapath * > > > > > > local_datapath_add__(struct hmap *local_datapaths, > > > > > > diff --git a/controller/ldata.h b/controller/ldata.h > > > > > > index 16ad43c8f..91624d0b4 100644 > > > > > > --- a/controller/ldata.h > > > > > > +++ b/controller/ldata.h > > > > > > @@ -19,10 +19,14 @@ > > > > > > /* OVS includes. */ > > > > > > #include "include/openvswitch/shash.h" > > > > > > #include "lib/smap.h" > > > > > > +#include "lib/simap.h" > > > > > > > > > > > > struct sbrec_datapath_binding; > > > > > > struct sbrec_port_binding; > > > > > > +struct sbrec_chassis; > > > > > > struct ovsdb_idl_index; > > > > > > +struct ovsrec_bridge; > > > > > > +struct ovsrec_interface_table; > > > > > > > > > > > > /* A logical datapath that has some relevance to this > hypervisor. A > > > > > logical > > > > > > * datapath D is relevant to hypervisor H if: > > > > > > @@ -117,4 +121,44 @@ void tracked_datapath_lport_add(const struct > > > > > sbrec_port_binding *, > > > > > > struct hmap *tracked_datapaths); > > > > > > void tracked_datapaths_destroy(struct hmap *tracked_datapaths); > > > > > > > > > > > > +/* Must be a bit-field ordered from most-preferred (higher > number) to > > > > > > + * least-preferred (lower number). */ > > > > > > +enum chassis_tunnel_type { > > > > > > + GENEVE = 1 << 2, > > > > > > + STT = 1 << 1, > > > > > > + VXLAN = 1 << 0 > > > > > > +}; > > > > > > + > > > > > > +/* Maps from a chassis to the OpenFlow port number of the tunnel > that > > > > > can be > > > > > > + * used to reach that chassis. */ > > > > > > +struct chassis_tunnel { > > > > > > + struct hmap_node hmap_node; > > > > > > + char *chassis_id; > > > > > > + ofp_port_t ofport; > > > > > > + enum chassis_tunnel_type type; > > > > > > +}; > > > > > > + > > > > > > +struct local_nonvif_data { > > > > > > + struct simap patch_ofports; /* simap of patch ovs ports. */ > > > > > > + struct hmap chassis_tunnels; /* hmap of 'struct > chassis_tunnel' > > > from > > > > > the > > > > > > + * tunnel OVS ports. */ > > > > > > +}; > > > > > > + > > > > > > +void ldata_run(const struct ovsrec_bridge *br_int, > > > > > > + const struct sbrec_chassis *, > > > > > > + struct local_nonvif_data *nonvif_data); > > > > > > + > > > > > > +bool ldata_handle_ovs_iface_changes(const struct > > > ovsrec_interface_table > > > > > *); > > > > > > + > > > > > > +struct chassis_tunnel *chassis_tunnel_find(const struct hmap > > > > > *chassis_tunnels, > > > > > > + const char > *chassis_id, > > > > > > + char *encap_ip); > > > > > > + > > > > > > +bool get_chassis_tunnel_ofport(const struct hmap > *chassis_tunnels, > > > > > > + const char *chassis_name, char > > > *encap_ip, > > > > > > + ofp_port_t *ofport); > > > > > > + > > > > > > +void local_nonvif_data_init(struct local_nonvif_data > *nonvif_data); > > > > > > +void local_nonvif_data_destroy(struct local_nonvif_data > > > *nonvif_data); > > > > > > + > > > > > > #endif /* controller/ldata.h */ > > > > > > diff --git a/controller/lflow.c b/controller/lflow.c > > > > > > index d1f32077b..4ac671e40 100644 > > > > > > --- a/controller/lflow.c > > > > > > +++ b/controller/lflow.c > > > > > > @@ -58,6 +58,7 @@ struct lookup_port_aux { > > > > > > const struct sbrec_datapath_binding *dp; > > > > > > const struct sbrec_logical_flow *lflow; > > > > > > struct lflow_resource_ref *lfrr; > > > > > > + const struct hmap *chassis_tunnels; > > > > > > }; > > > > > > > > > > > > struct condition_aux { > > > > > > @@ -145,7 +146,8 @@ tunnel_ofport_cb(const void *aux_, const char > > > > > *port_name, ofp_port_t *ofport) > > > > > > return false; > > > > > > } > > > > > > > > > > > > - if (!get_tunnel_ofport(pb->chassis->name, NULL, ofport)) { > > > > > > + if (!get_chassis_tunnel_ofport(aux->chassis_tunnels, > > > > > pb->chassis->name, > > > > > > + NULL, ofport)) { > > > > > > return false; > > > > > > } > > > > > > > > > > > > @@ -591,6 +593,7 @@ add_matches_to_flow_table(const struct > > > > > sbrec_logical_flow *lflow, > > > > > > .dp = dp, > > > > > > .lflow = lflow, > > > > > > .lfrr = l_ctx_out->lfrr, > > > > > > + .chassis_tunnels = l_ctx_in->chassis_tunnels, > > > > > > }; > > > > > > > > > > > > /* Encode OVN logical actions into OpenFlow. */ > > > > > > diff --git a/controller/lflow.h b/controller/lflow.h > > > > > > index c17ff6dd4..e7dd31289 100644 > > > > > > --- a/controller/lflow.h > > > > > > +++ b/controller/lflow.h > > > > > > @@ -146,6 +146,7 @@ struct lflow_ctx_in { > > > > > > const struct shash *port_groups; > > > > > > const struct sset *active_tunnels; > > > > > > const struct sset *related_lport_ids; > > > > > > + const struct hmap *chassis_tunnels; > > > > > > }; > > > > > > > > > > > > struct lflow_ctx_out { > > > > > > diff --git a/controller/ovn-controller.c > b/controller/ovn-controller.c > > > > > > index 8f620e4ad..69d135046 100644 > > > > > > --- a/controller/ovn-controller.c > > > > > > +++ b/controller/ovn-controller.c > > > > > > @@ -1039,6 +1039,11 @@ struct ed_type_runtime_data { > > > > > > struct related_lports related_lports; > > > > > > struct sset active_tunnels; > > > > > > > > > > > > + /* Non VIF OVS interface information (mainly patch OVS > interfacs > > > > > > + * and tunnel interfaces) that are relevant to the local > > > > > > + * chassis (generated by ldata_run()). */ > > > > > > + struct local_nonvif_data nonvif_data; > > > > > > + > > > > > I don't see a benefit of adding this to runtime_data. It is > unrelated to > > > > > the other data in the current runtime_data node. Now if we combine > it to > > > > > runtime_data, it means we are coupling those data unnecessarily, > which > > > > > leads to unflexible handler implementation. An example is that now > > > > > recompute of nonvif_data would trigger recompute of runtime_data, > which > > > > > would trigger recompute of lflow_output. In fact, this can be just > in a > > > > > separate engine node, only as input to pflow_output. Would that be > more > > > > > straightforward and efficient? > > > > > > > > Hi Han, > > > > > > > > Thanks for the review comments. > > > > > > > > I see your point. I'll explore if we can add a new engine node for > this. > > > > > > > > My understanding of engine processing is this and runtime data engine > > > > in particular is this: > > > > > > > > 1. The first level of engine nodes would handle the db changes and > > > > generates/transforms the data > > > > which we can probably call - runtime_data. This was the > > > > motivation for me to add the nonvif_data > > > > in the runtime data engine. Perhaps we need to further divide > > > > the runtime_data engine or rename it > > > > so that we only store the VIF related data in this. > > > > > > Hi Numan, it seems we had different models for I-P engine nodes in our > > > minds. Sorry that I didn't document these thoughts initially for the I-P > > > engine. I don't think we should restrict the engine nodes in such > layers. > > > It should be flexible enough based on the real computation dependencies > - > > > just thinking about how DDlog programs would be written. I am not > against > > > the idea of a separate encapsulation layer for OVSDB IDL, but > runtime_data > > > was not for that purpose. Initially the I-P engine was very coarse > grained, > > > so I just created a big "runtime_data" node trying to contain all the > > > intermediate data, just enough to support the first version of I-P for > the > > > most frequent changes. Now that we are making the I-P engine more and > more > > > fine-grained, we definitely cannot simply put everything in a single > node. > > > The current runtime_data may be renamed to binding_data, or be further > > > split if necessary, and we don't need to put more data into it unless > it is > > > tightly related to the bindings handling. > > > > Thanks for the explanation. I'd agree renaming the current > > runtime_data to binding_data. > > > > Probably a patch later for that. > > > > Since we are discussing I-P, I'd like to bring up another case. > > > > Presently we abort the engine if a recompute needs to be done but > > recompute is not allowed > > due to an sb txn is in progress or due to ofctrl_can_put() returns > > false. We have engine nodes > > like ct_zone which does not have handlers for many inputs and it has > > to recompute. > > And suppose if engine aborts due to the reason I mentioned, then in > > the next engine run, we do > > a full recomputation of all engine nodes whereas only recompute of > > ct_zones (and perhaps pflow_output) > > was required. In our scale testing we noticed that this recomputation > > of all the engine nodes is costing > > a bit. > > > Aha, I just debugged a problem and noticed a similar issue yesterday! It is > on the same ct_zones node, but the trigger was not because of sb txn, but > the ofctrl_can_put() == false (i.e. there are inflight messages). > I think an easy solution is to apply the abort-if-recompute strategy only > for certain nodes that either require high cost of recompute (i.e. > lflow_output) or require DB txn. This way, recompute in ct_zones node > should always be allowed and wouldn't abort and trigger next full recompute > for the whole engine. A property can be added to engine_node for this > purpose. Thanks for the comments. I noticed the ofctrl_can_put() returning false a lot in our testing. I'll try to address the TXN NULL issue based on your suggestion. And explore if the other one can be solved too. Thanks Numan > > > I think we should address this. And probably we can separate out db > > transactions from the engine > > and can be done separately. The binding module will not set > > sbrec_port_binding_set_chassis() > > for example. > > > This may be worth exploring, too. There may be benefits more than just the > scenario above. However, it cannot solve the scenario I encountered > yesterday, which was not triggered by the SB txn but in-flight OF messages. > > > Any thoughts on this ? > > > > Thanks > > Numan > > > > > > > > > 2. And the flow output engines ideally would use the runtime data for > > > > flow generation. > > > > > > The output nodes should only depend on whatever data that is necessary > for > > > flow computation. What you said is true if "runtime data" here contains > > > everything that is needed for flow computation, but it should never be a > > > goal to keep all these data in a single I-P engine node, because that > would > > > not really benefit from the I-P engine. > > > > > > > 3. Ideally I'd think (or prefer) to engine nodes one or two level > > > > down to not access any db changes at all. > > > > For example, lfow_output or pflow_output engine handles should > > > > not call IDL TRACKED loops. > > > > > > > > Maybe we could try to achieve follow up patches if that makes sense. > > > > > > > Encapsulating IDL to a separate layer may be reasonable, if it provides > > > values, but I think it is another topic. I don't think it changes the > I-P > > > model. > > > > > > Thanks, > > > Han > > > > > > > > > > > > > > > > > > > > > > > > As to the code organization, I think now I understand why you added > the > > > new > > > > > module ldata.c (suppose it is going to be renamed to local_data.c > to be > > > > > more clear). Although it is not harmful to have that new module, it > > > seems > > > > > not quite necessary to me, either. The original localvif_to_ofport > data > > > is > > > > > now split into two parts, VIF related and nonVIF related. I don't > see > > > > > benefit of keeping these two parts in the same file. It is > reasonable to > > > > > combine the VIF related data in runtime_data (which could be > renamed, > > > > > because the name was vague), to avoid maintaining redundant data. I > > > think > > > > > it is ok to stay in binding.c. For the nonVIF part, I think the new > > > engine > > > > > node can be defined in ovn-controller.c and implemented in > physical.c > > > > > because that data is used by physical flow processing only. I don't > > > have a > > > > > strong argument for this - maybe just less change is needed for this > > > series > > > > > (and so the change history would be easier to follow). > > > > > > > > I'll explore and see if this can be separated. Although I think > > > > having a separate file local_data.c would uncomplicate the binding.c a > > > > bit. > > > > > > > > > > > > > > > > > > > > > > > > /* runtime data engine private data. */ > > > > > > struct sset egress_ifaces; > > > > > > struct smap local_iface_ids; > > > > > > @@ -1139,6 +1144,7 @@ en_runtime_data_init(struct engine_node > *node > > > > > OVS_UNUSED, > > > > > > local_binding_data_init(&data->lbinding_data); > > > > > > shash_init(&data->local_active_ports_ipv6_pd); > > > > > > shash_init(&data->local_active_ports_ras); > > > > > > + local_nonvif_data_init(&data->nonvif_data); > > > > > > > > > > > > /* Init the tracked data. */ > > > > > > hmap_init(&data->tracked_dp_bindings); > > > > > > @@ -1160,6 +1166,7 @@ en_runtime_data_cleanup(void *data) > > > > > > > shash_destroy_free_data(&rt_data->local_active_ports_ipv6_pd); > > > > > > shash_destroy_free_data(&rt_data->local_active_ports_ras); > > > > > > local_binding_data_destroy(&rt_data->lbinding_data); > > > > > > + local_nonvif_data_destroy(&rt_data->nonvif_data); > > > > > > } > > > > > > > > > > > > static void > > > > > > @@ -1272,6 +1279,7 @@ en_runtime_data_run(struct engine_node > *node, > > > void > > > > > *data) > > > > > > shash_clear_free_data(local_active_ipv6_pd); > > > > > > shash_clear_free_data(local_active_ras); > > > > > > local_binding_data_destroy(&rt_data->lbinding_data); > > > > > > + local_nonvif_data_destroy(&rt_data->nonvif_data); > > > > > > sset_destroy(local_lports); > > > > > > related_lports_destroy(&rt_data->related_lports); > > > > > > sset_destroy(active_tunnels); > > > > > > @@ -1284,6 +1292,7 @@ en_runtime_data_run(struct engine_node > *node, > > > void > > > > > *data) > > > > > > sset_init(&rt_data->egress_ifaces); > > > > > > smap_init(&rt_data->local_iface_ids); > > > > > > local_binding_data_init(&rt_data->lbinding_data); > > > > > > + local_nonvif_data_init(&rt_data->nonvif_data); > > > > > > } > > > > > > > > > > > > struct binding_ctx_in b_ctx_in; > > > > > > @@ -1303,6 +1312,7 @@ en_runtime_data_run(struct engine_node > *node, > > > void > > > > > *data) > > > > > > bfd_calculate_active_tunnels(b_ctx_in.br_int, > > > active_tunnels); > > > > > > } > > > > > > > > > > > > + ldata_run(b_ctx_in.br_int, b_ctx_in.chassis_rec, > > > > > &rt_data->nonvif_data); > > > > > > binding_run(&b_ctx_in, &b_ctx_out); > > > > > > > > > > > > engine_set_node_state(node, EN_UPDATED); > > > > > > @@ -1318,6 +1328,10 @@ runtime_data_ovs_interface_handler(struct > > > > > engine_node *node, void *data) > > > > > > rt_data->tracked = true; > > > > > > b_ctx_out.tracked_dp_bindings = > &rt_data->tracked_dp_bindings; > > > > > > > > > > > > + if (!ldata_handle_ovs_iface_changes(b_ctx_in.iface_table)) { > > > > > > + return false; > > > > > > + } > > > > > > + > > > > > > > > > > This is the performance problem I mentioned above. Before this > change, > > > > > tunnel/patch interface changes only triggered physical_run(), now it > > > would > > > > > trigger lflow_run(). > > > > > > > > Actually that's not the case. Any change to tunnel/patch OVS > interfaces > > > results > > > > in the function binding_handle_ovs_interface_changes() to return false > > > and hence > > > > lflow_run() would be called - > > > > https://github.com/ovn-org/ovn/blob/master/controller/binding.c#L2198 > > > > > > > > > > > > > > > > > > > > > > > if (!binding_handle_ovs_interface_changes(&b_ctx_in, > > > &b_ctx_out)) { > > > > > > return false; > > > > > > } > > > > > > @@ -2060,6 +2074,7 @@ init_lflow_ctx(struct engine_node *node, > > > > > > l_ctx_in->port_groups = port_groups; > > > > > > l_ctx_in->active_tunnels = &rt_data->active_tunnels; > > > > > > l_ctx_in->related_lport_ids = > &rt_data->related_lports.lport_ids; > > > > > > + l_ctx_in->chassis_tunnels = > > > &rt_data->nonvif_data.chassis_tunnels; > > > > > > > > > > > > l_ctx_out->flow_table = &fo->flow_table; > > > > > > l_ctx_out->group_table = &fo->group_table; > > > > > > @@ -2527,6 +2542,7 @@ static void init_physical_ctx(struct > engine_node > > > > > *node, > > > > > > p_ctx->ct_zones = ct_zones; > > > > > > p_ctx->mff_ovn_geneve = ed_mff_ovn_geneve->mff_ovn_geneve; > > > > > > p_ctx->local_bindings = &rt_data->lbinding_data.bindings; > > > > > > + p_ctx->nonvif_data = &rt_data->nonvif_data; > > > > > > } > > > > > > > > > > > > static void * > > > > > > @@ -2583,7 +2599,11 @@ pflow_output_sb_port_binding_handler(struct > > > > > engine_node *node, > > > > > > * only. flow_output runtime data handler takes care of > > > processing > > > > > > * logical flows for any port binding changes. > > > > > > */ > > > > > > - physical_handle_port_binding_changes(&p_ctx, > &pfo->flow_table); > > > > > > + const struct sbrec_port_binding *pb; > > > > > > + SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED (pb, > > > > > p_ctx.port_binding_table) { > > > > > > + bool removed = sbrec_port_binding_is_deleted(pb); > > > > > > + physical_handle_flows_for_lport(pb, removed, &p_ctx, > > > > > &pfo->flow_table); > > > > > > + } > > > > > > > > > > nit: I think it is better to keep the interface > > > > > physical_handle_port_binding_changes() and hide this loop details > in the > > > > > physical.c module. > > > > > > > > Ack. > > > > > > > > Thanks > > > > Numan > > > > > > > > > > > > > > Thanks, > > > > > Han > > > > > > > > > > > > > > > > > engine_set_node_state(node, EN_UPDATED); > > > > > > return true; > > > > > > @@ -2613,13 +2633,55 @@ pflow_output_ovs_iface_handler(struct > > > engine_node > > > > > *node OVS_UNUSED, > > > > > > struct ed_type_runtime_data *rt_data = > > > > > > engine_get_input_data("runtime_data", node); > > > > > > > > > > > > + struct physical_ctx p_ctx; > > > > > > + init_physical_ctx(node, rt_data, &p_ctx); > > > > > > + > > > > > > + engine_set_node_state(node, EN_UPDATED); > > > > > > + return physical_handle_ovs_iface_changes(&p_ctx); > > > > > > +} > > > > > > + > > > > > > +static bool > > > > > > +pflow_output_runtime_data_handler(struct engine_node *node, void > > > *data) > > > > > > +{ > > > > > > + struct ed_type_runtime_data *rt_data = > > > > > > + engine_get_input_data("runtime_data", node); > > > > > > + > > > > > > + /* There is no tracked data. Fall back to full recompute of > > > > > > + * pflow_output. */ > > > > > > + if (!rt_data->tracked) { > > > > > > + return false; > > > > > > + } > > > > > > + > > > > > > + struct hmap *tracked_dp_bindings = > &rt_data->tracked_dp_bindings; > > > > > > + if (hmap_is_empty(tracked_dp_bindings)) { > > > > > > + return true; > > > > > > + } > > > > > > + > > > > > > struct ed_type_pflow_output *pfo = data; > > > > > > > > > > > > struct physical_ctx p_ctx; > > > > > > init_physical_ctx(node, rt_data, &p_ctx); > > > > > > > > > > > > + struct tracked_datapath *tdp; > > > > > > + HMAP_FOR_EACH (tdp, node, tracked_dp_bindings) { > > > > > > + if (tdp->tracked_type != TRACKED_RESOURCE_UPDATED) { > > > > > > + /* Fall back to full recompute when a local datapath > > > > > > + * is added or deleted. */ > > > > > > + return false; > > > > > > + } > > > > > > + > > > > > > + struct shash_node *shash_node; > > > > > > + SHASH_FOR_EACH (shash_node, &tdp->lports) { > > > > > > + struct tracked_lport *lport = shash_node->data; > > > > > > + bool removed = > > > > > > + lport->tracked_type == TRACKED_RESOURCE_REMOVED ? > > > true: > > > > > false; > > > > > > + physical_handle_flows_for_lport(lport->pb, removed, > > > &p_ctx, > > > > > > + &pfo->flow_table); > > > > > > + } > > > > > > + } > > > > > > + > > > > > > engine_set_node_state(node, EN_UPDATED); > > > > > > - return physical_handle_ovs_iface_changes(&p_ctx, > > > &pfo->flow_table); > > > > > > + return true; > > > > > > } > > > > > > > > > > > > static void * > > > > > > @@ -2914,7 +2976,7 @@ main(int argc, char *argv[]) > > > > > > pflow_output_sb_multicast_group_handler); > > > > > > > > > > > > engine_add_input(&en_pflow_output, &en_runtime_data, > > > > > > - NULL); > > > > > > + pflow_output_runtime_data_handler); > > > > > > engine_add_input(&en_pflow_output, &en_sb_encap, NULL); > > > > > > engine_add_input(&en_pflow_output, &en_mff_ovn_geneve, NULL); > > > > > > engine_add_input(&en_pflow_output, &en_ovs_open_vswitch, > NULL); > > > > > > diff --git a/controller/ovn-controller.h > b/controller/ovn-controller.h > > > > > > index 578588305..78a53312f 100644 > > > > > > --- a/controller/ovn-controller.h > > > > > > +++ b/controller/ovn-controller.h > > > > > > @@ -45,14 +45,6 @@ const struct ovsrec_bridge *get_bridge(const > struct > > > > > ovsrec_bridge_table *, > > > > > > > > > > > > struct sbrec_encap *preferred_encap(const struct sbrec_chassis > *); > > > > > > > > > > > > -/* Must be a bit-field ordered from most-preferred (higher > number) to > > > > > > - * least-preferred (lower number). */ > > > > > > -enum chassis_tunnel_type { > > > > > > - GENEVE = 1 << 2, > > > > > > - STT = 1 << 1, > > > > > > - VXLAN = 1 << 0 > > > > > > -}; > > > > > > - > > > > > > uint32_t get_tunnel_type(const char *name); > > > > > > > > > > > > struct pb_ld_binding { > > > > > > diff --git a/controller/physical.c b/controller/physical.c > > > > > > index b244ff1c2..87080d001 100644 > > > > > > --- a/controller/physical.c > > > > > > +++ b/controller/physical.c > > > > > > @@ -86,46 +86,6 @@ physical_register_ovs_idl(struct ovsdb_idl > > > *ovs_idl) > > > > > > ovsdb_idl_track_add_column(ovs_idl, > > > > > &ovsrec_interface_col_external_ids); > > > > > > } > > > > > > > > > > > > -static struct simap localvif_to_ofport = > > > > > > - SIMAP_INITIALIZER(&localvif_to_ofport); > > > > > > -static struct hmap tunnels = HMAP_INITIALIZER(&tunnels); > > > > > > - > > > > > > -/* Maps from a chassis to the OpenFlow port number of the tunnel > that > > > > > can be > > > > > > - * used to reach that chassis. */ > > > > > > -struct chassis_tunnel { > > > > > > - struct hmap_node hmap_node; > > > > > > - char *chassis_id; > > > > > > - ofp_port_t ofport; > > > > > > - enum chassis_tunnel_type type; > > > > > > -}; > > > > > > - > > > > > > -/* > > > > > > - * This function looks up the list of tunnel ports (provided by > > > > > > - * ovn-chassis-id ports) and returns the tunnel for the given > > > chassid-id > > > > > and > > > > > > - * encap-ip. The ovn-chassis-id is formed using the chassis-id > and > > > > > encap-ip. > > > > > > - * The list is hashed using the chassis-id. If the encap-ip is > not > > > > > specified, > > > > > > - * it means we'll just return a tunnel for that chassis-id, i.e. > we > > > just > > > > > check > > > > > > - * for chassis-id and if there is a match, we'll return the > tunnel. > > > > > > - * If encap-ip is also provided we use both chassis-id and > encap-ip > > > to do > > > > > > - * a more specific lookup. > > > > > > - */ > > > > > > -static struct chassis_tunnel * > > > > > > -chassis_tunnel_find(const char *chassis_id, char *encap_ip) > > > > > > -{ > > > > > > - /* > > > > > > - * If the specific encap_ip is given, look for the > chassisid_ip > > > > > entry, > > > > > > - * else return the 1st found entry for the chassis. > > > > > > - */ > > > > > > - struct chassis_tunnel *tun = NULL; > > > > > > - HMAP_FOR_EACH_WITH_HASH (tun, hmap_node, > hash_string(chassis_id, > > > 0), > > > > > > - &tunnels) { > > > > > > - if (encaps_tunnel_id_match(tun->chassis_id, chassis_id, > > > > > encap_ip)) { > > > > > > - return tun; > > > > > > - } > > > > > > - } > > > > > > - return NULL; > > > > > > -} > > > > > > - > > > > > > static void > > > > > > put_load(uint64_t value, enum mf_field_id dst, int ofs, int > n_bits, > > > > > > struct ofpbuf *ofpacts) > > > > > > @@ -166,17 +126,18 @@ put_resubmit(uint8_t table_id, struct ofpbuf > > > > > *ofpacts) > > > > > > * from the associated encap. > > > > > > */ > > > > > > static struct chassis_tunnel * > > > > > > -get_port_binding_tun(const struct sbrec_port_binding *binding) > > > > > > +get_port_binding_tun(const struct sbrec_port_binding *binding, > > > > > > + const struct hmap *chassis_tunnels) > > > > > > { > > > > > > struct sbrec_encap *encap = binding->encap; > > > > > > struct sbrec_chassis *chassis = binding->chassis; > > > > > > struct chassis_tunnel *tun = NULL; > > > > > > > > > > > > if (encap) { > > > > > > - tun = chassis_tunnel_find(chassis->name, encap->ip); > > > > > > + tun = chassis_tunnel_find(chassis_tunnels, chassis->name, > > > > > encap->ip); > > > > > > } > > > > > > if (!tun) { > > > > > > - tun = chassis_tunnel_find(chassis->name, NULL); > > > > > > + tun = chassis_tunnel_find(chassis_tunnels, chassis->name, > > > NULL); > > > > > > } > > > > > > return tun; > > > > > > } > > > > > > @@ -325,12 +286,13 @@ put_remote_port_redirect_overlay(const > struct > > > > > > uint32_t port_key, > > > > > > struct match *match, > > > > > > struct ofpbuf *ofpacts_p, > > > > > > + const struct hmap > *chassis_tunnels, > > > > > > struct ovn_desired_flow_table > > > > > *flow_table) > > > > > > { > > > > > > if (!is_ha_remote) { > > > > > > /* Setup encapsulation */ > > > > > > const struct chassis_tunnel *rem_tun = > > > > > > - get_port_binding_tun(binding); > > > > > > + get_port_binding_tun(binding, chassis_tunnels); > > > > > > if (!rem_tun) { > > > > > > return; > > > > > > } > > > > > > @@ -348,10 +310,10 @@ put_remote_port_redirect_overlay(const > struct > > > > > > continue; > > > > > > } > > > > > > if (!tun) { > > > > > > - tun = chassis_tunnel_find(ch->name, NULL); > > > > > > + tun = chassis_tunnel_find(chassis_tunnels, > ch->name, > > > > > NULL); > > > > > > } else { > > > > > > struct chassis_tunnel *chassis_tunnel = > > > > > > - > chassis_tunnel_find(ch->name, > > > > > NULL); > > > > > > + chassis_tunnel_find(chassis_tunnels, > ch->name, > > > NULL); > > > > > > if (chassis_tunnel && > > > > > > tun->type != chassis_tunnel->type) { > > > > > > static struct vlog_rate_limit rl = > > > > > > @@ -385,7 +347,7 @@ put_remote_port_redirect_overlay(const struct > > > > > > if (!ch) { > > > > > > continue; > > > > > > } > > > > > > - tun = chassis_tunnel_find(ch->name, NULL); > > > > > > + tun = chassis_tunnel_find(chassis_tunnels, ch->name, > > > NULL); > > > > > > if (!tun) { > > > > > > continue; > > > > > > } > > > > > > @@ -925,6 +887,9 @@ consider_port_binding(struct ovsdb_idl_index > > > > > *sbrec_port_binding_by_name, > > > > > > const struct simap *ct_zones, > > > > > > const struct sset *active_tunnels, > > > > > > const struct hmap *local_datapaths, > > > > > > + const struct shash *local_bindings, > > > > > > + const struct simap *patch_ofports, > > > > > > + const struct hmap *chassis_tunnels, > > > > > > const struct sbrec_port_binding *binding, > > > > > > const struct sbrec_chassis *chassis, > > > > > > struct ovn_desired_flow_table *flow_table, > > > > > > @@ -1081,17 +1046,25 @@ consider_port_binding(struct > ovsdb_idl_index > > > > > *sbrec_port_binding_by_name, > > > > > > if (!binding->tag) { > > > > > > goto out; > > > > > > } > > > > > > - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, > > > > > > - binding->parent_port)); > > > > > > + ofport = local_binding_get_lport_ofport(local_bindings, > > > > > > + > > > binding->parent_port); > > > > > > if (ofport) { > > > > > > tag = *binding->tag; > > > > > > nested_container = true; > > > > > > parent_port = lport_lookup_by_name( > > > > > > sbrec_port_binding_by_name, > binding->parent_port); > > > > > > } > > > > > > - } else { > > > > > > - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, > > > > > > + } else if (!strcmp(binding->type, "localnet") > > > > > > + || !strcmp(binding->type, "l2gateway")) { > > > > > > + > > > > > > + ofport = u16_to_ofp(simap_get(patch_ofports, > > > > > > binding->logical_port)); > > > > > > + if (ofport && binding->tag) { > > > > > > + tag = *binding->tag; > > > > > > + } > > > > > > + } else { > > > > > > + ofport = local_binding_get_lport_ofport(local_bindings, > > > > > > + > > > binding->logical_port); > > > > > > const char *requested_chassis = > smap_get(&binding->options, > > > > > > > > > "requested-chassis"); > > > > > > if (ofport && requested_chassis && requested_chassis[0] > && > > > > > > @@ -1102,12 +1075,6 @@ consider_port_binding(struct > ovsdb_idl_index > > > > > *sbrec_port_binding_by_name, > > > > > > */ > > > > > > ofport = 0; > > > > > > } > > > > > > - > > > > > > - if ((!strcmp(binding->type, "localnet") > > > > > > - || !strcmp(binding->type, "l2gateway")) > > > > > > - && ofport && binding->tag) { > > > > > > - tag = *binding->tag; > > > > > > - } > > > > > > } > > > > > > > > > > > > bool is_ha_remote = false; > > > > > > @@ -1118,7 +1085,7 @@ consider_port_binding(struct ovsdb_idl_index > > > > > *sbrec_port_binding_by_name, > > > > > > /* It is remote port, may be reached by tunnel or > localnet > > > port > > > > > */ > > > > > > is_remote = true; > > > > > > if (localnet_port) { > > > > > > - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, > > > > > > + ofport = u16_to_ofp(simap_get(patch_ofports, > > > > > > > > > localnet_port->logical_port)); > > > > > > if (!ofport) { > > > > > > goto out; > > > > > > @@ -1129,7 +1096,8 @@ consider_port_binding(struct ovsdb_idl_index > > > > > *sbrec_port_binding_by_name, > > > > > > if (!binding->chassis) { > > > > > > goto out; > > > > > > } > > > > > > - tun = chassis_tunnel_find(binding->chassis->name, > > > NULL); > > > > > > + tun = chassis_tunnel_find(chassis_tunnels, > > > > > > + binding->chassis->name, > > > NULL); > > > > > > if (!tun) { > > > > > > goto out; > > > > > > } > > > > > > @@ -1383,7 +1351,7 @@ consider_port_binding(struct ovsdb_idl_index > > > > > *sbrec_port_binding_by_name, > > > > > > put_remote_port_redirect_overlay(binding, > is_ha_remote, > > > > > > ha_ch_ordered, > > > > > mff_ovn_geneve, > > > > > > tun, port_key, > &match, > > > > > ofpacts_p, > > > > > > - flow_table); > > > > > > + chassis_tunnels, > > > > > flow_table); > > > > > > } > > > > > > } > > > > > > out: > > > > > > @@ -1396,8 +1364,11 @@ static void > > > > > > consider_mc_group(enum mf_field_id mff_ovn_geneve, > > > > > > const struct simap *ct_zones, > > > > > > const struct hmap *local_datapaths, > > > > > > + struct shash *local_bindings, > > > > > > + struct simap *patch_ofports, > > > > > > const struct sbrec_chassis *chassis, > > > > > > const struct sbrec_multicast_group *mc, > > > > > > + const struct hmap *chassis_tunnels, > > > > > > struct ovn_desired_flow_table *flow_table) > > > > > > { > > > > > > uint32_t dp_key = mc->datapath->tunnel_key; > > > > > > @@ -1444,19 +1415,21 @@ consider_mc_group(enum mf_field_id > > > mff_ovn_geneve, > > > > > > put_load(zone_id, MFF_LOG_CT_ZONE, 0, 32, &ofpacts); > > > > > > } > > > > > > > > > > > > + const char *lport_name = (port->parent_port && > > > > > *port->parent_port) ? > > > > > > + port->parent_port : > > > port->logical_port; > > > > > > + > > > > > > if (!strcmp(port->type, "patch")) { > > > > > > put_load(port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, > > > > > > &remote_ofpacts); > > > > > > put_resubmit(OFTABLE_CHECK_LOOPBACK, > &remote_ofpacts); > > > > > > - } else if (simap_contains(&localvif_to_ofport, > > > > > > - (port->parent_port && > *port->parent_port) > > > > > > - ? port->parent_port : > port->logical_port) > > > > > > + } else if (local_binding_get_primary_pb(local_bindings, > > > > > lport_name) > > > > > > + || simap_contains(patch_ofports, > > > port->logical_port) > > > > > > || (!strcmp(port->type, "l3gateway") > > > > > > && port->chassis == chassis)) { > > > > > > put_load(port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, > > > &ofpacts); > > > > > > put_resubmit(OFTABLE_CHECK_LOOPBACK, &ofpacts); > > > > > > - } else if (port->chassis && > > > !get_localnet_port(local_datapaths, > > > > > > - > mc->datapath->tunnel_key)) { > > > > > > + } else if (port->chassis && !get_localnet_port( > > > > > > + local_datapaths, mc->datapath->tunnel_key)) { > > > > > > /* Add remote chassis only when localnet port not > exist, > > > > > > * otherwise multicast will reach remote ports > through > > > > > localnet > > > > > > * port. */ > > > > > > @@ -1497,7 +1470,7 @@ consider_mc_group(enum mf_field_id > > > mff_ovn_geneve, > > > > > > const struct chassis_tunnel *prev = NULL; > > > > > > SSET_FOR_EACH (chassis_name, &remote_chassis) { > > > > > > const struct chassis_tunnel *tun > > > > > > - = chassis_tunnel_find(chassis_name, NULL); > > > > > > + = chassis_tunnel_find(chassis_tunnels, > chassis_name, > > > > > NULL); > > > > > > if (!tun) { > > > > > > continue; > > > > > > } > > > > > > @@ -1524,41 +1497,50 @@ consider_mc_group(enum mf_field_id > > > mff_ovn_geneve, > > > > > > sset_destroy(&remote_chassis); > > > > > > } > > > > > > > > > > > > -/* Replaces 'old' by 'new' (destroying 'new'). Returns true if > 'old' > > > > > and 'new' > > > > > > - * contained different data, false if they were the same. */ > > > > > > -static bool > > > > > > -update_ofports(struct simap *old, struct simap *new) > > > > > > -{ > > > > > > - bool changed = !simap_equal(old, new); > > > > > > - simap_swap(old, new); > > > > > > - simap_destroy(new); > > > > > > - return changed; > > > > > > -} > > > > > > - > > > > > > void > > > > > > -physical_handle_port_binding_changes(struct physical_ctx *p_ctx, > > > > > > - struct > ovn_desired_flow_table > > > > > *flow_table) > > > > > > +physical_handle_flows_for_lport(const struct sbrec_port_binding > *pb, > > > > > > + bool removed, struct physical_ctx > > > *p_ctx, > > > > > > + struct ovn_desired_flow_table > > > > > *flow_table) > > > > > > { > > > > > > - const struct sbrec_port_binding *binding; > > > > > > - struct ofpbuf ofpacts; > > > > > > - ofpbuf_init(&ofpacts, 0); > > > > > > - SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED (binding, > > > > > > - > > > > > p_ctx->port_binding_table) { > > > > > > - if (sbrec_port_binding_is_deleted(binding)) { > > > > > > - ofctrl_remove_flows(flow_table, > &binding->header_.uuid); > > > > > > - } else { > > > > > > - if (!sbrec_port_binding_is_new(binding)) { > > > > > > - ofctrl_remove_flows(flow_table, > > > &binding->header_.uuid); > > > > > > - } > > > > > > + ofctrl_remove_flows(flow_table, &pb->header_.uuid); > > > > > > + > > > > > > + if (!strcmp(pb->type, "external")) { > > > > > > + /* External lports have a dependency on the localnet > port. > > > > > > + * We need to remove the flows of the localnet port as > well > > > > > > + * and re-consider adding the flows for it. > > > > > > + */ > > > > > > + struct local_datapath *ldp = > > > > > > + get_local_datapath(p_ctx->local_datapaths, > > > > > > + pb->datapath->tunnel_key); > > > > > > + if (ldp && ldp->localnet_port) { > > > > > > + struct ofpbuf ofpacts; > > > > > > + ofctrl_remove_flows(flow_table, > > > > > &ldp->localnet_port->header_.uuid); > > > > > > + ofpbuf_init(&ofpacts, 0); > > > > > > > consider_port_binding(p_ctx->sbrec_port_binding_by_name, > > > > > > p_ctx->mff_ovn_geneve, > > > p_ctx->ct_zones, > > > > > > p_ctx->active_tunnels, > > > > > > p_ctx->local_datapaths, > > > > > > - binding, p_ctx->chassis, > > > > > > + p_ctx->local_bindings, > > > > > > + > &p_ctx->nonvif_data->patch_ofports, > > > > > > + > > > &p_ctx->nonvif_data->chassis_tunnels, > > > > > > + ldp->localnet_port, > p_ctx->chassis, > > > > > > flow_table, &ofpacts); > > > > > > + ofpbuf_uninit(&ofpacts); > > > > > > } > > > > > > } > > > > > > - ofpbuf_uninit(&ofpacts); > > > > > > + > > > > > > + if (!removed) { > > > > > > + struct ofpbuf ofpacts; > > > > > > + ofpbuf_init(&ofpacts, 0); > > > > > > + consider_port_binding(p_ctx->sbrec_port_binding_by_name, > > > > > > + p_ctx->mff_ovn_geneve, > p_ctx->ct_zones, > > > > > > + p_ctx->active_tunnels, > > > > > p_ctx->local_datapaths, > > > > > > + p_ctx->local_bindings, > > > > > > + &p_ctx->nonvif_data->patch_ofports, > > > > > > + > &p_ctx->nonvif_data->chassis_tunnels, > > > pb, > > > > > > + p_ctx->chassis, flow_table, > &ofpacts); > > > > > > + ofpbuf_uninit(&ofpacts); > > > > > > + } > > > > > > } > > > > > > > > > > > > void > > > > > > @@ -1574,8 +1556,11 @@ physical_handle_mc_group_changes(struct > > > > > physical_ctx *p_ctx, > > > > > > ofctrl_remove_flows(flow_table, > &mc->header_.uuid); > > > > > > } > > > > > > consider_mc_group(p_ctx->mff_ovn_geneve, > p_ctx->ct_zones, > > > > > > - p_ctx->local_datapaths, > > > > > > - p_ctx->chassis, mc, flow_table); > > > > > > + p_ctx->local_datapaths, > > > > > p_ctx->local_bindings, > > > > > > + &p_ctx->nonvif_data->patch_ofports, > > > > > > + p_ctx->chassis, mc, > > > > > > + > &p_ctx->nonvif_data->chassis_tunnels, > > > > > > + flow_table); > > > > > > } > > > > > > } > > > > > > } > > > > > > @@ -1591,135 +1576,6 @@ physical_run(struct physical_ctx *p_ctx, > > > > > > uuid_generate(hc_uuid); > > > > > > } > > > > > > > > > > > > - /* This bool tracks physical mapping changes. */ > > > > > > - bool physical_map_changed = false; > > > > > > - > > > > > > - struct simap new_localvif_to_ofport = > > > > > > - SIMAP_INITIALIZER(&new_localvif_to_ofport); > > > > > > - struct simap new_tunnel_to_ofport = > > > > > > - SIMAP_INITIALIZER(&new_tunnel_to_ofport); > > > > > > - for (int i = 0; i < p_ctx->br_int->n_ports; i++) { > > > > > > - const struct ovsrec_port *port_rec = > p_ctx->br_int->ports[i]; > > > > > > - if (!strcmp(port_rec->name, p_ctx->br_int->name)) { > > > > > > - continue; > > > > > > - } > > > > > > - > > > > > > - const char *tunnel_id = smap_get(&port_rec->external_ids, > > > > > > - "ovn-chassis-id"); > > > > > > - if (tunnel_id && encaps_tunnel_id_match(tunnel_id, > > > > > > - > p_ctx->chassis->name, > > > > > > - NULL)) { > > > > > > - continue; > > > > > > - } > > > > > > - > > > > > > - const char *localnet = smap_get(&port_rec->external_ids, > > > > > > - "ovn-localnet-port"); > > > > > > - const char *l2gateway = smap_get(&port_rec->external_ids, > > > > > > - "ovn-l2gateway-port"); > > > > > > - > > > > > > - for (int j = 0; j < port_rec->n_interfaces; j++) { > > > > > > - const struct ovsrec_interface *iface_rec = > > > > > port_rec->interfaces[j]; > > > > > > - > > > > > > - /* Get OpenFlow port number. */ > > > > > > - if (!iface_rec->n_ofport) { > > > > > > - continue; > > > > > > - } > > > > > > - int64_t ofport = iface_rec->ofport[0]; > > > > > > - if (ofport < 1 || ofport > ofp_to_u16(OFPP_MAX)) { > > > > > > - continue; > > > > > > - } > > > > > > - > > > > > > - /* Record as patch to local net, logical patch port, > > > > > chassis, or > > > > > > - * local logical port. */ > > > > > > - bool is_patch = !strcmp(iface_rec->type, "patch"); > > > > > > - if (is_patch && localnet) { > > > > > > - /* localnet patch ports can be handled just like > > > VIFs. */ > > > > > > - simap_put(&new_localvif_to_ofport, localnet, > ofport); > > > > > > - break; > > > > > > - } else if (is_patch && l2gateway) { > > > > > > - /* L2 gateway patch ports can be handled just > like > > > VIFs. > > > > > */ > > > > > > - simap_put(&new_localvif_to_ofport, l2gateway, > > > ofport); > > > > > > - break; > > > > > > - } else if (tunnel_id) { > > > > > > - enum chassis_tunnel_type tunnel_type; > > > > > > - if (!strcmp(iface_rec->type, "geneve")) { > > > > > > - tunnel_type = GENEVE; > > > > > > - if (!p_ctx->mff_ovn_geneve) { > > > > > > - continue; > > > > > > - } > > > > > > - } else if (!strcmp(iface_rec->type, "stt")) { > > > > > > - tunnel_type = STT; > > > > > > - } else if (!strcmp(iface_rec->type, "vxlan")) { > > > > > > - tunnel_type = VXLAN; > > > > > > - } else { > > > > > > - continue; > > > > > > - } > > > > > > - > > > > > > - simap_put(&new_tunnel_to_ofport, tunnel_id, > ofport); > > > > > > - /* > > > > > > - * We split the tunnel_id to get the chassis-id > > > > > > - * and hash the tunnel list on the chassis-id. > The > > > > > > - * reason to use the chassis-id alone is because > > > > > > - * there might be cases (multicast, gateway > chassis) > > > > > > - * where we need to tunnel to the chassis, but > won't > > > > > > - * have the encap-ip specifically. > > > > > > - */ > > > > > > - char *hash_id = NULL; > > > > > > - char *ip = NULL; > > > > > > - > > > > > > - if (!encaps_tunnel_id_parse(tunnel_id, &hash_id, > > > &ip)) { > > > > > > - continue; > > > > > > - } > > > > > > - struct chassis_tunnel *tun = > > > > > chassis_tunnel_find(hash_id, ip); > > > > > > - if (tun) { > > > > > > - /* If the tunnel's ofport has changed, > update. */ > > > > > > - if (tun->ofport != u16_to_ofp(ofport) || > > > > > > - tun->type != tunnel_type) { > > > > > > - tun->ofport = u16_to_ofp(ofport); > > > > > > - tun->type = tunnel_type; > > > > > > - physical_map_changed = true; > > > > > > - } > > > > > > - } else { > > > > > > - tun = xmalloc(sizeof *tun); > > > > > > - hmap_insert(&tunnels, &tun->hmap_node, > > > > > > - hash_string(hash_id, 0)); > > > > > > - tun->chassis_id = xstrdup(tunnel_id); > > > > > > - tun->ofport = u16_to_ofp(ofport); > > > > > > - tun->type = tunnel_type; > > > > > > - physical_map_changed = true; > > > > > > - } > > > > > > - free(hash_id); > > > > > > - free(ip); > > > > > > - break; > > > > > > - } else { > > > > > > - const char *iface_id = > > > smap_get(&iface_rec->external_ids, > > > > > > - "iface-id"); > > > > > > - if (iface_id) { > > > > > > - simap_put(&new_localvif_to_ofport, iface_id, > > > ofport); > > > > > > - } > > > > > > - } > > > > > > - } > > > > > > - } > > > > > > - > > > > > > - /* Remove tunnels that are no longer here. */ > > > > > > - struct chassis_tunnel *tun, *tun_next; > > > > > > - HMAP_FOR_EACH_SAFE (tun, tun_next, hmap_node, &tunnels) { > > > > > > - if (!simap_find(&new_tunnel_to_ofport, tun->chassis_id)) > { > > > > > > - hmap_remove(&tunnels, &tun->hmap_node); > > > > > > - physical_map_changed = true; > > > > > > - free(tun->chassis_id); > > > > > > - free(tun); > > > > > > - } > > > > > > - } > > > > > > - > > > > > > - /* Capture changed or removed openflow ports. */ > > > > > > - physical_map_changed |= update_ofports(&localvif_to_ofport, > > > > > > - > &new_localvif_to_ofport); > > > > > > - if (physical_map_changed) { > > > > > > - /* Reprocess logical flow table immediately. */ > > > > > > - poll_immediate_wake(); > > > > > > - } > > > > > > - > > > > > > struct ofpbuf ofpacts; > > > > > > ofpbuf_init(&ofpacts, 0); > > > > > > > > > > > > @@ -1733,16 +1589,20 @@ physical_run(struct physical_ctx *p_ctx, > > > > > > consider_port_binding(p_ctx->sbrec_port_binding_by_name, > > > > > > p_ctx->mff_ovn_geneve, > p_ctx->ct_zones, > > > > > > p_ctx->active_tunnels, > > > > > p_ctx->local_datapaths, > > > > > > - binding, p_ctx->chassis, > > > > > > - flow_table, &ofpacts); > > > > > > + p_ctx->local_bindings, > > > > > > + &p_ctx->nonvif_data->patch_ofports, > > > > > > + > &p_ctx->nonvif_data->chassis_tunnels, > > > > > binding, > > > > > > + p_ctx->chassis, flow_table, > &ofpacts); > > > > > > } > > > > > > > > > > > > /* Handle output to multicast groups, in tables 32 and 33. */ > > > > > > const struct sbrec_multicast_group *mc; > > > > > > SBREC_MULTICAST_GROUP_TABLE_FOR_EACH (mc, > p_ctx->mc_group_table) > > > { > > > > > > consider_mc_group(p_ctx->mff_ovn_geneve, p_ctx->ct_zones, > > > > > > - p_ctx->local_datapaths, p_ctx->chassis, > > > > > > - mc, flow_table); > > > > > > + p_ctx->local_datapaths, > > > p_ctx->local_bindings, > > > > > > + &p_ctx->nonvif_data->patch_ofports, > > > > > p_ctx->chassis, > > > > > > + mc, > &p_ctx->nonvif_data->chassis_tunnels, > > > > > > + flow_table); > > > > > > } > > > > > > > > > > > > /* Table 0, priority 100. > > > > > > @@ -1757,7 +1617,8 @@ physical_run(struct physical_ctx *p_ctx, > > > > > > * We set MFF_LOG_DATAPATH, MFF_LOG_INPORT, and > MFF_LOG_OUTPORT > > > from > > > > > the > > > > > > * tunnel key data where possible, then resubmit to table 33 > to > > > > > handle > > > > > > * packets to the local hypervisor. */ > > > > > > - HMAP_FOR_EACH (tun, hmap_node, &tunnels) { > > > > > > + struct chassis_tunnel *tun; > > > > > > + HMAP_FOR_EACH (tun, hmap_node, > > > &p_ctx->nonvif_data->chassis_tunnels) > > > > > { > > > > > > struct match match = MATCH_CATCHALL_INITIALIZER; > > > > > > match_set_in_port(&match, tun->ofport); > > > > > > > > > > > > @@ -1788,7 +1649,7 @@ physical_run(struct physical_ctx *p_ctx, > > > > > > } > > > > > > > > > > > > /* Handle ramp switch encapsulations. */ > > > > > > - HMAP_FOR_EACH (tun, hmap_node, &tunnels) { > > > > > > + HMAP_FOR_EACH (tun, hmap_node, > > > &p_ctx->nonvif_data->chassis_tunnels) > > > > > { > > > > > > if (tun->type != VXLAN) { > > > > > > continue; > > > > > > } > > > > > > @@ -1925,13 +1786,10 @@ physical_run(struct physical_ctx *p_ctx, > > > > > > &ofpacts, hc_uuid); > > > > > > > > > > > > ofpbuf_uninit(&ofpacts); > > > > > > - > > > > > > - simap_destroy(&new_tunnel_to_ofport); > > > > > > } > > > > > > > > > > > > bool > > > > > > -physical_handle_ovs_iface_changes(struct physical_ctx *p_ctx, > > > > > > - struct ovn_desired_flow_table > > > > > *flow_table) > > > > > > +physical_handle_ovs_iface_changes(struct physical_ctx *p_ctx) > > > > > > { > > > > > > const struct ovsrec_interface *iface_rec; > > > > > > OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, > > > > > p_ctx->iface_table) { > > > > > > @@ -1943,64 +1801,6 @@ physical_handle_ovs_iface_changes(struct > > > > > physical_ctx *p_ctx, > > > > > > } > > > > > > } > > > > > > > > > > > > - struct ofpbuf ofpacts; > > > > > > - ofpbuf_init(&ofpacts, 0); > > > > > > - > > > > > > - OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, > > > > > p_ctx->iface_table) { > > > > > > - const char *iface_id = smap_get(&iface_rec->external_ids, > > > > > "iface-id"); > > > > > > - if (!iface_id) { > > > > > > - continue; > > > > > > - } > > > > > > - > > > > > > - const struct sbrec_port_binding *lb_pb = > > > > > > - local_binding_get_primary_pb(p_ctx->local_bindings, > > > > > iface_id); > > > > > > - if (!lb_pb) { > > > > > > - /* For regular VIFs (e.g. lsp) the upcoming > port-binding > > > > > update > > > > > > - * will remove lfows related to the unclaimed ovs > port. > > > > > > - * Localport is a special case and it needs to be > managed > > > > > here > > > > > > - * since the port is not binded and otherwise the > related > > > > > lfows > > > > > > - * will not be cleared removing the ovs port. > > > > > > - */ > > > > > > - lb_pb = > > > > > lport_lookup_by_name(p_ctx->sbrec_port_binding_by_name, > > > > > > - iface_id); > > > > > > - if (!lb_pb || strcmp(lb_pb->type, "localport")) { > > > > > > - continue; > > > > > > - } > > > > > > - } > > > > > > - > > > > > > - int64_t ofport = iface_rec->n_ofport ? > *iface_rec->ofport : > > > 0; > > > > > > - if (ovsrec_interface_is_deleted(iface_rec)) { > > > > > > - ofctrl_remove_flows(flow_table, > &lb_pb->header_.uuid); > > > > > > - simap_find_and_delete(&localvif_to_ofport, iface_id); > > > > > > - } else { > > > > > > - if (!ovsrec_interface_is_new(iface_rec)) { > > > > > > - ofctrl_remove_flows(flow_table, > > > &lb_pb->header_.uuid); > > > > > > - } > > > > > > - > > > > > > - simap_put(&localvif_to_ofport, iface_id, ofport); > > > > > > - > consider_port_binding(p_ctx->sbrec_port_binding_by_name, > > > > > > - p_ctx->mff_ovn_geneve, > > > p_ctx->ct_zones, > > > > > > - p_ctx->active_tunnels, > > > > > > - p_ctx->local_datapaths, > > > > > > - lb_pb, p_ctx->chassis, > > > > > > - flow_table, &ofpacts); > > > > > > - } > > > > > > - } > > > > > > - > > > > > > - ofpbuf_uninit(&ofpacts); > > > > > > - return true; > > > > > > -} > > > > > > - > > > > > > -bool > > > > > > -get_tunnel_ofport(const char *chassis_name, char *encap_ip, > > > ofp_port_t > > > > > *ofport) > > > > > > -{ > > > > > > - struct chassis_tunnel *tun = NULL; > > > > > > - tun = chassis_tunnel_find(chassis_name, encap_ip); > > > > > > - if (!tun) { > > > > > > - return false; > > > > > > - } > > > > > > - > > > > > > - *ofport = tun->ofport; > > > > > > return true; > > > > > > } > > > > > > > > > > > > diff --git a/controller/physical.h b/controller/physical.h > > > > > > index feab41df4..3fdc20005 100644 > > > > > > --- a/controller/physical.h > > > > > > +++ b/controller/physical.h > > > > > > @@ -34,6 +34,7 @@ struct simap; > > > > > > struct sbrec_multicast_group_table; > > > > > > struct sbrec_port_binding_table; > > > > > > struct sset; > > > > > > +struct local_nonvif_data; > > > > > > > > > > > > /* OVN Geneve option information. > > > > > > * > > > > > > @@ -56,18 +57,18 @@ struct physical_ctx { > > > > > > const struct simap *ct_zones; > > > > > > enum mf_field_id mff_ovn_geneve; > > > > > > struct shash *local_bindings; > > > > > > + struct local_nonvif_data *nonvif_data; > > > > > > }; > > > > > > > > > > > > void physical_register_ovs_idl(struct ovsdb_idl *); > > > > > > void physical_run(struct physical_ctx *, > > > > > > struct ovn_desired_flow_table *); > > > > > > void physical_clear_unassoc_flows_with_db(struct > > > ovn_desired_flow_table > > > > > *); > > > > > > -void physical_handle_port_binding_changes(struct physical_ctx *, > > > > > > - struct > > > ovn_desired_flow_table > > > > > *); > > > > > > void physical_handle_mc_group_changes(struct physical_ctx *, > > > > > > struct > ovn_desired_flow_table > > > *); > > > > > > -bool physical_handle_ovs_iface_changes(struct physical_ctx *, > > > > > > - struct > ovn_desired_flow_table > > > *); > > > > > > -bool get_tunnel_ofport(const char *chassis_name, char *encap_ip, > > > > > > - ofp_port_t *ofport); > > > > > > +bool physical_handle_ovs_iface_changes(struct physical_ctx *); > > > > > > +void physical_handle_flows_for_lport(const struct > sbrec_port_binding > > > *, > > > > > > + bool removed, > > > > > > + struct physical_ctx *, > > > > > > + struct > ovn_desired_flow_table > > > *); > > > > > > #endif /* controller/physical.h */ > > > > > > -- > > > > > > 2.31.1 > > > > > > > > > > > > _______________________________________________ > > > > > > dev mailing list > > > > > > dev@openvswitch.org > > > > > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > > > > _______________________________________________ > > > > > dev mailing list > > > > > dev@openvswitch.org > > > > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > > > > > > > _______________________________________________ > > > dev mailing list > > > dev@openvswitch.org > > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > > > _______________________________________________ > dev mailing list > dev@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev >
diff --git a/controller/binding.c b/controller/binding.c index 0fd951ad7..b50139726 100644 --- a/controller/binding.c +++ b/controller/binding.c @@ -546,23 +546,6 @@ update_active_pb_ras_pd(const struct sbrec_port_binding *pb, } } -/* Corresponds to each Port_Binding.type. */ -enum en_lport_type { - LP_UNKNOWN, - LP_VIF, - LP_CONTAINER, - LP_PATCH, - LP_L3GATEWAY, - LP_LOCALNET, - LP_LOCALPORT, - LP_L2GATEWAY, - LP_VTEP, - LP_CHASSISREDIRECT, - LP_VIRTUAL, - LP_EXTERNAL, - LP_REMOTE -}; - /* Local bindings. binding.c module binds the logical port (represented by * Port_Binding rows) and sets the 'chassis' column when it sees the * OVS interface row (of type "" or "internal") with the @@ -616,7 +599,7 @@ static struct local_binding *local_binding_create( static void local_binding_add(struct shash *local_bindings, struct local_binding *); static struct local_binding *local_binding_find( - struct shash *local_bindings, const char *name); + const struct shash *local_bindings, const char *name); static void local_binding_destroy(struct local_binding *, struct shash *binding_lports); static void local_binding_delete(struct local_binding *, @@ -701,7 +684,8 @@ local_binding_data_destroy(struct local_binding_data *lbinding_data) } const struct sbrec_port_binding * -local_binding_get_primary_pb(struct shash *local_bindings, const char *pb_name) +local_binding_get_primary_pb(struct shash *local_bindings, + const char *pb_name) { struct local_binding *lbinding = local_binding_find(local_bindings, pb_name); @@ -710,6 +694,19 @@ local_binding_get_primary_pb(struct shash *local_bindings, const char *pb_name) return b_lport ? b_lport->pb : NULL; } +ofp_port_t +local_binding_get_lport_ofport(const struct shash *local_bindings, + const char *pb_name) +{ + struct local_binding *lbinding = + local_binding_find(local_bindings, pb_name); + struct binding_lport *b_lport = + local_binding_get_primary_or_localport_lport(lbinding); + + return (b_lport && lbinding->iface && lbinding->iface->n_ofport) ? + u16_to_ofp(lbinding->iface->ofport[0]) : 0; +} + bool local_binding_is_up(struct shash *local_bindings, const char *pb_name) { @@ -871,7 +868,7 @@ is_lport_vif(const struct sbrec_port_binding *pb) return !pb->type[0]; } -static enum en_lport_type +enum en_lport_type get_lport_type(const struct sbrec_port_binding *pb) { if (is_lport_vif(pb)) { @@ -2555,7 +2552,7 @@ local_binding_create(const char *name, const struct ovsrec_interface *iface) } static struct local_binding * -local_binding_find(struct shash *local_bindings, const char *name) +local_binding_find(const struct shash *local_bindings, const char *name) { return shash_find_data(local_bindings, name); } diff --git a/controller/binding.h b/controller/binding.h index b1717bd2b..f1abc4b9c 100644 --- a/controller/binding.h +++ b/controller/binding.h @@ -114,6 +114,9 @@ void local_binding_data_destroy(struct local_binding_data *); const struct sbrec_port_binding *local_binding_get_primary_pb( struct shash *local_bindings, const char *pb_name); +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_down(struct shash *local_bindings, const char *pb_name); void local_binding_set_up(struct shash *local_bindings, const char *pb_name, @@ -134,4 +137,24 @@ bool binding_handle_port_binding_changes(struct binding_ctx_in *, void binding_tracked_dp_destroy(struct hmap *tracked_datapaths); void binding_dump_local_bindings(struct local_binding_data *, struct ds *); + +/* Corresponds to each Port_Binding.type. */ +enum en_lport_type { + LP_UNKNOWN, + LP_VIF, + LP_CONTAINER, + LP_PATCH, + LP_L3GATEWAY, + LP_LOCALNET, + LP_LOCALPORT, + LP_L2GATEWAY, + LP_VTEP, + LP_CHASSISREDIRECT, + LP_VIRTUAL, + LP_EXTERNAL, + LP_REMOTE +}; + +enum en_lport_type get_lport_type(const struct sbrec_port_binding *); + #endif /* controller/binding.h */ diff --git a/controller/ldata.c b/controller/ldata.c index a6df9b1da..f55905551 100644 --- a/controller/ldata.c +++ b/controller/ldata.c @@ -18,10 +18,13 @@ /* OVS includes. */ #include "include/openvswitch/json.h" #include "lib/hmapx.h" +#include "lib/flow.h" #include "lib/util.h" +#include "lib/vswitch-idl.h" #include "openvswitch/vlog.h" /* OVN includes. */ +#include "encaps.h" #include "ldata.h" #include "lport.h" #include "lib/ovn-util.h" @@ -275,6 +278,172 @@ tracked_datapaths_destroy(struct hmap *tracked_datapaths) hmap_destroy(tracked_datapaths); } +/* Iterates the br_int ports and build the simap of patch to ofports + * and chassis tunnels. */ +void +ldata_run(const struct ovsrec_bridge *br_int, + const struct sbrec_chassis *chassis_rec, + struct local_nonvif_data *nonvif_data) +{ + for (int i = 0; i < br_int->n_ports; i++) { + const struct ovsrec_port *port_rec = br_int->ports[i]; + if (!strcmp(port_rec->name, br_int->name)) { + continue; + } + + const char *tunnel_id = smap_get(&port_rec->external_ids, + "ovn-chassis-id"); + if (tunnel_id && encaps_tunnel_id_match(tunnel_id, + chassis_rec->name, + NULL)) { + continue; + } + + const char *localnet = smap_get(&port_rec->external_ids, + "ovn-localnet-port"); + const char *l2gateway = smap_get(&port_rec->external_ids, + "ovn-l2gateway-port"); + + for (int j = 0; j < port_rec->n_interfaces; j++) { + const struct ovsrec_interface *iface_rec = port_rec->interfaces[j]; + + /* Get OpenFlow port number. */ + if (!iface_rec->n_ofport) { + continue; + } + int64_t ofport = iface_rec->ofport[0]; + if (ofport < 1 || ofport > ofp_to_u16(OFPP_MAX)) { + continue; + } + + bool is_patch = !strcmp(iface_rec->type, "patch"); + if (is_patch && localnet) { + simap_put(&nonvif_data->patch_ofports, localnet, ofport); + break; + } else if (is_patch && l2gateway) { + /* L2 gateway patch ports can be handled just like VIFs. */ + simap_put(&nonvif_data->patch_ofports, l2gateway, ofport); + break; + } else if (tunnel_id) { + enum chassis_tunnel_type tunnel_type; + if (!strcmp(iface_rec->type, "geneve")) { + tunnel_type = GENEVE; + } else if (!strcmp(iface_rec->type, "stt")) { + tunnel_type = STT; + } else if (!strcmp(iface_rec->type, "vxlan")) { + tunnel_type = VXLAN; + } else { + continue; + } + + /* We split the tunnel_id to get the chassis-id + * and hash the tunnel list on the chassis-id. The + * reason to use the chassis-id alone is because + * there might be cases (multicast, gateway chassis) + * where we need to tunnel to the chassis, but won't + * have the encap-ip specifically. + */ + char *hash_id = NULL; + char *ip = NULL; + + if (!encaps_tunnel_id_parse(tunnel_id, &hash_id, &ip)) { + continue; + } + struct chassis_tunnel *tun = xmalloc(sizeof *tun); + hmap_insert(&nonvif_data->chassis_tunnels, &tun->hmap_node, + hash_string(hash_id, 0)); + tun->chassis_id = xstrdup(tunnel_id); + tun->ofport = u16_to_ofp(ofport); + tun->type = tunnel_type; + + free(hash_id); + free(ip); + break; + } + } + } +} + +bool +ldata_handle_ovs_iface_changes( + const struct ovsrec_interface_table *iface_table) +{ + const struct ovsrec_interface *iface_rec; + OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, iface_table) { + if (!strcmp(iface_rec->type, "geneve") || + !strcmp(iface_rec->type, "patch") || + !strcmp(iface_rec->type, "vxlan") || + !strcmp(iface_rec->type, "stt")) { + return false; + } + } + + return true; +} + +bool +get_chassis_tunnel_ofport(const struct hmap *chassis_tunnels, + const char *chassis_name, char *encap_ip, + ofp_port_t *ofport) +{ + struct chassis_tunnel *tun = NULL; + tun = chassis_tunnel_find(chassis_tunnels, chassis_name, encap_ip); + if (!tun) { + return false; + } + + *ofport = tun->ofport; + return true; +} + +void +local_nonvif_data_init(struct local_nonvif_data *nonvif_data) +{ + simap_init(&nonvif_data->patch_ofports); + hmap_init(&nonvif_data->chassis_tunnels); +} + +void +local_nonvif_data_destroy(struct local_nonvif_data *nonvif_data) +{ + simap_destroy(&nonvif_data->patch_ofports); + struct chassis_tunnel *tun; + HMAP_FOR_EACH_POP (tun, hmap_node, &nonvif_data->chassis_tunnels) { + free(tun->chassis_id); + free(tun); + } + hmap_destroy(&nonvif_data->chassis_tunnels); +} + + +/* + * This function looks up the list of tunnel ports (provided by + * ovn-chassis-id ports) and returns the tunnel for the given chassid-id and + * encap-ip. The ovn-chassis-id is formed using the chassis-id and encap-ip. + * The list is hashed using the chassis-id. If the encap-ip is not specified, + * it means we'll just return a tunnel for that chassis-id, i.e. we just check + * for chassis-id and if there is a match, we'll return the tunnel. + * If encap-ip is also provided we use both chassis-id and encap-ip to do + * a more specific lookup. + */ +struct chassis_tunnel * +chassis_tunnel_find(const struct hmap *chassis_tunnels, const char *chassis_id, + char *encap_ip) +{ + /* + * If the specific encap_ip is given, look for the chassisid_ip entry, + * else return the 1st found entry for the chassis. + */ + struct chassis_tunnel *tun = NULL; + HMAP_FOR_EACH_WITH_HASH (tun, hmap_node, hash_string(chassis_id, 0), + chassis_tunnels) { + if (encaps_tunnel_id_match(tun->chassis_id, chassis_id, encap_ip)) { + return tun; + } + } + return NULL; +} + /* static functions. */ static struct local_datapath * local_datapath_add__(struct hmap *local_datapaths, diff --git a/controller/ldata.h b/controller/ldata.h index 16ad43c8f..91624d0b4 100644 --- a/controller/ldata.h +++ b/controller/ldata.h @@ -19,10 +19,14 @@ /* OVS includes. */ #include "include/openvswitch/shash.h" #include "lib/smap.h" +#include "lib/simap.h" struct sbrec_datapath_binding; struct sbrec_port_binding; +struct sbrec_chassis; struct ovsdb_idl_index; +struct ovsrec_bridge; +struct ovsrec_interface_table; /* A logical datapath that has some relevance to this hypervisor. A logical * datapath D is relevant to hypervisor H if: @@ -117,4 +121,44 @@ void tracked_datapath_lport_add(const struct sbrec_port_binding *, struct hmap *tracked_datapaths); void tracked_datapaths_destroy(struct hmap *tracked_datapaths); +/* Must be a bit-field ordered from most-preferred (higher number) to + * least-preferred (lower number). */ +enum chassis_tunnel_type { + GENEVE = 1 << 2, + STT = 1 << 1, + VXLAN = 1 << 0 +}; + +/* Maps from a chassis to the OpenFlow port number of the tunnel that can be + * used to reach that chassis. */ +struct chassis_tunnel { + struct hmap_node hmap_node; + char *chassis_id; + ofp_port_t ofport; + enum chassis_tunnel_type type; +}; + +struct local_nonvif_data { + struct simap patch_ofports; /* simap of patch ovs ports. */ + struct hmap chassis_tunnels; /* hmap of 'struct chassis_tunnel' from the + * tunnel OVS ports. */ +}; + +void ldata_run(const struct ovsrec_bridge *br_int, + const struct sbrec_chassis *, + struct local_nonvif_data *nonvif_data); + +bool ldata_handle_ovs_iface_changes(const struct ovsrec_interface_table *); + +struct chassis_tunnel *chassis_tunnel_find(const struct hmap *chassis_tunnels, + const char *chassis_id, + char *encap_ip); + +bool get_chassis_tunnel_ofport(const struct hmap *chassis_tunnels, + const char *chassis_name, char *encap_ip, + ofp_port_t *ofport); + +void local_nonvif_data_init(struct local_nonvif_data *nonvif_data); +void local_nonvif_data_destroy(struct local_nonvif_data *nonvif_data); + #endif /* controller/ldata.h */ diff --git a/controller/lflow.c b/controller/lflow.c index d1f32077b..4ac671e40 100644 --- a/controller/lflow.c +++ b/controller/lflow.c @@ -58,6 +58,7 @@ struct lookup_port_aux { const struct sbrec_datapath_binding *dp; const struct sbrec_logical_flow *lflow; struct lflow_resource_ref *lfrr; + const struct hmap *chassis_tunnels; }; struct condition_aux { @@ -145,7 +146,8 @@ tunnel_ofport_cb(const void *aux_, const char *port_name, ofp_port_t *ofport) return false; } - if (!get_tunnel_ofport(pb->chassis->name, NULL, ofport)) { + if (!get_chassis_tunnel_ofport(aux->chassis_tunnels, pb->chassis->name, + NULL, ofport)) { return false; } @@ -591,6 +593,7 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow, .dp = dp, .lflow = lflow, .lfrr = l_ctx_out->lfrr, + .chassis_tunnels = l_ctx_in->chassis_tunnels, }; /* Encode OVN logical actions into OpenFlow. */ diff --git a/controller/lflow.h b/controller/lflow.h index c17ff6dd4..e7dd31289 100644 --- a/controller/lflow.h +++ b/controller/lflow.h @@ -146,6 +146,7 @@ struct lflow_ctx_in { const struct shash *port_groups; const struct sset *active_tunnels; const struct sset *related_lport_ids; + const struct hmap *chassis_tunnels; }; struct lflow_ctx_out { diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 8f620e4ad..69d135046 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -1039,6 +1039,11 @@ struct ed_type_runtime_data { struct related_lports related_lports; struct sset active_tunnels; + /* Non VIF OVS interface information (mainly patch OVS interfacs + * and tunnel interfaces) that are relevant to the local + * chassis (generated by ldata_run()). */ + struct local_nonvif_data nonvif_data; + /* runtime data engine private data. */ struct sset egress_ifaces; struct smap local_iface_ids; @@ -1139,6 +1144,7 @@ en_runtime_data_init(struct engine_node *node OVS_UNUSED, local_binding_data_init(&data->lbinding_data); shash_init(&data->local_active_ports_ipv6_pd); shash_init(&data->local_active_ports_ras); + local_nonvif_data_init(&data->nonvif_data); /* Init the tracked data. */ hmap_init(&data->tracked_dp_bindings); @@ -1160,6 +1166,7 @@ en_runtime_data_cleanup(void *data) shash_destroy_free_data(&rt_data->local_active_ports_ipv6_pd); shash_destroy_free_data(&rt_data->local_active_ports_ras); local_binding_data_destroy(&rt_data->lbinding_data); + local_nonvif_data_destroy(&rt_data->nonvif_data); } static void @@ -1272,6 +1279,7 @@ en_runtime_data_run(struct engine_node *node, void *data) shash_clear_free_data(local_active_ipv6_pd); shash_clear_free_data(local_active_ras); local_binding_data_destroy(&rt_data->lbinding_data); + local_nonvif_data_destroy(&rt_data->nonvif_data); sset_destroy(local_lports); related_lports_destroy(&rt_data->related_lports); sset_destroy(active_tunnels); @@ -1284,6 +1292,7 @@ en_runtime_data_run(struct engine_node *node, void *data) sset_init(&rt_data->egress_ifaces); smap_init(&rt_data->local_iface_ids); local_binding_data_init(&rt_data->lbinding_data); + local_nonvif_data_init(&rt_data->nonvif_data); } struct binding_ctx_in b_ctx_in; @@ -1303,6 +1312,7 @@ en_runtime_data_run(struct engine_node *node, void *data) bfd_calculate_active_tunnels(b_ctx_in.br_int, active_tunnels); } + ldata_run(b_ctx_in.br_int, b_ctx_in.chassis_rec, &rt_data->nonvif_data); binding_run(&b_ctx_in, &b_ctx_out); engine_set_node_state(node, EN_UPDATED); @@ -1318,6 +1328,10 @@ runtime_data_ovs_interface_handler(struct engine_node *node, void *data) rt_data->tracked = true; b_ctx_out.tracked_dp_bindings = &rt_data->tracked_dp_bindings; + if (!ldata_handle_ovs_iface_changes(b_ctx_in.iface_table)) { + return false; + } + if (!binding_handle_ovs_interface_changes(&b_ctx_in, &b_ctx_out)) { return false; } @@ -2060,6 +2074,7 @@ init_lflow_ctx(struct engine_node *node, l_ctx_in->port_groups = port_groups; l_ctx_in->active_tunnels = &rt_data->active_tunnels; l_ctx_in->related_lport_ids = &rt_data->related_lports.lport_ids; + l_ctx_in->chassis_tunnels = &rt_data->nonvif_data.chassis_tunnels; l_ctx_out->flow_table = &fo->flow_table; l_ctx_out->group_table = &fo->group_table; @@ -2527,6 +2542,7 @@ static void init_physical_ctx(struct engine_node *node, p_ctx->ct_zones = ct_zones; p_ctx->mff_ovn_geneve = ed_mff_ovn_geneve->mff_ovn_geneve; p_ctx->local_bindings = &rt_data->lbinding_data.bindings; + p_ctx->nonvif_data = &rt_data->nonvif_data; } static void * @@ -2583,7 +2599,11 @@ pflow_output_sb_port_binding_handler(struct engine_node *node, * only. flow_output runtime data handler takes care of processing * logical flows for any port binding changes. */ - physical_handle_port_binding_changes(&p_ctx, &pfo->flow_table); + const struct sbrec_port_binding *pb; + SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED (pb, p_ctx.port_binding_table) { + bool removed = sbrec_port_binding_is_deleted(pb); + physical_handle_flows_for_lport(pb, removed, &p_ctx, &pfo->flow_table); + } engine_set_node_state(node, EN_UPDATED); return true; @@ -2613,13 +2633,55 @@ pflow_output_ovs_iface_handler(struct engine_node *node OVS_UNUSED, struct ed_type_runtime_data *rt_data = engine_get_input_data("runtime_data", node); + struct physical_ctx p_ctx; + init_physical_ctx(node, rt_data, &p_ctx); + + engine_set_node_state(node, EN_UPDATED); + return physical_handle_ovs_iface_changes(&p_ctx); +} + +static bool +pflow_output_runtime_data_handler(struct engine_node *node, void *data) +{ + struct ed_type_runtime_data *rt_data = + engine_get_input_data("runtime_data", node); + + /* There is no tracked data. Fall back to full recompute of + * pflow_output. */ + if (!rt_data->tracked) { + return false; + } + + struct hmap *tracked_dp_bindings = &rt_data->tracked_dp_bindings; + if (hmap_is_empty(tracked_dp_bindings)) { + return true; + } + struct ed_type_pflow_output *pfo = data; struct physical_ctx p_ctx; init_physical_ctx(node, rt_data, &p_ctx); + struct tracked_datapath *tdp; + HMAP_FOR_EACH (tdp, node, tracked_dp_bindings) { + if (tdp->tracked_type != TRACKED_RESOURCE_UPDATED) { + /* Fall back to full recompute when a local datapath + * is added or deleted. */ + return false; + } + + struct shash_node *shash_node; + SHASH_FOR_EACH (shash_node, &tdp->lports) { + struct tracked_lport *lport = shash_node->data; + bool removed = + lport->tracked_type == TRACKED_RESOURCE_REMOVED ? true: false; + physical_handle_flows_for_lport(lport->pb, removed, &p_ctx, + &pfo->flow_table); + } + } + engine_set_node_state(node, EN_UPDATED); - return physical_handle_ovs_iface_changes(&p_ctx, &pfo->flow_table); + return true; } static void * @@ -2914,7 +2976,7 @@ main(int argc, char *argv[]) pflow_output_sb_multicast_group_handler); engine_add_input(&en_pflow_output, &en_runtime_data, - NULL); + pflow_output_runtime_data_handler); engine_add_input(&en_pflow_output, &en_sb_encap, NULL); engine_add_input(&en_pflow_output, &en_mff_ovn_geneve, NULL); engine_add_input(&en_pflow_output, &en_ovs_open_vswitch, NULL); diff --git a/controller/ovn-controller.h b/controller/ovn-controller.h index 578588305..78a53312f 100644 --- a/controller/ovn-controller.h +++ b/controller/ovn-controller.h @@ -45,14 +45,6 @@ const struct ovsrec_bridge *get_bridge(const struct ovsrec_bridge_table *, struct sbrec_encap *preferred_encap(const struct sbrec_chassis *); -/* Must be a bit-field ordered from most-preferred (higher number) to - * least-preferred (lower number). */ -enum chassis_tunnel_type { - GENEVE = 1 << 2, - STT = 1 << 1, - VXLAN = 1 << 0 -}; - uint32_t get_tunnel_type(const char *name); struct pb_ld_binding { diff --git a/controller/physical.c b/controller/physical.c index b244ff1c2..87080d001 100644 --- a/controller/physical.c +++ b/controller/physical.c @@ -86,46 +86,6 @@ physical_register_ovs_idl(struct ovsdb_idl *ovs_idl) ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_external_ids); } -static struct simap localvif_to_ofport = - SIMAP_INITIALIZER(&localvif_to_ofport); -static struct hmap tunnels = HMAP_INITIALIZER(&tunnels); - -/* Maps from a chassis to the OpenFlow port number of the tunnel that can be - * used to reach that chassis. */ -struct chassis_tunnel { - struct hmap_node hmap_node; - char *chassis_id; - ofp_port_t ofport; - enum chassis_tunnel_type type; -}; - -/* - * This function looks up the list of tunnel ports (provided by - * ovn-chassis-id ports) and returns the tunnel for the given chassid-id and - * encap-ip. The ovn-chassis-id is formed using the chassis-id and encap-ip. - * The list is hashed using the chassis-id. If the encap-ip is not specified, - * it means we'll just return a tunnel for that chassis-id, i.e. we just check - * for chassis-id and if there is a match, we'll return the tunnel. - * If encap-ip is also provided we use both chassis-id and encap-ip to do - * a more specific lookup. - */ -static struct chassis_tunnel * -chassis_tunnel_find(const char *chassis_id, char *encap_ip) -{ - /* - * If the specific encap_ip is given, look for the chassisid_ip entry, - * else return the 1st found entry for the chassis. - */ - struct chassis_tunnel *tun = NULL; - HMAP_FOR_EACH_WITH_HASH (tun, hmap_node, hash_string(chassis_id, 0), - &tunnels) { - if (encaps_tunnel_id_match(tun->chassis_id, chassis_id, encap_ip)) { - return tun; - } - } - return NULL; -} - static void put_load(uint64_t value, enum mf_field_id dst, int ofs, int n_bits, struct ofpbuf *ofpacts) @@ -166,17 +126,18 @@ put_resubmit(uint8_t table_id, struct ofpbuf *ofpacts) * from the associated encap. */ static struct chassis_tunnel * -get_port_binding_tun(const struct sbrec_port_binding *binding) +get_port_binding_tun(const struct sbrec_port_binding *binding, + const struct hmap *chassis_tunnels) { struct sbrec_encap *encap = binding->encap; struct sbrec_chassis *chassis = binding->chassis; struct chassis_tunnel *tun = NULL; if (encap) { - tun = chassis_tunnel_find(chassis->name, encap->ip); + tun = chassis_tunnel_find(chassis_tunnels, chassis->name, encap->ip); } if (!tun) { - tun = chassis_tunnel_find(chassis->name, NULL); + tun = chassis_tunnel_find(chassis_tunnels, chassis->name, NULL); } return tun; } @@ -325,12 +286,13 @@ put_remote_port_redirect_overlay(const struct uint32_t port_key, struct match *match, struct ofpbuf *ofpacts_p, + const struct hmap *chassis_tunnels, struct ovn_desired_flow_table *flow_table) { if (!is_ha_remote) { /* Setup encapsulation */ const struct chassis_tunnel *rem_tun = - get_port_binding_tun(binding); + get_port_binding_tun(binding, chassis_tunnels); if (!rem_tun) { return; } @@ -348,10 +310,10 @@ put_remote_port_redirect_overlay(const struct continue; } if (!tun) { - tun = chassis_tunnel_find(ch->name, NULL); + tun = chassis_tunnel_find(chassis_tunnels, ch->name, NULL); } else { struct chassis_tunnel *chassis_tunnel = - chassis_tunnel_find(ch->name, NULL); + chassis_tunnel_find(chassis_tunnels, ch->name, NULL); if (chassis_tunnel && tun->type != chassis_tunnel->type) { static struct vlog_rate_limit rl = @@ -385,7 +347,7 @@ put_remote_port_redirect_overlay(const struct if (!ch) { continue; } - tun = chassis_tunnel_find(ch->name, NULL); + tun = chassis_tunnel_find(chassis_tunnels, ch->name, NULL); if (!tun) { continue; } @@ -925,6 +887,9 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, const struct simap *ct_zones, const struct sset *active_tunnels, const struct hmap *local_datapaths, + const struct shash *local_bindings, + const struct simap *patch_ofports, + const struct hmap *chassis_tunnels, const struct sbrec_port_binding *binding, const struct sbrec_chassis *chassis, struct ovn_desired_flow_table *flow_table, @@ -1081,17 +1046,25 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, if (!binding->tag) { goto out; } - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, - binding->parent_port)); + ofport = local_binding_get_lport_ofport(local_bindings, + binding->parent_port); if (ofport) { tag = *binding->tag; nested_container = true; parent_port = lport_lookup_by_name( sbrec_port_binding_by_name, binding->parent_port); } - } else { - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, + } else if (!strcmp(binding->type, "localnet") + || !strcmp(binding->type, "l2gateway")) { + + ofport = u16_to_ofp(simap_get(patch_ofports, binding->logical_port)); + if (ofport && binding->tag) { + tag = *binding->tag; + } + } else { + ofport = local_binding_get_lport_ofport(local_bindings, + binding->logical_port); const char *requested_chassis = smap_get(&binding->options, "requested-chassis"); if (ofport && requested_chassis && requested_chassis[0] && @@ -1102,12 +1075,6 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, */ ofport = 0; } - - if ((!strcmp(binding->type, "localnet") - || !strcmp(binding->type, "l2gateway")) - && ofport && binding->tag) { - tag = *binding->tag; - } } bool is_ha_remote = false; @@ -1118,7 +1085,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, /* It is remote port, may be reached by tunnel or localnet port */ is_remote = true; if (localnet_port) { - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, + ofport = u16_to_ofp(simap_get(patch_ofports, localnet_port->logical_port)); if (!ofport) { goto out; @@ -1129,7 +1096,8 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, if (!binding->chassis) { goto out; } - tun = chassis_tunnel_find(binding->chassis->name, NULL); + tun = chassis_tunnel_find(chassis_tunnels, + binding->chassis->name, NULL); if (!tun) { goto out; } @@ -1383,7 +1351,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, put_remote_port_redirect_overlay(binding, is_ha_remote, ha_ch_ordered, mff_ovn_geneve, tun, port_key, &match, ofpacts_p, - flow_table); + chassis_tunnels, flow_table); } } out: @@ -1396,8 +1364,11 @@ static void consider_mc_group(enum mf_field_id mff_ovn_geneve, const struct simap *ct_zones, const struct hmap *local_datapaths, + struct shash *local_bindings, + struct simap *patch_ofports, const struct sbrec_chassis *chassis, const struct sbrec_multicast_group *mc, + const struct hmap *chassis_tunnels, struct ovn_desired_flow_table *flow_table) { uint32_t dp_key = mc->datapath->tunnel_key; @@ -1444,19 +1415,21 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve, put_load(zone_id, MFF_LOG_CT_ZONE, 0, 32, &ofpacts); } + const char *lport_name = (port->parent_port && *port->parent_port) ? + port->parent_port : port->logical_port; + if (!strcmp(port->type, "patch")) { put_load(port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, &remote_ofpacts); put_resubmit(OFTABLE_CHECK_LOOPBACK, &remote_ofpacts); - } else if (simap_contains(&localvif_to_ofport, - (port->parent_port && *port->parent_port) - ? port->parent_port : port->logical_port) + } else if (local_binding_get_primary_pb(local_bindings, lport_name) + || simap_contains(patch_ofports, port->logical_port) || (!strcmp(port->type, "l3gateway") && port->chassis == chassis)) { put_load(port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, &ofpacts); put_resubmit(OFTABLE_CHECK_LOOPBACK, &ofpacts); - } else if (port->chassis && !get_localnet_port(local_datapaths, - mc->datapath->tunnel_key)) { + } else if (port->chassis && !get_localnet_port( + local_datapaths, mc->datapath->tunnel_key)) { /* Add remote chassis only when localnet port not exist, * otherwise multicast will reach remote ports through localnet * port. */ @@ -1497,7 +1470,7 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve, const struct chassis_tunnel *prev = NULL; SSET_FOR_EACH (chassis_name, &remote_chassis) { const struct chassis_tunnel *tun - = chassis_tunnel_find(chassis_name, NULL); + = chassis_tunnel_find(chassis_tunnels, chassis_name, NULL); if (!tun) { continue; } @@ -1524,41 +1497,50 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve, sset_destroy(&remote_chassis); } -/* Replaces 'old' by 'new' (destroying 'new'). Returns true if 'old' and 'new' - * contained different data, false if they were the same. */ -static bool -update_ofports(struct simap *old, struct simap *new) -{ - bool changed = !simap_equal(old, new); - simap_swap(old, new); - simap_destroy(new); - return changed; -} - void -physical_handle_port_binding_changes(struct physical_ctx *p_ctx, - struct ovn_desired_flow_table *flow_table) +physical_handle_flows_for_lport(const struct sbrec_port_binding *pb, + bool removed, struct physical_ctx *p_ctx, + struct ovn_desired_flow_table *flow_table) { - const struct sbrec_port_binding *binding; - struct ofpbuf ofpacts; - ofpbuf_init(&ofpacts, 0); - SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED (binding, - p_ctx->port_binding_table) { - if (sbrec_port_binding_is_deleted(binding)) { - ofctrl_remove_flows(flow_table, &binding->header_.uuid); - } else { - if (!sbrec_port_binding_is_new(binding)) { - ofctrl_remove_flows(flow_table, &binding->header_.uuid); - } + ofctrl_remove_flows(flow_table, &pb->header_.uuid); + + if (!strcmp(pb->type, "external")) { + /* External lports have a dependency on the localnet port. + * We need to remove the flows of the localnet port as well + * and re-consider adding the flows for it. + */ + struct local_datapath *ldp = + get_local_datapath(p_ctx->local_datapaths, + pb->datapath->tunnel_key); + if (ldp && ldp->localnet_port) { + struct ofpbuf ofpacts; + ofctrl_remove_flows(flow_table, &ldp->localnet_port->header_.uuid); + ofpbuf_init(&ofpacts, 0); consider_port_binding(p_ctx->sbrec_port_binding_by_name, p_ctx->mff_ovn_geneve, p_ctx->ct_zones, p_ctx->active_tunnels, p_ctx->local_datapaths, - binding, p_ctx->chassis, + p_ctx->local_bindings, + &p_ctx->nonvif_data->patch_ofports, + &p_ctx->nonvif_data->chassis_tunnels, + ldp->localnet_port, p_ctx->chassis, flow_table, &ofpacts); + ofpbuf_uninit(&ofpacts); } } - ofpbuf_uninit(&ofpacts); + + if (!removed) { + struct ofpbuf ofpacts; + ofpbuf_init(&ofpacts, 0); + consider_port_binding(p_ctx->sbrec_port_binding_by_name, + p_ctx->mff_ovn_geneve, p_ctx->ct_zones, + p_ctx->active_tunnels, p_ctx->local_datapaths, + p_ctx->local_bindings, + &p_ctx->nonvif_data->patch_ofports, + &p_ctx->nonvif_data->chassis_tunnels, pb, + p_ctx->chassis, flow_table, &ofpacts); + ofpbuf_uninit(&ofpacts); + } } void @@ -1574,8 +1556,11 @@ physical_handle_mc_group_changes(struct physical_ctx *p_ctx, ofctrl_remove_flows(flow_table, &mc->header_.uuid); } consider_mc_group(p_ctx->mff_ovn_geneve, p_ctx->ct_zones, - p_ctx->local_datapaths, - p_ctx->chassis, mc, flow_table); + p_ctx->local_datapaths, p_ctx->local_bindings, + &p_ctx->nonvif_data->patch_ofports, + p_ctx->chassis, mc, + &p_ctx->nonvif_data->chassis_tunnels, + flow_table); } } } @@ -1591,135 +1576,6 @@ physical_run(struct physical_ctx *p_ctx, uuid_generate(hc_uuid); } - /* This bool tracks physical mapping changes. */ - bool physical_map_changed = false; - - struct simap new_localvif_to_ofport = - SIMAP_INITIALIZER(&new_localvif_to_ofport); - struct simap new_tunnel_to_ofport = - SIMAP_INITIALIZER(&new_tunnel_to_ofport); - for (int i = 0; i < p_ctx->br_int->n_ports; i++) { - const struct ovsrec_port *port_rec = p_ctx->br_int->ports[i]; - if (!strcmp(port_rec->name, p_ctx->br_int->name)) { - continue; - } - - const char *tunnel_id = smap_get(&port_rec->external_ids, - "ovn-chassis-id"); - if (tunnel_id && encaps_tunnel_id_match(tunnel_id, - p_ctx->chassis->name, - NULL)) { - continue; - } - - const char *localnet = smap_get(&port_rec->external_ids, - "ovn-localnet-port"); - const char *l2gateway = smap_get(&port_rec->external_ids, - "ovn-l2gateway-port"); - - for (int j = 0; j < port_rec->n_interfaces; j++) { - const struct ovsrec_interface *iface_rec = port_rec->interfaces[j]; - - /* Get OpenFlow port number. */ - if (!iface_rec->n_ofport) { - continue; - } - int64_t ofport = iface_rec->ofport[0]; - if (ofport < 1 || ofport > ofp_to_u16(OFPP_MAX)) { - continue; - } - - /* Record as patch to local net, logical patch port, chassis, or - * local logical port. */ - bool is_patch = !strcmp(iface_rec->type, "patch"); - if (is_patch && localnet) { - /* localnet patch ports can be handled just like VIFs. */ - simap_put(&new_localvif_to_ofport, localnet, ofport); - break; - } else if (is_patch && l2gateway) { - /* L2 gateway patch ports can be handled just like VIFs. */ - simap_put(&new_localvif_to_ofport, l2gateway, ofport); - break; - } else if (tunnel_id) { - enum chassis_tunnel_type tunnel_type; - if (!strcmp(iface_rec->type, "geneve")) { - tunnel_type = GENEVE; - if (!p_ctx->mff_ovn_geneve) { - continue; - } - } else if (!strcmp(iface_rec->type, "stt")) { - tunnel_type = STT; - } else if (!strcmp(iface_rec->type, "vxlan")) { - tunnel_type = VXLAN; - } else { - continue; - } - - simap_put(&new_tunnel_to_ofport, tunnel_id, ofport); - /* - * We split the tunnel_id to get the chassis-id - * and hash the tunnel list on the chassis-id. The - * reason to use the chassis-id alone is because - * there might be cases (multicast, gateway chassis) - * where we need to tunnel to the chassis, but won't - * have the encap-ip specifically. - */ - char *hash_id = NULL; - char *ip = NULL; - - if (!encaps_tunnel_id_parse(tunnel_id, &hash_id, &ip)) { - continue; - } - struct chassis_tunnel *tun = chassis_tunnel_find(hash_id, ip); - if (tun) { - /* If the tunnel's ofport has changed, update. */ - if (tun->ofport != u16_to_ofp(ofport) || - tun->type != tunnel_type) { - tun->ofport = u16_to_ofp(ofport); - tun->type = tunnel_type; - physical_map_changed = true; - } - } else { - tun = xmalloc(sizeof *tun); - hmap_insert(&tunnels, &tun->hmap_node, - hash_string(hash_id, 0)); - tun->chassis_id = xstrdup(tunnel_id); - tun->ofport = u16_to_ofp(ofport); - tun->type = tunnel_type; - physical_map_changed = true; - } - free(hash_id); - free(ip); - break; - } else { - const char *iface_id = smap_get(&iface_rec->external_ids, - "iface-id"); - if (iface_id) { - simap_put(&new_localvif_to_ofport, iface_id, ofport); - } - } - } - } - - /* Remove tunnels that are no longer here. */ - struct chassis_tunnel *tun, *tun_next; - HMAP_FOR_EACH_SAFE (tun, tun_next, hmap_node, &tunnels) { - if (!simap_find(&new_tunnel_to_ofport, tun->chassis_id)) { - hmap_remove(&tunnels, &tun->hmap_node); - physical_map_changed = true; - free(tun->chassis_id); - free(tun); - } - } - - /* Capture changed or removed openflow ports. */ - physical_map_changed |= update_ofports(&localvif_to_ofport, - &new_localvif_to_ofport); - if (physical_map_changed) { - /* Reprocess logical flow table immediately. */ - poll_immediate_wake(); - } - struct ofpbuf ofpacts; ofpbuf_init(&ofpacts, 0); @@ -1733,16 +1589,20 @@ physical_run(struct physical_ctx *p_ctx, consider_port_binding(p_ctx->sbrec_port_binding_by_name, p_ctx->mff_ovn_geneve, p_ctx->ct_zones, p_ctx->active_tunnels, p_ctx->local_datapaths, - binding, p_ctx->chassis, - flow_table, &ofpacts); + p_ctx->local_bindings, + &p_ctx->nonvif_data->patch_ofports, + &p_ctx->nonvif_data->chassis_tunnels, binding, + p_ctx->chassis, flow_table, &ofpacts); } /* Handle output to multicast groups, in tables 32 and 33. */ const struct sbrec_multicast_group *mc; SBREC_MULTICAST_GROUP_TABLE_FOR_EACH (mc, p_ctx->mc_group_table) { consider_mc_group(p_ctx->mff_ovn_geneve, p_ctx->ct_zones, - p_ctx->local_datapaths, p_ctx->chassis, - mc, flow_table); + p_ctx->local_datapaths, p_ctx->local_bindings, + &p_ctx->nonvif_data->patch_ofports, p_ctx->chassis, + mc, &p_ctx->nonvif_data->chassis_tunnels, + flow_table); } /* Table 0, priority 100. @@ -1757,7 +1617,8 @@ physical_run(struct physical_ctx *p_ctx, * We set MFF_LOG_DATAPATH, MFF_LOG_INPORT, and MFF_LOG_OUTPORT from the * tunnel key data where possible, then resubmit to table 33 to handle * packets to the local hypervisor. */ - HMAP_FOR_EACH (tun, hmap_node, &tunnels) { + struct chassis_tunnel *tun; + HMAP_FOR_EACH (tun, hmap_node, &p_ctx->nonvif_data->chassis_tunnels) { struct match match = MATCH_CATCHALL_INITIALIZER; match_set_in_port(&match, tun->ofport); @@ -1788,7 +1649,7 @@ physical_run(struct physical_ctx *p_ctx, } /* Handle ramp switch encapsulations. */ - HMAP_FOR_EACH (tun, hmap_node, &tunnels) { + HMAP_FOR_EACH (tun, hmap_node, &p_ctx->nonvif_data->chassis_tunnels) { if (tun->type != VXLAN) { continue; } @@ -1925,13 +1786,10 @@ physical_run(struct physical_ctx *p_ctx, &ofpacts, hc_uuid); ofpbuf_uninit(&ofpacts); - - simap_destroy(&new_tunnel_to_ofport); } bool -physical_handle_ovs_iface_changes(struct physical_ctx *p_ctx, - struct ovn_desired_flow_table *flow_table) +physical_handle_ovs_iface_changes(struct physical_ctx *p_ctx) { const struct ovsrec_interface *iface_rec; OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, p_ctx->iface_table) { @@ -1943,64 +1801,6 @@ physical_handle_ovs_iface_changes(struct physical_ctx *p_ctx, } } - struct ofpbuf ofpacts; - ofpbuf_init(&ofpacts, 0); - - OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, p_ctx->iface_table) { - const char *iface_id = smap_get(&iface_rec->external_ids, "iface-id"); - if (!iface_id) { - continue; - } - - const struct sbrec_port_binding *lb_pb = - local_binding_get_primary_pb(p_ctx->local_bindings, iface_id); - if (!lb_pb) { - /* For regular VIFs (e.g. lsp) the upcoming port-binding update - * will remove lfows related to the unclaimed ovs port. - * Localport is a special case and it needs to be managed here - * since the port is not binded and otherwise the related lfows - * will not be cleared removing the ovs port. - */ - lb_pb = lport_lookup_by_name(p_ctx->sbrec_port_binding_by_name, - iface_id); - if (!lb_pb || strcmp(lb_pb->type, "localport")) { - continue; - } - } - - int64_t ofport = iface_rec->n_ofport ? *iface_rec->ofport : 0; - if (ovsrec_interface_is_deleted(iface_rec)) { - ofctrl_remove_flows(flow_table, &lb_pb->header_.uuid); - simap_find_and_delete(&localvif_to_ofport, iface_id); - } else { - if (!ovsrec_interface_is_new(iface_rec)) { - ofctrl_remove_flows(flow_table, &lb_pb->header_.uuid); - } - - simap_put(&localvif_to_ofport, iface_id, ofport); - consider_port_binding(p_ctx->sbrec_port_binding_by_name, - p_ctx->mff_ovn_geneve, p_ctx->ct_zones, - p_ctx->active_tunnels, - p_ctx->local_datapaths, - lb_pb, p_ctx->chassis, - flow_table, &ofpacts); - } - } - - ofpbuf_uninit(&ofpacts); - return true; -} - -bool -get_tunnel_ofport(const char *chassis_name, char *encap_ip, ofp_port_t *ofport) -{ - struct chassis_tunnel *tun = NULL; - tun = chassis_tunnel_find(chassis_name, encap_ip); - if (!tun) { - return false; - } - - *ofport = tun->ofport; return true; } diff --git a/controller/physical.h b/controller/physical.h index feab41df4..3fdc20005 100644 --- a/controller/physical.h +++ b/controller/physical.h @@ -34,6 +34,7 @@ struct simap; struct sbrec_multicast_group_table; struct sbrec_port_binding_table; struct sset; +struct local_nonvif_data; /* OVN Geneve option information. * @@ -56,18 +57,18 @@ struct physical_ctx { const struct simap *ct_zones; enum mf_field_id mff_ovn_geneve; struct shash *local_bindings; + struct local_nonvif_data *nonvif_data; }; void physical_register_ovs_idl(struct ovsdb_idl *); void physical_run(struct physical_ctx *, struct ovn_desired_flow_table *); void physical_clear_unassoc_flows_with_db(struct ovn_desired_flow_table *); -void physical_handle_port_binding_changes(struct physical_ctx *, - struct ovn_desired_flow_table *); void physical_handle_mc_group_changes(struct physical_ctx *, struct ovn_desired_flow_table *); -bool physical_handle_ovs_iface_changes(struct physical_ctx *, - struct ovn_desired_flow_table *); -bool get_tunnel_ofport(const char *chassis_name, char *encap_ip, - ofp_port_t *ofport); +bool physical_handle_ovs_iface_changes(struct physical_ctx *); +void physical_handle_flows_for_lport(const struct sbrec_port_binding *, + bool removed, + struct physical_ctx *, + struct ovn_desired_flow_table *); #endif /* controller/physical.h */