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

Mark Gray mark.d.gray at redhat.com
Tue Jul 27 12:46:12 UTC 2021


On 24/07/2021 15:01, Lorenzo Bianconi wrote:
> Introduce check_pkt_larger action for ingress traffic
> entering the cluster from a distributed gw router port
> or from a gw router. This patch enables pMTU discovery
> for ingress traffic.
> 
> Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi at redhat.com>
> ---
>  northd/ovn-northd.8.xml |  60 +++++++++++--
>  northd/ovn-northd.c     | 184 +++++++++++++++++++++++-----------------
>  northd/ovn_northd.dl    | 157 +++++++++++++++++++++++++++++++---
>  tests/ovn-northd.at     |  40 ++++-----
>  tests/ovn.at            | 135 ++++++++++++++++++++++++++++-
>  5 files changed, 458 insertions(+), 118 deletions(-)
> 
> diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
> index 5f2b43cd1..290de7540 100644
> --- a/northd/ovn-northd.8.xml
> +++ b/northd/ovn-northd.8.xml
> @@ -1940,6 +1940,15 @@ output;
>            <code>eth.dst == <var>E</var></code> is only programmed on
>            the gateway port instance on the gateway chassis.
>          </p>
> +
> +        <p>
> +          For a distributed logical router or for gateway router where
> +          the port is configured with <code>options:gateway_mtu</code>
> +          the action of the above flow is modified adding
> +          <code>check_pkt_larger</code> in order to mark the packet
> +          setting <code>REGBIT_PKT_LARGER</code> if the size is greater
> +          than the MTU

nit: Forgot trailing '.'

> +        </p>
>        </li>
>  
>        <li>
> @@ -2164,6 +2173,46 @@ next;
>      </p>
>  
>      <ul>
> +      <li>
> +        <p>
> +          For distributed logical routers or gateway routers with gateway port
> +          configured with <code>options:gateway_mtu</code> to a valid integer
> +          value, a priority-150 flow with the match <code>inport ==
> +          <var>LRP</var> && REGBIT_PKT_LARGER &&
> +          REGBIT_EGRESS_LOOPBACK == 0</code>, where <var>LRP</var> is the
> +          logical router port and applies the following action for ipv4
> +          and ipv6 respectively:
> +        </p>
> +
> +    <pre>
> +icmp4 {
> +    icmp4.type = 3; /* Destination Unreachable. */
> +    icmp4.code = 4;  /* Frag Needed and DF was Set. */
> +    icmp4.frag_mtu = <var>M</var>;
> +    eth.dst = <var>E</var>;
> +    ip4.dst = ip4.src;
> +    ip4.src = <var>I</var>;
> +    ip.ttl = 255;
> +    REGBIT_EGRESS_LOOPBACK = 1;
> +    REGBIT_PKT_LARGER 0;
> +    next(pipeline=ingress, table=0);
> +};
> +
> +icmp6 {
> +    icmp6.type = 2;
> +    icmp6.code = 0;
> +    icmp6.frag_mtu = <var>M</var>;
> +    eth.dst = <var>E</var>;
> +    ip6.dst = ip6.src;
> +    ip6.src = <var>I</var>;
> +    ip.ttl = 255;
> +    REGBIT_EGRESS_LOOPBACK = 1;
> +    REGBIT_PKT_LARGER 0;
> +    next(pipeline=ingress, table=0);
> +};
> +    </pre>
> +      </li>
> +
>        <li>
>          <p>
>            For each NAT entry of a distributed logical router  (with
> @@ -3705,12 +3754,11 @@ REGBIT_PKT_LARGER = check_pkt_larger(<var>L</var>); next;
>      <p>
>        For distributed logical routers or gateway routers with gateway port
>        configured with <code>options:gateway_mtu</code> to a valid integer
> -      value, this table adds the following priority-50 logical flow for each
> +      value, this table adds the following priority-150 logical flow for each

Why have you chnaged from a priority 50 flow to a priority 150 flow?

>        logical router port with the match <code>inport == <var>LRP</var>
> -      && outport == <var>GW_PORT</var> &&
> -      REGBIT_PKT_LARGER</code>, where <var>LRP</var> is the logical
> -      router port and <var>GW_PORT</var> is the gateway router port and applies
> -      the following action for ipv4 and ipv6 respectively:
> +      && REGBIT_PKT_LARGER && !REGBIT_EGRESS_LOOPBACK</code>,
> +      where <var>LRP</var> is the logical router port and applies the following
> +      action for ipv4 and ipv6 respectively:
>      </p>
>  
>      <pre>
> @@ -3723,6 +3771,7 @@ icmp4 {
>      ip4.src = <var>I</var>;
>      ip.ttl = 255;
>      REGBIT_EGRESS_LOOPBACK = 1;
> +    REGBIT_PKT_LARGER = 0;
>      next(pipeline=ingress, table=0);
>  };
>  
> @@ -3735,6 +3784,7 @@ icmp6 {
>      ip6.src = <var>I</var>;
>      ip.ttl = 255;
>      REGBIT_EGRESS_LOOPBACK = 1;
> +    REGBIT_PKT_LARGER = 0;
>      next(pipeline=ingress, table=0);
>  };
>      </pre>
> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> index 20f8d7b73..9d6f52c2e 100644
> --- a/northd/ovn-northd.c
> +++ b/northd/ovn-northd.c
> @@ -9952,6 +9952,10 @@ build_adm_ctrl_flows_for_lrouter(
>      }
>  }
>  
> +static void
> +build_check_pkt_len_action_string(struct ovn_port *op, int *pmtu,
> +                                  struct ds *actions);
> +
>  /* Logical router ingress Table 0: L2 Admission Control
>   * This table drops packets that the router shouldn’t see at all based
>   * on their Ethernet headers.
> @@ -9979,6 +9983,8 @@ build_adm_ctrl_flows_for_lrouter_port(
>           * the pipeline.
>           */
>          ds_clear(actions);
> +
> +        build_check_pkt_len_action_string(op, NULL, actions);
>          ds_put_format(actions, REG_INPORT_ETH_ADDR " = %s; next;",
>                        op->lrp_networks.ea_s);
>  
> @@ -10914,33 +10920,121 @@ build_arp_resolve_flows_for_lrouter_port(
>  
>  }
>  
> +static void
> +build_icmperr_pkt_big_flows(struct ovn_port *op, int mtu, struct hmap *lflows,
> +                            struct shash *meter_groups, struct ds *match,
> +                            struct ds *actions, enum ovn_stage stage)
> +{
> +    if (op->lrp_networks.ipv4_addrs) {
> +        ds_clear(match);
> +        ds_put_format(match,
> +                      "inport == %s && ip4 && "REGBIT_PKT_LARGER
> +                      " && "REGBIT_EGRESS_LOOPBACK" == 0", op->json_key);
> +
> +        ds_clear(actions);
> +        /* Set icmp4.frag_mtu to gw_mtu */
> +        ds_put_format(actions,
> +            "icmp4_error {"
> +            REGBIT_EGRESS_LOOPBACK" = 1; "
> +            REGBIT_PKT_LARGER" = 0; "
> +            "eth.dst = %s; "
> +            "ip4.dst = ip4.src; "
> +            "ip4.src = %s; "
> +            "ip.ttl = 255; "
> +            "icmp4.type = 3; /* Destination Unreachable. */ "
> +            "icmp4.code = 4; /* Frag Needed and DF was Set. */ "
> +            "icmp4.frag_mtu = %d; "
> +            "next(pipeline=ingress, table=%d); };",
> +            op->lrp_networks.ea_s,
> +            op->lrp_networks.ipv4_addrs[0].addr_s,
> +            mtu, ovn_stage_get_table(S_ROUTER_IN_ADMISSION));
> +        ovn_lflow_add_with_hint__(lflows, op->od, stage, 150,
> +                                  ds_cstr(match), ds_cstr(actions),
> +                                  NULL,
> +                                  copp_meter_get(
> +                                        COPP_ICMP4_ERR,
> +                                        op->od->nbr->copp,
> +                                        meter_groups),
> +                                  &op->nbrp->header_);
> +    }
> +
> +    if (op->lrp_networks.ipv6_addrs) {
> +        ds_clear(match);
> +        ds_put_format(match, "inport == %s && ip6 && "REGBIT_PKT_LARGER
> +                      " && "REGBIT_EGRESS_LOOPBACK" == 0", op->json_key);
> +
> +        ds_clear(actions);
> +        /* Set icmp6.frag_mtu to gw_mtu */
> +        ds_put_format(actions,
> +            "icmp6_error {"
> +            REGBIT_EGRESS_LOOPBACK" = 1; "
> +            REGBIT_PKT_LARGER" = 0; "
> +            "eth.dst = %s; "
> +            "ip6.dst = ip6.src; "
> +            "ip6.src = %s; "
> +            "ip.ttl = 255; "
> +            "icmp6.type = 2; /* Packet Too Big. */ "
> +            "icmp6.code = 0; "
> +            "icmp6.frag_mtu = %d; "
> +            "next(pipeline=ingress, table=%d); };",
> +            op->lrp_networks.ea_s,
> +            op->lrp_networks.ipv6_addrs[0].addr_s,
> +            mtu, ovn_stage_get_table(S_ROUTER_IN_ADMISSION));
> +        ovn_lflow_add_with_hint__(lflows, op->od, stage, 150,
> +                                  ds_cstr(match), ds_cstr(actions),
> +                                  NULL,
> +                                  copp_meter_get(
> +                                        COPP_ICMP6_ERR,
> +                                        op->od->nbr->copp,
> +                                        meter_groups),
> +                                  &op->nbrp->header_);
> +    }
> +}
> +
> +static void
> +build_check_pkt_len_action_string(struct ovn_port *op, int *pmtu,
> +                                  struct ds *actions)

