Introduce REGBIT_PKT_SAMPLED (reg0[22]) bit in the logical switch
pipeline in order to avoid sampling traffic hitting the ACLs multiple
times (e.g. when the traffic is egressing from the patch port connecting
the logical switch to a logical router).
Preserve the REGBIT_PKT_SAMPLED value passing from the logical switch
ingress pipeline to  the logical switch egress one.
This patch will fix the oversampling issue reported in
https://mail.openvswitch.org/pipermail/ovs-discuss/2025-May/053626.html

Reported-at: https://issues.redhat.com/browse/FDP-1408
Signed-off-by: Lorenzo Bianconi <[email protected]>
---
Changes in v2:
- Do not always clear connection tracking entry for patch port since
  this will break some allow-related ACL use-cases.
---
 controller/physical.c |  11 +++-
 northd/northd.c       |  25 ++++++---
 tests/ovn-northd.at   |  86 ++++++++++++++---------------
 tests/system-ovn.at   | 125 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 193 insertions(+), 54 deletions(-)

diff --git a/controller/physical.c b/controller/physical.c
index 9ca535a6c..6008a5c24 100644
--- a/controller/physical.c
+++ b/controller/physical.c
@@ -3256,10 +3256,17 @@ physical_run(struct physical_ctx *p_ctx,
      *
      * Resubmit packets that don't output to the ingress port (already checked
      * in table 44) to the logical egress pipeline, clearing the logical
-     * registers (for consistent behavior with packets that get tunneled). */
+     * registers (for consistent behavior with packets that get tunneled).
+     * Do not clear reg0[22] since it contains the bit to allow sampling on
+     * egress pipeline. */
     match_init_catchall(&match);
     ofpbuf_clear(&ofpacts);
