On 8/19/26 8:39 AM, Ales Musil via dev wrote:
> EVPN-learned MAC bindings (Type-2 routes from FRR via
> the kernel neighbor table) were only installed as local
> OpenFlow flows on the chassis running FRR.  When a VM on
> a different chassis routed traffic through a logical
> router that needed to resolve an EVPN-learned next-hop,
> the MAC binding lookup failed because the flow only
> existed on the FRR chassis.
> 
> Add a new engine node, en_evpn_mac_binding_sync, that
> writes EVPN-learned MAC bindings to the SB MAC_Binding
> table.  Once in SB, every chassis consumes them through
> the existing lflow MAC_Binding pipeline at the same
> priority as regular ARP/ND-learned entries.
> 
> The sync node tracks which (logical_port, ip, mac)
> tuples it has written so it only deletes its own entries
> without interfering with pinctrl-written dynamic
> bindings, and skips SB writes when the MAC has not
> changed.  A companion waker node periodically triggers
> timestamp refreshes on synced entries to prevent northd
> aging from removing entries that are still present in
> the kernel neighbor table but not actively carrying
> traffic.
> 
> The router-side consider_neighbor_flow() call is removed
> from physical_consider_evpn_arp() since those flows now
> come from the SB path.  The switch-side EVPN ARP lookup
> flows (table 113, used for ARP/ND suppression) remain
> local-only.
> 
> Note: the dynamic-routing-arp-prefer-local option no
> longer affects the router MAC_Binding table priority for
> EVPN entries (they are now always at the same priority
> as dynamic entries).  It still controls the EVPN ARP
> lookup side table (table 113) priority.  Removal of the
> option is planned as a follow-up.
> 
> Fixes: 93ae6396e225 ("controller, northd: Add support for learning IP 
> neighbors through EVPN.")
> Reported-at: https://redhat.atlassian.net/browse/FDP-3587
> Reported-at: https://redhat.atlassian.net/browse/FDP-4001
> Assisted-by: Claude Opus 4.6, OpenCode
> Signed-off-by: Ales Musil <[email protected]>
> ---

Hi Ales,

Thanks for the fix!

Overall this looks good to me, please see some minor items inline.

>  NEWS                               |   5 +
>  TODO.rst                           |   3 -
>  controller/automake.mk             |   2 +
>  controller/evpn-mac-binding-sync.c | 243 +++++++++++++++++++++
>  controller/evpn-mac-binding-sync.h |  68 ++++++
>  controller/garp_rarp.c             |   2 +-
>  controller/ovn-controller.c        | 133 +++++++++++-
>  controller/physical.c              |  29 +--
>  controller/physical.h              |   3 +-
>  controller/pinctrl.c               |   2 +-
>  lib/mac-binding-index.c            |  25 ++-
>  lib/mac-binding-index.h            |   5 +-
>  ovn-sb.xml                         |   8 +
>  tests/ovn-inc-proc-graph-dump.at   |   9 +
>  tests/system-ovn.at                | 336 +++++++++++++++++++----------
>  15 files changed, 710 insertions(+), 163 deletions(-)
>  create mode 100644 controller/evpn-mac-binding-sync.c
>  create mode 100644 controller/evpn-mac-binding-sync.h
> 
> diff --git a/NEWS b/NEWS
> index fcee8b8c2..385e35590 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -65,6 +65,11 @@ Post v26.03.0
>         "external_ids:dynamic-routing-port-mapping" for veth-based routing
>         daemon integrations.  This feature is Linux-only and requires
>         OVS version >= 4.0.
> +     * EVPN-learned MAC bindings (Type-2 routes from FRR) are now stored
> +       in the SB MAC_Binding table so they are distributed to all chassis.
> +       Previously these bindings were local-only OpenFlow flows on the
> +       chassis running FRR, causing MAC resolution failures for traffic
> +       originating on other chassis.

Arguably we don't need this NEWS item.  It's a bit of an implementation
detail, I don't think users care that much about it.  I'd remove it.

>     - Added "override-connected" option to Logical Router Static Routes to 
> mark
>       static routes as higher-priority than connected routes, which in turn 
> led
>       to changes in administrative distance for specific route types. Please 
> see
> diff --git a/TODO.rst b/TODO.rst
> index beca38daf..25ac01ee9 100644
> --- a/TODO.rst
> +++ b/TODO.rst
> @@ -156,9 +156,6 @@ OVN To-do List
>      Otherwise we could try to add duplicated Learned_Routes and the ovnsb
>      commit would fail.
>  
> -  * Add support for EVPN L3, that involves MAC Binding learning and
> -    advertisement.
> -
>  * Datapath sync nodes
>  
>    * Migrate data stored in the ovn\_datapath structure to
> diff --git a/controller/automake.mk b/controller/automake.mk
> index a779250cb..bf126d257 100644
> --- a/controller/automake.mk
> +++ b/controller/automake.mk
> @@ -16,6 +16,8 @@ controller_ovn_controller_SOURCES = \
>       controller/evpn-binding.h \
>       controller/evpn-fdb.c \
>       controller/evpn-fdb.h \
> +     controller/evpn-mac-binding-sync.c \
> +     controller/evpn-mac-binding-sync.h \
>       controller/ha-chassis.c \
>       controller/ha-chassis.h \
>       controller/if-status.c \
> diff --git a/controller/evpn-mac-binding-sync.c 
> b/controller/evpn-mac-binding-sync.c
> new file mode 100644
> index 000000000..8d927d2ce
> --- /dev/null
> +++ b/controller/evpn-mac-binding-sync.c
> @@ -0,0 +1,243 @@
> +/* Copyright (c) 2026, Red Hat, Inc.
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at:
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +#include <config.h>
> +
> +#include "openvswitch/poll-loop.h"
> +#include "packets.h"
> +#include "timeval.h"
> +
> +#include "evpn-arp.h"
> +#include "evpn-mac-binding-sync.h"
> +#include "lib/mac-binding-index.h"
> +#include "local_data.h"
> +#include "mac-cache.h"
> +#include "ovn-sb-idl.h"
> +#include "ovn-util.h"
> +#include "vec.h"
> +
> +/* Hash a (logical_port, ip) pair. */
> +static uint32_t
> +evpn_mb_hash(const char *logical_port, const char *ip)
> +{
> +    uint32_t hash = hash_string(logical_port, 0);
> +    return hash_string(ip, hash);
> +}
> +
> +static struct evpn_mb_synced_entry *
> +evpn_mb_synced_find(const struct hmap *synced, const char *logical_port,
> +                    const char *ip)
> +{
> +    uint32_t hash = evpn_mb_hash(logical_port, ip);
> +
> +    struct evpn_mb_synced_entry *entry;
> +    HMAP_FOR_EACH_WITH_HASH (entry, hmap_node, hash, synced) {
> +        if (!strcmp(entry->logical_port, logical_port) &&
> +            !strcmp(entry->ip, ip)) {
> +            return entry;
> +        }
> +    }
> +
> +    return NULL;
> +}
> +
> +static struct evpn_mb_synced_entry *
> +evpn_mb_synced_add(struct hmap *synced, const char *logical_port,
> +                   const char *ip)
> +{
> +    struct evpn_mb_synced_entry *entry = xmalloc(sizeof *entry);
> +    entry->logical_port = xstrdup(logical_port);
> +    entry->ip = xstrdup(ip);

Nit: designated initializers like we do in other cases?

> +    hmap_insert(synced, &entry->hmap_node,
> +                evpn_mb_hash(logical_port, ip));
> +    return entry;
> +}
> +
> +static void
> +evpn_mb_synced_remove(struct hmap *synced, struct evpn_mb_synced_entry 
> *entry)
> +{
> +    hmap_remove(synced, &entry->hmap_node);
> +    free(entry->logical_port);
> +    free(entry->ip);
> +    free(entry);
> +}
> +
> +/* Schedule the waker to fire after 'delay_ms' milliseconds. */
> +static void
> +evpn_mb_sync_waker_schedule(struct evpn_mb_sync_waker *waker,
> +                            int64_t delay_ms)
> +{
> +    if (delay_ms < INT64_MAX) {
> +        waker->should_schedule = true;
> +        waker->next_wake_msec = time_msec() + delay_ms;
> +        poll_timer_wait_until(waker->next_wake_msec);
> +    }
> +}
> +
> +/* Sync a single EVPN ARP entry to the SB MAC_Binding table for one
> + * router port.  Caller must ensure 'ovnsb_idl_txn' is valid.
> + * Returns the remaining time (in ms) until the next timestamp
> + * refresh is needed, or INT64_MAX if none. */
> +static int64_t
> +sync_evpn_mb_for_router_port(
> +    struct ovsdb_idl_txn *ovnsb_idl_txn,
> +    struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
> +    const struct sbrec_mac_binding_table *mb_table,
> +    const struct sbrec_port_binding *router_pb,
> +    const struct evpn_arp *arp,
> +    struct mac_cache_data *mac_cache_data,
> +    struct ed_type_evpn_mac_binding_sync *data,
> +    long long timewall_now)
> +{
> +    char *ip_s = normalize_v46(&arp->ip);
> +    struct evpn_mb_synced_entry *existing =
> +        evpn_mb_synced_find(&data->synced_entries,
> +                            router_pb->logical_port, ip_s);
> +
> +    /* Resolve the cached UUID to a row pointer.  This is a cheap
> +     * single-key hash lookup that avoids the heavier two-column
> +     * index lookup inside mac_binding_add_to_sb(). */

Nit: this comment is a bit of AI slop, I think.  I'd remove it, it's
obvious what's going on below and we know that lookup by UUID is O(1)
amortized.

> +    const struct sbrec_mac_binding *sb_mb = existing
> +        ? sbrec_mac_binding_table_get_for_uuid(mb_table, &existing->mb_uuid)
> +        : NULL;
> +
> +    /* Insert or update the SB MAC_Binding row. */
> +    const struct sbrec_mac_binding *b =
> +        mac_binding_add_to_sb(ovnsb_idl_txn,
> +                              sbrec_mac_binding_by_lport_ip,
> +                              router_pb->logical_port,
> +                              router_pb->datapath,
> +                              arp->mac, ip_s, false,
> +                              sb_mb);
> +
> +    if (!existing) {
> +        existing = evpn_mb_synced_add(&data->synced_entries,
> +                                      router_pb->logical_port, ip_s);
> +    }
> +
> +    free(ip_s);
> +    existing->mb_uuid = b->header_.uuid;
> +    existing->stale = false;
> +
> +    /* Refresh timestamp to prevent aging. */
> +    struct mac_cache_threshold *threshold =
> +        mac_cache_threshold_find(mac_cache_data,
> +                                 router_pb->datapath->tunnel_key);
> +    if (!threshold) {
> +        return INT64_MAX;
> +    }
> +
> +    uint64_t since_updated = timewall_now - b->timestamp;
> +    if (since_updated >= threshold->cooldown_period) {
> +        sbrec_mac_binding_set_timestamp(b, timewall_now);
> +        return threshold->cooldown_period;
> +    }
> +
> +    return threshold->cooldown_period - since_updated;
> +}
> +
> +void
> +evpn_mac_binding_sync_run(
> +    struct ovsdb_idl_txn *ovnsb_idl_txn,
> +    struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
> +    const struct sbrec_mac_binding_table *mb_table,
> +    const struct hmap *local_datapaths,
> +    const struct hmap *evpn_arps,
> +    struct mac_cache_data *mac_cache_data,
> +    struct ed_type_evpn_mac_binding_sync *data,
> +    struct evpn_mb_sync_waker *waker)
> +{
> +    if (!ovnsb_idl_txn) {
> +        data->sb_changes_pending = true;

Isn't this a bit too conservative?  We might not have any pending
changes, right?  Should we delay setting data->sb_changes_pending until
we actually need to update the SB somewhere later in this function?

> +        return;
> +    }
> +
> +    long long timewall_now = time_wall_msec();
> +    int64_t min_next_refresh_ms = INT64_MAX;
> +
> +    /* Mark all synced entries as stale.  SB row pointers are resolved
> +     * lazily by UUID only where needed (insert/update, timestamp
> +     * refresh, delete), avoiding a per-entry index lookup here. */
> +    struct evpn_mb_synced_entry *synced_entry;
> +    HMAP_FOR_EACH (synced_entry, hmap_node, &data->synced_entries) {
> +        synced_entry->stale = true;
> +    }
> +
> +    /* Walk current EVPN ARPs and sync to SB. */
> +    const struct evpn_arp *arp;
> +    HMAP_FOR_EACH (arp, hmap_node, evpn_arps) {
> +        const struct peer_ports *peers;
> +        VECTOR_FOR_EACH_PTR (&arp->ldp->peer_ports, peers) {
> +            const struct sbrec_port_binding *remote_pb = peers->remote;
> +            struct local_datapath *peer_ld =
> +                get_local_datapath(local_datapaths,
> +                                   remote_pb->datapath->tunnel_key);
> +            if (!peer_ld || peer_ld->is_switch) {
> +                continue;
> +            }
> +
> +            int64_t remaining =
> +                sync_evpn_mb_for_router_port(ovnsb_idl_txn,
> +                                             sbrec_mac_binding_by_lport_ip,
> +                                             mb_table,
> +                                             remote_pb, arp,
> +                                             mac_cache_data, data,
> +                                             timewall_now);
> +            if (remaining < min_next_refresh_ms) {
> +                min_next_refresh_ms = remaining;
> +            }
> +        }
> +    }
> +
> +    /* Delete stale entries from SB. */
> +    HMAP_FOR_EACH_SAFE (synced_entry, hmap_node, &data->synced_entries) {
> +        if (!synced_entry->stale) {
> +            continue;
> +        }
> +
> +        const struct sbrec_mac_binding *sb_mb =
> +            sbrec_mac_binding_table_get_for_uuid(
> +                mb_table, &synced_entry->mb_uuid);
> +        if (sb_mb) {
> +            sbrec_mac_binding_delete(sb_mb);
> +        }
> +
> +        evpn_mb_synced_remove(&data->synced_entries, synced_entry);
> +    }
> +
> +    /* Schedule the waker for the next timestamp refresh. */
> +    if (min_next_refresh_ms < INT64_MAX) {
> +        evpn_mb_sync_waker_schedule(waker, min_next_refresh_ms);
> +    }
> +}
> +
> +void
> +evpn_mac_binding_sync_init(struct ed_type_evpn_mac_binding_sync *data)
> +{
> +    hmap_init(&data->synced_entries);
> +    data->sb_changes_pending = false;
> +}
> +
> +void
> +evpn_mac_binding_sync_cleanup(struct ed_type_evpn_mac_binding_sync *data)
> +{
> +    struct evpn_mb_synced_entry *entry;
> +    HMAP_FOR_EACH_POP (entry, hmap_node, &data->synced_entries) {
> +        free(entry->logical_port);
> +        free(entry->ip);
> +        free(entry);
> +    }
> +    hmap_destroy(&data->synced_entries);
> +}
> diff --git a/controller/evpn-mac-binding-sync.h 
> b/controller/evpn-mac-binding-sync.h
> new file mode 100644
> index 000000000..dc1e63a6a
> --- /dev/null
> +++ b/controller/evpn-mac-binding-sync.h
> @@ -0,0 +1,68 @@
> +/* Copyright (c) 2026, Red Hat, Inc.
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at:
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +#ifndef EVPN_MAC_BINDING_SYNC_H
> +#define EVPN_MAC_BINDING_SYNC_H 1
> +
> +#include "openvswitch/hmap.h"
> +#include "openvswitch/uuid.h"
> +
> +struct mac_cache_data;
> +struct ovsdb_idl_index;
> +struct ovsdb_idl_txn;
> +struct sbrec_mac_binding_table;
> +
> +/* Tracks a MAC_Binding row that was written to SB by the EVPN sync. */
> +struct evpn_mb_synced_entry {
> +    struct hmap_node hmap_node;
> +    char *logical_port;                  /* Router port name. */
> +    char *ip;                            /* Normalized IP string. */
> +    struct uuid mb_uuid;                 /* UUID of the SB MAC_Binding row.
> +                                          * All-zeros when not yet synced. */
> +    bool stale;                          /* Marked true at start of sync,
> +                                          * cleared when still desired. */
> +};
> +
> +/* Persistent state for the en_evpn_mac_binding_sync engine node. */
> +struct ed_type_evpn_mac_binding_sync {
> +    /* Contains 'struct evpn_mb_synced_entry'.  Tracks which
> +     * (logical_port, ip) pairs we have written to SB. */
> +    struct hmap synced_entries;
> +
> +    /* True when an SB write was skipped because ovnsb_idl_txn was NULL. */
> +    bool sb_changes_pending;
> +};
> +
> +/* Timer that periodically wakes the sync node so it can refresh
> + * timestamps on SB MAC_Binding rows it owns. */
> +struct evpn_mb_sync_waker {
> +    bool should_schedule;         /* Whether a wake is pending. */
> +    long long next_wake_msec;     /* Absolute time of next wake. */
> +};
> +
> +void evpn_mac_binding_sync_run(
> +    struct ovsdb_idl_txn *ovnsb_idl_txn,
> +    struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
> +    const struct sbrec_mac_binding_table *mb_table,
> +    const struct hmap *local_datapaths,
> +    const struct hmap *evpn_arps,
> +    struct mac_cache_data *mac_cache_data,
> +    struct ed_type_evpn_mac_binding_sync *data,
> +    struct evpn_mb_sync_waker *waker);
> +
> +void evpn_mac_binding_sync_init(struct ed_type_evpn_mac_binding_sync *);
> +void evpn_mac_binding_sync_cleanup(struct ed_type_evpn_mac_binding_sync *);
> +
> +#endif /* EVPN_MAC_BINDING_SYNC_H */
> diff --git a/controller/garp_rarp.c b/controller/garp_rarp.c
> index 1cf415a9f..9de8345c7 100644
> --- a/controller/garp_rarp.c
> +++ b/controller/garp_rarp.c
> @@ -365,7 +365,7 @@ send_garp_locally(const struct garp_rarp_ctx_in *r_ctx_in,
>          mac_binding_add_to_sb(r_ctx_in->ovnsb_idl_txn,
>                                r_ctx_in->sbrec_mac_binding_by_lport_ip,
>                                remote->logical_port, remote->datapath,
> -                              ea, ds_cstr(&ip_s), update_only);
> +                              ea, ds_cstr(&ip_s), update_only, NULL);
>          ds_destroy(&ip_s);
>      }
>  }
> diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
> index 6551a4e30..c57695ec1 100644
> --- a/controller/ovn-controller.c
> +++ b/controller/ovn-controller.c
> @@ -104,6 +104,7 @@
>  #include "evpn-arp.h"
>  #include "evpn-binding.h"
>  #include "evpn-fdb.h"
> +#include "evpn-mac-binding-sync.h"
>  
>  VLOG_DEFINE_THIS_MODULE(main);
>  
> @@ -5157,13 +5158,10 @@ static enum engine_input_handler_result
>  pflow_output_arp_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_evpn_arp *ea_data =
>          engine_get_input_data("evpn_arp", node);
>  
> -    physical_handle_evpn_arp_changes(&rt_data->local_datapaths,
> -                                     &pfo->flow_table,
> +    physical_handle_evpn_arp_changes(&pfo->flow_table,
>                                       &ea_data->updated_arps,
>                                       &ea_data->removed_arps);
>      return EN_HANDLED_UPDATED;
> @@ -5238,6 +5236,14 @@ controller_output_garp_rarp_handler(struct engine_node 
> *node OVS_UNUSED,
>      return EN_HANDLED_UPDATED;
>  }
>  
> +static enum engine_input_handler_result
> +controller_output_evpn_mac_binding_sync_handler(
> +    struct engine_node *node OVS_UNUSED,
> +    void *data OVS_UNUSED)
> +{
> +    return EN_HANDLED_UPDATED;
> +}
> +
>  static enum engine_input_handler_result
>  controller_output_datapaths_updated_handler(
>      struct engine_node *node OVS_UNUSED,
> @@ -7189,6 +7195,106 @@ evpn_arp_vtep_binding_handler(struct engine_node 
> *node, void *data OVS_UNUSED)
>      return EN_UNHANDLED;
>  }
>  
> +/* EVPN MAC binding sync waker: a timer-based input node that
> + * periodically fires EN_UPDATED to trigger the sync node so it
> + * can refresh timestamps on SB MAC_Binding rows. */
> +static void *
> +en_evpn_mac_binding_sync_waker_init(struct engine_node *node OVS_UNUSED,
> +                                    struct engine_arg *arg OVS_UNUSED)
> +{
> +    struct evpn_mb_sync_waker *waker = xzalloc(sizeof *waker);
> +    return waker;
> +}
> +
> +static enum engine_node_state
> +en_evpn_mac_binding_sync_waker_run(struct engine_node *node OVS_UNUSED,
> +                                   void *data)
> +{
> +    struct evpn_mb_sync_waker *waker = data;
> +
> +    if (!waker->should_schedule) {
> +        return EN_UNCHANGED;
> +    }
> +
> +    if (time_msec() >= waker->next_wake_msec) {
> +        waker->should_schedule = false;
> +        return EN_UPDATED;
> +    }
> +
> +    poll_timer_wait_until(waker->next_wake_msec);
> +    return EN_UNCHANGED;
> +}
> +
> +static void
> +en_evpn_mac_binding_sync_waker_cleanup(void *data OVS_UNUSED)
> +{
> +}
> +
> +/* EVPN MAC binding sync node: syncs EVPN-learned MAC bindings
> + * to the SB MAC_Binding table so they are distributed to all
> + * chassis. */
> +static void *
> +en_evpn_mac_binding_sync_init(struct engine_node *node OVS_UNUSED,
> +                              struct engine_arg *arg OVS_UNUSED)
> +{
> +    struct ed_type_evpn_mac_binding_sync *data = xmalloc(sizeof *data);
> +    evpn_mac_binding_sync_init(data);
> +    return data;
> +}
> +
> +static enum engine_node_state
> +en_evpn_mac_binding_sync_run(struct engine_node *node, void *data_)
> +{
> +    struct ed_type_evpn_mac_binding_sync *data = data_;
> +
> +    struct ed_type_evpn_arp *earp_data =
> +        engine_get_input_data("evpn_arp", node);
> +    struct ed_type_runtime_data *rt_data =
> +        engine_get_input_data("runtime_data", node);
> +    struct mac_cache_data *mac_cache_data =
> +        engine_get_input_data("mac_cache", node);
> +    struct engine_node *sb_mb_node =
> +        engine_get_input("SB_mac_binding", node);
> +    struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip =
> +        engine_ovsdb_node_get_index(sb_mb_node, "lport_ip");
> +    const struct sbrec_mac_binding_table *mb_table =
> +        EN_OVSDB_GET(sb_mb_node);
> +
> +    struct evpn_mb_sync_waker *waker =
> +        engine_get_input_data("evpn_mac_binding_sync_waker", node);
> +
> +    data->sb_changes_pending = false;
> +
> +    evpn_mac_binding_sync_run(engine_get_context()->ovnsb_idl_txn,
> +                              sbrec_mac_binding_by_lport_ip,
> +                              mb_table,
> +                              &rt_data->local_datapaths,
> +                              &earp_data->arps,
> +                              mac_cache_data,
> +                              data, waker);
> +
> +    return EN_UPDATED;
> +}
> +
> +static void
> +en_evpn_mac_binding_sync_cleanup(void *data_)
> +{
> +    struct ed_type_evpn_mac_binding_sync *data = data_;
> +    evpn_mac_binding_sync_cleanup(data);
> +}
> +
> +static enum engine_input_handler_result
> +evpn_mac_binding_sync_sb_ro_handler(struct engine_node *node OVS_UNUSED,
> +                                    void *data_)
> +{
> +    struct ed_type_evpn_mac_binding_sync *data = data_;
> +    if (data->sb_changes_pending) {
> +        return EN_UNHANDLED;
> +    }
> +
> +    return EN_HANDLED_UNCHANGED;
> +}
> +
>  /* Define engine node functions for nodes that represent SB tables.
>   *
>   * en_sb_<TABLE_NAME>_run()
> @@ -7314,6 +7420,8 @@ static ENGINE_NODE(nexthop_exchange);
>  static ENGINE_NODE(evpn_vtep_binding, CLEAR_TRACKED_DATA);
>  static ENGINE_NODE(evpn_fdb, CLEAR_TRACKED_DATA);
>  static ENGINE_NODE(evpn_arp, CLEAR_TRACKED_DATA);
> +static ENGINE_NODE(evpn_mac_binding_sync_waker);
> +static ENGINE_NODE(evpn_mac_binding_sync, SB_WRITE);
>  static ENGINE_NODE(datapaths_updated);
>  static ENGINE_NODE(sb_cond_seqno);
>  
> @@ -7603,6 +7711,21 @@ inc_proc_ovn_controller_init(
>      engine_add_input(&en_evpn_arp, &en_evpn_vtep_binding,
>                       evpn_arp_vtep_binding_handler);
>  
> +    engine_add_input(&en_evpn_mac_binding_sync,
> +                     &en_evpn_mac_binding_sync_waker, NULL);
> +    engine_add_input(&en_evpn_mac_binding_sync, &en_evpn_arp, NULL);
> +    /* MAC_Binding data is only used via an index for lookups. */
> +    engine_add_input(&en_evpn_mac_binding_sync, &en_sb_mac_binding,
> +                     engine_noop_handler);
> +    /* Runtime data is only used for local_datapaths access. */
> +    engine_add_input(&en_evpn_mac_binding_sync, &en_runtime_data,
> +                     engine_noop_handler);
> +    /* MAC cache data is only used for aging threshold lookup. */
> +    engine_add_input(&en_evpn_mac_binding_sync, &en_mac_cache,
> +                     engine_noop_handler);
> +    engine_add_input(&en_evpn_mac_binding_sync, &en_sb_ro,
> +                     evpn_mac_binding_sync_sb_ro_handler);
> +
>      engine_add_input(&en_pflow_output, &en_evpn_vtep_binding,
>                       pflow_output_evpn_binding_handler);
>      engine_add_input(&en_pflow_output, &en_evpn_fdb,
> @@ -7624,6 +7747,8 @@ inc_proc_ovn_controller_init(
>                       controller_output_route_exchange_handler);
>      engine_add_input(&en_controller_output, &en_garp_rarp,
>                       controller_output_garp_rarp_handler);
> +    engine_add_input(&en_controller_output, &en_evpn_mac_binding_sync,
> +                     controller_output_evpn_mac_binding_sync_handler);
>  
>      engine_add_input(&en_acl_id, &en_sb_acl_id, NULL);
>      engine_add_input(&en_controller_output, &en_acl_id,
> diff --git a/controller/physical.c b/controller/physical.c
> index 452256e7a..8a70f913c 100644
> --- a/controller/physical.c
> +++ b/controller/physical.c
> @@ -58,7 +58,6 @@
>  #include "vec.h"
>  #include "vswitch-idl.h"
>  #include "hmapx.h"
> -#include "neighbor-of.h"
>  
>  VLOG_DEFINE_THIS_MODULE(physical);
>  
> @@ -3706,28 +3705,11 @@ physical_consider_evpn_fdb(const struct evpn_fdb *fdb,
>  }
>  
>  static void
> -physical_consider_evpn_arp(const struct hmap *local_datapaths,
> -                           const struct evpn_arp *arp,
> +physical_consider_evpn_arp(const struct evpn_arp *arp,
>                             struct ofpbuf *ofpacts,
>                             struct match *match,
>                             struct ovn_desired_flow_table *flow_table)
>  {
> -    /* Walk connected OVN routers and install neighbor flows for the ARPs
> -     * learned on EVPN datapaths.*/
> -    const struct peer_ports *peers;
> -    VECTOR_FOR_EACH_PTR (&arp->ldp->peer_ports, peers) {
> -        const struct sbrec_port_binding *remote_pb = peers->remote;
> -        struct local_datapath *peer_ld =
> -            get_local_datapath(local_datapaths,
> -                               remote_pb->datapath->tunnel_key);
> -        if (!peer_ld || peer_ld->is_switch) {
> -            continue;
> -        }
> -
> -        consider_neighbor_flow(remote_pb, &arp->flow_uuid, &arp->ip, 
> arp->mac,
> -                               flow_table, arp->priority, false);
> -    }
> -
>      /* Install EVPN ARP lookup flows in the dedicated side table for the
>       * switch datapath.  These flows are matched by the chk_evpn_arp()
>       * action.  On a hit they load the resolved MAC into eth.dst
> @@ -3806,8 +3788,7 @@ physical_eval_evpn_flows(const struct physical_ctx *ctx,
>  
>      const struct evpn_arp *arp;
>      HMAP_FOR_EACH (arp, hmap_node, ctx->evpn_arps) {
> -        physical_consider_evpn_arp(ctx->local_datapaths, arp, ofpacts,
> -                                   &match, flow_table);
> +        physical_consider_evpn_arp(arp, ofpacts, &match, flow_table);
>      }
>  }
>  
> @@ -4016,8 +3997,7 @@ physical_handle_evpn_fdb_changes(struct 
> ovn_desired_flow_table *flow_table,
>  }
>  
>  void
> -physical_handle_evpn_arp_changes(const struct hmap *local_datapaths,
> -                                 struct ovn_desired_flow_table *flow_table,
> +physical_handle_evpn_arp_changes(struct ovn_desired_flow_table *flow_table,
>                                   const struct hmapx *updated_arps,
>                                   const struct uuidset *removed_arps)
>  {
> @@ -4030,8 +4010,7 @@ physical_handle_evpn_arp_changes(const struct hmap 
> *local_datapaths,
>          const struct evpn_arp *arp = node->data;
>  
>          ofctrl_remove_flows(flow_table, &arp->flow_uuid);
> -        physical_consider_evpn_arp(local_datapaths, arp, &ofpacts,
> -                                   &match, flow_table);
> +        physical_consider_evpn_arp(arp, &ofpacts, &match, flow_table);
>      }
>      ofpbuf_uninit(&ofpacts);
>  
> diff --git a/controller/physical.h b/controller/physical.h
> index b02caea88..8218096d5 100644
> --- a/controller/physical.h
> +++ b/controller/physical.h
> @@ -106,8 +106,7 @@ void physical_handle_evpn_fdb_changes(struct 
> ovn_desired_flow_table *,
>                                        struct ovn_extend_table *group_table,
>                                        const struct hmapx *updated_fdbs,
>                                        const struct uuidset *removed_fdbs);
> -void physical_handle_evpn_arp_changes(const struct hmap *local_datapaths,
> -                                      struct ovn_desired_flow_table *,
> +void physical_handle_evpn_arp_changes(struct ovn_desired_flow_table *,
>                                        const struct hmapx *updated_arps,
>                                        const struct uuidset *removed_arps);
>  #endif /* controller/physical.h */
> diff --git a/controller/pinctrl.c b/controller/pinctrl.c
> index 216831e6e..333dcedb6 100644
> --- a/controller/pinctrl.c
> +++ b/controller/pinctrl.c
> @@ -4918,7 +4918,7 @@ run_put_mac_binding(struct ovsdb_idl_txn *ovnsb_idl_txn,
>      ipv6_format_mapped(&mb->data.ip, &ip_s);
>      mac_binding_add_to_sb(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip,
>                            pb->logical_port, pb->datapath, mb->data.mac,
> -                          ds_cstr(&ip_s), false);
> +                          ds_cstr(&ip_s), false, NULL);
>      ds_destroy(&ip_s);
>  }
>  
> diff --git a/lib/mac-binding-index.c b/lib/mac-binding-index.c
> index ad6be0a4e..3e49b07f3 100644
> --- a/lib/mac-binding-index.c
> +++ b/lib/mac-binding-index.c
> @@ -52,27 +52,34 @@ mac_binding_lookup(struct ovsdb_idl_index 
> *sbrec_mac_binding_by_lport_ip,
>  }
>  
>  /* Update or add an IP-MAC binding for 'logical_port'.
> - * Caller should make sure that 'ovnsb_idl_txn' is valid. */
> -void
> + * Caller should make sure that 'ovnsb_idl_txn' is valid.
> + * Returns the SB row that was inserted or updated, or NULL
> + * if 'update_only' is true and no existing row was found. */
> +const struct sbrec_mac_binding *
>  mac_binding_add_to_sb(struct ovsdb_idl_txn *ovnsb_idl_txn,
>                        struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
>                        const char *logical_port,
>                        const struct sbrec_datapath_binding *dp,
>                        struct eth_addr ea, const char *ip,
> -                      bool update_only)
> +                      bool update_only,
> +                      const struct sbrec_mac_binding *sb_mb)
>  {
>      /* Convert ethernet argument to string form for database. */
>      char mac_string[ETH_ADDR_STRLEN + 1];
>      snprintf(mac_string, sizeof mac_string, ETH_ADDR_FMT, ETH_ADDR_ARGS(ea));
>  
> -    const struct sbrec_mac_binding *b =
> -            mac_binding_lookup(sbrec_mac_binding_by_lport_ip,
> -                               logical_port, ip);
> +    const struct sbrec_mac_binding *b = sb_mb
> +            ? sb_mb
> +            : mac_binding_lookup(sbrec_mac_binding_by_lport_ip,
> +                                 logical_port, ip);
>      if (!b) {
>          if (update_only) {
> -            return;
> +            return NULL;
>          }
> -        b = sbrec_mac_binding_insert(ovnsb_idl_txn);
> +
> +        /* Make sure the uuid persists between txn inserts. */
> +        struct uuid uuid = uuid_random();
> +        b = sbrec_mac_binding_insert_persist_uuid(ovnsb_idl_txn, &uuid);
>          sbrec_mac_binding_set_logical_port(b, logical_port);
>          sbrec_mac_binding_set_ip(b, ip);
>          sbrec_mac_binding_set_datapath(b, dp);
> @@ -91,4 +98,6 @@ mac_binding_add_to_sb(struct ovsdb_idl_txn *ovnsb_idl_txn,
>              sbrec_mac_binding_set_timestamp(b, time_wall_msec());
>          }
>      }
> +
> +    return b;
>  }
> diff --git a/lib/mac-binding-index.h b/lib/mac-binding-index.h
> index 3bcb29359..8832eda16 100644
> --- a/lib/mac-binding-index.h
> +++ b/lib/mac-binding-index.h
> @@ -27,10 +27,11 @@ const struct sbrec_mac_binding *
>  mac_binding_lookup(struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
>                     const char *logical_port, const char *ip);
>  
> -void mac_binding_add_to_sb(
> +const struct sbrec_mac_binding *mac_binding_add_to_sb(
>      struct ovsdb_idl_txn *,
>      struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
>      const char *logical_port, const struct sbrec_datapath_binding *,
> -    struct eth_addr, const char *ip, bool update_only);
> +    struct eth_addr, const char *ip, bool update_only,
> +    const struct sbrec_mac_binding *sb_mb);
>  
>  #endif /* lib/mac-binding-index.h */
> diff --git a/ovn-sb.xml b/ovn-sb.xml
> index d5c5210dc..a147f2675 100644
> --- a/ovn-sb.xml
> +++ b/ovn-sb.xml
> @@ -4185,6 +4185,14 @@ tcp.flags = RST;
>        </li>
>      </ol>
>  
> +    <p>
> +      In EVPN deployments, <code>ovn-controller</code> also writes rows to
> +      this table for MAC bindings learned through EVPN Type-2 routes (via
> +      FRR and the kernel neighbor table).  These entries are keyed by the
> +      router port connected to the EVPN logical switch and behave identically
> +      to ARP/ND-learned bindings for consumption and aging purposes.
> +    </p>
> +
>      <column name="logical_port">
>        The logical port on which the binding was discovered.
>      </column>
> diff --git a/tests/ovn-inc-proc-graph-dump.at 
> b/tests/ovn-inc-proc-graph-dump.at
> index ea70293ce..a56fa8bd8 100644
> --- a/tests/ovn-inc-proc-graph-dump.at
> +++ b/tests/ovn-inc-proc-graph-dump.at
> @@ -483,6 +483,14 @@ digraph "Incremental-Processing-Engine" {
>       SB_datapath_binding -> garp_rarp 
> [[label="garp_rarp_sb_datapath_binding_handler"]];
>       SB_mac_binding -> garp_rarp [[label="engine_noop_handler"]];
>       runtime_data -> garp_rarp [[label="garp_rarp_runtime_data_handler"]];
> +     evpn_mac_binding_sync_waker [[style=filled, shape=box, fillcolor=white, 
> label="evpn_mac_binding_sync_waker"]];
> +     evpn_mac_binding_sync [[style=filled, shape=box, fillcolor=white, 
> label="evpn_mac_binding_sync"]];
> +     evpn_mac_binding_sync_waker -> evpn_mac_binding_sync [[label=""]];
> +     evpn_arp -> evpn_mac_binding_sync [[label=""]];
> +     SB_mac_binding -> evpn_mac_binding_sync [[label="engine_noop_handler"]];
> +     runtime_data -> evpn_mac_binding_sync [[label="engine_noop_handler"]];
> +     mac_cache -> evpn_mac_binding_sync [[label="engine_noop_handler"]];
> +     sb_ro -> evpn_mac_binding_sync 
> [[label="evpn_mac_binding_sync_sb_ro_handler"]];
>       SB_acl_id [[style=filled, shape=box, fillcolor=white, 
> label="SB_acl_id"]];
>       acl_id [[style=filled, shape=box, fillcolor=white, label="acl_id"]];
>       SB_acl_id -> acl_id [[label=""]];
> @@ -498,6 +506,7 @@ digraph "Incremental-Processing-Engine" {
>       bfd_chassis -> controller_output 
> [[label="controller_output_bfd_chassis_handler"]];
>       route_exchange -> controller_output 
> [[label="controller_output_route_exchange_handler"]];
>       garp_rarp -> controller_output 
> [[label="controller_output_garp_rarp_handler"]];
> +     evpn_mac_binding_sync -> controller_output 
> [[label="controller_output_evpn_mac_binding_sync_handler"]];
>       acl_id -> controller_output 
> [[label="controller_output_acl_id_handler"]];
>       datapaths_updated -> controller_output 
> [[label="controller_output_datapaths_updated_handler"]];
>  }
> diff --git a/tests/system-ovn.at b/tests/system-ovn.at
> index d4f2ce69e..9fc27f976 100644
> --- a/tests/system-ovn.at
> +++ b/tests/system-ovn.at
> @@ -18505,9 +18505,9 @@ rtr_dp_key=$(fetch_column Datapath tunnel_key 
> external_ids:name=lr)
>  rtr_port_key=$(fetch_column Port_Binding tunnel_key logical_port=lr-ls-evpn)
>  
>  # Simulate remote workload ARPs (type-2 MAC+IP EVPN route).
> -# ovn-controller needs to add OF rules for ARP lookup but no rules for
> -# MAC_CACHE use.  These entries do not age out automatically, their lifetime
> -# is controlled by the BGP-EVPN control plane.
> +# EVPN-learned MAC bindings are written to the SB MAC_Binding table and
> +# distributed to all chassis.  These entries do not age out automatically,
> +# their lifetime is controlled by the BGP-EVPN control plane.
>  check ip neigh add dev $BR_NAME 172.16.1.50 lladdr f0:00:0f:16:10:50 nud 
> noarp extern_learn
>  check ip neigh add dev $BR_NAME 172.16.1.60 lladdr f0:00:0f:16:10:60 nud 
> noarp extern_learn
>  check ip neigh add dev $BR_NAME 172.16.1.70 lladdr f0:00:0f:16:10:70 nud 
> noarp extern_learn
> @@ -18525,35 +18525,52 @@ OVS_WAIT_FOR_OUTPUT_UNQUOTED([ovn-appctl 
> evpn/vtep-arp-list | cut -d',' -f2- | s
>   VNI: 10, MAC: f0:00:0f:16:10:70, IP: 172:16::70, dp_key: $dp_key
>  ])
>  
> +dnl Verify EVPN-learned MAC bindings appear in the SB MAC_Binding table.
> +wait_row_count MAC_Binding 1 ip=172.16.1.50
> +wait_row_count MAC_Binding 1 ip=172.16.1.60
> +wait_row_count MAC_Binding 1 ip=172.16.1.70
> +wait_row_count MAC_Binding 1 ip="172\:16\:\:50"
> +wait_row_count MAC_Binding 1 ip="172\:16\:\:60"
> +wait_row_count MAC_Binding 1 ip="172\:16\:\:70"
> +
>  AS_BOX([Check dynamic-routing-arp-prefer-local=true])
>  check ovn-nbctl --wait=hv set Logical_Switch ls-evpn 
> other_config:dynamic-routing-arp-prefer-local=true
>  
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_BINDING | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  priority=100,reg0=0xac10010a,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:01:10,load:0x1->NXM_NX_REG10[[6]]
> -priority=20,reg0=0xac100132,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> -priority=20,reg0=0xac10013c,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> -priority=20,reg0=0xac100146,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> -priority=20,reg4=0x1720016,reg5=0,reg6=0,reg7=0x50,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> -priority=20,reg4=0x1720016,reg5=0,reg6=0,reg7=0x60,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> -priority=20,reg4=0x1720016,reg5=0,reg6=0,reg7=0x70,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac100132,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac10013c,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac100146,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x50,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x60,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x70,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
>  ])
>  
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_LOOKUP | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  
> priority=100,arp,reg0=0xac10010a,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=20,arp,reg0=0xac100132,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=20,arp,reg0=0xac10013c,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=20,arp,reg0=0xac100146,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=20,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x50,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=20,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x60,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=20,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x70,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac100132,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac10013c,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac100146,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x50,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x60,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x70,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
>  ])
>  
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  
> priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10,arp_spa=172.16.1.10,arp_op=2
>  actions=drop
> +priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,arp_spa=172.16.1.50,arp_op=2
>  actions=drop
> +priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,arp_spa=172.16.1.60,arp_op=2
>  actions=drop
> +priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,arp_spa=172.16.1.70,arp_op=2
>  actions=drop
>  
> priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10,nw_src=172.16.1.10
>  actions=drop
> +priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,nw_src=172.16.1.50
>  actions=drop
> +priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,nw_src=172.16.1.60
>  actions=drop
> +priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,nw_src=172.16.1.70
>  actions=drop
> +priority=100,ipv6,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,ipv6_src=172:16::50
>  actions=drop
> +priority=100,ipv6,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,ipv6_src=172:16::60
>  actions=drop
> +priority=100,ipv6,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,ipv6_src=172:16::70
>  actions=drop
>  ])
>  
>  AS_BOX([Check dynamic-routing-arp-prefer-local=false])
> @@ -18562,29 +18579,38 @@ check ovn-nbctl --wait=hv set Logical_Switch 
> ls-evpn other_config:dynamic-routin
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_BINDING | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  priority=100,reg0=0xac10010a,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:01:10,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg0=0xac100132,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg0=0xac10013c,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg0=0xac100146,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x50,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x60,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x70,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac100132,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac10013c,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac100146,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x50,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x60,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x70,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
>  ])
>  
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_LOOKUP | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  
> priority=100,arp,reg0=0xac10010a,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,arp,reg0=0xac100132,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,arp,reg0=0xac10013c,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,arp,reg0=0xac100146,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x50,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x60,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x70,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac100132,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac10013c,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac100146,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x50,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x60,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x70,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
>  ])
>  
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  
> priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10,arp_spa=172.16.1.10,arp_op=2
>  actions=drop
> +priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,arp_spa=172.16.1.50,arp_op=2
>  actions=drop
> +priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,arp_spa=172.16.1.60,arp_op=2
>  actions=drop
> +priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,arp_spa=172.16.1.70,arp_op=2
>  actions=drop
>  
> priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10,nw_src=172.16.1.10
>  actions=drop
> +priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,nw_src=172.16.1.50
>  actions=drop
> +priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,nw_src=172.16.1.60
>  actions=drop
> +priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,nw_src=172.16.1.70
>  actions=drop
> +priority=100,ipv6,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,ipv6_src=172:16::50
>  actions=drop
> +priority=100,ipv6,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,ipv6_src=172:16::60
>  actions=drop
> +priority=100,ipv6,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,ipv6_src=172:16::70
>  actions=drop
>  ])
>  
>  # Check that the recompute won't change the UUIDs and flows.
> @@ -18651,6 +18677,14 @@ check ip -6 neigh del dev $BR_NAME 172:16::70
>  OVS_WAIT_UNTIL([test "$(ovs-ofctl dump-flows br-int 
> table=OFTABLE_EVPN_ARP_LOOKUP | \
>                           grep -c priority)" = "0"])
>  
> +dnl Verify EVPN MAC_Binding rows are deleted from SB.
> +wait_row_count MAC_Binding 0 ip=172.16.1.50
> +wait_row_count MAC_Binding 0 ip=172.16.1.60
> +wait_row_count MAC_Binding 0 ip=172.16.1.70
> +wait_row_count MAC_Binding 0 ip="172\:16\:\:50"
> +wait_row_count MAC_Binding 0 ip="172\:16\:\:60"
> +wait_row_count MAC_Binding 0 ip="172\:16\:\:70"
> +
>  dnl Re-add the EVPN entries for subsequent tests.
>  check ip neigh add dev $BR_NAME 172.16.1.50 lladdr f0:00:0f:16:10:50 nud 
> noarp extern_learn
>  check ip neigh add dev $BR_NAME 172.16.1.60 lladdr f0:00:0f:16:10:60 nud 
> noarp extern_learn
> @@ -18790,23 +18824,23 @@ OVS_WAIT_FOR_OUTPUT_UNQUOTED([ovn-appctl 
> evpn/vtep-arp-list | cut -d',' -f2- | s
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_BINDING | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  priority=100,reg0=0xac10010a,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:01:10,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg0=0xac100132,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg0=0xac10013c,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg0=0xac100146,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x50,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x60,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x70,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac100132,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac10013c,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac100146,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x50,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x60,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x70,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
>  ])
>  
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_LOOKUP | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  
> priority=100,arp,reg0=0xac10010a,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,arp,reg0=0xac100132,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,arp,reg0=0xac10013c,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,arp,reg0=0xac100146,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x50,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x60,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x70,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac100132,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac10013c,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac100146,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x50,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x60,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x70,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
>  ])
>  
>  check ovn-nbctl --wait=hv lr-del lr
> @@ -19191,9 +19225,9 @@ rtr_dp_key=$(fetch_column Datapath tunnel_key 
> external_ids:name=lr)
>  rtr_port_key=$(fetch_column Port_Binding tunnel_key logical_port=lr-ls-evpn)
>  
>  # Simulate remote workload ARPs (type-2 MAC+IP EVPN route).
> -# ovn-controller needs to add OF rules for ARP lookup but no rules for
> -# MAC_CACHE use.  These entries do not age out automatically, their lifetime
> -# is controlled by the BGP-EVPN control plane.
> +# EVPN-learned MAC bindings are written to the SB MAC_Binding table and
> +# distributed to all chassis.  These entries do not age out automatically,
> +# their lifetime is controlled by the BGP-EVPN control plane.
>  check ip neigh add dev $BR_NAME 172.16.1.50 lladdr f0:00:0f:16:10:50 nud 
> noarp extern_learn
>  check ip neigh add dev $BR_NAME 172.16.1.60 lladdr f0:00:0f:16:10:60 nud 
> noarp extern_learn
>  check ip neigh add dev $BR_NAME 172.16.1.70 lladdr f0:00:0f:16:10:70 nud 
> noarp extern_learn
> @@ -19211,35 +19245,52 @@ OVS_WAIT_FOR_OUTPUT_UNQUOTED([ovn-appctl 
> evpn/vtep-arp-list | cut -d',' -f2- | s
>   VNI: 10, MAC: f0:00:0f:16:10:70, IP: 172:16::70, dp_key: $dp_key
>  ])
>  
> +dnl Verify EVPN-learned MAC bindings appear in the SB MAC_Binding table.
> +wait_row_count MAC_Binding 1 ip=172.16.1.50
> +wait_row_count MAC_Binding 1 ip=172.16.1.60
> +wait_row_count MAC_Binding 1 ip=172.16.1.70
> +wait_row_count MAC_Binding 1 ip="172\:16\:\:50"
> +wait_row_count MAC_Binding 1 ip="172\:16\:\:60"
> +wait_row_count MAC_Binding 1 ip="172\:16\:\:70"
> +
>  AS_BOX([Check dynamic-routing-arp-prefer-local=true])
>  check ovn-nbctl --wait=hv set Logical_Switch ls-evpn 
> other_config:dynamic-routing-arp-prefer-local=true
>  
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_BINDING | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  priority=100,reg0=0xac10010a,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:01:10,load:0x1->NXM_NX_REG10[[6]]
> -priority=20,reg0=0xac100132,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> -priority=20,reg0=0xac10013c,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> -priority=20,reg0=0xac100146,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> -priority=20,reg4=0x1720016,reg5=0,reg6=0,reg7=0x50,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> -priority=20,reg4=0x1720016,reg5=0,reg6=0,reg7=0x60,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> -priority=20,reg4=0x1720016,reg5=0,reg6=0,reg7=0x70,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac100132,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac10013c,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac100146,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x50,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x60,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x70,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
>  ])
>  
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_LOOKUP | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  
> priority=100,arp,reg0=0xac10010a,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=20,arp,reg0=0xac100132,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=20,arp,reg0=0xac10013c,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=20,arp,reg0=0xac100146,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=20,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x50,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=20,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x60,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=20,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x70,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac100132,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac10013c,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac100146,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x50,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x60,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x70,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
>  ])
>  
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  
> priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10,arp_spa=172.16.1.10,arp_op=2
>  actions=drop
> +priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,arp_spa=172.16.1.50,arp_op=2
>  actions=drop
> +priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,arp_spa=172.16.1.60,arp_op=2
>  actions=drop
> +priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,arp_spa=172.16.1.70,arp_op=2
>  actions=drop
>  
> priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10,nw_src=172.16.1.10
>  actions=drop
> +priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,nw_src=172.16.1.50
>  actions=drop
> +priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,nw_src=172.16.1.60
>  actions=drop
> +priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,nw_src=172.16.1.70
>  actions=drop
> +priority=100,ipv6,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,ipv6_src=172:16::50
>  actions=drop
> +priority=100,ipv6,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,ipv6_src=172:16::60
>  actions=drop
> +priority=100,ipv6,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,ipv6_src=172:16::70
>  actions=drop
>  ])
>  
>  AS_BOX([Check dynamic-routing-arp-prefer-local=false])
> @@ -19248,29 +19299,38 @@ check ovn-nbctl --wait=hv set Logical_Switch 
> ls-evpn other_config:dynamic-routin
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_BINDING | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  priority=100,reg0=0xac10010a,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:01:10,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg0=0xac100132,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg0=0xac10013c,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg0=0xac100146,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x50,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x60,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x70,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac100132,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac10013c,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac100146,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x50,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x60,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x70,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
>  ])
>  
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_LOOKUP | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  
> priority=100,arp,reg0=0xac10010a,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,arp,reg0=0xac100132,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,arp,reg0=0xac10013c,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,arp,reg0=0xac100146,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x50,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x60,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x70,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac100132,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac10013c,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac100146,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x50,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x60,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x70,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
>  ])
>  
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  
> priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10,arp_spa=172.16.1.10,arp_op=2
>  actions=drop
> +priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,arp_spa=172.16.1.50,arp_op=2
>  actions=drop
> +priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,arp_spa=172.16.1.60,arp_op=2
>  actions=drop
> +priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,arp_spa=172.16.1.70,arp_op=2
>  actions=drop
>  
> priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10,nw_src=172.16.1.10
>  actions=drop
> +priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,nw_src=172.16.1.50
>  actions=drop
> +priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,nw_src=172.16.1.60
>  actions=drop
> +priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,nw_src=172.16.1.70
>  actions=drop
> +priority=100,ipv6,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,ipv6_src=172:16::50
>  actions=drop
> +priority=100,ipv6,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,ipv6_src=172:16::60
>  actions=drop
> +priority=100,ipv6,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,ipv6_src=172:16::70
>  actions=drop
>  ])
>  
>  # Check that the recompute won't change the UUIDs and flows.
> @@ -19295,6 +19355,14 @@ check ip -6 neigh del dev $BR_NAME 172:16::70
>  OVS_WAIT_FOR_OUTPUT_UNQUOTED([ovn-appctl evpn/vtep-arp-list | cut -d',' -f2- 
> | sort], [0], [dnl
>  ])
>  
> +dnl Verify EVPN MAC_Binding rows are deleted from SB.
> +wait_row_count MAC_Binding 0 ip=172.16.1.50
> +wait_row_count MAC_Binding 0 ip=172.16.1.60
> +wait_row_count MAC_Binding 0 ip=172.16.1.70
> +wait_row_count MAC_Binding 0 ip="172\:16\:\:50"
> +wait_row_count MAC_Binding 0 ip="172\:16\:\:60"
> +wait_row_count MAC_Binding 0 ip="172\:16\:\:70"
> +
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_BINDING | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  priority=100,reg0=0xac10010a,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:01:10,load:0x1->NXM_NX_REG10[[6]]
> @@ -19334,23 +19402,23 @@ OVS_WAIT_FOR_OUTPUT_UNQUOTED([ovn-appctl 
> evpn/vtep-arp-list | cut -d',' -f2- | s
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_BINDING | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  priority=100,reg0=0xac10010a,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:01:10,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg0=0xac100132,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg0=0xac10013c,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg0=0xac100146,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x50,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x60,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x70,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac100132,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac10013c,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac100146,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x50,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x60,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x70,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
>  ])
>  
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_LOOKUP | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  
> priority=100,arp,reg0=0xac10010a,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,arp,reg0=0xac100132,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,arp,reg0=0xac10013c,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,arp,reg0=0xac100146,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x50,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x60,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x70,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac100132,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac10013c,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac100146,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x50,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x60,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x70,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
>  ])
>  
>  check ovn-nbctl --wait=hv lr-del lr
> @@ -19774,9 +19842,9 @@ rtr_dp_key=$(fetch_column Datapath tunnel_key 
> external_ids:name=lr)
>  rtr_port_key=$(fetch_column Port_Binding tunnel_key logical_port=lr-ls-evpn)
>  
>  # Simulate remote workload ARPs (type-2 MAC+IP EVPN route).
> -# ovn-controller needs to add OF rules for ARP lookup but no rules for
> -# MAC_CACHE use.  These entries do not age out automatically, their lifetime
> -# is controlled by the BGP-EVPN control plane.
> +# EVPN-learned MAC bindings are written to the SB MAC_Binding table and
> +# distributed to all chassis.  These entries do not age out automatically,
> +# their lifetime is controlled by the BGP-EVPN control plane.
>  check ip neigh add dev $BR_NAME 172.16.1.50 lladdr f0:00:0f:16:10:50 nud 
> noarp extern_learn
>  check ip neigh add dev $BR_NAME 172.16.1.60 lladdr f0:00:0f:16:10:60 nud 
> noarp extern_learn
>  check ip neigh add dev $BR_NAME 172.16.1.70 lladdr f0:00:0f:16:10:70 nud 
> noarp extern_learn
> @@ -19794,35 +19862,52 @@ OVS_WAIT_FOR_OUTPUT_UNQUOTED([ovn-appctl 
> evpn/vtep-arp-list | cut -d',' -f2- | s
>   VNI: 10, MAC: f0:00:0f:16:10:70, IP: 172:16::70, dp_key: $dp_key
>  ])
>  
> +dnl Verify EVPN-learned MAC bindings appear in the SB MAC_Binding table.
> +wait_row_count MAC_Binding 1 ip=172.16.1.50
> +wait_row_count MAC_Binding 1 ip=172.16.1.60
> +wait_row_count MAC_Binding 1 ip=172.16.1.70
> +wait_row_count MAC_Binding 1 ip="172\:16\:\:50"
> +wait_row_count MAC_Binding 1 ip="172\:16\:\:60"
> +wait_row_count MAC_Binding 1 ip="172\:16\:\:70"
> +
>  AS_BOX([Check dynamic-routing-arp-prefer-local=true])
>  check ovn-nbctl --wait=hv set Logical_Switch ls-evpn 
> other_config:dynamic-routing-arp-prefer-local=true
>  
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_BINDING | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  priority=100,reg0=0xac10010a,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:01:10,load:0x1->NXM_NX_REG10[[6]]
> -priority=20,reg0=0xac100132,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> -priority=20,reg0=0xac10013c,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> -priority=20,reg0=0xac100146,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> -priority=20,reg4=0x1720016,reg5=0,reg6=0,reg7=0x50,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> -priority=20,reg4=0x1720016,reg5=0,reg6=0,reg7=0x60,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> -priority=20,reg4=0x1720016,reg5=0,reg6=0,reg7=0x70,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac100132,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac10013c,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac100146,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x50,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x60,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x70,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
>  ])
>  
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_LOOKUP | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  
> priority=100,arp,reg0=0xac10010a,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=20,arp,reg0=0xac100132,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=20,arp,reg0=0xac10013c,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=20,arp,reg0=0xac100146,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=20,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x50,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=20,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x60,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=20,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x70,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac100132,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac10013c,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac100146,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x50,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x60,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x70,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
>  ])
>  
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  
> priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10,arp_spa=172.16.1.10,arp_op=2
>  actions=drop
> +priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,arp_spa=172.16.1.50,arp_op=2
>  actions=drop
> +priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,arp_spa=172.16.1.60,arp_op=2
>  actions=drop
> +priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,arp_spa=172.16.1.70,arp_op=2
>  actions=drop
>  
> priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10,nw_src=172.16.1.10
>  actions=drop
> +priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,nw_src=172.16.1.50
>  actions=drop
> +priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,nw_src=172.16.1.60
>  actions=drop
> +priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,nw_src=172.16.1.70
>  actions=drop
> +priority=100,ipv6,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,ipv6_src=172:16::50
>  actions=drop
> +priority=100,ipv6,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,ipv6_src=172:16::60
>  actions=drop
> +priority=100,ipv6,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,ipv6_src=172:16::70
>  actions=drop
>  ])
>  
>  AS_BOX([Check dynamic-routing-arp-prefer-local=false])
> @@ -19831,29 +19916,38 @@ check ovn-nbctl --wait=hv set Logical_Switch 
> ls-evpn other_config:dynamic-routin
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_BINDING | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  priority=100,reg0=0xac10010a,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:01:10,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg0=0xac100132,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg0=0xac10013c,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg0=0xac100146,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x50,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x60,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x70,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac100132,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac10013c,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac100146,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x50,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x60,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x70,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
>  ])
>  
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_LOOKUP | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  
> priority=100,arp,reg0=0xac10010a,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,arp,reg0=0xac100132,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,arp,reg0=0xac10013c,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,arp,reg0=0xac100146,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x50,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x60,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x70,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac100132,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac10013c,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac100146,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x50,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x60,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x70,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
>  ])
>  
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  
> priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10,arp_spa=172.16.1.10,arp_op=2
>  actions=drop
> +priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,arp_spa=172.16.1.50,arp_op=2
>  actions=drop
> +priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,arp_spa=172.16.1.60,arp_op=2
>  actions=drop
> +priority=100,arp,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,arp_spa=172.16.1.70,arp_op=2
>  actions=drop
>  
> priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10,nw_src=172.16.1.10
>  actions=drop
> +priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,nw_src=172.16.1.50
>  actions=drop
> +priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,nw_src=172.16.1.60
>  actions=drop
> +priority=100,ip,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,nw_src=172.16.1.70
>  actions=drop
> +priority=100,ipv6,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,ipv6_src=172:16::50
>  actions=drop
> +priority=100,ipv6,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,ipv6_src=172:16::60
>  actions=drop
> +priority=100,ipv6,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,ipv6_src=172:16::70
>  actions=drop
>  ])
>  
>  # Check that the recompute won't change the UUIDs and flows.
> @@ -19878,6 +19972,14 @@ check ip -6 neigh del dev $BR_NAME 172:16::70
>  OVS_WAIT_FOR_OUTPUT_UNQUOTED([ovn-appctl evpn/vtep-arp-list | cut -d',' -f2- 
> | sort], [0], [dnl
>  ])
>  
> +dnl Verify EVPN MAC_Binding rows are deleted from SB.
> +wait_row_count MAC_Binding 0 ip=172.16.1.50
> +wait_row_count MAC_Binding 0 ip=172.16.1.60
> +wait_row_count MAC_Binding 0 ip=172.16.1.70
> +wait_row_count MAC_Binding 0 ip="172\:16\:\:50"
> +wait_row_count MAC_Binding 0 ip="172\:16\:\:60"
> +wait_row_count MAC_Binding 0 ip="172\:16\:\:70"
> +
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_BINDING | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  priority=100,reg0=0xac10010a,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:01:10,load:0x1->NXM_NX_REG10[[6]]
> @@ -19917,23 +20019,23 @@ OVS_WAIT_FOR_OUTPUT_UNQUOTED([ovn-appctl 
> evpn/vtep-arp-list | cut -d',' -f2- | s
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_BINDING | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  priority=100,reg0=0xac10010a,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:01:10,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg0=0xac100132,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg0=0xac10013c,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg0=0xac100146,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x50,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x60,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> -priority=200,reg4=0x1720016,reg5=0,reg6=0,reg7=0x70,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac100132,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac10013c,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg0=0xac100146,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key 
> actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x50,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:50,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x60,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:60,load:0x1->NXM_NX_REG10[[6]]
> +priority=100,reg4=0x1720016,reg5=0,reg6=0,reg7=0x70,reg15=0x$rtr_port_key,metadata=0x$rtr_dp_key
>  actions=mod_dl_dst:f0:00:0f:16:10:70,load:0x1->NXM_NX_REG10[[6]]
>  ])
>  
>  AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_LOOKUP | 
> grep priority | \
>                     awk '{print $[7], $[8]}' | sort], [0], [dnl
>  
> priority=100,arp,reg0=0xac10010a,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:01:10
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,arp,reg0=0xac100132,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,arp,reg0=0xac10013c,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,arp,reg0=0xac100146,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x50,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x60,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> -priority=200,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x70,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac100132,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac10013c,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,arp,reg0=0xac100146,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x50,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:50,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x60,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:60,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
> +priority=100,icmp6,reg0=0x1720016,reg1=0,reg2=0,reg3=0x70,reg14=0x$rtr_port_key,metadata=0x$rtr_dp_key,dl_src=f0:00:0f:16:10:70,icmp_code=0
>  actions=load:0x1->NXM_NX_REG10[[6]]
>  ])
>  
>  check ovn-nbctl --wait=hv lr-del lr

Regards,
Dumitru


_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to