Could you just return the pmtu? i.e. something like

static int
build_check_pkt_len_action_string(struct ovn_port *op,
         struct ds *actions)
{
   int gw_mtu = smap_get_int(&op->nbrp->options, "gateway_mtu", 0);

   if (gw_mtu > 0) {
       /* Add the flows only if gateway_mtu is configured. */
       ds_put_format(actions,
                     REGBIT_PKT_LARGER" = check_pkt_larger(%d); ",
                     gw_mtu + VLAN_ETH_HEADER_LEN);
   }

   return gw_mtu
}


> +{
> +    int gw_mtu = smap_get_int(&op->nbrp->options, "gateway_mtu", 0);
> +
> +    if (gw_mtu > 0) {
> +        /* Add the flows only if gateway_mtu is configured. */
> +        ds_put_format(actions,
> +                      REGBIT_PKT_LARGER" = check_pkt_larger(%d); ",
> +                      gw_mtu + VLAN_ETH_HEADER_LEN);
> +    }
> +    if (pmtu) {
> +        *pmtu = gw_mtu;
> +    }
> +}
> +
>  static void
>  build_check_pkt_len_flows_for_lrp(struct ovn_port *op,
>                                    struct hmap *lflows, struct hmap *ports,
>                                    struct shash *meter_groups, struct ds *match,
>                                    struct ds *actions)
>  {
> -    int gw_mtu = 0;
> +    int gw_mtu;
>  
> -    if (op->nbrp) {
> -         gw_mtu = smap_get_int(&op->nbrp->options, "gateway_mtu", 0);
> -    }
> -    /* Add the flows only if gateway_mtu is configured. */
> +    ds_clear(actions);
> +    build_check_pkt_len_action_string(op, &gw_mtu, actions);
>      if (gw_mtu <= 0) {
>          return;
>      }
>  
> +    ds_put_format(actions, "next;");
> +
>      ds_clear(match);
>      ds_put_format(match, "outport == %s", op->json_key);
>  
> -    ds_clear(actions);
> -    ds_put_format(actions,
> -                  REGBIT_PKT_LARGER" = check_pkt_larger(%d);"
> -                  " next;", gw_mtu + VLAN_ETH_HEADER_LEN);
>      ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_CHK_PKT_LEN, 50,
>                              ds_cstr(match), ds_cstr(actions),
>                              &op->nbrp->header_);
>  
> +    /* ingress traffic */
> +    build_icmperr_pkt_big_flows(op, gw_mtu, lflows, meter_groups,
> +                                match, actions, S_ROUTER_IN_IP_INPUT);
> +
>      for (size_t i = 0; i < op->od->nbr->n_ports; i++) {
>          struct ovn_port *rp = ovn_port_find(ports,
>                                              op->od->nbr->ports[i]->name);
> @@ -10948,73 +11042,9 @@ build_check_pkt_len_flows_for_lrp(struct ovn_port *op,
>              continue;
>          }
>  
> -        if (rp->lrp_networks.ipv4_addrs) {
> -            ds_clear(match);
> -            ds_put_format(match, "inport == %s && outport == %s"
> -                          " && ip4 && "REGBIT_PKT_LARGER,
> -                          rp->json_key, op->json_key);
> -
> -            ds_clear(actions);
> -            /* Set icmp4.frag_mtu to gw_mtu */
> -            ds_put_format(actions,
> -                "icmp4_error {"
> -                REGBIT_EGRESS_LOOPBACK" = 1; "
> -                "eth.dst = %s; "
> -                "ip4.dst = ip4.src; "
> -                "ip4.src = %s; "
> -                "ip.ttl = 255; "
> -                "icmp4.type = 3; /* Destination Unreachable. */ "
> -                "icmp4.code = 4; /* Frag Needed and DF was Set. */ "
> -                "icmp4.frag_mtu = %d; "
> -                "next(pipeline=ingress, table=%d); };",
> -                rp->lrp_networks.ea_s,
> -                rp->lrp_networks.ipv4_addrs[0].addr_s,
> -                gw_mtu,
> -                ovn_stage_get_table(S_ROUTER_IN_ADMISSION));
> -            ovn_lflow_add_with_hint__(lflows, op->od,
> -                                      S_ROUTER_IN_LARGER_PKTS, 50,
> -                                      ds_cstr(match), ds_cstr(actions),
> -                                      NULL,
> -                                      copp_meter_get(
> -                                            COPP_ICMP4_ERR,
> -                                            rp->od->nbr->copp,
> -                                            meter_groups),
> -                                      &rp->nbrp->header_);
> -        }
> -
> -        if (rp->lrp_networks.ipv6_addrs) {
> -            ds_clear(match);
> -            ds_put_format(match, "inport == %s && outport == %s"
> -                          " && ip6 && "REGBIT_PKT_LARGER,
> -                          rp->json_key, op->json_key);
> -
> -            ds_clear(actions);
> -            /* Set icmp6.frag_mtu to gw_mtu */
> -            ds_put_format(actions,
> -                "icmp6_error {"
> -                REGBIT_EGRESS_LOOPBACK" = 1; "
> -                "eth.dst = %s; "
> -                "ip6.dst = ip6.src; "
> -                "ip6.src = %s; "
> -                "ip.ttl = 255; "
> -                "icmp6.type = 2; /* Packet Too Big. */ "
> -                "icmp6.code = 0; "
> -                "icmp6.frag_mtu = %d; "
> -                "next(pipeline=ingress, table=%d); };",
> -                rp->lrp_networks.ea_s,
> -                rp->lrp_networks.ipv6_addrs[0].addr_s,
> -                gw_mtu,
> -                ovn_stage_get_table(S_ROUTER_IN_ADMISSION));
> -            ovn_lflow_add_with_hint__(lflows, op->od,
> -                                      S_ROUTER_IN_LARGER_PKTS, 50,
> -                                      ds_cstr(match), ds_cstr(actions),
> -                                      NULL,
> -                                      copp_meter_get(
> -                                            COPP_ICMP6_ERR,
> -                                            rp->od->nbr->copp,
> -                                            meter_groups),
> -                                      &rp->nbrp->header_);
> -        }
> +        /* egress traffic */
> +        build_icmperr_pkt_big_flows(rp, gw_mtu, lflows, meter_groups,
> +                                    match, actions, S_ROUTER_IN_LARGER_PKTS);
>      }
>  }
>  
> @@ -12121,6 +12151,8 @@ build_lrouter_ingress_flow(struct hmap *lflows, struct ovn_datapath *od,
>          * down in the pipeline.
>          */
>          ds_clear(actions);
> +
> +        build_check_pkt_len_action_string(od->l3dgw_port, NULL, actions);
>          ds_put_format(actions, REG_INPORT_ETH_ADDR " = %s; next;",
>                        od->l3dgw_port->lrp_networks.ea_s);
>  
> diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl
> index 4c7bf386a..63553be30 100644
> --- a/northd/ovn_northd.dl
> +++ b/northd/ovn_northd.dl
> @@ -4728,7 +4728,12 @@ for (&RouterPort(.lrp = lrp,
>       * This will save us from having to match on inport further down in
>       * the pipeline.
>       */
> -    var actions = "${rEG_INPORT_ETH_ADDR()} = ${lrp_networks.ea}; next;" in {
> +    var gw_mtu = lrp.options.get_int_def("gateway_mtu", 0) in
> +    var mtu = gw_mtu + vLAN_ETH_HEADER_LEN() in
> +    var actions = "${rEG_INPORT_ETH_ADDR()} = ${lrp_networks.ea}; " ++
> +    if (gw_mtu > 0) {
> +        "${rEGBIT_PKT_LARGER()} = check_pkt_larger(${mtu}); next;"
> +    } else { "next;" } in {
>          Flow(.logical_datapath = router._uuid,
>               .stage            = s_ROUTER_IN_ADMISSION(),
>               .priority         = 50,
> @@ -7558,11 +7563,12 @@ Flow(.logical_datapath = lr_uuid,
>      var mtu = gw_mtu + vLAN_ETH_HEADER_LEN().
>  MeteredFlow(.logical_datapath = lr_uuid,
>              .stage            = s_ROUTER_IN_LARGER_PKTS(),
> -            .priority         = 50,
> -            .__match          = "inport == ${rp.json_name} && outport == ${l3dgw_port_json_name} && "
> -                                "ip4 && ${rEGBIT_PKT_LARGER()}",
> +            .priority         = 150,
> +            .__match          = "inport == ${rp.json_name} && ip4 && "
> +                                "${rEGBIT_PKT_LARGER()} && ${rEGBIT_EGRESS_LOOPBACK()} == 0",
>              .actions          = "icmp4_error {"
>                                  "${rEGBIT_EGRESS_LOOPBACK()} = 1; "
> +                                "${rEGBIT_PKT_LARGER()} = 0; "
>                                  "eth.dst = ${rp.networks.ea}; "
>                                  "ip4.dst = ip4.src; "
>                                  "ip4.src = ${first_ipv4.addr}; "
> @@ -7585,13 +7591,46 @@ MeteredFlow(.logical_datapath = lr_uuid,
>      rp in &RouterPort(.router = r),
>      rp.lrp != l3dgw_port,
>      Some{var first_ipv4} = rp.networks.ipv4_addrs.nth(0).
> +
> +MeteredFlow(.logical_datapath = lr_uuid,
> +            .stage            = s_ROUTER_IN_IP_INPUT(),
> +            .priority         = 150,
> +            .__match          = "inport == ${rp.json_name} && ip4 && "
> +                                "${rEGBIT_PKT_LARGER()} && ${rEGBIT_EGRESS_LOOPBACK()} == 0",
> +            .actions          = "icmp4_error {"
> +                                "${rEGBIT_EGRESS_LOOPBACK()} = 1; "
> +                                "${rEGBIT_PKT_LARGER()} = 0; "
> +                                "eth.dst = ${rp.networks.ea}; "
> +                                "ip4.dst = ip4.src; "
> +                                "ip4.src = ${first_ipv4.addr}; "
> +                                "ip.ttl = 255; "
> +                                "icmp4.type = 3; /* Destination Unreachable. */ "
> +                                "icmp4.code = 4; /* Frag Needed and DF was Set. */ "
> +                                /* Set icmp4.frag_mtu to gw_mtu */
> +                                "icmp4.frag_mtu = ${gw_mtu}; "
> +                                "next(pipeline=ingress, table=0); "
> +                                "};",
> +            .tags             = map_empty(),
> +            .controller_meter = r.copp.get(cOPP_ICMP4_ERR()),
> +            .external_ids     = stage_hint(rp.lrp._uuid)) :-
> +    r in &Router(._uuid = lr_uuid),
> +    Some{var l3dgw_port} = r.l3dgw_port,
> +    var l3dgw_port_json_name = json_string_escape(l3dgw_port.name),
> +    r.redirect_port_name != "",
> +    var gw_mtu = l3dgw_port.options.get_int_def("gateway_mtu", 0),
> +    gw_mtu > 0,
> +    rp in &RouterPort(.router = r),
> +    rp.lrp == l3dgw_port,
> +    Some{var first_ipv4} = rp.networks.ipv4_addrs.nth(0).
> +
>  MeteredFlow(.logical_datapath = lr_uuid,
>              .stage            = s_ROUTER_IN_LARGER_PKTS(),
> -            .priority         = 50,
> -            .__match          = "inport == ${rp.json_name} && outport == ${l3dgw_port_json_name} && "
> -                                "ip6 && ${rEGBIT_PKT_LARGER()}",
> +            .priority         = 150,
> +            .__match          = "inport == ${rp.json_name} && ip6 && "
> +                                "${rEGBIT_PKT_LARGER()} && ${rEGBIT_EGRESS_LOOPBACK()} == 0",
>              .actions          = "icmp6_error {"
>                                  "${rEGBIT_EGRESS_LOOPBACK()} = 1; "
> +                                "${rEGBIT_PKT_LARGER()} = 0; "
>                                  "eth.dst = ${rp.networks.ea}; "
>                                  "ip6.dst = ip6.src; "
>                                  "ip6.src = ${first_ipv6.addr}; "
> @@ -7615,6 +7654,37 @@ MeteredFlow(.logical_datapath = lr_uuid,
>      rp.lrp != l3dgw_port,
>      Some{var first_ipv6} = rp.networks.ipv6_addrs.nth(0).
>  
> +MeteredFlow(.logical_datapath = lr_uuid,
> +            .stage            = s_ROUTER_IN_IP_INPUT(),
> +            .priority         = 150,
> +            .__match          = "inport == ${rp.json_name} && ip6 && "
> +                                "${rEGBIT_PKT_LARGER()} && ${rEGBIT_EGRESS_LOOPBACK()} == 0",
> +            .actions          = "icmp6_error {"
> +                                "${rEGBIT_EGRESS_LOOPBACK()} = 1; "
> +                                "${rEGBIT_PKT_LARGER()} = 0; "
> +                                "eth.dst = ${rp.networks.ea}; "
> +                                "ip6.dst = ip6.src; "
> +                                "ip6.src = ${first_ipv6.addr}; "
> +                                "ip.ttl = 255; "
> +                                "icmp6.type = 2; /* Packet Too Big. */ "
> +                                "icmp6.code = 0; "
> +                                /* Set icmp6.frag_mtu to gw_mtu */
> +                                "icmp6.frag_mtu = ${gw_mtu}; "
> +                                "next(pipeline=ingress, table=0); "
> +                                "};",
> +            .tags             = map_empty(),
> +            .controller_meter = r.copp.get(cOPP_ICMP6_ERR()),
> +            .external_ids     = stage_hint(rp.lrp._uuid)) :-
> +    r in &Router(._uuid = lr_uuid),
> +    Some{var l3dgw_port} = r.l3dgw_port,
> +    var l3dgw_port_json_name = json_string_escape(l3dgw_port.name),
> +    r.redirect_port_name != "",
> +    var gw_mtu = l3dgw_port.options.get_int_def("gateway_mtu", 0),
> +    gw_mtu > 0,
> +    rp in &RouterPort(.router = r),
> +    rp.lrp == l3dgw_port,
> +    Some{var first_ipv6} = rp.networks.ipv6_addrs.nth(0).
> +
>  /* Gateway routers. */
>  Flow(.logical_datapath = lr_uuid,
>       .stage            = s_ROUTER_IN_CHK_PKT_LEN(),
> @@ -7631,11 +7701,12 @@ Flow(.logical_datapath = lr_uuid,
>      var mtu = gw_mtu + vLAN_ETH_HEADER_LEN().
>  Flow(.logical_datapath = lr_uuid,
>       .stage            = s_ROUTER_IN_LARGER_PKTS(),
> -     .priority         = 50,
> -     .__match          = "inport == ${rp.json_name} && outport == ${gw_mtu_rp.json_name} && "
> -                         "ip4 && ${rEGBIT_PKT_LARGER()}",
> +     .priority         = 150,
> +     .__match          = "inport == ${rp.json_name} && ip4 && "
> +                         "${rEGBIT_PKT_LARGER()} && ${rEGBIT_EGRESS_LOOPBACK()} == 0",
>       .actions          = "icmp4_error {"
>                           "${rEGBIT_EGRESS_LOOPBACK()} = 1; "
> +                         "${rEGBIT_PKT_LARGER()} = 0; "
>                           "eth.dst = ${rp.networks.ea}; "
>                           "ip4.dst = ip4.src; "
>                           "ip4.src = ${first_ipv4.addr}; "
> @@ -7656,13 +7727,44 @@ Flow(.logical_datapath = lr_uuid,
>      rp in &RouterPort(.router = r),
>      rp.lrp != gw_mtu_rp.lrp,
>      Some{var first_ipv4} = rp.networks.ipv4_addrs.nth(0).
> +
> +Flow(.logical_datapath = lr_uuid,
> +     .stage            = s_ROUTER_IN_IP_INPUT(),
> +     .priority         = 150,
> +     .__match          = "inport == ${rp.json_name} && ip4 && "
> +                         "${rEGBIT_PKT_LARGER()} && ${rEGBIT_EGRESS_LOOPBACK()} == 0",
> +     .actions          = "icmp4_error {"
> +                         "${rEGBIT_EGRESS_LOOPBACK()} = 1; "
> +                         "${rEGBIT_PKT_LARGER()} = 0; "
> +                         "eth.dst = ${rp.networks.ea}; "
> +                         "ip4.dst = ip4.src; "
> +                         "ip4.src = ${first_ipv4.addr}; "
> +                         "ip.ttl = 255; "
> +                         "icmp4.type = 3; /* Destination Unreachable. */ "
> +                         "icmp4.code = 4; /* Frag Needed and DF was Set. */ "
> +                         /* Set icmp4.frag_mtu to gw_mtu */
> +                         "icmp4.frag_mtu = ${gw_mtu}; "
> +                         "next(pipeline=ingress, table=0); "
> +                         "};",
> +     .external_ids     = stage_hint(rp.lrp._uuid)) :-
> +    r in &Router(._uuid = lr_uuid),
> +    r.is_gateway,
> +    gw_mtu_rp in &RouterPort(.router = r),
> +    var gw_mtu = gw_mtu_rp.lrp.options.get_int_def("gateway_mtu", 0),
> +    gw_mtu > 0,
> +    var mtu = gw_mtu + vLAN_ETH_HEADER_LEN(),
> +    rp in &RouterPort(.router = r),
> +    rp.lrp == gw_mtu_rp.lrp,
> +    Some{var first_ipv4} = rp.networks.ipv4_addrs.nth(0).
> +
>  Flow(.logical_datapath = lr_uuid,
>       .stage            = s_ROUTER_IN_LARGER_PKTS(),
> -     .priority         = 50,
> -     .__match          = "inport == ${rp.json_name} && outport == ${gw_mtu_rp.json_name} && "
> -                         "ip6 && ${rEGBIT_PKT_LARGER()}",
> +     .priority         = 150,
> +     .__match          = "inport == ${rp.json_name} && ip6 && "
> +                         "${rEGBIT_PKT_LARGER()} && ${rEGBIT_EGRESS_LOOPBACK()} == 0",
>       .actions          = "icmp6_error {"
>                           "${rEGBIT_EGRESS_LOOPBACK()} = 1; "
> +                         "${rEGBIT_PKT_LARGER()} = 0; "
>                           "eth.dst = ${rp.networks.ea}; "
>                           "ip6.dst = ip6.src; "
>                           "ip6.src = ${first_ipv6.addr}; "
> @@ -7684,6 +7786,35 @@ Flow(.logical_datapath = lr_uuid,
>      rp.lrp != gw_mtu_rp.lrp,
>      Some{var first_ipv6} = rp.networks.ipv6_addrs.nth(0).
>  
> +Flow(.logical_datapath = lr_uuid,
> +     .stage            = s_ROUTER_IN_IP_INPUT(),
> +     .priority         = 150,
> +     .__match          = "inport == ${rp.json_name} && ip6 && "
> +                         "${rEGBIT_PKT_LARGER()} && ${rEGBIT_EGRESS_LOOPBACK()} == 0",
> +     .actions          = "icmp6_error {"
> +                         "${rEGBIT_EGRESS_LOOPBACK()} = 1; "
> +                         "${rEGBIT_PKT_LARGER()} = 0; "
> +                         "eth.dst = ${rp.networks.ea}; "
> +                         "ip6.dst = ip6.src; "
> +                         "ip6.src = ${first_ipv6.addr}; "
> +                         "ip.ttl = 255; "
> +                         "icmp6.type = 2; /* Packet Too Big. */ "
> +                         "icmp6.code = 0; "
> +                         /* Set icmp6.frag_mtu to gw_mtu */
> +                         "icmp6.frag_mtu = ${gw_mtu}; "
> +                         "next(pipeline=ingress, table=0); "
> +                         "};",
> +     .external_ids     = stage_hint(rp.lrp._uuid)) :-
> +    r in &Router(._uuid = lr_uuid),
> +    r.is_gateway,
> +    gw_mtu_rp in &RouterPort(.router = r),
> +    var gw_mtu = gw_mtu_rp.lrp.options.get_int_def("gateway_mtu", 0),
> +    gw_mtu > 0,
> +    var mtu = gw_mtu + vLAN_ETH_HEADER_LEN(),
> +    rp in &RouterPort(.router = r),
> +    rp.lrp == gw_mtu_rp.lrp,
> +    Some{var first_ipv6} = rp.networks.ipv6_addrs.nth(0).
> +
>  /* Logical router ingress table GW_REDIRECT: Gateway redirect.
>   *
>   * For traffic with outport equal to the l3dgw_port
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at

You should add additional checks for flows in the ingress switch
pipeline for the "L2 Admission Control" table.

You should also add checks for flows in the ingress router pipeline for
the "IP Input" table.

> index 56d8be7cc..f0a047d56 100644
> --- a/tests/ovn-northd.at
> +++ b/tests/ovn-northd.at
> @@ -4865,10 +4865,10 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sort], [0], [d
>    table=15(lr_in_chk_pkt_len  ), priority=0    , match=(1), action=(next;)
>    table=15(lr_in_chk_pkt_len  ), priority=50   , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); next;)
>    table=16(lr_in_larger_pkts  ), priority=0    , match=(1), action=(next;)
> -  table=16(lr_in_larger_pkts  ), priority=50   , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]]), action=(icmp4_error {reg9[[0]] = 1; 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=0); };)
> -  table=16(lr_in_larger_pkts  ), priority=50   , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]]), action=(icmp6_error {reg9[[0]] = 1; 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=0); };)
> -  table=16(lr_in_larger_pkts  ), priority=50   , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]]), action=(icmp4_error {reg9[[0]] = 1; 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=0); };)
> -  table=16(lr_in_larger_pkts  ), priority=50   , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]]), action=(icmp6_error {reg9[[0]] = 1; 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=0); };)
> +  table=16(lr_in_larger_pkts  ), priority=150  , match=(inport == "lr0-sw0" && 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=0); };)
> +  table=16(lr_in_larger_pkts  ), priority=150  , match=(inport == "lr0-sw0" && 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=0); };)
> +  table=16(lr_in_larger_pkts  ), priority=150  , match=(inport == "lr0-sw1" && 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=0); };)
> +  table=16(lr_in_larger_pkts  ), priority=150  , match=(inport == "lr0-sw1" && 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=0); };)
>  ])
>  
>  # Clear the gateway-chassis for lr0-public
> @@ -4892,10 +4892,10 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sort], [0], [d
>    table=15(lr_in_chk_pkt_len  ), priority=0    , match=(1), action=(next;)
>    table=15(lr_in_chk_pkt_len  ), priority=50   , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); next;)
>    table=16(lr_in_larger_pkts  ), priority=0    , match=(1), action=(next;)
> -  table=16(lr_in_larger_pkts  ), priority=50   , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]]), action=(icmp4_error {reg9[[0]] = 1; 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=0); };)
> -  table=16(lr_in_larger_pkts  ), priority=50   , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]]), action=(icmp6_error {reg9[[0]] = 1; 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=0); };)
> -  table=16(lr_in_larger_pkts  ), priority=50   , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]]), action=(icmp4_error {reg9[[0]] = 1; 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=0); };)
> -  table=16(lr_in_larger_pkts  ), priority=50   , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]]), action=(icmp6_error {reg9[[0]] = 1; 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=0); };)
> +  table=16(lr_in_larger_pkts  ), priority=150  , match=(inport == "lr0-sw0" && 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=0); };)
> +  table=16(lr_in_larger_pkts  ), priority=150  , match=(inport == "lr0-sw0" && 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=0); };)
> +  table=16(lr_in_larger_pkts  ), priority=150  , match=(inport == "lr0-sw1" && 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=0); };)
> +  table=16(lr_in_larger_pkts  ), priority=150  , match=(inport == "lr0-sw1" && 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=0); };)
>  ])
>  
>  # Set gateway_mtu option on lr0-sw0
> @@ -4909,14 +4909,14 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sort], [0], [d
>    table=15(lr_in_chk_pkt_len  ), priority=50   , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); next;)
>    table=15(lr_in_chk_pkt_len  ), priority=50   , match=(outport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1418); next;)
>    table=16(lr_in_larger_pkts  ), priority=0    , match=(1), action=(next;)
> -  table=16(lr_in_larger_pkts  ), priority=50   , match=(inport == "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]]), action=(icmp4_error {reg9[[0]] = 1; 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=0); };)
> -  table=16(lr_in_larger_pkts  ), priority=50   , match=(inport == "lr0-public" && outport == "lr0-sw0" && ip6 && reg9[[1]]), action=(icmp6_error {reg9[[0]] = 1; 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=0); };)
> -  table=16(lr_in_larger_pkts  ), priority=50   , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]]), action=(icmp4_error {reg9[[0]] = 1; 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=0); };)
> -  table=16(lr_in_larger_pkts  ), priority=50   , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]]), action=(icmp6_error {reg9[[0]] = 1; 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=0); };)
> -  table=16(lr_in_larger_pkts  ), priority=50   , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]]), action=(icmp4_error {reg9[[0]] = 1; 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=0); };)
> -  table=16(lr_in_larger_pkts  ), priority=50   , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]]), action=(icmp6_error {reg9[[0]] = 1; 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=0); };)
> -  table=16(lr_in_larger_pkts  ), priority=50   , match=(inport == "lr0-sw1" && outport == "lr0-sw0" && ip4 && reg9[[1]]), action=(icmp4_error {reg9[[0]] = 1; 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=0); };)
> -  table=16(lr_in_larger_pkts  ), priority=50   , match=(inport == "lr0-sw1" && outport == "lr0-sw0" && ip6 && reg9[[1]]), action=(icmp6_error {reg9[[0]] = 1; 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=0); };)
> +  table=16(lr_in_larger_pkts  ), priority=150  , match=(inport == "lr0-public" && 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=0); };)
> +  table=16(lr_in_larger_pkts  ), priority=150  , match=(inport == "lr0-public" && 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=0); };)
> +  table=16(lr_in_larger_pkts  ), priority=150  , match=(inport == "lr0-sw0" && 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=0); };)
> +  table=16(lr_in_larger_pkts  ), priority=150  , match=(inport == "lr0-sw0" && 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=0); };)
> +  table=16(lr_in_larger_pkts  ), priority=150  , match=(inport == "lr0-sw1" && 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=0); };)
> +  table=16(lr_in_larger_pkts  ), priority=150  , match=(inport == "lr0-sw1" && 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=0); };)
> +  table=16(lr_in_larger_pkts  ), priority=150  , match=(inport == "lr0-sw1" && 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=0); };)
> +  table=16(lr_in_larger_pkts  ), priority=150  , match=(inport == "lr0-sw1" && 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=0); };)
>  ])
>  
>  # Clear gateway_mtu option on lr0-public
> @@ -4928,10 +4928,10 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sort], [0], [d
>    table=15(lr_in_chk_pkt_len  ), priority=0    , match=(1), action=(next;)
>    table=15(lr_in_chk_pkt_len  ), priority=50   , match=(outport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1418); next;)
>    table=16(lr_in_larger_pkts  ), priority=0    , match=(1), action=(next;)
> -  table=16(lr_in_larger_pkts  ), priority=50   , match=(inport == "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]]), action=(icmp4_error {reg9[[0]] = 1; 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=0); };)
> -  table=16(lr_in_larger_pkts  ), priority=50   , match=(inport == "lr0-public" && outport == "lr0-sw0" && ip6 && reg9[[1]]), action=(icmp6_error {reg9[[0]] = 1; 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=0); };)
> -  table=16(lr_in_larger_pkts  ), priority=50   , match=(inport == "lr0-sw1" && outport == "lr0-sw0" && ip4 && reg9[[1]]), action=(icmp4_error {reg9[[0]] = 1; 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=0); };)
> -  table=16(lr_in_larger_pkts  ), priority=50   , match=(inport == "lr0-sw1" && outport == "lr0-sw0" && ip6 && reg9[[1]]), action=(icmp6_error {reg9[[0]] = 1; 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=0); };)
> +  table=16(lr_in_larger_pkts  ), priority=150  , match=(inport == "lr0-public" && 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=0); };)
> +  table=16(lr_in_larger_pkts  ), priority=150  , match=(inport == "lr0-public" && 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=0); };)
> +  table=16(lr_in_larger_pkts  ), priority=150  , match=(inport == "lr0-sw1" && 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=0); };)
> +  table=16(lr_in_larger_pkts  ), priority=150  , match=(inport == "lr0-sw1" && 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=0); };)
>  ])
>  
>  AT_CLEANUP
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 6af62aab0..49741f45b 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -16637,6 +16637,52 @@ test_ip_packet_larger() {
>      fi
>  }
>  
> +test_ip_packet_larger_ext() {
> +    local mtu=$1
> +
> +    # Send ip packet from sw0-port1 to outside
> +    src_mac="00000012af11" # external mac
> +    dst_mac="000020201213" # lr0-public mac
> +    src_ip=`ip_to_hex 172 168 0 4`
> +    dst_ip=`ip_to_hex 172 168 0 100`
> +    # Set the packet length to 118.
> +    pkt_len=0076
> +    packet=${dst_mac}${src_mac}08004500${pkt_len}00000000400120cf
> +    orig_packet_l3=${src_ip}${dst_ip}0900000000000000
> +    orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
> +    orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
> +    orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
> +    orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
> +    orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
> +    packet=${packet}${orig_packet_l3}
> +
> +    gw_ip_garp=ffffffffffff00002020121308060001080006040001000020201213aca80064000000000000aca80064
> +    ext_ip_garp=ffffffffffff00000012af110806000108000604000100000012af11aca80004000000000000aca80004
> +
> +    src_ip=`ip_to_hex 172 168 0 100`
> +    dst_ip=`ip_to_hex 172 168 0 4`
> +    # pkt len should be 146 (28 (icmp packet) + 118 (orig ip + payload))
> +    reply_pkt_len=0092
> +    ip_csum=f397
> +    icmp_reply=${src_mac}${dst_mac}08004500${reply_pkt_len}00004000fe0122b2
> +    icmp_reply=${icmp_reply}${src_ip}${dst_ip}0304${ip_csum}0000$(printf "%04x" $mtu)
> +    icmp_reply=${icmp_reply}4500${pkt_len}00000000400120cf
> +    icmp_reply=${icmp_reply}${orig_packet_l3}
> +    echo $icmp_reply > br-phys_n1.expected
> +
> +    echo $gw_ip_garp >> br-phys_n1.expected
> +
> +    as hv1 reset_pcap_file br-phys_n1 hv1/br-phys_n1
> +    as hv1 reset_pcap_file hv1-vif1 hv1/vif1
> +
> +    check as hv1 ovs-appctl netdev-dummy/receive br-phys_n1 $ext_ip_garp
> +    sleep 1
> +    # Send packet from sw0-port1 to outside
> +    check as hv1 ovs-appctl netdev-dummy/receive br-phys_n1 $packet
> +
> +    OVN_CHECK_PACKETS([hv1/br-phys_n1-tx.pcap], [br-phys_n1.expected])
> +}
> +
>  test_ip6_packet_larger() {
>      local mtu=$1
>  
> @@ -16652,7 +16698,7 @@ test_ip6_packet_larger() {
>      local payload=${payload}0000000000000000000000000000000000000000
>      local payload=${payload}0000000000000000000000000000000000000000
>  
> -    local ip6_hdr=6000000000583aff${ipv6_src}${ipv6_dst}
> +    local ip6_hdr=6000000000583afe${ipv6_src}${ipv6_dst}
>      local packet=${eth_dst}${eth_src}86dd${ip6_hdr}8000ec7662f00001${payload}
>  
>      as hv1 reset_pcap_file br-phys_n1 hv1/br-phys_n1
> @@ -16669,7 +16715,7 @@ test_ip6_packet_larger() {
>      mtu_needed=$(expr ${packet_bytes} - 18)
>      if test $mtu -lt $mtu_needed; then
>          # First construct the inner IPv6 packet.
> -        inner_ip6=6000000000583afe${ipv6_src}${ipv6_dst}
> +        inner_ip6=6000000000583afd${ipv6_src}${ipv6_dst}
>          inner_icmp6=8000000062f00001
>          inner_icmp6_and_payload=$(icmp6_csum_inplace ${inner_icmp6}${payload} ${inner_ip6})
>          inner_packet=${inner_ip6}${inner_icmp6_and_payload}
> @@ -16691,6 +16737,53 @@ test_ip6_packet_larger() {
>      fi
>  }
>  
> +test_ip6_packet_larger_ext() {

What is the difference between test_ip6_packet_larger_ext() and
test_ip6_packet_larger()? Can you add a comment? Its hard to decode the
IPv6 header which makes it difficult to review the changes to the test :S


> +    local mtu=$1
> +
> +    local eth_src=00000012af11
> +    local eth_dst=000020201213
> +
> +    local ipv6_src=20000000000000000000000000000004
> +    local ipv6_dst=20000000000000000000000000000001
> +
> +    local payload=0000000000000000000000000000000000000000
> +    local payload=${payload}0000000000000000000000000000000000000000
> +    local payload=${payload}0000000000000000000000000000000000000000
> +    local payload=${payload}0000000000000000000000000000000000000000
> +
> +    local ip6_hdr=6000000000583afe${ipv6_src}${ipv6_dst}
> +    local packet=${eth_dst}${eth_src}86dd${ip6_hdr}9000cc7662f00001${payload}
> +
> +    local ns=ffffffffffff00002020121308060001080006040001000020201213aca80064000000000000aca80064
> +    echo $ns > br-phys_n1.expected
> +
> +    as hv1 reset_pcap_file br-phys_n1 hv1/br-phys_n1
> +    as hv1 reset_pcap_file hv1-vif1 hv1/vif1
> +
> +    local na_ip6_hdr=6000000000203aff${ipv6_src}${ipv6_dst}
> +    local na=${eth_dst}${eth_src}86dd${na_ip6_hdr}8800d78440000000${ipv6_src}0201${eth_src}
> +    check as hv1 ovs-appctl netdev-dummy/receive br-phys_n1 $na
> +    sleep 1
> +    check as hv1 ovs-appctl netdev-dummy/receive br-phys_n1 $packet
> +    AT_CAPTURE_FILE([trace-$mtu])
> +
> +    # First construct the inner IPv6 packet.
> +    inner_ip6=6000000000583afe${ipv6_src}${ipv6_dst}
> +    inner_icmp6=9000000062f00001
> +    inner_icmp6_and_payload=$(icmp6_csum_inplace ${inner_icmp6}${payload} ${inner_ip6})
> +    inner_packet=${inner_ip6}${inner_icmp6_and_payload}
> +
> +    # Then the outer.
> +    outer_ip6=6000000000883afe${ipv6_dst}${ipv6_src}
> +    outer_icmp6_and_payload=$(icmp6_csum_inplace 020000000000$(printf "%04x" $mtu)${inner_packet} $outer_ip6)
> +    outer_packet=${outer_ip6}${outer_icmp6_and_payload}
> +
> +    icmp6_reply=${eth_src}${eth_dst}86dd${outer_packet}
> +    echo $icmp6_reply >> br-phys_n1.expected
> +
> +    OVN_CHECK_PACKETS([hv1/br-phys_n1-tx.pcap], [br-phys_n1.expected])
> +}
> +
>  wait_for_ports_up
>  ovn-nbctl --wait=hv sync
>  
> @@ -16723,7 +16816,7 @@ for mtu in 100 500 118; do
>      OVS_WAIT_FOR_OUTPUT([
>          as hv1 ovs-ofctl dump-flows br-int > br-int-flows-$mtu
>          AT_CAPTURE_FILE([br-int-flows-$mtu])
> -        grep "check_pkt_larger($(expr $mtu + 18))" br-int-flows-$mtu | wc -l], [0], [1
> +        grep "check_pkt_larger($(expr $mtu + 18))" br-int-flows-$mtu | wc -l], [0], [3
>  ])
>  
>      AS_BOX([testing mtu $mtu - IPv4])
> @@ -16733,6 +16826,23 @@ for mtu in 100 500 118; do
>      test_ip6_packet_larger $mtu
>  done
>  
> +AS_BOX([testing mtu $mtu])
> +check ovn-nbctl --wait=hv set logical_router_port lr0-public options:gateway_mtu=100
> +ovn-sbctl dump-flows > ext-sbflows-100
> +AT_CAPTURE_FILE([ext-sbflows-$mtu])
> +
> +OVS_WAIT_FOR_OUTPUT([
> +    as hv1 ovs-ofctl dump-flows br-int > ext-br-int-flows-100
> +    AT_CAPTURE_FILE([ext-br-int-flows-100])
> +    grep "check_pkt_larger(118)" ext-br-int-flows-100 | wc -l], [0], [3
> +])
> +
> +AS_BOX([testing ext mtu 100 - IPv4])
> +test_ip_packet_larger_ext 100
> +
> +AS_BOX([testing mtu 100 - IPv6])
> +test_ip6_packet_larger_ext 100
> +
>  ovn-nbctl lsp-del sw0-lr0
>  
>  ovn-nbctl lr-del lr0
> @@ -16770,7 +16880,7 @@ for mtu in 100 500 118; do
>      OVS_WAIT_FOR_OUTPUT([
>          as hv1 ovs-ofctl dump-flows br-int > br-int-gw-flows-$mtu
>          AT_CAPTURE_FILE([br-int-gw-flows-$mtu])
> -        grep "check_pkt_larger($(expr $mtu + 18))" br-int-gw-flows-$mtu | wc -l], [0], [1
> +        grep "check_pkt_larger($(expr $mtu + 18))" br-int-gw-flows-$mtu | wc -l], [0], [3
>  ])
>  
>      AS_BOX([testing gw mtu $mtu - IPv4])
> @@ -16780,6 +16890,23 @@ for mtu in 100 500 118; do
>      test_ip6_packet_larger $mtu
>  done
>  
> +AS_BOX([testing gw mtu $mtu])

s/$mtu/100

Also could you maybe change the description? The AS_BOX text is the same
as in the loop above this AS_BOX but the tests are different (i.e. the
run test_ip6_packet_larger_ext). What does test_ip6_packet_larger_ext()
do differently to test_ip6_packet_larger()?

> +check ovn-nbctl --wait=hv set logical_router_port lr1-public options:gateway_mtu=100
> +ovn-sbctl dump-flows > ext-gw-sbflows-100
> +AT_CAPTURE_FILE([ext-gw-sbflows-$mtu])
> +
> +OVS_WAIT_FOR_OUTPUT([
> +    as hv1 ovs-ofctl dump-flows br-int > ext-br-int-gw-flows-100
> +    AT_CAPTURE_FILE([ext-br-int-gw-flows-100])
> +    grep "check_pkt_larger(118)" ext-br-int-gw-flows-100 | wc -l], [0], [3
> +])
> +
> +AS_BOX([testing gw ext mtu 100 - IPv4])
> +test_ip_packet_larger_ext 100
> +
> +AS_BOX([testing gw mtu 100 - IPv6])
> +test_ip6_packet_larger_ext 100
> +
>  OVN_CLEANUP([hv1])
>  AT_CLEANUP
>  ])
> 
> 
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> 



More information about the dev mailing list