diff mbox series

[ovs-dev] northd: Add new NB_Global.options:default_acl_drop option.

Message ID 20220419133746.17712-1-dceara@redhat.com
State Accepted
Headers show
Series [ovs-dev] northd: Add new NB_Global.options:default_acl_drop option. | expand

Checks

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

Commit Message

Dumitru Ceara April 19, 2022, 1:37 p.m. UTC
This option changes how logical switch ACL related flows are generated
such that the following behavior is ensured:

a. If a logical switch has no ACL applied to it (either directly or
indirectly via a port group) then traffic is always allowed in the
ls_in_acl, ls_in_acl_after_lb, ls_out_acl stages.

b. If a logical switch has ACLs applied (directly or indirectly) and
NB_Global.options:default_acl_drop is set to 'false', then traffic that
doesn't match any ACL in the ls_in_acl, ls_in_acl_after_lb, ls_out_acl
stages is allowed to advance to the next step in the processing
pipeline.

c. If a logical switch has *any* ACL applied (directly or indirectly)
and NB_Global.options:default_acl_drop is set to 'true', then a default
lowest-priority rule is added to the ls_in_acl, ls_in_acl_after_lb,
ls_out_acl stages to drop traffic that is not matched by any ACLs.

The goal of the feature is to simplify the configuration of the ACLs and
port groups for CMSs that require a default-deny firewall
implementation.  One such example is with OpenStack security groups
which, when enabled, implicitly drop all not explicitly allowed traffic.

Until now the CMS had to add all logical ports corresponding to VMs in a
network to a single, huge, default-drop-port-group and apply a single
drop ACL to the port group.

With this new feature, the CMS can enable 'default_acl_drop', and punch
holes for traffic that needs to be allowed.  The resulting NB and SB
configuration is also reduced in size.

Reported-by: Daniel Alvarez Sanchez <dalvarez@redhat.com>
Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1947807
Signed-off-by: Dumitru Ceara <dceara@redhat.com>
---
v1:
- Removed RFC tag.
- Added flows for the stateful-ACL case as pointed by Han.
---
 NEWS                    |   2 +
 northd/northd.c         |  50 ++++-
 northd/ovn-northd.8.xml |  28 ++-
 ovn-nb.xml              |   8 +
 tests/ovn-northd.at     | 483 +++++++++++++++++++++++++++++++++++++++-
 5 files changed, 551 insertions(+), 20 deletions(-)

Comments

Han Zhou April 20, 2022, 3:58 p.m. UTC | #1
On Tue, Apr 19, 2022 at 6:38 AM Dumitru Ceara <dceara@redhat.com> wrote:
>
> This option changes how logical switch ACL related flows are generated
> such that the following behavior is ensured:
>
> a. If a logical switch has no ACL applied to it (either directly or
> indirectly via a port group) then traffic is always allowed in the
> ls_in_acl, ls_in_acl_after_lb, ls_out_acl stages.
>
> b. If a logical switch has ACLs applied (directly or indirectly) and
> NB_Global.options:default_acl_drop is set to 'false', then traffic that
> doesn't match any ACL in the ls_in_acl, ls_in_acl_after_lb, ls_out_acl
> stages is allowed to advance to the next step in the processing
> pipeline.
>
> c. If a logical switch has *any* ACL applied (directly or indirectly)
> and NB_Global.options:default_acl_drop is set to 'true', then a default
> lowest-priority rule is added to the ls_in_acl, ls_in_acl_after_lb,
> ls_out_acl stages to drop traffic that is not matched by any ACLs.
>
> The goal of the feature is to simplify the configuration of the ACLs and
> port groups for CMSs that require a default-deny firewall
> implementation.  One such example is with OpenStack security groups
> which, when enabled, implicitly drop all not explicitly allowed traffic.
>
> Until now the CMS had to add all logical ports corresponding to VMs in a
> network to a single, huge, default-drop-port-group and apply a single
> drop ACL to the port group.
>
> With this new feature, the CMS can enable 'default_acl_drop', and punch
> holes for traffic that needs to be allowed.  The resulting NB and SB
> configuration is also reduced in size.
>
> Reported-by: Daniel Alvarez Sanchez <dalvarez@redhat.com>
> Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1947807
> Signed-off-by: Dumitru Ceara <dceara@redhat.com>
> ---
> v1:
> - Removed RFC tag.
> - Added flows for the stateful-ACL case as pointed by Han.
> ---
>  NEWS                    |   2 +
>  northd/northd.c         |  50 ++++-
>  northd/ovn-northd.8.xml |  28 ++-
>  ovn-nb.xml              |   8 +
>  tests/ovn-northd.at     | 483 +++++++++++++++++++++++++++++++++++++++-
>  5 files changed, 551 insertions(+), 20 deletions(-)
>
> diff --git a/NEWS b/NEWS
> index c881764a6..dbe89e9cf 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -5,6 +5,8 @@ Post v22.03.0
>    - Replaced the usage of masked ct_label by ct_mark in most cases to
work
>      better with hardware-offloading.
>    - Support NAT for logical routers with multiple distributed gateway
ports.
> +  - Add global option (NB_Global.options:default_acl_drop) to enable
> +    implicit drop behavior on logical switches with ACLs applied.
>
>  OVN v22.03.0 - 11 Mar 2022
>  --------------------------
> diff --git a/northd/northd.c b/northd/northd.c
> index bcd36bbaa..43b028c2c 100644
> --- a/northd/northd.c
> +++ b/northd/northd.c
> @@ -74,6 +74,12 @@ static struct eth_addr svc_monitor_mac_ea;
>   * Otherwise, it will avoid using it.  The default is true. */
>  static bool use_ct_inv_match = true;
>
> +/* If this option is 'true' northd will implicitly add a lowest-priority
> + * drop rule in the ACL stage of logical switches that have at least one
> + * ACL.
> + */
> +static bool default_acl_drop;
> +
>  #define MAX_OVN_TAGS 4096
>
>  /* Pipeline stages. */
> @@ -6617,6 +6623,7 @@ static void
>  build_acls(struct ovn_datapath *od, struct hmap *lflows,
>             const struct hmap *port_groups, const struct shash
*meter_groups)
>  {
> +    const char *default_acl_action = default_acl_drop ? "drop;" :
"next;";
>      bool has_stateful = od->has_stateful_acl || od->has_lb_vip;
>      struct ds match   = DS_EMPTY_INITIALIZER;
>      struct ds actions = DS_EMPTY_INITIALIZER;
> @@ -6628,22 +6635,34 @@ build_acls(struct ovn_datapath *od, struct hmap
*lflows,
>       *
>       * A related rule at priority 1 is added below if there
>       * are any stateful ACLs in this datapath. */
> -    if (!od->has_acls && !od->has_lb_vip) {
> -        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX, "1",
"next;");
> -        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX, "1",
"next;");
> +    if (!od->has_acls) {
> +        if (!od->has_lb_vip) {
> +            ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX, "1",
> +                          "next;");
> +            ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX, "1",
> +                          "next;");
> +        } else {
> +            ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 1, "1", "next;");
> +            ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 1, "1", "next;");
> +        }
> +        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, 0, "1",
"next;");
>      } else {
> -        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 0, "1", "next;");
> -        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 0, "1", "next;");
> +        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 0, "1",
> +                      default_acl_action);
> +        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 0, "1",
> +                      default_acl_action);
> +        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, 0, "1",
> +                      default_acl_action);
>      }
>
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, 0, "1", "next;");
>
>      if (has_stateful) {
>          /* Ingress and Egress ACL Table (Priority 1).
>           *
> -         * By default, traffic is allowed.  This is partially handled by
> -         * the Priority 0 ACL flows added earlier, but we also need to
> -         * commit IP flows.  This is because, while the initiater's
> +         * By default, traffic is allowed (if default_acl_drop is
'false') or
> +         * dropped (if default_acl_drop is 'true').  This is partially
> +         * handled by the Priority 0 ACL flows added earlier, but we also
> +         * need to commit IP flows.  This is because, while the
initiater's
>           * direction may not have any stateful rules, the server's may
>           * and then its return traffic would not have an associated
>           * conntrack entry and would return "+invalid".
> @@ -6661,12 +6680,20 @@ build_acls(struct ovn_datapath *od, struct hmap
*lflows,
>           * Subsequent packets will hit the flow at priority 0 that just
>           * uses "next;". */
>          ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 1,
> -                      "ip && (!ct.est || (ct.est && ct_mark.blocked ==
1))",
> +                      "ip && ct.est && ct_mark.blocked == 1",
>                         REGBIT_CONNTRACK_COMMIT" = 1; next;");
>          ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 1,
> -                      "ip && (!ct.est || (ct.est && ct_mark.blocked ==
1))",
> +                      "ip && ct.est && ct_mark.blocked == 1",
>                         REGBIT_CONNTRACK_COMMIT" = 1; next;");
>
> +        default_acl_action = default_acl_drop
> +                             ? "drop;"
> +                             : REGBIT_CONNTRACK_COMMIT" = 1; next;";
> +        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 1, "ip && !ct.est",
> +                      default_acl_action);
> +        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 1, "ip && !ct.est",
> +                      default_acl_action);
> +
>          /* Ingress and Egress ACL Table (Priority 65532).
>           *
>           * Always drop traffic that's in an invalid state.  Also drop
> @@ -15321,6 +15348,7 @@ ovnnb_db_run(struct northd_input *input_data,
>                                          "controller_event", false);
>      check_lsp_is_up = !smap_get_bool(&nb->options,
>                                       "ignore_lsp_down", true);
> +    default_acl_drop = smap_get_bool(&nb->options, "default_acl_drop",
false);
>
>      build_datapaths(input_data, ovnsb_txn, &data->datapaths,
&data->lr_list);
>      build_lbs(input_data, &data->datapaths, &data->lbs);
> diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
> index db4f4d267..68e0bd626 100644
> --- a/northd/ovn-northd.8.xml
> +++ b/northd/ovn-northd.8.xml
> @@ -774,8 +774,12 @@
>      <p>
>        This table contains a priority-65535 flow to advance to the next
table
>        if the logical switch has <code>no</code> ACLs configured,
otherwise a
> -        priority-0 flow to advance to the next table so that ACLs allow
> -        packets by default.
> +      priority-0 flow to advance to the next table so that ACLs allow
> +      packets by default if <ref column="options:default_acl_drop"
> +      table="NB_Global" db="OVN_Northbound"/> colum of <ref
table="NB_Global"
> +      db="OVN_Northbound"/> is <code>false</code> or not set.  Otherwise
> +      the flow action is set to <code>drop;</code> to implement a default
> +      drop behavior.
>      </p>
>
>      <p>
> @@ -784,6 +788,26 @@
>      </p>
>
>      <ul>
> +      <li>
> +        If <ref column="options:default_acl_drop" table="NB_Global"
> +        db="OVN_Northbound"/> colum of <ref table="NB_Global"
> +        db="OVN_Northbound"/> is <code>false</code> or not set, a
priority-1
> +        flow that sets the hint to commit IP traffic that is not part of
> +        established sessions to the connection tracker (with action
> +        <code>reg0[1] = 1; next;</code>).  This is needed for
> +        the default allow policy because, while the initiator's direction
> +        may not have any stateful rules, the server's may and then
> +        its return traffic would not be known and marked as invalid.
> +      </li>
> +
> +      <li>
> +        If <ref column="options:default_acl_drop" table="NB_Global"
> +        db="OVN_Northbound"/> colum of <ref table="NB_Global"
> +        db="OVN_Northbound"/> is <code>true</code>, a priority-1
> +        flow that drops IP traffic that is not part of established
> +        sessions.
> +      </li>
> +
>        <li>
>          A priority-1 flow that sets the hint to commit IP traffic to the
>          connection tracker (with action <code>reg0[1] = 1;
next;</code>).  This
> diff --git a/ovn-nb.xml b/ovn-nb.xml
> index 547f7f48a..9010240a8 100644
> --- a/ovn-nb.xml
> +++ b/ovn-nb.xml
> @@ -255,6 +255,14 @@
>          </p>
>        </column>
>
> +      <column name="options" key="default_acl_drop">
> +        <p>
> +          If set to <code>true</code>., <code>ovn-northd</code> will
> +          generate a logical flow to drop all traffic in the ACL stages.
> +          By default this option is set to <code>false</code>.
> +        </p>
> +      </column>
> +
>        <group title="Options for configuring interconnection route
advertisement">
>          <p>
>            These options control how routes are advertised between OVN
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> index adb304385..724ca2057 100644
> --- a/tests/ovn-northd.at
> +++ b/tests/ovn-northd.at
> @@ -2227,7 +2227,8 @@ AT_CHECK([ovn-sbctl lflow-list ls | grep -e
ls_in_acl_hint -e ls_out_acl_hint -e
>    table=3 (ls_out_acl_hint    ), priority=5    , match=(!ct.trk),
action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
>    table=3 (ls_out_acl_hint    ), priority=6    , match=(!ct.new &&
ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1;
reg0[[9]] = 1; next;)
>    table=3 (ls_out_acl_hint    ), priority=7    , match=(ct.new &&
!ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
> -  table=4 (ls_out_acl         ), priority=1    , match=(ip && (!ct.est
|| (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;)
> +  table=4 (ls_out_acl         ), priority=1    , match=(ip && !ct.est),
action=(reg0[[1]] = 1; next;)
> +  table=4 (ls_out_acl         ), priority=1    , match=(ip && ct.est &&
ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
>    table=4 (ls_out_acl         ), priority=65532, match=(!ct.est &&
ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
>    table=4 (ls_out_acl         ), priority=65532, match=(ct.est &&
!ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0),
action=(next;)
>    table=4 (ls_out_acl         ), priority=65532, match=(ct.inv ||
(ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
> @@ -2238,7 +2239,8 @@ AT_CHECK([ovn-sbctl lflow-list ls | grep -e
ls_in_acl_hint -e ls_out_acl_hint -e
>    table=8 (ls_in_acl_hint     ), priority=5    , match=(!ct.trk),
action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
>    table=8 (ls_in_acl_hint     ), priority=6    , match=(!ct.new &&
ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1;
reg0[[9]] = 1; next;)
>    table=8 (ls_in_acl_hint     ), priority=7    , match=(ct.new &&
!ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
> -  table=9 (ls_in_acl          ), priority=1    , match=(ip && (!ct.est
|| (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;)
> +  table=9 (ls_in_acl          ), priority=1    , match=(ip && !ct.est),
action=(reg0[[1]] = 1; next;)
> +  table=9 (ls_in_acl          ), priority=1    , match=(ip && ct.est &&
ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
>    table=9 (ls_in_acl          ), priority=65532, match=(!ct.est &&
ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
>    table=9 (ls_in_acl          ), priority=65532, match=(ct.est &&
!ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0),
action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
>    table=9 (ls_in_acl          ), priority=65532, match=(ct.inv ||
(ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
> @@ -2262,7 +2264,8 @@ AT_CHECK([ovn-sbctl lflow-list ls | grep -e
ls_in_acl_hint -e ls_out_acl_hint -e
>    table=3 (ls_out_acl_hint    ), priority=6    , match=(!ct.new &&
ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1;
reg0[[9]] = 1; next;)
>    table=3 (ls_out_acl_hint    ), priority=7    , match=(ct.new &&
!ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
>    table=4 (ls_out_acl         ), priority=0    , match=(1),
action=(next;)
> -  table=4 (ls_out_acl         ), priority=1    , match=(ip && (!ct.est
|| (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;)
> +  table=4 (ls_out_acl         ), priority=1    , match=(ip && !ct.est),
action=(reg0[[1]] = 1; next;)
> +  table=4 (ls_out_acl         ), priority=1    , match=(ip && ct.est &&
ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
>    table=4 (ls_out_acl         ), priority=1001 , match=(reg0[[7]] == 1
&& (ip)), action=(reg0[[1]] = 1; next;)
>    table=4 (ls_out_acl         ), priority=1001 , match=(reg0[[8]] == 1
&& (ip)), action=(next;)
>    table=4 (ls_out_acl         ), priority=34000, match=(eth.src ==
$svc_monitor_mac), action=(next;)
> @@ -2279,7 +2282,8 @@ AT_CHECK([ovn-sbctl lflow-list ls | grep -e
ls_in_acl_hint -e ls_out_acl_hint -e
>    table=8 (ls_in_acl_hint     ), priority=6    , match=(!ct.new &&
ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1;
reg0[[9]] = 1; next;)
>    table=8 (ls_in_acl_hint     ), priority=7    , match=(ct.new &&
!ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
>    table=9 (ls_in_acl          ), priority=0    , match=(1),
action=(next;)
> -  table=9 (ls_in_acl          ), priority=1    , match=(ip && (!ct.est
|| (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;)
> +  table=9 (ls_in_acl          ), priority=1    , match=(ip && !ct.est),
action=(reg0[[1]] = 1; next;)
> +  table=9 (ls_in_acl          ), priority=1    , match=(ip && ct.est &&
ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
>    table=9 (ls_in_acl          ), priority=1001 , match=(reg0[[7]] == 1
&& (ip)), action=(reg0[[1]] = 1; next;)
>    table=9 (ls_in_acl          ), priority=1001 , match=(reg0[[8]] == 1
&& (ip)), action=(next;)
>    table=9 (ls_in_acl          ), priority=34000, match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> @@ -6331,7 +6335,8 @@ AT_CAPTURE_FILE([lsflows])
>
>  AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' |
sort], [0], [dnl
>    table=??(ls_in_acl          ), priority=0    , match=(1),
action=(next;)
> -  table=??(ls_in_acl          ), priority=1    , match=(ip && (!ct.est
|| (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl          ), priority=1    , match=(ip && !ct.est),
action=(reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl          ), priority=1    , match=(ip && ct.est &&
ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
>    table=??(ls_in_acl          ), priority=2001 , match=(reg0[[10]] == 1
&& (ip4)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */)
>    table=??(ls_in_acl          ), priority=2001 , match=(reg0[[9]] == 1
&& (ip4)), action=(/* drop */)
>    table=??(ls_in_acl          ), priority=2002 , match=(reg0[[7]] == 1
&& (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
> @@ -6383,7 +6388,8 @@ AT_CAPTURE_FILE([lsflows])
>
>  AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' |
sort], [0], [dnl
>    table=??(ls_in_acl          ), priority=0    , match=(1),
action=(next;)
> -  table=??(ls_in_acl          ), priority=1    , match=(ip && (!ct.est
|| (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl          ), priority=1    , match=(ip && !ct.est),
action=(reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl          ), priority=1    , match=(ip && ct.est &&
ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
>    table=??(ls_in_acl          ), priority=34000, match=(eth.dst ==
$svc_monitor_mac), action=(next;)
>    table=??(ls_in_acl          ), priority=65532, match=(!ct.est &&
ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
>    table=??(ls_in_acl          ), priority=65532, match=(ct.est &&
!ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0),
action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
> @@ -6435,7 +6441,8 @@ AT_CAPTURE_FILE([lsflows])
>
>  AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' |
sort], [0], [dnl
>    table=??(ls_in_acl          ), priority=0    , match=(1),
action=(next;)
> -  table=??(ls_in_acl          ), priority=1    , match=(ip && (!ct.est
|| (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl          ), priority=1    , match=(ip && !ct.est),
action=(reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl          ), priority=1    , match=(ip && ct.est &&
ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
>    table=??(ls_in_acl          ), priority=2002 , match=(reg0[[7]] == 1
&& (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
>    table=??(ls_in_acl          ), priority=2002 , match=(reg0[[8]] == 1
&& (ip4 && tcp)), action=(next;)
>    table=??(ls_in_acl          ), priority=2003 , match=(reg0[[7]] == 1
&& (ip4 && icmp)), action=(reg0[[1]] = 1; next;)
> @@ -6664,3 +6671,465 @@ ovn-nbctl --may-exist static-mac-binding-add
lr0-p0 192.168.10.100 00:00:22:33:5
>  wait_row_count Static_MAC_Binding 1 logical_port=lr0-p0
ip=192.168.10.100 mac="00\:00\:22\:33\:55\:66"
>
>  AT_CLEANUP
> +
> +OVN_FOR_EACH_NORTHD([
> +AT_SETUP([LS default ACL drop])
> +AT_KEYWORDS([acl])
> +
> +ovn_start
> +
> +check ovn-nbctl ls-add ls
> +check ovn-nbctl lsp-add ls lsp1 -- lsp-set-addresses lsp1
00:00:00:00:00:01
> +check ovn-nbctl lsp-add ls lsp2 -- lsp-set-addresses lsp2
00:00:00:00:00:02
> +
> +flow="inport == \"lsp1\" && eth.src == 00:00:00:00:00:01 && eth.dst ==
00:00:00:00:00:02 && ip.ttl == 64 && ip4.src == 42.42.42.42 && ip4.dst ==
42.42.42.43 && udp && udp.src == 42 && udp.dst == 84"
> +
> +AS_BOX([No ACL, default_acl_drop not set])
> +check ovn-nbctl --wait=sb sync
> +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed
's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_acl          ), priority=65535, match=(1),
action=(next;)
> +  table=??(ls_in_acl_after_lb ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_acl_hint     ), priority=65535, match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl         ), priority=65535, match=(1),
action=(next;)
> +  table=??(ls_out_acl_hint    ), priority=65535, match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +])
> +
> +dnl UDP traffic should be allowed.
> +AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"],
[0], [dnl
> +#
udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
> +output("lsp2");
> +])
> +
> +AS_BOX([No ACL, default_acl_drop false])
> +check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=false
> +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed
's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_acl          ), priority=65535, match=(1),
action=(next;)
> +  table=??(ls_in_acl_after_lb ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_acl_hint     ), priority=65535, match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl         ), priority=65535, match=(1),
action=(next;)
> +  table=??(ls_out_acl_hint    ), priority=65535, match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +])
> +
> +dnl UDP traffic should be allowed.
> +AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"],
[0], [dnl
> +#
udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
> +output("lsp2");
> +])
> +
> +AS_BOX([No ACL, default_acl_drop true])
> +check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=true
> +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed
's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_acl          ), priority=65535, match=(1),
action=(next;)
> +  table=??(ls_in_acl_after_lb ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_acl_hint     ), priority=65535, match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl         ), priority=65535, match=(1),
action=(next;)
> +  table=??(ls_out_acl_hint    ), priority=65535, match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +])
> +
> +dnl UDP traffic should be allowed.
> +AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"],
[0], [dnl
> +#
udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
> +output("lsp2");
> +])
> +
> +AS_BOX([from-lport ACL])
> +check ovn-nbctl acl-del ls
> +check ovn-nbctl acl-add ls from-lport 1 "ip4 && tcp" allow
> +
> +AS_BOX([from-lport ACL, default_acl_drop not set])
> +check ovn-nbctl --wait=sb remove NB_Global . options default_acl_drop
> +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed
's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_acl          ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_acl          ), priority=1001 , match=(ip4 && tcp),
action=(next;)
> +  table=??(ls_in_acl          ), priority=34000, match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_in_acl_after_lb ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_acl_hint     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl         ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_acl         ), priority=34000, match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl_hint    ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +])
> +
> +dnl UDP traffic should be allowed.
> +AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"],
[0], [dnl
> +#
udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
> +output("lsp2");
> +])
> +
> +AS_BOX([from-lport ACL, default_acl_drop false])
> +check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=false
> +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed
's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_acl          ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_acl          ), priority=1001 , match=(ip4 && tcp),
action=(next;)
> +  table=??(ls_in_acl          ), priority=34000, match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_in_acl_after_lb ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_acl_hint     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl         ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_acl         ), priority=34000, match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl_hint    ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +])
> +
> +dnl UDP traffic should be allowed.
> +AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"],
[0], [dnl
> +#
udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
> +output("lsp2");
> +])
> +
> +AS_BOX([from-lport ACL, default_acl_drop true])
> +check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=true
> +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed
's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_acl          ), priority=0    , match=(1),
action=(drop;)
> +  table=??(ls_in_acl          ), priority=1001 , match=(ip4 && tcp),
action=(next;)
> +  table=??(ls_in_acl          ), priority=34000, match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_in_acl_after_lb ), priority=0    , match=(1),
action=(drop;)
> +  table=??(ls_in_acl_hint     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl         ), priority=0    , match=(1),
action=(drop;)
> +  table=??(ls_out_acl         ), priority=34000, match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl_hint    ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +])
> +
> +dnl UDP traffic should be dropped.
> +AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"],
[0], [dnl
> +#
udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
> +])
> +
> +AS_BOX([from-lport ACL allow-related, default_acl_drop true])
> +check ovn-nbctl acl-del ls
> +check ovn-nbctl --wait=sb acl-add ls from-lport 1 "ip4 && tcp"
allow-related
> +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed
's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_acl          ), priority=0    , match=(1),
action=(drop;)
> +  table=??(ls_in_acl          ), priority=1    , match=(ip && !ct.est),
action=(drop;)
> +  table=??(ls_in_acl          ), priority=1    , match=(ip && ct.est &&
ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl          ), priority=1001 , match=(reg0[[7]] == 1
&& (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl          ), priority=1001 , match=(reg0[[8]] == 1
&& (ip4 && tcp)), action=(next;)
> +  table=??(ls_in_acl          ), priority=34000, match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_in_acl          ), priority=65532, match=(!ct.est &&
ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
> +  table=??(ls_in_acl          ), priority=65532, match=(ct.est &&
!ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0),
action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
> +  table=??(ls_in_acl          ), priority=65532, match=(ct.inv ||
(ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
> +  table=??(ls_in_acl          ), priority=65532, match=(nd || nd_ra ||
nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_in_acl_after_lb ), priority=0    , match=(1),
action=(drop;)
> +  table=??(ls_in_acl_hint     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_acl_hint     ), priority=1    , match=(ct.est &&
ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
> +  table=??(ls_in_acl_hint     ), priority=2    , match=(ct.est &&
ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
> +  table=??(ls_in_acl_hint     ), priority=3    , match=(!ct.est),
action=(reg0[[9]] = 1; next;)
> +  table=??(ls_in_acl_hint     ), priority=4    , match=(!ct.new &&
ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1;
reg0[[10]] = 1; next;)
> +  table=??(ls_in_acl_hint     ), priority=5    , match=(!ct.trk),
action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
> +  table=??(ls_in_acl_hint     ), priority=6    , match=(!ct.new &&
ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1;
reg0[[9]] = 1; next;)
> +  table=??(ls_in_acl_hint     ), priority=7    , match=(ct.new &&
!ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
> +  table=??(ls_in_pre_acl      ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=100  , match=(ip),
action=(reg0[[0]] = 1; next;)
> +  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.mcast),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=110  , match=(nd || nd_rs ||
nd_ra || mldv1 || mldv2 || (udp && udp.src == 546 && udp.dst == 547)),
action=(next;)
> +  table=??(ls_out_acl         ), priority=0    , match=(1),
action=(drop;)
> +  table=??(ls_out_acl         ), priority=1    , match=(ip && !ct.est),
action=(drop;)
> +  table=??(ls_out_acl         ), priority=1    , match=(ip && ct.est &&
ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
> +  table=??(ls_out_acl         ), priority=34000, match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl         ), priority=65532, match=(!ct.est &&
ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
> +  table=??(ls_out_acl         ), priority=65532, match=(ct.est &&
!ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0),
action=(next;)
> +  table=??(ls_out_acl         ), priority=65532, match=(ct.inv ||
(ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
> +  table=??(ls_out_acl         ), priority=65532, match=(nd || nd_ra ||
nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_out_acl_hint    ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_acl_hint    ), priority=1    , match=(ct.est &&
ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
> +  table=??(ls_out_acl_hint    ), priority=2    , match=(ct.est &&
ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
> +  table=??(ls_out_acl_hint    ), priority=3    , match=(!ct.est),
action=(reg0[[9]] = 1; next;)
> +  table=??(ls_out_acl_hint    ), priority=4    , match=(!ct.new &&
ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1;
reg0[[10]] = 1; next;)
> +  table=??(ls_out_acl_hint    ), priority=5    , match=(!ct.trk),
action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
> +  table=??(ls_out_acl_hint    ), priority=6    , match=(!ct.new &&
ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1;
reg0[[9]] = 1; next;)
> +  table=??(ls_out_acl_hint    ), priority=7    , match=(ct.new &&
!ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
> +  table=??(ls_out_pre_acl     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=100  , match=(ip),
action=(reg0[[0]] = 1; next;)
> +  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.mcast),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=110  , match=(nd || nd_rs ||
nd_ra || mldv1 || mldv2 || (udp && udp.src == 546 && udp.dst == 547)),
action=(next;)
> +])
> +
> +dnl UDP traffic should be dropped.
> +AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"],
[0], [dnl
> +#
udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
> +ct_next(ct_state=new|trk);
> +])
> +
> +AS_BOX([from-lport --apply-after-lb ACL])
> +check ovn-nbctl acl-del ls
> +check ovn-nbctl --apply-after-lb acl-add ls from-lport 1 "ip4 && tcp"
allow
> +
> +AS_BOX([from-lport --apply-after-lb ACL, default_acl_drop not set])
> +check ovn-nbctl --wait=sb remove NB_Global . options default_acl_drop
> +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed
's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_acl          ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_acl          ), priority=34000, match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_in_acl_after_lb ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_acl_after_lb ), priority=1001 , match=(ip4 && tcp),
action=(next;)
> +  table=??(ls_in_acl_hint     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl         ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_acl         ), priority=34000, match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl_hint    ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +])
> +
> +dnl UDP traffic should be allowed.
> +AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"],
[0], [dnl
> +#
udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
> +output("lsp2");
> +])
> +
> +AS_BOX([from-lport --apply-after-lb ACL, default_acl_drop false])
> +check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=false
> +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed
's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_acl          ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_acl          ), priority=34000, match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_in_acl_after_lb ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_acl_after_lb ), priority=1001 , match=(ip4 && tcp),
action=(next;)
> +  table=??(ls_in_acl_hint     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl         ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_acl         ), priority=34000, match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl_hint    ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +])
> +
> +dnl UDP traffic should be allowed.
> +AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"],
[0], [dnl
> +#
udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
> +output("lsp2");
> +])
> +
> +AS_BOX([from-lport --apply-after-lb ACL, default_acl_drop true])
> +check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=true
> +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed
's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_acl          ), priority=0    , match=(1),
action=(drop;)
> +  table=??(ls_in_acl          ), priority=34000, match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_in_acl_after_lb ), priority=0    , match=(1),
action=(drop;)
> +  table=??(ls_in_acl_after_lb ), priority=1001 , match=(ip4 && tcp),
action=(next;)
> +  table=??(ls_in_acl_hint     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl         ), priority=0    , match=(1),
action=(drop;)
> +  table=??(ls_out_acl         ), priority=34000, match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl_hint    ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +])
> +
> +dnl UDP traffic should be dropped.
> +AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"],
[0], [dnl
> +#
udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
> +])
> +
> +AS_BOX([from-lport --apply-after-lb ACL allow-related, default_acl_drop
true])
> +check ovn-nbctl acl-del ls
> +check ovn-nbctl --wait=sb --apply-after-lb acl-add ls from-lport 1 "ip4
&& tcp" allow-related
> +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed
's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_acl          ), priority=0    , match=(1),
action=(drop;)
> +  table=??(ls_in_acl          ), priority=1    , match=(ip && !ct.est),
action=(drop;)
> +  table=??(ls_in_acl          ), priority=1    , match=(ip && ct.est &&
ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl          ), priority=34000, match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_in_acl          ), priority=65532, match=(!ct.est &&
ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
> +  table=??(ls_in_acl          ), priority=65532, match=(ct.est &&
!ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0),
action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
> +  table=??(ls_in_acl          ), priority=65532, match=(ct.inv ||
(ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
> +  table=??(ls_in_acl          ), priority=65532, match=(nd || nd_ra ||
nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_in_acl_after_lb ), priority=0    , match=(1),
action=(drop;)
> +  table=??(ls_in_acl_after_lb ), priority=1001 , match=(reg0[[7]] == 1
&& (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl_after_lb ), priority=1001 , match=(reg0[[8]] == 1
&& (ip4 && tcp)), action=(next;)
> +  table=??(ls_in_acl_hint     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_acl_hint     ), priority=1    , match=(ct.est &&
ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
> +  table=??(ls_in_acl_hint     ), priority=2    , match=(ct.est &&
ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
> +  table=??(ls_in_acl_hint     ), priority=3    , match=(!ct.est),
action=(reg0[[9]] = 1; next;)
> +  table=??(ls_in_acl_hint     ), priority=4    , match=(!ct.new &&
ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1;
reg0[[10]] = 1; next;)
> +  table=??(ls_in_acl_hint     ), priority=5    , match=(!ct.trk),
action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
> +  table=??(ls_in_acl_hint     ), priority=6    , match=(!ct.new &&
ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1;
reg0[[9]] = 1; next;)
> +  table=??(ls_in_acl_hint     ), priority=7    , match=(ct.new &&
!ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
> +  table=??(ls_in_pre_acl      ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=100  , match=(ip),
action=(reg0[[0]] = 1; next;)
> +  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.mcast),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=110  , match=(nd || nd_rs ||
nd_ra || mldv1 || mldv2 || (udp && udp.src == 546 && udp.dst == 547)),
action=(next;)
> +  table=??(ls_out_acl         ), priority=0    , match=(1),
action=(drop;)
> +  table=??(ls_out_acl         ), priority=1    , match=(ip && !ct.est),
action=(drop;)
> +  table=??(ls_out_acl         ), priority=1    , match=(ip && ct.est &&
ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
> +  table=??(ls_out_acl         ), priority=34000, match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl         ), priority=65532, match=(!ct.est &&
ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
> +  table=??(ls_out_acl         ), priority=65532, match=(ct.est &&
!ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0),
action=(next;)
> +  table=??(ls_out_acl         ), priority=65532, match=(ct.inv ||
(ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
> +  table=??(ls_out_acl         ), priority=65532, match=(nd || nd_ra ||
nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_out_acl_hint    ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_acl_hint    ), priority=1    , match=(ct.est &&
ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
> +  table=??(ls_out_acl_hint    ), priority=2    , match=(ct.est &&
ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
> +  table=??(ls_out_acl_hint    ), priority=3    , match=(!ct.est),
action=(reg0[[9]] = 1; next;)
> +  table=??(ls_out_acl_hint    ), priority=4    , match=(!ct.new &&
ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1;
reg0[[10]] = 1; next;)
> +  table=??(ls_out_acl_hint    ), priority=5    , match=(!ct.trk),
action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
> +  table=??(ls_out_acl_hint    ), priority=6    , match=(!ct.new &&
ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1;
reg0[[9]] = 1; next;)
> +  table=??(ls_out_acl_hint    ), priority=7    , match=(ct.new &&
!ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
> +  table=??(ls_out_pre_acl     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=100  , match=(ip),
action=(reg0[[0]] = 1; next;)
> +  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.mcast),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=110  , match=(nd || nd_rs ||
nd_ra || mldv1 || mldv2 || (udp && udp.src == 546 && udp.dst == 547)),
action=(next;)
> +])
> +
> +dnl UDP traffic should be dropped.
> +AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"],
[0], [dnl
> +#
udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
> +ct_next(ct_state=new|trk);
> +])
> +
> +AS_BOX([to-lport ACL])
> +check ovn-nbctl acl-del ls
> +check ovn-nbctl acl-add ls to-lport 1 "ip4 && tcp" allow
> +
> +AS_BOX([to-lport ACL, default_acl_drop not set])
> +check ovn-nbctl --wait=sb remove NB_Global . options default_acl_drop
> +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed
's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_acl          ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_acl          ), priority=34000, match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_in_acl_after_lb ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_acl_hint     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl         ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_acl         ), priority=1001 , match=(ip4 && tcp),
action=(next;)
> +  table=??(ls_out_acl         ), priority=34000, match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl_hint    ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +])
> +
> +dnl UDP traffic should be allowed.
> +AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"],
[0], [dnl
> +#
udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
> +output("lsp2");
> +])
> +
> +AS_BOX([to-lport ACL, default_acl_drop false])
> +check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=false
> +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed
's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_acl          ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_acl          ), priority=34000, match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_in_acl_after_lb ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_acl_hint     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl         ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_acl         ), priority=1001 , match=(ip4 && tcp),
action=(next;)
> +  table=??(ls_out_acl         ), priority=34000, match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl_hint    ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +])
> +
> +dnl UDP traffic should be allowed.
> +AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"],
[0], [dnl
> +#
udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
> +output("lsp2");
> +])
> +
> +AS_BOX([to-lport ACL, default_acl_drop true])
> +check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=true
> +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed
's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_acl          ), priority=0    , match=(1),
action=(drop;)
> +  table=??(ls_in_acl          ), priority=34000, match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_in_acl_after_lb ), priority=0    , match=(1),
action=(drop;)
> +  table=??(ls_in_acl_hint     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl         ), priority=0    , match=(1),
action=(drop;)
> +  table=??(ls_out_acl         ), priority=1001 , match=(ip4 && tcp),
action=(next;)
> +  table=??(ls_out_acl         ), priority=34000, match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl_hint    ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +])
> +
> +dnl UDP traffic should be dropped.
> +AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"],
[0], [dnl
> +#
udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
> +])
> +
> +AS_BOX([to-lport ACL allow-related, default_acl_drop true])
> +check ovn-nbctl acl-del ls
> +check ovn-nbctl --wait=sb acl-add ls to-lport 1 "ip4 && tcp"
allow-related
> +AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed
's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_acl          ), priority=0    , match=(1),
action=(drop;)
> +  table=??(ls_in_acl          ), priority=1    , match=(ip && !ct.est),
action=(drop;)
> +  table=??(ls_in_acl          ), priority=1    , match=(ip && ct.est &&
ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl          ), priority=34000, match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_in_acl          ), priority=65532, match=(!ct.est &&
ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
> +  table=??(ls_in_acl          ), priority=65532, match=(ct.est &&
!ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0),
action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
> +  table=??(ls_in_acl          ), priority=65532, match=(ct.inv ||
(ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
> +  table=??(ls_in_acl          ), priority=65532, match=(nd || nd_ra ||
nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_in_acl_after_lb ), priority=0    , match=(1),
action=(drop;)
> +  table=??(ls_in_acl_hint     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_acl_hint     ), priority=1    , match=(ct.est &&
ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
> +  table=??(ls_in_acl_hint     ), priority=2    , match=(ct.est &&
ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
> +  table=??(ls_in_acl_hint     ), priority=3    , match=(!ct.est),
action=(reg0[[9]] = 1; next;)
> +  table=??(ls_in_acl_hint     ), priority=4    , match=(!ct.new &&
ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1;
reg0[[10]] = 1; next;)
> +  table=??(ls_in_acl_hint     ), priority=5    , match=(!ct.trk),
action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
> +  table=??(ls_in_acl_hint     ), priority=6    , match=(!ct.new &&
ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1;
reg0[[9]] = 1; next;)
> +  table=??(ls_in_acl_hint     ), priority=7    , match=(ct.new &&
!ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
> +  table=??(ls_in_pre_acl      ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=100  , match=(ip),
action=(reg0[[0]] = 1; next;)
> +  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.mcast),
action=(next;)
> +  table=??(ls_in_pre_acl      ), priority=110  , match=(nd || nd_rs ||
nd_ra || mldv1 || mldv2 || (udp && udp.src == 546 && udp.dst == 547)),
action=(next;)
> +  table=??(ls_out_acl         ), priority=0    , match=(1),
action=(drop;)
> +  table=??(ls_out_acl         ), priority=1    , match=(ip && !ct.est),
action=(drop;)
> +  table=??(ls_out_acl         ), priority=1    , match=(ip && ct.est &&
ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
> +  table=??(ls_out_acl         ), priority=1001 , match=(reg0[[7]] == 1
&& (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
> +  table=??(ls_out_acl         ), priority=1001 , match=(reg0[[8]] == 1
&& (ip4 && tcp)), action=(next;)
> +  table=??(ls_out_acl         ), priority=34000, match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_acl         ), priority=65532, match=(!ct.est &&
ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
> +  table=??(ls_out_acl         ), priority=65532, match=(ct.est &&
!ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0),
action=(next;)
> +  table=??(ls_out_acl         ), priority=65532, match=(ct.inv ||
(ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
> +  table=??(ls_out_acl         ), priority=65532, match=(nd || nd_ra ||
nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_out_acl_hint    ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_acl_hint    ), priority=1    , match=(ct.est &&
ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
> +  table=??(ls_out_acl_hint    ), priority=2    , match=(ct.est &&
ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
> +  table=??(ls_out_acl_hint    ), priority=3    , match=(!ct.est),
action=(reg0[[9]] = 1; next;)
> +  table=??(ls_out_acl_hint    ), priority=4    , match=(!ct.new &&
ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1;
reg0[[10]] = 1; next;)
> +  table=??(ls_out_acl_hint    ), priority=5    , match=(!ct.trk),
action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
> +  table=??(ls_out_acl_hint    ), priority=6    , match=(!ct.new &&
ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1;
reg0[[9]] = 1; next;)
> +  table=??(ls_out_acl_hint    ), priority=7    , match=(ct.new &&
!ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
> +  table=??(ls_out_pre_acl     ), priority=0    , match=(1),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=100  , match=(ip),
action=(reg0[[0]] = 1; next;)
> +  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.mcast),
action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src ==
$svc_monitor_mac), action=(next;)
> +  table=??(ls_out_pre_acl     ), priority=110  , match=(nd || nd_rs ||
nd_ra || mldv1 || mldv2 || (udp && udp.src == 546 && udp.dst == 547)),
action=(next;)
> +])
> +
> +dnl UDP traffic should be dropped.
> +AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"],
[0], [dnl
> +#
udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
> +ct_next(ct_state=new|trk);
> +])
> +
> +AT_CLEANUP
> +])
> --
> 2.27.0
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Thanks Dumitru. Mark had reviewed the RFC earlier, so I will let him
confirm the change again.
Acked-by: Han Zhou <hzhou@ovn.org>
Dumitru Ceara April 22, 2022, 7:11 a.m. UTC | #2
On 4/20/22 17:58, Han Zhou wrote:
> Thanks Dumitru. Mark had reviewed the RFC earlier, so I will let him
> confirm the change again.
> Acked-by: Han Zhou <hzhou@ovn.org>

Thanks, Han, for the review!
Mark Michelson April 26, 2022, 1:35 p.m. UTC | #3
On 4/22/22 03:11, Dumitru Ceara wrote:
> On 4/20/22 17:58, Han Zhou wrote:
>> Thanks Dumitru. Mark had reviewed the RFC earlier, so I will let him
>> confirm the change again.
>> Acked-by: Han Zhou <hzhou@ovn.org>
> 
> Thanks, Han, for the review!
> 

Thanks yall, I merged the change to main.
Dumitru Ceara April 26, 2022, 3:36 p.m. UTC | #4
On 4/26/22 15:35, Mark Michelson wrote:
> On 4/22/22 03:11, Dumitru Ceara wrote:
>> On 4/20/22 17:58, Han Zhou wrote:
>>> Thanks Dumitru. Mark had reviewed the RFC earlier, so I will let him
>>> confirm the change again.
>>> Acked-by: Han Zhou <hzhou@ovn.org>
>>
>> Thanks, Han, for the review!
>>
> 
> Thanks yall, I merged the change to main.
> 

Sorry, I just realized this commit breaks the scenario when load
balancers are applied to switches that don't have any ACLs applied to them.

I should've seen it earlier because system tests are failing.  For some
reason I also completely ignored the email from ovsrobot and the status
on patchwork, I apologize:

https://mail.openvswitch.org/pipermail/ovs-build/2022-April/021407.html

Follow up fix posted:
https://patchwork.ozlabs.org/project/ovn/patch/20220426153529.4130-1-dceara@redhat.com/

Sorry for the noise.
diff mbox series

Patch

diff --git a/NEWS b/NEWS
index c881764a6..dbe89e9cf 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,8 @@  Post v22.03.0
   - Replaced the usage of masked ct_label by ct_mark in most cases to work
     better with hardware-offloading.
   - Support NAT for logical routers with multiple distributed gateway ports.
+  - Add global option (NB_Global.options:default_acl_drop) to enable
+    implicit drop behavior on logical switches with ACLs applied.
 
 OVN v22.03.0 - 11 Mar 2022
 --------------------------
diff --git a/northd/northd.c b/northd/northd.c
index bcd36bbaa..43b028c2c 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -74,6 +74,12 @@  static struct eth_addr svc_monitor_mac_ea;
  * Otherwise, it will avoid using it.  The default is true. */
 static bool use_ct_inv_match = true;
 
+/* If this option is 'true' northd will implicitly add a lowest-priority
+ * drop rule in the ACL stage of logical switches that have at least one
+ * ACL.
+ */
+static bool default_acl_drop;
+
 #define MAX_OVN_TAGS 4096
 
 /* Pipeline stages. */
@@ -6617,6 +6623,7 @@  static void
 build_acls(struct ovn_datapath *od, struct hmap *lflows,
            const struct hmap *port_groups, const struct shash *meter_groups)
 {
+    const char *default_acl_action = default_acl_drop ? "drop;" : "next;";
     bool has_stateful = od->has_stateful_acl || od->has_lb_vip;
     struct ds match   = DS_EMPTY_INITIALIZER;
     struct ds actions = DS_EMPTY_INITIALIZER;
@@ -6628,22 +6635,34 @@  build_acls(struct ovn_datapath *od, struct hmap *lflows,
      *
      * A related rule at priority 1 is added below if there
      * are any stateful ACLs in this datapath. */
-    if (!od->has_acls && !od->has_lb_vip) {
-        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX, "1", "next;");
-        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX, "1", "next;");
+    if (!od->has_acls) {
+        if (!od->has_lb_vip) {
+            ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX, "1",
+                          "next;");
+            ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX, "1",
+                          "next;");
+        } else {
+            ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 1, "1", "next;");
+            ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 1, "1", "next;");
+        }
+        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, 0, "1", "next;");
     } else {
-        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 0, "1", "next;");
-        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 0, "1", "next;");
+        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 0, "1",
+                      default_acl_action);
+        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 0, "1",
+                      default_acl_action);
+        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, 0, "1",
+                      default_acl_action);
     }
 
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, 0, "1", "next;");
 
     if (has_stateful) {
         /* Ingress and Egress ACL Table (Priority 1).
          *
-         * By default, traffic is allowed.  This is partially handled by
-         * the Priority 0 ACL flows added earlier, but we also need to
-         * commit IP flows.  This is because, while the initiater's
+         * By default, traffic is allowed (if default_acl_drop is 'false') or
+         * dropped (if default_acl_drop is 'true').  This is partially
+         * handled by the Priority 0 ACL flows added earlier, but we also
+         * need to commit IP flows.  This is because, while the initiater's
          * direction may not have any stateful rules, the server's may
          * and then its return traffic would not have an associated
          * conntrack entry and would return "+invalid".
@@ -6661,12 +6680,20 @@  build_acls(struct ovn_datapath *od, struct hmap *lflows,
          * Subsequent packets will hit the flow at priority 0 that just
          * uses "next;". */
         ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 1,
-                      "ip && (!ct.est || (ct.est && ct_mark.blocked == 1))",
+                      "ip && ct.est && ct_mark.blocked == 1",
                        REGBIT_CONNTRACK_COMMIT" = 1; next;");
         ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 1,
-                      "ip && (!ct.est || (ct.est && ct_mark.blocked == 1))",
+                      "ip && ct.est && ct_mark.blocked == 1",
                        REGBIT_CONNTRACK_COMMIT" = 1; next;");
 
+        default_acl_action = default_acl_drop
+                             ? "drop;"
+                             : REGBIT_CONNTRACK_COMMIT" = 1; next;";
+        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 1, "ip && !ct.est",
+                      default_acl_action);
+        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 1, "ip && !ct.est",
+                      default_acl_action);
+
         /* Ingress and Egress ACL Table (Priority 65532).
          *
          * Always drop traffic that's in an invalid state.  Also drop
@@ -15321,6 +15348,7 @@  ovnnb_db_run(struct northd_input *input_data,
                                         "controller_event", false);
     check_lsp_is_up = !smap_get_bool(&nb->options,
                                      "ignore_lsp_down", true);
+    default_acl_drop = smap_get_bool(&nb->options, "default_acl_drop", false);
 
     build_datapaths(input_data, ovnsb_txn, &data->datapaths, &data->lr_list);
     build_lbs(input_data, &data->datapaths, &data->lbs);
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index db4f4d267..68e0bd626 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -774,8 +774,12 @@ 
     <p>
       This table contains a priority-65535 flow to advance to the next table
       if the logical switch has <code>no</code> ACLs configured, otherwise a
-        priority-0 flow to advance to the next table so that ACLs allow
-        packets by default.
+      priority-0 flow to advance to the next table so that ACLs allow
+      packets by default if <ref column="options:default_acl_drop"
+      table="NB_Global" db="OVN_Northbound"/> colum of <ref table="NB_Global"
+      db="OVN_Northbound"/> is <code>false</code> or not set.  Otherwise
+      the flow action is set to <code>drop;</code> to implement a default
+      drop behavior.
     </p>
 
     <p>
@@ -784,6 +788,26 @@ 
     </p>
 
     <ul>
+      <li>
+        If <ref column="options:default_acl_drop" table="NB_Global"
+        db="OVN_Northbound"/> colum of <ref table="NB_Global"
+        db="OVN_Northbound"/> is <code>false</code> or not set, a priority-1
+        flow that sets the hint to commit IP traffic that is not part of
+        established sessions to the connection tracker (with action
+        <code>reg0[1] = 1; next;</code>).  This is needed for
+        the default allow policy because, while the initiator's direction
+        may not have any stateful rules, the server's may and then
+        its return traffic would not be known and marked as invalid.
+      </li>
+
+      <li>
+        If <ref column="options:default_acl_drop" table="NB_Global"
+        db="OVN_Northbound"/> colum of <ref table="NB_Global"
+        db="OVN_Northbound"/> is <code>true</code>, a priority-1
+        flow that drops IP traffic that is not part of established
+        sessions.
+      </li>
+
       <li>
         A priority-1 flow that sets the hint to commit IP traffic to the
         connection tracker (with action <code>reg0[1] = 1; next;</code>).  This
diff --git a/ovn-nb.xml b/ovn-nb.xml
index 547f7f48a..9010240a8 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -255,6 +255,14 @@ 
         </p>
       </column>
 
+      <column name="options" key="default_acl_drop">
+        <p>
+          If set to <code>true</code>., <code>ovn-northd</code> will
+          generate a logical flow to drop all traffic in the ACL stages.
+          By default this option is set to <code>false</code>.
+        </p>
+      </column>
+
       <group title="Options for configuring interconnection route advertisement">
         <p>
           These options control how routes are advertised between OVN
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index adb304385..724ca2057 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -2227,7 +2227,8 @@  AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e
   table=3 (ls_out_acl_hint    ), priority=5    , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
   table=3 (ls_out_acl_hint    ), priority=6    , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
   table=3 (ls_out_acl_hint    ), priority=7    , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
-  table=4 (ls_out_acl         ), priority=1    , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;)
+  table=4 (ls_out_acl         ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
+  table=4 (ls_out_acl         ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
   table=4 (ls_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
   table=4 (ls_out_acl         ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;)
   table=4 (ls_out_acl         ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
@@ -2238,7 +2239,8 @@  AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e
   table=8 (ls_in_acl_hint     ), priority=5    , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
   table=8 (ls_in_acl_hint     ), priority=6    , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
   table=8 (ls_in_acl_hint     ), priority=7    , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
-  table=9 (ls_in_acl          ), priority=1    , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;)
+  table=9 (ls_in_acl          ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
+  table=9 (ls_in_acl          ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
   table=9 (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
   table=9 (ls_in_acl          ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
   table=9 (ls_in_acl          ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
@@ -2262,7 +2264,8 @@  AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e
   table=3 (ls_out_acl_hint    ), priority=6    , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
   table=3 (ls_out_acl_hint    ), priority=7    , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
   table=4 (ls_out_acl         ), priority=0    , match=(1), action=(next;)
-  table=4 (ls_out_acl         ), priority=1    , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;)
+  table=4 (ls_out_acl         ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
+  table=4 (ls_out_acl         ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
   table=4 (ls_out_acl         ), priority=1001 , match=(reg0[[7]] == 1 && (ip)), action=(reg0[[1]] = 1; next;)
   table=4 (ls_out_acl         ), priority=1001 , match=(reg0[[8]] == 1 && (ip)), action=(next;)
   table=4 (ls_out_acl         ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
@@ -2279,7 +2282,8 @@  AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e
   table=8 (ls_in_acl_hint     ), priority=6    , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
   table=8 (ls_in_acl_hint     ), priority=7    , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
   table=9 (ls_in_acl          ), priority=0    , match=(1), action=(next;)
-  table=9 (ls_in_acl          ), priority=1    , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;)
+  table=9 (ls_in_acl          ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
+  table=9 (ls_in_acl          ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
   table=9 (ls_in_acl          ), priority=1001 , match=(reg0[[7]] == 1 && (ip)), action=(reg0[[1]] = 1; next;)
   table=9 (ls_in_acl          ), priority=1001 , match=(reg0[[8]] == 1 && (ip)), action=(next;)
   table=9 (ls_in_acl          ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
@@ -6331,7 +6335,8 @@  AT_CAPTURE_FILE([lsflows])
 
 AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
   table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
-  table=??(ls_in_acl          ), priority=1    , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;)
+  table=??(ls_in_acl          ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
+  table=??(ls_in_acl          ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
   table=??(ls_in_acl          ), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */)
   table=??(ls_in_acl          ), priority=2001 , match=(reg0[[9]] == 1 && (ip4)), action=(/* drop */)
   table=??(ls_in_acl          ), priority=2002 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
