diff mbox series

[ovs-dev,v3,3/3] northd: Move REG_SRC_IPV4 from reg1 to reg5.

Message ID 20241127124438.96047-4-martin.kalcok@canonical.com
State Superseded
Headers show
Series IPv4 routes over IPv6 next hop addresses. | expand

Checks

Context Check Description
ovsrobot/apply-robot warning apply and check: warning
ovsrobot/github-robot-_Build_and_Test success github build: passed
ovsrobot/github-robot-_ovn-kubernetes fail github build: failed

Commit Message

Martin Kalcok Nov. 27, 2024, 12:43 p.m. UTC
Introduction of IPv4 routes with IPv6 next hop addresses
can cause a register corruption in scenario where distributed
NAT is enabled [0]. This happens because reg1, used to store IPv4
address of ARP request (REG_SRC_IPV4), is overlapping with xxreg0
used to store IPv6 next hop address in the LR pipeline.

This changes aims to solve this issue by moving REG_SRC_IP4 from
reg1 to unused register reg5. This register overlaps only with
xreg2 and xxreg1 but there should be any risk of corruption in LR
pipeline:

 * xreg2 is currently unused
 * xxreg1 is used for REG_SRC_IPV6 but its usage is
   mutually exclusive with REG_SRC_IPV4
 * xxreg1 is used for REG_ECMP_ETH_FULL as well, but according to the
   documentation, the usage is temporary and the original value is
   restored within the same flow rule.

[0] https://patchwork.ozlabs.org/project/ovn/patch/9d1431a90b587e2f56bb7be5ae8c90902a758b5d.1718174935.git.felix.huettner@mail.schwarz/#3341306

Signed-off-by: Martin Kalcok <martin.kalcok@canonical.com>
---
 northd/northd.c     | 15 +++----
 tests/ovn-northd.at | 96 ++++++++++++++++++++++-----------------------
 tests/ovn.at        |  2 +-
 3 files changed, 57 insertions(+), 56 deletions(-)

Comments

Frode Nordahl Nov. 28, 2024, 7:33 a.m. UTC | #1
Hello, Martin,

As mentioned in the reply to the cover letter, this patch should
probably be the first patch of the series to maintain a bisectable git
history.

On Wed, Nov 27, 2024 at 2:00 PM Martin Kalcok
<martin.kalcok@canonical.com> wrote:
>
> Introduction of IPv4 routes with IPv6 next hop addresses
> can cause a register corruption in scenario where distributed

s/a//
s/scenario/scenarios/

> NAT is enabled [0]. This happens because reg1, used to store IPv4
> address of ARP request (REG_SRC_IPV4), is overlapping with xxreg0
> used to store IPv6 next hop address in the LR pipeline.
>
> This changes aims to solve this issue by moving REG_SRC_IP4 from

s/changes/change

> reg1 to unused register reg5. This register overlaps only with
> xreg2 and xxreg1 but there should be any risk of corruption in LR

Is there a missing 'not' above?

> pipeline:
>
>  * xreg2 is currently unused
>  * xxreg1 is used for REG_SRC_IPV6 but its usage is
>    mutually exclusive with REG_SRC_IPV4
>  * xxreg1 is used for REG_ECMP_ETH_FULL as well, but according to the
>    documentation, the usage is temporary and the original value is
>    restored within the same flow rule.
>
> [0] https://patchwork.ozlabs.org/project/ovn/patch/9d1431a90b587e2f56bb7be5ae8c90902a758b5d.1718174935.git.felix.huettner@mail.schwarz/#3341306

The referenced review describes in detail a use case that causes the
corruption, yet I see no test case added that detects it.

We would need that to ensure future changes do not regress this
feature, it would also be more convenient for our reviewer to verify
that this actually fixes the issue with a test case.

> Signed-off-by: Martin Kalcok <martin.kalcok@canonical.com>
> ---
>  northd/northd.c     | 15 +++----
>  tests/ovn-northd.at | 96 ++++++++++++++++++++++-----------------------
>  tests/ovn.at        |  2 +-
>  3 files changed, 57 insertions(+), 56 deletions(-)
>
> diff --git a/northd/northd.c b/northd/northd.c
> index 7a902085d..436e42248 100644
> --- a/northd/northd.c
> +++ b/northd/northd.c
> @@ -188,7 +188,7 @@ BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 << 2));
>  /* Registers used for routing. */
>  #define REG_NEXT_HOP_IPV4 "reg0"
>  #define REG_NEXT_HOP_IPV6 "xxreg0"
> -#define REG_SRC_IPV4 "reg1"
> +#define REG_SRC_IPV4 "reg5"
>  #define REG_SRC_IPV6 "xxreg1"
>  #define REG_DHCP_RELAY_DIP_IPV4 "reg2"
>  #define REG_ROUTE_TABLE_ID "reg7"
> @@ -259,8 +259,8 @@ BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 << 2));
>   * |     |      NEXT_HOP_IPV4        | R |                 |   |                                    |
>   * |     |      (>= IP_INPUT)        | E | INPORT_ETH_ADDR | X |                                    |
>   * +-----+---------------------------+ G |   (< IP_INPUT)  | X |                                    |
> - * | R1  |   SRC_IPV4 for ARP-REQ    | 0 |                 | R |                                    |
> - * |     |      (>= IP_INPUT)        |   |                 | E |     NEXT_HOP_IPV6 (>= DEFRAG )     |
> + * | R1  |        UNUSED             | 0 |                 | R |                                    |

Is documenting this as unused right, would that not invite people to
attempt to use it? It would probably be safer to label it RESERVED
with a reference to this use case?

--
Frode Nordahl

> + * |     |                           |   |                 | E |     NEXT_HOP_IPV6 (>= DEFRAG )     |
>   * +-----+---------------------------+---+-----------------+ G |                                    |
>   * | R2     REG_DHCP_RELAY_DIP_IPV4  | X |                 | 0 |                                    |
>   * |     |                           | R |                 |   |                                    |
> @@ -271,8 +271,8 @@ BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 << 2));
>   * | R4  |  REG_LB_AFF_BACKEND_IP4   | X |                 |   |                                    |
>   * |     |                           | R |                 |   |                                    |
>   * +-----+---------------------------+ E |     UNUSED      | X |                                    |
> - * | R5  |        UNUSED             | G |                 | X |                                    |
> - * |     |                           | 2 |                 | R |        LB_L3_AFF_BACKEND_IP6       |
> + * | R5  |  SRC_IPV4 for ARP-REQ     | G |                 | X |                                    |
> + * |     |      (>= IP_INPUT)        | 2 |                 | R |        LB_L3_AFF_BACKEND_IP6       |
>   * +-----+---------------------------+---+-----------------+ E |           (<= IN_DNAT)             |
>   * | R6  |        UNUSED             | X |                 | G |                                    |
>   * |     |                           | R |                 | 1 |                                    |
> @@ -11602,9 +11602,10 @@ add_ecmp_symmetric_reply_flows(struct lflow_table *lflows,
>                    ds_cstr(route_match));
>      ds_clear(&actions);
>      ds_put_format(&actions, "ip.ttl--; flags.loopback = 1; "
> -                  "eth.src = %s; %sreg1 = %s; outport = %s; next;",
> +                  "eth.src = %s; %s = %s; outport = %s; next;",
>                    out_port->lrp_networks.ea_s,
> -                  IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "" : "xx",
> +                  IN6_IS_ADDR_V4MAPPED(&route->prefix) ?
> +                      REG_SRC_IPV4 : REG_SRC_IPV6,
>                    port_ip, out_port->json_key);
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_ROUTING, 10300,
>                             ds_cstr(&match), ds_cstr(&actions),
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> index 6ec6648dd..4335baeec 100644
> --- a/tests/ovn-northd.at
> +++ b/tests/ovn-northd.at
> @@ -3442,8 +3442,8 @@ AT_CHECK([grep "lr_in_policy" lr0flows3 | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_policy       ), priority=0    , match=(1), action=(reg8[[0..15]] = 0; next;)
>    table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.3), action=(reg8[[0..15]] = 1; reg8[[16..31]] = select(1, 2);)
>    table=??(lr_in_policy_ecmp  ), priority=0    , match=(1), action=(drop;)
> -  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> -  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
>    table=??(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == 0), action=(next;)
>  ])
>
> @@ -3458,11 +3458,11 @@ sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lf
>    table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.3), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2);)
>    table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2, 3);)
>    table=??(lr_in_policy_ecmp  ), priority=0    , match=(1), action=(drop;)
> -  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> -  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> -  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> -  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> -  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
>    table=??(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == <cleared>), action=(next;)
>  ])
>
> @@ -3476,13 +3476,13 @@ sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lf
>    table=??(lr_in_policy       ), priority=0    , match=(1), action=(reg8[[0..15]] = <cleared>; next;)
>    table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.3), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2);)
>    table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2, 3);)
> -  table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;)
> +  table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;)
>    table=??(lr_in_policy_ecmp  ), priority=0    , match=(1), action=(drop;)
> -  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> -  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> -  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> -  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> -  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
>    table=??(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == <cleared>), action=(next;)
>  ])
>
> @@ -3495,11 +3495,11 @@ sed 's/reg8\[[0..15\]] = [[0-9]]*/reg8\[[0..15\]] = <cleared>/' | \
>  sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_policy       ), priority=0    , match=(1), action=(reg8[[0..15]] = <cleared>; next;)
>    table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2, 3);)
> -  table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;)
> +  table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;)
>    table=??(lr_in_policy_ecmp  ), priority=0    , match=(1), action=(drop;)
> -  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> -  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> -  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
>    table=??(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == <cleared>), action=(next;)
>  ])
>
> @@ -3511,7 +3511,7 @@ AT_CHECK([grep "lr_in_policy" lr0flows3 |  \
>  sed 's/reg8\[[0..15\]] = [[0-9]]*/reg8\[[0..15\]] = <cleared>/' | \
>  sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_policy       ), priority=0    , match=(1), action=(reg8[[0..15]] = <cleared>; next;)
> -  table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;)
> +  table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;)
>    table=??(lr_in_policy_ecmp  ), priority=0    , match=(1), action=(drop;)
>    table=??(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == <cleared>), action=(next;)
>  ])
> @@ -6821,16 +6821,16 @@ ovn-sbctl dump-flows lr0 > lr0flows
>
>  AT_CHECK([grep -w "lr_in_ip_routing" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_ip_routing   ), priority=0    , match=(1), action=(drop;)
> -  table=??(lr_in_ip_routing   ), priority=10300, match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = 00:00:20:20:12:13; reg1 = 192.168.0.1; outport = "lr0-public"; next;)
> +  table=??(lr_in_ip_routing   ), priority=10300, match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public"; next;)
>    table=??(lr_in_ip_routing   ), priority=10550, match=(nd_rs || nd_ra), action=(drop;)
> -  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
>    table=??(lr_in_ip_routing   ), priority=162  , match=(reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; reg8[[0..15]] = 1; reg8[[16..31]] = 1; next;)
>    table=??(lr_in_ip_routing   ), priority=324  , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;)
>  ])
>
>  AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_ip_routing_ecmp), priority=0    , match=(1), action=(drop;)
> -  table=??(lr_in_ip_routing_ecmp), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.10; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;)
> +  table=??(lr_in_ip_routing_ecmp), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;)
>    table=??(lr_in_ip_routing_ecmp), priority=150  , match=(reg8[[0..15]] == 0), action=(next;)
>  ])
>
> @@ -6839,16 +6839,16 @@ check ovn-nbctl --wait=sb --ecmp-symmetric-reply lr-route-add lr0 1.0.0.1 192.16
>  ovn-sbctl dump-flows lr0 > lr0flows
>  AT_CHECK([grep -w "lr_in_ip_routing" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_ip_routing   ), priority=0    , match=(1), action=(drop;)
> -  table=??(lr_in_ip_routing   ), priority=10300, match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = 00:00:20:20:12:13; reg1 = 192.168.0.1; outport = "lr0-public"; next;)
> +  table=??(lr_in_ip_routing   ), priority=10300, match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public"; next;)
>    table=??(lr_in_ip_routing   ), priority=10550, match=(nd_rs || nd_ra), action=(drop;)
> -  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
>    table=??(lr_in_ip_routing   ), priority=162  , match=(reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; reg8[[0..15]] = 1; reg8[[16..31]] = select(1, 2);)
>    table=??(lr_in_ip_routing   ), priority=324  , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;)
>  ])
>  AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed 's/192\.168\.0\..0/192.168.0.??/' | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_ip_routing_ecmp), priority=0    , match=(1), action=(drop;)
> -  table=??(lr_in_ip_routing_ecmp), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;)
> -  table=??(lr_in_ip_routing_ecmp), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 192.168.0.??; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;)
> +  table=??(lr_in_ip_routing_ecmp), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;)
> +  table=??(lr_in_ip_routing_ecmp), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;)
>    table=??(lr_in_ip_routing_ecmp), priority=150  , match=(reg8[[0..15]] == 0), action=(next;)
>  ])
>
> @@ -6868,16 +6868,16 @@ check ovn-nbctl --wait=sb --ecmp-symmetric-reply lr-route-add lr0 1.0.0.1 192.16
>  ovn-sbctl dump-flows lr0 > lr0flows
>  AT_CHECK([grep -w "lr_in_ip_routing" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_ip_routing   ), priority=0    , match=(1), action=(drop;)
> -  table=??(lr_in_ip_routing   ), priority=10300, match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = 00:00:20:20:12:13; reg1 = 192.168.0.1; outport = "lr0-public"; next;)
> +  table=??(lr_in_ip_routing   ), priority=10300, match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public"; next;)
>    table=??(lr_in_ip_routing   ), priority=10550, match=(nd_rs || nd_ra), action=(drop;)
> -  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
>    table=??(lr_in_ip_routing   ), priority=162  , match=(reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; reg8[[0..15]] = 1; reg8[[16..31]] = select(1, 2);)
>    table=??(lr_in_ip_routing   ), priority=324  , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;)
>  ])
>  AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed 's/192\.168\.0\..0/192.168.0.??/' | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_ip_routing_ecmp), priority=0    , match=(1), action=(drop;)
> -  table=??(lr_in_ip_routing_ecmp), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;)
> -  table=??(lr_in_ip_routing_ecmp), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 192.168.0.??; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;)
> +  table=??(lr_in_ip_routing_ecmp), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;)
> +  table=??(lr_in_ip_routing_ecmp), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;)
>    table=??(lr_in_ip_routing_ecmp), priority=150  , match=(reg8[[0..15]] == 0), action=(next;)
>  ])
>
> @@ -6888,14 +6888,14 @@ check ovn-nbctl --wait=sb lr-route-add lr0 1.0.0.0/24 192.168.0.10
>  ovn-sbctl dump-flows lr0 > lr0flows
>
>  AT_CHECK([grep -e "lr_in_ip_routing.*192.168.0.10" lr0flows | ovn_strip_lflows], [0], [dnl
> -  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 0 && ip4.dst == 1.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 0 && ip4.dst == 1.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
>  ])
>
>  check ovn-nbctl --wait=sb lr-route-add lr0 2.0.0.0/24 lr0-public
>
>  ovn-sbctl dump-flows lr0 > lr0flows
>  AT_CHECK([grep -e "lr_in_ip_routing.*2.0.0.0" lr0flows | ovn_strip_lflows], [0], [dnl
> -  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 0 && ip4.dst == 2.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 0 && ip4.dst == 2.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
>  ])
>
>  check ovn-nbctl lr-route-add lr0 3.3.0.0/16 192.168.0.11
> @@ -6960,10 +6960,10 @@ ovn-sbctl dump-flows lr0 > lr0flows
>  AT_CHECK([grep -e "lr_in_ip_routing " lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_ip_routing   ), priority=0    , match=(1), action=(drop;)
>    table=??(lr_in_ip_routing   ), priority=10550, match=(nd_rs || nd_ra), action=(drop;)
> -  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 0 && ip4.dst == 10.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 0 && ip4.dst == 10.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
>    table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 0 && ip4.dst == 11.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = 2001:db8::10; xxreg1 = 2001:db8::1; eth.src = 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;)
> -  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> -  table=??(lr_in_ip_routing   ), priority=322  , match=(reg7 == 0 && ip6.dst == 2001:db8:1::/64), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.20; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_ip_routing   ), priority=322  , match=(reg7 == 0 && ip6.dst == 2001:db8:1::/64), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.20; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
>    table=??(lr_in_ip_routing   ), priority=322  , match=(reg7 == 0 && ip6.dst == 2001:db8:2::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = 2001:db8::20; xxreg1 = 2001:db8::1; eth.src = 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;)
>    table=??(lr_in_ip_routing   ), priority=324  , match=(inport == "lr0-private" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1214; eth.src = 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;)
>    table=??(lr_in_ip_routing   ), priority=324  , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;)
> @@ -6980,7 +6980,7 @@ AT_CHECK([grep -e "lr_in_arp_resolve" lr0flows | ovn_strip_lflows], [0], [dnl
>  AT_CHECK([grep -e "lr_in_arp_request" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_arp_request  ), priority=0    , match=(1), action=(output;)
>    table=??(lr_in_arp_request  ), priority=100  , match=(eth.dst == 00:00:00:00:00:00 && reg9[[9]] == 0), action=(nd_ns { nd.target = xxreg0; output; }; output;)
> -  table=??(lr_in_arp_request  ), priority=100  , match=(eth.dst == 00:00:00:00:00:00 && reg9[[9]] == 1), action=(arp { eth.dst = ff:ff:ff:ff:ff:ff; arp.spa = reg1; arp.tpa = reg0; arp.op = 1; output; }; output;)
> +  table=??(lr_in_arp_request  ), priority=100  , match=(eth.dst == 00:00:00:00:00:00 && reg9[[9]] == 1), action=(arp { eth.dst = ff:ff:ff:ff:ff:ff; arp.spa = reg5; arp.tpa = reg0; arp.op = 1; output; }; output;)
>    table=??(lr_in_arp_request  ), priority=200  , match=(eth.dst == 00:00:00:00:00:00 && reg9[[9]] == 0 && xxreg0 == 2001:db8::10), action=(nd_ns { eth.dst = 33:33:ff:00:00:10; ip6.dst = ff02::1:ff00:10; nd.target = 2001:db8::10; output; }; output;)
>    table=??(lr_in_arp_request  ), priority=200  , match=(eth.dst == 00:00:00:00:00:00 && reg9[[9]] == 0 && xxreg0 == 2001:db8::20), action=(nd_ns { eth.dst = 33:33:ff:00:00:20; ip6.dst = ff02::1:ff00:20; nd.target = 2001:db8::20; output; }; output;)
>  ])
> @@ -7406,13 +7406,13 @@ AT_CHECK([grep "lr_in_ip_routing_pre" lr0flows | ovn_strip_lflows], [0], [dnl
>  grep -e "(lr_in_ip_routing   ).*outport" lr0flows
>
>  AT_CHECK([grep -e "(lr_in_ip_routing   ).*outport" lr0flows | ovn_strip_lflows], [0], [dnl
> -  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 1 && ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.1.10; reg1 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; reg9[[9]] = 1; next;)
> -  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
> -  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.1.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; reg9[[9]] = 1; next;)
> -  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.2.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.2.1; eth.src = 00:00:00:00:02:01; outport = "lrp2"; flags.loopback = 1; reg9[[9]] = 1; next;)
> -  table=??(lr_in_ip_routing   ), priority=162  , match=(reg7 == 2 && ip4.dst == 1.1.1.1/32), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.20; reg1 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
> -  table=??(lr_in_ip_routing   ), priority=2    , match=(reg7 == 0 && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg1 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
> -  table=??(lr_in_ip_routing   ), priority=2    , match=(reg7 == 2 && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg1 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 1 && ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.1.10; reg5 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.1.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.2.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.2.1; eth.src = 00:00:00:00:02:01; outport = "lrp2"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_ip_routing   ), priority=162  , match=(reg7 == 2 && ip4.dst == 1.1.1.1/32), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.20; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_ip_routing   ), priority=2    , match=(reg7 == 0 && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
> +  table=??(lr_in_ip_routing   ), priority=2    , match=(reg7 == 2 && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
>    table=??(lr_in_ip_routing   ), priority=324  , match=(inport == "lrp0" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:ff:fe00:1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 0; next;)
>    table=??(lr_in_ip_routing   ), priority=324  , match=(inport == "lrp1" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:ff:fe00:101; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; reg9[[9]] = 0; next;)
>    table=??(lr_in_ip_routing   ), priority=324  , match=(inport == "lrp2" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:ff:fe00:201; eth.src = 00:00:00:00:02:01; outport = "lrp2"; flags.loopback = 1; reg9[[9]] = 0; next;)
> @@ -11058,7 +11058,7 @@ AT_CAPTURE_FILE([R1flows])
>
>  AT_CHECK([grep "lr_in_gw_redirect" R1flows | sed s'/table=../table=??/' |sort], [0], [dnl
>    table=??(lr_in_gw_redirect  ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")), action=(eth.src = 30:54:00:00:00:03; reg1 = 172.16.0.110; next;)
> +  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")), action=(eth.src = 30:54:00:00:00:03; reg5 = 172.16.0.110; next;)
>    table=??(lr_in_gw_redirect  ), priority=100  , match=(ip6.src == 1000::3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")), action=(eth.src = 40:54:00:00:00:03; xxreg1 = 3000::c; next;)
>    table=??(lr_in_gw_redirect  ), priority=50   , match=(outport == "R1-PUB"), action=(outport = "cr-R1-PUB"; next;)
>  ])
> @@ -11072,7 +11072,7 @@ ovn-sbctl dump-flows R1 > R1flows
>  AT_CAPTURE_FILE([R1flows])
>  AT_CHECK([grep "lr_in_gw_redirect" R1flows |sed s'/table=../table=??/' |sort], [0], [dnl
>    table=??(lr_in_gw_redirect  ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")), action=(eth.src = 30:54:00:00:00:03; reg1 = 172.16.0.110; next;)
> +  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")), action=(eth.src = 30:54:00:00:00:03; reg5 = 172.16.0.110; next;)
>    table=??(lr_in_gw_redirect  ), priority=100  , match=(ip6.src == 1000::3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")), action=(eth.src = 40:54:00:00:00:03; xxreg1 = 3000::c; next;)
>    table=??(lr_in_gw_redirect  ), priority=200  , match=(ip4 && ((ip4.src == 10.0.0.2 && tcp.src == 50001) || (ip4.src == 10.0.0.3 && tcp.src == 50001) || (ip4.src == 10.0.0.4 && tcp.src == 50001)) && outport == "R1-PUB"), action=(outport = "cr-R1-PUB"; next;)
>    table=??(lr_in_gw_redirect  ), priority=200  , match=(ip6 && ((ip6.src == 1000::3 && tcp.src == 8080)) && outport == "R1-PUB"), action=(outport = "cr-R1-PUB"; next;)
> @@ -13523,7 +13523,7 @@ AT_CHECK([grep "lr_in_arp_resolve" lr0flows | ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep "lr_in_gw_redirect" lr0flows | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_gw_redirect  ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-port1")), action=(eth.src = 30:54:00:00:00:03; reg1 = 172.168.0.110; next;)
> +  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-port1")), action=(eth.src = 30:54:00:00:00:03; reg5 = 172.168.0.110; next;)
>    table=??(lr_in_gw_redirect  ), priority=50   , match=(outport == "lr0-public"), action=(outport = "cr-lr0-public"; next;)
>  ])
>
> @@ -13575,7 +13575,7 @@ AT_CHECK([grep -e "172.168.0.110" -e "172.168.0.120" -e "10.0.0.3" -e "20.0.0.3"
>    table=??(lr_in_arp_resolve  ), priority=150  , match=(inport == "lr0-public" && outport == "lr0-public" && ip4.dst == 172.168.0.120), action=(drop;)
>    table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 172.168.0.110 && inport == "lr0-public"), action=(ct_dnat(10.0.0.3);)
>    table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 172.168.0.120 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_dnat(20.0.0.3);)
> -  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-port1")), action=(eth.src = 30:54:00:00:00:03; reg1 = 172.168.0.110; next;)
> +  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-port1")), action=(eth.src = 30:54:00:00:00:03; reg5 = 172.168.0.110; next;)
>    table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa == 172.168.0.110), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = inport; flags.loopback = 1; output;)
>    table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa == 172.168.0.120), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = inport; flags.loopback = 1; output;)
>    table=??(lr_in_ip_input     ), priority=91   , match=(inport == "lr0-public" && arp.op == 1 && arp.tpa == 172.168.0.110), action=(drop;)
> @@ -13794,7 +13794,7 @@ AT_CHECK([grep -e "172.168.0.110" -e "172.168.0.120" -e "10.0.0.3" -e "20.0.0.3"
>    table=??(lr_in_arp_resolve  ), priority=150  , match=(inport == "lr0-public" && outport == "lr0-public" && ip4.dst == 172.168.0.120), action=(drop;)
>    table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 172.168.0.110 && inport == "lr0-public"), action=(ct_dnat(10.0.0.3);)
>    table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 172.168.0.120 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_dnat(20.0.0.3);)
> -  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-port1")), action=(eth.src = 30:54:00:00:00:03; reg1 = 172.168.0.110; next;)
> +  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-port1")), action=(eth.src = 30:54:00:00:00:03; reg5 = 172.168.0.110; next;)
>    table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa == 172.168.0.110), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = inport; flags.loopback = 1; output;)
>    table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa == 172.168.0.120), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = inport; flags.loopback = 1; output;)
>    table=??(lr_in_ip_input     ), priority=91   , match=(inport == "lr0-public" && arp.op == 1 && arp.tpa == 172.168.0.110), action=(drop;)
> @@ -13855,7 +13855,7 @@ AT_CHECK([grep -e "172.168.0.110" -e "172.168.0.120" -e "10.0.0.3" -e "20.0.0.3"
>    table=??(lr_in_arp_resolve  ), priority=150  , match=(inport == "lr0-public" && outport == "lr0-public" && ip4.dst == 172.168.0.120), action=(drop;)
>    table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 172.168.0.110 && inport == "lr0-public"), action=(ct_dnat(10.0.0.3);)
>    table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 172.168.0.120 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_dnat(20.0.0.3);)
> -  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-port1")), action=(eth.src = 30:54:00:00:00:03; reg1 = 172.168.0.110; next;)
> +  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-port1")), action=(eth.src = 30:54:00:00:00:03; reg5 = 172.168.0.110; next;)
>    table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa == 172.168.0.110), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = inport; flags.loopback = 1; output;)
>    table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa == 172.168.0.120), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = inport; flags.loopback = 1; output;)
>    table=??(lr_in_ip_input     ), priority=91   , match=(inport == "lr0-public" && arp.op == 1 && arp.tpa == 172.168.0.110), action=(drop;)
> diff --git a/tests/ovn.at b/tests/ovn.at
> index b94cddf0f..a29ec7114 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -22134,7 +22134,7 @@ check ovn-nbctl --wait=hv sync
>
>  # verify the traffic from virtual port is discarded if the port is not claimed
>  AT_CHECK([grep lr_in_gw_redirect lr0-flows2 | grep "ip4.src == 10.0.0.10" | ovn_strip_lflows], [0], [dnl
> -  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("sw0-vir")), action=(eth.src = 10:54:00:00:00:10; reg1 = 172.168.0.50; next;)
> +  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("sw0-vir")), action=(eth.src = 10:54:00:00:00:10; reg5 = 172.168.0.50; next;)
>    table=??(lr_in_gw_redirect  ), priority=80   , match=(ip4.src == 10.0.0.10 && outport == "lr0-public"), action=(drop;)
>  ])
>
> --
> 2.43.0
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
Martin Kalcok Nov. 28, 2024, 10:17 a.m. UTC | #2
Hi Frode,
thank you for the review.

On Thu, 2024-11-28 at 08:33 +0100, Frode Nordahl wrote:
> Hello, Martin,
> 
> As mentioned in the reply to the cover letter, this patch should
> probably be the first patch of the series to maintain a bisectable
> git
> history.

Yes, that's a good idea, I'll do that.

> 
> On Wed, Nov 27, 2024 at 2:00 PM Martin Kalcok
> <martin.kalcok@canonical.com> wrote:
> > 
> > Introduction of IPv4 routes with IPv6 next hop addresses
> > can cause a register corruption in scenario where distributed
> 
> s/a//
> s/scenario/scenarios/

ack

> 
> > NAT is enabled [0]. This happens because reg1, used to store IPv4
> > address of ARP request (REG_SRC_IPV4), is overlapping with xxreg0
> > used to store IPv6 next hop address in the LR pipeline.
> > 
> > This changes aims to solve this issue by moving REG_SRC_IP4 from
> 
> s/changes/change

ack

> 
> > reg1 to unused register reg5. This register overlaps only with
> > xreg2 and xxreg1 but there should be any risk of corruption in LR
> 
> Is there a missing 'not' above?

yup, thanks. Turns out that proofreading is hard when your brain reads
what you wanted to write, instead of what you actually written :D

> 
> > pipeline:
> > 
> >  * xreg2 is currently unused
> >  * xxreg1 is used for REG_SRC_IPV6 but its usage is
> >    mutually exclusive with REG_SRC_IPV4
> >  * xxreg1 is used for REG_ECMP_ETH_FULL as well, but according to
> > the
> >    documentation, the usage is temporary and the original value is
> >    restored within the same flow rule.
> > 
> > [0]
> > https://patchwork.ozlabs.org/project/ovn/patch/9d1431a90b587e2f56bb7be5ae8c90902a758b5d.1718174935.git.felix.huettner@mail.schwarz/#3341306
> 
> The referenced review describes in detail a use case that causes the
> corruption, yet I see no test case added that detects it.
> 
> We would need that to ensure future changes do not regress this
> feature, it would also be more convenient for our reviewer to verify
> that this actually fixes the issue with a test case.

That is a good point, I'll try to build the scenario in unit tests, but
I might have to resort to system test to ensure that the packets are
not getting mangled.

> 
> > Signed-off-by: Martin Kalcok <martin.kalcok@canonical.com>
> > ---
> >  northd/northd.c     | 15 +++----
> >  tests/ovn-northd.at | 96 ++++++++++++++++++++++-------------------
> > ----
> >  tests/ovn.at        |  2 +-
> >  3 files changed, 57 insertions(+), 56 deletions(-)
> > 
> > diff --git a/northd/northd.c b/northd/northd.c
> > index 7a902085d..436e42248 100644
> > --- a/northd/northd.c
> > +++ b/northd/northd.c
> > @@ -188,7 +188,7 @@ BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 <<
> > 2));
> >  /* Registers used for routing. */
> >  #define REG_NEXT_HOP_IPV4 "reg0"
> >  #define REG_NEXT_HOP_IPV6 "xxreg0"
> > -#define REG_SRC_IPV4 "reg1"
> > +#define REG_SRC_IPV4 "reg5"
> >  #define REG_SRC_IPV6 "xxreg1"
> >  #define REG_DHCP_RELAY_DIP_IPV4 "reg2"
> >  #define REG_ROUTE_TABLE_ID "reg7"
> > @@ -259,8 +259,8 @@ BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 <<
> > 2));
> >   * |     |      NEXT_HOP_IPV4        | R |                 |  
> > |                                    |
> >   * |     |      (>= IP_INPUT)        | E | INPORT_ETH_ADDR | X
> > |                                    |
> >   * +-----+---------------------------+ G |   (< IP_INPUT)  | X
> > |                                    |
> > - * | R1  |   SRC_IPV4 for ARP-REQ    | 0 |                 | R
> > |                                    |
> > - * |     |      (>= IP_INPUT)        |   |                 | E
> > |     NEXT_HOP_IPV6 (>= DEFRAG )     |
> > + * | R1  |        UNUSED             | 0 |                 | R
> > |                                    |
> 
> Is documenting this as unused right, would that not invite people to
> attempt to use it? It would probably be safer to label it RESERVED
> with a reference to this use case?

I disagree here. Just because the register is overlaid by extended
register, it doesn't make it unusable. It can still be used in a
mutually exclusive way with the xreg, or in non-overlapping stages of
the pipeline. Otherwise we'd have to mark every reg as "RESERVED" if
overlaying xreg is used. Right?

--
Martin
 
> 
> --
> Frode Nordahl
> 
> > + * |     |                           |   |                 | E
> > |     NEXT_HOP_IPV6 (>= DEFRAG )     |
> >   * +-----+---------------------------+---+-----------------+ G
> > |                                    |
> >   * | R2     REG_DHCP_RELAY_DIP_IPV4  | X |                 | 0
> > |                                    |
> >   * |     |                           | R |                 |  
> > |                                    |
> > @@ -271,8 +271,8 @@ BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 <<
> > 2));
> >   * | R4  |  REG_LB_AFF_BACKEND_IP4   | X |                 |  
> > |                                    |
> >   * |     |                           | R |                 |  
> > |                                    |
> >   * +-----+---------------------------+ E |     UNUSED      | X
> > |                                    |
> > - * | R5  |        UNUSED             | G |                 | X
> > |                                    |
> > - * |     |                           | 2 |                 | R
> > |        LB_L3_AFF_BACKEND_IP6       |
> > + * | R5  |  SRC_IPV4 for ARP-REQ     | G |                 | X
> > |                                    |
> > + * |     |      (>= IP_INPUT)        | 2 |                 | R
> > |        LB_L3_AFF_BACKEND_IP6       |
> >   * +-----+---------------------------+---+-----------------+ E
> > |           (<= IN_DNAT)             |
> >   * | R6  |        UNUSED             | X |                 | G
> > |                                    |
> >   * |     |                           | R |                 | 1
> > |                                    |
> > @@ -11602,9 +11602,10 @@ add_ecmp_symmetric_reply_flows(struct
> > lflow_table *lflows,
> >                    ds_cstr(route_match));
> >      ds_clear(&actions);
> >      ds_put_format(&actions, "ip.ttl--; flags.loopback = 1; "
> > -                  "eth.src = %s; %sreg1 = %s; outport = %s;
> > next;",
> > +                  "eth.src = %s; %s = %s; outport = %s; next;",
> >                    out_port->lrp_networks.ea_s,
> > -                  IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "" :
> > "xx",
> > +                  IN6_IS_ADDR_V4MAPPED(&route->prefix) ?
> > +                      REG_SRC_IPV4 : REG_SRC_IPV6,
> >                    port_ip, out_port->json_key);
> >      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_ROUTING,
> > 10300,
> >                             ds_cstr(&match), ds_cstr(&actions),
> > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> > index 6ec6648dd..4335baeec 100644
> > --- a/tests/ovn-northd.at
> > +++ b/tests/ovn-northd.at
> > @@ -3442,8 +3442,8 @@ AT_CHECK([grep "lr_in_policy" lr0flows3 |
> > ovn_strip_lflows], [0], [dnl
> >    table=??(lr_in_policy       ), priority=0    , match=(1),
> > action=(reg8[[0..15]] = 0; next;)
> >    table=??(lr_in_policy       ), priority=10   , match=(ip4.src ==
> > 10.0.0.3), action=(reg8[[0..15]] = 1; reg8[[16..31]] = select(1,
> > 2);)
> >    table=??(lr_in_policy_ecmp  ), priority=0    , match=(1),
> > action=(drop;)
> > -  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 =
> > 172.168.0.101; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13;
> > outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> > -  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 =
> > 172.168.0.102; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13;
> > outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> > +  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 =
> > 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13;
> > outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> > +  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 =
> > 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13;
> > outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> >    table=??(lr_in_policy_ecmp  ), priority=150  ,
> > match=(reg8[[0..15]] == 0), action=(next;)
> >  ])
> > 
> > @@ -3458,11 +3458,11 @@ sed 's/reg8\[[0..15\]] == [[0-
> > 9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lf
> >    table=??(lr_in_policy       ), priority=10   , match=(ip4.src ==
> > 10.0.0.3), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] =
> > select(1, 2);)
> >    table=??(lr_in_policy       ), priority=10   , match=(ip4.src ==
> > 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] =
> > select(1, 2, 3);)
> >    table=??(lr_in_policy_ecmp  ), priority=0    , match=(1),
> > action=(drop;)
> > -  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1),
> > action=(reg0 = 172.168.0.101; reg1 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > -  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1),
> > action=(reg0 = 172.168.0.101; reg1 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > -  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2),
> > action=(reg0 = 172.168.0.102; reg1 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > -  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2),
> > action=(reg0 = 172.168.0.102; reg1 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > -  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3),
> > action=(reg0 = 172.168.0.103; reg1 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > +  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1),
> > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > +  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1),
> > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > +  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2),
> > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > +  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2),
> > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > +  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3),
> > action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> >    table=??(lr_in_policy_ecmp  ), priority=150  ,
> > match=(reg8[[0..15]] == <cleared>), action=(next;)
> >  ])
> > 
> > @@ -3476,13 +3476,13 @@ sed 's/reg8\[[0..15\]] == [[0-
> > 9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lf
> >    table=??(lr_in_policy       ), priority=0    , match=(1),
> > action=(reg8[[0..15]] = <cleared>; next;)
> >    table=??(lr_in_policy       ), priority=10   , match=(ip4.src ==
> > 10.0.0.3), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] =
> > select(1, 2);)
> >    table=??(lr_in_policy       ), priority=10   , match=(ip4.src ==
> > 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] =
> > select(1, 2, 3);)
> > -  table=??(lr_in_policy       ), priority=10   , match=(ip4.src ==
> > 10.0.0.5), action=(reg0 = 172.168.0.110; reg1 = 172.168.0.100;
> > eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback
> > = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;)
> > +  table=??(lr_in_policy       ), priority=10   , match=(ip4.src ==
> > 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100;
> > eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback
> > = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;)
> >    table=??(lr_in_policy_ecmp  ), priority=0    , match=(1),
> > action=(drop;)
> > -  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1),
> > action=(reg0 = 172.168.0.101; reg1 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > -  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1),
> > action=(reg0 = 172.168.0.101; reg1 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > -  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2),
> > action=(reg0 = 172.168.0.102; reg1 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > -  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2),
> > action=(reg0 = 172.168.0.102; reg1 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > -  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3),
> > action=(reg0 = 172.168.0.103; reg1 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > +  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1),
> > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > +  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1),
> > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > +  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2),
> > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > +  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2),
> > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > +  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3),
> > action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> >    table=??(lr_in_policy_ecmp  ), priority=150  ,
> > match=(reg8[[0..15]] == <cleared>), action=(next;)
> >  ])
> > 
> > @@ -3495,11 +3495,11 @@ sed 's/reg8\[[0..15\]] = [[0-
> > 9]]*/reg8\[[0..15\]] = <cleared>/' | \
> >  sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/'
> > | ovn_strip_lflows], [0], [dnl
> >    table=??(lr_in_policy       ), priority=0    , match=(1),
> > action=(reg8[[0..15]] = <cleared>; next;)
> >    table=??(lr_in_policy       ), priority=10   , match=(ip4.src ==
> > 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] =
> > select(1, 2, 3);)
> > -  table=??(lr_in_policy       ), priority=10   , match=(ip4.src ==
> > 10.0.0.5), action=(reg0 = 172.168.0.110; reg1 = 172.168.0.100;
> > eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback
> > = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;)
> > +  table=??(lr_in_policy       ), priority=10   , match=(ip4.src ==
> > 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100;
> > eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback
> > = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;)
> >    table=??(lr_in_policy_ecmp  ), priority=0    , match=(1),
> > action=(drop;)
> > -  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1),
> > action=(reg0 = 172.168.0.101; reg1 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > -  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2),
> > action=(reg0 = 172.168.0.102; reg1 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > -  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3),
> > action=(reg0 = 172.168.0.103; reg1 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > +  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1),
> > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > +  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2),
> > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > +  table=??(lr_in_policy_ecmp  ), priority=100  ,
> > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3),
> > action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> >    table=??(lr_in_policy_ecmp  ), priority=150  ,
> > match=(reg8[[0..15]] == <cleared>), action=(next;)
> >  ])
> > 
> > @@ -3511,7 +3511,7 @@ AT_CHECK([grep "lr_in_policy" lr0flows3 |  \
> >  sed 's/reg8\[[0..15\]] = [[0-9]]*/reg8\[[0..15\]] = <cleared>/' |
> > \
> >  sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/'
> > | ovn_strip_lflows], [0], [dnl
> >    table=??(lr_in_policy       ), priority=0    , match=(1),
> > action=(reg8[[0..15]] = <cleared>; next;)
> > -  table=??(lr_in_policy       ), priority=10   , match=(ip4.src ==
> > 10.0.0.5), action=(reg0 = 172.168.0.110; reg1 = 172.168.0.100;
> > eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback
> > = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;)
> > +  table=??(lr_in_policy       ), priority=10   , match=(ip4.src ==
> > 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100;
> > eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback
> > = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;)
> >    table=??(lr_in_policy_ecmp  ), priority=0    , match=(1),
> > action=(drop;)
> >    table=??(lr_in_policy_ecmp  ), priority=150  ,
> > match=(reg8[[0..15]] == <cleared>), action=(next;)
> >  ])
> > @@ -6821,16 +6821,16 @@ ovn-sbctl dump-flows lr0 > lr0flows
> > 
> >  AT_CHECK([grep -w "lr_in_ip_routing" lr0flows | ovn_strip_lflows],
> > [0], [dnl
> >    table=??(lr_in_ip_routing   ), priority=0    , match=(1),
> > action=(drop;)
> > -  table=??(lr_in_ip_routing   ), priority=10300,
> > match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst ==
> > 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src =
> > 00:00:20:20:12:13; reg1 = 192.168.0.1; outport = "lr0-public";
> > next;)
> > +  table=??(lr_in_ip_routing   ), priority=10300,
> > match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst ==
> > 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src =
> > 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public";
> > next;)
> >    table=??(lr_in_ip_routing   ), priority=10550, match=(nd_rs ||
> > nd_ra), action=(drop;)
> > -  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst ==
> > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 =
> > ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport =
> > "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> > +  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst ==
> > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 =
> > ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport =
> > "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> >    table=??(lr_in_ip_routing   ), priority=162  , match=(reg7 == 0
> > && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1;
> > reg8[[0..15]] = 1; reg8[[16..31]] = 1; next;)
> >    table=??(lr_in_ip_routing   ), priority=324  , match=(inport ==
> > "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--;
> > reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 =
> > fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport =
> > "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;)
> >  ])
> > 
> >  AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows |
> > ovn_strip_lflows], [0], [dnl
> >    table=??(lr_in_ip_routing_ecmp), priority=0    , match=(1),
> > action=(drop;)
> > -  table=??(lr_in_ip_routing_ecmp), priority=100  ,
> > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 =
> > 192.168.0.10; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13;
> > outport = "lr0-public"; reg9[[9]] = 1; next;)
> > +  table=??(lr_in_ip_routing_ecmp), priority=100  ,
> > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 =
> > 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13;
> > outport = "lr0-public"; reg9[[9]] = 1; next;)
> >    table=??(lr_in_ip_routing_ecmp), priority=150  ,
> > match=(reg8[[0..15]] == 0), action=(next;)
> >  ])
> > 
> > @@ -6839,16 +6839,16 @@ check ovn-nbctl --wait=sb --ecmp-symmetric-
> > reply lr-route-add lr0 1.0.0.1 192.16
> >  ovn-sbctl dump-flows lr0 > lr0flows
> >  AT_CHECK([grep -w "lr_in_ip_routing" lr0flows | ovn_strip_lflows],
> > [0], [dnl
> >    table=??(lr_in_ip_routing   ), priority=0    , match=(1),
> > action=(drop;)
> > -  table=??(lr_in_ip_routing   ), priority=10300,
> > match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst ==
> > 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src =
> > 00:00:20:20:12:13; reg1 = 192.168.0.1; outport = "lr0-public";
> > next;)
> > +  table=??(lr_in_ip_routing   ), priority=10300,
> > match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst ==
> > 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src =
> > 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public";
> > next;)
> >    table=??(lr_in_ip_routing   ), priority=10550, match=(nd_rs ||
> > nd_ra), action=(drop;)
> > -  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst ==
> > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 =
> > ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport =
> > "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> > +  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst ==
> > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 =
> > ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport =
> > "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> >    table=??(lr_in_ip_routing   ), priority=162  , match=(reg7 == 0
> > && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1;
> > reg8[[0..15]] = 1; reg8[[16..31]] = select(1, 2);)
> >    table=??(lr_in_ip_routing   ), priority=324  , match=(inport ==
> > "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--;
> > reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 =
> > fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport =
> > "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;)
> >  ])
> >  AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed
> > 's/192\.168\.0\..0/192.168.0.??/' | ovn_strip_lflows], [0], [dnl
> >    table=??(lr_in_ip_routing_ecmp), priority=0    , match=(1),
> > action=(drop;)
> > -  table=??(lr_in_ip_routing_ecmp), priority=100  ,
> > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 =
> > 192.168.0.??; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13;
> > outport = "lr0-public"; reg9[[9]] = 1; next;)
> > -  table=??(lr_in_ip_routing_ecmp), priority=100  ,
> > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 =
> > 192.168.0.??; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13;
> > outport = "lr0-public"; reg9[[9]] = 1; next;)
> > +  table=??(lr_in_ip_routing_ecmp), priority=100  ,
> > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 =
> > 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13;
> > outport = "lr0-public"; reg9[[9]] = 1; next;)
> > +  table=??(lr_in_ip_routing_ecmp), priority=100  ,
> > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 =
> > 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13;
> > outport = "lr0-public"; reg9[[9]] = 1; next;)
> >    table=??(lr_in_ip_routing_ecmp), priority=150  ,
> > match=(reg8[[0..15]] == 0), action=(next;)
> >  ])
> > 
> > @@ -6868,16 +6868,16 @@ check ovn-nbctl --wait=sb --ecmp-symmetric-
> > reply lr-route-add lr0 1.0.0.1 192.16
> >  ovn-sbctl dump-flows lr0 > lr0flows
> >  AT_CHECK([grep -w "lr_in_ip_routing" lr0flows | ovn_strip_lflows],
> > [0], [dnl
> >    table=??(lr_in_ip_routing   ), priority=0    , match=(1),
> > action=(drop;)
> > -  table=??(lr_in_ip_routing   ), priority=10300,
> > match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst ==
> > 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src =
> > 00:00:20:20:12:13; reg1 = 192.168.0.1; outport = "lr0-public";
> > next;)
> > +  table=??(lr_in_ip_routing   ), priority=10300,
> > match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst ==
> > 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src =
> > 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public";
> > next;)
> >    table=??(lr_in_ip_routing   ), priority=10550, match=(nd_rs ||
> > nd_ra), action=(drop;)
> > -  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst ==
> > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 =
> > ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport =
> > "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> > +  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst ==
> > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 =
> > ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport =
> > "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> >    table=??(lr_in_ip_routing   ), priority=162  , match=(reg7 == 0
> > && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1;
> > reg8[[0..15]] = 1; reg8[[16..31]] = select(1, 2);)
> >    table=??(lr_in_ip_routing   ), priority=324  , match=(inport ==
> > "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--;
> > reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 =
> > fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport =
> > "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;)
> >  ])
> >  AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed
> > 's/192\.168\.0\..0/192.168.0.??/' | ovn_strip_lflows], [0], [dnl
> >    table=??(lr_in_ip_routing_ecmp), priority=0    , match=(1),
> > action=(drop;)
> > -  table=??(lr_in_ip_routing_ecmp), priority=100  ,
> > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 =
> > 192.168.0.??; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13;
> > outport = "lr0-public"; reg9[[9]] = 1; next;)
> > -  table=??(lr_in_ip_routing_ecmp), priority=100  ,
> > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 =
> > 192.168.0.??; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13;
> > outport = "lr0-public"; reg9[[9]] = 1; next;)
> > +  table=??(lr_in_ip_routing_ecmp), priority=100  ,
> > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 =
> > 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13;
> > outport = "lr0-public"; reg9[[9]] = 1; next;)
> > +  table=??(lr_in_ip_routing_ecmp), priority=100  ,
> > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 =
> > 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13;
> > outport = "lr0-public"; reg9[[9]] = 1; next;)
> >    table=??(lr_in_ip_routing_ecmp), priority=150  ,
> > match=(reg8[[0..15]] == 0), action=(next;)
> >  ])
> > 
> > @@ -6888,14 +6888,14 @@ check ovn-nbctl --wait=sb lr-route-add lr0
> > 1.0.0.0/24 192.168.0.10
> >  ovn-sbctl dump-flows lr0 > lr0flows
> > 
> >  AT_CHECK([grep -e "lr_in_ip_routing.*192.168.0.10" lr0flows |
> > ovn_strip_lflows], [0], [dnl
> > -  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 0
> > && ip4.dst == 1.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0;
> > reg0 = 192.168.0.10; reg1 = 192.168.0.1; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > +  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 0
> > && ip4.dst == 1.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0;
> > reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> >  ])
> > 
> >  check ovn-nbctl --wait=sb lr-route-add lr0 2.0.0.0/24 lr0-public
> > 
> >  ovn-sbctl dump-flows lr0 > lr0flows
> >  AT_CHECK([grep -e "lr_in_ip_routing.*2.0.0.0" lr0flows |
> > ovn_strip_lflows], [0], [dnl
> > -  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 0
> > && ip4.dst == 2.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0;
> > reg0 = ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13;
> > outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> > +  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 0
> > && ip4.dst == 2.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0;
> > reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13;
> > outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> >  ])
> > 
> >  check ovn-nbctl lr-route-add lr0 3.3.0.0/16 192.168.0.11
> > @@ -6960,10 +6960,10 @@ ovn-sbctl dump-flows lr0 > lr0flows
> >  AT_CHECK([grep -e "lr_in_ip_routing " lr0flows |
> > ovn_strip_lflows], [0], [dnl
> >    table=??(lr_in_ip_routing   ), priority=0    , match=(1),
> > action=(drop;)
> >    table=??(lr_in_ip_routing   ), priority=10550, match=(nd_rs ||
> > nd_ra), action=(drop;)
> > -  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 0
> > && ip4.dst == 10.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0;
> > reg0 = 192.168.0.10; reg1 = 192.168.0.1; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > +  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 0
> > && ip4.dst == 10.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0;
> > reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> >    table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 0
> > && ip4.dst == 11.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0;
> > xxreg0 = 2001:db8::10; xxreg1 = 2001:db8::1; eth.src =
> > 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1;
> > reg9[[9]] = 0; next;)
> > -  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst ==
> > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 =
> > ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport =
> > "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> > -  table=??(lr_in_ip_routing   ), priority=322  , match=(reg7 == 0
> > && ip6.dst == 2001:db8:1::/64), action=(ip.ttl--; reg8[[0..15]] =
> > 0; reg0 = 192.168.0.20; reg1 = 192.168.0.1; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> > +  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst ==
> > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 =
> > ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport =
> > "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
> > +  table=??(lr_in_ip_routing   ), priority=322  , match=(reg7 == 0
> > && ip6.dst == 2001:db8:1::/64), action=(ip.ttl--; reg8[[0..15]] =
> > 0; reg0 = 192.168.0.20; reg5 = 192.168.0.1; eth.src =
> > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
> > reg9[[9]] = 1; next;)
> >    table=??(lr_in_ip_routing   ), priority=322  , match=(reg7 == 0
> > && ip6.dst == 2001:db8:2::/64), action=(ip.ttl--; reg8[[0..15]] =
> > 0; xxreg0 = 2001:db8::20; xxreg1 = 2001:db8::1; eth.src =
> > 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1;
> > reg9[[9]] = 0; next;)
> >    table=??(lr_in_ip_routing   ), priority=324  , match=(inport ==
> > "lr0-private" && ip6.dst == fe80::/64), action=(ip.ttl--;
> > reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 =
> > fe80::200:20ff:fe20:1214; eth.src = 00:00:20:20:12:14; outport =
> > "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;)
> >    table=??(lr_in_ip_routing   ), priority=324  , match=(inport ==
> > "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--;
> > reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 =
> > fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport =
> > "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;)
> > @@ -6980,7 +6980,7 @@ AT_CHECK([grep -e "lr_in_arp_resolve"
> > lr0flows | ovn_strip_lflows], [0], [dnl
> >  AT_CHECK([grep -e "lr_in_arp_request" lr0flows |
> > ovn_strip_lflows], [0], [dnl
> >    table=??(lr_in_arp_request  ), priority=0    , match=(1),
> > action=(output;)
> >    table=??(lr_in_arp_request  ), priority=100  , match=(eth.dst ==
> > 00:00:00:00:00:00 && reg9[[9]] == 0), action=(nd_ns { nd.target =
> > xxreg0; output; }; output;)
> > -  table=??(lr_in_arp_request  ), priority=100  , match=(eth.dst ==
> > 00:00:00:00:00:00 && reg9[[9]] == 1), action=(arp { eth.dst =
> > ff:ff:ff:ff:ff:ff; arp.spa = reg1; arp.tpa = reg0; arp.op = 1;
> > output; }; output;)
> > +  table=??(lr_in_arp_request  ), priority=100  , match=(eth.dst ==
> > 00:00:00:00:00:00 && reg9[[9]] == 1), action=(arp { eth.dst =
> > ff:ff:ff:ff:ff:ff; arp.spa = reg5; arp.tpa = reg0; arp.op = 1;
> > output; }; output;)
> >    table=??(lr_in_arp_request  ), priority=200  , match=(eth.dst ==
> > 00:00:00:00:00:00 && reg9[[9]] == 0 && xxreg0 == 2001:db8::10),
> > action=(nd_ns { eth.dst = 33:33:ff:00:00:10; ip6.dst =
> > ff02::1:ff00:10; nd.target = 2001:db8::10; output; }; output;)
> >    table=??(lr_in_arp_request  ), priority=200  , match=(eth.dst ==
> > 00:00:00:00:00:00 && reg9[[9]] == 0 && xxreg0 == 2001:db8::20),
> > action=(nd_ns { eth.dst = 33:33:ff:00:00:20; ip6.dst =
> > ff02::1:ff00:20; nd.target = 2001:db8::20; output; }; output;)
> >  ])
> > @@ -7406,13 +7406,13 @@ AT_CHECK([grep "lr_in_ip_routing_pre"
> > lr0flows | ovn_strip_lflows], [0], [dnl
> >  grep -e "(lr_in_ip_routing   ).*outport" lr0flows
> > 
> >  AT_CHECK([grep -e "(lr_in_ip_routing   ).*outport" lr0flows |
> > ovn_strip_lflows], [0], [dnl
> > -  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 1
> > && ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0;
> > reg0 = 192.168.1.10; reg1 = 192.168.1.1; eth.src =
> > 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; reg9[[9]]
> > = 1; next;)
> > -  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst ==
> > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 =
> > ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport =
> > "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
> > -  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst ==
> > 192.168.1.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 =
> > ip4.dst; reg1 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport =
> > "lrp1"; flags.loopback = 1; reg9[[9]] = 1; next;)
> > -  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst ==
> > 192.168.2.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 =
> > ip4.dst; reg1 = 192.168.2.1; eth.src = 00:00:00:00:02:01; outport =
> > "lrp2"; flags.loopback = 1; reg9[[9]] = 1; next;)
> > -  table=??(lr_in_ip_routing   ), priority=162  , match=(reg7 == 2
> > && ip4.dst == 1.1.1.1/32), action=(ip.ttl--; reg8[[0..15]] = 0;
> > reg0 = 192.168.0.20; reg1 = 192.168.0.1; eth.src =
> > 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]]
> > = 1; next;)
> > -  table=??(lr_in_ip_routing   ), priority=2    , match=(reg7 == 0
> > && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0
> > = 192.168.0.10; reg1 = 192.168.0.1; eth.src = 00:00:00:00:00:01;
> > outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
> > -  table=??(lr_in_ip_routing   ), priority=2    , match=(reg7 == 2
> > && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0
> > = 192.168.0.10; reg1 = 192.168.0.1; eth.src = 00:00:00:00:00:01;
> > outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
> > +  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 1
> > && ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0;
> > reg0 = 192.168.1.10; reg5 = 192.168.1.1; eth.src =
> > 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; reg9[[9]]
> > = 1; next;)
> > +  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst ==
> > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 =
> > ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport =
> > "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
> > +  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst ==
> > 192.168.1.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 =
> > ip4.dst; reg5 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport =
> > "lrp1"; flags.loopback = 1; reg9[[9]] = 1; next;)
> > +  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst ==
> > 192.168.2.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 =
> > ip4.dst; reg5 = 192.168.2.1; eth.src = 00:00:00:00:02:01; outport =
> > "lrp2"; flags.loopback = 1; reg9[[9]] = 1; next;)
> > +  table=??(lr_in_ip_routing   ), priority=162  , match=(reg7 == 2
> > && ip4.dst == 1.1.1.1/32), action=(ip.ttl--; reg8[[0..15]] = 0;
> > reg0 = 192.168.0.20; reg5 = 192.168.0.1; eth.src =
> > 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]]
> > = 1; next;)
> > +  table=??(lr_in_ip_routing   ), priority=2    , match=(reg7 == 0
> > && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0
> > = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01;
> > outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
> > +  table=??(lr_in_ip_routing   ), priority=2    , match=(reg7 == 2
> > && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0
> > = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01;
> > outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
> >    table=??(lr_in_ip_routing   ), priority=324  , match=(inport ==
> > "lrp0" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] =
> > 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:ff:fe00:1; eth.src =
> > 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]]
> > = 0; next;)
> >    table=??(lr_in_ip_routing   ), priority=324  , match=(inport ==
> > "lrp1" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] =
> > 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:ff:fe00:101; eth.src =
> > 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; reg9[[9]]
> > = 0; next;)
> >    table=??(lr_in_ip_routing   ), priority=324  , match=(inport ==
> > "lrp2" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] =
> > 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:ff:fe00:201; eth.src =
> > 00:00:00:00:02:01; outport = "lrp2"; flags.loopback = 1; reg9[[9]]
> > = 0; next;)
> > @@ -11058,7 +11058,7 @@ AT_CAPTURE_FILE([R1flows])
> > 
> >  AT_CHECK([grep "lr_in_gw_redirect" R1flows | sed
> > s'/table=../table=??/' |sort], [0], [dnl
> >    table=??(lr_in_gw_redirect  ), priority=0    , match=(1),
> > action=(next;)
> > -  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src ==
> > 10.0.0.3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")),
> > action=(eth.src = 30:54:00:00:00:03; reg1 = 172.16.0.110; next;)
> > +  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src ==
> > 10.0.0.3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")),
> > action=(eth.src = 30:54:00:00:00:03; reg5 = 172.16.0.110; next;)
> >    table=??(lr_in_gw_redirect  ), priority=100  , match=(ip6.src ==
> > 1000::3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")),
> > action=(eth.src = 40:54:00:00:00:03; xxreg1 = 3000::c; next;)
> >    table=??(lr_in_gw_redirect  ), priority=50   , match=(outport ==
> > "R1-PUB"), action=(outport = "cr-R1-PUB"; next;)
> >  ])
> > @@ -11072,7 +11072,7 @@ ovn-sbctl dump-flows R1 > R1flows
> >  AT_CAPTURE_FILE([R1flows])
> >  AT_CHECK([grep "lr_in_gw_redirect" R1flows |sed
> > s'/table=../table=??/' |sort], [0], [dnl
> >    table=??(lr_in_gw_redirect  ), priority=0    , match=(1),
> > action=(next;)
> > -  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src ==
> > 10.0.0.3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")),
> > action=(eth.src = 30:54:00:00:00:03; reg1 = 172.16.0.110; next;)
> > +  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src ==
> > 10.0.0.3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")),
> > action=(eth.src = 30:54:00:00:00:03; reg5 = 172.16.0.110; next;)
> >    table=??(lr_in_gw_redirect  ), priority=100  , match=(ip6.src ==
> > 1000::3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")),
> > action=(eth.src = 40:54:00:00:00:03; xxreg1 = 3000::c; next;)
> >    table=??(lr_in_gw_redirect  ), priority=200  , match=(ip4 &&
> > ((ip4.src == 10.0.0.2 && tcp.src == 50001) || (ip4.src == 10.0.0.3
> > && tcp.src == 50001) || (ip4.src == 10.0.0.4 && tcp.src == 50001))
> > && outport == "R1-PUB"), action=(outport = "cr-R1-PUB"; next;)
> >    table=??(lr_in_gw_redirect  ), priority=200  , match=(ip6 &&
> > ((ip6.src == 1000::3 && tcp.src == 8080)) && outport == "R1-PUB"),
> > action=(outport = "cr-R1-PUB"; next;)
> > @@ -13523,7 +13523,7 @@ AT_CHECK([grep "lr_in_arp_resolve" lr0flows
> > | ovn_strip_lflows], [0], [dnl
> > 
> >  AT_CHECK([grep "lr_in_gw_redirect" lr0flows | ovn_strip_lflows],
> > [0], [dnl
> >    table=??(lr_in_gw_redirect  ), priority=0    , match=(1),
> > action=(next;)
> > -  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src ==
> > 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-
> > port1")), action=(eth.src = 30:54:00:00:00:03; reg1 =
> > 172.168.0.110; next;)
> > +  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src ==
> > 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-
> > port1")), action=(eth.src = 30:54:00:00:00:03; reg5 =
> > 172.168.0.110; next;)
> >    table=??(lr_in_gw_redirect  ), priority=50   , match=(outport ==
> > "lr0-public"), action=(outport = "cr-lr0-public"; next;)
> >  ])
> > 
> > @@ -13575,7 +13575,7 @@ AT_CHECK([grep -e "172.168.0.110" -e
> > "172.168.0.120" -e "10.0.0.3" -e "20.0.0.3"
> >    table=??(lr_in_arp_resolve  ), priority=150  , match=(inport ==
> > "lr0-public" && outport == "lr0-public" && ip4.dst ==
> > 172.168.0.120), action=(drop;)
> >    table=??(lr_in_dnat         ), priority=100  , match=(ip &&
> > ip4.dst == 172.168.0.110 && inport == "lr0-public"),
> > action=(ct_dnat(10.0.0.3);)
> >    table=??(lr_in_dnat         ), priority=100  , match=(ip &&
> > ip4.dst == 172.168.0.120 && inport == "lr0-public" &&
> > is_chassis_resident("cr-lr0-public")), action=(ct_dnat(20.0.0.3);)
> > -  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src ==
> > 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-
> > port1")), action=(eth.src = 30:54:00:00:00:03; reg1 =
> > 172.168.0.110; next;)
> > +  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src ==
> > 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-
> > port1")), action=(eth.src = 30:54:00:00:00:03; reg5 =
> > 172.168.0.110; next;)
> >    table=??(lr_in_ip_input     ), priority=90   , match=(arp.op ==
> > 1 && arp.tpa == 172.168.0.110), action=(eth.dst = eth.src; eth.src
> > = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha;
> > arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = inport;
> > flags.loopback = 1; output;)
> >    table=??(lr_in_ip_input     ), priority=90   , match=(arp.op ==
> > 1 && arp.tpa == 172.168.0.120), action=(eth.dst = eth.src; eth.src
> > = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha;
> > arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = inport;
> > flags.loopback = 1; output;)
> >    table=??(lr_in_ip_input     ), priority=91   , match=(inport ==
> > "lr0-public" && arp.op == 1 && arp.tpa == 172.168.0.110),
> > action=(drop;)
> > @@ -13794,7 +13794,7 @@ AT_CHECK([grep -e "172.168.0.110" -e
> > "172.168.0.120" -e "10.0.0.3" -e "20.0.0.3"
> >    table=??(lr_in_arp_resolve  ), priority=150  , match=(inport ==
> > "lr0-public" && outport == "lr0-public" && ip4.dst ==
> > 172.168.0.120), action=(drop;)
> >    table=??(lr_in_dnat         ), priority=100  , match=(ip &&
> > ip4.dst == 172.168.0.110 && inport == "lr0-public"),
> > action=(ct_dnat(10.0.0.3);)
> >    table=??(lr_in_dnat         ), priority=100  , match=(ip &&
> > ip4.dst == 172.168.0.120 && inport == "lr0-public" &&
> > is_chassis_resident("cr-lr0-public")), action=(ct_dnat(20.0.0.3);)
> > -  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src ==
> > 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-
> > port1")), action=(eth.src = 30:54:00:00:00:03; reg1 =
> > 172.168.0.110; next;)
> > +  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src ==
> > 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-
> > port1")), action=(eth.src = 30:54:00:00:00:03; reg5 =
> > 172.168.0.110; next;)
> >    table=??(lr_in_ip_input     ), priority=90   , match=(arp.op ==
> > 1 && arp.tpa == 172.168.0.110), action=(eth.dst = eth.src; eth.src
> > = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha;
> > arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = inport;
> > flags.loopback = 1; output;)
> >    table=??(lr_in_ip_input     ), priority=90   , match=(arp.op ==
> > 1 && arp.tpa == 172.168.0.120), action=(eth.dst = eth.src; eth.src
> > = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha;
> > arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = inport;
> > flags.loopback = 1; output;)
> >    table=??(lr_in_ip_input     ), priority=91   , match=(inport ==
> > "lr0-public" && arp.op == 1 && arp.tpa == 172.168.0.110),
> > action=(drop;)
> > @@ -13855,7 +13855,7 @@ AT_CHECK([grep -e "172.168.0.110" -e
> > "172.168.0.120" -e "10.0.0.3" -e "20.0.0.3"
> >    table=??(lr_in_arp_resolve  ), priority=150  , match=(inport ==
> > "lr0-public" && outport == "lr0-public" && ip4.dst ==
> > 172.168.0.120), action=(drop;)
> >    table=??(lr_in_dnat         ), priority=100  , match=(ip &&
> > ip4.dst == 172.168.0.110 && inport == "lr0-public"),
> > action=(ct_dnat(10.0.0.3);)
> >    table=??(lr_in_dnat         ), priority=100  , match=(ip &&
> > ip4.dst == 172.168.0.120 && inport == "lr0-public" &&
> > is_chassis_resident("cr-lr0-public")), action=(ct_dnat(20.0.0.3);)
> > -  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src ==
> > 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-
> > port1")), action=(eth.src = 30:54:00:00:00:03; reg1 =
> > 172.168.0.110; next;)
> > +  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src ==
> > 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-
> > port1")), action=(eth.src = 30:54:00:00:00:03; reg5 =
> > 172.168.0.110; next;)
> >    table=??(lr_in_ip_input     ), priority=90   , match=(arp.op ==
> > 1 && arp.tpa == 172.168.0.110), action=(eth.dst = eth.src; eth.src
> > = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha;
> > arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = inport;
> > flags.loopback = 1; output;)
> >    table=??(lr_in_ip_input     ), priority=90   , match=(arp.op ==
> > 1 && arp.tpa == 172.168.0.120), action=(eth.dst = eth.src; eth.src
> > = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha;
> > arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = inport;
> > flags.loopback = 1; output;)
> >    table=??(lr_in_ip_input     ), priority=91   , match=(inport ==
> > "lr0-public" && arp.op == 1 && arp.tpa == 172.168.0.110),
> > action=(drop;)
> > diff --git a/tests/ovn.at b/tests/ovn.at
> > index b94cddf0f..a29ec7114 100644
> > --- a/tests/ovn.at
> > +++ b/tests/ovn.at
> > @@ -22134,7 +22134,7 @@ check ovn-nbctl --wait=hv sync
> > 
> >  # verify the traffic from virtual port is discarded if the port is
> > not claimed
> >  AT_CHECK([grep lr_in_gw_redirect lr0-flows2 | grep "ip4.src ==
> > 10.0.0.10" | ovn_strip_lflows], [0], [dnl
> > -  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src ==
> > 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("sw0-
> > vir")), action=(eth.src = 10:54:00:00:00:10; reg1 = 172.168.0.50;
> > next;)
> > +  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src ==
> > 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("sw0-
> > vir")), action=(eth.src = 10:54:00:00:00:10; reg5 = 172.168.0.50;
> > next;)
> >    table=??(lr_in_gw_redirect  ), priority=80   , match=(ip4.src ==
> > 10.0.0.10 && outport == "lr0-public"), action=(drop;)
> >  ])
> > 
> > --
> > 2.43.0
> > 
> > _______________________________________________
> > dev mailing list
> > dev@openvswitch.org
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
diff mbox series

Patch

diff --git a/northd/northd.c b/northd/northd.c
index 7a902085d..436e42248 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -188,7 +188,7 @@  BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 << 2));
 /* Registers used for routing. */
 #define REG_NEXT_HOP_IPV4 "reg0"
 #define REG_NEXT_HOP_IPV6 "xxreg0"
-#define REG_SRC_IPV4 "reg1"
+#define REG_SRC_IPV4 "reg5"
 #define REG_SRC_IPV6 "xxreg1"
 #define REG_DHCP_RELAY_DIP_IPV4 "reg2"
 #define REG_ROUTE_TABLE_ID "reg7"
@@ -259,8 +259,8 @@  BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 << 2));
  * |     |      NEXT_HOP_IPV4        | R |                 |   |                                    |
  * |     |      (>= IP_INPUT)        | E | INPORT_ETH_ADDR | X |                                    |
  * +-----+---------------------------+ G |   (< IP_INPUT)  | X |                                    |
- * | R1  |   SRC_IPV4 for ARP-REQ    | 0 |                 | R |                                    |
- * |     |      (>= IP_INPUT)        |   |                 | E |     NEXT_HOP_IPV6 (>= DEFRAG )     |
+ * | R1  |        UNUSED             | 0 |                 | R |                                    |
+ * |     |                           |   |                 | E |     NEXT_HOP_IPV6 (>= DEFRAG )     |
  * +-----+---------------------------+---+-----------------+ G |                                    |
  * | R2     REG_DHCP_RELAY_DIP_IPV4  | X |                 | 0 |                                    |
  * |     |                           | R |                 |   |                                    |
@@ -271,8 +271,8 @@  BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 << 2));
  * | R4  |  REG_LB_AFF_BACKEND_IP4   | X |                 |   |                                    |
  * |     |                           | R |                 |   |                                    |
  * +-----+---------------------------+ E |     UNUSED      | X |                                    |
- * | R5  |        UNUSED             | G |                 | X |                                    |
- * |     |                           | 2 |                 | R |        LB_L3_AFF_BACKEND_IP6       |
+ * | R5  |  SRC_IPV4 for ARP-REQ     | G |                 | X |                                    |
+ * |     |      (>= IP_INPUT)        | 2 |                 | R |        LB_L3_AFF_BACKEND_IP6       |
  * +-----+---------------------------+---+-----------------+ E |           (<= IN_DNAT)             |
  * | R6  |        UNUSED             | X |                 | G |                                    |
  * |     |                           | R |                 | 1 |                                    |
