[ovs-dev] [PATCH ovn 3/3] northd: add chec_pkt_len lflows for ingress traffic

Numan Siddique numans at ovn.org
Fri May 21 20:56:01 UTC 2021


On Wed, May 19, 2021 at 11:36 AM Lorenzo Bianconi
<lorenzo.bianconi at redhat.com> wrote:
>
> Introduce chec_pkt_len action for ingress traffic entering the cluster
> from a distributed gw router port or from a gw router.
> Rearrange logical router ingress pipeline in order to properly manage
> icmp error packets.
>
> Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi at redhat.com>

Hi Lorenzo,

Thanks for working on this support.

This patch series adds the below logical flow

  table=5 (lr_in_chk_pkt_len  ), priority=50   , match=(1),
action=(reg9[1] = check_pkt_larger(1460); next;)

which means all the packets which enter the router pipeline are
checked for the packet length.

In the case of a logical router with a distributed gateway port, it
seems totally unnecessary to me to check for
packet length for packets entering from all router ports.

I think we should add the flow like

  table=5 (lr_in_chk_pkt_len  ), priority=50   , match=(inport ==
lr0-public || outport == lr0-public), action=(reg9[1] =
check_pkt_larger(1460); next;)

 where lr0-public is the router port which has the gateway_chassis configured.

Even in the case of a gateway router, it seems unnecessary to do the
same.  I think whichever router port has the gateway_mtu configured
we should check the packet lengths for the packets received from that
router port or destined towards that router port.

What was the reason to move up the lr_in_chk_pkt_len stage ?  If we
have chk_pkt_len stage after lr_in_arp_resolve
we can match both on inport and outport since by this time, outport
would be determined.

I spotted a missing space for the lflow matching for IPv6 case.

**
 match=(inport == "lr0-public"&& ip6 && reg9[1])  -> notice the
missing space before "&&".
***

Thanks
Numan




> ---
>  northd/ovn-northd.c | 154 +++++++++++++-------------
>  tests/ovn-northd.at | 150 +++++++++++++-------------
>  tests/ovn.at        | 258 ++++++++++++++++++++++++++++++++++++++++----
>  3 files changed, 394 insertions(+), 168 deletions(-)
>
> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> index ec63eb75c..95fcee69d 100644
> --- a/northd/ovn-northd.c
> +++ b/northd/ovn-northd.c
> @@ -183,18 +183,18 @@ enum ovn_stage {
>      PIPELINE_STAGE(ROUTER, IN,  LEARN_NEIGHBOR,  2, "lr_in_learn_neighbor") \
>      PIPELINE_STAGE(ROUTER, IN,  IP_INPUT,        3, "lr_in_ip_input")     \
>      PIPELINE_STAGE(ROUTER, IN,  DEFRAG,          4, "lr_in_defrag")       \
> -    PIPELINE_STAGE(ROUTER, IN,  UNSNAT,          5, "lr_in_unsnat")       \
> -    PIPELINE_STAGE(ROUTER, IN,  DNAT,            6, "lr_in_dnat")         \
> -    PIPELINE_STAGE(ROUTER, IN,  ECMP_STATEFUL,   7, "lr_in_ecmp_stateful") \
> -    PIPELINE_STAGE(ROUTER, IN,  ND_RA_OPTIONS,   8, "lr_in_nd_ra_options") \
> -    PIPELINE_STAGE(ROUTER, IN,  ND_RA_RESPONSE,  9, "lr_in_nd_ra_response") \
> -    PIPELINE_STAGE(ROUTER, IN,  IP_ROUTING,      10, "lr_in_ip_routing")   \
> -    PIPELINE_STAGE(ROUTER, IN,  IP_ROUTING_ECMP, 11, "lr_in_ip_routing_ecmp") \
> -    PIPELINE_STAGE(ROUTER, IN,  POLICY,          12, "lr_in_policy")       \
> -    PIPELINE_STAGE(ROUTER, IN,  POLICY_ECMP,     13, "lr_in_policy_ecmp")  \
> -    PIPELINE_STAGE(ROUTER, IN,  ARP_RESOLVE,     14, "lr_in_arp_resolve")  \
> -    PIPELINE_STAGE(ROUTER, IN,  CHK_PKT_LEN   ,  15, "lr_in_chk_pkt_len")  \
> -    PIPELINE_STAGE(ROUTER, IN,  LARGER_PKTS,     16, "lr_in_larger_pkts")  \
> +    PIPELINE_STAGE(ROUTER, IN,  CHK_PKT_LEN,     5, "lr_in_chk_pkt_len")  \
> +    PIPELINE_STAGE(ROUTER, IN,  LARGER_PKTS,     6, "lr_in_larger_pkts")  \
> +    PIPELINE_STAGE(ROUTER, IN,  UNSNAT,          7, "lr_in_unsnat")       \
> +    PIPELINE_STAGE(ROUTER, IN,  DNAT,            8, "lr_in_dnat")         \
> +    PIPELINE_STAGE(ROUTER, IN,  ECMP_STATEFUL,   9, "lr_in_ecmp_stateful") \
> +    PIPELINE_STAGE(ROUTER, IN,  ND_RA_OPTIONS,   10, "lr_in_nd_ra_options") \
> +    PIPELINE_STAGE(ROUTER, IN,  ND_RA_RESPONSE,  11, "lr_in_nd_ra_response") \
> +    PIPELINE_STAGE(ROUTER, IN,  IP_ROUTING,      12, "lr_in_ip_routing")   \
> +    PIPELINE_STAGE(ROUTER, IN,  IP_ROUTING_ECMP, 13, "lr_in_ip_routing_ecmp") \
> +    PIPELINE_STAGE(ROUTER, IN,  POLICY,          14, "lr_in_policy")       \
> +    PIPELINE_STAGE(ROUTER, IN,  POLICY_ECMP,     15, "lr_in_policy_ecmp")  \
> +    PIPELINE_STAGE(ROUTER, IN,  ARP_RESOLVE,     16, "lr_in_arp_resolve")  \
>      PIPELINE_STAGE(ROUTER, IN,  GW_REDIRECT,     17, "lr_in_gw_redirect")  \
>      PIPELINE_STAGE(ROUTER, IN,  ARP_REQUEST,     18, "lr_in_arp_request")  \
>                                                                        \
> @@ -10399,6 +10399,67 @@ build_arp_resolve_flows_for_lrouter_port(
>
>  }
>
> +static void
> +build_icmperr_pkt_big_flows(struct ovn_port *op, int mtu, struct hmap *lflows,
> +                            struct ds *match, struct ds *actions)
> +{
> +    if (op->lrp_networks.ipv4_addrs) {
> +        ds_clear(match);
> +        ds_put_format(match, "inport == %s && ip4 && "REGBIT_PKT_LARGER,
> +                      op->json_key);
> +
> +        ds_clear(actions);
> +        /* Set icmp4.frag_mtu to gw_mtu */
> +        ds_put_format(actions,
> +            "icmp4_error {"
> +            REGBIT_EGRESS_LOOPBACK" = 1; "
> +            REGBIT_PKT_LARGER" = 0; "
> +            "eth.dst = %s; "
> +            "ip4.dst = ip4.src; "
> +            "ip4.src = %s; "
> +            "ip.ttl = 255; "
> +            "icmp4.type = 3; /* Destination Unreachable. */ "
> +            "icmp4.code = 4; /* Frag Needed and DF was Set. */ "
> +            "icmp4.frag_mtu = %d; "
> +            "next(pipeline=ingress, table=%d); };",
> +            op->lrp_networks.ea_s,
> +            op->lrp_networks.ipv4_addrs[0].addr_s,
> +            mtu, ovn_stage_get_table(S_ROUTER_IN_ADMISSION));
> +        ovn_lflow_add_with_hint(lflows, op->od,
> +                                S_ROUTER_IN_LARGER_PKTS, 50,
> +                                ds_cstr(match), ds_cstr(actions),
> +                                &op->nbrp->header_);
> +    }
> +
> +    if (op->lrp_networks.ipv6_addrs) {
> +        ds_clear(match);
> +        ds_put_format(match, "inport == %s&& ip6 && "REGBIT_PKT_LARGER,
> +                      op->json_key);
> +
> +        ds_clear(actions);
> +        /* Set icmp6.frag_mtu to gw_mtu */
> +        ds_put_format(actions,
> +            "icmp6_error {"
> +            REGBIT_EGRESS_LOOPBACK" = 1; "
> +            REGBIT_PKT_LARGER" = 0; "
> +            "eth.dst = %s; "
> +            "ip6.dst = ip6.src; "
> +            "ip6.src = %s; "
> +            "ip.ttl = 255; "
> +            "icmp6.type = 2; /* Packet Too Big. */ "
> +            "icmp6.code = 0; "
> +            "icmp6.frag_mtu = %d; "
> +            "next(pipeline=ingress, table=%d); };",
> +            op->lrp_networks.ea_s,
> +            op->lrp_networks.ipv6_addrs[0].addr_s,
> +            mtu, ovn_stage_get_table(S_ROUTER_IN_ADMISSION));
> +        ovn_lflow_add_with_hint(lflows, op->od,
> +                                S_ROUTER_IN_LARGER_PKTS, 50,
> +                                ds_cstr(match), ds_cstr(actions),
> +                                &op->nbrp->header_);
> +    }
> +}
> +
>  static void
>  build_check_pkt_len_flows_for_lrp(struct ovn_port *op,
>                                    struct hmap *lflows, struct hmap *ports,
> @@ -10414,81 +10475,26 @@ build_check_pkt_len_flows_for_lrp(struct ovn_port *op,
>          return;
>      }
>
> -    ds_clear(match);
> -    ds_put_format(match, "outport == %s", op->json_key);
> -
>      ds_clear(actions);
>      ds_put_format(actions,
>                    REGBIT_PKT_LARGER" = check_pkt_larger(%d);"
>                    " next;", gw_mtu + VLAN_ETH_HEADER_LEN);
> +
> +    ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_CHK_PKT_LEN, 100,
> +                            REGBIT_EGRESS_LOOPBACK, "next;",
> +                            &op->nbrp->header_);
>      ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_CHK_PKT_LEN, 50,
> -                            ds_cstr(match), ds_cstr(actions),
> +                            "1", ds_cstr(actions),
>                              &op->nbrp->header_);
>
>      for (size_t i = 0; i < op->od->nbr->n_ports; i++) {
>          struct ovn_port *rp = ovn_port_find(ports,
>                                              op->od->nbr->ports[i]->name);
> -        if (!rp || rp == op) {
> +        if (!rp) {
>              continue;
>          }
>
> -        if (rp->lrp_networks.ipv4_addrs) {
> -            ds_clear(match);
> -            ds_put_format(match, "inport == %s && outport == %s"
> -                          " && ip4 && "REGBIT_PKT_LARGER,
> -                          rp->json_key, op->json_key);
> -
> -            ds_clear(actions);
> -            /* Set icmp4.frag_mtu to gw_mtu */
> -            ds_put_format(actions,
> -                "icmp4_error {"
> -                REGBIT_EGRESS_LOOPBACK" = 1; "
> -                "eth.dst = %s; "
> -                "ip4.dst = ip4.src; "
> -                "ip4.src = %s; "
> -                "ip.ttl = 255; "
> -                "icmp4.type = 3; /* Destination Unreachable. */ "
> -                "icmp4.code = 4; /* Frag Needed and DF was Set. */ "
> -                "icmp4.frag_mtu = %d; "
> -                "next(pipeline=ingress, table=%d); };",
> -                rp->lrp_networks.ea_s,
> -                rp->lrp_networks.ipv4_addrs[0].addr_s,
> -                gw_mtu,
> -                ovn_stage_get_table(S_ROUTER_IN_ADMISSION));
> -            ovn_lflow_add_with_hint(lflows, op->od,
> -                                    S_ROUTER_IN_LARGER_PKTS, 50,
> -                                    ds_cstr(match), ds_cstr(actions),
> -                                    &rp->nbrp->header_);
> -        }
> -
> -        if (rp->lrp_networks.ipv6_addrs) {
> -            ds_clear(match);
> -            ds_put_format(match, "inport == %s && outport == %s"
> -                          " && ip6 && "REGBIT_PKT_LARGER,
> -                          rp->json_key, op->json_key);
> -
> -            ds_clear(actions);
> -            /* Set icmp6.frag_mtu to gw_mtu */
> -            ds_put_format(actions,
> -                "icmp6_error {"
> -                REGBIT_EGRESS_LOOPBACK" = 1; "
> -                "eth.dst = %s; "
> -                "ip6.dst = ip6.src; "
> -                "ip6.src = %s; "
> -                "ip.ttl = 255; "
> -                "icmp6.type = 2; /* Packet Too Big. */ "
> -                "icmp6.code = 0; "
> -                "icmp6.frag_mtu = %d; "
> -                "next(pipeline=ingress, table=%d); };",
> -                rp->lrp_networks.ea_s,
> -                rp->lrp_networks.ipv6_addrs[0].addr_s,
> -                gw_mtu,
> -                ovn_stage_get_table(S_ROUTER_IN_ADMISSION));
> -            ovn_lflow_add_with_hint(lflows, op->od,
> -                                    S_ROUTER_IN_LARGER_PKTS, 50,
> -                                    ds_cstr(match), ds_cstr(actions),
> -                                    &rp->nbrp->header_);
> -        }
> +        build_icmperr_pkt_big_flows(rp, gw_mtu, lflows, match, actions);
>      }
>  }
>
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> index bff2ade43..77d3abdb3 100644
> --- a/tests/ovn-northd.at
> +++ b/tests/ovn-northd.at
> @@ -1466,8 +1466,8 @@ ovn-nbctl set logical_router lr0 options:dnat_force_snat_ip=192.168.2.3
>  ovn-nbctl --wait=sb sync
>
>  AT_CHECK([ovn-sbctl lflow-list lr0 | grep lr_in_unsnat | sort], [0], [dnl
> -  table=5 (lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> -  table=5 (lr_in_unsnat       ), priority=110  , match=(ip4 && ip4.dst == 192.168.2.3), action=(ct_snat;)
> +  table=7 (lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=7 (lr_in_unsnat       ), priority=110  , match=(ip4 && ip4.dst == 192.168.2.3), action=(ct_snat;)
>  ])
>
>  AT_CLEANUP
> @@ -2596,11 +2596,11 @@ ovn-sbctl dump-flows lr0 > lr0flows3
>  AT_CAPTURE_FILE([lr0flows3])
>
>  AT_CHECK([grep "lr_in_policy" lr0flows3 | sort], [0], [dnl
> -  table=12(lr_in_policy       ), priority=0    , match=(1), action=(reg8[[0..15]] = 0; next;)
> -  table=12(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.3), action=(reg8[[0..15]] = 1; reg8[[16..31]] = select(1, 2);)
> -  table=13(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; next;)
> -  table=13(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; next;)
> -  table=13(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == 0), action=(next;)
> +  table=14(lr_in_policy       ), priority=0    , match=(1), action=(reg8[[0..15]] = 0; next;)
> +  table=14(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.3), action=(reg8[[0..15]] = 1; reg8[[16..31]] = select(1, 2);)
> +  table=15(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; next;)
> +  table=15(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; next;)
> +  table=15(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == 0), action=(next;)
>  ])
>
>  check ovn-nbctl --wait=sb lr-policy-add lr0  10 "ip4.src == 10.0.0.4" reroute 172.168.0.101,172.168.0.102,172.168.0.103
> @@ -2610,15 +2610,15 @@ AT_CAPTURE_FILE([lr0flows3])
>  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>/' | sort], [0], [dnl
> -  table=12(lr_in_policy       ), priority=0    , match=(1), action=(reg8[[0..15]] = <cleared>; next;)
> -  table=12(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.3), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2);)
> -  table=12(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=13(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; next;)
> -  table=13(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; next;)
> -  table=13(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; next;)
> -  table=13(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; next;)
> -  table=13(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; next;)
> -  table=13(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == <cleared>), action=(next;)
> +  table=14(lr_in_policy       ), priority=0    , match=(1), action=(reg8[[0..15]] = <cleared>; next;)
> +  table=14(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.3), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2);)
> +  table=14(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=15(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; next;)
> +  table=15(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; next;)
> +  table=15(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; next;)
> +  table=15(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; next;)
> +  table=15(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; next;)
> +  table=15(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == <cleared>), action=(next;)
>  ])
>
>  check ovn-nbctl --wait=sb lr-policy-add lr0  10 "ip4.src == 10.0.0.5" reroute 172.168.0.110
> @@ -2628,16 +2628,16 @@ AT_CAPTURE_FILE([lr0flows3])
>  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>/' | sort], [0], [dnl
> -  table=12(lr_in_policy       ), priority=0    , match=(1), action=(reg8[[0..15]] = <cleared>; next;)
> -  table=12(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.3), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2);)
> -  table=12(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=12(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>; next;)
> -  table=13(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; next;)
> -  table=13(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; next;)
> -  table=13(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; next;)
> -  table=13(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; next;)
> -  table=13(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; next;)
> -  table=13(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == <cleared>), action=(next;)
> +  table=14(lr_in_policy       ), priority=0    , match=(1), action=(reg8[[0..15]] = <cleared>; next;)
> +  table=14(lr_in_policy       ), priority=10   , match=(ip4.src == 10.0.0.3), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2);)
> +  table=14(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=14(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>; next;)
> +  table=15(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; next;)
> +  table=15(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; next;)
> +  table=15(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; next;)
> +  table=15(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; next;)
> +  table=15(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; next;)
> +  table=15(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == <cleared>), action=(next;)
>  ])
>
>  check ovn-nbctl --wait=sb lr-policy-del lr0  10 "ip4.src == 10.0.0.3"
> @@ -2647,13 +2647,13 @@ AT_CAPTURE_FILE([lr0flows3])
>  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>/' | sort], [0], [dnl
> -  table=12(lr_in_policy       ), priority=0    , match=(1), action=(reg8[[0..15]] = <cleared>; next;)
> -  table=12(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=12(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>; next;)
> -  table=13(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; next;)
> -  table=13(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; next;)
> -  table=13(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; next;)
> -  table=13(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == <cleared>), action=(next;)
> +  table=14(lr_in_policy       ), priority=0    , match=(1), action=(reg8[[0..15]] = <cleared>; next;)
> +  table=14(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=14(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>; next;)
> +  table=15(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; next;)
> +  table=15(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; next;)
> +  table=15(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; next;)
> +  table=15(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == <cleared>), action=(next;)
>  ])
>
>  check ovn-nbctl --wait=sb lr-policy-del lr0  10 "ip4.src == 10.0.0.4"
> @@ -2663,9 +2663,9 @@ AT_CAPTURE_FILE([lr0flows3])
>  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>/' | sort], [0], [dnl
> -  table=12(lr_in_policy       ), priority=0    , match=(1), action=(reg8[[0..15]] = <cleared>; next;)
> -  table=12(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>; next;)
> -  table=13(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == <cleared>), action=(next;)
> +  table=14(lr_in_policy       ), priority=0    , match=(1), action=(reg8[[0..15]] = <cleared>; next;)
> +  table=14(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>; next;)
> +  table=15(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == <cleared>), action=(next;)
>  ])
>
>  check ovn-nbctl --wait=sb add logical_router_policy . nexthops "2000\:\:b"
> @@ -2675,8 +2675,8 @@ AT_CAPTURE_FILE([lr0flows3])
>  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>/' | sort], [0], [dnl
> -  table=12(lr_in_policy       ), priority=0    , match=(1), action=(reg8[[0..15]] = <cleared>; next;)
> -  table=13(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == <cleared>), action=(next;)
> +  table=14(lr_in_policy       ), priority=0    , match=(1), action=(reg8[[0..15]] = <cleared>; next;)
> +  table=15(lr_in_policy_ecmp  ), priority=150  , match=(reg8[[0..15]] == <cleared>), action=(next;)
>  ])
>
>  AT_CLEANUP
> @@ -3113,14 +3113,14 @@ ovn-sbctl dump-flows lr0 > lr0flows
>  AT_CAPTURE_FILE([lr0flows])
>
>  AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
> -  table=5 (lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=7 (lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
>  ])
>
>  AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
> -  table=6 (lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> -  table=6 (lr_in_dnat         ), priority=120  , match=(ct.est && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(ct_dnat;)
> -  table=6 (lr_in_dnat         ), priority=120  , match=(ct.new && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(ct_lb(backends=10.0.0.4:8080);)
> -  table=6 (lr_in_dnat         ), priority=50   , match=(ip), action=(flags.loopback = 1; ct_dnat;)
> +  table=8 (lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=8 (lr_in_dnat         ), priority=120  , match=(ct.est && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(ct_dnat;)
> +  table=8 (lr_in_dnat         ), priority=120  , match=(ct.new && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(ct_lb(backends=10.0.0.4:8080);)
> +  table=8 (lr_in_dnat         ), priority=50   , match=(ip), action=(flags.loopback = 1; ct_dnat;)
>  ])
>
>  check ovn-nbctl --wait=sb set logical_router lr0 options:lb_force_snat_ip="20.0.0.4 aef0::4"
> @@ -3130,16 +3130,16 @@ AT_CAPTURE_FILE([lr0flows])
>
>
>  AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
> -  table=5 (lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> -  table=5 (lr_in_unsnat       ), priority=110  , match=(ip4 && ip4.dst == 20.0.0.4), action=(ct_snat;)
> -  table=5 (lr_in_unsnat       ), priority=110  , match=(ip6 && ip6.dst == aef0::4), action=(ct_snat;)
> +  table=7 (lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=7 (lr_in_unsnat       ), priority=110  , match=(ip4 && ip4.dst == 20.0.0.4), action=(ct_snat;)
> +  table=7 (lr_in_unsnat       ), priority=110  , match=(ip6 && ip6.dst == aef0::4), action=(ct_snat;)
>  ])
>
>  AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
> -  table=6 (lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> -  table=6 (lr_in_dnat         ), priority=120  , match=(ct.est && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_dnat;)
> -  table=6 (lr_in_dnat         ), priority=120  , match=(ct.new && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.4:8080);)
> -  table=6 (lr_in_dnat         ), priority=50   , match=(ip), action=(flags.loopback = 1; ct_dnat;)
> +  table=8 (lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=8 (lr_in_dnat         ), priority=120  , match=(ct.est && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_dnat;)
> +  table=8 (lr_in_dnat         ), priority=120  , match=(ct.new && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.4:8080);)
> +  table=8 (lr_in_dnat         ), priority=50   , match=(ip), action=(flags.loopback = 1; ct_dnat;)
>  ])
>
>  AT_CHECK([grep "lr_out_snat" lr0flows | sort], [0], [dnl
> @@ -3158,17 +3158,17 @@ AT_CHECK([grep "lr_in_ip_input" lr0flows | grep "priority=60" | sort], [0], [dnl
>  ])
>
>  AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
> -  table=5 (lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> -  table=5 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-public" && ip4.dst == 172.168.0.100), action=(ct_snat;)
> -  table=5 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;)
> -  table=5 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw1" && ip4.dst == 20.0.0.1), action=(ct_snat;)
> +  table=7 (lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=7 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-public" && ip4.dst == 172.168.0.100), action=(ct_snat;)
> +  table=7 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;)
> +  table=7 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw1" && ip4.dst == 20.0.0.1), action=(ct_snat;)
>  ])
>
>  AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
> -  table=6 (lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> -  table=6 (lr_in_dnat         ), priority=120  , match=(ct.est && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_dnat;)
> -  table=6 (lr_in_dnat         ), priority=120  , match=(ct.new && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.4:8080);)
> -  table=6 (lr_in_dnat         ), priority=50   , match=(ip), action=(flags.loopback = 1; ct_dnat;)
> +  table=8 (lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=8 (lr_in_dnat         ), priority=120  , match=(ct.est && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_dnat;)
> +  table=8 (lr_in_dnat         ), priority=120  , match=(ct.new && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.4:8080);)
> +  table=8 (lr_in_dnat         ), priority=50   , match=(ip), action=(flags.loopback = 1; ct_dnat;)
>  ])
>
>  AT_CHECK([grep "lr_out_snat" lr0flows | sort], [0], [dnl
> @@ -3185,7 +3185,7 @@ ovn-sbctl dump-flows lr0 > lr0flows
>  AT_CAPTURE_FILE([lr0flows])
>
>  AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
> -  table=5 (lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=7 (lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
>  ])
>
>  AT_CHECK([grep "lr_out_snat" lr0flows | sort], [0], [dnl
> @@ -3200,18 +3200,18 @@ ovn-sbctl dump-flows lr0 > lr0flows
>  AT_CAPTURE_FILE([lr0flows])
>
>  AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
> -  table=5 (lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> -  table=5 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-public" && ip4.dst == 172.168.0.100), action=(ct_snat;)
> -  table=5 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;)
> -  table=5 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw1" && ip4.dst == 20.0.0.1), action=(ct_snat;)
> -  table=5 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw1" && ip6.dst == bef0::1), action=(ct_snat;)
> +  table=7 (lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=7 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-public" && ip4.dst == 172.168.0.100), action=(ct_snat;)
> +  table=7 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;)
> +  table=7 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw1" && ip4.dst == 20.0.0.1), action=(ct_snat;)
> +  table=7 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw1" && ip6.dst == bef0::1), action=(ct_snat;)
>  ])
>
>  AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
> -  table=6 (lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> -  table=6 (lr_in_dnat         ), priority=120  , match=(ct.est && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_dnat;)
> -  table=6 (lr_in_dnat         ), priority=120  , match=(ct.new && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.4:8080);)
> -  table=6 (lr_in_dnat         ), priority=50   , match=(ip), action=(flags.loopback = 1; ct_dnat;)
> +  table=8 (lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=8 (lr_in_dnat         ), priority=120  , match=(ct.est && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_dnat;)
> +  table=8 (lr_in_dnat         ), priority=120  , match=(ct.new && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.4:8080);)
> +  table=8 (lr_in_dnat         ), priority=50   , match=(ip), action=(flags.loopback = 1; ct_dnat;)
>  ])
>
>  AT_CHECK([grep "lr_out_snat" lr0flows | sort], [0], [dnl
> @@ -3230,16 +3230,16 @@ check ovn-nbctl --wait=sb lb-del lb1
>  ovn-sbctl dump-flows lr0 > lr0flows
>
>  AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
> -  table=5 (lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> -  table=5 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-public" && ip4.dst == 172.168.0.100), action=(ct_snat;)
> -  table=5 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;)
> -  table=5 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw1" && ip4.dst == 20.0.0.1), action=(ct_snat;)
> -  table=5 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw1" && ip6.dst == bef0::1), action=(ct_snat;)
> +  table=7 (lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
> +  table=7 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-public" && ip4.dst == 172.168.0.100), action=(ct_snat;)
> +  table=7 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;)
> +  table=7 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw1" && ip4.dst == 20.0.0.1), action=(ct_snat;)
> +  table=7 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw1" && ip6.dst == bef0::1), action=(ct_snat;)
>  ])
>
>  AT_CHECK([grep "lr_in_dnat" lr0flows | grep skip_snat_for_lb | sort], [0], [dnl
> -  table=6 (lr_in_dnat         ), priority=120  , match=(ct.est && ip && ip4.dst == 10.0.0.20 && tcp && tcp.dst == 80), action=(flags.skip_snat_for_lb = 1; ct_dnat;)
> -  table=6 (lr_in_dnat         ), priority=120  , match=(ct.new && ip && ip4.dst == 10.0.0.20 && tcp && tcp.dst == 80), action=(flags.skip_snat_for_lb = 1; ct_lb(backends=10.0.0.40:8080);)
> +  table=8 (lr_in_dnat         ), priority=120  , match=(ct.est && ip && ip4.dst == 10.0.0.20 && tcp && tcp.dst == 80), action=(flags.skip_snat_for_lb = 1; ct_dnat;)
> +  table=8 (lr_in_dnat         ), priority=120  , match=(ct.new && ip && ip4.dst == 10.0.0.20 && tcp && tcp.dst == 80), action=(flags.skip_snat_for_lb = 1; ct_lb(backends=10.0.0.40:8080);)
>  ])
>
>  AT_CHECK([grep "lr_out_snat" lr0flows | grep skip_snat_for_lb | sort], [0], [dnl
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 248319262..eef03982c 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -16246,7 +16246,7 @@ test_ip_packet_larger() {
>          ip_csum=f993
>          icmp_reply=${src_mac}${dst_mac}08004500${reply_pkt_len}00004000fe016867
>          icmp_reply=${icmp_reply}${src_ip}${dst_ip}0304${ip_csum}0000$(printf "%04x" $mtu)
> -        icmp_reply=${icmp_reply}4500${pkt_len}000000003f01c4d9
> +        icmp_reply=${icmp_reply}4500${pkt_len}000000004001c3d9
>          icmp_reply=${icmp_reply}${orig_packet_l3}
>          echo $icmp_reply > hv1-vif1.expected
>      fi
> @@ -16275,6 +16275,52 @@ test_ip_packet_larger() {
>      fi
>  }
>
> +test_ip_packet_larger_ext() {
> +    local mtu=$1
> +
> +    # Send ip packet from sw0-port1 to outside
> +    src_mac="00000012af11" # external mac
> +    dst_mac="000020201213" # lr0-public mac
> +    src_ip=`ip_to_hex 172 168 0 4`
> +    dst_ip=`ip_to_hex 172 168 0 100`
> +    # Set the packet length to 118.
> +    pkt_len=0076
> +    packet=${dst_mac}${src_mac}08004500${pkt_len}000000004001c3d9
> +    orig_packet_l3=${src_ip}${dst_ip}0900000000000000
> +    orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
> +    orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
> +    orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
> +    orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
> +    orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
> +    packet=${packet}${orig_packet_l3}
> +
> +    gw_ip_garp=ffffffffffff00002020121308060001080006040001000020201213aca80064000000000000aca80064
> +    ext_ip_garp=ffffffffffff00000012af110806000108000604000100000012af11aca80004000000000000aca80004
> +
> +    src_ip=`ip_to_hex 172 168 0 100`
> +    dst_ip=`ip_to_hex 172 168 0 4`
> +    # pkt len should be 146 (28 (icmp packet) + 118 (orig ip + payload))
> +    reply_pkt_len=0092
> +    ip_csum=508d
> +    icmp_reply=${src_mac}${dst_mac}08004500${reply_pkt_len}00004000fe0122b2
> +    icmp_reply=${icmp_reply}${src_ip}${dst_ip}0304${ip_csum}0000$(printf "%04x" $mtu)
> +    icmp_reply=${icmp_reply}4500${pkt_len}000000004001c3d9
> +    icmp_reply=${icmp_reply}${orig_packet_l3}
> +    echo $icmp_reply > br-phys_n1.expected
> +
> +    echo $gw_ip_garp >> br-phys_n1.expected
> +
> +    as hv1 reset_pcap_file br-phys_n1 hv1/br-phys_n1
> +    as hv1 reset_pcap_file hv1-vif1 hv1/vif1
> +
> +    check as hv1 ovs-appctl netdev-dummy/receive br-phys_n1 $ext_ip_garp
> +    sleep 1
> +    # Send packet from sw0-port1 to outside
> +    check as hv1 ovs-appctl netdev-dummy/receive br-phys_n1 $packet
> +
> +    OVN_CHECK_PACKETS([hv1/br-phys_n1-tx.pcap], [br-phys_n1.expected])
> +}
> +
>  test_ip6_packet_larger() {
>      local mtu=$1
>
> @@ -16307,7 +16353,7 @@ test_ip6_packet_larger() {
>      mtu_needed=$(expr ${packet_bytes} - 18)
>      if test $mtu -lt $mtu_needed; then
>          # First construct the inner IPv6 packet.
> -        inner_ip6=6000000000583afe${ipv6_src}${ipv6_dst}
> +        inner_ip6=6000000000583aff${ipv6_src}${ipv6_dst}
>          inner_icmp6=8000000062f00001
>          inner_icmp6_and_payload=$(icmp6_csum_inplace ${inner_icmp6}${payload} ${inner_ip6})
>          inner_packet=${inner_ip6}${inner_icmp6_and_payload}
> @@ -16329,6 +16375,53 @@ test_ip6_packet_larger() {
>      fi
>  }
>
> +test_ip6_packet_larger_ext() {
> +    local mtu=$1
> +
> +    local eth_src=00000012af11
> +    local eth_dst=000020201213
> +
> +    local ipv6_src=20000000000000000000000000000004
> +    local ipv6_dst=20000000000000000000000000000001
> +
> +    local payload=0000000000000000000000000000000000000000
> +    local payload=${payload}0000000000000000000000000000000000000000
> +    local payload=${payload}0000000000000000000000000000000000000000
> +    local payload=${payload}0000000000000000000000000000000000000000
> +
> +    local ip6_hdr=6000000000583aff${ipv6_src}${ipv6_dst}
> +    local packet=${eth_dst}${eth_src}86dd${ip6_hdr}9000cc7662f00001${payload}
> +
> +    local ns=ffffffffffff00002020121308060001080006040001000020201213aca80064000000000000aca80064
> +    echo $ns > br-phys_n1.expected
> +
> +    as hv1 reset_pcap_file br-phys_n1 hv1/br-phys_n1
> +    as hv1 reset_pcap_file hv1-vif1 hv1/vif1
> +
> +    local na_ip6_hdr=6000000000203aff${ipv6_src}${ipv6_dst}
> +    local na=${eth_dst}${eth_src}86dd${na_ip6_hdr}8800d78440000000${ipv6_src}0201${eth_src}
> +    check as hv1 ovs-appctl netdev-dummy/receive br-phys_n1 $na
> +    sleep 1
> +    check as hv1 ovs-appctl netdev-dummy/receive br-phys_n1 $packet
> +    AT_CAPTURE_FILE([trace-$mtu])
> +
> +    # First construct the inner IPv6 packet.
> +    inner_ip6=6000000000583aff${ipv6_src}${ipv6_dst}
> +    inner_icmp6=9000000062f00001
> +    inner_icmp6_and_payload=$(icmp6_csum_inplace ${inner_icmp6}${payload} ${inner_ip6})
> +    inner_packet=${inner_ip6}${inner_icmp6_and_payload}
> +
> +    # Then the outer.
> +    outer_ip6=6000000000883afe${ipv6_dst}${ipv6_src}
> +    outer_icmp6_and_payload=$(icmp6_csum_inplace 020000000000$(printf "%04x" $mtu)${inner_packet} $outer_ip6)
> +    outer_packet=${outer_ip6}${outer_icmp6_and_payload}
> +
> +    icmp6_reply=${eth_src}${eth_dst}86dd${outer_packet}
> +    echo $icmp6_reply >> br-phys_n1.expected
> +
> +    OVN_CHECK_PACKETS([hv1/br-phys_n1-tx.pcap], [br-phys_n1.expected])
> +}
> +
>  wait_for_ports_up
>  ovn-nbctl --wait=hv sync
>
> @@ -16371,6 +16464,23 @@ for mtu in 100 500 118; do
>      test_ip6_packet_larger $mtu
>  done
>
> +AS_BOX([testing mtu $mtu])
> +check ovn-nbctl --wait=hv set logical_router_port lr0-public options:gateway_mtu=100
> +ovn-sbctl dump-flows > ext-sbflows-100
> +AT_CAPTURE_FILE([ext-sbflows-$mtu])
> +
> +OVS_WAIT_FOR_OUTPUT([
> +    as hv1 ovs-ofctl dump-flows br-int > ext-br-int-flows-100
> +    AT_CAPTURE_FILE([ext-br-int-flows-100])
> +    grep "check_pkt_larger(118)" ext-br-int-flows-100 | wc -l], [0], [1
> +])
> +
> +AS_BOX([testing ext mtu 100 - IPv4])
> +test_ip_packet_larger_ext 100
> +
> +AS_BOX([testing mtu 100 - IPv6])
> +test_ip6_packet_larger_ext 100
> +
>  OVN_CLEANUP([hv1])
>  AT_CLEANUP
>  ])
> @@ -16484,7 +16594,7 @@ test_ip_packet_larger() {
>          ip_csum=f993
>          icmp_reply=${src_mac}${dst_mac}08004500${reply_pkt_len}00004000fe016867
>          icmp_reply=${icmp_reply}${src_ip}${dst_ip}0304${ip_csum}0000$(printf "%04x" $mtu)
> -        icmp_reply=${icmp_reply}4500${pkt_len}000000003f01c4d9
> +        icmp_reply=${icmp_reply}4500${pkt_len}000000004001c3d9
>          icmp_reply=${icmp_reply}${orig_packet_l3}
>          echo $icmp_reply > hv1-vif1.expected
>      fi
> @@ -16513,6 +16623,52 @@ test_ip_packet_larger() {
>      fi
>  }
>
> +test_ip_packet_larger_ext() {
> +    local mtu=$1
> +
> +    # Send ip packet from sw0-port1 to outside
> +    src_mac="00000012af11" # external mac
> +    dst_mac="000020201213" # lr0-public mac
> +    src_ip=`ip_to_hex 172 168 0 4`
> +    dst_ip=`ip_to_hex 172 168 0 100`
> +    # Set the packet length to 118.
> +    pkt_len=0076
> +    packet=${dst_mac}${src_mac}08004500${pkt_len}000000004001c3d9
> +    orig_packet_l3=${src_ip}${dst_ip}0900000000000000
> +    orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
> +    orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
> +    orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
> +    orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
> +    orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
> +    packet=${packet}${orig_packet_l3}
> +
> +    gw_ip_garp=ffffffffffff00002020121308060001080006040001000020201213aca80064000000000000aca80064
> +    ext_ip_garp=ffffffffffff00000012af110806000108000604000100000012af11aca80004000000000000aca80004
> +
> +    src_ip=`ip_to_hex 172 168 0 100`
> +    dst_ip=`ip_to_hex 172 168 0 4`
> +    # pkt len should be 146 (28 (icmp packet) + 118 (orig ip + payload))
> +    reply_pkt_len=0092
> +    ip_csum=508d
> +    icmp_reply=${src_mac}${dst_mac}08004500${reply_pkt_len}00004000fe0122b2
> +    icmp_reply=${icmp_reply}${src_ip}${dst_ip}0304${ip_csum}0000$(printf "%04x" $mtu)
> +    icmp_reply=${icmp_reply}4500${pkt_len}000000004001c3d9
> +    icmp_reply=${icmp_reply}${orig_packet_l3}
> +    echo $icmp_reply > br-phys_n1.expected
> +
> +    echo $gw_ip_garp >> br-phys_n1.expected
> +
> +    as hv1 reset_pcap_file br-phys_n1 hv1/br-phys_n1
> +    as hv1 reset_pcap_file hv1-vif1 hv1/vif1
> +
> +    check as hv1 ovs-appctl netdev-dummy/receive br-phys_n1 $ext_ip_garp
> +    sleep 1
> +    # Send packet from sw0-port1 to outside
> +    check as hv1 ovs-appctl netdev-dummy/receive br-phys_n1 $packet
> +
> +    OVN_CHECK_PACKETS([hv1/br-phys_n1-tx.pcap], [br-phys_n1.expected])
> +}
> +
>  test_ip6_packet_larger() {
>      local mtu=$1
>
> @@ -16545,7 +16701,7 @@ test_ip6_packet_larger() {
>      mtu_needed=$(expr ${packet_bytes} - 18)
>      if test $mtu -lt $mtu_needed; then
>          # First construct the inner IPv6 packet.
> -        inner_ip6=6000000000583afe${ipv6_src}${ipv6_dst}
> +        inner_ip6=6000000000583aff${ipv6_src}${ipv6_dst}
>          inner_icmp6=8000000062f00001
>          inner_icmp6_and_payload=$(icmp6_csum_inplace ${inner_icmp6}${payload} ${inner_ip6})
>          inner_packet=${inner_ip6}${inner_icmp6_and_payload}
> @@ -16567,6 +16723,53 @@ test_ip6_packet_larger() {
>      fi
>  }
>
> +test_ip6_packet_larger_ext() {
> +    local mtu=$1
> +
> +    local eth_src=00000012af11
> +    local eth_dst=000020201213
> +
> +    local ipv6_src=20000000000000000000000000000004
> +    local ipv6_dst=20000000000000000000000000000001
> +
> +    local payload=0000000000000000000000000000000000000000
> +    local payload=${payload}0000000000000000000000000000000000000000
> +    local payload=${payload}0000000000000000000000000000000000000000
> +    local payload=${payload}0000000000000000000000000000000000000000
> +
> +    local ip6_hdr=6000000000583aff${ipv6_src}${ipv6_dst}
> +    local packet=${eth_dst}${eth_src}86dd${ip6_hdr}9000cc7662f00001${payload}
> +
> +    local ns=ffffffffffff00002020121308060001080006040001000020201213aca80064000000000000aca80064
> +    echo $ns > br-phys_n1.expected
> +
> +    as hv1 reset_pcap_file br-phys_n1 hv1/br-phys_n1
> +    as hv1 reset_pcap_file hv1-vif1 hv1/vif1
> +
> +    local na_ip6_hdr=6000000000203aff${ipv6_src}${ipv6_dst}
> +    local na=${eth_dst}${eth_src}86dd${na_ip6_hdr}8800d78440000000${ipv6_src}0201${eth_src}
> +    check as hv1 ovs-appctl netdev-dummy/receive br-phys_n1 $na
> +    sleep 1
> +    check as hv1 ovs-appctl netdev-dummy/receive br-phys_n1 $packet
> +    AT_CAPTURE_FILE([trace-$mtu])
> +
> +    # First construct the inner IPv6 packet.
> +    inner_ip6=6000000000583aff${ipv6_src}${ipv6_dst}
> +    inner_icmp6=9000000062f00001
> +    inner_icmp6_and_payload=$(icmp6_csum_inplace ${inner_icmp6}${payload} ${inner_ip6})
> +    inner_packet=${inner_ip6}${inner_icmp6_and_payload}
> +
> +    # Then the outer.
> +    outer_ip6=6000000000883afe${ipv6_dst}${ipv6_src}
> +    outer_icmp6_and_payload=$(icmp6_csum_inplace 020000000000$(printf "%04x" $mtu)${inner_packet} $outer_ip6)
> +    outer_packet=${outer_ip6}${outer_icmp6_and_payload}
> +
> +    icmp6_reply=${eth_src}${eth_dst}86dd${outer_packet}
> +    echo $icmp6_reply >> br-phys_n1.expected
> +
> +    OVN_CHECK_PACKETS([hv1/br-phys_n1-tx.pcap], [br-phys_n1.expected])
> +}
> +
>  wait_for_ports_up
>  ovn-nbctl --wait=hv sync
>
> @@ -16609,6 +16812,23 @@ for mtu in 100 500 118; do
>      test_ip6_packet_larger $mtu
>  done
>
> +AS_BOX([testing mtu $mtu])
> +check ovn-nbctl --wait=hv set logical_router_port lr0-public options:gateway_mtu=100
> +ovn-sbctl dump-flows > ext-sbflows-100
> +AT_CAPTURE_FILE([ext-sbflows-$mtu])
> +
> +OVS_WAIT_FOR_OUTPUT([
> +    as hv1 ovs-ofctl dump-flows br-int > ext-br-int-flows-100
> +    AT_CAPTURE_FILE([ext-br-int-flows-100])
> +    grep "check_pkt_larger(118)" ext-br-int-flows-100 | wc -l], [0], [1
> +])
> +
> +AS_BOX([testing ext mtu 100 - IPv4])
> +test_ip_packet_larger_ext 100
> +
> +AS_BOX([testing mtu 100 - IPv6])
> +test_ip6_packet_larger_ext 100
> +
>  OVN_CLEANUP([hv1])
>  AT_CLEANUP
>  ])
> @@ -22511,7 +22731,7 @@ ovn-sbctl dump-flows > sbflows
>  AT_CAPTURE_FILE([sbflows])
>  AT_CAPTURE_FILE([offlows])
>  OVS_WAIT_UNTIL([
> -    as hv1 ovs-ofctl dump-flows br-int table=20 > offlows
> +    as hv1 ovs-ofctl dump-flows br-int table=22 > offlows
>      test $(grep -c "load:0x64->NXM_NX_PKT_MARK" offlows) = 1 && \
>      test $(grep -c "load:0x3->NXM_NX_PKT_MARK" offlows) = 1 && \
>      test $(grep -c "load:0x4->NXM_NX_PKT_MARK" offlows) = 1 && \
> @@ -22604,12 +22824,12 @@ send_ipv4_pkt hv1 hv1-vif1 505400000003 00000000ff01 \
>      $(ip_to_hex 10 0 0 3) $(ip_to_hex 172 168 0 120)
>
>  OVS_WAIT_UNTIL([
> -    test 1 -eq $(as hv1 ovs-ofctl dump-flows br-int table=20 | \
> +    test 1 -eq $(as hv1 ovs-ofctl dump-flows br-int table=22 | \
>      grep "load:0x2->NXM_NX_PKT_MARK" -c)
>  ])
>
>  AT_CHECK([
> -    test 0 -eq $(as hv1 ovs-ofctl dump-flows br-int table=20 | \
> +    test 0 -eq $(as hv1 ovs-ofctl dump-flows br-int table=22 | \
>      grep "load:0x64->NXM_NX_PKT_MARK" -c)
>  ])
>
> @@ -22681,31 +22901,31 @@ AT_CHECK([
>  ])
>
>  AT_CHECK([ovn-sbctl lflow-list | grep -E "lr_in_policy.*priority=1001" | sort], [0], [dnl
> -  table=12(lr_in_policy       ), priority=1001 , dnl
> +  table=14(lr_in_policy       ), priority=1001 , dnl
>  match=(ip6), action=(pkt.mark = 4294967295; reg8[[0..15]] = 0; next;)
>  ])
>
>  ovn-nbctl --wait=hv set logical_router_policy $pol5 options:pkt_mark=-1
>  AT_CHECK([ovn-sbctl lflow-list | grep -E "lr_in_policy.*priority=1001" | sort], [0], [dnl
> -  table=12(lr_in_policy       ), priority=1001 , dnl
> +  table=14(lr_in_policy       ), priority=1001 , dnl
>  match=(ip6), action=(reg8[[0..15]] = 0; next;)
>  ])
>
>  ovn-nbctl --wait=hv set logical_router_policy $pol5 options:pkt_mark=2147483648
>  AT_CHECK([ovn-sbctl lflow-list | grep -E "lr_in_policy.*priority=1001" | sort], [0], [dnl
> -  table=12(lr_in_policy       ), priority=1001 , dnl
> +  table=14(lr_in_policy       ), priority=1001 , dnl
>  match=(ip6), action=(pkt.mark = 2147483648; reg8[[0..15]] = 0; next;)
>  ])
>
>  ovn-nbctl --wait=hv set logical_router_policy $pol5 options:pkt_mark=foo
>  AT_CHECK([ovn-sbctl lflow-list | grep -E "lr_in_policy.*priority=1001" | sort], [0], [dnl
> -  table=12(lr_in_policy       ), priority=1001 , dnl
> +  table=14(lr_in_policy       ), priority=1001 , dnl
>  match=(ip6), action=(reg8[[0..15]] = 0; next;)
>  ])
>
>  ovn-nbctl --wait=hv set logical_router_policy $pol5 options:pkt_mark=4294967296
>  AT_CHECK([ovn-sbctl lflow-list | grep -E "lr_in_policy.*priority=1001" | sort], [0], [dnl
> -  table=12(lr_in_policy       ), priority=1001 , dnl
> +  table=14(lr_in_policy       ), priority=1001 , dnl
>  match=(ip6), action=(reg8[[0..15]] = 0; next;)
>  ])
>
> @@ -23275,23 +23495,23 @@ check ovn-nbctl --wait=hv sync
>
>  # Ensure ECMP symmetric reply flows are not present on any hypervisor.
>  AT_CHECK([
> -    test 0 -eq $(as hv1 ovs-ofctl dump-flows br-int table=15 | \
> +    test 0 -eq $(as hv1 ovs-ofctl dump-flows br-int table=17 | \
>      grep "priority=100" | \
>      grep "ct(commit,zone=NXM_NX_REG11\\[[0..15\\]],exec(move:NXM_OF_ETH_SRC\\[[\\]]->NXM_NX_CT_LABEL\\[[32..79\\]],load:0x[[0-9]]->NXM_NX_CT_LABEL\\[[80..95\\]]))" -c)
>  ])
>  AT_CHECK([
> -    test 0 -eq $(as hv1 ovs-ofctl dump-flows br-int table=21 | \
> +    test 0 -eq $(as hv1 ovs-ofctl dump-flows br-int table=23 | \
>      grep "priority=200" | \
>      grep "actions=move:NXM_NX_CT_LABEL\\[[32..79\\]]->NXM_OF_ETH_DST\\[[\\]]" -c)
>  ])
>
>  AT_CHECK([
> -    test 0 -eq $(as hv2 ovs-ofctl dump-flows br-int table=15 | \
> +    test 0 -eq $(as hv2 ovs-ofctl dump-flows br-int table=17 | \
>      grep "priority=100" | \
>      grep "ct(commit,zone=NXM_NX_REG11\\[[0..15\\]],exec(move:NXM_OF_ETH_SRC\\[[\\]]->NXM_NX_CT_LABEL\\[[32..79\\]],load:0x[[0-9]]->NXM_NX_CT_LABEL\\[[80..95\\]]))" -c)
>  ])
>  AT_CHECK([
> -    test 0 -eq $(as hv2 ovs-ofctl dump-flows br-int table=21 | \
> +    test 0 -eq $(as hv2 ovs-ofctl dump-flows br-int table=23 | \
>      grep "priority=200" | \
>      grep "actions=move:NXM_NX_CT_LABEL\\[[32..79\\]]->NXM_OF_ETH_DST\\[[\\]]" -c)
>  ])
> @@ -23308,11 +23528,11 @@ AT_CAPTURE_FILE([hv2flows])
>
>  AT_CHECK([
>      for hv in 1 2; do
> -        grep table=15 hv${hv}flows | \
> +        grep table=17 hv${hv}flows | \
>          grep "priority=100" | \
>          grep -c "ct(commit,zone=NXM_NX_REG11\\[[0..15\\]],exec(move:NXM_OF_ETH_SRC\\[[\\]]->NXM_NX_CT_LABEL\\[[32..79\\]],load:0x[[0-9]]->NXM_NX_CT_LABEL\\[[80..95\\]]))"
>
> -        grep table=22 hv${hv}flows | \
> +        grep table=24 hv${hv}flows | \
>          grep "priority=200" | \
>          grep -c "actions=move:NXM_NX_CT_LABEL\\[[32..79\\]]->NXM_OF_ETH_DST\\[[\\]]"
>      done; :], [0], [dnl
> @@ -23932,7 +24152,7 @@ AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep "actions=controller" | grep
>  ])
>
>  # The packet should've been dropped in the lr_in_arp_resolve stage.
> -AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep -E "table=22, n_packets=1,.* priority=1,ip,metadata=0x${sw_key},nw_dst=10.0.1.1 actions=drop" -c], [0], [dnl
> +AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep -E "table=24, n_packets=1,.* priority=1,ip,metadata=0x${sw_key},nw_dst=10.0.1.1 actions=drop" -c], [0], [dnl
>  1
>  ])
>
> --
> 2.31.1
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>


More information about the dev mailing list