On Thu, Aug 14, 2025 at 2:58 PM Ilya Maximets <i.maxim...@ovn.org> wrote:
> On 8/12/25 4:56 PM, Ales Musil via dev wrote: > > Add physical flows based on the EVPN bindings and multicast groups > > that ensure the proper flow of traffic that is going through the > > EVPN. In order for this to wrk the CMS needs to ensure that there > > is proper VXLAN tunnel port in br-int and also the > > "external_ids:ovn-evpn-local-ip" is set properly in the local OvS > > database. > > > > All traffic will be flooded through the UNKNOWN group if there is > > unknown port at this stage. That's due to missing support for FDB > > learning. > > > > Signed-off-by: Ales Musil <amu...@redhat.com> > > --- > Hi Ilya, thank you for the review. > > v3: Rebase on top of latest main. > > Add an assert that mc groups have some bindings. > > > > v2: Rebase on top of latest main. > > Add WARN about mossing local_ip. > > --- > > NEWS | 3 + > > TODO.rst | 4 + > > controller/chassis.c | 18 +++ > > controller/lflow.h | 7 +- > > controller/ovn-controller.8.xml | 8 + > > controller/ovn-controller.c | 30 +++- > > controller/physical.c | 276 ++++++++++++++++++++++++++++---- > > controller/physical.h | 8 + > > include/ovn/logical-fields.h | 3 + > > tests/ovn-macros.at | 5 +- > > tests/ovn.at | 2 +- > > 11 files changed, 326 insertions(+), 38 deletions(-) > > > > diff --git a/NEWS b/NEWS > > index ec52f0d90..6aef31fa4 100644 > > --- a/NEWS > > +++ b/NEWS > > @@ -49,6 +49,9 @@ Post v25.03.0 > > * Add the option "external_ids:ovn-evpn-vxlan-ports" into OvS > datapath. > > This option allows CMS to set list of UDP destination ports that > will be > > used to create the VXLAN tunnels. > > + * Add the option "external_ids:ovn-evpn-local-ip" into OvS > datapath. > > Same comment as for the previous NEWS entry. > > > + This option allows CMS to set IP address that will be used as > source > > + for the EVPN traffic egressing through the tunnel. > > > > OVN v25.03.0 - 07 Mar 2025 > > -------------------------- > > diff --git a/TODO.rst b/TODO.rst > > index 85208bfe3..9a9df78f2 100644 > > --- a/TODO.rst > > +++ b/TODO.rst > > @@ -153,3 +153,7 @@ OVN To-do List > > monitoring conditions to update before we actually try to learn > routes. > > Otherwise we could try to add duplicated Learned_Routes and the > ovnsb > > commit would fail. > > + > > + * Allow ovn-evpn-local-ip to accept list of > > + $VNI1:$LOCAL_IP1,$VNI2:$LOCAL_IP2 combinations which will be > properly > > + reflected in physical flows for given LS with VNI. > > diff --git a/controller/chassis.c b/controller/chassis.c > > index 34adc98be..772a57c7f 100644 > > --- a/controller/chassis.c > > +++ b/controller/chassis.c > > @@ -59,6 +59,7 @@ struct ovs_chassis_cfg { > > const char *trim_wmark_perc_lflow_cache; > > const char *trim_timeout_ms; > > const char *evpn_vxlan_port; > > + const char *evpn_local_ip; > > > > /* Set of encap types parsed from the 'ovn-encap-type' external-id. > */ > > struct sset encap_type_set; > > @@ -206,6 +207,13 @@ get_evpn_vxlan_port(const struct smap *ext_ids, > const char *chassis_id) > > "ovn-evpn-vxlan-ports", ""); > > } > > > > +static const char * > > +get_evpn_local_ip(const struct smap *ext_ids, const char *chassis_id) > > +{ > > + return get_chassis_external_id_value(ext_ids, chassis_id, > > + "ovn-evpn-local-ip", "true"); > > Why IP defaults to "true"? > Ah good catch, that's a typo. > > > +} > > + > > static const char * > > get_datapath_type(const struct ovsrec_bridge *br_int) > > { > > @@ -342,6 +350,8 @@ chassis_parse_ovs_config(const struct > ovsrec_open_vswitch_table *ovs_table, > > get_trim_timeout(&cfg->external_ids, chassis_id); > > ovs_cfg->evpn_vxlan_port = > > get_evpn_vxlan_port(&cfg->external_ids, chassis_id); > > + ovs_cfg->evpn_local_ip = > > + get_evpn_local_ip(&cfg->external_ids, chassis_id); > > > > chassis_parse_ovs_encap_type(encap_type, &ovs_cfg->encap_type_set); > > > > @@ -395,6 +405,7 @@ chassis_build_other_config(const struct > ovs_chassis_cfg *ovs_cfg, > > smap_replace(config, "iface-types", > ds_cstr_ro(&ovs_cfg->iface_types)); > > smap_replace(config, "ovn-chassis-mac-mappings", > ovs_cfg->chassis_macs); > > smap_replace(config, "ovn-evpn-vxlan-ports", > ovs_cfg->evpn_vxlan_port); > > + smap_replace(config, "ovn-evpn-local-ip", ovs_cfg->evpn_local_ip); > > smap_replace(config, "is-interconn", > > ovs_cfg->is_interconn ? "true" : "false"); > > smap_replace(config, OVN_FEATURE_PORT_UP_NOTIF, "true"); > > @@ -521,6 +532,12 @@ chassis_other_config_changed(const struct > ovs_chassis_cfg *ovs_cfg, > > return true; > > } > > > > + const char *chassis_evpn_local_ip = > > + get_evpn_local_ip(&chassis_rec->other_config, > chassis_rec->name); > > + if (strcmp(ovs_cfg->evpn_local_ip, chassis_evpn_local_ip)) { > > + return true; > > + } > > + > > > > if (!smap_get_bool(&chassis_rec->other_config, > OVN_FEATURE_PORT_UP_NOTIF, > > false)) { > > @@ -741,6 +758,7 @@ update_supported_sset(struct sset *supported) > > sset_add(supported, "ovn-chassis-mac-mappings"); > > sset_add(supported, "is-interconn"); > > sset_add(supported, "ovn-evpn-vxlan-ports"); > > + sset_add(supported, "ovn-evpn-local-ip"); > > > > /* Internal options. */ > > sset_add(supported, "is-vtep"); > > diff --git a/controller/lflow.h b/controller/lflow.h > > index fa9e795e0..c2d277078 100644 > > --- a/controller/lflow.h > > +++ b/controller/lflow.h > > @@ -70,14 +70,15 @@ struct uuid; > > #define OFTABLE_OUTPUT_LARGE_PKT_DETECT 41 > > #define OFTABLE_OUTPUT_LARGE_PKT_PROCESS 42 > > #define OFTABLE_REMOTE_OUTPUT 43 > > -#define OFTABLE_LOCAL_OUTPUT 44 > > -#define OFTABLE_CHECK_LOOPBACK 45 > > +#define OFTABLE_REMOTE_VTEP_OUTPUT 44 > > +#define OFTABLE_LOCAL_OUTPUT 45 > > +#define OFTABLE_CHECK_LOOPBACK 46 > > > > /* Start of the OUTPUT section of the pipeline. */ > > #define OFTABLE_OUTPUT_INIT OFTABLE_OUTPUT_LARGE_PKT_DETECT > > > > /* Start of LOG_PIPELINE_LEN tables. */ > > -#define OFTABLE_LOG_EGRESS_PIPELINE 46 > > +#define OFTABLE_LOG_EGRESS_PIPELINE 47 > > #define OFTABLE_SAVE_INPORT 64 > > #define OFTABLE_LOG_TO_PHY 65 > > #define OFTABLE_MAC_BINDING 66 > > diff --git a/controller/ovn-controller.8.xml > b/controller/ovn-controller.8.xml > > index e602ebca8..c6fd0780c 100644 > > --- a/controller/ovn-controller.8.xml > > +++ b/controller/ovn-controller.8.xml > > @@ -399,6 +399,14 @@ > > the EVPN tunnels created by this ovn-controller. NOTE: this > feature is > > experimental and may be subject to removal/change in the future. > > </dd> > > + > > + <dt><code>external_ids:ovn-evpn-local-ip</code></dt> > > + <dd> > > + IP address used as a source address for the EVPN traffic > leaving this > > + ovn-controller. There is currently support only for single IP > address > > s/ovn-controller/OVN setup/ ? > > > + being specified. NOTE: this feature is experimental and may be > subject > > + to removal/change in the future. > > + </dd> > > </dl> > > > > <p> > > diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c > > index 1cda8e71e..86cf5f537 100644 > > --- a/controller/ovn-controller.c > > +++ b/controller/ovn-controller.c > > @@ -4630,6 +4630,9 @@ static void init_physical_ctx(struct engine_node > *node, > > struct ed_type_northd_options *n_opts = > > engine_get_input_data("northd_options", node); > > > > + struct ed_type_evpn_vtep_binding *eb_data = > > + engine_get_input_data("evpn_vtep_binding", node); > > + > > parse_encap_ips(ovs_table, &p_ctx->n_encap_ips, &p_ctx->encap_ips); > > p_ctx->sbrec_port_binding_by_name = sbrec_port_binding_by_name; > > p_ctx->sbrec_port_binding_by_datapath = > sbrec_port_binding_by_datapath; > > @@ -4647,6 +4650,8 @@ static void init_physical_ctx(struct engine_node > *node, > > p_ctx->patch_ofports = &non_vif_data->patch_ofports; > > p_ctx->chassis_tunnels = &non_vif_data->chassis_tunnels; > > p_ctx->always_tunnel = n_opts->always_tunnel; > > + p_ctx->evpn_bindings = &eb_data->bindings; > > + p_ctx->evpn_multicast_groups = &eb_data->multicast_groups; > > > > struct controller_engine_ctx *ctrl_ctx = > engine_get_context()->client_ctx; > > p_ctx->if_mgr = ctrl_ctx->if_mgr; > > @@ -4936,6 +4941,28 @@ pflow_output_debug_handler(struct engine_node > *node, void *data) > > } > > return EN_HANDLED_UPDATED; > > } > > +static enum engine_input_handler_result > > +pflow_output_evpn_binding_handler(struct engine_node *node, void *data) > > +{ > > + struct ed_type_pflow_output *pfo = data; > > + struct ed_type_runtime_data *rt_data = > > + engine_get_input_data("runtime_data", node); > > + struct ed_type_non_vif_data *non_vif_data = > > + engine_get_input_data("non_vif_data", node); > > + struct ed_type_evpn_vtep_binding *eb_data = > > + engine_get_input_data("evpn_vtep_binding", node); > > + > > + struct physical_ctx ctx; > > + init_physical_ctx(node, rt_data, non_vif_data, &ctx); > > + > > + physical_handle_evpn_binding_changes(&ctx, &pfo->flow_table, > > + &eb_data->updated_bindings, > > + > &eb_data->updated_multicast_groups, > > + &eb_data->removed_bindings, > > + > &eb_data->removed_multicast_groups); > > + destroy_physical_ctx(&ctx); > > + return EN_HANDLED_UPDATED; > > +} > > > > static void * > > en_controller_output_init(struct engine_node *node OVS_UNUSED, > > @@ -6672,9 +6699,8 @@ main(int argc, char *argv[]) > > engine_add_input(&en_evpn_vtep_binding, &en_sb_datapath_binding, > > evpn_vtep_binding_datapath_binding_handler); > > > > - /* TODO Add real handler to process all bindings. */ > > engine_add_input(&en_pflow_output, &en_evpn_vtep_binding, > > - engine_noop_handler); > > + pflow_output_evpn_binding_handler); > > > > engine_add_input(&en_controller_output, &en_dns_cache, > > NULL); > > diff --git a/controller/physical.c b/controller/physical.c > > index c5f74010a..78cd98b61 100644 > > --- a/controller/physical.c > > +++ b/controller/physical.c > > @@ -19,6 +19,7 @@ > > #include "byte-order.h" > > #include "ct-zone.h" > > #include "encaps.h" > > +#include "evpn-binding.h" > > #include "flow.h" > > #include "ha-chassis.h" > > #include "lflow.h" > > @@ -475,7 +476,7 @@ put_remote_port_redirect_overlay(const struct > sbrec_port_binding *binding, > > port_key, is_vtep_port, > ofpacts_clone); > > ofpact_put_OUTPUT(ofpacts_clone)->port = tun->ofport; > > } > > - put_resubmit(OFTABLE_LOCAL_OUTPUT, ofpacts_clone); > > + put_resubmit(OFTABLE_REMOTE_VTEP_OUTPUT, ofpacts_clone); > > ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 100, > > binding->header_.uuid.parts[0], match, > > ofpacts_clone, &binding->header_.uuid); > > @@ -973,12 +974,12 @@ put_local_common_flows(uint32_t dp_key, > > > > uint32_t port_key = pb->tunnel_key; > > > > - /* Table 43, priority 100. > > + /* Table 45, priority 100. > > * ======================= > > * > > * Implements output to local hypervisor. Each flow matches a > > * logical output port on the local hypervisor, and resubmits to > > - * table 44. > > + * table 46. > > */ > > > > ofpbuf_clear(ofpacts_p); > > @@ -988,13 +989,13 @@ put_local_common_flows(uint32_t dp_key, > > > > put_zones_ofpacts(zone_ids, ofpacts_p); > > > > - /* Resubmit to table 44. */ > > + /* Resubmit to table 46. */ > > put_resubmit(OFTABLE_CHECK_LOOPBACK, ofpacts_p); > > ofctrl_add_flow(flow_table, OFTABLE_LOCAL_OUTPUT, 100, > > pb->header_.uuid.parts[0], &match, ofpacts_p, > > &pb->header_.uuid); > > > > - /* Table 44, Priority 100. > > + /* Table 46, Priority 100. > > * ======================= > > * > > * Drop packets whose logical inport and outport are the same > > @@ -1772,12 +1773,12 @@ consider_port_binding(const struct physical_ctx > *ctx, > > ha_chassis_group_is_active(binding->ha_chassis_group, > > ctx->active_tunnels, > ctx->chassis))) { > > > > - /* Table 43, priority 100. > > + /* Table 45, priority 100. > > * ======================= > > * > > * Implements output to local hypervisor. Each flow matches a > > * logical output port on the local hypervisor, and resubmits to > > - * table 41. For ports of type "chassisredirect", the logical > > + * table 46. For ports of type "chassisredirect", the logical > > * output port is changed from the "chassisredirect" port to the > > * underlying distributed port. */ > > > > @@ -1818,7 +1819,7 @@ consider_port_binding(const struct physical_ctx > *ctx, > > * go out from the same tunnel inport. */ > > put_load(ofp_to_u16(OFPP_NONE), MFF_IN_PORT, 0, 16, > ofpacts_p); > > > > - /* Resubmit to table 41. */ > > + /* Resubmit to table 46. */ > > put_resubmit(OFTABLE_CHECK_LOOPBACK, ofpacts_p); > > } > > > > @@ -2049,7 +2050,7 @@ consider_port_binding(const struct physical_ctx > *ctx, > > ofport, flow_table); > > } > > > > - /* Table 41, priority 160. > > + /* Table 46, priority 160. > > * ======================= > > * > > * Do not forward local traffic from a localport to a localnet > port. > > @@ -2120,13 +2121,13 @@ consider_port_binding(const struct physical_ctx > *ctx, > > } > > } > > > > - /* Table 42, priority 150. > > + /* Table 43, priority 150. > > * ======================= > > * > > * Handles packets received from ports of type "localport". > These > > * ports are present on every hypervisor. Traffic that > originates at > > * one should never go over a tunnel to a remote hypervisor, > > - * so resubmit them to table 40 for local delivery. */ > > + * so resubmit them to table 45 for local delivery. */ > > if (type == LP_LOCALPORT) { > > ofpbuf_clear(ofpacts_p); > > put_resubmit(OFTABLE_LOCAL_OUTPUT, ofpacts_p); > > @@ -2140,7 +2141,7 @@ consider_port_binding(const struct physical_ctx > *ctx, > > } > > } else if (access_type == PORT_LOCALNET && !ctx->always_tunnel) { > > /* Remote port connected by localnet port */ > > - /* Table 43, priority 100. > > + /* Table 45, priority 100. > > * ======================= > > * > > * Implements switching to localnet port. Each flow matches a > > @@ -2160,7 +2161,7 @@ consider_port_binding(const struct physical_ctx > *ctx, > > > > put_load(localnet_port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, > ofpacts_p); > > > > - /* Resubmit to table 43. */ > > + /* Resubmit to table 45. */ > > put_resubmit(OFTABLE_LOCAL_OUTPUT, ofpacts_p); > > ofctrl_add_flow(flow_table, OFTABLE_LOCAL_OUTPUT, 100, > > binding->header_.uuid.parts[0], > > @@ -2516,15 +2517,13 @@ consider_mc_group(const struct physical_ctx *ctx, > > > > remote_ports = remote_ctx->ofpacts.size > 0; > > if (remote_ports) { > > - if (local_lports) { > > - put_resubmit(OFTABLE_LOCAL_OUTPUT, &remote_ctx->ofpacts); > > - } > > + put_resubmit(OFTABLE_REMOTE_VTEP_OUTPUT, &remote_ctx->ofpacts); > > mc_ofctrl_add_flow(mc, remote_ctx, false, flow_table); > > } > > > > if (ramp_ports && has_vtep) { > > put_load(mc->tunnel_key, MFF_LOG_OUTPORT, 0, 32, > &ramp_ctx->ofpacts); > > - put_resubmit(OFTABLE_LOCAL_OUTPUT, &ramp_ctx->ofpacts); > > + put_resubmit(OFTABLE_REMOTE_VTEP_OUTPUT, &ramp_ctx->ofpacts); > > mc_ofctrl_add_flow(mc, ramp_ctx, false, flow_table); > > } > > > > @@ -2641,6 +2640,162 @@ physical_eval_remote_chassis_flows(const struct > physical_ctx *ctx, > > ofpbuf_uninit(&ingress_ofpacts); > > } > > > > +static void > > +physical_consider_evpn_binding(const struct evpn_binding *binding, > > + const struct in6_addr *local_ip, > > + struct ofpbuf *ofpacts, struct match > *match, > > + struct ovn_desired_flow_table > *flow_table, > > + bool ipv4) > > +{ > > + /* Ingress flows. */ > > + ofpbuf_clear(ofpacts); > > + match_init_catchall(match); > > + > > + match_set_in_port(match, binding->tunnel_ofport); > > + match_set_tun_id(match, htonll(binding->vni)); > > + if (ipv4) { > > + match_set_tun_src(match, > > + > in6_addr_get_mapped_ipv4(&binding->remote_ip)); > > + match_set_tun_dst(match, in6_addr_get_mapped_ipv4(local_ip)); > > + } else { > > + match_set_tun_ipv6_src(match, &binding->remote_ip); > > + match_set_tun_ipv6_dst(match, local_ip); > > + } > > + > > + put_load(binding->dp_key, MFF_LOG_DATAPATH, 0, 32, ofpacts); > > + put_load(binding->binding_key, MFF_LOG_INPORT, 0, 32, ofpacts); > > + put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, ofpacts); > > + > > + ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG, 1050, > > + binding->flow_uuid.parts[0], > > + match, ofpacts, &binding->flow_uuid); > > + > > + /* Egress flows. */ > > + ofpbuf_clear(ofpacts); > > + match_init_catchall(match); > > + > > + match_outport_dp_and_port_keys(match, binding->dp_key, > > + binding->binding_key); > > + > > + if (ipv4) { > > + ovs_be32 ip4 = in6_addr_get_mapped_ipv4(local_ip); > > + put_load_bytes(&ip4, sizeof ip4, MFF_TUN_SRC, 0, 32, ofpacts); > > + ip4 = in6_addr_get_mapped_ipv4(&binding->remote_ip); > > + put_load_bytes(&ip4, sizeof ip4, MFF_TUN_DST, 0, 32, ofpacts); > > + } else { > > + put_load_bytes(&local_ip, sizeof local_ip, MFF_TUN_IPV6_SRC, > > + 0, 128, ofpacts); > > + put_load_bytes(&binding->remote_ip, sizeof binding->remote_ip, > > + MFF_TUN_IPV6_DST, 0, 128, ofpacts); > > + } > > + put_load(binding->vni, MFF_TUN_ID, 0, 24, ofpacts); > > + > > + size_t ofpacts_size = ofpacts->size; > > + ofpact_put_OUTPUT(ofpacts)->port = binding->tunnel_ofport; > > + > > + ofctrl_add_flow(flow_table, OFTABLE_REMOTE_VTEP_OUTPUT, 50, > > + binding->flow_uuid.parts[0], > > + match, ofpacts, &binding->flow_uuid); > > + > > + /* Add flow that will match on LOOPBACK flag, in that case set > > + * in_port to none otherwise the hairpin traffic would be rejected > > + * by ovs. */ > > + match_set_reg_masked(match, MFF_LOG_FLAGS - MFF_REG0, > > + MLF_ALLOW_LOOPBACK, MLF_ALLOW_LOOPBACK); > > + > > + ofpbuf_truncate(ofpacts, ofpacts_size); > > + put_load(ofp_to_u16(OFPP_NONE), MFF_IN_PORT, 0, 16, ofpacts); > > + ofpact_put_OUTPUT(ofpacts)->port = binding->tunnel_ofport; > > + > > + ofctrl_add_flow(flow_table, OFTABLE_REMOTE_VTEP_OUTPUT, 55, > > + binding->flow_uuid.parts[0], > > + match, ofpacts, &binding->flow_uuid); > > +} > > + > > +static void > > +physical_consider_evpn_multicast(const struct evpn_multicast_group > *mc_group, > > + const struct in6_addr *local_ip, > > + struct ofpbuf *ofpacts, struct match > *match, > > + struct ovn_desired_flow_table > *flow_table, > > + bool ipv4) > > +{ > > + const struct evpn_binding *binding = NULL; > > + > > + ofpbuf_clear(ofpacts); > > + uint32_t multicast_tunnel_keys[] = {OVN_MCAST_FLOOD_TUNNEL_KEY, > > + OVN_MCAST_UNKNOWN_TUNNEL_KEY, > > + OVN_MCAST_FLOOD_L2_TUNNEL_KEY}; > > + if (ipv4) { > > + ovs_be32 ip4 = in6_addr_get_mapped_ipv4(local_ip); > > + put_load_bytes(&ip4, sizeof ip4, MFF_TUN_SRC, 0, 32, ofpacts); > > + } else { > > + put_load_bytes(&local_ip, sizeof local_ip, MFF_TUN_IPV6_SRC, > > + 0, 128, ofpacts); > > + } > > + put_load(mc_group->vni, MFF_TUN_ID, 0, 24, ofpacts); > > + > > + const struct hmapx_node *node; > > + HMAPX_FOR_EACH (node, &mc_group->bindings) { > > + binding = node->data; > > + if (ipv4) { > > + ovs_be32 ip4 = > in6_addr_get_mapped_ipv4(&binding->remote_ip); > > + put_load_bytes(&ip4, sizeof ip4, MFF_TUN_DST, 0, 32, > ofpacts); > > + } else { > > + put_load_bytes(&binding->remote_ip, sizeof > binding->remote_ip, > > + MFF_TUN_IPV6_DST, 0, 128, ofpacts); > > + } > > + ofpact_put_OUTPUT(ofpacts)->port = binding->tunnel_ofport; > > + } > > + put_resubmit(OFTABLE_LOCAL_OUTPUT, ofpacts); > > + > > + ovs_assert(!hmapx_is_empty(&mc_group->bindings)); > > + for (size_t i = 0; i < ARRAY_SIZE(multicast_tunnel_keys); i++) { > > + match_init_catchall(match); > > + match_outport_dp_and_port_keys(match, binding->dp_key, > > + multicast_tunnel_keys[i]); > > + > > + ofctrl_add_flow(flow_table, OFTABLE_REMOTE_VTEP_OUTPUT, 50, > > + mc_group->flow_uuid.parts[0], > > + match, ofpacts, &mc_group->flow_uuid); > > + } > > +} > > + > > +static void > > +physical_eval_evpn_flows(const struct physical_ctx *ctx, > > + struct ofpbuf *ofpacts, > > + struct ovn_desired_flow_table *flow_table) > > +{ > > + if (hmap_is_empty(ctx->evpn_bindings) && > > + hmap_is_empty(ctx->evpn_multicast_groups)) { > > + return; > > + } > > + > > + const char *local_ip_str = smap_get_def(&ctx->chassis->other_config, > > + "ovn-evpn-local-ip", ""); > > + struct in6_addr local_ip; > > + if (!ip46_parse(local_ip_str, &local_ip)) { > > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); > > + VLOG_WARN_RL(&rl, "EVPN enabled, but required 'evpn-local-ip' > is " > > + "missing or invalid %s ", local_ip_str); > > nit: slightly misaligned. > > > + return; > > + } > > + > > + struct match match = MATCH_CATCHALL_INITIALIZER; > > + bool ipv4 = IN6_IS_ADDR_V4MAPPED(&local_ip); > > + > > + const struct evpn_binding *binding; > > + HMAP_FOR_EACH (binding, hmap_node, ctx->evpn_bindings) { > > + physical_consider_evpn_binding(binding, &local_ip, ofpacts, > > + &match, flow_table, ipv4); > > + } > > + > > + const struct evpn_multicast_group *mc_group; > > + HMAP_FOR_EACH (mc_group, hmap_node, ctx->evpn_multicast_groups) { > > + physical_consider_evpn_multicast(mc_group, &local_ip, ofpacts, > > + &match, flow_table, ipv4); > > + } > > +} > > + > > static void > > physical_eval_port_binding(struct physical_ctx *p_ctx, > > const struct sbrec_port_binding *pb, > > @@ -2748,6 +2903,55 @@ physical_handle_mc_group_changes(struct > physical_ctx *p_ctx, > > } > > } > > > > +void > > +physical_handle_evpn_binding_changes( > > + struct physical_ctx *ctx, struct ovn_desired_flow_table *flow_table, > > + const struct hmapx *updated_bindings, > > + const struct hmapx *updated_multicast_groups, > > + const struct uuidset *removed_bindings, > > + const struct uuidset *removed_multicast_groups) > > +{ > > + const char *local_ip_str = smap_get_def(&ctx->chassis->other_config, > > + "ovn-evpn-local-ip", ""); > > + struct in6_addr local_ip; > > + if (!ip46_parse(local_ip_str, &local_ip)) { > > + return; > > + } > > + > > + struct ofpbuf ofpacts; > > + ofpbuf_init(&ofpacts, 0); > > + struct match match = MATCH_CATCHALL_INITIALIZER; > > + bool ipv4 = IN6_IS_ADDR_V4MAPPED(&local_ip); > > + > > + const struct hmapx_node *node; > > + HMAPX_FOR_EACH (node, updated_bindings) { > > + const struct evpn_binding *binding = node->data; > > + > > + ofctrl_remove_flows(flow_table, &binding->flow_uuid); > > + physical_consider_evpn_binding(binding, &local_ip, &ofpacts, > > + &match, flow_table, ipv4); > > + } > > + > > + HMAPX_FOR_EACH (node, updated_multicast_groups) { > > + const struct evpn_multicast_group *mc_group = node->data; > > + > > + ofctrl_remove_flows(flow_table, &mc_group->flow_uuid); > > + physical_consider_evpn_multicast(mc_group, &local_ip, &ofpacts, > > + &match, flow_table, ipv4); > > + } > > + > > + ofpbuf_uninit(&ofpacts); > > + > > + const struct uuidset_node *uuidset_node; > > + UUIDSET_FOR_EACH (uuidset_node, removed_bindings) { > > + ofctrl_remove_flows(flow_table, &uuidset_node->uuid); > > + } > > + > > + UUIDSET_FOR_EACH (uuidset_node, removed_multicast_groups) { > > + ofctrl_remove_flows(flow_table, &uuidset_node->uuid); > > + } > > +} > > + > > void > > physical_run(struct physical_ctx *p_ctx, > > struct ovn_desired_flow_table *flow_table) > > @@ -2797,7 +3001,7 @@ physical_run(struct physical_ctx *p_ctx, > > * have metadata about the ingress and egress logical ports. > > * VXLAN encapsulations have metadata about the egress logical port > only. > > * We set MFF_LOG_DATAPATH, MFF_LOG_INPORT, and MFF_LOG_OUTPORT > from the > > - * tunnel key data where possible, then resubmit to table 40 to > handle > > + * tunnel key data where possible, then resubmit to table 45 to > handle > > * packets to the local hypervisor. */ > > struct chassis_tunnel *tun; > > HMAP_FOR_EACH (tun, hmap_node, p_ctx->chassis_tunnels) { > > @@ -2910,7 +3114,7 @@ physical_run(struct physical_ctx *p_ctx, > > */ > > add_default_drop_flow(p_ctx, OFTABLE_PHY_TO_LOG, flow_table); > > > > - /* Table 40-43, priority 0. > > + /* Table 41-42, priority 0. > > * ======================== > > * > > * Default resubmit actions for OFTABLE_OUTPUT_LARGE_PKT_* tables. > > @@ -2936,7 +3140,7 @@ physical_run(struct physical_ctx *p_ctx, > > ofctrl_add_flow(flow_table, OFTABLE_OUTPUT_LARGE_PKT_PROCESS, 0, 0, > &match, > > &ofpacts, hc_uuid); > > > > - /* Table 42, priority 150. > > + /* Table 43, priority 150. > > * ======================= > > * > > * Handles packets received from a VXLAN tunnel which get > resubmitted to > > @@ -2949,13 +3153,13 @@ physical_run(struct physical_ctx *p_ctx, > > match_set_reg_masked(&match, MFF_LOG_FLAGS - MFF_REG0, > MLF_RCV_FROM_RAMP, > > MLF_RCV_FROM_RAMP | MLF_ALLOW_LOOPBACK); > > > > - /* Resubmit to table 40. */ > > + /* Resubmit to table 45. */ > > ofpbuf_clear(&ofpacts); > > put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts); > > ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150, 0, > > &match, &ofpacts, hc_uuid); > > > > - /* Table 42, priority 150. > > + /* Table 43, priority 150. > > * ======================= > > * > > * Packets that should not be sent to other hypervisors. > > @@ -2963,35 +3167,46 @@ physical_run(struct physical_ctx *p_ctx, > > match_init_catchall(&match); > > match_set_reg_masked(&match, MFF_LOG_FLAGS - MFF_REG0, > > MLF_LOCAL_ONLY, MLF_LOCAL_ONLY); > > - /* Resubmit to table 40. */ > > + /* Resubmit to table 45. */ > > ofpbuf_clear(&ofpacts); > > put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts); > > ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150, 0, > > &match, &ofpacts, hc_uuid); > > > > - /* Table 42, Priority 0. > > + /* Table 43, Priority 0. > > * ======================= > > * > > - * Resubmit packets that are not directed at tunnels or part of a > > - * multicast group to the local output table. */ > > + * Resubmit packets that are not directed at OVN tunnels or part of > a > > + * multicast group to the VTEP output table. */ > > match_init_catchall(&match); > > ofpbuf_clear(&ofpacts); > > - put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts); > > + put_resubmit(OFTABLE_REMOTE_VTEP_OUTPUT, &ofpacts); > > ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 0, 0, &match, > > &ofpacts, hc_uuid); > > > > - /* Table 40, priority 0. > > + /* Table 44, Priority 0. > > + * ======================= > > + * > > + * Resubmit packets that are not directed to remote VTEP to the > local > > + * output table. */ > > + match_init_catchall(&match); > > + ofpbuf_clear(&ofpacts); > > + put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts); > > + ofctrl_add_flow(flow_table, OFTABLE_REMOTE_VTEP_OUTPUT, 0, 0, > &match, > > + &ofpacts, hc_uuid); > > + > > + /* Table 45, priority 0. > > * ====================== > > * > > * Drop packets that do not match previous flows. > > */ > > add_default_drop_flow(p_ctx, OFTABLE_LOCAL_OUTPUT, flow_table); > > > > - /* Table 41, Priority 0. > > + /* Table 46, Priority 0. > > * ======================= > > * > > * Resubmit packets that don't output to the ingress port (already > checked > > - * in table 40) to the logical egress pipeline, clearing the logical > > + * in table 44) to the logical egress pipeline, clearing the logical > > * registers (for consistent behavior with packets that get > tunneled). */ > > match_init_catchall(&match); > > ofpbuf_clear(&ofpacts); > > @@ -3119,6 +3334,7 @@ physical_run(struct physical_ctx *p_ctx, > > &match, &ofpacts, hc_uuid); > > > > physical_eval_remote_chassis_flows(p_ctx, &ofpacts, flow_table); > > + physical_eval_evpn_flows(p_ctx, &ofpacts, flow_table); > > > > ofpbuf_uninit(&ofpacts); > > } > > diff --git a/controller/physical.h b/controller/physical.h > > index 0420251c6..e0443924b 100644 > > --- a/controller/physical.h > > +++ b/controller/physical.h > > @@ -69,6 +69,8 @@ struct physical_ctx { > > const char **encap_ips; > > struct physical_debug debug; > > bool always_tunnel; > > + const struct hmap *evpn_bindings; > > + const struct hmap *evpn_multicast_groups; > > > > /* Set of port binding names that have been already reprocessed > during > > * the I-P run. */ > > @@ -87,4 +89,10 @@ bool physical_handle_flows_for_lport(const struct > sbrec_port_binding *, > > void physical_multichassis_reprocess(const struct sbrec_port_binding *, > > struct physical_ctx *, > > struct ovn_desired_flow_table *); > > +void physical_handle_evpn_binding_changes( > > + struct physical_ctx *, struct ovn_desired_flow_table *, > > + const struct hmapx *updated_bindings, > > + const struct hmapx *updated_multicast_groups, > > + const struct uuidset *removed_bindings, > > + const struct uuidset *removed_multicast_groups); > > #endif /* controller/physical.h */ > > diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h > > index 8b1c1221e..9a8bf4874 100644 > > --- a/include/ovn/logical-fields.h > > +++ b/include/ovn/logical-fields.h > > @@ -63,6 +63,9 @@ enum ovn_controller_event { > > > > #define MFF_LOG_CT_SAVED_STATE MFF_REG4 > > > > +#define MFF_LOG_REMOTE_OUTPORT MFF_REG1 /* Logical remote output > > + * port (32 bits). */ > > + > > /* Logical registers that are needed for backwards > > * compatibility with older northd versions. > > * XXX: All of them can be removed in 26.09. */ > > diff --git a/tests/ovn-macros.at b/tests/ovn-macros.at > > index 3fb56d4be..d82c98e35 100644 > > --- a/tests/ovn-macros.at > > +++ b/tests/ovn-macros.at > > @@ -1480,8 +1480,9 @@ m4_define([OFTABLE_LOG_INGRESS_PIPELINE], [8]) > > m4_define([OFTABLE_OUTPUT_LARGE_PKT_DETECT], [41]) > > m4_define([OFTABLE_OUTPUT_LARGE_PKT_PROCESS], [42]) > > m4_define([OFTABLE_REMOTE_OUTPUT], [43]) > > -m4_define([OFTABLE_LOCAL_OUTPUT], [44]) > > -m4_define([OFTABLE_LOG_EGRESS_PIPELINE], [46]) > > +m4_define([OFTABLE_REMOTE_VTEP_OUTPUT], [44]) > > +m4_define([OFTABLE_LOCAL_OUTPUT], [45]) > > +m4_define([OFTABLE_LOG_EGRESS_PIPELINE], [47]) > > m4_define([OFTABLE_SAVE_INPORT], [64]) > > m4_define([OFTABLE_LOG_TO_PHY], [65]) > > m4_define([OFTABLE_MAC_BINDING], [66]) > > diff --git a/tests/ovn.at b/tests/ovn.at > > index bcf352ab3..6fbfc7fa9 100644 > > --- a/tests/ovn.at > > +++ b/tests/ovn.at > > @@ -40910,7 +40910,7 @@ check_output_flows_tunnelled() { > > dp_key=$2 > > dp_rport=$3 > > AT_CHECK_UNQUOTED([as $hv ovs-ofctl dump-flows br-int > table=OFTABLE_REMOTE_OUTPUT,metadata=0x${dp_key},reg15=0x${dp_rport} | > ofctl_strip_all | grep -v NXST_FLOW], [0], [dnl > > - table=OFTABLE_REMOTE_OUTPUT, > priority=100,reg13=0/0xffff0000,reg15=0x${dp_rport},metadata=0x${dp_key} > actions=load:0x${dp_key}->NXM_NX_TUN_ID[[0..23]],set_field:0x${dp_rport}->tun_metadata0,move:NXM_NX_REG14[[0..14]]->NXM_NX_TUN_METADATA0[[16..30]],output:1,resubmit(,OFTABLE_LOCAL_OUTPUT) > > + table=OFTABLE_REMOTE_OUTPUT, > priority=100,reg13=0/0xffff0000,reg15=0x${dp_rport},metadata=0x${dp_key} > actions=load:0x${dp_key}->NXM_NX_TUN_ID[[0..23]],set_field:0x${dp_rport}->tun_metadata0,move:NXM_NX_REG14[[0..14]]->NXM_NX_TUN_METADATA0[[16..30]],output:1,resubmit(,OFTABLE_REMOTE_VTEP_OUTPUT) > > ]) > > } > > > > I have addressed all of those nits in v4. Thanks, Ales _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev