On 12/10/24 9:38 AM, Ales Musil wrote:
> On Fri, Dec 6, 2024 at 8:17 PM Mark Michelson <[email protected]> wrote:
> 
>> When ACL tiers were introduced, the code kept track of the highest ACL
>> tier so that when iterating through ACL tiers, we would not attempt to
>> advance the current tier past the highest configured tier.
>>
>> Unfortunately, keeping track of a single max ACL tier doesn't work when
>> ACLs are evaluated in three separate places. ACLs can be evaluated on
>> ingress before load balancing, on ingress after load balancing, and on
>> egress. By only keeping track of a single max ACL tier, it means that we
>> could perform superfluous checks if one stage of ACLs has a higher max
>> tier than other stages. As an example, if ingress pre-load balancing
>> ACLs have a maximum tier of 1, and egress ACLs have a maximum tier of 2,
>> then it means that for all stages of ACLs, we will evaluate tiers 0, 1,
>> and 2 of ACLs, even though only one stage of ACLs uses tier 2.
>>
>> From a pure functionality standpoint, this doesn't cause any issues.
>> Even if we advance the tier past the highest configured value, it
>> results in a no-op and the same net result happens.
>>
>> However, the addition of sampling into ACLs has caused an unwanted side
>> effect. In the example scenario above, let's say the tier 1 ACL in the
>> ingress pre-load balancing stage evaluates to "pass". After the
>> evaluation, we send a sample for the "pass" result. We then advance
>> the tier to 2, then move back to ACL evaluation. There are no tier 2
>> ACLs, so we move on to the sampling stage again. We then send a second
>> sample for the previous "pass" result from tier 1. The result is
>> confusing since we've sent two samples for the same ACL evaluation.
>>
>> To remedy this, we now track the max ACL tier in each of the stages
>> where ACLs are evaluated. Now there are no superfluous ACL evaluations
>> and no superfluous samples sent either.
>>
>> Reported-at: https://issues.redhat.com/browse/FDP-760
>> Signed-off-by: Mark Michelson <[email protected]>
>> ---
>> v2 -> v3:
>>  * Instead of adding to an additional system test, this patch now
>>    creates a new system test for ensuring the mismatched tiers do
>>    not result in extra samples being sent. This makes the test pass
>>    consistently.
>>
>> v1 -> v2:
>>  * Add a comment to the memcmp() call to caution in case the
>>    acl_tier struct is altered and has padding added.
>>  * Switch to using MAX macro when assigning max ACL tiers.
>>  * Add a system test to ensure the referenced issue is fixed. For the
>>    record, this test fails on the main branch, but passes with this
>>    patch.
>> ---
>>  northd/en-ls-stateful.c |  54 ++++++++++++++---
>>  northd/en-ls-stateful.h |   8 ++-
>>  northd/northd.c         |  47 +++++++++++----
>>  tests/ovn-northd.at     |  34 +++++++++++
>>  tests/system-ovn.at     | 124 ++++++++++++++++++++++++++++++++++++++++
>>  5 files changed, 247 insertions(+), 20 deletions(-)
>>
>> diff --git a/northd/en-ls-stateful.c b/northd/en-ls-stateful.c
>> index 44f74ea08..11e97aa9b 100644
>> --- a/northd/en-ls-stateful.c
>> +++ b/northd/en-ls-stateful.c
>> @@ -204,16 +204,22 @@ ls_stateful_port_group_handler(struct engine_node
>> *node, void *data_)
>>              ovn_datapaths_find_by_index(input_data.ls_datapaths,
>>                                          ls_stateful_rec->ls_index);
>>          bool had_stateful_acl = ls_stateful_rec->has_stateful_acl;
>> -        uint64_t max_acl_tier = ls_stateful_rec->max_acl_tier;
>> +        struct acl_tier old_max = ls_stateful_rec->max_acl_tier;
>>          bool had_acls = ls_stateful_rec->has_acls;
>>          bool modified = false;
>>
>>          ls_stateful_record_reinit(ls_stateful_rec, od, ls_pg,
>>                                    input_data.ls_port_groups);
>>
>> +        struct acl_tier new_max = ls_stateful_rec->max_acl_tier;
>> +
>> +        /* Using memcmp for struct acl_tier is fine since there is no
>> padding
>> +         * in the struct. However, if the structure is changed, the memcmp
>> +         * may need to be updated to compare individual struct fields.
>> +         */
>>          if ((had_stateful_acl != ls_stateful_rec->has_stateful_acl)
>>              || (had_acls != ls_stateful_rec->has_acls)
>> -            || max_acl_tier != ls_stateful_rec->max_acl_tier) {
>> +            || memcmp(&old_max, &new_max, sizeof(old_max))) {
>>              modified = true;
>>          }
>>
>> @@ -365,7 +371,8 @@ ls_stateful_record_set_acl_flags(struct
>> ls_stateful_record *ls_stateful_rec,
>>                                   const struct ls_port_group_table *ls_pgs)
>>  {
>>      ls_stateful_rec->has_stateful_acl = false;
>> -    ls_stateful_rec->max_acl_tier = 0;
>> +    memset(&ls_stateful_rec->max_acl_tier, 0,
>> +           sizeof ls_stateful_rec->max_acl_tier);
>>      ls_stateful_rec->has_acls = false;
>>
>>      if (ls_stateful_record_set_acl_flags_(ls_stateful_rec, od->nbs->acls,
>> @@ -391,6 +398,38 @@ ls_stateful_record_set_acl_flags(struct
>> ls_stateful_record *ls_stateful_rec,
>>      }
>>  }
>>
>> +static void
>> +update_ls_max_acl_tier(struct ls_stateful_record *ls_stateful_rec,
>> +                       const struct nbrec_acl *acl)
>> +{
>> +    if (!acl->tier) {
>> +        return;
>> +    }
>> +
>> +    uint64_t *tier;
>> +
>> +    if (!strcmp(acl->direction, "from-lport")) {
>> +        if (smap_get_bool(&acl->options, "apply-after-lb", false)) {
>> +            tier = &ls_stateful_rec->max_acl_tier.ingress_post_lb;
>> +        } else {
>> +            tier = &ls_stateful_rec->max_acl_tier.ingress_pre_lb;
>> +        }
>> +    } else {
>> +        tier = &ls_stateful_rec->max_acl_tier.egress;
>> +    }
>> +
>> +    *tier = MAX(*tier, acl->tier);
>> +}
>> +
>> +static bool
>> +ls_acl_tiers_are_maxed_out(struct acl_tier *acl_tier,
>> +                           uint64_t max_allowed_acl_tier)
>> +{
>> +    return acl_tier->ingress_post_lb == max_allowed_acl_tier &&
>> +           acl_tier->ingress_pre_lb == max_allowed_acl_tier &&
>> +           acl_tier->egress == max_allowed_acl_tier;
>> +}
>> +
>>  static bool
>>  ls_stateful_record_set_acl_flags_(struct ls_stateful_record
>> *ls_stateful_rec,
>>                                    struct nbrec_acl **acls,
>> @@ -408,16 +447,15 @@ ls_stateful_record_set_acl_flags_(struct
>> ls_stateful_record *ls_stateful_rec,
>>      ls_stateful_rec->has_acls = true;
>>      for (size_t i = 0; i < n_acls; i++) {
>>          const struct nbrec_acl *acl = acls[i];
>> -        if (acl->tier > ls_stateful_rec->max_acl_tier) {
>> -            ls_stateful_rec->max_acl_tier = acl->tier;
>> -        }
>> +        update_ls_max_acl_tier(ls_stateful_rec, acl);
>>          if (!ls_stateful_rec->has_stateful_acl
>>                  && !strcmp(acl->action, "allow-related")) {
>>              ls_stateful_rec->has_stateful_acl = true;
>>          }
>>          if (ls_stateful_rec->has_stateful_acl &&
>> -            ls_stateful_rec->max_acl_tier ==
>> -                nbrec_acl_col_tier.type.value.integer.max) {
>> +            ls_acl_tiers_are_maxed_out(
>> +                &ls_stateful_rec->max_acl_tier,
>> +                nbrec_acl_col_tier.type.value.integer.max)) {
>>              return true;
>>          }
>>      }
>> diff --git a/northd/en-ls-stateful.h b/northd/en-ls-stateful.h
>> index eae4b08e2..18a7398a6 100644
>> --- a/northd/en-ls-stateful.h
>> +++ b/northd/en-ls-stateful.h
>> @@ -33,6 +33,12 @@
>>
>>  struct lflow_ref;
>>
>> +struct acl_tier {
>> +    uint64_t ingress_pre_lb;
>> +    uint64_t ingress_post_lb;
>> +    uint64_t egress;
>> +};
>> +
>>  struct ls_stateful_record {
>>      struct hmap_node key_node;
>>
>> @@ -46,7 +52,7 @@ struct ls_stateful_record {
>>      bool has_stateful_acl;
>>      bool has_lb_vip;
>>      bool has_acls;
>> -    uint64_t max_acl_tier;
>> +    struct acl_tier max_acl_tier;
>>
>>      /* 'lflow_ref' is used to reference logical flows generated for
>>       * this ls_stateful record.
>> diff --git a/northd/northd.c b/northd/northd.c
>> index 3a488ff3d..58ffeea92 100644
>> --- a/northd/northd.c
>> +++ b/northd/northd.c
>> @@ -7338,28 +7338,34 @@ build_acl_action_lflows(const struct
>> ls_stateful_record *ls_stateful_rec,
>>          S_SWITCH_OUT_ACL_EVAL,
>>      };
>>
>> +    uint64_t max_acl_tiers[] = {
>> +        ls_stateful_rec->max_acl_tier.ingress_pre_lb,
>> +        ls_stateful_rec->max_acl_tier.ingress_post_lb,
>> +        ls_stateful_rec->max_acl_tier.egress,
>> +    };
>> +
>>      ds_clear(actions);
>>      ds_put_cstr(actions, REGBIT_ACL_VERDICT_ALLOW " = 0; "
>>                          REGBIT_ACL_VERDICT_DROP " = 0; "
>>                          REGBIT_ACL_VERDICT_REJECT " = 0; ");
>> -    if (ls_stateful_rec->max_acl_tier) {
>> -        ds_put_cstr(actions, REG_ACL_TIER " = 0; ");
>> -    }
>>
>>      size_t verdict_len = actions->length;
>> -
>>      for (size_t i = 0; i < ARRAY_SIZE(stages); i++) {
>>          enum ovn_stage stage = stages[i];
>> +        if (max_acl_tiers[i]) {
>> +            ds_put_cstr(actions, REG_ACL_TIER " = 0; ");
>> +        }
>> +        size_t verdict_tier_len = actions->length;
>>          if (!ls_stateful_rec->has_acls) {
>>              ovn_lflow_add(lflows, od, stage, 0, "1", "next;", lflow_ref);
>>              continue;
>>          }
>> -        ds_truncate(actions, verdict_len);
>> +        ds_truncate(actions, verdict_tier_len);
>>          ds_put_cstr(actions, "next;");
>>          ovn_lflow_add(lflows, od, stage, 1000,
>>                        REGBIT_ACL_VERDICT_ALLOW " == 1", ds_cstr(actions),
>>                        lflow_ref);
>> -        ds_truncate(actions, verdict_len);
>> +        ds_truncate(actions, verdict_tier_len);
>>          ds_put_cstr(actions, debug_implicit_drop_action());
>>          ovn_lflow_add(lflows, od, stage, 1000,
>>                        REGBIT_ACL_VERDICT_DROP " == 1",
>> @@ -7367,7 +7373,7 @@ build_acl_action_lflows(const struct
>> ls_stateful_record *ls_stateful_rec,
>>                        lflow_ref);
>>          bool ingress = ovn_stage_get_pipeline(stage) == P_IN;
>>
>> -        ds_truncate(actions, verdict_len);
>> +        ds_truncate(actions, verdict_tier_len);
>>          build_acl_reject_action(actions, ingress);
>>
>>          ovn_lflow_metered(lflows, od, stage, 1000,
>> @@ -7375,12 +7381,12 @@ build_acl_action_lflows(const struct
>> ls_stateful_record *ls_stateful_rec,
>>                            copp_meter_get(COPP_REJECT, od->nbs->copp,
>>                            meter_groups), lflow_ref);
>>
>> -        ds_truncate(actions, verdict_len);
>> +        ds_truncate(actions, verdict_tier_len);
>>          ds_put_cstr(actions, default_acl_action);
>>          ovn_lflow_add(lflows, od, stage, 0, "1", ds_cstr(actions),
>> lflow_ref);
>>
>>          struct ds tier_actions = DS_EMPTY_INITIALIZER;
>> -        for (size_t j = 0; j < ls_stateful_rec->max_acl_tier; j++) {
>> +        for (size_t j = 0; j < max_acl_tiers[i]; j++) {
>>              ds_clear(match);
>>              ds_put_format(match, REG_ACL_TIER " == %"PRIuSIZE, j);
>>              ds_clear(&tier_actions);
>> @@ -7392,6 +7398,7 @@ build_acl_action_lflows(const struct
>> ls_stateful_record *ls_stateful_rec,
>>                           ds_cstr(&tier_actions), lflow_ref);
>>          }
>>          ds_destroy(&tier_actions);
>> +        ds_truncate(actions, verdict_len);
>>      }
>>  }
>>
>> @@ -7460,6 +7467,21 @@ build_acl_log_related_flows(const struct
>> ovn_datapath *od,
>>                              &acl->header_, lflow_ref);
>>  }
>>
>> +static uint64_t
>> +choose_max_acl_tier(const struct ls_stateful_record *ls_stateful_rec,
>> +                    const struct nbrec_acl *acl)
>> +{
>> +    if (!strcmp(acl->direction, "from-lport")) {
>> +        if (smap_get_bool(&acl->options, "apply-after-lb", false)) {
>> +            return ls_stateful_rec->max_acl_tier.ingress_post_lb;
>> +        } else {
>> +            return ls_stateful_rec->max_acl_tier.ingress_pre_lb;
>> +        }
>> +    } else {
>> +        return ls_stateful_rec->max_acl_tier.egress;
>> +    }
>> +}
>> +
>>  static void
>>  build_acls(const struct ls_stateful_record *ls_stateful_rec,
>>             const struct ovn_datapath *od,
>> @@ -7656,8 +7678,9 @@ build_acls(const struct ls_stateful_record
>> *ls_stateful_rec,
>>          build_acl_log_related_flows(od, lflows, acl, has_stateful,
>>                                      meter_groups, &match, &actions,
>>                                      lflow_ref);
>> +        uint64_t max_acl_tier = choose_max_acl_tier(ls_stateful_rec, acl);
>>          consider_acl(lflows, od, acl, has_stateful,
>> -                     meter_groups, ls_stateful_rec->max_acl_tier,
>> +                     meter_groups, max_acl_tier,
>>                       &match, &actions, lflow_ref);
>>          build_acl_sample_flows(ls_stateful_rec, od, lflows, acl,
>>                                 &match, &actions, sampling_apps,
>> @@ -7675,8 +7698,10 @@ build_acls(const struct ls_stateful_record
>> *ls_stateful_rec,
>>                  build_acl_log_related_flows(od, lflows, acl, has_stateful,
>>                                              meter_groups, &match,
>> &actions,
>>                                              lflow_ref);
>> +                uint64_t max_acl_tier =
>> choose_max_acl_tier(ls_stateful_rec,
>> +                                                            acl);
>>                  consider_acl(lflows, od, acl, has_stateful,
>> -                             meter_groups, ls_stateful_rec->max_acl_tier,
>> +                             meter_groups, max_acl_tier,
>>                               &match, &actions, lflow_ref);
>>                  build_acl_sample_flows(ls_stateful_rec, od, lflows, acl,
>>                                         &match, &actions, sampling_apps,
>> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
>> index 4eae1c67c..2013cc513 100644
>> --- a/tests/ovn-northd.at
>> +++ b/tests/ovn-northd.at
>> @@ -14253,3 +14253,37 @@ AT_CHECK([grep "lr_in_dnat" lr1flows |
>> ovn_strip_lflows | grep "30.0.0.1"], [0],
>>
>>  AT_CLEANUP
>>  ])
>> +
>> +OVN_FOR_EACH_NORTHD_NO_HV([
>> +AT_SETUP([ACL mismatched tiers])
>> +ovn_start
>> +
>> +check ovn-nbctl ls-add S1
>> +
>> +# Ingress pre-lb ACLs have only a tier 1 ACL configured.
>> +# Ingress post-lb ACLs have tier up to 3 configured.
>> +# Egress ACLs have up to tier 2 configured.
>> +check ovn-nbctl --tier=1 acl-add S1 from-lport 1001 "tcp" allow
>> +check ovn-nbctl --tier=3 --apply-after-lb acl-add  S1 from-lport 1001
>> "tcp" allow
>> +check ovn-nbctl --tier=2 acl-add S1 to-lport 1001 "tcp" allow
>> +
>> +# Ingress pre-lb ACLs should only ever increment the tier to 1.
>> +AT_CHECK([ovn-sbctl lflow-list S1 | grep ls_in_acl_action | grep
>> priority=500 | ovn_strip_lflows], [0], [dnl
>> +  table=??(ls_in_acl_action   ), priority=500  , match=(reg8[[30..31]] ==
>> 0), action=(reg8[[30..31]] = 1; next(pipeline=ingress,table=??);)
>> +])
>> +
>> +# Ingress post-lb ACLs should increment the tier to 3.
>> +AT_CHECK([ovn-sbctl lflow-list S1 | grep ls_in_acl_after_lb_action | grep
>> priority=500 | ovn_strip_lflows], [0], [dnl
>> +  table=??(ls_in_acl_after_lb_action), priority=500  ,
>> match=(reg8[[30..31]] == 0), action=(reg8[[30..31]] = 1;
>> next(pipeline=ingress,table=??);)
>> +  table=??(ls_in_acl_after_lb_action), priority=500  ,
>> match=(reg8[[30..31]] == 1), action=(reg8[[30..31]] = 2;
>> next(pipeline=ingress,table=??);)
>> +  table=??(ls_in_acl_after_lb_action), priority=500  ,
>> match=(reg8[[30..31]] == 2), action=(reg8[[30..31]] = 3;
>> next(pipeline=ingress,table=??);)
>> +])
>> +
>> +# Egress ACLs should increment the tier to 2.
>> +AT_CHECK([ovn-sbctl lflow-list S1 | grep ls_out_acl_action | grep
>> priority=500 | ovn_strip_lflows], [0], [dnl
>> +  table=??(ls_out_acl_action  ), priority=500  , match=(reg8[[30..31]] ==
>> 0), action=(reg8[[30..31]] = 1; next(pipeline=egress,table=??);)
>> +  table=??(ls_out_acl_action  ), priority=500  , match=(reg8[[30..31]] ==
>> 1), action=(reg8[[30..31]] = 2; next(pipeline=egress,table=??);)
>> +])
>> +
>> +AT_CLEANUP
>> +])
>> diff --git a/tests/system-ovn.at b/tests/system-ovn.at
>> index 4452d5676..e5b1fd43c 100644
>> --- a/tests/system-ovn.at
>> +++ b/tests/system-ovn.at
>> @@ -13430,6 +13430,130 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query
>> port patch-.*/d
>>  AT_CLEANUP
>>  ])
>>
>> +OVN_FOR_EACH_NORTHD([
>> +AT_SETUP([ovn -- Tiered ACL Sampling - tier mismatch])
>> +AT_SKIP_IF([test $HAVE_NFCAPD = no])
>> +AT_SKIP_IF([test $HAVE_NFDUMP = no])
>> +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 logical switch
>> +dnl 2 VIFs
>> +
>> +check ovn-nbctl                                                  \
>> +    -- ls-add ls                                                 \
>> +    -- lsp-add ls vm1 -- lsp-set-addresses vm1 00:00:00:00:00:01 \
>> +    -- lsp-add ls vm2 -- lsp-set-addresses vm2 00:00:00:00:00:02
>> +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, "42.42.42.3/24", "00:00:00:00:00:02",
>> "42.42.42.1")
>> +
>> +collector1=$(ovn-nbctl create Sample_Collector id=1 name=c1
>> probability=65535 set_id=100)
>> +check_row_count nb:Sample_Collector 1
>> +
>> +ovn-nbctl create Sampling_App type="acl-new" id="42"
>> +ovn-nbctl create Sampling_App type="acl-est" id="43"
>> +check_row_count nb:Sampling_App 2
>> +
>> +dnl Create two tiers of ACLs.
>> +dnl The first ACL is an ingress "pass" ACL at tier 0.
>> +ovn-nbctl
>>      \
>> +    -- --id=@sample_1_new create Sample collector="$collector1"
>> metadata=1001 \
>> +    -- --id=@sample_1_est create Sample collector="$collector1"
>> metadata=1002 \
>> +    -- --tier=0 --sample-new=@sample_1_new --sample-est=@sample_1_est
>>      \
>> +       acl-add ls from-lport 1 "inport == \"vm1\" && udp.dst == 1000"
>>      \
>> +       pass
>> +
>> +dnl The second ACL is an unrelated egress ACL. However, it uses tier 1
>> instead
>> +dnl of tier 0.
>> +ovn-nbctl --tier=1 acl-add ls to-lport 1 "inport == \"vm1\" && udp.dst ==
>> 1000" allow-related
>> +
>> +check_row_count nb:ACL 2
>> +check_row_count nb:Sample 2
>> +
>> +dnl Wait for ovn-controller to catch up.
>> +wait_for_ports_up
>> +check ovn-nbctl --wait=hv sync
>> +
>> +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=@ipfix create IPFIX targets=\"127.0.0.1:4242\"
>> template_interval=1 \
>> +    -- --id=@cs create Flow_Sample_Collector_Set id=100 bridge=@br
>> ipfix=@ipfix
>> +
>> +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 '1 ids'])
>> +
>> +dnl Start UDP echo server on vm2.
>> +NETNS_DAEMONIZE([vm2], [nc -e /bin/cat -k -u -v -l -m 1 1000],
>> [nc-vm2-1000.pid])
>> +
>> +dnl Send traffic to the UDP server (hits both ACL tiers).
>> +NS_CHECK_EXEC([vm1], [echo a | nc --send-only -u 42.42.42.3 1000])
>> +
>> +dnl Wait until OVS sampled all expected packets:
>> +dnl In this case, we only expect a single sampled packet.
>> +dnl The pass ACL should sample its "pass" result. The egress
>> +dnl ACL should not get hit (and it doesn't have sampling configured
>> +dnl anyway). A bug that previously existed in OVN would result in
>> +dnl the "pass" being sampled two times instead of just once.
>> +OVS_WAIT_UNTIL([ovs-ofctl dump-ipfix-flow br-int | grep -q 'sampled
>> pkts=1'])
>> +
>> +dnl Check the IPFIX samples.
>> +kill $(cat collector.pid)
>> +OVS_WAIT_WHILE([kill -0 $(cat collector.pid) 2>/dev/null])
>> +
>> +dnl Can't match on observation domain ID due to the followig fix not being
>> +dnl available in any released version of nfdump:
>> +dnl https://github.com/phaag/nfdump/issues/544
>> +dnl
>> +dnl Only match on the point ID.
>> +AT_CHECK([for f in $(ls -1 nfcapd.*); do nfdump -o json -r $f; done |
>> grep observationPointID | awk '{$1=$1;print}' | sort], [0], [dnl
>> +"observationPointID" : 1001,
>> +])
>> +
>> +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
>> +])
>> +
>>  OVN_FOR_EACH_NORTHD([
>>  AT_SETUP([ovn -- ACL Sampling - Stateful ACL - to-lport router port])
>>  AT_SKIP_IF([test $HAVE_NFCAPD = no])
>> --
>> 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]>

Thanks, Mark and Ales!  Applied to main and 24.09.

Regards,
Dumitru

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

Reply via email to