From patchwork Sat May 29 16:01:34 2021
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Alexey Roytman
X-Patchwork-Id: 1485381
Return-Path:
X-Original-To: incoming@patchwork.ozlabs.org
Delivered-To: patchwork-incoming@bilbo.ozlabs.org
Authentication-Results: ozlabs.org;
spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org
(client-ip=140.211.166.136; helo=smtp3.osuosl.org;
envelope-from=ovs-dev-bounces@openvswitch.org; receiver=)
Authentication-Results: ozlabs.org;
dkim=fail reason="signature verification failed" (2048-bit key;
unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256
header.s=20161025 header.b=cT7N3IA0;
dkim-atps=neutral
Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest
SHA256)
(No client certificate requested)
by ozlabs.org (Postfix) with ESMTPS id 4FsmXM09LLz9sSn
for ; Sun, 30 May 2021 02:02:10 +1000 (AEST)
Received: from localhost (localhost [127.0.0.1])
by smtp3.osuosl.org (Postfix) with ESMTP id B9AB06070A;
Sat, 29 May 2021 16:02:07 +0000 (UTC)
X-Virus-Scanned: amavisd-new at osuosl.org
Received: from smtp3.osuosl.org ([127.0.0.1])
by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)
with ESMTP id n4Y0PekbipVX; Sat, 29 May 2021 16:02:06 +0000 (UTC)
Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56])
by smtp3.osuosl.org (Postfix) with ESMTP id 9F9C6606C6;
Sat, 29 May 2021 16:02:05 +0000 (UTC)
Received: from lf-lists.osuosl.org (localhost [127.0.0.1])
by lists.linuxfoundation.org (Postfix) with ESMTP id 7C732C0019;
Sat, 29 May 2021 16:02:05 +0000 (UTC)
X-Original-To: dev@openvswitch.org
Delivered-To: ovs-dev@lists.linuxfoundation.org
Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138])
by lists.linuxfoundation.org (Postfix) with ESMTP id 797C4C000E
for ; Sat, 29 May 2021 16:02:03 +0000 (UTC)
Received: from localhost (localhost [127.0.0.1])
by smtp1.osuosl.org (Postfix) with ESMTP id 5EAEC8453F
for ; Sat, 29 May 2021 16:02:03 +0000 (UTC)
X-Virus-Scanned: amavisd-new at osuosl.org
Authentication-Results: smtp1.osuosl.org (amavisd-new);
dkim=pass (2048-bit key) header.d=gmail.com
Received: from smtp1.osuosl.org ([127.0.0.1])
by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)
with ESMTP id 7_LUUfhhaiuD for ;
Sat, 29 May 2021 16:02:02 +0000 (UTC)
X-Greylist: whitelisted by SQLgrey-1.8.0
Received: from mail-wr1-x429.google.com (mail-wr1-x429.google.com
[IPv6:2a00:1450:4864:20::429])
by smtp1.osuosl.org (Postfix) with ESMTPS id 26374844C9
for ; Sat, 29 May 2021 16:02:02 +0000 (UTC)
Received: by mail-wr1-x429.google.com with SMTP id n2so6320084wrm.0
for ; Sat, 29 May 2021 09:02:01 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;
h=from:to:cc:subject:date:message-id:mime-version
:content-transfer-encoding;
bh=QcmrFntuJ4fYpWMd2MCT+BEqg60JRkNimfOFUUwc0Hw=;
b=cT7N3IA0uEpntIGOM3B24bwbw0+0WW3RTpMhRWfv84tR4v4VJxcAG1EeEF2Mw02dya
1PW/+3KBm+oyC35TmWxmkdnFtSJ4sg2sF4JuzBRVzBuGptINNxxt3mNgsr4SOX1YzDIN
7C/aVbVgw0VfVrkoalD17zakK2RsjgAGDX3reTx5AZGvZWJNje6aYglfFgzVuPXcLi4w
3nTHSMTeCVCBgOfjqmGJQI2wIvtc5+sE4aJxAE8FFeoOcDHVGc/DX/4lD2JfcTEseNv+
jhl3t1E3tb/EklRcGU8c+terBB+nXfMH167dEvnFKI1BZVwURjUoFbWtdjHDe7DiwROI
cX1Q==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20161025;
h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version
:content-transfer-encoding;
bh=QcmrFntuJ4fYpWMd2MCT+BEqg60JRkNimfOFUUwc0Hw=;
b=gckTYdxLAMEw0HpTEO1Bv9Fh9Rt2AD9m9U//IrQ8y2lbd6+cD3JSj1gSmlKBc4lTri
kS32H5T5vQDG3lJzqhh66dCS8wt3faPWPDqpKUMTjXpNWJyddJvwR5V2fogmXNqtVwsp
PqBh48oyUCR8MqB98Y6zXWOCjMEMrpcXYKMl5Hxlu4YFQgMEOhMaCGSq4lA3N5Ft/6cF
gzO1b5oyABoc2GClbZR70O3V9uspE/xFxQi2Sxdd//BU7RE9SgQItvd0IacgvnIeLGkw
v9fazXAsu9Xf4HwVPhofpJ+97Wxj4aq0etteACi2qHRNuWPOp1/L9rnfK8qeEqY4768y
i2WA==
X-Gm-Message-State: AOAM530anApTaCr42BRRy7D6WL/ZkN7fnm/r0hQOTDIAaaf4sA0QXgvi
5rHjeKhQb1B1bjuLVwW8XaSi3bkfv9E=
X-Google-Smtp-Source:
ABdhPJwQ2ihm/Q8qtifirvDmzEhVSI5+X+2t7KmF5WGWF4Gvt5jBxvcyZ7Bl6sH56GxFBKe6xW1j8g==
X-Received: by 2002:adf:f80f:: with SMTP id
s15mr14199824wrp.341.1622304119884;
Sat, 29 May 2021 09:01:59 -0700 (PDT)
Received: from localhost (93-173-17-164.bb.netvision.net.il. [93.173.17.164])
by smtp.gmail.com with ESMTPSA id
z17sm12376893wrt.81.2021.05.29.09.01.58
(version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128);
Sat, 29 May 2021 09:01:59 -0700 (PDT)
From: Alexey Roytman
To: dev@openvswitch.org
Date: Sat, 29 May 2021 19:01:34 +0300
Message-Id: <20210529160134.393412-1-aroytman@gmail.com>
X-Mailer: git-send-email 2.25.1
MIME-Version: 1.0
Cc: Alexey Roytman
Subject: [ovs-dev] [PATCH ovn v6] ovn-sbctl.c Add logical flows count numbers
X-BeenThere: ovs-dev@openvswitch.org
X-Mailman-Version: 2.1.15
Precedence: list
List-Id:
List-Unsubscribe: ,
List-Archive:
List-Post:
List-Help:
List-Subscribe: ,
Errors-To: ovs-dev-bounces@openvswitch.org
Sender: "dev"
From: Alexey Roytman
For big scale deployments, when number of logical flows can be 2M+,
sometimes users just need to know the total number of logical flows
and numbers of logical flows per table/per datapath.
New command output
ovn-sbctl count-flows
Datapath: "sw1" (4b1e53d8-9f0f-4768-b4a6-6cbc58a4bfda) pipeline: ingress
table=0 (ls_in_port_sec_l2 ) lflows=2
table=1 (ls_in_port_sec_ip ) lflows=1
table=2 (ls_in_port_sec_nd ) lflows=1
table=3 (ls_in_lookup_fdb ) lflows=1
table=4 (ls_in_put_fdb ) lflows=1
table=5 (ls_in_pre_acl ) lflows=2
table=6 (ls_in_pre_lb ) lflows=3
table=7 (ls_in_pre_stateful ) lflows=2
table=8 (ls_in_acl_hint ) lflows=1
table=9 (ls_in_acl ) lflows=2
table=10(ls_in_qos_mark ) lflows=1
table=11(ls_in_qos_meter ) lflows=1
table=12(ls_in_lb ) lflows=1
table=13(ls_in_stateful ) lflows=8
table=14(ls_in_pre_hairpin ) lflows=1
table=15(ls_in_nat_hairpin ) lflows=1
table=16(ls_in_hairpin ) lflows=1
table=17(ls_in_arp_rsp ) lflows=1
table=18(ls_in_dhcp_options ) lflows=1
table=19(ls_in_dhcp_response) lflows=1
table=20(ls_in_dns_lookup ) lflows=1
table=21(ls_in_dns_response ) lflows=1
table=22(ls_in_external_port) lflows=1
table=23(ls_in_l2_lkup ) lflows=3
table=24(ls_in_l2_unknown ) lflows=2
Total number of logical flows in the datapath "sw1" (4b1e53d8-9f0f-4768-b4a6-6cbc58a4bfda) pipeline: ingress = 41
Datapath: "sw1" (4b1e53d8-9f0f-4768-b4a6-6cbc58a4bfda) pipeline: egress
table=0 (ls_out_pre_lb ) lflows=3
table=1 (ls_out_pre_acl ) lflows=2
table=2 (ls_out_pre_stateful) lflows=2
table=3 (ls_out_lb ) lflows=1
table=4 (ls_out_acl_hint ) lflows=1
table=5 (ls_out_acl ) lflows=2
table=6 (ls_out_qos_mark ) lflows=1
table=7 (ls_out_qos_meter ) lflows=1
table=8 (ls_out_stateful ) lflows=3
table=9 (ls_out_port_sec_ip ) lflows=1
table=10(ls_out_port_sec_l2 ) lflows=1
Total number of logical flows in the datapath "sw1" (4b1e53d8-9f0f-4768-b4a6-6cbc58a4bfda) pipeline: egress = 18
Total number of logical flows = 59
Signed-off-by: Alexey Roytman
---
v5 -> v6
* Addressed Ben's comments about replacemen the --count flag of lflow-list/dump-flows by a a "count-flows" command.
v3 -> v4
* Addressed review comments from Mark
NOTE: In the current ovn-sbctl (and probably ovn-nbctl) implementation, some of the methods do not work, when the
utility is running in the daemon mode (there is no output). All printf methods should be replaced by "ds_put_*" methods.
I can work on that in a separate path. Meantime, I added to temporary functions "print_datapath_name_new" and
"print_datapath_prompt_new" just for finishing this task.
tests/ovn-sbctl.at | 45 ++++++++++-
utilities/ovn-sbctl.8.xml | 4 +
utilities/ovn-sbctl.c | 153 +++++++++++++++++++++++++++++++++++---
3 files changed, 190 insertions(+), 12 deletions(-)
diff --git a/tests/ovn-sbctl.at b/tests/ovn-sbctl.at
index f49134381..ff727281e 100644
--- a/tests/ovn-sbctl.at
+++ b/tests/ovn-sbctl.at
@@ -175,4 +175,47 @@ inactivity_probe : 30000
OVN_SBCTL_TEST([ovn_sbctl_invalid_0x_flow], [invalid 0x flow], [
check ovn-sbctl lflow-list 0x12345678
-])
\ No newline at end of file
+])
+
+dnl ---------------------------------------------------------------------
+
+OVN_SBCTL_TEST([ovn_sbctl_count_flows], [ovn-sbctl - count-flows], [
+
+count_entries() {
+ ovn-sbctl --column=_uuid list Logical_Flow | sed -r '/^\s*$/d' | wc -l
+}
+
+count_pipeline() {
+ ovn-sbctl --column=pipeline list Logical_Flow | grep $1 | sed -r '/^\s*$/d' | wc -l
+}
+
+# we start with empty Logical_Flow table
+# validate that the table is indeed empty
+AT_CHECK([count_entries], [0], [dnl
+0
+])
+
+AT_CHECK([ovn-sbctl count-flows], [0], [stdout], [stderr])
+
+AT_CHECK([ovn-sbctl count-flows], [0], [dnl
+Total number of logical flows = 0
+])
+
+# create some logical flows
+check ovn-nbctl ls-add count-test
+
+OVS_WAIT_UNTIL([total_lflows=`count_entries`; test $total_lflows -ne 0])
+
+egress_lflows=`count_pipeline egress`
+ingress_lflows=`count_pipeline ingress`
+
+AT_CHECK_UNQUOTED([ovn-sbctl count-flows | grep "flows =" | awk 'NF>1{print $NF}'], [0], [dnl
+$total_lflows
+])
+AT_CHECK_UNQUOTED([ovn-sbctl count-flows | grep Total | grep egress | awk 'NF>1{print $NF}'], [0], [dnl
+$egress_lflows
+])
+AT_CHECK_UNQUOTED([ovn-sbctl count-flows | grep Total | grep ingress | awk 'NF>1{print $NF}'], [0], [dnl
+$ingress_lflows
+])
+])
diff --git a/utilities/ovn-sbctl.8.xml b/utilities/ovn-sbctl.8.xml
index 4e6b21c47..ad16f5fa3 100644
--- a/utilities/ovn-sbctl.8.xml
+++ b/utilities/ovn-sbctl.8.xml
@@ -416,10 +416,14 @@
chassis. The --ovs
and --stats
can also be used in conjunction with --vflows
.
+
[--uuid
] dump-flows
[logical-datapath]
Alias for lflow-list
.
+
+ count-flows
[logical-datapath]
+ prints numbers of logical flows per table and per datapath.
Remote Connectivity Commands
diff --git a/utilities/ovn-sbctl.c b/utilities/ovn-sbctl.c
index 53f10cdd8..ba352c05b 100644
--- a/utilities/ovn-sbctl.c
+++ b/utilities/ovn-sbctl.c
@@ -105,8 +105,9 @@ Port binding commands:\n\
lsp-unbind PORT reset the port binding of logical port PORT\n\
\n\
Logical flow commands:\n\
- lflow-list [DATAPATH] [LFLOW...] List logical flows for DATAPATH\n\
- dump-flows [DATAPATH] [LFLOW...] Alias for lflow-list\n\
+ lflow-list [DATAPATH] [LFLOW...] list logical flows for DATAPATH\n\
+ dump-flows [DATAPATH] [LFLOW...] alias for lflow-list\n\
+ count-flows [DATAPATH] count logical flows for DATAPATH\n\
\n\
Connection commands:\n\
get-connection print the connections\n\
@@ -682,6 +683,24 @@ print_datapath_name(const struct sbrec_datapath_binding *dp)
}
}
+/*
+ A temp function, will replace the original 'print_datapath_name'
+ when all prints will be replaced by ds_put methods.
+*/
+static void
+print_datapath_name_new(struct ds *ds, const struct sbrec_datapath_binding *dp)
+{
+ const struct smap *ids = &dp->external_ids;
+ const char *name = smap_get(ids, "name");
+ const char *name2 = smap_get(ids, "name2");
+ if (name && name2) {
+ ds_put_format(ds, "\"%s\" aka \"%s\"", name, name2);
+ } else if (name || name2) {
+ ds_put_format(ds, "\"%s\"", name ? name : name2);
+ }
+}
+
+
static void
print_vflow_datapath_name(const struct sbrec_datapath_binding *dp,
bool do_print)
@@ -898,14 +917,120 @@ sbctl_lflow_add(struct sbctl_lflow **lflows,
if (*n_flows == *n_capacity) {
*lflows = x2nrealloc(*lflows, n_capacity, sizeof **lflows);
}
- (*lflows)[*n_flows].lflow = lflow;
- (*lflows)[*n_flows].dp = dp;
+ (*lflows)[ *n_flows ].lflow = lflow;
+ (*lflows)[ *n_flows ].dp = dp;
(*n_flows)++;
}
+static void
+print_datapath_prompt(const struct sbrec_datapath_binding *dp,
+ const struct uuid *uuid,
+ char *pipeline) {
+ printf("Datapath: ");
+ print_datapath_name(dp);
+ printf(" ("UUID_FMT") pipeline: %s\n", UUID_ARGS(uuid), pipeline);
+}
+
+/*
+ A temp function, will replace the original 'print_datapath_prompt'
+ when all prints will be replaced by ds_put methods.
+*/
+static void
+print_datapath_prompt_new(struct ds *ds,
+ const struct sbrec_datapath_binding *dp,
+ const struct uuid *uuid,
+ char *pipeline) {
+ ds_put_cstr(ds, "Datapath: ");
+ print_datapath_name_new(ds, dp);
+ ds_put_format(ds,
+ " ("UUID_FMT") pipeline: %s\n",
+ UUID_ARGS(uuid), pipeline);
+}
+
+
+static void
+print_datapath_sum(struct ds *ds,
+ const struct sbrec_datapath_binding *dp,
+ const struct uuid *uuid,
+ char *pipeline,
+ long lflows) {
+ ds_put_cstr(ds, "Total number of logical flows in the datapath ");
+ print_datapath_name_new(ds, dp);
+ ds_put_format(ds, " ("UUID_FMT") pipeline: %s = %ld\n\n",
+ UUID_ARGS(uuid), pipeline, lflows);
+}
+
+
+static void
+print_lflows_count(struct ds *ds,
+ int64_t table_id,
+ const char *name,
+ long count) {
+ ds_put_format(ds, " table=%-2"PRId64"(%-19s) lflows=%ld\n", \
+ table_id, name, count);
+}
+
+static void
+print_lflow_counters(struct ds *ds, size_t n_flows, struct sbctl_lflow *lflows)
+{
+ const struct sbctl_lflow *curr, *prev = NULL;
+ long table_lflows = 0;
+ long dp_lflows = 0;
+
+ for (size_t i = 0; i < n_flows; i++) {
+ bool new_datapath = false;
+ curr = &lflows[i];
+ if (!prev
+ || prev->dp != curr->dp
+ || strcmp(prev->lflow->pipeline, curr->lflow->pipeline)) {
+ new_datapath = true;
+ }
+
+ if (prev &&
+ (prev->lflow->table_id != curr->lflow->table_id || new_datapath)) {
+ print_lflows_count(ds, prev->lflow->table_id,
+ smap_get_def(&prev->lflow->external_ids, "stage-name", ""),
+ table_lflows);
+ table_lflows = 1;
+ if (new_datapath) {
+ print_datapath_sum(ds, prev->dp, &prev->dp->header_.uuid,
+ prev->lflow->pipeline, dp_lflows);
+ dp_lflows = 1;
+ } else {
+ dp_lflows++;
+ }
+ } else {
+ dp_lflows++;
+ table_lflows++;
+ }
+
+ if (new_datapath) {
+ print_datapath_prompt_new(ds,
+ curr->dp,
+ &curr->dp->header_.uuid,
+ curr->lflow->pipeline);
+ }
+ prev = curr;
+ }
+ if (n_flows > 0) {
+ print_lflows_count(ds,
+ prev->lflow->table_id,
+ smap_get_def(&prev->lflow->external_ids,
+ "stage-name",
+ ""),
+ table_lflows);
+ print_datapath_sum(ds,
+ prev->dp, &prev->dp->header_.uuid,
+ prev->lflow->pipeline, dp_lflows);
+
+ }
+ ds_put_format(ds, "Total number of logical flows = %ld\n", n_flows);
+}
+
static void
cmd_lflow_list(struct ctl_context *ctx)
{
+ const char *cmd = ctx->argv[0];
const struct sbrec_datapath_binding *datapath = NULL;
if (ctx->argc > 1) {
const struct ovsdb_idl_row *row;
@@ -966,6 +1091,11 @@ cmd_lflow_list(struct ctl_context *ctx)
qsort(lflows, n_flows, sizeof *lflows, sbctl_lflow_cmp);
}
+ if (strcmp(cmd, "count-flows")==0) {
+ print_lflow_counters(&ctx->output, n_flows, lflows);
+ goto cleanup;
+ }
+
bool print_uuid = shash_find(&ctx->options, "--uuid") != NULL;
const struct sbctl_lflow *curr, *prev = NULL;
@@ -997,11 +1127,9 @@ cmd_lflow_list(struct ctl_context *ctx)
if (!prev
|| prev->dp != curr->dp
|| strcmp(prev->lflow->pipeline, curr->lflow->pipeline)) {
- printf("Datapath: ");
- print_datapath_name(curr->dp);
- printf(" ("UUID_FMT") Pipeline: %s\n",
- UUID_ARGS(&curr->dp->header_.uuid),
- curr->lflow->pipeline);
+ print_datapath_prompt(curr->dp,
+ &curr->dp->header_.uuid,
+ curr->lflow->pipeline);
}
/* Print the flow. */
@@ -1028,6 +1156,7 @@ cmd_lflow_list(struct ctl_context *ctx)
cmd_lflow_list_load_balancers(ctx, vconn, datapath, stats, print_uuid);
}
+cleanup:
vconn_close(vconn);
free(lflows);
}
@@ -1378,8 +1507,10 @@ static const struct ctl_command_syntax sbctl_commands[] = {
"--uuid,--ovs?,--stats,--vflows?", RO},
{"dump-flows", 0, INT_MAX, "[DATAPATH] [LFLOW...]",
pre_get_info, cmd_lflow_list, NULL,
- "--uuid,--ovs?,--stats,--vflows?",
- RO}, /* Friendly alias for lflow-list */
+ "--uuid,--ovs?,--stats,--vflows?", RO},
+ /* Friendly alias for lflow-list */
+ {"count-flows", 0, 1, "[DATAPATH]",
+ pre_get_info, cmd_lflow_list, NULL, "", RO},
/* IP multicast commands. */
{"ip-multicast-flush", 0, 1, "SWITCH",