Message ID | 20231026181557.3367139-1-numans@ovn.org |
---|---|
State | Changes Requested |
Headers | show |
Series | northd lflow incremental processing | expand |
Context | Check | Description |
---|---|---|
ovsrobot/apply-robot | warning | apply and check: warning |
ovsrobot/github-robot-_Build_and_Test | success | github build: passed |
ovsrobot/github-robot-_ovn-kubernetes | success | github build: passed |
On Thu, Oct 26, 2023 at 11:17 AM <numans@ovn.org> wrote: > > From: Numan Siddique <numans@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 > - NB logical switch node > - Port group node > > A record for each logical switch is maintained in the 'ls_lbacls' > 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; The node name indicates it contains LBs and ACLs of each LS, but it is actually about the stateful related flags. So I think it is better to be renamed to avoid confusion. > > This engine node becomes an input to 'lflow' node. > > Signed-off-by: Numan Siddique <numans@ovn.org> > --- > lib/stopwatch-names.h | 1 + > northd/automake.mk | 2 + > northd/en-lflow.c | 4 + > northd/en-lr-lb-nat-data.c | 8 +- > northd/en-lr-lb-nat-data.h | 2 + > northd/en-ls-lb-acls.c | 527 +++++++++++++++++++++++++++++++++++++ > northd/en-ls-lb-acls.h | 88 +++++++ > northd/en-port-group.h | 3 + > northd/inc-proc-northd.c | 9 + > northd/northd.c | 271 +++++++++---------- > northd/northd.h | 7 +- > 11 files changed, 776 insertions(+), 146 deletions(-) > create mode 100644 northd/en-ls-lb-acls.c > create mode 100644 northd/en-ls-lb-acls.h > > diff --git a/lib/stopwatch-names.h b/lib/stopwatch-names.h > index 7d85acdaea..8b0018a593 100644 > --- a/lib/stopwatch-names.h > +++ b/lib/stopwatch-names.h > @@ -34,5 +34,6 @@ > #define SYNC_METERS_RUN_STOPWATCH_NAME "sync_meters_run" > #define LR_NAT_RUN_STOPWATCH_NAME "lr_nat_run" > #define LR_LB_NAT_DATA_RUN_STOPWATCH_NAME "lr_lb_nat_data" > +#define LS_LBACLS_RUN_STOPWATCH_NAME "lr_lb_acls" > > #endif > diff --git a/northd/automake.mk b/northd/automake.mk > index 4116c487df..4593654726 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-lb-nat-data.c \ > northd/en-lr-lb-nat-data.h \ > + northd/en-ls-lb-acls.c \ > + northd/en-ls-lb-acls.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 229f4be1d0..648a477916 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-lb-nat-data.h" > +#include "en-ls-lb-acls.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_lb_nat_data *lr_lb_nat_data = > engine_get_input_data("lr_lb_nat_data", node); > + struct ed_type_ls_lbacls *ls_lbacls_data = > + engine_get_input_data("ls_lbacls", 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_lbnats = &lr_lb_nat_data->lr_lbnats; > + lflow_input->ls_lbacls = &ls_lbacls_data->ls_lbacls; > 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-lb-nat-data.c b/northd/en-lr-lb-nat-data.c > index 19b638ce0b..d816d2321d 100644 > --- a/northd/en-lr-lb-nat-data.c > +++ b/northd/en-lr-lb-nat-data.c > @@ -299,9 +299,11 @@ lr_lb_nat_data_lb_data_handler(struct engine_node *node, void *data_) > if (!hmapx_is_empty(&data->tracked_data.crupdated)) { > struct hmapx_node *hmapx_node; > /* For all the modified lr_lb_nat_data records (re)build the > - * vip nats. */ > + * vip nats and re-evaluate 'has_lb_vip'. */ > HMAPX_FOR_EACH (hmapx_node, &data->tracked_data.crupdated) { > - lr_lb_nat_data_build_vip_nats(hmapx_node->data); > + lr_lbnat_rec = hmapx_node->data; > + lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); > + lr_lbnat_rec->has_lb_vip = od_has_lb_vip(lr_lbnat_rec->od); Changes in this module should belong to an earlier patch instead of this one? > } > > data->tracked = true; > @@ -523,6 +525,8 @@ lr_lb_nat_data_record_init(struct lr_lb_nat_data_record *lr_lbnat_rec, > if (!nbr->n_nat) { > lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); > } > + > + lr_lbnat_rec->has_lb_vip = od_has_lb_vip(lr_lbnat_rec->od); > } > > static struct lr_lb_nat_data_input > diff --git a/northd/en-lr-lb-nat-data.h b/northd/en-lr-lb-nat-data.h > index ffe41cad73..ac21d28a57 100644 > --- a/northd/en-lr-lb-nat-data.h > +++ b/northd/en-lr-lb-nat-data.h > @@ -39,6 +39,8 @@ struct lr_lb_nat_data_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-lb-acls.c b/northd/en-ls-lb-acls.c > new file mode 100644 > index 0000000000..1ba7ecb3e2 > --- /dev/null > +++ b/northd/en-ls-lb-acls.c > @@ -0,0 +1,527 @@ > +/* > + * 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 <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-lb-acls.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_lbacls); > + > +/* Static function declarations. */ > +static void ls_lbacls_table_init(struct ls_lbacls_table *); > +static void ls_lbacls_table_clear(struct ls_lbacls_table *); > +static void ls_lbacls_table_destroy(struct ls_lbacls_table *); > +static struct ls_lbacls_record *ls_lbacls_table_find_( > + const struct ls_lbacls_table *, const struct nbrec_logical_switch *); > +static void ls_lbacls_table_build(struct ls_lbacls_table *, > + const struct ovn_datapaths *ls_datapaths, > + const struct ls_port_group_table *); > + > +static struct ls_lbacls_input ls_lbacls_get_input_data( > + struct engine_node *); > + > +static struct ls_lbacls_record *ls_lbacls_record_create( > + struct ls_lbacls_table *, > + const struct ovn_datapath *, > + const struct ls_port_group_table *); > +static void ls_lbacls_record_destroy(struct ls_lbacls_record *); > +static void ls_lbacls_record_init( > + struct ls_lbacls_record *, > + const struct ovn_datapath *, > + const struct ls_port_group *, > + const struct ls_port_group_table *); > +static void ls_lbacls_record_reinit( > + struct ls_lbacls_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_lbacls_record_set_acl_flags(struct ls_lbacls_record *, > + const struct ovn_datapath *, > + const struct ls_port_group *, > + const struct ls_port_group_table *); > +static bool ls_lbacls_record_set_acl_flags_(struct ls_lbacls_record *, > + struct nbrec_acl **, > + size_t n_acls); > +static struct ls_lbacls_input ls_lbacls_get_input_data(struct engine_node *); > +static bool is_ls_acls_changed(const struct nbrec_logical_switch *); > +static bool is_acls_seqno_changed(struct nbrec_acl **, size_t n_nb_acls); > + > + > +/* public functions. */ > +const struct ls_lbacls_record * > +ls_lbacls_table_find( > + const struct ls_lbacls_table *table, > + const struct nbrec_logical_switch *nbs) > +{ > + return ls_lbacls_table_find_(table, nbs); > +} > + > +void * > +en_ls_lbacls_init(struct engine_node *node OVS_UNUSED, > + struct engine_arg *arg OVS_UNUSED) > +{ > + struct ed_type_ls_lbacls *data = xzalloc(sizeof *data); > + ls_lbacls_table_init(&data->ls_lbacls); > + hmapx_init(&data->tracked_data.crupdated); > + hmapx_init(&data->tracked_data.deleted); > + return data; > +} > + > +void > +en_ls_lbacls_cleanup(void *data_) > +{ > + struct ed_type_ls_lbacls *data = > + (struct ed_type_ls_lbacls *) data_; > + ls_lbacls_table_destroy(&data->ls_lbacls); > + hmapx_destroy(&data->tracked_data.crupdated); > + hmapx_destroy(&data->tracked_data.deleted); > +} > + > +void > +en_ls_lbacls_clear_tracked_data(void *data_) > +{ > + struct ed_type_ls_lbacls *data = > + (struct ed_type_ls_lbacls *) data_; > + > + struct hmapx_node *hmapx_node; > + HMAPX_FOR_EACH_SAFE (hmapx_node, &data->tracked_data.deleted) { > + ls_lbacls_record_destroy(hmapx_node->data); > + hmapx_delete(&data->tracked_data.deleted, hmapx_node); > + } > + > + hmapx_clear(&data->tracked_data.crupdated); > + data->tracked = false; > +} > + > +void > +en_ls_lbacls_run(struct engine_node *node, void *data_) > +{ > + struct ls_lbacls_input input_data = ls_lbacls_get_input_data(node); > + struct ed_type_ls_lbacls *data = data_; > + > + stopwatch_start(LS_LBACLS_RUN_STOPWATCH_NAME, time_msec()); > + > + ls_lbacls_table_clear(&data->ls_lbacls); > + ls_lbacls_table_build(&data->ls_lbacls, input_data.ls_datapaths, > + input_data.ls_port_groups); > + > + data->tracked = false; > + stopwatch_stop(LS_LBACLS_RUN_STOPWATCH_NAME, time_msec()); > + engine_set_node_state(node, EN_UPDATED); > +} > + > +/* Handler functions. */ > +bool > +ls_lbacls_northd_handler(struct engine_node *node, void *data_) > +{ > + struct northd_data *northd_data = engine_get_input_data("northd", node); > + if (!northd_data->change_tracked) { > + return false; > + } > + > + struct northd_tracked_data *nd_changes = &northd_data->trk_northd_changes; > + struct ls_lbacls_input input_data = ls_lbacls_get_input_data(node); > + struct ls_lbacls_record *ls_lbacls_rec; > + struct ed_type_ls_lbacls *data = data_; > + const struct ovn_datapath *od; > + struct hmapx_node *hmapx_node; > + > + HMAPX_FOR_EACH (hmapx_node, &nd_changes->ls_with_changed_lbs.crupdated) { > + od = hmapx_node->data; > + > + ls_lbacls_rec = ls_lbacls_table_find_(&data->ls_lbacls, od->nbs); > + if (!ls_lbacls_rec) { > + ls_lbacls_rec = ls_lbacls_record_create(&data->ls_lbacls, od, > + input_data.ls_port_groups); > + } else { > + ls_lbacls_record_reinit(ls_lbacls_rec, NULL, > + input_data.ls_port_groups); > + } > + > + /* Add the ls_lbacls_rec to the tracking data. */ > + hmapx_add(&data->tracked_data.crupdated, ls_lbacls_rec); > + } > + > + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { > + data->tracked = true; > + engine_set_node_state(node, EN_UPDATED); > + } > + > + return true; > +} > + > +bool > +ls_lbacls_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_lbacls_rec. > + * This is still better than returning false. */ > + struct ls_lbacls_input input_data = ls_lbacls_get_input_data(node); > + struct ed_type_ls_lbacls *data = data_; > + const struct ls_port_group *ls_pg; > + > + LS_PORT_GROUP_TABLE_FOR_EACH (ls_pg, input_data.ls_port_groups) { > + struct ls_lbacls_record *ls_lbacls_rec = > + ls_lbacls_table_find_(&data->ls_lbacls, ls_pg->nbs); > + > + bool modified = false; > + if (!ls_lbacls_rec) { > + const struct ovn_datapath *od; > + od = ovn_datapath_find(&input_data.ls_datapaths->datapaths, > + &ls_pg->nbs->header_.uuid); > + ovs_assert(od); > + ls_lbacls_rec = ls_lbacls_record_create(&data->ls_lbacls, od, > + input_data.ls_port_groups); > + modified = true; > + } else { > + bool had_stateful_acl = ls_lbacls_rec->has_stateful_acl; > + uint64_t max_acl_tier = ls_lbacls_rec->max_acl_tier; > + bool had_acls = ls_lbacls_rec->has_acls; > + > + ls_lbacls_record_reinit(ls_lbacls_rec, ls_pg, > + input_data.ls_port_groups); > + > + if ((had_stateful_acl != ls_lbacls_rec->has_stateful_acl) > + || (had_acls != ls_lbacls_rec->has_acls) > + || max_acl_tier != ls_lbacls_rec->max_acl_tier) { > + modified = true; > + } > + } > + > + if (modified) { > + /* Add the ls_lbacls_rec to the tracking data. */ > + hmapx_add(&data->tracked_data.crupdated, ls_lbacls_rec); > + } > + } > + > + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { > + data->tracked = true; > + engine_set_node_state(node, EN_UPDATED); > + } > + > + return true; > +} > + > +bool > +ls_lbacls_logical_switch_handler(struct engine_node *node, void *data_) > +{ > + struct ls_lbacls_input input_data = ls_lbacls_get_input_data(node); > + const struct nbrec_logical_switch *nbs; > + struct ed_type_ls_lbacls *data = data_; > + > + NBREC_LOGICAL_SWITCH_TABLE_FOR_EACH_TRACKED (nbs, > + input_data.nbrec_logical_switch_table) { > + if (!is_ls_acls_changed(nbs)) { > + continue; > + } > + > + struct ls_lbacls_record *ls_lbacls_rec = > + ls_lbacls_table_find_(&data->ls_lbacls, nbs); > + > + if (nbrec_logical_switch_is_deleted(nbs)) { > + if (ls_lbacls_rec) { > + /* Remove the record from the entries. */ > + hmap_remove(&data->ls_lbacls.entries, > + &ls_lbacls_rec->key_node); > + > + /* Add the ls_lbacls_rec to the tracking data. */ > + hmapx_add(&data->tracked_data.deleted, ls_lbacls_rec); > + } > + } else { > + if (!ls_lbacls_rec) { > + const struct ovn_datapath *od; > + od = ovn_datapath_find(&input_data.ls_datapaths->datapaths, > + &nbs->header_.uuid); > + ovs_assert(od); > + ls_lbacls_rec = ls_lbacls_record_create(&data->ls_lbacls, od, > + input_data.ls_port_groups); > + } else { > + ls_lbacls_record_reinit(ls_lbacls_rec, NULL, > + input_data.ls_port_groups); > + } > + > + /* Add the ls_lbacls_rec to the tracking data. */ > + hmapx_add(&data->tracked_data.crupdated, ls_lbacls_rec); > + } > + } > + > + if (!hmapx_is_empty(&data->tracked_data.crupdated) > + || !hmapx_is_empty(&data->tracked_data.deleted)) { > + data->tracked = true; > + engine_set_node_state(node, EN_UPDATED); > + } > + > + return true; > +} > + > +/* static functions. */ > +static void > +ls_lbacls_table_init(struct ls_lbacls_table *table) > +{ > + *table = (struct ls_lbacls_table) { > + .entries = HMAP_INITIALIZER(&table->entries), > + }; > +} > + > +static void > +ls_lbacls_table_destroy(struct ls_lbacls_table *table) > +{ > + ls_lbacls_table_clear(table); > + hmap_destroy(&table->entries); > +} > + > +static void > +ls_lbacls_table_clear(struct ls_lbacls_table *table) > +{ > + struct ls_lbacls_record *ls_lbacls_rec; > + HMAP_FOR_EACH_POP (ls_lbacls_rec, key_node, &table->entries) { > + ls_lbacls_record_destroy(ls_lbacls_rec); > + } > +} > + > +static void > +ls_lbacls_table_build(struct ls_lbacls_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_lbacls_record_create(table, od, ls_pgs); > + } > +} > + > +struct ls_lbacls_record * > +ls_lbacls_table_find_(const struct ls_lbacls_table *table, > + const struct nbrec_logical_switch *nbs) > +{ > + struct ls_lbacls_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_lbacls_record * > +ls_lbacls_record_create(struct ls_lbacls_table *table, > + const struct ovn_datapath *od, > + const struct ls_port_group_table *ls_pgs) > +{ > + struct ls_lbacls_record *ls_lbacls_rec = xzalloc(sizeof *ls_lbacls_rec); > + ls_lbacls_rec->od = od; > + ls_lbacls_record_init(ls_lbacls_rec, od, NULL, ls_pgs); > + > + hmap_insert(&table->entries, &ls_lbacls_rec->key_node, > + uuid_hash(&ls_lbacls_rec->od->nbs->header_.uuid)); > + > + return ls_lbacls_rec; > +} > + > +static void > +ls_lbacls_record_destroy(struct ls_lbacls_record *ls_lbacls_rec) > +{ > + free(ls_lbacls_rec); > +} > + > +static void > +ls_lbacls_record_init(struct ls_lbacls_record *ls_lbacls_rec, > + const struct ovn_datapath *od, > + const struct ls_port_group *ls_pg, > + const struct ls_port_group_table *ls_pgs) > +{ > + ls_lbacls_rec->has_lb_vip = ls_has_lb_vip(od); > + ls_lbacls_record_set_acl_flags(ls_lbacls_rec, od, ls_pg, ls_pgs); > +} > + > +static void > +ls_lbacls_record_reinit(struct ls_lbacls_record *ls_lbacls_rec, > + const struct ls_port_group *ls_pg, > + const struct ls_port_group_table *ls_pgs) > +{ > + ls_lbacls_record_init(ls_lbacls_rec, ls_lbacls_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_lbacls_record_set_acl_flags(struct ls_lbacls_record *ls_lbacls_rec, > + const struct ovn_datapath *od, > + const struct ls_port_group *ls_pg, > + const struct ls_port_group_table *ls_pgs) > +{ > + ls_lbacls_rec->has_stateful_acl = false; > + ls_lbacls_rec->max_acl_tier = 0; > + ls_lbacls_rec->has_acls = false; > + > + if (ls_lbacls_record_set_acl_flags_(ls_lbacls_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_lbacls_record_set_acl_flags_(ls_lbacls_rec, > + ls_pg_rec->nb_pg->acls, > + ls_pg_rec->nb_pg->n_acls)) { > + return; > + } > + } > +} > + > +static bool > +ls_lbacls_record_set_acl_flags_(struct ls_lbacls_record *ls_lbacls_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_lbacls record. A false return indicates that > + * further ACLs should be explored in case more flags need to be > + * set on ls_lbacls record. > + */ > + if (!n_acls) { > + return false; > + } > + > + ls_lbacls_rec->has_acls = true; > + for (size_t i = 0; i < n_acls; i++) { > + const struct nbrec_acl *acl = acls[i]; > + if (acl->tier > ls_lbacls_rec->max_acl_tier) { > + ls_lbacls_rec->max_acl_tier = acl->tier; > + } > + if (!ls_lbacls_rec->has_stateful_acl > + && !strcmp(acl->action, "allow-related")) { > + ls_lbacls_rec->has_stateful_acl = true; > + } > + if (ls_lbacls_rec->has_stateful_acl && > + ls_lbacls_rec->max_acl_tier == > + nbrec_acl_col_tier.type.value.integer.max) { > + return true; > + } > + } > + > + return false; > +} > + > +static struct ls_lbacls_input > +ls_lbacls_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_lbacls_input) { > + .nbrec_logical_switch_table = > + EN_OVSDB_GET(engine_get_input("NB_logical_switch", node)), > + .ls_port_groups = &pg_data->ls_port_groups, > + .ls_datapaths = &northd_data->ls_datapaths, > + }; > +} > + > +static bool > +is_acls_seqno_changed(struct nbrec_acl **nb_acls, size_t n_nb_acls) > +{ > + for (size_t i = 0; i < n_nb_acls; i++) { > + if (nbrec_acl_row_get_seqno(nb_acls[i], > + OVSDB_IDL_CHANGE_MODIFY) > 0) { > + return true; > + } > + } > + > + return false; > +} > + > +static bool > +is_ls_acls_changed(const struct nbrec_logical_switch *nbs) { > + return (nbrec_logical_switch_is_new(nbs) > + || nbrec_logical_switch_is_deleted(nbs) > + || nbrec_logical_switch_is_updated(nbs, > + NBREC_LOGICAL_SWITCH_COL_ACLS) > + || is_acls_seqno_changed(nbs->acls, nbs->n_acls)); > +} > diff --git a/northd/en-ls-lb-acls.h b/northd/en-ls-lb-acls.h > new file mode 100644 > index 0000000000..ccb75e40e8 > --- /dev/null > +++ b/northd/en-ls-lb-acls.h > @@ -0,0 +1,88 @@ > +/* > + * 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_LS_LB_ACL_H > +#define EN_LS_LB_ACL_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_lbacls_record { > + struct hmap_node key_node; > + > + const struct ovn_datapath *od; Such reference is error-prone. In the en-flow node it directly uses this reference to access other data of the ovn_datapath, but the dependency is not tracked and propagated through this node. For example, ls_lbacls_rec->od->nbs->acls is used in build_acls but ACL changes are not propagated through this node. > + bool has_stateful_acl; > + bool has_lb_vip; > + bool has_acls; > + uint64_t max_acl_tier; > +}; > + > +struct ls_lbacls_table { > + struct hmap entries; > +}; > + > +#define LS_LBACLS_TABLE_FOR_EACH(LS_LBACLS_REC, TABLE) \ > + HMAP_FOR_EACH (LS_LBACLS_REC, key_node, &(TABLE)->entries) > + > +#define LS_LBACLS_TABLE_FOR_EACH_IN_P(LS_LBACLS_REC, JOBID, TABLE) \ > + HMAP_FOR_EACH_IN_PARALLEL (LS_LBACLS_REC, key_node, JOBID, \ > + &(TABLE)->entries) > + > +struct ls_lbacls_tracked_data { > + /* Created or updated logical switch with LB and ACL data. */ > + struct hmapx crupdated; /* Stores 'struct ls_lbacls_record'. */ > + > + /* Deleted logical switch with LB and ACL data. */ > + struct hmapx deleted; /* Stores 'struct ls_lbacls_record'. */ > +}; > + > +struct ed_type_ls_lbacls { > + struct ls_lbacls_table ls_lbacls; > + > + bool tracked; > + struct ls_lbacls_tracked_data tracked_data; > +}; > + > +struct ls_lbacls_input { > + const struct nbrec_logical_switch_table *nbrec_logical_switch_table; > + const struct ls_port_group_table *ls_port_groups; > + const struct ovn_datapaths *ls_datapaths; > +}; nit: this seems should be module internal and should move to the .c Thanks, Han > + > +void *en_ls_lbacls_init(struct engine_node *, struct engine_arg *); > +void en_ls_lbacls_cleanup(void *data); > +void en_ls_lbacls_clear_tracked_data(void *data); > +void en_ls_lbacls_run(struct engine_node *, void *data); > + > +bool ls_lbacls_northd_handler(struct engine_node *, void *data); > +bool ls_lbacls_port_group_handler(struct engine_node *, void *data); > +bool ls_lbacls_logical_switch_handler(struct engine_node *, void *data); > + > +const struct ls_lbacls_record *ls_lbacls_table_find( > + const struct ls_lbacls_table *, const struct nbrec_logical_switch *); > + > +#endif /* EN_LS_LB_ACL_H */ > 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 84627070a8..ab4af92aeb 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-lb-nat-data.h" > #include "en-lr-nat.h" > +#include "en-ls-lb-acls.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_lb_nat_data, "lr_lb_nat_data"); > +static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(ls_lbacls, "ls_lbacls"); > > void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > struct ovsdb_idl_loop *sb) > @@ -205,6 +207,12 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > engine_add_input(&en_lr_lb_nat_data, &en_lb_data, > lr_lb_nat_data_lb_data_handler); > > + engine_add_input(&en_ls_lbacls, &en_northd, ls_lbacls_northd_handler); > + engine_add_input(&en_ls_lbacls, &en_port_group, > + ls_lbacls_port_group_handler); > + engine_add_input(&en_ls_lbacls, &en_nb_logical_switch, > + ls_lbacls_logical_switch_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); > @@ -229,6 +237,7 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > engine_add_input(&en_lflow, &en_northd, lflow_northd_handler); > engine_add_input(&en_lflow, &en_port_group, lflow_port_group_handler); > engine_add_input(&en_lflow, &en_lr_lb_nat_data, NULL); > + engine_add_input(&en_lflow, &en_ls_lbacls, NULL); > > engine_add_input(&en_sync_to_sb_addr_set, &en_nb_address_set, > sync_to_sb_addr_set_nb_address_set_handler); > diff --git a/northd/northd.c b/northd/northd.c > index c8a224d3cd..924f5cd7e0 100644 > --- a/northd/northd.c > +++ b/northd/northd.c > @@ -45,6 +45,7 @@ > #include "en-lb-data.h" > #include "en-lr-nat.h" > #include "en-lr-lb-nat-data.h" > +#include "en-ls-lb-acls.h" > #include "lib/ovn-parallel-hmap.h" > #include "ovn/actions.h" > #include "ovn/features.h" > @@ -575,7 +576,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])) { > @@ -592,7 +593,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])) { > @@ -608,13 +609,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); > } > } > > @@ -1058,7 +1059,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; > @@ -1089,7 +1089,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; > } > @@ -2570,7 +2569,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_lbnat_rec > + || !lr_lbnat_rec->has_lb_vip)) > || !eth_addr_from_string(op->nbrp->mac, &mac)) { > *n = n_nats; > return NULL; > @@ -3817,7 +3817,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 > && !smap_get(&od->nbr->options, "chassis")) { > static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); > VLOG_WARN_RL(&rl, "Load-balancers are configured on logical " > @@ -5441,7 +5441,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > BITMAP_FOR_EACH_1 (index, ods_size(ls_datapaths), > lb_dps->nb_ls_map) { > od = ls_datapaths->array[index]; > - init_lb_for_datapath(od); > > /* Add the ls datapath to the northd tracked data. */ > hmapx_add(&nd_changes->ls_with_changed_lbs.crupdated, od); > @@ -5524,9 +5523,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > } > } > > - /* Re-evaluate 'od->has_lb_vip' */ > - init_lb_for_datapath(od); > - > /* Add the ls datapath to the northd tracked data. */ > hmapx_add(&nd_changes->ls_with_changed_lbs.crupdated, od); > } > @@ -5564,9 +5560,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > } > } > > - /* Re-evaluate 'od->has_lb_vip' */ > - init_lb_for_datapath(od); > - > /* Add the lr datapath to the northd tracked data. */ > hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); > } > @@ -5581,8 +5574,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > BITMAP_FOR_EACH_1 (index, ods_size(ls_datapaths), > lb_dps->nb_ls_map) { > od = ls_datapaths->array[index]; > - /* Re-evaluate 'od->has_lb_vip' */ > - init_lb_for_datapath(od); > > /* Add the ls datapath to the northd tracked data. */ > hmapx_add(&nd_changes->ls_with_changed_lbs.crupdated, od); > @@ -5591,8 +5582,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > BITMAP_FOR_EACH_1 (index, ods_size(lr_datapaths), > lb_dps->nb_lr_map) { > od = lr_datapaths->array[index]; > - /* Re-evaluate 'od->has_lb_vip' */ > - init_lb_for_datapath(od); > > /* Add the lr datapath to the northd tracked data. */ > hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); > @@ -5618,9 +5607,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > od = lbgrp_dps->lr[i]; > ovn_lb_datapaths_add_lr(lb_dps, 1, &od); > > - /* Re-evaluate 'od->has_lb_vip' */ > - init_lb_for_datapath(od); > - > /* Add the lr datapath to the northd tracked data. */ > hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); > } > @@ -5629,9 +5615,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > od = lbgrp_dps->ls[i]; > ovn_lb_datapaths_add_ls(lb_dps, 1, &od); > > - /* Re-evaluate 'od->has_lb_vip' */ > - init_lb_for_datapath(od); > - > /* Add the ls datapath to the northd tracked data. */ > hmapx_add(&nd_changes->ls_with_changed_lbs.crupdated, od); > } > @@ -6573,63 +6556,6 @@ build_dhcpv6_action(struct ovn_port *op, struct in6_addr *offer_ip, > return true; > } > > -static bool > -od_set_acl_flags(struct ovn_datapath *od, struct nbrec_acl **acls, > - size_t n_acls) > -{ > - /* A true return indicates that there are no possible ACL flags > - * left to set on od. A false return indicates that further ACLs > - * should be explored in case more flags need to be set on od > - */ > - if (!n_acls) { > - return false; > - } > - > - od->has_acls = true; > - for (size_t i = 0; i < n_acls; i++) { > - const struct nbrec_acl *acl = acls[i]; > - if (acl->tier > od->max_acl_tier) { > - od->max_acl_tier = acl->tier; > - } > - if (!od->has_stateful_acl && !strcmp(acl->action, "allow-related")) { > - od->has_stateful_acl = true; > - } > - if (od->has_stateful_acl && > - od->max_acl_tier == nbrec_acl_col_tier.type.value.integer.max) { > - return true; > - } > - } > - > - return false; > -} > - > -static void > -ls_get_acl_flags(struct ovn_datapath *od, > - const struct ls_port_group_table *ls_port_groups) > -{ > - od->has_acls = false; > - od->has_stateful_acl = false; > - od->max_acl_tier = 0; > - > - if (od_set_acl_flags(od, od->nbs->acls, od->nbs->n_acls)) { > - return; > - } > - > - const struct ls_port_group *ls_pg = > - ls_port_group_table_find(ls_port_groups, 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 (od_set_acl_flags(od, ls_pg_rec->nb_pg->acls, > - ls_pg_rec->nb_pg->n_acls)) { > - return; > - } > - } > -} > - > /* Adds the logical flows in the (in/out) check port sec stage only if > * - the lport is disabled or > * - lport is of type vtep - to skip the ingress pipeline. > @@ -6774,9 +6700,10 @@ build_lswitch_output_port_sec_od(struct ovn_datapath *od, > } > > static void > -skip_port_from_conntrack(struct ovn_datapath *od, struct ovn_port *op, > - enum ovn_stage in_stage, enum ovn_stage out_stage, > - uint16_t priority, struct hmap *lflows) > +skip_port_from_conntrack(const struct ovn_datapath *od, struct ovn_port *op, > + bool has_stateful_acl, enum ovn_stage in_stage, > + enum ovn_stage out_stage, uint16_t priority, > + struct hmap *lflows) > { > /* Can't use ct() for router ports. Consider the following configuration: > * lp1(10.0.0.2) on hostA--ls1--lr0--ls2--lp2(10.0.1.2) on hostB, For a > @@ -6789,7 +6716,7 @@ skip_port_from_conntrack(struct ovn_datapath *od, struct ovn_port *op, > * conntrack state across all chassis. */ > > const char *ingress_action = "next;"; > - const char *egress_action = od->has_stateful_acl > + const char *egress_action = has_stateful_acl > ? "next;" > : "ct_clear; next;"; > > @@ -6808,7 +6735,7 @@ skip_port_from_conntrack(struct ovn_datapath *od, struct ovn_port *op, > } > > static void > -build_stateless_filter(struct ovn_datapath *od, > +build_stateless_filter(const struct ovn_datapath *od, > const struct nbrec_acl *acl, > struct hmap *lflows) > { > @@ -6829,7 +6756,7 @@ build_stateless_filter(struct ovn_datapath *od, > } > > static void > -build_stateless_filters(struct ovn_datapath *od, > +build_stateless_filters(const struct ovn_datapath *od, > const struct ls_port_group_table *ls_port_groups, > struct hmap *lflows) > { > @@ -6859,9 +6786,7 @@ build_stateless_filters(struct ovn_datapath *od, > } > > static void > -build_pre_acls(struct ovn_datapath *od, > - const struct ls_port_group_table *ls_port_groups, > - struct hmap *lflows) > +build_pre_acls(struct ovn_datapath *od, struct hmap *lflows) > { > /* Ingress and Egress Pre-ACL Table (Priority 0): Packets are > * allowed by default. */ > @@ -6873,18 +6798,26 @@ build_pre_acls(struct ovn_datapath *od, > > ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, > "eth.src == $svc_monitor_mac", "next;"); > +} > + > +static void > +build_ls_lbacls_rec_pre_acls(const struct ls_lbacls_record *ls_lbacls_rec, > + const struct ls_port_group_table *ls_port_groups, > + struct hmap *lflows) > +{ > + const struct ovn_datapath *od = ls_lbacls_rec->od; > > /* If there are any stateful ACL rules in this datapath, we may > * send IP packets for some (allow) filters through the conntrack action, > * which handles defragmentation, in order to match L4 headers. */ > - if (od->has_stateful_acl) { > + if (ls_lbacls_rec->has_stateful_acl) { > for (size_t i = 0; i < od->n_router_ports; i++) { > - skip_port_from_conntrack(od, od->router_ports[i], > + skip_port_from_conntrack(od, od->router_ports[i], true, > S_SWITCH_IN_PRE_ACL, S_SWITCH_OUT_PRE_ACL, > 110, lflows); > } > for (size_t i = 0; i < od->n_localnet_ports; i++) { > - skip_port_from_conntrack(od, od->localnet_ports[i], > + skip_port_from_conntrack(od, od->localnet_ports[i], true, > S_SWITCH_IN_PRE_ACL, > S_SWITCH_OUT_PRE_ACL, > 110, lflows); > @@ -6922,7 +6855,7 @@ build_pre_acls(struct ovn_datapath *od, > REGBIT_CONNTRACK_DEFRAG" = 1; next;"); > ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 100, "ip", > REGBIT_CONNTRACK_DEFRAG" = 1; next;"); > - } else if (od->has_lb_vip) { > + } else if (ls_lbacls_rec->has_lb_vip) { > /* We'll build stateless filters if there are LB rules so that > * the stateless flows are not tracked in pre-lb. */ > build_stateless_filters(od, ls_port_groups, lflows); > @@ -7050,30 +6983,40 @@ build_pre_lb(struct ovn_datapath *od, const struct shash *meter_groups, > ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 0, "1", "next;"); > ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 0, "1", "next;"); > > + /* Do not send statless flows via conntrack */ > + ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110, > + REGBIT_ACL_STATELESS" == 1", "next;"); > + ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110, > + REGBIT_ACL_STATELESS" == 1", "next;"); > +} > + > +static void > +build_ls_lbacls_rec_pre_lb(const struct ls_lbacls_record *ls_lbacls_rec, > + struct hmap *lflows) > +{ > + const struct ovn_datapath *od = ls_lbacls_rec->od; > + > for (size_t i = 0; i < od->n_router_ports; i++) { > skip_port_from_conntrack(od, od->router_ports[i], > + ls_lbacls_rec->has_stateful_acl, > S_SWITCH_IN_PRE_LB, S_SWITCH_OUT_PRE_LB, > 110, lflows); > } > + > /* Localnet ports have no need for going through conntrack, unless > * the logical switch has a load balancer. Then, conntrack is necessary > * so that traffic arriving via the localnet port can be load > * balanced. > */ > - if (!od->has_lb_vip) { > + if (!ls_lbacls_rec->has_lb_vip) { > for (size_t i = 0; i < od->n_localnet_ports; i++) { > skip_port_from_conntrack(od, od->localnet_ports[i], > + ls_lbacls_rec->has_stateful_acl, > S_SWITCH_IN_PRE_LB, S_SWITCH_OUT_PRE_LB, > 110, lflows); > } > } > > - /* Do not sent statless flows via conntrack */ > - ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110, > - REGBIT_ACL_STATELESS" == 1", "next;"); > - ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110, > - REGBIT_ACL_STATELESS" == 1", "next;"); > - > /* 'REGBIT_CONNTRACK_NAT' is set to let the pre-stateful table send > * packet to conntrack for defragmentation and possibly for unNATting. > * > @@ -7104,7 +7047,7 @@ build_pre_lb(struct ovn_datapath *od, const struct shash *meter_groups, > * ingress pipeline if a load balancer is configured. We can now > * add a lflow to drop ct.inv packets. > */ > - if (od->has_lb_vip) { > + if (ls_lbacls_rec->has_lb_vip) { > ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, > 100, "ip", REGBIT_CONNTRACK_NAT" = 1; next;"); > ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, > @@ -7145,10 +7088,12 @@ build_pre_stateful(struct ovn_datapath *od, > } > > static void > -build_acl_hints(struct ovn_datapath *od, > +build_acl_hints(const struct ls_lbacls_record *ls_lbacls_rec, > const struct chassis_features *features, > struct hmap *lflows) > { > + const struct ovn_datapath *od = ls_lbacls_rec->od; > + > /* This stage builds hints for the IN/OUT_ACL stage. Based on various > * combinations of ct flags packets may hit only a subset of the logical > * flows in the IN/OUT_ACL stage. > @@ -7172,13 +7117,13 @@ build_acl_hints(struct ovn_datapath *od, > const char *match; > > /* In any case, advance to the next stage. */ > - if (!od->has_acls && !od->has_lb_vip) { > + if (!ls_lbacls_rec->has_acls && !ls_lbacls_rec->has_lb_vip) { > ovn_lflow_add(lflows, od, stage, UINT16_MAX, "1", "next;"); > } else { > ovn_lflow_add(lflows, od, stage, 0, "1", "next;"); > } > > - if (!od->has_stateful_acl && !od->has_lb_vip) { > + if (!ls_lbacls_rec->has_stateful_acl && !ls_lbacls_rec->has_lb_vip) { > continue; > } > > @@ -7314,10 +7259,10 @@ build_acl_log(struct ds *actions, const struct nbrec_acl *acl, > } > > static void > -consider_acl(struct hmap *lflows, struct ovn_datapath *od, > +consider_acl(struct hmap *lflows, const struct ovn_datapath *od, > const struct nbrec_acl *acl, bool has_stateful, > bool ct_masked_mark, const struct shash *meter_groups, > - struct ds *match, struct ds *actions) > + uint64_t max_acl_tier, struct ds *match, struct ds *actions) > { > const char *ct_blocked_match = ct_masked_mark > ? "ct_mark.blocked" > @@ -7354,7 +7299,7 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, > /* All ACLS will start by matching on their respective tier. */ > size_t match_tier_len = 0; > ds_clear(match); > - if (od->max_acl_tier) { > + if (max_acl_tier) { > ds_put_format(match, REG_ACL_TIER " == %"PRId64" && ", acl->tier); > match_tier_len = match->length; > } > @@ -7543,12 +7488,15 @@ ovn_update_ipv6_options(struct hmap *lr_ports) > #define IPV6_CT_OMIT_MATCH "nd || nd_ra || nd_rs || mldv1 || mldv2" > > static void > -build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, > +build_acl_action_lflows(const struct ls_lbacls_record *ls_lbacls_rec, > + struct hmap *lflows, > const char *default_acl_action, > const struct shash *meter_groups, > struct ds *match, > struct ds *actions) > { > + const struct ovn_datapath *od = ls_lbacls_rec->od; > + > enum ovn_stage stages [] = { > S_SWITCH_IN_ACL_ACTION, > S_SWITCH_IN_ACL_AFTER_LB_ACTION, > @@ -7559,7 +7507,7 @@ build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, > ds_put_cstr(actions, REGBIT_ACL_VERDICT_ALLOW " = 0; " > REGBIT_ACL_VERDICT_DROP " = 0; " > REGBIT_ACL_VERDICT_REJECT " = 0; "); > - if (od->max_acl_tier) { > + if (ls_lbacls_rec->max_acl_tier) { > ds_put_cstr(actions, REG_ACL_TIER " = 0; "); > } > > @@ -7567,7 +7515,7 @@ build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, > > for (size_t i = 0; i < ARRAY_SIZE(stages); i++) { > enum ovn_stage stage = stages[i]; > - if (!od->has_acls) { > + if (!ls_lbacls_rec->has_acls) { > ovn_lflow_add(lflows, od, stage, 0, "1", "next;"); > continue; > } > @@ -7602,7 +7550,7 @@ build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, > ovn_lflow_add(lflows, od, stage, 0, "1", ds_cstr(actions)); > > struct ds tier_actions = DS_EMPTY_INITIALIZER; > - for (size_t j = 0; j < od->max_acl_tier; j++) { > + for (size_t j = 0; j < ls_lbacls_rec->max_acl_tier; j++) { > ds_clear(match); > ds_put_format(match, REG_ACL_TIER " == %"PRIuSIZE, j); > ds_clear(&tier_actions); > @@ -7618,7 +7566,7 @@ build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, > } > > static void > -build_acl_log_related_flows(struct ovn_datapath *od, struct hmap *lflows, > +build_acl_log_related_flows(const struct ovn_datapath *od, struct hmap *lflows, > const struct nbrec_acl *acl, bool has_stateful, > bool ct_masked_mark, > const struct shash *meter_groups, > @@ -7691,15 +7639,19 @@ build_acl_log_related_flows(struct ovn_datapath *od, struct hmap *lflows, > } > > static void > -build_acls(struct ovn_datapath *od, const struct chassis_features *features, > +build_acls(const struct ls_lbacls_record *ls_lbacls_rec, > + const struct chassis_features *features, > struct hmap *lflows, > const struct ls_port_group_table *ls_port_groups, > const struct shash *meter_groups) > { > + const struct ovn_datapath *od = ls_lbacls_rec->od; > + > const char *default_acl_action = default_acl_drop > ? debug_implicit_drop_action() > : "next;"; > - bool has_stateful = od->has_stateful_acl || od->has_lb_vip; > + bool has_stateful = (ls_lbacls_rec->has_stateful_acl > + || ls_lbacls_rec->has_lb_vip); > const char *ct_blocked_match = features->ct_no_masked_label > ? "ct_mark.blocked" > : "ct_label.blocked"; > @@ -7713,8 +7665,8 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, > * > * A related rule at priority 1 is added below if there > * are any stateful ACLs in this datapath. */ > - if (!od->has_acls) { > - if (!od->has_lb_vip) { > + if (!ls_lbacls_rec->has_acls) { > + if (!ls_lbacls_rec->has_lb_vip) { > ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX, "1", > "next;"); > ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX, "1", > @@ -7877,7 +7829,8 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, > meter_groups, &match, &actions); > consider_acl(lflows, od, acl, has_stateful, > features->ct_no_masked_label, > - meter_groups, &match, &actions); > + meter_groups, ls_lbacls_rec->max_acl_tier, > + &match, &actions); > } > > const struct ls_port_group *ls_pg = > @@ -7893,7 +7846,8 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, > meter_groups, &match, &actions); > consider_acl(lflows, od, acl, has_stateful, > features->ct_no_masked_label, > - meter_groups, &match, &actions); > + meter_groups, ls_lbacls_rec->max_acl_tier, > + &match, &actions); > } > } > } > @@ -7911,7 +7865,7 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, > dns_actions); > } > > - if (od->has_acls || od->has_lb_vip) { > + if (ls_lbacls_rec->has_acls || ls_lbacls_rec->has_lb_vip) { > /* Add a 34000 priority flow to advance the service monitor reply > * packets to skip applying ingress ACLs. */ > ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 34000, > @@ -7925,8 +7879,8 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, > REGBIT_ACL_VERDICT_ALLOW" = 1; next;"); > } > > - build_acl_action_lflows(od, lflows, default_acl_action, meter_groups, > - &match, &actions); > + build_acl_action_lflows(ls_lbacls_rec, lflows, default_acl_action, > + meter_groups, &match, &actions); > > ds_destroy(&match); > ds_destroy(&actions); > @@ -8571,8 +8525,11 @@ build_stateful(struct ovn_datapath *od, > } > > static void > -build_lb_hairpin(struct ovn_datapath *od, struct hmap *lflows) > +build_lb_hairpin(const struct ls_lbacls_record *ls_lbacls_rec, > + struct hmap *lflows) > { > + const struct ovn_datapath *od = ls_lbacls_rec->od; > + > /* Ingress Pre-Hairpin/Nat-Hairpin/Hairpin tabled (Priority 0). > * Packets that don't need hairpinning should continue processing. > */ > @@ -8580,7 +8537,7 @@ build_lb_hairpin(struct ovn_datapath *od, struct hmap *lflows) > ovn_lflow_add(lflows, od, S_SWITCH_IN_NAT_HAIRPIN, 0, "1", "next;"); > ovn_lflow_add(lflows, od, S_SWITCH_IN_HAIRPIN, 0, "1", "next;"); > > - if (od->has_lb_vip) { > + if (ls_lbacls_rec->has_lb_vip) { > /* Check if the packet needs to be hairpinned. > * Set REGBIT_HAIRPIN in the original direction and > * REGBIT_HAIRPIN_REPLY in the reply direction. > @@ -9413,22 +9370,16 @@ build_lswitch_lflows_l2_unknown(struct ovn_datapath *od, > static void > build_lswitch_lflows_pre_acl_and_acl( > struct ovn_datapath *od, > - const struct ls_port_group_table *ls_port_groups, > const struct chassis_features *features, > struct hmap *lflows, > const struct shash *meter_groups) > { > ovs_assert(od->nbs); > - ls_get_acl_flags(od, ls_port_groups); > - > - build_pre_acls(od, ls_port_groups, lflows); > + build_pre_acls(od, lflows); > build_pre_lb(od, meter_groups, lflows); > build_pre_stateful(od, features, lflows); > - build_acl_hints(od, features, lflows); > - build_acls(od, features, lflows, ls_port_groups, meter_groups); > build_qos(od, lflows); > build_stateful(od, features, lflows); > - build_lb_hairpin(od, lflows); > build_vtep_hairpin(od, lflows); > } > > @@ -15487,7 +15438,7 @@ build_lrouter_nat_defrag_and_lb( > * a dynamically negotiated FTP data channel), but will allow > * related traffic such as an ICMP Port Unreachable through > * that's generated from a non-listening UDP port. */ > - if (od->has_lb_vip && features->ct_lb_related) { > + if (lr_lbnat_rec->has_lb_vip && features->ct_lb_related) { > ds_clear(match); > > ds_put_cstr(match, "ct.rel && !ct.est && !ct.new"); > @@ -15512,7 +15463,7 @@ build_lrouter_nat_defrag_and_lb( > * Pass the traffic that is already established to the next table with > * proper flags set. > */ > - if (od->has_lb_vip) { > + if (lr_lbnat_rec->has_lb_vip) { > ds_clear(match); > > ds_put_format(match, "ct.est && !ct.rel && !ct.new && %s.natted", > @@ -15542,7 +15493,7 @@ build_lrouter_nat_defrag_and_lb( > * not committed, it would produce ongoing datapath flows with the ct.new > * flag set. Some NICs are unable to offload these flows. > */ > - if (od->is_gw_router && (od->nbr->n_nat || od->has_lb_vip)) { > + if (od->is_gw_router && (od->nbr->n_nat || lr_lbnat_rec->has_lb_vip)) { > /* Do not send ND or ICMP packets to connection tracking. */ > ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 100, > "nd || nd_rs || nd_ra", "next;"); > @@ -15967,6 +15918,22 @@ build_lr_lbnat_data_flows(const struct lr_lb_nat_data_record *lr_lbnat_rec, > meter_groups); > } > > +static void > +build_ls_lbacls_flows(const struct ls_lbacls_record *ls_lbacls_rec, > + const struct ls_port_group_table *ls_pgs, > + const struct chassis_features *features, > + const struct shash *meter_groups, > + struct hmap *lflows) > +{ > + ovs_assert(ls_lbacls_rec->od); > + > + build_ls_lbacls_rec_pre_acls(ls_lbacls_rec, ls_pgs, lflows); > + build_ls_lbacls_rec_pre_lb(ls_lbacls_rec, lflows); > + build_acl_hints(ls_lbacls_rec, features, lflows); > + build_acls(ls_lbacls_rec, features, lflows, ls_pgs, meter_groups); > + build_lb_hairpin(ls_lbacls_rec, lflows); > +} > + > struct lswitch_flow_build_info { > const struct ovn_datapaths *ls_datapaths; > const struct ovn_datapaths *lr_datapaths; > @@ -15974,6 +15941,7 @@ struct lswitch_flow_build_info { > const struct hmap *lr_ports; > const struct ls_port_group_table *ls_port_groups; > const struct lr_lb_nat_data_table *lr_lbnats; > + const struct ls_lbacls_table *ls_lbacls; > struct hmap *lflows; > struct hmap *igmp_groups; > const struct shash *meter_groups; > @@ -15998,9 +15966,7 @@ build_lswitch_and_lrouter_iterate_by_ls(struct ovn_datapath *od, > struct lswitch_flow_build_info *lsi) > { > ovs_assert(od->nbs); > - build_lswitch_lflows_pre_acl_and_acl(od, lsi->ls_port_groups, > - lsi->features, > - lsi->lflows, > + build_lswitch_lflows_pre_acl_and_acl(od, lsi->features, lsi->lflows, > lsi->meter_groups); > > build_fwd_group_lflows(od, lsi->lflows); > @@ -16115,6 +16081,7 @@ build_lflows_thread(void *arg) > { > struct worker_control *control = (struct worker_control *) arg; > const struct lr_lb_nat_data_record *lr_lbnat_rec; > + const struct ls_lbacls_record *ls_lbacls_rec; > struct lswitch_flow_build_info *lsi; > struct ovn_igmp_group *igmp_group; > struct ovn_lb_datapaths *lb_dps; > @@ -16243,6 +16210,19 @@ build_lflows_thread(void *arg) > lsi->features); > } > } > + > + for (bnum = control->id; > + bnum <= lsi->ls_lbacls->entries.mask; > + bnum += control->pool->size) > + { > + LS_LBACLS_TABLE_FOR_EACH_IN_P (ls_lbacls_rec, bnum, > + lsi->ls_lbacls) { > + build_ls_lbacls_flows(ls_lbacls_rec, lsi->ls_port_groups, > + lsi->features, lsi->meter_groups, > + lsi->lflows); > + } > + } > + > for (bnum = control->id; > bnum <= lsi->igmp_groups->mask; > bnum += control->pool->size) > @@ -16303,6 +16283,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > const struct hmap *lr_ports, > const struct ls_port_group_table *ls_pgs, > const struct lr_lb_nat_data_table *lr_lbnats, > + const struct ls_lbacls_table *ls_lbacls, > struct hmap *lflows, > struct hmap *igmp_groups, > const struct shash *meter_groups, > @@ -16333,6 +16314,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > lsiv[index].lr_ports = lr_ports; > lsiv[index].ls_port_groups = ls_pgs; > lsiv[index].lr_lbnats = lr_lbnats; > + lsiv[index].ls_lbacls = ls_lbacls; > lsiv[index].igmp_groups = igmp_groups; > lsiv[index].meter_groups = meter_groups; > lsiv[index].lb_dps_map = lb_dps_map; > @@ -16358,6 +16340,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > free(lsiv); > } else { > const struct lr_lb_nat_data_record *lr_lbnat_rec; > + const struct ls_lbacls_record *ls_lbacls_rec; > struct ovn_igmp_group *igmp_group; > struct ovn_lb_datapaths *lb_dps; > struct ovn_datapath *od; > @@ -16370,6 +16353,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > .lr_ports = lr_ports, > .ls_port_groups = ls_pgs, > .lr_lbnats = lr_lbnats, > + .ls_lbacls = ls_lbacls, > .lflows = lflows, > .igmp_groups = igmp_groups, > .meter_groups = meter_groups, > @@ -16439,6 +16423,12 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > lsi.features); > } > > + LS_LBACLS_TABLE_FOR_EACH (ls_lbacls_rec, ls_lbacls) { > + build_ls_lbacls_flows(ls_lbacls_rec, lsi.ls_port_groups, > + lsi.features, lsi.meter_groups, > + lsi.lflows); > + } > + > stopwatch_start(LFLOWS_IGMP_STOPWATCH_NAME, time_msec()); > HMAP_FOR_EACH (igmp_group, hmap_node, igmp_groups) { > build_lswitch_ip_mcast_igmp_mld(igmp_group, > @@ -16535,6 +16525,7 @@ void build_lflows(struct ovsdb_idl_txn *ovnsb_txn, > input_data->lr_ports, > input_data->ls_port_groups, > input_data->lr_lbnats, > + input_data->ls_lbacls, > lflows, > &igmp_groups, > input_data->meter_groups, > diff --git a/northd/northd.h b/northd/northd.h > index 08a81b2c10..23b4754db4 100644 > --- a/northd/northd.h > +++ b/northd/northd.h > @@ -89,6 +89,8 @@ ods_size(const struct ovn_datapaths *datapaths) > return hmap_count(&datapaths->datapaths); > } > > +bool od_has_lb_vip(const struct ovn_datapath *od); > + > struct tracked_ovn_ports { > /* tracked created ports. > * hmapx node data is 'struct ovn_port *' */ > @@ -179,6 +181,7 @@ struct lflow_input { > const struct hmap *lr_ports; > const struct ls_port_group_table *ls_port_groups; > const struct lr_lb_nat_data_table *lr_lbnats; > + const struct ls_lbacls_table *ls_lbacls; > const struct shash *meter_groups; > const struct hmap *lb_datapaths_map; > const struct hmap *bfd_connections; > @@ -288,11 +291,7 @@ struct ovn_datapath { > struct hmap port_tnlids; > uint32_t port_key_hint; > > - bool has_stateful_acl; > - bool has_lb_vip; > bool has_unknown; > - bool has_acls; > - uint64_t max_acl_tier; > bool has_vtep_lports; > bool has_arp_proxy_port; > > -- > 2.41.0 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
On Wed, Nov 15, 2023 at 1:55 AM Han Zhou <hzhou@ovn.org> wrote: > > On Thu, Oct 26, 2023 at 11:17 AM <numans@ovn.org> wrote: > > > > From: Numan Siddique <numans@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 > > - NB logical switch node > > - Port group node > > > > A record for each logical switch is maintained in the 'ls_lbacls' > > 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; > > The node name indicates it contains LBs and ACLs of each LS, but it is > actually about the stateful related flags. So I think it is better to be > renamed to avoid confusion. Thanks. It makes sense to rename this node to 'ls_stateful'. And perhaps also rename 'lr_lbnat_data' to 'lr_stateful' too as both these nodes handle "LB + ACL" and "LB + NAT" respectively and these make use of conntrack internally. > > > > > This engine node becomes an input to 'lflow' node. > > > > Signed-off-by: Numan Siddique <numans@ovn.org> > > --- > > lib/stopwatch-names.h | 1 + > > northd/automake.mk | 2 + > > northd/en-lflow.c | 4 + > > northd/en-lr-lb-nat-data.c | 8 +- > > northd/en-lr-lb-nat-data.h | 2 + > > northd/en-ls-lb-acls.c | 527 +++++++++++++++++++++++++++++++++++++ > > northd/en-ls-lb-acls.h | 88 +++++++ > > northd/en-port-group.h | 3 + > > northd/inc-proc-northd.c | 9 + > > northd/northd.c | 271 +++++++++---------- > > northd/northd.h | 7 +- > > 11 files changed, 776 insertions(+), 146 deletions(-) > > create mode 100644 northd/en-ls-lb-acls.c > > create mode 100644 northd/en-ls-lb-acls.h > > > > diff --git a/lib/stopwatch-names.h b/lib/stopwatch-names.h > > index 7d85acdaea..8b0018a593 100644 > > --- a/lib/stopwatch-names.h > > +++ b/lib/stopwatch-names.h > > @@ -34,5 +34,6 @@ > > #define SYNC_METERS_RUN_STOPWATCH_NAME "sync_meters_run" > > #define LR_NAT_RUN_STOPWATCH_NAME "lr_nat_run" > > #define LR_LB_NAT_DATA_RUN_STOPWATCH_NAME "lr_lb_nat_data" > > +#define LS_LBACLS_RUN_STOPWATCH_NAME "lr_lb_acls" > > > > #endif > > diff --git a/northd/automake.mk b/northd/automake.mk > > index 4116c487df..4593654726 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-lb-nat-data.c \ > > northd/en-lr-lb-nat-data.h \ > > + northd/en-ls-lb-acls.c \ > > + northd/en-ls-lb-acls.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 229f4be1d0..648a477916 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-lb-nat-data.h" > > +#include "en-ls-lb-acls.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_lb_nat_data *lr_lb_nat_data = > > engine_get_input_data("lr_lb_nat_data", node); > > + struct ed_type_ls_lbacls *ls_lbacls_data = > > + engine_get_input_data("ls_lbacls", 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_lbnats = &lr_lb_nat_data->lr_lbnats; > > + lflow_input->ls_lbacls = &ls_lbacls_data->ls_lbacls; > > 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-lb-nat-data.c b/northd/en-lr-lb-nat-data.c > > index 19b638ce0b..d816d2321d 100644 > > --- a/northd/en-lr-lb-nat-data.c > > +++ b/northd/en-lr-lb-nat-data.c > > @@ -299,9 +299,11 @@ lr_lb_nat_data_lb_data_handler(struct engine_node > *node, void *data_) > > if (!hmapx_is_empty(&data->tracked_data.crupdated)) { > > struct hmapx_node *hmapx_node; > > /* For all the modified lr_lb_nat_data records (re)build the > > - * vip nats. */ > > + * vip nats and re-evaluate 'has_lb_vip'. */ > > HMAPX_FOR_EACH (hmapx_node, &data->tracked_data.crupdated) { > > - lr_lb_nat_data_build_vip_nats(hmapx_node->data); > > + lr_lbnat_rec = hmapx_node->data; > > + lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); > > + lr_lbnat_rec->has_lb_vip = od_has_lb_vip(lr_lbnat_rec->od); > > Changes in this module should belong to an earlier patch instead of this > one? > > > } > > > > data->tracked = true; > > @@ -523,6 +525,8 @@ lr_lb_nat_data_record_init(struct > lr_lb_nat_data_record *lr_lbnat_rec, > > if (!nbr->n_nat) { > > lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); > > } > > + > > + lr_lbnat_rec->has_lb_vip = od_has_lb_vip(lr_lbnat_rec->od); > > } > > > > static struct lr_lb_nat_data_input > > diff --git a/northd/en-lr-lb-nat-data.h b/northd/en-lr-lb-nat-data.h > > index ffe41cad73..ac21d28a57 100644 > > --- a/northd/en-lr-lb-nat-data.h > > +++ b/northd/en-lr-lb-nat-data.h > > @@ -39,6 +39,8 @@ struct lr_lb_nat_data_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-lb-acls.c b/northd/en-ls-lb-acls.c > > new file mode 100644 > > index 0000000000..1ba7ecb3e2 > > --- /dev/null > > +++ b/northd/en-ls-lb-acls.c > > @@ -0,0 +1,527 @@ > > +/* > > + * 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 <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-lb-acls.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_lbacls); > > + > > +/* Static function declarations. */ > > +static void ls_lbacls_table_init(struct ls_lbacls_table *); > > +static void ls_lbacls_table_clear(struct ls_lbacls_table *); > > +static void ls_lbacls_table_destroy(struct ls_lbacls_table *); > > +static struct ls_lbacls_record *ls_lbacls_table_find_( > > + const struct ls_lbacls_table *, const struct nbrec_logical_switch *); > > +static void ls_lbacls_table_build(struct ls_lbacls_table *, > > + const struct ovn_datapaths > *ls_datapaths, > > + const struct ls_port_group_table *); > > + > > +static struct ls_lbacls_input ls_lbacls_get_input_data( > > + struct engine_node *); > > + > > +static struct ls_lbacls_record *ls_lbacls_record_create( > > + struct ls_lbacls_table *, > > + const struct ovn_datapath *, > > + const struct ls_port_group_table *); > > +static void ls_lbacls_record_destroy(struct ls_lbacls_record *); > > +static void ls_lbacls_record_init( > > + struct ls_lbacls_record *, > > + const struct ovn_datapath *, > > + const struct ls_port_group *, > > + const struct ls_port_group_table *); > > +static void ls_lbacls_record_reinit( > > + struct ls_lbacls_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_lbacls_record_set_acl_flags(struct ls_lbacls_record *, > > + const struct ovn_datapath *, > > + const struct ls_port_group *, > > + const struct > ls_port_group_table *); > > +static bool ls_lbacls_record_set_acl_flags_(struct ls_lbacls_record *, > > + struct nbrec_acl **, > > + size_t n_acls); > > +static struct ls_lbacls_input ls_lbacls_get_input_data(struct > engine_node *); > > +static bool is_ls_acls_changed(const struct nbrec_logical_switch *); > > +static bool is_acls_seqno_changed(struct nbrec_acl **, size_t n_nb_acls); > > + > > + > > +/* public functions. */ > > +const struct ls_lbacls_record * > > +ls_lbacls_table_find( > > + const struct ls_lbacls_table *table, > > + const struct nbrec_logical_switch *nbs) > > +{ > > + return ls_lbacls_table_find_(table, nbs); > > +} > > + > > +void * > > +en_ls_lbacls_init(struct engine_node *node OVS_UNUSED, > > + struct engine_arg *arg OVS_UNUSED) > > +{ > > + struct ed_type_ls_lbacls *data = xzalloc(sizeof *data); > > + ls_lbacls_table_init(&data->ls_lbacls); > > + hmapx_init(&data->tracked_data.crupdated); > > + hmapx_init(&data->tracked_data.deleted); > > + return data; > > +} > > + > > +void > > +en_ls_lbacls_cleanup(void *data_) > > +{ > > + struct ed_type_ls_lbacls *data = > > + (struct ed_type_ls_lbacls *) data_; > > + ls_lbacls_table_destroy(&data->ls_lbacls); > > + hmapx_destroy(&data->tracked_data.crupdated); > > + hmapx_destroy(&data->tracked_data.deleted); > > +} > > + > > +void > > +en_ls_lbacls_clear_tracked_data(void *data_) > > +{ > > + struct ed_type_ls_lbacls *data = > > + (struct ed_type_ls_lbacls *) data_; > > + > > + struct hmapx_node *hmapx_node; > > + HMAPX_FOR_EACH_SAFE (hmapx_node, &data->tracked_data.deleted) { > > + ls_lbacls_record_destroy(hmapx_node->data); > > + hmapx_delete(&data->tracked_data.deleted, hmapx_node); > > + } > > + > > + hmapx_clear(&data->tracked_data.crupdated); > > + data->tracked = false; > > +} > > + > > +void > > +en_ls_lbacls_run(struct engine_node *node, void *data_) > > +{ > > + struct ls_lbacls_input input_data = ls_lbacls_get_input_data(node); > > + struct ed_type_ls_lbacls *data = data_; > > + > > + stopwatch_start(LS_LBACLS_RUN_STOPWATCH_NAME, time_msec()); > > + > > + ls_lbacls_table_clear(&data->ls_lbacls); > > + ls_lbacls_table_build(&data->ls_lbacls, input_data.ls_datapaths, > > + input_data.ls_port_groups); > > + > > + data->tracked = false; > > + stopwatch_stop(LS_LBACLS_RUN_STOPWATCH_NAME, time_msec()); > > + engine_set_node_state(node, EN_UPDATED); > > +} > > + > > +/* Handler functions. */ > > +bool > > +ls_lbacls_northd_handler(struct engine_node *node, void *data_) > > +{ > > + struct northd_data *northd_data = engine_get_input_data("northd", > node); > > + if (!northd_data->change_tracked) { > > + return false; > > + } > > + > > + struct northd_tracked_data *nd_changes = > &northd_data->trk_northd_changes; > > + struct ls_lbacls_input input_data = ls_lbacls_get_input_data(node); > > + struct ls_lbacls_record *ls_lbacls_rec; > > + struct ed_type_ls_lbacls *data = data_; > > + const struct ovn_datapath *od; > > + struct hmapx_node *hmapx_node; > > + > > + HMAPX_FOR_EACH (hmapx_node, > &nd_changes->ls_with_changed_lbs.crupdated) { > > + od = hmapx_node->data; > > + > > + ls_lbacls_rec = ls_lbacls_table_find_(&data->ls_lbacls, od->nbs); > > + if (!ls_lbacls_rec) { > > + ls_lbacls_rec = ls_lbacls_record_create(&data->ls_lbacls, od, > > + > input_data.ls_port_groups); > > + } else { > > + ls_lbacls_record_reinit(ls_lbacls_rec, NULL, > > + input_data.ls_port_groups); > > + } > > + > > + /* Add the ls_lbacls_rec to the tracking data. */ > > + hmapx_add(&data->tracked_data.crupdated, ls_lbacls_rec); > > + } > > + > > + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { > > + data->tracked = true; > > + engine_set_node_state(node, EN_UPDATED); > > + } > > + > > + return true; > > +} > > + > > +bool > > +ls_lbacls_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_lbacls_rec. > > + * This is still better than returning false. */ > > + struct ls_lbacls_input input_data = ls_lbacls_get_input_data(node); > > + struct ed_type_ls_lbacls *data = data_; > > + const struct ls_port_group *ls_pg; > > + > > + LS_PORT_GROUP_TABLE_FOR_EACH (ls_pg, input_data.ls_port_groups) { > > + struct ls_lbacls_record *ls_lbacls_rec = > > + ls_lbacls_table_find_(&data->ls_lbacls, ls_pg->nbs); > > + > > + bool modified = false; > > + if (!ls_lbacls_rec) { > > + const struct ovn_datapath *od; > > + od = ovn_datapath_find(&input_data.ls_datapaths->datapaths, > > + &ls_pg->nbs->header_.uuid); > > + ovs_assert(od); > > + ls_lbacls_rec = ls_lbacls_record_create(&data->ls_lbacls, od, > > + > input_data.ls_port_groups); > > + modified = true; > > + } else { > > + bool had_stateful_acl = ls_lbacls_rec->has_stateful_acl; > > + uint64_t max_acl_tier = ls_lbacls_rec->max_acl_tier; > > + bool had_acls = ls_lbacls_rec->has_acls; > > + > > + ls_lbacls_record_reinit(ls_lbacls_rec, ls_pg, > > + input_data.ls_port_groups); > > + > > + if ((had_stateful_acl != ls_lbacls_rec->has_stateful_acl) > > + || (had_acls != ls_lbacls_rec->has_acls) > > + || max_acl_tier != ls_lbacls_rec->max_acl_tier) { > > + modified = true; > > + } > > + } > > + > > + if (modified) { > > + /* Add the ls_lbacls_rec to the tracking data. */ > > + hmapx_add(&data->tracked_data.crupdated, ls_lbacls_rec); > > + } > > + } > > + > > + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { > > + data->tracked = true; > > + engine_set_node_state(node, EN_UPDATED); > > + } > > + > > + return true; > > +} > > + > > +bool > > +ls_lbacls_logical_switch_handler(struct engine_node *node, void *data_) > > +{ > > + struct ls_lbacls_input input_data = ls_lbacls_get_input_data(node); > > + const struct nbrec_logical_switch *nbs; > > + struct ed_type_ls_lbacls *data = data_; > > + > > + NBREC_LOGICAL_SWITCH_TABLE_FOR_EACH_TRACKED (nbs, > > + > input_data.nbrec_logical_switch_table) { > > + if (!is_ls_acls_changed(nbs)) { > > + continue; > > + } > > + > > + struct ls_lbacls_record *ls_lbacls_rec = > > + ls_lbacls_table_find_(&data->ls_lbacls, nbs); > > + > > + if (nbrec_logical_switch_is_deleted(nbs)) { > > + if (ls_lbacls_rec) { > > + /* Remove the record from the entries. */ > > + hmap_remove(&data->ls_lbacls.entries, > > + &ls_lbacls_rec->key_node); > > + > > + /* Add the ls_lbacls_rec to the tracking data. */ > > + hmapx_add(&data->tracked_data.deleted, ls_lbacls_rec); > > + } > > + } else { > > + if (!ls_lbacls_rec) { > > + const struct ovn_datapath *od; > > + od = > ovn_datapath_find(&input_data.ls_datapaths->datapaths, > > + &nbs->header_.uuid); > > + ovs_assert(od); > > + ls_lbacls_rec = > ls_lbacls_record_create(&data->ls_lbacls, od, > > + > input_data.ls_port_groups); > > + } else { > > + ls_lbacls_record_reinit(ls_lbacls_rec, NULL, > > + input_data.ls_port_groups); > > + } > > + > > + /* Add the ls_lbacls_rec to the tracking data. */ > > + hmapx_add(&data->tracked_data.crupdated, ls_lbacls_rec); > > + } > > + } > > + > > + if (!hmapx_is_empty(&data->tracked_data.crupdated) > > + || !hmapx_is_empty(&data->tracked_data.deleted)) { > > + data->tracked = true; > > + engine_set_node_state(node, EN_UPDATED); > > + } > > + > > + return true; > > +} > > + > > +/* static functions. */ > > +static void > > +ls_lbacls_table_init(struct ls_lbacls_table *table) > > +{ > > + *table = (struct ls_lbacls_table) { > > + .entries = HMAP_INITIALIZER(&table->entries), > > + }; > > +} > > + > > +static void > > +ls_lbacls_table_destroy(struct ls_lbacls_table *table) > > +{ > > + ls_lbacls_table_clear(table); > > + hmap_destroy(&table->entries); > > +} > > + > > +static void > > +ls_lbacls_table_clear(struct ls_lbacls_table *table) > > +{ > > + struct ls_lbacls_record *ls_lbacls_rec; > > + HMAP_FOR_EACH_POP (ls_lbacls_rec, key_node, &table->entries) { > > + ls_lbacls_record_destroy(ls_lbacls_rec); > > + } > > +} > > + > > +static void > > +ls_lbacls_table_build(struct ls_lbacls_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_lbacls_record_create(table, od, ls_pgs); > > + } > > +} > > + > > +struct ls_lbacls_record * > > +ls_lbacls_table_find_(const struct ls_lbacls_table *table, > > + const struct nbrec_logical_switch *nbs) > > +{ > > + struct ls_lbacls_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_lbacls_record * > > +ls_lbacls_record_create(struct ls_lbacls_table *table, > > + const struct ovn_datapath *od, > > + const struct ls_port_group_table *ls_pgs) > > +{ > > + struct ls_lbacls_record *ls_lbacls_rec = xzalloc(sizeof > *ls_lbacls_rec); > > + ls_lbacls_rec->od = od; > > + ls_lbacls_record_init(ls_lbacls_rec, od, NULL, ls_pgs); > > + > > + hmap_insert(&table->entries, &ls_lbacls_rec->key_node, > > + uuid_hash(&ls_lbacls_rec->od->nbs->header_.uuid)); > > + > > + return ls_lbacls_rec; > > +} > > + > > +static void > > +ls_lbacls_record_destroy(struct ls_lbacls_record *ls_lbacls_rec) > > +{ > > + free(ls_lbacls_rec); > > +} > > + > > +static void > > +ls_lbacls_record_init(struct ls_lbacls_record *ls_lbacls_rec, > > + const struct ovn_datapath *od, > > + const struct ls_port_group *ls_pg, > > + const struct ls_port_group_table *ls_pgs) > > +{ > > + ls_lbacls_rec->has_lb_vip = ls_has_lb_vip(od); > > + ls_lbacls_record_set_acl_flags(ls_lbacls_rec, od, ls_pg, ls_pgs); > > +} > > + > > +static void > > +ls_lbacls_record_reinit(struct ls_lbacls_record *ls_lbacls_rec, > > + const struct ls_port_group *ls_pg, > > + const struct ls_port_group_table *ls_pgs) > > +{ > > + ls_lbacls_record_init(ls_lbacls_rec, ls_lbacls_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_lbacls_record_set_acl_flags(struct ls_lbacls_record *ls_lbacls_rec, > > + const struct ovn_datapath *od, > > + const struct ls_port_group *ls_pg, > > + const struct ls_port_group_table *ls_pgs) > > +{ > > + ls_lbacls_rec->has_stateful_acl = false; > > + ls_lbacls_rec->max_acl_tier = 0; > > + ls_lbacls_rec->has_acls = false; > > + > > + if (ls_lbacls_record_set_acl_flags_(ls_lbacls_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_lbacls_record_set_acl_flags_(ls_lbacls_rec, > > + ls_pg_rec->nb_pg->acls, > > + ls_pg_rec->nb_pg->n_acls)) { > > + return; > > + } > > + } > > +} > > + > > +static bool > > +ls_lbacls_record_set_acl_flags_(struct ls_lbacls_record *ls_lbacls_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_lbacls record. A false return indicates that > > + * further ACLs should be explored in case more flags need to be > > + * set on ls_lbacls record. > > + */ > > + if (!n_acls) { > > + return false; > > + } > > + > > + ls_lbacls_rec->has_acls = true; > > + for (size_t i = 0; i < n_acls; i++) { > > + const struct nbrec_acl *acl = acls[i]; > > + if (acl->tier > ls_lbacls_rec->max_acl_tier) { > > + ls_lbacls_rec->max_acl_tier = acl->tier; > > + } > > + if (!ls_lbacls_rec->has_stateful_acl > > + && !strcmp(acl->action, "allow-related")) { > > + ls_lbacls_rec->has_stateful_acl = true; > > + } > > + if (ls_lbacls_rec->has_stateful_acl && > > + ls_lbacls_rec->max_acl_tier == > > + nbrec_acl_col_tier.type.value.integer.max) { > > + return true; > > + } > > + } > > + > > + return false; > > +} > > + > > +static struct ls_lbacls_input > > +ls_lbacls_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_lbacls_input) { > > + .nbrec_logical_switch_table = > > + EN_OVSDB_GET(engine_get_input("NB_logical_switch", node)), > > + .ls_port_groups = &pg_data->ls_port_groups, > > + .ls_datapaths = &northd_data->ls_datapaths, > > + }; > > +} > > + > > +static bool > > +is_acls_seqno_changed(struct nbrec_acl **nb_acls, size_t n_nb_acls) > > +{ > > + for (size_t i = 0; i < n_nb_acls; i++) { > > + if (nbrec_acl_row_get_seqno(nb_acls[i], > > + OVSDB_IDL_CHANGE_MODIFY) > 0) { > > + return true; > > + } > > + } > > + > > + return false; > > +} > > + > > +static bool > > +is_ls_acls_changed(const struct nbrec_logical_switch *nbs) { > > + return (nbrec_logical_switch_is_new(nbs) > > + || nbrec_logical_switch_is_deleted(nbs) > > + || nbrec_logical_switch_is_updated(nbs, > > + > NBREC_LOGICAL_SWITCH_COL_ACLS) > > + || is_acls_seqno_changed(nbs->acls, nbs->n_acls)); > > +} > > diff --git a/northd/en-ls-lb-acls.h b/northd/en-ls-lb-acls.h > > new file mode 100644 > > index 0000000000..ccb75e40e8 > > --- /dev/null > > +++ b/northd/en-ls-lb-acls.h > > @@ -0,0 +1,88 @@ > > +/* > > + * 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_LS_LB_ACL_H > > +#define EN_LS_LB_ACL_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_lbacls_record { > > + struct hmap_node key_node; > > + > > + const struct ovn_datapath *od; > > Such reference is error-prone. In the en-flow node it directly uses this > reference to access other data of the ovn_datapath, but the dependency is > not tracked and propagated through this node. For example, > ls_lbacls_rec->od->nbs->acls is used in build_acls but ACL changes are not > propagated through this node. I don't think that's the case. ls_lbacls engine node has the following inputs - northd engine node - NB_logical_switch - port_group If a logical switch's ACLs change (or a port group's ACLs change), those changes are handled and are tracked in this node so that en_lflow engine can handle it. We could also store 'struct nbrec_logical_switch *' in the 'struct ls_lbacls_record. But I don't see any benefit in it. We would just waste some pointer space. Thanks Numan > > > + bool has_stateful_acl; > > + bool has_lb_vip; > > + bool has_acls; > > + uint64_t max_acl_tier; > > +}; > > + > > +struct ls_lbacls_table { > > + struct hmap entries; > > +}; > > + > > +#define LS_LBACLS_TABLE_FOR_EACH(LS_LBACLS_REC, TABLE) \ > > + HMAP_FOR_EACH (LS_LBACLS_REC, key_node, &(TABLE)->entries) > > + > > +#define LS_LBACLS_TABLE_FOR_EACH_IN_P(LS_LBACLS_REC, JOBID, TABLE) \ > > + HMAP_FOR_EACH_IN_PARALLEL (LS_LBACLS_REC, key_node, JOBID, \ > > + &(TABLE)->entries) > > + > > +struct ls_lbacls_tracked_data { > > + /* Created or updated logical switch with LB and ACL data. */ > > + struct hmapx crupdated; /* Stores 'struct ls_lbacls_record'. */ > > + > > + /* Deleted logical switch with LB and ACL data. */ > > + struct hmapx deleted; /* Stores 'struct ls_lbacls_record'. */ > > +}; > > + > > +struct ed_type_ls_lbacls { > > + struct ls_lbacls_table ls_lbacls; > > + > > + bool tracked; > > + struct ls_lbacls_tracked_data tracked_data; > > +}; > > + > > +struct ls_lbacls_input { > > + const struct nbrec_logical_switch_table *nbrec_logical_switch_table; > > + const struct ls_port_group_table *ls_port_groups; > > + const struct ovn_datapaths *ls_datapaths; > > +}; > > nit: this seems should be module internal and should move to the .c > > Thanks, > Han > > > + > > +void *en_ls_lbacls_init(struct engine_node *, struct engine_arg *); > > +void en_ls_lbacls_cleanup(void *data); > > +void en_ls_lbacls_clear_tracked_data(void *data); > > +void en_ls_lbacls_run(struct engine_node *, void *data); > > + > > +bool ls_lbacls_northd_handler(struct engine_node *, void *data); > > +bool ls_lbacls_port_group_handler(struct engine_node *, void *data); > > +bool ls_lbacls_logical_switch_handler(struct engine_node *, void *data); > > + > > +const struct ls_lbacls_record *ls_lbacls_table_find( > > + const struct ls_lbacls_table *, const struct nbrec_logical_switch *); > > + > > +#endif /* EN_LS_LB_ACL_H */ > > 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 84627070a8..ab4af92aeb 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-lb-nat-data.h" > > #include "en-lr-nat.h" > > +#include "en-ls-lb-acls.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_lb_nat_data, > "lr_lb_nat_data"); > > +static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(ls_lbacls, "ls_lbacls"); > > > > void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > > struct ovsdb_idl_loop *sb) > > @@ -205,6 +207,12 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > > engine_add_input(&en_lr_lb_nat_data, &en_lb_data, > > lr_lb_nat_data_lb_data_handler); > > > > + engine_add_input(&en_ls_lbacls, &en_northd, > ls_lbacls_northd_handler); > > + engine_add_input(&en_ls_lbacls, &en_port_group, > > + ls_lbacls_port_group_handler); > > + engine_add_input(&en_ls_lbacls, &en_nb_logical_switch, > > + ls_lbacls_logical_switch_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); > > @@ -229,6 +237,7 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > > engine_add_input(&en_lflow, &en_northd, lflow_northd_handler); > > engine_add_input(&en_lflow, &en_port_group, > lflow_port_group_handler); > > engine_add_input(&en_lflow, &en_lr_lb_nat_data, NULL); > > + engine_add_input(&en_lflow, &en_ls_lbacls, NULL); > > > > engine_add_input(&en_sync_to_sb_addr_set, &en_nb_address_set, > > sync_to_sb_addr_set_nb_address_set_handler); > > diff --git a/northd/northd.c b/northd/northd.c > > index c8a224d3cd..924f5cd7e0 100644 > > --- a/northd/northd.c > > +++ b/northd/northd.c > > @@ -45,6 +45,7 @@ > > #include "en-lb-data.h" > > #include "en-lr-nat.h" > > #include "en-lr-lb-nat-data.h" > > +#include "en-ls-lb-acls.h" > > #include "lib/ovn-parallel-hmap.h" > > #include "ovn/actions.h" > > #include "ovn/features.h" > > @@ -575,7 +576,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])) { > > @@ -592,7 +593,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])) { > > @@ -608,13 +609,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); > > } > > } > > > > @@ -1058,7 +1059,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; > > @@ -1089,7 +1089,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; > > } > > @@ -2570,7 +2569,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_lbnat_rec > > + || !lr_lbnat_rec->has_lb_vip)) > > || !eth_addr_from_string(op->nbrp->mac, &mac)) { > > *n = n_nats; > > return NULL; > > @@ -3817,7 +3817,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 > > && !smap_get(&od->nbr->options, "chassis")) { > > static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, > 1); > > VLOG_WARN_RL(&rl, "Load-balancers are configured on logical " > > @@ -5441,7 +5441,6 @@ northd_handle_lb_data_changes(struct > tracked_lb_data *trk_lb_data, > > BITMAP_FOR_EACH_1 (index, ods_size(ls_datapaths), > > lb_dps->nb_ls_map) { > > od = ls_datapaths->array[index]; > > - init_lb_for_datapath(od); > > > > /* Add the ls datapath to the northd tracked data. */ > > hmapx_add(&nd_changes->ls_with_changed_lbs.crupdated, od); > > @@ -5524,9 +5523,6 @@ northd_handle_lb_data_changes(struct > tracked_lb_data *trk_lb_data, > > } > > } > > > > - /* Re-evaluate 'od->has_lb_vip' */ > > - init_lb_for_datapath(od); > > - > > /* Add the ls datapath to the northd tracked data. */ > > hmapx_add(&nd_changes->ls_with_changed_lbs.crupdated, od); > > } > > @@ -5564,9 +5560,6 @@ northd_handle_lb_data_changes(struct > tracked_lb_data *trk_lb_data, > > } > > } > > > > - /* Re-evaluate 'od->has_lb_vip' */ > > - init_lb_for_datapath(od); > > - > > /* Add the lr datapath to the northd tracked data. */ > > hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); > > } > > @@ -5581,8 +5574,6 @@ northd_handle_lb_data_changes(struct > tracked_lb_data *trk_lb_data, > > BITMAP_FOR_EACH_1 (index, ods_size(ls_datapaths), > > lb_dps->nb_ls_map) { > > od = ls_datapaths->array[index]; > > - /* Re-evaluate 'od->has_lb_vip' */ > > - init_lb_for_datapath(od); > > > > /* Add the ls datapath to the northd tracked data. */ > > hmapx_add(&nd_changes->ls_with_changed_lbs.crupdated, od); > > @@ -5591,8 +5582,6 @@ northd_handle_lb_data_changes(struct > tracked_lb_data *trk_lb_data, > > BITMAP_FOR_EACH_1 (index, ods_size(lr_datapaths), > > lb_dps->nb_lr_map) { > > od = lr_datapaths->array[index]; > > - /* Re-evaluate 'od->has_lb_vip' */ > > - init_lb_for_datapath(od); > > > > /* Add the lr datapath to the northd tracked data. */ > > hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); > > @@ -5618,9 +5607,6 @@ northd_handle_lb_data_changes(struct > tracked_lb_data *trk_lb_data, > > od = lbgrp_dps->lr[i]; > > ovn_lb_datapaths_add_lr(lb_dps, 1, &od); > > > > - /* Re-evaluate 'od->has_lb_vip' */ > > - init_lb_for_datapath(od); > > - > > /* Add the lr datapath to the northd tracked data. */ > > hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, > od); > > } > > @@ -5629,9 +5615,6 @@ northd_handle_lb_data_changes(struct > tracked_lb_data *trk_lb_data, > > od = lbgrp_dps->ls[i]; > > ovn_lb_datapaths_add_ls(lb_dps, 1, &od); > > > > - /* Re-evaluate 'od->has_lb_vip' */ > > - init_lb_for_datapath(od); > > - > > /* Add the ls datapath to the northd tracked data. */ > > hmapx_add(&nd_changes->ls_with_changed_lbs.crupdated, > od); > > } > > @@ -6573,63 +6556,6 @@ build_dhcpv6_action(struct ovn_port *op, struct > in6_addr *offer_ip, > > return true; > > } > > > > -static bool > > -od_set_acl_flags(struct ovn_datapath *od, struct nbrec_acl **acls, > > - size_t n_acls) > > -{ > > - /* A true return indicates that there are no possible ACL flags > > - * left to set on od. A false return indicates that further ACLs > > - * should be explored in case more flags need to be set on od > > - */ > > - if (!n_acls) { > > - return false; > > - } > > - > > - od->has_acls = true; > > - for (size_t i = 0; i < n_acls; i++) { > > - const struct nbrec_acl *acl = acls[i]; > > - if (acl->tier > od->max_acl_tier) { > > - od->max_acl_tier = acl->tier; > > - } > > - if (!od->has_stateful_acl && !strcmp(acl->action, > "allow-related")) { > > - od->has_stateful_acl = true; > > - } > > - if (od->has_stateful_acl && > > - od->max_acl_tier == > nbrec_acl_col_tier.type.value.integer.max) { > > - return true; > > - } > > - } > > - > > - return false; > > -} > > - > > -static void > > -ls_get_acl_flags(struct ovn_datapath *od, > > - const struct ls_port_group_table *ls_port_groups) > > -{ > > - od->has_acls = false; > > - od->has_stateful_acl = false; > > - od->max_acl_tier = 0; > > - > > - if (od_set_acl_flags(od, od->nbs->acls, od->nbs->n_acls)) { > > - return; > > - } > > - > > - const struct ls_port_group *ls_pg = > > - ls_port_group_table_find(ls_port_groups, 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 (od_set_acl_flags(od, ls_pg_rec->nb_pg->acls, > > - ls_pg_rec->nb_pg->n_acls)) { > > - return; > > - } > > - } > > -} > > - > > /* Adds the logical flows in the (in/out) check port sec stage only if > > * - the lport is disabled or > > * - lport is of type vtep - to skip the ingress pipeline. > > @@ -6774,9 +6700,10 @@ build_lswitch_output_port_sec_od(struct > ovn_datapath *od, > > } > > > > static void > > -skip_port_from_conntrack(struct ovn_datapath *od, struct ovn_port *op, > > - enum ovn_stage in_stage, enum ovn_stage > out_stage, > > - uint16_t priority, struct hmap *lflows) > > +skip_port_from_conntrack(const struct ovn_datapath *od, struct ovn_port > *op, > > + bool has_stateful_acl, enum ovn_stage in_stage, > > + enum ovn_stage out_stage, uint16_t priority, > > + struct hmap *lflows) > > { > > /* Can't use ct() for router ports. Consider the following > configuration: > > * lp1(10.0.0.2) on hostA--ls1--lr0--ls2--lp2(10.0.1.2) on hostB, > For a > > @@ -6789,7 +6716,7 @@ skip_port_from_conntrack(struct ovn_datapath *od, > struct ovn_port *op, > > * conntrack state across all chassis. */ > > > > const char *ingress_action = "next;"; > > - const char *egress_action = od->has_stateful_acl > > + const char *egress_action = has_stateful_acl > > ? "next;" > > : "ct_clear; next;"; > > > > @@ -6808,7 +6735,7 @@ skip_port_from_conntrack(struct ovn_datapath *od, > struct ovn_port *op, > > } > > > > static void > > -build_stateless_filter(struct ovn_datapath *od, > > +build_stateless_filter(const struct ovn_datapath *od, > > const struct nbrec_acl *acl, > > struct hmap *lflows) > > { > > @@ -6829,7 +6756,7 @@ build_stateless_filter(struct ovn_datapath *od, > > } > > > > static void > > -build_stateless_filters(struct ovn_datapath *od, > > +build_stateless_filters(const struct ovn_datapath *od, > > const struct ls_port_group_table *ls_port_groups, > > struct hmap *lflows) > > { > > @@ -6859,9 +6786,7 @@ build_stateless_filters(struct ovn_datapath *od, > > } > > > > static void > > -build_pre_acls(struct ovn_datapath *od, > > - const struct ls_port_group_table *ls_port_groups, > > - struct hmap *lflows) > > +build_pre_acls(struct ovn_datapath *od, struct hmap *lflows) > > { > > /* Ingress and Egress Pre-ACL Table (Priority 0): Packets are > > * allowed by default. */ > > @@ -6873,18 +6798,26 @@ build_pre_acls(struct ovn_datapath *od, > > > > ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, > > "eth.src == $svc_monitor_mac", "next;"); > > +} > > + > > +static void > > +build_ls_lbacls_rec_pre_acls(const struct ls_lbacls_record > *ls_lbacls_rec, > > + const struct ls_port_group_table > *ls_port_groups, > > + struct hmap *lflows) > > +{ > > + const struct ovn_datapath *od = ls_lbacls_rec->od; > > > > /* If there are any stateful ACL rules in this datapath, we may > > * send IP packets for some (allow) filters through the conntrack > action, > > * which handles defragmentation, in order to match L4 headers. */ > > - if (od->has_stateful_acl) { > > + if (ls_lbacls_rec->has_stateful_acl) { > > for (size_t i = 0; i < od->n_router_ports; i++) { > > - skip_port_from_conntrack(od, od->router_ports[i], > > + skip_port_from_conntrack(od, od->router_ports[i], true, > > S_SWITCH_IN_PRE_ACL, > S_SWITCH_OUT_PRE_ACL, > > 110, lflows); > > } > > for (size_t i = 0; i < od->n_localnet_ports; i++) { > > - skip_port_from_conntrack(od, od->localnet_ports[i], > > + skip_port_from_conntrack(od, od->localnet_ports[i], true, > > S_SWITCH_IN_PRE_ACL, > > S_SWITCH_OUT_PRE_ACL, > > 110, lflows); > > @@ -6922,7 +6855,7 @@ build_pre_acls(struct ovn_datapath *od, > > REGBIT_CONNTRACK_DEFRAG" = 1; next;"); > > ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 100, "ip", > > REGBIT_CONNTRACK_DEFRAG" = 1; next;"); > > - } else if (od->has_lb_vip) { > > + } else if (ls_lbacls_rec->has_lb_vip) { > > /* We'll build stateless filters if there are LB rules so that > > * the stateless flows are not tracked in pre-lb. */ > > build_stateless_filters(od, ls_port_groups, lflows); > > @@ -7050,30 +6983,40 @@ build_pre_lb(struct ovn_datapath *od, const > struct shash *meter_groups, > > ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 0, "1", "next;"); > > ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 0, "1", "next;"); > > > > + /* Do not send statless flows via conntrack */ > > + ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110, > > + REGBIT_ACL_STATELESS" == 1", "next;"); > > + ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110, > > + REGBIT_ACL_STATELESS" == 1", "next;"); > > +} > > + > > +static void > > +build_ls_lbacls_rec_pre_lb(const struct ls_lbacls_record *ls_lbacls_rec, > > + struct hmap *lflows) > > +{ > > + const struct ovn_datapath *od = ls_lbacls_rec->od; > > + > > for (size_t i = 0; i < od->n_router_ports; i++) { > > skip_port_from_conntrack(od, od->router_ports[i], > > + ls_lbacls_rec->has_stateful_acl, > > S_SWITCH_IN_PRE_LB, S_SWITCH_OUT_PRE_LB, > > 110, lflows); > > } > > + > > /* Localnet ports have no need for going through conntrack, unless > > * the logical switch has a load balancer. Then, conntrack is > necessary > > * so that traffic arriving via the localnet port can be load > > * balanced. > > */ > > - if (!od->has_lb_vip) { > > + if (!ls_lbacls_rec->has_lb_vip) { > > for (size_t i = 0; i < od->n_localnet_ports; i++) { > > skip_port_from_conntrack(od, od->localnet_ports[i], > > + ls_lbacls_rec->has_stateful_acl, > > S_SWITCH_IN_PRE_LB, > S_SWITCH_OUT_PRE_LB, > > 110, lflows); > > } > > } > > > > - /* Do not sent statless flows via conntrack */ > > - ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110, > > - REGBIT_ACL_STATELESS" == 1", "next;"); > > - ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110, > > - REGBIT_ACL_STATELESS" == 1", "next;"); > > - > > /* 'REGBIT_CONNTRACK_NAT' is set to let the pre-stateful table send > > * packet to conntrack for defragmentation and possibly for > unNATting. > > * > > @@ -7104,7 +7047,7 @@ build_pre_lb(struct ovn_datapath *od, const struct > shash *meter_groups, > > * ingress pipeline if a load balancer is configured. We can now > > * add a lflow to drop ct.inv packets. > > */ > > - if (od->has_lb_vip) { > > + if (ls_lbacls_rec->has_lb_vip) { > > ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, > > 100, "ip", REGBIT_CONNTRACK_NAT" = 1; next;"); > > ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, > > @@ -7145,10 +7088,12 @@ build_pre_stateful(struct ovn_datapath *od, > > } > > > > static void > > -build_acl_hints(struct ovn_datapath *od, > > +build_acl_hints(const struct ls_lbacls_record *ls_lbacls_rec, > > const struct chassis_features *features, > > struct hmap *lflows) > > { > > + const struct ovn_datapath *od = ls_lbacls_rec->od; > > + > > /* This stage builds hints for the IN/OUT_ACL stage. Based on various > > * combinations of ct flags packets may hit only a subset of the > logical > > * flows in the IN/OUT_ACL stage. > > @@ -7172,13 +7117,13 @@ build_acl_hints(struct ovn_datapath *od, > > const char *match; > > > > /* In any case, advance to the next stage. */ > > - if (!od->has_acls && !od->has_lb_vip) { > > + if (!ls_lbacls_rec->has_acls && !ls_lbacls_rec->has_lb_vip) { > > ovn_lflow_add(lflows, od, stage, UINT16_MAX, "1", "next;"); > > } else { > > ovn_lflow_add(lflows, od, stage, 0, "1", "next;"); > > } > > > > - if (!od->has_stateful_acl && !od->has_lb_vip) { > > + if (!ls_lbacls_rec->has_stateful_acl && > !ls_lbacls_rec->has_lb_vip) { > > continue; > > } > > > > @@ -7314,10 +7259,10 @@ build_acl_log(struct ds *actions, const struct > nbrec_acl *acl, > > } > > > > static void > > -consider_acl(struct hmap *lflows, struct ovn_datapath *od, > > +consider_acl(struct hmap *lflows, const struct ovn_datapath *od, > > const struct nbrec_acl *acl, bool has_stateful, > > bool ct_masked_mark, const struct shash *meter_groups, > > - struct ds *match, struct ds *actions) > > + uint64_t max_acl_tier, struct ds *match, struct ds *actions) > > { > > const char *ct_blocked_match = ct_masked_mark > > ? "ct_mark.blocked" > > @@ -7354,7 +7299,7 @@ consider_acl(struct hmap *lflows, struct > ovn_datapath *od, > > /* All ACLS will start by matching on their respective tier. */ > > size_t match_tier_len = 0; > > ds_clear(match); > > - if (od->max_acl_tier) { > > + if (max_acl_tier) { > > ds_put_format(match, REG_ACL_TIER " == %"PRId64" && ", > acl->tier); > > match_tier_len = match->length; > > } > > @@ -7543,12 +7488,15 @@ ovn_update_ipv6_options(struct hmap *lr_ports) > > #define IPV6_CT_OMIT_MATCH "nd || nd_ra || nd_rs || mldv1 || mldv2" > > > > static void > > -build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, > > +build_acl_action_lflows(const struct ls_lbacls_record *ls_lbacls_rec, > > + struct hmap *lflows, > > const char *default_acl_action, > > const struct shash *meter_groups, > > struct ds *match, > > struct ds *actions) > > { > > + const struct ovn_datapath *od = ls_lbacls_rec->od; > > + > > enum ovn_stage stages [] = { > > S_SWITCH_IN_ACL_ACTION, > > S_SWITCH_IN_ACL_AFTER_LB_ACTION, > > @@ -7559,7 +7507,7 @@ build_acl_action_lflows(struct ovn_datapath *od, > struct hmap *lflows, > > ds_put_cstr(actions, REGBIT_ACL_VERDICT_ALLOW " = 0; " > > REGBIT_ACL_VERDICT_DROP " = 0; " > > REGBIT_ACL_VERDICT_REJECT " = 0; "); > > - if (od->max_acl_tier) { > > + if (ls_lbacls_rec->max_acl_tier) { > > ds_put_cstr(actions, REG_ACL_TIER " = 0; "); > > } > > > > @@ -7567,7 +7515,7 @@ build_acl_action_lflows(struct ovn_datapath *od, > struct hmap *lflows, > > > > for (size_t i = 0; i < ARRAY_SIZE(stages); i++) { > > enum ovn_stage stage = stages[i]; > > - if (!od->has_acls) { > > + if (!ls_lbacls_rec->has_acls) { > > ovn_lflow_add(lflows, od, stage, 0, "1", "next;"); > > continue; > > } > > @@ -7602,7 +7550,7 @@ build_acl_action_lflows(struct ovn_datapath *od, > struct hmap *lflows, > > ovn_lflow_add(lflows, od, stage, 0, "1", ds_cstr(actions)); > > > > struct ds tier_actions = DS_EMPTY_INITIALIZER; > > - for (size_t j = 0; j < od->max_acl_tier; j++) { > > + for (size_t j = 0; j < ls_lbacls_rec->max_acl_tier; j++) { > > ds_clear(match); > > ds_put_format(match, REG_ACL_TIER " == %"PRIuSIZE, j); > > ds_clear(&tier_actions); > > @@ -7618,7 +7566,7 @@ build_acl_action_lflows(struct ovn_datapath *od, > struct hmap *lflows, > > } > > > > static void > > -build_acl_log_related_flows(struct ovn_datapath *od, struct hmap *lflows, > > +build_acl_log_related_flows(const struct ovn_datapath *od, struct hmap > *lflows, > > const struct nbrec_acl *acl, bool > has_stateful, > > bool ct_masked_mark, > > const struct shash *meter_groups, > > @@ -7691,15 +7639,19 @@ build_acl_log_related_flows(struct ovn_datapath > *od, struct hmap *lflows, > > } > > > > static void > > -build_acls(struct ovn_datapath *od, const struct chassis_features > *features, > > +build_acls(const struct ls_lbacls_record *ls_lbacls_rec, > > + const struct chassis_features *features, > > struct hmap *lflows, > > const struct ls_port_group_table *ls_port_groups, > > const struct shash *meter_groups) > > { > > + const struct ovn_datapath *od = ls_lbacls_rec->od; > > + > > const char *default_acl_action = default_acl_drop > > ? debug_implicit_drop_action() > > : "next;"; > > - bool has_stateful = od->has_stateful_acl || od->has_lb_vip; > > + bool has_stateful = (ls_lbacls_rec->has_stateful_acl > > + || ls_lbacls_rec->has_lb_vip); > > const char *ct_blocked_match = features->ct_no_masked_label > > ? "ct_mark.blocked" > > : "ct_label.blocked"; > > @@ -7713,8 +7665,8 @@ build_acls(struct ovn_datapath *od, const struct > chassis_features *features, > > * > > * A related rule at priority 1 is added below if there > > * are any stateful ACLs in this datapath. */ > > - if (!od->has_acls) { > > - if (!od->has_lb_vip) { > > + if (!ls_lbacls_rec->has_acls) { > > + if (!ls_lbacls_rec->has_lb_vip) { > > ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX, > "1", > > "next;"); > > ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX, > "1", > > @@ -7877,7 +7829,8 @@ build_acls(struct ovn_datapath *od, const struct > chassis_features *features, > > meter_groups, &match, &actions); > > consider_acl(lflows, od, acl, has_stateful, > > features->ct_no_masked_label, > > - meter_groups, &match, &actions); > > + meter_groups, ls_lbacls_rec->max_acl_tier, > > + &match, &actions); > > } > > > > const struct ls_port_group *ls_pg = > > @@ -7893,7 +7846,8 @@ build_acls(struct ovn_datapath *od, const struct > chassis_features *features, > > meter_groups, &match, > &actions); > > consider_acl(lflows, od, acl, has_stateful, > > features->ct_no_masked_label, > > - meter_groups, &match, &actions); > > + meter_groups, ls_lbacls_rec->max_acl_tier, > > + &match, &actions); > > } > > } > > } > > @@ -7911,7 +7865,7 @@ build_acls(struct ovn_datapath *od, const struct > chassis_features *features, > > dns_actions); > > } > > > > - if (od->has_acls || od->has_lb_vip) { > > + if (ls_lbacls_rec->has_acls || ls_lbacls_rec->has_lb_vip) { > > /* Add a 34000 priority flow to advance the service monitor reply > > * packets to skip applying ingress ACLs. */ > > ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 34000, > > @@ -7925,8 +7879,8 @@ build_acls(struct ovn_datapath *od, const struct > chassis_features *features, > > REGBIT_ACL_VERDICT_ALLOW" = 1; next;"); > > } > > > > - build_acl_action_lflows(od, lflows, default_acl_action, meter_groups, > > - &match, &actions); > > + build_acl_action_lflows(ls_lbacls_rec, lflows, default_acl_action, > > + meter_groups, &match, &actions); > > > > ds_destroy(&match); > > ds_destroy(&actions); > > @@ -8571,8 +8525,11 @@ build_stateful(struct ovn_datapath *od, > > } > > > > static void > > -build_lb_hairpin(struct ovn_datapath *od, struct hmap *lflows) > > +build_lb_hairpin(const struct ls_lbacls_record *ls_lbacls_rec, > > + struct hmap *lflows) > > { > > + const struct ovn_datapath *od = ls_lbacls_rec->od; > > + > > /* Ingress Pre-Hairpin/Nat-Hairpin/Hairpin tabled (Priority 0). > > * Packets that don't need hairpinning should continue processing. > > */ > > @@ -8580,7 +8537,7 @@ build_lb_hairpin(struct ovn_datapath *od, struct > hmap *lflows) > > ovn_lflow_add(lflows, od, S_SWITCH_IN_NAT_HAIRPIN, 0, "1", "next;"); > > ovn_lflow_add(lflows, od, S_SWITCH_IN_HAIRPIN, 0, "1", "next;"); > > > > - if (od->has_lb_vip) { > > + if (ls_lbacls_rec->has_lb_vip) { > > /* Check if the packet needs to be hairpinned. > > * Set REGBIT_HAIRPIN in the original direction and > > * REGBIT_HAIRPIN_REPLY in the reply direction. > > @@ -9413,22 +9370,16 @@ build_lswitch_lflows_l2_unknown(struct > ovn_datapath *od, > > static void > > build_lswitch_lflows_pre_acl_and_acl( > > struct ovn_datapath *od, > > - const struct ls_port_group_table *ls_port_groups, > > const struct chassis_features *features, > > struct hmap *lflows, > > const struct shash *meter_groups) > > { > > ovs_assert(od->nbs); > > - ls_get_acl_flags(od, ls_port_groups); > > - > > - build_pre_acls(od, ls_port_groups, lflows); > > + build_pre_acls(od, lflows); > > build_pre_lb(od, meter_groups, lflows); > > build_pre_stateful(od, features, lflows); > > - build_acl_hints(od, features, lflows); > > - build_acls(od, features, lflows, ls_port_groups, meter_groups); > > build_qos(od, lflows); > > build_stateful(od, features, lflows); > > - build_lb_hairpin(od, lflows); > > build_vtep_hairpin(od, lflows); > > } > > > > @@ -15487,7 +15438,7 @@ build_lrouter_nat_defrag_and_lb( > > * a dynamically negotiated FTP data channel), but will allow > > * related traffic such as an ICMP Port Unreachable through > > * that's generated from a non-listening UDP port. */ > > - if (od->has_lb_vip && features->ct_lb_related) { > > + if (lr_lbnat_rec->has_lb_vip && features->ct_lb_related) { > > ds_clear(match); > > > > ds_put_cstr(match, "ct.rel && !ct.est && !ct.new"); > > @@ -15512,7 +15463,7 @@ build_lrouter_nat_defrag_and_lb( > > * Pass the traffic that is already established to the next table > with > > * proper flags set. > > */ > > - if (od->has_lb_vip) { > > + if (lr_lbnat_rec->has_lb_vip) { > > ds_clear(match); > > > > ds_put_format(match, "ct.est && !ct.rel && !ct.new && %s.natted", > > @@ -15542,7 +15493,7 @@ build_lrouter_nat_defrag_and_lb( > > * not committed, it would produce ongoing datapath flows with the > ct.new > > * flag set. Some NICs are unable to offload these flows. > > */ > > - if (od->is_gw_router && (od->nbr->n_nat || od->has_lb_vip)) { > > + if (od->is_gw_router && (od->nbr->n_nat || > lr_lbnat_rec->has_lb_vip)) { > > /* Do not send ND or ICMP packets to connection tracking. */ > > ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 100, > > "nd || nd_rs || nd_ra", "next;"); > > @@ -15967,6 +15918,22 @@ build_lr_lbnat_data_flows(const struct > lr_lb_nat_data_record *lr_lbnat_rec, > > meter_groups); > > } > > > > +static void > > +build_ls_lbacls_flows(const struct ls_lbacls_record *ls_lbacls_rec, > > + const struct ls_port_group_table *ls_pgs, > > + const struct chassis_features *features, > > + const struct shash *meter_groups, > > + struct hmap *lflows) > > +{ > > + ovs_assert(ls_lbacls_rec->od); > > + > > + build_ls_lbacls_rec_pre_acls(ls_lbacls_rec, ls_pgs, lflows); > > + build_ls_lbacls_rec_pre_lb(ls_lbacls_rec, lflows); > > + build_acl_hints(ls_lbacls_rec, features, lflows); > > + build_acls(ls_lbacls_rec, features, lflows, ls_pgs, meter_groups); > > + build_lb_hairpin(ls_lbacls_rec, lflows); > > +} > > + > > struct lswitch_flow_build_info { > > const struct ovn_datapaths *ls_datapaths; > > const struct ovn_datapaths *lr_datapaths; > > @@ -15974,6 +15941,7 @@ struct lswitch_flow_build_info { > > const struct hmap *lr_ports; > > const struct ls_port_group_table *ls_port_groups; > > const struct lr_lb_nat_data_table *lr_lbnats; > > + const struct ls_lbacls_table *ls_lbacls; > > struct hmap *lflows; > > struct hmap *igmp_groups; > > const struct shash *meter_groups; > > @@ -15998,9 +15966,7 @@ build_lswitch_and_lrouter_iterate_by_ls(struct > ovn_datapath *od, > > struct lswitch_flow_build_info > *lsi) > > { > > ovs_assert(od->nbs); > > - build_lswitch_lflows_pre_acl_and_acl(od, lsi->ls_port_groups, > > - lsi->features, > > - lsi->lflows, > > + build_lswitch_lflows_pre_acl_and_acl(od, lsi->features, lsi->lflows, > > lsi->meter_groups); > > > > build_fwd_group_lflows(od, lsi->lflows); > > @@ -16115,6 +16081,7 @@ build_lflows_thread(void *arg) > > { > > struct worker_control *control = (struct worker_control *) arg; > > const struct lr_lb_nat_data_record *lr_lbnat_rec; > > + const struct ls_lbacls_record *ls_lbacls_rec; > > struct lswitch_flow_build_info *lsi; > > struct ovn_igmp_group *igmp_group; > > struct ovn_lb_datapaths *lb_dps; > > @@ -16243,6 +16210,19 @@ build_lflows_thread(void *arg) > > lsi->features); > > } > > } > > + > > + for (bnum = control->id; > > + bnum <= lsi->ls_lbacls->entries.mask; > > + bnum += control->pool->size) > > + { > > + LS_LBACLS_TABLE_FOR_EACH_IN_P (ls_lbacls_rec, bnum, > > + lsi->ls_lbacls) { > > + build_ls_lbacls_flows(ls_lbacls_rec, > lsi->ls_port_groups, > > + lsi->features, > lsi->meter_groups, > > + lsi->lflows); > > + } > > + } > > + > > for (bnum = control->id; > > bnum <= lsi->igmp_groups->mask; > > bnum += control->pool->size) > > @@ -16303,6 +16283,7 @@ build_lswitch_and_lrouter_flows(const struct > ovn_datapaths *ls_datapaths, > > const struct hmap *lr_ports, > > const struct ls_port_group_table *ls_pgs, > > const struct lr_lb_nat_data_table > *lr_lbnats, > > + const struct ls_lbacls_table *ls_lbacls, > > struct hmap *lflows, > > struct hmap *igmp_groups, > > const struct shash *meter_groups, > > @@ -16333,6 +16314,7 @@ build_lswitch_and_lrouter_flows(const struct > ovn_datapaths *ls_datapaths, > > lsiv[index].lr_ports = lr_ports; > > lsiv[index].ls_port_groups = ls_pgs; > > lsiv[index].lr_lbnats = lr_lbnats; > > + lsiv[index].ls_lbacls = ls_lbacls; > > lsiv[index].igmp_groups = igmp_groups; > > lsiv[index].meter_groups = meter_groups; > > lsiv[index].lb_dps_map = lb_dps_map; > > @@ -16358,6 +16340,7 @@ build_lswitch_and_lrouter_flows(const struct > ovn_datapaths *ls_datapaths, > > free(lsiv); > > } else { > > const struct lr_lb_nat_data_record *lr_lbnat_rec; > > + const struct ls_lbacls_record *ls_lbacls_rec; > > struct ovn_igmp_group *igmp_group; > > struct ovn_lb_datapaths *lb_dps; > > struct ovn_datapath *od; > > @@ -16370,6 +16353,7 @@ build_lswitch_and_lrouter_flows(const struct > ovn_datapaths *ls_datapaths, > > .lr_ports = lr_ports, > > .ls_port_groups = ls_pgs, > > .lr_lbnats = lr_lbnats, > > + .ls_lbacls = ls_lbacls, > > .lflows = lflows, > > .igmp_groups = igmp_groups, > > .meter_groups = meter_groups, > > @@ -16439,6 +16423,12 @@ build_lswitch_and_lrouter_flows(const struct > ovn_datapaths *ls_datapaths, > > lsi.features); > > } > > > > + LS_LBACLS_TABLE_FOR_EACH (ls_lbacls_rec, ls_lbacls) { > > + build_ls_lbacls_flows(ls_lbacls_rec, lsi.ls_port_groups, > > + lsi.features, lsi.meter_groups, > > + lsi.lflows); > > + } > > + > > stopwatch_start(LFLOWS_IGMP_STOPWATCH_NAME, time_msec()); > > HMAP_FOR_EACH (igmp_group, hmap_node, igmp_groups) { > > build_lswitch_ip_mcast_igmp_mld(igmp_group, > > @@ -16535,6 +16525,7 @@ void build_lflows(struct ovsdb_idl_txn *ovnsb_txn, > > input_data->lr_ports, > > input_data->ls_port_groups, > > input_data->lr_lbnats, > > + input_data->ls_lbacls, > > lflows, > > &igmp_groups, > > input_data->meter_groups, > > diff --git a/northd/northd.h b/northd/northd.h > > index 08a81b2c10..23b4754db4 100644 > > --- a/northd/northd.h > > +++ b/northd/northd.h > > @@ -89,6 +89,8 @@ ods_size(const struct ovn_datapaths *datapaths) > > return hmap_count(&datapaths->datapaths); > > } > > > > +bool od_has_lb_vip(const struct ovn_datapath *od); > > + > > struct tracked_ovn_ports { > > /* tracked created ports. > > * hmapx node data is 'struct ovn_port *' */ > > @@ -179,6 +181,7 @@ struct lflow_input { > > const struct hmap *lr_ports; > > const struct ls_port_group_table *ls_port_groups; > > const struct lr_lb_nat_data_table *lr_lbnats; > > + const struct ls_lbacls_table *ls_lbacls; > > const struct shash *meter_groups; > > const struct hmap *lb_datapaths_map; > > const struct hmap *bfd_connections; > > @@ -288,11 +291,7 @@ struct ovn_datapath { > > struct hmap port_tnlids; > > uint32_t port_key_hint; > > > > - bool has_stateful_acl; > > - bool has_lb_vip; > > bool has_unknown; > > - bool has_acls; > > - uint64_t max_acl_tier; > > bool has_vtep_lports; > > bool has_arp_proxy_port; > > > > -- > > 2.41.0 > > > > _______________________________________________ > > dev mailing list > > dev@openvswitch.org > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > _______________________________________________ > dev mailing list > dev@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
On 10/26/23 20:15, numans@ovn.org wrote: > From: Numan Siddique <numans@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 > - NB logical switch node > - Port group node > > A record for each logical switch is maintained in the 'ls_lbacls' > 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. > > Signed-off-by: Numan Siddique <numans@ovn.org> > --- > lib/stopwatch-names.h | 1 + > northd/automake.mk | 2 + > northd/en-lflow.c | 4 + > northd/en-lr-lb-nat-data.c | 8 +- > northd/en-lr-lb-nat-data.h | 2 + > northd/en-ls-lb-acls.c | 527 +++++++++++++++++++++++++++++++++++++ > northd/en-ls-lb-acls.h | 88 +++++++ > northd/en-port-group.h | 3 + > northd/inc-proc-northd.c | 9 + > northd/northd.c | 271 +++++++++---------- > northd/northd.h | 7 +- > 11 files changed, 776 insertions(+), 146 deletions(-) > create mode 100644 northd/en-ls-lb-acls.c > create mode 100644 northd/en-ls-lb-acls.h > > diff --git a/lib/stopwatch-names.h b/lib/stopwatch-names.h > index 7d85acdaea..8b0018a593 100644 > --- a/lib/stopwatch-names.h > +++ b/lib/stopwatch-names.h > @@ -34,5 +34,6 @@ > #define SYNC_METERS_RUN_STOPWATCH_NAME "sync_meters_run" > #define LR_NAT_RUN_STOPWATCH_NAME "lr_nat_run" > #define LR_LB_NAT_DATA_RUN_STOPWATCH_NAME "lr_lb_nat_data" > +#define LS_LBACLS_RUN_STOPWATCH_NAME "lr_lb_acls" > > #endif > diff --git a/northd/automake.mk b/northd/automake.mk > index 4116c487df..4593654726 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-lb-nat-data.c \ > northd/en-lr-lb-nat-data.h \ > + northd/en-ls-lb-acls.c \ > + northd/en-ls-lb-acls.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 229f4be1d0..648a477916 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-lb-nat-data.h" > +#include "en-ls-lb-acls.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_lb_nat_data *lr_lb_nat_data = > engine_get_input_data("lr_lb_nat_data", node); > + struct ed_type_ls_lbacls *ls_lbacls_data = > + engine_get_input_data("ls_lbacls", 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_lbnats = &lr_lb_nat_data->lr_lbnats; > + lflow_input->ls_lbacls = &ls_lbacls_data->ls_lbacls; > 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-lb-nat-data.c b/northd/en-lr-lb-nat-data.c > index 19b638ce0b..d816d2321d 100644 > --- a/northd/en-lr-lb-nat-data.c > +++ b/northd/en-lr-lb-nat-data.c > @@ -299,9 +299,11 @@ lr_lb_nat_data_lb_data_handler(struct engine_node *node, void *data_) > if (!hmapx_is_empty(&data->tracked_data.crupdated)) { > struct hmapx_node *hmapx_node; > /* For all the modified lr_lb_nat_data records (re)build the > - * vip nats. */ > + * vip nats and re-evaluate 'has_lb_vip'. */ > HMAPX_FOR_EACH (hmapx_node, &data->tracked_data.crupdated) { > - lr_lb_nat_data_build_vip_nats(hmapx_node->data); > + lr_lbnat_rec = hmapx_node->data; > + lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); > + lr_lbnat_rec->has_lb_vip = od_has_lb_vip(lr_lbnat_rec->od); > } > > data->tracked = true; > @@ -523,6 +525,8 @@ lr_lb_nat_data_record_init(struct lr_lb_nat_data_record *lr_lbnat_rec, > if (!nbr->n_nat) { > lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); > } > + > + lr_lbnat_rec->has_lb_vip = od_has_lb_vip(lr_lbnat_rec->od); > } > > static struct lr_lb_nat_data_input > diff --git a/northd/en-lr-lb-nat-data.h b/northd/en-lr-lb-nat-data.h > index ffe41cad73..ac21d28a57 100644 > --- a/northd/en-lr-lb-nat-data.h > +++ b/northd/en-lr-lb-nat-data.h > @@ -39,6 +39,8 @@ struct lr_lb_nat_data_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-lb-acls.c b/northd/en-ls-lb-acls.c > new file mode 100644 > index 0000000000..1ba7ecb3e2 > --- /dev/null > +++ b/northd/en-ls-lb-acls.c > @@ -0,0 +1,527 @@ > +/* > + * 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 <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-lb-acls.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_lbacls); > + > +/* Static function declarations. */ > +static void ls_lbacls_table_init(struct ls_lbacls_table *); > +static void ls_lbacls_table_clear(struct ls_lbacls_table *); > +static void ls_lbacls_table_destroy(struct ls_lbacls_table *); > +static struct ls_lbacls_record *ls_lbacls_table_find_( > + const struct ls_lbacls_table *, const struct nbrec_logical_switch *); > +static void ls_lbacls_table_build(struct ls_lbacls_table *, > + const struct ovn_datapaths *ls_datapaths, > + const struct ls_port_group_table *); > + > +static struct ls_lbacls_input ls_lbacls_get_input_data( > + struct engine_node *); > + > +static struct ls_lbacls_record *ls_lbacls_record_create( > + struct ls_lbacls_table *, > + const struct ovn_datapath *, > + const struct ls_port_group_table *); > +static void ls_lbacls_record_destroy(struct ls_lbacls_record *); > +static void ls_lbacls_record_init( > + struct ls_lbacls_record *, > + const struct ovn_datapath *, > + const struct ls_port_group *, > + const struct ls_port_group_table *); > +static void ls_lbacls_record_reinit( > + struct ls_lbacls_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_lbacls_record_set_acl_flags(struct ls_lbacls_record *, > + const struct ovn_datapath *, > + const struct ls_port_group *, > + const struct ls_port_group_table *); > +static bool ls_lbacls_record_set_acl_flags_(struct ls_lbacls_record *, > + struct nbrec_acl **, > + size_t n_acls); > +static struct ls_lbacls_input ls_lbacls_get_input_data(struct engine_node *); > +static bool is_ls_acls_changed(const struct nbrec_logical_switch *); > +static bool is_acls_seqno_changed(struct nbrec_acl **, size_t n_nb_acls); > + > + > +/* public functions. */ > +const struct ls_lbacls_record * > +ls_lbacls_table_find( > + const struct ls_lbacls_table *table, > + const struct nbrec_logical_switch *nbs) > +{ > + return ls_lbacls_table_find_(table, nbs); > +} > + > +void * > +en_ls_lbacls_init(struct engine_node *node OVS_UNUSED, > + struct engine_arg *arg OVS_UNUSED) > +{ > + struct ed_type_ls_lbacls *data = xzalloc(sizeof *data); > + ls_lbacls_table_init(&data->ls_lbacls); > + hmapx_init(&data->tracked_data.crupdated); > + hmapx_init(&data->tracked_data.deleted); > + return data; > +} > + > +void > +en_ls_lbacls_cleanup(void *data_) > +{ > + struct ed_type_ls_lbacls *data = > + (struct ed_type_ls_lbacls *) data_; > + ls_lbacls_table_destroy(&data->ls_lbacls); > + hmapx_destroy(&data->tracked_data.crupdated); > + hmapx_destroy(&data->tracked_data.deleted); > +} > + > +void > +en_ls_lbacls_clear_tracked_data(void *data_) > +{ > + struct ed_type_ls_lbacls *data = > + (struct ed_type_ls_lbacls *) data_; > + > + struct hmapx_node *hmapx_node; > + HMAPX_FOR_EACH_SAFE (hmapx_node, &data->tracked_data.deleted) { > + ls_lbacls_record_destroy(hmapx_node->data); > + hmapx_delete(&data->tracked_data.deleted, hmapx_node); > + } > + > + hmapx_clear(&data->tracked_data.crupdated); > + data->tracked = false; > +} > + > +void > +en_ls_lbacls_run(struct engine_node *node, void *data_) > +{ > + struct ls_lbacls_input input_data = ls_lbacls_get_input_data(node); > + struct ed_type_ls_lbacls *data = data_; > + > + stopwatch_start(LS_LBACLS_RUN_STOPWATCH_NAME, time_msec()); > + > + ls_lbacls_table_clear(&data->ls_lbacls); > + ls_lbacls_table_build(&data->ls_lbacls, input_data.ls_datapaths, > + input_data.ls_port_groups); > + > + data->tracked = false; > + stopwatch_stop(LS_LBACLS_RUN_STOPWATCH_NAME, time_msec()); Same comment about missing stopwatch_start(LS_LBACLS_RUN_STOPWATCH_NAME, ...) as in the previous patch in this series. Thanks, Dumitru > + engine_set_node_state(node, EN_UPDATED); > +} > + > +/* Handler functions. */ > +bool > +ls_lbacls_northd_handler(struct engine_node *node, void *data_) > +{ > + struct northd_data *northd_data = engine_get_input_data("northd", node); > + if (!northd_data->change_tracked) { > + return false; > + } > + > + struct northd_tracked_data *nd_changes = &northd_data->trk_northd_changes; > + struct ls_lbacls_input input_data = ls_lbacls_get_input_data(node); > + struct ls_lbacls_record *ls_lbacls_rec; > + struct ed_type_ls_lbacls *data = data_; > + const struct ovn_datapath *od; > + struct hmapx_node *hmapx_node; > + > + HMAPX_FOR_EACH (hmapx_node, &nd_changes->ls_with_changed_lbs.crupdated) { > + od = hmapx_node->data; > + > + ls_lbacls_rec = ls_lbacls_table_find_(&data->ls_lbacls, od->nbs); > + if (!ls_lbacls_rec) { > + ls_lbacls_rec = ls_lbacls_record_create(&data->ls_lbacls, od, > + input_data.ls_port_groups); > + } else { > + ls_lbacls_record_reinit(ls_lbacls_rec, NULL, > + input_data.ls_port_groups); > + } > + > + /* Add the ls_lbacls_rec to the tracking data. */ > + hmapx_add(&data->tracked_data.crupdated, ls_lbacls_rec); > + } > + > + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { > + data->tracked = true; > + engine_set_node_state(node, EN_UPDATED); > + } > + > + return true; > +} > + > +bool > +ls_lbacls_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_lbacls_rec. > + * This is still better than returning false. */ > + struct ls_lbacls_input input_data = ls_lbacls_get_input_data(node); > + struct ed_type_ls_lbacls *data = data_; > + const struct ls_port_group *ls_pg; > + > + LS_PORT_GROUP_TABLE_FOR_EACH (ls_pg, input_data.ls_port_groups) { > + struct ls_lbacls_record *ls_lbacls_rec = > + ls_lbacls_table_find_(&data->ls_lbacls, ls_pg->nbs); > + > + bool modified = false; > + if (!ls_lbacls_rec) { > + const struct ovn_datapath *od; > + od = ovn_datapath_find(&input_data.ls_datapaths->datapaths, > + &ls_pg->nbs->header_.uuid); > + ovs_assert(od); > + ls_lbacls_rec = ls_lbacls_record_create(&data->ls_lbacls, od, > + input_data.ls_port_groups); > + modified = true; > + } else { > + bool had_stateful_acl = ls_lbacls_rec->has_stateful_acl; > + uint64_t max_acl_tier = ls_lbacls_rec->max_acl_tier; > + bool had_acls = ls_lbacls_rec->has_acls; > + > + ls_lbacls_record_reinit(ls_lbacls_rec, ls_pg, > + input_data.ls_port_groups); > + > + if ((had_stateful_acl != ls_lbacls_rec->has_stateful_acl) > + || (had_acls != ls_lbacls_rec->has_acls) > + || max_acl_tier != ls_lbacls_rec->max_acl_tier) { > + modified = true; > + } > + } > + > + if (modified) { > + /* Add the ls_lbacls_rec to the tracking data. */ > + hmapx_add(&data->tracked_data.crupdated, ls_lbacls_rec); > + } > + } > + > + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { > + data->tracked = true; > + engine_set_node_state(node, EN_UPDATED); > + } > + > + return true; > +} > + > +bool > +ls_lbacls_logical_switch_handler(struct engine_node *node, void *data_) > +{ > + struct ls_lbacls_input input_data = ls_lbacls_get_input_data(node); > + const struct nbrec_logical_switch *nbs; > + struct ed_type_ls_lbacls *data = data_; > + > + NBREC_LOGICAL_SWITCH_TABLE_FOR_EACH_TRACKED (nbs, > + input_data.nbrec_logical_switch_table) { > + if (!is_ls_acls_changed(nbs)) { > + continue; > + } > + > + struct ls_lbacls_record *ls_lbacls_rec = > + ls_lbacls_table_find_(&data->ls_lbacls, nbs); > + > + if (nbrec_logical_switch_is_deleted(nbs)) { > + if (ls_lbacls_rec) { > + /* Remove the record from the entries. */ > + hmap_remove(&data->ls_lbacls.entries, > + &ls_lbacls_rec->key_node); > + > + /* Add the ls_lbacls_rec to the tracking data. */ > + hmapx_add(&data->tracked_data.deleted, ls_lbacls_rec); > + } > + } else { > + if (!ls_lbacls_rec) { > + const struct ovn_datapath *od; > + od = ovn_datapath_find(&input_data.ls_datapaths->datapaths, > + &nbs->header_.uuid); > + ovs_assert(od); > + ls_lbacls_rec = ls_lbacls_record_create(&data->ls_lbacls, od, > + input_data.ls_port_groups); > + } else { > + ls_lbacls_record_reinit(ls_lbacls_rec, NULL, > + input_data.ls_port_groups); > + } > + > + /* Add the ls_lbacls_rec to the tracking data. */ > + hmapx_add(&data->tracked_data.crupdated, ls_lbacls_rec); > + } > + } > + > + if (!hmapx_is_empty(&data->tracked_data.crupdated) > + || !hmapx_is_empty(&data->tracked_data.deleted)) { > + data->tracked = true; > + engine_set_node_state(node, EN_UPDATED); > + } > + > + return true; > +} > + > +/* static functions. */ > +static void > +ls_lbacls_table_init(struct ls_lbacls_table *table) > +{ > + *table = (struct ls_lbacls_table) { > + .entries = HMAP_INITIALIZER(&table->entries), > + }; > +} > + > +static void > +ls_lbacls_table_destroy(struct ls_lbacls_table *table) > +{ > + ls_lbacls_table_clear(table); > + hmap_destroy(&table->entries); > +} > + > +static void > +ls_lbacls_table_clear(struct ls_lbacls_table *table) > +{ > + struct ls_lbacls_record *ls_lbacls_rec; > + HMAP_FOR_EACH_POP (ls_lbacls_rec, key_node, &table->entries) { > + ls_lbacls_record_destroy(ls_lbacls_rec); > + } > +} > + > +static void > +ls_lbacls_table_build(struct ls_lbacls_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_lbacls_record_create(table, od, ls_pgs); > + } > +} > + > +struct ls_lbacls_record * > +ls_lbacls_table_find_(const struct ls_lbacls_table *table, > + const struct nbrec_logical_switch *nbs) > +{ > + struct ls_lbacls_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_lbacls_record * > +ls_lbacls_record_create(struct ls_lbacls_table *table, > + const struct ovn_datapath *od, > + const struct ls_port_group_table *ls_pgs) > +{ > + struct ls_lbacls_record *ls_lbacls_rec = xzalloc(sizeof *ls_lbacls_rec); > + ls_lbacls_rec->od = od; > + ls_lbacls_record_init(ls_lbacls_rec, od, NULL, ls_pgs); > + > + hmap_insert(&table->entries, &ls_lbacls_rec->key_node, > + uuid_hash(&ls_lbacls_rec->od->nbs->header_.uuid)); > + > + return ls_lbacls_rec; > +} > + > +static void > +ls_lbacls_record_destroy(struct ls_lbacls_record *ls_lbacls_rec) > +{ > + free(ls_lbacls_rec); > +} > + > +static void > +ls_lbacls_record_init(struct ls_lbacls_record *ls_lbacls_rec, > + const struct ovn_datapath *od, > + const struct ls_port_group *ls_pg, > + const struct ls_port_group_table *ls_pgs) > +{ > + ls_lbacls_rec->has_lb_vip = ls_has_lb_vip(od); > + ls_lbacls_record_set_acl_flags(ls_lbacls_rec, od, ls_pg, ls_pgs); > +} > + > +static void > +ls_lbacls_record_reinit(struct ls_lbacls_record *ls_lbacls_rec, > + const struct ls_port_group *ls_pg, > + const struct ls_port_group_table *ls_pgs) > +{ > + ls_lbacls_record_init(ls_lbacls_rec, ls_lbacls_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_lbacls_record_set_acl_flags(struct ls_lbacls_record *ls_lbacls_rec, > + const struct ovn_datapath *od, > + const struct ls_port_group *ls_pg, > + const struct ls_port_group_table *ls_pgs) > +{ > + ls_lbacls_rec->has_stateful_acl = false; > + ls_lbacls_rec->max_acl_tier = 0; > + ls_lbacls_rec->has_acls = false; > + > + if (ls_lbacls_record_set_acl_flags_(ls_lbacls_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_lbacls_record_set_acl_flags_(ls_lbacls_rec, > + ls_pg_rec->nb_pg->acls, > + ls_pg_rec->nb_pg->n_acls)) { > + return; > + } > + } > +} > + > +static bool > +ls_lbacls_record_set_acl_flags_(struct ls_lbacls_record *ls_lbacls_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_lbacls record. A false return indicates that > + * further ACLs should be explored in case more flags need to be > + * set on ls_lbacls record. > + */ > + if (!n_acls) { > + return false; > + } > + > + ls_lbacls_rec->has_acls = true; > + for (size_t i = 0; i < n_acls; i++) { > + const struct nbrec_acl *acl = acls[i]; > + if (acl->tier > ls_lbacls_rec->max_acl_tier) { > + ls_lbacls_rec->max_acl_tier = acl->tier; > + } > + if (!ls_lbacls_rec->has_stateful_acl > + && !strcmp(acl->action, "allow-related")) { > + ls_lbacls_rec->has_stateful_acl = true; > + } > + if (ls_lbacls_rec->has_stateful_acl && > + ls_lbacls_rec->max_acl_tier == > + nbrec_acl_col_tier.type.value.integer.max) { > + return true; > + } > + } > + > + return false; > +} > + > +static struct ls_lbacls_input > +ls_lbacls_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_lbacls_input) { > + .nbrec_logical_switch_table = > + EN_OVSDB_GET(engine_get_input("NB_logical_switch", node)), > + .ls_port_groups = &pg_data->ls_port_groups, > + .ls_datapaths = &northd_data->ls_datapaths, > + }; > +} > + > +static bool > +is_acls_seqno_changed(struct nbrec_acl **nb_acls, size_t n_nb_acls) > +{ > + for (size_t i = 0; i < n_nb_acls; i++) { > + if (nbrec_acl_row_get_seqno(nb_acls[i], > + OVSDB_IDL_CHANGE_MODIFY) > 0) { > + return true; > + } > + } > + > + return false; > +} > + > +static bool > +is_ls_acls_changed(const struct nbrec_logical_switch *nbs) { > + return (nbrec_logical_switch_is_new(nbs) > + || nbrec_logical_switch_is_deleted(nbs) > + || nbrec_logical_switch_is_updated(nbs, > + NBREC_LOGICAL_SWITCH_COL_ACLS) > + || is_acls_seqno_changed(nbs->acls, nbs->n_acls)); > +} > diff --git a/northd/en-ls-lb-acls.h b/northd/en-ls-lb-acls.h > new file mode 100644 > index 0000000000..ccb75e40e8 > --- /dev/null > +++ b/northd/en-ls-lb-acls.h > @@ -0,0 +1,88 @@ > +/* > + * 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_LS_LB_ACL_H > +#define EN_LS_LB_ACL_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_lbacls_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_lbacls_table { > + struct hmap entries; > +}; > + > +#define LS_LBACLS_TABLE_FOR_EACH(LS_LBACLS_REC, TABLE) \ > + HMAP_FOR_EACH (LS_LBACLS_REC, key_node, &(TABLE)->entries) > + > +#define LS_LBACLS_TABLE_FOR_EACH_IN_P(LS_LBACLS_REC, JOBID, TABLE) \ > + HMAP_FOR_EACH_IN_PARALLEL (LS_LBACLS_REC, key_node, JOBID, \ > + &(TABLE)->entries) > + > +struct ls_lbacls_tracked_data { > + /* Created or updated logical switch with LB and ACL data. */ > + struct hmapx crupdated; /* Stores 'struct ls_lbacls_record'. */ > + > + /* Deleted logical switch with LB and ACL data. */ > + struct hmapx deleted; /* Stores 'struct ls_lbacls_record'. */ > +}; > + > +struct ed_type_ls_lbacls { > + struct ls_lbacls_table ls_lbacls; > + > + bool tracked; > + struct ls_lbacls_tracked_data tracked_data; > +}; > + > +struct ls_lbacls_input { > + const struct nbrec_logical_switch_table *nbrec_logical_switch_table; > + const struct ls_port_group_table *ls_port_groups; > + const struct ovn_datapaths *ls_datapaths; > +}; > + > +void *en_ls_lbacls_init(struct engine_node *, struct engine_arg *); > +void en_ls_lbacls_cleanup(void *data); > +void en_ls_lbacls_clear_tracked_data(void *data); > +void en_ls_lbacls_run(struct engine_node *, void *data); > + > +bool ls_lbacls_northd_handler(struct engine_node *, void *data); > +bool ls_lbacls_port_group_handler(struct engine_node *, void *data); > +bool ls_lbacls_logical_switch_handler(struct engine_node *, void *data); > + > +const struct ls_lbacls_record *ls_lbacls_table_find( > + const struct ls_lbacls_table *, const struct nbrec_logical_switch *); > + > +#endif /* EN_LS_LB_ACL_H */ > 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 84627070a8..ab4af92aeb 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-lb-nat-data.h" > #include "en-lr-nat.h" > +#include "en-ls-lb-acls.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_lb_nat_data, "lr_lb_nat_data"); > +static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(ls_lbacls, "ls_lbacls"); > > void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > struct ovsdb_idl_loop *sb) > @@ -205,6 +207,12 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > engine_add_input(&en_lr_lb_nat_data, &en_lb_data, > lr_lb_nat_data_lb_data_handler); > > + engine_add_input(&en_ls_lbacls, &en_northd, ls_lbacls_northd_handler); > + engine_add_input(&en_ls_lbacls, &en_port_group, > + ls_lbacls_port_group_handler); > + engine_add_input(&en_ls_lbacls, &en_nb_logical_switch, > + ls_lbacls_logical_switch_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); > @@ -229,6 +237,7 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > engine_add_input(&en_lflow, &en_northd, lflow_northd_handler); > engine_add_input(&en_lflow, &en_port_group, lflow_port_group_handler); > engine_add_input(&en_lflow, &en_lr_lb_nat_data, NULL); > + engine_add_input(&en_lflow, &en_ls_lbacls, NULL); > > engine_add_input(&en_sync_to_sb_addr_set, &en_nb_address_set, > sync_to_sb_addr_set_nb_address_set_handler); > diff --git a/northd/northd.c b/northd/northd.c > index c8a224d3cd..924f5cd7e0 100644 > --- a/northd/northd.c > +++ b/northd/northd.c > @@ -45,6 +45,7 @@ > #include "en-lb-data.h" > #include "en-lr-nat.h" > #include "en-lr-lb-nat-data.h" > +#include "en-ls-lb-acls.h" > #include "lib/ovn-parallel-hmap.h" > #include "ovn/actions.h" > #include "ovn/features.h" > @@ -575,7 +576,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])) { > @@ -592,7 +593,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])) { > @@ -608,13 +609,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); > } > } > > @@ -1058,7 +1059,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; > @@ -1089,7 +1089,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; > } > @@ -2570,7 +2569,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_lbnat_rec > + || !lr_lbnat_rec->has_lb_vip)) > || !eth_addr_from_string(op->nbrp->mac, &mac)) { > *n = n_nats; > return NULL; > @@ -3817,7 +3817,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 > && !smap_get(&od->nbr->options, "chassis")) { > static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); > VLOG_WARN_RL(&rl, "Load-balancers are configured on logical " > @@ -5441,7 +5441,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > BITMAP_FOR_EACH_1 (index, ods_size(ls_datapaths), > lb_dps->nb_ls_map) { > od = ls_datapaths->array[index]; > - init_lb_for_datapath(od); > > /* Add the ls datapath to the northd tracked data. */ > hmapx_add(&nd_changes->ls_with_changed_lbs.crupdated, od); > @@ -5524,9 +5523,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > } > } > > - /* Re-evaluate 'od->has_lb_vip' */ > - init_lb_for_datapath(od); > - > /* Add the ls datapath to the northd tracked data. */ > hmapx_add(&nd_changes->ls_with_changed_lbs.crupdated, od); > } > @@ -5564,9 +5560,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > } > } > > - /* Re-evaluate 'od->has_lb_vip' */ > - init_lb_for_datapath(od); > - > /* Add the lr datapath to the northd tracked data. */ > hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); > } > @@ -5581,8 +5574,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > BITMAP_FOR_EACH_1 (index, ods_size(ls_datapaths), > lb_dps->nb_ls_map) { > od = ls_datapaths->array[index]; > - /* Re-evaluate 'od->has_lb_vip' */ > - init_lb_for_datapath(od); > > /* Add the ls datapath to the northd tracked data. */ > hmapx_add(&nd_changes->ls_with_changed_lbs.crupdated, od); > @@ -5591,8 +5582,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > BITMAP_FOR_EACH_1 (index, ods_size(lr_datapaths), > lb_dps->nb_lr_map) { > od = lr_datapaths->array[index]; > - /* Re-evaluate 'od->has_lb_vip' */ > - init_lb_for_datapath(od); > > /* Add the lr datapath to the northd tracked data. */ > hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); > @@ -5618,9 +5607,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > od = lbgrp_dps->lr[i]; > ovn_lb_datapaths_add_lr(lb_dps, 1, &od); > > - /* Re-evaluate 'od->has_lb_vip' */ > - init_lb_for_datapath(od); > - > /* Add the lr datapath to the northd tracked data. */ > hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); > } > @@ -5629,9 +5615,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > od = lbgrp_dps->ls[i]; > ovn_lb_datapaths_add_ls(lb_dps, 1, &od); > > - /* Re-evaluate 'od->has_lb_vip' */ > - init_lb_for_datapath(od); > - > /* Add the ls datapath to the northd tracked data. */ > hmapx_add(&nd_changes->ls_with_changed_lbs.crupdated, od); > } > @@ -6573,63 +6556,6 @@ build_dhcpv6_action(struct ovn_port *op, struct in6_addr *offer_ip, > return true; > } > > -static bool > -od_set_acl_flags(struct ovn_datapath *od, struct nbrec_acl **acls, > - size_t n_acls) > -{ > - /* A true return indicates that there are no possible ACL flags > - * left to set on od. A false return indicates that further ACLs > - * should be explored in case more flags need to be set on od > - */ > - if (!n_acls) { > - return false; > - } > - > - od->has_acls = true; > - for (size_t i = 0; i < n_acls; i++) { > - const struct nbrec_acl *acl = acls[i]; > - if (acl->tier > od->max_acl_tier) { > - od->max_acl_tier = acl->tier; > - } > - if (!od->has_stateful_acl && !strcmp(acl->action, "allow-related")) { > - od->has_stateful_acl = true; > - } > - if (od->has_stateful_acl && > - od->max_acl_tier == nbrec_acl_col_tier.type.value.integer.max) { > - return true; > - } > - } > - > - return false; > -} > - > -static void > -ls_get_acl_flags(struct ovn_datapath *od, > - const struct ls_port_group_table *ls_port_groups) > -{ > - od->has_acls = false; > - od->has_stateful_acl = false; > - od->max_acl_tier = 0; > - > - if (od_set_acl_flags(od, od->nbs->acls, od->nbs->n_acls)) { > - return; > - } > - > - const struct ls_port_group *ls_pg = > - ls_port_group_table_find(ls_port_groups, 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 (od_set_acl_flags(od, ls_pg_rec->nb_pg->acls, > - ls_pg_rec->nb_pg->n_acls)) { > - return; > - } > - } > -} > - > /* Adds the logical flows in the (in/out) check port sec stage only if > * - the lport is disabled or > * - lport is of type vtep - to skip the ingress pipeline. > @@ -6774,9 +6700,10 @@ build_lswitch_output_port_sec_od(struct ovn_datapath *od, > } > > static void > -skip_port_from_conntrack(struct ovn_datapath *od, struct ovn_port *op, > - enum ovn_stage in_stage, enum ovn_stage out_stage, > - uint16_t priority, struct hmap *lflows) > +skip_port_from_conntrack(const struct ovn_datapath *od, struct ovn_port *op, > + bool has_stateful_acl, enum ovn_stage in_stage, > + enum ovn_stage out_stage, uint16_t priority, > + struct hmap *lflows) > { > /* Can't use ct() for router ports. Consider the following configuration: > * lp1(10.0.0.2) on hostA--ls1--lr0--ls2--lp2(10.0.1.2) on hostB, For a > @@ -6789,7 +6716,7 @@ skip_port_from_conntrack(struct ovn_datapath *od, struct ovn_port *op, > * conntrack state across all chassis. */ > > const char *ingress_action = "next;"; > - const char *egress_action = od->has_stateful_acl > + const char *egress_action = has_stateful_acl > ? "next;" > : "ct_clear; next;"; > > @@ -6808,7 +6735,7 @@ skip_port_from_conntrack(struct ovn_datapath *od, struct ovn_port *op, > } > > static void > -build_stateless_filter(struct ovn_datapath *od, > +build_stateless_filter(const struct ovn_datapath *od, > const struct nbrec_acl *acl, > struct hmap *lflows) > { > @@ -6829,7 +6756,7 @@ build_stateless_filter(struct ovn_datapath *od, > } > > static void > -build_stateless_filters(struct ovn_datapath *od, > +build_stateless_filters(const struct ovn_datapath *od, > const struct ls_port_group_table *ls_port_groups, > struct hmap *lflows) > { > @@ -6859,9 +6786,7 @@ build_stateless_filters(struct ovn_datapath *od, > } > > static void > -build_pre_acls(struct ovn_datapath *od, > - const struct ls_port_group_table *ls_port_groups, > - struct hmap *lflows) > +build_pre_acls(struct ovn_datapath *od, struct hmap *lflows) > { > /* Ingress and Egress Pre-ACL Table (Priority 0): Packets are > * allowed by default. */ > @@ -6873,18 +6798,26 @@ build_pre_acls(struct ovn_datapath *od, > > ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, > "eth.src == $svc_monitor_mac", "next;"); > +} > + > +static void > +build_ls_lbacls_rec_pre_acls(const struct ls_lbacls_record *ls_lbacls_rec, > + const struct ls_port_group_table *ls_port_groups, > + struct hmap *lflows) > +{ > + const struct ovn_datapath *od = ls_lbacls_rec->od; > > /* If there are any stateful ACL rules in this datapath, we may > * send IP packets for some (allow) filters through the conntrack action, > * which handles defragmentation, in order to match L4 headers. */ > - if (od->has_stateful_acl) { > + if (ls_lbacls_rec->has_stateful_acl) { > for (size_t i = 0; i < od->n_router_ports; i++) { > - skip_port_from_conntrack(od, od->router_ports[i], > + skip_port_from_conntrack(od, od->router_ports[i], true, > S_SWITCH_IN_PRE_ACL, S_SWITCH_OUT_PRE_ACL, > 110, lflows); > } > for (size_t i = 0; i < od->n_localnet_ports; i++) { > - skip_port_from_conntrack(od, od->localnet_ports[i], > + skip_port_from_conntrack(od, od->localnet_ports[i], true, > S_SWITCH_IN_PRE_ACL, > S_SWITCH_OUT_PRE_ACL, > 110, lflows); > @@ -6922,7 +6855,7 @@ build_pre_acls(struct ovn_datapath *od, > REGBIT_CONNTRACK_DEFRAG" = 1; next;"); > ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 100, "ip", > REGBIT_CONNTRACK_DEFRAG" = 1; next;"); > - } else if (od->has_lb_vip) { > + } else if (ls_lbacls_rec->has_lb_vip) { > /* We'll build stateless filters if there are LB rules so that > * the stateless flows are not tracked in pre-lb. */ > build_stateless_filters(od, ls_port_groups, lflows); > @@ -7050,30 +6983,40 @@ build_pre_lb(struct ovn_datapath *od, const struct shash *meter_groups, > ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 0, "1", "next;"); > ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 0, "1", "next;"); > > + /* Do not send statless flows via conntrack */ > + ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110, > + REGBIT_ACL_STATELESS" == 1", "next;"); > + ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110, > + REGBIT_ACL_STATELESS" == 1", "next;"); > +} > + > +static void > +build_ls_lbacls_rec_pre_lb(const struct ls_lbacls_record *ls_lbacls_rec, > + struct hmap *lflows) > +{ > + const struct ovn_datapath *od = ls_lbacls_rec->od; > + > for (size_t i = 0; i < od->n_router_ports; i++) { > skip_port_from_conntrack(od, od->router_ports[i], > + ls_lbacls_rec->has_stateful_acl, > S_SWITCH_IN_PRE_LB, S_SWITCH_OUT_PRE_LB, > 110, lflows); > } > + > /* Localnet ports have no need for going through conntrack, unless > * the logical switch has a load balancer. Then, conntrack is necessary > * so that traffic arriving via the localnet port can be load > * balanced. > */ > - if (!od->has_lb_vip) { > + if (!ls_lbacls_rec->has_lb_vip) { > for (size_t i = 0; i < od->n_localnet_ports; i++) { > skip_port_from_conntrack(od, od->localnet_ports[i], > + ls_lbacls_rec->has_stateful_acl, > S_SWITCH_IN_PRE_LB, S_SWITCH_OUT_PRE_LB, > 110, lflows); > } > } > > - /* Do not sent statless flows via conntrack */ > - ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110, > - REGBIT_ACL_STATELESS" == 1", "next;"); > - ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110, > - REGBIT_ACL_STATELESS" == 1", "next;"); > - > /* 'REGBIT_CONNTRACK_NAT' is set to let the pre-stateful table send > * packet to conntrack for defragmentation and possibly for unNATting. > * > @@ -7104,7 +7047,7 @@ build_pre_lb(struct ovn_datapath *od, const struct shash *meter_groups, > * ingress pipeline if a load balancer is configured. We can now > * add a lflow to drop ct.inv packets. > */ > - if (od->has_lb_vip) { > + if (ls_lbacls_rec->has_lb_vip) { > ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, > 100, "ip", REGBIT_CONNTRACK_NAT" = 1; next;"); > ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, > @@ -7145,10 +7088,12 @@ build_pre_stateful(struct ovn_datapath *od, > } > > static void > -build_acl_hints(struct ovn_datapath *od, > +build_acl_hints(const struct ls_lbacls_record *ls_lbacls_rec, > const struct chassis_features *features, > struct hmap *lflows) > { > + const struct ovn_datapath *od = ls_lbacls_rec->od; > + > /* This stage builds hints for the IN/OUT_ACL stage. Based on various > * combinations of ct flags packets may hit only a subset of the logical > * flows in the IN/OUT_ACL stage. > @@ -7172,13 +7117,13 @@ build_acl_hints(struct ovn_datapath *od, > const char *match; > > /* In any case, advance to the next stage. */ > - if (!od->has_acls && !od->has_lb_vip) { > + if (!ls_lbacls_rec->has_acls && !ls_lbacls_rec->has_lb_vip) { > ovn_lflow_add(lflows, od, stage, UINT16_MAX, "1", "next;"); > } else { > ovn_lflow_add(lflows, od, stage, 0, "1", "next;"); > } > > - if (!od->has_stateful_acl && !od->has_lb_vip) { > + if (!ls_lbacls_rec->has_stateful_acl && !ls_lbacls_rec->has_lb_vip) { > continue; > } > > @@ -7314,10 +7259,10 @@ build_acl_log(struct ds *actions, const struct nbrec_acl *acl, > } > > static void > -consider_acl(struct hmap *lflows, struct ovn_datapath *od, > +consider_acl(struct hmap *lflows, const struct ovn_datapath *od, > const struct nbrec_acl *acl, bool has_stateful, > bool ct_masked_mark, const struct shash *meter_groups, > - struct ds *match, struct ds *actions) > + uint64_t max_acl_tier, struct ds *match, struct ds *actions) > { > const char *ct_blocked_match = ct_masked_mark > ? "ct_mark.blocked" > @@ -7354,7 +7299,7 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, > /* All ACLS will start by matching on their respective tier. */ > size_t match_tier_len = 0; > ds_clear(match); > - if (od->max_acl_tier) { > + if (max_acl_tier) { > ds_put_format(match, REG_ACL_TIER " == %"PRId64" && ", acl->tier); > match_tier_len = match->length; > } > @@ -7543,12 +7488,15 @@ ovn_update_ipv6_options(struct hmap *lr_ports) > #define IPV6_CT_OMIT_MATCH "nd || nd_ra || nd_rs || mldv1 || mldv2" > > static void > -build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, > +build_acl_action_lflows(const struct ls_lbacls_record *ls_lbacls_rec, > + struct hmap *lflows, > const char *default_acl_action, > const struct shash *meter_groups, > struct ds *match, > struct ds *actions) > { > + const struct ovn_datapath *od = ls_lbacls_rec->od; > + > enum ovn_stage stages [] = { > S_SWITCH_IN_ACL_ACTION, > S_SWITCH_IN_ACL_AFTER_LB_ACTION, > @@ -7559,7 +7507,7 @@ build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, > ds_put_cstr(actions, REGBIT_ACL_VERDICT_ALLOW " = 0; " > REGBIT_ACL_VERDICT_DROP " = 0; " > REGBIT_ACL_VERDICT_REJECT " = 0; "); > - if (od->max_acl_tier) { > + if (ls_lbacls_rec->max_acl_tier) { > ds_put_cstr(actions, REG_ACL_TIER " = 0; "); > } > > @@ -7567,7 +7515,7 @@ build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, > > for (size_t i = 0; i < ARRAY_SIZE(stages); i++) { > enum ovn_stage stage = stages[i]; > - if (!od->has_acls) { > + if (!ls_lbacls_rec->has_acls) { > ovn_lflow_add(lflows, od, stage, 0, "1", "next;"); > continue; > } > @@ -7602,7 +7550,7 @@ build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, > ovn_lflow_add(lflows, od, stage, 0, "1", ds_cstr(actions)); > > struct ds tier_actions = DS_EMPTY_INITIALIZER; > - for (size_t j = 0; j < od->max_acl_tier; j++) { > + for (size_t j = 0; j < ls_lbacls_rec->max_acl_tier; j++) { > ds_clear(match); > ds_put_format(match, REG_ACL_TIER " == %"PRIuSIZE, j); > ds_clear(&tier_actions); > @@ -7618,7 +7566,7 @@ build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, > } > > static void > -build_acl_log_related_flows(struct ovn_datapath *od, struct hmap *lflows, > +build_acl_log_related_flows(const struct ovn_datapath *od, struct hmap *lflows, > const struct nbrec_acl *acl, bool has_stateful, > bool ct_masked_mark, > const struct shash *meter_groups, > @@ -7691,15 +7639,19 @@ build_acl_log_related_flows(struct ovn_datapath *od, struct hmap *lflows, > } > > static void > -build_acls(struct ovn_datapath *od, const struct chassis_features *features, > +build_acls(const struct ls_lbacls_record *ls_lbacls_rec, > + const struct chassis_features *features, > struct hmap *lflows, > const struct ls_port_group_table *ls_port_groups, > const struct shash *meter_groups) > { > + const struct ovn_datapath *od = ls_lbacls_rec->od; > + > const char *default_acl_action = default_acl_drop > ? debug_implicit_drop_action() > : "next;"; > - bool has_stateful = od->has_stateful_acl || od->has_lb_vip; > + bool has_stateful = (ls_lbacls_rec->has_stateful_acl > + || ls_lbacls_rec->has_lb_vip); > const char *ct_blocked_match = features->ct_no_masked_label > ? "ct_mark.blocked" > : "ct_label.blocked"; > @@ -7713,8 +7665,8 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, > * > * A related rule at priority 1 is added below if there > * are any stateful ACLs in this datapath. */ > - if (!od->has_acls) { > - if (!od->has_lb_vip) { > + if (!ls_lbacls_rec->has_acls) { > + if (!ls_lbacls_rec->has_lb_vip) { > ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX, "1", > "next;"); > ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX, "1", > @@ -7877,7 +7829,8 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, > meter_groups, &match, &actions); > consider_acl(lflows, od, acl, has_stateful, > features->ct_no_masked_label, > - meter_groups, &match, &actions); > + meter_groups, ls_lbacls_rec->max_acl_tier, > + &match, &actions); > } > > const struct ls_port_group *ls_pg = > @@ -7893,7 +7846,8 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, > meter_groups, &match, &actions); > consider_acl(lflows, od, acl, has_stateful, > features->ct_no_masked_label, > - meter_groups, &match, &actions); > + meter_groups, ls_lbacls_rec->max_acl_tier, > + &match, &actions); > } > } > } > @@ -7911,7 +7865,7 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, > dns_actions); > } > > - if (od->has_acls || od->has_lb_vip) { > + if (ls_lbacls_rec->has_acls || ls_lbacls_rec->has_lb_vip) { > /* Add a 34000 priority flow to advance the service monitor reply > * packets to skip applying ingress ACLs. */ > ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 34000, > @@ -7925,8 +7879,8 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, > REGBIT_ACL_VERDICT_ALLOW" = 1; next;"); > } > > - build_acl_action_lflows(od, lflows, default_acl_action, meter_groups, > - &match, &actions); > + build_acl_action_lflows(ls_lbacls_rec, lflows, default_acl_action, > + meter_groups, &match, &actions); > > ds_destroy(&match); > ds_destroy(&actions); > @@ -8571,8 +8525,11 @@ build_stateful(struct ovn_datapath *od, > } > > static void > -build_lb_hairpin(struct ovn_datapath *od, struct hmap *lflows) > +build_lb_hairpin(const struct ls_lbacls_record *ls_lbacls_rec, > + struct hmap *lflows) > { > + const struct ovn_datapath *od = ls_lbacls_rec->od; > + > /* Ingress Pre-Hairpin/Nat-Hairpin/Hairpin tabled (Priority 0). > * Packets that don't need hairpinning should continue processing. > */ > @@ -8580,7 +8537,7 @@ build_lb_hairpin(struct ovn_datapath *od, struct hmap *lflows) > ovn_lflow_add(lflows, od, S_SWITCH_IN_NAT_HAIRPIN, 0, "1", "next;"); > ovn_lflow_add(lflows, od, S_SWITCH_IN_HAIRPIN, 0, "1", "next;"); > > - if (od->has_lb_vip) { > + if (ls_lbacls_rec->has_lb_vip) { > /* Check if the packet needs to be hairpinned. > * Set REGBIT_HAIRPIN in the original direction and > * REGBIT_HAIRPIN_REPLY in the reply direction. > @@ -9413,22 +9370,16 @@ build_lswitch_lflows_l2_unknown(struct ovn_datapath *od, > static void > build_lswitch_lflows_pre_acl_and_acl( > struct ovn_datapath *od, > - const struct ls_port_group_table *ls_port_groups, > const struct chassis_features *features, > struct hmap *lflows, > const struct shash *meter_groups) > { > ovs_assert(od->nbs); > - ls_get_acl_flags(od, ls_port_groups); > - > - build_pre_acls(od, ls_port_groups, lflows); > + build_pre_acls(od, lflows); > build_pre_lb(od, meter_groups, lflows); > build_pre_stateful(od, features, lflows); > - build_acl_hints(od, features, lflows); > - build_acls(od, features, lflows, ls_port_groups, meter_groups); > build_qos(od, lflows); > build_stateful(od, features, lflows); > - build_lb_hairpin(od, lflows); > build_vtep_hairpin(od, lflows); > } > > @@ -15487,7 +15438,7 @@ build_lrouter_nat_defrag_and_lb( > * a dynamically negotiated FTP data channel), but will allow > * related traffic such as an ICMP Port Unreachable through > * that's generated from a non-listening UDP port. */ > - if (od->has_lb_vip && features->ct_lb_related) { > + if (lr_lbnat_rec->has_lb_vip && features->ct_lb_related) { > ds_clear(match); > > ds_put_cstr(match, "ct.rel && !ct.est && !ct.new"); > @@ -15512,7 +15463,7 @@ build_lrouter_nat_defrag_and_lb( > * Pass the traffic that is already established to the next table with > * proper flags set. > */ > - if (od->has_lb_vip) { > + if (lr_lbnat_rec->has_lb_vip) { > ds_clear(match); > > ds_put_format(match, "ct.est && !ct.rel && !ct.new && %s.natted", > @@ -15542,7 +15493,7 @@ build_lrouter_nat_defrag_and_lb( > * not committed, it would produce ongoing datapath flows with the ct.new > * flag set. Some NICs are unable to offload these flows. > */ > - if (od->is_gw_router && (od->nbr->n_nat || od->has_lb_vip)) { > + if (od->is_gw_router && (od->nbr->n_nat || lr_lbnat_rec->has_lb_vip)) { > /* Do not send ND or ICMP packets to connection tracking. */ > ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 100, > "nd || nd_rs || nd_ra", "next;"); > @@ -15967,6 +15918,22 @@ build_lr_lbnat_data_flows(const struct lr_lb_nat_data_record *lr_lbnat_rec, > meter_groups); > } > > +static void > +build_ls_lbacls_flows(const struct ls_lbacls_record *ls_lbacls_rec, > + const struct ls_port_group_table *ls_pgs, > + const struct chassis_features *features, > + const struct shash *meter_groups, > + struct hmap *lflows) > +{ > + ovs_assert(ls_lbacls_rec->od); > + > + build_ls_lbacls_rec_pre_acls(ls_lbacls_rec, ls_pgs, lflows); > + build_ls_lbacls_rec_pre_lb(ls_lbacls_rec, lflows); > + build_acl_hints(ls_lbacls_rec, features, lflows); > + build_acls(ls_lbacls_rec, features, lflows, ls_pgs, meter_groups); > + build_lb_hairpin(ls_lbacls_rec, lflows); > +} > + > struct lswitch_flow_build_info { > const struct ovn_datapaths *ls_datapaths; > const struct ovn_datapaths *lr_datapaths; > @@ -15974,6 +15941,7 @@ struct lswitch_flow_build_info { > const struct hmap *lr_ports; > const struct ls_port_group_table *ls_port_groups; > const struct lr_lb_nat_data_table *lr_lbnats; > + const struct ls_lbacls_table *ls_lbacls; > struct hmap *lflows; > struct hmap *igmp_groups; > const struct shash *meter_groups; > @@ -15998,9 +15966,7 @@ build_lswitch_and_lrouter_iterate_by_ls(struct ovn_datapath *od, > struct lswitch_flow_build_info *lsi) > { > ovs_assert(od->nbs); > - build_lswitch_lflows_pre_acl_and_acl(od, lsi->ls_port_groups, > - lsi->features, > - lsi->lflows, > + build_lswitch_lflows_pre_acl_and_acl(od, lsi->features, lsi->lflows, > lsi->meter_groups); > > build_fwd_group_lflows(od, lsi->lflows); > @@ -16115,6 +16081,7 @@ build_lflows_thread(void *arg) > { > struct worker_control *control = (struct worker_control *) arg; > const struct lr_lb_nat_data_record *lr_lbnat_rec; > + const struct ls_lbacls_record *ls_lbacls_rec; > struct lswitch_flow_build_info *lsi; > struct ovn_igmp_group *igmp_group; > struct ovn_lb_datapaths *lb_dps; > @@ -16243,6 +16210,19 @@ build_lflows_thread(void *arg) > lsi->features); > } > } > + > + for (bnum = control->id; > + bnum <= lsi->ls_lbacls->entries.mask; > + bnum += control->pool->size) > + { > + LS_LBACLS_TABLE_FOR_EACH_IN_P (ls_lbacls_rec, bnum, > + lsi->ls_lbacls) { > + build_ls_lbacls_flows(ls_lbacls_rec, lsi->ls_port_groups, > + lsi->features, lsi->meter_groups, > + lsi->lflows); > + } > + } > + > for (bnum = control->id; > bnum <= lsi->igmp_groups->mask; > bnum += control->pool->size) > @@ -16303,6 +16283,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > const struct hmap *lr_ports, > const struct ls_port_group_table *ls_pgs, > const struct lr_lb_nat_data_table *lr_lbnats, > + const struct ls_lbacls_table *ls_lbacls, > struct hmap *lflows, > struct hmap *igmp_groups, > const struct shash *meter_groups, > @@ -16333,6 +16314,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > lsiv[index].lr_ports = lr_ports; > lsiv[index].ls_port_groups = ls_pgs; > lsiv[index].lr_lbnats = lr_lbnats; > + lsiv[index].ls_lbacls = ls_lbacls; > lsiv[index].igmp_groups = igmp_groups; > lsiv[index].meter_groups = meter_groups; > lsiv[index].lb_dps_map = lb_dps_map; > @@ -16358,6 +16340,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > free(lsiv); > } else { > const struct lr_lb_nat_data_record *lr_lbnat_rec; > + const struct ls_lbacls_record *ls_lbacls_rec; > struct ovn_igmp_group *igmp_group; > struct ovn_lb_datapaths *lb_dps; > struct ovn_datapath *od; > @@ -16370,6 +16353,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > .lr_ports = lr_ports, > .ls_port_groups = ls_pgs, > .lr_lbnats = lr_lbnats, > + .ls_lbacls = ls_lbacls, > .lflows = lflows, > .igmp_groups = igmp_groups, > .meter_groups = meter_groups, > @@ -16439,6 +16423,12 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > lsi.features); > } > > + LS_LBACLS_TABLE_FOR_EACH (ls_lbacls_rec, ls_lbacls) { > + build_ls_lbacls_flows(ls_lbacls_rec, lsi.ls_port_groups, > + lsi.features, lsi.meter_groups, > + lsi.lflows); > + } > + > stopwatch_start(LFLOWS_IGMP_STOPWATCH_NAME, time_msec()); > HMAP_FOR_EACH (igmp_group, hmap_node, igmp_groups) { > build_lswitch_ip_mcast_igmp_mld(igmp_group, > @@ -16535,6 +16525,7 @@ void build_lflows(struct ovsdb_idl_txn *ovnsb_txn, > input_data->lr_ports, > input_data->ls_port_groups, > input_data->lr_lbnats, > + input_data->ls_lbacls, > lflows, > &igmp_groups, > input_data->meter_groups, > diff --git a/northd/northd.h b/northd/northd.h > index 08a81b2c10..23b4754db4 100644 > --- a/northd/northd.h > +++ b/northd/northd.h > @@ -89,6 +89,8 @@ ods_size(const struct ovn_datapaths *datapaths) > return hmap_count(&datapaths->datapaths); > } > > +bool od_has_lb_vip(const struct ovn_datapath *od); > + > struct tracked_ovn_ports { > /* tracked created ports. > * hmapx node data is 'struct ovn_port *' */ > @@ -179,6 +181,7 @@ struct lflow_input { > const struct hmap *lr_ports; > const struct ls_port_group_table *ls_port_groups; > const struct lr_lb_nat_data_table *lr_lbnats; > + const struct ls_lbacls_table *ls_lbacls; > const struct shash *meter_groups; > const struct hmap *lb_datapaths_map; > const struct hmap *bfd_connections; > @@ -288,11 +291,7 @@ struct ovn_datapath { > struct hmap port_tnlids; > uint32_t port_key_hint; > > - bool has_stateful_acl; > - bool has_lb_vip; > bool has_unknown; > - bool has_acls; > - uint64_t max_acl_tier; > bool has_vtep_lports; > bool has_arp_proxy_port; >
On Fri, Nov 24, 2023 at 5:54 AM Dumitru Ceara <dceara@redhat.com> wrote: > > On 10/26/23 20:15, numans@ovn.org wrote: > > From: Numan Siddique <numans@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 > > - NB logical switch node > > - Port group node > > > > A record for each logical switch is maintained in the 'ls_lbacls' > > 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. > > > > Signed-off-by: Numan Siddique <numans@ovn.org> > > --- > > lib/stopwatch-names.h | 1 + > > northd/automake.mk | 2 + > > northd/en-lflow.c | 4 + > > northd/en-lr-lb-nat-data.c | 8 +- > > northd/en-lr-lb-nat-data.h | 2 + > > northd/en-ls-lb-acls.c | 527 +++++++++++++++++++++++++++++++++++++ > > northd/en-ls-lb-acls.h | 88 +++++++ > > northd/en-port-group.h | 3 + > > northd/inc-proc-northd.c | 9 + > > northd/northd.c | 271 +++++++++---------- > > northd/northd.h | 7 +- > > 11 files changed, 776 insertions(+), 146 deletions(-) > > create mode 100644 northd/en-ls-lb-acls.c > > create mode 100644 northd/en-ls-lb-acls.h > > > > diff --git a/lib/stopwatch-names.h b/lib/stopwatch-names.h > > index 7d85acdaea..8b0018a593 100644 > > --- a/lib/stopwatch-names.h > > +++ b/lib/stopwatch-names.h > > @@ -34,5 +34,6 @@ > > #define SYNC_METERS_RUN_STOPWATCH_NAME "sync_meters_run" > > #define LR_NAT_RUN_STOPWATCH_NAME "lr_nat_run" > > #define LR_LB_NAT_DATA_RUN_STOPWATCH_NAME "lr_lb_nat_data" > > +#define LS_LBACLS_RUN_STOPWATCH_NAME "lr_lb_acls" > > > > #endif > > diff --git a/northd/automake.mk b/northd/automake.mk > > index 4116c487df..4593654726 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-lb-nat-data.c \ > > northd/en-lr-lb-nat-data.h \ > > + northd/en-ls-lb-acls.c \ > > + northd/en-ls-lb-acls.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 229f4be1d0..648a477916 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-lb-nat-data.h" > > +#include "en-ls-lb-acls.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_lb_nat_data *lr_lb_nat_data = > > engine_get_input_data("lr_lb_nat_data", node); > > + struct ed_type_ls_lbacls *ls_lbacls_data = > > + engine_get_input_data("ls_lbacls", 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_lbnats = &lr_lb_nat_data->lr_lbnats; > > + lflow_input->ls_lbacls = &ls_lbacls_data->ls_lbacls; > > 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-lb-nat-data.c b/northd/en-lr-lb-nat-data.c > > index 19b638ce0b..d816d2321d 100644 > > --- a/northd/en-lr-lb-nat-data.c > > +++ b/northd/en-lr-lb-nat-data.c > > @@ -299,9 +299,11 @@ lr_lb_nat_data_lb_data_handler(struct engine_node *node, void *data_) > > if (!hmapx_is_empty(&data->tracked_data.crupdated)) { > > struct hmapx_node *hmapx_node; > > /* For all the modified lr_lb_nat_data records (re)build the > > - * vip nats. */ > > + * vip nats and re-evaluate 'has_lb_vip'. */ > > HMAPX_FOR_EACH (hmapx_node, &data->tracked_data.crupdated) { > > - lr_lb_nat_data_build_vip_nats(hmapx_node->data); > > + lr_lbnat_rec = hmapx_node->data; > > + lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); > > + lr_lbnat_rec->has_lb_vip = od_has_lb_vip(lr_lbnat_rec->od); > > } > > > > data->tracked = true; > > @@ -523,6 +525,8 @@ lr_lb_nat_data_record_init(struct lr_lb_nat_data_record *lr_lbnat_rec, > > if (!nbr->n_nat) { > > lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); > > } > > + > > + lr_lbnat_rec->has_lb_vip = od_has_lb_vip(lr_lbnat_rec->od); > > } > > > > static struct lr_lb_nat_data_input > > diff --git a/northd/en-lr-lb-nat-data.h b/northd/en-lr-lb-nat-data.h > > index ffe41cad73..ac21d28a57 100644 > > --- a/northd/en-lr-lb-nat-data.h > > +++ b/northd/en-lr-lb-nat-data.h > > @@ -39,6 +39,8 @@ struct lr_lb_nat_data_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-lb-acls.c b/northd/en-ls-lb-acls.c > > new file mode 100644 > > index 0000000000..1ba7ecb3e2 > > --- /dev/null > > +++ b/northd/en-ls-lb-acls.c > > @@ -0,0 +1,527 @@ > > +/* > > + * 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 <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-lb-acls.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_lbacls); > > + > > +/* Static function declarations. */ > > +static void ls_lbacls_table_init(struct ls_lbacls_table *); > > +static void ls_lbacls_table_clear(struct ls_lbacls_table *); > > +static void ls_lbacls_table_destroy(struct ls_lbacls_table *); > > +static struct ls_lbacls_record *ls_lbacls_table_find_( > > + const struct ls_lbacls_table *, const struct nbrec_logical_switch *); > > +static void ls_lbacls_table_build(struct ls_lbacls_table *, > > + const struct ovn_datapaths *ls_datapaths, > > + const struct ls_port_group_table *); > > + > > +static struct ls_lbacls_input ls_lbacls_get_input_data( > > + struct engine_node *); > > + > > +static struct ls_lbacls_record *ls_lbacls_record_create( > > + struct ls_lbacls_table *, > > + const struct ovn_datapath *, > > + const struct ls_port_group_table *); > > +static void ls_lbacls_record_destroy(struct ls_lbacls_record *); > > +static void ls_lbacls_record_init( > > + struct ls_lbacls_record *, > > + const struct ovn_datapath *, > > + const struct ls_port_group *, > > + const struct ls_port_group_table *); > > +static void ls_lbacls_record_reinit( > > + struct ls_lbacls_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_lbacls_record_set_acl_flags(struct ls_lbacls_record *, > > + const struct ovn_datapath *, > > + const struct ls_port_group *, > > + const struct ls_port_group_table *); > > +static bool ls_lbacls_record_set_acl_flags_(struct ls_lbacls_record *, > > + struct nbrec_acl **, > > + size_t n_acls); > > +static struct ls_lbacls_input ls_lbacls_get_input_data(struct engine_node *); > > +static bool is_ls_acls_changed(const struct nbrec_logical_switch *); > > +static bool is_acls_seqno_changed(struct nbrec_acl **, size_t n_nb_acls); > > + > > + > > +/* public functions. */ > > +const struct ls_lbacls_record * > > +ls_lbacls_table_find( > > + const struct ls_lbacls_table *table, > > + const struct nbrec_logical_switch *nbs) > > +{ > > + return ls_lbacls_table_find_(table, nbs); > > +} > > + > > +void * > > +en_ls_lbacls_init(struct engine_node *node OVS_UNUSED, > > + struct engine_arg *arg OVS_UNUSED) > > +{ > > + struct ed_type_ls_lbacls *data = xzalloc(sizeof *data); > > + ls_lbacls_table_init(&data->ls_lbacls); > > + hmapx_init(&data->tracked_data.crupdated); > > + hmapx_init(&data->tracked_data.deleted); > > + return data; > > +} > > + > > +void > > +en_ls_lbacls_cleanup(void *data_) > > +{ > > + struct ed_type_ls_lbacls *data = > > + (struct ed_type_ls_lbacls *) data_; > > + ls_lbacls_table_destroy(&data->ls_lbacls); > > + hmapx_destroy(&data->tracked_data.crupdated); > > + hmapx_destroy(&data->tracked_data.deleted); > > +} > > + > > +void > > +en_ls_lbacls_clear_tracked_data(void *data_) > > +{ > > + struct ed_type_ls_lbacls *data = > > + (struct ed_type_ls_lbacls *) data_; > > + > > + struct hmapx_node *hmapx_node; > > + HMAPX_FOR_EACH_SAFE (hmapx_node, &data->tracked_data.deleted) { > > + ls_lbacls_record_destroy(hmapx_node->data); > > + hmapx_delete(&data->tracked_data.deleted, hmapx_node); > > + } > > + > > + hmapx_clear(&data->tracked_data.crupdated); > > + data->tracked = false; > > +} > > + > > +void > > +en_ls_lbacls_run(struct engine_node *node, void *data_) > > +{ > > + struct ls_lbacls_input input_data = ls_lbacls_get_input_data(node); > > + struct ed_type_ls_lbacls *data = data_; > > + > > + stopwatch_start(LS_LBACLS_RUN_STOPWATCH_NAME, time_msec()); > > + > > + ls_lbacls_table_clear(&data->ls_lbacls); > > + ls_lbacls_table_build(&data->ls_lbacls, input_data.ls_datapaths, > > + input_data.ls_port_groups); > > + > > + data->tracked = false; > > + stopwatch_stop(LS_LBACLS_RUN_STOPWATCH_NAME, time_msec()); > > Same comment about missing stopwatch_start(LS_LBACLS_RUN_STOPWATCH_NAME, > ...) as in the previous patch in this series. Ack. Addressed in v3. Numan > > Thanks, > Dumitru > > > + engine_set_node_state(node, EN_UPDATED); > > +} > > + > > +/* Handler functions. */ > > +bool > > +ls_lbacls_northd_handler(struct engine_node *node, void *data_) > > +{ > > + struct northd_data *northd_data = engine_get_input_data("northd", node); > > + if (!northd_data->change_tracked) { > > + return false; > > + } > > + > > + struct northd_tracked_data *nd_changes = &northd_data->trk_northd_changes; > > + struct ls_lbacls_input input_data = ls_lbacls_get_input_data(node); > > + struct ls_lbacls_record *ls_lbacls_rec; > > + struct ed_type_ls_lbacls *data = data_; > > + const struct ovn_datapath *od; > > + struct hmapx_node *hmapx_node; > > + > > + HMAPX_FOR_EACH (hmapx_node, &nd_changes->ls_with_changed_lbs.crupdated) { > > + od = hmapx_node->data; > > + > > + ls_lbacls_rec = ls_lbacls_table_find_(&data->ls_lbacls, od->nbs); > > + if (!ls_lbacls_rec) { > > + ls_lbacls_rec = ls_lbacls_record_create(&data->ls_lbacls, od, > > + input_data.ls_port_groups); > > + } else { > > + ls_lbacls_record_reinit(ls_lbacls_rec, NULL, > > + input_data.ls_port_groups); > > + } > > + > > + /* Add the ls_lbacls_rec to the tracking data. */ > > + hmapx_add(&data->tracked_data.crupdated, ls_lbacls_rec); > > + } > > + > > + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { > > + data->tracked = true; > > + engine_set_node_state(node, EN_UPDATED); > > + } > > + > > + return true; > > +} > > + > > +bool > > +ls_lbacls_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_lbacls_rec. > > + * This is still better than returning false. */ > > + struct ls_lbacls_input input_data = ls_lbacls_get_input_data(node); > > + struct ed_type_ls_lbacls *data = data_; > > + const struct ls_port_group *ls_pg; > > + > > + LS_PORT_GROUP_TABLE_FOR_EACH (ls_pg, input_data.ls_port_groups) { > > + struct ls_lbacls_record *ls_lbacls_rec = > > + ls_lbacls_table_find_(&data->ls_lbacls, ls_pg->nbs); > > + > > + bool modified = false; > > + if (!ls_lbacls_rec) { > > + const struct ovn_datapath *od; > > + od = ovn_datapath_find(&input_data.ls_datapaths->datapaths, > > + &ls_pg->nbs->header_.uuid); > > + ovs_assert(od); > > + ls_lbacls_rec = ls_lbacls_record_create(&data->ls_lbacls, od, > > + input_data.ls_port_groups); > > + modified = true; > > + } else { > > + bool had_stateful_acl = ls_lbacls_rec->has_stateful_acl; > > + uint64_t max_acl_tier = ls_lbacls_rec->max_acl_tier; > > + bool had_acls = ls_lbacls_rec->has_acls; > > + > > + ls_lbacls_record_reinit(ls_lbacls_rec, ls_pg, > > + input_data.ls_port_groups); > > + > > + if ((had_stateful_acl != ls_lbacls_rec->has_stateful_acl) > > + || (had_acls != ls_lbacls_rec->has_acls) > > + || max_acl_tier != ls_lbacls_rec->max_acl_tier) { > > + modified = true; > > + } > > + } > > + > > + if (modified) { > > + /* Add the ls_lbacls_rec to the tracking data. */ > > + hmapx_add(&data->tracked_data.crupdated, ls_lbacls_rec); > > + } > > + } > > + > > + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { > > + data->tracked = true; > > + engine_set_node_state(node, EN_UPDATED); > > + } > > + > > + return true; > > +} > > + > > +bool > > +ls_lbacls_logical_switch_handler(struct engine_node *node, void *data_) > > +{ > > + struct ls_lbacls_input input_data = ls_lbacls_get_input_data(node); > > + const struct nbrec_logical_switch *nbs; > > + struct ed_type_ls_lbacls *data = data_; > > + > > + NBREC_LOGICAL_SWITCH_TABLE_FOR_EACH_TRACKED (nbs, > > + input_data.nbrec_logical_switch_table) { > > + if (!is_ls_acls_changed(nbs)) { > > + continue; > > + } > > + > > + struct ls_lbacls_record *ls_lbacls_rec = > > + ls_lbacls_table_find_(&data->ls_lbacls, nbs); > > + > > + if (nbrec_logical_switch_is_deleted(nbs)) { > > + if (ls_lbacls_rec) { > > + /* Remove the record from the entries. */ > > + hmap_remove(&data->ls_lbacls.entries, > > + &ls_lbacls_rec->key_node); > > + > > + /* Add the ls_lbacls_rec to the tracking data. */ > > + hmapx_add(&data->tracked_data.deleted, ls_lbacls_rec); > > + } > > + } else { > > + if (!ls_lbacls_rec) { > > + const struct ovn_datapath *od; > > + od = ovn_datapath_find(&input_data.ls_datapaths->datapaths, > > + &nbs->header_.uuid); > > + ovs_assert(od); > > + ls_lbacls_rec = ls_lbacls_record_create(&data->ls_lbacls, od, > > + input_data.ls_port_groups); > > + } else { > > + ls_lbacls_record_reinit(ls_lbacls_rec, NULL, > > + input_data.ls_port_groups); > > + } > > + > > + /* Add the ls_lbacls_rec to the tracking data. */ > > + hmapx_add(&data->tracked_data.crupdated, ls_lbacls_rec); > > + } > > + } > > + > > + if (!hmapx_is_empty(&data->tracked_data.crupdated) > > + || !hmapx_is_empty(&data->tracked_data.deleted)) { > > + data->tracked = true; > > + engine_set_node_state(node, EN_UPDATED); > > + } > > + > > + return true; > > +} > > + > > +/* static functions. */ > > +static void > > +ls_lbacls_table_init(struct ls_lbacls_table *table) > > +{ > > + *table = (struct ls_lbacls_table) { > > + .entries = HMAP_INITIALIZER(&table->entries), > > + }; > > +} > > + > > +static void > > +ls_lbacls_table_destroy(struct ls_lbacls_table *table) > > +{ > > + ls_lbacls_table_clear(table); > > + hmap_destroy(&table->entries); > > +} > > + > > +static void > > +ls_lbacls_table_clear(struct ls_lbacls_table *table) > > +{ > > + struct ls_lbacls_record *ls_lbacls_rec; > > + HMAP_FOR_EACH_POP (ls_lbacls_rec, key_node, &table->entries) { > > + ls_lbacls_record_destroy(ls_lbacls_rec); > > + } > > +} > > + > > +static void > > +ls_lbacls_table_build(struct ls_lbacls_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_lbacls_record_create(table, od, ls_pgs); > > + } > > +} > > + > > +struct ls_lbacls_record * > > +ls_lbacls_table_find_(const struct ls_lbacls_table *table, > > + const struct nbrec_logical_switch *nbs) > > +{ > > + struct ls_lbacls_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_lbacls_record * > > +ls_lbacls_record_create(struct ls_lbacls_table *table, > > + const struct ovn_datapath *od, > > + const struct ls_port_group_table *ls_pgs) > > +{ > > + struct ls_lbacls_record *ls_lbacls_rec = xzalloc(sizeof *ls_lbacls_rec); > > + ls_lbacls_rec->od = od; > > + ls_lbacls_record_init(ls_lbacls_rec, od, NULL, ls_pgs); > > + > > + hmap_insert(&table->entries, &ls_lbacls_rec->key_node, > > + uuid_hash(&ls_lbacls_rec->od->nbs->header_.uuid)); > > + > > + return ls_lbacls_rec; > > +} > > + > > +static void > > +ls_lbacls_record_destroy(struct ls_lbacls_record *ls_lbacls_rec) > > +{ > > + free(ls_lbacls_rec); > > +} > > + > > +static void > > +ls_lbacls_record_init(struct ls_lbacls_record *ls_lbacls_rec, > > + const struct ovn_datapath *od, > > + const struct ls_port_group *ls_pg, > > + const struct ls_port_group_table *ls_pgs) > > +{ > > + ls_lbacls_rec->has_lb_vip = ls_has_lb_vip(od); > > + ls_lbacls_record_set_acl_flags(ls_lbacls_rec, od, ls_pg, ls_pgs); > > +} > > + > > +static void > > +ls_lbacls_record_reinit(struct ls_lbacls_record *ls_lbacls_rec, > > + const struct ls_port_group *ls_pg, > > + const struct ls_port_group_table *ls_pgs) > > +{ > > + ls_lbacls_record_init(ls_lbacls_rec, ls_lbacls_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_lbacls_record_set_acl_flags(struct ls_lbacls_record *ls_lbacls_rec, > > + const struct ovn_datapath *od, > > + const struct ls_port_group *ls_pg, > > + const struct ls_port_group_table *ls_pgs) > > +{ > > + ls_lbacls_rec->has_stateful_acl = false; > > + ls_lbacls_rec->max_acl_tier = 0; > > + ls_lbacls_rec->has_acls = false; > > + > > + if (ls_lbacls_record_set_acl_flags_(ls_lbacls_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_lbacls_record_set_acl_flags_(ls_lbacls_rec, > > + ls_pg_rec->nb_pg->acls, > > + ls_pg_rec->nb_pg->n_acls)) { > > + return; > > + } > > + } > > +} > > + > > +static bool > > +ls_lbacls_record_set_acl_flags_(struct ls_lbacls_record *ls_lbacls_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_lbacls record. A false return indicates that > > + * further ACLs should be explored in case more flags need to be > > + * set on ls_lbacls record. > > + */ > > + if (!n_acls) { > > + return false; > > + } > > + > > + ls_lbacls_rec->has_acls = true; > > + for (size_t i = 0; i < n_acls; i++) { > > + const struct nbrec_acl *acl = acls[i]; > > + if (acl->tier > ls_lbacls_rec->max_acl_tier) { > > + ls_lbacls_rec->max_acl_tier = acl->tier; > > + } > > + if (!ls_lbacls_rec->has_stateful_acl > > + && !strcmp(acl->action, "allow-related")) { > > + ls_lbacls_rec->has_stateful_acl = true; > > + } > > + if (ls_lbacls_rec->has_stateful_acl && > > + ls_lbacls_rec->max_acl_tier == > > + nbrec_acl_col_tier.type.value.integer.max) { > > + return true; > > + } > > + } > > + > > + return false; > > +} > > + > > +static struct ls_lbacls_input > > +ls_lbacls_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_lbacls_input) { > > + .nbrec_logical_switch_table = > > + EN_OVSDB_GET(engine_get_input("NB_logical_switch", node)), > > + .ls_port_groups = &pg_data->ls_port_groups, > > + .ls_datapaths = &northd_data->ls_datapaths, > > + }; > > +} > > + > > +static bool > > +is_acls_seqno_changed(struct nbrec_acl **nb_acls, size_t n_nb_acls) > > +{ > > + for (size_t i = 0; i < n_nb_acls; i++) { > > + if (nbrec_acl_row_get_seqno(nb_acls[i], > > + OVSDB_IDL_CHANGE_MODIFY) > 0) { > > + return true; > > + } > > + } > > + > > + return false; > > +} > > + > > +static bool > > +is_ls_acls_changed(const struct nbrec_logical_switch *nbs) { > > + return (nbrec_logical_switch_is_new(nbs) > > + || nbrec_logical_switch_is_deleted(nbs) > > + || nbrec_logical_switch_is_updated(nbs, > > + NBREC_LOGICAL_SWITCH_COL_ACLS) > > + || is_acls_seqno_changed(nbs->acls, nbs->n_acls)); > > +} > > diff --git a/northd/en-ls-lb-acls.h b/northd/en-ls-lb-acls.h > > new file mode 100644 > > index 0000000000..ccb75e40e8 > > --- /dev/null > > +++ b/northd/en-ls-lb-acls.h > > @@ -0,0 +1,88 @@ > > +/* > > + * 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_LS_LB_ACL_H > > +#define EN_LS_LB_ACL_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_lbacls_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_lbacls_table { > > + struct hmap entries; > > +}; > > + > > +#define LS_LBACLS_TABLE_FOR_EACH(LS_LBACLS_REC, TABLE) \ > > + HMAP_FOR_EACH (LS_LBACLS_REC, key_node, &(TABLE)->entries) > > + > > +#define LS_LBACLS_TABLE_FOR_EACH_IN_P(LS_LBACLS_REC, JOBID, TABLE) \ > > + HMAP_FOR_EACH_IN_PARALLEL (LS_LBACLS_REC, key_node, JOBID, \ > > + &(TABLE)->entries) > > + > > +struct ls_lbacls_tracked_data { > > + /* Created or updated logical switch with LB and ACL data. */ > > + struct hmapx crupdated; /* Stores 'struct ls_lbacls_record'. */ > > + > > + /* Deleted logical switch with LB and ACL data. */ > > + struct hmapx deleted; /* Stores 'struct ls_lbacls_record'. */ > > +}; > > + > > +struct ed_type_ls_lbacls { > > + struct ls_lbacls_table ls_lbacls; > > + > > + bool tracked; > > + struct ls_lbacls_tracked_data tracked_data; > > +}; > > + > > +struct ls_lbacls_input { > > + const struct nbrec_logical_switch_table *nbrec_logical_switch_table; > > + const struct ls_port_group_table *ls_port_groups; > > + const struct ovn_datapaths *ls_datapaths; > > +}; > > + > > +void *en_ls_lbacls_init(struct engine_node *, struct engine_arg *); > > +void en_ls_lbacls_cleanup(void *data); > > +void en_ls_lbacls_clear_tracked_data(void *data); > > +void en_ls_lbacls_run(struct engine_node *, void *data); > > + > > +bool ls_lbacls_northd_handler(struct engine_node *, void *data); > > +bool ls_lbacls_port_group_handler(struct engine_node *, void *data); > > +bool ls_lbacls_logical_switch_handler(struct engine_node *, void *data); > > + > > +const struct ls_lbacls_record *ls_lbacls_table_find( > > + const struct ls_lbacls_table *, const struct nbrec_logical_switch *); > > + > > +#endif /* EN_LS_LB_ACL_H */ > > 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 84627070a8..ab4af92aeb 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-lb-nat-data.h" > > #include "en-lr-nat.h" > > +#include "en-ls-lb-acls.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_lb_nat_data, "lr_lb_nat_data"); > > +static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(ls_lbacls, "ls_lbacls"); > > > > void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > > struct ovsdb_idl_loop *sb) > > @@ -205,6 +207,12 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > > engine_add_input(&en_lr_lb_nat_data, &en_lb_data, > > lr_lb_nat_data_lb_data_handler); > > > > + engine_add_input(&en_ls_lbacls, &en_northd, ls_lbacls_northd_handler); > > + engine_add_input(&en_ls_lbacls, &en_port_group, > > + ls_lbacls_port_group_handler); > > + engine_add_input(&en_ls_lbacls, &en_nb_logical_switch, > > + ls_lbacls_logical_switch_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); > > @@ -229,6 +237,7 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > > engine_add_input(&en_lflow, &en_northd, lflow_northd_handler); > > engine_add_input(&en_lflow, &en_port_group, lflow_port_group_handler); > > engine_add_input(&en_lflow, &en_lr_lb_nat_data, NULL); > > + engine_add_input(&en_lflow, &en_ls_lbacls, NULL); > > > > engine_add_input(&en_sync_to_sb_addr_set, &en_nb_address_set, > > sync_to_sb_addr_set_nb_address_set_handler); > > diff --git a/northd/northd.c b/northd/northd.c > > index c8a224d3cd..924f5cd7e0 100644 > > --- a/northd/northd.c > > +++ b/northd/northd.c > > @@ -45,6 +45,7 @@ > > #include "en-lb-data.h" > > #include "en-lr-nat.h" > > #include "en-lr-lb-nat-data.h" > > +#include "en-ls-lb-acls.h" > > #include "lib/ovn-parallel-hmap.h" > > #include "ovn/actions.h" > > #include "ovn/features.h" > > @@ -575,7 +576,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])) { > > @@ -592,7 +593,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])) { > > @@ -608,13 +609,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); > > } > > } > > > > @@ -1058,7 +1059,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; > > @@ -1089,7 +1089,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; > > } > > @@ -2570,7 +2569,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_lbnat_rec > > + || !lr_lbnat_rec->has_lb_vip)) > > || !eth_addr_from_string(op->nbrp->mac, &mac)) { > > *n = n_nats; > > return NULL; > > @@ -3817,7 +3817,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 > > && !smap_get(&od->nbr->options, "chassis")) { > > static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); > > VLOG_WARN_RL(&rl, "Load-balancers are configured on logical " > > @@ -5441,7 +5441,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > > BITMAP_FOR_EACH_1 (index, ods_size(ls_datapaths), > > lb_dps->nb_ls_map) { > > od = ls_datapaths->array[index]; > > - init_lb_for_datapath(od); > > > > /* Add the ls datapath to the northd tracked data. */ > > hmapx_add(&nd_changes->ls_with_changed_lbs.crupdated, od); > > @@ -5524,9 +5523,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > > } > > } > > > > - /* Re-evaluate 'od->has_lb_vip' */ > > - init_lb_for_datapath(od); > > - > > /* Add the ls datapath to the northd tracked data. */ > > hmapx_add(&nd_changes->ls_with_changed_lbs.crupdated, od); > > } > > @@ -5564,9 +5560,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > > } > > } > > > > - /* Re-evaluate 'od->has_lb_vip' */ > > - init_lb_for_datapath(od); > > - > > /* Add the lr datapath to the northd tracked data. */ > > hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); > > } > > @@ -5581,8 +5574,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > > BITMAP_FOR_EACH_1 (index, ods_size(ls_datapaths), > > lb_dps->nb_ls_map) { > > od = ls_datapaths->array[index]; > > - /* Re-evaluate 'od->has_lb_vip' */ > > - init_lb_for_datapath(od); > > > > /* Add the ls datapath to the northd tracked data. */ > > hmapx_add(&nd_changes->ls_with_changed_lbs.crupdated, od); > > @@ -5591,8 +5582,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > > BITMAP_FOR_EACH_1 (index, ods_size(lr_datapaths), > > lb_dps->nb_lr_map) { > > od = lr_datapaths->array[index]; > > - /* Re-evaluate 'od->has_lb_vip' */ > > - init_lb_for_datapath(od); > > > > /* Add the lr datapath to the northd tracked data. */ > > hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); > > @@ -5618,9 +5607,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > > od = lbgrp_dps->lr[i]; > > ovn_lb_datapaths_add_lr(lb_dps, 1, &od); > > > > - /* Re-evaluate 'od->has_lb_vip' */ > > - init_lb_for_datapath(od); > > - > > /* Add the lr datapath to the northd tracked data. */ > > hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); > > } > > @@ -5629,9 +5615,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > > od = lbgrp_dps->ls[i]; > > ovn_lb_datapaths_add_ls(lb_dps, 1, &od); > > > > - /* Re-evaluate 'od->has_lb_vip' */ > > - init_lb_for_datapath(od); > > - > > /* Add the ls datapath to the northd tracked data. */ > > hmapx_add(&nd_changes->ls_with_changed_lbs.crupdated, od); > > } > > @@ -6573,63 +6556,6 @@ build_dhcpv6_action(struct ovn_port *op, struct in6_addr *offer_ip, > > return true; > > } > > > > -static bool > > -od_set_acl_flags(struct ovn_datapath *od, struct nbrec_acl **acls, > > - size_t n_acls) > > -{ > > - /* A true return indicates that there are no possible ACL flags > > - * left to set on od. A false return indicates that further ACLs > > - * should be explored in case more flags need to be set on od > > - */ > > - if (!n_acls) { > > - return false; > > - } > > - > > - od->has_acls = true; > > - for (size_t i = 0; i < n_acls; i++) { > > - const struct nbrec_acl *acl = acls[i]; > > - if (acl->tier > od->max_acl_tier) { > > - od->max_acl_tier = acl->tier; > > - } > > - if (!od->has_stateful_acl && !strcmp(acl->action, "allow-related")) { > > - od->has_stateful_acl = true; > > - } > > - if (od->has_stateful_acl && > > - od->max_acl_tier == nbrec_acl_col_tier.type.value.integer.max) { > > - return true; > > - } > > - } > > - > > - return false; > > -} > > - > > -static void > > -ls_get_acl_flags(struct ovn_datapath *od, > > - const struct ls_port_group_table *ls_port_groups) > > -{ > > - od->has_acls = false; > > - od->has_stateful_acl = false; > > - od->max_acl_tier = 0; > > - > > - if (od_set_acl_flags(od, od->nbs->acls, od->nbs->n_acls)) { > > - return; > > - } > > - > > - const struct ls_port_group *ls_pg = > > - ls_port_group_table_find(ls_port_groups, 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 (od_set_acl_flags(od, ls_pg_rec->nb_pg->acls, > > - ls_pg_rec->nb_pg->n_acls)) { > > - return; > > - } > > - } > > -} > > - > > /* Adds the logical flows in the (in/out) check port sec stage only if > > * - the lport is disabled or > > * - lport is of type vtep - to skip the ingress pipeline. > > @@ -6774,9 +6700,10 @@ build_lswitch_output_port_sec_od(struct ovn_datapath *od, > > } > > > > static void > > -skip_port_from_conntrack(struct ovn_datapath *od, struct ovn_port *op, > > - enum ovn_stage in_stage, enum ovn_stage out_stage, > > - uint16_t priority, struct hmap *lflows) > > +skip_port_from_conntrack(const struct ovn_datapath *od, struct ovn_port *op, > > + bool has_stateful_acl, enum ovn_stage in_stage, > > + enum ovn_stage out_stage, uint16_t priority, > > + struct hmap *lflows) > > { > > /* Can't use ct() for router ports. Consider the following configuration: > > * lp1(10.0.0.2) on hostA--ls1--lr0--ls2--lp2(10.0.1.2) on hostB, For a > > @@ -6789,7 +6716,7 @@ skip_port_from_conntrack(struct ovn_datapath *od, struct ovn_port *op, > > * conntrack state across all chassis. */ > > > > const char *ingress_action = "next;"; > > - const char *egress_action = od->has_stateful_acl > > + const char *egress_action = has_stateful_acl > > ? "next;" > > : "ct_clear; next;"; > > > > @@ -6808,7 +6735,7 @@ skip_port_from_conntrack(struct ovn_datapath *od, struct ovn_port *op, > > } > > > > static void > > -build_stateless_filter(struct ovn_datapath *od, > > +build_stateless_filter(const struct ovn_datapath *od, > > const struct nbrec_acl *acl, > > struct hmap *lflows) > > { > > @@ -6829,7 +6756,7 @@ build_stateless_filter(struct ovn_datapath *od, > > } > > > > static void > > -build_stateless_filters(struct ovn_datapath *od, > > +build_stateless_filters(const struct ovn_datapath *od, > > const struct ls_port_group_table *ls_port_groups, > > struct hmap *lflows) > > { > > @@ -6859,9 +6786,7 @@ build_stateless_filters(struct ovn_datapath *od, > > } > > > > static void > > -build_pre_acls(struct ovn_datapath *od, > > - const struct ls_port_group_table *ls_port_groups, > > - struct hmap *lflows) > > +build_pre_acls(struct ovn_datapath *od, struct hmap *lflows) > > { > > /* Ingress and Egress Pre-ACL Table (Priority 0): Packets are > > * allowed by default. */ > > @@ -6873,18 +6798,26 @@ build_pre_acls(struct ovn_datapath *od, > > > > ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, > > "eth.src == $svc_monitor_mac", "next;"); > > +} > > + > > +static void > > +build_ls_lbacls_rec_pre_acls(const struct ls_lbacls_record *ls_lbacls_rec, > > + const struct ls_port_group_table *ls_port_groups, > > + struct hmap *lflows) > > +{ > > + const struct ovn_datapath *od = ls_lbacls_rec->od; > > > > /* If there are any stateful ACL rules in this datapath, we may > > * send IP packets for some (allow) filters through the conntrack action, > > * which handles defragmentation, in order to match L4 headers. */ > > - if (od->has_stateful_acl) { > > + if (ls_lbacls_rec->has_stateful_acl) { > > for (size_t i = 0; i < od->n_router_ports; i++) { > > - skip_port_from_conntrack(od, od->router_ports[i], > > + skip_port_from_conntrack(od, od->router_ports[i], true, > > S_SWITCH_IN_PRE_ACL, S_SWITCH_OUT_PRE_ACL, > > 110, lflows); > > } > > for (size_t i = 0; i < od->n_localnet_ports; i++) { > > - skip_port_from_conntrack(od, od->localnet_ports[i], > > + skip_port_from_conntrack(od, od->localnet_ports[i], true, > > S_SWITCH_IN_PRE_ACL, > > S_SWITCH_OUT_PRE_ACL, > > 110, lflows); > > @@ -6922,7 +6855,7 @@ build_pre_acls(struct ovn_datapath *od, > > REGBIT_CONNTRACK_DEFRAG" = 1; next;"); > > ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 100, "ip", > > REGBIT_CONNTRACK_DEFRAG" = 1; next;"); > > - } else if (od->has_lb_vip) { > > + } else if (ls_lbacls_rec->has_lb_vip) { > > /* We'll build stateless filters if there are LB rules so that > > * the stateless flows are not tracked in pre-lb. */ > > build_stateless_filters(od, ls_port_groups, lflows); > > @@ -7050,30 +6983,40 @@ build_pre_lb(struct ovn_datapath *od, const struct shash *meter_groups, > > ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 0, "1", "next;"); > > ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 0, "1", "next;"); > > > > + /* Do not send statless flows via conntrack */ > > + ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110, > > + REGBIT_ACL_STATELESS" == 1", "next;"); > > + ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110, > > + REGBIT_ACL_STATELESS" == 1", "next;"); > > +} > > + > > +static void > > +build_ls_lbacls_rec_pre_lb(const struct ls_lbacls_record *ls_lbacls_rec, > > + struct hmap *lflows) > > +{ > > + const struct ovn_datapath *od = ls_lbacls_rec->od; > > + > > for (size_t i = 0; i < od->n_router_ports; i++) { > > skip_port_from_conntrack(od, od->router_ports[i], > > + ls_lbacls_rec->has_stateful_acl, > > S_SWITCH_IN_PRE_LB, S_SWITCH_OUT_PRE_LB, > > 110, lflows); > > } > > + > > /* Localnet ports have no need for going through conntrack, unless > > * the logical switch has a load balancer. Then, conntrack is necessary > > * so that traffic arriving via the localnet port can be load > > * balanced. > > */ > > - if (!od->has_lb_vip) { > > + if (!ls_lbacls_rec->has_lb_vip) { > > for (size_t i = 0; i < od->n_localnet_ports; i++) { > > skip_port_from_conntrack(od, od->localnet_ports[i], > > + ls_lbacls_rec->has_stateful_acl, > > S_SWITCH_IN_PRE_LB, S_SWITCH_OUT_PRE_LB, > > 110, lflows); > > } > > } > > > > - /* Do not sent statless flows via conntrack */ > > - ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110, > > - REGBIT_ACL_STATELESS" == 1", "next;"); > > - ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110, > > - REGBIT_ACL_STATELESS" == 1", "next;"); > > - > > /* 'REGBIT_CONNTRACK_NAT' is set to let the pre-stateful table send > > * packet to conntrack for defragmentation and possibly for unNATting. > > * > > @@ -7104,7 +7047,7 @@ build_pre_lb(struct ovn_datapath *od, const struct shash *meter_groups, > > * ingress pipeline if a load balancer is configured. We can now > > * add a lflow to drop ct.inv packets. > > */ > > - if (od->has_lb_vip) { > > + if (ls_lbacls_rec->has_lb_vip) { > > ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, > > 100, "ip", REGBIT_CONNTRACK_NAT" = 1; next;"); > > ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, > > @@ -7145,10 +7088,12 @@ build_pre_stateful(struct ovn_datapath *od, > > } > > > > static void > > -build_acl_hints(struct ovn_datapath *od, > > +build_acl_hints(const struct ls_lbacls_record *ls_lbacls_rec, > > const struct chassis_features *features, > > struct hmap *lflows) > > { > > + const struct ovn_datapath *od = ls_lbacls_rec->od; > > + > > /* This stage builds hints for the IN/OUT_ACL stage. Based on various > > * combinations of ct flags packets may hit only a subset of the logical > > * flows in the IN/OUT_ACL stage. > > @@ -7172,13 +7117,13 @@ build_acl_hints(struct ovn_datapath *od, > > const char *match; > > > > /* In any case, advance to the next stage. */ > > - if (!od->has_acls && !od->has_lb_vip) { > > + if (!ls_lbacls_rec->has_acls && !ls_lbacls_rec->has_lb_vip) { > > ovn_lflow_add(lflows, od, stage, UINT16_MAX, "1", "next;"); > > } else { > > ovn_lflow_add(lflows, od, stage, 0, "1", "next;"); > > } > > > > - if (!od->has_stateful_acl && !od->has_lb_vip) { > > + if (!ls_lbacls_rec->has_stateful_acl && !ls_lbacls_rec->has_lb_vip) { > > continue; > > } > > > > @@ -7314,10 +7259,10 @@ build_acl_log(struct ds *actions, const struct nbrec_acl *acl, > > } > > > > static void > > -consider_acl(struct hmap *lflows, struct ovn_datapath *od, > > +consider_acl(struct hmap *lflows, const struct ovn_datapath *od, > > const struct nbrec_acl *acl, bool has_stateful, > > bool ct_masked_mark, const struct shash *meter_groups, > > - struct ds *match, struct ds *actions) > > + uint64_t max_acl_tier, struct ds *match, struct ds *actions) > > { > > const char *ct_blocked_match = ct_masked_mark > > ? "ct_mark.blocked" > > @@ -7354,7 +7299,7 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, > > /* All ACLS will start by matching on their respective tier. */ > > size_t match_tier_len = 0; > > ds_clear(match); > > - if (od->max_acl_tier) { > > + if (max_acl_tier) { > > ds_put_format(match, REG_ACL_TIER " == %"PRId64" && ", acl->tier); > > match_tier_len = match->length; > > } > > @@ -7543,12 +7488,15 @@ ovn_update_ipv6_options(struct hmap *lr_ports) > > #define IPV6_CT_OMIT_MATCH "nd || nd_ra || nd_rs || mldv1 || mldv2" > > > > static void > > -build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, > > +build_acl_action_lflows(const struct ls_lbacls_record *ls_lbacls_rec, > > + struct hmap *lflows, > > const char *default_acl_action, > > const struct shash *meter_groups, > > struct ds *match, > > struct ds *actions) > > { > > + const struct ovn_datapath *od = ls_lbacls_rec->od; > > + > > enum ovn_stage stages [] = { > > S_SWITCH_IN_ACL_ACTION, > > S_SWITCH_IN_ACL_AFTER_LB_ACTION, > > @@ -7559,7 +7507,7 @@ build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, > > ds_put_cstr(actions, REGBIT_ACL_VERDICT_ALLOW " = 0; " > > REGBIT_ACL_VERDICT_DROP " = 0; " > > REGBIT_ACL_VERDICT_REJECT " = 0; "); > > - if (od->max_acl_tier) { > > + if (ls_lbacls_rec->max_acl_tier) { > > ds_put_cstr(actions, REG_ACL_TIER " = 0; "); > > } > > > > @@ -7567,7 +7515,7 @@ build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, > > > > for (size_t i = 0; i < ARRAY_SIZE(stages); i++) { > > enum ovn_stage stage = stages[i]; > > - if (!od->has_acls) { > > + if (!ls_lbacls_rec->has_acls) { > > ovn_lflow_add(lflows, od, stage, 0, "1", "next;"); > > continue; > > } > > @@ -7602,7 +7550,7 @@ build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, > > ovn_lflow_add(lflows, od, stage, 0, "1", ds_cstr(actions)); > > > > struct ds tier_actions = DS_EMPTY_INITIALIZER; > > - for (size_t j = 0; j < od->max_acl_tier; j++) { > > + for (size_t j = 0; j < ls_lbacls_rec->max_acl_tier; j++) { > > ds_clear(match); > > ds_put_format(match, REG_ACL_TIER " == %"PRIuSIZE, j); > > ds_clear(&tier_actions); > > @@ -7618,7 +7566,7 @@ build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, > > } > > > > static void > > -build_acl_log_related_flows(struct ovn_datapath *od, struct hmap *lflows, > > +build_acl_log_related_flows(const struct ovn_datapath *od, struct hmap *lflows, > > const struct nbrec_acl *acl, bool has_stateful, > > bool ct_masked_mark, > > const struct shash *meter_groups, > > @@ -7691,15 +7639,19 @@ build_acl_log_related_flows(struct ovn_datapath *od, struct hmap *lflows, > > } > > > > static void > > -build_acls(struct ovn_datapath *od, const struct chassis_features *features, > > +build_acls(const struct ls_lbacls_record *ls_lbacls_rec, > > + const struct chassis_features *features, > > struct hmap *lflows, > > const struct ls_port_group_table *ls_port_groups, > > const struct shash *meter_groups) > > { > > + const struct ovn_datapath *od = ls_lbacls_rec->od; > > + > > const char *default_acl_action = default_acl_drop > > ? debug_implicit_drop_action() > > : "next;"; > > - bool has_stateful = od->has_stateful_acl || od->has_lb_vip; > > + bool has_stateful = (ls_lbacls_rec->has_stateful_acl > > + || ls_lbacls_rec->has_lb_vip); > > const char *ct_blocked_match = features->ct_no_masked_label > > ? "ct_mark.blocked" > > : "ct_label.blocked"; > > @@ -7713,8 +7665,8 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, > > * > > * A related rule at priority 1 is added below if there > > * are any stateful ACLs in this datapath. */ > > - if (!od->has_acls) { > > - if (!od->has_lb_vip) { > > + if (!ls_lbacls_rec->has_acls) { > > + if (!ls_lbacls_rec->has_lb_vip) { > > ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX, "1", > > "next;"); > > ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX, "1", > > @@ -7877,7 +7829,8 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, > > meter_groups, &match, &actions); > > consider_acl(lflows, od, acl, has_stateful, > > features->ct_no_masked_label, > > - meter_groups, &match, &actions); > > + meter_groups, ls_lbacls_rec->max_acl_tier, > > + &match, &actions); > > } > > > > const struct ls_port_group *ls_pg = > > @@ -7893,7 +7846,8 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, > > meter_groups, &match, &actions); > > consider_acl(lflows, od, acl, has_stateful, > > features->ct_no_masked_label, > > - meter_groups, &match, &actions); > > + meter_groups, ls_lbacls_rec->max_acl_tier, > > + &match, &actions); > > } > > } > > } > > @@ -7911,7 +7865,7 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, > > dns_actions); > > } > > > > - if (od->has_acls || od->has_lb_vip) { > > + if (ls_lbacls_rec->has_acls || ls_lbacls_rec->has_lb_vip) { > > /* Add a 34000 priority flow to advance the service monitor reply > > * packets to skip applying ingress ACLs. */ > > ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 34000, > > @@ -7925,8 +7879,8 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, > > REGBIT_ACL_VERDICT_ALLOW" = 1; next;"); > > } > > > > - build_acl_action_lflows(od, lflows, default_acl_action, meter_groups, > > - &match, &actions); > > + build_acl_action_lflows(ls_lbacls_rec, lflows, default_acl_action, > > + meter_groups, &match, &actions); > > > > ds_destroy(&match); > > ds_destroy(&actions); > > @@ -8571,8 +8525,11 @@ build_stateful(struct ovn_datapath *od, > > } > > > > static void > > -build_lb_hairpin(struct ovn_datapath *od, struct hmap *lflows) > > +build_lb_hairpin(const struct ls_lbacls_record *ls_lbacls_rec, > > + struct hmap *lflows) > > { > > + const struct ovn_datapath *od = ls_lbacls_rec->od; > > + > > /* Ingress Pre-Hairpin/Nat-Hairpin/Hairpin tabled (Priority 0). > > * Packets that don't need hairpinning should continue processing. > > */ > > @@ -8580,7 +8537,7 @@ build_lb_hairpin(struct ovn_datapath *od, struct hmap *lflows) > > ovn_lflow_add(lflows, od, S_SWITCH_IN_NAT_HAIRPIN, 0, "1", "next;"); > > ovn_lflow_add(lflows, od, S_SWITCH_IN_HAIRPIN, 0, "1", "next;"); > > > > - if (od->has_lb_vip) { > > + if (ls_lbacls_rec->has_lb_vip) { > > /* Check if the packet needs to be hairpinned. > > * Set REGBIT_HAIRPIN in the original direction and > > * REGBIT_HAIRPIN_REPLY in the reply direction. > > @@ -9413,22 +9370,16 @@ build_lswitch_lflows_l2_unknown(struct ovn_datapath *od, > > static void > > build_lswitch_lflows_pre_acl_and_acl( > > struct ovn_datapath *od, > > - const struct ls_port_group_table *ls_port_groups, > > const struct chassis_features *features, > > struct hmap *lflows, > > const struct shash *meter_groups) > > { > > ovs_assert(od->nbs); > > - ls_get_acl_flags(od, ls_port_groups); > > - > > - build_pre_acls(od, ls_port_groups, lflows); > > + build_pre_acls(od, lflows); > > build_pre_lb(od, meter_groups, lflows); > > build_pre_stateful(od, features, lflows); > > - build_acl_hints(od, features, lflows); > > - build_acls(od, features, lflows, ls_port_groups, meter_groups); > > build_qos(od, lflows); > > build_stateful(od, features, lflows); > > - build_lb_hairpin(od, lflows); > > build_vtep_hairpin(od, lflows); > > } > > > > @@ -15487,7 +15438,7 @@ build_lrouter_nat_defrag_and_lb( > > * a dynamically negotiated FTP data channel), but will allow > > * related traffic such as an ICMP Port Unreachable through > > * that's generated from a non-listening UDP port. */ > > - if (od->has_lb_vip && features->ct_lb_related) { > > + if (lr_lbnat_rec->has_lb_vip && features->ct_lb_related) { > > ds_clear(match); > > > > ds_put_cstr(match, "ct.rel && !ct.est && !ct.new"); > > @@ -15512,7 +15463,7 @@ build_lrouter_nat_defrag_and_lb( > > * Pass the traffic that is already established to the next table with > > * proper flags set. > > */ > > - if (od->has_lb_vip) { > > + if (lr_lbnat_rec->has_lb_vip) { > > ds_clear(match); > > > > ds_put_format(match, "ct.est && !ct.rel && !ct.new && %s.natted", > > @@ -15542,7 +15493,7 @@ build_lrouter_nat_defrag_and_lb( > > * not committed, it would produce ongoing datapath flows with the ct.new > > * flag set. Some NICs are unable to offload these flows. > > */ > > - if (od->is_gw_router && (od->nbr->n_nat || od->has_lb_vip)) { > > + if (od->is_gw_router && (od->nbr->n_nat || lr_lbnat_rec->has_lb_vip)) { > > /* Do not send ND or ICMP packets to connection tracking. */ > > ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 100, > > "nd || nd_rs || nd_ra", "next;"); > > @@ -15967,6 +15918,22 @@ build_lr_lbnat_data_flows(const struct lr_lb_nat_data_record *lr_lbnat_rec, > > meter_groups); > > } > > > > +static void > > +build_ls_lbacls_flows(const struct ls_lbacls_record *ls_lbacls_rec, > > + const struct ls_port_group_table *ls_pgs, > > + const struct chassis_features *features, > > + const struct shash *meter_groups, > > + struct hmap *lflows) > > +{ > > + ovs_assert(ls_lbacls_rec->od); > > + > > + build_ls_lbacls_rec_pre_acls(ls_lbacls_rec, ls_pgs, lflows); > > + build_ls_lbacls_rec_pre_lb(ls_lbacls_rec, lflows); > > + build_acl_hints(ls_lbacls_rec, features, lflows); > > + build_acls(ls_lbacls_rec, features, lflows, ls_pgs, meter_groups); > > + build_lb_hairpin(ls_lbacls_rec, lflows); > > +} > > + > > struct lswitch_flow_build_info { > > const struct ovn_datapaths *ls_datapaths; > > const struct ovn_datapaths *lr_datapaths; > > @@ -15974,6 +15941,7 @@ struct lswitch_flow_build_info { > > const struct hmap *lr_ports; > > const struct ls_port_group_table *ls_port_groups; > > const struct lr_lb_nat_data_table *lr_lbnats; > > + const struct ls_lbacls_table *ls_lbacls; > > struct hmap *lflows; > > struct hmap *igmp_groups; > > const struct shash *meter_groups; > > @@ -15998,9 +15966,7 @@ build_lswitch_and_lrouter_iterate_by_ls(struct ovn_datapath *od, > > struct lswitch_flow_build_info *lsi) > > { > > ovs_assert(od->nbs); > > - build_lswitch_lflows_pre_acl_and_acl(od, lsi->ls_port_groups, > > - lsi->features, > > - lsi->lflows, > > + build_lswitch_lflows_pre_acl_and_acl(od, lsi->features, lsi->lflows, > > lsi->meter_groups); > > > > build_fwd_group_lflows(od, lsi->lflows); > > @@ -16115,6 +16081,7 @@ build_lflows_thread(void *arg) > > { > > struct worker_control *control = (struct worker_control *) arg; > > const struct lr_lb_nat_data_record *lr_lbnat_rec; > > + const struct ls_lbacls_record *ls_lbacls_rec; > > struct lswitch_flow_build_info *lsi; > > struct ovn_igmp_group *igmp_group; > > struct ovn_lb_datapaths *lb_dps; > > @@ -16243,6 +16210,19 @@ build_lflows_thread(void *arg) > > lsi->features); > > } > > } > > + > > + for (bnum = control->id; > > + bnum <= lsi->ls_lbacls->entries.mask; > > + bnum += control->pool->size) > > + { > > + LS_LBACLS_TABLE_FOR_EACH_IN_P (ls_lbacls_rec, bnum, > > + lsi->ls_lbacls) { > > + build_ls_lbacls_flows(ls_lbacls_rec, lsi->ls_port_groups, > > + lsi->features, lsi->meter_groups, > > + lsi->lflows); > > + } > > + } > > + > > for (bnum = control->id; > > bnum <= lsi->igmp_groups->mask; > > bnum += control->pool->size) > > @@ -16303,6 +16283,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > > const struct hmap *lr_ports, > > const struct ls_port_group_table *ls_pgs, > > const struct lr_lb_nat_data_table *lr_lbnats, > > + const struct ls_lbacls_table *ls_lbacls, > > struct hmap *lflows, > > struct hmap *igmp_groups, > > const struct shash *meter_groups, > > @@ -16333,6 +16314,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > > lsiv[index].lr_ports = lr_ports; > > lsiv[index].ls_port_groups = ls_pgs; > > lsiv[index].lr_lbnats = lr_lbnats; > > + lsiv[index].ls_lbacls = ls_lbacls; > > lsiv[index].igmp_groups = igmp_groups; > > lsiv[index].meter_groups = meter_groups; > > lsiv[index].lb_dps_map = lb_dps_map; > > @@ -16358,6 +16340,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > > free(lsiv); > > } else { > > const struct lr_lb_nat_data_record *lr_lbnat_rec; > > + const struct ls_lbacls_record *ls_lbacls_rec; > > struct ovn_igmp_group *igmp_group; > > struct ovn_lb_datapaths *lb_dps; > > struct ovn_datapath *od; > > @@ -16370,6 +16353,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > > .lr_ports = lr_ports, > > .ls_port_groups = ls_pgs, > > .lr_lbnats = lr_lbnats, > > + .ls_lbacls = ls_lbacls, > > .lflows = lflows, > > .igmp_groups = igmp_groups, > > .meter_groups = meter_groups, > > @@ -16439,6 +16423,12 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > > lsi.features); > > } > > > > + LS_LBACLS_TABLE_FOR_EACH (ls_lbacls_rec, ls_lbacls) { > > + build_ls_lbacls_flows(ls_lbacls_rec, lsi.ls_port_groups, > > + lsi.features, lsi.meter_groups, > > + lsi.lflows); > > + } > > + > > stopwatch_start(LFLOWS_IGMP_STOPWATCH_NAME, time_msec()); > > HMAP_FOR_EACH (igmp_group, hmap_node, igmp_groups) { > > build_lswitch_ip_mcast_igmp_mld(igmp_group, > > @@ -16535,6 +16525,7 @@ void build_lflows(struct ovsdb_idl_txn *ovnsb_txn, > > input_data->lr_ports, > > input_data->ls_port_groups, > > input_data->lr_lbnats, > > + input_data->ls_lbacls, > > lflows, > > &igmp_groups, > > input_data->meter_groups, > > diff --git a/northd/northd.h b/northd/northd.h > > index 08a81b2c10..23b4754db4 100644 > > --- a/northd/northd.h > > +++ b/northd/northd.h > > @@ -89,6 +89,8 @@ ods_size(const struct ovn_datapaths *datapaths) > > return hmap_count(&datapaths->datapaths); > > } > > > > +bool od_has_lb_vip(const struct ovn_datapath *od); > > + > > struct tracked_ovn_ports { > > /* tracked created ports. > > * hmapx node data is 'struct ovn_port *' */ > > @@ -179,6 +181,7 @@ struct lflow_input { > > const struct hmap *lr_ports; > > const struct ls_port_group_table *ls_port_groups; > > const struct lr_lb_nat_data_table *lr_lbnats; > > + const struct ls_lbacls_table *ls_lbacls; > > const struct shash *meter_groups; > > const struct hmap *lb_datapaths_map; > > const struct hmap *bfd_connections; > > @@ -288,11 +291,7 @@ struct ovn_datapath { > > struct hmap port_tnlids; > > uint32_t port_key_hint; > > > > - bool has_stateful_acl; > > - bool has_lb_vip; > > bool has_unknown; > > - bool has_acls; > > - uint64_t max_acl_tier; > > bool has_vtep_lports; > > bool has_arp_proxy_port; > > > > _______________________________________________ > dev mailing list > dev@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev >
diff --git a/lib/stopwatch-names.h b/lib/stopwatch-names.h index 7d85acdaea..8b0018a593 100644 --- a/lib/stopwatch-names.h +++ b/lib/stopwatch-names.h @@ -34,5 +34,6 @@ #define SYNC_METERS_RUN_STOPWATCH_NAME "sync_meters_run" #define LR_NAT_RUN_STOPWATCH_NAME "lr_nat_run" #define LR_LB_NAT_DATA_RUN_STOPWATCH_NAME "lr_lb_nat_data" +#define LS_LBACLS_RUN_STOPWATCH_NAME "lr_lb_acls" #endif diff --git a/northd/automake.mk b/northd/automake.mk index 4116c487df..4593654726 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-lb-nat-data.c \ northd/en-lr-lb-nat-data.h \ + northd/en-ls-lb-acls.c \ + northd/en-ls-lb-acls.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 229f4be1d0..648a477916 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-lb-nat-data.h" +#include "en-ls-lb-acls.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_lb_nat_data *lr_lb_nat_data = engine_get_input_data("lr_lb_nat_data", node); + struct ed_type_ls_lbacls *ls_lbacls_data = + engine_get_input_data("ls_lbacls", 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_lbnats = &lr_lb_nat_data->lr_lbnats; + lflow_input->ls_lbacls = &ls_lbacls_data->ls_lbacls; 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-lb-nat-data.c b/northd/en-lr-lb-nat-data.c index 19b638ce0b..d816d2321d 100644 --- a/northd/en-lr-lb-nat-data.c +++ b/northd/en-lr-lb-nat-data.c @@ -299,9 +299,11 @@ lr_lb_nat_data_lb_data_handler(struct engine_node *node, void *data_) if (!hmapx_is_empty(&data->tracked_data.crupdated)) { struct hmapx_node *hmapx_node; /* For all the modified lr_lb_nat_data records (re)build the - * vip nats. */ + * vip nats and re-evaluate 'has_lb_vip'. */ HMAPX_FOR_EACH (hmapx_node, &data->tracked_data.crupdated) { - lr_lb_nat_data_build_vip_nats(hmapx_node->data); + lr_lbnat_rec = hmapx_node->data; + lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); + lr_lbnat_rec->has_lb_vip = od_has_lb_vip(lr_lbnat_rec->od); } data->tracked = true; @@ -523,6 +525,8 @@ lr_lb_nat_data_record_init(struct lr_lb_nat_data_record *lr_lbnat_rec, if (!nbr->n_nat) { lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); } + + lr_lbnat_rec->has_lb_vip = od_has_lb_vip(lr_lbnat_rec->od); } static struct lr_lb_nat_data_input diff --git a/northd/en-lr-lb-nat-data.h b/northd/en-lr-lb-nat-data.h index ffe41cad73..ac21d28a57 100644 --- a/northd/en-lr-lb-nat-data.h +++ b/northd/en-lr-lb-nat-data.h @@ -39,6 +39,8 @@ struct lr_lb_nat_data_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-lb-acls.c b/northd/en-ls-lb-acls.c new file mode 100644 index 0000000000..1ba7ecb3e2 --- /dev/null +++ b/northd/en-ls-lb-acls.c @@ -0,0 +1,527 @@ +/* + * 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 <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-lb-acls.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_lbacls); + +/* Static function declarations. */ +static void ls_lbacls_table_init(struct ls_lbacls_table *); +static void ls_lbacls_table_clear(struct ls_lbacls_table *); +static void ls_lbacls_table_destroy(struct ls_lbacls_table *); +static struct ls_lbacls_record *ls_lbacls_table_find_( + const struct ls_lbacls_table *, const struct nbrec_logical_switch *); +static void ls_lbacls_table_build(struct ls_lbacls_table *, + const struct ovn_datapaths *ls_datapaths, + const struct ls_port_group_table *); + +static struct ls_lbacls_input ls_lbacls_get_input_data( + struct engine_node *); + +static struct ls_lbacls_record *ls_lbacls_record_create( + struct ls_lbacls_table *, + const struct ovn_datapath *, + const struct ls_port_group_table *); +static void ls_lbacls_record_destroy(struct ls_lbacls_record *); +static void ls_lbacls_record_init( + struct ls_lbacls_record *, + const struct ovn_datapath *, + const struct ls_port_group *, + const struct ls_port_group_table *); +static void ls_lbacls_record_reinit( + struct ls_lbacls_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_lbacls_record_set_acl_flags(struct ls_lbacls_record *, + const struct ovn_datapath *, + const struct ls_port_group *, + const struct ls_port_group_table *); +static bool ls_lbacls_record_set_acl_flags_(struct ls_lbacls_record *, + struct nbrec_acl **, + size_t n_acls); +static struct ls_lbacls_input ls_lbacls_get_input_data(struct engine_node *); +static bool is_ls_acls_changed(const struct nbrec_logical_switch *); +static bool is_acls_seqno_changed(struct nbrec_acl **, size_t n_nb_acls); + + +/* public functions. */ +const struct ls_lbacls_record * +ls_lbacls_table_find( + const struct ls_lbacls_table *table, + const struct nbrec_logical_switch *nbs) +{ + return ls_lbacls_table_find_(table, nbs); +} + +void * +en_ls_lbacls_init(struct engine_node *node OVS_UNUSED, + struct engine_arg *arg OVS_UNUSED) +{ + struct ed_type_ls_lbacls *data = xzalloc(sizeof *data); + ls_lbacls_table_init(&data->ls_lbacls); + hmapx_init(&data->tracked_data.crupdated); + hmapx_init(&data->tracked_data.deleted); + return data; +} + +void +en_ls_lbacls_cleanup(void *data_) +{ + struct ed_type_ls_lbacls *data = + (struct ed_type_ls_lbacls *) data_; + ls_lbacls_table_destroy(&data->ls_lbacls); + hmapx_destroy(&data->tracked_data.crupdated); + hmapx_destroy(&data->tracked_data.deleted); +} + +void +en_ls_lbacls_clear_tracked_data(void *data_) +{ + struct ed_type_ls_lbacls *data = + (struct ed_type_ls_lbacls *) data_; + + struct hmapx_node *hmapx_node; + HMAPX_FOR_EACH_SAFE (hmapx_node, &data->tracked_data.deleted) { + ls_lbacls_record_destroy(hmapx_node->data); + hmapx_delete(&data->tracked_data.deleted, hmapx_node); + } + + hmapx_clear(&data->tracked_data.crupdated); + data->tracked = false; +} + +void +en_ls_lbacls_run(struct engine_node *node, void *data_) +{ + struct ls_lbacls_input input_data = ls_lbacls_get_input_data(node); + struct ed_type_ls_lbacls *data = data_; + + stopwatch_start(LS_LBACLS_RUN_STOPWATCH_NAME, time_msec()); + + ls_lbacls_table_clear(&data->ls_lbacls); + ls_lbacls_table_build(&data->ls_lbacls, input_data.ls_datapaths, + input_data.ls_port_groups); + + data->tracked = false; + stopwatch_stop(LS_LBACLS_RUN_STOPWATCH_NAME, time_msec()); + engine_set_node_state(node, EN_UPDATED); +} + +/* Handler functions. */ +bool +ls_lbacls_northd_handler(struct engine_node *node, void *data_) +{ + struct northd_data *northd_data = engine_get_input_data("northd", node); + if (!northd_data->change_tracked) { + return false; + } + + struct northd_tracked_data *nd_changes = &northd_data->trk_northd_changes; + struct ls_lbacls_input input_data = ls_lbacls_get_input_data(node); + struct ls_lbacls_record *ls_lbacls_rec; + struct ed_type_ls_lbacls *data = data_; + const struct ovn_datapath *od; + struct hmapx_node *hmapx_node; + + HMAPX_FOR_EACH (hmapx_node, &nd_changes->ls_with_changed_lbs.crupdated) { + od = hmapx_node->data; + + ls_lbacls_rec = ls_lbacls_table_find_(&data->ls_lbacls, od->nbs); + if (!ls_lbacls_rec) { + ls_lbacls_rec = ls_lbacls_record_create(&data->ls_lbacls, od, + input_data.ls_port_groups); + } else { + ls_lbacls_record_reinit(ls_lbacls_rec, NULL, + input_data.ls_port_groups); + } + + /* Add the ls_lbacls_rec to the tracking data. */ + hmapx_add(&data->tracked_data.crupdated, ls_lbacls_rec); + } + + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { + data->tracked = true; + engine_set_node_state(node, EN_UPDATED); + } + + return true; +} + +bool +ls_lbacls_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_lbacls_rec. + * This is still better than returning false. */ + struct ls_lbacls_input input_data = ls_lbacls_get_input_data(node); + struct ed_type_ls_lbacls *data = data_; + const struct ls_port_group *ls_pg; + + LS_PORT_GROUP_TABLE_FOR_EACH (ls_pg, input_data.ls_port_groups) { + struct ls_lbacls_record *ls_lbacls_rec = + ls_lbacls_table_find_(&data->ls_lbacls, ls_pg->nbs); + + bool modified = false; + if (!ls_lbacls_rec) { + const struct ovn_datapath *od; + od = ovn_datapath_find(&input_data.ls_datapaths->datapaths, + &ls_pg->nbs->header_.uuid); + ovs_assert(od); + ls_lbacls_rec = ls_lbacls_record_create(&data->ls_lbacls, od, + input_data.ls_port_groups); + modified = true; + } else { + bool had_stateful_acl = ls_lbacls_rec->has_stateful_acl; + uint64_t max_acl_tier = ls_lbacls_rec->max_acl_tier; + bool had_acls = ls_lbacls_rec->has_acls; + + ls_lbacls_record_reinit(ls_lbacls_rec, ls_pg, + input_data.ls_port_groups); + + if ((had_stateful_acl != ls_lbacls_rec->has_stateful_acl) + || (had_acls != ls_lbacls_rec->has_acls) + || max_acl_tier != ls_lbacls_rec->max_acl_tier) { + modified = true; + } + } + + if (modified) { + /* Add the ls_lbacls_rec to the tracking data. */ + hmapx_add(&data->tracked_data.crupdated, ls_lbacls_rec); + } + } + + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { + data->tracked = true; + engine_set_node_state(node, EN_UPDATED); + } + + return true; +} + +bool +ls_lbacls_logical_switch_handler(struct engine_node *node, void *data_) +{ + struct ls_lbacls_input input_data = ls_lbacls_get_input_data(node); + const struct nbrec_logical_switch *nbs; + struct ed_type_ls_lbacls *data = data_; + + NBREC_LOGICAL_SWITCH_TABLE_FOR_EACH_TRACKED (nbs, + input_data.nbrec_logical_switch_table) { + if (!is_ls_acls_changed(nbs)) { + continue; + } + + struct ls_lbacls_record *ls_lbacls_rec = + ls_lbacls_table_find_(&data->ls_lbacls, nbs); + + if (nbrec_logical_switch_is_deleted(nbs)) { + if (ls_lbacls_rec) { + /* Remove the record from the entries. */ + hmap_remove(&data->ls_lbacls.entries, + &ls_lbacls_rec->key_node); + + /* Add the ls_lbacls_rec to the tracking data. */ + hmapx_add(&data->tracked_data.deleted, ls_lbacls_rec); + } + } else { + if (!ls_lbacls_rec) { + const struct ovn_datapath *od; + od = ovn_datapath_find(&input_data.ls_datapaths->datapaths, + &nbs->header_.uuid); + ovs_assert(od); + ls_lbacls_rec = ls_lbacls_record_create(&data->ls_lbacls, od, + input_data.ls_port_groups); + } else { + ls_lbacls_record_reinit(ls_lbacls_rec, NULL, + input_data.ls_port_groups); + } + + /* Add the ls_lbacls_rec to the tracking data. */ + hmapx_add(&data->tracked_data.crupdated, ls_lbacls_rec); + } + } + + if (!hmapx_is_empty(&data->tracked_data.crupdated) + || !hmapx_is_empty(&data->tracked_data.deleted)) { + data->tracked = true; + engine_set_node_state(node, EN_UPDATED); + } + + return true; +} + +/* static functions. */ +static void +ls_lbacls_table_init(struct ls_lbacls_table *table) +{ + *table = (struct ls_lbacls_table) { + .entries = HMAP_INITIALIZER(&table->entries), + }; +} + +static void +ls_lbacls_table_destroy(struct ls_lbacls_table *table) +{ + ls_lbacls_table_clear(table); + hmap_destroy(&table->entries); +} + +static void +ls_lbacls_table_clear(struct ls_lbacls_table *table) +{ + struct ls_lbacls_record *ls_lbacls_rec; + HMAP_FOR_EACH_POP (ls_lbacls_rec, key_node, &table->entries) { + ls_lbacls_record_destroy(ls_lbacls_rec); + } +} + +static void +ls_lbacls_table_build(struct ls_lbacls_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_lbacls_record_create(table, od, ls_pgs); + } +} + +struct ls_lbacls_record * +ls_lbacls_table_find_(const struct ls_lbacls_table *table, + const struct nbrec_logical_switch *nbs) +{ + struct ls_lbacls_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_lbacls_record * +ls_lbacls_record_create(struct ls_lbacls_table *table, + const struct ovn_datapath *od, + const struct ls_port_group_table *ls_pgs) +{ + struct ls_lbacls_record *ls_lbacls_rec = xzalloc(sizeof *ls_lbacls_rec); + ls_lbacls_rec->od = od; + ls_lbacls_record_init(ls_lbacls_rec, od, NULL, ls_pgs); + + hmap_insert(&table->entries, &ls_lbacls_rec->key_node, + uuid_hash(&ls_lbacls_rec->od->nbs->header_.uuid)); + + return ls_lbacls_rec; +} + +static void +ls_lbacls_record_destroy(struct ls_lbacls_record *ls_lbacls_rec) +{ + free(ls_lbacls_rec); +} + +static void +ls_lbacls_record_init(struct ls_lbacls_record *ls_lbacls_rec, + const struct ovn_datapath *od, + const struct ls_port_group *ls_pg, + const struct ls_port_group_table *ls_pgs) +{ + ls_lbacls_rec->has_lb_vip = ls_has_lb_vip(od); + ls_lbacls_record_set_acl_flags(ls_lbacls_rec, od, ls_pg, ls_pgs); +} + +static void +ls_lbacls_record_reinit(struct ls_lbacls_record *ls_lbacls_rec, + const struct ls_port_group *ls_pg, + const struct ls_port_group_table *ls_pgs) +{ + ls_lbacls_record_init(ls_lbacls_rec, ls_lbacls_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_lbacls_record_set_acl_flags(struct ls_lbacls_record *ls_lbacls_rec, + const struct ovn_datapath *od, + const struct ls_port_group *ls_pg, + const struct ls_port_group_table *ls_pgs) +{ + ls_lbacls_rec->has_stateful_acl = false; + ls_lbacls_rec->max_acl_tier = 0; + ls_lbacls_rec->has_acls = false; + + if (ls_lbacls_record_set_acl_flags_(ls_lbacls_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_lbacls_record_set_acl_flags_(ls_lbacls_rec, + ls_pg_rec->nb_pg->acls, + ls_pg_rec->nb_pg->n_acls)) { + return; + } + } +} + +static bool +ls_lbacls_record_set_acl_flags_(struct ls_lbacls_record *ls_lbacls_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_lbacls record. A false return indicates that + * further ACLs should be explored in case more flags need to be + * set on ls_lbacls record. + */ + if (!n_acls) { + return false; + } + + ls_lbacls_rec->has_acls = true; + for (size_t i = 0; i < n_acls; i++) { + const struct nbrec_acl *acl = acls[i]; + if (acl->tier > ls_lbacls_rec->max_acl_tier) { + ls_lbacls_rec->max_acl_tier = acl->tier; + } + if (!ls_lbacls_rec->has_stateful_acl + && !strcmp(acl->action, "allow-related")) { + ls_lbacls_rec->has_stateful_acl = true; + } + if (ls_lbacls_rec->has_stateful_acl && + ls_lbacls_rec->max_acl_tier == + nbrec_acl_col_tier.type.value.integer.max) { + return true; + } + } + + return false; +} + +static struct ls_lbacls_input +ls_lbacls_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_lbacls_input) { + .nbrec_logical_switch_table = + EN_OVSDB_GET(engine_get_input("NB_logical_switch", node)), + .ls_port_groups = &pg_data->ls_port_groups, + .ls_datapaths = &northd_data->ls_datapaths, + }; +} + +static bool +is_acls_seqno_changed(struct nbrec_acl **nb_acls, size_t n_nb_acls) +{ + for (size_t i = 0; i < n_nb_acls; i++) { + if (nbrec_acl_row_get_seqno(nb_acls[i], + OVSDB_IDL_CHANGE_MODIFY) > 0) { + return true; + } + } + + return false; +} + +static bool +is_ls_acls_changed(const struct nbrec_logical_switch *nbs) { + return (nbrec_logical_switch_is_new(nbs) + || nbrec_logical_switch_is_deleted(nbs) + || nbrec_logical_switch_is_updated(nbs, + NBREC_LOGICAL_SWITCH_COL_ACLS) + || is_acls_seqno_changed(nbs->acls, nbs->n_acls)); +} diff --git a/northd/en-ls-lb-acls.h b/northd/en-ls-lb-acls.h new file mode 100644 index 0000000000..ccb75e40e8 --- /dev/null +++ b/northd/en-ls-lb-acls.h @@ -0,0 +1,88 @@ +/* + * 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_LS_LB_ACL_H +#define EN_LS_LB_ACL_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_lbacls_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_lbacls_table { + struct hmap entries; +}; + +#define LS_LBACLS_TABLE_FOR_EACH(LS_LBACLS_REC, TABLE) \ + HMAP_FOR_EACH (LS_LBACLS_REC, key_node, &(TABLE)->entries) + +#define LS_LBACLS_TABLE_FOR_EACH_IN_P(LS_LBACLS_REC, JOBID, TABLE) \ + HMAP_FOR_EACH_IN_PARALLEL (LS_LBACLS_REC, key_node, JOBID, \ + &(TABLE)->entries) + +struct ls_lbacls_tracked_data { + /* Created or updated logical switch with LB and ACL data. */ + struct hmapx crupdated; /* Stores 'struct ls_lbacls_record'. */ + + /* Deleted logical switch with LB and ACL data. */ + struct hmapx deleted; /* Stores 'struct ls_lbacls_record'. */ +}; + +struct ed_type_ls_lbacls { + struct ls_lbacls_table ls_lbacls; + + bool tracked; + struct ls_lbacls_tracked_data tracked_data; +}; + +struct ls_lbacls_input { + const struct nbrec_logical_switch_table *nbrec_logical_switch_table; + const struct ls_port_group_table *ls_port_groups; + const struct ovn_datapaths *ls_datapaths; +}; + +void *en_ls_lbacls_init(struct engine_node *, struct engine_arg *); +void en_ls_lbacls_cleanup(void *data); +void en_ls_lbacls_clear_tracked_data(void *data); +void en_ls_lbacls_run(struct engine_node *, void *data); + +bool ls_lbacls_northd_handler(struct engine_node *, void *data); +bool ls_lbacls_port_group_handler(struct engine_node *, void *data); +bool ls_lbacls_logical_switch_handler(struct engine_node *, void *data); + +const struct ls_lbacls_record *ls_lbacls_table_find( + const struct ls_lbacls_table *, const struct nbrec_logical_switch *); + +#endif /* EN_LS_LB_ACL_H */ 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 84627070a8..ab4af92aeb 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-lb-nat-data.h" #include "en-lr-nat.h" +#include "en-ls-lb-acls.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_lb_nat_data, "lr_lb_nat_data"); +static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(ls_lbacls, "ls_lbacls"); void inc_proc_northd_init(struct ovsdb_idl_loop *nb, struct ovsdb_idl_loop *sb) @@ -205,6 +207,12 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, engine_add_input(&en_lr_lb_nat_data, &en_lb_data, lr_lb_nat_data_lb_data_handler); + engine_add_input(&en_ls_lbacls, &en_northd, ls_lbacls_northd_handler); + engine_add_input(&en_ls_lbacls, &en_port_group, + ls_lbacls_port_group_handler); + engine_add_input(&en_ls_lbacls, &en_nb_logical_switch, + ls_lbacls_logical_switch_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); @@ -229,6 +237,7 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, engine_add_input(&en_lflow, &en_northd, lflow_northd_handler); engine_add_input(&en_lflow, &en_port_group, lflow_port_group_handler); engine_add_input(&en_lflow, &en_lr_lb_nat_data, NULL); + engine_add_input(&en_lflow, &en_ls_lbacls, NULL); engine_add_input(&en_sync_to_sb_addr_set, &en_nb_address_set, sync_to_sb_addr_set_nb_address_set_handler); diff --git a/northd/northd.c b/northd/northd.c index c8a224d3cd..924f5cd7e0 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -45,6 +45,7 @@ #include "en-lb-data.h" #include "en-lr-nat.h" #include "en-lr-lb-nat-data.h" +#include "en-ls-lb-acls.h" #include "lib/ovn-parallel-hmap.h" #include "ovn/actions.h" #include "ovn/features.h" @@ -575,7 +576,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])) { @@ -592,7 +593,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])) { @@ -608,13 +609,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); } } @@ -1058,7 +1059,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; @@ -1089,7 +1089,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; } @@ -2570,7 +2569,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_lbnat_rec + || !lr_lbnat_rec->has_lb_vip)) || !eth_addr_from_string(op->nbrp->mac, &mac)) { *n = n_nats; return NULL; @@ -3817,7 +3817,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 && !smap_get(&od->nbr->options, "chassis")) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); VLOG_WARN_RL(&rl, "Load-balancers are configured on logical " @@ -5441,7 +5441,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, BITMAP_FOR_EACH_1 (index, ods_size(ls_datapaths), lb_dps->nb_ls_map) { od = ls_datapaths->array[index]; - init_lb_for_datapath(od); /* Add the ls datapath to the northd tracked data. */ hmapx_add(&nd_changes->ls_with_changed_lbs.crupdated, od); @@ -5524,9 +5523,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, } } - /* Re-evaluate 'od->has_lb_vip' */ - init_lb_for_datapath(od); - /* Add the ls datapath to the northd tracked data. */ hmapx_add(&nd_changes->ls_with_changed_lbs.crupdated, od); } @@ -5564,9 +5560,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, } } - /* Re-evaluate 'od->has_lb_vip' */ - init_lb_for_datapath(od); - /* Add the lr datapath to the northd tracked data. */ hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); } @@ -5581,8 +5574,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, BITMAP_FOR_EACH_1 (index, ods_size(ls_datapaths), lb_dps->nb_ls_map) { od = ls_datapaths->array[index]; - /* Re-evaluate 'od->has_lb_vip' */ - init_lb_for_datapath(od); /* Add the ls datapath to the northd tracked data. */ hmapx_add(&nd_changes->ls_with_changed_lbs.crupdated, od); @@ -5591,8 +5582,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, BITMAP_FOR_EACH_1 (index, ods_size(lr_datapaths), lb_dps->nb_lr_map) { od = lr_datapaths->array[index]; - /* Re-evaluate 'od->has_lb_vip' */ - init_lb_for_datapath(od); /* Add the lr datapath to the northd tracked data. */ hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); @@ -5618,9 +5607,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, od = lbgrp_dps->lr[i]; ovn_lb_datapaths_add_lr(lb_dps, 1, &od); - /* Re-evaluate 'od->has_lb_vip' */ - init_lb_for_datapath(od); - /* Add the lr datapath to the northd tracked data. */ hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); } @@ -5629,9 +5615,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, od = lbgrp_dps->ls[i]; ovn_lb_datapaths_add_ls(lb_dps, 1, &od); - /* Re-evaluate 'od->has_lb_vip' */ - init_lb_for_datapath(od); - /* Add the ls datapath to the northd tracked data. */ hmapx_add(&nd_changes->ls_with_changed_lbs.crupdated, od); } @@ -6573,63 +6556,6 @@ build_dhcpv6_action(struct ovn_port *op, struct in6_addr *offer_ip, return true; } -static bool -od_set_acl_flags(struct ovn_datapath *od, struct nbrec_acl **acls, - size_t n_acls) -{ - /* A true return indicates that there are no possible ACL flags - * left to set on od. A false return indicates that further ACLs - * should be explored in case more flags need to be set on od - */ - if (!n_acls) { - return false; - } - - od->has_acls = true; - for (size_t i = 0; i < n_acls; i++) { - const struct nbrec_acl *acl = acls[i]; - if (acl->tier > od->max_acl_tier) { - od->max_acl_tier = acl->tier; - } - if (!od->has_stateful_acl && !strcmp(acl->action, "allow-related")) { - od->has_stateful_acl = true; - } - if (od->has_stateful_acl && - od->max_acl_tier == nbrec_acl_col_tier.type.value.integer.max) { - return true; - } - } - - return false; -} - -static void -ls_get_acl_flags(struct ovn_datapath *od, - const struct ls_port_group_table *ls_port_groups) -{ - od->has_acls = false; - od->has_stateful_acl = false; - od->max_acl_tier = 0; - - if (od_set_acl_flags(od, od->nbs->acls, od->nbs->n_acls)) { - return; - } - - const struct ls_port_group *ls_pg = - ls_port_group_table_find(ls_port_groups, 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 (od_set_acl_flags(od, ls_pg_rec->nb_pg->acls, - ls_pg_rec->nb_pg->n_acls)) { - return; - } - } -} - /* Adds the logical flows in the (in/out) check port sec stage only if * - the lport is disabled or * - lport is of type vtep - to skip the ingress pipeline. @@ -6774,9 +6700,10 @@ build_lswitch_output_port_sec_od(struct ovn_datapath *od, } static void -skip_port_from_conntrack(struct ovn_datapath *od, struct ovn_port *op, - enum ovn_stage in_stage, enum ovn_stage out_stage, - uint16_t priority, struct hmap *lflows) +skip_port_from_conntrack(const struct ovn_datapath *od, struct ovn_port *op, + bool has_stateful_acl, enum ovn_stage in_stage, + enum ovn_stage out_stage, uint16_t priority, + struct hmap *lflows) { /* Can't use ct() for router ports. Consider the following configuration: * lp1(10.0.0.2) on hostA--ls1--lr0--ls2--lp2(10.0.1.2) on hostB, For a @@ -6789,7 +6716,7 @@ skip_port_from_conntrack(struct ovn_datapath *od, struct ovn_port *op, * conntrack state across all chassis. */ const char *ingress_action = "next;"; - const char *egress_action = od->has_stateful_acl + const char *egress_action = has_stateful_acl ? "next;" : "ct_clear; next;"; @@ -6808,7 +6735,7 @@ skip_port_from_conntrack(struct ovn_datapath *od, struct ovn_port *op, } static void -build_stateless_filter(struct ovn_datapath *od, +build_stateless_filter(const struct ovn_datapath *od, const struct nbrec_acl *acl, struct hmap *lflows) { @@ -6829,7 +6756,7 @@ build_stateless_filter(struct ovn_datapath *od, } static void -build_stateless_filters(struct ovn_datapath *od, +build_stateless_filters(const struct ovn_datapath *od, const struct ls_port_group_table *ls_port_groups, struct hmap *lflows) { @@ -6859,9 +6786,7 @@ build_stateless_filters(struct ovn_datapath *od, } static void -build_pre_acls(struct ovn_datapath *od, - const struct ls_port_group_table *ls_port_groups, - struct hmap *lflows) +build_pre_acls(struct ovn_datapath *od, struct hmap *lflows) { /* Ingress and Egress Pre-ACL Table (Priority 0): Packets are * allowed by default. */ @@ -6873,18 +6798,26 @@ build_pre_acls(struct ovn_datapath *od, ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, "eth.src == $svc_monitor_mac", "next;"); +} + +static void +build_ls_lbacls_rec_pre_acls(const struct ls_lbacls_record *ls_lbacls_rec, + const struct ls_port_group_table *ls_port_groups, + struct hmap *lflows) +{ + const struct ovn_datapath *od = ls_lbacls_rec->od; /* If there are any stateful ACL rules in this datapath, we may * send IP packets for some (allow) filters through the conntrack action, * which handles defragmentation, in order to match L4 headers. */ - if (od->has_stateful_acl) { + if (ls_lbacls_rec->has_stateful_acl) { for (size_t i = 0; i < od->n_router_ports; i++) { - skip_port_from_conntrack(od, od->router_ports[i], + skip_port_from_conntrack(od, od->router_ports[i], true, S_SWITCH_IN_PRE_ACL, S_SWITCH_OUT_PRE_ACL, 110, lflows); } for (size_t i = 0; i < od->n_localnet_ports; i++) { - skip_port_from_conntrack(od, od->localnet_ports[i], + skip_port_from_conntrack(od, od->localnet_ports[i], true, S_SWITCH_IN_PRE_ACL, S_SWITCH_OUT_PRE_ACL, 110, lflows); @@ -6922,7 +6855,7 @@ build_pre_acls(struct ovn_datapath *od, REGBIT_CONNTRACK_DEFRAG" = 1; next;"); ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 100, "ip", REGBIT_CONNTRACK_DEFRAG" = 1; next;"); - } else if (od->has_lb_vip) { + } else if (ls_lbacls_rec->has_lb_vip) { /* We'll build stateless filters if there are LB rules so that * the stateless flows are not tracked in pre-lb. */ build_stateless_filters(od, ls_port_groups, lflows); @@ -7050,30 +6983,40 @@ build_pre_lb(struct ovn_datapath *od, const struct shash *meter_groups, ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 0, "1", "next;"); ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 0, "1", "next;"); + /* Do not send statless flows via conntrack */ + ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110, + REGBIT_ACL_STATELESS" == 1", "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110, + REGBIT_ACL_STATELESS" == 1", "next;"); +} + +static void +build_ls_lbacls_rec_pre_lb(const struct ls_lbacls_record *ls_lbacls_rec, + struct hmap *lflows) +{ + const struct ovn_datapath *od = ls_lbacls_rec->od; + for (size_t i = 0; i < od->n_router_ports; i++) { skip_port_from_conntrack(od, od->router_ports[i], + ls_lbacls_rec->has_stateful_acl, S_SWITCH_IN_PRE_LB, S_SWITCH_OUT_PRE_LB, 110, lflows); } + /* Localnet ports have no need for going through conntrack, unless * the logical switch has a load balancer. Then, conntrack is necessary * so that traffic arriving via the localnet port can be load * balanced. */ - if (!od->has_lb_vip) { + if (!ls_lbacls_rec->has_lb_vip) { for (size_t i = 0; i < od->n_localnet_ports; i++) { skip_port_from_conntrack(od, od->localnet_ports[i], + ls_lbacls_rec->has_stateful_acl, S_SWITCH_IN_PRE_LB, S_SWITCH_OUT_PRE_LB, 110, lflows); } } - /* Do not sent statless flows via conntrack */ - ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110, - REGBIT_ACL_STATELESS" == 1", "next;"); - ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110, - REGBIT_ACL_STATELESS" == 1", "next;"); - /* 'REGBIT_CONNTRACK_NAT' is set to let the pre-stateful table send * packet to conntrack for defragmentation and possibly for unNATting. * @@ -7104,7 +7047,7 @@ build_pre_lb(struct ovn_datapath *od, const struct shash *meter_groups, * ingress pipeline if a load balancer is configured. We can now * add a lflow to drop ct.inv packets. */ - if (od->has_lb_vip) { + if (ls_lbacls_rec->has_lb_vip) { ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 100, "ip", REGBIT_CONNTRACK_NAT" = 1; next;"); ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, @@ -7145,10 +7088,12 @@ build_pre_stateful(struct ovn_datapath *od, } static void -build_acl_hints(struct ovn_datapath *od, +build_acl_hints(const struct ls_lbacls_record *ls_lbacls_rec, const struct chassis_features *features, struct hmap *lflows) { + const struct ovn_datapath *od = ls_lbacls_rec->od; + /* This stage builds hints for the IN/OUT_ACL stage. Based on various * combinations of ct flags packets may hit only a subset of the logical * flows in the IN/OUT_ACL stage. @@ -7172,13 +7117,13 @@ build_acl_hints(struct ovn_datapath *od, const char *match; /* In any case, advance to the next stage. */ - if (!od->has_acls && !od->has_lb_vip) { + if (!ls_lbacls_rec->has_acls && !ls_lbacls_rec->has_lb_vip) { ovn_lflow_add(lflows, od, stage, UINT16_MAX, "1", "next;"); } else { ovn_lflow_add(lflows, od, stage, 0, "1", "next;"); } - if (!od->has_stateful_acl && !od->has_lb_vip) { + if (!ls_lbacls_rec->has_stateful_acl && !ls_lbacls_rec->has_lb_vip) { continue; } @@ -7314,10 +7259,10 @@ build_acl_log(struct ds *actions, const struct nbrec_acl *acl, } static void -consider_acl(struct hmap *lflows, struct ovn_datapath *od, +consider_acl(struct hmap *lflows, const struct ovn_datapath *od, const struct nbrec_acl *acl, bool has_stateful, bool ct_masked_mark, const struct shash *meter_groups, - struct ds *match, struct ds *actions) + uint64_t max_acl_tier, struct ds *match, struct ds *actions) { const char *ct_blocked_match = ct_masked_mark ? "ct_mark.blocked" @@ -7354,7 +7299,7 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, /* All ACLS will start by matching on their respective tier. */ size_t match_tier_len = 0; ds_clear(match); - if (od->max_acl_tier) { + if (max_acl_tier) { ds_put_format(match, REG_ACL_TIER " == %"PRId64" && ", acl->tier); match_tier_len = match->length; } @@ -7543,12 +7488,15 @@ ovn_update_ipv6_options(struct hmap *lr_ports) #define IPV6_CT_OMIT_MATCH "nd || nd_ra || nd_rs || mldv1 || mldv2" static void -build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, +build_acl_action_lflows(const struct ls_lbacls_record *ls_lbacls_rec, + struct hmap *lflows, const char *default_acl_action, const struct shash *meter_groups, struct ds *match, struct ds *actions) { + const struct ovn_datapath *od = ls_lbacls_rec->od; + enum ovn_stage stages [] = { S_SWITCH_IN_ACL_ACTION, S_SWITCH_IN_ACL_AFTER_LB_ACTION, @@ -7559,7 +7507,7 @@ build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, ds_put_cstr(actions, REGBIT_ACL_VERDICT_ALLOW " = 0; " REGBIT_ACL_VERDICT_DROP " = 0; " REGBIT_ACL_VERDICT_REJECT " = 0; "); - if (od->max_acl_tier) { + if (ls_lbacls_rec->max_acl_tier) { ds_put_cstr(actions, REG_ACL_TIER " = 0; "); } @@ -7567,7 +7515,7 @@ build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, for (size_t i = 0; i < ARRAY_SIZE(stages); i++) { enum ovn_stage stage = stages[i]; - if (!od->has_acls) { + if (!ls_lbacls_rec->has_acls) { ovn_lflow_add(lflows, od, stage, 0, "1", "next;"); continue; } @@ -7602,7 +7550,7 @@ build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, ovn_lflow_add(lflows, od, stage, 0, "1", ds_cstr(actions)); struct ds tier_actions = DS_EMPTY_INITIALIZER; - for (size_t j = 0; j < od->max_acl_tier; j++) { + for (size_t j = 0; j < ls_lbacls_rec->max_acl_tier; j++) { ds_clear(match); ds_put_format(match, REG_ACL_TIER " == %"PRIuSIZE, j); ds_clear(&tier_actions); @@ -7618,7 +7566,7 @@ build_acl_action_lflows(struct ovn_datapath *od, struct hmap *lflows, } static void -build_acl_log_related_flows(struct ovn_datapath *od, struct hmap *lflows, +build_acl_log_related_flows(const struct ovn_datapath *od, struct hmap *lflows, const struct nbrec_acl *acl, bool has_stateful, bool ct_masked_mark, const struct shash *meter_groups, @@ -7691,15 +7639,19 @@ build_acl_log_related_flows(struct ovn_datapath *od, struct hmap *lflows, } static void -build_acls(struct ovn_datapath *od, const struct chassis_features *features, +build_acls(const struct ls_lbacls_record *ls_lbacls_rec, + const struct chassis_features *features, struct hmap *lflows, const struct ls_port_group_table *ls_port_groups, const struct shash *meter_groups) { + const struct ovn_datapath *od = ls_lbacls_rec->od; + const char *default_acl_action = default_acl_drop ? debug_implicit_drop_action() : "next;"; - bool has_stateful = od->has_stateful_acl || od->has_lb_vip; + bool has_stateful = (ls_lbacls_rec->has_stateful_acl + || ls_lbacls_rec->has_lb_vip); const char *ct_blocked_match = features->ct_no_masked_label ? "ct_mark.blocked" : "ct_label.blocked"; @@ -7713,8 +7665,8 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, * * A related rule at priority 1 is added below if there * are any stateful ACLs in this datapath. */ - if (!od->has_acls) { - if (!od->has_lb_vip) { + if (!ls_lbacls_rec->has_acls) { + if (!ls_lbacls_rec->has_lb_vip) { ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, UINT16_MAX, "1", "next;"); ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL_EVAL, UINT16_MAX, "1", @@ -7877,7 +7829,8 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, meter_groups, &match, &actions); consider_acl(lflows, od, acl, has_stateful, features->ct_no_masked_label, - meter_groups, &match, &actions); + meter_groups, ls_lbacls_rec->max_acl_tier, + &match, &actions); } const struct ls_port_group *ls_pg = @@ -7893,7 +7846,8 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, meter_groups, &match, &actions); consider_acl(lflows, od, acl, has_stateful, features->ct_no_masked_label, - meter_groups, &match, &actions); + meter_groups, ls_lbacls_rec->max_acl_tier, + &match, &actions); } } } @@ -7911,7 +7865,7 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, dns_actions); } - if (od->has_acls || od->has_lb_vip) { + if (ls_lbacls_rec->has_acls || ls_lbacls_rec->has_lb_vip) { /* Add a 34000 priority flow to advance the service monitor reply * packets to skip applying ingress ACLs. */ ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_EVAL, 34000, @@ -7925,8 +7879,8 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, REGBIT_ACL_VERDICT_ALLOW" = 1; next;"); } - build_acl_action_lflows(od, lflows, default_acl_action, meter_groups, - &match, &actions); + build_acl_action_lflows(ls_lbacls_rec, lflows, default_acl_action, + meter_groups, &match, &actions); ds_destroy(&match); ds_destroy(&actions); @@ -8571,8 +8525,11 @@ build_stateful(struct ovn_datapath *od, } static void -build_lb_hairpin(struct ovn_datapath *od, struct hmap *lflows) +build_lb_hairpin(const struct ls_lbacls_record *ls_lbacls_rec, + struct hmap *lflows) { + const struct ovn_datapath *od = ls_lbacls_rec->od; + /* Ingress Pre-Hairpin/Nat-Hairpin/Hairpin tabled (Priority 0). * Packets that don't need hairpinning should continue processing. */ @@ -8580,7 +8537,7 @@ build_lb_hairpin(struct ovn_datapath *od, struct hmap *lflows) ovn_lflow_add(lflows, od, S_SWITCH_IN_NAT_HAIRPIN, 0, "1", "next;"); ovn_lflow_add(lflows, od, S_SWITCH_IN_HAIRPIN, 0, "1", "next;"); - if (od->has_lb_vip) { + if (ls_lbacls_rec->has_lb_vip) { /* Check if the packet needs to be hairpinned. * Set REGBIT_HAIRPIN in the original direction and * REGBIT_HAIRPIN_REPLY in the reply direction. @@ -9413,22 +9370,16 @@ build_lswitch_lflows_l2_unknown(struct ovn_datapath *od, static void build_lswitch_lflows_pre_acl_and_acl( struct ovn_datapath *od, - const struct ls_port_group_table *ls_port_groups, const struct chassis_features *features, struct hmap *lflows, const struct shash *meter_groups) { ovs_assert(od->nbs); - ls_get_acl_flags(od, ls_port_groups); - - build_pre_acls(od, ls_port_groups, lflows); + build_pre_acls(od, lflows); build_pre_lb(od, meter_groups, lflows); build_pre_stateful(od, features, lflows); - build_acl_hints(od, features, lflows); - build_acls(od, features, lflows, ls_port_groups, meter_groups); build_qos(od, lflows); build_stateful(od, features, lflows); - build_lb_hairpin(od, lflows); build_vtep_hairpin(od, lflows); } @@ -15487,7 +15438,7 @@ build_lrouter_nat_defrag_and_lb( * a dynamically negotiated FTP data channel), but will allow * related traffic such as an ICMP Port Unreachable through * that's generated from a non-listening UDP port. */ - if (od->has_lb_vip && features->ct_lb_related) { + if (lr_lbnat_rec->has_lb_vip && features->ct_lb_related) { ds_clear(match); ds_put_cstr(match, "ct.rel && !ct.est && !ct.new"); @@ -15512,7 +15463,7 @@ build_lrouter_nat_defrag_and_lb( * Pass the traffic that is already established to the next table with * proper flags set. */ - if (od->has_lb_vip) { + if (lr_lbnat_rec->has_lb_vip) { ds_clear(match); ds_put_format(match, "ct.est && !ct.rel && !ct.new && %s.natted", @@ -15542,7 +15493,7 @@ build_lrouter_nat_defrag_and_lb( * not committed, it would produce ongoing datapath flows with the ct.new * flag set. Some NICs are unable to offload these flows. */ - if (od->is_gw_router && (od->nbr->n_nat || od->has_lb_vip)) { + if (od->is_gw_router && (od->nbr->n_nat || lr_lbnat_rec->has_lb_vip)) { /* Do not send ND or ICMP packets to connection tracking. */ ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 100, "nd || nd_rs || nd_ra", "next;"); @@ -15967,6 +15918,22 @@ build_lr_lbnat_data_flows(const struct lr_lb_nat_data_record *lr_lbnat_rec, meter_groups); } +static void +build_ls_lbacls_flows(const struct ls_lbacls_record *ls_lbacls_rec, + const struct ls_port_group_table *ls_pgs, + const struct chassis_features *features, + const struct shash *meter_groups, + struct hmap *lflows) +{ + ovs_assert(ls_lbacls_rec->od); + + build_ls_lbacls_rec_pre_acls(ls_lbacls_rec, ls_pgs, lflows); + build_ls_lbacls_rec_pre_lb(ls_lbacls_rec, lflows); + build_acl_hints(ls_lbacls_rec, features, lflows); + build_acls(ls_lbacls_rec, features, lflows, ls_pgs, meter_groups); + build_lb_hairpin(ls_lbacls_rec, lflows); +} + struct lswitch_flow_build_info { const struct ovn_datapaths *ls_datapaths; const struct ovn_datapaths *lr_datapaths; @@ -15974,6 +15941,7 @@ struct lswitch_flow_build_info { const struct hmap *lr_ports; const struct ls_port_group_table *ls_port_groups; const struct lr_lb_nat_data_table *lr_lbnats; + const struct ls_lbacls_table *ls_lbacls; struct hmap *lflows; struct hmap *igmp_groups; const struct shash *meter_groups; @@ -15998,9 +15966,7 @@ build_lswitch_and_lrouter_iterate_by_ls(struct ovn_datapath *od, struct lswitch_flow_build_info *lsi) { ovs_assert(od->nbs); - build_lswitch_lflows_pre_acl_and_acl(od, lsi->ls_port_groups, - lsi->features, - lsi->lflows, + build_lswitch_lflows_pre_acl_and_acl(od, lsi->features, lsi->lflows, lsi->meter_groups); build_fwd_group_lflows(od, lsi->lflows); @@ -16115,6 +16081,7 @@ build_lflows_thread(void *arg) { struct worker_control *control = (struct worker_control *) arg; const struct lr_lb_nat_data_record *lr_lbnat_rec; + const struct ls_lbacls_record *ls_lbacls_rec; struct lswitch_flow_build_info *lsi; struct ovn_igmp_group *igmp_group; struct ovn_lb_datapaths *lb_dps; @@ -16243,6 +16210,19 @@ build_lflows_thread(void *arg) lsi->features); } } + + for (bnum = control->id; + bnum <= lsi->ls_lbacls->entries.mask; + bnum += control->pool->size) + { + LS_LBACLS_TABLE_FOR_EACH_IN_P (ls_lbacls_rec, bnum, + lsi->ls_lbacls) { + build_ls_lbacls_flows(ls_lbacls_rec, lsi->ls_port_groups, + lsi->features, lsi->meter_groups, + lsi->lflows); + } + } + for (bnum = control->id; bnum <= lsi->igmp_groups->mask; bnum += control->pool->size) @@ -16303,6 +16283,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, const struct hmap *lr_ports, const struct ls_port_group_table *ls_pgs, const struct lr_lb_nat_data_table *lr_lbnats, + const struct ls_lbacls_table *ls_lbacls, struct hmap *lflows, struct hmap *igmp_groups, const struct shash *meter_groups, @@ -16333,6 +16314,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, lsiv[index].lr_ports = lr_ports; lsiv[index].ls_port_groups = ls_pgs; lsiv[index].lr_lbnats = lr_lbnats; + lsiv[index].ls_lbacls = ls_lbacls; lsiv[index].igmp_groups = igmp_groups; lsiv[index].meter_groups = meter_groups; lsiv[index].lb_dps_map = lb_dps_map; @@ -16358,6 +16340,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, free(lsiv); } else { const struct lr_lb_nat_data_record *lr_lbnat_rec; + const struct ls_lbacls_record *ls_lbacls_rec; struct ovn_igmp_group *igmp_group; struct ovn_lb_datapaths *lb_dps; struct ovn_datapath *od; @@ -16370,6 +16353,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, .lr_ports = lr_ports, .ls_port_groups = ls_pgs, .lr_lbnats = lr_lbnats, + .ls_lbacls = ls_lbacls, .lflows = lflows, .igmp_groups = igmp_groups, .meter_groups = meter_groups, @@ -16439,6 +16423,12 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, lsi.features); } + LS_LBACLS_TABLE_FOR_EACH (ls_lbacls_rec, ls_lbacls) { + build_ls_lbacls_flows(ls_lbacls_rec, lsi.ls_port_groups, + lsi.features, lsi.meter_groups, + lsi.lflows); + } + stopwatch_start(LFLOWS_IGMP_STOPWATCH_NAME, time_msec()); HMAP_FOR_EACH (igmp_group, hmap_node, igmp_groups) { build_lswitch_ip_mcast_igmp_mld(igmp_group, @@ -16535,6 +16525,7 @@ void build_lflows(struct ovsdb_idl_txn *ovnsb_txn, input_data->lr_ports, input_data->ls_port_groups, input_data->lr_lbnats, + input_data->ls_lbacls, lflows, &igmp_groups, input_data->meter_groups, diff --git a/northd/northd.h b/northd/northd.h index 08a81b2c10..23b4754db4 100644 --- a/northd/northd.h +++ b/northd/northd.h @@ -89,6 +89,8 @@ ods_size(const struct ovn_datapaths *datapaths) return hmap_count(&datapaths->datapaths); } +bool od_has_lb_vip(const struct ovn_datapath *od); + struct tracked_ovn_ports { /* tracked created ports. * hmapx node data is 'struct ovn_port *' */ @@ -179,6 +181,7 @@ struct lflow_input { const struct hmap *lr_ports; const struct ls_port_group_table *ls_port_groups; const struct lr_lb_nat_data_table *lr_lbnats; + const struct ls_lbacls_table *ls_lbacls; const struct shash *meter_groups; const struct hmap *lb_datapaths_map; const struct hmap *bfd_connections; @@ -288,11 +291,7 @@ struct ovn_datapath { struct hmap port_tnlids; uint32_t port_key_hint; - bool has_stateful_acl; - bool has_lb_vip; bool has_unknown; - bool has_acls; - uint64_t max_acl_tier; bool has_vtep_lports; bool has_arp_proxy_port;