On 3/17/23 20:34, Numan Siddique wrote:
> On Mon, Feb 13, 2023 at 11:36 AM Abhiram Sangana
> <[email protected]> wrote:
>>
>> This patch adds support to commit connections dropped/rejected by
>> ACLs to the connection tracking table. Dropped connections are
>> committed to conntrack only if NB_Global options:ct_commit_acl_drop
>> is set to true (false by default) and ACL dropping/rejecting the
>> connection has label configured. The dropped connections are
>> committed in a separate conntrack zone so that they can be managed
>> independently and do not interact with the connection tracking state
>> of allowed connections.
>>
>> This provides a new approach to identify connections dropped by ACLs
>> besides the existing ACL logging and drop sampling approaches.
>>
>> Each logical switch is assigned a new conntrack zone for committing
>> dropped flows. The zone is loaded into register MFF_LOG_ACL_DROP_ZONE.
>> A new lflow action "ct_commit_drop" is introduced that commits flows
>> to connection tracking table in a zone identified by
>> MFF_LOG_ACL_DROP_ZONE register. An ACL with "drop" or "reject" action
>> and non-empty label translates to include "ct_commit_drop" in its
>> actions instead of simply dropping/rejecting the packet.
>>
>> Signed-off-by: Abhiram Sangana <[email protected]>
>
> Hi Abhiram,
>
Hi Abhiram,
> Sorry for the delays in the reviews.
>
> Overall the patch looks good to me.
>
> I do have a few comments and suggestions.
>
> Instead of adding a global option, how about an option per ACL (in the
> ACL options column) ?
> Users can enable or disable conntrack commit per ACL.
>
+1 for this, finer granularity is probably better.
I only have a few minor comments below.
> Are you going to use this feature all the time in your deployment ?
> Or enable it only when debugging an issue ?
> If you want to enable it during debugging, is it a bit of a hassle to
> enable the ct_commit option for the interested ACL ?
>
>
> I'm a little bit concerned with allocating a zone id for each logical
> switch even if there are no ACLs configured with this option.
> But I think it's not a big deal.
>
> Thanks
> Numan
>
>> ---
>> controller/ovn-controller.c | 14 +++-
>> controller/physical.c | 32 ++++++++-
>> include/ovn/actions.h | 1 +
>> include/ovn/logical-fields.h | 1 +
>> lib/actions.c | 65 +++++++++++++++++
>> lib/ovn-util.c | 4 +-
>> lib/ovn-util.h | 2 +-
>> northd/northd.c | 25 ++++++-
>> northd/ovn-northd.8.xml | 30 +++++++-
>> ovn-nb.xml | 17 +++--
>> ovn-sb.xml | 22 ++++++
>> tests/ovn-nbctl.at | 10 ++-
>> tests/ovn-northd.at | 133 ++++++++++++++++++++++++-----------
>> tests/ovn.at | 90 +++++++++++++++++++++++-
>> utilities/ovn-nbctl.c | 7 --
>> utilities/ovn-trace.c | 2 +
Please also add a NEWS entry.
>> 16 files changed, 383 insertions(+), 72 deletions(-)
>>
>> diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
>> index 265740cab..e8f0b7242 100644
>> --- a/controller/ovn-controller.c
>> +++ b/controller/ovn-controller.c
>> @@ -734,8 +734,8 @@ update_ct_zones(const struct shash *binding_lports,
>> HMAP_FOR_EACH (ld, hmap_node, local_datapaths) {
>> /* XXX Add method to limit zone assignment to logical router
>> * datapaths with NAT */
>> - char *dnat = alloc_nat_zone_key(&ld->datapath->header_.uuid,
>> "dnat");
>> - char *snat = alloc_nat_zone_key(&ld->datapath->header_.uuid,
>> "snat");
>> + char *dnat = alloc_ct_zone_key(&ld->datapath->header_.uuid, "dnat");
>> + char *snat = alloc_ct_zone_key(&ld->datapath->header_.uuid, "snat");
>> sset_add(&all_users, dnat);
>> sset_add(&all_users, snat);
>>
>> @@ -745,6 +745,14 @@ update_ct_zones(const struct shash *binding_lports,
>> }
>> free(dnat);
>> free(snat);
>> +
>> + /* Zone for committing connections dropped by ACLs with labels. */
>> + if (ld->is_switch) {
>> + char *drop = alloc_ct_zone_key(
>> + &ld->datapath->header_.uuid, "drop");
>> + sset_add(&all_users, drop);
>> + free(drop);
>> + }
>> }
>>
>> /* Delete zones that do not exist in above sset. */
>> @@ -2420,7 +2428,7 @@ ct_zones_datapath_binding_handler(struct engine_node
>> *node, void *data)
>> /* Check if the requested snat zone has changed for the datapath
>> * or not. If so, then fall back to full recompute of
>> * ct_zone engine. */
>> - char *snat_dp_zone_key = alloc_nat_zone_key(&dp->header_.uuid,
>> "snat");
>> + char *snat_dp_zone_key = alloc_ct_zone_key(&dp->header_.uuid,
>> "snat");
>> struct simap_node *simap_node = simap_find(&ct_zones_data->current,
>> snat_dp_zone_key);
>> free(snat_dp_zone_key);
>> diff --git a/controller/physical.c b/controller/physical.c
>> index 4dcf44e01..3c573c492 100644
>> --- a/controller/physical.c
>> +++ b/controller/physical.c
>> @@ -60,6 +60,7 @@ struct zone_ids {
>> int ct; /* MFF_LOG_CT_ZONE. */
>> int dnat; /* MFF_LOG_DNAT_ZONE. */
>> int snat; /* MFF_LOG_SNAT_ZONE. */
>> + int drop; /* MFF_LOG_ACL_DROP_ZONE. */
>> };
>>
>> struct tunnel {
>> @@ -204,14 +205,18 @@ get_zone_ids(const struct sbrec_port_binding *binding,
>>
>> const struct uuid *key = &binding->datapath->header_.uuid;
>>
>> - char *dnat = alloc_nat_zone_key(key, "dnat");
>> + char *dnat = alloc_ct_zone_key(key, "dnat");
>> zone_ids.dnat = simap_get(ct_zones, dnat);
>> free(dnat);
>>
>> - char *snat = alloc_nat_zone_key(key, "snat");
>> + char *snat = alloc_ct_zone_key(key, "snat");
>> zone_ids.snat = simap_get(ct_zones, snat);
>> free(snat);
>>
>> + char *drop = alloc_ct_zone_key(key, "drop");
>> + zone_ids.drop = simap_get(ct_zones, drop);
>> + free(drop);
>> +
>> return zone_ids;
>> }
>>
>> @@ -830,6 +835,9 @@ put_zones_ofpacts(const struct zone_ids *zone_ids,
>> struct ofpbuf *ofpacts_p)
>> if (zone_ids->snat) {
>> put_load(zone_ids->snat, MFF_LOG_SNAT_ZONE, 0, 32, ofpacts_p);
>> }
>> + if (zone_ids->drop) {
>> + put_load(zone_ids->drop, MFF_LOG_ACL_DROP_ZONE, 0, 32,
>> ofpacts_p);
>> + }
>> }
>> }
>>
>> @@ -896,6 +904,26 @@ put_local_common_flows(uint32_t dp_key,
>> pb->header_.uuid.parts[0], &match, ofpacts_p,
>> &pb->header_.uuid);
>>
>> + if (zone_ids->drop) {
>> + /* Table 39, Priority 1.
>> + * =======================
>> + *
>> + * Clear the logical registers (for consistent behavior with packets
>> + * that get tunneled) except MFF_LOG_ACL_DROP_ZONE. */
>> + match_init_catchall(&match);
>> + ofpbuf_clear(ofpacts_p);
>> + match_set_metadata(&match, htonll(dp_key));
>> + for (int i = 0; i < MFF_N_LOG_REGS; i++) {
>> + if ((MFF_REG0 + i) != MFF_LOG_ACL_DROP_ZONE) {
>> + put_load(0, MFF_REG0 + i, 0, 32, ofpacts_p);
>> + }
>> + }
Why do we need this? Don't we load the CT zone anyway for "to-lport"
ACLs? Can't we also load the drop zone in the same place?
>> + put_resubmit(OFTABLE_LOG_EGRESS_PIPELINE, ofpacts_p);
>> + ofctrl_add_flow(flow_table, OFTABLE_CHECK_LOOPBACK, 1,
>> + pb->datapath->header_.uuid.parts[0], &match,
>> + ofpacts_p, &pb->datapath->header_.uuid);
>> + }
>> +
>> /* Table 39, Priority 100.
>> * =======================
>> *
>> diff --git a/include/ovn/actions.h b/include/ovn/actions.h
>> index 6ca08b3c6..c7a6785d3 100644
>> --- a/include/ovn/actions.h
>> +++ b/include/ovn/actions.h
>> @@ -125,6 +125,7 @@ struct ovn_extend_table;
>> OVNACT(COMMIT_LB_AFF, ovnact_commit_lb_aff) \
>> OVNACT(CHK_LB_AFF, ovnact_result) \
>> OVNACT(SAMPLE, ovnact_sample) \
>> + OVNACT(CT_COMMIT_DROP, ovnact_nest) \
>>
>> /* enum ovnact_type, with a member OVNACT_<ENUM> for each action. */
>> enum OVS_PACKED_ENUM ovnact_type {
>> diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h
>> index a7b64ef67..c7ea9e0ce 100644
>> --- a/include/ovn/logical-fields.h
>> +++ b/include/ovn/logical-fields.h
>> @@ -47,6 +47,7 @@ enum ovn_controller_event {
>> #define MFF_LOG_REG0 MFF_REG0
>> #define MFF_LOG_LB_ORIG_DIP_IPV4 MFF_REG1
>> #define MFF_LOG_LB_ORIG_TP_DPORT MFF_REG2
>> +#define MFF_LOG_ACL_DROP_ZONE MFF_REG9
>>
>> #define MFF_LOG_XXREG0 MFF_XXREG0
>> #define MFF_LOG_LB_ORIG_DIP_IPV6 MFF_XXREG1
>> diff --git a/lib/actions.c b/lib/actions.c
>> index 2da5a696b..d86b1efbc 100644
>> --- a/lib/actions.c
>> +++ b/lib/actions.c
>> @@ -5210,6 +5210,69 @@ encode_CHK_LB_AFF(const struct ovnact_result *res,
>> MLF_USE_LB_AFF_SESSION_BIT, ofpacts);
>> }
>>
>> +static void
>> +parse_ct_commit_drop(struct action_context *ctx)
>> +{
>> + if (ctx->lexer->token.type == LEX_T_LCURLY) {
>> + parse_nested_action(ctx, OVNACT_CT_COMMIT_DROP, "ip",
>> + WR_CT_COMMIT);
>> + } else {
>> + /* Add an empty nested action to allow for "ct_commit_drop;" syntax
>> */
>> + add_prerequisite(ctx, "ip");
>> + struct ovnact_nest *on = ovnact_put(ctx->ovnacts,
>> + OVNACT_CT_COMMIT_DROP,
>> + OVNACT_ALIGN(sizeof *on));
>> + on->nested_len = 0;
>> + on->nested = NULL;
>> + }
>> +}
>> +
>> +static void
>> +format_CT_COMMIT_DROP(const struct ovnact_nest *on, struct ds *s)
>> +{
>> + if (on->nested_len) {
>> + format_nested_action(on, "ct_commit_drop", s);
>> + } else {
>> + ds_put_cstr(s, "ct_commit_drop;");
>> + }
>> +}
>> +
>> +static void
>> +encode_CT_COMMIT_DROP(const struct ovnact_nest *on,
>> + const struct ovnact_encode_params *ep OVS_UNUSED,
>> + struct ofpbuf *ofpacts)
>> +{
>> + struct ofpact_conntrack *ct = ofpact_put_CT(ofpacts);
>> + ct->flags = NX_CT_F_COMMIT;
>> + ct->recirc_table = NX_CT_RECIRC_NONE;
>> + ct->zone_src.field = mf_from_id(MFF_LOG_ACL_DROP_ZONE);
>> + ct->zone_src.ofs = 0;
>> + ct->zone_src.n_bits = 16;
>> +
>> + /* If the datapath supports all-zero SNAT then use it to avoid tuple
>> + * collisions at commit time between NATed and firewalled-only sessions.
>> + */
>> + if (ovs_feature_is_supported(OVS_CT_ZERO_SNAT_SUPPORT)) {
>> + size_t nat_offset = ofpacts->size;
>> + ofpbuf_pull(ofpacts, nat_offset);
>> +
>> + struct ofpact_nat *nat = ofpact_put_NAT(ofpacts);
>> + nat->flags = 0;
>> + nat->range_af = AF_UNSPEC;
>> + nat->flags |= NX_NAT_F_SRC;
>> + ofpacts->header = ofpbuf_push_uninit(ofpacts, nat_offset);
>> + ct = ofpacts->header;
>> + }
I'm not completely sure about the all-zero SNAT for dropped packets. Do
we really need it?
Thanks,
Dumitru
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev