diff mbox series

[ovs-dev,v5,1/4] northd: Break ACLs into two stages.

Message ID 20230518184842.1681582-1-mmichels@redhat.com
State Accepted
Headers show
Series [ovs-dev,v5,1/4] northd: Break ACLs into two stages. | expand

Checks

Context Check Description
ovsrobot/apply-robot fail apply and check: fail

Commit Message

Mark Michelson May 18, 2023, 6:48 p.m. UTC
Prior to this commit, ACLs were evaluated and acted on in a single
stage. With this commit, evaluation of ACLs and acting on an ACL's
decision are separated into two stages.

The acl_eval stage checks the ACL match and will set a bit to indicate
the verdict of the ACL. The acl_action stage then checks the relevant
bits to determine how to proceed. If no ACLs are matched, then the
default ACL action is taken.

A couple of notes about updated tests:
- For test cases where I just had to increment a table number, I changed
  the check so the table numbers are masked. This should prevent similar
  changes from being needed later.
- The port security test changes may seem odd. The issue here is that
  the ls_out_apply_port_sec table number changed from 9 to 10. This
  means that this table's flows now sort to a lower position than
  before. This is why the check had to change for this test.

Signed-off-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Ales Musil <amusil@redhat.com>
---
 northd/northd.c         |  669 +++++++++++----------
 northd/ovn-northd.8.xml |  312 ++++++----
 tests/ovn-controller.at |  144 ++---
 tests/ovn-northd.at     | 1254 ++++++++++++++++++++++-----------------
 tests/ovn.at            |  114 ++--
 tests/system-ovn.at     |    2 +-
 6 files changed, 1399 insertions(+), 1096 deletions(-)

Comments

Mark Michelson May 18, 2023, 6:51 p.m. UTC | #1
I added Numan's ack from v4 and pushed this series to main. Thanks 
everyone for the reviews and feedback.

On 5/18/23 14:48, Mark Michelson wrote:
> Prior to this commit, ACLs were evaluated and acted on in a single
> stage. With this commit, evaluation of ACLs and acting on an ACL's
> decision are separated into two stages.
> 
> The acl_eval stage checks the ACL match and will set a bit to indicate
> the verdict of the ACL. The acl_action stage then checks the relevant
> bits to determine how to proceed. If no ACLs are matched, then the
> default ACL action is taken.
> 
> A couple of notes about updated tests:
> - For test cases where I just had to increment a table number, I changed
>    the check so the table numbers are masked. This should prevent similar
>    changes from being needed later.
> - The port security test changes may seem odd. The issue here is that
>    the ls_out_apply_port_sec table number changed from 9 to 10. This
>    means that this table's flows now sort to a lower position than
>    before. This is why the check had to change for this test.
> 
> Signed-off-by: Mark Michelson <mmichels@redhat.com>
> Reviewed-by: Ales Musil <amusil@redhat.com>
> ---
>   northd/northd.c         |  669 +++++++++++----------
>   northd/ovn-northd.8.xml |  312 ++++++----
>   tests/ovn-controller.at |  144 ++---
>   tests/ovn-northd.at     | 1254 ++++++++++++++++++++++-----------------
>   tests/ovn.at            |  114 ++--
>   tests/system-ovn.at     |    2 +-
>   6 files changed, 1399 insertions(+), 1096 deletions(-)
> 
> diff --git a/northd/northd.c b/northd/northd.c
> index 2f96d15a4..c7969e0ba 100644
> --- a/northd/northd.c
> +++ b/northd/northd.c
> @@ -122,37 +122,42 @@ enum ovn_stage {
>       PIPELINE_STAGE(SWITCH, IN,  PRE_LB,         5, "ls_in_pre_lb")        \
>       PIPELINE_STAGE(SWITCH, IN,  PRE_STATEFUL,   6, "ls_in_pre_stateful")  \
>       PIPELINE_STAGE(SWITCH, IN,  ACL_HINT,       7, "ls_in_acl_hint")      \
> -    PIPELINE_STAGE(SWITCH, IN,  ACL,            8, "ls_in_acl")           \
> -    PIPELINE_STAGE(SWITCH, IN,  QOS_MARK,       9, "ls_in_qos_mark")      \
> -    PIPELINE_STAGE(SWITCH, IN,  QOS_METER,     10, "ls_in_qos_meter")     \
> -    PIPELINE_STAGE(SWITCH, IN,  LB_AFF_CHECK,  11, "ls_in_lb_aff_check")  \
> -    PIPELINE_STAGE(SWITCH, IN,  LB,            12, "ls_in_lb")            \
> -    PIPELINE_STAGE(SWITCH, IN,  LB_AFF_LEARN,  13, "ls_in_lb_aff_learn")  \
> -    PIPELINE_STAGE(SWITCH, IN,  PRE_HAIRPIN,   14, "ls_in_pre_hairpin")   \
> -    PIPELINE_STAGE(SWITCH, IN,  NAT_HAIRPIN,   15, "ls_in_nat_hairpin")   \
> -    PIPELINE_STAGE(SWITCH, IN,  HAIRPIN,       16, "ls_in_hairpin")       \
> -    PIPELINE_STAGE(SWITCH, IN,  ACL_AFTER_LB,  17, "ls_in_acl_after_lb")  \
> -    PIPELINE_STAGE(SWITCH, IN,  STATEFUL,      18, "ls_in_stateful")      \
> -    PIPELINE_STAGE(SWITCH, IN,  ARP_ND_RSP,    19, "ls_in_arp_rsp")       \
> -    PIPELINE_STAGE(SWITCH, IN,  DHCP_OPTIONS,  20, "ls_in_dhcp_options")  \
> -    PIPELINE_STAGE(SWITCH, IN,  DHCP_RESPONSE, 21, "ls_in_dhcp_response") \
> -    PIPELINE_STAGE(SWITCH, IN,  DNS_LOOKUP,    22, "ls_in_dns_lookup")    \
> -    PIPELINE_STAGE(SWITCH, IN,  DNS_RESPONSE,  23, "ls_in_dns_response")  \
> -    PIPELINE_STAGE(SWITCH, IN,  EXTERNAL_PORT, 24, "ls_in_external_port") \
> -    PIPELINE_STAGE(SWITCH, IN,  L2_LKUP,       25, "ls_in_l2_lkup")       \
> -    PIPELINE_STAGE(SWITCH, IN,  L2_UNKNOWN,    26, "ls_in_l2_unknown")    \
> +    PIPELINE_STAGE(SWITCH, IN,  ACL_EVAL,       8, "ls_in_acl_eval")      \
> +    PIPELINE_STAGE(SWITCH, IN,  ACL_ACTION,     9, "ls_in_acl_action")    \
> +    PIPELINE_STAGE(SWITCH, IN,  QOS_MARK,      10, "ls_in_qos_mark")      \
> +    PIPELINE_STAGE(SWITCH, IN,  QOS_METER,     11, "ls_in_qos_meter")     \
> +    PIPELINE_STAGE(SWITCH, IN,  LB_AFF_CHECK,  12, "ls_in_lb_aff_check")  \
> +    PIPELINE_STAGE(SWITCH, IN,  LB,            13, "ls_in_lb")            \
> +    PIPELINE_STAGE(SWITCH, IN,  LB_AFF_LEARN,  14, "ls_in_lb_aff_learn")  \
> +    PIPELINE_STAGE(SWITCH, IN,  PRE_HAIRPIN,   15, "ls_in_pre_hairpin")   \
> +    PIPELINE_STAGE(SWITCH, IN,  NAT_HAIRPIN,   16, "ls_in_nat_hairpin")   \
> +    PIPELINE_STAGE(SWITCH, IN,  HAIRPIN,       17, "ls_in_hairpin")       \
> +    PIPELINE_STAGE(SWITCH, IN,  ACL_AFTER_LB_EVAL,  18, \
> +                   "ls_in_acl_after_lb_eval")  \
> +    PIPELINE_STAGE(SWITCH, IN,  ACL_AFTER_LB_ACTION,  19, \
> +                   "ls_in_acl_after_lb_action")  \
> +    PIPELINE_STAGE(SWITCH, IN,  STATEFUL,      20, "ls_in_stateful")      \
> +    PIPELINE_STAGE(SWITCH, IN,  ARP_ND_RSP,    21, "ls_in_arp_rsp")       \
> +    PIPELINE_STAGE(SWITCH, IN,  DHCP_OPTIONS,  22, "ls_in_dhcp_options")  \
> +    PIPELINE_STAGE(SWITCH, IN,  DHCP_RESPONSE, 23, "ls_in_dhcp_response") \
> +    PIPELINE_STAGE(SWITCH, IN,  DNS_LOOKUP,    24, "ls_in_dns_lookup")    \
> +    PIPELINE_STAGE(SWITCH, IN,  DNS_RESPONSE,  25, "ls_in_dns_response")  \
> +    PIPELINE_STAGE(SWITCH, IN,  EXTERNAL_PORT, 26, "ls_in_external_port") \
> +    PIPELINE_STAGE(SWITCH, IN,  L2_LKUP,       27, "ls_in_l2_lkup")       \
> +    PIPELINE_STAGE(SWITCH, IN,  L2_UNKNOWN,    28, "ls_in_l2_unknown")    \
>                                                                             \
>       /* Logical switch egress stages. */                                   \
>       PIPELINE_STAGE(SWITCH, OUT, PRE_ACL,      0, "ls_out_pre_acl")        \
>       PIPELINE_STAGE(SWITCH, OUT, PRE_LB,       1, "ls_out_pre_lb")         \
>       PIPELINE_STAGE(SWITCH, OUT, PRE_STATEFUL, 2, "ls_out_pre_stateful")   \
>       PIPELINE_STAGE(SWITCH, OUT, ACL_HINT,     3, "ls_out_acl_hint")       \
> -    PIPELINE_STAGE(SWITCH, OUT, ACL,          4, "ls_out_acl")            \
> -    PIPELINE_STAGE(SWITCH, OUT, QOS_MARK,     5, "ls_out_qos_mark")       \
> -    PIPELINE_STAGE(SWITCH, OUT, QOS_METER,    6, "ls_out_qos_meter")      \
> -    PIPELINE_STAGE(SWITCH, OUT, STATEFUL,     7, "ls_out_stateful")       \
> -    PIPELINE_STAGE(SWITCH, OUT, CHECK_PORT_SEC,  8, "ls_out_check_port_sec") \
> -    PIPELINE_STAGE(SWITCH, OUT, APPLY_PORT_SEC,  9, "ls_out_apply_port_sec") \
> +    PIPELINE_STAGE(SWITCH, OUT, ACL_EVAL,     4, "ls_out_acl_eval")       \
> +    PIPELINE_STAGE(SWITCH, OUT, ACL_ACTION,   5, "ls_out_acl_action")     \
> +    PIPELINE_STAGE(SWITCH, OUT, QOS_MARK,     6, "ls_out_qos_mark")       \
> +    PIPELINE_STAGE(SWITCH, OUT, QOS_METER,    7, "ls_out_qos_meter")      \
> +    PIPELINE_STAGE(SWITCH, OUT, STATEFUL,     8, "ls_out_stateful")       \
> +    PIPELINE_STAGE(SWITCH, OUT, CHECK_PORT_SEC,  9, "ls_out_check_port_sec") \
> +    PIPELINE_STAGE(SWITCH, OUT, APPLY_PORT_SEC, 10, "ls_out_apply_port_sec") \
>                                                                         \
>       /* Logical router ingress stages. */                              \
>       PIPELINE_STAGE(ROUTER, IN,  ADMISSION,       0, "lr_in_admission")    \
> @@ -236,6 +241,11 @@ enum ovn_stage {
>   #define REG_LB_AFF_BACKEND_IP4  "reg4"
>   #define REG_LB_AFF_MATCH_PORT   "reg8[0..15]"
>   
> +/* Registers for ACL evaluation */
> +#define REGBIT_ACL_VERDICT_ALLOW "reg8[16]"
> +#define REGBIT_ACL_VERDICT_DROP "reg8[17]"
> +#define REGBIT_ACL_VERDICT_REJECT "reg8[18]"
> +
>   /* Indicate that this packet has been recirculated using egress
>    * loopback.  This allows certain checks to be bypassed, such as a
>    * logical router dropping packets with source IP address equals
> @@ -6364,54 +6374,11 @@ build_acl_log(struct ds *actions, const struct nbrec_acl *acl,
>       ds_put_cstr(actions, "); ");
>   }
>   
> -static void
> -build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows,
> -                       enum ovn_stage stage, struct nbrec_acl *acl,
> -                       struct ds *extra_match, struct ds *extra_actions,
> -                       const struct ovsdb_idl_row *stage_hint,
> -                       const struct shash *meter_groups)
> -{
> -    struct ds match = DS_EMPTY_INITIALIZER;
> -    struct ds actions = DS_EMPTY_INITIALIZER;
> -    bool ingress = (ovn_stage_get_pipeline(stage) == P_IN);
> -
> -    char *next_action =
> -        xasprintf("next(pipeline=%s,table=%d);",
> -                  ingress ? "egress": "ingress",
> -                  ingress ? ovn_stage_get_table(S_SWITCH_OUT_QOS_MARK)
> -                          : ovn_stage_get_table(S_SWITCH_IN_L2_LKUP));
> -
> -    build_acl_log(&actions, acl, meter_groups);
> -    if (extra_match->length > 0) {
> -        ds_put_format(&match, "(%s) && ", extra_match->string);
> -    }
> -    ds_put_cstr(&match, acl->match);
> -
> -    if (extra_actions->length > 0) {
> -        ds_put_format(&actions, "%s ", extra_actions->string);
> -    }
> -
> -    ds_put_format(&actions, "reg0 = 0; "
> -                  "reject { "
> -                  "/* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ "
> -                  "outport <-> inport; %s };", next_action);
> -    ovn_lflow_add_with_hint__(lflows, od, stage,
> -                              acl->priority + OVN_ACL_PRI_OFFSET,
> -                              ds_cstr(&match), ds_cstr(&actions), NULL,
> -                              copp_meter_get(COPP_REJECT, od->nbs->copp,
> -                                             meter_groups),
> -                              stage_hint);
> -
> -    free(next_action);
> -    ds_destroy(&match);
> -    ds_destroy(&actions);
> -}
> -
>   static void
>   consider_acl(struct hmap *lflows, struct ovn_datapath *od,
> -             struct nbrec_acl *acl, bool has_stateful, bool ct_masked_mark,
> -             const struct shash *meter_groups, struct ds *match,
> -             struct ds *actions)
> +             const struct nbrec_acl *acl, bool has_stateful,
> +             bool ct_masked_mark, const struct shash *meter_groups,
> +             struct ds *match, struct ds *actions)
>   {
>       const char *ct_blocked_match = ct_masked_mark
>                                      ? "ct_mark.blocked"
> @@ -6420,210 +6387,131 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od,
>       enum ovn_stage stage;
>   
>       if (ingress && smap_get_bool(&acl->options, "apply-after-lb", false)) {
> -        stage = S_SWITCH_IN_ACL_AFTER_LB;
> +        stage = S_SWITCH_IN_ACL_AFTER_LB_EVAL;
>       } else if (ingress) {
> -        stage = S_SWITCH_IN_ACL;
> +        stage = S_SWITCH_IN_ACL_EVAL;
>       } else {
> -        stage = S_SWITCH_OUT_ACL;
> +        stage = S_SWITCH_OUT_ACL_EVAL;
>       }
>   
> -    if (!strcmp(acl->action, "allow-stateless")) {
> -        ds_clear(actions);
> -        build_acl_log(actions, acl, meter_groups);
> +    const char *verdict;
> +    if (!strcmp(acl->action, "drop")) {
> +        verdict = REGBIT_ACL_VERDICT_DROP " = 1; ";
> +    } else if (!strcmp(acl->action, "reject")) {
> +        verdict = REGBIT_ACL_VERDICT_REJECT " = 1; ";
> +    } else {
> +        verdict = REGBIT_ACL_VERDICT_ALLOW " = 1; ";
> +    }
> +
> +    ds_clear(actions);
> +    /* All ACLs will have the same actions as a basis. */
> +    build_acl_log(actions, acl, meter_groups);
> +    ds_put_cstr(actions, verdict);
> +    size_t log_verdict_len = actions->length;
> +    uint16_t priority = acl->priority + OVN_ACL_PRI_OFFSET;
> +
> +    if (!has_stateful || !strcmp(acl->action, "allow-stateless")) {
>           ds_put_cstr(actions, "next;");
> -        ovn_lflow_add_with_hint(lflows, od, stage,
> -                                acl->priority + OVN_ACL_PRI_OFFSET,
> +        ovn_lflow_add_with_hint(lflows, od, stage, priority,
>                                   acl->match, ds_cstr(actions),
>                                   &acl->header_);
> -    } else if (!strcmp(acl->action, "allow")
> +        return;
> +    }
> +
> +    if (!strcmp(acl->action, "allow")
>           || !strcmp(acl->action, "allow-related")) {
>           /* If there are any stateful flows, we must even commit "allow"
>            * actions.  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". */
> -        if (!has_stateful) {
> -            ds_clear(actions);
> -            build_acl_log(actions, acl, meter_groups);
> -            ds_put_cstr(actions, "next;");
> -            ovn_lflow_add_with_hint(lflows, od, stage,
> -                                    acl->priority + OVN_ACL_PRI_OFFSET,
> -                                    acl->match, ds_cstr(actions),
> -                                    &acl->header_);
> -        } else {
> -            /* Commit the connection tracking entry if it's a new
> -             * connection that matches this ACL.  After this commit,
> -             * the reply traffic is allowed by a flow we create at
> -             * priority 65535, defined earlier.
> -             *
> -             * It's also possible that a known connection was marked for
> -             * deletion after a policy was deleted, but the policy was
> -             * re-added while that connection is still known.  We catch
> -             * that case here and un-set ct_mark.blocked (which will be done
> -             * by ct_commit in the "stateful" stage) to indicate that the
> -             * connection should be allowed to resume.
> -             */
> -            ds_clear(match);
> -            ds_clear(actions);
> -            ds_put_format(match, REGBIT_ACL_HINT_ALLOW_NEW " == 1 && (%s)",
> -                          acl->match);
>   
> -            ds_put_cstr(actions, REGBIT_CONNTRACK_COMMIT" = 1; ");
> -            if (acl->label) {
> -                ds_put_format(actions, REGBIT_ACL_LABEL" = 1; "
> -                              REG_LABEL" = %"PRId64"; ", acl->label);
> -            }
> -            build_acl_log(actions, acl, meter_groups);
> -            ds_put_cstr(actions, "next;");
> -            ovn_lflow_add_with_hint(lflows, od, stage,
> -                                    acl->priority + OVN_ACL_PRI_OFFSET,
> -                                    ds_cstr(match),
> -                                    ds_cstr(actions),
> -                                    &acl->header_);
> -
> -            /* Match on traffic in the request direction for an established
> -             * connection tracking entry that has not been marked for
> -             * deletion. We use this to ensure that this
> -             * connection is still allowed by the currently defined
> -             * policy. Match untracked packets too.
> -             * Commit the connection only if the ACL has a label. This is done
> -             * to update the connection tracking entry label in case the ACL
> -             * allowing the connection changes. */
> -            ds_clear(match);
> -            ds_clear(actions);
> -            ds_put_format(match, REGBIT_ACL_HINT_ALLOW " == 1 && (%s)",
> -                          acl->match);
> -            if (acl->label) {
> -                ds_put_cstr(actions, REGBIT_CONNTRACK_COMMIT" = 1; ");
> -                ds_put_format(actions, REGBIT_ACL_LABEL" = 1; "
> -                              REG_LABEL" = %"PRId64"; ", acl->label);
> -            }
> -            build_acl_log(actions, acl, meter_groups);
> -            ds_put_cstr(actions, "next;");
> -            ovn_lflow_add_with_hint(lflows, od, stage,
> -                                    acl->priority + OVN_ACL_PRI_OFFSET,
> -                                    ds_cstr(match), ds_cstr(actions),
> -                                    &acl->header_);
> -
> -            /* Related and reply traffic are universally allowed by priority
> -             * 65532 flows created in build_acls(). If logging is enabled on
> -             * the ACL, then we need to ensure that the related and reply
> -             * traffic is logged, so we install a slightly higher-priority
> -             * flow that matches the ACL, allows the traffic, and logs it.
> -             *
> -             * Note: Matching the ct_label.label may prevent OVS flow HW
> -             * offloading to work for some NICs because masked-access of
> -             * ct_label is not supported on those NICs due to HW
> -             * limitations. In such case the user may choose to avoid using the
> -             * "log-related" option.
> -             */
> -            bool log_related = smap_get_bool(&acl->options, "log-related",
> -                                             false);
> -            if (acl->log && acl->label && log_related) {
> -                /* Related/reply flows need to be set on the opposite pipeline
> -                 * from where the ACL itself is set.
> -                 */
> -                enum ovn_stage log_related_stage = ingress ?
> -                    S_SWITCH_OUT_ACL :
> -                    S_SWITCH_IN_ACL;
> -                ds_clear(match);
> -                ds_clear(actions);
> -
> -                ds_put_format(match, "ct.est && !ct.rel && !ct.new%s && "
> -                              "ct.rpl && %s == 0 && "
> -                              "ct_label.label == %" PRId64,
> -                              use_ct_inv_match ? " && !ct.inv" : "",
> -                              ct_blocked_match, acl->label);
> -                build_acl_log(actions, acl, meter_groups);
> -                ds_put_cstr(actions, "next;");
> -                ovn_lflow_add_with_hint(lflows, od, log_related_stage,
> -                                        UINT16_MAX - 2,
> -                                        ds_cstr(match), ds_cstr(actions),
> -                                        &acl->header_);
> +        /* Commit the connection tracking entry if it's a new
> +         * connection that matches this ACL.  After this commit,
> +         * the reply traffic is allowed by a flow we create at
> +         * priority 65535, defined earlier.
> +         *
> +         * It's also possible that a known connection was marked for
> +         * deletion after a policy was deleted, but the policy was
> +         * re-added while that connection is still known.  We catch
> +         * that case here and un-set ct_mark.blocked (which will be done
> +         * by ct_commit in the "stateful" stage) to indicate that the
> +         * connection should be allowed to resume.
> +         */
> +        ds_clear(match);
> +        ds_put_format(match, REGBIT_ACL_HINT_ALLOW_NEW " == 1 && (%s)",
> +                      acl->match);
>   
> -                ds_clear(match);
> -                ds_put_format(match, "!ct.est && ct.rel && !ct.new%s && "
> -                                     "%s == 0 && "
> -                                     "ct_label.label == %" PRId64,
> -                                     use_ct_inv_match ? " && !ct.inv" : "",
> -                                     ct_blocked_match, acl->label);
> -                ovn_lflow_add_with_hint(lflows, od, log_related_stage,
> -                                        UINT16_MAX - 2,
> -                                        ds_cstr(match), ds_cstr(actions),
> -                                        &acl->header_);
> -            }
> +        ds_truncate(actions, log_verdict_len);
> +        ds_put_cstr(actions, REGBIT_CONNTRACK_COMMIT" = 1; ");
> +        if (acl->label) {
> +            ds_put_format(actions, REGBIT_ACL_LABEL" = 1; "
> +                          REG_LABEL" = %"PRId64"; ", acl->label);
> +        }
> +        ds_put_cstr(actions, "next;");
> +        ovn_lflow_add_with_hint(lflows, od, stage, priority,
> +                                ds_cstr(match), ds_cstr(actions),
> +                                &acl->header_);
>   
> +        /* Match on traffic in the request direction for an established
> +         * connection tracking entry that has not been marked for
> +         * deletion. We use this to ensure that this
> +         * connection is still allowed by the currently defined
> +         * policy. Match untracked packets too.
> +         * Commit the connection only if the ACL has a label. This is done
> +         * to update the connection tracking entry label in case the ACL
> +         * allowing the connection changes. */
> +        ds_clear(match);
> +        ds_truncate(actions, log_verdict_len);
> +        ds_put_format(match, REGBIT_ACL_HINT_ALLOW " == 1 && (%s)",
> +                      acl->match);
> +        if (acl->label) {
> +            ds_put_cstr(actions, REGBIT_CONNTRACK_COMMIT" = 1; ");
> +            ds_put_format(actions, REGBIT_ACL_LABEL" = 1; "
> +                          REG_LABEL" = %"PRId64"; ", acl->label);
>           }
> +        ds_put_cstr(actions, "next;");
> +        ovn_lflow_add_with_hint(lflows, od, stage, priority,
> +                                ds_cstr(match), ds_cstr(actions),
> +                                &acl->header_);
>       } else if (!strcmp(acl->action, "drop")
>                  || !strcmp(acl->action, "reject")) {
>           /* The implementation of "drop" differs if stateful ACLs are in
>            * use for this datapath.  In that case, the actions differ
>            * depending on whether the connection was previously committed
>            * to the connection tracker with ct_commit. */
> -        if (has_stateful) {
> -            /* If the packet is not tracked or not part of an established
> -             * connection, then we can simply reject/drop it. */
> -            ds_clear(match);
> -            ds_clear(actions);
> -            ds_put_cstr(match, REGBIT_ACL_HINT_DROP " == 1");
> -            if (!strcmp(acl->action, "reject")) {
> -                build_reject_acl_rules(od, lflows, stage, acl, match,
> -                                       actions, &acl->header_, meter_groups);
> -            } else {
> -                ds_put_format(match, " && (%s)", acl->match);
> -                build_acl_log(actions, acl, meter_groups);
> -                ds_put_cstr(actions, debug_implicit_drop_action());
> -                ovn_lflow_add_with_hint(lflows, od, stage,
> -                                        acl->priority + OVN_ACL_PRI_OFFSET,
> -                                        ds_cstr(match), ds_cstr(actions),
> -                                        &acl->header_);
> -            }
> -            /* For an existing connection without ct_mark.blocked set, we've
> -             * encountered a policy change. ACLs previously allowed
> -             * this connection and we committed the connection tracking
> -             * entry.  Current policy says that we should drop this
> -             * connection.  First, we set ct_mark.blocked to indicate
> -             * that this connection is set for deletion.  By not
> -             * specifying "next;", we implicitly drop the packet after
> -             * updating conntrack state.  We would normally defer
> -             * ct_commit() to the "stateful" stage, but since we're
> -             * rejecting/dropping the packet, we go ahead and do it here.
> -             */
> -            ds_clear(match);
> -            ds_clear(actions);
> -            ds_put_cstr(match, REGBIT_ACL_HINT_BLOCK " == 1");
> -            ds_put_format(actions, "ct_commit { %s = 1; }; ",
> -                          ct_blocked_match);
> -            if (!strcmp(acl->action, "reject")) {
> -                build_reject_acl_rules(od, lflows, stage, acl, match,
> -                                       actions, &acl->header_, meter_groups);
> -            } else {
> -                ds_put_format(match, " && (%s)", acl->match);
> -                build_acl_log(actions, acl, meter_groups);
> -                ds_put_cstr(actions, debug_implicit_drop_action());
> -                ovn_lflow_add_with_hint(lflows, od, stage,
> -                                        acl->priority + OVN_ACL_PRI_OFFSET,
> -                                        ds_cstr(match), ds_cstr(actions),
> -                                        &acl->header_);
> -            }
> -        } else {
> -            /* There are no stateful ACLs in use on this datapath,
> -             * so a "reject/drop" ACL is simply the "reject/drop"
> -             * logical flow action in all cases. */
> -            ds_clear(match);
> -            ds_clear(actions);
> -            if (!strcmp(acl->action, "reject")) {
> -                build_reject_acl_rules(od, lflows, stage, acl, match,
> -                                       actions, &acl->header_, meter_groups);
> -            } else {
> -                build_acl_log(actions, acl, meter_groups);
> -                ds_put_cstr(actions, debug_implicit_drop_action());
> -                ovn_lflow_add_with_hint(lflows, od, stage,
> -                                        acl->priority + OVN_ACL_PRI_OFFSET,
> -                                        acl->match, ds_cstr(actions),
> -                                        &acl->header_);
> -            }
> -        }
> +        /* If the packet is not tracked or not part of an established
> +         * connection, then we can simply reject/drop it. */
> +        ds_clear(match);
> +        ds_put_cstr(match, REGBIT_ACL_HINT_DROP " == 1");
> +        ds_put_format(match, " && (%s)", acl->match);
> +
> +        ds_truncate(actions, log_verdict_len);
> +        ds_put_cstr(actions, "next;");
> +        ovn_lflow_add_with_hint(lflows, od, stage, priority,
> +                                ds_cstr(match), ds_cstr(actions),
> +                                &acl->header_);
> +        /* For an existing connection without ct_mark.blocked set, we've
> +         * encountered a policy change. ACLs previously allowed
> +         * this connection and we committed the connection tracking
> +         * entry.  Current policy says that we should drop this
> +         * connection.  First, we set ct_mark.blocked to indicate
> +         * that this connection is set for deletion.  By not
> +         * specifying "next;", we implicitly drop the packet after
> +         * updating conntrack state.  We would normally defer
> +         * ct_commit() to the "stateful" stage, but since we're
> +         * rejecting/dropping the packet, we go ahead and do it here.
> +         */
> +        ds_clear(match);
> +        ds_put_cstr(match, REGBIT_ACL_HINT_BLOCK " == 1");
> +        ds_put_format(match, " && (%s)", acl->match);
> +
> +        ds_truncate(actions, log_verdict_len);
> +        ds_put_format(actions, "ct_commit { %s = 1; }; next;",
> +                      ct_blocked_match);
> +        ovn_lflow_add_with_hint(lflows, od, stage, priority,
> +                                ds_cstr(match), ds_cstr(actions),
> +                                &acl->header_);
>       }
>   }
>   
> @@ -6764,13 +6652,143 @@ build_port_group_lswitches(
>   
>   #define IPV6_CT_OMIT_MATCH "nd || nd_ra || nd_rs || mldv1 || mldv2"
>   
> +static void
> +build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows,
> +                        const char *default_acl_action,
> +                        const struct shash *meter_groups,
> +                        struct ds *actions)
> +{
> +    enum ovn_stage stages [] = {
> +        S_SWITCH_IN_ACL_ACTION,
> +        S_SWITCH_IN_ACL_AFTER_LB_ACTION,
> +        S_SWITCH_OUT_ACL_ACTION,
> +    };
> +
> +    ds_clear(actions);
> +    ds_put_cstr(actions, REGBIT_ACL_VERDICT_ALLOW " = 0; "
> +                        REGBIT_ACL_VERDICT_DROP " = 0; "
> +                        REGBIT_ACL_VERDICT_REJECT " = 0; ");
> +    size_t verdict_len = actions->length;
> +
> +    for (size_t i = 0; i < ARRAY_SIZE(stages); i++) {
> +        enum ovn_stage stage = stages[i];
> +        if (!od->has_acls) {
> +            ovn_lflow_add(lflows, od, stage, 0, "1", "next;");
> +            continue;
> +        }
> +        ds_truncate(actions, verdict_len);
> +        ds_put_cstr(actions, "next;");
> +        ovn_lflow_add(lflows, od, stage, 1000,
> +                      REGBIT_ACL_VERDICT_ALLOW " == 1", ds_cstr(actions));
> +        ds_truncate(actions, verdict_len);
> +        ds_put_cstr(actions, debug_implicit_drop_action());
> +        ovn_lflow_add(lflows, od, stage, 1000,
> +                      REGBIT_ACL_VERDICT_DROP " == 1",
> +                      ds_cstr(actions));
> +        bool ingress = ovn_stage_get_pipeline(stage) == P_IN;
> +
> +        ds_truncate(actions, verdict_len);
> +        ds_put_format(
> +            actions, "reg0 = 0; "
> +            "reject { "
> +            "/* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ "
> +            "outport <-> inport; next(pipeline=%s,table=%d); };",
> +            ingress ? "egress" : "ingress",
> +            ingress ? ovn_stage_get_table(S_SWITCH_OUT_QOS_MARK)
> +                : ovn_stage_get_table(S_SWITCH_IN_L2_LKUP));
> +
> +        ovn_lflow_metered(lflows, od, stage, 1000,
> +                          REGBIT_ACL_VERDICT_REJECT " == 1", ds_cstr(actions),
> +                          copp_meter_get(COPP_REJECT, od->nbs->copp,
> +                          meter_groups));
> +
> +        ds_truncate(actions, verdict_len);
> +        ds_put_cstr(actions, default_acl_action);
> +        ovn_lflow_add(lflows, od, stage, 0, "1", ds_cstr(actions));
> +    }
> +}
> +
> +static void
> +build_acl_log_related_flows(struct ovn_datapath *od, struct hmap *lflows,
> +                            const struct nbrec_acl *acl, bool has_stateful,
> +                            bool ct_masked_mark,
> +                            const struct shash *meter_groups,
> +                            struct ds *match, struct ds *actions)
> +{
> +    /* Related and reply traffic are universally allowed by priority
> +     * 65532 flows created in build_acls(). If logging is enabled on
> +     * the ACL, then we need to ensure that the related and reply
> +     * traffic is logged, so we install a slightly higher-priority
> +     * flow that matches the ACL, allows the traffic, and logs it.
> +     *
> +     * Note: Matching the ct_label.label may prevent OVS flow HW
> +     * offloading to work for some NICs because masked-access of
> +     * ct_label is not supported on those NICs due to HW
> +     * limitations. In such case the user may choose to avoid using the
> +     * "log-related" option.
> +     */
> +    const char *ct_blocked_match = ct_masked_mark
> +                                   ? "ct_mark.blocked"
> +                                   : "ct_label.blocked";
> +    bool ingress = !strcmp(acl->direction, "from-lport") ? true :false;
> +    bool log_related = smap_get_bool(&acl->options, "log-related",
> +                                     false);
> +
> +    if (!strcmp(acl->action, "allow-stateless") || !has_stateful) {
> +        /* Not stateful */
> +        return;
> +    }
> +
> +    if (strcmp(acl->action, "allow") && strcmp(acl->action, "allow-related")) {
> +        /* Not an allow ACL */
> +        return;
> +    }
> +
> +    if (!acl->log || !acl->label || !log_related) {
> +        /* Missing requirements for logging related ACLs */
> +        return;
> +    }
> +
> +    ds_clear(actions);
> +    build_acl_log(actions, acl, meter_groups);
> +    ds_put_cstr(actions, REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
> +    /* Related/reply flows need to be set on the opposite pipeline
> +     * from where the ACL itself is set.
> +     */
> +    enum ovn_stage log_related_stage = ingress ?
> +        S_SWITCH_OUT_ACL_EVAL :
> +        S_SWITCH_IN_ACL_EVAL;
> +    ds_clear(match);
> +    ds_put_format(match, "ct.est && !ct.rel && !ct.new%s && "
> +                  "ct.rpl && %s == 0 && "
> +                  "ct_label.label == %" PRId64,
> +                  use_ct_inv_match ? " && !ct.inv" : "",
> +                  ct_blocked_match, acl->label);
> +    ovn_lflow_add_with_hint(lflows, od, log_related_stage,
> +                            UINT16_MAX - 2,
> +                            ds_cstr(match), ds_cstr(actions),
> +                            &acl->header_);
> +
> +    ds_clear(match);
> +    ds_put_format(match, "!ct.est && ct.rel && !ct.new%s && "
> +                         "%s == 0 && "
> +                         "ct_label.label == %" PRId64,
> +                         use_ct_inv_match ? " && !ct.inv" : "",
> +                         ct_blocked_match, acl->label);
> +    ovn_lflow_add_with_hint(lflows, od, log_related_stage,
> +                            UINT16_MAX - 2,
> +                            ds_cstr(match), ds_cstr(actions),
> +                            &acl->header_);
> +}
> +
>   static void
>   build_acls(struct ovn_datapath *od, const struct chassis_features *features,
>              struct hmap *lflows, const struct hmap *port_groups,
>              const struct shash *meter_groups)
>   {
> -    const char *default_acl_action = default_acl_drop ? debug_drop_action() :
> -                                                        "next;";
> +    const char *default_acl_action = default_acl_drop
> +                                     ? debug_implicit_drop_action()
> +                                     : "next;";
>       bool has_stateful = od->has_stateful_acl || od->has_lb_vip;
>       const char *ct_blocked_match = features->ct_no_masked_label
>                                      ? "ct_mark.blocked"
> @@ -6787,22 +6805,21 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features,
>        * are any stateful ACLs in this datapath. */
>       if (!od->has_acls) {
>           if (!od->has_lb_vip) {
> -            ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX, "1",
> +            ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX, "1",
>                             "next;");
> -            ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX, "1",
> +            ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX, "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_EVAL, 0, "1", "next;");
> +            ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 0, "1", "next;");
>           }
> -        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, 0, "1", "next;");
> +        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB_EVAL, 0, "1",
> +                      "next;");
>       } else {
> -        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_EVAL, 0, "1", "next;");
> +        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 0, "1", "next;");
> +        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB_EVAL, 0, "1",
> +                      "next;");
>       }
>   
>   
> @@ -6831,20 +6848,22 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features,
>            * uses "next;". */
>           ds_clear(&match);
>           ds_put_format(&match, "ip && ct.est && %s == 1", ct_blocked_match);
> -        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 1,
> +        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 1,
>                         ds_cstr(&match),
> -                      REGBIT_CONNTRACK_COMMIT" = 1; next;");
> -        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 1,
> +                      REGBIT_CONNTRACK_COMMIT" = 1; "
> +                      REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
> +        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 1,
>                         ds_cstr(&match),
> -                      REGBIT_CONNTRACK_COMMIT" = 1; next;");
> +                      REGBIT_CONNTRACK_COMMIT" = 1; "
> +                      REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
>   
> -        default_acl_action = default_acl_drop
> -                             ? debug_drop_action()
> +        const char *next_action = default_acl_drop
> +                             ? "next;"
>                                : 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);
> +        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 1, "ip && !ct.est",
> +                      next_action);
> +        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 1, "ip && !ct.est",
> +                      next_action);
>   
>           /* Ingress and Egress ACL Table (Priority 65532).
>            *
> @@ -6857,10 +6876,10 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features,
>           ds_put_format(&match, "%s(ct.est && ct.rpl && %s == 1)",
>                         use_ct_inv_match ? "ct.inv || " : "",
>                         ct_blocked_match);
> -        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3,
> -                      ds_cstr(&match), debug_drop_action());
> -        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3,
> -                      ds_cstr(&match),  debug_drop_action());
> +        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX - 3,
> +                      ds_cstr(&match), REGBIT_ACL_VERDICT_DROP " = 1; next;");
> +        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX - 3,
> +                      ds_cstr(&match), REGBIT_ACL_VERDICT_DROP " = 1; next;");
>   
>           /* Ingress and Egress ACL Table (Priority 65535 - 3).
>            *
> @@ -6876,12 +6895,14 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features,
>                         "ct.rpl && %s == 0",
>                         use_ct_inv_match ? " && !ct.inv" : "",
>                         ct_blocked_match);
> -        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3,
> +        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX - 3,
>                         ds_cstr(&match), REGBIT_ACL_HINT_DROP" = 0; "
>                         REGBIT_ACL_HINT_BLOCK" = 0; "
> -                      REGBIT_ACL_HINT_ALLOW_REL" = 1; next;");
> -        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3,
> -                      ds_cstr(&match), "next;");
> +                      REGBIT_ACL_HINT_ALLOW_REL" = 1; "
> +                      REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
> +        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX - 3,
> +                      ds_cstr(&match),
> +                      REGBIT_ACL_VERDICT_ALLOW " = 1; next;");
>   
>           /* Ingress and Egress ACL Table (Priority 65535).
>            *
> @@ -6897,24 +6918,28 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features,
>            * that's generated from a non-listening UDP port.  */
>           const char *ct_in_acl_action =
>               features->ct_lb_related
> -            ? REGBIT_ACL_HINT_ALLOW_REL" = 1; ct_commit_nat;"
> -            : REGBIT_ACL_HINT_ALLOW_REL" = 1; next;";
> -        const char *ct_out_acl_action = features->ct_lb_related
> -                                        ? "ct_commit_nat;"
> -                                        : "next;";
> +            ? REGBIT_ACL_HINT_ALLOW_REL" = 1; "
> +              REGBIT_ACL_VERDICT_ALLOW" = 1; ct_commit_nat;"
> +            : REGBIT_ACL_HINT_ALLOW_REL" = 1; "
> +              REGBIT_ACL_VERDICT_ALLOW" = 1; next;";
> +        const char *ct_out_acl_action =
> +            features->ct_lb_related
> +            ? REGBIT_ACL_VERDICT_ALLOW" = 1; ct_commit_nat;"
> +            : REGBIT_ACL_VERDICT_ALLOW" = 1; next;";
>           ds_clear(&match);
>           ds_put_format(&match, "!ct.est && ct.rel && !ct.new%s && %s == 0",
>                         use_ct_inv_match ? " && !ct.inv" : "",
>                         ct_blocked_match);
> -        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3,
> +        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX - 3,
>                         ds_cstr(&match), ct_in_acl_action);
> -        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3,
> +        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX - 3,
>                         ds_cstr(&match), ct_out_acl_action);
> -
>           /* Reply and related traffic matched by an "allow-related" ACL
>            * should be allowed in the ls_in_acl_after_lb stage too. */
> -        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, UINT16_MAX - 3,
> -                      REGBIT_ACL_HINT_ALLOW_REL" == 1", "next;");
> +        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB_EVAL,
> +                      UINT16_MAX - 3,
> +                      REGBIT_ACL_HINT_ALLOW_REL" == 1",
> +                      REGBIT_ACL_VERDICT_ALLOW " = 1; next;");
>       }
>   
>       /* Ingress and Egress ACL Table (Priority 65532).
> @@ -6924,16 +6949,22 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features,
>        * Also, don't send them to conntrack because session tracking
>        * for these protocols is not working properly:
>        * https://bugzilla.kernel.org/show_bug.cgi?id=11797. */
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3,
> -                  IPV6_CT_OMIT_MATCH, "next;");
> -    ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3,
> -                  IPV6_CT_OMIT_MATCH, "next;");
> -    ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, UINT16_MAX - 3,
> -                  IPV6_CT_OMIT_MATCH, "next;");
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX - 3,
> +                  IPV6_CT_OMIT_MATCH,
> +                  REGBIT_ACL_VERDICT_ALLOW " = 1; next;");
> +    ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX - 3,
> +                  IPV6_CT_OMIT_MATCH,
> +                  REGBIT_ACL_VERDICT_ALLOW " = 1; next;");
> +    ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB_EVAL, UINT16_MAX - 3,
> +                  IPV6_CT_OMIT_MATCH,
> +                  REGBIT_ACL_VERDICT_ALLOW " = 1; next;");
>   
>       /* Ingress or Egress ACL Table (Various priorities). */
>       for (size_t i = 0; i < od->nbs->n_acls; i++) {
>           struct nbrec_acl *acl = od->nbs->acls[i];
> +        build_acl_log_related_flows(od, lflows, acl, has_stateful,
> +                                    features->ct_no_masked_label,
> +                                    meter_groups, &match, &actions);
>           consider_acl(lflows, od, acl, has_stateful,
>                        features->ct_no_masked_label,
>                        meter_groups, &match, &actions);
> @@ -6942,7 +6973,11 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features,
>       HMAP_FOR_EACH (pg, key_node, port_groups) {
>           if (ovn_port_group_ls_find(pg, &od->nbs->header_.uuid)) {
>               for (size_t i = 0; i < pg->nb_pg->n_acls; i++) {
> -                consider_acl(lflows, od, pg->nb_pg->acls[i], has_stateful,
> +                const struct nbrec_acl *acl = pg->nb_pg->acls[i];
> +                build_acl_log_related_flows(od, lflows, acl, has_stateful,
> +                                            features->ct_no_masked_label,
> +                                            meter_groups, &match, &actions);
> +                consider_acl(lflows, od, acl, has_stateful,
>                                features->ct_no_masked_label,
>                                meter_groups, &match, &actions);
>               }
> @@ -6966,14 +7001,16 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features,
>                   &od->nbs->ports[i]->dhcpv4_options->options, "lease_time");
>               if (server_id && server_mac && lease_time) {
>                   const char *dhcp_actions =
> -                    has_stateful ? "ct_commit; next;" : "next;";
> +                    has_stateful ? REGBIT_ACL_VERDICT_ALLOW" = 1; "
> +                                   "ct_commit; next;"
> +                                 : REGBIT_ACL_VERDICT_ALLOW" = 1; next;";
>                   ds_clear(&match);
>                   ds_put_format(&match, "outport == \"%s\" && eth.src == %s "
>                                 "&& ip4.src == %s && udp && udp.src == 67 "
>                                 "&& udp.dst == 68", od->nbs->ports[i]->name,
>                                 server_mac, server_id);
>                   ovn_lflow_add_with_lport_and_hint(
> -                    lflows, od, S_SWITCH_OUT_ACL, 34000, ds_cstr(&match),
> +                    lflows, od, S_SWITCH_OUT_ACL_EVAL, 34000, ds_cstr(&match),
>                       dhcp_actions, od->nbs->ports[i]->name,
>                       &od->nbs->ports[i]->dhcpv4_options->header_);
>               }
> @@ -6992,15 +7029,17 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features,
>                   char server_ip[INET6_ADDRSTRLEN + 1];
>                   ipv6_string_mapped(server_ip, &lla);
>   
> -                const char *dhcp6_actions = has_stateful ? "ct_commit; next;" :
> -                    "next;";
> +                const char *dhcp6_actions =
> +                    has_stateful ? REGBIT_ACL_VERDICT_ALLOW" = 1; "
> +                                   "ct_commit; next;"
> +                                 : REGBIT_ACL_VERDICT_ALLOW" = 1; next;";
>                   ds_clear(&match);
>                   ds_put_format(&match, "outport == \"%s\" && eth.src == %s "
>                                 "&& ip6.src == %s && udp && udp.src == 547 "
>                                 "&& udp.dst == 546", od->nbs->ports[i]->name,
>                                 server_mac, server_ip);
>                   ovn_lflow_add_with_lport_and_hint(
> -                    lflows, od, S_SWITCH_OUT_ACL, 34000, ds_cstr(&match),
> +                    lflows, od, S_SWITCH_OUT_ACL_EVAL, 34000, ds_cstr(&match),
>                       dhcp6_actions, od->nbs->ports[i]->name,
>                       &od->nbs->ports[i]->dhcpv6_options->header_);
>               }
> @@ -7011,24 +7050,32 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features,
>        * if the CMS has configured DNS records for the datapath.
>        */
>       if (ls_has_dns_records(od->nbs)) {
> -        const char *dns_actions = has_stateful ? "ct_commit; next;" : "next;";
> +        const char *dns_actions =
> +            has_stateful ? REGBIT_ACL_VERDICT_ALLOW" = 1; "
> +                           "ct_commit; next;"
> +                         : REGBIT_ACL_VERDICT_ALLOW" = 1; next;";
>           ovn_lflow_add(
> -            lflows, od, S_SWITCH_OUT_ACL, 34000, "udp.src == 53",
> +            lflows, od, S_SWITCH_OUT_ACL_EVAL, 34000, "udp.src == 53",
>               dns_actions);
>       }
>   
>       if (od->has_acls || od->has_lb_vip) {
>           /* Add a 34000 priority flow to advance the service monitor reply
>           * packets to skip applying ingress ACLs. */
> -        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 34000,
> -                    "eth.dst == $svc_monitor_mac", "next;");
> +        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 34000,
> +                    "eth.dst == $svc_monitor_mac",
> +                    REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
>   
>           /* Add a 34000 priority flow to advance the service monitor packets
>           * generated by ovn-controller to skip applying egress ACLs. */
> -        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 34000,
> -                    "eth.src == $svc_monitor_mac", "next;");
> +        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 34000,
> +                    "eth.src == $svc_monitor_mac",
> +                    REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
>       }
>   
> +    build_acl_action_lflows(od, lflows, default_acl_action, meter_groups,
> +                            &actions);
> +
>       ds_destroy(&match);
>       ds_destroy(&actions);
>   }
> diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
> index 7da912da3..40c5ec95b 100644
> --- a/northd/ovn-northd.8.xml
> +++ b/northd/ovn-northd.8.xml
> @@ -684,7 +684,7 @@
>         </li>
>       </ul>
>   
> -    <h3>Ingress table 8: <code>from-lport</code> ACLs before LB</h3>
> +    <h3>Ingress table 8: <code>from-lport</code> ACL evaluation before LB</h3>
>   
>       <p>
>         Logical flows in this table closely reproduce those in the
> @@ -697,61 +697,71 @@
>       </p>
>       <ul>
>         <li>
> -        <code>allow</code> ACLs translate into logical flows with
> -        the <code>next;</code> action.  If there are any stateful ACLs
> -        on this datapath, then <code>allow</code> ACLs translate to
> -        <code>ct_commit; next;</code> (which acts as a hint for the next tables
> -        to commit the connection to conntrack). In case the <code>ACL</code>
> -        has a label then <code>reg3</code> is loaded with the label value and
> +        This table is responsible for evaluating ACLs, and setting a register
> +        bit to indicate whether the ACL decided to allow, drop, or reject the
> +        traffic. The allow bit is <code>reg8[16]</code>. The drop bit is
> +        <code>reg8[17]</code>. All flows in this table will advance the packet
> +        to the next table, where the bits from before are evaluated to
> +        determine what to do with the packet. Any flows in this table that
> +        intend for the packet to pass will set <code>reg8[16]</code> to 1,
> +        even if an ACL with an allow-type action was not matched. This lets the
> +        next table know to allow the traffic to pass. These bits will be
> +        referred to as the "allow", "drop", and "reject" bits in the upcoming
> +        paragraphs.
> +      </li>
> +      <li>
> +        <code>allow</code> ACLs translate into logical flows that set the allow
> +        bit to 1 and advance the packet to the next table. If there are any
> +        stateful ACLs on this datapath, then <code>allow</code> ACLs set the
> +        allow bit to one and in addition perform <code>ct_commit;</code> (which
> +        acts as a hint for future tables to commit the connection to
> +        conntrack). In case the <code>ACL</code> has a label then
> +        <code>reg3</code> is loaded with the label value and
>           <code>reg0[13]</code> bit is set to 1 (which acts as a hint for the
>           next tables to commit the label to conntrack).
>         </li>
>         <li>
> -        <code>allow-related</code> ACLs translate into logical
> -        flows with the <code>ct_commit(ct_label=0/1); next;</code> actions
> -        for new connections and <code>reg0[1] = 1; next;</code> for existing
> -        connections.  In case the <code>ACL</code> has a label then
> -        <code>reg3</code> is loaded with the label value and
> +        <code>allow-related</code> ACLs translate into logical flows that set
> +        the allow bit and additionally have <code>ct_commit(ct_label=0/1);
> +        next;</code> actions for new connections and <code>reg0[1] = 1;
> +        next;</code> for existing connections.  In case the <code>ACL</code>
> +        has a label then <code>reg3</code> is loaded with the label value and
>           <code>reg0[13]</code> bit is set to 1 (which acts as a hint for the
>           next tables to commit the label to conntrack).
>         </li>
>         <li>
> -        <code>allow-stateless</code> ACLs translate into logical
> -        flows with the <code>next;</code> action.
> +        <code>allow-stateless</code> ACLs translate into logical flows that set
> +        the allow bit and advance to the next table.
>         </li>
>         <li>
> -        <code>reject</code> ACLs translate into logical
> -        flows with the
> -        <code>tcp_reset { output &lt;-&gt; inport;
> -        next(pipeline=egress,table=5);}</code>
> -        action for TCP connections,<code>icmp4/icmp6</code> action
> -        for UDP connections, and <code>sctp_abort {output &lt;-%gt; inport;
> -        next(pipeline=egress,table=5);}</code> action for SCTP associations.
> +        <code>reject</code> ACLs translate into logical flows with that set the
> +        reject bit and advance to the next table.
>         </li>
>         <li>
> -        Other ACLs translate to <code>drop;</code> for new or untracked
> -        connections and <code>ct_commit(ct_label=1/1);</code> for known
> -        connections.  Setting <code>ct_label</code> marks a connection
> -        as one that was previously allowed, but should no longer be
> -        allowed due to a policy change.
> +        Other ACLs set the drop bit and advance to the next table for new or
> +        untracked connections. For known connections, they set the drop bit,
> +        as well as running the <code>ct_commit(ct_label=1/1);</code> action.
> +        Setting <code>ct_label</code> marks a connection as one that was
> +        previously allowed, but should no longer be allowed due to a policy
> +        change.
>         </li>
>       </ul>
>   
>       <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 if <ref column="options:default_acl_drop"
> -      table="NB_Global" db="OVN_Northbound"/> column 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.
> +      This table contains a priority-65535 flow to set the allow bit and
> +      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 is added. This flow does not set the allow bit, so that the next
> +      table can decide whether to allow or drop the packet based on the value
> +      of the <ref column="options:default_acl_drop" table="NB_Global"
> +      db="OVN_Northbound"/> column of the <ref table="NB_Global"
> +      db="OVN_Northbound"/> table.
>       </p>
>   
>       <p>
> -      A priority-65532 flow is added to allow IPv6 Neighbor solicitation,
> -      Neighbor discover, Router solicitation, Router advertisement and MLD
> -      packets regardless of other ACLs defined.
> +      A priority-65532 flow is added that sets the allow bit for
> +      IPv6 Neighbor solicitation, Neighbor discover, Router solicitation,
> +      Router advertisement and MLD packets regardless of other ACLs defined.
>       </p>
>   
>       <p>
> @@ -773,24 +783,17 @@
>         </li>
>   
>         <li>
> -        If <ref column="options:default_acl_drop" table="NB_Global"
> -        db="OVN_Northbound"/> column 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
> -        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.
> +        A priority-1 flow that sets the allow bit and sets the hint to commit
> +        IP traffic 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>
> -        A priority-65532 flow that allows any traffic in the reply
> -        direction for a connection that has been committed to the
> +        A priority-65532 flow that sets the allow bit for any traffic in the
> +        reply direction for a connection that has been committed to the
>           connection tracker (i.e., established flows), as long as
>           the committed flow does not have <code>ct_mark.blocked</code> set.
>           We only handle traffic in the reply direction here because
> @@ -807,9 +810,9 @@
>         </li>
>   
>         <li>
> -        A priority-65532 flow that allows any traffic that is considered
> -        related to a committed flow in the connection tracker (e.g., an
> -        ICMP Port Unreachable from a non-listening UDP port), as long
> +        A priority-65532 flow that sets the allow bit for any traffic that is
> +        considered related to a committed flow in the connection tracker (e.g.,
> +        an ICMP Port Unreachable from a non-listening UDP port), as long
>           as the committed flow does not have <code>ct_mark.blocked</code> set.
>           This flow also applies NAT to the related traffic so that ICMP headers
>           and the inner packet have correct addresses.
> @@ -819,14 +822,14 @@
>         </li>
>   
>         <li>
> -        A priority-65532 flow that drops all traffic marked by the
> -        connection tracker as invalid.
> +        A priority-65532 flow that sets the drop bit for all traffic marked by
> +        the connection tracker as invalid.
>         </li>
>   
>         <li>
> -        A priority-65532 flow that drops all traffic in the reply direction
> -        with <code>ct_mark.blocked</code> set meaning that the connection
> -        should no longer be allowed due to a policy change.  Packets
> +        A priority-65532 flow that sets the drop bit for all traffic in the
> +        reply direction with <code>ct_mark.blocked</code> set meaning that the
> +        connection should no longer be allowed due to a policy change.  Packets
>           in the request direction are skipped here to let a newly created
>           ACL re-allow this connection.
>         </li>
> @@ -842,7 +845,7 @@
>           A priority 34000 logical flow is added for each logical switch datapath
>           with the match <code>eth.dst = <var>E</var></code> to allow the service
>           monitor reply packet destined to <code>ovn-controller</code>
> -        with the action <code>next</code>, where <var>E</var> is the
> +        that sets the allow bit, where <var>E</var> is the
>           service monitor mac defined in the
>           <ref column="options:svc_monitor_mac" table="NB_Global"
>           db="OVN_Northbound"/> column of <ref table="NB_Global"
> @@ -850,7 +853,40 @@
>         </li>
>       </ul>
>   
> -    <h3>Ingress Table 9: <code>from-lport</code> QoS Marking</h3>
> +    <h3>Ingress Table 9: <code>from-lport</code> ACL action</h3>
> +
> +    <p>
> +      Logical flows in this table decide how to proceed based on the values of
> +      the allow, drop, and reject bits that may have been set in the previous
> +      table.
> +    </p>
> +
> +    <ul>
> +      <li>
> +        If no ACLs are configured, then a priority 0 flow is installed that
> +        matches everything and advances to the next table.
> +      </li>
> +
> +      <li>
> +        A priority 1000 flow is installed that will advance the packet to the
> +        next table if the allow bit is set.
> +      </li>
> +
> +      <li>
> +        A priority 1000 flow is installed that will run the <code>drop;</code>
> +        action if the drop bit is set.
> +      </li>
> +
> +      <li>
> +        A priority 1000 flow is installed that will run the <code>tcp_reset
> +        { output &lt;-&gt; inport; next(pipeline=egress,table=5);}</code>
> +        action for TCP connections,<code>icmp4/icmp6</code> action
> +        for UDP connections, and <code>sctp_abort {output &lt;-%gt; inport;
> +        next(pipeline=egress,table=5);}</code> action for SCTP associations.
> +      </li>
> +    </ul>
> +
> +    <h3>Ingress Table 10: <code>from-lport</code> QoS Marking</h3>
>   
>       <p>
>         Logical flows in this table closely reproduce those in the
> @@ -872,7 +908,7 @@
>         </li>
>       </ul>
>   
> -    <h3>Ingress Table 10: <code>from-lport</code> QoS Meter</h3>
> +    <h3>Ingress Table 11: <code>from-lport</code> QoS Meter</h3>
>   
>       <p>
>         Logical flows in this table closely reproduce those in the
> @@ -894,7 +930,7 @@
>         </li>
>       </ul>
>   
> -    <h3>Ingress Table 11: Load balancing affinity check</h3>
> +    <h3>Ingress Table 12: Load balancing affinity check</h3>
>   
>       <p>
>         Load balancing affinity check table contains the following
> @@ -922,7 +958,7 @@
>         </li>
>       </ul>
>   
> -    <h3>Ingress Table 12: LB</h3>
> +    <h3>Ingress Table 13: LB</h3>
>   
>       <ul>
>         <li>
> @@ -1002,7 +1038,7 @@
>         </li>
>       </ul>
>   
> -    <h3>Ingress Table 13: Load balancing affinity learn</h3>
> +    <h3>Ingress Table 14: Load balancing affinity learn</h3>
>   
>       <p>
>         Load balancing affinity learn table contains the following
> @@ -1033,7 +1069,7 @@
>         </li>
>       </ul>
>   
> -    <h3>Ingress Table 14: Pre-Hairpin</h3>
> +    <h3>Ingress Table 15: Pre-Hairpin</h3>
>       <ul>
>         <li>
>           If the logical switch has load balancer(s) configured, then a
> @@ -1051,7 +1087,7 @@
>         </li>
>       </ul>
>   
> -    <h3>Ingress Table 15: Nat-Hairpin</h3>
> +    <h3>Ingress Table 16: Nat-Hairpin</h3>
>       <ul>
>         <li>
>            If the logical switch has load balancer(s) configured, then a
> @@ -1086,7 +1122,7 @@
>         </li>
>       </ul>
>   
> -    <h3>Ingress Table 16: Hairpin</h3>
> +    <h3>Ingress Table 17: Hairpin</h3>
>       <ul>
>         <li>
>           <p>
> @@ -1120,56 +1156,57 @@
>         </li>
>       </ul>
>   
> -    <h3>Ingress table 17: <code>from-lport</code> ACLs after LB</h3>
> +    <h3>Ingress table 18: <code>from-lport</code> ACL evaluation after LB</h3>
>   
>       <p>
>         Logical flows in this table closely reproduce those in the
> -      <code>ACL</code> table in the <code>OVN_Northbound</code> database
> +      <code>ACL eval</code> table in the <code>OVN_Northbound</code> database
>         for the <code>from-lport</code> direction with the option
>         <code>apply-after-lb</code> set to <code>true</code>.
>         The <code>priority</code> values from the <code>ACL</code> table have a
>         limited range and have 1000 added to them to leave room for OVN default
> -      flows at both higher and lower priorities.
> +      flows at both higher and lower priorities. The flows in this table
> +      indicate the ACL verdict by setting <code>reg8[16]</code> for
> +      <code>allow-type</code> ACLs, <code>reg8[17]</code> for <code>drop</code>
> +      ACLs, and <code>reg8[17]</code> for <code>reject</code> ACLs, and then
> +      advancing the packet to the next table. These will be reffered to as the
> +      allow bit, drop bit, and reject bit throughout the documentation for this
> +      table and the next one.
>       </p>
>   
>       <ul>
>         <li>
>           <code>allow</code> apply-after-lb ACLs translate into logical flows
> -        with the <code>next;</code> action.  If there are any stateful ACLs
> +        that set the allow bit.  If there are any stateful ACLs
>           (including both before-lb and after-lb ACLs)
> -        on this datapath, then <code>allow</code> ACLs translate to
> -        <code>ct_commit; next;</code> (which acts as a hint for the next tables
> -        to commit the connection to conntrack). In case the <code>ACL</code>
> -        has a label then <code>reg3</code> is loaded with the label value and
> -        <code>reg0[13]</code> bit is set to 1 (which acts as a hint for the
> -        next tables to commit the label to conntrack).
> +        on this datapath, then <code>allow</code> ACLs also run
> +        <code>ct_commit; next;</code> (which acts as a hint for an upcoming
> +        table to commit the connection to conntrack). In case the
> +        <code>ACL</code> has a label then <code>reg3</code> is loaded with the
> +        label value and <code>reg0[13]</code> bit is set to 1 (which acts as a
> +        hint for the next tables to commit the label to conntrack).
>         </li>
>         <li>
>           <code>allow-related</code> apply-after-lb ACLs translate into logical
> -        flows with the <code>ct_commit(ct_label=0/1); next;</code> actions
> -        for new connections and <code>reg0[1] = 1; next;</code> for existing
> -        connections.  In case the <code>ACL</code> has a label then
> -        <code>reg3</code> is loaded with the label value and
> +        flows that set the allow bit and run the <code>ct_commit(ct_label=0/1);
> +        next;</code> actions for new connections and <code>reg0[1] = 1;
> +        next;</code> for existing connections.  In case the <code>ACL</code>
> +        has a label then <code>reg3</code> is loaded with the label value and
>           <code>reg0[13]</code> bit is set to 1 (which acts as a hint for the
>           next tables to commit the label to conntrack).
>         </li>
>         <li>
>           <code>allow-stateless</code> apply-after-lb ACLs translate into logical
> -        flows with the <code>next;</code> action.
> +        flows that set the allow bit and advance to the next table.
>         </li>
>         <li>
>           <code>reject</code> apply-after-lb ACLs translate into logical
> -        flows with the
> -        <code>tcp_reset { output &lt;-&gt; inport;
> -        next(pipeline=egress,table=5);}</code>
> -        action for TCP connections,<code>icmp4/icmp6</code> action
> -        for UDP connections, and <code>sctp_abort {output &lt;-%gt; inport;
> -        next(pipeline=egress,table=5);}</code> action for SCTP associations.
> +        flows that set the reject bit and advance to the next table.
>         </li>
>         <li>
> -        Other apply-after-lb ACLs translate to <code>drop;</code> for new
> -        or untracked connections and <code>ct_commit(ct_label=1/1);</code> for
> -        known connections.  Setting <code>ct_label</code> marks a connection
> +        Other apply-after-lb ACLs set the drop bit for new or untracked
> +        connections and <code>ct_commit(ct_label=1/1);</code> for known
> +        connections.  Setting <code>ct_label</code> marks a connection
>           as one that was previously allowed, but should no longer be
>           allowed due to a policy change.
>         </li>
> @@ -1179,8 +1216,8 @@
>         <li>
>           One priority-65532 flow matching packets with <code>reg0[17]</code>
>           set (either replies to existing sessions or traffic related to
> -        existing sessions) and allows these by advancing to the next
> -        table.
> +        existing sessions) and allows these by setting the allow bit and
> +        advancing to the next table.
>         </li>
>       </ul>
>   
> @@ -1191,7 +1228,40 @@
>         </li>
>       </ul>
>   
> -    <h3>Ingress Table 18: Stateful</h3>
> +    <h3>Ingress Table 19: <code>from-lport</code> ACL action after LB</h3>
> +
> +    <p>
> +      Logical flows in this table decide how to proceed based on the values of
> +      the allow, drop, and reject bits that may have been set in the previous
> +      table.
> +    </p>
> +
> +    <ul>
> +      <li>
> +        If no ACLs are configured, then a priority 0 flow is installed that
> +        matches everything and advances to the next table.
> +      </li>
> +
> +      <li>
> +        A priority 1000 flow is installed that will advance the packet to the
> +        next table if the allow bit is set.
> +      </li>
> +
> +      <li>
> +        A priority 1000 flow is installed that will run the <code>drop;</code>
> +        action if the drop bit is set.
> +      </li>
> +
> +      <li>
> +        A priority 1000 flow is installed that will run the <code>tcp_reset
> +        { output &lt;-&gt; inport; next(pipeline=egress,table=5);}</code>
> +        action for TCP connections,<code>icmp4/icmp6</code> action
> +        for UDP connections, and <code>sctp_abort {output &lt;-%gt; inport;
> +        next(pipeline=egress,table=5);}</code> action for SCTP associations.
> +      </li>
> +    </ul>
> +
> +    <h3>Ingress Table 20: Stateful</h3>
>   
>       <ul>
>         <li>
> @@ -1214,7 +1284,7 @@
>         </li>
>       </ul>
>   
> -    <h3>Ingress Table 19: ARP/ND responder</h3>
> +    <h3>Ingress Table 21: ARP/ND responder</h3>
>   
>       <p>
>         This table implements ARP/ND responder in a logical switch for known
> @@ -1541,7 +1611,7 @@ output;
>         </li>
>       </ul>
>   
> -    <h3>Ingress Table 20: DHCP option processing</h3>
> +    <h3>Ingress Table 22: DHCP option processing</h3>
>   
>       <p>
>         This table adds the DHCPv4 options to a DHCPv4 packet from the
> @@ -1602,7 +1672,7 @@ next;
>         </li>
>       </ul>
>   
> -    <h3>Ingress Table 21: DHCP responses</h3>
> +    <h3>Ingress Table 23: DHCP responses</h3>
>   
>       <p>
>         This table implements DHCP responder for the DHCP replies generated by
> @@ -1683,7 +1753,7 @@ output;
>         </li>
>       </ul>
>   
> -    <h3>Ingress Table 22 DNS Lookup</h3>
> +    <h3>Ingress Table 24 DNS Lookup</h3>
>   
>       <p>
>         This table looks up and resolves the DNS names to the corresponding
> @@ -1712,7 +1782,7 @@ reg0[4] = dns_lookup(); next;
>         </li>
>       </ul>
>   
> -    <h3>Ingress Table 23 DNS Responses</h3>
> +    <h3>Ingress Table 25 DNS Responses</h3>
>   
>       <p>
>         This table implements DNS responder for the DNS replies generated by
> @@ -1747,7 +1817,7 @@ output;
>         </li>
>       </ul>
>   
> -    <h3>Ingress table 24 External ports</h3>
> +    <h3>Ingress table 26 External ports</h3>
>   
>       <p>
>         Traffic from the <code>external</code> logical ports enter the ingress
> @@ -1790,7 +1860,7 @@ output;
>         </li>
>       </ul>
>   
> -    <h3>Ingress Table 25 Destination Lookup</h3>
> +    <h3>Ingress Table 27 Destination Lookup</h3>
>   
>       <p>
>         This table implements switching behavior.  It contains these logical
> @@ -1966,7 +2036,7 @@ output;
>         </li>
>       </ul>
>   
> -    <h3>Ingress Table 26 Destination unknown</h3>
> +    <h3>Ingress Table 28 Destination unknown</h3>
>   
>       <p>
>         This table handles the packets whose destination was not found or
> @@ -2116,11 +2186,15 @@ output;
>         This is similar to ingress table <code>ACL hints</code>.
>       </p>
>   
> -    <h3>Egress Table 4: <code>to-lport</code> ACLs</h3>
> +    <h3>Egress Table 4: <code>to-lport</code> ACL evaluation</h3>
>   
>       <p>
> -      This is similar to ingress table <code>ACLs</code> except for
> -      <code>to-lport</code> ACLs.
> +      This is similar to ingress table <code>ACL eval</code> except for
> +      <code>to-lport</code> ACLs. As a reminder, these flows use the
> +      following register bits to indicate their verdicts.
> +      <code>Allow-type</code> ACLs set <code>reg8[16]</code>, <code>drop</code>
> +      ACLs set <code>reg8[17]</code>, and <code>reject</code> ACLs set
> +      <code>reg8[18]</code>.
>       </p>
>   
>       <p>
> @@ -2137,14 +2211,16 @@ output;
>           A priority 34000 logical flow is added for each logical port which
>           has DHCPv4 options defined to allow the DHCPv4 reply packet and which has
>           DHCPv6 options defined to allow the DHCPv6 reply packet from the
> -        <code>Ingress Table 18: DHCP responses</code>.
> +        <code>Ingress Table 18: DHCP responses</code>. This is indicated by
> +        setting the allow bit.
>         </li>
>   
>         <li>
>           A priority 34000 logical flow is added for each logical switch datapath
>           configured with DNS records with the match <code>udp.dst = 53</code>
>           to allow the DNS reply packet from the
> -        <code>Ingress Table 20: DNS responses</code>.
> +        <code>Ingress Table 20: DNS responses</code>. This is indicated by
> +        setting the allow bit.
>         </li>
>   
>         <li>
> @@ -2155,32 +2231,38 @@ output;
>           service monitor mac defined in the
>           <ref column="options:svc_monitor_mac" table="NB_Global"
>           db="OVN_Northbound"/> column of <ref table="NB_Global"
> -        db="OVN_Northbound"/> table.
> +        db="OVN_Northbound"/> table. This is indicated by setting the allow
> +        bit.
>         </li>
>       </ul>
>   
> -    <h3>Egress Table 5: <code>to-lport</code> QoS Marking</h3>
> +    <h3>Egress Table 5: <code>to-lport</code> ACL action</h3>
> +    <p>
> +      This is similar to ingress table <code>ACL action</code>.
> +    </p>
> +
> +    <h3>Egress Table 6: <code>to-lport</code> QoS Marking</h3>
>   
>       <p>
>         This is similar to ingress table <code>QoS marking</code> except
>         they apply to <code>to-lport</code> QoS rules.
>       </p>
>   
> -    <h3>Egress Table 6: <code>to-lport</code> QoS Meter</h3>
> +    <h3>Egress Table 7: <code>to-lport</code> QoS Meter</h3>
>   
>       <p>
>         This is similar to ingress table <code>QoS meter</code> except
>         they apply to <code>to-lport</code> QoS rules.
>       </p>
>   
> -    <h3>Egress Table 7: Stateful</h3>
> +    <h3>Egress Table 8: Stateful</h3>
>   
>       <p>
>         This is similar to ingress table <code>Stateful</code> except that
>         there are no rules added for load balancing new connections.
>       </p>
>   
> -    <h3>Egress Table 8: Egress Port Security - check</h3>
> +    <h3>Egress Table 9: Egress Port Security - check</h3>
>   
>       <p>
>         This is similar to the port security logic in table
> @@ -2209,7 +2291,7 @@ output;
>         </li>
>       </ul>
>   
> -    <h3>Egress Table 9: Egress Port Security - Apply</h3>
> +    <h3>Egress Table 10: Egress Port Security - Apply</h3>
>   
>       <p>
>         This is similar to the ingress port security logic in ingress table
> diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at
> index 137724723..64d6a9336 100644
> --- a/tests/ovn-controller.at
> +++ b/tests/ovn-controller.at
> @@ -919,9 +919,9 @@ for i in $(seq 10); do
>       if test "$i" = 3; then
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3 actions=drop
> +priority=1100,ip,reg15=0x1,metadata=0x1,nw_src=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x1,metadata=0x1,nw_src=10.0.0.2 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x1,metadata=0x1,nw_src=10.0.0.3 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   ])
>       fi
>       AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$i
> @@ -941,7 +941,7 @@ for i in $(seq 10); do
>       if test "$i" = 9; then
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}'], [0], [dnl
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10 actions=drop
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   ])
>       fi
>       if test "$i" = 10; then
> @@ -967,12 +967,12 @@ for i in $(seq 10); do
>       if test "$i" = 3; then
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.1.1 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.1.2 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.1.3 actions=drop
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.1.1 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.1.2 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.1.3 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   ])
>       fi
>       AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$(($i * 2))
> @@ -1092,9 +1092,9 @@ for i in $(seq 10); do
>       if test "$i" = 1; then
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
> -priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,tp_dst=111 actions=drop
> -priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,tp_dst=222 actions=drop
> -priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,tp_dst=333 actions=drop
> +priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,tp_dst=111 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,tp_dst=222 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,tp_dst=333 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   ])
>       else
>           # (1 conj_id flow + 3 tp_dst flows) = 4 extra flows
> @@ -1106,8 +1106,8 @@ priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,tp_dst=33
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}' | \
>               sed -r 's/conjunction.*,/conjunction,/' | \
> -            sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
> -priority=1100,conj_id=,metadata=0x$dp_key actions=drop
> +            sed -r 's/conj_id=.*,metadata/conj_id=,metadata/' | sort], [0], [dnl
> +priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=conjunction,1/2)
>   priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2 actions=conjunction,1/2)
>   priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3 actions=conjunction,1/2)
> @@ -1134,9 +1134,9 @@ for i in $(seq 10); do
>           # no conjunction left
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
> -priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,tp_dst=111 actions=drop
> -priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,tp_dst=222 actions=drop
> -priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,tp_dst=333 actions=drop
> +priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,tp_dst=111 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,tp_dst=222 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,tp_dst=333 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   ])
>       else
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$((14 - $i))
> @@ -1158,8 +1158,8 @@ for i in $(seq 10); do
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}' | \
>               sed -r 's/conjunction.*,/conjunction,/' | \
> -            sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
> -priority=1100,conj_id=,metadata=0x$dp_key actions=drop
> +            sed -r 's/conj_id=.*,metadata/conj_id=,metadata/' | sort], [0], [dnl
> +priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=conjunction,1/2)
>   priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2 actions=conjunction,1/2)
>   priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3 actions=conjunction,1/2)
> @@ -1289,7 +1289,7 @@ for i in $(seq 10); do
>       if test "$i" = 1; then
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,nw_dst=10.0.0.6 actions=drop
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,nw_dst=10.0.0.6 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   ])
>       else
>           # (1 conj_id + nw_src * i + nw_dst * i) = 1 + i*2 flows
> @@ -1301,8 +1301,8 @@ priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,nw_dst=10.
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}' | \
>               sed -r 's/conjunction.*,/conjunction,/' | \
> -            sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
> -priority=1100,conj_id=,metadata=0x$dp_key actions=drop
> +            sed -r 's/conj_id=.*,metadata/conj_id=,metadata/' | sort], [0], [dnl
> +priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.6 actions=conjunction,1/2)
>   priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.7 actions=conjunction,1/2)
>   priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.8 actions=conjunction,1/2)
> @@ -1331,7 +1331,7 @@ for i in $(seq 10); do
>           # no conjunction left
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,nw_dst=10.0.0.15 actions=drop
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,nw_dst=10.0.0.15 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   ])
>       else
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$((21 - $i*2))
> @@ -1357,9 +1357,9 @@ for i in $(seq 2 10); do
>       if test "$i" = 3; then
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,nw_dst=10.0.0.6 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2,nw_dst=10.0.0.6 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3,nw_dst=10.0.0.6 actions=drop
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,nw_dst=10.0.0.6 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2,nw_dst=10.0.0.6 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3,nw_dst=10.0.0.6 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   ])
>       fi
>       AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$i
> @@ -1383,8 +1383,8 @@ for i in $(seq 10); do
>       if test "$i" = 9; then
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}'], [0], [dnl
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,nw_dst=10.0.0.6 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,nw_dst=10.0.0.7 actions=drop
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,nw_dst=10.0.0.6 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,nw_dst=10.0.0.7 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   ])
>       elif test "$i" = 10; then
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep "priority=1100"], [1], [ignore])
> @@ -1446,8 +1446,8 @@ for i in $(seq 10); do
>       if test "$i" = 1; then
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.6 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=drop
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.6 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   ])
>       else
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$(($i*2))
> @@ -1459,12 +1459,12 @@ priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=dr
>               grep -v reply | awk '{print $7, $8}' | \
>               sed -r 's/conjunction.*,/conjunction,/' | \
>               sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.6 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.7 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.8 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3 actions=drop
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.6 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.7 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.8 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   ])
>       fi
>   done
> @@ -1542,8 +1542,8 @@ for i in $(seq 10); do
>       if test "$i" = 1; then
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.6 actions=drop
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.6 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   ])
>       elif test "$i" -lt 6; then
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$(($i*2))
> @@ -1558,12 +1558,12 @@ priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.6 actions=dr
>               grep -v reply | awk '{print $7, $8}' | \
>               sed -r 's/conjunction.*,/conjunction,/' | \
>               sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.6 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.7 actions=drop
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.8 actions=drop
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.6 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.7 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.8 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   ])
>       fi
>   done
> @@ -1640,7 +1640,7 @@ for i in $(seq 10); do
>       if test "$i" = 1; then
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,nw_dst=10.0.0.1 actions=drop
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,nw_dst=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   ])
>       else
>           # (1 conj_id + nw_src * i + nw_dst * i) = 1 + i*2 flows
> @@ -1652,8 +1652,8 @@ priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,nw_dst=10.
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}' | \
>               sed -r 's/conjunction.*,/conjunction,/' | \
> -            sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
> -priority=1100,conj_id=,metadata=0x$dp_key actions=drop
> +            sed -r 's/conj_id=.*,metadata/conj_id=,metadata/' | sort], [0], [dnl
> +priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.1 actions=conjunction,1/2)
>   priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.2 actions=conjunction,1/2)
>   priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.3 actions=conjunction,1/2)
> @@ -1680,7 +1680,7 @@ for i in $(seq 10); do
>           # no conjunction left
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
> -priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,nw_dst=10.0.0.10 actions=drop
> +priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,nw_dst=10.0.0.10 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   ])
>       else
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$((21 - $i*2))
> @@ -1702,8 +1702,8 @@ for i in $(seq 10); do
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}' | \
>               sed -r 's/conjunction.*,/conjunction,/' | \
> -            sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
> -priority=1100,conj_id=,metadata=0x$dp_key actions=drop
> +            sed -r 's/conj_id=.*,metadata/conj_id=,metadata/' | sort], [0], [dnl
> +priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.1 actions=conjunction,1/2)
>   priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.2 actions=conjunction,1/2)
>   priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.3 actions=conjunction,1/2)
> @@ -1742,8 +1742,8 @@ check ovn-nbctl --wait=hv sync
>   AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>       grep -v reply | awk '{print $7, $8}' | \
>       sed -r 's/conjunction.*,/conjunction,/' | \
> -    sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
> -priority=1100,conj_id=,metadata=0x$dp_key actions=drop
> +    sed -r 's/conj_id=.*,metadata/conj_id=,metadata/' | sort], [0], [dnl
> +priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.1 actions=conjunction,1/2)
>   priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.2 actions=conjunction,1/2)
>   priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.3 actions=conjunction,1/2)
> @@ -1766,8 +1766,8 @@ check ovn-nbctl --wait=hv remove address_set as1 addresses 10.0.0.4,10.0.0.5
>   AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>       grep -v reply | awk '{print $7, $8}' | \
>       sed -r 's/conjunction.*,/conjunction,/' | \
> -    sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
> -priority=1100,conj_id=,metadata=0x$dp_key actions=drop
> +    sed -r 's/conj_id=.*,metadata/conj_id=,metadata/' | sort], [0], [dnl
> +priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.1 actions=conjunction,1/2)
>   priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.2 actions=conjunction,1/2)
>   priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.3 actions=conjunction,1/2)
> @@ -1824,9 +1824,9 @@ check ovn-nbctl --wait=hv sync
>   AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>       grep -v reply | awk '{print $7, $8}' | \
>       sed -r 's/conjunction.[[0-9]]*,/conjunction,/g' | \
> -    sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
> -priority=1100,conj_id=,metadata=0x$dp_key actions=drop
> -priority=1100,conj_id=,metadata=0x$dp_key actions=drop
> +    sed -r 's/conj_id=.*,metadata/conj_id=,metadata/' | sort], [0], [dnl
> +priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.11 actions=conjunction,1/2)
>   priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.12 actions=conjunction,1/2)
>   priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.13 actions=conjunction,1/2)
> @@ -1849,9 +1849,9 @@ check ovn-nbctl --wait=hv sync
>   AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>       grep -v reply | awk '{print $7, $8}' | \
>       sed -r 's/conjunction.[[0-9]]*,/conjunction,/g' | \
> -    sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
> -priority=1100,conj_id=,metadata=0x$dp_key actions=drop
> -priority=1100,conj_id=,metadata=0x$dp_key actions=drop
> +    sed -r 's/conj_id=.*,metadata/conj_id=,metadata/' | sort], [0], [dnl
> +priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.11 actions=conjunction,1/2)
>   priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.12 actions=conjunction,1/2)
>   priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.13 actions=conjunction,1/2)
> @@ -1880,9 +1880,9 @@ check ovn-nbctl --wait=hv sync
>   AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>       grep -v reply | awk '{print $7, $8}' | \
>       sed -r 's/conjunction.[[0-9]]*,/conjunction,/g' | \
> -    sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
> -priority=1100,conj_id=,metadata=0x$dp_key actions=drop
> -priority=1100,conj_id=,metadata=0x$dp_key actions=drop
> +    sed -r 's/conj_id=.*,metadata/conj_id=,metadata/' | sort], [0], [dnl
> +priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.11 actions=conjunction,1/2)
>   priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.12 actions=conjunction,1/2)
>   priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.13 actions=conjunction,1/2)
> @@ -1944,9 +1944,9 @@ for i in $(seq 5); do
>       if test "$i" = 3; then
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
> -priority=1100,reg15=0x$port_key,metadata=0x$dp_key,dl_src=aa:aa:aa:aa:aa:01 actions=drop
> -priority=1100,reg15=0x$port_key,metadata=0x$dp_key,dl_src=aa:aa:aa:aa:aa:02 actions=drop
> -priority=1100,reg15=0x$port_key,metadata=0x$dp_key,dl_src=aa:aa:aa:aa:aa:03 actions=drop
> +priority=1100,reg15=0x$port_key,metadata=0x$dp_key,dl_src=aa:aa:aa:aa:aa:01 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,reg15=0x$port_key,metadata=0x$dp_key,dl_src=aa:aa:aa:aa:aa:02 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,reg15=0x$port_key,metadata=0x$dp_key,dl_src=aa:aa:aa:aa:aa:03 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   ])
>       fi
>       AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$i
> @@ -1967,7 +1967,7 @@ for i in $(seq 5); do
>       if test "$i" = 4; then
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}'], [0], [dnl
> -priority=1100,reg15=0x$port_key,metadata=0x$dp_key,dl_src=aa:aa:aa:aa:aa:05 actions=drop
> +priority=1100,reg15=0x$port_key,metadata=0x$dp_key,dl_src=aa:aa:aa:aa:aa:05 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   ])
>       fi
>       if test "$i" = 5; then
> @@ -2025,9 +2025,9 @@ for i in $(seq 5); do
>       if test "$i" = 3; then
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
> -priority=1100,ipv6,reg15=0x$port_key,metadata=0x$dp_key,ipv6_src=ff::1 actions=drop
> -priority=1100,ipv6,reg15=0x$port_key,metadata=0x$dp_key,ipv6_src=ff::2 actions=drop
> -priority=1100,ipv6,reg15=0x$port_key,metadata=0x$dp_key,ipv6_src=ff::3 actions=drop
> +priority=1100,ipv6,reg15=0x$port_key,metadata=0x$dp_key,ipv6_src=ff::1 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ipv6,reg15=0x$port_key,metadata=0x$dp_key,ipv6_src=ff::2 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
> +priority=1100,ipv6,reg15=0x$port_key,metadata=0x$dp_key,ipv6_src=ff::3 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   ])
>       fi
>       AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$i
> @@ -2047,7 +2047,7 @@ for i in $(seq 5); do
>       if test "$i" = 4; then
>           AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
>               grep -v reply | awk '{print $7, $8}'], [0], [dnl
> -priority=1100,ipv6,reg15=0x$port_key,metadata=0x$dp_key,ipv6_src=ff::5 actions=drop
> +priority=1100,ipv6,reg15=0x$port_key,metadata=0x$dp_key,ipv6_src=ff::5 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
>   ])
>       fi
>       if test "$i" = 5; then
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> index c52f86490..1c9958c6b 100644
> --- a/tests/ovn-northd.at
> +++ b/tests/ovn-northd.at
> @@ -1442,7 +1442,7 @@ ovn-sbctl set service_monitor $sm_sw1_p1 status=offline
>   AT_CAPTURE_FILE([sbflows12])
>   OVS_WAIT_FOR_OUTPUT(
>     [ovn-sbctl dump-flows sw0 | tee sbflows12 | grep "ip4.dst == 10.0.0.10 && tcp.dst == 80" | grep priority=120 | grep ls_in_lb | sed 's/table=..//'], [0], [dnl
> -  (ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0 = 0; reject { outport <-> inport; next(pipeline=egress,table=5);};)
> +  (ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0 = 0; reject { outport <-> inport; next(pipeline=egress,table=6);};)
>   ])
>   
>   AT_CLEANUP
> @@ -2161,10 +2161,10 @@ AT_CAPTURE_FILE([sw1flows])
>   
>   AT_CHECK(
>     [grep -E 'ls_(in|out)_acl' sw0flows sw1flows | grep pg0 | sort], [0], [dnl
> -sw0flows:  table=4 (ls_out_acl         ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
> -sw0flows:  table=8 (ls_in_acl          ), priority=2002 , match=(inport == @pg0 && ip4 && tcp && tcp.dst == 80), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=5); };)
> -sw1flows:  table=4 (ls_out_acl         ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
> -sw1flows:  table=8 (ls_in_acl          ), priority=2002 , match=(inport == @pg0 && ip4 && tcp && tcp.dst == 80), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=5); };)
> +sw0flows:  table=4 (ls_out_acl_eval    ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg8[[18]] = 1; next;)
> +sw0flows:  table=8 (ls_in_acl_eval     ), priority=2002 , match=(inport == @pg0 && ip4 && tcp && tcp.dst == 80), action=(reg8[[18]] = 1; next;)
> +sw1flows:  table=4 (ls_out_acl_eval    ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg8[[18]] = 1; next;)
> +sw1flows:  table=8 (ls_in_acl_eval     ), priority=2002 , match=(inport == @pg0 && ip4 && tcp && tcp.dst == 80), action=(reg8[[18]] = 1; next;)
>   ])
>   
>   AS_BOX([2])
> @@ -2177,10 +2177,10 @@ ovn-sbctl dump-flows sw1 > sw1flows2
>   AT_CAPTURE_FILE([sw1flows2])
>   
>   AT_CHECK([grep "ls_out_acl" sw0flows2 sw1flows2 | grep pg0 | sort], [0], [dnl
> -sw0flows2:  table=4 (ls_out_acl         ), priority=2002 , match=(outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
> -sw0flows2:  table=4 (ls_out_acl         ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
> -sw1flows2:  table=4 (ls_out_acl         ), priority=2002 , match=(outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
> -sw1flows2:  table=4 (ls_out_acl         ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
> +sw0flows2:  table=4 (ls_out_acl_eval    ), priority=2002 , match=(outport == @pg0 && ip4 && udp), action=(reg8[[18]] = 1; next;)
> +sw0flows2:  table=4 (ls_out_acl_eval    ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg8[[18]] = 1; next;)
> +sw1flows2:  table=4 (ls_out_acl_eval    ), priority=2002 , match=(outport == @pg0 && ip4 && udp), action=(reg8[[18]] = 1; next;)
> +sw1flows2:  table=4 (ls_out_acl_eval    ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg8[[18]] = 1; next;)
>   ])
>   
>   AS_BOX([3])
> @@ -2193,19 +2193,20 @@ ovn-sbctl dump-flows sw1 > sw1flows3
>   AT_CAPTURE_FILE([sw1flows3])
>   
>   AT_CHECK([grep "ls_out_acl" sw0flows3 sw1flows3 | grep pg0 | sort], [0], [dnl
> -sw0flows3:  table=4 (ls_out_acl         ), priority=2001 , match=(reg0[[7]] == 1 && (outport == @pg0 && ip)), action=(reg0[[1]] = 1; next;)
> -sw0flows3:  table=4 (ls_out_acl         ), priority=2001 , match=(reg0[[8]] == 1 && (outport == @pg0 && ip)), action=(next;)
> -sw0flows3:  table=4 (ls_out_acl         ), priority=2002 , match=((reg0[[10]] == 1) && outport == @pg0 && ip4 && udp), action=(ct_commit { ct_mark.blocked = 1; };  reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
> -sw0flows3:  table=4 (ls_out_acl         ), priority=2002 , match=((reg0[[9]] == 1) && outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
> -sw0flows3:  table=4 (ls_out_acl         ), priority=2003 , match=((reg0[[10]] == 1) && outport == @pg0 && ip6 && udp), action=(ct_commit { ct_mark.blocked = 1; };  reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
> -sw0flows3:  table=4 (ls_out_acl         ), priority=2003 , match=((reg0[[9]] == 1) && outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
> -sw1flows3:  table=4 (ls_out_acl         ), priority=2001 , match=(reg0[[7]] == 1 && (outport == @pg0 && ip)), action=(reg0[[1]] = 1; next;)
> -sw1flows3:  table=4 (ls_out_acl         ), priority=2001 , match=(reg0[[8]] == 1 && (outport == @pg0 && ip)), action=(next;)
> -sw1flows3:  table=4 (ls_out_acl         ), priority=2002 , match=((reg0[[10]] == 1) && outport == @pg0 && ip4 && udp), action=(ct_commit { ct_mark.blocked = 1; };  reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
> -sw1flows3:  table=4 (ls_out_acl         ), priority=2002 , match=((reg0[[9]] == 1) && outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
> -sw1flows3:  table=4 (ls_out_acl         ), priority=2003 , match=((reg0[[10]] == 1) && outport == @pg0 && ip6 && udp), action=(ct_commit { ct_mark.blocked = 1; };  reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
> -sw1flows3:  table=4 (ls_out_acl         ), priority=2003 , match=((reg0[[9]] == 1) && outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
> +sw0flows3:  table=4 (ls_out_acl_eval    ), priority=2001 , match=(reg0[[7]] == 1 && (outport == @pg0 && ip)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
> +sw0flows3:  table=4 (ls_out_acl_eval    ), priority=2001 , match=(reg0[[8]] == 1 && (outport == @pg0 && ip)), action=(reg8[[16]] = 1; next;)
> +sw0flows3:  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[10]] == 1 && (outport == @pg0 && ip4 && udp)), action=(reg8[[18]] = 1; ct_commit { ct_mark.blocked = 1; }; next;)
> +sw0flows3:  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[9]] == 1 && (outport == @pg0 && ip4 && udp)), action=(reg8[[18]] = 1; next;)
> +sw0flows3:  table=4 (ls_out_acl_eval    ), priority=2003 , match=(reg0[[10]] == 1 && (outport == @pg0 && ip6 && udp)), action=(reg8[[18]] = 1; ct_commit { ct_mark.blocked = 1; }; next;)
> +sw0flows3:  table=4 (ls_out_acl_eval    ), priority=2003 , match=(reg0[[9]] == 1 && (outport == @pg0 && ip6 && udp)), action=(reg8[[18]] = 1; next;)
> +sw1flows3:  table=4 (ls_out_acl_eval    ), priority=2001 , match=(reg0[[7]] == 1 && (outport == @pg0 && ip)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
> +sw1flows3:  table=4 (ls_out_acl_eval    ), priority=2001 , match=(reg0[[8]] == 1 && (outport == @pg0 && ip)), action=(reg8[[16]] = 1; next;)
> +sw1flows3:  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[10]] == 1 && (outport == @pg0 && ip4 && udp)), action=(reg8[[18]] = 1; ct_commit { ct_mark.blocked = 1; }; next;)
> +sw1flows3:  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[9]] == 1 && (outport == @pg0 && ip4 && udp)), action=(reg8[[18]] = 1; next;)
> +sw1flows3:  table=4 (ls_out_acl_eval    ), priority=2003 , match=(reg0[[10]] == 1 && (outport == @pg0 && ip6 && udp)), action=(reg8[[18]] = 1; ct_commit { ct_mark.blocked = 1; }; next;)
> +sw1flows3:  table=4 (ls_out_acl_eval    ), priority=2003 , match=(reg0[[9]] == 1 && (outport == @pg0 && ip6 && udp)), action=(reg8[[18]] = 1; next;)
>   ])
> +
>   AT_CLEANUP
>   ])
>   
> @@ -2454,11 +2455,11 @@ 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), 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=(ct_commit_nat;)
> -  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;)
> +  table=4 (ls_out_acl_eval    ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
> +  table=4 (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
>     table=7 (ls_in_acl_hint     ), priority=1    , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
>     table=7 (ls_in_acl_hint     ), priority=2    , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
>     table=7 (ls_in_acl_hint     ), priority=3    , match=(!ct.est), action=(reg0[[9]] = 1; next;)
> @@ -2466,11 +2467,11 @@ AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e
>     table=7 (ls_in_acl_hint     ), priority=5    , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
>     table=7 (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=7 (ls_in_acl_hint     ), priority=7    , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
> -  table=8 (ls_in_acl          ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
> -  table=8 (ls_in_acl          ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
> -  table=8 (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;)
> -  table=8 (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; reg0[[17]] = 1; next;)
> -  table=8 (ls_in_acl          ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
> +  table=8 (ls_in_acl_eval     ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
> +  table=8 (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
>   ])
>   
>   AS_BOX([Check match ct_state with load balancer])
> @@ -2480,10 +2481,10 @@ check ovn-nbctl --wait=sb \
>       -- lb-add lb "10.0.0.1" "10.0.0.2" \
>       -- ls-lb-add ls lb
>   
> -AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e ls_in_acl -e ls_out_acl | sort], [0], [dnl
> -  table=17(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
> -  table=17(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  table=17(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
> +AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e ls_in_acl_eval -e ls_out_acl_eval -e ls_in_acl_after_lb_eval | sort], [0], [dnl
> +  table=18(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=18(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=18(ls_in_acl_after_lb_eval), priority=65532, match=(reg0[[17]] == 1), action=(reg8[[16]] = 1; next;)
>     table=3 (ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
>     table=3 (ls_out_acl_hint    ), priority=1    , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
>     table=3 (ls_out_acl_hint    ), priority=2    , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
> @@ -2492,16 +2493,16 @@ 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=0    , match=(1), action=(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;)
> -  table=4 (ls_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(ct_commit_nat;)
> -  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;)
> -  table=4 (ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=4 (ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
> +  table=4 (ls_out_acl_eval    ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=1001 , match=(reg0[[7]] == 1 && (ip)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=1001 , match=(reg0[[8]] == 1 && (ip)), action=(reg8[[16]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
> +  table=4 (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
>     table=7 (ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
>     table=7 (ls_in_acl_hint     ), priority=1    , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
>     table=7 (ls_in_acl_hint     ), priority=2    , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
> @@ -2510,30 +2511,30 @@ AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e
>     table=7 (ls_in_acl_hint     ), priority=5    , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
>     table=7 (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=7 (ls_in_acl_hint     ), priority=7    , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
> -  table=8 (ls_in_acl          ), priority=0    , match=(1), action=(next;)
> -  table=8 (ls_in_acl          ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
> -  table=8 (ls_in_acl          ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
> -  table=8 (ls_in_acl          ), priority=1001 , match=(reg0[[7]] == 1 && (ip)), action=(reg0[[1]] = 1; next;)
> -  table=8 (ls_in_acl          ), priority=1001 , match=(reg0[[8]] == 1 && (ip)), action=(next;)
> -  table=8 (ls_in_acl          ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
> -  table=8 (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;)
> -  table=8 (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; reg0[[17]] = 1; next;)
> -  table=8 (ls_in_acl          ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
> -  table=8 (ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=8 (ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
> +  table=8 (ls_in_acl_eval     ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=1001 , match=(reg0[[7]] == 1 && (ip)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=1001 , match=(reg0[[8]] == 1 && (ip)), action=(reg8[[16]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
> +  table=8 (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
>   ])
>   
>   ovn-nbctl --wait=sb clear logical_switch ls acls
>   ovn-nbctl --wait=sb clear logical_switch ls load_balancer
>   
> -AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e ls_in_acl -e ls_out_acl | sort], [0], [dnl
> -  table=17(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
> -  table=17(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e ls_in_acl_eval -e ls_out_acl_eval -e ls_in_acl_after_lb_eval | sort], [0], [dnl
> +  table=18(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=18(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
>     table=3 (ls_out_acl_hint    ), priority=65535, match=(1), action=(next;)
> -  table=4 (ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  table=4 (ls_out_acl         ), priority=65535, match=(1), action=(next;)
> +  table=4 (ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=65535, match=(1), action=(next;)
>     table=7 (ls_in_acl_hint     ), priority=65535, match=(1), action=(next;)
> -  table=8 (ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  table=8 (ls_in_acl          ), priority=65535, match=(1), action=(next;)
> +  table=8 (ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=65535, match=(1), action=(next;)
>   ])
>   
>   
> @@ -4255,10 +4256,10 @@ check_stateful_flows() {
>   
>       AT_CHECK([grep "ls_out_lb" sw0flows | sort], [0], [])
>   
> -    AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl
> -  table=7 (ls_out_stateful    ), priority=0    , match=(1), action=(next;)
> -  table=7 (ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
> -  table=7 (ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
> +    AT_CHECK([grep "ls_out_stateful" sw0flows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_out_stateful    ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
> +  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
>   ])
>   }
>   
> @@ -4318,19 +4319,19 @@ AT_CHECK([grep "ls_out_pre_stateful" sw0flows | sort], [0], [dnl
>     table=2 (ls_out_pre_stateful), priority=110  , match=(reg0[[2]] == 1), action=(ct_lb_mark;)
>   ])
>   
> -AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl
> -  table=7 (ls_out_stateful    ), priority=0    , match=(1), action=(next;)
> -  table=7 (ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
> -  table=7 (ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
> +AT_CHECK([grep "ls_out_stateful" sw0flows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_out_stateful    ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
> +  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
>   ])
>   
>   # LB with event=false and reject=false
>   AT_CHECK([ovn-nbctl create load_balancer name=lb1 options:reject=false options:event=false vips:\"10.0.0.20\"=\"\" protocol=tcp], [0], [ignore])
>   check ovn-nbctl --wait=sb ls-lb-add sw0 lb1
>   
> -AT_CHECK([ovn-sbctl dump-flows sw0 | grep "ls_in_lb " | sort ], [0], [dnl
> -  table=12(ls_in_lb           ), priority=0    , match=(1), action=(next;)
> -  table=12(ls_in_lb           ), priority=110  , match=(ct.new && ip4.dst == 10.0.0.20), action=(drop;)
> +AT_CHECK([ovn-sbctl dump-flows sw0 | grep "ls_in_lb " | sed 's/table=../table=??/' | sort ], [0], [dnl
> +  table=??(ls_in_lb           ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_lb           ), priority=110  , match=(ct.new && ip4.dst == 10.0.0.20), action=(drop;)
>   ])
>   
>   AT_CLEANUP
> @@ -4349,9 +4350,9 @@ check ovn-nbctl --wait=sb --label=1234 acl-add sw0 from-lport 1002 tcp allow-rel
>   ovn-sbctl dump-flows sw0 > sw0flows
>   AT_CAPTURE_FILE([sw0flows])
>   
> -AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 2002 | sort | sed 's/table=./table=?/'], [0], [dnl
> -  table=? (ls_in_acl          ), priority=2002 , match=(reg0[[7]] == 1 && (tcp)), action=(reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
> -  table=? (ls_in_acl          ), priority=2002 , match=(reg0[[8]] == 1 && (tcp)), action=(reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
> +AT_CHECK([grep -w "ls_in_acl_eval" sw0flows | grep 2002 | sort | sed 's/table=./table=?/'], [0], [dnl
> +  table=? (ls_in_acl_eval     ), priority=2002 , match=(reg0[[7]] == 1 && (tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
> +  table=? (ls_in_acl_eval     ), priority=2002 , match=(reg0[[8]] == 1 && (tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
>   ])
>   AT_CHECK([grep "ls_in_stateful" sw0flows | sort | sed 's/table=../table=??/'], [0], [dnl
>     table=??(ls_in_stateful     ), priority=0    , match=(1), action=(next;)
> @@ -4359,14 +4360,14 @@ AT_CHECK([grep "ls_in_stateful" sw0flows | sort | sed 's/table=../table=??/'], [
>     table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
>   ])
>   
> -AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 2002 | sort], [0], [dnl
> -  table=4 (ls_out_acl         ), priority=2002 , match=(reg0[[7]] == 1 && (tcp)), action=(reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
> -  table=4 (ls_out_acl         ), priority=2002 , match=(reg0[[8]] == 1 && (tcp)), action=(reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
> +AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep 2002 | sort], [0], [dnl
> +  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[7]] == 1 && (tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
> +  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[8]] == 1 && (tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
>   ])
> -AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl
> -  table=7 (ls_out_stateful    ), priority=0    , match=(1), action=(next;)
> -  table=7 (ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
> -  table=7 (ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
> +AT_CHECK([grep "ls_out_stateful" sw0flows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_out_stateful    ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
> +  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
>   ])
>   
>   # Add new ACL without label
> @@ -4376,11 +4377,11 @@ check ovn-nbctl --wait=sb acl-add sw0 from-lport 1002 udp allow-related
>   ovn-sbctl dump-flows sw0 > sw0flows
>   AT_CAPTURE_FILE([sw0flows])
>   
> -AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 2002 | sort | sed 's/table=./table=?/'], [0], [dnl
> -  table=? (ls_in_acl          ), priority=2002 , match=(reg0[[7]] == 1 && (tcp)), action=(reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
> -  table=? (ls_in_acl          ), priority=2002 , match=(reg0[[7]] == 1 && (udp)), action=(reg0[[1]] = 1; next;)
> -  table=? (ls_in_acl          ), priority=2002 , match=(reg0[[8]] == 1 && (tcp)), action=(reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
> -  table=? (ls_in_acl          ), priority=2002 , match=(reg0[[8]] == 1 && (udp)), action=(next;)
> +AT_CHECK([grep -w "ls_in_acl_eval" sw0flows | grep 2002 | sort | sed 's/table=./table=?/'], [0], [dnl
> +  table=? (ls_in_acl_eval     ), priority=2002 , match=(reg0[[7]] == 1 && (tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
> +  table=? (ls_in_acl_eval     ), priority=2002 , match=(reg0[[7]] == 1 && (udp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
> +  table=? (ls_in_acl_eval     ), priority=2002 , match=(reg0[[8]] == 1 && (tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
> +  table=? (ls_in_acl_eval     ), priority=2002 , match=(reg0[[8]] == 1 && (udp)), action=(reg8[[16]] = 1; next;)
>   ])
>   AT_CHECK([grep "ls_in_stateful" sw0flows | sort | sed 's/table=../table=??/'], [0], [dnl
>     table=??(ls_in_stateful     ), priority=0    , match=(1), action=(next;)
> @@ -4388,16 +4389,16 @@ AT_CHECK([grep "ls_in_stateful" sw0flows | sort | sed 's/table=../table=??/'], [
>     table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
>   ])
>   
> -AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 2002 | sort], [0], [dnl
> -  table=4 (ls_out_acl         ), priority=2002 , match=(reg0[[7]] == 1 && (tcp)), action=(reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
> -  table=4 (ls_out_acl         ), priority=2002 , match=(reg0[[7]] == 1 && (udp)), action=(reg0[[1]] = 1; next;)
> -  table=4 (ls_out_acl         ), priority=2002 , match=(reg0[[8]] == 1 && (tcp)), action=(reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
> -  table=4 (ls_out_acl         ), priority=2002 , match=(reg0[[8]] == 1 && (udp)), action=(next;)
> +AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep 2002 | sort], [0], [dnl
> +  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[7]] == 1 && (tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
> +  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[7]] == 1 && (udp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[8]] == 1 && (tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
> +  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[8]] == 1 && (udp)), action=(reg8[[16]] = 1; next;)
>   ])
> -AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl
> -  table=7 (ls_out_stateful    ), priority=0    , match=(1), action=(next;)
> -  table=7 (ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
> -  table=7 (ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
> +AT_CHECK([grep "ls_out_stateful" sw0flows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_out_stateful    ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
> +  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
>   ])
>   
>   # Delete new ACL with label
> @@ -4407,9 +4408,9 @@ check ovn-nbctl --wait=sb acl-del sw0 from-lport 1002 tcp
>   ovn-sbctl dump-flows sw0 > sw0flows
>   AT_CAPTURE_FILE([sw0flows])
>   
> -AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 2002 | sort | sed 's/table=./table=?/'], [0], [dnl
> -  table=? (ls_in_acl          ), priority=2002 , match=(reg0[[7]] == 1 && (udp)), action=(reg0[[1]] = 1; next;)
> -  table=? (ls_in_acl          ), priority=2002 , match=(reg0[[8]] == 1 && (udp)), action=(next;)
> +AT_CHECK([grep -w "ls_in_acl_eval" sw0flows | grep 2002 | sort | sed 's/table=./table=?/'], [0], [dnl
> +  table=? (ls_in_acl_eval     ), priority=2002 , match=(reg0[[7]] == 1 && (udp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
> +  table=? (ls_in_acl_eval     ), priority=2002 , match=(reg0[[8]] == 1 && (udp)), action=(reg8[[16]] = 1; next;)
>   ])
>   AT_CHECK([grep "ls_in_stateful" sw0flows | sort | sed 's/table=../table=??/'], [0], [dnl
>     table=??(ls_in_stateful     ), priority=0    , match=(1), action=(next;)
> @@ -4417,14 +4418,14 @@ AT_CHECK([grep "ls_in_stateful" sw0flows | sort | sed 's/table=../table=??/'], [
>     table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
>   ])
>   
> -AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 2002 | sort], [0], [dnl
> -  table=4 (ls_out_acl         ), priority=2002 , match=(reg0[[7]] == 1 && (udp)), action=(reg0[[1]] = 1; next;)
> -  table=4 (ls_out_acl         ), priority=2002 , match=(reg0[[8]] == 1 && (udp)), action=(next;)
> +AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep 2002 | sort], [0], [dnl
> +  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[7]] == 1 && (udp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[8]] == 1 && (udp)), action=(reg8[[16]] = 1; next;)
>   ])
> -AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl
> -  table=7 (ls_out_stateful    ), priority=0    , match=(1), action=(next;)
> -  table=7 (ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
> -  table=7 (ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
> +AT_CHECK([grep "ls_out_stateful" sw0flows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_out_stateful    ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
> +  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
>   ])
>   AT_CLEANUP
>   ])
> @@ -4441,18 +4442,18 @@ check ovn-nbctl --wait=sb acl-add sw0 to-lport 1002 ip allow-related
>   ovn-sbctl dump-flows sw0 > sw0flows
>   AT_CAPTURE_FILE([sw0flows])
>   
> -AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
> -  table=? (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;)
> -  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; reg0[[17]] = 1; 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;)
> +AT_CHECK([grep -w "ls_in_acl_eval" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
>   ])
>   
> -AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
> -  table=? (ls_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(ct_commit_nat;)
> -  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;)
> +AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
>   ])
>   
>   # Disable ct.inv usage.
> @@ -4461,18 +4462,18 @@ check ovn-nbctl --wait=sb set NB_Global . options:use_ct_inv_match=false
>   ovn-sbctl dump-flows sw0 > sw0flows
>   AT_CAPTURE_FILE([sw0flows])
>   
> -AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
> -  table=? (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;)
> -  table=? (ls_in_acl          ), priority=65532, match=((ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
> -  table=? (ls_in_acl          ), priority=65532, match=(ct.est && !ct.rel && !ct.new && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; next;)
> -  table=? (ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +AT_CHECK([grep -w "ls_in_acl_eval" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
> +  table=? (ls_in_acl_eval     ), priority=65532, match=((ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
>   ])
>   
> -AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
> -  table=? (ls_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && ct_mark.blocked == 0), action=(ct_commit_nat;)
> -  table=? (ls_out_acl         ), priority=65532, match=((ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
> -  table=? (ls_out_acl         ), priority=65532, match=(ct.est && !ct.rel && !ct.new && ct.rpl && ct_mark.blocked == 0), action=(next;)
> -  table=? (ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
> +  table=? (ls_out_acl_eval    ), priority=65532, match=((ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
>   ])
>   
>   AT_CHECK([grep -c "ct.inv" sw0flows], [1], [dnl
> @@ -4485,18 +4486,18 @@ check ovn-nbctl --wait=sb set NB_Global . options:use_ct_inv_match=true
>   ovn-sbctl dump-flows sw0 > sw0flows
>   AT_CAPTURE_FILE([sw0flows])
>   
> -AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
> -  table=? (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;)
> -  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; reg0[[17]] = 1; 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;)
> +AT_CHECK([grep -w "ls_in_acl_eval" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
>   ])
>   
> -AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
> -  table=? (ls_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(ct_commit_nat;)
> -  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;)
> +AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
>   ])
>   
>   AT_CHECK([grep -c "ct.inv" sw0flows], [0], [dnl
> @@ -6722,7 +6723,7 @@ set_acl_options() {
>   }
>   
>   record_log_flows() {
> -    ovn-sbctl lflow-list sw0 | grep -E 'ls_(out|in)_acl.*, priority=65533' | sed 's/table=../table=??/' | sort > log_flows
> +    ovn-sbctl lflow-list sw0 | grep -E 'ls_(out|in)_acl_eval.*, priority=65533' | sed 's/table=../table=??/' | sort > log_flows
>   }
>   
>   check_log_flows_count() {
> @@ -6732,9 +6733,9 @@ check_log_flows_count() {
>   
>       echo $table
>       if test -f log_flows; then
> -        count=$(grep -c -E ls_${table}_acl log_flows)
> +        count=$(grep -c -E ls_${table}_acl_eval log_flows)
>       else
> -        count=$(ovn-sbctl lflow-list sw0 | grep -c -E "ls_$table_acl.*, priority=65533")
> +        count=$(ovn-sbctl lflow-list sw0 | grep -c -E "ls_$table_acl_eval.*, priority=65533")
>       fi
>   
>       check test "$count" -eq "$expected"
> @@ -6778,10 +6779,10 @@ check_log_flows_count 0 in
>   
>   # Now ensure the flows are what we expect them to be for the ACLs we created
>   AT_CHECK([cat log_flows], [0], [dnl
> -  table=??(ls_out_acl         ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
> -  table=??(ls_out_acl         ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
> -  table=??(ls_out_acl         ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
> -  table=??(ls_out_acl         ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
> +  table=??(ls_out_acl_eval    ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
>   ])
>   
>   rm log_flows
> @@ -6799,10 +6800,10 @@ check_log_flows_count 0 in
>   
>   # And the log flows will remain the same since the stateless ACL will not be represented.
>   AT_CHECK([cat log_flows], [0], [dnl
> -  table=??(ls_out_acl         ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
> -  table=??(ls_out_acl         ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
> -  table=??(ls_out_acl         ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
> -  table=??(ls_out_acl         ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
> +  table=??(ls_out_acl_eval    ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
>   ])
>   
>   rm log_flows
> @@ -6821,8 +6822,8 @@ check_log_flows_count 0 in
>   
>   # And make sure only the allow ACL has the log flows installed
>   AT_CHECK([cat log_flows], [0], [dnl
> -  table=??(ls_out_acl         ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
> -  table=??(ls_out_acl         ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
> +  table=??(ls_out_acl_eval    ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
>   ])
>   
>   rm log_flows
> @@ -6838,8 +6839,8 @@ check_log_flows_count 0 in
>   
>   # And make sure only the allow ACL has the log flows installed
>   AT_CHECK([cat log_flows], [0], [dnl
> -  table=??(ls_out_acl         ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
> -  table=??(ls_out_acl         ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
> +  table=??(ls_out_acl_eval    ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
>   ])
>   
>   rm log_flows
> @@ -6883,10 +6884,10 @@ check_log_flows_count 0 out
>   
>   # Now ensure the flows are what we expect them to be for the ACLs we created
>   AT_CHECK([cat log_flows], [0], [dnl
> -  table=??(ls_in_acl          ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
> -  table=??(ls_in_acl          ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
> -  table=??(ls_in_acl          ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
> -  table=??(ls_in_acl          ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
> +  table=??(ls_in_acl_eval     ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
>   ])
>   
>   rm log_flows
> @@ -6904,10 +6905,10 @@ check_log_flows_count 0 out
>   
>   # And the log flows will remain the same since the stateless ACL will not be represented.
>   AT_CHECK([cat log_flows], [0], [dnl
> -  table=??(ls_in_acl          ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
> -  table=??(ls_in_acl          ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
> -  table=??(ls_in_acl          ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
> -  table=??(ls_in_acl          ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
> +  table=??(ls_in_acl_eval     ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
>   ])
>   
>   rm log_flows
> @@ -6926,8 +6927,8 @@ check_log_flows_count 0 out
>   
>   # And make sure only the allow ACL has the log flows installed
>   AT_CHECK([cat log_flows], [0], [dnl
> -  table=??(ls_in_acl          ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
> -  table=??(ls_in_acl          ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
> +  table=??(ls_in_acl_eval     ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
>   ])
>   
>   rm log_flows
> @@ -6943,8 +6944,8 @@ check_log_flows_count 0 out
>   
>   # And make sure only the allow ACL has the log flows installed
>   AT_CHECK([cat log_flows], [0], [dnl
> -  table=??(ls_in_acl          ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
> -  table=??(ls_in_acl          ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
> +  table=??(ls_in_acl_eval     ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
>   ])
>   
>   rm log_flows
> @@ -7027,26 +7028,26 @@ check ovn-nbctl --wait=sb sync
>   ovn-sbctl dump-flows ls > lsflows
>   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), 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;)
> -  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;)
> -  table=??(ls_in_acl          ), priority=2003 , match=(reg0[[8]] == 1 && (ip4 && icmp)), action=(next;)
> -  table=??(ls_in_acl          ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */)
> -  table=??(ls_in_acl          ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(/* drop */)
> -  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=(reg0[[17]] = 1; ct_commit_nat;)
> -  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; reg0[[17]] = 1; 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=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
> +AT_CHECK([grep -e "ls_in_acl.*eval" -e "ls_in_acl_hint" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(reg0[[17]] == 1), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(reg8[[17]] = 1; ct_commit { ct_mark.blocked = 1; }; next;)
> +  table=??(ls_in_acl_eval     ), priority=2001 , match=(reg0[[9]] == 1 && (ip4)), action=(reg8[[17]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=2002 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=2002 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=2003 , match=(reg0[[7]] == 1 && (ip4 && icmp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=2003 , match=(reg0[[8]] == 1 && (ip4 && icmp)), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(reg8[[17]] = 1; ct_commit { ct_mark.blocked = 1; }; next;)
> +  table=??(ls_in_acl_eval     ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(reg8[[17]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
> @@ -7082,26 +7083,26 @@ check ovn-nbctl --wait=sb sync
>   ovn-sbctl dump-flows ls > lsflows
>   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), 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=(reg0[[17]] = 1; ct_commit_nat;)
> -  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; reg0[[17]] = 1; 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=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */)
> -  table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[9]] == 1 && (ip4)), action=(/* drop */)
> -  table=??(ls_in_acl_after_lb ), priority=2002 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
> -  table=??(ls_in_acl_after_lb ), priority=2002 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=2003 , match=(reg0[[7]] == 1 && (ip4 && icmp)), action=(reg0[[1]] = 1; next;)
> -  table=??(ls_in_acl_after_lb ), priority=2003 , match=(reg0[[8]] == 1 && (ip4 && icmp)), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */)
> -  table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(/* drop */)
> -  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
> +AT_CHECK([grep -e "ls_in_acl.*eval" -e "ls_in_acl_hint" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(reg8[[17]] = 1; ct_commit { ct_mark.blocked = 1; }; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=2001 , match=(reg0[[9]] == 1 && (ip4)), action=(reg8[[17]] = 1; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=2002 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=2002 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=2003 , match=(reg0[[7]] == 1 && (ip4 && icmp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=2003 , match=(reg0[[8]] == 1 && (ip4 && icmp)), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(reg8[[17]] = 1; ct_commit { ct_mark.blocked = 1; }; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(reg8[[17]] = 1; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(reg0[[17]] == 1), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
> @@ -7137,26 +7138,26 @@ check ovn-nbctl --wait=sb sync
>   ovn-sbctl dump-flows ls > lsflows
>   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), 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;)
> -  table=??(ls_in_acl          ), priority=2003 , match=(reg0[[8]] == 1 && (ip4 && icmp)), 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=(reg0[[17]] = 1; ct_commit_nat;)
> -  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; reg0[[17]] = 1; 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=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */)
> -  table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[9]] == 1 && (ip4)), action=(/* drop */)
> -  table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */)
> -  table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(/* drop */)
> -  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
> +AT_CHECK([grep -e "ls_in_acl.*eval" -e "ls_in_acl_hint" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(reg8[[17]] = 1; ct_commit { ct_mark.blocked = 1; }; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=2001 , match=(reg0[[9]] == 1 && (ip4)), action=(reg8[[17]] = 1; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(reg8[[17]] = 1; ct_commit { ct_mark.blocked = 1; }; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(reg8[[17]] = 1; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(reg0[[17]] == 1), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=2002 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=2002 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=2003 , match=(reg0[[7]] == 1 && (ip4 && icmp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=2003 , match=(reg0[[8]] == 1 && (ip4 && icmp)), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
> @@ -7435,15 +7436,18 @@ flow="inport == \"lsp1\" && eth.src == 00:00:00:00:00:01 && eth.dst == 00:00:00:
>   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=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  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_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65535, 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=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  table=??(ls_out_acl         ), priority=65535, match=(1), action=(next;)
> +  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), 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;)
> @@ -7457,15 +7461,18 @@ 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=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  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_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65535, 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=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  table=??(ls_out_acl         ), priority=65535, match=(1), action=(next;)
> +  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), 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;)
> @@ -7479,15 +7486,18 @@ 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=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  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_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65535, 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=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  table=??(ls_out_acl         ), priority=65535, match=(1), action=(next;)
> +  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), 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;)
> @@ -7505,18 +7515,30 @@ 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          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=1001 , match=(ip4 && tcp), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
> +  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
> @@ -7530,18 +7552,30 @@ 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          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=1001 , match=(ip4 && tcp), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
> +  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
> @@ -7555,18 +7589,30 @@ 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          ), 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=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=1001 , match=(ip4 && tcp), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
> +  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
> @@ -7580,19 +7626,27 @@ 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=(reg0[[17]] = 1; ct_commit_nat;)
> -  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; reg0[[17]] = 1; 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=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
> +  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(reg0[[17]] == 1), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && !ct.est), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=1001 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=1001 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
> @@ -7606,14 +7660,18 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/
>     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=(ct_commit_nat;)
> -  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_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
> +  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_out_acl_eval    ), priority=1    , match=(ip && !ct.est), action=(next;)
> +  table=??(ls_out_acl_eval    ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
> @@ -7641,18 +7699,30 @@ 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          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), 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_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=1001 , match=(ip4 && tcp), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
> +  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
> @@ -7666,18 +7736,30 @@ 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          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), 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_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=1001 , match=(ip4 && tcp), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
> +  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
> @@ -7691,18 +7773,30 @@ 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          ), 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=(ip4 && tcp), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=1001 , match=(ip4 && tcp), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
> +  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
> @@ -7716,19 +7810,27 @@ 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=(reg0[[17]] = 1; ct_commit_nat;)
> -  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; reg0[[17]] = 1; 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_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
> +  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=1001 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=1001 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(reg0[[17]] == 1), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && !ct.est), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
> @@ -7742,14 +7844,18 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/
>     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=(ct_commit_nat;)
> -  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_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
> +  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_out_acl_eval    ), priority=1    , match=(ip && !ct.est), action=(next;)
> +  table=??(ls_out_acl_eval    ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
> @@ -7777,18 +7883,30 @@ 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          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
> +  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_out_acl_eval    ), priority=1001 , match=(ip4 && tcp), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
> @@ -7802,18 +7920,30 @@ 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          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
> +  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_out_acl_eval    ), priority=1001 , match=(ip4 && tcp), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
> @@ -7827,18 +7957,30 @@ 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          ), 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=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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=1001 , match=(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=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> +  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
> +  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_out_acl_eval    ), priority=1001 , match=(ip4 && tcp), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
> @@ -7852,17 +7994,25 @@ 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=(reg0[[17]] = 1; ct_commit_nat;)
> -  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; reg0[[17]] = 1; 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=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
> +  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(reg0[[17]] == 1), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && !ct.est), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
> @@ -7876,16 +8026,20 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/
>     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=(ct_commit_nat;)
> -  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_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
> +  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_out_acl_eval    ), priority=1    , match=(ip && !ct.est), action=(next;)
> +  table=??(ls_out_acl_eval    ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=1001 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=1001 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
> @@ -8038,6 +8192,8 @@ sort | sed 's/table=../table=??/' ], [0], [dnl
>     table=??(ls_in_check_port_sec), priority=50   , match=(1), action=(reg0[[15]] = check_in_port_sec(); next;)
>     table=??(ls_in_apply_port_sec), priority=0    , match=(1), action=(next;)
>     table=??(ls_in_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
> +  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
> +  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
>     table=??(ls_in_l2_lkup      ), priority=0    , match=(1), action=(outport = get_fdb(eth.dst); next;)
>     table=??(ls_in_l2_lkup      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
>     table=??(ls_in_l2_lkup      ), priority=70   , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
> @@ -8045,8 +8201,6 @@ sort | sed 's/table=../table=??/' ], [0], [dnl
>     table=??(ls_in_l2_unknown   ), priority=50   , match=(outport == "none"), action=(drop;)
>     table=??(ls_out_check_port_sec), priority=0    , match=(1), action=(reg0[[15]] = check_out_port_sec(); next;)
>     table=??(ls_out_check_port_sec), priority=100  , match=(eth.mcast), action=(reg0[[15]] = 0; next;)
> -  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
> -  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
>   ])
>   
>   check ovn-nbctl lsp-add sw0 sw0p1 -- lsp-set-addresses sw0p1 "00:00:00:00:00:01"
> @@ -8063,6 +8217,8 @@ sort | sed 's/table=../table=??/' ], [0], [dnl
>     table=??(ls_in_check_port_sec), priority=50   , match=(1), action=(reg0[[15]] = check_in_port_sec(); next;)
>     table=??(ls_in_apply_port_sec), priority=0    , match=(1), action=(next;)
>     table=??(ls_in_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
> +  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
> +  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
>     table=??(ls_in_l2_lkup      ), priority=0    , match=(1), action=(outport = get_fdb(eth.dst); next;)
>     table=??(ls_in_l2_lkup      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
>     table=??(ls_in_l2_lkup      ), priority=50   , match=(eth.dst == 00:00:00:00:00:01), action=(outport = "sw0p1"; output;)
> @@ -8072,8 +8228,6 @@ sort | sed 's/table=../table=??/' ], [0], [dnl
>     table=??(ls_in_l2_unknown   ), priority=50   , match=(outport == "none"), action=(drop;)
>     table=??(ls_out_check_port_sec), priority=0    , match=(1), action=(reg0[[15]] = check_out_port_sec(); next;)
>     table=??(ls_out_check_port_sec), priority=100  , match=(eth.mcast), action=(reg0[[15]] = 0; next;)
> -  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
> -  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
>   ])
>   
>   check ovn-nbctl lsp-set-port-security sw0p1 "00:00:00:00:00:01 10.0.0.3 1000::3"
> @@ -8089,6 +8243,8 @@ sort | sed 's/table=../table=??/' ], [0], [dnl
>     table=??(ls_in_check_port_sec), priority=50   , match=(1), action=(reg0[[15]] = check_in_port_sec(); next;)
>     table=??(ls_in_apply_port_sec), priority=0    , match=(1), action=(next;)
>     table=??(ls_in_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
> +  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
> +  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
>     table=??(ls_in_l2_lkup      ), priority=0    , match=(1), action=(outport = get_fdb(eth.dst); next;)
>     table=??(ls_in_l2_lkup      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
>     table=??(ls_in_l2_lkup      ), priority=50   , match=(eth.dst == 00:00:00:00:00:01), action=(outport = "sw0p1"; output;)
> @@ -8098,8 +8254,6 @@ sort | sed 's/table=../table=??/' ], [0], [dnl
>     table=??(ls_in_l2_unknown   ), priority=50   , match=(outport == "none"), action=(drop;)
>     table=??(ls_out_check_port_sec), priority=0    , match=(1), action=(reg0[[15]] = check_out_port_sec(); next;)
>     table=??(ls_out_check_port_sec), priority=100  , match=(eth.mcast), action=(reg0[[15]] = 0; next;)
> -  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
> -  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
>   ])
>   
>   # Disable sw0p1
> @@ -8116,6 +8270,8 @@ sort | sed 's/table=../table=??/' ], [0], [dnl
>     table=??(ls_in_check_port_sec), priority=50   , match=(1), action=(reg0[[15]] = check_in_port_sec(); next;)
>     table=??(ls_in_apply_port_sec), priority=0    , match=(1), action=(next;)
>     table=??(ls_in_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
> +  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
> +  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
>     table=??(ls_in_l2_lkup      ), priority=0    , match=(1), action=(outport = get_fdb(eth.dst); next;)
>     table=??(ls_in_l2_lkup      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
>     table=??(ls_in_l2_lkup      ), priority=50   , match=(eth.dst == 00:00:00:00:00:01), action=(drop;)
> @@ -8126,8 +8282,6 @@ sort | sed 's/table=../table=??/' ], [0], [dnl
>     table=??(ls_in_l2_unknown   ), priority=50   , match=(outport == "sw0p1"), action=(drop;)
>     table=??(ls_out_check_port_sec), priority=0    , match=(1), action=(reg0[[15]] = check_out_port_sec(); next;)
>     table=??(ls_out_check_port_sec), priority=100  , match=(eth.mcast), action=(reg0[[15]] = 0; next;)
> -  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
> -  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
>   ])
>   
>   check ovn-nbctl --wait=sb lsp-set-options sw0p2 qdisc_queue_id=10
> @@ -8143,6 +8297,9 @@ sort | sed 's/table=../table=??/' ], [0], [dnl
>     table=??(ls_in_check_port_sec), priority=70   , match=(inport == "sw0p2"), action=(set_queue(10); reg0[[15]] = check_in_port_sec(); next;)
>     table=??(ls_in_apply_port_sec), priority=0    , match=(1), action=(next;)
>     table=??(ls_in_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
> +  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
> +  table=??(ls_out_apply_port_sec), priority=110  , match=(outport == "localnetport" && inport == "sw0p2"), action=(set_queue(10); output;)
> +  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
>     table=??(ls_in_l2_lkup      ), priority=0    , match=(1), action=(outport = get_fdb(eth.dst); next;)
>     table=??(ls_in_l2_lkup      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
>     table=??(ls_in_l2_lkup      ), priority=50   , match=(eth.dst == 00:00:00:00:00:01), action=(drop;)
> @@ -8153,9 +8310,6 @@ sort | sed 's/table=../table=??/' ], [0], [dnl
>     table=??(ls_in_l2_unknown   ), priority=50   , match=(outport == "sw0p1"), action=(drop;)
>     table=??(ls_out_check_port_sec), priority=0    , match=(1), action=(reg0[[15]] = check_out_port_sec(); next;)
>     table=??(ls_out_check_port_sec), priority=100  , match=(eth.mcast), action=(reg0[[15]] = 0; next;)
> -  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
> -  table=??(ls_out_apply_port_sec), priority=110  , match=(outport == "localnetport" && inport == "sw0p2"), action=(set_queue(10); output;)
> -  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
>   ])
>   
>   check ovn-nbctl set logical_switch_port sw0p1 enabled=true
> @@ -8170,10 +8324,14 @@ sort | sed 's/table=../table=??/' ], [0], [dnl
>     table=??(ls_in_check_port_sec), priority=100  , match=(vlan.present), action=(drop;)
>     table=??(ls_in_check_port_sec), priority=50   , match=(1), action=(reg0[[15]] = check_in_port_sec(); next;)
>     table=??(ls_in_check_port_sec), priority=70   , match=(inport == "localnetport"), action=(set_queue(10); reg0[[15]] = check_in_port_sec(); next;)
> -  table=??(ls_in_check_port_sec), priority=70   , match=(inport == "sw0p1"), action=(reg0[[14]] = 1; next(pipeline=ingress, table=16);)
> +  table=??(ls_in_check_port_sec), priority=70   , match=(inport == "sw0p1"), action=(reg0[[14]] = 1; next(pipeline=ingress, table=17);)
>     table=??(ls_in_check_port_sec), priority=70   , match=(inport == "sw0p2"), action=(set_queue(10); reg0[[15]] = check_in_port_sec(); next;)
>     table=??(ls_in_apply_port_sec), priority=0    , match=(1), action=(next;)
>     table=??(ls_in_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
> +  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
> +  table=??(ls_out_apply_port_sec), priority=100  , match=(outport == "localnetport"), action=(set_queue(10); output;)
> +  table=??(ls_out_apply_port_sec), priority=110  , match=(outport == "localnetport" && inport == "sw0p2"), action=(set_queue(10); output;)
> +  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
>     table=??(ls_in_l2_lkup      ), priority=0    , match=(1), action=(outport = get_fdb(eth.dst); next;)
>     table=??(ls_in_l2_lkup      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
>     table=??(ls_in_l2_lkup      ), priority=50   , match=(eth.dst == 00:00:00:00:00:01), action=(outport = "sw0p1"; output;)
> @@ -8183,10 +8341,6 @@ sort | sed 's/table=../table=??/' ], [0], [dnl
>     table=??(ls_in_l2_unknown   ), priority=50   , match=(outport == "none"), action=(drop;)
>     table=??(ls_out_check_port_sec), priority=0    , match=(1), action=(reg0[[15]] = check_out_port_sec(); next;)
>     table=??(ls_out_check_port_sec), priority=100  , match=(eth.mcast), action=(reg0[[15]] = 0; next;)
> -  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
> -  table=??(ls_out_apply_port_sec), priority=100  , match=(outport == "localnetport"), action=(set_queue(10); output;)
> -  table=??(ls_out_apply_port_sec), priority=110  , match=(outport == "localnetport" && inport == "sw0p2"), action=(set_queue(10); output;)
> -  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
>   ])
>   
>   AT_CLEANUP
> @@ -8214,7 +8368,7 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e natted -e ct_lb], [0], [dnl
>     table=7 (lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
>     table=6 (ls_in_pre_stateful ), priority=120  , match=(reg0[[2]] == 1 && ip4.dst == 66.66.66.66), action=(reg1 = 66.66.66.66; ct_lb_mark;)
>     table=6 (ls_in_pre_stateful ), priority=110  , match=(reg0[[2]] == 1), action=(ct_lb_mark;)
> -  table=12(ls_in_lb           ), priority=110  , match=(ct.new && ip4.dst == 66.66.66.66), action=(reg0[[1]] = 0; ct_lb_mark(backends=42.42.42.2);)
> +  table=13(ls_in_lb           ), priority=110  , match=(ct.new && ip4.dst == 66.66.66.66), action=(reg0[[1]] = 0; ct_lb_mark(backends=42.42.42.2);)
>     table=2 (ls_out_pre_stateful), priority=110  , match=(reg0[[2]] == 1), action=(ct_lb_mark;)
>   ])
>   
> @@ -8228,7 +8382,7 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e natted -e ct_lb], [0], [dnl
>     table=7 (lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_label.natted), action=(next;)
>     table=6 (ls_in_pre_stateful ), priority=120  , match=(reg0[[2]] == 1 && ip4.dst == 66.66.66.66), action=(reg1 = 66.66.66.66; ct_lb;)
>     table=6 (ls_in_pre_stateful ), priority=110  , match=(reg0[[2]] == 1), action=(ct_lb;)
> -  table=12(ls_in_lb           ), priority=110  , match=(ct.new && ip4.dst == 66.66.66.66), action=(reg0[[1]] = 0; ct_lb(backends=42.42.42.2);)
> +  table=13(ls_in_lb           ), priority=110  , match=(ct.new && ip4.dst == 66.66.66.66), action=(reg0[[1]] = 0; ct_lb(backends=42.42.42.2);)
>     table=2 (ls_out_pre_stateful), priority=110  , match=(reg0[[2]] == 1), action=(ct_lb;)
>   ])
>   
> @@ -8262,7 +8416,7 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e natted -e ct_lb], [0], [dnl
>     table=7 (lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
>     table=6 (ls_in_pre_stateful ), priority=120  , match=(reg0[[2]] == 1 && ip4.dst == 66.66.66.66), action=(reg1 = 66.66.66.66; ct_lb_mark;)
>     table=6 (ls_in_pre_stateful ), priority=110  , match=(reg0[[2]] == 1), action=(ct_lb_mark;)
> -  table=12(ls_in_lb           ), priority=110  , match=(ct.new && ip4.dst == 66.66.66.66), action=(reg0[[1]] = 0; ct_lb_mark(backends=42.42.42.2);)
> +  table=13(ls_in_lb           ), priority=110  , match=(ct.new && ip4.dst == 66.66.66.66), action=(reg0[[1]] = 0; ct_lb_mark(backends=42.42.42.2);)
>     table=2 (ls_out_pre_stateful), priority=110  , match=(reg0[[2]] == 1), action=(ct_lb_mark;)
>   ])
>   
> @@ -8287,18 +8441,18 @@ AT_CHECK([ovn-sbctl lflow-list | grep 'ls.*acl.*blocked' ], [0], [dnl
>     table=7 (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=7 (ls_in_acl_hint     ), priority=2    , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
>     table=7 (ls_in_acl_hint     ), priority=1    , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
> -  table=8 (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;)
> -  table=8 (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; reg0[[17]] = 1; next;)
> -  table=8 (ls_in_acl          ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
> -  table=8 (ls_in_acl          ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
> +  table=8 (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 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=4    , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
>     table=3 (ls_out_acl_hint    ), priority=2    , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
>     table=3 (ls_out_acl_hint    ), priority=1    , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
> -  table=4 (ls_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(ct_commit_nat;)
> -  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;)
> -  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_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
> +  table=4 (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
>   ])
>   
>   AS_BOX([Chassis registered that doesn't support ct_mark.blocked - use ct_label.blocked])
> @@ -8309,18 +8463,18 @@ AT_CHECK([ovn-sbctl lflow-list | grep 'ls.*acl.*blocked' ], [0], [dnl
>     table=7 (ls_in_acl_hint     ), priority=4    , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
>     table=7 (ls_in_acl_hint     ), priority=2    , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;)
>     table=7 (ls_in_acl_hint     ), priority=1    , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;)
> -  table=8 (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(reg0[[17]] = 1; next;)
> -  table=8 (ls_in_acl          ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; next;)
> -  table=8 (ls_in_acl          ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
> -  table=8 (ls_in_acl          ), priority=1    , match=(ip && ct.est && ct_label.blocked == 1), action=(reg0[[1]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_label.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
>     table=3 (ls_out_acl_hint    ), priority=6    , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
>     table=3 (ls_out_acl_hint    ), priority=4    , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
>     table=3 (ls_out_acl_hint    ), priority=2    , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;)
>     table=3 (ls_out_acl_hint    ), priority=1    , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;)
> -  table=4 (ls_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
> -  table=4 (ls_out_acl         ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;)
> -  table=4 (ls_out_acl         ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
> -  table=4 (ls_out_acl         ), priority=1    , match=(ip && ct.est && ct_label.blocked == 1), action=(reg0[[1]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(reg8[[16]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg8[[16]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=1    , match=(ip && ct.est && ct_label.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
>   ])
>   
>   AS_BOX([Chassis upgrades and supports ct_mark.blocked - use ct_mark.blocked])
> @@ -8331,18 +8485,18 @@ AT_CHECK([ovn-sbctl lflow-list | grep 'ls.*acl.*blocked' ], [0], [dnl
>     table=7 (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=7 (ls_in_acl_hint     ), priority=2    , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
>     table=7 (ls_in_acl_hint     ), priority=1    , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
> -  table=8 (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; next;)
> -  table=8 (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; reg0[[17]] = 1; next;)
> -  table=8 (ls_in_acl          ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
> -  table=8 (ls_in_acl          ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=8 (ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 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=4    , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
>     table=3 (ls_out_acl_hint    ), priority=2    , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
>     table=3 (ls_out_acl_hint    ), priority=1    , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 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;)
> -  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_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=4 (ls_out_acl_eval    ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
>   ])
>   
>   AT_CLEANUP
> @@ -8424,11 +8578,11 @@ ovn-sbctl dump-flows S1 > S1flows
>   AT_CAPTURE_FILE([S0flows])
>   AT_CAPTURE_FILE([S1flows])
>   
> -AT_CHECK([grep "ls_in_lb " S0flows | sort], [0], [dnl
> -  table=12(ls_in_lb           ), priority=0    , match=(1), action=(next;)
> +AT_CHECK([grep "ls_in_lb " S0flows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_lb           ), priority=0    , match=(1), action=(next;)
>   ])
> -AT_CHECK([grep "ls_in_lb " S1flows | sort], [0], [dnl
> -  table=12(ls_in_lb           ), priority=0    , match=(1), action=(next;)
> +AT_CHECK([grep "ls_in_lb " S1flows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_lb           ), priority=0    , match=(1), action=(next;)
>   ])
>   
>   ovn-nbctl --wait=sb set NB_Global . options:install_ls_lb_from_router=true
> @@ -8439,15 +8593,15 @@ ovn-sbctl dump-flows S1 > S1flows
>   AT_CAPTURE_FILE([S0flows])
>   AT_CAPTURE_FILE([S1flows])
>   
> -AT_CHECK([grep "ls_in_lb " S0flows | sort], [0], [dnl
> -  table=12(ls_in_lb           ), priority=0    , match=(1), action=(next;)
> -  table=12(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 172.16.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:80);)
> -  table=12(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 172.16.0.11 && tcp.dst == 8080), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:8080);)
> +AT_CHECK([grep "ls_in_lb " S0flows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_lb           ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 172.16.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:80);)
> +  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 172.16.0.11 && tcp.dst == 8080), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:8080);)
>   ])
> -AT_CHECK([grep "ls_in_lb " S1flows | sort], [0], [dnl
> -  table=12(ls_in_lb           ), priority=0    , match=(1), action=(next;)
> -  table=12(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 172.16.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:80);)
> -  table=12(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 172.16.0.11 && tcp.dst == 8080), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:8080);)
> +AT_CHECK([grep "ls_in_lb " S1flows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_lb           ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 172.16.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:80);)
> +  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 172.16.0.11 && tcp.dst == 8080), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:8080);)
>   ])
>   
>   ovn-sbctl get datapath S0 _uuid > dp_uuids
> @@ -8466,11 +8620,11 @@ ovn-sbctl dump-flows S1 > S1flows
>   AT_CAPTURE_FILE([S0flows])
>   AT_CAPTURE_FILE([S1flows])
>   
> -AT_CHECK([grep "ls_in_lb " S0flows | sort], [0], [dnl
> -  table=12(ls_in_lb           ), priority=0    , match=(1), action=(next;)
> +AT_CHECK([grep "ls_in_lb " S0flows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_lb           ), priority=0    , match=(1), action=(next;)
>   ])
> -AT_CHECK([grep "ls_in_lb " S1flows | sort], [0], [dnl
> -  table=12(ls_in_lb           ), priority=0    , match=(1), action=(next;)
> +AT_CHECK([grep "ls_in_lb " S1flows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_lb           ), priority=0    , match=(1), action=(next;)
>   ])
>   
>   check_column "" sb:load_balancer datapaths name=lb0
> @@ -8550,18 +8704,18 @@ ovn-sbctl dump-flows R1 > R1flows
>   AT_CAPTURE_FILE([S0flows])
>   AT_CAPTURE_FILE([R1flows])
>   
> -AT_CHECK([grep "ls_in_lb_aff_check" S0flows | sort], [0], [dnl
> -  table=11(ls_in_lb_aff_check ), priority=0    , match=(1), action=(next;)
> +AT_CHECK([grep "ls_in_lb_aff_check" S0flows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_lb_aff_check ), priority=0    , match=(1), action=(next;)
>   ])
> -AT_CHECK([grep "ls_in_lb_aff_learn" S0flows | sort], [0], [dnl
> -  table=13(ls_in_lb_aff_learn ), priority=0    , match=(1), action=(next;)
> +AT_CHECK([grep "ls_in_lb_aff_learn" S0flows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_lb_aff_learn ), priority=0    , match=(1), action=(next;)
>   ])
>   
> -AT_CHECK([grep "lr_in_lb_aff_check" R1flows | sort], [0], [dnl
> -  table=6 (lr_in_lb_aff_check ), priority=0    , match=(1), action=(next;)
> +AT_CHECK([grep "lr_in_lb_aff_check" R1flows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(lr_in_lb_aff_check ), priority=0    , match=(1), action=(next;)
>   ])
> -AT_CHECK([grep "lr_in_lb_aff_learn" R1flows | sort], [0], [dnl
> -  table=8 (lr_in_lb_aff_learn ), priority=0    , match=(1), action=(next;)
> +AT_CHECK([grep "lr_in_lb_aff_learn" R1flows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(lr_in_lb_aff_learn ), priority=0    , match=(1), action=(next;)
>   ])
>   
>   ovn-nbctl --wait=sb set load_balancer lb0 options:affinity_timeout=60
> @@ -8570,46 +8724,46 @@ AS_BOX([Test LS flows])
>   ovn-sbctl dump-flows S0 > S0flows
>   AT_CAPTURE_FILE([S0flows])
>   
> -AT_CHECK([grep "ls_in_lb_aff_check" S0flows | sort], [0], [dnl
> -  table=11(ls_in_lb_aff_check ), priority=0    , match=(1), action=(next;)
> -  table=11(ls_in_lb_aff_check ), priority=100  , match=(ct.new && ip4 && reg1 == 172.16.0.10 && reg2[[0..15]] == 80), action=(reg9[[6]] = chk_lb_aff(); next;)
> +AT_CHECK([grep "ls_in_lb_aff_check" S0flows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_lb_aff_check ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_lb_aff_check ), priority=100  , match=(ct.new && ip4 && reg1 == 172.16.0.10 && reg2[[0..15]] == 80), action=(reg9[[6]] = chk_lb_aff(); next;)
>   ])
> -AT_CHECK([grep "ls_in_lb " S0flows | sort], [0], [dnl
> -  table=12(ls_in_lb           ), priority=0    , match=(1), action=(next;)
> -  table=12(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 172.16.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80);)
> -  table=12(ls_in_lb           ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0[[1]] = 0; reg1 = 172.16.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.2:80);)
> -  table=12(ls_in_lb           ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0[[1]] = 0; reg1 = 172.16.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=20.0.0.2:80);)
> +AT_CHECK([grep "ls_in_lb " S0flows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_lb           ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 172.16.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80);)
> +  table=??(ls_in_lb           ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0[[1]] = 0; reg1 = 172.16.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.2:80);)
> +  table=??(ls_in_lb           ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0[[1]] = 0; reg1 = 172.16.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=20.0.0.2:80);)
>   ])
> -AT_CHECK([grep "ls_in_lb_aff_learn" S0flows | sort], [0], [dnl
> -  table=13(ls_in_lb_aff_learn ), priority=0    , match=(1), action=(next;)
> -  table=13(ls_in_lb_aff_learn ), priority=100  , match=(reg9[[6]] == 0 && ct.new && ip4 && reg1 == 172.16.0.10 && reg2[[0..15]] == 80 && ip4.dst == 10.0.0.2 && tcp.dst == 80), action=(commit_lb_aff(vip = "172.16.0.10:80", backend = "10.0.0.2:80", proto = tcp, timeout = 60); /* drop */)
> -  table=13(ls_in_lb_aff_learn ), priority=100  , match=(reg9[[6]] == 0 && ct.new && ip4 && reg1 == 172.16.0.10 && reg2[[0..15]] == 80 && ip4.dst == 20.0.0.2 && tcp.dst == 80), action=(commit_lb_aff(vip = "172.16.0.10:80", backend = "20.0.0.2:80", proto = tcp, timeout = 60); /* drop */)
> +AT_CHECK([grep "ls_in_lb_aff_learn" S0flows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_in_lb_aff_learn ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_lb_aff_learn ), priority=100  , match=(reg9[[6]] == 0 && ct.new && ip4 && reg1 == 172.16.0.10 && reg2[[0..15]] == 80 && ip4.dst == 10.0.0.2 && tcp.dst == 80), action=(commit_lb_aff(vip = "172.16.0.10:80", backend = "10.0.0.2:80", proto = tcp, timeout = 60); /* drop */)
> +  table=??(ls_in_lb_aff_learn ), priority=100  , match=(reg9[[6]] == 0 && ct.new && ip4 && reg1 == 172.16.0.10 && reg2[[0..15]] == 80 && ip4.dst == 20.0.0.2 && tcp.dst == 80), action=(commit_lb_aff(vip = "172.16.0.10:80", backend = "20.0.0.2:80", proto = tcp, timeout = 60); /* drop */)
>   ])
>   
>   AS_BOX([Test LR flows])
>   ovn-sbctl dump-flows R1 > R1flows
>   AT_CAPTURE_FILE([R1flows])
>   
> -AT_CHECK([grep "lr_in_lb_aff_check" R1flows | sort], [0], [dnl
> -  table=6 (lr_in_lb_aff_check ), priority=0    , match=(1), action=(next;)
> -  table=6 (lr_in_lb_aff_check ), priority=100  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(reg0 = ip4.dst; reg9[[16..31]] = tcp.dst; reg9[[6]] = chk_lb_aff(); next;)
> +AT_CHECK([grep "lr_in_lb_aff_check" R1flows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(lr_in_lb_aff_check ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_lb_aff_check ), priority=100  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(reg0 = ip4.dst; reg9[[16..31]] = tcp.dst; reg9[[6]] = chk_lb_aff(); next;)
>   ])
> -AT_CHECK([grep "lr_in_dnat " R1flows | sort], [0], [dnl
> -  table=7 (lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> -  table=7 (lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80);)
> -  table=7 (lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; ct_lb_mark(backends=10.0.0.2:80);)
> -  table=7 (lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; ct_lb_mark(backends=20.0.0.2:80);)
> -  table=7 (lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
> -  table=7 (lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
> -  table=7 (lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
> -  table=7 (lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
> -  table=7 (lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
> -  table=7 (lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
> +AT_CHECK([grep "lr_in_dnat " R1flows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80);)
> +  table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; ct_lb_mark(backends=10.0.0.2:80);)
> +  table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; ct_lb_mark(backends=20.0.0.2:80);)
> +  table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
> +  table=??(lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
> +  table=??(lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
> +  table=??(lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
> +  table=??(lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
> +  table=??(lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
>   ])
> -AT_CHECK([grep "lr_in_lb_aff_learn" R1flows | sort], [0], [dnl
> -  table=8 (lr_in_lb_aff_learn ), priority=0    , match=(1), action=(next;)
> -  table=8 (lr_in_lb_aff_learn ), priority=100  , match=(reg9[[6]] == 0 && ct.new && ip4 && reg0 == 172.16.0.10 && reg9[[16..31]] == 80 && ip4.dst == 10.0.0.2 && tcp.dst == 80), action=(commit_lb_aff(vip = "172.16.0.10:80", backend = "10.0.0.2:80", proto = tcp, timeout = 60); /* drop */)
> -  table=8 (lr_in_lb_aff_learn ), priority=100  , match=(reg9[[6]] == 0 && ct.new && ip4 && reg0 == 172.16.0.10 && reg9[[16..31]] == 80 && ip4.dst == 20.0.0.2 && tcp.dst == 80), action=(commit_lb_aff(vip = "172.16.0.10:80", backend = "20.0.0.2:80", proto = tcp, timeout = 60); /* drop */)
> +AT_CHECK([grep "lr_in_lb_aff_learn" R1flows | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(lr_in_lb_aff_learn ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_lb_aff_learn ), priority=100  , match=(reg9[[6]] == 0 && ct.new && ip4 && reg0 == 172.16.0.10 && reg9[[16..31]] == 80 && ip4.dst == 10.0.0.2 && tcp.dst == 80), action=(commit_lb_aff(vip = "172.16.0.10:80", backend = "10.0.0.2:80", proto = tcp, timeout = 60); /* drop */)
> +  table=??(lr_in_lb_aff_learn ), priority=100  , match=(reg9[[6]] == 0 && ct.new && ip4 && reg0 == 172.16.0.10 && reg9[[16..31]] == 80 && ip4.dst == 20.0.0.2 && tcp.dst == 80), action=(commit_lb_aff(vip = "172.16.0.10:80", backend = "20.0.0.2:80", proto = tcp, timeout = 60); /* drop */)
>   ])
>   
>   AS_BOX([Test LR flows - skip_snat=true])
> @@ -8618,17 +8772,17 @@ check ovn-nbctl --wait=sb set load_balancer lb0 options:skip_snat=true
>   ovn-sbctl dump-flows R1 > R1flows_skip_snat
>   AT_CAPTURE_FILE([R1flows_skip_snat])
>   
> -AT_CHECK([grep "lr_in_dnat " R1flows_skip_snat | sort], [0], [dnl
> -  table=7 (lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> -  table=7 (lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; skip_snat);)
> -  table=7 (lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; skip_snat);)
> -  table=7 (lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; skip_snat);)
> -  table=7 (lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
> -  table=7 (lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
> -  table=7 (lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
> -  table=7 (lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
> -  table=7 (lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
> -  table=7 (lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
> +AT_CHECK([grep "lr_in_dnat " R1flows_skip_snat | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; skip_snat);)
> +  table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; skip_snat);)
> +  table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; skip_snat);)
> +  table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
> +  table=??(lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
> +  table=??(lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
> +  table=??(lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
> +  table=??(lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
> +  table=??(lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
>   ])
>   
>   check ovn-nbctl remove load_balancer lb0 options skip_snat
> @@ -8639,17 +8793,17 @@ check ovn-nbctl --wait=sb set logical_router R1 options:lb_force_snat_ip="172.16
>   ovn-sbctl dump-flows R1 > R1flows_force_snat
>   AT_CAPTURE_FILE([R1flows_force_snat])
>   
> -AT_CHECK([grep "lr_in_dnat " R1flows_force_snat | sort], [0], [dnl
> -  table=7 (lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> -  table=7 (lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; force_snat);)
> -  table=7 (lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; force_snat);)
> -  table=7 (lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.force_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; force_snat);)
> -  table=7 (lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
> -  table=7 (lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
> -  table=7 (lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
> -  table=7 (lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
> -  table=7 (lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
> -  table=7 (lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
> +AT_CHECK([grep "lr_in_dnat " R1flows_force_snat | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
> +  table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; force_snat);)
> +  table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; force_snat);)
> +  table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.force_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; force_snat);)
> +  table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
> +  table=??(lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
> +  table=??(lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
> +  table=??(lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
> +  table=??(lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
> +  table=??(lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
>   ])
>   
>   AT_CLEANUP
> @@ -8811,8 +8965,10 @@ check ovn-nbctl --wait=sb \
>                   -- acl-add S1 from-lport 100 'inport=p1 && ip4' allow-stateless
>   
>   AT_CHECK([ovn-sbctl dump-flows | grep "ls_in_acl" | grep "match=(1)"  | sed 's/table=../table=??/' | sort], [0], [dnl
> -  table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
>     table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
>   ])
>   
> @@ -8824,8 +8980,10 @@ check ovn-nbctl --wait=sb \
>                   -- acl-add S1 from-lport 2 "udp" allow-related
>   
>   AT_CHECK([ovn-sbctl dump-flows | grep "ls_in_acl" | grep "match=(1)"  | sed 's/table=../table=??/' | sort], [0], [dnl
> -  table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
>     table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
>   ])
>   
> @@ -8837,8 +8995,10 @@ check ovn-nbctl --wait=sb \
>       -- ls-lb-add S1 lb
>   
>   AT_CHECK([ovn-sbctl dump-flows | grep "ls_in_acl" | grep "match=(1)"  | sed 's/table=../table=??/' | sort], [0], [dnl
> -  table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
>     table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
>   ])
>   
> @@ -8848,8 +9008,10 @@ check ovn-nbctl --wait=sb \
>                   -- acl-add S1 from-lport 100 'inport=p1 && ip4' allow-stateless
>   
>   AT_CHECK([ovn-sbctl dump-flows | grep "ls_in_acl" | grep "match=(1)"  | sed 's/table=../table=??/' | sort], [0], [dnl
> -  table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
>     table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
>   ])
>   
> @@ -8860,8 +9022,10 @@ check ovn-nbctl --wait=sb \
>                   -- acl-add S1 from-lport 2 "udp" allow-related
>   
>   AT_CHECK([ovn-sbctl dump-flows | grep "ls_in_acl" | grep "match=(1)"  | sed 's/table=../table=??/' | sort], [0], [dnl
> -  table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
> -  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
> +  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
>     table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
>   ])
>   
> @@ -8935,16 +9099,16 @@ AT_CHECK([grep -e "lr_in_defrag" -e "lr_in_dnat" lflows0], [0], [dnl
>   ])
>   
>   AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows0 | grep "priority=65532"], [0], [dnl
> -  table=? (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;)
> -  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; reg0[[17]] = 1; 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_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(ct_commit_nat;)
> -  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_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  table=?(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=?(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=?(ls_in_acl_after_lb_eval), priority=65532, match=(reg0[[17]] == 1), action=(reg8[[16]] = 1; next;)
>   ])
>   
>   
> @@ -8984,16 +9148,16 @@ AT_CHECK([ovn-sbctl lflow-list | grep lr_in_dnat], [0], [dnl
>   check ovn-nbctl remove load_balancer lb-test options skip_snat
>   
>   AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows1 | grep "priority=65532"], [0], [dnl
> -  table=? (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(reg0[[17]] = 1; next;)
> -  table=? (ls_in_acl          ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; next;)
> -  table=? (ls_in_acl          ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
> -  table=? (ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  table=? (ls_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
> -  table=? (ls_out_acl         ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;)
> -  table=? (ls_out_acl         ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
> -  table=? (ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  table=?(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  table=?(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; next;)
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(reg8[[16]] = 1; next;)
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg8[[16]] = 1; next;)
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=?(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=?(ls_in_acl_after_lb_eval), priority=65532, match=(reg0[[17]] == 1), action=(reg8[[16]] = 1; next;)
>   ])
>   
>   AS_BOX([Chassis upgrades and supports CT related])
> @@ -9016,16 +9180,16 @@ AT_CHECK([grep -e "lr_in_defrag" -e "lr_in_dnat" lflows2], [0], [dnl
>   ])
>   
>   AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows2 | grep "priority=65532"], [0], [dnl
> -  table=? (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;)
> -  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; reg0[[17]] = 1; 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_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(ct_commit_nat;)
> -  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_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
> -  table=?(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=? (ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
> +  table=? (ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=?(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
> +  table=?(ls_in_acl_after_lb_eval), priority=65532, match=(reg0[[17]] == 1), action=(reg8[[16]] = 1; next;)
>   ])
>   
>   AT_CLEANUP
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 161fb000a..9e6e8a14a 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -13308,15 +13308,20 @@ grep active_backup | grep members:$hv2_gw1_ofport,$hv2_gw2_ofport \
>   ])
>   
>   # make sure that flows for handling the outside router port reside on gw1 through ls_in_l2_lkup table
> -OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \
> +
> +sleep 10
> +
> +as gw1 ovs-ofctl dump-flows br-int
> +
> +OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=35 | \
>   grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1
>   ]])
> -OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \
> +OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=35 | \
>   grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[0
>   ]])
>   
>   # make sure ARP responder flows for outside router port reside on gw1 too through ls_in_arp_rsp table
> -OVS_WAIT_UNTIL([test `as gw1 ovs-ofctl dump-flows br-int table=27 | \
> +OVS_WAIT_UNTIL([test `as gw1 ovs-ofctl dump-flows br-int table=29 | \
>   grep arp_tpa=192.168.0.101 | wc -l` -ge 1])
>   
>   # check that the chassis redirect port has been claimed by the gw1 chassis
> @@ -13398,10 +13403,10 @@ AT_CHECK([ovs-vsctl --bare --columns bfd find Interface name=ovn-hv1-0],[0],
>   ]])
>   
>   # make sure that flows for handling the outside router port reside on gw2 now
> -OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \
> +OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=35 | \
>   grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1
>   ]])
> -OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \
> +OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=35 | \
>   grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[0
>   ]])
>   
> @@ -13413,10 +13418,10 @@ as main ovs-vsctl del-port n1 $port
>   bfd_dump
>   
>   # make sure that flows for handling the outside router port reside on gw1 now
> -OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \
> +OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=35 | \
>   grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1
>   ]])
> -OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \
> +OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=35 | \
>   grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[0
>   ]])
>   
> @@ -13530,15 +13535,15 @@ grep active_backup | grep members:$hv2_gw1_ofport,$hv2_gw2_ofport \
>   ])
>   
>   # make sure that flows for handling the outside router port reside on gw1
> -OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \
> +OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=35 | \
>   grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1
>   ]])
> -OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \
> +OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=35 | \
>   grep "dl_dst:00:00:02:01:02:04" | wc -l], [0], [[0
>   ]])
>   
>   # make sure ARP responder flows for outside router port reside on gw1 too
> -OVS_WAIT_UNTIL([test `as gw1 ovs-ofctl dump-flows br-int table=27 | \
> +OVS_WAIT_UNTIL([test `as gw1 ovs-ofctl dump-flows br-int table=29 | \
>   grep arp_tpa=192.168.0.101 | wc -l` -ge 1 ])
>   
>   # check that the chassis redirect port has been claimed by the gw1 chassis
> @@ -13602,10 +13607,10 @@ AT_CHECK([ovs-vsctl --bare --columns bfd find Interface name=ovn-hv1-0],[0],
>   ]])
>   
>   # make sure that flows for handling the outside router port reside on gw2 now
> -OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \
> +OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=35 | \
>   grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1
>   ]])
> -OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \
> +OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=35 | \
>   grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[0
>   ]])
>   
> @@ -13617,10 +13622,10 @@ as main ovs-vsctl del-port n1 $port
>   bfd_dump
>   
>   # make sure that flows for handling the outside router port reside on gw2 now
> -OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \
> +OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=35 | \
>   grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1
>   ]])
> -OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \
> +OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=35 | \
>   grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[0
>   ]])
>   
> @@ -16400,8 +16405,8 @@ ovn-nbctl --wait=hv sync
>   ovn-sbctl dump-flows sw0 > sw0-flows
>   AT_CAPTURE_FILE([sw0-flows])
>   
> -AT_CHECK([grep -E 'ls_(in|out)_acl' sw0-flows |grep reject| sed 's/table=../table=??/' | sort], [0], [dnl
> -  table=??(ls_out_acl         ), priority=2002 , match=(ip), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
> +AT_CHECK([grep -E 'ls_out_acl' sw0-flows | grep reject | sed 's/table=../table=??/' | sort], [0], [dnl
> +  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
>   ])
>   
>   
> @@ -18099,15 +18104,15 @@ check ovn-nbctl acl-add ls1 to-lport 3 'ip4.src==10.0.0.1' allow
>   check ovn-nbctl --wait=hv sync
>   
>   # Check OVS flows, the less restrictive flows should have been installed.
> -AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=44 | ofctl_strip_all | \
> +AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=44 | ofctl_strip_all |
>       grep "priority=1003" | \
>       sed 's/conjunction([[^)]]*)/conjunction()/g' | \
>       sed 's/conj_id=[[0-9]]*,/conj_id=xxx,/g' | sort], [0], [dnl
> - table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
> - table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
> + table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
> + table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
>    table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.3 actions=conjunction(),conjunction()
>    table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.4 actions=conjunction(),conjunction()
> - table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=resubmit(,45)
> + table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
>    table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.2 actions=conjunction()
>    table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.42 actions=conjunction()
>   ])
> @@ -18148,11 +18153,11 @@ AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=44 | ofctl_strip_all | \
>       grep "priority=1003" | \
>       sed 's/conjunction([[^)]]*)/conjunction()/g' | \
>       sed 's/conj_id=[[0-9]]*,/conj_id=xxx,/g' | sort], [0], [dnl
> - table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
> - table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
> + table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
> + table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
>    table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.3 actions=conjunction(),conjunction()
>    table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.4 actions=conjunction(),conjunction()
> - table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=resubmit(,45)
> + table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
>    table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.2 actions=conjunction()
>    table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.42 actions=conjunction()
>   ])
> @@ -18166,8 +18171,8 @@ AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=44 | ofctl_strip_all | \
>       grep "priority=1003" | \
>       sed 's/conjunction([[^)]]*)/conjunction()/g' | \
>       sed 's/conj_id=[[0-9]]*,/conj_id=xxx,/g' | sort], [0], [dnl
> - table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
> - table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
> + table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
> + table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
>    table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.3 actions=conjunction(),conjunction()
>    table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.4 actions=conjunction(),conjunction()
>    table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=conjunction(),conjunction()
> @@ -18206,11 +18211,11 @@ AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=44 | ofctl_strip_all | \
>      grep "priority=1003" | \
>      sed 's/conjunction([[^)]]*)/conjunction()/g' | \
>      sed 's/conj_id=[[0-9]]*,/conj_id=xxx,/g' | sort], [0], [dnl
> - table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
> - table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
> + table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
> + table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
>    table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.3 actions=conjunction(),conjunction()
>    table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.4 actions=conjunction(),conjunction()
> - table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=resubmit(,45)
> + table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
>    table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.2 actions=conjunction()
>    table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.42 actions=conjunction()
>   ])
> @@ -18227,16 +18232,16 @@ AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=44 | ofctl_strip_all | \
>      grep "priority=1003" | \
>      sed 's/conjunction([[^)]]*)/conjunction()/g' | \
>      sed 's/conj_id=[[0-9]]*,/conj_id=xxx,/g' | sort], [0], [dnl
> - table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
> - table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
> - table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
> + table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
> + table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
> + table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
>    table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.3 actions=conjunction(),conjunction(),conjunction()
>    table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.4 actions=conjunction(),conjunction(),conjunction()
> - table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=resubmit(,45)
> + table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
>    table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.2 actions=conjunction(),conjunction()
>    table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.42 actions=conjunction()
> - table=44, priority=1003,udp,metadata=0x1 actions=resubmit(,45)
> - table=44, priority=1003,udp6,metadata=0x1 actions=resubmit(,45)
> + table=44, priority=1003,udp,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
> + table=44, priority=1003,udp6,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
>   ])
>   
>   OVN_CLEANUP([hv1])
> @@ -19642,7 +19647,7 @@ wait_for_ports_up ls1-lp_ext1
>   # There should be a flow in hv2 to drop traffic from ls1-lp_ext1 destined
>   # to router mac.
>   AT_CHECK([as hv2 ovs-ofctl dump-flows br-int \
> -table=32,dl_src=f0:00:00:00:00:03,dl_dst=a0:10:00:00:00:01 | \
> +table=34,dl_src=f0:00:00:00:00:03,dl_dst=a0:10:00:00:00:01 | \
>   grep -c "actions=drop"], [0], [1
>   ])
>   # Stop ovn-controllers on hv1 and hv3.
> @@ -21265,7 +21270,7 @@ check_virtual_offlows_present() {
>       lr0_public_dp_key=$(printf "%x" $(fetch_column Port_Binding tunnel_key logical_port=lr0-public))
>   
>       AT_CHECK_UNQUOTED([as $hv ovs-ofctl dump-flows br-int table=44,ip | ofctl_strip_all | grep "priority=2000"], [0], [dnl
> - table=44, priority=2000,ip,metadata=0x$sw0_dp_key actions=resubmit(,45)
> + table=44, priority=2000,ip,metadata=0x$sw0_dp_key actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
>   ])
>   
>       AT_CHECK_UNQUOTED([as $hv ovs-ofctl dump-flows br-int table=11 | ofctl_strip_all | \
> @@ -21303,7 +21308,7 @@ check_row_count Port_Binding 1 logical_port=sw0-vir virtual_parent=sw0-p1
>   wait_for_ports_up sw0-vir
>   check ovn-nbctl --wait=hv sync
>   AT_CHECK([test 2 = `cat hv1/ovn-controller.log | grep "pinctrl received  packet-in" | \
> -grep opcode=BIND_VPORT | grep OF_Table_ID=27 | wc -l`])
> +grep opcode=BIND_VPORT | grep OF_Table_ID=29 | wc -l`])
>   
>   wait_row_count Port_Binding 1 logical_port=sw0-vir6 chassis=$hv1_ch_uuid
>   check_row_count Port_Binding 1 logical_port=sw0-vir6 virtual_parent=sw0-p1
> @@ -28642,7 +28647,11 @@ check ovn-nbctl acl-add ls1 from-lport 1 '1' drop
>   check ovn-nbctl --wait=hv sync
>   
>   AT_CHECK([test "$expr_cnt" = "$(get_cache_count cache-expr)"], [0], [])
> -AT_CHECK([test "$(($matches_cnt + 1))" = "$(get_cache_count cache-matches)"], [0], [])
> +# Changing from having no ACLs to having ACLs adds 9 logical flows, 3 in each
> +# of ls_in_acl_action, ls_in_acl_after_lb_action, and ls_out_acl_action, plus the
> +# logical flow representing the ACL itself. This is where the 10 comes from in
> +# the calculation below.
> +AT_CHECK([test "$(($matches_cnt + 10))" = "$(get_cache_count cache-matches)"], [0], [])
>   
>   AS_BOX([Check expr caching for is_chassis_resident() matches])
>   expr_cnt=$(get_cache_count cache-expr)
> @@ -32009,9 +32018,10 @@ check ovn-nbctl --wait=hv sync
>   dp_key=$(fetch_column Datapath_Binding tunnel_key external_ids:name=ls)
>   rtr_port_key=$(fetch_column Port_Binding tunnel_key logical_port=ls_lr)
>   
> +ovs-ofctl dump-flows br-int table=16 | grep "reg14=0x${rtr_port_key},metadata=0x${dp_key},nw_dst=42.42.42.42 actions=load:0x1->OXM_OF_PKT_REG4[49],resubmit(,17)"
>   # Check that ovn-controller adds a flow to drop packets with dest IP
>   # 42.42.42.42 coming from the router port.
> -AT_CHECK([ovs-ofctl dump-flows br-int table=16 | grep "reg14=0x${rtr_port_key},metadata=0x${dp_key},nw_dst=42.42.42.42 actions=drop" -c], [0], [dnl
> +AT_CHECK([ovs-ofctl dump-flows br-int table=16 | grep "reg14=0x${rtr_port_key},metadata=0x${dp_key},nw_dst=42.42.42.42 actions=load:0x1->OXM_OF_PKT_REG4\[\[49\]\],resubmit(,17)" -c], [0], [dnl
>   1
>   ])
>   
> @@ -32767,15 +32777,15 @@ done
>   check ovn-nbctl --wait=hv sync
>   
>   # hv0 should see flows for lsp1 but not lsp2
> -AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=27 | grep 10.0.1.2], [0], [ignore])
> -AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=27 | grep 10.0.2.2], [1])
> +AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=29 | grep 10.0.1.2], [0], [ignore])
> +AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=29 | grep 10.0.2.2], [1])
>   # hv2 should see flows for lsp2 but not lsp1
> -AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=27 | grep 10.0.2.2], [0], [ignore])
> -AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=27 | grep 10.0.1.2], [1])
> +AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=29 | grep 10.0.2.2], [0], [ignore])
> +AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=29 | grep 10.0.1.2], [1])
>   
>   # Change lrp_lr_ls1 to a regular lrp, hv2 should see flows for lsp1
>   check ovn-nbctl --wait=hv lrp-del-gateway-chassis lrp_lr_ls1 hv1
> -AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=27 | grep 10.0.1.2], [0], [ignore])
> +AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=29 | grep 10.0.1.2], [0], [ignore])
>   
>   # Change it back, and trigger recompute to make sure extra flows are removed
>   # from hv2 (recompute is needed because currently I-P adds local datapaths but
> @@ -32783,11 +32793,11 @@ AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=27 | grep 10.0.1.2], [0], [ig
>   check ovn-nbctl --wait=hv lrp-set-gateway-chassis lrp_lr_ls1 hv1 1
>   as hv2 check ovn-appctl -t ovn-controller recompute
>   ovn-nbctl --wait=hv sync
> -AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=27 | grep 10.0.1.2], [1])
> +AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=29 | grep 10.0.1.2], [1])
>   
>   # Enable dnat_and_snat on lr, and now hv2 should see flows for lsp1.
>   AT_CHECK([ovn-nbctl --wait=hv --gateway-port=lrp_lr_ls1 lr-nat-add lr dnat_and_snat 192.168.0.1 10.0.1.3 lsp1 f0:00:00:00:00:03])
> -AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=27 | grep 10.0.1.2], [0], [ignore])
> +AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=29 | grep 10.0.1.2], [0], [ignore])
>   
>   OVN_CLEANUP([hv1],[hv2])
>   AT_CLEANUP
> @@ -34804,14 +34814,14 @@ lsp2=0x$(fetch_column Port_Binding tunnel_key logical_port=lsp2)
>   dnl Ensure the ACL is translated to OpenFlows expanding pg1.
>   as hv1
>   AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int | grep '42\.42\.42\.42' | ofctl_strip_all], [0], [dnl
> - table=16, priority=1001,ip,reg14=$lsp1,metadata=0x1,nw_src=42.42.42.42 actions=resubmit(,17)
> - table=16, priority=1001,ip,reg14=$lsp2,metadata=0x1,nw_src=42.42.42.42 actions=resubmit(,17)
> + table=16, priority=1001,ip,reg14=$lsp1,metadata=0x1,nw_src=42.42.42.42 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,17)
> + table=16, priority=1001,ip,reg14=$lsp2,metadata=0x1,nw_src=42.42.42.42 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,17)
>   ])
>   
>   dnl Remove a port from pg1 and expect OpenFlows to be correctly updated.
>   check ovn-nbctl --wait=hv pg-set-ports pg1 lsp2
>   AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int | grep '42\.42\.42\.42' | ofctl_strip_all], [0], [dnl
> - table=16, priority=1001,ip,reg14=$lsp2,metadata=0x1,nw_src=42.42.42.42 actions=resubmit(,17)
> + table=16, priority=1001,ip,reg14=$lsp2,metadata=0x1,nw_src=42.42.42.42 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,17)
>   ])
>   
>   dnl Change the Chassis_Template_Var mapping to use the address set.
> @@ -34820,14 +34830,14 @@ check ovn-nbctl --wait=hv set Chassis_Template_Var hv1 variables:CONDITION='ip4.
>   dnl Ensure the ACL is translated to OpenFlows expanding as1.
>   as hv1
>   AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int | grep '42\.42\.42\.42' | ofctl_strip_all], [0], [dnl
> - table=16, priority=1001,ip,metadata=0x1,nw_src=42.42.42.42,nw_dst=1.1.1.1 actions=resubmit(,17)
> - table=16, priority=1001,ip,metadata=0x1,nw_src=42.42.42.42,nw_dst=1.1.1.2 actions=resubmit(,17)
> + table=16, priority=1001,ip,metadata=0x1,nw_src=42.42.42.42,nw_dst=1.1.1.1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,17)
> + table=16, priority=1001,ip,metadata=0x1,nw_src=42.42.42.42,nw_dst=1.1.1.2 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,17)
>   ])
>   
>   dnl Remove an IP from AS1 and expect OpenFlows to be correctly updated.
>   check ovn-nbctl set address_set as1 addresses=\"1.1.1.1\"
>   AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int | grep '42\.42\.42\.42' | ofctl_strip_all], [0], [dnl
> - table=16, priority=1001,ip,metadata=0x1,nw_src=42.42.42.42,nw_dst=1.1.1.1 actions=resubmit(,17)
> + table=16, priority=1001,ip,metadata=0x1,nw_src=42.42.42.42,nw_dst=1.1.1.1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,17)
>   ])
>   
>   dnl Remove the mapping and expect OpenFlows to be removed.
> diff --git a/tests/system-ovn.at b/tests/system-ovn.at
> index 8fe8e4d28..5ee044e19 100644
> --- a/tests/system-ovn.at
> +++ b/tests/system-ovn.at
> @@ -8686,7 +8686,7 @@ ovn-sbctl list ip_multicast
>   
>   wait_igmp_flows_installed()
>   {
> -    OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int table=33 | \
> +    OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int table=35 | \
>       grep 'priority=90' | grep "nw_dst=$1"])
>   }
>
0-day Robot May 18, 2023, 6:57 p.m. UTC | #2
Bleep bloop.  Greetings Mark Michelson, I am a robot and I have tried out your patch.
Thanks for your contribution.

I encountered some error that I wasn't expecting.  See the details below.


git-am:
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
Patch failed at 0001 northd: Break ACLs into two stages.
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".


Please check this out.  If you feel there has been an error, please email aconole@redhat.com

Thanks,
0-day Robot
diff mbox series

Patch

diff --git a/northd/northd.c b/northd/northd.c
index 2f96d15a4..c7969e0ba 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -122,37 +122,42 @@  enum ovn_stage {
     PIPELINE_STAGE(SWITCH, IN,  PRE_LB,         5, "ls_in_pre_lb")        \
     PIPELINE_STAGE(SWITCH, IN,  PRE_STATEFUL,   6, "ls_in_pre_stateful")  \
     PIPELINE_STAGE(SWITCH, IN,  ACL_HINT,       7, "ls_in_acl_hint")      \
-    PIPELINE_STAGE(SWITCH, IN,  ACL,            8, "ls_in_acl")           \
-    PIPELINE_STAGE(SWITCH, IN,  QOS_MARK,       9, "ls_in_qos_mark")      \
-    PIPELINE_STAGE(SWITCH, IN,  QOS_METER,     10, "ls_in_qos_meter")     \
-    PIPELINE_STAGE(SWITCH, IN,  LB_AFF_CHECK,  11, "ls_in_lb_aff_check")  \
-    PIPELINE_STAGE(SWITCH, IN,  LB,            12, "ls_in_lb")            \
-    PIPELINE_STAGE(SWITCH, IN,  LB_AFF_LEARN,  13, "ls_in_lb_aff_learn")  \
-    PIPELINE_STAGE(SWITCH, IN,  PRE_HAIRPIN,   14, "ls_in_pre_hairpin")   \
-    PIPELINE_STAGE(SWITCH, IN,  NAT_HAIRPIN,   15, "ls_in_nat_hairpin")   \
-    PIPELINE_STAGE(SWITCH, IN,  HAIRPIN,       16, "ls_in_hairpin")       \
-    PIPELINE_STAGE(SWITCH, IN,  ACL_AFTER_LB,  17, "ls_in_acl_after_lb")  \
-    PIPELINE_STAGE(SWITCH, IN,  STATEFUL,      18, "ls_in_stateful")      \
-    PIPELINE_STAGE(SWITCH, IN,  ARP_ND_RSP,    19, "ls_in_arp_rsp")       \
-    PIPELINE_STAGE(SWITCH, IN,  DHCP_OPTIONS,  20, "ls_in_dhcp_options")  \
-    PIPELINE_STAGE(SWITCH, IN,  DHCP_RESPONSE, 21, "ls_in_dhcp_response") \
-    PIPELINE_STAGE(SWITCH, IN,  DNS_LOOKUP,    22, "ls_in_dns_lookup")    \
-    PIPELINE_STAGE(SWITCH, IN,  DNS_RESPONSE,  23, "ls_in_dns_response")  \
-    PIPELINE_STAGE(SWITCH, IN,  EXTERNAL_PORT, 24, "ls_in_external_port") \
-    PIPELINE_STAGE(SWITCH, IN,  L2_LKUP,       25, "ls_in_l2_lkup")       \
-    PIPELINE_STAGE(SWITCH, IN,  L2_UNKNOWN,    26, "ls_in_l2_unknown")    \
+    PIPELINE_STAGE(SWITCH, IN,  ACL_EVAL,       8, "ls_in_acl_eval")      \
+    PIPELINE_STAGE(SWITCH, IN,  ACL_ACTION,     9, "ls_in_acl_action")    \
+    PIPELINE_STAGE(SWITCH, IN,  QOS_MARK,      10, "ls_in_qos_mark")      \
+    PIPELINE_STAGE(SWITCH, IN,  QOS_METER,     11, "ls_in_qos_meter")     \
+    PIPELINE_STAGE(SWITCH, IN,  LB_AFF_CHECK,  12, "ls_in_lb_aff_check")  \
+    PIPELINE_STAGE(SWITCH, IN,  LB,            13, "ls_in_lb")            \
+    PIPELINE_STAGE(SWITCH, IN,  LB_AFF_LEARN,  14, "ls_in_lb_aff_learn")  \
+    PIPELINE_STAGE(SWITCH, IN,  PRE_HAIRPIN,   15, "ls_in_pre_hairpin")   \
+    PIPELINE_STAGE(SWITCH, IN,  NAT_HAIRPIN,   16, "ls_in_nat_hairpin")   \
+    PIPELINE_STAGE(SWITCH, IN,  HAIRPIN,       17, "ls_in_hairpin")       \
+    PIPELINE_STAGE(SWITCH, IN,  ACL_AFTER_LB_EVAL,  18, \
+                   "ls_in_acl_after_lb_eval")  \
+    PIPELINE_STAGE(SWITCH, IN,  ACL_AFTER_LB_ACTION,  19, \
+                   "ls_in_acl_after_lb_action")  \
+    PIPELINE_STAGE(SWITCH, IN,  STATEFUL,      20, "ls_in_stateful")      \
+    PIPELINE_STAGE(SWITCH, IN,  ARP_ND_RSP,    21, "ls_in_arp_rsp")       \
+    PIPELINE_STAGE(SWITCH, IN,  DHCP_OPTIONS,  22, "ls_in_dhcp_options")  \
+    PIPELINE_STAGE(SWITCH, IN,  DHCP_RESPONSE, 23, "ls_in_dhcp_response") \
+    PIPELINE_STAGE(SWITCH, IN,  DNS_LOOKUP,    24, "ls_in_dns_lookup")    \
+    PIPELINE_STAGE(SWITCH, IN,  DNS_RESPONSE,  25, "ls_in_dns_response")  \
+    PIPELINE_STAGE(SWITCH, IN,  EXTERNAL_PORT, 26, "ls_in_external_port") \
+    PIPELINE_STAGE(SWITCH, IN,  L2_LKUP,       27, "ls_in_l2_lkup")       \
+    PIPELINE_STAGE(SWITCH, IN,  L2_UNKNOWN,    28, "ls_in_l2_unknown")    \
                                                                           \
     /* Logical switch egress stages. */                                   \
     PIPELINE_STAGE(SWITCH, OUT, PRE_ACL,      0, "ls_out_pre_acl")        \
     PIPELINE_STAGE(SWITCH, OUT, PRE_LB,       1, "ls_out_pre_lb")         \
     PIPELINE_STAGE(SWITCH, OUT, PRE_STATEFUL, 2, "ls_out_pre_stateful")   \
     PIPELINE_STAGE(SWITCH, OUT, ACL_HINT,     3, "ls_out_acl_hint")       \
-    PIPELINE_STAGE(SWITCH, OUT, ACL,          4, "ls_out_acl")            \
-    PIPELINE_STAGE(SWITCH, OUT, QOS_MARK,     5, "ls_out_qos_mark")       \
-    PIPELINE_STAGE(SWITCH, OUT, QOS_METER,    6, "ls_out_qos_meter")      \
-    PIPELINE_STAGE(SWITCH, OUT, STATEFUL,     7, "ls_out_stateful")       \
-    PIPELINE_STAGE(SWITCH, OUT, CHECK_PORT_SEC,  8, "ls_out_check_port_sec") \
-    PIPELINE_STAGE(SWITCH, OUT, APPLY_PORT_SEC,  9, "ls_out_apply_port_sec") \
+    PIPELINE_STAGE(SWITCH, OUT, ACL_EVAL,     4, "ls_out_acl_eval")       \
+    PIPELINE_STAGE(SWITCH, OUT, ACL_ACTION,   5, "ls_out_acl_action")     \
+    PIPELINE_STAGE(SWITCH, OUT, QOS_MARK,     6, "ls_out_qos_mark")       \
+    PIPELINE_STAGE(SWITCH, OUT, QOS_METER,    7, "ls_out_qos_meter")      \
+    PIPELINE_STAGE(SWITCH, OUT, STATEFUL,     8, "ls_out_stateful")       \
+    PIPELINE_STAGE(SWITCH, OUT, CHECK_PORT_SEC,  9, "ls_out_check_port_sec") \
+    PIPELINE_STAGE(SWITCH, OUT, APPLY_PORT_SEC, 10, "ls_out_apply_port_sec") \
                                                                       \
     /* Logical router ingress stages. */                              \
     PIPELINE_STAGE(ROUTER, IN,  ADMISSION,       0, "lr_in_admission")    \
@@ -236,6 +241,11 @@  enum ovn_stage {
 #define REG_LB_AFF_BACKEND_IP4  "reg4"
 #define REG_LB_AFF_MATCH_PORT   "reg8[0..15]"
 
+/* Registers for ACL evaluation */
+#define REGBIT_ACL_VERDICT_ALLOW "reg8[16]"
+#define REGBIT_ACL_VERDICT_DROP "reg8[17]"
+#define REGBIT_ACL_VERDICT_REJECT "reg8[18]"
+
 /* Indicate that this packet has been recirculated using egress
  * loopback.  This allows certain checks to be bypassed, such as a
  * logical router dropping packets with source IP address equals
@@ -6364,54 +6374,11 @@  build_acl_log(struct ds *actions, const struct nbrec_acl *acl,
     ds_put_cstr(actions, "); ");
 }
 
-static void
-build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows,
-                       enum ovn_stage stage, struct nbrec_acl *acl,
-                       struct ds *extra_match, struct ds *extra_actions,
-                       const struct ovsdb_idl_row *stage_hint,
-                       const struct shash *meter_groups)
-{
-    struct ds match = DS_EMPTY_INITIALIZER;
-    struct ds actions = DS_EMPTY_INITIALIZER;
-    bool ingress = (ovn_stage_get_pipeline(stage) == P_IN);
-
-    char *next_action =
-        xasprintf("next(pipeline=%s,table=%d);",
-                  ingress ? "egress": "ingress",
-                  ingress ? ovn_stage_get_table(S_SWITCH_OUT_QOS_MARK)
-                          : ovn_stage_get_table(S_SWITCH_IN_L2_LKUP));
-
-    build_acl_log(&actions, acl, meter_groups);
-    if (extra_match->length > 0) {
-        ds_put_format(&match, "(%s) && ", extra_match->string);
-    }
-    ds_put_cstr(&match, acl->match);
-
-    if (extra_actions->length > 0) {
-        ds_put_format(&actions, "%s ", extra_actions->string);
-    }
-
-    ds_put_format(&actions, "reg0 = 0; "
-                  "reject { "
-                  "/* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ "
-                  "outport <-> inport; %s };", next_action);
-    ovn_lflow_add_with_hint__(lflows, od, stage,
-                              acl->priority + OVN_ACL_PRI_OFFSET,
-                              ds_cstr(&match), ds_cstr(&actions), NULL,
-                              copp_meter_get(COPP_REJECT, od->nbs->copp,
-                                             meter_groups),
-                              stage_hint);
-
-    free(next_action);
-    ds_destroy(&match);
-    ds_destroy(&actions);
-}
-
 static void
 consider_acl(struct hmap *lflows, struct ovn_datapath *od,
-             struct nbrec_acl *acl, bool has_stateful, bool ct_masked_mark,
-             const struct shash *meter_groups, struct ds *match,
-             struct ds *actions)
+             const struct nbrec_acl *acl, bool has_stateful,
+             bool ct_masked_mark, const struct shash *meter_groups,
+             struct ds *match, struct ds *actions)
 {
     const char *ct_blocked_match = ct_masked_mark
                                    ? "ct_mark.blocked"
@@ -6420,210 +6387,131 @@  consider_acl(struct hmap *lflows, struct ovn_datapath *od,
     enum ovn_stage stage;
 
     if (ingress && smap_get_bool(&acl->options, "apply-after-lb", false)) {
-        stage = S_SWITCH_IN_ACL_AFTER_LB;
+        stage = S_SWITCH_IN_ACL_AFTER_LB_EVAL;
     } else if (ingress) {
-        stage = S_SWITCH_IN_ACL;
+        stage = S_SWITCH_IN_ACL_EVAL;
     } else {
-        stage = S_SWITCH_OUT_ACL;
+        stage = S_SWITCH_OUT_ACL_EVAL;
     }
 
-    if (!strcmp(acl->action, "allow-stateless")) {
-        ds_clear(actions);
-        build_acl_log(actions, acl, meter_groups);
+    const char *verdict;
+    if (!strcmp(acl->action, "drop")) {
+        verdict = REGBIT_ACL_VERDICT_DROP " = 1; ";
+    } else if (!strcmp(acl->action, "reject")) {
+        verdict = REGBIT_ACL_VERDICT_REJECT " = 1; ";
+    } else {
+        verdict = REGBIT_ACL_VERDICT_ALLOW " = 1; ";
+    }
+
+    ds_clear(actions);
+    /* All ACLs will have the same actions as a basis. */
+    build_acl_log(actions, acl, meter_groups);
+    ds_put_cstr(actions, verdict);
+    size_t log_verdict_len = actions->length;
+    uint16_t priority = acl->priority + OVN_ACL_PRI_OFFSET;
+
+    if (!has_stateful || !strcmp(acl->action, "allow-stateless")) {
         ds_put_cstr(actions, "next;");
-        ovn_lflow_add_with_hint(lflows, od, stage,
-                                acl->priority + OVN_ACL_PRI_OFFSET,
+        ovn_lflow_add_with_hint(lflows, od, stage, priority,
                                 acl->match, ds_cstr(actions),
                                 &acl->header_);
-    } else if (!strcmp(acl->action, "allow")
+        return;
+    }
+
+    if (!strcmp(acl->action, "allow")
         || !strcmp(acl->action, "allow-related")) {
         /* If there are any stateful flows, we must even commit "allow"
          * actions.  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". */
-        if (!has_stateful) {
-            ds_clear(actions);
-            build_acl_log(actions, acl, meter_groups);
-            ds_put_cstr(actions, "next;");
-            ovn_lflow_add_with_hint(lflows, od, stage,
-                                    acl->priority + OVN_ACL_PRI_OFFSET,
-                                    acl->match, ds_cstr(actions),
-                                    &acl->header_);
-        } else {
-            /* Commit the connection tracking entry if it's a new
-             * connection that matches this ACL.  After this commit,
-             * the reply traffic is allowed by a flow we create at
-             * priority 65535, defined earlier.
-             *
-             * It's also possible that a known connection was marked for
-             * deletion after a policy was deleted, but the policy was
-             * re-added while that connection is still known.  We catch
-             * that case here and un-set ct_mark.blocked (which will be done
-             * by ct_commit in the "stateful" stage) to indicate that the
-             * connection should be allowed to resume.
-             */
-            ds_clear(match);
-            ds_clear(actions);
-            ds_put_format(match, REGBIT_ACL_HINT_ALLOW_NEW " == 1 && (%s)",
-                          acl->match);
 
-            ds_put_cstr(actions, REGBIT_CONNTRACK_COMMIT" = 1; ");
-            if (acl->label) {
-                ds_put_format(actions, REGBIT_ACL_LABEL" = 1; "
-                              REG_LABEL" = %"PRId64"; ", acl->label);
-            }
-            build_acl_log(actions, acl, meter_groups);
-            ds_put_cstr(actions, "next;");
-            ovn_lflow_add_with_hint(lflows, od, stage,
-                                    acl->priority + OVN_ACL_PRI_OFFSET,
-                                    ds_cstr(match),
-                                    ds_cstr(actions),
-                                    &acl->header_);
-
-            /* Match on traffic in the request direction for an established
-             * connection tracking entry that has not been marked for
-             * deletion. We use this to ensure that this
-             * connection is still allowed by the currently defined
-             * policy. Match untracked packets too.
-             * Commit the connection only if the ACL has a label. This is done
-             * to update the connection tracking entry label in case the ACL
-             * allowing the connection changes. */
-            ds_clear(match);
-            ds_clear(actions);
-            ds_put_format(match, REGBIT_ACL_HINT_ALLOW " == 1 && (%s)",
-                          acl->match);
-            if (acl->label) {
-                ds_put_cstr(actions, REGBIT_CONNTRACK_COMMIT" = 1; ");
-                ds_put_format(actions, REGBIT_ACL_LABEL" = 1; "
-                              REG_LABEL" = %"PRId64"; ", acl->label);
-            }
-            build_acl_log(actions, acl, meter_groups);
-            ds_put_cstr(actions, "next;");
-            ovn_lflow_add_with_hint(lflows, od, stage,
-                                    acl->priority + OVN_ACL_PRI_OFFSET,
-                                    ds_cstr(match), ds_cstr(actions),
-                                    &acl->header_);
-
-            /* Related and reply traffic are universally allowed by priority
-             * 65532 flows created in build_acls(). If logging is enabled on
-             * the ACL, then we need to ensure that the related and reply
-             * traffic is logged, so we install a slightly higher-priority
-             * flow that matches the ACL, allows the traffic, and logs it.
-             *
-             * Note: Matching the ct_label.label may prevent OVS flow HW
-             * offloading to work for some NICs because masked-access of
-             * ct_label is not supported on those NICs due to HW
-             * limitations. In such case the user may choose to avoid using the
-             * "log-related" option.
-             */
-            bool log_related = smap_get_bool(&acl->options, "log-related",
-                                             false);
-            if (acl->log && acl->label && log_related) {
-                /* Related/reply flows need to be set on the opposite pipeline
-                 * from where the ACL itself is set.
-                 */
-                enum ovn_stage log_related_stage = ingress ?
-                    S_SWITCH_OUT_ACL :
-                    S_SWITCH_IN_ACL;
-                ds_clear(match);
-                ds_clear(actions);
-
-                ds_put_format(match, "ct.est && !ct.rel && !ct.new%s && "
-                              "ct.rpl && %s == 0 && "
-                              "ct_label.label == %" PRId64,
-                              use_ct_inv_match ? " && !ct.inv" : "",
-                              ct_blocked_match, acl->label);
-                build_acl_log(actions, acl, meter_groups);
-                ds_put_cstr(actions, "next;");
-                ovn_lflow_add_with_hint(lflows, od, log_related_stage,
-                                        UINT16_MAX - 2,
-                                        ds_cstr(match), ds_cstr(actions),
-                                        &acl->header_);
+        /* Commit the connection tracking entry if it's a new
+         * connection that matches this ACL.  After this commit,
+         * the reply traffic is allowed by a flow we create at
+         * priority 65535, defined earlier.
+         *
+         * It's also possible that a known connection was marked for
+         * deletion after a policy was deleted, but the policy was
+         * re-added while that connection is still known.  We catch
+         * that case here and un-set ct_mark.blocked (which will be done
+         * by ct_commit in the "stateful" stage) to indicate that the
+         * connection should be allowed to resume.
+         */
+        ds_clear(match);
+        ds_put_format(match, REGBIT_ACL_HINT_ALLOW_NEW " == 1 && (%s)",
+                      acl->match);
 
-                ds_clear(match);
-                ds_put_format(match, "!ct.est && ct.rel && !ct.new%s && "
-                                     "%s == 0 && "
-                                     "ct_label.label == %" PRId64,
-                                     use_ct_inv_match ? " && !ct.inv" : "",
-                                     ct_blocked_match, acl->label);
-                ovn_lflow_add_with_hint(lflows, od, log_related_stage,
-                                        UINT16_MAX - 2,
-                                        ds_cstr(match), ds_cstr(actions),
-                                        &acl->header_);
-            }
+        ds_truncate(actions, log_verdict_len);
+        ds_put_cstr(actions, REGBIT_CONNTRACK_COMMIT" = 1; ");
+        if (acl->label) {
+            ds_put_format(actions, REGBIT_ACL_LABEL" = 1; "
+                          REG_LABEL" = %"PRId64"; ", acl->label);
+        }
+        ds_put_cstr(actions, "next;");
+        ovn_lflow_add_with_hint(lflows, od, stage, priority,
+                                ds_cstr(match), ds_cstr(actions),
+                                &acl->header_);
 
+        /* Match on traffic in the request direction for an established
+         * connection tracking entry that has not been marked for
+         * deletion. We use this to ensure that this
+         * connection is still allowed by the currently defined
+         * policy. Match untracked packets too.
+         * Commit the connection only if the ACL has a label. This is done
+         * to update the connection tracking entry label in case the ACL
+         * allowing the connection changes. */
+        ds_clear(match);
+        ds_truncate(actions, log_verdict_len);
+        ds_put_format(match, REGBIT_ACL_HINT_ALLOW " == 1 && (%s)",
+                      acl->match);
+        if (acl->label) {
+            ds_put_cstr(actions, REGBIT_CONNTRACK_COMMIT" = 1; ");
+            ds_put_format(actions, REGBIT_ACL_LABEL" = 1; "
+                          REG_LABEL" = %"PRId64"; ", acl->label);
         }
+        ds_put_cstr(actions, "next;");
+        ovn_lflow_add_with_hint(lflows, od, stage, priority,
+                                ds_cstr(match), ds_cstr(actions),
+                                &acl->header_);
     } else if (!strcmp(acl->action, "drop")
                || !strcmp(acl->action, "reject")) {
         /* The implementation of "drop" differs if stateful ACLs are in
          * use for this datapath.  In that case, the actions differ
          * depending on whether the connection was previously committed
          * to the connection tracker with ct_commit. */
-        if (has_stateful) {
-            /* If the packet is not tracked or not part of an established
-             * connection, then we can simply reject/drop it. */
-            ds_clear(match);
-            ds_clear(actions);
-            ds_put_cstr(match, REGBIT_ACL_HINT_DROP " == 1");
-            if (!strcmp(acl->action, "reject")) {
-                build_reject_acl_rules(od, lflows, stage, acl, match,
-                                       actions, &acl->header_, meter_groups);
-            } else {
-                ds_put_format(match, " && (%s)", acl->match);
-                build_acl_log(actions, acl, meter_groups);
-                ds_put_cstr(actions, debug_implicit_drop_action());
-                ovn_lflow_add_with_hint(lflows, od, stage,
-                                        acl->priority + OVN_ACL_PRI_OFFSET,
-                                        ds_cstr(match), ds_cstr(actions),
-                                        &acl->header_);
-            }
-            /* For an existing connection without ct_mark.blocked set, we've
-             * encountered a policy change. ACLs previously allowed
-             * this connection and we committed the connection tracking
-             * entry.  Current policy says that we should drop this
-             * connection.  First, we set ct_mark.blocked to indicate
-             * that this connection is set for deletion.  By not
-             * specifying "next;", we implicitly drop the packet after
-             * updating conntrack state.  We would normally defer
-             * ct_commit() to the "stateful" stage, but since we're
-             * rejecting/dropping the packet, we go ahead and do it here.
-             */
-            ds_clear(match);
-            ds_clear(actions);
-            ds_put_cstr(match, REGBIT_ACL_HINT_BLOCK " == 1");
-            ds_put_format(actions, "ct_commit { %s = 1; }; ",
-                          ct_blocked_match);
-            if (!strcmp(acl->action, "reject")) {
-                build_reject_acl_rules(od, lflows, stage, acl, match,
-                                       actions, &acl->header_, meter_groups);
-            } else {
-                ds_put_format(match, " && (%s)", acl->match);
-                build_acl_log(actions, acl, meter_groups);
-                ds_put_cstr(actions, debug_implicit_drop_action());
-                ovn_lflow_add_with_hint(lflows, od, stage,
-                                        acl->priority + OVN_ACL_PRI_OFFSET,
-                                        ds_cstr(match), ds_cstr(actions),
-                                        &acl->header_);
-            }
-        } else {
-            /* There are no stateful ACLs in use on this datapath,
-             * so a "reject/drop" ACL is simply the "reject/drop"
-             * logical flow action in all cases. */
-            ds_clear(match);
-            ds_clear(actions);
-            if (!strcmp(acl->action, "reject")) {
-                build_reject_acl_rules(od, lflows, stage, acl, match,
-                                       actions, &acl->header_, meter_groups);
-            } else {
-                build_acl_log(actions, acl, meter_groups);
-                ds_put_cstr(actions, debug_implicit_drop_action());
-                ovn_lflow_add_with_hint(lflows, od, stage,
-                                        acl->priority + OVN_ACL_PRI_OFFSET,
-                                        acl->match, ds_cstr(actions),
-                                        &acl->header_);
-            }
-        }
+        /* If the packet is not tracked or not part of an established
+         * connection, then we can simply reject/drop it. */
+        ds_clear(match);
+        ds_put_cstr(match, REGBIT_ACL_HINT_DROP " == 1");
+        ds_put_format(match, " && (%s)", acl->match);
+
+        ds_truncate(actions, log_verdict_len);
+        ds_put_cstr(actions, "next;");
+        ovn_lflow_add_with_hint(lflows, od, stage, priority,
+                                ds_cstr(match), ds_cstr(actions),
+                                &acl->header_);
+        /* For an existing connection without ct_mark.blocked set, we've
+         * encountered a policy change. ACLs previously allowed
+         * this connection and we committed the connection tracking
+         * entry.  Current policy says that we should drop this
+         * connection.  First, we set ct_mark.blocked to indicate
+         * that this connection is set for deletion.  By not
+         * specifying "next;", we implicitly drop the packet after
+         * updating conntrack state.  We would normally defer
+         * ct_commit() to the "stateful" stage, but since we're
+         * rejecting/dropping the packet, we go ahead and do it here.
+         */
+        ds_clear(match);
+        ds_put_cstr(match, REGBIT_ACL_HINT_BLOCK " == 1");
+        ds_put_format(match, " && (%s)", acl->match);
+
+        ds_truncate(actions, log_verdict_len);
+        ds_put_format(actions, "ct_commit { %s = 1; }; next;",
+                      ct_blocked_match);
+        ovn_lflow_add_with_hint(lflows, od, stage, priority,
+                                ds_cstr(match), ds_cstr(actions),
+                                &acl->header_);
     }
 }
 
@@ -6764,13 +6652,143 @@  build_port_group_lswitches(
 
 #define IPV6_CT_OMIT_MATCH "nd || nd_ra || nd_rs || mldv1 || mldv2"
 
+static void
+build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows,
+                        const char *default_acl_action,
+                        const struct shash *meter_groups,
+                        struct ds *actions)
+{
+    enum ovn_stage stages [] = {
+        S_SWITCH_IN_ACL_ACTION,
+        S_SWITCH_IN_ACL_AFTER_LB_ACTION,
+        S_SWITCH_OUT_ACL_ACTION,
+    };
+
+    ds_clear(actions);
+    ds_put_cstr(actions, REGBIT_ACL_VERDICT_ALLOW " = 0; "
+                        REGBIT_ACL_VERDICT_DROP " = 0; "
+                        REGBIT_ACL_VERDICT_REJECT " = 0; ");
+    size_t verdict_len = actions->length;
+
+    for (size_t i = 0; i < ARRAY_SIZE(stages); i++) {
+        enum ovn_stage stage = stages[i];
+        if (!od->has_acls) {
+            ovn_lflow_add(lflows, od, stage, 0, "1", "next;");
+            continue;
+        }
+        ds_truncate(actions, verdict_len);
+        ds_put_cstr(actions, "next;");
+        ovn_lflow_add(lflows, od, stage, 1000,
+                      REGBIT_ACL_VERDICT_ALLOW " == 1", ds_cstr(actions));
+        ds_truncate(actions, verdict_len);
+        ds_put_cstr(actions, debug_implicit_drop_action());
+        ovn_lflow_add(lflows, od, stage, 1000,
+                      REGBIT_ACL_VERDICT_DROP " == 1",
+                      ds_cstr(actions));
+        bool ingress = ovn_stage_get_pipeline(stage) == P_IN;
+
+        ds_truncate(actions, verdict_len);
+        ds_put_format(
+            actions, "reg0 = 0; "
+            "reject { "
+            "/* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ "
+            "outport <-> inport; next(pipeline=%s,table=%d); };",
+            ingress ? "egress" : "ingress",
+            ingress ? ovn_stage_get_table(S_SWITCH_OUT_QOS_MARK)
+                : ovn_stage_get_table(S_SWITCH_IN_L2_LKUP));
+
+        ovn_lflow_metered(lflows, od, stage, 1000,
+                          REGBIT_ACL_VERDICT_REJECT " == 1", ds_cstr(actions),
+                          copp_meter_get(COPP_REJECT, od->nbs->copp,
+                          meter_groups));
+
+        ds_truncate(actions, verdict_len);
+        ds_put_cstr(actions, default_acl_action);
+        ovn_lflow_add(lflows, od, stage, 0, "1", ds_cstr(actions));
+    }
+}
+
+static void
+build_acl_log_related_flows(struct ovn_datapath *od, struct hmap *lflows,
+                            const struct nbrec_acl *acl, bool has_stateful,
+                            bool ct_masked_mark,
+                            const struct shash *meter_groups,
+                            struct ds *match, struct ds *actions)
+{
+    /* Related and reply traffic are universally allowed by priority
+     * 65532 flows created in build_acls(). If logging is enabled on
+     * the ACL, then we need to ensure that the related and reply
+     * traffic is logged, so we install a slightly higher-priority
+     * flow that matches the ACL, allows the traffic, and logs it.
+     *
+     * Note: Matching the ct_label.label may prevent OVS flow HW
+     * offloading to work for some NICs because masked-access of
+     * ct_label is not supported on those NICs due to HW
+     * limitations. In such case the user may choose to avoid using the
+     * "log-related" option.
+     */
+    const char *ct_blocked_match = ct_masked_mark
+                                   ? "ct_mark.blocked"
+                                   : "ct_label.blocked";
+    bool ingress = !strcmp(acl->direction, "from-lport") ? true :false;
+    bool log_related = smap_get_bool(&acl->options, "log-related",
+                                     false);
+
+    if (!strcmp(acl->action, "allow-stateless") || !has_stateful) {
+        /* Not stateful */
+        return;
+    }
+
+    if (strcmp(acl->action, "allow") && strcmp(acl->action, "allow-related")) {
+        /* Not an allow ACL */
+        return;
+    }
+
+    if (!acl->log || !acl->label || !log_related) {
+        /* Missing requirements for logging related ACLs */
+        return;
+    }
+
+    ds_clear(actions);
+    build_acl_log(actions, acl, meter_groups);
+    ds_put_cstr(actions, REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
+    /* Related/reply flows need to be set on the opposite pipeline
+     * from where the ACL itself is set.
+     */
+    enum ovn_stage log_related_stage = ingress ?
+        S_SWITCH_OUT_ACL_EVAL :
+        S_SWITCH_IN_ACL_EVAL;
+    ds_clear(match);
+    ds_put_format(match, "ct.est && !ct.rel && !ct.new%s && "
+                  "ct.rpl && %s == 0 && "
+                  "ct_label.label == %" PRId64,
+                  use_ct_inv_match ? " && !ct.inv" : "",
+                  ct_blocked_match, acl->label);
+    ovn_lflow_add_with_hint(lflows, od, log_related_stage,
+                            UINT16_MAX - 2,
+                            ds_cstr(match), ds_cstr(actions),
+                            &acl->header_);
+
+    ds_clear(match);
+    ds_put_format(match, "!ct.est && ct.rel && !ct.new%s && "
+                         "%s == 0 && "
+                         "ct_label.label == %" PRId64,
+                         use_ct_inv_match ? " && !ct.inv" : "",
+                         ct_blocked_match, acl->label);
+    ovn_lflow_add_with_hint(lflows, od, log_related_stage,
+                            UINT16_MAX - 2,
+                            ds_cstr(match), ds_cstr(actions),
+                            &acl->header_);
+}
+
 static void
 build_acls(struct ovn_datapath *od, const struct chassis_features *features,
            struct hmap *lflows, const struct hmap *port_groups,
            const struct shash *meter_groups)
 {
-    const char *default_acl_action = default_acl_drop ? debug_drop_action() :
-                                                        "next;";
+    const char *default_acl_action = default_acl_drop
+                                     ? debug_implicit_drop_action()
+                                     : "next;";
     bool has_stateful = od->has_stateful_acl || od->has_lb_vip;
     const char *ct_blocked_match = features->ct_no_masked_label
                                    ? "ct_mark.blocked"
@@ -6787,22 +6805,21 @@  build_acls(struct ovn_datapath *od, const struct chassis_features *features,
      * are any stateful ACLs in this datapath. */
     if (!od->has_acls) {
         if (!od->has_lb_vip) {
-            ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX, "1",
+            ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX, "1",
                           "next;");
-            ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX, "1",
+            ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX, "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_EVAL, 0, "1", "next;");
+            ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 0, "1", "next;");
         }
-        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, 0, "1", "next;");
+        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB_EVAL, 0, "1",
+                      "next;");
     } else {
-        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_EVAL, 0, "1", "next;");
+        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 0, "1", "next;");
+        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB_EVAL, 0, "1",
+                      "next;");
     }
 
 
@@ -6831,20 +6848,22 @@  build_acls(struct ovn_datapath *od, const struct chassis_features *features,
          * uses "next;". */
         ds_clear(&match);
         ds_put_format(&match, "ip && ct.est && %s == 1", ct_blocked_match);
-        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 1,
+        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 1,
                       ds_cstr(&match),
-                      REGBIT_CONNTRACK_COMMIT" = 1; next;");
-        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 1,
+                      REGBIT_CONNTRACK_COMMIT" = 1; "
+                      REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
+        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 1,
                       ds_cstr(&match),
-                      REGBIT_CONNTRACK_COMMIT" = 1; next;");
+                      REGBIT_CONNTRACK_COMMIT" = 1; "
+                      REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
 
-        default_acl_action = default_acl_drop
-                             ? debug_drop_action()
+        const char *next_action = default_acl_drop
+                             ? "next;"
                              : 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);
+        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 1, "ip && !ct.est",
+                      next_action);
+        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 1, "ip && !ct.est",
+                      next_action);
 
         /* Ingress and Egress ACL Table (Priority 65532).
          *
@@ -6857,10 +6876,10 @@  build_acls(struct ovn_datapath *od, const struct chassis_features *features,
         ds_put_format(&match, "%s(ct.est && ct.rpl && %s == 1)",
                       use_ct_inv_match ? "ct.inv || " : "",
                       ct_blocked_match);
-        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3,
-                      ds_cstr(&match), debug_drop_action());
-        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3,
-                      ds_cstr(&match),  debug_drop_action());
+        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX - 3,
+                      ds_cstr(&match), REGBIT_ACL_VERDICT_DROP " = 1; next;");
+        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX - 3,
+                      ds_cstr(&match), REGBIT_ACL_VERDICT_DROP " = 1; next;");
 
         /* Ingress and Egress ACL Table (Priority 65535 - 3).
          *
@@ -6876,12 +6895,14 @@  build_acls(struct ovn_datapath *od, const struct chassis_features *features,
                       "ct.rpl && %s == 0",
                       use_ct_inv_match ? " && !ct.inv" : "",
                       ct_blocked_match);
-        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3,
+        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX - 3,
                       ds_cstr(&match), REGBIT_ACL_HINT_DROP" = 0; "
                       REGBIT_ACL_HINT_BLOCK" = 0; "
-                      REGBIT_ACL_HINT_ALLOW_REL" = 1; next;");
-        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3,
-                      ds_cstr(&match), "next;");
+                      REGBIT_ACL_HINT_ALLOW_REL" = 1; "
+                      REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
+        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX - 3,
+                      ds_cstr(&match),
+                      REGBIT_ACL_VERDICT_ALLOW " = 1; next;");
 
         /* Ingress and Egress ACL Table (Priority 65535).
          *
@@ -6897,24 +6918,28 @@  build_acls(struct ovn_datapath *od, const struct chassis_features *features,
          * that's generated from a non-listening UDP port.  */
         const char *ct_in_acl_action =
             features->ct_lb_related
-            ? REGBIT_ACL_HINT_ALLOW_REL" = 1; ct_commit_nat;"
-            : REGBIT_ACL_HINT_ALLOW_REL" = 1; next;";
-        const char *ct_out_acl_action = features->ct_lb_related
-                                        ? "ct_commit_nat;"
-                                        : "next;";
+            ? REGBIT_ACL_HINT_ALLOW_REL" = 1; "
+              REGBIT_ACL_VERDICT_ALLOW" = 1; ct_commit_nat;"
+            : REGBIT_ACL_HINT_ALLOW_REL" = 1; "
+              REGBIT_ACL_VERDICT_ALLOW" = 1; next;";
+        const char *ct_out_acl_action =
+            features->ct_lb_related
+            ? REGBIT_ACL_VERDICT_ALLOW" = 1; ct_commit_nat;"
+            : REGBIT_ACL_VERDICT_ALLOW" = 1; next;";
         ds_clear(&match);
         ds_put_format(&match, "!ct.est && ct.rel && !ct.new%s && %s == 0",
                       use_ct_inv_match ? " && !ct.inv" : "",
                       ct_blocked_match);
-        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3,
+        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX - 3,
                       ds_cstr(&match), ct_in_acl_action);
-        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3,
+        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX - 3,
                       ds_cstr(&match), ct_out_acl_action);
-
         /* Reply and related traffic matched by an "allow-related" ACL
          * should be allowed in the ls_in_acl_after_lb stage too. */
-        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, UINT16_MAX - 3,
-                      REGBIT_ACL_HINT_ALLOW_REL" == 1", "next;");
+        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB_EVAL,
+                      UINT16_MAX - 3,
+                      REGBIT_ACL_HINT_ALLOW_REL" == 1",
+                      REGBIT_ACL_VERDICT_ALLOW " = 1; next;");
     }
 
     /* Ingress and Egress ACL Table (Priority 65532).
@@ -6924,16 +6949,22 @@  build_acls(struct ovn_datapath *od, const struct chassis_features *features,
      * Also, don't send them to conntrack because session tracking
      * for these protocols is not working properly:
      * https://bugzilla.kernel.org/show_bug.cgi?id=11797. */
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3,
-                  IPV6_CT_OMIT_MATCH, "next;");
-    ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3,
-                  IPV6_CT_OMIT_MATCH, "next;");
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, UINT16_MAX - 3,
-                  IPV6_CT_OMIT_MATCH, "next;");
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX - 3,
+                  IPV6_CT_OMIT_MATCH,
+                  REGBIT_ACL_VERDICT_ALLOW " = 1; next;");
+    ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX - 3,
+                  IPV6_CT_OMIT_MATCH,
+                  REGBIT_ACL_VERDICT_ALLOW " = 1; next;");
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB_EVAL, UINT16_MAX - 3,
+                  IPV6_CT_OMIT_MATCH,
+                  REGBIT_ACL_VERDICT_ALLOW " = 1; next;");
 
     /* Ingress or Egress ACL Table (Various priorities). */
     for (size_t i = 0; i < od->nbs->n_acls; i++) {
         struct nbrec_acl *acl = od->nbs->acls[i];
+        build_acl_log_related_flows(od, lflows, acl, has_stateful,
+                                    features->ct_no_masked_label,
+                                    meter_groups, &match, &actions);
         consider_acl(lflows, od, acl, has_stateful,
                      features->ct_no_masked_label,
                      meter_groups, &match, &actions);
@@ -6942,7 +6973,11 @@  build_acls(struct ovn_datapath *od, const struct chassis_features *features,
     HMAP_FOR_EACH (pg, key_node, port_groups) {
         if (ovn_port_group_ls_find(pg, &od->nbs->header_.uuid)) {
             for (size_t i = 0; i < pg->nb_pg->n_acls; i++) {
-                consider_acl(lflows, od, pg->nb_pg->acls[i], has_stateful,
+                const struct nbrec_acl *acl = pg->nb_pg->acls[i];
+                build_acl_log_related_flows(od, lflows, acl, has_stateful,
+                                            features->ct_no_masked_label,
+                                            meter_groups, &match, &actions);
+                consider_acl(lflows, od, acl, has_stateful,
                              features->ct_no_masked_label,
                              meter_groups, &match, &actions);
             }
@@ -6966,14 +7001,16 @@  build_acls(struct ovn_datapath *od, const struct chassis_features *features,
                 &od->nbs->ports[i]->dhcpv4_options->options, "lease_time");
             if (server_id && server_mac && lease_time) {
                 const char *dhcp_actions =
-                    has_stateful ? "ct_commit; next;" : "next;";
+                    has_stateful ? REGBIT_ACL_VERDICT_ALLOW" = 1; "
+                                   "ct_commit; next;"
+                                 : REGBIT_ACL_VERDICT_ALLOW" = 1; next;";
                 ds_clear(&match);
                 ds_put_format(&match, "outport == \"%s\" && eth.src == %s "
                               "&& ip4.src == %s && udp && udp.src == 67 "
                               "&& udp.dst == 68", od->nbs->ports[i]->name,
                               server_mac, server_id);
                 ovn_lflow_add_with_lport_and_hint(
-                    lflows, od, S_SWITCH_OUT_ACL, 34000, ds_cstr(&match),
+                    lflows, od, S_SWITCH_OUT_ACL_EVAL, 34000, ds_cstr(&match),
                     dhcp_actions, od->nbs->ports[i]->name,
                     &od->nbs->ports[i]->dhcpv4_options->header_);
             }
@@ -6992,15 +7029,17 @@  build_acls(struct ovn_datapath *od, const struct chassis_features *features,
                 char server_ip[INET6_ADDRSTRLEN + 1];
                 ipv6_string_mapped(server_ip, &lla);
 
-                const char *dhcp6_actions = has_stateful ? "ct_commit; next;" :
-                    "next;";
+                const char *dhcp6_actions =
+                    has_stateful ? REGBIT_ACL_VERDICT_ALLOW" = 1; "
+                                   "ct_commit; next;"
+                                 : REGBIT_ACL_VERDICT_ALLOW" = 1; next;";
                 ds_clear(&match);
                 ds_put_format(&match, "outport == \"%s\" && eth.src == %s "
                               "&& ip6.src == %s && udp && udp.src == 547 "
                               "&& udp.dst == 546", od->nbs->ports[i]->name,
                               server_mac, server_ip);
                 ovn_lflow_add_with_lport_and_hint(
-                    lflows, od, S_SWITCH_OUT_ACL, 34000, ds_cstr(&match),
+                    lflows, od, S_SWITCH_OUT_ACL_EVAL, 34000, ds_cstr(&match),
                     dhcp6_actions, od->nbs->ports[i]->name,
                     &od->nbs->ports[i]->dhcpv6_options->header_);
             }
@@ -7011,24 +7050,32 @@  build_acls(struct ovn_datapath *od, const struct chassis_features *features,
      * if the CMS has configured DNS records for the datapath.
      */
     if (ls_has_dns_records(od->nbs)) {
-        const char *dns_actions = has_stateful ? "ct_commit; next;" : "next;";
+        const char *dns_actions =
+            has_stateful ? REGBIT_ACL_VERDICT_ALLOW" = 1; "
+                           "ct_commit; next;"
+                         : REGBIT_ACL_VERDICT_ALLOW" = 1; next;";
         ovn_lflow_add(
-            lflows, od, S_SWITCH_OUT_ACL, 34000, "udp.src == 53",
+            lflows, od, S_SWITCH_OUT_ACL_EVAL, 34000, "udp.src == 53",
             dns_actions);
     }
 
     if (od->has_acls || od->has_lb_vip) {
         /* Add a 34000 priority flow to advance the service monitor reply
         * packets to skip applying ingress ACLs. */
-        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 34000,
-                    "eth.dst == $svc_monitor_mac", "next;");
+        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 34000,
+                    "eth.dst == $svc_monitor_mac",
+                    REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
 
         /* Add a 34000 priority flow to advance the service monitor packets
         * generated by ovn-controller to skip applying egress ACLs. */
-        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 34000,
-                    "eth.src == $svc_monitor_mac", "next;");
+        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, 34000,
+                    "eth.src == $svc_monitor_mac",
+                    REGBIT_ACL_VERDICT_ALLOW" = 1; next;");
     }
 
+    build_acl_action_lflows(od, lflows, default_acl_action, meter_groups,
+                            &actions);
+
     ds_destroy(&match);
     ds_destroy(&actions);
 }
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index 7da912da3..40c5ec95b 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -684,7 +684,7 @@ 
       </li>
     </ul>
 
-    <h3>Ingress table 8: <code>from-lport</code> ACLs before LB</h3>
+    <h3>Ingress table 8: <code>from-lport</code> ACL evaluation before LB</h3>
 
     <p>
       Logical flows in this table closely reproduce those in the
@@ -697,61 +697,71 @@ 
     </p>
     <ul>
       <li>
-        <code>allow</code> ACLs translate into logical flows with
-        the <code>next;</code> action.  If there are any stateful ACLs
-        on this datapath, then <code>allow</code> ACLs translate to
-        <code>ct_commit; next;</code> (which acts as a hint for the next tables
-        to commit the connection to conntrack). In case the <code>ACL</code>
-        has a label then <code>reg3</code> is loaded with the label value and
+        This table is responsible for evaluating ACLs, and setting a register
+        bit to indicate whether the ACL decided to allow, drop, or reject the
+        traffic. The allow bit is <code>reg8[16]</code>. The drop bit is
+        <code>reg8[17]</code>. All flows in this table will advance the packet
+        to the next table, where the bits from before are evaluated to
+        determine what to do with the packet. Any flows in this table that
+        intend for the packet to pass will set <code>reg8[16]</code> to 1,
+        even if an ACL with an allow-type action was not matched. This lets the
+        next table know to allow the traffic to pass. These bits will be
+        referred to as the "allow", "drop", and "reject" bits in the upcoming
+        paragraphs.
+      </li>
+      <li>
+        <code>allow</code> ACLs translate into logical flows that set the allow
+        bit to 1 and advance the packet to the next table. If there are any
+        stateful ACLs on this datapath, then <code>allow</code> ACLs set the
+        allow bit to one and in addition perform <code>ct_commit;</code> (which
+        acts as a hint for future tables to commit the connection to
+        conntrack). In case the <code>ACL</code> has a label then
+        <code>reg3</code> is loaded with the label value and
         <code>reg0[13]</code> bit is set to 1 (which acts as a hint for the
         next tables to commit the label to conntrack).
       </li>
       <li>
-        <code>allow-related</code> ACLs translate into logical
-        flows with the <code>ct_commit(ct_label=0/1); next;</code> actions
-        for new connections and <code>reg0[1] = 1; next;</code> for existing
-        connections.  In case the <code>ACL</code> has a label then
-        <code>reg3</code> is loaded with the label value and
+        <code>allow-related</code> ACLs translate into logical flows that set
+        the allow bit and additionally have <code>ct_commit(ct_label=0/1);
+        next;</code> actions for new connections and <code>reg0[1] = 1;
+        next;</code> for existing connections.  In case the <code>ACL</code>
+        has a label then <code>reg3</code> is loaded with the label value and
         <code>reg0[13]</code> bit is set to 1 (which acts as a hint for the
         next tables to commit the label to conntrack).
       </li>
       <li>
-        <code>allow-stateless</code> ACLs translate into logical
-        flows with the <code>next;</code> action.
+        <code>allow-stateless</code> ACLs translate into logical flows that set
+        the allow bit and advance to the next table.
       </li>
       <li>
-        <code>reject</code> ACLs translate into logical
-        flows with the
-        <code>tcp_reset { output &lt;-&gt; inport;
-        next(pipeline=egress,table=5);}</code>
-        action for TCP connections,<code>icmp4/icmp6</code> action
-        for UDP connections, and <code>sctp_abort {output &lt;-%gt; inport;
-        next(pipeline=egress,table=5);}</code> action for SCTP associations.
+        <code>reject</code> ACLs translate into logical flows with that set the
+        reject bit and advance to the next table.
       </li>
       <li>
-        Other ACLs translate to <code>drop;</code> for new or untracked
-        connections and <code>ct_commit(ct_label=1/1);</code> for known
-        connections.  Setting <code>ct_label</code> marks a connection
-        as one that was previously allowed, but should no longer be
-        allowed due to a policy change.
+        Other ACLs set the drop bit and advance to the next table for new or
+        untracked connections. For known connections, they set the drop bit,
+        as well as running the <code>ct_commit(ct_label=1/1);</code> action.
+        Setting <code>ct_label</code> marks a connection as one that was
+        previously allowed, but should no longer be allowed due to a policy
+        change.
       </li>
     </ul>
 
     <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 if <ref column="options:default_acl_drop"
-      table="NB_Global" db="OVN_Northbound"/> column 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.
+      This table contains a priority-65535 flow to set the allow bit and
+      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 is added. This flow does not set the allow bit, so that the next
+      table can decide whether to allow or drop the packet based on the value
+      of the <ref column="options:default_acl_drop" table="NB_Global"
+      db="OVN_Northbound"/> column of the <ref table="NB_Global"
+      db="OVN_Northbound"/> table.
     </p>
 
     <p>
-      A priority-65532 flow is added to allow IPv6 Neighbor solicitation,
-      Neighbor discover, Router solicitation, Router advertisement and MLD
-      packets regardless of other ACLs defined.
+      A priority-65532 flow is added that sets the allow bit for
+      IPv6 Neighbor solicitation, Neighbor discover, Router solicitation,
+      Router advertisement and MLD packets regardless of other ACLs defined.
     </p>
 
     <p>
@@ -773,24 +783,17 @@ 
       </li>
 
       <li>
-        If <ref column="options:default_acl_drop" table="NB_Global"
-        db="OVN_Northbound"/> column 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
-        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.
+        A priority-1 flow that sets the allow bit and sets the hint to commit
+        IP traffic 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>
-        A priority-65532 flow that allows any traffic in the reply
-        direction for a connection that has been committed to the
+        A priority-65532 flow that sets the allow bit for any traffic in the
+        reply direction for a connection that has been committed to the
         connection tracker (i.e., established flows), as long as
         the committed flow does not have <code>ct_mark.blocked</code> set.
         We only handle traffic in the reply direction here because
@@ -807,9 +810,9 @@ 
       </li>
 
       <li>
-        A priority-65532 flow that allows any traffic that is considered
-        related to a committed flow in the connection tracker (e.g., an
-        ICMP Port Unreachable from a non-listening UDP port), as long
+        A priority-65532 flow that sets the allow bit for any traffic that is
+        considered related to a committed flow in the connection tracker (e.g.,
+        an ICMP Port Unreachable from a non-listening UDP port), as long
         as the committed flow does not have <code>ct_mark.blocked</code> set.
         This flow also applies NAT to the related traffic so that ICMP headers
         and the inner packet have correct addresses.
@@ -819,14 +822,14 @@ 
       </li>
 
       <li>
-        A priority-65532 flow that drops all traffic marked by the
-        connection tracker as invalid.
+        A priority-65532 flow that sets the drop bit for all traffic marked by
+        the connection tracker as invalid.
       </li>
 
       <li>
-        A priority-65532 flow that drops all traffic in the reply direction
-        with <code>ct_mark.blocked</code> set meaning that the connection
-        should no longer be allowed due to a policy change.  Packets
+        A priority-65532 flow that sets the drop bit for all traffic in the
+        reply direction with <code>ct_mark.blocked</code> set meaning that the
+        connection should no longer be allowed due to a policy change.  Packets
         in the request direction are skipped here to let a newly created
         ACL re-allow this connection.
       </li>
@@ -842,7 +845,7 @@ 
         A priority 34000 logical flow is added for each logical switch datapath
         with the match <code>eth.dst = <var>E</var></code> to allow the service
         monitor reply packet destined to <code>ovn-controller</code>
-        with the action <code>next</code>, where <var>E</var> is the
+        that sets the allow bit, where <var>E</var> is the
         service monitor mac defined in the
         <ref column="options:svc_monitor_mac" table="NB_Global"
         db="OVN_Northbound"/> column of <ref table="NB_Global"
@@ -850,7 +853,40 @@ 
       </li>
     </ul>
 
-    <h3>Ingress Table 9: <code>from-lport</code> QoS Marking</h3>
+    <h3>Ingress Table 9: <code>from-lport</code> ACL action</h3>
+
+    <p>
+      Logical flows in this table decide how to proceed based on the values of
+      the allow, drop, and reject bits that may have been set in the previous
+      table.
+    </p>
+
+    <ul>
+      <li>
+        If no ACLs are configured, then a priority 0 flow is installed that
+        matches everything and advances to the next table.
+      </li>
+
+      <li>
+        A priority 1000 flow is installed that will advance the packet to the
+        next table if the allow bit is set.
+      </li>
+
+      <li>
+        A priority 1000 flow is installed that will run the <code>drop;</code>
+        action if the drop bit is set.
+      </li>
+
+      <li>
+        A priority 1000 flow is installed that will run the <code>tcp_reset
+        { output &lt;-&gt; inport; next(pipeline=egress,table=5);}</code>
+        action for TCP connections,<code>icmp4/icmp6</code> action
+        for UDP connections, and <code>sctp_abort {output &lt;-%gt; inport;
+        next(pipeline=egress,table=5);}</code> action for SCTP associations.
+      </li>
+    </ul>
+
+    <h3>Ingress Table 10: <code>from-lport</code> QoS Marking</h3>
 
     <p>
       Logical flows in this table closely reproduce those in the
@@ -872,7 +908,7 @@ 
       </li>
     </ul>
 
-    <h3>Ingress Table 10: <code>from-lport</code> QoS Meter</h3>
+    <h3>Ingress Table 11: <code>from-lport</code> QoS Meter</h3>
 
     <p>
       Logical flows in this table closely reproduce those in the
@@ -894,7 +930,7 @@ 
       </li>
     </ul>
 
-    <h3>Ingress Table 11: Load balancing affinity check</h3>
+    <h3>Ingress Table 12: Load balancing affinity check</h3>
 
     <p>
       Load balancing affinity check table contains the following
@@ -922,7 +958,7 @@ 
       </li>
     </ul>
 
-    <h3>Ingress Table 12: LB</h3>
+    <h3>Ingress Table 13: LB</h3>
 
     <ul>
       <li>
@@ -1002,7 +1038,7 @@ 
       </li>
     </ul>
 
-    <h3>Ingress Table 13: Load balancing affinity learn</h3>
+    <h3>Ingress Table 14: Load balancing affinity learn</h3>
 
     <p>
       Load balancing affinity learn table contains the following
@@ -1033,7 +1069,7 @@ 
       </li>
     </ul>
 
-    <h3>Ingress Table 14: Pre-Hairpin</h3>
+    <h3>Ingress Table 15: Pre-Hairpin</h3>
     <ul>
       <li>
         If the logical switch has load balancer(s) configured, then a
@@ -1051,7 +1087,7 @@ 
       </li>
     </ul>
 
-    <h3>Ingress Table 15: Nat-Hairpin</h3>
+    <h3>Ingress Table 16: Nat-Hairpin</h3>
     <ul>
       <li>
          If the logical switch has load balancer(s) configured, then a
@@ -1086,7 +1122,7 @@ 
       </li>
     </ul>
 
-    <h3>Ingress Table 16: Hairpin</h3>
+    <h3>Ingress Table 17: Hairpin</h3>
     <ul>
       <li>
         <p>
@@ -1120,56 +1156,57 @@ 
       </li>
     </ul>
 
-    <h3>Ingress table 17: <code>from-lport</code> ACLs after LB</h3>
+    <h3>Ingress table 18: <code>from-lport</code> ACL evaluation after LB</h3>
 
     <p>
       Logical flows in this table closely reproduce those in the
-      <code>ACL</code> table in the <code>OVN_Northbound</code> database
+      <code>ACL eval</code> table in the <code>OVN_Northbound</code> database
       for the <code>from-lport</code> direction with the option
       <code>apply-after-lb</code> set to <code>true</code>.
       The <code>priority</code> values from the <code>ACL</code> table have a
       limited range and have 1000 added to them to leave room for OVN default
-      flows at both higher and lower priorities.
+      flows at both higher and lower priorities. The flows in this table
+      indicate the ACL verdict by setting <code>reg8[16]</code> for
+      <code>allow-type</code> ACLs, <code>reg8[17]</code> for <code>drop</code>
+      ACLs, and <code>reg8[17]</code> for <code>reject</code> ACLs, and then
+      advancing the packet to the next table. These will be reffered to as the
+      allow bit, drop bit, and reject bit throughout the documentation for this
+      table and the next one.
     </p>
 
     <ul>
       <li>
         <code>allow</code> apply-after-lb ACLs translate into logical flows
-        with the <code>next;</code> action.  If there are any stateful ACLs
+        that set the allow bit.  If there are any stateful ACLs
         (including both before-lb and after-lb ACLs)
-        on this datapath, then <code>allow</code> ACLs translate to
-        <code>ct_commit; next;</code> (which acts as a hint for the next tables
-        to commit the connection to conntrack). In case the <code>ACL</code>
-        has a label then <code>reg3</code> is loaded with the label value and
-        <code>reg0[13]</code> bit is set to 1 (which acts as a hint for the
-        next tables to commit the label to conntrack).
+        on this datapath, then <code>allow</code> ACLs also run
+        <code>ct_commit; next;</code> (which acts as a hint for an upcoming
+        table to commit the connection to conntrack). In case the
+        <code>ACL</code> has a label then <code>reg3</code> is loaded with the
+        label value and <code>reg0[13]</code> bit is set to 1 (which acts as a
+        hint for the next tables to commit the label to conntrack).
       </li>
       <li>
         <code>allow-related</code> apply-after-lb ACLs translate into logical
-        flows with the <code>ct_commit(ct_label=0/1); next;</code> actions
-        for new connections and <code>reg0[1] = 1; next;</code> for existing
-        connections.  In case the <code>ACL</code> has a label then
-        <code>reg3</code> is loaded with the label value and
+        flows that set the allow bit and run the <code>ct_commit(ct_label=0/1);
+        next;</code> actions for new connections and <code>reg0[1] = 1;
+        next;</code> for existing connections.  In case the <code>ACL</code>
+        has a label then <code>reg3</code> is loaded with the label value and
         <code>reg0[13]</code> bit is set to 1 (which acts as a hint for the
         next tables to commit the label to conntrack).
       </li>
       <li>
         <code>allow-stateless</code> apply-after-lb ACLs translate into logical
-        flows with the <code>next;</code> action.
+        flows that set the allow bit and advance to the next table.
       </li>
       <li>
         <code>reject</code> apply-after-lb ACLs translate into logical
-        flows with the
-        <code>tcp_reset { output &lt;-&gt; inport;
-        next(pipeline=egress,table=5);}</code>
-        action for TCP connections,<code>icmp4/icmp6</code> action
-        for UDP connections, and <code>sctp_abort {output &lt;-%gt; inport;
-        next(pipeline=egress,table=5);}</code> action for SCTP associations.
+        flows that set the reject bit and advance to the next table.
       </li>
       <li>
-        Other apply-after-lb ACLs translate to <code>drop;</code> for new
-        or untracked connections and <code>ct_commit(ct_label=1/1);</code> for
-        known connections.  Setting <code>ct_label</code> marks a connection
+        Other apply-after-lb ACLs set the drop bit for new or untracked
+        connections and <code>ct_commit(ct_label=1/1);</code> for known
+        connections.  Setting <code>ct_label</code> marks a connection
         as one that was previously allowed, but should no longer be
         allowed due to a policy change.
       </li>
@@ -1179,8 +1216,8 @@ 
       <li>
         One priority-65532 flow matching packets with <code>reg0[17]</code>
         set (either replies to existing sessions or traffic related to
-        existing sessions) and allows these by advancing to the next
-        table.
+        existing sessions) and allows these by setting the allow bit and
+        advancing to the next table.
       </li>
     </ul>
 
@@ -1191,7 +1228,40 @@ 
       </li>
     </ul>
 
-    <h3>Ingress Table 18: Stateful</h3>
+    <h3>Ingress Table 19: <code>from-lport</code> ACL action after LB</h3>
+
+    <p>
+      Logical flows in this table decide how to proceed based on the values of
+      the allow, drop, and reject bits that may have been set in the previous
+      table.
+    </p>
+
+    <ul>
+      <li>
+        If no ACLs are configured, then a priority 0 flow is installed that
+        matches everything and advances to the next table.
+      </li>
+
+      <li>
+        A priority 1000 flow is installed that will advance the packet to the
+        next table if the allow bit is set.
+      </li>
+
+      <li>
+        A priority 1000 flow is installed that will run the <code>drop;</code>
+        action if the drop bit is set.
+      </li>
+
+      <li>
+        A priority 1000 flow is installed that will run the <code>tcp_reset
+        { output &lt;-&gt; inport; next(pipeline=egress,table=5);}</code>
+        action for TCP connections,<code>icmp4/icmp6</code> action
+        for UDP connections, and <code>sctp_abort {output &lt;-%gt; inport;
+        next(pipeline=egress,table=5);}</code> action for SCTP associations.
+      </li>
+    </ul>
+
+    <h3>Ingress Table 20: Stateful</h3>
 
     <ul>
       <li>
@@ -1214,7 +1284,7 @@ 
       </li>
     </ul>
 
-    <h3>Ingress Table 19: ARP/ND responder</h3>
+    <h3>Ingress Table 21: ARP/ND responder</h3>
 
     <p>
       This table implements ARP/ND responder in a logical switch for known
@@ -1541,7 +1611,7 @@  output;
       </li>
     </ul>
 
-    <h3>Ingress Table 20: DHCP option processing</h3>
+    <h3>Ingress Table 22: DHCP option processing</h3>
 
     <p>
       This table adds the DHCPv4 options to a DHCPv4 packet from the
@@ -1602,7 +1672,7 @@  next;
       </li>
     </ul>
 
-    <h3>Ingress Table 21: DHCP responses</h3>
+    <h3>Ingress Table 23: DHCP responses</h3>
 
     <p>
       This table implements DHCP responder for the DHCP replies generated by
@@ -1683,7 +1753,7 @@  output;
       </li>
     </ul>
 
-    <h3>Ingress Table 22 DNS Lookup</h3>
+    <h3>Ingress Table 24 DNS Lookup</h3>
 
     <p>
       This table looks up and resolves the DNS names to the corresponding
@@ -1712,7 +1782,7 @@  reg0[4] = dns_lookup(); next;
       </li>
     </ul>
 
-    <h3>Ingress Table 23 DNS Responses</h3>
+    <h3>Ingress Table 25 DNS Responses</h3>
 
     <p>
       This table implements DNS responder for the DNS replies generated by
@@ -1747,7 +1817,7 @@  output;
       </li>
     </ul>
 
-    <h3>Ingress table 24 External ports</h3>
+    <h3>Ingress table 26 External ports</h3>
 
     <p>
       Traffic from the <code>external</code> logical ports enter the ingress
@@ -1790,7 +1860,7 @@  output;
       </li>
     </ul>
 
-    <h3>Ingress Table 25 Destination Lookup</h3>
+    <h3>Ingress Table 27 Destination Lookup</h3>
 
     <p>
       This table implements switching behavior.  It contains these logical
@@ -1966,7 +2036,7 @@  output;
       </li>
     </ul>
 
-    <h3>Ingress Table 26 Destination unknown</h3>
+    <h3>Ingress Table 28 Destination unknown</h3>
 
     <p>
       This table handles the packets whose destination was not found or
@@ -2116,11 +2186,15 @@  output;
       This is similar to ingress table <code>ACL hints</code>.
     </p>
 
-    <h3>Egress Table 4: <code>to-lport</code> ACLs</h3>
+    <h3>Egress Table 4: <code>to-lport</code> ACL evaluation</h3>
 
     <p>
-      This is similar to ingress table <code>ACLs</code> except for
-      <code>to-lport</code> ACLs.
+      This is similar to ingress table <code>ACL eval</code> except for
+      <code>to-lport</code> ACLs. As a reminder, these flows use the
+      following register bits to indicate their verdicts.
+      <code>Allow-type</code> ACLs set <code>reg8[16]</code>, <code>drop</code>
+      ACLs set <code>reg8[17]</code>, and <code>reject</code> ACLs set
+      <code>reg8[18]</code>.
     </p>
 
     <p>
@@ -2137,14 +2211,16 @@  output;
         A priority 34000 logical flow is added for each logical port which
         has DHCPv4 options defined to allow the DHCPv4 reply packet and which has
         DHCPv6 options defined to allow the DHCPv6 reply packet from the
-        <code>Ingress Table 18: DHCP responses</code>.
+        <code>Ingress Table 18: DHCP responses</code>. This is indicated by
+        setting the allow bit.
       </li>
 
       <li>
         A priority 34000 logical flow is added for each logical switch datapath
         configured with DNS records with the match <code>udp.dst = 53</code>
         to allow the DNS reply packet from the
-        <code>Ingress Table 20: DNS responses</code>.
+        <code>Ingress Table 20: DNS responses</code>. This is indicated by
+        setting the allow bit.
       </li>
 
       <li>
@@ -2155,32 +2231,38 @@  output;
         service monitor mac defined in the
         <ref column="options:svc_monitor_mac" table="NB_Global"
         db="OVN_Northbound"/> column of <ref table="NB_Global"
-        db="OVN_Northbound"/> table.
+        db="OVN_Northbound"/> table. This is indicated by setting the allow
+        bit.
       </li>
     </ul>
 
-    <h3>Egress Table 5: <code>to-lport</code> QoS Marking</h3>
+    <h3>Egress Table 5: <code>to-lport</code> ACL action</h3>
+    <p>
+      This is similar to ingress table <code>ACL action</code>.
+    </p>
+
+    <h3>Egress Table 6: <code>to-lport</code> QoS Marking</h3>
 
     <p>
       This is similar to ingress table <code>QoS marking</code> except
       they apply to <code>to-lport</code> QoS rules.
     </p>
 
-    <h3>Egress Table 6: <code>to-lport</code> QoS Meter</h3>
+    <h3>Egress Table 7: <code>to-lport</code> QoS Meter</h3>
 
     <p>
       This is similar to ingress table <code>QoS meter</code> except
       they apply to <code>to-lport</code> QoS rules.
     </p>
 
-    <h3>Egress Table 7: Stateful</h3>
+    <h3>Egress Table 8: Stateful</h3>
 
     <p>
       This is similar to ingress table <code>Stateful</code> except that
       there are no rules added for load balancing new connections.
     </p>
 
-    <h3>Egress Table 8: Egress Port Security - check</h3>
+    <h3>Egress Table 9: Egress Port Security - check</h3>
 
     <p>
       This is similar to the port security logic in table
@@ -2209,7 +2291,7 @@  output;
       </li>
     </ul>
 
-    <h3>Egress Table 9: Egress Port Security - Apply</h3>
+    <h3>Egress Table 10: Egress Port Security - Apply</h3>
 
     <p>
       This is similar to the ingress port security logic in ingress table
diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at
index 137724723..64d6a9336 100644
--- a/tests/ovn-controller.at
+++ b/tests/ovn-controller.at
@@ -919,9 +919,9 @@  for i in $(seq 10); do
     if test "$i" = 3; then
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3 actions=drop
+priority=1100,ip,reg15=0x1,metadata=0x1,nw_src=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x1,metadata=0x1,nw_src=10.0.0.2 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x1,metadata=0x1,nw_src=10.0.0.3 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 ])
     fi
     AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$i
@@ -941,7 +941,7 @@  for i in $(seq 10); do
     if test "$i" = 9; then
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}'], [0], [dnl
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10 actions=drop
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 ])
     fi
     if test "$i" = 10; then
@@ -967,12 +967,12 @@  for i in $(seq 10); do
     if test "$i" = 3; then
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.1.1 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.1.2 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.1.3 actions=drop
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.1.1 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.1.2 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.1.3 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 ])
     fi
     AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$(($i * 2))
@@ -1092,9 +1092,9 @@  for i in $(seq 10); do
     if test "$i" = 1; then
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
-priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,tp_dst=111 actions=drop
-priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,tp_dst=222 actions=drop
-priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,tp_dst=333 actions=drop
+priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,tp_dst=111 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,tp_dst=222 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,tp_dst=333 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 ])
     else
         # (1 conj_id flow + 3 tp_dst flows) = 4 extra flows
@@ -1106,8 +1106,8 @@  priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,tp_dst=33
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}' | \
             sed -r 's/conjunction.*,/conjunction,/' | \
-            sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-priority=1100,conj_id=,metadata=0x$dp_key actions=drop
+            sed -r 's/conj_id=.*,metadata/conj_id=,metadata/' | sort], [0], [dnl
+priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=conjunction,1/2)
 priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2 actions=conjunction,1/2)
 priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3 actions=conjunction,1/2)
@@ -1134,9 +1134,9 @@  for i in $(seq 10); do
         # no conjunction left
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
-priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,tp_dst=111 actions=drop
-priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,tp_dst=222 actions=drop
-priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,tp_dst=333 actions=drop
+priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,tp_dst=111 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,tp_dst=222 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,tp_dst=333 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 ])
     else
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$((14 - $i))
@@ -1158,8 +1158,8 @@  for i in $(seq 10); do
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}' | \
             sed -r 's/conjunction.*,/conjunction,/' | \
-            sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-priority=1100,conj_id=,metadata=0x$dp_key actions=drop
+            sed -r 's/conj_id=.*,metadata/conj_id=,metadata/' | sort], [0], [dnl
+priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=conjunction,1/2)
 priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2 actions=conjunction,1/2)
 priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3 actions=conjunction,1/2)
@@ -1289,7 +1289,7 @@  for i in $(seq 10); do
     if test "$i" = 1; then
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,nw_dst=10.0.0.6 actions=drop
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,nw_dst=10.0.0.6 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 ])
     else
         # (1 conj_id + nw_src * i + nw_dst * i) = 1 + i*2 flows
@@ -1301,8 +1301,8 @@  priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,nw_dst=10.
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}' | \
             sed -r 's/conjunction.*,/conjunction,/' | \
-            sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-priority=1100,conj_id=,metadata=0x$dp_key actions=drop
+            sed -r 's/conj_id=.*,metadata/conj_id=,metadata/' | sort], [0], [dnl
+priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.6 actions=conjunction,1/2)
 priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.7 actions=conjunction,1/2)
 priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.8 actions=conjunction,1/2)
@@ -1331,7 +1331,7 @@  for i in $(seq 10); do
         # no conjunction left
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,nw_dst=10.0.0.15 actions=drop
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,nw_dst=10.0.0.15 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 ])
     else
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$((21 - $i*2))
@@ -1357,9 +1357,9 @@  for i in $(seq 2 10); do
     if test "$i" = 3; then
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,nw_dst=10.0.0.6 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2,nw_dst=10.0.0.6 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3,nw_dst=10.0.0.6 actions=drop
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,nw_dst=10.0.0.6 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2,nw_dst=10.0.0.6 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3,nw_dst=10.0.0.6 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 ])
     fi
     AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$i
@@ -1383,8 +1383,8 @@  for i in $(seq 10); do
     if test "$i" = 9; then
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}'], [0], [dnl
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,nw_dst=10.0.0.6 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,nw_dst=10.0.0.7 actions=drop
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,nw_dst=10.0.0.6 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,nw_dst=10.0.0.7 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 ])
     elif test "$i" = 10; then
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep "priority=1100"], [1], [ignore])
@@ -1446,8 +1446,8 @@  for i in $(seq 10); do
     if test "$i" = 1; then
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.6 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=drop
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.6 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 ])
     else
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$(($i*2))
@@ -1459,12 +1459,12 @@  priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=dr
             grep -v reply | awk '{print $7, $8}' | \
             sed -r 's/conjunction.*,/conjunction,/' | \
             sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.6 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.7 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.8 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3 actions=drop
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.6 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.7 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.8 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 ])
     fi
 done
@@ -1542,8 +1542,8 @@  for i in $(seq 10); do
     if test "$i" = 1; then
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.6 actions=drop
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.6 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 ])
     elif test "$i" -lt 6; then
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$(($i*2))
@@ -1558,12 +1558,12 @@  priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.6 actions=dr
             grep -v reply | awk '{print $7, $8}' | \
             sed -r 's/conjunction.*,/conjunction,/' | \
             sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.6 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.7 actions=drop
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.8 actions=drop
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.6 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.7 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.8 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 ])
     fi
 done
@@ -1640,7 +1640,7 @@  for i in $(seq 10); do
     if test "$i" = 1; then
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,nw_dst=10.0.0.1 actions=drop
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,nw_dst=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 ])
     else
         # (1 conj_id + nw_src * i + nw_dst * i) = 1 + i*2 flows
@@ -1652,8 +1652,8 @@  priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,nw_dst=10.
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}' | \
             sed -r 's/conjunction.*,/conjunction,/' | \
-            sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-priority=1100,conj_id=,metadata=0x$dp_key actions=drop
+            sed -r 's/conj_id=.*,metadata/conj_id=,metadata/' | sort], [0], [dnl
+priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.1 actions=conjunction,1/2)
 priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.2 actions=conjunction,1/2)
 priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.3 actions=conjunction,1/2)
@@ -1680,7 +1680,7 @@  for i in $(seq 10); do
         # no conjunction left
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
-priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,nw_dst=10.0.0.10 actions=drop
+priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,nw_dst=10.0.0.10 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 ])
     else
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$((21 - $i*2))
@@ -1702,8 +1702,8 @@  for i in $(seq 10); do
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}' | \
             sed -r 's/conjunction.*,/conjunction,/' | \
-            sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-priority=1100,conj_id=,metadata=0x$dp_key actions=drop
+            sed -r 's/conj_id=.*,metadata/conj_id=,metadata/' | sort], [0], [dnl
+priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.1 actions=conjunction,1/2)
 priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.2 actions=conjunction,1/2)
 priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.3 actions=conjunction,1/2)
@@ -1742,8 +1742,8 @@  check ovn-nbctl --wait=hv sync
 AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
     grep -v reply | awk '{print $7, $8}' | \
     sed -r 's/conjunction.*,/conjunction,/' | \
-    sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-priority=1100,conj_id=,metadata=0x$dp_key actions=drop
+    sed -r 's/conj_id=.*,metadata/conj_id=,metadata/' | sort], [0], [dnl
+priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.1 actions=conjunction,1/2)
 priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.2 actions=conjunction,1/2)
 priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.3 actions=conjunction,1/2)
@@ -1766,8 +1766,8 @@  check ovn-nbctl --wait=hv remove address_set as1 addresses 10.0.0.4,10.0.0.5
 AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
     grep -v reply | awk '{print $7, $8}' | \
     sed -r 's/conjunction.*,/conjunction,/' | \
-    sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-priority=1100,conj_id=,metadata=0x$dp_key actions=drop
+    sed -r 's/conj_id=.*,metadata/conj_id=,metadata/' | sort], [0], [dnl
+priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.1 actions=conjunction,1/2)
 priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.2 actions=conjunction,1/2)
 priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.3 actions=conjunction,1/2)
@@ -1824,9 +1824,9 @@  check ovn-nbctl --wait=hv sync
 AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
     grep -v reply | awk '{print $7, $8}' | \
     sed -r 's/conjunction.[[0-9]]*,/conjunction,/g' | \
-    sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-priority=1100,conj_id=,metadata=0x$dp_key actions=drop
-priority=1100,conj_id=,metadata=0x$dp_key actions=drop
+    sed -r 's/conj_id=.*,metadata/conj_id=,metadata/' | sort], [0], [dnl
+priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.11 actions=conjunction,1/2)
 priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.12 actions=conjunction,1/2)
 priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.13 actions=conjunction,1/2)
@@ -1849,9 +1849,9 @@  check ovn-nbctl --wait=hv sync
 AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
     grep -v reply | awk '{print $7, $8}' | \
     sed -r 's/conjunction.[[0-9]]*,/conjunction,/g' | \
-    sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-priority=1100,conj_id=,metadata=0x$dp_key actions=drop
-priority=1100,conj_id=,metadata=0x$dp_key actions=drop
+    sed -r 's/conj_id=.*,metadata/conj_id=,metadata/' | sort], [0], [dnl
+priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.11 actions=conjunction,1/2)
 priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.12 actions=conjunction,1/2)
 priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.13 actions=conjunction,1/2)
@@ -1880,9 +1880,9 @@  check ovn-nbctl --wait=hv sync
 AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
     grep -v reply | awk '{print $7, $8}' | \
     sed -r 's/conjunction.[[0-9]]*,/conjunction,/g' | \
-    sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-priority=1100,conj_id=,metadata=0x$dp_key actions=drop
-priority=1100,conj_id=,metadata=0x$dp_key actions=drop
+    sed -r 's/conj_id=.*,metadata/conj_id=,metadata/' | sort], [0], [dnl
+priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,conj_id=,metadata=0x$dp_key actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.11 actions=conjunction,1/2)
 priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.12 actions=conjunction,1/2)
 priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.13 actions=conjunction,1/2)
@@ -1944,9 +1944,9 @@  for i in $(seq 5); do
     if test "$i" = 3; then
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
-priority=1100,reg15=0x$port_key,metadata=0x$dp_key,dl_src=aa:aa:aa:aa:aa:01 actions=drop
-priority=1100,reg15=0x$port_key,metadata=0x$dp_key,dl_src=aa:aa:aa:aa:aa:02 actions=drop
-priority=1100,reg15=0x$port_key,metadata=0x$dp_key,dl_src=aa:aa:aa:aa:aa:03 actions=drop
+priority=1100,reg15=0x$port_key,metadata=0x$dp_key,dl_src=aa:aa:aa:aa:aa:01 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,reg15=0x$port_key,metadata=0x$dp_key,dl_src=aa:aa:aa:aa:aa:02 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,reg15=0x$port_key,metadata=0x$dp_key,dl_src=aa:aa:aa:aa:aa:03 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 ])
     fi
     AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$i
@@ -1967,7 +1967,7 @@  for i in $(seq 5); do
     if test "$i" = 4; then
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}'], [0], [dnl
-priority=1100,reg15=0x$port_key,metadata=0x$dp_key,dl_src=aa:aa:aa:aa:aa:05 actions=drop
+priority=1100,reg15=0x$port_key,metadata=0x$dp_key,dl_src=aa:aa:aa:aa:aa:05 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 ])
     fi
     if test "$i" = 5; then
@@ -2025,9 +2025,9 @@  for i in $(seq 5); do
     if test "$i" = 3; then
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
-priority=1100,ipv6,reg15=0x$port_key,metadata=0x$dp_key,ipv6_src=ff::1 actions=drop
-priority=1100,ipv6,reg15=0x$port_key,metadata=0x$dp_key,ipv6_src=ff::2 actions=drop
-priority=1100,ipv6,reg15=0x$port_key,metadata=0x$dp_key,ipv6_src=ff::3 actions=drop
+priority=1100,ipv6,reg15=0x$port_key,metadata=0x$dp_key,ipv6_src=ff::1 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ipv6,reg15=0x$port_key,metadata=0x$dp_key,ipv6_src=ff::2 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
+priority=1100,ipv6,reg15=0x$port_key,metadata=0x$dp_key,ipv6_src=ff::3 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 ])
     fi
     AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$i
@@ -2047,7 +2047,7 @@  for i in $(seq 5); do
     if test "$i" = 4; then
         AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
             grep -v reply | awk '{print $7, $8}'], [0], [dnl
-priority=1100,ipv6,reg15=0x$port_key,metadata=0x$dp_key,ipv6_src=ff::5 actions=drop
+priority=1100,ipv6,reg15=0x$port_key,metadata=0x$dp_key,ipv6_src=ff::5 actions=load:0x1->OXM_OF_PKT_REG4[[49]],resubmit(,45)
 ])
     fi
     if test "$i" = 5; then
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index c52f86490..1c9958c6b 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -1442,7 +1442,7 @@  ovn-sbctl set service_monitor $sm_sw1_p1 status=offline
 AT_CAPTURE_FILE([sbflows12])
 OVS_WAIT_FOR_OUTPUT(
   [ovn-sbctl dump-flows sw0 | tee sbflows12 | grep "ip4.dst == 10.0.0.10 && tcp.dst == 80" | grep priority=120 | grep ls_in_lb | sed 's/table=..//'], [0], [dnl
-  (ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0 = 0; reject { outport <-> inport; next(pipeline=egress,table=5);};)
+  (ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0 = 0; reject { outport <-> inport; next(pipeline=egress,table=6);};)
 ])
 
 AT_CLEANUP
@@ -2161,10 +2161,10 @@  AT_CAPTURE_FILE([sw1flows])
 
 AT_CHECK(
   [grep -E 'ls_(in|out)_acl' sw0flows sw1flows | grep pg0 | sort], [0], [dnl
-sw0flows:  table=4 (ls_out_acl         ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
-sw0flows:  table=8 (ls_in_acl          ), priority=2002 , match=(inport == @pg0 && ip4 && tcp && tcp.dst == 80), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=5); };)
-sw1flows:  table=4 (ls_out_acl         ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
-sw1flows:  table=8 (ls_in_acl          ), priority=2002 , match=(inport == @pg0 && ip4 && tcp && tcp.dst == 80), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=5); };)
+sw0flows:  table=4 (ls_out_acl_eval    ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg8[[18]] = 1; next;)
+sw0flows:  table=8 (ls_in_acl_eval     ), priority=2002 , match=(inport == @pg0 && ip4 && tcp && tcp.dst == 80), action=(reg8[[18]] = 1; next;)
+sw1flows:  table=4 (ls_out_acl_eval    ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg8[[18]] = 1; next;)
+sw1flows:  table=8 (ls_in_acl_eval     ), priority=2002 , match=(inport == @pg0 && ip4 && tcp && tcp.dst == 80), action=(reg8[[18]] = 1; next;)
 ])
 
 AS_BOX([2])
@@ -2177,10 +2177,10 @@  ovn-sbctl dump-flows sw1 > sw1flows2
 AT_CAPTURE_FILE([sw1flows2])
 
 AT_CHECK([grep "ls_out_acl" sw0flows2 sw1flows2 | grep pg0 | sort], [0], [dnl
-sw0flows2:  table=4 (ls_out_acl         ), priority=2002 , match=(outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
-sw0flows2:  table=4 (ls_out_acl         ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
-sw1flows2:  table=4 (ls_out_acl         ), priority=2002 , match=(outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
-sw1flows2:  table=4 (ls_out_acl         ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
+sw0flows2:  table=4 (ls_out_acl_eval    ), priority=2002 , match=(outport == @pg0 && ip4 && udp), action=(reg8[[18]] = 1; next;)
+sw0flows2:  table=4 (ls_out_acl_eval    ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg8[[18]] = 1; next;)
+sw1flows2:  table=4 (ls_out_acl_eval    ), priority=2002 , match=(outport == @pg0 && ip4 && udp), action=(reg8[[18]] = 1; next;)
+sw1flows2:  table=4 (ls_out_acl_eval    ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg8[[18]] = 1; next;)
 ])
 
 AS_BOX([3])
@@ -2193,19 +2193,20 @@  ovn-sbctl dump-flows sw1 > sw1flows3
 AT_CAPTURE_FILE([sw1flows3])
 
 AT_CHECK([grep "ls_out_acl" sw0flows3 sw1flows3 | grep pg0 | sort], [0], [dnl
-sw0flows3:  table=4 (ls_out_acl         ), priority=2001 , match=(reg0[[7]] == 1 && (outport == @pg0 && ip)), action=(reg0[[1]] = 1; next;)
-sw0flows3:  table=4 (ls_out_acl         ), priority=2001 , match=(reg0[[8]] == 1 && (outport == @pg0 && ip)), action=(next;)
-sw0flows3:  table=4 (ls_out_acl         ), priority=2002 , match=((reg0[[10]] == 1) && outport == @pg0 && ip4 && udp), action=(ct_commit { ct_mark.blocked = 1; };  reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
-sw0flows3:  table=4 (ls_out_acl         ), priority=2002 , match=((reg0[[9]] == 1) && outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
-sw0flows3:  table=4 (ls_out_acl         ), priority=2003 , match=((reg0[[10]] == 1) && outport == @pg0 && ip6 && udp), action=(ct_commit { ct_mark.blocked = 1; };  reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
-sw0flows3:  table=4 (ls_out_acl         ), priority=2003 , match=((reg0[[9]] == 1) && outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
-sw1flows3:  table=4 (ls_out_acl         ), priority=2001 , match=(reg0[[7]] == 1 && (outport == @pg0 && ip)), action=(reg0[[1]] = 1; next;)
-sw1flows3:  table=4 (ls_out_acl         ), priority=2001 , match=(reg0[[8]] == 1 && (outport == @pg0 && ip)), action=(next;)
-sw1flows3:  table=4 (ls_out_acl         ), priority=2002 , match=((reg0[[10]] == 1) && outport == @pg0 && ip4 && udp), action=(ct_commit { ct_mark.blocked = 1; };  reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
-sw1flows3:  table=4 (ls_out_acl         ), priority=2002 , match=((reg0[[9]] == 1) && outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
-sw1flows3:  table=4 (ls_out_acl         ), priority=2003 , match=((reg0[[10]] == 1) && outport == @pg0 && ip6 && udp), action=(ct_commit { ct_mark.blocked = 1; };  reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
-sw1flows3:  table=4 (ls_out_acl         ), priority=2003 , match=((reg0[[9]] == 1) && outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
+sw0flows3:  table=4 (ls_out_acl_eval    ), priority=2001 , match=(reg0[[7]] == 1 && (outport == @pg0 && ip)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
+sw0flows3:  table=4 (ls_out_acl_eval    ), priority=2001 , match=(reg0[[8]] == 1 && (outport == @pg0 && ip)), action=(reg8[[16]] = 1; next;)
+sw0flows3:  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[10]] == 1 && (outport == @pg0 && ip4 && udp)), action=(reg8[[18]] = 1; ct_commit { ct_mark.blocked = 1; }; next;)
+sw0flows3:  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[9]] == 1 && (outport == @pg0 && ip4 && udp)), action=(reg8[[18]] = 1; next;)
+sw0flows3:  table=4 (ls_out_acl_eval    ), priority=2003 , match=(reg0[[10]] == 1 && (outport == @pg0 && ip6 && udp)), action=(reg8[[18]] = 1; ct_commit { ct_mark.blocked = 1; }; next;)
+sw0flows3:  table=4 (ls_out_acl_eval    ), priority=2003 , match=(reg0[[9]] == 1 && (outport == @pg0 && ip6 && udp)), action=(reg8[[18]] = 1; next;)
+sw1flows3:  table=4 (ls_out_acl_eval    ), priority=2001 , match=(reg0[[7]] == 1 && (outport == @pg0 && ip)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
+sw1flows3:  table=4 (ls_out_acl_eval    ), priority=2001 , match=(reg0[[8]] == 1 && (outport == @pg0 && ip)), action=(reg8[[16]] = 1; next;)
+sw1flows3:  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[10]] == 1 && (outport == @pg0 && ip4 && udp)), action=(reg8[[18]] = 1; ct_commit { ct_mark.blocked = 1; }; next;)
+sw1flows3:  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[9]] == 1 && (outport == @pg0 && ip4 && udp)), action=(reg8[[18]] = 1; next;)
+sw1flows3:  table=4 (ls_out_acl_eval    ), priority=2003 , match=(reg0[[10]] == 1 && (outport == @pg0 && ip6 && udp)), action=(reg8[[18]] = 1; ct_commit { ct_mark.blocked = 1; }; next;)
+sw1flows3:  table=4 (ls_out_acl_eval    ), priority=2003 , match=(reg0[[9]] == 1 && (outport == @pg0 && ip6 && udp)), action=(reg8[[18]] = 1; next;)
 ])
+
 AT_CLEANUP
 ])
 
@@ -2454,11 +2455,11 @@  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), 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=(ct_commit_nat;)
-  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;)
+  table=4 (ls_out_acl_eval    ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
+  table=4 (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
   table=7 (ls_in_acl_hint     ), priority=1    , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
   table=7 (ls_in_acl_hint     ), priority=2    , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
   table=7 (ls_in_acl_hint     ), priority=3    , match=(!ct.est), action=(reg0[[9]] = 1; next;)
@@ -2466,11 +2467,11 @@  AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e
   table=7 (ls_in_acl_hint     ), priority=5    , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
   table=7 (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=7 (ls_in_acl_hint     ), priority=7    , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
-  table=8 (ls_in_acl          ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
-  table=8 (ls_in_acl          ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
-  table=8 (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;)
-  table=8 (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; reg0[[17]] = 1; next;)
-  table=8 (ls_in_acl          ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
+  table=8 (ls_in_acl_eval     ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
+  table=8 (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
 ])
 
 AS_BOX([Check match ct_state with load balancer])
@@ -2480,10 +2481,10 @@  check ovn-nbctl --wait=sb \
     -- lb-add lb "10.0.0.1" "10.0.0.2" \
     -- ls-lb-add ls lb
 
-AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e ls_in_acl -e ls_out_acl | sort], [0], [dnl
-  table=17(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
-  table=17(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  table=17(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
+AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e ls_in_acl_eval -e ls_out_acl_eval -e ls_in_acl_after_lb_eval | sort], [0], [dnl
+  table=18(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=18(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=18(ls_in_acl_after_lb_eval), priority=65532, match=(reg0[[17]] == 1), action=(reg8[[16]] = 1; next;)
   table=3 (ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
   table=3 (ls_out_acl_hint    ), priority=1    , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
   table=3 (ls_out_acl_hint    ), priority=2    , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
@@ -2492,16 +2493,16 @@  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=0    , match=(1), action=(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;)
-  table=4 (ls_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(ct_commit_nat;)
-  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;)
-  table=4 (ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=4 (ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
+  table=4 (ls_out_acl_eval    ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=1001 , match=(reg0[[7]] == 1 && (ip)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=1001 , match=(reg0[[8]] == 1 && (ip)), action=(reg8[[16]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
+  table=4 (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
   table=7 (ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
   table=7 (ls_in_acl_hint     ), priority=1    , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
   table=7 (ls_in_acl_hint     ), priority=2    , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
@@ -2510,30 +2511,30 @@  AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e
   table=7 (ls_in_acl_hint     ), priority=5    , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
   table=7 (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=7 (ls_in_acl_hint     ), priority=7    , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
-  table=8 (ls_in_acl          ), priority=0    , match=(1), action=(next;)
-  table=8 (ls_in_acl          ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
-  table=8 (ls_in_acl          ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
-  table=8 (ls_in_acl          ), priority=1001 , match=(reg0[[7]] == 1 && (ip)), action=(reg0[[1]] = 1; next;)
-  table=8 (ls_in_acl          ), priority=1001 , match=(reg0[[8]] == 1 && (ip)), action=(next;)
-  table=8 (ls_in_acl          ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
-  table=8 (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;)
-  table=8 (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; reg0[[17]] = 1; next;)
-  table=8 (ls_in_acl          ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
-  table=8 (ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=8 (ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
+  table=8 (ls_in_acl_eval     ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=1001 , match=(reg0[[7]] == 1 && (ip)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=1001 , match=(reg0[[8]] == 1 && (ip)), action=(reg8[[16]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
+  table=8 (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
 ])
 
 ovn-nbctl --wait=sb clear logical_switch ls acls
 ovn-nbctl --wait=sb clear logical_switch ls load_balancer
 
-AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e ls_in_acl -e ls_out_acl | sort], [0], [dnl
-  table=17(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
-  table=17(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e ls_in_acl_eval -e ls_out_acl_eval -e ls_in_acl_after_lb_eval | sort], [0], [dnl
+  table=18(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=18(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
   table=3 (ls_out_acl_hint    ), priority=65535, match=(1), action=(next;)
-  table=4 (ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  table=4 (ls_out_acl         ), priority=65535, match=(1), action=(next;)
+  table=4 (ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=65535, match=(1), action=(next;)
   table=7 (ls_in_acl_hint     ), priority=65535, match=(1), action=(next;)
-  table=8 (ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  table=8 (ls_in_acl          ), priority=65535, match=(1), action=(next;)
+  table=8 (ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=65535, match=(1), action=(next;)
 ])
 
 
@@ -4255,10 +4256,10 @@  check_stateful_flows() {
 
     AT_CHECK([grep "ls_out_lb" sw0flows | sort], [0], [])
 
-    AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl
-  table=7 (ls_out_stateful    ), priority=0    , match=(1), action=(next;)
-  table=7 (ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
-  table=7 (ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
+    AT_CHECK([grep "ls_out_stateful" sw0flows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_out_stateful    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
+  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
 ])
 }
 
@@ -4318,19 +4319,19 @@  AT_CHECK([grep "ls_out_pre_stateful" sw0flows | sort], [0], [dnl
   table=2 (ls_out_pre_stateful), priority=110  , match=(reg0[[2]] == 1), action=(ct_lb_mark;)
 ])
 
-AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl
-  table=7 (ls_out_stateful    ), priority=0    , match=(1), action=(next;)
-  table=7 (ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
-  table=7 (ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
+AT_CHECK([grep "ls_out_stateful" sw0flows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_out_stateful    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
+  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
 ])
 
 # LB with event=false and reject=false
 AT_CHECK([ovn-nbctl create load_balancer name=lb1 options:reject=false options:event=false vips:\"10.0.0.20\"=\"\" protocol=tcp], [0], [ignore])
 check ovn-nbctl --wait=sb ls-lb-add sw0 lb1
 
-AT_CHECK([ovn-sbctl dump-flows sw0 | grep "ls_in_lb " | sort ], [0], [dnl
-  table=12(ls_in_lb           ), priority=0    , match=(1), action=(next;)
-  table=12(ls_in_lb           ), priority=110  , match=(ct.new && ip4.dst == 10.0.0.20), action=(drop;)
+AT_CHECK([ovn-sbctl dump-flows sw0 | grep "ls_in_lb " | sed 's/table=../table=??/' | sort ], [0], [dnl
+  table=??(ls_in_lb           ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_lb           ), priority=110  , match=(ct.new && ip4.dst == 10.0.0.20), action=(drop;)
 ])
 
 AT_CLEANUP
@@ -4349,9 +4350,9 @@  check ovn-nbctl --wait=sb --label=1234 acl-add sw0 from-lport 1002 tcp allow-rel
 ovn-sbctl dump-flows sw0 > sw0flows
 AT_CAPTURE_FILE([sw0flows])
 
-AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 2002 | sort | sed 's/table=./table=?/'], [0], [dnl
-  table=? (ls_in_acl          ), priority=2002 , match=(reg0[[7]] == 1 && (tcp)), action=(reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
-  table=? (ls_in_acl          ), priority=2002 , match=(reg0[[8]] == 1 && (tcp)), action=(reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
+AT_CHECK([grep -w "ls_in_acl_eval" sw0flows | grep 2002 | sort | sed 's/table=./table=?/'], [0], [dnl
+  table=? (ls_in_acl_eval     ), priority=2002 , match=(reg0[[7]] == 1 && (tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
+  table=? (ls_in_acl_eval     ), priority=2002 , match=(reg0[[8]] == 1 && (tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
 ])
 AT_CHECK([grep "ls_in_stateful" sw0flows | sort | sed 's/table=../table=??/'], [0], [dnl
   table=??(ls_in_stateful     ), priority=0    , match=(1), action=(next;)
@@ -4359,14 +4360,14 @@  AT_CHECK([grep "ls_in_stateful" sw0flows | sort | sed 's/table=../table=??/'], [
   table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
 ])
 
-AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 2002 | sort], [0], [dnl
-  table=4 (ls_out_acl         ), priority=2002 , match=(reg0[[7]] == 1 && (tcp)), action=(reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
-  table=4 (ls_out_acl         ), priority=2002 , match=(reg0[[8]] == 1 && (tcp)), action=(reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
+AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep 2002 | sort], [0], [dnl
+  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[7]] == 1 && (tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
+  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[8]] == 1 && (tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
 ])
-AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl
-  table=7 (ls_out_stateful    ), priority=0    , match=(1), action=(next;)
-  table=7 (ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
-  table=7 (ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
+AT_CHECK([grep "ls_out_stateful" sw0flows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_out_stateful    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
+  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
 ])
 
 # Add new ACL without label
@@ -4376,11 +4377,11 @@  check ovn-nbctl --wait=sb acl-add sw0 from-lport 1002 udp allow-related
 ovn-sbctl dump-flows sw0 > sw0flows
 AT_CAPTURE_FILE([sw0flows])
 
-AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 2002 | sort | sed 's/table=./table=?/'], [0], [dnl
-  table=? (ls_in_acl          ), priority=2002 , match=(reg0[[7]] == 1 && (tcp)), action=(reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
-  table=? (ls_in_acl          ), priority=2002 , match=(reg0[[7]] == 1 && (udp)), action=(reg0[[1]] = 1; next;)
-  table=? (ls_in_acl          ), priority=2002 , match=(reg0[[8]] == 1 && (tcp)), action=(reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
-  table=? (ls_in_acl          ), priority=2002 , match=(reg0[[8]] == 1 && (udp)), action=(next;)
+AT_CHECK([grep -w "ls_in_acl_eval" sw0flows | grep 2002 | sort | sed 's/table=./table=?/'], [0], [dnl
+  table=? (ls_in_acl_eval     ), priority=2002 , match=(reg0[[7]] == 1 && (tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
+  table=? (ls_in_acl_eval     ), priority=2002 , match=(reg0[[7]] == 1 && (udp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
+  table=? (ls_in_acl_eval     ), priority=2002 , match=(reg0[[8]] == 1 && (tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
+  table=? (ls_in_acl_eval     ), priority=2002 , match=(reg0[[8]] == 1 && (udp)), action=(reg8[[16]] = 1; next;)
 ])
 AT_CHECK([grep "ls_in_stateful" sw0flows | sort | sed 's/table=../table=??/'], [0], [dnl
   table=??(ls_in_stateful     ), priority=0    , match=(1), action=(next;)
@@ -4388,16 +4389,16 @@  AT_CHECK([grep "ls_in_stateful" sw0flows | sort | sed 's/table=../table=??/'], [
   table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
 ])
 
-AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 2002 | sort], [0], [dnl
-  table=4 (ls_out_acl         ), priority=2002 , match=(reg0[[7]] == 1 && (tcp)), action=(reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
-  table=4 (ls_out_acl         ), priority=2002 , match=(reg0[[7]] == 1 && (udp)), action=(reg0[[1]] = 1; next;)
-  table=4 (ls_out_acl         ), priority=2002 , match=(reg0[[8]] == 1 && (tcp)), action=(reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
-  table=4 (ls_out_acl         ), priority=2002 , match=(reg0[[8]] == 1 && (udp)), action=(next;)
+AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep 2002 | sort], [0], [dnl
+  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[7]] == 1 && (tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
+  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[7]] == 1 && (udp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[8]] == 1 && (tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;)
+  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[8]] == 1 && (udp)), action=(reg8[[16]] = 1; next;)
 ])
-AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl
-  table=7 (ls_out_stateful    ), priority=0    , match=(1), action=(next;)
-  table=7 (ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
-  table=7 (ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
+AT_CHECK([grep "ls_out_stateful" sw0flows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_out_stateful    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
+  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
 ])
 
 # Delete new ACL with label
@@ -4407,9 +4408,9 @@  check ovn-nbctl --wait=sb acl-del sw0 from-lport 1002 tcp
 ovn-sbctl dump-flows sw0 > sw0flows
 AT_CAPTURE_FILE([sw0flows])
 
-AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 2002 | sort | sed 's/table=./table=?/'], [0], [dnl
-  table=? (ls_in_acl          ), priority=2002 , match=(reg0[[7]] == 1 && (udp)), action=(reg0[[1]] = 1; next;)
-  table=? (ls_in_acl          ), priority=2002 , match=(reg0[[8]] == 1 && (udp)), action=(next;)
+AT_CHECK([grep -w "ls_in_acl_eval" sw0flows | grep 2002 | sort | sed 's/table=./table=?/'], [0], [dnl
+  table=? (ls_in_acl_eval     ), priority=2002 , match=(reg0[[7]] == 1 && (udp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
+  table=? (ls_in_acl_eval     ), priority=2002 , match=(reg0[[8]] == 1 && (udp)), action=(reg8[[16]] = 1; next;)
 ])
 AT_CHECK([grep "ls_in_stateful" sw0flows | sort | sed 's/table=../table=??/'], [0], [dnl
   table=??(ls_in_stateful     ), priority=0    , match=(1), action=(next;)
@@ -4417,14 +4418,14 @@  AT_CHECK([grep "ls_in_stateful" sw0flows | sort | sed 's/table=../table=??/'], [
   table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
 ])
 
-AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 2002 | sort], [0], [dnl
-  table=4 (ls_out_acl         ), priority=2002 , match=(reg0[[7]] == 1 && (udp)), action=(reg0[[1]] = 1; next;)
-  table=4 (ls_out_acl         ), priority=2002 , match=(reg0[[8]] == 1 && (udp)), action=(next;)
+AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep 2002 | sort], [0], [dnl
+  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[7]] == 1 && (udp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=2002 , match=(reg0[[8]] == 1 && (udp)), action=(reg8[[16]] = 1; next;)
 ])
-AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl
-  table=7 (ls_out_stateful    ), priority=0    , match=(1), action=(next;)
-  table=7 (ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
-  table=7 (ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
+AT_CHECK([grep "ls_out_stateful" sw0flows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_out_stateful    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
+  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
 ])
 AT_CLEANUP
 ])
@@ -4441,18 +4442,18 @@  check ovn-nbctl --wait=sb acl-add sw0 to-lport 1002 ip allow-related
 ovn-sbctl dump-flows sw0 > sw0flows
 AT_CAPTURE_FILE([sw0flows])
 
-AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
-  table=? (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;)
-  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; reg0[[17]] = 1; 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;)
+AT_CHECK([grep -w "ls_in_acl_eval" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
+  table=? (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
+  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
+  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=? (ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
 ])
 
-AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
-  table=? (ls_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(ct_commit_nat;)
-  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;)
+AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
+  table=? (ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
+  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
+  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=? (ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
 ])
 
 # Disable ct.inv usage.
@@ -4461,18 +4462,18 @@  check ovn-nbctl --wait=sb set NB_Global . options:use_ct_inv_match=false
 ovn-sbctl dump-flows sw0 > sw0flows
 AT_CAPTURE_FILE([sw0flows])
 
-AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
-  table=? (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;)
-  table=? (ls_in_acl          ), priority=65532, match=((ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
-  table=? (ls_in_acl          ), priority=65532, match=(ct.est && !ct.rel && !ct.new && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; next;)
-  table=? (ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+AT_CHECK([grep -w "ls_in_acl_eval" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
+  table=? (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
+  table=? (ls_in_acl_eval     ), priority=65532, match=((ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
+  table=? (ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
 ])
 
-AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
-  table=? (ls_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && ct_mark.blocked == 0), action=(ct_commit_nat;)
-  table=? (ls_out_acl         ), priority=65532, match=((ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
-  table=? (ls_out_acl         ), priority=65532, match=(ct.est && !ct.rel && !ct.new && ct.rpl && ct_mark.blocked == 0), action=(next;)
-  table=? (ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
+  table=? (ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
+  table=? (ls_out_acl_eval    ), priority=65532, match=((ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
+  table=? (ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
 ])
 
 AT_CHECK([grep -c "ct.inv" sw0flows], [1], [dnl
@@ -4485,18 +4486,18 @@  check ovn-nbctl --wait=sb set NB_Global . options:use_ct_inv_match=true
 ovn-sbctl dump-flows sw0 > sw0flows
 AT_CAPTURE_FILE([sw0flows])
 
-AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
-  table=? (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;)
-  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; reg0[[17]] = 1; 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;)
+AT_CHECK([grep -w "ls_in_acl_eval" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
+  table=? (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
+  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
+  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=? (ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
 ])
 
-AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
-  table=? (ls_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(ct_commit_nat;)
-  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;)
+AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl
+  table=? (ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
+  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
+  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=? (ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
 ])
 
 AT_CHECK([grep -c "ct.inv" sw0flows], [0], [dnl
@@ -6722,7 +6723,7 @@  set_acl_options() {
 }
 
 record_log_flows() {
-    ovn-sbctl lflow-list sw0 | grep -E 'ls_(out|in)_acl.*, priority=65533' | sed 's/table=../table=??/' | sort > log_flows
+    ovn-sbctl lflow-list sw0 | grep -E 'ls_(out|in)_acl_eval.*, priority=65533' | sed 's/table=../table=??/' | sort > log_flows
 }
 
 check_log_flows_count() {
@@ -6732,9 +6733,9 @@  check_log_flows_count() {
 
     echo $table
     if test -f log_flows; then
-        count=$(grep -c -E ls_${table}_acl log_flows)
+        count=$(grep -c -E ls_${table}_acl_eval log_flows)
     else
-        count=$(ovn-sbctl lflow-list sw0 | grep -c -E "ls_$table_acl.*, priority=65533")
+        count=$(ovn-sbctl lflow-list sw0 | grep -c -E "ls_$table_acl_eval.*, priority=65533")
     fi
 
     check test "$count" -eq "$expected"
@@ -6778,10 +6779,10 @@  check_log_flows_count 0 in
 
 # Now ensure the flows are what we expect them to be for the ACLs we created
 AT_CHECK([cat log_flows], [0], [dnl
-  table=??(ls_out_acl         ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
-  table=??(ls_out_acl         ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
-  table=??(ls_out_acl         ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
-  table=??(ls_out_acl         ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
+  table=??(ls_out_acl_eval    ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
 ])
 
 rm log_flows
@@ -6799,10 +6800,10 @@  check_log_flows_count 0 in
 
 # And the log flows will remain the same since the stateless ACL will not be represented.
 AT_CHECK([cat log_flows], [0], [dnl
-  table=??(ls_out_acl         ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
-  table=??(ls_out_acl         ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
-  table=??(ls_out_acl         ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
-  table=??(ls_out_acl         ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
+  table=??(ls_out_acl_eval    ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
 ])
 
 rm log_flows
@@ -6821,8 +6822,8 @@  check_log_flows_count 0 in
 
 # And make sure only the allow ACL has the log flows installed
 AT_CHECK([cat log_flows], [0], [dnl
-  table=??(ls_out_acl         ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
-  table=??(ls_out_acl         ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
+  table=??(ls_out_acl_eval    ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
 ])
 
 rm log_flows
@@ -6838,8 +6839,8 @@  check_log_flows_count 0 in
 
 # And make sure only the allow ACL has the log flows installed
 AT_CHECK([cat log_flows], [0], [dnl
-  table=??(ls_out_acl         ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
-  table=??(ls_out_acl         ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
+  table=??(ls_out_acl_eval    ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
 ])
 
 rm log_flows
@@ -6883,10 +6884,10 @@  check_log_flows_count 0 out
 
 # Now ensure the flows are what we expect them to be for the ACLs we created
 AT_CHECK([cat log_flows], [0], [dnl
-  table=??(ls_in_acl          ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
-  table=??(ls_in_acl          ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
-  table=??(ls_in_acl          ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
-  table=??(ls_in_acl          ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
+  table=??(ls_in_acl_eval     ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
 ])
 
 rm log_flows
@@ -6904,10 +6905,10 @@  check_log_flows_count 0 out
 
 # And the log flows will remain the same since the stateless ACL will not be represented.
 AT_CHECK([cat log_flows], [0], [dnl
-  table=??(ls_in_acl          ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
-  table=??(ls_in_acl          ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
-  table=??(ls_in_acl          ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
-  table=??(ls_in_acl          ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
+  table=??(ls_in_acl_eval     ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
 ])
 
 rm log_flows
@@ -6926,8 +6927,8 @@  check_log_flows_count 0 out
 
 # And make sure only the allow ACL has the log flows installed
 AT_CHECK([cat log_flows], [0], [dnl
-  table=??(ls_in_acl          ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
-  table=??(ls_in_acl          ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
+  table=??(ls_in_acl_eval     ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
 ])
 
 rm log_flows
@@ -6943,8 +6944,8 @@  check_log_flows_count 0 out
 
 # And make sure only the allow ACL has the log flows installed
 AT_CHECK([cat log_flows], [0], [dnl
-  table=??(ls_in_acl          ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
-  table=??(ls_in_acl          ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
+  table=??(ls_in_acl_eval     ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); reg8[[16]] = 1; next;)
 ])
 
 rm log_flows
@@ -7027,26 +7028,26 @@  check ovn-nbctl --wait=sb sync
 ovn-sbctl dump-flows ls > lsflows
 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), 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;)
-  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;)
-  table=??(ls_in_acl          ), priority=2003 , match=(reg0[[8]] == 1 && (ip4 && icmp)), action=(next;)
-  table=??(ls_in_acl          ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */)
-  table=??(ls_in_acl          ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(/* drop */)
-  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=(reg0[[17]] = 1; ct_commit_nat;)
-  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; reg0[[17]] = 1; 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=(next;)
-  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
+AT_CHECK([grep -e "ls_in_acl.*eval" -e "ls_in_acl_hint" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(reg0[[17]] == 1), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(reg8[[17]] = 1; ct_commit { ct_mark.blocked = 1; }; next;)
+  table=??(ls_in_acl_eval     ), priority=2001 , match=(reg0[[9]] == 1 && (ip4)), action=(reg8[[17]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=2002 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=2002 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=2003 , match=(reg0[[7]] == 1 && (ip4 && icmp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=2003 , match=(reg0[[8]] == 1 && (ip4 && icmp)), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(reg8[[17]] = 1; ct_commit { ct_mark.blocked = 1; }; next;)
+  table=??(ls_in_acl_eval     ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(reg8[[17]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
@@ -7082,26 +7083,26 @@  check ovn-nbctl --wait=sb sync
 ovn-sbctl dump-flows ls > lsflows
 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), 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=(reg0[[17]] = 1; ct_commit_nat;)
-  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; reg0[[17]] = 1; 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=(next;)
-  table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */)
-  table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[9]] == 1 && (ip4)), action=(/* drop */)
-  table=??(ls_in_acl_after_lb ), priority=2002 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
-  table=??(ls_in_acl_after_lb ), priority=2002 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=2003 , match=(reg0[[7]] == 1 && (ip4 && icmp)), action=(reg0[[1]] = 1; next;)
-  table=??(ls_in_acl_after_lb ), priority=2003 , match=(reg0[[8]] == 1 && (ip4 && icmp)), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */)
-  table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(/* drop */)
-  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
+AT_CHECK([grep -e "ls_in_acl.*eval" -e "ls_in_acl_hint" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(reg8[[17]] = 1; ct_commit { ct_mark.blocked = 1; }; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=2001 , match=(reg0[[9]] == 1 && (ip4)), action=(reg8[[17]] = 1; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=2002 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=2002 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=2003 , match=(reg0[[7]] == 1 && (ip4 && icmp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=2003 , match=(reg0[[8]] == 1 && (ip4 && icmp)), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(reg8[[17]] = 1; ct_commit { ct_mark.blocked = 1; }; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(reg8[[17]] = 1; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(reg0[[17]] == 1), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
@@ -7137,26 +7138,26 @@  check ovn-nbctl --wait=sb sync
 ovn-sbctl dump-flows ls > lsflows
 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), 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;)
-  table=??(ls_in_acl          ), priority=2003 , match=(reg0[[8]] == 1 && (ip4 && icmp)), 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=(reg0[[17]] = 1; ct_commit_nat;)
-  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; reg0[[17]] = 1; 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=(next;)
-  table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */)
-  table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[9]] == 1 && (ip4)), action=(/* drop */)
-  table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */)
-  table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(/* drop */)
-  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
+AT_CHECK([grep -e "ls_in_acl.*eval" -e "ls_in_acl_hint" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(reg8[[17]] = 1; ct_commit { ct_mark.blocked = 1; }; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=2001 , match=(reg0[[9]] == 1 && (ip4)), action=(reg8[[17]] = 1; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(reg8[[17]] = 1; ct_commit { ct_mark.blocked = 1; }; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(reg8[[17]] = 1; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(reg0[[17]] == 1), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=2002 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=2002 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=2003 , match=(reg0[[7]] == 1 && (ip4 && icmp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=2003 , match=(reg0[[8]] == 1 && (ip4 && icmp)), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
@@ -7435,15 +7436,18 @@  flow="inport == \"lsp1\" && eth.src == 00:00:00:00:00:01 && eth.dst == 00:00:00:
 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=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  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_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65535, 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=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  table=??(ls_out_acl         ), priority=65535, match=(1), action=(next;)
+  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), 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;)
@@ -7457,15 +7461,18 @@  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=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  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_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65535, 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=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  table=??(ls_out_acl         ), priority=65535, match=(1), action=(next;)
+  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), 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;)
@@ -7479,15 +7486,18 @@  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=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  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_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65535, 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=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  table=??(ls_out_acl         ), priority=65535, match=(1), action=(next;)
+  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), 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;)
@@ -7505,18 +7515,30 @@  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          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=1001 , match=(ip4 && tcp), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
+  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
@@ -7530,18 +7552,30 @@  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          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=1001 , match=(ip4 && tcp), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
+  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
@@ -7555,18 +7589,30 @@  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          ), 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=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=1001 , match=(ip4 && tcp), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
+  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
@@ -7580,19 +7626,27 @@  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=(reg0[[17]] = 1; ct_commit_nat;)
-  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; reg0[[17]] = 1; 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=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
+  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(reg0[[17]] == 1), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && !ct.est), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=1001 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=1001 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
@@ -7606,14 +7660,18 @@  AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/
   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=(ct_commit_nat;)
-  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_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
+  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl_eval    ), priority=1    , match=(ip && !ct.est), action=(next;)
+  table=??(ls_out_acl_eval    ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
@@ -7641,18 +7699,30 @@  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          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), 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_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=1001 , match=(ip4 && tcp), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
+  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
@@ -7666,18 +7736,30 @@  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          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), 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_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=1001 , match=(ip4 && tcp), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
+  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
@@ -7691,18 +7773,30 @@  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          ), 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=(ip4 && tcp), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=1001 , match=(ip4 && tcp), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
+  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
@@ -7716,19 +7810,27 @@  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=(reg0[[17]] = 1; ct_commit_nat;)
-  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; reg0[[17]] = 1; 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_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
+  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=1001 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=1001 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(reg0[[17]] == 1), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && !ct.est), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
@@ -7742,14 +7844,18 @@  AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/
   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=(ct_commit_nat;)
-  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_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
+  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl_eval    ), priority=1    , match=(ip && !ct.est), action=(next;)
+  table=??(ls_out_acl_eval    ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
@@ -7777,18 +7883,30 @@  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          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
+  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl_eval    ), priority=1001 , match=(ip4 && tcp), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
@@ -7802,18 +7920,30 @@  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          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
+  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl_eval    ), priority=1001 , match=(ip4 && tcp), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
@@ -7827,18 +7957,30 @@  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          ), 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=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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=1001 , match=(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=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
+  table=??(ls_out_acl_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
+  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl_eval    ), priority=1001 , match=(ip4 && tcp), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
@@ -7852,17 +7994,25 @@  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=(reg0[[17]] = 1; ct_commit_nat;)
-  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; reg0[[17]] = 1; 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=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
+  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_action   ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_in_acl_after_lb_action), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };)
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=65532, match=(reg0[[17]] == 1), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && !ct.est), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=??(ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
@@ -7876,16 +8026,20 @@  AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/
   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=(ct_commit_nat;)
-  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_action  ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[16]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[17]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; /* drop */)
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
+  table=??(ls_out_acl_eval    ), priority=0    , match=(1), action=(next;)
+  table=??(ls_out_acl_eval    ), priority=1    , match=(ip && !ct.est), action=(next;)
+  table=??(ls_out_acl_eval    ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=1001 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=1001 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=??(ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; 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;)
@@ -8038,6 +8192,8 @@  sort | sed 's/table=../table=??/' ], [0], [dnl
   table=??(ls_in_check_port_sec), priority=50   , match=(1), action=(reg0[[15]] = check_in_port_sec(); next;)
   table=??(ls_in_apply_port_sec), priority=0    , match=(1), action=(next;)
   table=??(ls_in_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
+  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
+  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
   table=??(ls_in_l2_lkup      ), priority=0    , match=(1), action=(outport = get_fdb(eth.dst); next;)
   table=??(ls_in_l2_lkup      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
   table=??(ls_in_l2_lkup      ), priority=70   , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
@@ -8045,8 +8201,6 @@  sort | sed 's/table=../table=??/' ], [0], [dnl
   table=??(ls_in_l2_unknown   ), priority=50   , match=(outport == "none"), action=(drop;)
   table=??(ls_out_check_port_sec), priority=0    , match=(1), action=(reg0[[15]] = check_out_port_sec(); next;)
   table=??(ls_out_check_port_sec), priority=100  , match=(eth.mcast), action=(reg0[[15]] = 0; next;)
-  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
-  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
 ])
 
 check ovn-nbctl lsp-add sw0 sw0p1 -- lsp-set-addresses sw0p1 "00:00:00:00:00:01"
@@ -8063,6 +8217,8 @@  sort | sed 's/table=../table=??/' ], [0], [dnl
   table=??(ls_in_check_port_sec), priority=50   , match=(1), action=(reg0[[15]] = check_in_port_sec(); next;)
   table=??(ls_in_apply_port_sec), priority=0    , match=(1), action=(next;)
   table=??(ls_in_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
+  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
+  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
   table=??(ls_in_l2_lkup      ), priority=0    , match=(1), action=(outport = get_fdb(eth.dst); next;)
   table=??(ls_in_l2_lkup      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
   table=??(ls_in_l2_lkup      ), priority=50   , match=(eth.dst == 00:00:00:00:00:01), action=(outport = "sw0p1"; output;)
@@ -8072,8 +8228,6 @@  sort | sed 's/table=../table=??/' ], [0], [dnl
   table=??(ls_in_l2_unknown   ), priority=50   , match=(outport == "none"), action=(drop;)
   table=??(ls_out_check_port_sec), priority=0    , match=(1), action=(reg0[[15]] = check_out_port_sec(); next;)
   table=??(ls_out_check_port_sec), priority=100  , match=(eth.mcast), action=(reg0[[15]] = 0; next;)
-  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
-  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
 ])
 
 check ovn-nbctl lsp-set-port-security sw0p1 "00:00:00:00:00:01 10.0.0.3 1000::3"
@@ -8089,6 +8243,8 @@  sort | sed 's/table=../table=??/' ], [0], [dnl
   table=??(ls_in_check_port_sec), priority=50   , match=(1), action=(reg0[[15]] = check_in_port_sec(); next;)
   table=??(ls_in_apply_port_sec), priority=0    , match=(1), action=(next;)
   table=??(ls_in_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
+  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
+  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
   table=??(ls_in_l2_lkup      ), priority=0    , match=(1), action=(outport = get_fdb(eth.dst); next;)
   table=??(ls_in_l2_lkup      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
   table=??(ls_in_l2_lkup      ), priority=50   , match=(eth.dst == 00:00:00:00:00:01), action=(outport = "sw0p1"; output;)
@@ -8098,8 +8254,6 @@  sort | sed 's/table=../table=??/' ], [0], [dnl
   table=??(ls_in_l2_unknown   ), priority=50   , match=(outport == "none"), action=(drop;)
   table=??(ls_out_check_port_sec), priority=0    , match=(1), action=(reg0[[15]] = check_out_port_sec(); next;)
   table=??(ls_out_check_port_sec), priority=100  , match=(eth.mcast), action=(reg0[[15]] = 0; next;)
-  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
-  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
 ])
 
 # Disable sw0p1
@@ -8116,6 +8270,8 @@  sort | sed 's/table=../table=??/' ], [0], [dnl
   table=??(ls_in_check_port_sec), priority=50   , match=(1), action=(reg0[[15]] = check_in_port_sec(); next;)
   table=??(ls_in_apply_port_sec), priority=0    , match=(1), action=(next;)
   table=??(ls_in_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
+  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
+  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
   table=??(ls_in_l2_lkup      ), priority=0    , match=(1), action=(outport = get_fdb(eth.dst); next;)
   table=??(ls_in_l2_lkup      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
   table=??(ls_in_l2_lkup      ), priority=50   , match=(eth.dst == 00:00:00:00:00:01), action=(drop;)
@@ -8126,8 +8282,6 @@  sort | sed 's/table=../table=??/' ], [0], [dnl
   table=??(ls_in_l2_unknown   ), priority=50   , match=(outport == "sw0p1"), action=(drop;)
   table=??(ls_out_check_port_sec), priority=0    , match=(1), action=(reg0[[15]] = check_out_port_sec(); next;)
   table=??(ls_out_check_port_sec), priority=100  , match=(eth.mcast), action=(reg0[[15]] = 0; next;)
-  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
-  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
 ])
 
 check ovn-nbctl --wait=sb lsp-set-options sw0p2 qdisc_queue_id=10
@@ -8143,6 +8297,9 @@  sort | sed 's/table=../table=??/' ], [0], [dnl
   table=??(ls_in_check_port_sec), priority=70   , match=(inport == "sw0p2"), action=(set_queue(10); reg0[[15]] = check_in_port_sec(); next;)
   table=??(ls_in_apply_port_sec), priority=0    , match=(1), action=(next;)
   table=??(ls_in_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
+  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
+  table=??(ls_out_apply_port_sec), priority=110  , match=(outport == "localnetport" && inport == "sw0p2"), action=(set_queue(10); output;)
+  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
   table=??(ls_in_l2_lkup      ), priority=0    , match=(1), action=(outport = get_fdb(eth.dst); next;)
   table=??(ls_in_l2_lkup      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
   table=??(ls_in_l2_lkup      ), priority=50   , match=(eth.dst == 00:00:00:00:00:01), action=(drop;)
@@ -8153,9 +8310,6 @@  sort | sed 's/table=../table=??/' ], [0], [dnl
   table=??(ls_in_l2_unknown   ), priority=50   , match=(outport == "sw0p1"), action=(drop;)
   table=??(ls_out_check_port_sec), priority=0    , match=(1), action=(reg0[[15]] = check_out_port_sec(); next;)
   table=??(ls_out_check_port_sec), priority=100  , match=(eth.mcast), action=(reg0[[15]] = 0; next;)
-  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
-  table=??(ls_out_apply_port_sec), priority=110  , match=(outport == "localnetport" && inport == "sw0p2"), action=(set_queue(10); output;)
-  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
 ])
 
 check ovn-nbctl set logical_switch_port sw0p1 enabled=true
@@ -8170,10 +8324,14 @@  sort | sed 's/table=../table=??/' ], [0], [dnl
   table=??(ls_in_check_port_sec), priority=100  , match=(vlan.present), action=(drop;)
   table=??(ls_in_check_port_sec), priority=50   , match=(1), action=(reg0[[15]] = check_in_port_sec(); next;)
   table=??(ls_in_check_port_sec), priority=70   , match=(inport == "localnetport"), action=(set_queue(10); reg0[[15]] = check_in_port_sec(); next;)
-  table=??(ls_in_check_port_sec), priority=70   , match=(inport == "sw0p1"), action=(reg0[[14]] = 1; next(pipeline=ingress, table=16);)
+  table=??(ls_in_check_port_sec), priority=70   , match=(inport == "sw0p1"), action=(reg0[[14]] = 1; next(pipeline=ingress, table=17);)
   table=??(ls_in_check_port_sec), priority=70   , match=(inport == "sw0p2"), action=(set_queue(10); reg0[[15]] = check_in_port_sec(); next;)
   table=??(ls_in_apply_port_sec), priority=0    , match=(1), action=(next;)
   table=??(ls_in_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
+  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
+  table=??(ls_out_apply_port_sec), priority=100  , match=(outport == "localnetport"), action=(set_queue(10); output;)
+  table=??(ls_out_apply_port_sec), priority=110  , match=(outport == "localnetport" && inport == "sw0p2"), action=(set_queue(10); output;)
+  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
   table=??(ls_in_l2_lkup      ), priority=0    , match=(1), action=(outport = get_fdb(eth.dst); next;)
   table=??(ls_in_l2_lkup      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
   table=??(ls_in_l2_lkup      ), priority=50   , match=(eth.dst == 00:00:00:00:00:01), action=(outport = "sw0p1"; output;)
@@ -8183,10 +8341,6 @@  sort | sed 's/table=../table=??/' ], [0], [dnl
   table=??(ls_in_l2_unknown   ), priority=50   , match=(outport == "none"), action=(drop;)
   table=??(ls_out_check_port_sec), priority=0    , match=(1), action=(reg0[[15]] = check_out_port_sec(); next;)
   table=??(ls_out_check_port_sec), priority=100  , match=(eth.mcast), action=(reg0[[15]] = 0; next;)
-  table=??(ls_out_apply_port_sec), priority=0    , match=(1), action=(output;)
-  table=??(ls_out_apply_port_sec), priority=100  , match=(outport == "localnetport"), action=(set_queue(10); output;)
-  table=??(ls_out_apply_port_sec), priority=110  , match=(outport == "localnetport" && inport == "sw0p2"), action=(set_queue(10); output;)
-  table=??(ls_out_apply_port_sec), priority=50   , match=(reg0[[15]] == 1), action=(drop;)
 ])
 
 AT_CLEANUP
@@ -8214,7 +8368,7 @@  AT_CHECK([ovn-sbctl lflow-list | grep -e natted -e ct_lb], [0], [dnl
   table=7 (lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
   table=6 (ls_in_pre_stateful ), priority=120  , match=(reg0[[2]] == 1 && ip4.dst == 66.66.66.66), action=(reg1 = 66.66.66.66; ct_lb_mark;)
   table=6 (ls_in_pre_stateful ), priority=110  , match=(reg0[[2]] == 1), action=(ct_lb_mark;)
-  table=12(ls_in_lb           ), priority=110  , match=(ct.new && ip4.dst == 66.66.66.66), action=(reg0[[1]] = 0; ct_lb_mark(backends=42.42.42.2);)
+  table=13(ls_in_lb           ), priority=110  , match=(ct.new && ip4.dst == 66.66.66.66), action=(reg0[[1]] = 0; ct_lb_mark(backends=42.42.42.2);)
   table=2 (ls_out_pre_stateful), priority=110  , match=(reg0[[2]] == 1), action=(ct_lb_mark;)
 ])
 
@@ -8228,7 +8382,7 @@  AT_CHECK([ovn-sbctl lflow-list | grep -e natted -e ct_lb], [0], [dnl
   table=7 (lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_label.natted), action=(next;)
   table=6 (ls_in_pre_stateful ), priority=120  , match=(reg0[[2]] == 1 && ip4.dst == 66.66.66.66), action=(reg1 = 66.66.66.66; ct_lb;)
   table=6 (ls_in_pre_stateful ), priority=110  , match=(reg0[[2]] == 1), action=(ct_lb;)
-  table=12(ls_in_lb           ), priority=110  , match=(ct.new && ip4.dst == 66.66.66.66), action=(reg0[[1]] = 0; ct_lb(backends=42.42.42.2);)
+  table=13(ls_in_lb           ), priority=110  , match=(ct.new && ip4.dst == 66.66.66.66), action=(reg0[[1]] = 0; ct_lb(backends=42.42.42.2);)
   table=2 (ls_out_pre_stateful), priority=110  , match=(reg0[[2]] == 1), action=(ct_lb;)
 ])
 
@@ -8262,7 +8416,7 @@  AT_CHECK([ovn-sbctl lflow-list | grep -e natted -e ct_lb], [0], [dnl
   table=7 (lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
   table=6 (ls_in_pre_stateful ), priority=120  , match=(reg0[[2]] == 1 && ip4.dst == 66.66.66.66), action=(reg1 = 66.66.66.66; ct_lb_mark;)
   table=6 (ls_in_pre_stateful ), priority=110  , match=(reg0[[2]] == 1), action=(ct_lb_mark;)
-  table=12(ls_in_lb           ), priority=110  , match=(ct.new && ip4.dst == 66.66.66.66), action=(reg0[[1]] = 0; ct_lb_mark(backends=42.42.42.2);)
+  table=13(ls_in_lb           ), priority=110  , match=(ct.new && ip4.dst == 66.66.66.66), action=(reg0[[1]] = 0; ct_lb_mark(backends=42.42.42.2);)
   table=2 (ls_out_pre_stateful), priority=110  , match=(reg0[[2]] == 1), action=(ct_lb_mark;)
 ])
 
@@ -8287,18 +8441,18 @@  AT_CHECK([ovn-sbctl lflow-list | grep 'ls.*acl.*blocked' ], [0], [dnl
   table=7 (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=7 (ls_in_acl_hint     ), priority=2    , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
   table=7 (ls_in_acl_hint     ), priority=1    , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
-  table=8 (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;)
-  table=8 (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; reg0[[17]] = 1; next;)
-  table=8 (ls_in_acl          ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
-  table=8 (ls_in_acl          ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
+  table=8 (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 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=4    , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
   table=3 (ls_out_acl_hint    ), priority=2    , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
   table=3 (ls_out_acl_hint    ), priority=1    , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
-  table=4 (ls_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(ct_commit_nat;)
-  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;)
-  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_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
+  table=4 (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
 ])
 
 AS_BOX([Chassis registered that doesn't support ct_mark.blocked - use ct_label.blocked])
@@ -8309,18 +8463,18 @@  AT_CHECK([ovn-sbctl lflow-list | grep 'ls.*acl.*blocked' ], [0], [dnl
   table=7 (ls_in_acl_hint     ), priority=4    , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
   table=7 (ls_in_acl_hint     ), priority=2    , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;)
   table=7 (ls_in_acl_hint     ), priority=1    , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;)
-  table=8 (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(reg0[[17]] = 1; next;)
-  table=8 (ls_in_acl          ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; next;)
-  table=8 (ls_in_acl          ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
-  table=8 (ls_in_acl          ), priority=1    , match=(ip && ct.est && ct_label.blocked == 1), action=(reg0[[1]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_label.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
   table=3 (ls_out_acl_hint    ), priority=6    , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
   table=3 (ls_out_acl_hint    ), priority=4    , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
   table=3 (ls_out_acl_hint    ), priority=2    , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;)
   table=3 (ls_out_acl_hint    ), priority=1    , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;)
-  table=4 (ls_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
-  table=4 (ls_out_acl         ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;)
-  table=4 (ls_out_acl         ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
-  table=4 (ls_out_acl         ), priority=1    , match=(ip && ct.est && ct_label.blocked == 1), action=(reg0[[1]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(reg8[[16]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg8[[16]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=1    , match=(ip && ct.est && ct_label.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
 ])
 
 AS_BOX([Chassis upgrades and supports ct_mark.blocked - use ct_mark.blocked])
@@ -8331,18 +8485,18 @@  AT_CHECK([ovn-sbctl lflow-list | grep 'ls.*acl.*blocked' ], [0], [dnl
   table=7 (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=7 (ls_in_acl_hint     ), priority=2    , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
   table=7 (ls_in_acl_hint     ), priority=1    , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
-  table=8 (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; next;)
-  table=8 (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; reg0[[17]] = 1; next;)
-  table=8 (ls_in_acl          ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
-  table=8 (ls_in_acl          ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=8 (ls_in_acl_eval     ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 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=4    , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
   table=3 (ls_out_acl_hint    ), priority=2    , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
   table=3 (ls_out_acl_hint    ), priority=1    , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 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;)
-  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_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=4 (ls_out_acl_eval    ), priority=1    , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; reg8[[16]] = 1; next;)
 ])
 
 AT_CLEANUP
@@ -8424,11 +8578,11 @@  ovn-sbctl dump-flows S1 > S1flows
 AT_CAPTURE_FILE([S0flows])
 AT_CAPTURE_FILE([S1flows])
 
-AT_CHECK([grep "ls_in_lb " S0flows | sort], [0], [dnl
-  table=12(ls_in_lb           ), priority=0    , match=(1), action=(next;)
+AT_CHECK([grep "ls_in_lb " S0flows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_lb           ), priority=0    , match=(1), action=(next;)
 ])
-AT_CHECK([grep "ls_in_lb " S1flows | sort], [0], [dnl
-  table=12(ls_in_lb           ), priority=0    , match=(1), action=(next;)
+AT_CHECK([grep "ls_in_lb " S1flows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_lb           ), priority=0    , match=(1), action=(next;)
 ])
 
 ovn-nbctl --wait=sb set NB_Global . options:install_ls_lb_from_router=true
@@ -8439,15 +8593,15 @@  ovn-sbctl dump-flows S1 > S1flows
 AT_CAPTURE_FILE([S0flows])
 AT_CAPTURE_FILE([S1flows])
 
-AT_CHECK([grep "ls_in_lb " S0flows | sort], [0], [dnl
-  table=12(ls_in_lb           ), priority=0    , match=(1), action=(next;)
-  table=12(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 172.16.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:80);)
-  table=12(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 172.16.0.11 && tcp.dst == 8080), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:8080);)
+AT_CHECK([grep "ls_in_lb " S0flows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_lb           ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 172.16.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:80);)
+  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 172.16.0.11 && tcp.dst == 8080), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:8080);)
 ])
-AT_CHECK([grep "ls_in_lb " S1flows | sort], [0], [dnl
-  table=12(ls_in_lb           ), priority=0    , match=(1), action=(next;)
-  table=12(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 172.16.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:80);)
-  table=12(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 172.16.0.11 && tcp.dst == 8080), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:8080);)
+AT_CHECK([grep "ls_in_lb " S1flows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_lb           ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 172.16.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:80);)
+  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 172.16.0.11 && tcp.dst == 8080), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:8080);)
 ])
 
 ovn-sbctl get datapath S0 _uuid > dp_uuids
@@ -8466,11 +8620,11 @@  ovn-sbctl dump-flows S1 > S1flows
 AT_CAPTURE_FILE([S0flows])
 AT_CAPTURE_FILE([S1flows])
 
-AT_CHECK([grep "ls_in_lb " S0flows | sort], [0], [dnl
-  table=12(ls_in_lb           ), priority=0    , match=(1), action=(next;)
+AT_CHECK([grep "ls_in_lb " S0flows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_lb           ), priority=0    , match=(1), action=(next;)
 ])
-AT_CHECK([grep "ls_in_lb " S1flows | sort], [0], [dnl
-  table=12(ls_in_lb           ), priority=0    , match=(1), action=(next;)
+AT_CHECK([grep "ls_in_lb " S1flows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_lb           ), priority=0    , match=(1), action=(next;)
 ])
 
 check_column "" sb:load_balancer datapaths name=lb0
@@ -8550,18 +8704,18 @@  ovn-sbctl dump-flows R1 > R1flows
 AT_CAPTURE_FILE([S0flows])
 AT_CAPTURE_FILE([R1flows])
 
-AT_CHECK([grep "ls_in_lb_aff_check" S0flows | sort], [0], [dnl
-  table=11(ls_in_lb_aff_check ), priority=0    , match=(1), action=(next;)
+AT_CHECK([grep "ls_in_lb_aff_check" S0flows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_lb_aff_check ), priority=0    , match=(1), action=(next;)
 ])
-AT_CHECK([grep "ls_in_lb_aff_learn" S0flows | sort], [0], [dnl
-  table=13(ls_in_lb_aff_learn ), priority=0    , match=(1), action=(next;)
+AT_CHECK([grep "ls_in_lb_aff_learn" S0flows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_lb_aff_learn ), priority=0    , match=(1), action=(next;)
 ])
 
-AT_CHECK([grep "lr_in_lb_aff_check" R1flows | sort], [0], [dnl
-  table=6 (lr_in_lb_aff_check ), priority=0    , match=(1), action=(next;)
+AT_CHECK([grep "lr_in_lb_aff_check" R1flows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(lr_in_lb_aff_check ), priority=0    , match=(1), action=(next;)
 ])
-AT_CHECK([grep "lr_in_lb_aff_learn" R1flows | sort], [0], [dnl
-  table=8 (lr_in_lb_aff_learn ), priority=0    , match=(1), action=(next;)
+AT_CHECK([grep "lr_in_lb_aff_learn" R1flows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(lr_in_lb_aff_learn ), priority=0    , match=(1), action=(next;)
 ])
 
 ovn-nbctl --wait=sb set load_balancer lb0 options:affinity_timeout=60
@@ -8570,46 +8724,46 @@  AS_BOX([Test LS flows])
 ovn-sbctl dump-flows S0 > S0flows
 AT_CAPTURE_FILE([S0flows])
 
-AT_CHECK([grep "ls_in_lb_aff_check" S0flows | sort], [0], [dnl
-  table=11(ls_in_lb_aff_check ), priority=0    , match=(1), action=(next;)
-  table=11(ls_in_lb_aff_check ), priority=100  , match=(ct.new && ip4 && reg1 == 172.16.0.10 && reg2[[0..15]] == 80), action=(reg9[[6]] = chk_lb_aff(); next;)
+AT_CHECK([grep "ls_in_lb_aff_check" S0flows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_lb_aff_check ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_lb_aff_check ), priority=100  , match=(ct.new && ip4 && reg1 == 172.16.0.10 && reg2[[0..15]] == 80), action=(reg9[[6]] = chk_lb_aff(); next;)
 ])
-AT_CHECK([grep "ls_in_lb " S0flows | sort], [0], [dnl
-  table=12(ls_in_lb           ), priority=0    , match=(1), action=(next;)
-  table=12(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 172.16.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80);)
-  table=12(ls_in_lb           ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0[[1]] = 0; reg1 = 172.16.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.2:80);)
-  table=12(ls_in_lb           ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0[[1]] = 0; reg1 = 172.16.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=20.0.0.2:80);)
+AT_CHECK([grep "ls_in_lb " S0flows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_lb           ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 172.16.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80);)
+  table=??(ls_in_lb           ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0[[1]] = 0; reg1 = 172.16.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.2:80);)
+  table=??(ls_in_lb           ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0[[1]] = 0; reg1 = 172.16.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=20.0.0.2:80);)
 ])
-AT_CHECK([grep "ls_in_lb_aff_learn" S0flows | sort], [0], [dnl
-  table=13(ls_in_lb_aff_learn ), priority=0    , match=(1), action=(next;)
-  table=13(ls_in_lb_aff_learn ), priority=100  , match=(reg9[[6]] == 0 && ct.new && ip4 && reg1 == 172.16.0.10 && reg2[[0..15]] == 80 && ip4.dst == 10.0.0.2 && tcp.dst == 80), action=(commit_lb_aff(vip = "172.16.0.10:80", backend = "10.0.0.2:80", proto = tcp, timeout = 60); /* drop */)
-  table=13(ls_in_lb_aff_learn ), priority=100  , match=(reg9[[6]] == 0 && ct.new && ip4 && reg1 == 172.16.0.10 && reg2[[0..15]] == 80 && ip4.dst == 20.0.0.2 && tcp.dst == 80), action=(commit_lb_aff(vip = "172.16.0.10:80", backend = "20.0.0.2:80", proto = tcp, timeout = 60); /* drop */)
+AT_CHECK([grep "ls_in_lb_aff_learn" S0flows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_lb_aff_learn ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_lb_aff_learn ), priority=100  , match=(reg9[[6]] == 0 && ct.new && ip4 && reg1 == 172.16.0.10 && reg2[[0..15]] == 80 && ip4.dst == 10.0.0.2 && tcp.dst == 80), action=(commit_lb_aff(vip = "172.16.0.10:80", backend = "10.0.0.2:80", proto = tcp, timeout = 60); /* drop */)
+  table=??(ls_in_lb_aff_learn ), priority=100  , match=(reg9[[6]] == 0 && ct.new && ip4 && reg1 == 172.16.0.10 && reg2[[0..15]] == 80 && ip4.dst == 20.0.0.2 && tcp.dst == 80), action=(commit_lb_aff(vip = "172.16.0.10:80", backend = "20.0.0.2:80", proto = tcp, timeout = 60); /* drop */)
 ])
 
 AS_BOX([Test LR flows])
 ovn-sbctl dump-flows R1 > R1flows
 AT_CAPTURE_FILE([R1flows])
 
-AT_CHECK([grep "lr_in_lb_aff_check" R1flows | sort], [0], [dnl
-  table=6 (lr_in_lb_aff_check ), priority=0    , match=(1), action=(next;)
-  table=6 (lr_in_lb_aff_check ), priority=100  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(reg0 = ip4.dst; reg9[[16..31]] = tcp.dst; reg9[[6]] = chk_lb_aff(); next;)
+AT_CHECK([grep "lr_in_lb_aff_check" R1flows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(lr_in_lb_aff_check ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_lb_aff_check ), priority=100  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(reg0 = ip4.dst; reg9[[16..31]] = tcp.dst; reg9[[6]] = chk_lb_aff(); next;)
 ])
-AT_CHECK([grep "lr_in_dnat " R1flows | sort], [0], [dnl
-  table=7 (lr_in_dnat         ), priority=0    , match=(1), action=(next;)
-  table=7 (lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80);)
-  table=7 (lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; ct_lb_mark(backends=10.0.0.2:80);)
-  table=7 (lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; ct_lb_mark(backends=20.0.0.2:80);)
-  table=7 (lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
-  table=7 (lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-  table=7 (lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-  table=7 (lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
-  table=7 (lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
-  table=7 (lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
+AT_CHECK([grep "lr_in_dnat " R1flows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80);)
+  table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; ct_lb_mark(backends=10.0.0.2:80);)
+  table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; ct_lb_mark(backends=20.0.0.2:80);)
+  table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
+  table=??(lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
+  table=??(lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
+  table=??(lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
+  table=??(lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
+  table=??(lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
 ])
-AT_CHECK([grep "lr_in_lb_aff_learn" R1flows | sort], [0], [dnl
-  table=8 (lr_in_lb_aff_learn ), priority=0    , match=(1), action=(next;)
-  table=8 (lr_in_lb_aff_learn ), priority=100  , match=(reg9[[6]] == 0 && ct.new && ip4 && reg0 == 172.16.0.10 && reg9[[16..31]] == 80 && ip4.dst == 10.0.0.2 && tcp.dst == 80), action=(commit_lb_aff(vip = "172.16.0.10:80", backend = "10.0.0.2:80", proto = tcp, timeout = 60); /* drop */)
-  table=8 (lr_in_lb_aff_learn ), priority=100  , match=(reg9[[6]] == 0 && ct.new && ip4 && reg0 == 172.16.0.10 && reg9[[16..31]] == 80 && ip4.dst == 20.0.0.2 && tcp.dst == 80), action=(commit_lb_aff(vip = "172.16.0.10:80", backend = "20.0.0.2:80", proto = tcp, timeout = 60); /* drop */)
+AT_CHECK([grep "lr_in_lb_aff_learn" R1flows | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(lr_in_lb_aff_learn ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_lb_aff_learn ), priority=100  , match=(reg9[[6]] == 0 && ct.new && ip4 && reg0 == 172.16.0.10 && reg9[[16..31]] == 80 && ip4.dst == 10.0.0.2 && tcp.dst == 80), action=(commit_lb_aff(vip = "172.16.0.10:80", backend = "10.0.0.2:80", proto = tcp, timeout = 60); /* drop */)
+  table=??(lr_in_lb_aff_learn ), priority=100  , match=(reg9[[6]] == 0 && ct.new && ip4 && reg0 == 172.16.0.10 && reg9[[16..31]] == 80 && ip4.dst == 20.0.0.2 && tcp.dst == 80), action=(commit_lb_aff(vip = "172.16.0.10:80", backend = "20.0.0.2:80", proto = tcp, timeout = 60); /* drop */)
 ])
 
 AS_BOX([Test LR flows - skip_snat=true])
@@ -8618,17 +8772,17 @@  check ovn-nbctl --wait=sb set load_balancer lb0 options:skip_snat=true
 ovn-sbctl dump-flows R1 > R1flows_skip_snat
 AT_CAPTURE_FILE([R1flows_skip_snat])
 
-AT_CHECK([grep "lr_in_dnat " R1flows_skip_snat | sort], [0], [dnl
-  table=7 (lr_in_dnat         ), priority=0    , match=(1), action=(next;)
-  table=7 (lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; skip_snat);)
-  table=7 (lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; skip_snat);)
-  table=7 (lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; skip_snat);)
-  table=7 (lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
-  table=7 (lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-  table=7 (lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-  table=7 (lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
-  table=7 (lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
-  table=7 (lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
+AT_CHECK([grep "lr_in_dnat " R1flows_skip_snat | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; skip_snat);)
+  table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; skip_snat);)
+  table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; skip_snat);)
+  table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
+  table=??(lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
+  table=??(lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
+  table=??(lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
+  table=??(lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
+  table=??(lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
 ])
 
 check ovn-nbctl remove load_balancer lb0 options skip_snat
@@ -8639,17 +8793,17 @@  check ovn-nbctl --wait=sb set logical_router R1 options:lb_force_snat_ip="172.16
 ovn-sbctl dump-flows R1 > R1flows_force_snat
 AT_CAPTURE_FILE([R1flows_force_snat])
 
-AT_CHECK([grep "lr_in_dnat " R1flows_force_snat | sort], [0], [dnl
-  table=7 (lr_in_dnat         ), priority=0    , match=(1), action=(next;)
-  table=7 (lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; force_snat);)
-  table=7 (lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; force_snat);)
-  table=7 (lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.force_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; force_snat);)
-  table=7 (lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
-  table=7 (lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-  table=7 (lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-  table=7 (lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
-  table=7 (lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
-  table=7 (lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
+AT_CHECK([grep "lr_in_dnat " R1flows_force_snat | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(lr_in_dnat         ), priority=0    , match=(1), action=(next;)
+  table=??(lr_in_dnat         ), priority=120  , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; force_snat);)
+  table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; force_snat);)
+  table=??(lr_in_dnat         ), priority=150  , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.force_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; force_snat);)
+  table=??(lr_in_dnat         ), priority=50   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
+  table=??(lr_in_dnat         ), priority=50   , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
+  table=??(lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
+  table=??(lr_in_dnat         ), priority=70   , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
+  table=??(lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
+  table=??(lr_in_dnat         ), priority=70   , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
 ])
 
 AT_CLEANUP
@@ -8811,8 +8965,10 @@  check ovn-nbctl --wait=sb \
                 -- acl-add S1 from-lport 100 'inport=p1 && ip4' allow-stateless
 
 AT_CHECK([ovn-sbctl dump-flows | grep "ls_in_acl" | grep "match=(1)"  | sed 's/table=../table=??/' | sort], [0], [dnl
-  table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
 ])
 
@@ -8824,8 +8980,10 @@  check ovn-nbctl --wait=sb \
                 -- acl-add S1 from-lport 2 "udp" allow-related
 
 AT_CHECK([ovn-sbctl dump-flows | grep "ls_in_acl" | grep "match=(1)"  | sed 's/table=../table=??/' | sort], [0], [dnl
-  table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
 ])
 
@@ -8837,8 +8995,10 @@  check ovn-nbctl --wait=sb \
     -- ls-lb-add S1 lb
 
 AT_CHECK([ovn-sbctl dump-flows | grep "ls_in_acl" | grep "match=(1)"  | sed 's/table=../table=??/' | sort], [0], [dnl
-  table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
 ])
 
@@ -8848,8 +9008,10 @@  check ovn-nbctl --wait=sb \
                 -- acl-add S1 from-lport 100 'inport=p1 && ip4' allow-stateless
 
 AT_CHECK([ovn-sbctl dump-flows | grep "ls_in_acl" | grep "match=(1)"  | sed 's/table=../table=??/' | sort], [0], [dnl
-  table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
 ])
 
@@ -8860,8 +9022,10 @@  check ovn-nbctl --wait=sb \
                 -- acl-add S1 from-lport 2 "udp" allow-related
 
 AT_CHECK([ovn-sbctl dump-flows | grep "ls_in_acl" | grep "match=(1)"  | sed 's/table=../table=??/' | sort], [0], [dnl
-  table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
-  table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_action   ), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_action), priority=0    , match=(1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; next;)
+  table=??(ls_in_acl_after_lb_eval), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_eval     ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
 ])
 
@@ -8935,16 +9099,16 @@  AT_CHECK([grep -e "lr_in_defrag" -e "lr_in_dnat" lflows0], [0], [dnl
 ])
 
 AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows0 | grep "priority=65532"], [0], [dnl
-  table=? (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;)
-  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; reg0[[17]] = 1; 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_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(ct_commit_nat;)
-  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_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  table=?(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
+  table=? (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
+  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
+  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=? (ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=? (ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
+  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
+  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=? (ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=?(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=?(ls_in_acl_after_lb_eval), priority=65532, match=(reg0[[17]] == 1), action=(reg8[[16]] = 1; next;)
 ])
 
 
@@ -8984,16 +9148,16 @@  AT_CHECK([ovn-sbctl lflow-list | grep lr_in_dnat], [0], [dnl
 check ovn-nbctl remove load_balancer lb-test options skip_snat
 
 AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows1 | grep "priority=65532"], [0], [dnl
-  table=? (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(reg0[[17]] = 1; next;)
-  table=? (ls_in_acl          ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; next;)
-  table=? (ls_in_acl          ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
-  table=? (ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  table=? (ls_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
-  table=? (ls_out_acl         ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;)
-  table=? (ls_out_acl         ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
-  table=? (ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  table=?(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  table=?(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
+  table=? (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; next;)
+  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
+  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=? (ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=? (ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(reg8[[16]] = 1; next;)
+  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg8[[16]] = 1; next;)
+  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=? (ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=?(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=?(ls_in_acl_after_lb_eval), priority=65532, match=(reg0[[17]] == 1), action=(reg8[[16]] = 1; next;)
 ])
 
 AS_BOX([Chassis upgrades and supports CT related])
@@ -9016,16 +9180,16 @@  AT_CHECK([grep -e "lr_in_defrag" -e "lr_in_dnat" lflows2], [0], [dnl
 ])
 
 AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows2 | grep "priority=65532"], [0], [dnl
-  table=? (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;)
-  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; reg0[[17]] = 1; 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_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(ct_commit_nat;)
-  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_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-  table=?(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
+  table=? (ls_in_acl_eval     ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; reg8[[16]] = 1; ct_commit_nat;)
+  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; reg0[[17]] = 1; reg8[[16]] = 1; next;)
+  table=? (ls_in_acl_eval     ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=? (ls_in_acl_eval     ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=? (ls_out_acl_eval    ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg8[[16]] = 1; ct_commit_nat;)
+  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg8[[16]] = 1; next;)
+  table=? (ls_out_acl_eval    ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(reg8[[17]] = 1; next;)
+  table=? (ls_out_acl_eval    ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=?(ls_in_acl_after_lb_eval), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(reg8[[16]] = 1; next;)
+  table=?(ls_in_acl_after_lb_eval), priority=65532, match=(reg0[[17]] == 1), action=(reg8[[16]] = 1; next;)
 ])
 
 AT_CLEANUP
diff --git a/tests/ovn.at b/tests/ovn.at
index 161fb000a..9e6e8a14a 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -13308,15 +13308,20 @@  grep active_backup | grep members:$hv2_gw1_ofport,$hv2_gw2_ofport \
 ])
 
 # make sure that flows for handling the outside router port reside on gw1 through ls_in_l2_lkup table
-OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \
+
+sleep 10
+
+as gw1 ovs-ofctl dump-flows br-int
+
+OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=35 | \
 grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1
 ]])
-OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \
+OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=35 | \
 grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[0
 ]])
 
 # make sure ARP responder flows for outside router port reside on gw1 too through ls_in_arp_rsp table
-OVS_WAIT_UNTIL([test `as gw1 ovs-ofctl dump-flows br-int table=27 | \
+OVS_WAIT_UNTIL([test `as gw1 ovs-ofctl dump-flows br-int table=29 | \
 grep arp_tpa=192.168.0.101 | wc -l` -ge 1])
 
 # check that the chassis redirect port has been claimed by the gw1 chassis
@@ -13398,10 +13403,10 @@  AT_CHECK([ovs-vsctl --bare --columns bfd find Interface name=ovn-hv1-0],[0],
 ]])
 
 # make sure that flows for handling the outside router port reside on gw2 now
-OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \
+OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=35 | \
 grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1
 ]])
-OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \
+OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=35 | \
 grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[0
 ]])
 
@@ -13413,10 +13418,10 @@  as main ovs-vsctl del-port n1 $port
 bfd_dump
 
 # make sure that flows for handling the outside router port reside on gw1 now
-OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \
+OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=35 | \
 grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1
 ]])
-OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \
+OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=35 | \
 grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[0
 ]])
 
@@ -13530,15 +13535,15 @@  grep active_backup | grep members:$hv2_gw1_ofport,$hv2_gw2_ofport \
 ])
 
 # make sure that flows for handling the outside router port reside on gw1
-OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \
+OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=35 | \
 grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1
 ]])
-OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \
+OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=35 | \
 grep "dl_dst:00:00:02:01:02:04" | wc -l], [0], [[0
 ]])
 
 # make sure ARP responder flows for outside router port reside on gw1 too
-OVS_WAIT_UNTIL([test `as gw1 ovs-ofctl dump-flows br-int table=27 | \
+OVS_WAIT_UNTIL([test `as gw1 ovs-ofctl dump-flows br-int table=29 | \
 grep arp_tpa=192.168.0.101 | wc -l` -ge 1 ])
 
 # check that the chassis redirect port has been claimed by the gw1 chassis
@@ -13602,10 +13607,10 @@  AT_CHECK([ovs-vsctl --bare --columns bfd find Interface name=ovn-hv1-0],[0],
 ]])
 
 # make sure that flows for handling the outside router port reside on gw2 now
-OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \
+OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=35 | \
 grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1
 ]])
-OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \
+OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=35 | \
 grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[0
 ]])
 
@@ -13617,10 +13622,10 @@  as main ovs-vsctl del-port n1 $port
 bfd_dump
 
 # make sure that flows for handling the outside router port reside on gw2 now
-OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \
+OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=35 | \
 grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1
 ]])
-OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \
+OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=35 | \
 grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[0
 ]])
 
@@ -16400,8 +16405,8 @@  ovn-nbctl --wait=hv sync
 ovn-sbctl dump-flows sw0 > sw0-flows
 AT_CAPTURE_FILE([sw0-flows])
 
-AT_CHECK([grep -E 'ls_(in|out)_acl' sw0-flows |grep reject| sed 's/table=../table=??/' | sort], [0], [dnl
-  table=??(ls_out_acl         ), priority=2002 , match=(ip), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=25); };)
+AT_CHECK([grep -E 'ls_out_acl' sw0-flows | grep reject | sed 's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_out_acl_action  ), priority=1000 , match=(reg8[[18]] == 1), action=(reg8[[16]] = 0; reg8[[17]] = 0; reg8[[18]] = 0; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=27); };)
 ])
 
 
@@ -18099,15 +18104,15 @@  check ovn-nbctl acl-add ls1 to-lport 3 'ip4.src==10.0.0.1' allow
 check ovn-nbctl --wait=hv sync
 
 # Check OVS flows, the less restrictive flows should have been installed.
-AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=44 | ofctl_strip_all | \
+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=44 | ofctl_strip_all |
     grep "priority=1003" | \
     sed 's/conjunction([[^)]]*)/conjunction()/g' | \
     sed 's/conj_id=[[0-9]]*,/conj_id=xxx,/g' | sort], [0], [dnl
- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
+ table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
+ table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
  table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.3 actions=conjunction(),conjunction()
  table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.4 actions=conjunction(),conjunction()
- table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=resubmit(,45)
+ table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
  table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.2 actions=conjunction()
  table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.42 actions=conjunction()
 ])
@@ -18148,11 +18153,11 @@  AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=44 | ofctl_strip_all | \
     grep "priority=1003" | \
     sed 's/conjunction([[^)]]*)/conjunction()/g' | \
     sed 's/conj_id=[[0-9]]*,/conj_id=xxx,/g' | sort], [0], [dnl
- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
+ table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
+ table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
  table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.3 actions=conjunction(),conjunction()
  table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.4 actions=conjunction(),conjunction()
- table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=resubmit(,45)
+ table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
  table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.2 actions=conjunction()
  table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.42 actions=conjunction()
 ])
@@ -18166,8 +18171,8 @@  AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=44 | ofctl_strip_all | \
     grep "priority=1003" | \
     sed 's/conjunction([[^)]]*)/conjunction()/g' | \
     sed 's/conj_id=[[0-9]]*,/conj_id=xxx,/g' | sort], [0], [dnl
- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
+ table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
+ table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
  table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.3 actions=conjunction(),conjunction()
  table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.4 actions=conjunction(),conjunction()
  table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=conjunction(),conjunction()
@@ -18206,11 +18211,11 @@  AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=44 | ofctl_strip_all | \
    grep "priority=1003" | \
    sed 's/conjunction([[^)]]*)/conjunction()/g' | \
    sed 's/conj_id=[[0-9]]*,/conj_id=xxx,/g' | sort], [0], [dnl
- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
+ table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
+ table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
  table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.3 actions=conjunction(),conjunction()
  table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.4 actions=conjunction(),conjunction()
- table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=resubmit(,45)
+ table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
  table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.2 actions=conjunction()
  table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.42 actions=conjunction()
 ])
@@ -18227,16 +18232,16 @@  AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=44 | ofctl_strip_all | \
    grep "priority=1003" | \
    sed 's/conjunction([[^)]]*)/conjunction()/g' | \
    sed 's/conj_id=[[0-9]]*,/conj_id=xxx,/g' | sort], [0], [dnl
- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
+ table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
+ table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
+ table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
  table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.3 actions=conjunction(),conjunction(),conjunction()
  table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.4 actions=conjunction(),conjunction(),conjunction()
- table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=resubmit(,45)
+ table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
  table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.2 actions=conjunction(),conjunction()
  table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.42 actions=conjunction()
- table=44, priority=1003,udp,metadata=0x1 actions=resubmit(,45)
- table=44, priority=1003,udp6,metadata=0x1 actions=resubmit(,45)
+ table=44, priority=1003,udp,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
+ table=44, priority=1003,udp6,metadata=0x1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
 ])
 
 OVN_CLEANUP([hv1])
@@ -19642,7 +19647,7 @@  wait_for_ports_up ls1-lp_ext1
 # There should be a flow in hv2 to drop traffic from ls1-lp_ext1 destined
 # to router mac.
 AT_CHECK([as hv2 ovs-ofctl dump-flows br-int \
-table=32,dl_src=f0:00:00:00:00:03,dl_dst=a0:10:00:00:00:01 | \
+table=34,dl_src=f0:00:00:00:00:03,dl_dst=a0:10:00:00:00:01 | \
 grep -c "actions=drop"], [0], [1
 ])
 # Stop ovn-controllers on hv1 and hv3.
@@ -21265,7 +21270,7 @@  check_virtual_offlows_present() {
     lr0_public_dp_key=$(printf "%x" $(fetch_column Port_Binding tunnel_key logical_port=lr0-public))
 
     AT_CHECK_UNQUOTED([as $hv ovs-ofctl dump-flows br-int table=44,ip | ofctl_strip_all | grep "priority=2000"], [0], [dnl
- table=44, priority=2000,ip,metadata=0x$sw0_dp_key actions=resubmit(,45)
+ table=44, priority=2000,ip,metadata=0x$sw0_dp_key actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,45)
 ])
 
     AT_CHECK_UNQUOTED([as $hv ovs-ofctl dump-flows br-int table=11 | ofctl_strip_all | \
@@ -21303,7 +21308,7 @@  check_row_count Port_Binding 1 logical_port=sw0-vir virtual_parent=sw0-p1
 wait_for_ports_up sw0-vir
 check ovn-nbctl --wait=hv sync
 AT_CHECK([test 2 = `cat hv1/ovn-controller.log | grep "pinctrl received  packet-in" | \
-grep opcode=BIND_VPORT | grep OF_Table_ID=27 | wc -l`])
+grep opcode=BIND_VPORT | grep OF_Table_ID=29 | wc -l`])
 
 wait_row_count Port_Binding 1 logical_port=sw0-vir6 chassis=$hv1_ch_uuid
 check_row_count Port_Binding 1 logical_port=sw0-vir6 virtual_parent=sw0-p1
@@ -28642,7 +28647,11 @@  check ovn-nbctl acl-add ls1 from-lport 1 '1' drop
 check ovn-nbctl --wait=hv sync
 
 AT_CHECK([test "$expr_cnt" = "$(get_cache_count cache-expr)"], [0], [])
-AT_CHECK([test "$(($matches_cnt + 1))" = "$(get_cache_count cache-matches)"], [0], [])
+# Changing from having no ACLs to having ACLs adds 9 logical flows, 3 in each
+# of ls_in_acl_action, ls_in_acl_after_lb_action, and ls_out_acl_action, plus the
+# logical flow representing the ACL itself. This is where the 10 comes from in
+# the calculation below.
+AT_CHECK([test "$(($matches_cnt + 10))" = "$(get_cache_count cache-matches)"], [0], [])
 
 AS_BOX([Check expr caching for is_chassis_resident() matches])
 expr_cnt=$(get_cache_count cache-expr)
@@ -32009,9 +32018,10 @@  check ovn-nbctl --wait=hv sync
 dp_key=$(fetch_column Datapath_Binding tunnel_key external_ids:name=ls)
 rtr_port_key=$(fetch_column Port_Binding tunnel_key logical_port=ls_lr)
 
+ovs-ofctl dump-flows br-int table=16 | grep "reg14=0x${rtr_port_key},metadata=0x${dp_key},nw_dst=42.42.42.42 actions=load:0x1->OXM_OF_PKT_REG4[49],resubmit(,17)"
 # Check that ovn-controller adds a flow to drop packets with dest IP
 # 42.42.42.42 coming from the router port.
-AT_CHECK([ovs-ofctl dump-flows br-int table=16 | grep "reg14=0x${rtr_port_key},metadata=0x${dp_key},nw_dst=42.42.42.42 actions=drop" -c], [0], [dnl
+AT_CHECK([ovs-ofctl dump-flows br-int table=16 | grep "reg14=0x${rtr_port_key},metadata=0x${dp_key},nw_dst=42.42.42.42 actions=load:0x1->OXM_OF_PKT_REG4\[\[49\]\],resubmit(,17)" -c], [0], [dnl
 1
 ])
 
@@ -32767,15 +32777,15 @@  done
 check ovn-nbctl --wait=hv sync
 
 # hv0 should see flows for lsp1 but not lsp2
-AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=27 | grep 10.0.1.2], [0], [ignore])
-AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=27 | grep 10.0.2.2], [1])
+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=29 | grep 10.0.1.2], [0], [ignore])
+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=29 | grep 10.0.2.2], [1])
 # hv2 should see flows for lsp2 but not lsp1
-AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=27 | grep 10.0.2.2], [0], [ignore])
-AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=27 | grep 10.0.1.2], [1])
+AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=29 | grep 10.0.2.2], [0], [ignore])
+AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=29 | grep 10.0.1.2], [1])
 
 # Change lrp_lr_ls1 to a regular lrp, hv2 should see flows for lsp1
 check ovn-nbctl --wait=hv lrp-del-gateway-chassis lrp_lr_ls1 hv1
-AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=27 | grep 10.0.1.2], [0], [ignore])
+AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=29 | grep 10.0.1.2], [0], [ignore])
 
 # Change it back, and trigger recompute to make sure extra flows are removed
 # from hv2 (recompute is needed because currently I-P adds local datapaths but
@@ -32783,11 +32793,11 @@  AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=27 | grep 10.0.1.2], [0], [ig
 check ovn-nbctl --wait=hv lrp-set-gateway-chassis lrp_lr_ls1 hv1 1
 as hv2 check ovn-appctl -t ovn-controller recompute
 ovn-nbctl --wait=hv sync
-AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=27 | grep 10.0.1.2], [1])
+AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=29 | grep 10.0.1.2], [1])
 
 # Enable dnat_and_snat on lr, and now hv2 should see flows for lsp1.
 AT_CHECK([ovn-nbctl --wait=hv --gateway-port=lrp_lr_ls1 lr-nat-add lr dnat_and_snat 192.168.0.1 10.0.1.3 lsp1 f0:00:00:00:00:03])
-AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=27 | grep 10.0.1.2], [0], [ignore])
+AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=29 | grep 10.0.1.2], [0], [ignore])
 
 OVN_CLEANUP([hv1],[hv2])
 AT_CLEANUP
@@ -34804,14 +34814,14 @@  lsp2=0x$(fetch_column Port_Binding tunnel_key logical_port=lsp2)
 dnl Ensure the ACL is translated to OpenFlows expanding pg1.
 as hv1
 AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int | grep '42\.42\.42\.42' | ofctl_strip_all], [0], [dnl
- table=16, priority=1001,ip,reg14=$lsp1,metadata=0x1,nw_src=42.42.42.42 actions=resubmit(,17)
- table=16, priority=1001,ip,reg14=$lsp2,metadata=0x1,nw_src=42.42.42.42 actions=resubmit(,17)
+ table=16, priority=1001,ip,reg14=$lsp1,metadata=0x1,nw_src=42.42.42.42 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,17)
+ table=16, priority=1001,ip,reg14=$lsp2,metadata=0x1,nw_src=42.42.42.42 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,17)
 ])
 
 dnl Remove a port from pg1 and expect OpenFlows to be correctly updated.
 check ovn-nbctl --wait=hv pg-set-ports pg1 lsp2
 AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int | grep '42\.42\.42\.42' | ofctl_strip_all], [0], [dnl
- table=16, priority=1001,ip,reg14=$lsp2,metadata=0x1,nw_src=42.42.42.42 actions=resubmit(,17)
+ table=16, priority=1001,ip,reg14=$lsp2,metadata=0x1,nw_src=42.42.42.42 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,17)
 ])
 
 dnl Change the Chassis_Template_Var mapping to use the address set.
@@ -34820,14 +34830,14 @@  check ovn-nbctl --wait=hv set Chassis_Template_Var hv1 variables:CONDITION='ip4.
 dnl Ensure the ACL is translated to OpenFlows expanding as1.
 as hv1
 AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int | grep '42\.42\.42\.42' | ofctl_strip_all], [0], [dnl
- table=16, priority=1001,ip,metadata=0x1,nw_src=42.42.42.42,nw_dst=1.1.1.1 actions=resubmit(,17)
- table=16, priority=1001,ip,metadata=0x1,nw_src=42.42.42.42,nw_dst=1.1.1.2 actions=resubmit(,17)
+ table=16, priority=1001,ip,metadata=0x1,nw_src=42.42.42.42,nw_dst=1.1.1.1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,17)
+ table=16, priority=1001,ip,metadata=0x1,nw_src=42.42.42.42,nw_dst=1.1.1.2 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,17)
 ])
 
 dnl Remove an IP from AS1 and expect OpenFlows to be correctly updated.
 check ovn-nbctl set address_set as1 addresses=\"1.1.1.1\"
 AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int | grep '42\.42\.42\.42' | ofctl_strip_all], [0], [dnl
- table=16, priority=1001,ip,metadata=0x1,nw_src=42.42.42.42,nw_dst=1.1.1.1 actions=resubmit(,17)
+ table=16, priority=1001,ip,metadata=0x1,nw_src=42.42.42.42,nw_dst=1.1.1.1 actions=load:0x1->OXM_OF_PKT_REG4[[48]],resubmit(,17)
 ])
 
 dnl Remove the mapping and expect OpenFlows to be removed.
diff --git a/tests/system-ovn.at b/tests/system-ovn.at
index 8fe8e4d28..5ee044e19 100644
--- a/tests/system-ovn.at
+++ b/tests/system-ovn.at
@@ -8686,7 +8686,7 @@  ovn-sbctl list ip_multicast
 
 wait_igmp_flows_installed()
 {
-    OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int table=33 | \
+    OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int table=35 | \
     grep 'priority=90' | grep "nw_dst=$1"])
 }