On 1/26/24 06:27, Numan Siddique wrote:
> On Wed, Jan 17, 2024 at 10:17 AM Dumitru Ceara <dce...@redhat.com> wrote:
>>
>> On 1/11/24 16:30, num...@ovn.org wrote:
>>> From: Numan Siddique <num...@ovn.org>
>>>
>>> This new engine now maintains the load balancer and ACL data of a
>>> logical switch which was earlier part of northd engine node data.
>>> The main inputs to this engine are:
>>>     - northd node
>>>     - Port group node
>>>
>>> A record for each logical switch is maintained in the 'ls_statefuls'
>>> hmap table and this record stores the below data which was earlier
>>> part of 'struct ovn_datapath'.
>>>
>>>     - bool has_stateful_acl;
>>>     - bool has_lb_vip;
>>>     - bool has_acls;
>>>     - uint64_t max_acl_tier;
>>>
>>> This engine node becomes an input to 'lflow' node.
>>>
>>> If a logical switch is configured with
>>>    - DHCP for all or some of its ports
>>>    - stateful ACLs and/or load balancers
>>>
>>> ovn-northd was adding flows to commit the DHCP response generated by
>>> ovn-controller to conntrack.  With this patch we don't commit the
>>> DHCP response to conntrack anymore for the following reasons:
>>>   1.  There is no need to actually commit the response.
>>>   2.  Since stateful information is moved to 'ls_stateful' node, it
>>>       becomes ineffecient to access ls_stateful's data
>>>       ('has_lb_vip' and 'has_acls') in build_dhcpv4_options_flows().
>>>
>>> Signed-off-by: Numan Siddique <num...@ovn.org>
>>> ---
>>
>> Hi Numan,
>>
>> Overall this looks correct to me.  I only had a few minor comments,
>> please see below.
>>
>> If you address them feel free to add my ack:
>>
>> Acked-by: Dumitru Ceara <dce...@redhat.com>
>>
>> Thanks,
>> Dumitru
>>
>>>  lib/stopwatch-names.h    |   1 +
>>>  northd/automake.mk       |   2 +
>>>  northd/en-lflow.c        |   4 +
>>>  northd/en-lr-stateful.c  |   6 +-
>>>  northd/en-lr-stateful.h  |   2 +
>>>  northd/en-ls-stateful.c  | 440 +++++++++++++++++++++++++++++++++++++++
>>>  northd/en-ls-stateful.h  |  81 +++++++
>>>  northd/en-northd.c       |   2 +-
>>>  northd/en-port-group.h   |   3 +
>>>  northd/inc-proc-northd.c |   7 +
>>>  northd/northd.c          | 335 +++++++++++++++--------------
>>>  northd/northd.h          |  29 ++-
>>>  northd/ovn-northd.c      |   1 +
>>>  13 files changed, 753 insertions(+), 160 deletions(-)
>>>  create mode 100644 northd/en-ls-stateful.c
>>>  create mode 100644 northd/en-ls-stateful.h
>>>
>>> diff --git a/lib/stopwatch-names.h b/lib/stopwatch-names.h
>>> index e5e41fbfd8..c865f125be 100644
>>> --- a/lib/stopwatch-names.h
>>> +++ b/lib/stopwatch-names.h
>>> @@ -31,5 +31,6 @@
>>>  #define SYNC_METERS_RUN_STOPWATCH_NAME "sync_meters_run"
>>>  #define LR_NAT_RUN_STOPWATCH_NAME "lr_nat_run"
>>>  #define LR_STATEFUL_RUN_STOPWATCH_NAME "lr_stateful"
>>> +#define LS_STATEFUL_RUN_STOPWATCH_NAME "ls_stateful"
>>>
>>>  #endif
>>> diff --git a/northd/automake.mk b/northd/automake.mk
>>> index b886356c9c..a178541759 100644
>>> --- a/northd/automake.mk
>>> +++ b/northd/automake.mk
>>> @@ -28,6 +28,8 @@ northd_ovn_northd_SOURCES = \
>>>       northd/en-lr-nat.h \
>>>       northd/en-lr-stateful.c \
>>>       northd/en-lr-stateful.h \
>>> +     northd/en-ls-stateful.c \
>>> +     northd/en-ls-stateful.h \
>>>       northd/inc-proc-northd.c \
>>>       northd/inc-proc-northd.h \
>>>       northd/ipam.c \
>>> diff --git a/northd/en-lflow.c b/northd/en-lflow.c
>>> index a3a0d62f15..eb6b2a8666 100644
>>> --- a/northd/en-lflow.c
>>> +++ b/northd/en-lflow.c
>>> @@ -21,6 +21,7 @@
>>>  #include "en-lflow.h"
>>>  #include "en-lr-nat.h"
>>>  #include "en-lr-stateful.h"
>>> +#include "en-ls-stateful.h"
>>>  #include "en-northd.h"
>>>  #include "en-meters.h"
>>>
>>> @@ -44,6 +45,8 @@ lflow_get_input_data(struct engine_node *node,
>>>          engine_get_input_data("sync_meters", node);
>>>      struct ed_type_lr_stateful *lr_stateful_data =
>>>          engine_get_input_data("lr_stateful", node);
>>> +    struct ed_type_ls_stateful *ls_stateful_data =
>>> +        engine_get_input_data("ls_stateful", node);
>>>
>>>      lflow_input->nbrec_bfd_table =
>>>          EN_OVSDB_GET(engine_get_input("NB_bfd", node));
>>> @@ -67,6 +70,7 @@ lflow_get_input_data(struct engine_node *node,
>>>      lflow_input->lr_ports = &northd_data->lr_ports;
>>>      lflow_input->ls_port_groups = &pg_data->ls_port_groups;
>>>      lflow_input->lr_stateful_table = &lr_stateful_data->table;
>>> +    lflow_input->ls_stateful_table = &ls_stateful_data->table;
>>>      lflow_input->meter_groups = &sync_meters_data->meter_groups;
>>>      lflow_input->lb_datapaths_map = &northd_data->lb_datapaths_map;
>>>      lflow_input->svc_monitor_map = &northd_data->svc_monitor_map;
>>> diff --git a/northd/en-lr-stateful.c b/northd/en-lr-stateful.c
>>> index dedfdf6747..4287aaddc9 100644
>>> --- a/northd/en-lr-stateful.c
>>> +++ b/northd/en-lr-stateful.c
>>> @@ -295,7 +295,9 @@ lr_stateful_lb_data_handler(struct engine_node *node, 
>>> void *data_)
>>>          /* For all the modified lr_stateful records (re)build the
>>>           * vip nats. */
>>>          HMAPX_FOR_EACH (hmapx_node, &data->trk_data.crupdated) {
>>> -            lr_stateful_build_vip_nats(hmapx_node->data);
>>> +            struct lr_stateful_record *lr_stateful_rec = hmapx_node->data;
>>> +            lr_stateful_build_vip_nats(lr_stateful_rec);
>>> +            lr_stateful_rec->has_lb_vip = 
>>> od_has_lb_vip(lr_stateful_rec->od);
>>>          }
>>>
>>>          engine_set_node_state(node, EN_UPDATED);
>>> @@ -510,6 +512,8 @@ lr_stateful_record_init(struct lr_stateful_record 
>>> *lr_stateful_rec,
>>>      if (nbr->n_nat) {
>>>          lr_stateful_build_vip_nats(lr_stateful_rec);
>>>      }
>>> +
>>> +    lr_stateful_rec->has_lb_vip = od_has_lb_vip(lr_stateful_rec->od);
>>>  }
>>>
>>>  static struct lr_stateful_input
>>> diff --git a/northd/en-lr-stateful.h b/northd/en-lr-stateful.h
>>> index 74029c9a6c..5d647d8863 100644
>>> --- a/northd/en-lr-stateful.h
>>> +++ b/northd/en-lr-stateful.h
>>> @@ -49,6 +49,8 @@ struct lr_stateful_record {
>>>      const struct ovn_datapath *od;
>>>      const struct lr_nat_record *lrnat_rec;
>>>
>>> +    bool has_lb_vip;
>>> +
>>>      /* Load Balancer vIPs relevant for this datapath. */
>>>      struct ovn_lb_ip_set *lb_ips;
>>>
>>> diff --git a/northd/en-ls-stateful.c b/northd/en-ls-stateful.c
>>> new file mode 100644
>>> index 0000000000..5fa305bc29
>>> --- /dev/null
>>> +++ b/northd/en-ls-stateful.c
>>> @@ -0,0 +1,440 @@
>>> +/*
>>> + * Copyright (c) 2023, Red Hat, Inc.
>>
>> 2024
> 
> Ack
> 
>>
>>> + *
>>> + * 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 <getopt.h>
>>> +#include <stdlib.h>
>>> +#include <stdio.h>
>>> +
>>> +/* OVS includes */
>>> +#include "include/openvswitch/hmap.h"
>>> +#include "lib/bitmap.h"
>>> +#include "lib/socket-util.h"
>>> +#include "lib/uuidset.h"
>>> +#include "openvswitch/util.h"
>>> +#include "openvswitch/vlog.h"
>>> +#include "stopwatch.h"
>>> +
>>> +/* OVN includes */
>>> +#include "en-lb-data.h"
>>> +#include "en-ls-stateful.h"
>>> +#include "en-port-group.h"
>>> +#include "lib/inc-proc-eng.h"
>>> +#include "lib/lb.h"
>>> +#include "lib/ovn-nb-idl.h"
>>> +#include "lib/ovn-sb-idl.h"
>>> +#include "lib/ovn-util.h"
>>> +#include "lib/stopwatch-names.h"
>>> +#include "northd.h"
>>> +
>>> +VLOG_DEFINE_THIS_MODULE(en_ls_stateful);
>>> +
>>> +/* Static function declarations. */
>>> +static void ls_stateful_table_init(struct ls_stateful_table *);
>>> +static void ls_stateful_table_clear(struct ls_stateful_table *);
>>> +static void ls_stateful_table_destroy(struct ls_stateful_table *);
>>> +static struct ls_stateful_record *ls_stateful_table_find_(
>>> +    const struct ls_stateful_table *, const struct nbrec_logical_switch *);
>>> +static void ls_stateful_table_build(struct ls_stateful_table *,
>>> +                                    const struct ovn_datapaths 
>>> *ls_datapaths,
>>> +                                    const struct ls_port_group_table *);
>>> +
>>> +static struct ls_stateful_input ls_stateful_get_input_data(
>>> +    struct engine_node *);
>>> +
>>> +static struct ls_stateful_record *ls_stateful_record_create(
>>> +    struct ls_stateful_table *,
>>> +    const struct ovn_datapath *,
>>> +    const struct ls_port_group_table *);
>>> +static void ls_stateful_record_destroy(struct ls_stateful_record *);
>>> +static void ls_stateful_record_init(
>>> +    struct ls_stateful_record *,
>>> +    const struct ovn_datapath *,
>>> +    const struct ls_port_group *,
>>> +    const struct ls_port_group_table *);
>>> +static void ls_stateful_record_reinit(
>>> +    struct ls_stateful_record *,
>>> +    const struct ls_port_group *,
>>> +    const struct ls_port_group_table *);
>>> +static bool ls_has_lb_vip(const struct ovn_datapath *);
>>> +static void ls_stateful_record_set_acl_flags(
>>> +    struct ls_stateful_record *, const struct ovn_datapath *,
>>> +    const struct ls_port_group *, const struct ls_port_group_table *);
>>> +static bool ls_stateful_record_set_acl_flags_(struct ls_stateful_record *,
>>> +                                              struct nbrec_acl **,
>>> +                                              size_t n_acls);
>>> +static struct ls_stateful_input ls_stateful_get_input_data(
>>> +    struct engine_node *);
>>> +
>>> +struct ls_stateful_input {
>>> +    const struct ls_port_group_table *ls_port_groups;
>>> +    const struct ovn_datapaths *ls_datapaths;
>>> +};
>>> +
>>> +/* public functions. */
>>> +const struct ls_stateful_record *
>>> +ls_stateful_table_find(const struct ls_stateful_table *table,
>>> +                       const struct nbrec_logical_switch *nbs)
>>> +{
>>> +    return ls_stateful_table_find_(table, nbs);
>>> +}
>>> +
>>> +void *
>>> +en_ls_stateful_init(struct engine_node *node OVS_UNUSED,
>>> +                    struct engine_arg *arg OVS_UNUSED)
>>> +{
>>> +    struct ed_type_ls_stateful *data = xzalloc(sizeof *data);
>>> +    ls_stateful_table_init(&data->table);
>>> +    hmapx_init(&data->trk_data.crupdated);
>>> +    return data;
>>> +}
>>> +
>>> +void
>>> +en_ls_stateful_cleanup(void *data_)
>>> +{
>>> +    struct ed_type_ls_stateful *data = data_;
>>> +    ls_stateful_table_destroy(&data->table);
>>> +    hmapx_destroy(&data->trk_data.crupdated);
>>> +}
>>> +
>>> +void
>>> +en_ls_stateful_clear_tracked_data(void *data_)
>>> +{
>>> +    struct ed_type_ls_stateful *data = data_;
>>> +    hmapx_clear(&data->trk_data.crupdated);
>>> +}
>>> +
>>> +void
>>> +en_ls_stateful_run(struct engine_node *node, void *data_)
>>> +{
>>> +    struct ls_stateful_input input_data = ls_stateful_get_input_data(node);
>>> +    struct ed_type_ls_stateful *data = data_;
>>> +
>>> +    stopwatch_start(LS_STATEFUL_RUN_STOPWATCH_NAME, time_msec());
>>> +
>>> +    ls_stateful_table_clear(&data->table);
>>> +    ls_stateful_table_build(&data->table, input_data.ls_datapaths,
>>> +                          input_data.ls_port_groups);
>>> +
>>> +    stopwatch_stop(LS_STATEFUL_RUN_STOPWATCH_NAME, time_msec());
>>> +    engine_set_node_state(node, EN_UPDATED);
>>> +}
>>> +
>>> +/* Handler functions. */
>>> +bool
>>> +ls_stateful_northd_handler(struct engine_node *node, void *data_)
>>> +{
>>> +    struct northd_data *northd_data = engine_get_input_data("northd", 
>>> node);
>>> +    if (!northd_has_tracked_data(&northd_data->trk_data)) {
>>> +        return false;
>>> +    }
>>> +
>>> +    if (!northd_has_ls_lbs_in_tracked_data(&northd_data->trk_data) &&
>>> +        !northd_has_ls_acls_in_tracked_data(&northd_data->trk_data)) {
>>> +        return true;
>>> +    }
>>> +
>>> +    struct northd_tracked_data *nd_changes = &northd_data->trk_data;
>>> +    struct ls_stateful_input input_data = ls_stateful_get_input_data(node);
>>> +    struct ed_type_ls_stateful *data = data_;
>>> +    struct hmapx_node *hmapx_node;
>>> +
>>> +    struct hmapx changed_stateful_od = 
>>> HMAPX_INITIALIZER(&changed_stateful_od);
>>> +    HMAPX_FOR_EACH (hmapx_node, &nd_changes->ls_with_changed_lbs) {
>>> +        hmapx_add(&changed_stateful_od, hmapx_node->data);
>>> +    }
>>> +
>>> +    HMAPX_FOR_EACH (hmapx_node, &nd_changes->ls_with_changed_acls) {
>>> +        hmapx_add(&changed_stateful_od, hmapx_node->data);
>>> +    }
>>> +
>>> +    HMAPX_FOR_EACH (hmapx_node, &changed_stateful_od) {
>>> +        const struct ovn_datapath *od = hmapx_node->data;
>>> +
>>> +        struct ls_stateful_record *ls_stateful_rec = 
>>> ls_stateful_table_find_(
>>> +            &data->table, od->nbs);
>>> +        ovs_assert(ls_stateful_rec);
>>> +        ls_stateful_record_reinit(ls_stateful_rec, NULL,
>>> +                                  input_data.ls_port_groups);
>>> +
>>> +        /* Add the ls_stateful_rec to the tracking data. */
>>> +        hmapx_add(&data->trk_data.crupdated, ls_stateful_rec);
>>> +    }
>>> +
>>> +    if (ls_stateful_has_tracked_data(&data->trk_data)) {
>>> +        engine_set_node_state(node, EN_UPDATED);
>>> +    }
>>> +
>>> +    hmapx_destroy(&changed_stateful_od);
>>> +
>>> +    return true;
>>> +}
>>> +
>>> +bool
>>> +ls_stateful_port_group_handler(struct engine_node *node, void *data_)
>>> +{
>>> +    struct port_group_data *pg_data =
>>> +        engine_get_input_data("port_group", node);
>>> +
>>> +    if (pg_data->ls_port_groups_sets_changed) {
>>> +        return false;
>>> +    }
>>> +
>>> +    /* port_group engine node doesn't provide the tracking data yet.
>>> +     * Loop through all the ls port groups and update the ls_stateful_rec.
>>> +     * This is still better than returning false. */
>>> +    struct ls_stateful_input input_data = ls_stateful_get_input_data(node);
>>> +    struct ed_type_ls_stateful *data = data_;
>>> +    const struct ls_port_group *ls_pg;
>>> +
>>> +    LS_PORT_GROUP_TABLE_FOR_EACH (ls_pg, input_data.ls_port_groups) {
>>> +        struct ls_stateful_record *ls_stateful_rec =
>>> +            ls_stateful_table_find_(&data->table, ls_pg->nbs);
>>> +        ovs_assert(ls_stateful_rec);
>>> +
>>> +        bool had_stateful_acl = ls_stateful_rec->has_stateful_acl;
>>> +        uint64_t max_acl_tier = ls_stateful_rec->max_acl_tier;
>>> +        bool had_acls = ls_stateful_rec->has_acls;
>>> +        bool modified = false;
>>> +
>>> +        ls_stateful_record_reinit(ls_stateful_rec, ls_pg,
>>> +                                  input_data.ls_port_groups);
>>> +
>>> +        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) {
>>> +            modified = true;
>>> +        }
>>> +
>>> +        if (modified) {
>>> +            /* Add the ls_stateful_rec to the tracking data. */
>>> +            hmapx_add(&data->trk_data.crupdated, ls_stateful_rec);
>>> +        }
>>> +    }
>>> +
>>> +    if (ls_stateful_has_tracked_data(&data->trk_data)) {
>>> +        engine_set_node_state(node, EN_UPDATED);
>>> +    }
>>> +    return true;
>>> +}
>>> +
>>> +/* static functions. */
>>> +static void
>>> +ls_stateful_table_init(struct ls_stateful_table *table)
>>> +{
>>> +    *table = (struct ls_stateful_table) {
>>> +        .entries = HMAP_INITIALIZER(&table->entries),
>>> +    };
>>> +}
>>> +
>>> +static void
>>> +ls_stateful_table_destroy(struct ls_stateful_table *table)
>>> +{
>>> +    ls_stateful_table_clear(table);
>>> +    hmap_destroy(&table->entries);
>>> +}
>>> +
>>> +static void
>>> +ls_stateful_table_clear(struct ls_stateful_table *table)
>>> +{
>>> +    struct ls_stateful_record *ls_stateful_rec;
>>> +    HMAP_FOR_EACH_POP (ls_stateful_rec, key_node, &table->entries) {
>>> +        ls_stateful_record_destroy(ls_stateful_rec);
>>> +    }
>>> +}
>>> +
>>> +static void
>>> +ls_stateful_table_build(struct ls_stateful_table *table,
>>> +                        const struct ovn_datapaths *ls_datapaths,
>>> +                        const struct ls_port_group_table *ls_pgs)
>>> +{
>>> +    const struct ovn_datapath *od;
>>> +    HMAP_FOR_EACH (od, key_node, &ls_datapaths->datapaths) {
>>> +        ls_stateful_record_create(table, od, ls_pgs);
>>> +    }
>>> +}
>>> +
>>> +struct ls_stateful_record *
>>> +ls_stateful_table_find_(const struct ls_stateful_table *table,
>>> +                        const struct nbrec_logical_switch *nbs)
>>> +{
>>> +    struct ls_stateful_record *rec;
>>> +
>>> +    HMAP_FOR_EACH_WITH_HASH (rec, key_node,
>>> +                             uuid_hash(&nbs->header_.uuid), 
>>> &table->entries) {
>>> +        if (nbs == rec->od->nbs) {
>>> +            return rec;
>>> +        }
>>> +    }
>>> +    return NULL;
>>> +}
>>> +
>>> +static struct ls_stateful_record *
>>> +ls_stateful_record_create(struct ls_stateful_table *table,
>>> +                          const struct ovn_datapath *od,
>>> +                          const struct ls_port_group_table *ls_pgs)
>>> +{
>>> +    struct ls_stateful_record *ls_stateful_rec =
>>> +        xzalloc(sizeof *ls_stateful_rec);
>>> +    ls_stateful_rec->od = od;
>>> +    ls_stateful_record_init(ls_stateful_rec, od, NULL, ls_pgs);
>>> +
>>> +    hmap_insert(&table->entries, &ls_stateful_rec->key_node,
>>> +                uuid_hash(&ls_stateful_rec->od->nbs->header_.uuid));
>>> +
>>> +    return ls_stateful_rec;
>>> +}
>>> +
>>> +static void
>>> +ls_stateful_record_destroy(struct ls_stateful_record *ls_stateful_rec)
>>> +{
>>> +    free(ls_stateful_rec);
>>> +}
>>> +
>>> +static void
>>> +ls_stateful_record_init(struct ls_stateful_record *ls_stateful_rec,
>>> +                        const struct ovn_datapath *od,
>>> +                        const struct ls_port_group *ls_pg,
>>> +                        const struct ls_port_group_table *ls_pgs)
>>> +{
>>> +    ls_stateful_rec->has_lb_vip = ls_has_lb_vip(od);
>>> +    ls_stateful_record_set_acl_flags(ls_stateful_rec, od, ls_pg, ls_pgs);
>>> +}
>>> +
>>> +static void
>>> +ls_stateful_record_reinit(struct ls_stateful_record *ls_stateful_rec,
>>> +                          const struct ls_port_group *ls_pg,
>>> +                          const struct ls_port_group_table *ls_pgs)
>>> +{
>>> +    ls_stateful_record_init(ls_stateful_rec, ls_stateful_rec->od,
>>> +                            ls_pg, ls_pgs);
>>> +}
>>> +
>>> +static bool
>>> +lb_has_vip(const struct nbrec_load_balancer *lb)
>>> +{
>>> +    return !smap_is_empty(&lb->vips);
>>> +}
>>> +
>>> +static bool
>>> +lb_group_has_vip(const struct nbrec_load_balancer_group *lb_group)
>>> +{
>>> +    for (size_t i = 0; i < lb_group->n_load_balancer; i++) {
>>> +        if (lb_has_vip(lb_group->load_balancer[i])) {
>>> +            return true;
>>> +        }
>>> +    }
>>> +    return false;
>>> +}
>>> +
>>> +static bool
>>> +ls_has_lb_vip(const struct ovn_datapath *od)
>>> +{
>>> +    for (size_t i = 0; i < od->nbs->n_load_balancer; i++) {
>>> +        if (lb_has_vip(od->nbs->load_balancer[i])) {
>>> +            return true;
>>> +        }
>>> +    }
>>> +
>>> +    for (size_t i = 0; i < od->nbs->n_load_balancer_group; i++) {
>>> +        if (lb_group_has_vip(od->nbs->load_balancer_group[i])) {
>>> +            return true;
>>> +        }
>>> +    }
>>> +    return false;
>>> +}
>>> +
>>> +static void
>>> +ls_stateful_record_set_acl_flags(struct ls_stateful_record 
>>> *ls_stateful_rec,
>>> +                                 const struct ovn_datapath *od,
>>> +                                 const struct ls_port_group *ls_pg,
>>> +                                 const struct ls_port_group_table *ls_pgs)
>>> +{
>>> +    ls_stateful_rec->has_stateful_acl = false;
>>> +    ls_stateful_rec->max_acl_tier = 0;
>>> +    ls_stateful_rec->has_acls = false;
>>> +
>>> +    if (ls_stateful_record_set_acl_flags_(ls_stateful_rec, od->nbs->acls,
>>> +                                          od->nbs->n_acls)) {
>>> +        return;
>>> +    }
>>> +
>>> +    if (!ls_pg) {
>>> +        ls_pg = ls_port_group_table_find(ls_pgs, od->nbs);
>>> +    }
>>> +
>>> +    if (!ls_pg) {
>>> +        return;
>>> +    }
>>> +
>>> +    const struct ls_port_group_record *ls_pg_rec;
>>> +    HMAP_FOR_EACH (ls_pg_rec, key_node, &ls_pg->nb_pgs) {
>>> +        if (ls_stateful_record_set_acl_flags_(ls_stateful_rec,
>>> +                                              ls_pg_rec->nb_pg->acls,
>>> +                                              ls_pg_rec->nb_pg->n_acls)) {
>>> +            return;
>>> +        }
>>> +    }
>>> +}
>>> +
>>> +static bool
>>> +ls_stateful_record_set_acl_flags_(struct ls_stateful_record 
>>> *ls_stateful_rec,
>>> +                                  struct nbrec_acl **acls,
>>> +                                  size_t n_acls)
>>> +{
>>> +    /* A true return indicates that there are no possible ACL flags
>>> +     * left to set on ls_stateful record. A false return indicates that
>>> +     * further ACLs should be explored in case more flags need to be
>>> +     * set on ls_stateful record.
>>> +     */
>>> +    if (!n_acls) {
>>> +        return false;
>>> +    }
>>> +
>>> +    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;
>>> +        }
>>> +        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) {
>>> +            return true;
>>> +        }
>>> +    }
>>> +
>>> +    return false;
>>> +}
>>> +
>>> +static struct ls_stateful_input
>>> +ls_stateful_get_input_data(struct engine_node *node)
>>> +{
>>> +    const struct northd_data *northd_data =
>>> +        engine_get_input_data("northd", node);
>>> +    const struct port_group_data *pg_data =
>>> +        engine_get_input_data("port_group", node);
>>> +
>>> +    return (struct ls_stateful_input) {
>>> +        .ls_port_groups = &pg_data->ls_port_groups,
>>> +        .ls_datapaths = &northd_data->ls_datapaths,
>>> +    };
>>> +}
>>> diff --git a/northd/en-ls-stateful.h b/northd/en-ls-stateful.h
>>> new file mode 100644
>>> index 0000000000..cba53e1f29
>>> --- /dev/null
>>> +++ b/northd/en-ls-stateful.h
>>> @@ -0,0 +1,81 @@
>>> +/*
>>> + * Copyright (c) 2023, Red Hat, Inc.
>>
>> 2024
> 
> Ack
> 
>>
>>> + *
>>> + * 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_LS_STATEFUL_H
>>> +#define EN_LS_STATEFUL_H 1
>>> +
>>> +#include <stdint.h>
>>> +
>>> +/* OVS includes. */
>>> +#include "lib/hmapx.h"
>>> +#include "openvswitch/hmap.h"
>>> +#include "sset.h"
>>> +
>>> +/* OVN includes. */
>>> +#include "lib/inc-proc-eng.h"
>>> +#include "lib/lb.h"
>>> +#include "lib/ovn-nb-idl.h"
>>> +#include "lib/ovn-sb-idl.h"
>>> +#include "lib/ovn-util.h"
>>> +#include "lib/stopwatch-names.h"
>>> +
>>> +struct ls_stateful_record {
>>> +    struct hmap_node key_node;
>>> +
>>> +    const struct ovn_datapath *od;
>>> +    bool has_stateful_acl;
>>> +    bool has_lb_vip;
>>> +    bool has_acls;
>>> +    uint64_t max_acl_tier;
>>> +};
>>> +
>>> +struct ls_stateful_table {
>>> +    struct hmap entries;
>>> +};
>>> +
>>> +#define LS_STATEFUL_TABLE_FOR_EACH(LS_STATEFUL_REC, TABLE) \
>>> +    HMAP_FOR_EACH (LS_STATEFUL_REC, key_node, &(TABLE)->entries)
>>> +
>>> +#define LS_STATEFUL_TABLE_FOR_EACH_IN_P(LS_STATEFUL_REC, JOBID, TABLE) \
>>> +    HMAP_FOR_EACH_IN_PARALLEL (LS_STATEFUL_REC, key_node, JOBID, \
>>> +                               &(TABLE)->entries)
>>> +
>>> +struct ls_stateful_tracked_data {
>>> +    /* Created or updated logical switch with LB and ACL data. */
>>> +    struct hmapx crupdated; /* Stores 'struct ls_stateful_record'. */
>>> +};
>>> +
>>> +struct ed_type_ls_stateful {
>>> +    struct ls_stateful_table table;
>>> +    struct ls_stateful_tracked_data trk_data;
>>> +};
>>> +
>>> +void *en_ls_stateful_init(struct engine_node *, struct engine_arg *);
>>> +void en_ls_stateful_cleanup(void *data);
>>> +void en_ls_stateful_clear_tracked_data(void *data);
>>> +void en_ls_stateful_run(struct engine_node *, void *data);
>>> +
>>> +bool ls_stateful_northd_handler(struct engine_node *, void *data);
>>> +bool ls_stateful_port_group_handler(struct engine_node *, void *data);
>>> +
>>> +const struct ls_stateful_record *ls_stateful_table_find(
>>> +    const struct ls_stateful_table *, const struct nbrec_logical_switch *);
>>> +
>>> +static inline bool
>>> +ls_stateful_has_tracked_data(struct ls_stateful_tracked_data *trk_data) {
>>> +    return !hmapx_is_empty(&trk_data->crupdated);
>>> +}
>>> +
>>> +#endif /* EN_LS_STATEFUL_H */
>>> diff --git a/northd/en-northd.c b/northd/en-northd.c
>>> index 546397f3dc..5143603f39 100644
>>> --- a/northd/en-northd.c
>>> +++ b/northd/en-northd.c
>>> @@ -171,7 +171,7 @@ northd_nb_logical_switch_handler(struct engine_node 
>>> *node,
>>>          return false;
>>>      }
>>>
>>> -    if (northd_has_lsps_in_tracked_data(&nd->trk_data)) {
>>> +    if (northd_has_tracked_data(&nd->trk_data)) {
>>>          engine_set_node_state(node, EN_UPDATED);
>>>      }
>>>
>>> diff --git a/northd/en-port-group.h b/northd/en-port-group.h
>>> index 3b28a23694..54014062ce 100644
>>> --- a/northd/en-port-group.h
>>> +++ b/northd/en-port-group.h
>>> @@ -48,6 +48,9 @@ struct ls_port_group_record {
>>>      struct sset ports;          /* Subset of 'nb_pg' ports in this record. 
>>> */
>>>  };
>>>
>>> +#define LS_PORT_GROUP_TABLE_FOR_EACH(LS_PG, TABLE) \
>>> +    HMAP_FOR_EACH (LS_PG, key_node, &(TABLE)->entries)
>>> +
>>>  void ls_port_group_table_init(struct ls_port_group_table *);
>>>  void ls_port_group_table_clear(struct ls_port_group_table *);
>>>  void ls_port_group_table_destroy(struct ls_port_group_table *);
>>> diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c
>>> index adb38dde78..9ce4279ee8 100644
>>> --- a/northd/inc-proc-northd.c
>>> +++ b/northd/inc-proc-northd.c
>>> @@ -33,6 +33,7 @@
>>>  #include "en-lb-data.h"
>>>  #include "en-lr-stateful.h"
>>>  #include "en-lr-nat.h"
>>> +#include "en-ls-stateful.h"
>>>  #include "en-northd.h"
>>>  #include "en-lflow.h"
>>>  #include "en-northd-output.h"
>>> @@ -150,6 +151,7 @@ static ENGINE_NODE(sync_to_sb_pb, "sync_to_sb_pb");
>>>  static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lb_data, "lb_data");
>>>  static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lr_nat, "lr_nat");
>>>  static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lr_stateful, "lr_stateful");
>>> +static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(ls_stateful, "ls_stateful");
>>>
>>>  void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
>>>                            struct ovsdb_idl_loop *sb)
>>> @@ -200,6 +202,10 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
>>>      engine_add_input(&en_lr_stateful, &en_lb_data,
>>>                       lr_stateful_lb_data_handler);
>>>
>>> +    engine_add_input(&en_ls_stateful, &en_northd, 
>>> ls_stateful_northd_handler);
>>> +    engine_add_input(&en_ls_stateful, &en_port_group,
>>> +                     ls_stateful_port_group_handler);
>>> +
>>>      engine_add_input(&en_mac_binding_aging, &en_nb_nb_global, NULL);
>>>      engine_add_input(&en_mac_binding_aging, &en_sb_mac_binding, NULL);
>>>      engine_add_input(&en_mac_binding_aging, &en_northd, NULL);
>>> @@ -222,6 +228,7 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
>>>      engine_add_input(&en_lflow, &en_sb_multicast_group, NULL);
>>>      engine_add_input(&en_lflow, &en_sb_igmp_group, NULL);
>>>      engine_add_input(&en_lflow, &en_lr_stateful, NULL);
>>> +    engine_add_input(&en_lflow, &en_ls_stateful, NULL);
>>>      engine_add_input(&en_lflow, &en_northd, lflow_northd_handler);
>>>      engine_add_input(&en_lflow, &en_port_group, lflow_port_group_handler);
>>>
>>> diff --git a/northd/northd.c b/northd/northd.c
>>> index f56a7c5ea4..68f2b0bab4 100644
>>> --- a/northd/northd.c
>>> +++ b/northd/northd.c
>>> @@ -46,6 +46,7 @@
>>>  #include "en-lb-data.h"
>>>  #include "en-lr-nat.h"
>>>  #include "en-lr-stateful.h"
>>> +#include "en-ls-stateful.h"
>>>  #include "lib/ovn-parallel-hmap.h"
>>>  #include "ovn/actions.h"
>>>  #include "ovn/features.h"
>>> @@ -576,7 +577,7 @@ lb_group_has_vip(const struct nbrec_load_balancer_group 
>>> *lb_group)
>>>  }
>>>
>>>  static bool
>>> -ls_has_lb_vip(struct ovn_datapath *od)
>>> +ls_has_lb_vip(const struct ovn_datapath *od)
>>>  {
>>>      for (size_t i = 0; i < od->nbs->n_load_balancer; i++) {
>>>          if (lb_has_vip(od->nbs->load_balancer[i])) {
>>> @@ -593,7 +594,7 @@ ls_has_lb_vip(struct ovn_datapath *od)
>>>  }
>>>
>>>  static bool
>>> -lr_has_lb_vip(struct ovn_datapath *od)
>>> +lr_has_lb_vip(const struct ovn_datapath *od)
>>>  {
>>>      for (size_t i = 0; i < od->nbr->n_load_balancer; i++) {
>>>          if (lb_has_vip(od->nbr->load_balancer[i])) {
>>> @@ -609,13 +610,13 @@ lr_has_lb_vip(struct ovn_datapath *od)
>>>      return false;
>>>  }
>>>
>>> -static void
>>> -init_lb_for_datapath(struct ovn_datapath *od)
>>> +bool
>>> +od_has_lb_vip(const struct ovn_datapath *od)
>>>  {
>>>      if (od->nbs) {
>>> -        od->has_lb_vip = ls_has_lb_vip(od);
>>> +        return ls_has_lb_vip(od);
>>>      } else {
>>> -        od->has_lb_vip = lr_has_lb_vip(od);
>>> +        return lr_has_lb_vip(od);
>>>      }
>>>  }
>>>
>>> @@ -1065,7 +1066,6 @@ join_datapaths(const struct 
>>> nbrec_logical_switch_table *nbrec_ls_table,
>>>
>>>          init_ipam_info_for_datapath(od);
>>>          init_mcast_info_for_datapath(od);
>>> -        init_lb_for_datapath(od);
>>>      }
>>>
>>>      const struct nbrec_logical_router *nbr;
>>> @@ -1096,7 +1096,6 @@ join_datapaths(const struct 
>>> nbrec_logical_switch_table *nbrec_ls_table,
>>>              ovs_list_push_back(nb_only, &od->list);
>>>          }
>>>          init_mcast_info_for_datapath(od);
>>> -        init_lb_for_datapath(od);
>>>          if (smap_get(&od->nbr->options, "chassis")) {
>>>              od->is_gw_router = true;
>>>          }
>>> @@ -2583,7 +2582,8 @@ get_nat_addresses(const struct ovn_port *op, size_t 
>>> *n, bool routable_only,
>>>      size_t n_nats = 0;
>>>      struct eth_addr mac;
>>>      if (!op || !op->nbrp || !op->od || !op->od->nbr
>>> -        || (!op->od->nbr->n_nat && !op->od->has_lb_vip)
>>> +        || (!op->od->nbr->n_nat && (!lr_stateful_rec
>>> +                                    || !lr_stateful_rec->has_lb_vip))
>>
>> IMO this is very hard to read.  What about a simple inline function in
>> en-lr-stateful.h to do this instead?  E.g.:
>>
>> static inline bool
>> lr_stateful_rec_has_lb_vip(const struct lr_stateful_record* lr_rec)
>> {
>>     return lr_rec && lr_rec->has_lb_vip;
>> }
> 
> Ack
> 
> 
>>
>>>          || !eth_addr_from_string(op->nbrp->mac, &mac)) {
>>>          *n = n_nats;
>>>          return NULL;
>>> @@ -3830,7 +3830,7 @@ build_lrouter_lbs_check(const struct ovn_datapaths 
>>> *lr_datapaths)
>>>      HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) {
>>>          ovs_assert(od->nbr);
>>>
>>> -        if (od->has_lb_vip && od->n_l3dgw_ports > 1
>>> +        if (od_has_lb_vip(od) && od->n_l3dgw_ports > 1
>>
>> This walks all LBs applied to the router again.  It's probably fine to
>> just query the lr_stateful_rec associated to this router (it's O(1) to
>> do that).
> 
> build_lrouter_lbs_check() is part of the northd engine and hence we
> can't use the lr_stateful_rec here
> as en_lr_stateful is not the input node to en_northd engine node.  Its
> actually the other way.
> 

Ah, right, I see now.

> This function only prints warning log.  Shall we move this instead to
> lr_stateful.c ?

Yes, that'd be great.

> 
> I'll address all other comments and add your Acked-by.  Let me know if
> that's not fine as I can't address the above comment.
> 

It's fine if we move the check to en-lr-stateful.c.

Thanks,
Dumitru

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

Reply via email to