On Thu, Aug 14, 2025 at 3:23 PM Ilya Maximets <i.maxim...@ovn.org> wrote:
> On 8/12/25 4:56 PM, Ales Musil via dev wrote: > > Add extra action called "get_remote_fdb()", which is almost the same > > as "get_fdb()" but goes into the new OFTABLE_GET_REMOTE_FDB table. > > Use the new action in the logical flows to determine if the traffic > > should go towards the remote FDB. The current implementation will > > give a priority to remove FDB in case there is duplicate MAC between > > the SB FDB table and the remote FDB table. > > > > In order to make the logical action that assigns to two registers > > work, add default flows for the FDB and remote FDB side tables. > > The packet would be dropped otherwise if it would fall through > > the table without finding any FDB. This doesn't change > > the behavior for non-EVPN LS, because the packet is either dropped > > or will go towards the "unknown" multicast group as previously. > > > > There is also an option that will allow CMS to set FDB preference > > (local/remote), called "dynamic-routing-fdb-prefer-local" in LS > > other config. It defaults to "false", which means remote has the > > priority. > > > > Reported-at: https://issues.redhat.com/browse/FDP-1387 > > Signed-off-by: Ales Musil <amu...@redhat.com> > > --- > > v3: Rebase on top of latest main. > > Add the option to set FDB preference. > > > > v2: Rebase on top of latest main. > > --- > Hi Ilya, thank you for the review. > > NEWS | 3 ++ > > TODO.rst | 3 -- > > controller/lflow.c | 1 + > > controller/physical.c | 14 +++++++++ > > include/ovn/actions.h | 3 ++ > > lib/actions.c | 53 ++++++++++++++++++++++++++------ > > lib/logical-fields.c | 5 +++ > > lib/ovn-util.c | 4 +-- > > northd/northd.c | 71 +++++++++++++++++++++++++++++++++++-------- > > northd/northd.h | 3 ++ > > ovn-nb.xml | 21 +++++++++++++ > > tests/ovn-northd.at | 59 +++++++++++++++++++++++++++++++++++ > > tests/ovn.at | 19 ++++++++++-- > > tests/system-ovn.at | 19 ++++++++++++ > > tests/test-ovn.c | 1 + > > utilities/ovn-trace.c | 6 ++++ > > 16 files changed, 257 insertions(+), 28 deletions(-) > > > > diff --git a/NEWS b/NEWS > > index 9a7e2c8a8..eac073cac 100644 > > --- a/NEWS > > +++ b/NEWS > > @@ -54,6 +54,9 @@ Post v25.03.0 > > for the EVPN traffic egressing through the tunnel. > > * Add the "other_config:dynamic-routing-vni" to Logical Switches. > If set > > to valid integer the LS is considered to be connected to EVPN L2 > domain. > > + * Add the "other_config:dynamic-routing-fdb-prefer-local" to > Logical > > + Switches. If set to "true" the LS will prefer SB FDB table for > > + FDB lookup. Default is false. > > > > OVN v25.03.0 - 07 Mar 2025 > > -------------------------- > > diff --git a/TODO.rst b/TODO.rst > > index 0d3c29506..9a9df78f2 100644 > > --- a/TODO.rst > > +++ b/TODO.rst > > @@ -157,6 +157,3 @@ OVN To-do List > > * 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. > > - > > - * Allow CMS to set FDB priority for EVPN, currently the remote FDB has > > - higher priority. > > diff --git a/controller/lflow.c b/controller/lflow.c > > index 04fb3ceed..b75ae5c0d 100644 > > --- a/controller/lflow.c > > +++ b/controller/lflow.c > > @@ -885,6 +885,7 @@ add_matches_to_flow_table(const struct > sbrec_logical_flow *lflow, > > .lb_hairpin_reply_ptable = OFTABLE_CHK_LB_HAIRPIN_REPLY, > > .ct_snat_vip_ptable = OFTABLE_CT_SNAT_HAIRPIN, > > .fdb_ptable = OFTABLE_GET_FDB, > > + .remote_fdb_ptable = OFTABLE_GET_REMOTE_FDB, > > .fdb_lookup_ptable = OFTABLE_LOOKUP_FDB, > > .in_port_sec_ptable = OFTABLE_CHK_IN_PORT_SEC, > > .out_port_sec_ptable = OFTABLE_CHK_OUT_PORT_SEC, > > diff --git a/controller/physical.c b/controller/physical.c > > index a2b8c4071..60077ff71 100644 > > --- a/controller/physical.c > > +++ b/controller/physical.c > > @@ -3385,5 +3385,19 @@ physical_run(struct physical_ctx *p_ctx, > > physical_eval_remote_chassis_flows(p_ctx, &ofpacts, flow_table); > > physical_eval_evpn_flows(p_ctx, &ofpacts, flow_table); > > > > + /* Default flow for OFTABLE_GET_FDB table. */ > > + match_init_catchall(&match); > > + ofpbuf_clear(&ofpacts); > > + put_load(0, MFF_LOG_OUTPORT, 0, 32, &ofpacts); > > + ofctrl_add_flow(flow_table, OFTABLE_GET_FDB, 0, 0, > > + &match, &ofpacts, hc_uuid); > > + > > + /* Default flow for OFTABLE_GET_REMOTE_FDB table. */ > > + match_init_catchall(&match); > > + ofpbuf_clear(&ofpacts); > > + put_load(0, MFF_LOG_REMOTE_OUTPORT, 0, 32, &ofpacts); > > + ofctrl_add_flow(flow_table, OFTABLE_GET_REMOTE_FDB, 0, 0, > > + &match, &ofpacts, hc_uuid); > > + > > ofpbuf_uninit(&ofpacts); > > } > > diff --git a/include/ovn/actions.h b/include/ovn/actions.h > > index 30e5e4229..0eaef9112 100644 > > --- a/include/ovn/actions.h > > +++ b/include/ovn/actions.h > > @@ -121,6 +121,7 @@ struct collector_set_ids; > > OVNACT(SCTP_ABORT, ovnact_nest) \ > > OVNACT(PUT_FDB, ovnact_put_fdb) \ > > OVNACT(GET_FDB, ovnact_get_fdb) \ > > + OVNACT(GET_REMOTE_FDB, ovnact_get_fdb) \ > > OVNACT(LOOKUP_FDB, ovnact_lookup_fdb) \ > > OVNACT(CHECK_IN_PORT_SEC, ovnact_result) \ > > OVNACT(CHECK_OUT_PORT_SEC, ovnact_result) \ > > @@ -956,6 +957,8 @@ struct ovnact_encode_params { > > * 'ct_snat_to_vip' to resubmit. */ > > uint8_t fdb_ptable; /* OpenFlow table for > > * 'get_fdb' to resubmit. */ > > + uint8_t remote_fdb_ptable; /* OpenFlow table for > > + * 'get_remote_fdb' to resubmit. */ > > uint8_t fdb_lookup_ptable; /* OpenFlow table for > > * 'lookup_fdb' to resubmit. */ > > uint8_t in_port_sec_ptable; /* OpenFlow table for > > diff --git a/lib/actions.c b/lib/actions.c > > index 00e439285..98ab368fc 100644 > > --- a/lib/actions.c > > +++ b/lib/actions.c > > @@ -4385,19 +4385,22 @@ ovnact_put_fdb_free(struct ovnact_put_fdb > *put_fdb OVS_UNUSED) > > } > > > > static void > > -format_GET_FDB(const struct ovnact_get_fdb *get_fdb, struct ds *s) > > +format_get_fdb(const struct ovnact_get_fdb *get_fdb, const char *type, > > + struct ds *s) > > { > > expr_field_format(&get_fdb->dst, s); > > - ds_put_cstr(s, " = get_fdb("); > > + ds_put_format(s, " = %s(", type); > > expr_field_format(&get_fdb->mac, s); > > ds_put_cstr(s, ");"); > > } > > > > static void > > -encode_GET_FDB(const struct ovnact_get_fdb *get_fdb, > > +encode_get_fdb(const struct ovnact_get_fdb *get_fdb, > > const struct ovnact_encode_params *ep, > > - struct ofpbuf *ofpacts) > > + bool remote, struct ofpbuf *ofpacts) > > { > > + const enum mf_field_id outport_id = > > + remote ? MFF_LOG_REMOTE_OUTPORT : MFF_LOG_OUTPORT; > > struct mf_subfield dst = expr_resolve_field(&get_fdb->dst); > > ovs_assert(dst.field); > > > > @@ -4405,25 +4408,53 @@ encode_GET_FDB(const struct ovnact_get_fdb > *get_fdb, > > { expr_resolve_field(&get_fdb->mac), MFF_ETH_DST }, > > }; > > encode_setup_args(args, ARRAY_SIZE(args), ofpacts); > > - put_load(0, MFF_LOG_OUTPORT, 0, 32, ofpacts); > > - emit_resubmit(ofpacts, ep->fdb_ptable); > > + put_load(0, outport_id, 0, 32, ofpacts); > > + emit_resubmit(ofpacts, remote ? ep->remote_fdb_ptable : > ep->fdb_ptable); > > encode_restore_args(args, ARRAY_SIZE(args), ofpacts); > > > > - if (dst.field->id != MFF_LOG_OUTPORT) { > > + if (dst.field->id != outport_id) { > > struct ofpact_reg_move *orm = ofpact_put_REG_MOVE(ofpacts); > > orm->dst = dst; > > - orm->src.field = mf_from_id(MFF_LOG_OUTPORT); > > + orm->src.field = mf_from_id(outport_id); > > orm->src.ofs = 0; > > orm->src.n_bits = 32; > > } > > } > > > > +static void > > +format_GET_FDB(const struct ovnact_get_fdb *get_fdb, struct ds *s) > > +{ > > + format_get_fdb(get_fdb, "get_fdb", s); > > +} > > + > > +static void > > +encode_GET_FDB(const struct ovnact_get_fdb *get_fdb, > > + const struct ovnact_encode_params *ep, > > + struct ofpbuf *ofpacts) > > +{ > > + encode_get_fdb(get_fdb, ep, false, ofpacts); > > +} > > + > > +static void > > +format_GET_REMOTE_FDB(const struct ovnact_get_fdb *get_fdb, struct ds > *s) > > +{ > > + format_get_fdb(get_fdb, "get_remote_fdb", s); > > +} > > + > > +static void > > +encode_GET_REMOTE_FDB(const struct ovnact_get_fdb *get_fdb, > > + const struct ovnact_encode_params *ep, > > + struct ofpbuf *ofpacts) > > +{ > > + encode_get_fdb(get_fdb, ep, true, ofpacts); > > +} > > + > > static void > > parse_get_fdb(struct action_context *ctx, > > struct expr_field *dst, > > struct ovnact_get_fdb *get_fdb) > > { > > - lexer_get(ctx->lexer); /* Skip get_bfd. */ > > + lexer_get(ctx->lexer); /* Skip get_bfd/get_remote_fdb. */ > > lexer_get(ctx->lexer); /* Skip '('. */ > > > > /* Validate that the destination is a 32-bit, modifiable field if it > > @@ -5765,6 +5796,10 @@ parse_set_action(struct action_context *ctx) > > && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) { > > parse_get_fdb( > > ctx, &lhs, ovnact_put_GET_FDB(ctx->ovnacts)); > > + } else if (!strcmp(ctx->lexer->token.s, "get_remote_fdb") > > + && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) { > > + parse_get_fdb( > > + ctx, &lhs, ovnact_put_GET_REMOTE_FDB(ctx->ovnacts)); > > } else if (!strcmp(ctx->lexer->token.s, "lookup_fdb") > > && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) { > > parse_lookup_fdb( > > diff --git a/lib/logical-fields.c b/lib/logical-fields.c > > index f19eb579b..fcafeeac2 100644 > > --- a/lib/logical-fields.c > > +++ b/lib/logical-fields.c > > @@ -72,6 +72,11 @@ ovn_init_symtab(struct shash *symtab) > > expr_symtab_add_string(symtab, "inport", MFF_LOG_INPORT, NULL); > > expr_symtab_add_string(symtab, "outport", MFF_LOG_OUTPORT, NULL); > > > > + /* The port isn't reserved along the pipeline it's just defined as > symbol > > + * to support matching on string and moving between string > registers. */ > > + expr_symtab_add_string(symtab, "remote_outport", > > + MFF_LOG_REMOTE_OUTPORT, NULL); > > + > > /* Logical registers: > > * 128-bit xxregs > > * 64-bit xregs > > diff --git a/lib/ovn-util.c b/lib/ovn-util.c > > index 70a1c9404..fbba82758 100644 > > --- a/lib/ovn-util.c > > +++ b/lib/ovn-util.c > > @@ -915,8 +915,8 @@ ip_address_and_port_from_lb_key(const char *key, > char **ip_address, > > * > > * NOTE: If OVN_NORTHD_PIPELINE_CSUM is updated make sure to double > check > > * whether an update of OVN_INTERNAL_MINOR_VER is required. */ > > -#define OVN_NORTHD_PIPELINE_CSUM "1158333617 10744" > > -#define OVN_INTERNAL_MINOR_VER 9 > > +#define OVN_NORTHD_PIPELINE_CSUM "2405300854 10800" > > +#define OVN_INTERNAL_MINOR_VER 10 > > > > /* Returns the OVN version. The caller must free the returned value. */ > > char * > > diff --git a/northd/northd.c b/northd/northd.c > > index f02801f48..98d223177 100644 > > --- a/northd/northd.c > > +++ b/northd/northd.c > > @@ -254,12 +254,14 @@ static const char *reg_ct_state[] = { > > * | R0 | REGBIT_{CONNTRACK/DHCP/DNS} | | > | > > * | | REGBIT_{HAIRPIN/HAIRPIN_REPLY} | | > | > > * | | REGBIT_ACL_HINT_{ALLOW_NEW/ALLOW/DROP/BLOCK} | | > | > > - * | | REGBIT_ACL_{LABEL/STATELESS} | X | > | > > - * +----+----------------------------------------------+ X | > | > > - * | R1 | REG_CT_TP_DST (0..15) | R | > | > > - * | | REG_CT_PROTO (16..23) | E | > | > > - * | | (>= IN_CT_EXTRACT && <= IN_LB_AFF_LEARN) | G | > | > > - * +----+----------------------------------------------+ 0 | > | > > + * | | REGBIT_ACL_{LABEL/STATELESS} | | > | > > + * +----+----------------------------------------------+ | > | > > + * | R1 | REG_CT_TP_DST (0..15) | | > | > > + * | | REG_CT_PROTO (16..23) | | > | > > + * | | (>= IN_CT_EXTRACT && <= IN_LB_AFF_LEARN) | X | > | > > + * | | remote_outport | X | > | > > + * | | (>= L2_LKUP && <= L2_UNKNOWN) | R | > | > > + * +----+----------------------------------------------+ E | > | > > * | R2 | REG_LB_PORT | G | > | > > * | | (>= IN_PRE_STATEFUL && <= IN_LB_AFF_LEARN) | 0 | > | > > * | | REG_ACL_ID | | > | > > @@ -812,10 +814,10 @@ ovn_datapath_update_external_ids(struct > ovn_datapath *od) > > "%u", age_threshold); > > } > > > > - int64_t vni = ovn_smap_get_llong(&od->nbs->other_config, > > - "dynamic-routing-vni", -1); > > - if (ovn_is_valid_vni(vni)) { > > - smap_add_format(&ids, "dynamic-routing-vni", "%"PRIi64, > vni); > > + if (od->has_evpn_vni) { > > join_datapaths() sets this value after calling > ovn_datapath_update_external_ids() > for the existing datapath. Is it a problem? > This shouldn't be an issue after the I-P change. > > > + const char *vni = smap_get(&od->nbs->other_config, > > + "dynamic-routing-vni"); > > + smap_add(&ids, "dynamic-routing-vni", vni); > > } > > } > > > > @@ -976,6 +978,12 @@ join_datapaths(const struct > nbrec_logical_switch_table *nbrec_ls_table, > > false)) { > > od->lb_with_stateless_mode = true; > > } > > + > > + int64_t vni = ovn_smap_get_llong(&od->nbs->other_config, > > + "dynamic-routing-vni", -1); > > + if (ovn_is_valid_vni(vni)) { > > + od->has_evpn_vni = true; > > So, it seems like this value can never become false again, right? > We may need a test for this. > > Same problem for the 'lb_with_stateless_mode', I suppose. > This shouldn't be an issue after the I-P change. > > + } > > } > > > > const struct nbrec_logical_router *nbr; > > @@ -5816,12 +5824,17 @@ build_lswitch_learn_fdb_od( > > struct lflow_ref *lflow_ref) > > { > > ovs_assert(od->nbs); > > + const char *lkp_action = od->has_evpn_vni > > + ? "outport = get_fdb(eth.dst); " > > + "remote_outport = get_remote_fdb(eth.dst); next;" > > + : "outport = get_fdb(eth.dst); next;"; > > + > > ovn_lflow_add(lflows, od, S_SWITCH_IN_LOOKUP_FDB, 0, "1", "next;", > > lflow_ref); > > ovn_lflow_add(lflows, od, S_SWITCH_IN_PUT_FDB, 0, "1", "next;", > > lflow_ref); > > ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 0, "1", > > - "outport = get_fdb(eth.dst); next;", lflow_ref); > > + lkp_action, lflow_ref); > > > > ovn_lflow_add(lflows, od, S_SWITCH_OUT_LOOKUP_FDB, 0, "1", "next;", > > lflow_ref); > > @@ -9351,6 +9364,36 @@ is_vlan_transparent(const struct ovn_datapath *od) > > return smap_get_bool(&od->nbs->other_config, "vlan-passthru", > false); > > } > > > > +static void > > +build_lswitch_lflows_evpn_l2_unknown(struct ovn_datapath *od, > > + struct lflow_table *lflows, > > + struct lflow_ref *lflow_ref) > > +{ > > + if (od->has_unknown) { > > + ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_UNKNOWN, 50, > > + "outport == \"none\" && remote_outport == > \"none\"", > > + "outport = \""MC_UNKNOWN "\"; output;", > lflow_ref); > > + } else { > > + ovn_lflow_add_drop_with_desc( > > + lflows, od, S_SWITCH_IN_L2_UNKNOWN, 50, "outport == > \"none\" && " > > + "remote_outport == \"none\"", "No L2 destination", > lflow_ref); > > + } > > + > > + if (smap_get_bool(&od->nbs->other_config, > > + "dynamic-routing-fdb-prefer-local", false)) { > > + ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_UNKNOWN, 25, > > + "outport == \"none\"", > > + "outport = remote_outport; output;", lflow_ref); > > + ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_UNKNOWN, 0, "1", > > + "output;", lflow_ref); > > + } else { > > + ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_UNKNOWN, 25, > > + "remote_outport == \"none\"", "output;", > lflow_ref); > > + ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_UNKNOWN, 0, "1", > > + "outport = remote_outport; output;", lflow_ref); > > + } > > +} > > + > > static void > > build_lswitch_lflows_l2_unknown(struct ovn_datapath *od, > > struct lflow_table *lflows, > > @@ -17604,7 +17647,11 @@ build_lswitch_and_lrouter_iterate_by_ls(struct > ovn_datapath *od, > > ovn_lflow_add(lsi->lflows, od, S_SWITCH_IN_CT_EXTRACT, 0, "1", > "next;", > > NULL); > > build_lswitch_lb_affinity_default_flows(od, lsi->lflows, NULL); > > - build_lswitch_lflows_l2_unknown(od, lsi->lflows, NULL); > > + if (od->has_evpn_vni) { > > + build_lswitch_lflows_evpn_l2_unknown(od, lsi->lflows, NULL); > > + } else { > > + build_lswitch_lflows_l2_unknown(od, lsi->lflows, NULL); > > + } > > build_mcast_flood_lswitch(od, lsi->lflows, &lsi->actions, NULL); > > } > > > > diff --git a/northd/northd.h b/northd/northd.h > > index 1108793d7..1235f3912 100644 > > --- a/northd/northd.h > > +++ b/northd/northd.h > > @@ -404,6 +404,9 @@ struct ovn_datapath { > > * This is applicable only to routers with "remote" ports. */ > > bool is_transit_router; > > > > + /* Indicates that the LS has valid vni associated with it. */ > > + bool has_evpn_vni; > > + > > /* OVN northd only needs to know about logical router gateway ports > for > > * NAT/LB on a distributed router. The "distributed gateway ports" > are > > * populated only when there is a gateway chassis or ha chassis > group > > diff --git a/ovn-nb.xml b/ovn-nb.xml > > index c7c1fd6c7..84c4e2b88 100644 > > --- a/ovn-nb.xml > > +++ b/ovn-nb.xml > > @@ -886,6 +886,27 @@ > > removal/change in the future. > > </p> > > </column> > > + > > + <column name="other_config" > key="dynamic-routing-evpn-fdb-prefer-local" > > + type='{"type": "boolean"}'> > > + <p> > > + This option defines the preference of FDB lookup, if set to > > + true OVN will try to find the FDB entry in SB <code>FDB</code> > > + table first. Then it tries to resolve the FDB via > > + <code>ovn-controller</code> local EVPN FDB cache. The option > > + default to false. > > *defaults > Fixed in v4. > > > + </p> > > + > > + <p> > > + Only relevant if <ref column="other_config" > key="dynamic-routing-vni" > > + table="Logical_switch"/> is set to > valid VNI. > > + </p> > > + > > + <p> > > + NOTE: this feature is experimental and may be subject to > > + removal/change in the future. > > + </p> > > + </column> > > </group> > > > > <group title="IP Multicast Snooping Options"> > > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at > > index 05acd6f4d..303619a8b 100644 > > --- a/tests/ovn-northd.at > > +++ b/tests/ovn-northd.at > > @@ -17641,3 +17641,62 @@ check as northd ovn-appctl -t ovn-northd > inc-engine/clear-stats > > > > AT_CLEANUP > > ]) > > + > > +OVN_FOR_EACH_NORTHD_NO_HV([ > > +AT_SETUP([LS dynamic-routing-fdb-prefer-local]) > > +ovn_start ovn-northd > > + > > +AS_BOX([Create logical switch.]) > > +check ovn-nbctl --wait=sb ls-add ls-evpn > > +ovn-sbctl dump-flows ls-evpn > lflows > > + > > +AT_CHECK([grep 'ls_in_l2_lkup' lflows | grep "get_fdb" | > ovn_strip_lflows], [0], [dnl > > + table=??(ls_in_l2_lkup ), priority=0 , match=(1), > action=(outport = get_fdb(eth.dst); next;) > > +]) > > + > > +AT_CHECK([grep 'ls_in_l2_unknown' lflows | ovn_strip_lflows], [0], [dnl > > + table=??(ls_in_l2_unknown ), priority=0 , match=(1), > action=(output;) > > + table=??(ls_in_l2_unknown ), priority=50 , match=(outport == > "none"), action=(drop;) > > +]) > > + > > +check ovn-nbctl --wait=hv set logical_switch ls-evpn > other_config:dynamic-routing-vni=10 > > +ovn-sbctl dump-flows ls-evpn > lflows > > + > > +AT_CHECK([grep 'ls_in_l2_lkup' lflows | grep "get_fdb" | > ovn_strip_lflows], [0], [dnl > > + table=??(ls_in_l2_lkup ), priority=0 , match=(1), > action=(outport = get_fdb(eth.dst); remote_outport = > get_remote_fdb(eth.dst); next;) > > +]) > > + > > +AT_CHECK([grep 'ls_in_l2_unknown' lflows | ovn_strip_lflows], [0], [dnl > > + table=??(ls_in_l2_unknown ), priority=0 , match=(1), > action=(outport = remote_outport; output;) > > + table=??(ls_in_l2_unknown ), priority=25 , match=(remote_outport > == "none"), action=(output;) > > + table=??(ls_in_l2_unknown ), priority=50 , match=(outport == > "none" && remote_outport == "none"), action=(drop;) > > +]) > > + > > +check ovn-nbctl --wait=hv set logical_switch ls-evpn > other_config:dynamic-routing-fdb-prefer-local=true > > +ovn-sbctl dump-flows ls-evpn > lflows > > + > > +AT_CHECK([grep 'ls_in_l2_lkup' lflows | grep "get_fdb" | > ovn_strip_lflows], [0], [dnl > > + table=??(ls_in_l2_lkup ), priority=0 , match=(1), > action=(outport = get_fdb(eth.dst); remote_outport = > get_remote_fdb(eth.dst); next;) > > +]) > > + > > +AT_CHECK([grep 'ls_in_l2_unknown' lflows | ovn_strip_lflows], [0], [dnl > > + table=??(ls_in_l2_unknown ), priority=0 , match=(1), > action=(output;) > > + table=??(ls_in_l2_unknown ), priority=25 , match=(outport == > "none"), action=(outport = remote_outport; output;) > > + table=??(ls_in_l2_unknown ), priority=50 , match=(outport == > "none" && remote_outport == "none"), action=(drop;) > > +]) > > + > > +check ovn-nbctl --wait=hv remove logical_switch ls-evpn other_config > dynamic-routing-fdb-prefer-local > > +ovn-sbctl dump-flows ls-evpn > lflows > > + > > +AT_CHECK([grep 'ls_in_l2_lkup' lflows | grep "get_fdb" | > ovn_strip_lflows], [0], [dnl > > + table=??(ls_in_l2_lkup ), priority=0 , match=(1), > action=(outport = get_fdb(eth.dst); remote_outport = > get_remote_fdb(eth.dst); next;) > > +]) > > + > > +AT_CHECK([grep 'ls_in_l2_unknown' lflows | ovn_strip_lflows], [0], [dnl > > + table=??(ls_in_l2_unknown ), priority=0 , match=(1), > action=(outport = remote_outport; output;) > > + table=??(ls_in_l2_unknown ), priority=25 , match=(remote_outport > == "none"), action=(output;) > > + table=??(ls_in_l2_unknown ), priority=50 , match=(outport == > "none" && remote_outport == "none"), action=(drop;) > > +]) > > + > > +AT_CLEANUP > > +]) > > diff --git a/tests/ovn.at b/tests/ovn.at > > index 6fbfc7fa9..dd8ef1e06 100644 > > --- a/tests/ovn.at > > +++ b/tests/ovn.at > > @@ -2087,6 +2087,13 @@ reg15 = get_fdb(eth.dst); > > outport = get_fdb(ip4.dst); > > Cannot use 32-bit field ip4.dst[[0..31]] where 48-bit field is > required. > > > > +# get_remote_fdb > > +reg1 = get_remote_fdb(eth.dst); > > + encodes as > set_field:0->reg1,resubmit(,OFTABLE_GET_REMOTE_FDB),move:NXM_NX_REG1[[]]->NXM_NX_XXREG0[[64..95]] > > + > > +reg1 = get_remote_fdb(eth.src); > > + encodes as > push:NXM_OF_ETH_DST[[]],push:NXM_OF_ETH_SRC[[]],pop:NXM_OF_ETH_DST[[]],set_field:0->reg1,resubmit(,OFTABLE_GET_REMOTE_FDB),pop:NXM_OF_ETH_DST[[]],move:NXM_NX_REG1[[]]->NXM_NX_XXREG0[[64..95]] > > + > > # lookup_fdb > > reg0[[0]] = lookup_fdb(inport, eth.src); > > encodes as > set_field:0/0x100->reg10,resubmit(,OFTABLE_LOOKUP_FDB),move:NXM_NX_REG10[[8]]->NXM_NX_XXREG0[[96]] > > @@ -32987,10 +32994,12 @@ as hv2 ovs-ofctl dump-flows br-int > table=OFTABLE_GET_FDB > hv2_offlows_table71.t > > AT_CAPTURE_FILE([hv1_offlows_table71.txt]) > > AT_CAPTURE_FILE([hv2_offlows_table71.txt]) > > AT_CHECK_UNQUOTED([cat hv1_offlows_table71.txt | grep -v NXST | cut -d > ' ' -f8- | sort], [0], [dnl > > +priority=0 actions=load:0->NXM_NX_REG15[[]] > > priority=100,metadata=0x$dp_key,dl_dst=50:54:00:00:00:13 > actions=load:0x$port_key->NXM_NX_REG15[[]] > > ]) > > > > AT_CHECK_UNQUOTED([cat hv2_offlows_table71.txt | grep -v NXST | cut -d > ' ' -f8- | sort], [0], [dnl > > +priority=0 actions=load:0->NXM_NX_REG15[[]] > > priority=100,metadata=0x$dp_key,dl_dst=50:54:00:00:00:13 > actions=load:0x$port_key->NXM_NX_REG15[[]] > > ]) > > > > @@ -33024,6 +33033,7 @@ AT_CAPTURE_FILE([hv3_offlows_table71.txt]) > > AT_CAPTURE_FILE([hv3_offlows_table72.txt]) > > > > AT_CHECK_UNQUOTED([cat hv3_offlows_table71.txt | grep -v NXST | cut -d > ' ' -f8- | sort], [0], [dnl > > +priority=0 actions=load:0->NXM_NX_REG15[[]] > > priority=100,metadata=0x$dp_key,dl_dst=50:54:00:00:00:13 > actions=load:0x$port_key->NXM_NX_REG15[[]] > > ]) > > > > @@ -33056,16 +33066,19 @@ AT_CAPTURE_FILE([hv1_offlows_table71.txt]) > > AT_CAPTURE_FILE([hv2_offlows_table71.txt]) > > AT_CAPTURE_FILE([hv3_offlows_table71.txt]) > > AT_CHECK_UNQUOTED([cat hv1_offlows_table71.txt | grep -v NXST | cut -d > ' ' -f8- | sort], [0], [dnl > > +priority=0 actions=load:0->NXM_NX_REG15[[]] > > priority=100,metadata=0x$dp_key,dl_dst=50:54:00:00:00:13 > actions=load:0x$port_key->NXM_NX_REG15[[]] > > priority=100,metadata=0x$dp_key,dl_dst=50:54:00:00:00:14 > actions=load:0x$port_key->NXM_NX_REG15[[]] > > ]) > > > > AT_CHECK_UNQUOTED([cat hv2_offlows_table71.txt | grep -v NXST | cut -d > ' ' -f8- | sort], [0], [dnl > > +priority=0 actions=load:0->NXM_NX_REG15[[]] > > priority=100,metadata=0x$dp_key,dl_dst=50:54:00:00:00:13 > actions=load:0x$port_key->NXM_NX_REG15[[]] > > priority=100,metadata=0x$dp_key,dl_dst=50:54:00:00:00:14 > actions=load:0x$port_key->NXM_NX_REG15[[]] > > ]) > > > > AT_CHECK_UNQUOTED([cat hv3_offlows_table71.txt | grep -v NXST | cut -d > ' ' -f8- | sort], [0], [dnl > > +priority=0 actions=load:0->NXM_NX_REG15[[]] > > priority=100,metadata=0x$dp_key,dl_dst=50:54:00:00:00:13 > actions=load:0x$port_key->NXM_NX_REG15[[]] > > priority=100,metadata=0x$dp_key,dl_dst=50:54:00:00:00:14 > actions=load:0x$port_key->NXM_NX_REG15[[]] > > ]) > > @@ -33258,10 +33271,12 @@ as hv2 ovs-ofctl dump-flows br-int > table=OFTABLE_GET_FDB > hv2_offlows_table71.t > > > > AT_CAPTURE_FILE([hv1_offlows_table71.txt]) > > AT_CAPTURE_FILE([hv2_offlows_table71.txt]) > > -AT_CHECK([cat hv1_offlows_table71.txt | grep -v NXST], [1], [dnl > > +AT_CHECK([cat hv1_offlows_table71.txt | grep -v NXST | cut -d ' ' -f8- > | sort], [0], [dnl > > +priority=0 actions=load:0->NXM_NX_REG15[[]] > > ]) > > > > -AT_CHECK([cat hv2_offlows_table71.txt | grep -v NXST], [1], [dnl > > +AT_CHECK([cat hv2_offlows_table71.txt | grep -v NXST | cut -d ' ' -f8- > | sort], [0], [dnl > > +priority=0 actions=load:0->NXM_NX_REG15[[]] > > ]) > > > > as hv1 ovs-ofctl dump-flows br-int table=OFTABLE_LOOKUP_FDB > > hv1_offlows_table72.txt > > diff --git a/tests/system-ovn.at b/tests/system-ovn.at > > index 9c1e0e0dd..2366f513c 100644 > > --- a/tests/system-ovn.at > > +++ b/tests/system-ovn.at > > @@ -18417,18 +18417,37 @@ AT_CHECK([grep "resubmit" > oftable_remote_vtep_output | grep -c "load:0xa900000a" > > AT_CHECK([grep "resubmit" oftable_remote_vtep_output | grep -c > "load:0xa9000014"], [0], [3 > > ]) > > > > +# Simulate remote workload. > > +check bridge fdb add f0:00:0f:16:10:50 dev vxlan-$vni dst 169.0.0.10 > static extern_learn > > +check bridge fdb add f0:00:0f:16:10:60 dev vxlan-$vni dst 169.0.0.20 > static extern_learn > > + > > +OVS_WAIT_FOR_OUTPUT_UNQUOTED([ovn-appctl evpn/vtep-fdb-list | cut -d',' > -f2- | sort], [0], [dnl > > + MAC: f0:00:0f:16:10:50, binding_key: 0x80000001, dp_key: $dp_key > > + MAC: f0:00:0f:16:10:60, binding_key: 0x80000002, dp_key: $dp_key > > +]) > > + > > +AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int > table=OFTABLE_GET_REMOTE_FDB | grep priority | \ > > + awk '{print $7, $8}' | sort], [0], [dnl > > +priority=0 actions=load:0->NXM_NX_REG1[[]] > > +priority=150,metadata=0x$dp_key,dl_dst=f0:00:0f:16:10:50 > actions=load:0x80000001->NXM_NX_REG1[[]] > > +priority=150,metadata=0x$dp_key,dl_dst=f0:00:0f:16:10:60 > actions=load:0x80000002->NXM_NX_REG1[[]] > > +]) > > + > > # Check that the recompute won't change the UUIDs and tunnel keys. > > ovn-appctl evpn/vtep-binding-list > bindings_before > > ovn-appctl evpn/vtep-multicast-group-list > mc_groups_before > > +ovn-appctl evpn/vtep-fdb-list > fdb_before > > > > check ovn-appctl inc-engine/recompute > > check ovn-nbctl --wait=hv sync > > > > ovn-appctl evpn/vtep-binding-list > bindings_after > > ovn-appctl evpn/vtep-multicast-group-list > mc_groups_after > > +ovn-appctl evpn/vtep-fdb-list > fdb_after > > > > check diff -q bindings_before bindings_after > > check diff -q mc_groups_before mc_groups_after > > +check diff -q fdb_before fdb_after > > > > OVN_CLEANUP_CONTROLLER([hv1]) > > > > diff --git a/tests/test-ovn.c b/tests/test-ovn.c > > index 1580f44c4..fae7e7bd5 100644 > > --- a/tests/test-ovn.c > > +++ b/tests/test-ovn.c > > @@ -1380,6 +1380,7 @@ test_parse_actions(struct ovs_cmdl_context *ctx > OVS_UNUSED) > > .lb_hairpin_reply_ptable = OFTABLE_CHK_LB_HAIRPIN_REPLY, > > .ct_snat_vip_ptable = OFTABLE_CT_SNAT_HAIRPIN, > > .fdb_ptable = OFTABLE_GET_FDB, > > + .remote_fdb_ptable = OFTABLE_GET_REMOTE_FDB, > > .fdb_lookup_ptable = OFTABLE_LOOKUP_FDB, > > .common_nat_ct_zone = MFF_LOG_DNAT_ZONE, > > .in_port_sec_ptable = OFTABLE_CHK_IN_PORT_SEC, > > diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c > > index a63a3be19..caeec9619 100644 > > --- a/utilities/ovn-trace.c > > +++ b/utilities/ovn-trace.c > > @@ -3536,6 +3536,12 @@ trace_actions(const struct ovnact *ovnacts, > size_t ovnacts_len, > > execute_get_fdb(ovnact_get_GET_FDB(a), dp, uflow); > > break; > > > > + case OVNACT_GET_REMOTE_FDB: > > + ovntrace_node_append(super, OVNTRACE_NODE_OUTPUT, > > + "/* The remote FDB table is different" > > + " per each chassis. */"); > > + break; > > + > > case OVNACT_LOOKUP_FDB: > > execute_lookup_fdb(ovnact_get_LOOKUP_FDB(a), dp, uflow, > super); > > break; > > Thanks, Ales _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev