On 8/17/23 12:43, Ales Musil wrote:
> On Wed, Aug 16, 2023 at 10:42 PM Dumitru Ceara <dce...@redhat.com> wrote:
> 
>> This is beneficial in a few ways:
>> - first, it reduces the number of different types of data the northd
>>   I-P node has to process.
>> - it turns out the northd I-P node (whose recompute is rather costly)
>>   doesn't really depend on meters or ACLs.
>> - prepares the ground for a pure I-P implementation for ACLs, with a
>>   simple/clear dependency between NB.ACL and the lflow I-P node.
>>
>> From a meters synchronization perspective this commit doesn't change any
>> of the existing behavior and logic.  It mostly just moves the meters
>> related code out of northd.c and into en-meters.c.
>>
>> Signed-off-by: Dumitru Ceara <dce...@redhat.com>
>>
> ---
>>
> 
> Hi Dumitru,
> 

Hi Ales,

> I have a couple of suggestions.
> 

Thanks for your review!

> 
>>  lib/stopwatch-names.h    |   1 +
>>  northd/automake.mk       |   2 +
>>  northd/en-lflow.c        |   5 +-
>>  northd/en-meters.c       | 295 +++++++++++++++++++++++++++++++++++++++
>>  northd/en-meters.h       |  44 ++++++
>>  northd/en-northd.c       |   6 -
>>  northd/inc-proc-northd.c |  14 +-
>>  northd/northd.c          | 249 ++-------------------------------
>>  northd/northd.h          |   4 -
>>  northd/ovn-northd.c      |   3 +
>>  tests/ovn-northd.at      |  36 +++++
>>  11 files changed, 404 insertions(+), 255 deletions(-)
>>  create mode 100644 northd/en-meters.c
>>  create mode 100644 northd/en-meters.h
>>
>> diff --git a/lib/stopwatch-names.h b/lib/stopwatch-names.h
>> index de6fca4ccc..98535fff5a 100644
>> --- a/lib/stopwatch-names.h
>> +++ b/lib/stopwatch-names.h
>> @@ -30,5 +30,6 @@
>>  #define LFLOWS_IGMP_STOPWATCH_NAME "lflows_igmp"
>>  #define LFLOWS_DP_GROUPS_STOPWATCH_NAME "lflows_dp_groups"
>>  #define LFLOWS_TO_SB_STOPWATCH_NAME "lflows_to_sb"
>> +#define SYNC_METERS_RUN_STOPWATCH_NAME "sync_meters_run"
>>
>>  #endif
>> diff --git a/northd/automake.mk b/northd/automake.mk
>> index b17f1fdb54..f52766de0c 100644
>> --- a/northd/automake.mk
>> +++ b/northd/automake.mk
>> @@ -12,6 +12,8 @@ northd_ovn_northd_SOURCES = \
>>         northd/en-northd.h \
>>         northd/en-lflow.c \
>>         northd/en-lflow.h \
>> +       northd/en-meters.c \
>> +       northd/en-meters.h \
>>         northd/en-northd-output.c \
>>         northd/en-northd-output.h \
>>         northd/en-sync-sb.c \
>> diff --git a/northd/en-lflow.c b/northd/en-lflow.c
>> index 28ab1c67fb..0886d4c5ca 100644
>> --- a/northd/en-lflow.c
>> +++ b/northd/en-lflow.c
>> @@ -20,6 +20,7 @@
>>
>>  #include "en-lflow.h"
>>  #include "en-northd.h"
>> +#include "en-meters.h"
>>
>>  #include "lib/inc-proc-eng.h"
>>  #include "northd.h"
>> @@ -35,6 +36,8 @@ lflow_get_input_data(struct engine_node *node,
>>                       struct lflow_input *lflow_input)
>>  {
>>      struct northd_data *northd_data = engine_get_input_data("northd",
>> node);
>> +    struct sync_meters_data *sync_meters_data =
>> +        engine_get_input_data("sync_meters", node);
>>      lflow_input->nbrec_bfd_table =
>>          EN_OVSDB_GET(engine_get_input("NB_bfd", node));
>>      lflow_input->sbrec_bfd_table =
>> @@ -56,7 +59,7 @@ lflow_get_input_data(struct engine_node *node,
>>      lflow_input->ls_ports = &northd_data->ls_ports;
>>      lflow_input->lr_ports = &northd_data->lr_ports;
>>      lflow_input->port_groups = &northd_data->port_groups;
>> -    lflow_input->meter_groups = &northd_data->meter_groups;
>> +    lflow_input->meter_groups = &sync_meters_data->meter_groups;
>>      lflow_input->lbs = &northd_data->lbs;
>>      lflow_input->features = &northd_data->features;
>>      lflow_input->ovn_internal_version_changed =
>> diff --git a/northd/en-meters.c b/northd/en-meters.c
>> new file mode 100644
>> index 0000000000..3d3b22368f
>> --- /dev/null
>> +++ b/northd/en-meters.c
>> @@ -0,0 +1,295 @@
>> +/*
>> + * Copyright (c) 2023, Red Hat, Inc.
>> + *
>> + * Licensed under the Apache License, Version 2.0 (the "License");
>> + * you may not use this file except in compliance with the License.
>> + * You may obtain a copy of the License at:
>> + *
>> + *     http://www.apache.org/licenses/LICENSE-2.0
>> + *
>> + * Unless required by applicable law or agreed to in writing, software
>> + * distributed under the License is distributed on an "AS IS" BASIS,
>> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
>> implied.
>> + * See the License for the specific language governing permissions and
>> + * limitations under the License.
>> + */
>> +
>> +#include <config.h>
>> +
>> +#include "openvswitch/vlog.h"
>> +#include "stopwatch.h"
>> +
>> +#include "en-meters.h"
>> +#include "lib/stopwatch-names.h"
>> +
>> +VLOG_DEFINE_THIS_MODULE(en_meters);
>> +
>> +static void build_meter_groups(struct shash *meter_group,
>> +                               const struct nbrec_meter_table *);
>> +static void sync_meters(struct ovsdb_idl_txn *ovnsb_txn,
>> +                        const struct nbrec_meter_table *,
>> +                        const struct nbrec_acl_table *,
>> +                        const struct sbrec_meter_table *,
>> +                        struct shash *meter_groups);
>> +
>> +void
>> +*en_sync_meters_init(struct engine_node *node OVS_UNUSED,
>> +                     struct engine_arg *arg OVS_UNUSED)
>> +{
>> +    struct sync_meters_data *data = xmalloc(sizeof *data);
>> +
>> +    *data = (struct sync_meters_data) {
>> +        .meter_groups = SHASH_INITIALIZER(&data->meter_groups),
>> +    };
>> +    return data;
>> +}
>> +
>> +void
>> +en_sync_meters_cleanup(void *data_)
>> +{
>> +    struct sync_meters_data *data = data_;
>> +
>> +    shash_destroy(&data->meter_groups);
>> +}
>> +
>> +void
>> +en_sync_meters_run(struct engine_node *node, void *data_)
>> +{
>> +    struct sync_meters_data *data = data_;
>> +
>> +    const struct nbrec_acl_table *acl_table =
>> +        EN_OVSDB_GET(engine_get_input("NB_acl", node));
>> +
>> +    const struct nbrec_meter_table *nb_meter_table =
>> +        EN_OVSDB_GET(engine_get_input("NB_meter", node));
>> +
>> +    const struct sbrec_meter_table *sb_meter_table =
>> +        EN_OVSDB_GET(engine_get_input("SB_meter", node));
>> +
>> +    const struct engine_context *eng_ctx = engine_get_context();
>> +
>> +    stopwatch_start(SYNC_METERS_RUN_STOPWATCH_NAME, time_msec());
>> +
>> +    build_meter_groups(&data->meter_groups, nb_meter_table);
>> +
>> +    sync_meters(eng_ctx->ovnsb_idl_txn, nb_meter_table, acl_table,
>> +                sb_meter_table, &data->meter_groups);
>> +
>> +    stopwatch_stop(SYNC_METERS_RUN_STOPWATCH_NAME, time_msec());
>> +    engine_set_node_state(node, EN_UPDATED);
>> +}
>> +
>> +const struct nbrec_meter*
>> +fair_meter_lookup_by_name(const struct shash *meter_groups,
>> +                          const char *meter_name)
>> +{
>> +    const struct nbrec_meter *nb_meter =
>> +        meter_name ? shash_find_data(meter_groups, meter_name) : NULL;
>> +    if (nb_meter) {
>> +        return (nb_meter->fair && *nb_meter->fair) ? nb_meter : NULL;
>> +    }
>> +    return NULL;
>> +}
>> +
>> +struct band_entry {
>> +    int64_t rate;
>> +    int64_t burst_size;
>> +    const char *action;
>> +};
>> +
>> +static int
>> +band_cmp(const void *band1_, const void *band2_)
>> +{
>> +    const struct band_entry *band1p = band1_;
>> +    const struct band_entry *band2p = band2_;
>> +
>> +    if (band1p->rate != band2p->rate) {
>> +        return band1p->rate > band2p->rate ? -1 : 1;
>>
> 
> We could spare the extra comparison by doing "return band1p->rate >
> band2p->rate" instead.
> 

We clarified this offline; it's actually supposed to be:

return band1p->rate - band2p->rate;

I changed it accordingly.

> 
>> +    } else if (band1p->burst_size != band2p->burst_size) {
>> +        return band1p->burst_size > band2p->burst_size ? -1 : 1;
>>
> 
> Same here.
> 

Here too.

> 
>> +    } else {
>> +        return strcmp(band1p->action, band2p->action);
>> +    }
>> +}
>> +
>> +static bool
>> +bands_need_update(const struct nbrec_meter *nb_meter,
>> +                  const struct sbrec_meter *sb_meter)
>> +{
>> +    if (nb_meter->n_bands != sb_meter->n_bands) {
>> +        return true;
>> +    }
>> +
>> +    /* A single band is the most common scenario, so speed up that
>> +     * check. */
>> +    if (nb_meter->n_bands == 1) {
>> +        struct nbrec_meter_band *nb_band = nb_meter->bands[0];
>> +        struct sbrec_meter_band *sb_band = sb_meter->bands[0];
>> +
>> +        return !(nb_band->rate == sb_band->rate
>> +                 && nb_band->burst_size == sb_band->burst_size
>> +                 && !strcmp(sb_band->action, nb_band->action));
>>
> 
> I know that it's effectively the same, but actually more readable to use
> "return !band_cmp".
> 

There's a catch.  band_cmp() expects struct band_entry as arguments.
However, I disagree with the micro-optimization done in this "if" so I
just removed it all together in v2.

> 
>> +    }
>> +
>> +    /* Place the Northbound entries in sorted order. */
>> +    struct band_entry *nb_bands;
>> +    nb_bands = xmalloc(sizeof *nb_bands * nb_meter->n_bands);
>> +    for (size_t i = 0; i < nb_meter->n_bands; i++) {
>> +        struct nbrec_meter_band *nb_band = nb_meter->bands[i];
>> +
>> +        nb_bands[i].rate = nb_band->rate;
>> +        nb_bands[i].burst_size = nb_band->burst_size;
>> +        nb_bands[i].action = nb_band->action;
>> +    }
>> +    qsort(nb_bands, nb_meter->n_bands, sizeof *nb_bands, band_cmp);
>> +
>> +    /* Place the Southbound entries in sorted order. */
>> +    struct band_entry *sb_bands;
>> +    sb_bands = xmalloc(sizeof *sb_bands * sb_meter->n_bands);
>> +    for (size_t i = 0; i < sb_meter->n_bands; i++) {
>> +        struct sbrec_meter_band *sb_band = sb_meter->bands[i];
>> +
>> +        sb_bands[i].rate = sb_band->rate;
>> +        sb_bands[i].burst_size = sb_band->burst_size;
>> +        sb_bands[i].action = sb_band->action;
>> +    }
>> +    qsort(sb_bands, sb_meter->n_bands, sizeof *sb_bands, band_cmp);
>> +
>> +    bool need_update = false;
>> +    for (size_t i = 0; i < nb_meter->n_bands; i++) {
>> +        if (nb_bands[i].rate != sb_bands[i].rate
>> +            || nb_bands[i].burst_size != sb_bands[i].burst_size
>> +            || strcmp(nb_bands[i].action, sb_bands[i].action)) {
>>
> 
> Same here we could just use the band_cmp.
> 

Done.

> 
>> +            need_update = true;
>> +            goto done;
>>
> 
> Done label is not needed.
> 

True, I added a break here.

> 
>> +        }
>> +    }
>> +
>> +done:
>> +    free(nb_bands);
>> +    free(sb_bands);
>> +
>> +    return need_update;
>> +}
>> +
>> +static void
>> +sync_meters_iterate_nb_meter(struct ovsdb_idl_txn *ovnsb_txn,
>> +                             const char *meter_name,
>> +                             const struct nbrec_meter *nb_meter,
>> +                             struct shash *sb_meters,
>> +                             struct sset *used_sb_meters)
>> +{
>> +    const struct sbrec_meter *sb_meter;
>> +    bool new_sb_meter = false;
>> +
>> +    sb_meter = shash_find_data(sb_meters, meter_name);
>> +    if (!sb_meter) {
>> +        sb_meter = sbrec_meter_insert(ovnsb_txn);
>> +        sbrec_meter_set_name(sb_meter, meter_name);
>> +        shash_add(sb_meters, sb_meter->name, sb_meter);
>> +        new_sb_meter = true;
>> +    }
>> +    sset_add(used_sb_meters, meter_name);
>> +
>> +    if (new_sb_meter || bands_need_update(nb_meter, sb_meter)) {
>> +        struct sbrec_meter_band **sb_bands;
>> +        sb_bands = xcalloc(nb_meter->n_bands, sizeof *sb_bands);
>> +        for (size_t i = 0; i < nb_meter->n_bands; i++) {
>> +            const struct nbrec_meter_band *nb_band = nb_meter->bands[i];
>> +
>> +            sb_bands[i] = sbrec_meter_band_insert(ovnsb_txn);
>> +
>> +            sbrec_meter_band_set_action(sb_bands[i], nb_band->action);
>> +            sbrec_meter_band_set_rate(sb_bands[i], nb_band->rate);
>> +            sbrec_meter_band_set_burst_size(sb_bands[i],
>> +                                            nb_band->burst_size);
>> +        }
>> +        sbrec_meter_set_bands(sb_meter, sb_bands, nb_meter->n_bands);
>> +        free(sb_bands);
>> +    }
>> +
>> +    sbrec_meter_set_unit(sb_meter, nb_meter->unit);
>> +}
>> +
>> +static void
>> +sync_acl_fair_meter(struct ovsdb_idl_txn *ovnsb_txn,
>> +                    struct shash *meter_groups,
>> +                    const struct nbrec_acl *acl, struct shash *sb_meters,
>> +                    struct sset *used_sb_meters)
>> +{
>> +    const struct nbrec_meter *nb_meter =
>> +        fair_meter_lookup_by_name(meter_groups, acl->meter);
>> +
>> +    if (!nb_meter) {
>> +        return;
>> +    }
>> +
>> +    char *meter_name = alloc_acl_log_unique_meter_name(acl);
>> +    sync_meters_iterate_nb_meter(ovnsb_txn, meter_name, nb_meter,
>> sb_meters,
>> +                                 used_sb_meters);
>> +    free(meter_name);
>> +}
>> +
>> +static void
>> +build_meter_groups(struct shash *meter_groups,
>> +                   const struct nbrec_meter_table *nb_meter_table)
>> +{
>> +    const struct nbrec_meter *nb_meter;
>> +
>> +    shash_clear(meter_groups);
>> +    NBREC_METER_TABLE_FOR_EACH (nb_meter, nb_meter_table) {
>> +        shash_add(meter_groups, nb_meter->name, nb_meter);
>> +    }
>> +}
>> +
>> +/* Each entry in the Meter and Meter_Band tables in OVN_Northbound have
>> + * a corresponding entries in the Meter and Meter_Band tables in
>> + * OVN_Southbound. Additionally, ACL logs that use fair meters have
>> + * a private copy of its meter in the SB table.
>> + */
>> +static void
>> +sync_meters(struct ovsdb_idl_txn *ovnsb_txn,
>> +            const struct nbrec_meter_table *nbrec_meter_table,
>> +            const struct nbrec_acl_table *nbrec_acl_table,
>> +            const struct sbrec_meter_table *sbrec_meter_table,
>> +            struct shash *meter_groups)
>> +{
>> +    struct shash sb_meters = SHASH_INITIALIZER(&sb_meters);
>> +    struct sset used_sb_meters = SSET_INITIALIZER(&used_sb_meters);
>> +
>> +    const struct sbrec_meter *sb_meter;
>> +    SBREC_METER_TABLE_FOR_EACH (sb_meter, sbrec_meter_table) {
>> +        shash_add(&sb_meters, sb_meter->name, sb_meter);
>> +    }
>> +
>> +    const struct nbrec_meter *nb_meter;
>> +    NBREC_METER_TABLE_FOR_EACH (nb_meter, nbrec_meter_table) {
>> +        sync_meters_iterate_nb_meter(ovnsb_txn, nb_meter->name, nb_meter,
>> +                                     &sb_meters, &used_sb_meters);
>> +    }
>> +
>> +    /*
>> +     * In addition to creating Meters in the SB from the block above,
>> check
>> +     * and see if additional rows are needed to get ACLs logs individually
>> +     * rate-limited.
>> +     */
>> +    const struct nbrec_acl *acl;
>> +    NBREC_ACL_TABLE_FOR_EACH (acl, nbrec_acl_table) {
>> +        sync_acl_fair_meter(ovnsb_txn, meter_groups, acl,
>> +                            &sb_meters, &used_sb_meters);
>> +    }
>> +
>> +    const char *used_meter;
>> +    SSET_FOR_EACH_SAFE (used_meter, &used_sb_meters) {
>> +        shash_find_and_delete(&sb_meters, used_meter);
>> +        sset_delete(&used_sb_meters, SSET_NODE_FROM_NAME(used_meter));
>> +    }
>> +    sset_destroy(&used_sb_meters);
>> +
>> +    struct shash_node *node;
>> +    SHASH_FOR_EACH_SAFE (node, &sb_meters) {
>> +        sbrec_meter_delete(node->data);
>> +        shash_delete(&sb_meters, node);
>> +    }
>> +    shash_destroy(&sb_meters);
>> +}
>> diff --git a/northd/en-meters.h b/northd/en-meters.h
>> new file mode 100644
>> index 0000000000..a1743282e3
>> --- /dev/null
>> +++ b/northd/en-meters.h
>> @@ -0,0 +1,44 @@
>> +/*
>> + * Copyright (c) 2023, Red Hat, Inc.
>> + *
>> + * Licensed under the Apache License, Version 2.0 (the "License");
>> + * you may not use this file except in compliance with the License.
>> + * You may obtain a copy of the License at:
>> + *
>> + *     http://www.apache.org/licenses/LICENSE-2.0
>> + *
>> + * Unless required by applicable law or agreed to in writing, software
>> + * distributed under the License is distributed on an "AS IS" BASIS,
>> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
>> implied.
>> + * See the License for the specific language governing permissions and
>> + * limitations under the License.
>> + */
>> +#ifndef EN_METERS_H
>> +#define EN_METERS_H 1
>> +
>> +#include "openvswitch/shash.h"
>> +
>> +#include "lib/inc-proc-eng.h"
>> +#include "lib/ovn-nb-idl.h"
>> +#include "lib/ovn-sb-idl.h"
>> +
>> +struct sync_meters_data {
>> +    struct shash meter_groups;
>> +};
>> +
>> +void *en_sync_meters_init(struct engine_node *, struct engine_arg *);
>> +void en_sync_meters_cleanup(void *data);
>> +void en_sync_meters_run(struct engine_node *, void *data);
>> +
>> +const struct nbrec_meter *fair_meter_lookup_by_name(
>> +    const struct shash *meter_groups,
>> +    const char *meter_name);
>> +
>> +static inline char*
>> +alloc_acl_log_unique_meter_name(const struct nbrec_acl *acl)
>> +{
>> +    return xasprintf("%s__" UUID_FMT,
>> +                     acl->meter, UUID_ARGS(&acl->header_.uuid));
>> +}
>> +
>> +#endif /* EN_ACL_H */
>> diff --git a/northd/en-northd.c b/northd/en-northd.c
>> index 044fa70190..cc05efdbbc 100644
>> --- a/northd/en-northd.c
>> +++ b/northd/en-northd.c
>> @@ -76,10 +76,6 @@ northd_get_input_data(struct engine_node *node,
>>          EN_OVSDB_GET(engine_get_input("NB_load_balancer_group", node));
>>      input_data->nbrec_port_group_table =
>>          EN_OVSDB_GET(engine_get_input("NB_port_group", node));
>> -    input_data->nbrec_meter_table =
>> -        EN_OVSDB_GET(engine_get_input("NB_meter", node));
>> -    input_data->nbrec_acl_table =
>> -        EN_OVSDB_GET(engine_get_input("NB_acl", node));
>>      input_data->nbrec_static_mac_binding_table =
>>          EN_OVSDB_GET(engine_get_input("NB_static_mac_binding", node));
>>      input_data->nbrec_chassis_template_var_table =
>> @@ -107,8 +103,6 @@ northd_get_input_data(struct engine_node *node,
>>          EN_OVSDB_GET(engine_get_input("SB_service_monitor", node));
>>      input_data->sbrec_port_group_table =
>>          EN_OVSDB_GET(engine_get_input("SB_port_group", node));
>> -    input_data->sbrec_meter_table =
>> -        EN_OVSDB_GET(engine_get_input("SB_meter", node));
>>      input_data->sbrec_dns_table =
>>          EN_OVSDB_GET(engine_get_input("SB_dns", node));
>>      input_data->sbrec_ip_multicast_table =
>> diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c
>> index d328deb222..1de0551b3d 100644
>> --- a/northd/inc-proc-northd.c
>> +++ b/northd/inc-proc-northd.c
>> @@ -33,6 +33,7 @@
>>  #include "en-northd.h"
>>  #include "en-lflow.h"
>>  #include "en-northd-output.h"
>> +#include "en-meters.h"
>>  #include "en-sync-sb.h"
>>  #include "en-sync-from-sb.h"
>>  #include "unixctl.h"
>> @@ -135,6 +136,7 @@ static ENGINE_NODE(lflow, "lflow");
>>  static ENGINE_NODE(mac_binding_aging, "mac_binding_aging");
>>  static ENGINE_NODE(mac_binding_aging_waker, "mac_binding_aging_waker");
>>  static ENGINE_NODE(northd_output, "northd_output");
>> +static ENGINE_NODE(sync_meters, "sync_meters");
>>  static ENGINE_NODE(sync_to_sb, "sync_to_sb");
>>  static ENGINE_NODE(sync_to_sb_addr_set, "sync_to_sb_addr_set");
>>  static ENGINE_NODE(fdb_aging, "fdb_aging");
>> @@ -148,10 +150,8 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
>>      engine_add_input(&en_northd, &en_nb_port_group, NULL);
>>      engine_add_input(&en_northd, &en_nb_load_balancer, NULL);
>>      engine_add_input(&en_northd, &en_nb_load_balancer_group, NULL);
>> -    engine_add_input(&en_northd, &en_nb_acl, NULL);
>>      engine_add_input(&en_northd, &en_nb_logical_router, NULL);
>>      engine_add_input(&en_northd, &en_nb_mirror, NULL);
>> -    engine_add_input(&en_northd, &en_nb_meter, NULL);
>>      engine_add_input(&en_northd, &en_nb_static_mac_binding, NULL);
>>      engine_add_input(&en_northd, &en_nb_chassis_template_var, NULL);
>>
>> @@ -188,7 +188,13 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
>>      engine_add_input(&en_fdb_aging, &en_northd, NULL);
>>      engine_add_input(&en_fdb_aging, &en_fdb_aging_waker, NULL);
>>
>> +    engine_add_input(&en_sync_meters, &en_nb_acl, NULL);
>> +    engine_add_input(&en_sync_meters, &en_nb_meter, NULL);
>> +    engine_add_input(&en_sync_meters, &en_sb_meter, NULL);
>> +
>>      engine_add_input(&en_lflow, &en_nb_bfd, NULL);
>> +    engine_add_input(&en_lflow, &en_nb_acl, NULL);
>> +    engine_add_input(&en_lflow, &en_sync_meters, NULL);
>>      engine_add_input(&en_lflow, &en_sb_bfd, NULL);
>>      engine_add_input(&en_lflow, &en_sb_logical_flow, NULL);
>>      engine_add_input(&en_lflow, &en_sb_multicast_group, NULL);
>> @@ -204,9 +210,11 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
>>
>>      /* en_sync_to_sb engine node syncs the SB database tables from
>>       * the NB database tables.
>> -     * Right now this engine only syncs the SB Address_Set table.
>> +     * Right now this engine syncs the SB Address_Set table and
>> +     * SB Meter/Meter_Band tables.
>>       */
>>      engine_add_input(&en_sync_to_sb, &en_sync_to_sb_addr_set, NULL);
>> +    engine_add_input(&en_sync_to_sb, &en_sync_meters, NULL);
>>
>>      engine_add_input(&en_sync_from_sb, &en_northd,
>>                       sync_from_sb_northd_handler);
>> diff --git a/northd/northd.c b/northd/northd.c
>> index 9a12a94ae2..48fb44a8be 100644
>> --- a/northd/northd.c
>> +++ b/northd/northd.c
>> @@ -21,6 +21,7 @@
>>  #include "bitmap.h"
>>  #include "coverage.h"
>>  #include "dirs.h"
>> +#include "en-meters.h"
>>  #include "ipam.h"
>>  #include "openvswitch/dynamic-string.h"
>>  #include "hash.h"
>> @@ -4980,25 +4981,22 @@ ls_port_create(struct ovsdb_idl_txn *ovnsb_txn,
>> struct hmap *ls_ports,
>>  }
>>
>>  static bool
>> -check_ls_changes_other_than_lsp(const struct nbrec_logical_switch *ls)
>> +check_ls_changes_other_than_lsp_acl(const struct nbrec_logical_switch *ls)
>>  {
>>      /* Check if the columns are changed in this row. */
>>      enum nbrec_logical_switch_column_id col;
>>      for (col = 0; col < NBREC_LOGICAL_SWITCH_N_COLUMNS; col++) {
>> -        if (nbrec_logical_switch_is_updated(ls, col) &&
>> -            col != NBREC_LOGICAL_SWITCH_COL_PORTS) {
>> +        if (nbrec_logical_switch_is_updated(ls, col)) {
>> +            if (col == NBREC_LOGICAL_SWITCH_COL_ACLS ||
>> +                col == NBREC_LOGICAL_SWITCH_COL_PORTS) {
>> +                continue;
>> +            }
>>              return true;
>>          }
>>      }
>>
>>      /* Check if the referenced rows are changed.
>>         XXX: Need a better OVSDB IDL interface for this check. */
>> -    for (size_t i = 0; i < ls->n_acls; i++) {
>> -        if (nbrec_acl_row_get_seqno(ls->acls[i],
>> -                                OVSDB_IDL_CHANGE_MODIFY) > 0) {
>> -            return true;
>> -        }
>> -    }
>>      if (ls->copp && nbrec_copp_row_get_seqno(ls->copp,
>>                                  OVSDB_IDL_CHANGE_MODIFY) > 0) {
>>          return true;
>> @@ -5106,7 +5104,7 @@ northd_handle_ls_changes(struct ovsdb_idl_txn
>> *ovnsb_idl_txn,
>>          }
>>
>>          /* Now only able to handle lsp changes. */
>> -        if (check_ls_changes_other_than_lsp(changed_ls)) {
>> +        if (check_ls_changes_other_than_lsp_acl(changed_ls)) {
>>              goto fail;
>>          }
>>
>> @@ -6987,25 +6985,6 @@ build_acl_hints(struct ovn_datapath *od,
>>      }
>>  }
>>
>> -static const struct nbrec_meter*
>> -fair_meter_lookup_by_name(const struct shash *meter_groups,
>> -                          const char *meter_name)
>> -{
>> -    const struct nbrec_meter *nb_meter =
>> -        meter_name ? shash_find_data(meter_groups, meter_name) : NULL;
>> -    if (nb_meter) {
>> -        return (nb_meter->fair && *nb_meter->fair) ? nb_meter : NULL;
>> -    }
>> -    return NULL;
>> -}
>> -
>> -static char*
>> -alloc_acl_log_unique_meter_name(const struct nbrec_acl *acl)
>> -{
>> -    return xasprintf("%s__" UUID_FMT,
>> -                     acl->meter, UUID_ARGS(&acl->header_.uuid));
>> -}
>> -
>>  static void
>>  build_acl_log_meter(struct ds *actions, const struct nbrec_acl *acl,
>>                      const struct shash *meter_groups)
>> @@ -16608,197 +16587,6 @@ sync_port_groups(struct ovsdb_idl_txn *ovnsb_txn,
>>      shash_destroy(&sb_port_groups);
>>  }
>>
>> -struct band_entry {
>> -    int64_t rate;
>> -    int64_t burst_size;
>> -    const char *action;
>> -};
>> -
>> -static int
>> -band_cmp(const void *band1_, const void *band2_)
>> -{
>> -    const struct band_entry *band1p = band1_;
>> -    const struct band_entry *band2p = band2_;
>> -
>> -    if (band1p->rate != band2p->rate) {
>> -        return band1p->rate > band2p->rate ? -1 : 1;
>> -    } else if (band1p->burst_size != band2p->burst_size) {
>> -        return band1p->burst_size > band2p->burst_size ? -1 : 1;
>> -    } else {
>> -        return strcmp(band1p->action, band2p->action);
>> -    }
>> -}
>> -
>> -static bool
>> -bands_need_update(const struct nbrec_meter *nb_meter,
>> -                  const struct sbrec_meter *sb_meter)
>> -{
>> -    if (nb_meter->n_bands != sb_meter->n_bands) {
>> -        return true;
>> -    }
>> -
>> -    /* A single band is the most common scenario, so speed up that
>> -     * check. */
>> -    if (nb_meter->n_bands == 1) {
>> -        struct nbrec_meter_band *nb_band = nb_meter->bands[0];
>> -        struct sbrec_meter_band *sb_band = sb_meter->bands[0];
>> -
>> -        return !(nb_band->rate == sb_band->rate
>> -                 && nb_band->burst_size == sb_band->burst_size
>> -                 && !strcmp(sb_band->action, nb_band->action));
>> -    }
>> -
>> -    /* Place the Northbound entries in sorted order. */
>> -    struct band_entry *nb_bands;
>> -    nb_bands = xmalloc(sizeof *nb_bands * nb_meter->n_bands);
>> -    for (size_t i = 0; i < nb_meter->n_bands; i++) {
>> -        struct nbrec_meter_band *nb_band = nb_meter->bands[i];
>> -
>> -        nb_bands[i].rate = nb_band->rate;
>> -        nb_bands[i].burst_size = nb_band->burst_size;
>> -        nb_bands[i].action = nb_band->action;
>> -    }
>> -    qsort(nb_bands, nb_meter->n_bands, sizeof *nb_bands, band_cmp);
>> -
>> -    /* Place the Southbound entries in sorted order. */
>> -    struct band_entry *sb_bands;
>> -    sb_bands = xmalloc(sizeof *sb_bands * sb_meter->n_bands);
>> -    for (size_t i = 0; i < sb_meter->n_bands; i++) {
>> -        struct sbrec_meter_band *sb_band = sb_meter->bands[i];
>> -
>> -        sb_bands[i].rate = sb_band->rate;
>> -        sb_bands[i].burst_size = sb_band->burst_size;
>> -        sb_bands[i].action = sb_band->action;
>> -    }
>> -    qsort(sb_bands, sb_meter->n_bands, sizeof *sb_bands, band_cmp);
>> -
>> -    bool need_update = false;
>> -    for (size_t i = 0; i < nb_meter->n_bands; i++) {
>> -        if (nb_bands[i].rate != sb_bands[i].rate
>> -            || nb_bands[i].burst_size != sb_bands[i].burst_size
>> -            || strcmp(nb_bands[i].action, sb_bands[i].action)) {
>> -            need_update = true;
>> -            goto done;
>> -        }
>> -    }
>> -
>> -done:
>> -    free(nb_bands);
>> -    free(sb_bands);
>> -
>> -    return need_update;
>> -}
>> -
>> -static void
>> -sync_meters_iterate_nb_meter(struct ovsdb_idl_txn *ovnsb_txn,
>> -                             const char *meter_name,
>> -                             const struct nbrec_meter *nb_meter,
>> -                             struct shash *sb_meters,
>> -                             struct sset *used_sb_meters)
>> -{
>> -    const struct sbrec_meter *sb_meter;
>> -    bool new_sb_meter = false;
>> -
>> -    sb_meter = shash_find_data(sb_meters, meter_name);
>> -    if (!sb_meter) {
>> -        sb_meter = sbrec_meter_insert(ovnsb_txn);
>> -        sbrec_meter_set_name(sb_meter, meter_name);
>> -        shash_add(sb_meters, sb_meter->name, sb_meter);
>> -        new_sb_meter = true;
>> -    }
>> -    sset_add(used_sb_meters, meter_name);
>> -
>> -    if (new_sb_meter || bands_need_update(nb_meter, sb_meter)) {
>> -        struct sbrec_meter_band **sb_bands;
>> -        sb_bands = xcalloc(nb_meter->n_bands, sizeof *sb_bands);
>> -        for (size_t i = 0; i < nb_meter->n_bands; i++) {
>> -            const struct nbrec_meter_band *nb_band = nb_meter->bands[i];
>> -
>> -            sb_bands[i] = sbrec_meter_band_insert(ovnsb_txn);
>> -
>> -            sbrec_meter_band_set_action(sb_bands[i], nb_band->action);
>> -            sbrec_meter_band_set_rate(sb_bands[i], nb_band->rate);
>> -            sbrec_meter_band_set_burst_size(sb_bands[i],
>> -                                            nb_band->burst_size);
>> -        }
>> -        sbrec_meter_set_bands(sb_meter, sb_bands, nb_meter->n_bands);
>> -        free(sb_bands);
>> -    }
>> -
>> -    sbrec_meter_set_unit(sb_meter, nb_meter->unit);
>> -}
>> -
>> -static void
>> -sync_acl_fair_meter(struct ovsdb_idl_txn *ovnsb_txn,
>> -                    struct shash *meter_groups,
>> -                    const struct nbrec_acl *acl, struct shash *sb_meters,
>> -                    struct sset *used_sb_meters)
>> -{
>> -    const struct nbrec_meter *nb_meter =
>> -        fair_meter_lookup_by_name(meter_groups, acl->meter);
>> -
>> -    if (!nb_meter) {
>> -        return;
>> -    }
>> -
>> -    char *meter_name = alloc_acl_log_unique_meter_name(acl);
>> -    sync_meters_iterate_nb_meter(ovnsb_txn, meter_name, nb_meter,
>> sb_meters,
>> -                                 used_sb_meters);
>> -    free(meter_name);
>> -}
>> -
>> -/* Each entry in the Meter and Meter_Band tables in OVN_Northbound have
>> - * a corresponding entries in the Meter and Meter_Band tables in
>> - * OVN_Southbound. Additionally, ACL logs that use fair meters have
>> - * a private copy of its meter in the SB table.
>> - */
>> -static void
>> -sync_meters(struct ovsdb_idl_txn *ovnsb_txn,
>> -            const struct nbrec_meter_table *nbrec_meter_table,
>> -            const struct nbrec_acl_table *nbrec_acl_table,
>> -            const struct sbrec_meter_table *sbrec_meter_table,
>> -            struct shash *meter_groups)
>> -{
>> -    struct shash sb_meters = SHASH_INITIALIZER(&sb_meters);
>> -    struct sset used_sb_meters = SSET_INITIALIZER(&used_sb_meters);
>> -
>> -    const struct sbrec_meter *sb_meter;
>> -    SBREC_METER_TABLE_FOR_EACH (sb_meter, sbrec_meter_table) {
>> -        shash_add(&sb_meters, sb_meter->name, sb_meter);
>> -    }
>> -
>> -    const struct nbrec_meter *nb_meter;
>> -    NBREC_METER_TABLE_FOR_EACH (nb_meter, nbrec_meter_table) {
>> -        sync_meters_iterate_nb_meter(ovnsb_txn, nb_meter->name, nb_meter,
>> -                                     &sb_meters, &used_sb_meters);
>> -    }
>> -
>> -    /*
>> -     * In addition to creating Meters in the SB from the block above,
>> check
>> -     * and see if additional rows are needed to get ACLs logs individually
>> -     * rate-limited.
>> -     */
>> -    const struct nbrec_acl *acl;
>> -    NBREC_ACL_TABLE_FOR_EACH (acl, nbrec_acl_table) {
>> -        sync_acl_fair_meter(ovnsb_txn, meter_groups, acl,
>> -                            &sb_meters, &used_sb_meters);
>> -    }
>> -
>> -    const char *used_meter;
>> -    SSET_FOR_EACH_SAFE (used_meter, &used_sb_meters) {
>> -        shash_find_and_delete(&sb_meters, used_meter);
>> -        sset_delete(&used_sb_meters, SSET_NODE_FROM_NAME(used_meter));
>> -    }
>> -    sset_destroy(&used_sb_meters);
>> -
>> -    struct shash_node *node;
>> -    SHASH_FOR_EACH_SAFE (node, &sb_meters) {
>> -        sbrec_meter_delete(node->data);
>> -        shash_delete(&sb_meters, node);
>> -    }
>> -    shash_destroy(&sb_meters);
>> -}
>> -
>>  static bool
>>  mirror_needs_update(const struct nbrec_mirror *nb_mirror,
>>                      const struct sbrec_mirror *sb_mirror)
>> @@ -17268,16 +17056,6 @@ build_mcast_groups(const struct
>> sbrec_igmp_group_table *sbrec_igmp_group_table,
>>      }
>>  }
>>
>> -static void
>> -build_meter_groups(const struct nbrec_meter_table *nbrec_meter_table,
>> -                   struct shash *meter_groups)
>> -{
>> -    const struct nbrec_meter *nb_meter;
>> -    NBREC_METER_TABLE_FOR_EACH (nb_meter, nbrec_meter_table) {
>> -        shash_add(meter_groups, nb_meter->name, nb_meter);
>> -    }
>> -}
>> -
>>  static const struct nbrec_static_mac_binding *
>>  static_mac_binding_by_port_ip(
>>      const struct nbrec_static_mac_binding_table *nbrec_static_mb_table,
>> @@ -17419,7 +17197,6 @@ northd_init(struct northd_data *data)
>>      hmap_init(&data->ls_ports);
>>      hmap_init(&data->lr_ports);
>>      hmap_init(&data->port_groups);
>> -    shash_init(&data->meter_groups);
>>      hmap_init(&data->lbs);
>>      hmap_init(&data->lb_groups);
>>      ovs_list_init(&data->lr_list);
>> @@ -17457,12 +17234,6 @@ northd_destroy(struct northd_data *data)
>>
>>      hmap_destroy(&data->port_groups);
>>
>> -    struct shash_node *node;
>> -    SHASH_FOR_EACH_SAFE (node, &data->meter_groups) {
>> -        shash_delete(&data->meter_groups, node);
>> -    }
>> -    shash_destroy(&data->meter_groups);
>> -
>>      /* XXX Having to explicitly clean up macam here
>>       * is a bit strange. We don't explicitly initialize
>>       * macam in this module, but this is the logical place
>> @@ -17601,7 +17372,6 @@ ovnnb_db_run(struct northd_input *input_data,
>>      build_ip_mcast(ovnsb_txn, input_data->sbrec_ip_multicast_table,
>>                     input_data->sbrec_ip_mcast_by_dp,
>>                     &data->ls_datapaths.datapaths);
>> -    build_meter_groups(input_data->nbrec_meter_table,
>> &data->meter_groups);
>>      build_static_mac_binding_table(ovnsb_txn,
>>          input_data->nbrec_static_mac_binding_table,
>>          input_data->sbrec_static_mac_binding_table,
>> @@ -17616,9 +17386,6 @@ ovnnb_db_run(struct northd_input *input_data,
>>               &data->ls_datapaths, &data->lbs);
>>      sync_port_groups(ovnsb_txn, input_data->sbrec_port_group_table,
>>                       &data->port_groups);
>> -    sync_meters(ovnsb_txn, input_data->nbrec_meter_table,
>> -                input_data->nbrec_acl_table,
>> input_data->sbrec_meter_table,
>> -                &data->meter_groups);
>>      sync_mirrors(ovnsb_txn, input_data->nbrec_mirror_table,
>>                   input_data->sbrec_mirror_table);
>>      sync_dns_entries(ovnsb_txn, input_data->sbrec_dns_table,
>> diff --git a/northd/northd.h b/northd/northd.h
>> index f3e63b1e1a..dcc3acabd5 100644
>> --- a/northd/northd.h
>> +++ b/northd/northd.h
>> @@ -31,8 +31,6 @@ struct northd_input {
>>      const struct nbrec_load_balancer_group_table
>>          *nbrec_load_balancer_group_table;
>>      const struct nbrec_port_group_table *nbrec_port_group_table;
>> -    const struct nbrec_meter_table *nbrec_meter_table;
>> -    const struct nbrec_acl_table *nbrec_acl_table;
>>      const struct nbrec_static_mac_binding_table
>>          *nbrec_static_mac_binding_table;
>>      const struct nbrec_chassis_template_var_table
>> @@ -50,7 +48,6 @@ struct northd_input {
>>      const struct sbrec_load_balancer_table *sbrec_load_balancer_table;
>>      const struct sbrec_service_monitor_table *sbrec_service_monitor_table;
>>      const struct sbrec_port_group_table *sbrec_port_group_table;
>> -    const struct sbrec_meter_table *sbrec_meter_table;
>>      const struct sbrec_dns_table *sbrec_dns_table;
>>      const struct sbrec_ip_multicast_table *sbrec_ip_multicast_table;
>>      const struct sbrec_static_mac_binding_table
>> @@ -109,7 +106,6 @@ struct northd_data {
>>      struct hmap ls_ports;
>>      struct hmap lr_ports;
>>      struct hmap port_groups;
>> -    struct shash meter_groups;
>>      struct hmap lbs;
>>      struct hmap lb_groups;
>>      struct ovs_list lr_list;
>> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
>> index 4fa1b039ea..45362f4f93 100644
>> --- a/northd/ovn-northd.c
>> +++ b/northd/ovn-northd.c
>> @@ -836,6 +836,9 @@ main(int argc, char *argv[])
>>          ovsdb_idl_omit_alert(ovnsb_idl_loop.idl,
>>                               &sbrec_multicast_group_columns[i]);
>>      }
>> +    for (size_t i = 0; i < SBREC_METER_N_COLUMNS; i++) {
>> +        ovsdb_idl_omit_alert(ovnsb_idl_loop.idl, &sbrec_meter_columns[i]);
>> +    }
>>
>>      unixctl_command_register("sb-connection-status", "", 0, 0,
>>                               ovn_conn_show, ovnsb_idl_loop.idl);
>> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
>> index d5be3be75b..dc8bf253f1 100644
>> --- a/tests/ovn-northd.at
>> +++ b/tests/ovn-northd.at
>> @@ -9,6 +9,8 @@ m4_define([_DUMP_DB_TABLES], [
>>      ovn-sbctl list logical_flow >> $1
>>      ovn-sbctl list port_binding >> $1
>>      ovn-sbctl list address_set >> $1
>> +    ovn-sbctl list meter >> $1
>> +    ovn-sbctl list meter_band >> $1
>>  ])
>>
>>  # CHECK_NO_CHANGE_AFTER_RECOMPUTE
>> @@ -9679,6 +9681,40 @@ OVN_CLEANUP([hv1])
>>  AT_CLEANUP
>>  ])
>>
>> +OVN_FOR_EACH_NORTHD_NO_HV([
>> +AT_SETUP([ACL/Meter incremental processing - no northd recompute])
>> +ovn_start
>> +
>> +check_recompute_counter() {
>> +    northd_recomp=$(as northd ovn-appctl -t NORTHD_TYPE
>> inc-engine/show-stats northd recompute)
>> +    AT_CHECK([test x$northd_recomp = x$1])
>> +
>> +    northd_recomp=$(as northd ovn-appctl -t NORTHD_TYPE
>> inc-engine/show-stats northd recompute)
>> +    AT_CHECK([test x$northd_recomp = x$1])
>> +
>> +    sync_meters_recomp=$(as northd ovn-appctl -t NORTHD_TYPE
>> inc-engine/show-stats sync_meters recompute)
>> +    AT_CHECK([test x$sync_meters_recomp = x$3])
>> +}
>> +
>> +check ovn-nbctl --wait=sb ls-add ls
>> +
>> +check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
>> +check ovn-nbctl --wait=sb meter-add m drop 1 pktps
>> +check ovn-nbctl --wait=sb acl-add ls from-lport 1 1 allow
>> +dnl Only triggers recompute of the sync_meters and lflow nodes.
>> +check_recompute_counter 0 2 2
>> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
>> +
>> +check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
>> +check ovn-nbctl --wait=sb meter-del m
>> +check ovn-nbctl --wait=sb acl-del ls
>> +dnl Only triggers recompute of the sync_meters and lflow nodes.
>> +check_recompute_counter 0 2 2
>> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
>> +
>> +AT_CLEANUP
>> +])
>> +
>>  OVN_FOR_EACH_NORTHD_NO_HV([
>>  AT_SETUP([check fip and lb flows])
>>  AT_KEYWORDS([fip-lb-flows])
>> --
>> 2.39.3
>>
>> _______________________________________________
>> dev mailing list
>> d...@openvswitch.org
>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>>
>>
> Other than that it looks good.
> 
> Thanks,
> Ales
> 

V2 posted:

https://patchwork.ozlabs.org/project/ovn/list/?series=369253&state=*

Thanks,
Dumitru


_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to