From patchwork Thu Jul 25 10:21:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ales Musil X-Patchwork-Id: 1964688 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=bkSXrTY6; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4WV6Pz0ZNxz1yY9 for ; Thu, 25 Jul 2024 20:22:14 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 1C8464077F; Thu, 25 Jul 2024 10:22:13 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id WDDOhjMqv_HP; Thu, 25 Jul 2024 10:22:10 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=2605:bc80:3010:104::8cd3:938; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org B3B0940708 Authentication-Results: smtp4.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=bkSXrTY6 Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp4.osuosl.org (Postfix) with ESMTPS id B3B0940708; Thu, 25 Jul 2024 10:22:10 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 5A2BEC003D; Thu, 25 Jul 2024 10:22:10 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 142F0C002A for ; Thu, 25 Jul 2024 10:22:09 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id ECA6E60A51 for ; Thu, 25 Jul 2024 10:22:08 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id GyMIPLBXQOTx for ; Thu, 25 Jul 2024 10:22:07 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=170.10.129.124; helo=us-smtp-delivery-124.mimecast.com; envelope-from=amusil@redhat.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp3.osuosl.org 7311A60073 Authentication-Results: smtp3.osuosl.org; dmarc=pass (p=none dis=none) header.from=redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 7311A60073 Authentication-Results: smtp3.osuosl.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=bkSXrTY6 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by smtp3.osuosl.org (Postfix) with ESMTPS id 7311A60073 for ; Thu, 25 Jul 2024 10:22:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1721902926; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pXOEugglP4Uw1D4reRHPE3dNS6DWUTUAeeOuwHJaX1w=; b=bkSXrTY6wAx3c9ota54rucS7J3bxPqElhvQmklbm1g4P0n1SeWFgXgQBYUFuM6gDJZpkTK TcSX5IiebvPD1mO1fBVTQpFxQGsADNqBkSKMwNOU/nLasacTB4J5VfjTUQ8h1P60ZhALxa EERKXnl9t/ebjnK1vCeiK2e/x+ohjYk= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-107-mEphhefpOOSeu7E-HpMVVw-1; Thu, 25 Jul 2024 06:22:04 -0400 X-MC-Unique: mEphhefpOOSeu7E-HpMVVw-1 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 0B5351955F41 for ; Thu, 25 Jul 2024 10:22:04 +0000 (UTC) Received: from amusil.redhat.com (unknown [10.45.224.17]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 35C713000192; Thu, 25 Jul 2024 10:22:01 +0000 (UTC) From: Ales Musil To: dev@openvswitch.org Date: Thu, 25 Jul 2024 12:21:58 +0200 Message-ID: <20240725102159.1416553-2-amusil@redhat.com> In-Reply-To: <20240725102159.1416553-1-amusil@redhat.com> References: <20240725102159.1416553-1-amusil@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH ovn v6 1/2] controller: Prepare structure around CT zone limiting. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" In order to be able to store CT limits for specified zone, store the zone inside separate struct instead of simap. This allows to add the addition of limit without changing the whole infrastructure again. This is a preparation step for the CT zone limits. Acked-by: Mark Michelson Signed-off-by: Ales Musil Acked-by: Numan Siddique --- v6: Rebase on top of latest main. Add ack from Mark. v5: Rebase on top of latest main. Address comments from Dumitru: Remove the CT_ZONE_STATE_NEW enum variant. Add wrappers for ct_zone_ctx_init/destroy(). v4: Rebase on top of latest main. Address comments from Lorenzo. v3: Rebase on top of latest main. v2: Fix NULL ptr deref. --- controller/ct-zone.c | 183 ++++++++++++++++++++++-------------- controller/ct-zone.h | 13 ++- controller/ofctrl.c | 2 +- controller/ovn-controller.c | 17 ++-- controller/physical.c | 17 ++-- controller/physical.h | 2 +- 6 files changed, 140 insertions(+), 94 deletions(-) diff --git a/controller/ct-zone.c b/controller/ct-zone.c index e4f66a52a..ab0eec9d0 100644 --- a/controller/ct-zone.c +++ b/controller/ct-zone.c @@ -26,12 +26,28 @@ ct_zone_restore(const struct sbrec_datapath_binding_table *dp_table, struct ct_zone_ctx *ctx, const char *name, int zone); static void ct_zone_add_pending(struct shash *pending_ct_zones, enum ct_zone_pending_state state, - int zone, bool add, const char *name); + struct ct_zone *zone, bool add, + const char *name); static int ct_zone_get_snat(const struct sbrec_datapath_binding *dp); static bool ct_zone_assign_unused(struct ct_zone_ctx *ctx, const char *zone_name, int *scan_start); -static bool ct_zone_remove(struct ct_zone_ctx *ctx, - struct simap_node *ct_zone); +static bool ct_zone_remove(struct ct_zone_ctx *ctx, const char *name); +static void ct_zone_add(struct ct_zone_ctx *ctx, const char *name, + uint16_t zone, bool set_pending); + +void +ct_zone_ctx_init(struct ct_zone_ctx *ctx) +{ + shash_init(&ctx->pending); + shash_init(&ctx->current); +} + +void +ct_zone_ctx_destroy(struct ct_zone_ctx *ctx) +{ + shash_destroy_free_data(&ctx->current); + shash_destroy_free_data(&ctx->pending); +} void ct_zones_restore(struct ct_zone_ctx *ctx, @@ -47,7 +63,8 @@ ct_zones_restore(struct ct_zone_ctx *ctx, struct ct_zone_pending_entry *ctpe = pending_node->data; if (ctpe->add) { - ct_zone_restore(dp_table, ctx, pending_node->name, ctpe->zone); + ct_zone_restore(dp_table, ctx, pending_node->name, + ctpe->ct_zone.zone); } } @@ -91,7 +108,6 @@ void ct_zones_update(const struct sset *local_lports, const struct hmap *local_datapaths, struct ct_zone_ctx *ctx) { - struct simap_node *ct_zone; int scan_start = 1; const char *user; struct sset all_users = SSET_INITIALIZER(&all_users); @@ -132,12 +148,14 @@ ct_zones_update(const struct sset *local_lports, } /* Delete zones that do not exist in above sset. */ - SIMAP_FOR_EACH_SAFE (ct_zone, &ctx->current) { - if (!sset_contains(&all_users, ct_zone->name)) { - ct_zone_remove(ctx, ct_zone); - } else if (!simap_find(&req_snat_zones, ct_zone->name)) { - bitmap_set1(unreq_snat_zones_map, ct_zone->data); - simap_put(&unreq_snat_zones, ct_zone->name, ct_zone->data); + struct shash_node *node; + SHASH_FOR_EACH_SAFE (node, &ctx->current) { + struct ct_zone *ct_zone = node->data; + if (!sset_contains(&all_users, node->name)) { + ct_zone_remove(ctx, node->name); + } else if (!simap_find(&req_snat_zones, node->name)) { + bitmap_set1(unreq_snat_zones_map, ct_zone->zone); + simap_put(&unreq_snat_zones, node->name, ct_zone->zone); } } @@ -152,7 +170,7 @@ ct_zones_update(const struct sset *local_lports, struct simap_node *unreq_node; SIMAP_FOR_EACH_SAFE (unreq_node, &unreq_snat_zones) { if (unreq_node->data == snat_req_node->data) { - simap_find_and_delete(&ctx->current, unreq_node->name); + ct_zone_remove(ctx, unreq_node->name); simap_delete(&unreq_snat_zones, unreq_node); } } @@ -163,26 +181,12 @@ ct_zones_update(const struct sset *local_lports, bitmap_set0(unreq_snat_zones_map, snat_req_node->data); } - struct simap_node *node = simap_find(&ctx->current, - snat_req_node->name); - if (node) { - if (node->data != snat_req_node->data) { - /* Zone request has changed for this node. delete old entry and - * create new one*/ - ct_zone_add_pending(&ctx->pending, CT_ZONE_OF_QUEUED, - snat_req_node->data, true, - snat_req_node->name); - bitmap_set0(ctx->bitmap, node->data); - } - bitmap_set1(ctx->bitmap, snat_req_node->data); - node->data = snat_req_node->data; - } else { - ct_zone_add_pending(&ctx->pending, CT_ZONE_OF_QUEUED, - snat_req_node->data, true, - snat_req_node->name); - bitmap_set1(ctx->bitmap, snat_req_node->data); - simap_put(&ctx->current, snat_req_node->name, snat_req_node->data); + struct ct_zone *ct_zone = shash_find_data(&ctx->current, + snat_req_node->name); + if (node && ct_zone->zone != snat_req_node->data) { + ct_zone_remove(ctx, snat_req_node->name); } + ct_zone_add(ctx, snat_req_node->name, snat_req_node->data, true); } /* xxx This is wasteful to assign a zone to each port--even if no @@ -191,7 +195,7 @@ ct_zones_update(const struct sset *local_lports, /* Assign a unique zone id for each logical port and two zones * to a gateway router. */ SSET_FOR_EACH (user, &all_users) { - if (simap_contains(&ctx->current, user)) { + if (shash_find(&ctx->current, user)) { continue; } @@ -222,7 +226,7 @@ ct_zones_commit(const struct ovsrec_bridge *br_int, char *user_str = xasprintf("ct-zone-%s", iter->name); if (ctzpe->add) { - char *zone_str = xasprintf("%"PRId32, ctzpe->zone); + char *zone_str = xasprintf("%"PRIu16, ctzpe->ct_zone.zone); struct smap_node *node = smap_get_node(&br_int->external_ids, user_str); if (!node || strcmp(node->value, zone_str)) { @@ -281,12 +285,17 @@ ct_zone_handle_dp_update(struct ct_zone_ctx *ctx, * or not. If so, then fall back to full recompute of * ct_zone engine. */ char *snat_dp_zone_key = alloc_nat_zone_key(name, "snat"); - struct simap_node *simap_node = - simap_find(&ctx->current, snat_dp_zone_key); + struct shash_node *node = shash_find(&ctx->current, snat_dp_zone_key); free(snat_dp_zone_key); - if (!simap_node || simap_node->data != req_snat_zone) { - /* There is no entry yet or the requested snat zone has changed. - * Trigger full recompute of ct_zones engine. */ + + if (!node) { + return false; + } + + struct ct_zone *ct_zone = node->data; + if (ct_zone->zone != req_snat_zone) { + /* The requested snat zone has changed. Trigger full recompute of + * ct_zones engine. */ return false; } @@ -298,17 +307,24 @@ bool ct_zone_handle_port_update(struct ct_zone_ctx *ctx, const char *name, bool updated, int *scan_start) { - struct simap_node *ct_zone = simap_find(&ctx->current, name); - if (updated && !ct_zone) { + struct shash_node *node = shash_find(&ctx->current, name); + if (updated && !node) { ct_zone_assign_unused(ctx, name, scan_start); return true; - } else if (!updated && ct_zone_remove(ctx, ct_zone)) { + } else if (!updated && node && ct_zone_remove(ctx, node->name)) { return true; } return false; } +uint16_t +ct_zone_find_zone(const struct shash *ct_zones, const char *name) +{ + struct ct_zone *ct_zone = shash_find_data(ct_zones, name); + return ct_zone ? ct_zone->zone : 0; +} + static bool ct_zone_assign_unused(struct ct_zone_ctx *ctx, const char *zone_name, @@ -323,33 +339,53 @@ ct_zone_assign_unused(struct ct_zone_ctx *ctx, const char *zone_name, } *scan_start = zone + 1; + ct_zone_add(ctx, zone_name, zone, true); - ct_zone_add_pending(&ctx->pending, CT_ZONE_OF_QUEUED, - zone, true, zone_name); - - bitmap_set1(ctx->bitmap, zone); - simap_put(&ctx->current, zone_name, zone); return true; } static bool -ct_zone_remove(struct ct_zone_ctx *ctx, struct simap_node *ct_zone) +ct_zone_remove(struct ct_zone_ctx *ctx, const char *name) { - if (!ct_zone) { + struct shash_node *node = shash_find(&ctx->current, name); + if (!node) { return false; } - VLOG_DBG("removing ct zone %"PRId32" for '%s'", ct_zone->data, - ct_zone->name); + struct ct_zone *ct_zone = node->data; + + VLOG_DBG("removing ct zone %"PRIu16" for '%s'", ct_zone->zone, name); ct_zone_add_pending(&ctx->pending, CT_ZONE_OF_QUEUED, - ct_zone->data, false, ct_zone->name); - bitmap_set0(ctx->bitmap, ct_zone->data); - simap_delete(&ctx->current, ct_zone); + ct_zone, false, name); + bitmap_set0(ctx->bitmap, ct_zone->zone); + shash_delete(&ctx->current, node); + free(ct_zone); return true; } +static void +ct_zone_add(struct ct_zone_ctx *ctx, const char *name, uint16_t zone, + bool set_pending) +{ + VLOG_DBG("assigning ct zone %"PRIu16" for '%s'", zone, name); + + struct ct_zone *ct_zone = shash_find_data(&ctx->current, name); + if (!ct_zone) { + ct_zone = xmalloc(sizeof *ct_zone); + shash_add(&ctx->current, name, ct_zone); + } + + ct_zone->zone = zone; + + if (set_pending) { + ct_zone_add_pending(&ctx->pending, CT_ZONE_OF_QUEUED, + ct_zone, true, name); + } + bitmap_set1(ctx->bitmap, zone); +} + static int ct_zone_get_snat(const struct sbrec_datapath_binding *dp) { @@ -359,27 +395,29 @@ ct_zone_get_snat(const struct sbrec_datapath_binding *dp) static void ct_zone_add_pending(struct shash *pending_ct_zones, enum ct_zone_pending_state state, - int zone, bool add, const char *name) + struct ct_zone *zone, bool add, const char *name) { - VLOG_DBG("%s ct zone %"PRId32" for '%s'", - add ? "assigning" : "removing", zone, name); - - struct ct_zone_pending_entry *pending = xmalloc(sizeof *pending); - *pending = (struct ct_zone_pending_entry) { - .state = state, - .zone = zone, - .add = add, - }; - /* Its important that we add only one entry for the key 'name'. * Replace 'pending' with 'existing' and free up 'existing'. * Otherwise, we may end up in a continuous loop of adding * and deleting the zone entry in the 'external_ids' of * integration bridge. */ - struct ct_zone_pending_entry *existing = - shash_replace(pending_ct_zones, name, pending); - free(existing); + struct ct_zone_pending_entry *entry = + shash_find_data(pending_ct_zones, name); + + if (!entry) { + entry = xmalloc(sizeof *entry); + entry->state = state; + + shash_add(pending_ct_zones, name, entry); + } + + *entry = (struct ct_zone_pending_entry) { + .ct_zone = *zone, + .state = MIN(entry->state, state), + .add = add, + }; } /* Replaces a UUID prefix from 'uuid_zone' (if any) with the @@ -420,19 +458,20 @@ ct_zone_restore(const struct sbrec_datapath_binding_table *dp_table, VLOG_DBG("ct zone %"PRId32" replace uuid name '%s' with '%s'", zone, name, new_name); + struct ct_zone ct_zone = { + .zone = zone, + }; /* Make sure we remove the uuid one in the next OvS DB commit without * flush. */ ct_zone_add_pending(&ctx->pending, CT_ZONE_DB_QUEUED, - zone, false, name); + &ct_zone, false, name); /* Store the zone in OvS DB with name instead of uuid without flush. * */ ct_zone_add_pending(&ctx->pending, CT_ZONE_DB_QUEUED, - zone, true, new_name); + &ct_zone, true, new_name); current_name = new_name; } - simap_put(&ctx->current, current_name, zone); - bitmap_set1(ctx->bitmap, zone); - + ct_zone_add(ctx, current_name, zone, false); free(new_name); } diff --git a/controller/ct-zone.h b/controller/ct-zone.h index 889bdf2fc..a7c2011a1 100644 --- a/controller/ct-zone.h +++ b/controller/ct-zone.h @@ -37,8 +37,12 @@ struct ct_zone_ctx { struct shash pending; /* Pending entries, * 'struct ct_zone_pending_entry' * by name. */ - struct simap current; /* Current CT zones mapping - * (zone id by name). */ + struct shash current; /* Current CT zones mapping + * (struct ct_zone by name). */ +}; + +struct ct_zone { + uint16_t zone; }; /* States to move through when a new conntrack zone has been allocated. */ @@ -50,12 +54,14 @@ enum ct_zone_pending_state { }; struct ct_zone_pending_entry { - int zone; + struct ct_zone ct_zone; bool add; /* Is the entry being added? */ ovs_be32 of_xid; /* Transaction id for barrier. */ enum ct_zone_pending_state state; }; +void ct_zone_ctx_init(struct ct_zone_ctx *ctx); +void ct_zone_ctx_destroy(struct ct_zone_ctx *ctx); void ct_zones_restore(struct ct_zone_ctx *ctx, const struct ovsrec_open_vswitch_table *ovs_table, const struct sbrec_datapath_binding_table *dp_table, @@ -70,5 +76,6 @@ bool ct_zone_handle_dp_update(struct ct_zone_ctx *ctx, const struct sbrec_datapath_binding *dp); bool ct_zone_handle_port_update(struct ct_zone_ctx *ctx, const char *name, bool updated, int *scan_start); +uint16_t ct_zone_find_zone(const struct shash *ct_zones, const char *name); #endif /* controller/ct-zone.h */ diff --git a/controller/ofctrl.c b/controller/ofctrl.c index 8a19106c2..f9387d375 100644 --- a/controller/ofctrl.c +++ b/controller/ofctrl.c @@ -2709,7 +2709,7 @@ ofctrl_put(struct ovn_desired_flow_table *lflow_table, SHASH_FOR_EACH(iter, pending_ct_zones) { struct ct_zone_pending_entry *ctzpe = iter->data; if (ctzpe->state == CT_ZONE_OF_QUEUED) { - add_ct_flush_zone(ctzpe->zone, &msgs); + add_ct_flush_zone(ctzpe->ct_zone.zone, &msgs); ctzpe->state = CT_ZONE_OF_SENT; ctzpe->of_xid = 0; } diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 4e30302ea..aee558f9a 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -2188,8 +2188,7 @@ en_ct_zones_init(struct engine_node *node OVS_UNUSED, { struct ed_type_ct_zones *data = xzalloc(sizeof *data); - shash_init(&data->ctx.pending); - simap_init(&data->ctx.current); + ct_zone_ctx_init(&data->ctx); return data; } @@ -2206,8 +2205,7 @@ en_ct_zones_cleanup(void *data) { struct ed_type_ct_zones *ct_zones_data = data; - simap_destroy(&ct_zones_data->ctx.current); - shash_destroy_free_data(&ct_zones_data->ctx.pending); + ct_zone_ctx_destroy(&ct_zones_data->ctx); } static void @@ -4335,7 +4333,7 @@ static void init_physical_ctx(struct engine_node *node, struct ed_type_ct_zones *ct_zones_data = engine_get_input_data("ct_zones", node); - struct simap *ct_zones = &ct_zones_data->ctx.current; + struct shash *ct_zones = &ct_zones_data->ctx.current; struct ed_type_northd_options *n_opts = engine_get_input_data("northd_options", node); @@ -6060,12 +6058,13 @@ static void ct_zone_list(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, void *ct_zones_) { - struct simap *ct_zones = ct_zones_; + struct shash *ct_zones = ct_zones_; struct ds ds = DS_EMPTY_INITIALIZER; - struct simap_node *zone; + struct shash_node *node; - SIMAP_FOR_EACH(zone, ct_zones) { - ds_put_format(&ds, "%s %d\n", zone->name, zone->data); + SHASH_FOR_EACH (node, ct_zones) { + struct ct_zone *ct_zone = node->data; + ds_put_format(&ds, "%s %d\n", node->name, ct_zone->zone); } unixctl_command_reply(conn, ds_cstr(&ds)); diff --git a/controller/physical.c b/controller/physical.c index 876ceccf1..290a06109 100644 --- a/controller/physical.c +++ b/controller/physical.c @@ -17,6 +17,7 @@ #include "binding.h" #include "coverage.h" #include "byte-order.h" +#include "ct-zone.h" #include "encaps.h" #include "flow.h" #include "ha-chassis.h" @@ -212,10 +213,10 @@ get_vtep_port(const struct hmap *local_datapaths, int64_t tunnel_key) static struct zone_ids get_zone_ids(const struct sbrec_port_binding *binding, - const struct simap *ct_zones) + const struct shash *ct_zones) { struct zone_ids zone_ids = { - .ct = simap_get(ct_zones, binding->logical_port) + .ct = ct_zone_find_zone(ct_zones, binding->logical_port) }; const char *name = smap_get(&binding->datapath->external_ids, "name"); @@ -228,11 +229,11 @@ get_zone_ids(const struct sbrec_port_binding *binding, } char *dnat = alloc_nat_zone_key(name, "dnat"); - zone_ids.dnat = simap_get(ct_zones, dnat); + zone_ids.dnat = ct_zone_find_zone(ct_zones, dnat); free(dnat); char *snat = alloc_nat_zone_key(name, "snat"); - zone_ids.snat = simap_get(ct_zones, snat); + zone_ids.snat = ct_zone_find_zone(ct_zones, snat); free(snat); return zone_ids; @@ -631,7 +632,7 @@ put_chassis_mac_conj_id_flow(const struct sbrec_chassis_table *chassis_table, } static void -put_replace_chassis_mac_flows(const struct simap *ct_zones, +put_replace_chassis_mac_flows(const struct shash *ct_zones, const struct sbrec_port_binding *localnet_port, const struct hmap *local_datapaths, @@ -1477,7 +1478,7 @@ enforce_tunneling_for_multichassis_ports( static void consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, enum mf_field_id mff_ovn_geneve, - const struct simap *ct_zones, + const struct shash *ct_zones, const struct sset *active_tunnels, const struct hmap *local_datapaths, const struct shash *local_bindings, @@ -2116,7 +2117,7 @@ mc_ofctrl_add_flow(const struct sbrec_multicast_group *mc, static void consider_mc_group(struct ovsdb_idl_index *sbrec_port_binding_by_name, enum mf_field_id mff_ovn_geneve, - const struct simap *ct_zones, + const struct shash *ct_zones, const struct hmap *local_datapaths, struct shash *local_bindings, struct simap *patch_ofports, @@ -2180,7 +2181,7 @@ consider_mc_group(struct ovsdb_idl_index *sbrec_port_binding_by_name, continue; } - int zone_id = simap_get(ct_zones, port->logical_port); + int zone_id = ct_zone_find_zone(ct_zones, port->logical_port); if (zone_id) { put_load(zone_id, MFF_LOG_CT_ZONE, 0, 16, &ofpacts); } diff --git a/controller/physical.h b/controller/physical.h index 4dd228cf8..dd4be7041 100644 --- a/controller/physical.h +++ b/controller/physical.h @@ -61,7 +61,7 @@ struct physical_ctx { const struct if_status_mgr *if_mgr; struct hmap *local_datapaths; struct sset *local_lports; - const struct simap *ct_zones; + const struct shash *ct_zones; enum mf_field_id mff_ovn_geneve; struct shash *local_bindings; struct simap *patch_ofports; From patchwork Thu Jul 25 10:21:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ales Musil X-Patchwork-Id: 1964690 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=HB0/gaC7; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4WV6Q40nJnz1yY9 for ; Thu, 25 Jul 2024 20:22:20 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 87C3860A6B; Thu, 25 Jul 2024 10:22:18 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id vCJcwMPC1pdp; Thu, 25 Jul 2024 10:22:15 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=2605:bc80:3010:104::8cd3:938; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 9961F60073 Authentication-Results: smtp3.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=HB0/gaC7 Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTPS id 9961F60073; Thu, 25 Jul 2024 10:22:15 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 5EFBEC002B; Thu, 25 Jul 2024 10:22:15 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 611B9C002A for ; Thu, 25 Jul 2024 10:22:13 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 18DD260A6A for ; Thu, 25 Jul 2024 10:22:13 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id EH_9RPPR1Y2U for ; Thu, 25 Jul 2024 10:22:09 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=170.10.129.124; helo=us-smtp-delivery-124.mimecast.com; envelope-from=amusil@redhat.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp3.osuosl.org 1A07760073 Authentication-Results: smtp3.osuosl.org; dmarc=pass (p=none dis=none) header.from=redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 1A07760073 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by smtp3.osuosl.org (Postfix) with ESMTPS id 1A07760073 for ; Thu, 25 Jul 2024 10:22:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1721902928; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=SErOXncVb+s8a4vewfGGwt9BXWPetcXKxj1Rq6l8hkQ=; b=HB0/gaC7TA+ydmxUBO/VBxrwQpUKLFJHLK1OvTwrBIr5lA/PwLeaH3+h7FWXTlW2DWhw5q ju94cKXsDqwOZ2z57Z27QIXi+O/8b3AysadQPiGBwKkQMIWzxBwi7YDNi5Z7/I+GjPax15 UQFWHI2ozrVCzwnMnInqxQhVuWAfAT8= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-575-giiQRUVZMwqZh19Rv3RrxQ-1; Thu, 25 Jul 2024 06:22:06 -0400 X-MC-Unique: giiQRUVZMwqZh19Rv3RrxQ-1 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C6FC51955BF8 for ; Thu, 25 Jul 2024 10:22:05 +0000 (UTC) Received: from amusil.redhat.com (unknown [10.45.224.17]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 5E76A3000192; Thu, 25 Jul 2024 10:22:04 +0000 (UTC) From: Ales Musil To: dev@openvswitch.org Date: Thu, 25 Jul 2024 12:21:59 +0200 Message-ID: <20240725102159.1416553-3-amusil@redhat.com> In-Reply-To: <20240725102159.1416553-1-amusil@redhat.com> References: <20240725102159.1416553-1-amusil@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH ovn v6 2/2] Controller, northd: Add support for CT zone limits. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Add support for limiting the CT zone usage per Ls, LR or LSP. When the limit is configured on logical switch it will also implicitly set limits for all ports in that logical switch. The port configuration can be overwritten individually and has priority over the whole logical switch configuration. The value 0 means unlimited, when the value is not specified it is derived from OvS default CT limit specified for given OvS datapath. Reported-at: https://bugzilla.redhat.com/2189924 Signed-off-by: Ales Musil --- v6: Rebase on top of latest main. Addressed comments from Mark: - Fix spelling error in the documenation. Addressed comments from Numan: - Avoid looping over all interface and loop over local ones only. - Do not loop over interfaces when the DP limit didn't change. v5: Rebase on top of latest main. Avoid OvS CT zone lookup in every loop of pending commit. v4: Rebase on top of latest main. Change naming of the ct_zone_limit_sync to avoid potential confusion as suggested by Lorenzo. v3: Rebase on top of latest main. --- NEWS | 3 + controller/ct-zone.c | 180 ++++++++++++++++++++++++++++++++---- controller/ct-zone.h | 15 ++- controller/ovn-controller.c | 21 +++-- lib/ovn-util.c | 17 ++++ lib/ovn-util.h | 3 + northd/northd.c | 8 ++ ovn-nb.xml | 29 ++++++ tests/ovn-controller.at | 99 ++++++++++++++++++++ 9 files changed, 346 insertions(+), 29 deletions(-) diff --git a/NEWS b/NEWS index 72933b5b9..4c711d1ef 100644 --- a/NEWS +++ b/NEWS @@ -42,6 +42,9 @@ Post v24.03.0 true, the traffic destined to a logical port of a provider logical switch (having a localnet port) will be tunnelled instead of sending it via the localnet port. + - Add support for CT zone limit that can be specified per LR + (options:ct-zone-limit), LS (other_config:ct-zone-limit) or LSP + (options:ct-zone-limit). OVN v24.03.0 - 01 Mar 2024 -------------------------- diff --git a/controller/ct-zone.c b/controller/ct-zone.c index ab0eec9d0..1aab7ccef 100644 --- a/controller/ct-zone.c +++ b/controller/ct-zone.c @@ -15,6 +15,7 @@ #include +#include "binding.h" #include "ct-zone.h" #include "local_data.h" #include "openvswitch/vlog.h" @@ -34,6 +35,16 @@ static bool ct_zone_assign_unused(struct ct_zone_ctx *ctx, static bool ct_zone_remove(struct ct_zone_ctx *ctx, const char *name); static void ct_zone_add(struct ct_zone_ctx *ctx, const char *name, uint16_t zone, bool set_pending); +static void +ct_zone_limits_update_per_dp(struct ct_zone_ctx *ctx, + const struct local_datapath *local_dp, + const struct shash *local_lports, + const char *name); +static bool ct_zone_limit_update(struct ct_zone_ctx *ctx, const char *name, + int64_t limit); +static int64_t ct_zone_get_dp_limit(const struct sbrec_datapath_binding *dp); +static int64_t ct_zone_get_pb_limit(const struct sbrec_port_binding *pb); +static int64_t ct_zone_limit_normalize(int64_t limit); void ct_zone_ctx_init(struct ct_zone_ctx *ctx) @@ -210,11 +221,24 @@ ct_zones_update(const struct sset *local_lports, void ct_zones_commit(const struct ovsrec_bridge *br_int, - struct shash *pending_ct_zones) + const struct ovsrec_datapath *ovs_dp, + struct ovsdb_idl_txn *ovs_idl_txn, + struct ct_zone_ctx *ctx) { + if (shash_is_empty(&ctx->pending)) { + return; + } + + struct ovsrec_ct_zone **all_zones = + xzalloc(sizeof *all_zones * (MAX_CT_ZONES + 1)); + for (size_t i = 0; i < ovs_dp->n_ct_zones; i++) { + all_zones[ovs_dp->key_ct_zones[i]] = ovs_dp->value_ct_zones[i]; + } + struct shash_node *iter; - SHASH_FOR_EACH (iter, pending_ct_zones) { + SHASH_FOR_EACH (iter, &ctx->pending) { struct ct_zone_pending_entry *ctzpe = iter->data; + struct ct_zone *ct_zone = &ctzpe->ct_zone; /* The transaction is open, so any pending entries in the * CT_ZONE_DB_QUEUED must be sent and any in CT_ZONE_DB_QUEUED @@ -226,7 +250,7 @@ ct_zones_commit(const struct ovsrec_bridge *br_int, char *user_str = xasprintf("ct-zone-%s", iter->name); if (ctzpe->add) { - char *zone_str = xasprintf("%"PRIu16, ctzpe->ct_zone.zone); + char *zone_str = xasprintf("%"PRIu16, ct_zone->zone); struct smap_node *node = smap_get_node(&br_int->external_ids, user_str); if (!node || strcmp(node->value, zone_str)) { @@ -241,8 +265,22 @@ ct_zones_commit(const struct ovsrec_bridge *br_int, } free(user_str); + struct ovsrec_ct_zone *ovs_zone = all_zones[ct_zone->zone]; + if ((!ctzpe->add || ct_zone->limit < 0) && ovs_zone) { + ovsrec_datapath_update_ct_zones_delkey(ovs_dp, ct_zone->zone); + } else if (ctzpe->add && ct_zone->limit >= 0) { + if (!ovs_zone) { + ovs_zone = ovsrec_ct_zone_insert(ovs_idl_txn); + ovsrec_datapath_update_ct_zones_setkey(ovs_dp, ct_zone->zone, + ovs_zone); + } + ovsrec_ct_zone_set_limit(ovs_zone, &ct_zone->limit, 1); + } + ctzpe->state = CT_ZONE_DB_SENT; } + + free(all_zones); } void @@ -261,9 +299,21 @@ ct_zones_pending_clear_commited(struct shash *pending) /* Returns "true" when there is no need for full recompute. */ bool ct_zone_handle_dp_update(struct ct_zone_ctx *ctx, - const struct sbrec_datapath_binding *dp) + const struct local_datapath *local_dp, + const struct shash *local_lports) { - int req_snat_zone = ct_zone_get_snat(dp); + const char *name = smap_get(&local_dp->datapath->external_ids, "name"); + if (!name) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_ERR_RL(&rl, "Missing name for datapath '"UUID_FMT"' skipping" + "zone check.", + UUID_ARGS(&local_dp->datapath->header_.uuid)); + return true; + } + + ct_zone_limits_update_per_dp(ctx, local_dp, local_lports, name); + + int req_snat_zone = ct_zone_get_snat(local_dp->datapath); if (req_snat_zone == -1) { /* datapath snat ct zone is not set. This condition will also hit * when CMS clears the snat-ct-zone for the logical router. @@ -273,14 +323,6 @@ ct_zone_handle_dp_update(struct ct_zone_ctx *ctx, return true; } - const char *name = smap_get(&dp->external_ids, "name"); - if (!name) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); - VLOG_ERR_RL(&rl, "Missing name for datapath '"UUID_FMT"' skipping" - "zone check.", UUID_ARGS(&dp->header_.uuid)); - return true; - } - /* 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. */ @@ -304,14 +346,18 @@ ct_zone_handle_dp_update(struct ct_zone_ctx *ctx, /* Returns "true" if there was an update to the context. */ bool -ct_zone_handle_port_update(struct ct_zone_ctx *ctx, const char *name, +ct_zone_handle_port_update(struct ct_zone_ctx *ctx, + const struct sbrec_port_binding *pb, bool updated, int *scan_start) { - struct shash_node *node = shash_find(&ctx->current, name); - if (updated && !node) { - ct_zone_assign_unused(ctx, name, scan_start); + struct shash_node *node = shash_find(&ctx->current, pb->logical_port); + if (updated) { + if (!node) { + ct_zone_assign_unused(ctx, pb->logical_port, scan_start); + } + ct_zone_limit_update(ctx, pb->logical_port, ct_zone_get_pb_limit(pb)); return true; - } else if (!updated && node && ct_zone_remove(ctx, node->name)) { + } else if (node && ct_zone_remove(ctx, node->name)) { return true; } @@ -325,6 +371,25 @@ ct_zone_find_zone(const struct shash *ct_zones, const char *name) return ct_zone ? ct_zone->zone : 0; } +void +ct_zones_limits_sync(struct ct_zone_ctx *ctx, + const struct hmap *local_datapaths, + const struct shash *local_lports) +{ + const struct local_datapath *ld; + HMAP_FOR_EACH (ld, hmap_node, local_datapaths) { + const char *name = smap_get(&ld->datapath->external_ids, "name"); + if (!name) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_ERR_RL(&rl, "Missing name for datapath '"UUID_FMT"' " + "skipping zone assignment.", + UUID_ARGS(&ld->datapath->header_.uuid)); + continue; + } + + ct_zone_limits_update_per_dp(ctx, ld, local_lports, name); + } +} static bool ct_zone_assign_unused(struct ct_zone_ctx *ctx, const char *zone_name, @@ -377,7 +442,10 @@ ct_zone_add(struct ct_zone_ctx *ctx, const char *name, uint16_t zone, shash_add(&ctx->current, name, ct_zone); } - ct_zone->zone = zone; + *ct_zone = (struct ct_zone) { + .zone = zone, + .limit = -1, + }; if (set_pending) { ct_zone_add_pending(&ctx->pending, CT_ZONE_OF_QUEUED, @@ -460,6 +528,7 @@ ct_zone_restore(const struct sbrec_datapath_binding_table *dp_table, struct ct_zone ct_zone = { .zone = zone, + .limit = -1, }; /* Make sure we remove the uuid one in the next OvS DB commit without * flush. */ @@ -475,3 +544,76 @@ ct_zone_restore(const struct sbrec_datapath_binding_table *dp_table, ct_zone_add(ctx, current_name, zone, false); free(new_name); } + +static void +ct_zone_limits_update_per_dp(struct ct_zone_ctx *ctx, + const struct local_datapath *local_dp, + const struct shash *local_lports, + const char *name) +{ + + int64_t dp_limit = ct_zone_get_dp_limit(local_dp->datapath); + char *dnat = alloc_nat_zone_key(name, "dnat"); + char *snat = alloc_nat_zone_key(name, "snat"); + + bool zone_updated = ct_zone_limit_update(ctx, dnat, dp_limit); + zone_updated |= ct_zone_limit_update(ctx, snat, dp_limit); + + if (local_dp->is_switch && zone_updated) { + const struct shash_node *node; + SHASH_FOR_EACH (node, local_lports) { + const struct binding_lport *lport = node->data; + + if (lport->pb->datapath != local_dp->datapath) { + continue; + } + + ct_zone_limit_update(ctx, lport->name, + ct_zone_get_pb_limit(lport->pb)); + } + } + + free(dnat); + free(snat); +} + +static bool +ct_zone_limit_update(struct ct_zone_ctx *ctx, const char *name, int64_t limit) +{ + struct ct_zone *ct_zone = shash_find_data(&ctx->current, name); + + if (!ct_zone || ct_zone->limit == limit) { + return false; + } + + ct_zone->limit = limit; + /* Add pending entry only for DB store to avoid flushing the zone. */ + ct_zone_add_pending(&ctx->pending, CT_ZONE_DB_QUEUED, ct_zone, true, name); + VLOG_DBG("setting ct zone %"PRIu16" limit to %"PRId64, + ct_zone->zone, ct_zone->limit); + + return true; +} + +static int64_t +ct_zone_get_dp_limit(const struct sbrec_datapath_binding *dp) +{ + int64_t limit = ovn_smap_get_llong(&dp->external_ids, "ct-zone-limit", -1); + return ct_zone_limit_normalize(limit); +} + +static int64_t +ct_zone_get_pb_limit(const struct sbrec_port_binding *pb) +{ + int64_t dp_limit = ovn_smap_get_llong(&pb->datapath->external_ids, + "ct-zone-limit", -1); + int64_t limit = ovn_smap_get_llong(&pb->options, + "ct-zone-limit", dp_limit); + return ct_zone_limit_normalize(limit); +} + +static int64_t +ct_zone_limit_normalize(int64_t limit) +{ + return limit >= 0 && limit <= UINT32_MAX ? limit : -1; +} diff --git a/controller/ct-zone.h b/controller/ct-zone.h index a7c2011a1..e74af1d66 100644 --- a/controller/ct-zone.h +++ b/controller/ct-zone.h @@ -22,6 +22,7 @@ #include "openvswitch/hmap.h" #include "openvswitch/shash.h" #include "openvswitch/types.h" +#include "local_data.h" #include "ovn-sb-idl.h" #include "simap.h" #include "vswitch-idl.h" @@ -43,6 +44,7 @@ struct ct_zone_ctx { struct ct_zone { uint16_t zone; + int64_t limit; }; /* States to move through when a new conntrack zone has been allocated. */ @@ -70,12 +72,19 @@ void ct_zones_update(const struct sset *local_lports, const struct hmap *local_datapaths, struct ct_zone_ctx *ctx); void ct_zones_commit(const struct ovsrec_bridge *br_int, - struct shash *pending_ct_zones); + const struct ovsrec_datapath *ovs_dp, + struct ovsdb_idl_txn *ovs_idl_txn, + struct ct_zone_ctx *ctx); void ct_zones_pending_clear_commited(struct shash *pending); bool ct_zone_handle_dp_update(struct ct_zone_ctx *ctx, - const struct sbrec_datapath_binding *dp); -bool ct_zone_handle_port_update(struct ct_zone_ctx *ctx, const char *name, + const struct local_datapath *local_dp, + const struct shash *local_lports); +bool ct_zone_handle_port_update(struct ct_zone_ctx *ctx, + const struct sbrec_port_binding *pb, bool updated, int *scan_start); uint16_t ct_zone_find_zone(const struct shash *ct_zones, const char *name); +void ct_zones_limits_sync(struct ct_zone_ctx *ctx, + const struct hmap *local_datapaths, + const struct shash *local_lports); #endif /* controller/ct-zone.h */ diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index aee558f9a..28f4fe407 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -795,6 +795,7 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl) ovsdb_idl_add_column(ovs_idl, &ovsrec_ssl_col_private_key); ovsdb_idl_add_table(ovs_idl, &ovsrec_table_datapath); ovsdb_idl_add_column(ovs_idl, &ovsrec_datapath_col_capabilities); + ovsdb_idl_add_column(ovs_idl, &ovsrec_datapath_col_ct_zones); ovsdb_idl_add_table(ovs_idl, &ovsrec_table_flow_sample_collector_set); ovsdb_idl_add_table(ovs_idl, &ovsrec_table_qos); ovsdb_idl_add_column(ovs_idl, &ovsrec_qos_col_other_config); @@ -804,6 +805,8 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl) ovsdb_idl_add_column(ovs_idl, &ovsrec_queue_col_other_config); ovsdb_idl_add_column(ovs_idl, &ovsrec_queue_col_external_ids); ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_link_state); + ovsdb_idl_add_table(ovs_idl, &ovsrec_table_ct_zone); + ovsdb_idl_add_column(ovs_idl, &ovsrec_ct_zone_col_limit); chassis_register_ovs_idl(ovs_idl); encaps_register_ovs_idl(ovs_idl); @@ -2227,6 +2230,8 @@ en_ct_zones_run(struct engine_node *node, void *data) ct_zones_restore(&ct_zones_data->ctx, ovs_table, dp_table, br_int); ct_zones_update(&rt_data->local_lports, &rt_data->local_datapaths, &ct_zones_data->ctx); + ct_zones_limits_sync(&ct_zones_data->ctx, &rt_data->local_datapaths, + &rt_data->lbinding_data.lports); ct_zones_data->recomputed = true; engine_set_node_state(node, EN_UPDATED); @@ -2246,8 +2251,9 @@ ct_zones_datapath_binding_handler(struct engine_node *node, void *data) EN_OVSDB_GET(engine_get_input("SB_datapath_binding", node)); SBREC_DATAPATH_BINDING_TABLE_FOR_EACH_TRACKED (dp, dp_table) { - if (!get_local_datapath(&rt_data->local_datapaths, - dp->tunnel_key)) { + const struct local_datapath *local_dp= + get_local_datapath(&rt_data->local_datapaths, dp->tunnel_key); + if (!local_dp) { continue; } @@ -2257,7 +2263,8 @@ ct_zones_datapath_binding_handler(struct engine_node *node, void *data) return false; } - if (!ct_zone_handle_dp_update(&ct_zones_data->ctx, dp)) { + if (!ct_zone_handle_dp_update(&ct_zones_data->ctx, local_dp, + &rt_data->lbinding_data.lports)) { return false; } } @@ -2306,8 +2313,8 @@ ct_zones_runtime_data_handler(struct engine_node *node, void *data) t_lport->tracked_type == TRACKED_RESOURCE_NEW || t_lport->tracked_type == TRACKED_RESOURCE_UPDATED; updated |= ct_zone_handle_port_update(&ct_zones_data->ctx, - t_lport->pb->logical_port, - port_updated, &scan_start); + t_lport->pb, port_updated, + &scan_start); } } @@ -5560,8 +5567,8 @@ main(int argc, char *argv[]) if (ct_zones_data) { stopwatch_start(CT_ZONE_COMMIT_STOPWATCH_NAME, time_msec()); - ct_zones_commit(br_int, - &ct_zones_data->ctx.pending); + ct_zones_commit(br_int, br_int_dp, ovs_idl_txn, + &ct_zones_data->ctx); stopwatch_stop(CT_ZONE_COMMIT_STOPWATCH_NAME, time_msec()); } diff --git a/lib/ovn-util.c b/lib/ovn-util.c index 58e941193..1ad347419 100644 --- a/lib/ovn-util.c +++ b/lib/ovn-util.c @@ -816,6 +816,23 @@ str_tolower(const char *orig) return copy; } +/* This is a wrapper function which get the value associated with 'key' in + * 'smap' and converts it to a long long. If 'key' is not in 'smap' or a + * valid unsigned integer can't be parsed from its value, returns 'def'. + */ +long long +ovn_smap_get_llong(const struct smap *smap, const char *key, long long def) +{ + const char *value = smap_get(smap, key); + long long ll_value; + + if (!value || !str_to_llong(value, 10, &ll_value)) { + return def; + } + + return ll_value; +} + /* For a 'key' of the form "IP:port" or just "IP", sets 'port', * 'ip_address' and 'ip' ('struct in6_addr' IPv6 or IPv4 mapped address). * The caller must free() the memory allocated for 'ip_address'. diff --git a/lib/ovn-util.h b/lib/ovn-util.h index f75b821b6..ae971ce5a 100644 --- a/lib/ovn-util.h +++ b/lib/ovn-util.h @@ -211,6 +211,9 @@ char *normalize_v46_prefix(const struct in6_addr *prefix, unsigned int plen); */ char *str_tolower(const char *orig); +long long ovn_smap_get_llong(const struct smap *smap, const char *key, + long long def); + /* OVN daemon options. Taken from ovs/lib/daemon.h. */ #define OVN_DAEMON_OPTION_ENUMS \ OVN_OPT_DETACH, \ diff --git a/northd/northd.c b/northd/northd.c index 5b50ea191..325b412db 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -741,6 +741,14 @@ ovn_datapath_update_external_ids(struct ovn_datapath *od) smap_add(&ids, "name2", name2); } + int64_t ct_zone_limit = ovn_smap_get_llong(od->nbs ? + &od->nbs->other_config : + &od->nbr->options, + "ct-zone-limit", -1); + if (ct_zone_limit > 0) { + smap_add_format(&ids, "ct-zone-limit", "%"PRId64, ct_zone_limit); + } + /* Set interconn-ts. */ if (od->nbs) { const char *ts = smap_get(&od->nbs->other_config, "interconn-ts"); diff --git a/ovn-nb.xml b/ovn-nb.xml index 0f9a1005a..7087c0cf2 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -747,6 +747,17 @@ this timeout will be automatically removed. The value defaults to 0, which means disabled. + + + CT zone limit value for given + . This value will be propagated to all + when configured, but can be + overwritten individually per . The + value 0 means unlimited. When the option is not present the limit + is not set and the zone limit is derived from OvS default datapath + limit. + @@ -1148,6 +1159,16 @@ false. + + CT zone limit value for given + . This value has priority over + limit specified on when configured. + The value 0 means unlimited. When the option is not present the limit + is not set and the zone limit is derived from OvS default datapath + limit. + + @@ -2811,6 +2832,14 @@ or