-    for (int i = 0; i < MFF_N_LOG_REGS; i++) {
+
+    ovs_be32 value = htonl(0);
+    ovs_be32 mask = htonl(~(1 << 22));
+    ofpact_put_set_field(
+        &ofpacts, mf_from_id(MFF_REG0), &value, &mask);
+    for (int i = 1; i < MFF_N_LOG_REGS; i++) {
         put_load(0, MFF_REG0 + i, 0, 32, &ofpacts);
     }
     put_resubmit(OFTABLE_LOG_EGRESS_PIPELINE, &ofpacts);
diff --git a/northd/northd.c b/northd/northd.c
index fe5199a86..fde4a7393 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -135,6 +135,7 @@ static bool vxlan_mode;
 #define REGBIT_IP_FRAG            "reg0[19]"
 #define REGBIT_ACL_PERSIST_ID     "reg0[20]"
 #define REGBIT_ACL_HINT_ALLOW_PERSISTED "reg0[21]"
+#define REGBIT_PKT_SAMPLED        "reg0[22]"
 
 /* Register definitions for switches and routers. */
 
@@ -5849,7 +5850,7 @@ skip_port_from_conntrack(const struct ovn_datapath *od, 
struct ovn_port *op,
     const char *ingress_action = "next;";
     const char *egress_action = has_stateful_acl
                                 ? "next;"
-                                : "ct_clear; next;";
+                                : REGBIT_PKT_SAMPLED" = 0; ct_clear; next;";
 
     char *ingress_match = xasprintf("ip && inport == %s", op->json_key);
     char *egress_match = xasprintf("ip && outport == %s", op->json_key);
@@ -6463,7 +6464,8 @@ build_acl_sample_action(struct ds *actions, const struct 
nbrec_acl *acl,
     }
 
     for (size_t i = 0; i < sample->n_collectors; i++) {
-        ds_put_format(actions, "sample(probability=%"PRIu16","
+        ds_put_format(actions, REGBIT_PKT_SAMPLED" = 1; "
+                               "sample(probability=%"PRIu16","
                                "collector_set=%"PRIu32","
                                "obs_domain=%"PRIu32","
                                "obs_point=%"PRIu32");",
@@ -6621,7 +6623,8 @@ build_acl_sample_est_orig_stateful_flows(const struct 
ovn_datapath *od,
     ds_clear(actions);
     ds_clear(match);
 
-    ds_put_cstr(match, "ip && ct.trk && "
+    ds_put_cstr(match, REGBIT_PKT_SAMPLED" == 0 && "
+                       "ip && ct.trk && "
                        "(ct.est || ct.rel) && "
                        "!ct.rpl && ");
     build_acl_sample_label_match(match, acl, acl->sample_est);
@@ -6654,9 +6657,10 @@ build_acl_sample_est_rpl_stateful_flows(const struct 
ovn_datapath *od,
     ds_clear(actions);
     ds_clear(match);
 
-    ds_put_cstr(match, "ip && ct.trk && "
-                        "(ct.est || ct.rel) && "
-                        "ct.rpl && ");
+    ds_put_cstr(match, REGBIT_PKT_SAMPLED" == 0 && "
+                       "ip && ct.trk && "
+                       "(ct.est || ct.rel) && "
+                       "ct.rpl && ");
     build_acl_sample_label_match(match, acl, acl->sample_est);
 
     build_acl_sample_action(actions, acl, acl->sample_est, sample_domain_id);
@@ -6731,7 +6735,8 @@ build_acl_sample_generic_new_flows(const struct 
ovn_datapath *od,
                          (uint8_t) coll->id,
                          (uint8_t) obs_stage);
 
-    ds_put_format(actions, "sample(probability=%"PRIu16","
+    ds_put_format(actions, REGBIT_PKT_SAMPLED" = 1; "
+                           "sample(probability=%"PRIu16","
                            "collector_set=%"PRIu32","
                            "obs_domain=%"PRIu32","
                            "obs_point="REG_OBS_POINT_ID_NEW");"
@@ -6761,7 +6766,8 @@ build_acl_sample_generic_est_flows(const struct 
ovn_datapath *od,
     ds_clear(match);
     ds_clear(actions);
 
-    ds_put_cstr(match, "ip && ct.trk && (ct.est || ct.rel) && "
+    ds_put_cstr(match, REGBIT_PKT_SAMPLED" == 0 && "
+                       "ip && ct.trk && (ct.est || ct.rel) && "
                        "ct_label.obs_unused == 0 && ");
 
     size_t match_len = match->length;
@@ -6770,7 +6776,8 @@ build_acl_sample_generic_est_flows(const struct 
ovn_datapath *od,
                          (uint8_t) coll->id,
                          (uint8_t) obs_stage);
 
-    ds_put_format(actions, "sample(probability=%"PRIu16","
+    ds_put_format(actions, REGBIT_PKT_SAMPLED" = 1; "
+                           "sample(probability=%"PRIu16","
                            "collector_set=%"PRIu32","
                            "obs_domain=%"PRIu32","
                            "obs_point=ct_label.obs_point_id);"
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index 83a142d20..f5009946c 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -4872,7 +4872,7 @@ check_stateful_flows() {
 ])
 }
 
-check_stateful_flows "ct_clear; next;"
+check_stateful_flows "reg0[[22]] = 0; ct_clear; next;"
 
 # Add few ACLs
 check ovn-nbctl --wait=sb acl-add sw0 from-lport 1002 "ip4 && tcp && tcp.dst 
== 80" allow-related
@@ -10913,7 +10913,7 @@ AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_pre_lb | 
grep priority=110 | grep
 ])
 
 AT_CHECK([ovn-sbctl lflow-list sw | grep ls_out_pre_lb | grep priority=110 | 
grep sw-ln | ovn_strip_lflows], [0], [dnl
-  table=??(ls_out_pre_lb      ), priority=110  , match=(ip && outport == 
"sw-ln"), action=(ct_clear; next;)
+  table=??(ls_out_pre_lb      ), priority=110  , match=(ip && outport == 
"sw-ln"), action=(reg0[[22]] = 0; ct_clear; next;)
 ])
 
 # Now add a load balancer and ensure that we no longer are skipping conntrack
@@ -10939,7 +10939,7 @@ AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_pre_lb | 
grep priority=110 | grep
 ])
 
 AT_CHECK([ovn-sbctl lflow-list sw | grep ls_out_pre_lb | grep priority=110 | 
grep sw-ln | ovn_strip_lflows], [0], [dnl
-  table=??(ls_out_pre_lb      ), priority=110  , match=(ip && outport == 
"sw-ln"), action=(ct_clear; next;)
+  table=??(ls_out_pre_lb      ), priority=110  , match=(ip && outport == 
"sw-ln"), action=(reg0[[22]] = 0; ct_clear; next;)
 ])
 
 AT_CLEANUP
@@ -13184,10 +13184,10 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e 
ls_in_acl_sample -e ls_in_acl_eval -e l
   table=??(ls_in_acl_eval     ), priority=1001 , match=(reg0[[7]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 = 4302; 
reg8[[0..7]] = 0; reg8[[8..15]] = 0; reg8[[19..20]] = 0; next;)
   table=??(ls_in_acl_eval     ), priority=1001 , match=(reg0[[8]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 
= 4302; reg8[[0..7]] = 0; reg8[[8..15]] = 0; reg8[[19..20]] = 0; next;)
   table=??(ls_in_acl_sample   ), priority=0    , match=(1), action=(next;)
-  table=??(ls_in_acl_sample   ), priority=1100 , match=(ip && ct.new && reg3 
== 4301), 
action=(sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301);sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301);
 next;)
-  table=??(ls_in_acl_sample   ), priority=1200 , match=(ip && ct.trk && 
(ct.est || ct.rel) && !ct.rpl && ct_label.obs_point_id == 4302 && 
ct_label.obs_unused == 0), 
action=(sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302);sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302);
 next;)
+  table=??(ls_in_acl_sample   ), priority=1100 , match=(ip && ct.new && reg3 
== 4301), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301);reg0[[22]]
 = 1; sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301); 
next;)
+  table=??(ls_in_acl_sample   ), priority=1200 , match=(reg0[[22]] == 0 && ip 
&& ct.trk && (ct.est || ct.rel) && !ct.rpl && ct_label.obs_point_id == 4302 && 
ct_label.obs_unused == 0), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302);reg0[[22]]
 = 1; sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302); 
next;)
   table=??(ls_out_acl_sample  ), priority=0    , match=(1), action=(next;)
-  table=??(ls_out_acl_sample  ), priority=1200 , match=(ip && ct.trk && 
(ct.est || ct.rel) && ct.rpl && ct_label.obs_point_id == 4302 && 
ct_label.obs_unused == 0), 
action=(sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302);sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302);
 next;)
+  table=??(ls_out_acl_sample  ), priority=1200 , match=(reg0[[22]] == 0 && ip 
&& ct.trk && (ct.est || ct.rel) && ct.rpl && ct_label.obs_point_id == 4302 && 
ct_label.obs_unused == 0), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302);reg0[[22]]
 = 1; sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302); 
next;)
 ])
 
 dnl Trace new connections.
@@ -13217,7 +13217,7 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e 
ls_in_acl_sample -e ls_in_acl_eval -e l
   table=??(ls_in_acl_eval     ), priority=1001 , match=(reg0[[7]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 = 0; 
reg8[[0..7]] = 0; reg8[[8..15]] = 0; reg8[[19..20]] = 0; next;)
   table=??(ls_in_acl_eval     ), priority=1001 , match=(reg0[[8]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 = 0; 
reg8[[0..7]] = 0; reg8[[8..15]] = 0; reg8[[19..20]] = 0; next;)
   table=??(ls_in_acl_sample   ), priority=0    , match=(1), action=(next;)
-  table=??(ls_in_acl_sample   ), priority=1100 , match=(ip && ct.new && reg3 
== 4301), 
action=(sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301);sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301);
 next;)
+  table=??(ls_in_acl_sample   ), priority=1100 , match=(ip && ct.new && reg3 
== 4301), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301);reg0[[22]]
 = 1; sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301); 
next;)
   table=??(ls_out_acl_sample  ), priority=0    , match=(1), action=(next;)
 ])
 
@@ -13247,10 +13247,10 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e 
ls_in_acl_after_lb_sample -e ls_in_acl_
   table=??(ls_in_acl_after_lb_eval), priority=1001 , match=(reg0[[7]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 = 4302; 
reg8[[0..7]] = 0; reg8[[8..15]] = 0; reg8[[19..20]] = 1; next;)
   table=??(ls_in_acl_after_lb_eval), priority=1001 , match=(reg0[[8]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 
= 4302; reg8[[0..7]] = 0; reg8[[8..15]] = 0; reg8[[19..20]] = 1; next;)
   table=??(ls_in_acl_after_lb_sample), priority=0    , match=(1), 
action=(next;)
-  table=??(ls_in_acl_after_lb_sample), priority=1100 , match=(ip && ct.new && 
reg3 == 4301), 
action=(sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301);sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301);
 next;)
-  table=??(ls_in_acl_after_lb_sample), priority=1200 , match=(ip && ct.trk && 
(ct.est || ct.rel) && !ct.rpl && ct_label.obs_point_id == 4302 && 
ct_label.obs_unused == 0), 
action=(sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302);sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302);
 next;)
+  table=??(ls_in_acl_after_lb_sample), priority=1100 , match=(ip && ct.new && 
reg3 == 4301), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301);reg0[[22]]
 = 1; sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301); 
next;)
+  table=??(ls_in_acl_after_lb_sample), priority=1200 , match=(reg0[[22]] == 0 
&& ip && ct.trk && (ct.est || ct.rel) && !ct.rpl && ct_label.obs_point_id == 
4302 && ct_label.obs_unused == 0), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302);reg0[[22]]
 = 1; sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302); 
next;)
   table=??(ls_out_acl_sample  ), priority=0    , match=(1), action=(next;)
-  table=??(ls_out_acl_sample  ), priority=1200 , match=(ip && ct.trk && 
(ct.est || ct.rel) && ct.rpl && ct_label.obs_point_id == 4302 && 
ct_label.obs_unused == 0), 
action=(sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302);sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302);
 next;)
+  table=??(ls_out_acl_sample  ), priority=1200 , match=(reg0[[22]] == 0 && ip 
&& ct.trk && (ct.est || ct.rel) && ct.rpl && ct_label.obs_point_id == 4302 && 
ct_label.obs_unused == 0), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302);reg0[[22]]
 = 1; sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302); 
next;)
 ])
 
 dnl Trace new connections.
@@ -13280,7 +13280,7 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e 
ls_in_acl_after_lb_sample -e ls_in_acl_
   table=??(ls_in_acl_after_lb_eval), priority=1001 , match=(reg0[[7]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 = 0; 
reg8[[0..7]] = 0; reg8[[8..15]] = 0; reg8[[19..20]] = 1; next;)
   table=??(ls_in_acl_after_lb_eval), priority=1001 , match=(reg0[[8]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 = 0; 
reg8[[0..7]] = 0; reg8[[8..15]] = 0; reg8[[19..20]] = 1; next;)
   table=??(ls_in_acl_after_lb_sample), priority=0    , match=(1), 
action=(next;)
-  table=??(ls_in_acl_after_lb_sample), priority=1100 , match=(ip && ct.new && 
reg3 == 4301), 
action=(sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301);sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301);
 next;)
+  table=??(ls_in_acl_after_lb_sample), priority=1100 , match=(ip && ct.new && 
reg3 == 4301), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301);reg0[[22]]
 = 1; sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301); 
next;)
   table=??(ls_out_acl_sample  ), priority=0    , match=(1), action=(next;)
 ])
 
@@ -13308,12 +13308,12 @@ check_uuid ovn-nbctl --wait=sb \
   --sample-new=@sample1 --sample-est=@sample2 acl-add ls to-lport 1 "1" 
allow-related
 AT_CHECK([ovn-sbctl lflow-list | grep -e ls_out_acl_sample -e ls_out_acl_eval 
-e ls_in_acl_sample | ovn_strip_lflows | ovn_strip_collector_set | grep -e reg3 
-e reg9 -e sample], [0], [dnl
   table=??(ls_in_acl_sample   ), priority=0    , match=(1), action=(next;)
-  table=??(ls_in_acl_sample   ), priority=1200 , match=(ip && ct.trk && 
(ct.est || ct.rel) && ct.rpl && ct_label.obs_point_id == 4302 && 
ct_label.obs_unused == 0), 
action=(sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302);sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302);
 next;)
+  table=??(ls_in_acl_sample   ), priority=1200 , match=(reg0[[22]] == 0 && ip 
&& ct.trk && (ct.est || ct.rel) && ct.rpl && ct_label.obs_point_id == 4302 && 
ct_label.obs_unused == 0), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302);reg0[[22]]
 = 1; sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302); 
