On Mon, Apr 14, 2025 at 10:52 AM Dumitru Ceara <dce...@redhat.com> wrote:

> Since commit f2e8130d0a42 ("northd: Explicitly handle SNAT for ICMP
> need frag."), if LRP.gw_mtu is set, ovn-northd adds a priority 160
> logical flow in the lr_in_larger_pkts router pipeline that matches
> on "ct.trk && ct.rpl && ct.dnat" for egress traffic that's larger
> than the configured MTU (if REGBIT_PKT_LARGER] == 1):
>
>   table=23(lr_in_larger_pkts  ), priority=160,
>   match=(inport == "lrp1" && outport == "lrp0" && ip4 &&
>          reg9[1] && reg9[0] == 0 && ct.trk && ct.rpl && ct.dnat),
>   action=(icmp4_error {...};)
>
> The lr_in_larger_pkts logical pipeline stage (23) is translated by
> ovn-controller to OpenFlow table 31.
>
>  table=31, priority=160,
>    ct_state=+rpl+trk+dnat,ip,reg9=0x2/0x3,reg14=0x2,reg15=0x1,metadata=0x3
>    actions=controller(...)
>
> Due to the way ovs-vswitchd translates OF rules to datapath flows,
> all OpenFlow rules in table 31 that have a priority lower than 160
> automatically get an implicit match on the inverse ct_state match
> that's generated for the priority 160 OF rule, that is:
>
> ct_state=-trk-rpl-dnat
>
> On specific NICs, such matches (on dnat/snat ct_state) are not
> offloadable to hardware.
>
> However, in OVN, logical switches and logical routers pipelines both
> get translated to the same set of OpenFlow tables. In theory that's
> fine because the logical datapath distinction happens thanks to
> additional metadata field matches (the metadata OF field is actually
> logical datapath id).  But in this specific case it means that all
> logical switch traffic that hits OpenFlow table 31 will also generate
> a datapath flow that matches on ct_state=-trk-rpl-dnat, making it
> non-offloadable.
>
> E.g., in an OVN cluster with a logical switch that has no stateful
> config (no stateful ACLs or LBs) traffic hitting the following
> logical switch pipeline stage will also fail to be offloaded to
> hardware if there's a logical router with gw_mtu configured:
>
>   table=23(ls_in_dhcp_options ), priority=0, match=(1), action=(next;)
>
> That is essentially all traffic forwarded on that logical switch.
>
> Change the way we match on large packets that have been DNATed and
> instead of directly matching on ct_state first save that into a
> register (using the new ct_state_save() logical action).
>
> That means that with the configuration mentioned above:
> - all routed traffic that is less than MTU will now be forwarded by
>   a datapath flow matching on ct_state=-trk
> - all switched traffic will be forwarded by a datapath flow matching on
>   ct_state=-trk
>
> In order to not disrupt upgrades on stable branches generate the new
> logical flows only if the ct_state_save() action is supported by all
> ovn-controllers.
>
> Reported-at: https://issues.redhat.com/browse/FDP-1271
> Fixes: f2e8130d0a42 ("northd: Explicitly handle SNAT for ICMP need frag.")
> Signed-off-by: Dumitru Ceara <dce...@redhat.com>
> ---
> V2:
> - Addressed Ales' comment:
>   - simplified code that generates the ct_state match and removed not so
>     obvious micro-optimization
> ---
>  northd/northd.c          |  52 ++++++++++++----
>  northd/ovn-northd.8.xml  |   8 ++-
>  tests/ovn-northd.at      | 128 ++++++++++++++++++++++-----------------
>  tests/system-ovn-kmod.at |  49 ++++++++++++---
>  4 files changed, 160 insertions(+), 77 deletions(-)
>
> diff --git a/northd/northd.c b/northd/northd.c
> index 762e4e057d..1f9340e555 100644
> --- a/northd/northd.c
> +++ b/northd/northd.c
> @@ -213,6 +213,19 @@ BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 << 2));
>  /* Register used for storing persistent ACL IDs */
>  #define REG_ACL_ID "reg2[16..31]"
>
> +/* Register used for storing the ct_state in the router pipeline and
> + * ct_saved_state helpers, matching the ct_state bits definitions from
> + * ovs-fields(7). */
> +#define REG_CT_STATE "reg4[0..7]"
> +
> +static const char *reg_ct_state[] = {
> +#define CS_STATE(ENUM, INDEX, NAME) \
> +    [CS_##ENUM] = "reg4[" #INDEX "]",
> +
> +    CS_STATES
> +#undef CS_STATE
> +};
> +
>  /* Register used for temporarily store ECMP eth.src to avoid masked
> ct_label
>   * access. It doesn't really occupy registers because the content of the
>   * register is saved to stack and then restored in the same flow.
> @@ -282,10 +295,13 @@ BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 << 2));
>   * | R3  |        UNUSED             | 1 |                 |   |
>                           |
>   * |     |                           |   |                 |   |
>                           |
>   *
> +-----+---------------------------+---+-----------------+---+------------------------------------+
> - * | R4  |        REG_LB_IPV4        | X |                 |   |
>                           |
> - * |     |  (>= IN_LB_AFF_CHECK &&   | R |                 |   |
>                           |
> - * |     |   <= IN_LB_AFF_LEARN)     | R |                 |   |
>                           |
> - * +-----+---------------------------+ E |     UNUSED      | X |
>                           |
> + * |     |        REG_LB_IPV4        |   |                 |   |
>                           |
> + * | R4  |  (>= IN_LB_AFF_CHECK &&   |   |                 |   |
>                           |
> + * |     |   <= IN_LB_AFF_LEARN)     |   |                 |   |
>                           |
> + * |     |        REG_CT_STATE       | X |                 |   |
>                           |
> + * |     |  (>= IN_CHK_PKT_LEN &&    | R |     UNUSED      |   |
>                           |
> + * |     |   <= IN_LARGER_PKTS)      | R |                 |   |
>                           |
> + * +-----+---------------------------+ E |                 | X |
>                           |
>   * | R5  |  SRC_IPV4 for ARP-REQ     | G |                 | X |
>   REG_LB_IPV6             |
>   * |     |      (>= IP_INPUT)        | 2 |                 | R |
> (>= IN_LB_AFF_CHECK &&      |
>   * +-----+---------------------------+---+-----------------+ E |
>  <= IN_LB_AFF_LEARN)        |
> @@ -14690,6 +14706,7 @@ build_icmperr_pkt_big_flows(struct ovn_port *op,
> int mtu,
>                              const struct shash *meter_groups, struct ds
> *match,
>                              struct ds *actions, enum ovn_stage stage,
>                              struct ovn_port *outport,
> +                            const char *ct_state_match,
>                              struct lflow_ref *lflow_ref)
>  {
>      const char *ipv4_meter = copp_meter_get(COPP_ICMP4_ERR,
> op->od->nbr->copp,
> @@ -14701,15 +14718,17 @@ build_icmperr_pkt_big_flows(struct ovn_port *op,
> int mtu,
>      ds_put_format(match, "inport == %s", op->json_key);
>
>      if (outport) {
> +        ovs_assert(ct_state_match);
> +
>          ds_put_format(match, " && outport == %s", outport->json_key);
>
>          create_icmp_need_frag_lflow(op, mtu, actions, match, ipv4_meter,
>                                      lflows, lflow_ref, stage, 160, false,
> -                                    "ct.trk && ct.rpl && ct.dnat",
> +                                    ct_state_match,
>                                      "flags.icmp_snat = 1; ");
>          create_icmp_need_frag_lflow(op, mtu, actions, match, ipv6_meter,
>                                      lflows, lflow_ref, stage, 160, true,
> -                                    "ct.trk && ct.rpl && ct.dnat",
> +                                    ct_state_match,
>                                      "flags.icmp_snat = 1; ");
>      }
>
> @@ -14735,15 +14754,25 @@ build_check_pkt_len_flows_for_lrp(struct
> ovn_port *op,
>
>      ds_clear(match);
>      ds_put_format(match, "outport == %s", op->json_key);
> +    const char *mtu_flow_action = features->ct_state_save
> +                                  ? REG_CT_STATE " = ct_state_save();
> next;"
> +                                  : "next;";
>      build_gateway_mtu_flow(lflows, op, S_ROUTER_IN_CHK_PKT_LEN, 50, 55,
> -                           match, actions, &op->nbrp->header_,
> -                           lflow_ref, "next;");
> +                           match, actions, &op->nbrp->header_, lflow_ref,
> +                           "%s", mtu_flow_action);
>
>      /* ingress traffic */
>      build_icmperr_pkt_big_flows(op, gw_mtu, lflows, meter_groups,
>                                  match, actions, S_ROUTER_IN_IP_INPUT,
> -                                NULL, lflow_ref);
> -
> +                                NULL, NULL, lflow_ref);
> +
> +    /* Additional match at egress on tracked and reply and dnat-ed
> traffic. */
> +    char *ct_match = features->ct_state_save
> +                     ? xasprintf("%s && %s && %s",
> +                                 reg_ct_state[CS_TRACKED],
> +                                 reg_ct_state[CS_REPLY_DIR],
> +                                 reg_ct_state[CS_DST_NAT])
> +                     : xstrdup("ct.trk && ct.rpl && ct.dnat");
>      for (size_t i = 0; i < op->od->nbr->n_ports; i++) {
>          struct ovn_port *rp = ovn_port_find(lr_ports,
>                                              op->od->nbr->ports[i]->name);
> @@ -14754,8 +14783,9 @@ build_check_pkt_len_flows_for_lrp(struct ovn_port
> *op,
>          /* egress traffic */
>          build_icmperr_pkt_big_flows(rp, gw_mtu, lflows, meter_groups,
>                                      match, actions,
> S_ROUTER_IN_LARGER_PKTS,
> -                                    op, lflow_ref);
> +                                    op, ct_match, lflow_ref);
>      }
> +    free(ct_match);
>
>      if (features->ct_commit_nat_v2) {
>          ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_OUT_POST_SNAT,
> 100,
> diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
> index 1a70ba579d..e087b6f59f 100644
> --- a/northd/ovn-northd.8.xml
> +++ b/northd/ovn-northd.8.xml
> @@ -4899,12 +4899,14 @@ output;
>        integer value, this table adds a priority-50 logical flow with
>        the match <code>outport == <var>GW_PORT</var></code> where
>        <var>GW_PORT</var> is the gateway router port and applies the
> -      action <code>check_pkt_larger</code> and advances the packet to
> -      the next table.
> +      actions <code>check_pkt_larger</code> and <code>ct_state_save</code>
> +      and then advances the packet to the next table.
>      </p>
>
>      <pre>
> -REGBIT_PKT_LARGER = check_pkt_larger(<var>L</var>); next;
> +REGBIT_PKT_LARGER = check_pkt_larger(<var>L</var>);
> +REG_CT_STATE = ct_state_save();
> +next;
>      </pre>
>
>      <p>
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> index 8ee3c977f2..12d6611b69 100644
> --- a/tests/ovn-northd.at
> +++ b/tests/ovn-northd.at
> @@ -6654,12 +6654,17 @@ AT_CHECK([ovn-sbctl --columns=tags list
> logical_flow | grep lsp0 -c], [0], [dnl
>  AT_CLEANUP
>  ])
>
> -OVN_FOR_EACH_NORTHD_NO_HV([
> -AT_SETUP([ovn -- gateway mtu check pkt larger flows])
> +m4_define([GATEWAY_MTU_FLOWS_TEST],
> +[OVN_FOR_EACH_NORTHD_NO_HV([
> +AT_SETUP([ovn -- gateway mtu check pkt larger flows - ct-state-save=$2])
>  ovn_start
>
> -check ovn-sbctl chassis-add ch1 geneve 127.0.0.1 --\
> -                set chassis ch1 other_config:ct-commit-nat-v2=true
> +AS_BOX([$1])
> +use_ct_save=$2
> +
> +check ovn-sbctl chassis-add ch1 geneve 127.0.0.1 --                     \
> +                set chassis ch1 other_config:ct-commit-nat-v2=true --   \
> +                set chassis ch1 other_config:ct-state-save=$use_ct_save
>
>  check ovn-nbctl ls-add sw0
>  check ovn-nbctl ls-add sw1
> @@ -6700,18 +6705,26 @@ check ovn-nbctl --wait=sb set logical_router_port
> lr0-public options:gateway_mtu
>  ovn-sbctl dump-flows lr0 > lr0flows
>  AT_CAPTURE_FILE([lr0flows])
>
> -AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows |
> ovn_strip_lflows], [0], [dnl
> +if [[ "$use_ct_save" == "true" ]]; then
> +    ct_save_action='reg4[[0..7]] = ct_state_save(); next'
> +    larger_pkts_ct_match='reg4[[5]] && reg4[[3]] && reg4[[7]]'
> +else
> +    ct_save_action='next'
> +    larger_pkts_ct_match='ct.trk && ct.rpl && ct.dnat'
> +fi
> +
> +AT_CHECK_UNQUOTED([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows
> | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_chk_pkt_len  ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_in_chk_pkt_len  ), priority=50   , match=(outport ==
> "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); next;)
> +  table=??(lr_in_chk_pkt_len  ), priority=50   , match=(outport ==
> "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); $ct_save_action;)
>    table=??(lr_in_larger_pkts  ), priority=0    , match=(1), action=(next;)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] ==
> 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:00:00:ff:01; ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255;
> icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag
> Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress,
> table=??); };)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] ==
> 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:00:00:ff:01; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff01;
> ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0;
> icmp6.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] ==
> 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255;
> icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag
> Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress,
> table=??); };)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] ==
> 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02;
> ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0;
> icmp6.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip4.dst =
> ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500;
> next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst =
> ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500;
> next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip4.dst =
> ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500;
> next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst =
> ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500;
> next(pipeline=ingress, table=??); };)
>  ])
>
>  AT_CHECK([grep -E "lr_in_admission.*check_pkt_larger" lr0flows |
> ovn_strip_lflows], [0], [dnl
> @@ -6739,18 +6752,18 @@ check ovn-nbctl --wait=sb set logical_router lr0
> options:chassis=ch1
>  ovn-sbctl dump-flows lr0 > lr0flows
>  AT_CAPTURE_FILE([lr0flows])
>
> -AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows |
> ovn_strip_lflows], [0], [dnl
> +AT_CHECK_UNQUOTED([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows
> | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_chk_pkt_len  ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_in_chk_pkt_len  ), priority=50   , match=(outport ==
> "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); next;)
> +  table=??(lr_in_chk_pkt_len  ), priority=50   , match=(outport ==
> "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); $ct_save_action;)
>    table=??(lr_in_larger_pkts  ), priority=0    , match=(1), action=(next;)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] ==
> 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:00:00:ff:01; ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255;
> icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag
> Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress,
> table=??); };)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] ==
> 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:00:00:ff:01; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff01;
> ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0;
> icmp6.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] ==
> 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255;
> icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag
> Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress,
> table=??); };)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] ==
> 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02;
> ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0;
> icmp6.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip4.dst =
> ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500;
> next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst =
> ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500;
> next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip4.dst =
> ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500;
> next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst =
> ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500;
> next(pipeline=ingress, table=??); };)
>  ])
>
>  AT_CHECK([grep -E "lr_in_admission.*check_pkt_larger" lr0flows |
> ovn_strip_lflows], [0], [dnl
> @@ -6775,19 +6788,19 @@ check ovn-nbctl --wait=sb set logical_router_port
> lr0-public options:gateway_mtu
>  ovn-sbctl dump-flows lr0 > lr0flows
>  AT_CAPTURE_FILE([lr0flows])
>
> -AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows |
> ovn_strip_lflows], [0], [dnl
> +AT_CHECK_UNQUOTED([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows
> | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_chk_pkt_len  ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_in_chk_pkt_len  ), priority=50   , match=(outport ==
> "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); next;)
> -  table=??(lr_in_chk_pkt_len  ), priority=55   , match=(outport ==
> "lr0-public" && (tcp)), action=(next;)
> +  table=??(lr_in_chk_pkt_len  ), priority=50   , match=(outport ==
> "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); $ct_save_action;)
> +  table=??(lr_in_chk_pkt_len  ), priority=55   , match=(outport ==
> "lr0-public" && (tcp)), action=($ct_save_action;)
>    table=??(lr_in_larger_pkts  ), priority=0    , match=(1), action=(next;)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] ==
> 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:00:00:ff:01; ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255;
> icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag
> Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress,
> table=??); };)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] ==
> 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:00:00:ff:01; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff01;
> ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0;
> icmp6.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] ==
> 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255;
> icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag
> Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress,
> table=??); };)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] ==
> 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02;
> ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0;
> icmp6.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip4.dst =
> ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500;
> next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst =
> ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500;
> next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip4.dst =
> ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500;
> next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst =
> ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500;
> next(pipeline=ingress, table=??); };)
>  ])
>
>  AT_CHECK([grep "lr_in_admission" lr0flows | grep -e "check_pkt_larger" -e
> "tcp" | ovn_strip_lflows], [0], [dnl
> @@ -6803,11 +6816,11 @@ check ovn-nbctl --wait=sb set logical_router_port
> lr0-sw0 options:gateway_mtu=14
>  ovn-sbctl dump-flows lr0 > lr0flows
>  AT_CAPTURE_FILE([lr0flows])
>
> -AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows |
> ovn_strip_lflows], [0], [dnl
> +AT_CHECK_UNQUOTED([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows
> | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_chk_pkt_len  ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_in_chk_pkt_len  ), priority=50   , match=(outport ==
> "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); next;)
> -  table=??(lr_in_chk_pkt_len  ), priority=50   , match=(outport ==
> "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); next;)
> -  table=??(lr_in_chk_pkt_len  ), priority=55   , match=(outport ==
> "lr0-public" && (tcp)), action=(next;)
> +  table=??(lr_in_chk_pkt_len  ), priority=50   , match=(outport ==
> "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); $ct_save_action;)
> +  table=??(lr_in_chk_pkt_len  ), priority=50   , match=(outport ==
> "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); $ct_save_action;)
> +  table=??(lr_in_chk_pkt_len  ), priority=55   , match=(outport ==
> "lr0-public" && (tcp)), action=($ct_save_action;)
>    table=??(lr_in_larger_pkts  ), priority=0    , match=(1), action=(next;)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] ==
> 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:20:20:12:13; ip4.dst = ip4.src; ip4.src = 172.168.0.100; ip.ttl =
> 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag
> Needed and DF was Set. */ icmp4.frag_mtu = 1400; next(pipeline=ingress,
> table=??); };)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-public" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] ==
> 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:20:20:12:13; ip6.dst = ip6.src; ip6.src = fe80::200:20ff:fe20:1213;
> ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0;
> icmp6.frag_mtu = 1400; next(pipeline=ingress, table=??); };)
> @@ -6817,14 +6830,14 @@ AT_CHECK([grep -e "chk_pkt_len" -e
> "lr_in_larger_pkts" lr0flows | ovn_strip_lflo
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] ==
> 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02;
> ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0;
> icmp6.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-sw1" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0),
> action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255;
> icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag
> Needed and DF was Set. */ icmp4.frag_mtu = 1400; next(pipeline=ingress,
> table=??); };)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-sw1" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0),
> action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02;
> ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0;
> icmp6.frag_mtu = 1400; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip4.dst =
> ip4.src; ip4.src = 172.168.0.100; ip.ttl = 255; icmp4.type = 3; /*
> Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set.
> */ icmp4.frag_mtu = 1400; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-public" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip6.dst =
> ip6.src; ip6.src = fe80::200:20ff:fe20:1213; ip.ttl = 255; icmp6.type = 2;
> /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400;
> next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip4.dst =
> ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500;
> next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst =
> ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500;
> next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0 &&
> ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst =
> ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1400; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0 &&
> ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400;
> next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip4.dst =
> ip4.src; ip4.src = 172.168.0.100; ip.ttl = 255; icmp4.type = 3; /*
> Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set.
> */ icmp4.frag_mtu = 1400; next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-public" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip6.dst =
> ip6.src; ip6.src = fe80::200:20ff:fe20:1213; ip.ttl = 255; icmp6.type = 2;
> /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400;
> next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip4.dst =
> ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500;
> next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst =
> ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500;
> next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0 &&
> $larger_pkts_ct_match), action=(icmp4_error {flags.icmp_snat = 1; reg9[[0]]
> = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src
> = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */
> icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1400;
> next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0 &&
> $larger_pkts_ct_match), action=(icmp6_error {flags.icmp_snat = 1; reg9[[0]]
> = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src
> = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big.
> */ icmp6.code = 0; icmp6.frag_mtu = 1400; next(pipeline=ingress, table=??);
> };)
>  ])
>
>  AT_CHECK([grep "lr_in_admission.*check_pkt_larger" lr0flows |
> ovn_strip_lflows], [0], [dnl
> @@ -6853,12 +6866,12 @@ check ovn-nbctl --wait=sb set logical_router_port
> lr0-sw0 options:gateway_mtu_by
>  ovn-sbctl dump-flows lr0 > lr0flows
>  AT_CAPTURE_FILE([lr0flows])
>
> -AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows |
> ovn_strip_lflows], [0], [dnl
> +AT_CHECK_UNQUOTED([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows
> | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_chk_pkt_len  ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_in_chk_pkt_len  ), priority=50   , match=(outport ==
> "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); next;)
> -  table=??(lr_in_chk_pkt_len  ), priority=50   , match=(outport ==
> "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); next;)
> -  table=??(lr_in_chk_pkt_len  ), priority=55   , match=(outport ==
> "lr0-public" && (tcp)), action=(next;)
> -  table=??(lr_in_chk_pkt_len  ), priority=55   , match=(outport ==
> "lr0-sw0" && (tcp)), action=(next;)
> +  table=??(lr_in_chk_pkt_len  ), priority=50   , match=(outport ==
> "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); $ct_save_action;)
> +  table=??(lr_in_chk_pkt_len  ), priority=50   , match=(outport ==
> "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); $ct_save_action;)
> +  table=??(lr_in_chk_pkt_len  ), priority=55   , match=(outport ==
> "lr0-public" && (tcp)), action=($ct_save_action;)
> +  table=??(lr_in_chk_pkt_len  ), priority=55   , match=(outport ==
> "lr0-sw0" && (tcp)), action=($ct_save_action;)
>    table=??(lr_in_larger_pkts  ), priority=0    , match=(1), action=(next;)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] ==
> 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:20:20:12:13; ip4.dst = ip4.src; ip4.src = 172.168.0.100; ip.ttl =
> 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag
> Needed and DF was Set. */ icmp4.frag_mtu = 1400; next(pipeline=ingress,
> table=??); };)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-public" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] ==
> 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:20:20:12:13; ip6.dst = ip6.src; ip6.src = fe80::200:20ff:fe20:1213;
> ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0;
> icmp6.frag_mtu = 1400; next(pipeline=ingress, table=??); };)
> @@ -6868,14 +6881,14 @@ AT_CHECK([grep -e "chk_pkt_len" -e
> "lr_in_larger_pkts" lr0flows | ovn_strip_lflo
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] ==
> 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02;
> ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0;
> icmp6.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-sw1" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0),
> action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255;
> icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag
> Needed and DF was Set. */ icmp4.frag_mtu = 1400; next(pipeline=ingress,
> table=??); };)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-sw1" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0),
> action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02;
> ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0;
> icmp6.frag_mtu = 1400; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip4.dst =
> ip4.src; ip4.src = 172.168.0.100; ip.ttl = 255; icmp4.type = 3; /*
> Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set.
> */ icmp4.frag_mtu = 1400; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-public" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip6.dst =
> ip6.src; ip6.src = fe80::200:20ff:fe20:1213; ip.ttl = 255; icmp6.type = 2;
> /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400;
> next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip4.dst =
> ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500;
> next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst =
> ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500;
> next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0 &&
> ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst =
> ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1400; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0 &&
> ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400;
> next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip4.dst =
> ip4.src; ip4.src = 172.168.0.100; ip.ttl = 255; icmp4.type = 3; /*
> Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set.
> */ icmp4.frag_mtu = 1400; next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-public" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip6.dst =
> ip6.src; ip6.src = fe80::200:20ff:fe20:1213; ip.ttl = 255; icmp6.type = 2;
> /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400;
> next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip4.dst =
> ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500;
> next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst =
> ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1500; next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500;
> next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0 &&
> $larger_pkts_ct_match), action=(icmp4_error {flags.icmp_snat = 1; reg9[[0]]
> = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src
> = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */
> icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1400;
> next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0 &&
> $larger_pkts_ct_match), action=(icmp6_error {flags.icmp_snat = 1; reg9[[0]]
> = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src
> = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big.
> */ icmp6.code = 0; icmp6.frag_mtu = 1400; next(pipeline=ingress, table=??);
> };)
>  ])
>
>  AT_CHECK([grep "lr_in_admission" lr0flows | grep -e "check_pkt_larger" -e
> "tcp" | ovn_strip_lflows], [0], [dnl
> @@ -6894,19 +6907,19 @@ check ovn-nbctl --wait=sb clear
> logical_router_port lr0-public options
>  ovn-sbctl dump-flows lr0 > lr0flows
>  AT_CAPTURE_FILE([lr0flows])
>
> -AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows |
> ovn_strip_lflows], [0], [dnl
> +AT_CHECK_UNQUOTED([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows
> | ovn_strip_lflows], [0], [dnl
>    table=??(lr_in_chk_pkt_len  ), priority=0    , match=(1), action=(next;)
> -  table=??(lr_in_chk_pkt_len  ), priority=50   , match=(outport ==
> "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); next;)
> -  table=??(lr_in_chk_pkt_len  ), priority=55   , match=(outport ==
> "lr0-sw0" && (tcp)), action=(next;)
> +  table=??(lr_in_chk_pkt_len  ), priority=50   , match=(outport ==
> "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); $ct_save_action;)
> +  table=??(lr_in_chk_pkt_len  ), priority=55   , match=(outport ==
> "lr0-sw0" && (tcp)), action=($ct_save_action;)
>    table=??(lr_in_larger_pkts  ), priority=0    , match=(1), action=(next;)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] ==
> 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:20:20:12:13; ip4.dst = ip4.src; ip4.src = 172.168.0.100; ip.ttl =
> 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag
> Needed and DF was Set. */ icmp4.frag_mtu = 1400; next(pipeline=ingress,
> table=??); };)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-public" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] ==
> 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:20:20:12:13; ip6.dst = ip6.src; ip6.src = fe80::200:20ff:fe20:1213;
> ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0;
> icmp6.frag_mtu = 1400; next(pipeline=ingress, table=??); };)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-sw1" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0),
> action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255;
> icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag
> Needed and DF was Set. */ icmp4.frag_mtu = 1400; next(pipeline=ingress,
> table=??); };)
>    table=??(lr_in_larger_pkts  ), priority=150  , match=(inport ==
> "lr0-sw1" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0),
> action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst =
> 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02;
> ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0;
> icmp6.frag_mtu = 1400; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip4.dst =
> ip4.src; ip4.src = 172.168.0.100; ip.ttl = 255; icmp4.type = 3; /*
> Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set.
> */ icmp4.frag_mtu = 1400; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-public" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip6.dst =
> ip6.src; ip6.src = fe80::200:20ff:fe20:1213; ip.ttl = 255; icmp6.type = 2;
> /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400;
> next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0 &&
> ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst =
> ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination
> Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */
> icmp4.frag_mtu = 1400; next(pipeline=ingress, table=??); };)
> -  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0 &&
> ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst =
> ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /*
> Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400;
> next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp4_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip4.dst =
> ip4.src; ip4.src = 172.168.0.100; ip.ttl = 255; icmp4.type = 3; /*
> Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set.
> */ icmp4.frag_mtu = 1400; next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-public" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0
> && $larger_pkts_ct_match), action=(icmp6_error {flags.icmp_snat = 1;
> reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip6.dst =
> ip6.src; ip6.src = fe80::200:20ff:fe20:1213; ip.ttl = 255; icmp6.type = 2;
> /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400;
> next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0 &&
> $larger_pkts_ct_match), action=(icmp4_error {flags.icmp_snat = 1; reg9[[0]]
> = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src
> = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */
> icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1400;
> next(pipeline=ingress, table=??); };)
> +  table=??(lr_in_larger_pkts  ), priority=160  , match=(inport ==
> "lr0-sw1" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0 &&
> $larger_pkts_ct_match), action=(icmp6_error {flags.icmp_snat = 1; reg9[[0]]
> = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src
> = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big.
> */ icmp6.code = 0; icmp6.frag_mtu = 1400; next(pipeline=ingress, table=??);
> };)
>  ])
>
>  check ovn-nbctl --wait=sb clear logical_router_port lr0-sw0 options
> @@ -6946,7 +6959,10 @@ ovn-sbctl dump-flows lr0 > lr0flows
>  AT_CHECK([grep -E "lr_out_post_snat.*ct_commit_nat" lr0flows], [1])
>
>  AT_CLEANUP
> -])
> +])])
> +
> +GATEWAY_MTU_FLOWS_TEST([Simulate hv that does not support
> 'ct-state-save'], [false])
> +GATEWAY_MTU_FLOWS_TEST([Simulate hv that supports 'ct-state-save'],
> [true])
>
>  OVN_FOR_EACH_NORTHD_NO_HV([
>  AT_SETUP([ovn -- static routes flows])
> diff --git a/tests/system-ovn-kmod.at b/tests/system-ovn-kmod.at
> index df00f99f7d..f0d4de1f8e 100644
> --- a/tests/system-ovn-kmod.at
> +++ b/tests/system-ovn-kmod.at
> @@ -922,9 +922,11 @@ dnl Logical network:
>  dnl 2 logical switches "public" (192.168.10.0/24 and fd10::/64)
>  dnl and "internal" (192.168.20.0/24 and fd20::/64) connected to a router
> lr.
>  dnl internal has a client.
> -dnl server is connected through localnet.
> +dnl Server1 is connected through localnet.
> +dnl Server2 is connected to the same switch as the client.
>  dnl
> -dnl Server IP 192.168.10.2 fd10:2
> +dnl Server1 IP 192.168.10.2 fd10:2
> +dnl Server1 IP 192.168.20.3 fd20:3
>  dnl Client IP 192.168.20.2 fd20:2
>  dnl
>  dnl SNAT for internal 192.168.20.0/24 with router ip 192.168.10.1.
> @@ -960,17 +962,25 @@ check ovn-nbctl lsp-add public ln_port \
>                  -- lsp-set-type ln_port localnet \
>                  -- lsp-set-options ln_port network_name=phynet
>
> -ADD_NAMESPACES(server)
> -ADD_VETH(server, server, br-ext, "fd10::2/64", "f0:00:00:01:02:03",
> "fd10::1",
> +ADD_NAMESPACES(server1)
> +ADD_VETH(server1, server1, br-ext, "fd10::2/64", "f0:00:00:01:02:03",
> "fd10::1",
>           "nodad", "192.168.10.2/24", "192.168.10.1")
> -NS_EXEC([server], [ip a show dev server])
> +NS_EXEC([server1], [ip a show dev server1])
>
>  ADD_NAMESPACES(client)
>  ADD_VETH(client, client, br-int, "fd20::2/64", "f0:00:0f:01:02:03",
> "fd20::1",
>           "nodad", "192.168.20.2/24", "192.168.20.1")
>  NS_EXEC([client], [ip a show dev client])
> +
> +ADD_NAMESPACES(server2)
> +ADD_VETH(server2, server2, br-int, "fd20::3/64", "f0:00:0f:01:02:04",
> "fd20::1",
> +         "nodad", "192.168.20.3/24", "192.168.20.1")
> +NS_EXEC([server2], [ip a show dev server2])
> +
>  check ovn-nbctl lsp-add internal client \
>    -- lsp-set-addresses client "f0:00:0f:01:02:03 192.168.20.2 fd20::2"
> +check ovn-nbctl lsp-add internal server2 \
> +  -- lsp-set-addresses server2 "f0:00:0f:01:02:04 192.168.20.3 fd20::3"
>
>  check ovn-nbctl set logical_router lr options:chassis=hv1
>  check ovn-nbctl set logical_router_port lr-internal
> options:gateway_mtu=1300
> @@ -979,6 +989,7 @@ check ovn-nbctl lr-nat-add lr snat 192.168.10.1
> 192.168.20.0/24
>  check ovn-nbctl lr-nat-add lr snat fd10::1 fd20::/64
>
>  OVN_POPULATE_ARP
> +wait_for_ports_up
>  check ovn-nbctl --wait=hv sync
>
>  ovn-nbctl show
> @@ -994,7 +1005,7 @@ NS_CHECK_EXEC([client], [ping -c 1 -W 2 -s 1400
> 192.168.10.2 | FORMAT_PING],
>  ])
>
>  NS_CHECK_EXEC([client], [ip r get 192.168.10.2 | grep -q "mtu 1300"])
> -NS_CHECK_EXEC([server], [ip r get 192.168.10.1 | grep -q "mtu 1300"])
> +NS_CHECK_EXEC([server1], [ip r get 192.168.10.1 | grep -q "mtu 1300"])
>
>  AS_BOX([IPv6])
>  NS_CHECK_EXEC([client], [ping -c 1 -W 2 -s 1400 fd10::2 | grep -q "Packet
> too big: mtu=1300"])
> @@ -1005,7 +1016,31 @@ NS_CHECK_EXEC([client], [ping -c 1 -W 2 -s 1400
> fd10::2 | FORMAT_PING],
>  ])
>
>  NS_CHECK_EXEC([client], [ip r get fd10::2 | grep -q "mtu 1300"])
> -NS_CHECK_EXEC([server], [ip r get fd10::1 | grep -q "mtu 1300"])
> +NS_CHECK_EXEC([server1], [ip r get fd10::1 | grep -q "mtu 1300"])
> +
> +AS_BOX([Switched traffic - smaller than MTU - connect to server2])
> +check ovs-appctl revalidator/purge
> +NS_CHECK_EXEC([client], [ping -c 1 -W 2 192.168.20.3 | FORMAT_PING],
> +[0], [dnl
> +1 packets transmitted, 1 received, 0% packet loss, time 0ms
> +])
> +NS_CHECK_EXEC([client], [ping -c 1 -W 2 fd20::3 | FORMAT_PING],
> +[0], [dnl
> +1 packets transmitted, 1 received, 0% packet loss, time 0ms
> +])
> +
> +dnl While the traffic is only switched, OpenFlow tables are shared between
> +dnl router and switch datapaths, making it such that stateful
> configurations
> +dnl in the router pipeline can cause ct_state matches to "leak" to switch
> +dnl specific datapath flows.
> +dnl
> +dnl Ensure datapath flows don't match on any dnat and/or snat conntrack
> states.
> +dnl Those are known to not be offloadable to hardware.
> +ovs-appctl dpctl/dump-flows > dp-flows
> +AT_CAPTURE_FILE([dp-flows])
> +AT_CHECK([grep 'ct_state(.*nat.*)' -c dp-flows], [1], [dnl
> +0
> +])
>
>  ovn-appctl -t ovn-controller vlog/set info
>
> --
> 2.49.0
>
>
Looks good to me, thanks.

Acked-by: Ales Musil <amu...@redhat.com>
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to