+ + + CT zone limit value for given + . The value 0 means unlimited, when the + option is not present the limit is not set and the zone limit is + derived from OvS default datapath limit. +
diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at index 9cb099e68..cc308468b 100644 --- a/tests/ovn-controller.at +++ b/tests/ovn-controller.at @@ -3127,3 +3127,102 @@ OVS_WAIT_UNTIL([grep -q 'tcp:127.0.0.1:1235: connected' hv1/ovn-controller.log]) OVN_CLEANUP([hv1]) AT_CLEANUP + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([ovn-controller - CT zone limit]) +ovn_start + +net_add n1 +sim_add hv1 +as hv1 +check ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 + +check ovn-appctl -t ovn-controller vlog/set dbg:ct_zone + +check ovs-vsctl add-port br-int lsp \ + -- set Interface lsp external-ids:iface-id=lsp + +check ovn-nbctl lr-add lr + +check ovn-nbctl ls-add ls +check ovn-nbctl lsp-add ls ls-lr +check ovn-nbctl lsp-set-type ls-lr router +check ovn-nbctl lsp-set-addresses ls-lr router +check ovn-nbctl lrp-add lr lr-ls 00:00:00:00:00:01 10.0.0.1 + +check ovn-nbctl lsp-add ls lsp +check ovn-nbctl lsp-set-addresses lsp "00:00:00:00:00:02 10.0.0.2" + +check ovn-nbctl lrp-add lr lrp-gw 01:00:00:00:00:01 172.16.0.1 +check ovn-nbctl lrp-set-gateway-chassis lrp-gw hv1 + +wait_for_ports_up +check ovn-nbctl --wait=hv sync + +get_zone_num() { + output=$1 + name=$2 + + printf "$output" | grep $name | cut -d ' ' -f 2 +} + +check_ovs_ct_limit() { + zone=$1 + limit=$2 + + AT_CHECK_UNQUOTED([ovs-appctl dpctl/ct-get-limits zone=$zone | sed "s/count=.*/count=?/;s/default limit=.*/default limit=?/" | sort], [0], [dnl +default limit=? +zone=$zone,limit=$limit,count=? +]) +} + +wait_ovs_ct_limit_count() { + count=$1 + + OVS_WAIT_UNTIL([test $count -eq $(ovs-vsctl --no-headings --format=table list CT_Zone | wc -l)]) +} + +ct_zones=$(ovn-appctl -t ovn-controller ct-zone-list) +lr_dnat=$(get_zone_num "$ct_zones" lr_dnat) +lr_snat=$(get_zone_num "$ct_zones" lr_snat) + +ls_dnat=$(get_zone_num "$ct_zones" ls_dnat) +ls_snat=$(get_zone_num "$ct_zones" ls_snat) + +lsp=$(get_zone_num "$ct_zones" lsp) + +wait_ovs_ct_limit_count 0 + +check ovn-nbctl --wait=hv set Logical_Router lr options:ct-zone-limit=5 +wait_ovs_ct_limit_count 2 +check_ovs_ct_limit $lr_dnat 5 +check_ovs_ct_limit $lr_snat 5 + +check ovn-nbctl --wait=hv remove Logical_Router lr options ct-zone-limit +wait_ovs_ct_limit_count 0 + +check ovn-nbctl --wait=hv set Logical_Switch ls other_config:ct-zone-limit=10 +wait_ovs_ct_limit_count 3 +check_ovs_ct_limit $ls_dnat 10 +check_ovs_ct_limit $ls_snat 10 +check_ovs_ct_limit $lsp 10 + +check ovn-nbctl --wait=hv set Logical_Switch_Port lsp options:ct-zone-limit=5 +wait_ovs_ct_limit_count 3 +check_ovs_ct_limit $ls_dnat 10 +check_ovs_ct_limit $ls_snat 10 +check_ovs_ct_limit $lsp 5 + +check ovn-nbctl --wait=hv remove Logical_Switch_Port lsp options ct-zone-limit +wait_ovs_ct_limit_count 3 +check_ovs_ct_limit $ls_dnat 10 +check_ovs_ct_limit $ls_snat 10 +check_ovs_ct_limit $lsp 10 + +check ovn-nbctl --wait=hv remove Logical_Switch ls other_config ct-zone-limit +wait_ovs_ct_limit_count 0 + +OVN_CLEANUP([hv1]) +AT_CLEANUP +])