On Thu, Aug 14, 2025 at 12:41 PM Xavier Simonart <xsimo...@redhat.com>
wrote:

> Hi Ales, Dumitru
>
> Thanks for the patch.
> Two small nits below
>
> Acked-by: Xavier Simonart <xsimo...@redhat.com>
>
> Thanks
> Xavier
>

Hi Xavier,

thank you for the review.


>
>
> On Tue, Aug 12, 2025 at 4:58 PM Ales Musil via dev <
> ovs-dev@openvswitch.org> 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.
>> ---
>>  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) {
>> +            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;
>> +        }
>>
> nit: should we log (rl) when a invalid vni has been configured ?
>

We actually don't do that for any other config here. It's also a bit tricky
as we would have to change the default.


>      }
>>
>>      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"
>>
> s/dynamic-routing-evpn-fdb-prefer-local/dynamic-routing-fdb-prefer-local/
>

Nice catch, addressed in v4.


> +              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.
>> +        </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;
>> --
>> 2.50.1
>>
>> _______________________________________________
>> dev mailing list
>> d...@openvswitch.org
>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>>
>>
Thanks,
Ales
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to