On 4/14/25 3:45 PM, Ales Musil wrote:
> 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>
> 

Hi Ales,

Thanks for the reviews!  I applied this series to main, 25.03, 24.09 and
24.03.

Regards,
Dumitru


_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to