@@ -11602,9 +11602,10 @@  add_ecmp_symmetric_reply_flows(struct lflow_table *lflows,
                   ds_cstr(route_match));
     ds_clear(&actions);
     ds_put_format(&actions, "ip.ttl--; flags.loopback = 1; "
-                  "eth.src = %s; %sreg1 = %s; outport = %s; next;",
+                  "eth.src = %s; %s = %s; outport = %s; next;",
                   out_port->lrp_networks.ea_s,
-                  IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "" : "xx",
+                  IN6_IS_ADDR_V4MAPPED(&route->prefix) ?
+                      REG_SRC_IPV4 : REG_SRC_IPV6,
                   port_ip, out_port->json_key);
     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_ROUTING, 10300,
                            ds_cstr(&match), ds_cstr(&actions),
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index 6ec6648dd..4335baeec 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -3442,8 +3442,8 @@  AT_CHECK([grep "lr_in_policy" lr0flows3 | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_policy       ), priority=0    , match=(1), action=(reg8[[0..15]] = 0; next;)
   table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.3), action=(reg8[[0..15]] = 1; reg8[[16..31]] = select(1, 2);)
   table=??(lr_in_policy_ecmp  ), priority=0    , match=(1), action=(drop;)
-  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
-  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
   table=??(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == 0), action=(next;)
 ])
 
@@ -3458,11 +3458,11 @@  sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lf
   table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.3), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2);)
   table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2, 3);)
   table=??(lr_in_policy_ecmp  ), priority=0    , match=(1), action=(drop;)
-  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
-  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
-  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
-  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
-  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
   table=??(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == <cleared>), action=(next;)
 ])
 
@@ -3476,13 +3476,13 @@  sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lf
   table=??(lr_in_policy       ), priority=0    , match=(1), action=(reg8[[0..15]] = <cleared>; next;)
   table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.3), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2);)
   table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2, 3);)
-  table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;)
+  table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;)
   table=??(lr_in_policy_ecmp  ), priority=0    , match=(1), action=(drop;)
-  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
-  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
-  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
-  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
-  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
   table=??(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == <cleared>), action=(next;)
 ])
 
@@ -3495,11 +3495,11 @@  sed 's/reg8\[[0..15\]] = [[0-9]]*/reg8\[[0..15\]] = <cleared>/' | \
 sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_policy       ), priority=0    , match=(1), action=(reg8[[0..15]] = <cleared>; next;)
   table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2, 3);)
-  table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;)
+  table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;)
   table=??(lr_in_policy_ecmp  ), priority=0    , match=(1), action=(drop;)
-  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
-  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
-  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_policy_ecmp  ), priority=100  , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
   table=??(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == <cleared>), action=(next;)
 ])
 
@@ -3511,7 +3511,7 @@  AT_CHECK([grep "lr_in_policy" lr0flows3 |  \
 sed 's/reg8\[[0..15\]] = [[0-9]]*/reg8\[[0..15\]] = <cleared>/' | \
 sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_policy       ), priority=0    , match=(1), action=(reg8[[0..15]] = <cleared>; next;)
-  table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg1 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;)
+  table=??(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;)
   table=??(lr_in_policy_ecmp  ), priority=0    , match=(1), action=(drop;)
   table=??(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == <cleared>), action=(next;)
 ])
@@ -6821,16 +6821,16 @@  ovn-sbctl dump-flows lr0 > lr0flows
 
 AT_CHECK([grep -w "lr_in_ip_routing" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_ip_routing   ), priority=0    , match=(1), action=(drop;)
-  table=??(lr_in_ip_routing   ), priority=10300, match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = 00:00:20:20:12:13; reg1 = 192.168.0.1; outport = "lr0-public"; next;)
+  table=??(lr_in_ip_routing   ), priority=10300, match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public"; next;)
   table=??(lr_in_ip_routing   ), priority=10550, match=(nd_rs || nd_ra), action=(drop;)
-  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
   table=??(lr_in_ip_routing   ), priority=162  , match=(reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; reg8[[0..15]] = 1; reg8[[16..31]] = 1; next;)
   table=??(lr_in_ip_routing   ), priority=324  , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;)
 ])
 
 AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_ip_routing_ecmp), priority=0    , match=(1), action=(drop;)
-  table=??(lr_in_ip_routing_ecmp), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.10; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;)
+  table=??(lr_in_ip_routing_ecmp), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;)
   table=??(lr_in_ip_routing_ecmp), priority=150  , match=(reg8[[0..15]] == 0), action=(next;)
 ])
 
@@ -6839,16 +6839,16 @@  check ovn-nbctl --wait=sb --ecmp-symmetric-reply lr-route-add lr0 1.0.0.1 192.16
 ovn-sbctl dump-flows lr0 > lr0flows
 AT_CHECK([grep -w "lr_in_ip_routing" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_ip_routing   ), priority=0    , match=(1), action=(drop;)
-  table=??(lr_in_ip_routing   ), priority=10300, match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = 00:00:20:20:12:13; reg1 = 192.168.0.1; outport = "lr0-public"; next;)
+  table=??(lr_in_ip_routing   ), priority=10300, match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public"; next;)
   table=??(lr_in_ip_routing   ), priority=10550, match=(nd_rs || nd_ra), action=(drop;)
-  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
   table=??(lr_in_ip_routing   ), priority=162  , match=(reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; reg8[[0..15]] = 1; reg8[[16..31]] = select(1, 2);)
   table=??(lr_in_ip_routing   ), priority=324  , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;)
 ])
 AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed 's/192\.168\.0\..0/192.168.0.??/' | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_ip_routing_ecmp), priority=0    , match=(1), action=(drop;)
-  table=??(lr_in_ip_routing_ecmp), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;)
-  table=??(lr_in_ip_routing_ecmp), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 192.168.0.??; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;)
+  table=??(lr_in_ip_routing_ecmp), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;)
+  table=??(lr_in_ip_routing_ecmp), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;)
   table=??(lr_in_ip_routing_ecmp), priority=150  , match=(reg8[[0..15]] == 0), action=(next;)
 ])
 
@@ -6868,16 +6868,16 @@  check ovn-nbctl --wait=sb --ecmp-symmetric-reply lr-route-add lr0 1.0.0.1 192.16
 ovn-sbctl dump-flows lr0 > lr0flows
 AT_CHECK([grep -w "lr_in_ip_routing" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_ip_routing   ), priority=0    , match=(1), action=(drop;)
-  table=??(lr_in_ip_routing   ), priority=10300, match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = 00:00:20:20:12:13; reg1 = 192.168.0.1; outport = "lr0-public"; next;)
+  table=??(lr_in_ip_routing   ), priority=10300, match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public"; next;)
   table=??(lr_in_ip_routing   ), priority=10550, match=(nd_rs || nd_ra), action=(drop;)
-  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
   table=??(lr_in_ip_routing   ), priority=162  , match=(reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; reg8[[0..15]] = 1; reg8[[16..31]] = select(1, 2);)
   table=??(lr_in_ip_routing   ), priority=324  , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;)
 ])
 AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed 's/192\.168\.0\..0/192.168.0.??/' | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_ip_routing_ecmp), priority=0    , match=(1), action=(drop;)
-  table=??(lr_in_ip_routing_ecmp), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;)
-  table=??(lr_in_ip_routing_ecmp), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 192.168.0.??; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;)
+  table=??(lr_in_ip_routing_ecmp), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;)
+  table=??(lr_in_ip_routing_ecmp), priority=100  , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;)
   table=??(lr_in_ip_routing_ecmp), priority=150  , match=(reg8[[0..15]] == 0), action=(next;)
 ])
 
@@ -6888,14 +6888,14 @@  check ovn-nbctl --wait=sb lr-route-add lr0 1.0.0.0/24 192.168.0.10
 ovn-sbctl dump-flows lr0 > lr0flows
 
 AT_CHECK([grep -e "lr_in_ip_routing.*192.168.0.10" lr0flows | ovn_strip_lflows], [0], [dnl
-  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 0 && ip4.dst == 1.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 0 && ip4.dst == 1.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
 ])
 
 check ovn-nbctl --wait=sb lr-route-add lr0 2.0.0.0/24 lr0-public
 
 ovn-sbctl dump-flows lr0 > lr0flows
 AT_CHECK([grep -e "lr_in_ip_routing.*2.0.0.0" lr0flows | ovn_strip_lflows], [0], [dnl
-  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 0 && ip4.dst == 2.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 0 && ip4.dst == 2.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
 ])
 
 check ovn-nbctl lr-route-add lr0 3.3.0.0/16 192.168.0.11
@@ -6960,10 +6960,10 @@  ovn-sbctl dump-flows lr0 > lr0flows
 AT_CHECK([grep -e "lr_in_ip_routing " lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_ip_routing   ), priority=0    , match=(1), action=(drop;)
   table=??(lr_in_ip_routing   ), priority=10550, match=(nd_rs || nd_ra), action=(drop;)
-  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 0 && ip4.dst == 10.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 0 && ip4.dst == 10.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
   table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 0 && ip4.dst == 11.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = 2001:db8::10; xxreg1 = 2001:db8::1; eth.src = 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;)