next;)
   table=??(ls_out_acl_eval    ), priority=1001 , match=(reg0[[7]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 = 4302; 
reg8[[0..7]] = 0; reg8[[8..15]] = 0; reg8[[19..20]] = 2; next;)
   table=??(ls_out_acl_eval    ), priority=1001 , match=(reg0[[8]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 
= 4302; reg8[[0..7]] = 0; reg8[[8..15]] = 0; reg8[[19..20]] = 2; next;)
   table=??(ls_out_acl_sample  ), priority=0    , match=(1), action=(next;)
-  table=??(ls_out_acl_sample  ), priority=1100 , match=(ip && (ct.new || 
!ct.trk) && reg3 == 4301), 
action=(sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301);sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301);
 next;)
-  table=??(ls_out_acl_sample  ), priority=1200 , match=(ip && ct.trk && 
(ct.est || ct.rel) && !ct.rpl && ct_label.obs_point_id == 4302 && 
ct_label.obs_unused == 0), 
action=(sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302);sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302);
 next;)
+  table=??(ls_out_acl_sample  ), priority=1100 , match=(ip && (ct.new || 
!ct.trk) && reg3 == 4301), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301);reg0[[22]]
 = 1; sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301); 
next;)
+  table=??(ls_out_acl_sample  ), priority=1200 , match=(reg0[[22]] == 0 && ip 
&& ct.trk && (ct.est || ct.rel) && !ct.rpl && ct_label.obs_point_id == 4302 && 
ct_label.obs_unused == 0), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302);reg0[[22]]
 = 1; sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302); 
next;)
 ])
 
 dnl Trace new connections.
@@ -13345,7 +13345,7 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e 
ls_out_acl_sample -e ls_out_acl_eval -e
   table=??(ls_out_acl_eval    ), priority=1001 , match=(reg0[[7]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 = 0; 
reg8[[0..7]] = 0; reg8[[8..15]] = 0; reg8[[19..20]] = 2; next;)
   table=??(ls_out_acl_eval    ), priority=1001 , match=(reg0[[8]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 = 0; 
reg8[[0..7]] = 0; reg8[[8..15]] = 0; reg8[[19..20]] = 2; next;)
   table=??(ls_out_acl_sample  ), priority=0    , match=(1), action=(next;)
-  table=??(ls_out_acl_sample  ), priority=1100 , match=(ip && (ct.new || 
!ct.trk) && reg3 == 4301), 
action=(sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301);sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301);
 next;)
+  table=??(ls_out_acl_sample  ), priority=1100 , match=(ip && (ct.new || 
!ct.trk) && reg3 == 4301), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301);reg0[[22]]
 = 1; sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301); 
next;)
 ])
 
 dnl Trace new connections.
@@ -13405,10 +13405,10 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e 
ls_in_acl_sample -e ls_in_acl_eval -e l
   table=??(ls_in_acl_eval     ), priority=1001 , match=(reg0[[7]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 = 4302; 
reg8[[0..7]] = 1; reg8[[8..15]] = 1; reg8[[19..20]] = 0; next;)
   table=??(ls_in_acl_eval     ), priority=1001 , match=(reg0[[8]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 
= 4302; reg8[[0..7]] = 1; reg8[[8..15]] = 1; reg8[[19..20]] = 0; next;)
   table=??(ls_in_acl_sample   ), priority=0    , match=(1), action=(next;)
-  table=??(ls_in_acl_sample   ), priority=1100 , match=(ip && ct.new && reg3 
== 4301), 
action=(sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301);
 next;)
-  table=??(ls_in_acl_sample   ), priority=1200 , match=(ip && ct.trk && 
(ct.est || ct.rel) && !ct.rpl && ct_label.obs_point_id == 4302 && 
ct_label.obs_unused == 0), 
action=(sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302);
 next;)
+  table=??(ls_in_acl_sample   ), priority=1100 , match=(ip && ct.new && reg3 
== 4301), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=42,obs_point=4301); next;)
+  table=??(ls_in_acl_sample   ), priority=1200 , match=(reg0[[22]] == 0 && ip 
&& ct.trk && (ct.est || ct.rel) && !ct.rpl && ct_label.obs_point_id == 4302 && 
ct_label.obs_unused == 0), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302); next;)
   table=??(ls_out_acl_sample  ), priority=0    , match=(1), action=(next;)
-  table=??(ls_out_acl_sample  ), priority=1200 , match=(ip && ct.trk && 
(ct.est || ct.rel) && ct.rpl && ct_label.obs_point_id == 4302 && 
ct_label.obs_unused == 0), 
action=(sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302);
 next;)
+  table=??(ls_out_acl_sample  ), priority=1200 , match=(reg0[[22]] == 0 && ip 
&& ct.trk && (ct.est || ct.rel) && ct.rpl && ct_label.obs_point_id == 4302 && 
ct_label.obs_unused == 0), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=43,obs_point=4302); next;)
 ])
 
 dnl Trace new connections.
