On Fri, Jan 17, 2025 at 5:14 AM Mark Michelson <[email protected]> wrote:

> On allow-related ACLs, if the ACL changes and no longer matches an
> established session, then traffic will no longer automatically be
> allowed. Instead, traffic on the established session will be subject
> to ACL matching, and therefore the traffic may be dropped.
>
> This behavior can be altered by setting the "persist-established"
> option on allow-related ACLs. When set to true, we set a specific
> bit in the ct_mark when the conntrack entry is committed. If this bit
> is set, then established session traffic will always be allowed, even
> if the ACL is altered to no longer match the traffic.
>
> Upcoming commits will put in place methods so that deleting the ACL or
> changing the action type on the ACL will remove the conntrack entry that
> allows the established traffic.
>
> Signed-off-by: Mark Michelson <[email protected]>
> ---
> v4 -> v5:
>  * Renamed option from "persist_established" to "persist-established" to
>    be consistent with other multi-word options.
>  * Fixed failing tests.
>
> v3 -> v4:
>  * Rebased.
>  * Addressed minor formatting comments from Ales.
>  * Changed the name of the new option to "persist_established".
>  * Changed system test to match on cookie instead of other properties
>    when testing if the ACL drop was hit.
>  * The version in the northbound database is unchanged by this patch
>    now.
>  * The python client now passes the newline to the server. This way if
>    a future test uses this file and passes a line longer than 1024
>    characters, there won't be extra newlines inserted by the server.
>  * The server now prints a message when it is ready to accept
>    connections. I did this because I noticed the test would sometimes
>    fail because the client would get a "Connection Refused" error. Now
>    the test waits for the server to ensure it is ready before attempting
>    to start the client.
>
> v2 -> v3:
>  * The configuration mechanism changed from a new ACL action to being an
>    option that supplements "allow-related" ACLs. The new option is
>    called bypass_match_for_established. A suggestion for the option was
>    "flush_ct_on_removal". I elected not to go with this because flushing
>    CT on removal isn't the real draw of the option. Admins set the
>    option so that the ACL does not have to be matched once the
>    connection is established. The flush of CT is a necessity of the
>    feature, but it's not why the admin is setting the option.
>
> v1 -> v2:
>  * Fixed formatting issues
>  * Fixed flake8 issues
>  * Check for CT label flush chassis feature
> ---
>
>  include/ovn/logical-fields.h |   1 +
>  lib/logical-fields.c         |   5 +
>  northd/northd.c              |  48 +++++++-
>  ovn-nb.xml                   |  26 ++++
>  tests/automake.mk            |   4 +-
>  tests/client.py              |  36 ++++++
>  tests/ovn-northd.at          | 233 +++++++++++++++++++++++++++++------
>  tests/ovn.at                 |   1 +
>  tests/server.py              |  33 +++++
>  tests/system-ovn.at          | 172 ++++++++++++++++++++++++++
>  10 files changed, 518 insertions(+), 41 deletions(-)
>  create mode 100755 tests/client.py
>  create mode 100755 tests/server.py
>
> diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h
> index 70c6b93c4..dd47bd4ce 100644
> --- a/include/ovn/logical-fields.h
> +++ b/include/ovn/logical-fields.h
> @@ -204,6 +204,7 @@ const struct ovn_field *ovn_field_from_name(const char
> *name);
>  #define OVN_CT_LB_FORCE_SNAT_BIT 3
>  #define OVN_CT_OBS_STAGE_1ST_BIT 4
>  #define OVN_CT_OBS_STAGE_END_BIT 5
> +#define OVN_CT_ALLOW_ESTABLISHED_BIT 6
>
>  #define OVN_CT_BLOCKED 1
>  #define OVN_CT_NATTED  2
> diff --git a/lib/logical-fields.c b/lib/logical-fields.c
> index 5a8b53f2b..5b578b5c2 100644
> --- a/lib/logical-fields.c
> +++ b/lib/logical-fields.c
> @@ -171,6 +171,11 @@ ovn_init_symtab(struct shash *symtab)
>                                      OVN_CT_STR(OVN_CT_OBS_STAGE_END_BIT)
>                                      "]",
>                                      WR_CT_COMMIT);
> +    expr_symtab_add_subfield_scoped(symtab, "ct_mark.allow_established",
> NULL,
> +                                    "ct_mark["
> +
> OVN_CT_STR(OVN_CT_ALLOW_ESTABLISHED_BIT)
> +                                    "]",
> +                                    WR_CT_COMMIT);
>      expr_symtab_add_subfield_scoped(symtab, "ct_mark.obs_collector_id",
> NULL,
>                                      "ct_mark[16..23]", WR_CT_COMMIT);
>
> diff --git a/northd/northd.c b/northd/northd.c
> index b01e40ecd..7434ab1db 100644
> --- a/northd/northd.c
> +++ b/northd/northd.c
> @@ -124,6 +124,7 @@ static bool vxlan_mode;
>  #define REGBIT_ACL_HINT_ALLOW_REL "reg0[17]"
>  #define REGBIT_FROM_ROUTER_PORT   "reg0[18]"
>  #define REGBIT_IP_FRAG            "reg0[19]"
> +#define REGBIT_ACL_PERSIST_ID     "reg0[20]"
>
>  #define REG_ORIG_DIP_IPV4         "reg1"
>  #define REG_ORIG_DIP_IPV6         "xxreg1"
> @@ -7095,7 +7096,8 @@ consider_acl(struct lflow_table *lflows, const
> struct ovn_datapath *od,
>               const struct nbrec_acl *acl, bool has_stateful,
>               const struct shash *meter_groups, uint64_t max_acl_tier,
>               struct ds *match, struct ds *actions,
> -             struct lflow_ref *lflow_ref)
> +             struct lflow_ref *lflow_ref,
> +             const struct chassis_features *features)
>  {
>      bool ingress = !strcmp(acl->direction, "from-lport") ? true :false;
>      enum ovn_stage stage;
> @@ -7181,6 +7183,19 @@ consider_acl(struct lflow_table *lflows, const
> struct ovn_datapath *od,
>          ds_truncate(actions, log_verdict_len);
>          ds_put_cstr(actions, REGBIT_CONNTRACK_COMMIT" = 1; ");
>
> +        if (smap_get_bool(&acl->options, "persist-established", false)) {
> +            if (!features->ct_label_flush) {
> +                static struct vlog_rate_limit rl =
> VLOG_RATE_LIMIT_INIT(1, 1);
> +                VLOG_WARN_RL(&rl, "OVS does not support CT label flush. "
> +                             "persist-established option cannot "
> +                             "be honored for ACL "UUID_FMT".",
> +                             UUID_ARGS(&acl->header_.uuid));
> +            } else {
> +                ds_put_format(actions,
> +                              REGBIT_ACL_PERSIST_ID " = 1; ");
> +            }
> +        }
> +
>          /* For stateful ACLs sample "new" and "established" packets. */
>          build_acl_sample_label_action(actions, acl, acl->sample_new,
>                                        acl->sample_est, obs_stage);
> @@ -7682,6 +7697,26 @@ build_acls(const struct ls_stateful_record
> *ls_stateful_rec,
>                        REGBIT_ACL_HINT_ALLOW_REL" == 1",
>                        REGBIT_ACL_VERDICT_ALLOW " = 1; next;",
>                        lflow_ref);
> +
> +        /* Ingress and egress ACL Table (Priority 65535).
> +         *
> +         * Allow traffic that is established if the ACL has a persistent
> +         * conntrack ID configured.
> +         */
> +        ds_clear(&match);
> +        ds_put_format(&match, "ct.est && ct_mark.allow_established == 1");
> +        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX,
> +                      ds_cstr(&match),
> +                      REGBIT_ACL_VERDICT_ALLOW " = 1; next;",
> +                      lflow_ref);
> +        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB_EVAL,
> UINT16_MAX,
> +                      ds_cstr(&match),
> +                      REGBIT_ACL_VERDICT_ALLOW " = 1; next;",
> +                      lflow_ref);
> +        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX,
> +                      ds_cstr(&match),
> +                      REGBIT_ACL_VERDICT_ALLOW " = 1; next;",
> +                      lflow_ref);
>      }
>
>      /* Ingress and Egress ACL Table (Priority 65532).
> @@ -7715,7 +7750,7 @@ build_acls(const struct ls_stateful_record
> *ls_stateful_rec,
>          uint64_t max_acl_tier = choose_max_acl_tier(ls_stateful_rec, acl);
>          consider_acl(lflows, od, acl, has_stateful,
>                       meter_groups, max_acl_tier,
> -                     &match, &actions, lflow_ref);
> +                     &match, &actions, lflow_ref, features);
>          build_acl_sample_flows(ls_stateful_rec, od, lflows, acl,
>                                 &match, &actions, sampling_apps,
>                                 features, lflow_ref);
> @@ -7736,7 +7771,7 @@ build_acls(const struct ls_stateful_record
> *ls_stateful_rec,
>                                                              acl);
>                  consider_acl(lflows, od, acl, has_stateful,
>                               meter_groups, max_acl_tier,
> -                             &match, &actions, lflow_ref);
> +                             &match, &actions, lflow_ref, features);
>                  build_acl_sample_flows(ls_stateful_rec, od, lflows, acl,
>                                         &match, &actions, sampling_apps,
>                                         features, lflow_ref);
> @@ -8421,6 +8456,7 @@ build_stateful(struct ovn_datapath *od, struct
> lflow_table *lflows,
>      ds_put_cstr(&actions,
>                   "ct_commit { "
>                      "ct_mark.blocked = 0; "
> +                    "ct_mark.allow_established = " REGBIT_ACL_PERSIST_ID
> "; "
>                      "ct_mark.obs_stage = " REGBIT_ACL_OBS_STAGE "; "
>                      "ct_mark.obs_collector_id = "
> REG_OBS_COLLECTOR_ID_EST "; "
>                      "ct_label.obs_point_id = " REG_OBS_POINT_ID_EST "; "
> @@ -8441,7 +8477,11 @@ build_stateful(struct ovn_datapath *od, struct
> lflow_table *lflows,
>       * any packet that makes it this far is part of a connection we
>       * want to allow to continue. */
>      ds_clear(&actions);
> -    ds_put_cstr(&actions, "ct_commit { ct_mark.blocked = 0; }; next;");
> +    ds_put_cstr(&actions,
> +                "ct_commit { "
> +                   "ct_mark.blocked = 0; "
> +                   "ct_mark.allow_established = " REGBIT_ACL_PERSIST_ID
> "; "
> +                "}; next;");
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, 100,
>                    REGBIT_CONNTRACK_COMMIT" == 1 && "
>                    REGBIT_ACL_LABEL" == 0",
> diff --git a/ovn-nb.xml b/ovn-nb.xml
> index 24ef12f3b..caa370837 100644
> --- a/ovn-nb.xml
> +++ b/ovn-nb.xml
> @@ -2558,6 +2558,32 @@ or
>            of all the ACLs and the default deny/allow ACLs if any.
>          </p>
>        </column>
> +
> +      <column name="options" key="persist-established">
> +        <p>
> +          This option applies only to ACLs whose <ref column="action"/>
> is set
> +          to <code>allow-related</code>.
> +        </p>
> +
> +        <p>
> +          <code>allow-related</code> ACLs create a conntrack entry when a
> +          packet matches the ACL's <ref column="match"/> column.
> Typically,
> +          traffic must continue to match these conditions in order to
> continue
> +          to be allowed by the ACL. With this option set to
> <code>true</code>,
> +          then the ACL match is bypassed once the original match occurs.
> +          Instead, a mark bit in the conntrack entry is used to allow the
> +          traffic. This means that traffic will continue to be allowed
> even if
> +          the ACL's match changes and no longer matches the established
> +          traffic.
> +        </p>
> +
> +        <p>
> +          The traffic will stop being allowed automatically if this
> option is
> +          set to <code>false</code>, if the ACL's <ref column="action"/>
> is
> +          changed to something other than <code>allow-related</code>, or
> if the
> +          ACL is destroyed.
> +        </p>
> +      </column>
>      </group>
>
>      <group title="Logging">
> diff --git a/tests/automake.mk b/tests/automake.mk
> index 3899c9e80..940f5b923 100644
> --- a/tests/automake.mk
> +++ b/tests/automake.mk
> @@ -313,7 +313,9 @@ CHECK_PYFILES = \
>         tests/uuidfilt.py \
>         tests/test-tcp-rst.py \
>         tests/check_acl_log.py \
> -       tests/scapy-server.py
> +       tests/scapy-server.py \
> +       tests/client.py \
> +       tests/server.py
>
>  EXTRA_DIST += $(CHECK_PYFILES)
>  PYCOV_CLEAN_FILES += $(CHECK_PYFILES:.py=.py,cover) .coverage
> diff --git a/tests/client.py b/tests/client.py
> new file mode 100755
> index 000000000..22fb7f126
> --- /dev/null
> +++ b/tests/client.py
> @@ -0,0 +1,36 @@
> +#!/usr/bin/env python3
> +
> +import socket
> +import time
> +import argparse
> +
> +
> +def send_data_from_fifo_to_server(
> +    fifo_path='/tmp/myfifo', host='127.0.0.1', port=10000
> +):
> +    # Open the FIFO for reading (blocking mode)
> +    with open(fifo_path, 'r') as fifo_file:
> +        with socket.socket(
> +            socket.AF_INET, socket.SOCK_STREAM
> +        ) as client_socket:
> +            client_socket.connect((host, port))
> +            # Continuously read from the FIFO and send to the server
> +            while True:
> +                data = fifo_file.readline()
> +                if data:
> +                    client_socket.sendall(data.encode())
> +                else:
> +                    time.sleep(0.1)
> +
> +
> +if __name__ == "__main__":
> +    parser = argparse.ArgumentParser()
> +    group = parser.add_argument_group()
> +    group.add_argument("-f", "--fifo_path")
> +    group.add_argument("-i", "--server-host")
> +    group.add_argument("-p", "--server-port", type=int)
> +    args = parser.parse_args()
> +
> +    send_data_from_fifo_to_server(
> +        args.fifo_path, args.server_host, args.server_port
> +    )
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> index 507cc302f..61280c3f8 100644
> --- a/tests/ovn-northd.at
> +++ b/tests/ovn-northd.at
> @@ -2661,11 +2661,13 @@ check ovn-nbctl --wait=sb \
>      -- acl-add ls from-lport 2 "udp" allow-related \
>      -- acl-add ls to-lport 2 "udp" allow-related
>  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 | grep 'ct\.' |
> ovn_strip_lflows], [0], [dnl
> +  table=??(ls_in_acl_after_lb_eval), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 1), action=(reg8[[16]] = 1; 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=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=65535, match=(ct.est &&
> ct_mark.allow_established == 1), action=(reg8[[16]] = 1; next;)
>    table=??(ls_in_acl_hint     ), priority=1    , match=(ct.est &&
> ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
>    table=??(ls_in_acl_hint     ), priority=2    , match=(ct.est &&
> ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
>    table=??(ls_in_acl_hint     ), priority=3    , match=(!ct.est),
> action=(reg0[[9]] = 1; next;)
> @@ -2678,6 +2680,7 @@ AT_CHECK([ovn-sbctl lflow-list ls | grep -e
> ls_in_acl_hint -e ls_out_acl_hint -e
>    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=65535, match=(ct.est &&
> ct_mark.allow_established == 1), action=(reg8[[16]] = 1; next;)
>    table=??(ls_out_acl_hint    ), priority=1    , match=(ct.est &&
> ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
>    table=??(ls_out_acl_hint    ), priority=2    , match=(ct.est &&
> ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
>    table=??(ls_out_acl_hint    ), priority=3    , match=(!ct.est),
> action=(reg0[[9]] = 1; next;)
> @@ -2698,6 +2701,7 @@ AT_CHECK([ovn-sbctl lflow-list ls | grep -e
> ls_in_acl_hint -e ls_out_acl_hint -e
>    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_after_lb_eval), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 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;)
> @@ -2708,6 +2712,7 @@ AT_CHECK([ovn-sbctl lflow-list ls | grep -e
> ls_in_acl_hint -e ls_out_acl_hint -e
>    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_eval     ), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 1), 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;)
> @@ -2726,6 +2731,7 @@ AT_CHECK([ovn-sbctl lflow-list ls | grep -e
> ls_in_acl_hint -e ls_out_acl_hint -e
>    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_eval    ), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 1), 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;)
> @@ -4674,8 +4680,8 @@ check_stateful_flows() {
>
>      AT_CHECK([grep "ls_in_stateful" sw0flows | ovn_strip_lflows], [0],
> [dnl
>    table=??(ls_in_stateful     ), priority=0    , match=(1), action=(next;)
> -  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
> -  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; }; next;)
> +  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.allow_established = reg0[[20]]; }; next;)
> +  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.allow_established = reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> next;)
>  ])
>
>      AT_CHECK_UNQUOTED([grep "ls_out_pre_lb" sw0flows | ovn_strip_lflows],
> [0], [dnl
> @@ -4800,8 +4806,8 @@ AT_CHECK([grep -w "ls_in_acl_eval" sw0flows | grep
> 2002 | ovn_strip_lflows], [0]
>  ])
>  AT_CHECK([grep "ls_in_stateful" sw0flows | ovn_strip_lflows], [0], [dnl
>    table=??(ls_in_stateful     ), priority=0    , match=(1), action=(next;)
> -  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
> -  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; }; next;)
> +  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.allow_established = reg0[[20]]; }; next;)
> +  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.allow_established = reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> next;)
>  ])
>
>  AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep 2002 |
> ovn_strip_lflows], [0], [dnl
> @@ -4810,8 +4816,8 @@ AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep
> 2002 | ovn_strip_lflows], [0
>  ])
>  AT_CHECK([grep "ls_out_stateful" sw0flows | ovn_strip_lflows], [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_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; }; next;)
> +  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.allow_established = reg0[[20]]; }; next;)
> +  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.allow_established = reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> next;)
>  ])
>
>  # Add new ACL without label
> @@ -4829,8 +4835,8 @@ AT_CHECK([grep -w "ls_in_acl_eval" sw0flows | grep
> 2002 | ovn_strip_lflows], [0]
>  ])
>  AT_CHECK([grep "ls_in_stateful" sw0flows | ovn_strip_lflows], [0], [dnl
>    table=??(ls_in_stateful     ), priority=0    , match=(1), action=(next;)
> -  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
> -  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; }; next;)
> +  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.allow_established = reg0[[20]]; }; next;)
> +  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.allow_established = reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> next;)
>  ])
>
>  AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep 2002 |
> ovn_strip_lflows], [0], [dnl
> @@ -4841,8 +4847,8 @@ AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep
> 2002 | ovn_strip_lflows], [0
>  ])
>  AT_CHECK([grep "ls_out_stateful" sw0flows | ovn_strip_lflows], [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_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; }; next;)
> +  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.allow_established = reg0[[20]]; }; next;)
> +  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.allow_established = reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> next;)
>  ])
>
>  # Delete new ACL with label
> @@ -4858,8 +4864,8 @@ AT_CHECK([grep -w "ls_in_acl_eval" sw0flows | grep
> 2002 | ovn_strip_lflows], [0]
>  ])
>  AT_CHECK([grep "ls_in_stateful" sw0flows | ovn_strip_lflows], [0], [dnl
>    table=??(ls_in_stateful     ), priority=0    , match=(1), action=(next;)
> -  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
> -  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; }; next;)
> +  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.allow_established = reg0[[20]]; }; next;)
> +  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.allow_established = reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> next;)
>  ])
>
>  AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep 2002 |
> ovn_strip_lflows], [0], [dnl
> @@ -4868,8 +4874,8 @@ AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep
> 2002 | ovn_strip_lflows], [0
>  ])
>  AT_CHECK([grep "ls_out_stateful" sw0flows | ovn_strip_lflows], [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_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; }; next;)
> +  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.allow_established = reg0[[20]]; }; next;)
> +  table=??(ls_out_stateful    ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.allow_established = reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> next;)
>  ])
>  AT_CLEANUP
>  ])
> @@ -4897,7 +4903,7 @@ check ovn-nbctl --wait=sb -- acl-del ls --
> --label=1234 acl-add ls from-lport 1
>
>  dnl Check that the label is committed to conntrack in the ingress pipeline
>  AT_CHECK_UNQUOTED([ovn_trace --ct new --ct new --ct new ls "$flow" | grep
> -e ls_in_stateful -A 2 | grep commit], [0], [dnl
> -    ct_commit { ct_mark.blocked = 0; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> +    ct_commit { ct_mark.blocked = 0; ct_mark.allow_established =
> reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; };
>  ])
>
>  AS_BOX([from-lport --apply-after-lb allow-related ACL])
> @@ -4905,7 +4911,7 @@ check ovn-nbctl --wait=sb -- acl-del ls --
> --apply-after-lb --label=1234 acl-add
>
>  dnl Check that the label is committed to conntrack in the ingress pipeline
>  AT_CHECK_UNQUOTED([ovn_trace --ct new --ct new --ct new ls "$flow" | grep
> -e ls_in_stateful -A 2 | grep commit], [0], [dnl
> -    ct_commit { ct_mark.blocked = 0; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> +    ct_commit { ct_mark.blocked = 0; ct_mark.allow_established =
> reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; };
>  ])
>
>  AS_BOX([to-lport allow-related ACL])
> @@ -4913,7 +4919,7 @@ check ovn-nbctl --wait=sb -- acl-del ls --
> --label=1234 acl-add ls to-lport 1 ip
>
>  dnl Check that the label is committed to conntrack in the ingress pipeline
>  AT_CHECK_UNQUOTED([ovn_trace --ct new --ct new --ct new ls "$flow" | grep
> -e ls_out_stateful -A 2 | grep commit], [0], [dnl
> -    ct_commit { ct_mark.blocked = 0; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> +    ct_commit { ct_mark.blocked = 0; ct_mark.allow_established =
> reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; };
>  ])
>
>  AT_CLEANUP
> @@ -4936,6 +4942,7 @@ AT_CHECK([grep -w "ls_in_acl_eval" sw0flows | grep
> 6553 | ovn_strip_lflows], [0]
>    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_eval     ), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 1), action=(reg8[[16]] = 1; next;)
>  ])
>
>  AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep 6553 |
> ovn_strip_lflows], [0], [dnl
> @@ -4943,6 +4950,7 @@ AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep
> 6553 | ovn_strip_lflows], [0
>    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_eval    ), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 1), action=(reg8[[16]] = 1; next;)
>  ])
>
>  # Disable ct.inv usage.
> @@ -4956,6 +4964,7 @@ AT_CHECK([grep -w "ls_in_acl_eval" sw0flows | grep
> 6553 | ovn_strip_lflows], [0]
>    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;)
> +  table=??(ls_in_acl_eval     ), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 1), action=(reg8[[16]] = 1; next;)
>  ])
>
>  AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep 6553 |
> ovn_strip_lflows], [0], [dnl
> @@ -4963,6 +4972,7 @@ AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep
> 6553 | ovn_strip_lflows], [0
>    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;)
> +  table=??(ls_out_acl_eval    ), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 1), action=(reg8[[16]] = 1; next;)
>  ])
>
>  AT_CHECK([grep -c "ct.inv" sw0flows], [1], [dnl
> @@ -4980,6 +4990,7 @@ AT_CHECK([grep -w "ls_in_acl_eval" sw0flows | grep
> 6553 | ovn_strip_lflows], [0]
>    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_eval     ), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 1), action=(reg8[[16]] = 1; next;)
>  ])
>
>  AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep 6553 |
> ovn_strip_lflows], [0], [dnl
> @@ -4987,6 +4998,7 @@ AT_CHECK([grep -w "ls_out_acl_eval" sw0flows | grep
> 6553 | ovn_strip_lflows], [0
>    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_eval    ), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 1), action=(reg8[[16]] = 1; next;)
>  ])
>
>  AT_CHECK([grep -c "ct.inv" sw0flows], [0], [dnl
> @@ -7808,6 +7820,7 @@ AT_CHECK([grep -e "ls_in_acl.*eval" -e
> "ls_in_acl_hint" lsflows | ovn_strip_lflo
>    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_after_lb_eval), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 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;)
> @@ -7824,6 +7837,7 @@ AT_CHECK([grep -e "ls_in_acl.*eval" -e
> "ls_in_acl_hint" lsflows | ovn_strip_lflo
>    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_eval     ), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 1), 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;)
> @@ -7843,8 +7857,8 @@ AT_CHECK([grep -e "ls_in_lb " lsflows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep -e "ls_in_stateful" lsflows | ovn_strip_lflows], [0], [dnl
>    table=??(ls_in_stateful     ), priority=0    , match=(1), action=(next;)
> -  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
> -  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; }; next;)
> +  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.allow_established = reg0[[20]]; }; next;)
> +  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.allow_established = reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> next;)
>  ])
>
>  AS_BOX([Remove and add the ACLs back with the apply-after-lb option])
> @@ -7873,6 +7887,7 @@ AT_CHECK([grep -e "ls_in_acl.*eval" -e
> "ls_in_acl_hint" lsflows | ovn_strip_lflo
>    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_after_lb_eval), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 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;)
> @@ -7881,6 +7896,7 @@ AT_CHECK([grep -e "ls_in_acl.*eval" -e
> "ls_in_acl_hint" lsflows | ovn_strip_lflo
>    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_eval     ), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 1), 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;)
> @@ -7900,8 +7916,8 @@ AT_CHECK([grep -e "ls_in_lb " lsflows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep -e "ls_in_stateful" lsflows | ovn_strip_lflows], [0], [dnl
>    table=??(ls_in_stateful     ), priority=0    , match=(1), action=(next;)
> -  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
> -  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; }; next;)
> +  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.allow_established = reg0[[20]]; }; next;)
> +  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.allow_established = reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> next;)
>  ])
>
>  AS_BOX([Remove and add the ACLs back with a few ACLs with apply-after-lb
> option])
> @@ -7926,6 +7942,7 @@ AT_CHECK([grep -e "ls_in_acl.*eval" -e
> "ls_in_acl_hint" lsflows | ovn_strip_lflo
>    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_after_lb_eval), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 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;)
> @@ -7938,6 +7955,7 @@ AT_CHECK([grep -e "ls_in_acl.*eval" -e
> "ls_in_acl_hint" lsflows | ovn_strip_lflo
>    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_eval     ), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 1), 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;)
> @@ -7957,8 +7975,8 @@ AT_CHECK([grep -e "ls_in_lb " lsflows |
> ovn_strip_lflows], [0], [dnl
>
>  AT_CHECK([grep -e "ls_in_stateful" lsflows | ovn_strip_lflows], [0], [dnl
>    table=??(ls_in_stateful     ), priority=0    , match=(1), action=(next;)
> -  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
> -  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; }; next;)
> +  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.allow_established = reg0[[20]]; }; next;)
> +  table=??(ls_in_stateful     ), priority=100  , match=(reg0[[1]] == 1 &&
> reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0;
> ct_mark.allow_established = reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> next;)
>  ])
>
>  AT_CLEANUP
> @@ -8470,6 +8488,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl"
> | ovn_strip_lflows], [0], [
>    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_after_lb_eval), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 1), action=(reg8[[16]] = 1; next;)
>    table=??(ls_in_acl_after_lb_sample), priority=0    , match=(1),
> action=(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;)
> @@ -8481,6 +8500,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl"
> | ovn_strip_lflows], [0], [
>    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_eval     ), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 1), 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;)
> @@ -8508,6 +8528,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl"
> | ovn_strip_lflows], [0], [
>    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_eval    ), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 1), 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;)
> @@ -8669,6 +8690,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl"
> | ovn_strip_lflows], [0], [
>    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_after_lb_eval), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 1), action=(reg8[[16]] = 1; next;)
>    table=??(ls_in_acl_after_lb_sample), priority=0    , match=(1),
> action=(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;)
> @@ -8678,6 +8700,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl"
> | ovn_strip_lflows], [0], [
>    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_eval     ), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 1), 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;)
> @@ -8705,6 +8728,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl"
> | ovn_strip_lflows], [0], [
>    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_eval    ), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 1), 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;)
> @@ -8864,6 +8888,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl"
> | ovn_strip_lflows], [0], [
>    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_after_lb_eval), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 1), action=(reg8[[16]] = 1; next;)
>    table=??(ls_in_acl_after_lb_sample), priority=0    , match=(1),
> action=(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;)
> @@ -8873,6 +8898,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl"
> | ovn_strip_lflows], [0], [
>    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_eval     ), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 1), 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;)
> @@ -8902,6 +8928,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl"
> | ovn_strip_lflows], [0], [
>    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_eval    ), priority=65535, match=(ct.est &&
> ct_mark.allow_established == 1), 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;)
> @@ -13055,7 +13082,7 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e
> ls_in_acl_sample -e ls_in_acl_eval -e l
>  dnl Trace new connections.
>  flow="$base_flow"
>  AT_CHECK_UNQUOTED([ovn_trace --ct new ls "$flow" | TRACE_FILTER], [0],
> [dnl
> -    ct_commit { ct_mark.blocked = 0; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> +    ct_commit { ct_mark.blocked = 0; ct_mark.allow_established =
> reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; };
>      reg8[[0..7]] = 1;
>      reg8[[8..15]] = 1;
>      reg9 = 4302;
> @@ -13065,7 +13092,7 @@ AT_CHECK_UNQUOTED([ovn_trace --ct new ls "$flow" |
> TRACE_FILTER], [0], [dnl
>  dnl Trace estasblished connections.
>  flow="$base_flow && ct_label.obs_point_id == 4302"
>  AT_CHECK_UNQUOTED([ovn_trace --ct est ls "$flow" | TRACE_FILTER], [0],
> [dnl
> -    ct_commit { ct_mark.blocked = 0; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> +    ct_commit { ct_mark.blocked = 0; ct_mark.allow_established =
> reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; };
>      reg8[[0..7]] = 1;
>      reg8[[8..15]] = 1;
>      reg9 = 4302;
> @@ -13093,7 +13120,7 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e
> ls_in_acl_sample -e ls_in_acl_eval -e l
>  dnl Trace new connections.
>  flow="$base_flow"
>  AT_CHECK_UNQUOTED([ovn_trace --ct new ls "$flow" | TRACE_FILTER], [0],
> [dnl
> -    ct_commit { ct_mark.blocked = 0; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> +    ct_commit { ct_mark.blocked = 0; ct_mark.allow_established =
> reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; };
>      reg8[[0..7]] = 1;
>      reg8[[8..15]] = 1;
>      reg9 = 4302;
> @@ -13103,7 +13130,7 @@ AT_CHECK_UNQUOTED([ovn_trace --ct new ls "$flow" |
> TRACE_FILTER], [0], [dnl
>  dnl Trace estasblished connections.
>  flow="$base_flow && ct_label.obs_point_id == 4302 && ct_mark.obs_stage ==
> 0 && ct_mark.obs_collector_id == 1"
>  AT_CHECK_UNQUOTED([ovn_trace --ct est ls "$flow" | TRACE_FILTER], [0],
> [dnl
> -    ct_commit { ct_mark.blocked = 0; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> +    ct_commit { ct_mark.blocked = 0; ct_mark.allow_established =
> reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; };
>      reg8[[0..7]] = 1;
>      reg8[[8..15]] = 1;
>      reg9 = 4302;
> @@ -13126,7 +13153,7 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e
> ls_in_acl_sample -e ls_in_acl_eval -e l
>  dnl Trace new connections.
>  flow="$base_flow"
>  AT_CHECK_UNQUOTED([ovn_trace --ct new ls "$flow" | TRACE_FILTER], [0],
> [dnl
> -    ct_commit { ct_mark.blocked = 0; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> +    ct_commit { ct_mark.blocked = 0; ct_mark.allow_established =
> reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; };
>      reg8[[0..7]] = 1;
>      reg8[[8..15]] = 0;
>      reg9 = 0;
> @@ -13161,7 +13188,7 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e
> ls_in_acl_after_lb_sample -e ls_in_acl_
>  dnl Trace new connections.
>  flow="$base_flow"
>  AT_CHECK_UNQUOTED([ovn_trace --ct new ls "$flow" | TRACE_FILTER], [0],
> [dnl
> -    ct_commit { ct_mark.blocked = 0; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> +    ct_commit { ct_mark.blocked = 0; ct_mark.allow_established =
> reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; };
>      reg8[[0..7]] = 1;
>      reg8[[8..15]] = 1;
>      reg9 = 4302;
> @@ -13171,7 +13198,7 @@ AT_CHECK_UNQUOTED([ovn_trace --ct new ls "$flow" |
> TRACE_FILTER], [0], [dnl
>  dnl Trace estasblished connections.
>  flow="$base_flow && ct_label.obs_point_id == 4302 && ct_mark.obs_stage ==
> 1 && ct_mark.obs_collector_id == 1"
>  AT_CHECK_UNQUOTED([ovn_trace --ct est ls "$flow" | TRACE_FILTER], [0],
> [dnl
> -    ct_commit { ct_mark.blocked = 0; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> +    ct_commit { ct_mark.blocked = 0; ct_mark.allow_established =
> reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; };
>      reg8[[0..7]] = 1;
>      reg8[[8..15]] = 1;
>      reg9 = 4302;
> @@ -13194,7 +13221,7 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e
> ls_in_acl_after_lb_sample -e ls_in_acl_
>  dnl Trace new connections.
>  flow="$base_flow"
>  AT_CHECK_UNQUOTED([ovn_trace --ct new ls "$flow" | TRACE_FILTER], [0],
> [dnl
> -    ct_commit { ct_mark.blocked = 0; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> +    ct_commit { ct_mark.blocked = 0; ct_mark.allow_established =
> reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; };
>      reg8[[0..7]] = 1;
>      reg8[[8..15]] = 0;
>      reg9 = 0;
> @@ -13229,8 +13256,8 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e
> ls_out_acl_sample -e ls_out_acl_eval -e
>  dnl Trace new connections.
>  flow="$base_flow"
>  AT_CHECK_UNQUOTED([ovn_trace --ct new --ct new ls "$flow" |
> TRACE_FILTER], [0], [dnl
> -    ct_commit { ct_mark.blocked = 0; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> -    ct_commit { ct_mark.blocked = 0; };
> +    ct_commit { ct_mark.blocked = 0; ct_mark.allow_established =
> reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> +    ct_commit { ct_mark.blocked = 0; ct_mark.allow_established =
> reg0[[20]]; };
>      reg8[[0..7]] = 1;
>      reg8[[8..15]] = 1;
>      reg9 = 4302;
> @@ -13240,7 +13267,7 @@ AT_CHECK_UNQUOTED([ovn_trace --ct new --ct new ls
> "$flow" | TRACE_FILTER], [0],
>  dnl Trace estasblished connections.
>  flow="$base_flow && ct_label.obs_point_id == 4302 && ct_mark.obs_stage ==
> 2 && ct_mark.obs_collector_id == 1"
>  AT_CHECK_UNQUOTED([ovn_trace --ct est --ct est ls "$flow" |
> TRACE_FILTER], [0], [dnl
> -    ct_commit { ct_mark.blocked = 0; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> +    ct_commit { ct_mark.blocked = 0; ct_mark.allow_established =
> reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; };
>      reg8[[0..7]] = 1;
>      reg8[[8..15]] = 1;
>      reg9 = 4302;
> @@ -13263,8 +13290,8 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e
> ls_out_acl_sample -e ls_out_acl_eval -e
>  dnl Trace new connections.
>  flow="$base_flow"
>  AT_CHECK_UNQUOTED([ovn_trace --ct new --ct new ls "$flow" |
> TRACE_FILTER], [0], [dnl
> -    ct_commit { ct_mark.blocked = 0; ct_mark.obs_stage = reg8[[19..20]];
> ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> -    ct_commit { ct_mark.blocked = 0; };
> +    ct_commit { ct_mark.blocked = 0; ct_mark.allow_established =
> reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id =
> reg8[[8..15]]; ct_label.obs_point_id = reg9; };
> +    ct_commit { ct_mark.blocked = 0; ct_mark.allow_established =
> reg0[[20]]; };
>      reg8[[0..7]] = 1;
>      reg8[[8..15]] = 0;
>      reg9 = 0;
> @@ -14384,3 +14411,137 @@ AT_CHECK([ovn-sbctl lflow-list S1 | grep
> ls_out_acl_action | grep priority=500 |
>
>  AT_CLEANUP
>  ])
> +
> +OVN_FOR_EACH_NORTHD_NO_HV([
> +AT_SETUP([ACL persistent ID - Logical Flows])
> +ovn_start
> +
> +dnl For this test, we want to ensure that the logical flows for ACLs are
> +dnl what we expect.
> +dnl
> +dnl First, we'll ensure that an ACL that does not have
> +dnl "persist-established" sets the relevant CT values to 0.
> +dnl
> +dnl Then we'll change the ACL to have "persist-established" to true
> +dnl and ensure the logical flows do set the appropriate values.
> +dnl
> +dnl Then finally, we'll check other ACL actions and ensure that
> +dnl "persist-established" sets the relevant CT values to 0.
> +
> +check ovn-nbctl ls-add sw
> +
> +check ovn-nbctl acl-add sw from-lport 1001 "tcp" allow-related
> +check ovn-nbctl acl-add sw to-lport 1002 "ip" allow-related
> +check ovn-nbctl --apply-after-lb acl-add sw from-lport 1003 "udp"
> allow-related
> +
> +AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_acl_eval | grep
> priority=2001 | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_in_acl_eval     ), priority=2001 , match=(reg0[[7]] == 1 &&
> (tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=2001 , match=(reg0[[8]] == 1 &&
> (tcp)), action=(reg8[[16]] = 1; next;)
> +])
> +
> +AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_acl_after_lb_eval | grep
> priority=2003 | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_in_acl_after_lb_eval), priority=2003 , match=(reg0[[7]] ==
> 1 && (udp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=2003 , match=(reg0[[8]] ==
> 1 && (udp)), action=(reg8[[16]] = 1; next;)
> +])
> +
> +AT_CHECK([ovn-sbctl lflow-list sw | grep ls_out_acl_eval | grep
> priority=2002 | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_out_acl_eval    ), priority=2002 , match=(reg0[[7]] == 1 &&
> (ip)), action=(reg8[[16]] = 1; reg0[[1]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=2002 , match=(reg0[[8]] == 1 &&
> (ip)), action=(reg8[[16]] = 1; next;)
> +])
> +
> +ingress_uuid=$(fetch_column nb:ACL _uuid priority=1001)
> +egress_uuid=$(fetch_column nb:ACL _uuid priority=1002)
> +after_lb_uuid=$(fetch_column nb:ACL _uuid priority=1003)
> +
> +check ovn-nbctl set acl $ingress_uuid options:persist-established=true
> +check ovn-nbctl set acl $egress_uuid options:persist-established=true
> +check ovn-nbctl set acl $after_lb_uuid options:persist-established=true
> +
> +dnl Now we should see the registers being set to the appropriate values.
> +AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_acl_eval | grep
> priority=2001 | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_in_acl_eval     ), priority=2001 , match=(reg0[[7]] == 1 &&
> (tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[20]] = 1; next;)
> +  table=??(ls_in_acl_eval     ), priority=2001 , match=(reg0[[8]] == 1 &&
> (tcp)), action=(reg8[[16]] = 1; next;)
> +])
> +
> +AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_acl_after_lb_eval | grep
> priority=2003 | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_in_acl_after_lb_eval), priority=2003 , match=(reg0[[7]] ==
> 1 && (udp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[20]] = 1; next;)
> +  table=??(ls_in_acl_after_lb_eval), priority=2003 , match=(reg0[[8]] ==
> 1 && (udp)), action=(reg8[[16]] = 1; next;)
> +])
> +
> +AT_CHECK([ovn-sbctl lflow-list sw | grep ls_out_acl_eval | grep
> priority=2002 | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_out_acl_eval    ), priority=2002 , match=(reg0[[7]] == 1 &&
> (ip)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[20]] = 1; next;)
> +  table=??(ls_out_acl_eval    ), priority=2002 , match=(reg0[[8]] == 1 &&
> (ip)), action=(reg8[[16]] = 1; next;)
> +])
> +
> +dnl Now try the other ACL verdicts and ensure that they do not
> +dnl try to set the values.
> +for verdict in allow allow-stateless
> +do
> +    echo "verdict is $verdict"
> +    check ovn-nbctl set acl $ingress_uuid action=$verdict
> +    check ovn-nbctl set acl $egress_uuid action=$verdict
> +    check ovn-nbctl set acl $after_lb_uuid action=$verdict
> +
> +    AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_acl_eval | grep
> priority=2001 | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_in_acl_eval     ), priority=2001 , match=((tcp)),
> action=(reg8[[16]] = 1; next;)
> +])
> +
> +    AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_acl_after_lb_eval |
> grep priority=2003 | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_in_acl_after_lb_eval), priority=2003 , match=((udp)),
> action=(reg8[[16]] = 1; next;)
> +])
> +
> +    AT_CHECK([ovn-sbctl lflow-list sw | grep ls_out_acl_eval | grep
> priority=2002 | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_out_acl_eval    ), priority=2002 , match=((ip)),
> action=(reg8[[16]] = 1; next;)
> +])
> +done
> +
> +check ovn-nbctl set acl $ingress_uuid action=drop
> +check ovn-nbctl set acl $egress_uuid action=drop
> +check ovn-nbctl set acl $after_lb_uuid action=drop
> +
> +AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_acl_eval | grep
> priority=2001 | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_in_acl_eval     ), priority=2001 , match=((tcp)),
> action=(reg8[[17]] = 1; next;)
> +])
> +
> +AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_acl_after_lb_eval | grep
> priority=2003 | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_in_acl_after_lb_eval), priority=2003 , match=((udp)),
> action=(reg8[[17]] = 1; next;)
> +])
> +
> +AT_CHECK([ovn-sbctl lflow-list sw | grep ls_out_acl_eval | grep
> priority=2002 | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_out_acl_eval    ), priority=2002 , match=((ip)),
> action=(reg8[[17]] = 1; next;)
> +])
> +
> +check ovn-nbctl set acl $ingress_uuid action=reject
> +check ovn-nbctl set acl $egress_uuid action=reject
> +check ovn-nbctl set acl $after_lb_uuid action=reject
> +
> +AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_acl_eval | grep
> priority=2001 | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_in_acl_eval     ), priority=2001 , match=((tcp)),
> action=(reg8[[18]] = 1; next;)
> +])
> +
> +AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_acl_after_lb_eval | grep
> priority=2003 | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_in_acl_after_lb_eval), priority=2003 , match=((udp)),
> action=(reg8[[18]] = 1; next;)
> +])
> +
> +AT_CHECK([ovn-sbctl lflow-list sw | grep ls_out_acl_eval | grep
> priority=2002 | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_out_acl_eval    ), priority=2002 , match=((ip)),
> action=(reg8[[18]] = 1; next;)
> +])
> +
> +check ovn-nbctl set acl $ingress_uuid action=pass
> +check ovn-nbctl set acl $egress_uuid action=pass
> +check ovn-nbctl set acl $after_lb_uuid action=pass
> +
> +AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_acl_eval | grep
> priority=2001 | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_in_acl_eval     ), priority=2001 , match=((tcp)),
> action=(next;)
> +])
> +
> +AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_acl_after_lb_eval | grep
> priority=2003 | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_in_acl_after_lb_eval), priority=2003 , match=((udp)),
> action=(next;)
> +])
> +
> +AT_CHECK([ovn-sbctl lflow-list sw | grep ls_out_acl_eval | grep
> priority=2002 | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_out_acl_eval    ), priority=2002 , match=((ip)),
> action=(next;)
> +])
> +
> +AT_CLEANUP
> +])
> diff --git a/tests/ovn.at b/tests/ovn.at
> index de01a649f..ae316d19e 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -145,6 +145,7 @@ ct_label.label = ct_label[96..127]
>  ct_label.obs_point_id = ct_label[96..127]
>  ct_label.obs_unused = ct_label[0..95]
>  ct_mark = NXM_NX_CT_MARK
> +ct_mark.allow_established = ct_mark[6]
>  ct_mark.blocked = ct_mark[0]
>  ct_mark.ecmp_reply_port = ct_mark[16..31]
>  ct_mark.force_snat = ct_mark[3]
> diff --git a/tests/server.py b/tests/server.py
> new file mode 100755
> index 000000000..ac0321f20
> --- /dev/null
> +++ b/tests/server.py
> @@ -0,0 +1,33 @@
> +#!/usr/bin/env python3
> +
> +import socket
> +import argparse
> +
> +
> +def start_server(host='127.0.0.1', port=10000):
> +    # Create a TCP/IP socket
> +    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as
> server_socket:
> +        server_socket.bind((host, port))
> +        server_socket.listen()
> +        with open("output.txt", "a") as f:
> +            f.write("Server Ready\n")
> +        while True:
> +            client_socket, client_address = server_socket.accept()
> +            with client_socket:
> +                # Receive the data from the client in chunks and write
> +                # to a file
> +                data = client_socket.recv(1024)
> +                while data:
> +                    with open("output.txt", "a") as f:
> +                        f.write(data.decode())
> +                    data = client_socket.recv(1024)
> +
> +
> +if __name__ == "__main__":
> +    parser = argparse.ArgumentParser()
> +    group = parser.add_argument_group()
> +    group.add_argument("-i", "--bind-host")
> +    group.add_argument("-p", "--bind-port", type=int)
> +    args = parser.parse_args()
> +
> +    start_server(args.bind_host, args.bind_port)
> diff --git a/tests/system-ovn.at b/tests/system-ovn.at
> index 19ec1eb8d..2f7de0eef 100644
> --- a/tests/system-ovn.at
> +++ b/tests/system-ovn.at
> @@ -14391,6 +14391,178 @@ as
>  OVS_TRAFFIC_VSWITCHD_STOP(["/.*error receiving.*/d
>  /failed to query port patch-.*/d
>  /.*terminating with signal 15.*/d"])
> +
> +AT_CLEANUP
> +])
> +
> +OVN_FOR_EACH_NORTHD([
> +AT_SETUP([ACLs - persistent sessions])
> +
> +CHECK_CONNTRACK()
> +CHECK_CONNTRACK_NAT()
> +ovn_start
> +OVS_TRAFFIC_VSWITCHD_START()
> +ADD_BR([br-int])
> +
> +ovs-vsctl set-fail-mode br-ext standalone
> +# Set external-ids in br-int needed for ovn-controller
> +ovs-vsctl \
> +        -- set Open_vSwitch . external-ids:system-id=hv1 \
> +        -- set Open_vSwitch .
> external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
> +        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
> +        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
> +        -- set bridge br-int fail-mode=secure
> other-config:disable-in-band=true
> +
> +start_daemon ovn-controller
> +
> +# For this test, we want to ensure that established traffic
> +# is allowed on ACLs when the persist-established option
> +# is enabled.
> +#
> +# To start, we will set up allow-related ACLs.
> +# We will send traffic and ensure it is allowed. Then we will adjust
> +# the ACL so it no longer matches, and we will ensure that the traffic
> +# is no longer allowed.
> +#
> +# Next, we will reset the ACL to its initial state, but we will also
> +# change the ACL to have persist-established enabled.
> +# We will flush conntrack, and rerun the test exactly as before.
> +# The difference this time is that after we adjust the ACL so it no
> +# longer matches, the traffic should still be allowed.
> +
> +check ovn-nbctl ls-add sw
> +check ovn-nbctl lsp-add sw swp1 -- lsp-set-addresses swp1
> "00:00:00:00:00:01 192.168.1.1"
> +check ovn-nbctl lsp-add sw swp2 -- lsp-set-addresses swp2
> "00:00:00:00:00:02 192.168.1.2"
> +
> +ADD_NAMESPACES(swp1)
> +ADD_VETH(swp1, swp1, br-int, "192.168.1.1/24", "00:00:00:00:00:01")
> +
> +ADD_NAMESPACES(swp2)
> +ADD_VETH(swp2, swp2, br-int, "192.168.1.2/24", "00:00:00:00:00:02")
> +
> +# Start a TCP server on swp2.
> +NETNS_DAEMONIZE(swp2, [server.py -i 192.168.1.2 -p 10000], [server.pid])
> +
> +# Ensure TCP server is ready for connections
> +OVS_WAIT_FOR_OUTPUT([cat output.txt], [0], [dnl
> +Server Ready
> +])
> +: > output.txt
> +
> +# Make a FIFO and send its output to a client
> +# from swp1
> +mkfifo /tmp/myfifo
> +on_exit 'rm -rf /tmp/myfifo'
> +
> +NETNS_DAEMONIZE(swp1, [client.py -f "/tmp/myfifo" -i 192.168.1.2 -p
> 10000], [client.pid])
> +
> +# First, ensure that we have basic connectivity before we even start
> setting
> +# up ACLs.
> +AT_CHECK([printf "test\n" > /tmp/myfifo], [0], [dnl
> +])
> +
> +OVS_WAIT_FOR_OUTPUT([cat output.txt], [0], [dnl
> +test
> +])
> +
> +: > output.txt
> +
> +check ovn-nbctl acl-add sw from-lport 1000 'ip4.dst == 192.168.1.2'
> allow-related
> +check ovn-nbctl acl-add sw from-lport 0 '1' drop
> +
> +# Do another basic connectivity check to ensure the ACL is allowing
> traffic as expected.
> +AT_CHECK([printf "test\n" > /tmp/myfifo], [0], [dnl
> +])
> +
> +OVS_WAIT_FOR_OUTPUT([cat output.txt], [0], [dnl
> +test
> +])
> +
> +: > output.txt
> +
> +# At this point, I need to adjust the ACL so it no longer matches. We
> then need
> +# to ensure that the traffic does not pass. How we test this
> is...interesting. I'm
> +# not sure how to test for a negative condition accurately.
> +
> +acl_uuid=$(fetch_column nb:ACL _uuid priority=1000)
> +
> +# Update the ACL so that it no longer matches our client-server traffic
> +check ovn-nbctl set ACL $acl_uuid match="\"ip4.dst == 192.168.1.3\""
> +
> +# Send another packet from the client to the server.
> +AT_CHECK([printf "test\n" > /tmp/myfifo], [0], [dnl
> +])
> +
> +# The traffic should be blocked. We'll check the "drop" ACL to see if it
> has
> +# been hit. We can't predict the number of packets that will be seen, but
> we know
> +# it will be non-zero.
> +lflow_table=$(ovn-debug lflow-stage-to-ltable ls_in_acl_eval)
> +drop_acl_lflow_uuid=$(fetch_column Logical_Flow _uuid pipeline=ingress
> table_id=$lflow_table priority=1000 match="\"reg0[[9]] == 1 && (1)\"")
> +drop_acl_cookie=$(ovn-debug uuid-to-cookie $drop_acl_lflow_uuid)
> +
> +OVS_WAIT_FOR_OUTPUT([ovs-ofctl dump-flows br-int | grep
> "cookie=$drop_acl_cookie" | grep -c "n_packets=[[1-9]][[0-9]]*"], [0], [dnl
> +1
> +])
> +
> +# And just to be safe, let's make sure the output file is still empty
> +AT_CHECK([cat output.txt], [0], [dnl
> +])
> +
> +# Reset the client and server processes so that we create a new connection
> +client_pid=$(cat client.pid)
> +server_pid=$(cat server.pid)
> +kill $server_pid
> +kill $client_pid
> +OVS_WAIT_WHILE([kill -0 $server_pid 2>/dev/null])
> +OVS_WAIT_WHILE([kill -0 $client_pid 2>/dev/null])
> +
> +NETNS_DAEMONIZE(swp2, [server.py -i 192.168.1.2 -p 20000], [server.pid])
> +NETNS_DAEMONIZE(swp1, [client.py -f "/tmp/myfifo" -i 192.168.1.2 -p
> 20000], [client.pid])
> +
> +# Now we'll re-set the ACL to allow the traffic.
> +check ovn-nbctl set ACL $acl_uuid match="\"ip4.dst == 192.168.1.2\""
> +
> +# We'll also enable persist-established.
> +check ovn-nbctl --wait=hv set ACL $acl_uuid
> options:persist-established=true
> +
> +# Make sure traffic passes
> +AT_CHECK([printf "test\n" > /tmp/myfifo], [0], [dnl
> +])
> +
> +OVS_WAIT_FOR_OUTPUT([cat output.txt], [0], [dnl
> +test
> +])
> +
> +: > output.txt
> +
> +# Adjust the ACL so that it no longer matches
> +check ovn-nbctl set ACL $acl_uuid match="\"ip4.dst == 192.168.1.3\""
> +
> +# Traffic should still pass
> +AT_CHECK([printf "test\n" > /tmp/myfifo], [0], [dnl
> +])
> +
> +OVS_WAIT_FOR_OUTPUT([cat output.txt], [0], [dnl
> +test
> +])
> +
> +: > output.txt
> +
> +OVS_APP_EXIT_AND_WAIT([ovn-controller])
> +
> +as ovn-sb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as ovn-nb
> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> +
> +as northd
> +OVS_APP_EXIT_AND_WAIT([ovn-northd])
> +
> +as
> +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
> +/connection dropped.*/d"])
> +
>  AT_CLEANUP
>  ])
>
> --
> 2.45.2
>
> _______________________________________________
> dev mailing list
> [email protected]
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
>
Looks good to me, thanks.
Acked-by: Ales Musil <[email protected]>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to