-  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
-  table=??(lr_in_ip_routing   ), priority=322  , match=(reg7 == 0 && ip6.dst == 2001:db8:1::/64), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.20; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_ip_routing   ), priority=322  , match=(reg7 == 0 && ip6.dst == 2001:db8:1::/64), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.20; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
   table=??(lr_in_ip_routing   ), priority=322  , match=(reg7 == 0 && ip6.dst == 2001:db8:2::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = 2001:db8::20; xxreg1 = 2001:db8::1; eth.src = 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;)
   table=??(lr_in_ip_routing   ), priority=324  , match=(inport == "lr0-private" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1214; eth.src = 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;)
   table=??(lr_in_ip_routing   ), priority=324  , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;)
@@ -6980,7 +6980,7 @@  AT_CHECK([grep -e "lr_in_arp_resolve" lr0flows | ovn_strip_lflows], [0], [dnl
 AT_CHECK([grep -e "lr_in_arp_request" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_arp_request  ), priority=0    , match=(1), action=(output;)
   table=??(lr_in_arp_request  ), priority=100  , match=(eth.dst == 00:00:00:00:00:00 && reg9[[9]] == 0), action=(nd_ns { nd.target = xxreg0; output; }; output;)
-  table=??(lr_in_arp_request  ), priority=100  , match=(eth.dst == 00:00:00:00:00:00 && reg9[[9]] == 1), action=(arp { eth.dst = ff:ff:ff:ff:ff:ff; arp.spa = reg1; arp.tpa = reg0; arp.op = 1; output; }; output;)
+  table=??(lr_in_arp_request  ), priority=100  , match=(eth.dst == 00:00:00:00:00:00 && reg9[[9]] == 1), action=(arp { eth.dst = ff:ff:ff:ff:ff:ff; arp.spa = reg5; arp.tpa = reg0; arp.op = 1; output; }; output;)
   table=??(lr_in_arp_request  ), priority=200  , match=(eth.dst == 00:00:00:00:00:00 && reg9[[9]] == 0 && xxreg0 == 2001:db8::10), action=(nd_ns { eth.dst = 33:33:ff:00:00:10; ip6.dst = ff02::1:ff00:10; nd.target = 2001:db8::10; output; }; output;)
   table=??(lr_in_arp_request  ), priority=200  , match=(eth.dst == 00:00:00:00:00:00 && reg9[[9]] == 0 && xxreg0 == 2001:db8::20), action=(nd_ns { eth.dst = 33:33:ff:00:00:20; ip6.dst = ff02::1:ff00:20; nd.target = 2001:db8::20; output; }; output;)
 ])
@@ -7406,13 +7406,13 @@  AT_CHECK([grep "lr_in_ip_routing_pre" lr0flows | ovn_strip_lflows], [0], [dnl
 grep -e "(lr_in_ip_routing   ).*outport" lr0flows
 
 AT_CHECK([grep -e "(lr_in_ip_routing   ).*outport" lr0flows | ovn_strip_lflows], [0], [dnl
-  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 1 && ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.1.10; reg1 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; reg9[[9]] = 1; next;)
-  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
-  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.1.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; reg9[[9]] = 1; next;)
-  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.2.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.2.1; eth.src = 00:00:00:00:02:01; outport = "lrp2"; flags.loopback = 1; reg9[[9]] = 1; next;)
-  table=??(lr_in_ip_routing   ), priority=162  , match=(reg7 == 2 && ip4.dst == 1.1.1.1/32), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.20; reg1 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
-  table=??(lr_in_ip_routing   ), priority=2    , match=(reg7 == 0 && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg1 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
-  table=??(lr_in_ip_routing   ), priority=2    , match=(reg7 == 2 && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg1 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_ip_routing   ), priority=122  , match=(reg7 == 1 && ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.1.10; reg5 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.1.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_ip_routing   ), priority=124  , match=(ip4.dst == 192.168.2.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.2.1; eth.src = 00:00:00:00:02:01; outport = "lrp2"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_ip_routing   ), priority=162  , match=(reg7 == 2 && ip4.dst == 1.1.1.1/32), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.20; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_ip_routing   ), priority=2    , match=(reg7 == 0 && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
+  table=??(lr_in_ip_routing   ), priority=2    , match=(reg7 == 2 && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;)
   table=??(lr_in_ip_routing   ), priority=324  , match=(inport == "lrp0" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:ff:fe00:1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 0; next;)
   table=??(lr_in_ip_routing   ), priority=324  , match=(inport == "lrp1" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:ff:fe00:101; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; reg9[[9]] = 0; next;)
   table=??(lr_in_ip_routing   ), priority=324  , match=(inport == "lrp2" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:ff:fe00:201; eth.src = 00:00:00:00:02:01; outport = "lrp2"; flags.loopback = 1; reg9[[9]] = 0; next;)
@@ -11058,7 +11058,7 @@  AT_CAPTURE_FILE([R1flows])
 
 AT_CHECK([grep "lr_in_gw_redirect" R1flows | sed s'/table=../table=??/' |sort], [0], [dnl
   table=??(lr_in_gw_redirect  ), priority=0    , match=(1), action=(next;)
-  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")), action=(eth.src = 30:54:00:00:00:03; reg1 = 172.16.0.110; next;)
+  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")), action=(eth.src = 30:54:00:00:00:03; reg5 = 172.16.0.110; next;)
   table=??(lr_in_gw_redirect  ), priority=100  , match=(ip6.src == 1000::3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")), action=(eth.src = 40:54:00:00:00:03; xxreg1 = 3000::c; next;)
   table=??(lr_in_gw_redirect  ), priority=50   , match=(outport == "R1-PUB"), action=(outport = "cr-R1-PUB"; next;)
 ])
@@ -11072,7 +11072,7 @@  ovn-sbctl dump-flows R1 > R1flows
 AT_CAPTURE_FILE([R1flows])
 AT_CHECK([grep "lr_in_gw_redirect" R1flows |sed s'/table=../table=??/' |sort], [0], [dnl
   table=??(lr_in_gw_redirect  ), priority=0    , match=(1), action=(next;)
-  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")), action=(eth.src = 30:54:00:00:00:03; reg1 = 172.16.0.110; next;)
+  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")), action=(eth.src = 30:54:00:00:00:03; reg5 = 172.16.0.110; next;)
   table=??(lr_in_gw_redirect  ), priority=100  , match=(ip6.src == 1000::3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")), action=(eth.src = 40:54:00:00:00:03; xxreg1 = 3000::c; next;)
   table=??(lr_in_gw_redirect  ), priority=200  , match=(ip4 && ((ip4.src == 10.0.0.2 && tcp.src == 50001) || (ip4.src == 10.0.0.3 && tcp.src == 50001) || (ip4.src == 10.0.0.4 && tcp.src == 50001)) && outport == "R1-PUB"), action=(outport = "cr-R1-PUB"; next;)
   table=??(lr_in_gw_redirect  ), priority=200  , match=(ip6 && ((ip6.src == 1000::3 && tcp.src == 8080)) && outport == "R1-PUB"), action=(outport = "cr-R1-PUB"; next;)
@@ -13523,7 +13523,7 @@  AT_CHECK([grep "lr_in_arp_resolve" lr0flows | ovn_strip_lflows], [0], [dnl
 
 AT_CHECK([grep "lr_in_gw_redirect" lr0flows | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_gw_redirect  ), priority=0    , match=(1), action=(next;)
-  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-port1")), action=(eth.src = 30:54:00:00:00:03; reg1 = 172.168.0.110; next;)
+  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-port1")), action=(eth.src = 30:54:00:00:00:03; reg5 = 172.168.0.110; next;)
   table=??(lr_in_gw_redirect  ), priority=50   , match=(outport == "lr0-public"), action=(outport = "cr-lr0-public"; next;)
 ])
 
@@ -13575,7 +13575,7 @@  AT_CHECK([grep -e "172.168.0.110" -e "172.168.0.120" -e "10.0.0.3" -e "20.0.0.3"
   table=??(lr_in_arp_resolve  ), priority=150  , match=(inport == "lr0-public" && outport == "lr0-public" && ip4.dst == 172.168.0.120), action=(drop;)
   table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 172.168.0.110 && inport == "lr0-public"), action=(ct_dnat(10.0.0.3);)
   table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 172.168.0.120 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_dnat(20.0.0.3);)
-  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-port1")), action=(eth.src = 30:54:00:00:00:03; reg1 = 172.168.0.110; next;)
+  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-port1")), action=(eth.src = 30:54:00:00:00:03; reg5 = 172.168.0.110; next;)
   table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa == 172.168.0.110), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = inport; flags.loopback = 1; output;)
   table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa == 172.168.0.120), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = inport; flags.loopback = 1; output;)
   table=??(lr_in_ip_input     ), priority=91   , match=(inport == "lr0-public" && arp.op == 1 && arp.tpa == 172.168.0.110), action=(drop;)
@@ -13794,7 +13794,7 @@  AT_CHECK([grep -e "172.168.0.110" -e "172.168.0.120" -e "10.0.0.3" -e "20.0.0.3"
   table=??(lr_in_arp_resolve  ), priority=150  , match=(inport == "lr0-public" && outport == "lr0-public" && ip4.dst == 172.168.0.120), action=(drop;)
   table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 172.168.0.110 && inport == "lr0-public"), action=(ct_dnat(10.0.0.3);)
   table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 172.168.0.120 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_dnat(20.0.0.3);)
-  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-port1")), action=(eth.src = 30:54:00:00:00:03; reg1 = 172.168.0.110; next;)
+  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-port1")), action=(eth.src = 30:54:00:00:00:03; reg5 = 172.168.0.110; next;)
   table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa == 172.168.0.110), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = inport; flags.loopback = 1; output;)
   table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa == 172.168.0.120), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = inport; flags.loopback = 1; output;)
   table=??(lr_in_ip_input     ), priority=91   , match=(inport == "lr0-public" && arp.op == 1 && arp.tpa == 172.168.0.110), action=(drop;)
@@ -13855,7 +13855,7 @@  AT_CHECK([grep -e "172.168.0.110" -e "172.168.0.120" -e "10.0.0.3" -e "20.0.0.3"
   table=??(lr_in_arp_resolve  ), priority=150  , match=(inport == "lr0-public" && outport == "lr0-public" && ip4.dst == 172.168.0.120), action=(drop;)
   table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 172.168.0.110 && inport == "lr0-public"), action=(ct_dnat(10.0.0.3);)
   table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 172.168.0.120 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_dnat(20.0.0.3);)
-  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-port1")), action=(eth.src = 30:54:00:00:00:03; reg1 = 172.168.0.110; next;)
+  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("sw0-port1")), action=(eth.src = 30:54:00:00:00:03; reg5 = 172.168.0.110; next;)
   table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa == 172.168.0.110), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = inport; flags.loopback = 1; output;)
   table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa == 172.168.0.120), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = inport; flags.loopback = 1; output;)
   table=??(lr_in_ip_input     ), priority=91   , match=(inport == "lr0-public" && arp.op == 1 && arp.tpa == 172.168.0.110), action=(drop;)
diff --git a/tests/ovn.at b/tests/ovn.at
index b94cddf0f..a29ec7114 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -22134,7 +22134,7 @@  check ovn-nbctl --wait=hv sync
 
 # verify the traffic from virtual port is discarded if the port is not claimed
 AT_CHECK([grep lr_in_gw_redirect lr0-flows2 | grep "ip4.src == 10.0.0.10" | ovn_strip_lflows], [0], [dnl
-  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("sw0-vir")), action=(eth.src = 10:54:00:00:00:10; reg1 = 172.168.0.50; next;)
+  table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("sw0-vir")), action=(eth.src = 10:54:00:00:00:10; reg5 = 172.168.0.50; next;)
   table=??(lr_in_gw_redirect  ), priority=80   , match=(ip4.src == 10.0.0.10 && outport == "lr0-public"), action=(drop;)
 ])