@@ -13443,10 +13443,10 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e 
ls_in_acl_sample -e ls_in_acl_eval -e l
   table=??(ls_in_acl_eval     ), priority=1001 , match=(reg0[[7]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 = 4302; 
reg8[[0..7]] = 1; reg8[[8..15]] = 1; reg8[[19..20]] = 0; next;)
   table=??(ls_in_acl_eval     ), priority=1001 , match=(reg0[[8]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 
= 4302; reg8[[0..7]] = 1; reg8[[8..15]] = 1; reg8[[19..20]] = 0; next;)
   table=??(ls_in_acl_sample   ), priority=0    , match=(1), action=(next;)
-  table=??(ls_in_acl_sample   ), priority=1000 , match=(ip && ct.new && 
reg8[[0..7]] == 1 && reg8[[19..20]] == 0), 
action=(sample(probability=65535,collector_set=??,obs_domain=42,obs_point=reg3);
 next;)
-  table=??(ls_in_acl_sample   ), priority=1000 , match=(ip && ct.trk && 
(ct.est || ct.rel) && ct_label.obs_unused == 0 && !ct.rpl && 
ct_mark.obs_collector_id == 1 && ct_mark.obs_stage == 0), 
action=(sample(probability=65535,collector_set=??,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
+  table=??(ls_in_acl_sample   ), priority=1000 , match=(ip && ct.new && 
reg8[[0..7]] == 1 && reg8[[19..20]] == 0), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=42,obs_point=reg3); next;)
+  table=??(ls_in_acl_sample   ), priority=1000 , match=(reg0[[22]] == 0 && ip 
&& ct.trk && (ct.est || ct.rel) && ct_label.obs_unused == 0 && !ct.rpl && 
ct_mark.obs_collector_id == 1 && ct_mark.obs_stage == 0), action=(reg0[[22]] = 
1; 
sample(probability=65535,collector_set=??,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
   table=??(ls_out_acl_sample  ), priority=0    , match=(1), action=(next;)
-  table=??(ls_out_acl_sample  ), priority=1000 , match=(ip && ct.trk && 
(ct.est || ct.rel) && ct_label.obs_unused == 0 && ct.rpl && 
ct_mark.obs_collector_id == 1), 
action=(sample(probability=65535,collector_set=??,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
+  table=??(ls_out_acl_sample  ), priority=1000 , match=(reg0[[22]] == 0 && ip 
&& ct.trk && (ct.est || ct.rel) && ct_label.obs_unused == 0 && ct.rpl && 
ct_mark.obs_collector_id == 1), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
 ])
 
 dnl Trace new connections.
@@ -13478,7 +13478,7 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e 
ls_in_acl_sample -e ls_in_acl_eval -e l
   table=??(ls_in_acl_eval     ), priority=1001 , match=(reg0[[7]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 = 0; 
reg8[[0..7]] = 1; reg8[[8..15]] = 0; reg8[[19..20]] = 0; next;)
   table=??(ls_in_acl_eval     ), priority=1001 , match=(reg0[[8]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 = 0; 
reg8[[0..7]] = 1; reg8[[8..15]] = 0; reg8[[19..20]] = 0; next;)
   table=??(ls_in_acl_sample   ), priority=0    , match=(1), action=(next;)
-  table=??(ls_in_acl_sample   ), priority=1000 , match=(ip && ct.new && 
reg8[[0..7]] == 1 && reg8[[19..20]] == 0), 
action=(sample(probability=65535,collector_set=??,obs_domain=42,obs_point=reg3);
 next;)
+  table=??(ls_in_acl_sample   ), priority=1000 , match=(ip && ct.new && 
reg8[[0..7]] == 1 && reg8[[19..20]] == 0), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=42,obs_point=reg3); next;)
   table=??(ls_out_acl_sample  ), priority=0    , match=(1), action=(next;)
 ])
 
@@ -13511,10 +13511,10 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e 
ls_in_acl_after_lb_sample -e ls_in_acl_
   table=??(ls_in_acl_after_lb_eval), priority=1001 , match=(reg0[[7]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 = 4302; 
reg8[[0..7]] = 1; reg8[[8..15]] = 1; reg8[[19..20]] = 1; next;)
   table=??(ls_in_acl_after_lb_eval), priority=1001 , match=(reg0[[8]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 
= 4302; reg8[[0..7]] = 1; reg8[[8..15]] = 1; reg8[[19..20]] = 1; next;)
   table=??(ls_in_acl_after_lb_sample), priority=0    , match=(1), 
action=(next;)
-  table=??(ls_in_acl_after_lb_sample), priority=1000 , match=(ip && ct.new && 
reg8[[0..7]] == 1 && reg8[[19..20]] == 1), 
action=(sample(probability=65535,collector_set=??,obs_domain=42,obs_point=reg3);
 next;)
-  table=??(ls_in_acl_after_lb_sample), priority=1000 , match=(ip && ct.trk && 
(ct.est || ct.rel) && ct_label.obs_unused == 0 && !ct.rpl && 
ct_mark.obs_collector_id == 1 && ct_mark.obs_stage == 1), 
action=(sample(probability=65535,collector_set=??,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
+  table=??(ls_in_acl_after_lb_sample), priority=1000 , match=(ip && ct.new && 
reg8[[0..7]] == 1 && reg8[[19..20]] == 1), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=42,obs_point=reg3); next;)
+  table=??(ls_in_acl_after_lb_sample), priority=1000 , match=(reg0[[22]] == 0 
&& ip && ct.trk && (ct.est || ct.rel) && ct_label.obs_unused == 0 && !ct.rpl && 
ct_mark.obs_collector_id == 1 && ct_mark.obs_stage == 1), action=(reg0[[22]] = 
1; 
sample(probability=65535,collector_set=??,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
   table=??(ls_out_acl_sample  ), priority=0    , match=(1), action=(next;)
-  table=??(ls_out_acl_sample  ), priority=1000 , match=(ip && ct.trk && 
(ct.est || ct.rel) && ct_label.obs_unused == 0 && ct.rpl && 
ct_mark.obs_collector_id == 1), 
action=(sample(probability=65535,collector_set=??,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
+  table=??(ls_out_acl_sample  ), priority=1000 , match=(reg0[[22]] == 0 && ip 
&& ct.trk && (ct.est || ct.rel) && ct_label.obs_unused == 0 && ct.rpl && 
ct_mark.obs_collector_id == 1), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
 ])
 
 dnl Trace new connections.
@@ -13546,7 +13546,7 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e 
ls_in_acl_after_lb_sample -e ls_in_acl_
   table=??(ls_in_acl_after_lb_eval), priority=1001 , match=(reg0[[7]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 = 0; 
reg8[[0..7]] = 1; reg8[[8..15]] = 0; reg8[[19..20]] = 1; next;)
   table=??(ls_in_acl_after_lb_eval), priority=1001 , match=(reg0[[8]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 = 0; 
reg8[[0..7]] = 1; reg8[[8..15]] = 0; reg8[[19..20]] = 1; next;)
   table=??(ls_in_acl_after_lb_sample), priority=0    , match=(1), 
action=(next;)
-  table=??(ls_in_acl_after_lb_sample), priority=1000 , match=(ip && ct.new && 
reg8[[0..7]] == 1 && reg8[[19..20]] == 1), 
action=(sample(probability=65535,collector_set=??,obs_domain=42,obs_point=reg3);
 next;)
+  table=??(ls_in_acl_after_lb_sample), priority=1000 , match=(ip && ct.new && 
reg8[[0..7]] == 1 && reg8[[19..20]] == 1), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=42,obs_point=reg3); next;)
   table=??(ls_out_acl_sample  ), priority=0    , match=(1), action=(next;)
 ])
 
@@ -13577,12 +13577,12 @@ check_uuid ovn-nbctl --wait=sb                        
                 \
   --sample-new=@sample1 --sample-est=@sample2 acl-add ls to-lport 1 "1" 
allow-related
 AT_CHECK([ovn-sbctl lflow-list | grep -e ls_out_acl_sample -e ls_out_acl_eval 
-e ls_in_acl_sample | ovn_strip_lflows | ovn_strip_collector_set | grep -e reg3 
-e reg9 -e sample], [0], [dnl
   table=??(ls_in_acl_sample   ), priority=0    , match=(1), action=(next;)
-  table=??(ls_in_acl_sample   ), priority=1000 , match=(ip && ct.trk && 
(ct.est || ct.rel) && ct_label.obs_unused == 0 && ct.rpl && 
ct_mark.obs_collector_id == 1), 
action=(sample(probability=65535,collector_set=??,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
+  table=??(ls_in_acl_sample   ), priority=1000 , match=(reg0[[22]] == 0 && ip 
&& ct.trk && (ct.est || ct.rel) && ct_label.obs_unused == 0 && ct.rpl && 
ct_mark.obs_collector_id == 1), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
   table=??(ls_out_acl_eval    ), priority=1001 , match=(reg0[[7]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 = 4302; 
reg8[[0..7]] = 1; reg8[[8..15]] = 1; reg8[[19..20]] = 2; next;)
   table=??(ls_out_acl_eval    ), priority=1001 , match=(reg0[[8]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 
= 4302; reg8[[0..7]] = 1; reg8[[8..15]] = 1; reg8[[19..20]] = 2; next;)
   table=??(ls_out_acl_sample  ), priority=0    , match=(1), action=(next;)
-  table=??(ls_out_acl_sample  ), priority=1000 , match=(ip && (ct.new || 
!ct.trk) && reg8[[0..7]] == 1 && reg8[[19..20]] == 2), 
action=(sample(probability=65535,collector_set=??,obs_domain=42,obs_point=reg3);
 next;)
-  table=??(ls_out_acl_sample  ), priority=1000 , match=(ip && ct.trk && 
(ct.est || ct.rel) && ct_label.obs_unused == 0 && !ct.rpl && 
ct_mark.obs_collector_id == 1 && ct_mark.obs_stage == 2), 
action=(sample(probability=65535,collector_set=??,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
+  table=??(ls_out_acl_sample  ), priority=1000 , match=(ip && (ct.new || 
!ct.trk) && reg8[[0..7]] == 1 && reg8[[19..20]] == 2), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=42,obs_point=reg3); next;)
+  table=??(ls_out_acl_sample  ), priority=1000 , match=(reg0[[22]] == 0 && ip 
&& ct.trk && (ct.est || ct.rel) && ct_label.obs_unused == 0 && !ct.rpl && 
ct_mark.obs_collector_id == 1 && ct_mark.obs_stage == 2), action=(reg0[[22]] = 
1; 
sample(probability=65535,collector_set=??,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
 ])
 
 dnl Trace new connections.
@@ -13616,7 +13616,7 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e 
ls_out_acl_sample -e ls_out_acl_eval -e
   table=??(ls_out_acl_eval    ), priority=1001 , match=(reg0[[7]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 = 0; 
reg8[[0..7]] = 1; reg8[[8..15]] = 0; reg8[[19..20]] = 2; next;)
   table=??(ls_out_acl_eval    ), priority=1001 , match=(reg0[[8]] == 1 && 
(1)), action=(reg8[[16]] = 1; reg0[[13]] = 1; reg3 = 4301; reg9 = 0; 
reg8[[0..7]] = 1; reg8[[8..15]] = 0; reg8[[19..20]] = 2; next;)
   table=??(ls_out_acl_sample  ), priority=0    , match=(1), action=(next;)
-  table=??(ls_out_acl_sample  ), priority=1000 , match=(ip && (ct.new || 
!ct.trk) && reg8[[0..7]] == 1 && reg8[[19..20]] == 2), 
action=(sample(probability=65535,collector_set=??,obs_domain=42,obs_point=reg3);
 next;)
+  table=??(ls_out_acl_sample  ), priority=1000 , match=(ip && (ct.new || 
!ct.trk) && reg8[[0..7]] == 1 && reg8[[19..20]] == 2), action=(reg0[[22]] = 1; 
sample(probability=65535,collector_set=??,obs_domain=42,obs_point=reg3); next;)
 ])
 
 dnl Trace new connections.
@@ -13682,21 +13682,21 @@ check ovn-nbctl --wait=sb sync
 
 AT_CHECK([ovn-sbctl lflow-list | grep probability | ovn_strip_lflows], [0], 
[dnl
   table=??(ls_in_acl_after_lb_sample), priority=1000 , match=(ip && ct.new && 
reg8[[0..7]] == 1 && reg8[[19..20]] == 1), dnl
-action=(sample(probability=10000,collector_set=100,obs_domain=42,obs_point=reg3);
 next;)
-  table=??(ls_in_acl_after_lb_sample), priority=1000 , match=(ip && ct.trk && 
(ct.est || ct.rel) && ct_label.obs_unused == 0 && !ct.rpl && 
ct_mark.obs_collector_id == 2 && ct_mark.obs_stage == 1), dnl
-action=(sample(probability=20000,collector_set=100,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
+action=(reg0[[22]] = 1; 
sample(probability=10000,collector_set=100,obs_domain=42,obs_point=reg3); next;)
+  table=??(ls_in_acl_after_lb_sample), priority=1000 , match=(reg0[[22]] == 0 
&& ip && ct.trk && (ct.est || ct.rel) && ct_label.obs_unused == 0 && !ct.rpl && 
ct_mark.obs_collector_id == 2 && ct_mark.obs_stage == 1), dnl
+action=(reg0[[22]] = 1; 
sample(probability=20000,collector_set=100,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
   table=??(ls_in_acl_sample   ), priority=1000 , match=(ip && ct.new && 
reg8[[0..7]] == 1 && reg8[[19..20]] == 0), dnl
-action=(sample(probability=10000,collector_set=100,obs_domain=42,obs_point=reg3);
 next;)
-  table=??(ls_in_acl_sample   ), priority=1000 , match=(ip && ct.trk && 
(ct.est || ct.rel) && ct_label.obs_unused == 0 && !ct.rpl && 
ct_mark.obs_collector_id == 2 && ct_mark.obs_stage == 0), dnl
-action=(sample(probability=20000,collector_set=100,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
-  table=??(ls_in_acl_sample   ), priority=1000 , match=(ip && ct.trk && 
(ct.est || ct.rel) && ct_label.obs_unused == 0 && ct.rpl && 
ct_mark.obs_collector_id == 2), dnl
-action=(sample(probability=20000,collector_set=100,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
+action=(reg0[[22]] = 1; 
sample(probability=10000,collector_set=100,obs_domain=42,obs_point=reg3); next;)
+  table=??(ls_in_acl_sample   ), priority=1000 , match=(reg0[[22]] == 0 && ip 
&& ct.trk && (ct.est || ct.rel) && ct_label.obs_unused == 0 && !ct.rpl && 
ct_mark.obs_collector_id == 2 && ct_mark.obs_stage == 0), dnl
+action=(reg0[[22]] = 1; 
sample(probability=20000,collector_set=100,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
+  table=??(ls_in_acl_sample   ), priority=1000 , match=(reg0[[22]] == 0 && ip 
&& ct.trk && (ct.est || ct.rel) && ct_label.obs_unused == 0 && ct.rpl && 
ct_mark.obs_collector_id == 2), dnl
+action=(reg0[[22]] = 1; 
sample(probability=20000,collector_set=100,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
   table=??(ls_out_acl_sample  ), priority=1000 , match=(ip && (ct.new || 
!ct.trk) && reg8[[0..7]] == 1 && reg8[[19..20]] == 2), dnl
-action=(sample(probability=10000,collector_set=100,obs_domain=42,obs_point=reg3);
 next;)
-  table=??(ls_out_acl_sample  ), priority=1000 , match=(ip && ct.trk && 
(ct.est || ct.rel) && ct_label.obs_unused == 0 && !ct.rpl && 
ct_mark.obs_collector_id == 2 && ct_mark.obs_stage == 2), dnl
-action=(sample(probability=20000,collector_set=100,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
-  table=??(ls_out_acl_sample  ), priority=1000 , match=(ip && ct.trk && 
(ct.est || ct.rel) && ct_label.obs_unused == 0 && ct.rpl && 
ct_mark.obs_collector_id == 2), dnl
-action=(sample(probability=20000,collector_set=100,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
+action=(reg0[[22]] = 1; 
sample(probability=10000,collector_set=100,obs_domain=42,obs_point=reg3); next;)
+  table=??(ls_out_acl_sample  ), priority=1000 , match=(reg0[[22]] == 0 && ip 
&& ct.trk && (ct.est || ct.rel) && ct_label.obs_unused == 0 && !ct.rpl && 
ct_mark.obs_collector_id == 2 && ct_mark.obs_stage == 2), dnl
+action=(reg0[[22]] = 1; 
sample(probability=20000,collector_set=100,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
+  table=??(ls_out_acl_sample  ), priority=1000 , match=(reg0[[22]] == 0 && ip 
&& ct.trk && (ct.est || ct.rel) && ct_label.obs_unused == 0 && ct.rpl && 
ct_mark.obs_collector_id == 2), dnl
+action=(reg0[[22]] = 1; 
sample(probability=20000,collector_set=100,obs_domain=43,obs_point=ct_label.obs_point_id);
 next;)
 ])
 
 AT_CLEANUP
diff --git a/tests/system-ovn.at b/tests/system-ovn.at
index 3a321f84a..3fed5bce0 100644
--- a/tests/system-ovn.at
+++ b/tests/system-ovn.at
@@ -13969,6 +13969,131 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port 
patch-.*/d
 AT_CLEANUP
 ])
 
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([ovn -- ACL Sampling - Stateful ACL - routed traffic])
+AT_KEYWORDS([ACL])
+
+CHECK_CONNTRACK()
+CHECK_CONNTRACK_NAT()
+ovn_start
+OVS_TRAFFIC_VSWITCHD_START()
+ADD_BR([br-int])
+
+dnl Set external-ids in br-int needed for ovn-controller
+check 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
+
+dnl Start ovn-controller
+start_daemon ovn-controller
+
+dnl Logical network:
+dnl 1 router
+dnl 2 logical switch
+dnl 2 VIF
+
+check ovn-nbctl                                      \
+  -- lr-add lr                                       \
+  -- lrp-add lr lrp1 00:00:00:00:01:00 42.42.42.1/24 \
+  -- lrp-add lr lrp2 00:00:00:00:02:00 43.43.43.1/24 \
+  -- ls-add ls1                                      \
+  -- ls-add ls2                                      \
+  -- lsp-add ls1 vm1                                 \
+  -- lsp-add ls2 vm2                                 \
+  -- lsp-set-addresses vm1 00:00:00:00:00:01         \
+  -- lsp-set-addresses vm2 00:00:00:00:00:02         \
+  -- lsp-add ls1 ls1-lr                              \
+  -- lsp-add ls2 ls2-lr                              \
+  -- lsp-set-type ls1-lr router                      \
+  -- lsp-set-type ls2-lr router                      \
+  -- lsp-set-options ls1-lr router-port=lrp1         \
+  -- lsp-set-options ls2-lr router-port=lrp2         \
+  -- lsp-set-addresses ls1-lr router                 \
+  -- lsp-set-addresses ls2-lr router
+check ovn-nbctl --wait=hv sync
+
+ADD_NAMESPACES(vm1)
+ADD_VETH(vm1, vm1, br-int, "42.42.42.2/24", "00:00:00:00:00:01", "42.42.42.1")
+ADD_NAMESPACES(vm2)
+ADD_VETH(vm2, vm2, br-int, "43.43.43.2/24", "00:00:00:00:00:02", "43.43.43.1")
+
+wait_for_ports_up
+
+NS_CHECK_EXEC([vm1], [ping -q -c 3 -i 0.3 -w 2 43.43.43.2 | FORMAT_PING], \
+[0], [dnl
+3 packets transmitted, 3 received, 0% packet loss, time 0ms
+])
+
+collector1=$(ovn-nbctl create Sample_Collector id=1 name=c1 probability=65535 
set_id=100)
+collector2=$(ovn-nbctl create Sample_Collector id=2 name=c2 probability=65535 
set_id=200)
+check_row_count nb:Sample_Collector 2
+
+check_uuid ovn-nbctl create Sampling_App type="acl-est" id="43"
+check_row_count nb:Sampling_App 1
+
+check ovn-nbctl pg-add pg vm1 vm2
+check_uuid ovn-nbctl                                                           
              \
+    -- --id=@sample1 create Sample collector="$collector1" metadata=1001       
              \
+    -- --sample-est=@sample1 acl-add pg from-lport 200 "inport == @pg && udp" 
allow-related  \
+    -- --id=@sample2 create Sample collector="$collector2" metadata=1004       
              \
+    -- --sample-est=@sample2 acl-add pg to-lport 200 "outport == @pg && udp" 
allow-related
+check ovn-nbctl --wait=hv sync
+check_row_count nb:ACL 2
+check_row_count nb:Sample 2
+
+NETNS_DAEMONIZE([vm1], [nc -l -u 1234], [udp1.pid])
+NETNS_DAEMONIZE([vm2], [nc -l -u 1235], [udp2.pid])
+
+dnl Start an IPFIX collector.
+DAEMONIZE([nfcapd -B 1024000 -w . -p 4242 2> collector.err], [collector.pid])
+dnl Wait for the collector to be up.
+OVS_WAIT_UNTIL([grep -q 'Startup nfcapd.' collector.err])
+
+dnl Configure the OVS flow sample collector.
+ovs-vsctl --id=@br get Bridge br-int \
+    -- --id=@ipfix1 create IPFIX targets=\"127.0.0.1:4242\" 
template_interval=1   \
+    -- --id=@cs1 create Flow_Sample_Collector_Set id=100 bridge=@br 
ipfix=@ipfix1 \
+    -- --id=@ipfix2 create IPFIX targets=\"127.0.0.1:4242\" 
template_interval=1   \
+    -- --id=@cs2 create Flow_Sample_Collector_Set id=200 bridge=@br 
ipfix=@ipfix2
+
+check ovn-nbctl --wait=hv sync
+dnl And wait for it to be up and running.
+OVS_WAIT_UNTIL([ovs-ofctl dump-ipfix-flow br-int | grep -q '2 ids'])
+
+# Create the connection in the CT table.
+echo "Hello" > Hello
+NS_EXEC([vm1], [nc -p 1234 -u 43.43.43.2 1235 < Hello])
+NS_EXEC([vm2], [nc -p 1235 -u 42.42.42.2 1234 < Hello])
+# Send some more packets.
+for i in $(seq 10); do
+NS_EXEC([vm1], [nc -p 1234 -u 43.43.43.2 1235 < Hello])
+NS_EXEC([vm2], [nc -p 1235 -u 42.42.42.2 1234 < Hello])
+done
+
+OVS_WAIT_UNTIL([ovs-ofctl dump-ipfix-flow br-int | grep 'id 100' | grep -q 
'sampled pkts=21'])
+OVS_WAIT_UNTIL([ovs-ofctl dump-ipfix-flow br-int | grep 'id 200' | grep -q 
'sampled pkts=21'])
+
+OVN_CLEANUP_CONTROLLER([hv1])
+
+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
+])
+
 OVN_FOR_EACH_NORTHD([
 AT_SETUP([SB Disconnect - MAC_Binding])
 ovn_start
-- 
2.51.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to