@@ -6383,7 +6388,8 @@  AT_CAPTURE_FILE([lsflows])
 
 AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
   table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
-  table=??(ls_in_acl          ), priority=1    , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;)
+  table=??(ls_in_acl          ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
+  table=??(ls_in_acl          ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
   table=??(ls_in_acl          ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
   table=??(ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
   table=??(ls_in_acl          ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
@@ -6435,7 +6441,8 @@  AT_CAPTURE_FILE([lsflows])
 
 AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
   table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
-  table=??(ls_in_acl          ), priority=1    , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;)
+  table=??(ls_in_acl          ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
+  table=??(ls_in_acl          ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
   table=??(ls_in_acl          ), priority=2002 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
   table=??(ls_in_acl          ), priority=2002 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(next;)
   table=??(ls_in_acl          ), priority=2003 , match=(reg0[[7]] == 1 && (ip4 && icmp)), action=(reg0[[1]] = 1; next;)
@@ -6664,3 +6671,465 @@  ovn-nbctl --may-exist static-mac-binding-add lr0-p0 192.168.10.100 00:00:22:33:5
 wait_row_count Static_MAC_Binding 1 logical_port=lr0-p0 ip=192.168.10.100 mac="00\:00\:22\:33\:55\:66"
 
 AT_CLEANUP
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([LS default ACL drop])
+AT_KEYWORDS([acl])
+
+ovn_start
+
+check ovn-nbctl ls-add ls
+check ovn-nbctl lsp-add ls lsp1 -- lsp-set-addresses lsp1 00:00:00:00:00:01
+check ovn-nbctl lsp-add ls lsp2 -- lsp-set-addresses lsp2 00:00:00:00:00:02
+
+flow="inport == \"lsp1\" && eth.src == 00:00:00:00:00:01 && eth.dst == 00:00:00:00:00:02 && ip.ttl == 64 && ip4.src == 42.42.42.42 && ip4.dst == 42.42.42.43 && udp && udp.src == 42 && udp.dst == 84"
+
+AS_BOX([No ACL, default_acl_drop not set])
+check ovn-nbctl --wait=sb sync
+AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_acl          ), priority=65535, match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_hint     ), priority=65535, match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=65535, match=(1), action=(next;)
+  table=??(ls_out_acl_hint    ), priority=65535, match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == $svc_monitor_mac), action=(next;)
+])
+
+dnl UDP traffic should be allowed.
+AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
+# udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
+output("lsp2");
+])
+
+AS_BOX([No ACL, default_acl_drop false])
+check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=false
+AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_acl          ), priority=65535, match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_hint     ), priority=65535, match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=65535, match=(1), action=(next;)
+  table=??(ls_out_acl_hint    ), priority=65535, match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == $svc_monitor_mac), action=(next;)
+])
+
+dnl UDP traffic should be allowed.
+AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
+# udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
+output("lsp2");
+])
+
+AS_BOX([No ACL, default_acl_drop true])
+check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=true
+AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_acl          ), priority=65535, match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_hint     ), priority=65535, match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=65535, match=(1), action=(next;)
+  table=??(ls_out_acl_hint    ), priority=65535, match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == $svc_monitor_mac), action=(next;)
+])
+
+dnl UDP traffic should be allowed.
+AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
+# udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
+output("lsp2");
+])
+
+AS_BOX([from-lport ACL])
+check ovn-nbctl acl-del ls
+check ovn-nbctl acl-add ls from-lport 1 "ip4 && tcp" allow
+
+AS_BOX([from-lport ACL, default_acl_drop not set])
+check ovn-nbctl --wait=sb remove NB_Global . options default_acl_drop
+AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl          ), priority=1001 , match=(ip4 && tcp), action=(next;)
+  table=??(ls_in_acl          ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl         ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == $svc_monitor_mac), action=(next;)
+])
+
+dnl UDP traffic should be allowed.
+AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
+# udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
+output("lsp2");
+])
+
+AS_BOX([from-lport ACL, default_acl_drop false])
+check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=false
+AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl          ), priority=1001 , match=(ip4 && tcp), action=(next;)
+  table=??(ls_in_acl          ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl         ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == $svc_monitor_mac), action=(next;)
+])
+
+dnl UDP traffic should be allowed.
+AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
+# udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
+output("lsp2");
+])
+
+AS_BOX([from-lport ACL, default_acl_drop true])
+check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=true
+AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_acl          ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_in_acl          ), priority=1001 , match=(ip4 && tcp), action=(next;)
+  table=??(ls_in_acl          ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_out_acl         ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == $svc_monitor_mac), action=(next;)
+])
+
+dnl UDP traffic should be dropped.
+AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
+# udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
+])
+
+AS_BOX([from-lport ACL allow-related, default_acl_drop true])
+check ovn-nbctl acl-del ls
+check ovn-nbctl --wait=sb acl-add ls from-lport 1 "ip4 && tcp" allow-related
+AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_acl          ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_in_acl          ), priority=1    , match=(ip && !ct.est), action=(drop;)
+  table=??(ls_in_acl          ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
+  table=??(ls_in_acl          ), priority=1001 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
+  table=??(ls_in_acl          ), priority=1001 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(next;)
+  table=??(ls_in_acl          ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
+  table=??(ls_in_acl          ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
+  table=??(ls_in_acl          ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
+  table=??(ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_hint     ), priority=1    , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
+  table=??(ls_in_acl_hint     ), priority=2    , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
+  table=??(ls_in_acl_hint     ), priority=3    , match=(!ct.est), action=(reg0[[9]] = 1; next;)
+  table=??(ls_in_acl_hint     ), priority=4    , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
+  table=??(ls_in_acl_hint     ), priority=5    , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
+  table=??(ls_in_acl_hint     ), priority=6    , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
+  table=??(ls_in_acl_hint     ), priority=7    , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
+  table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=100  , match=(ip), action=(reg0[[0]] = 1; next;)
+  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.mcast), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=110  , match=(nd || nd_rs || nd_ra || mldv1 || mldv2 || (udp && udp.src == 546 && udp.dst == 547)), action=(next;)
+  table=??(ls_out_acl         ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_out_acl         ), priority=1    , match=(ip && !ct.est), action=(drop;)
+  table=??(ls_out_acl         ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
+  table=??(ls_out_acl         ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
+  table=??(ls_out_acl         ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;)
+  table=??(ls_out_acl         ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
+  table=??(ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl_hint    ), priority=1    , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
+  table=??(ls_out_acl_hint    ), priority=2    , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
+  table=??(ls_out_acl_hint    ), priority=3    , match=(!ct.est), action=(reg0[[9]] = 1; next;)
+  table=??(ls_out_acl_hint    ), priority=4    , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
+  table=??(ls_out_acl_hint    ), priority=5    , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
+  table=??(ls_out_acl_hint    ), priority=6    , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
+  table=??(ls_out_acl_hint    ), priority=7    , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
+  table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=100  , match=(ip), action=(reg0[[0]] = 1; next;)
+  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.mcast), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=110  , match=(nd || nd_rs || nd_ra || mldv1 || mldv2 || (udp && udp.src == 546 && udp.dst == 547)), action=(next;)
+])
+
+dnl UDP traffic should be dropped.
+AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
+# udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
+ct_next(ct_state=new|trk);
+])
+
+AS_BOX([from-lport --apply-after-lb ACL])
+check ovn-nbctl acl-del ls
+check ovn-nbctl --apply-after-lb acl-add ls from-lport 1 "ip4 && tcp" allow
+
+AS_BOX([from-lport --apply-after-lb ACL, default_acl_drop not set])
+check ovn-nbctl --wait=sb remove NB_Global . options default_acl_drop
+AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl          ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=1001 , match=(ip4 && tcp), action=(next;)
+  table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl         ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == $svc_monitor_mac), action=(next;)
+])
+
+dnl UDP traffic should be allowed.
+AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
+# udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
+output("lsp2");
+])
+
+AS_BOX([from-lport --apply-after-lb ACL, default_acl_drop false])
+check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=false
+AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl          ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=1001 , match=(ip4 && tcp), action=(next;)
+  table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl         ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == $svc_monitor_mac), action=(next;)
+])
+
+dnl UDP traffic should be allowed.
+AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
+# udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
+output("lsp2");
+])
+
+AS_BOX([from-lport --apply-after-lb ACL, default_acl_drop true])
+check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=true
+AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_acl          ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_in_acl          ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_in_acl_after_lb ), priority=1001 , match=(ip4 && tcp), action=(next;)
+  table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_out_acl         ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == $svc_monitor_mac), action=(next;)
+])
+
+dnl UDP traffic should be dropped.
+AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
+# udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
+])
+
+AS_BOX([from-lport --apply-after-lb ACL allow-related, default_acl_drop true])
+check ovn-nbctl acl-del ls
+check ovn-nbctl --wait=sb --apply-after-lb acl-add ls from-lport 1 "ip4 && tcp" allow-related
+AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_acl          ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_in_acl          ), priority=1    , match=(ip && !ct.est), action=(drop;)
+  table=??(ls_in_acl          ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
+  table=??(ls_in_acl          ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
+  table=??(ls_in_acl          ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
+  table=??(ls_in_acl          ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
+  table=??(ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_in_acl_after_lb ), priority=1001 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
+  table=??(ls_in_acl_after_lb ), priority=1001 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(next;)
+  table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_hint     ), priority=1    , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
+  table=??(ls_in_acl_hint     ), priority=2    , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
+  table=??(ls_in_acl_hint     ), priority=3    , match=(!ct.est), action=(reg0[[9]] = 1; next;)
+  table=??(ls_in_acl_hint     ), priority=4    , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
+  table=??(ls_in_acl_hint     ), priority=5    , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
+  table=??(ls_in_acl_hint     ), priority=6    , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
+  table=??(ls_in_acl_hint     ), priority=7    , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
+  table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=100  , match=(ip), action=(reg0[[0]] = 1; next;)
+  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.mcast), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=110  , match=(nd || nd_rs || nd_ra || mldv1 || mldv2 || (udp && udp.src == 546 && udp.dst == 547)), action=(next;)
+  table=??(ls_out_acl         ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_out_acl         ), priority=1    , match=(ip && !ct.est), action=(drop;)
+  table=??(ls_out_acl         ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
+  table=??(ls_out_acl         ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
+  table=??(ls_out_acl         ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;)
+  table=??(ls_out_acl         ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
+  table=??(ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl_hint    ), priority=1    , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
+  table=??(ls_out_acl_hint    ), priority=2    , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
+  table=??(ls_out_acl_hint    ), priority=3    , match=(!ct.est), action=(reg0[[9]] = 1; next;)
+  table=??(ls_out_acl_hint    ), priority=4    , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
+  table=??(ls_out_acl_hint    ), priority=5    , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
+  table=??(ls_out_acl_hint    ), priority=6    , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
+  table=??(ls_out_acl_hint    ), priority=7    , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
+  table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=100  , match=(ip), action=(reg0[[0]] = 1; next;)
+  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.mcast), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=110  , match=(nd || nd_rs || nd_ra || mldv1 || mldv2 || (udp && udp.src == 546 && udp.dst == 547)), action=(next;)
+])
+
+dnl UDP traffic should be dropped.
+AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
+# udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
+ct_next(ct_state=new|trk);
+])
+
+AS_BOX([to-lport ACL])
+check ovn-nbctl acl-del ls
+check ovn-nbctl acl-add ls to-lport 1 "ip4 && tcp" allow
+
+AS_BOX([to-lport ACL, default_acl_drop not set])
+check ovn-nbctl --wait=sb remove NB_Global . options default_acl_drop
+AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl          ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl         ), priority=1001 , match=(ip4 && tcp), action=(next;)
+  table=??(ls_out_acl         ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == $svc_monitor_mac), action=(next;)
+])
+
+dnl UDP traffic should be allowed.
+AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
+# udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
+output("lsp2");
+])
+
+AS_BOX([to-lport ACL, default_acl_drop false])
+check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=false
+AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl          ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl         ), priority=1001 , match=(ip4 && tcp), action=(next;)
+  table=??(ls_out_acl         ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == $svc_monitor_mac), action=(next;)
+])
+
+dnl UDP traffic should be allowed.
+AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
+# udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
+output("lsp2");
+])
+
+AS_BOX([to-lport ACL, default_acl_drop true])
+check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=true
+AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_acl          ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_in_acl          ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_out_acl         ), priority=1001 , match=(ip4 && tcp), action=(next;)
+  table=??(ls_out_acl         ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == $svc_monitor_mac), action=(next;)
+])
+
+dnl UDP traffic should be dropped.
+AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
+# udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
+])
+
+AS_BOX([to-lport ACL allow-related, default_acl_drop true])
+check ovn-nbctl acl-del ls
+check ovn-nbctl --wait=sb acl-add ls to-lport 1 "ip4 && tcp" allow-related
+AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_acl          ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_in_acl          ), priority=1    , match=(ip && !ct.est), action=(drop;)
+  table=??(ls_in_acl          ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
+  table=??(ls_in_acl          ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
+  table=??(ls_in_acl          ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
+  table=??(ls_in_acl          ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
+  table=??(ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_hint     ), priority=1    , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
+  table=??(ls_in_acl_hint     ), priority=2    , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
+  table=??(ls_in_acl_hint     ), priority=3    , match=(!ct.est), action=(reg0[[9]] = 1; next;)
+  table=??(ls_in_acl_hint     ), priority=4    , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
+  table=??(ls_in_acl_hint     ), priority=5    , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
+  table=??(ls_in_acl_hint     ), priority=6    , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
+  table=??(ls_in_acl_hint     ), priority=7    , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
+  table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=100  , match=(ip), action=(reg0[[0]] = 1; next;)
+  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=110  , match=(eth.mcast), action=(next;)
+  table=??(ls_in_pre_acl      ), priority=110  , match=(nd || nd_rs || nd_ra || mldv1 || mldv2 || (udp && udp.src == 546 && udp.dst == 547)), action=(next;)
+  table=??(ls_out_acl         ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_out_acl         ), priority=1    , match=(ip && !ct.est), action=(drop;)
+  table=??(ls_out_acl         ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
+  table=??(ls_out_acl         ), priority=1001 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
+  table=??(ls_out_acl         ), priority=1001 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(next;)
+  table=??(ls_out_acl         ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
+  table=??(ls_out_acl         ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;)
+  table=??(ls_out_acl         ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
+  table=??(ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl_hint    ), priority=1    , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
+  table=??(ls_out_acl_hint    ), priority=2    , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
+  table=??(ls_out_acl_hint    ), priority=3    , match=(!ct.est), action=(reg0[[9]] = 1; next;)
+  table=??(ls_out_acl_hint    ), priority=4    , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
+  table=??(ls_out_acl_hint    ), priority=5    , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
+  table=??(ls_out_acl_hint    ), priority=6    , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
+  table=??(ls_out_acl_hint    ), priority=7    , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
+  table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=100  , match=(ip), action=(reg0[[0]] = 1; next;)
+  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.mcast), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == $svc_monitor_mac), action=(next;)
+  table=??(ls_out_pre_acl     ), priority=110  , match=(nd || nd_rs || nd_ra || mldv1 || mldv2 || (udp && udp.src == 546 && udp.dst == 547)), action=(next;)
+])
+
+dnl UDP traffic should be dropped.
+AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
+# udp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.42,nw_dst=42.42.42.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=42,tp_dst=84
+ct_next(ct_state=new|trk);
+])
+
+AT_CLEANUP
+])