Using the ACL IDs created in the previous commit, northd adds this ID to the conntrack entry for allow-established ACLs.
ovn-controller keeps track of the southbound ACL IDs. If an ACL ID is removed from the southbound database, then ovn-controller flushes the conntrack entry whose label contains the deleted ACL ID. With this change, it means that deleting an allow-established ACL, or changing its action type to something else, will result in the conntrack entry being flushed. This will cause the traffic to no longer automatically be allowed. Reported-at: https://issues.redhat.com/browse/FDP-815 Signed-off-by: Mark Michelson <mmich...@redhat.com> --- controller/acl_ids.c | 279 ++++++++++++++++++++++++++++++++++++ controller/acl_ids.h | 30 ++++ controller/automake.mk | 2 + controller/ovn-controller.c | 12 +- lib/logical-fields.c | 2 + northd/en-acl-ids.c | 13 ++ northd/en-acl-ids.h | 3 + northd/en-lflow.c | 1 + northd/inc-proc-northd.c | 1 + northd/northd.c | 54 +++++-- northd/northd.h | 1 + tests/ovn-northd.at | 20 ++- tests/system-ovn.at | 20 +++ 13 files changed, 417 insertions(+), 21 deletions(-) create mode 100644 controller/acl_ids.c create mode 100644 controller/acl_ids.h diff --git a/controller/acl_ids.c b/controller/acl_ids.c new file mode 100644 index 000000000..6267f3399 --- /dev/null +++ b/controller/acl_ids.c @@ -0,0 +1,279 @@ +/* Copyright (c) 2024, Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <config.h> + +#include "openvswitch/hmap.h" +#include "openvswitch/rconn.h" +#include "openvswitch/ofp-ct.h" +#include "openvswitch/ofp-util.h" +#include "openvswitch/ofp-msgs.h" +#include "openvswitch/vlog.h" +#include "lib/socket-util.h" + +#include "lib/ovn-sb-idl.h" +#include "acl_ids.h" + +VLOG_DEFINE_THIS_MODULE(acl_ids); + +enum acl_id_state { + /* The ID exists in the SB DB. */ + ACTIVE, + /* The ID has been removed from the DB and needs to have its conntrack + * entries flushed. + */ + SB_DELETED, + /* We have sent the conntrack flush request to OVS for this ACL ID. */ + FLUSHING, + /* We have either successfully flushed the ID, or we have failed enough + * times that we have given up. + */ + TO_DELETE, +}; + +struct acl_id { + int64_t id; + enum acl_id_state state; + struct hmap_node hmap_node; + ovs_be32 xid; + int flush_count; +}; + +struct tracked_acl_ids { + struct hmap ids; +}; + +static struct acl_id * +find_tracked_acl_id(struct tracked_acl_ids *tracked_ids, int64_t id) +{ + uint32_t hash = hash_uint64(id); + struct acl_id *acl_id; + HMAP_FOR_EACH_WITH_HASH (acl_id, hmap_node, hash, &tracked_ids->ids) { + if (acl_id->id == id) { + return acl_id; + } + } + return NULL; +} + +static void +acl_id_destroy(struct acl_id *acl_id) +{ + free(acl_id); +} + +void * +en_acl_id_init(struct engine_node *node OVS_UNUSED, + struct engine_arg *arg OVS_UNUSED) +{ + struct tracked_acl_ids *ids = xzalloc(sizeof *ids); + hmap_init(&ids->ids); + return ids; +} + +void +en_acl_id_run(struct engine_node *node, void *data) +{ + const struct sbrec_acl_id_table *sb_acl_id_table = + EN_OVSDB_GET(engine_get_input("SB_acl_id", node)); + const struct sbrec_acl_id *sb_id; + + struct tracked_acl_ids *ids = data; + struct acl_id *id; + + /* Pre-mark each active ID as SB_DELETED. */ + HMAP_FOR_EACH (id, hmap_node, &ids->ids) { + if (id->state == ACTIVE) { + id->state = SB_DELETED; + } + } + + SBREC_ACL_ID_TABLE_FOR_EACH (sb_id, sb_acl_id_table) { + id = find_tracked_acl_id(ids, sb_id->id); + if (!id) { + id = xzalloc(sizeof *id); + id->id = sb_id->id; + hmap_insert(&ids->ids, &id->hmap_node, hash_uint64(sb_id->id)); + } + id->state = ACTIVE; + } + + engine_set_node_state(node, EN_UPDATED); +} + +void +en_acl_id_cleanup(void *data) +{ + struct tracked_acl_ids *tracked_ids = data; + struct acl_id *id; + HMAP_FOR_EACH_POP (id, hmap_node, &tracked_ids->ids) { + acl_id_destroy(id); + } + hmap_destroy(&tracked_ids->ids); +} + +static struct rconn *swconn; +static ovs_be32 barrier_xid; + +void +acl_ids_update_swconn(const char *target, int probe_interval) +{ + if (!swconn) { + swconn = rconn_create(0, 0, DSCP_DEFAULT, 1 << OFP15_VERSION); + } + ovn_update_swconn_at(swconn, target, probe_interval, "acl_ids"); +} + +#define MAX_FLUSHES 3 + +static void +acl_ids_handle_rconn_msg(struct ofpbuf *msg, struct tracked_acl_ids *acl_ids) +{ + const struct ofp_header *oh = msg->data; + + enum ofptype type; + ofptype_decode(&type, oh); + + if (type == OFPTYPE_ECHO_REQUEST) { + rconn_send(swconn, ofputil_encode_echo_reply(oh), NULL); + return; + } + + struct acl_id *acl_id; + if (oh->xid != barrier_xid) { + if (type != OFPTYPE_ERROR) { + return; + } + /* Uh oh! It looks like one of the flushes failed :( + * Let's find this particular one and move its state + * back to SB_DELETED so we can retry the flush. Of + * course, if this is a naughty little ID and has + * been flushed unsuccessfully too many times, we'll + * set it to TO_DELETE so it doesn't cause any more + * trouble. + */ + HMAP_FOR_EACH (acl_id, hmap_node, &acl_ids->ids) { + if (acl_id->xid != oh->xid) { + continue; + } + + acl_id->xid = 0; + acl_id->flush_count++; + if (acl_id->flush_count >= MAX_FLUSHES) { + acl_id->state = TO_DELETE; + } else { + acl_id->state = SB_DELETED; + } + + break; + } + } else { + HMAP_FOR_EACH (acl_id, hmap_node, &acl_ids->ids) { + if (acl_id->state != FLUSHING) { + continue; + } + acl_id->state = TO_DELETE; + } + barrier_xid = 0; + } +} + +static void +flush_expired_ids(struct tracked_acl_ids *acl_ids) +{ + if (barrier_xid != 0) { + /* We haven't received the previous barrier's reply, so + * hold off on sending new flushes until we get the + * reply. + */ + return; + } + + ovs_u128 mask = { + /* ct_labels.label BITS[80-95] */ + .u64.hi = 0xffff0000, + }; + struct acl_id *acl_id; + bool send_barrier = false; + HMAP_FOR_EACH (acl_id, hmap_node, &acl_ids->ids) { + if (acl_id->state != SB_DELETED) { + continue; + } + ovs_u128 ct_id = { + .u64.hi = acl_id->id << 16, + }; + VLOG_DBG("Flushing conntrack entry for ACL id %"PRId64, acl_id->id); + struct ofp_ct_match match = { + .labels = ct_id, + .labels_mask = mask, + }; + struct ofpbuf *msg = ofp_ct_match_encode(&match, NULL, + rconn_get_version(swconn)); + const struct ofp_header *oh = msg->data; + acl_id->xid = oh->xid; + acl_id->state = FLUSHING; + rconn_send(swconn, msg, NULL); + send_barrier = true; + } + + if (!send_barrier) { + return; + } + + struct ofpbuf *barrier = ofputil_encode_barrier_request(OFP15_VERSION); + const struct ofp_header *oh = barrier->data; + barrier_xid = oh->xid; + rconn_send(swconn, barrier, NULL); +} + +static void +clear_flushed_ids(struct tracked_acl_ids *acl_ids) +{ + struct acl_id *acl_id; + HMAP_FOR_EACH_SAFE (acl_id, hmap_node, &acl_ids->ids) { + if (acl_id->state != TO_DELETE) { + continue; + } + hmap_remove(&acl_ids->ids, &acl_id->hmap_node); + acl_id_destroy(acl_id); + } +} + +#define MAX_RECV_MSGS 50 + +void +acl_ids_run(struct tracked_acl_ids *acl_ids) +{ + rconn_run(swconn); + if (!rconn_is_connected(swconn)) { + rconn_run_wait(swconn); + rconn_recv_wait(swconn); + return; + } + + for (int i = 0; i < MAX_RECV_MSGS; i++) { + struct ofpbuf *msg = rconn_recv(swconn); + if (!msg) { + break; + } + acl_ids_handle_rconn_msg(msg, acl_ids); + ofpbuf_delete(msg); + } + flush_expired_ids(acl_ids); + clear_flushed_ids(acl_ids); + + rconn_run_wait(swconn); + rconn_recv_wait(swconn); +} diff --git a/controller/acl_ids.h b/controller/acl_ids.h new file mode 100644 index 000000000..e3556c37e --- /dev/null +++ b/controller/acl_ids.h @@ -0,0 +1,30 @@ +/* Copyright (c) 2024 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 OVN_ACL_IDS_H +#define OVN_ACL_IDS_H + +#include <config.h> +#include "lib/inc-proc-eng.h" + +void *en_acl_id_init(struct engine_node *, struct engine_arg *); +void en_acl_id_run(struct engine_node *, void *); +void en_acl_id_cleanup(void *); + +struct tracked_acl_ids; +void acl_ids_update_swconn(const char *target, int probe_interval); +void acl_ids_run(struct tracked_acl_ids *); + +#endif /* OVN_ACL_IDS_H */ diff --git a/controller/automake.mk b/controller/automake.mk index bb0bf2d33..c19ae27be 100644 --- a/controller/automake.mk +++ b/controller/automake.mk @@ -1,5 +1,7 @@ bin_PROGRAMS += controller/ovn-controller controller_ovn_controller_SOURCES = \ + controller/acl_ids.c \ + controller/acl_ids.h \ controller/bfd.c \ controller/bfd.h \ controller/binding.c \ diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 157def2a3..f19c291d6 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -88,6 +88,7 @@ #include "lib/dns-resolve.h" #include "ct-zone.h" #include "ovn-dns.h" +#include "acl_ids.h" VLOG_DEFINE_THIS_MODULE(main); @@ -864,7 +865,8 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl) SB_NODE(fdb, "fdb") \ SB_NODE(meter, "meter") \ SB_NODE(static_mac_binding, "static_mac_binding") \ - SB_NODE(chassis_template_var, "chassis_template_var") + SB_NODE(chassis_template_var, "chassis_template_var") \ + SB_NODE(acl_id, "acl_id") enum sb_engine_node { #define SB_NODE(NAME, NAME_STR) SB_##NAME, @@ -5095,6 +5097,7 @@ main(int argc, char *argv[]) ENGINE_NODE(mac_cache, "mac_cache"); ENGINE_NODE(bfd_chassis, "bfd_chassis"); ENGINE_NODE(dns_cache, "dns_cache"); + ENGINE_NODE(acl_id, "acl_id"); #define SB_NODE(NAME, NAME_STR) ENGINE_NODE_SB(NAME, NAME_STR); SB_NODES @@ -5303,6 +5306,9 @@ main(int argc, char *argv[]) engine_add_input(&en_controller_output, &en_bfd_chassis, controller_output_bfd_chassis_handler); + engine_add_input(&en_acl_id, &en_sb_acl_id, NULL); + engine_add_input(&en_controller_output, &en_acl_id, NULL); + struct engine_arg engine_arg = { .sb_idl = ovnsb_idl_loop.idl, .ovs_idl = ovs_idl_loop.idl, @@ -5538,6 +5544,8 @@ main(int argc, char *argv[]) br_int_remote.probe_interval); pinctrl_update_swconn(br_int_remote.target, br_int_remote.probe_interval); + acl_ids_update_swconn(br_int_remote.target, + br_int_remote.probe_interval); /* Enable ACL matching for double tagged traffic. */ if (ovs_idl_txn && cfg) { @@ -5842,6 +5850,8 @@ main(int argc, char *argv[]) !ovnsb_idl_txn, !ovs_idl_txn); stopwatch_stop(IF_STATUS_MGR_RUN_STOPWATCH_NAME, time_msec()); + + acl_ids_run(engine_get_data(&en_acl_id)); } } diff --git a/lib/logical-fields.c b/lib/logical-fields.c index 5b578b5c2..89431b939 100644 --- a/lib/logical-fields.c +++ b/lib/logical-fields.c @@ -192,6 +192,8 @@ ovn_init_symtab(struct shash *symtab) "ct_label[96..127]", WR_CT_COMMIT); expr_symtab_add_subfield_scoped(symtab, "ct_label.obs_unused", NULL, "ct_label[0..95]", WR_CT_COMMIT); + expr_symtab_add_subfield_scoped(symtab, "ct_label.acl_id", NULL, + "ct_label[80..95]", WR_CT_COMMIT); expr_symtab_add_field(symtab, "ct_state", MFF_CT_STATE, NULL, false); diff --git a/northd/en-acl-ids.c b/northd/en-acl-ids.c index 897cc2da1..cb220dd80 100644 --- a/northd/en-acl-ids.c +++ b/northd/en-acl-ids.c @@ -204,3 +204,16 @@ void sync_acl_ids(const struct acl_id_data *id_data, } } } + +int64_t +get_acl_id(const struct acl_id_data *acl_id_data, const struct nbrec_acl *acl) +{ + struct acl_id *acl_id; + uint32_t hash = uuid_hash(&acl->header_.uuid); + HMAP_FOR_EACH_WITH_HASH (acl_id, node, hash, &acl_id_data->ids) { + if (uuid_equals(&acl_id->nb_acl_uuid, &acl->header_.uuid)) { + return acl_id->id; + } + } + return 0; +} diff --git a/northd/en-acl-ids.h b/northd/en-acl-ids.h index 8b60b3c7c..8bea2e078 100644 --- a/northd/en-acl-ids.h +++ b/northd/en-acl-ids.h @@ -14,4 +14,7 @@ void en_acl_id_cleanup(void *data); struct acl_id_data; void sync_acl_ids(const struct acl_id_data *, struct ovsdb_idl_txn *, struct ovsdb_idl_index *sbrec_acl_id_by_id); + +struct nbrec_acl; +int64_t get_acl_id(const struct acl_id_data *, const struct nbrec_acl *); #endif diff --git a/northd/en-lflow.c b/northd/en-lflow.c index fa1f0236d..3d57a469b 100644 --- a/northd/en-lflow.c +++ b/northd/en-lflow.c @@ -96,6 +96,7 @@ lflow_get_input_data(struct engine_node *node, struct ed_type_sampling_app_data *sampling_app_data = engine_get_input_data("sampling_app", node); lflow_input->sampling_apps = &sampling_app_data->apps; + lflow_input->acl_id_data = engine_get_input_data("acl_id", node); } void en_lflow_run(struct engine_node *node, void *data) diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c index 43abf042d..04c208c97 100644 --- a/northd/inc-proc-northd.c +++ b/northd/inc-proc-northd.c @@ -293,6 +293,7 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, engine_add_input(&en_lflow, &en_port_group, lflow_port_group_handler); engine_add_input(&en_lflow, &en_lr_stateful, lflow_lr_stateful_handler); engine_add_input(&en_lflow, &en_ls_stateful, lflow_ls_stateful_handler); + engine_add_input(&en_lflow, &en_acl_id, NULL); engine_add_input(&en_sync_to_sb_addr_set, &en_northd, NULL); engine_add_input(&en_sync_to_sb_addr_set, &en_lr_stateful, NULL); diff --git a/northd/northd.c b/northd/northd.c index 8dab88f62..081305b09 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -206,6 +206,9 @@ BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 << 2)); #define REG_OBS_COLLECTOR_ID_NEW "reg8[0..7]" #define REG_OBS_COLLECTOR_ID_EST "reg8[8..15]" +/* Register used for storing persistent ACL IDs */ +#define REG_ACL_ID "reg7[0..15]" + /* Register used for temporarily store ECMP eth.src to avoid masked ct_label * access. It doesn't really occupy registers because the content of the * register is saved to stack and then restored in the same flow. @@ -7063,7 +7066,8 @@ consider_acl(struct lflow_table *lflows, const struct ovn_datapath *od, const struct nbrec_acl *acl, bool has_stateful, const struct shash *meter_groups, uint64_t max_acl_tier, struct ds *match, struct ds *actions, - struct lflow_ref *lflow_ref) + struct lflow_ref *lflow_ref, + const struct acl_id_data *acl_id_data) { bool ingress = !strcmp(acl->direction, "from-lport") ? true :false; enum ovn_stage stage; @@ -7151,8 +7155,17 @@ consider_acl(struct lflow_table *lflows, const struct ovn_datapath *od, ds_put_cstr(actions, REGBIT_CONNTRACK_COMMIT" = 1; "); if (!strcmp(acl->action, "allow-established")) { - ds_put_format(actions, - REGBIT_ACL_PERSIST_ID " = 1; "); + int64_t id = get_acl_id(acl_id_data, acl); + if (id) { + ds_put_format(actions, + REG_ACL_ID " = %"PRId64 "; " + REGBIT_ACL_PERSIST_ID " = 1; ", + id); + } else { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + VLOG_WARN_RL(&rl, "No ID found for ACL "UUID_FMT" (%s)", + UUID_ARGS(&acl->header_.uuid), acl->match); + } } /* For stateful ACLs sample "new" and "established" packets. */ @@ -7476,7 +7489,8 @@ build_acls(const struct ls_stateful_record *ls_stateful_rec, const struct shash *meter_groups, const struct sampling_app_table *sampling_apps, const struct chassis_features *features, - struct lflow_ref *lflow_ref) + struct lflow_ref *lflow_ref, + const struct acl_id_data *acl_id_data) { const char *default_acl_action = default_acl_drop ? debug_implicit_drop_action() @@ -7686,7 +7700,8 @@ build_acls(const struct ls_stateful_record *ls_stateful_rec, lflow_ref); consider_acl(lflows, od, acl, has_stateful, meter_groups, ls_stateful_rec->max_acl_tier, - &match, &actions, lflow_ref); + &match, &actions, lflow_ref, + acl_id_data); build_acl_sample_flows(ls_stateful_rec, od, lflows, acl, &match, &actions, sampling_apps, features, lflow_ref); @@ -7705,7 +7720,8 @@ build_acls(const struct ls_stateful_record *ls_stateful_rec, lflow_ref); consider_acl(lflows, od, acl, has_stateful, meter_groups, ls_stateful_rec->max_acl_tier, - &match, &actions, lflow_ref); + &match, &actions, lflow_ref, + acl_id_data); build_acl_sample_flows(ls_stateful_rec, od, lflows, acl, &match, &actions, sampling_apps, features, lflow_ref); @@ -8394,6 +8410,7 @@ build_stateful(struct ovn_datapath *od, struct lflow_table *lflows, "ct_mark.obs_stage = " REGBIT_ACL_OBS_STAGE "; " "ct_mark.obs_collector_id = " REG_OBS_COLLECTOR_ID_EST "; " "ct_label.obs_point_id = " REG_OBS_POINT_ID_EST "; " + "ct_label.acl_id = " REG_ACL_ID "; " "}; next;"); ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, 100, REGBIT_CONNTRACK_COMMIT" == 1 && " @@ -8415,6 +8432,7 @@ build_stateful(struct ovn_datapath *od, struct lflow_table *lflows, "ct_commit { " "ct_mark.blocked = 0; " "ct_mark.allow_established = " REGBIT_ACL_PERSIST_ID "; " + "ct_label.acl_id = " REG_ACL_ID "; " "}; next;"); ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, 100, REGBIT_CONNTRACK_COMMIT" == 1 && " @@ -17216,7 +17234,8 @@ build_ls_stateful_flows(const struct ls_stateful_record *ls_stateful_rec, const struct shash *meter_groups, const struct sampling_app_table *sampling_apps, const struct chassis_features *features, - struct lflow_table *lflows) + struct lflow_table *lflows, + const struct acl_id_data *acl_id_data) { build_ls_stateful_rec_pre_acls(ls_stateful_rec, od, ls_pgs, lflows, ls_stateful_rec->lflow_ref); @@ -17225,7 +17244,8 @@ build_ls_stateful_flows(const struct ls_stateful_record *ls_stateful_rec, build_acl_hints(ls_stateful_rec, od, lflows, ls_stateful_rec->lflow_ref); build_acls(ls_stateful_rec, od, lflows, ls_pgs, meter_groups, - sampling_apps, features, ls_stateful_rec->lflow_ref); + sampling_apps, features, ls_stateful_rec->lflow_ref, + acl_id_data); build_lb_hairpin(ls_stateful_rec, od, lflows, ls_stateful_rec->lflow_ref); } @@ -17253,6 +17273,7 @@ struct lswitch_flow_build_info { struct hmap *parsed_routes; struct hmap *route_policies; struct simap *route_tables; + const struct acl_id_data *acl_id_data; }; /* Helper function to combine all lflow generation which is iterated by @@ -17552,7 +17573,8 @@ build_lflows_thread(void *arg) lsi->meter_groups, lsi->sampling_apps, lsi->features, - lsi->lflows); + lsi->lflows, + lsi->acl_id_data); } } @@ -17629,7 +17651,8 @@ build_lswitch_and_lrouter_flows( const struct sampling_app_table *sampling_apps, struct hmap *parsed_routes, struct hmap *route_policies, - struct simap *route_tables) + struct simap *route_tables, + const struct acl_id_data *acl_id_data) { char *svc_check_match = xasprintf("eth.dst == %s", svc_monitor_mac); @@ -17667,6 +17690,7 @@ build_lswitch_and_lrouter_flows( lsiv[index].parsed_routes = parsed_routes; lsiv[index].route_tables = route_tables; lsiv[index].route_policies = route_policies; + lsiv[index].acl_id_data = acl_id_data; ds_init(&lsiv[index].match); ds_init(&lsiv[index].actions); @@ -17713,6 +17737,7 @@ build_lswitch_and_lrouter_flows( .route_policies = route_policies, .match = DS_EMPTY_INITIALIZER, .actions = DS_EMPTY_INITIALIZER, + .acl_id_data = acl_id_data, }; /* Combined build - all lflow generation from lswitch and lrouter @@ -17786,7 +17811,8 @@ build_lswitch_and_lrouter_flows( lsi.meter_groups, lsi.sampling_apps, lsi.features, - lsi.lflows); + lsi.lflows, + lsi.acl_id_data); } stopwatch_stop(LFLOWS_LS_STATEFUL_STOPWATCH_NAME, time_msec()); stopwatch_start(LFLOWS_IGMP_STOPWATCH_NAME, time_msec()); @@ -17879,7 +17905,8 @@ void build_lflows(struct ovsdb_idl_txn *ovnsb_txn, input_data->sampling_apps, input_data->parsed_routes, input_data->route_policies, - input_data->route_tables); + input_data->route_tables, + input_data->acl_id_data); if (parallelization_state == STATE_INIT_HASH_SIZES) { parallelization_state = STATE_USE_PARALLELIZATION; @@ -18306,7 +18333,8 @@ lflow_handle_ls_stateful_changes(struct ovsdb_idl_txn *ovnsb_txn, lflow_input->meter_groups, lflow_input->sampling_apps, lflow_input->features, - lflows); + lflows, + lflow_input->acl_id_data); /* Sync the new flows to SB. */ bool handled = lflow_ref_sync_lflows( diff --git a/northd/northd.h b/northd/northd.h index bccb1c5d8..175c318af 100644 --- a/northd/northd.h +++ b/northd/northd.h @@ -232,6 +232,7 @@ struct lflow_input { struct hmap *parsed_routes; struct hmap *route_policies; struct simap *route_tables; + const struct acl_id_data *acl_id_data; }; extern int parallelization_state; diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index 1d90622e1..b5b94330b 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -14297,21 +14297,27 @@ after_lb_uuid=$(fetch_column nb:ACL _uuid priority=1003) check ovn-nbctl set acl $ingress_uuid action=allow-established check ovn-nbctl set acl $egress_uuid action=allow-established -check ovn-nbctl set acl $after_lb_uuid action=allow-established +check ovn-nbctl --wait=sb set acl $after_lb_uuid action=allow-established + +dnl Retrieve the IDs for the ACLs so we can check them properly. + +ingress_id=$(fetch_column ACL_ID id nb_acl=$ingress_uuid) +egress_id=$(fetch_column ACL_ID id nb_acl=$egress_uuid) +after_lb_id=$(fetch_column ACL_ID id nb_acl=$after_lb_uuid) dnl Now we should see the registers being set to the appropriate values. -AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_acl_eval | grep priority=2001 | ovn_strip_lflows], [0], [dnl - table=??(ls_in_acl_eval ), priority=2001 , match=(reg0[[7]] == 1 && (tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[20]] = 1; next;) +AT_CHECK_UNQUOTED([ovn-sbctl lflow-list sw | grep ls_in_acl_eval | grep priority=2001 | ovn_strip_lflows], [0], [dnl + table=??(ls_in_acl_eval ), priority=2001 , match=(reg0[[7]] == 1 && (tcp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg7[[0..15]] = $ingress_id; reg0[[20]] = 1; next;) table=??(ls_in_acl_eval ), priority=2001 , match=(reg0[[8]] == 1 && (tcp)), action=(reg8[[16]] = 1; next;) ]) -AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_acl_after_lb_eval | grep priority=2003 | ovn_strip_lflows], [0], [dnl - table=??(ls_in_acl_after_lb_eval), priority=2003 , match=(reg0[[7]] == 1 && (udp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[20]] = 1; next;) +AT_CHECK_UNQUOTED([ovn-sbctl lflow-list sw | grep ls_in_acl_after_lb_eval | grep priority=2003 | ovn_strip_lflows], [0], [dnl + table=??(ls_in_acl_after_lb_eval), priority=2003 , match=(reg0[[7]] == 1 && (udp)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg7[[0..15]] = $after_lb_id; reg0[[20]] = 1; next;) table=??(ls_in_acl_after_lb_eval), priority=2003 , match=(reg0[[8]] == 1 && (udp)), action=(reg8[[16]] = 1; next;) ]) -AT_CHECK([ovn-sbctl lflow-list sw | grep ls_out_acl_eval | grep priority=2002 | ovn_strip_lflows], [0], [dnl - table=??(ls_out_acl_eval ), priority=2002 , match=(reg0[[7]] == 1 && (ip)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg0[[20]] = 1; next;) +AT_CHECK_UNQUOTED([ovn-sbctl lflow-list sw | grep ls_out_acl_eval | grep priority=2002 | ovn_strip_lflows], [0], [dnl + table=??(ls_out_acl_eval ), priority=2002 , match=(reg0[[7]] == 1 && (ip)), action=(reg8[[16]] = 1; reg0[[1]] = 1; reg7[[0..15]] = $egress_id; reg0[[20]] = 1; next;) table=??(ls_out_acl_eval ), priority=2002 , match=(reg0[[8]] == 1 && (ip)), action=(reg8[[16]] = 1; next;) ]) diff --git a/tests/system-ovn.at b/tests/system-ovn.at index a6ddda0f7..27e112a26 100644 --- a/tests/system-ovn.at +++ b/tests/system-ovn.at @@ -14251,6 +14251,18 @@ test : > output.txt +# Get the ID for this ACL +acl_id=$(fetch_column ACL_ID id nb_acl=$acl_uuid) +acl_id=$(printf %x $acl_id) + +OVS_WAIT_FOR_OUTPUT([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.1.2) | \ +grep "labels=0x"$acl_id"00000000000000000000" | \ +sed -e 's/zone=[[0-9]]*/zone=<cleared>/' | \ +sed -e 's/mark=[[0-9]]*/mark=<cleared>/' | \ +sed -e 's/labels=0x[[0-9a-f]]*/labels=<cleared>/'], [0], [dnl +tcp,orig=(src=192.168.1.1,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=192.168.1.1,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=<cleared>,labels=<cleared>,protoinfo=(state=<cleared>) +]) + # Adjust the ACL so that it no longer matches check ovn-nbctl set ACL $acl_uuid match="\"ip4.dst == 192.168.1.3\"" @@ -14264,6 +14276,14 @@ test : > output.txt +# Now remove the ACL. This should remove the conntrack entry as well. +check ovn-nbctl --wait=hv acl-del sw from-lport 1000 'ip4.dst == 192.168.1.3' + +OVS_WAIT_FOR_OUTPUT([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.1.2) | \ +grep "labels=0x"$acl_id"00000000000000000000" | \ +sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl +]) + OVS_APP_EXIT_AND_WAIT([ovn-controller]) as ovn-sb -- 2.45.2 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev