From patchwork Wed Aug 12 13:07:50 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Timothy Redaelli X-Patchwork-Id: 2284411 X-Patchwork-Delegate: echaudro@redhat.com 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=KGuo3ld1; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) (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 4hKphR5Ypcz1xx2 for ; Wed, 12 Aug 2026 23:08:23 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 668DA8127C; Wed, 12 Aug 2026 13:08:22 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id ay16g-RN0ZbU; Wed, 12 Aug 2026 13:08:20 +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 smtp1.osuosl.org 3EF978125F Authentication-Results: smtp1.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=KGuo3ld1 Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp1.osuosl.org (Postfix) with ESMTPS id 3EF978125F; Wed, 12 Aug 2026 13:08:20 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 0F1DDC040E; Wed, 12 Aug 2026 13:08:20 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 11117C059F for ; Wed, 12 Aug 2026 13:08:19 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id E313460A92 for ; Wed, 12 Aug 2026 13:08: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 RQuTFHDNKVcG for ; Wed, 12 Aug 2026 13:08:16 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=170.10.133.124; helo=us-smtp-delivery-124.mimecast.com; envelope-from=tredaelli@redhat.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp3.osuosl.org 77EAD60A68 Authentication-Results: smtp3.osuosl.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 77EAD60A68 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=KGuo3ld1 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by smtp3.osuosl.org (Postfix) with ESMTP id 77EAD60A68 for ; Wed, 12 Aug 2026 13:08:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1786540095; 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=3fn4j2BlQNHHx6CscIdkpR+o8Qdy5D3wobSWXgOh5gI=; b=KGuo3ld1bF11sKXt3Q4XgrH3GoXfhxKcm7nWtpyfcLtZbqUFrifl9N2qxhb0aB0zAzb2T4 H8of8Cv6ZSNhP8YNow87VCwhrsHItTiEfcvKtP/prl01ZrTeQYHxe6b3GjGjGbz23SsQnd XCopz7BTzX4PueUuUyPaaeRq5fYnnls= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-146-X_AphajbNA-o7U3Ln8ExDw-1; Wed, 12 Aug 2026 09:08:06 -0400 X-MC-Unique: X_AphajbNA-o7U3Ln8ExDw-1 X-Mimecast-MFC-AGG-ID: X_AphajbNA-o7U3Ln8ExDw_1786540086 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id E445C18000A3; Wed, 12 Aug 2026 13:08:05 +0000 (UTC) Received: from aldebaran.drizzt.lan (unknown [10.44.49.243]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 8CD0F180049F; Wed, 12 Aug 2026 13:08:04 +0000 (UTC) To: dev@openvswitch.org Date: Wed, 12 Aug 2026 15:07:50 +0200 Message-ID: In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 48xidkmDvvOM4LsjvFTmrXa-lGnZ2294LKrHsk5-pU0_1786540086 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH v5 2/5] ofproto-dpif-upcall: Add JSON output to upcall/show. 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: , X-Patchwork-Original-From: Timothy Redaelli via dev From: Timothy Redaelli Reply-To: Timothy Redaelli Cc: Ilya Maximets Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" When --format json is passed to ovs-appctl, upcall/show returns a JSON object keyed by datapath name. Each entry contains a "flows" sub-object (with "average", "current", "limit", "maximum", and "offloaded" counts), "dump-duration-ms", "ufid-enabled", and a "revalidators" object indexed by revalidator ID. The implementation is split into separate text and JSON helper functions. Example output: {"ovs-system": {"dump-duration-ms": 1, "flows": {"average": 0, "current": 0, "limit": 10000, "maximum": 0, "offloaded": 0}, "revalidators": {"4": {"keys": 0}}, "ufid-enabled": true}} Signed-off-by: Timothy Redaelli Acked-by: Eelco Chaudron --- NEWS | 1 + ofproto/ofproto-dpif-upcall.c | 95 +++++++++++++++++++++++++++++------ tests/ofproto-dpif.at | 49 +++++++++++++++++- 3 files changed, 130 insertions(+), 15 deletions(-) diff --git a/NEWS b/NEWS index eb5e84d6f..045cc0d6f 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,7 @@ Post-v4.0.0 -------------------- - ovs-appctl: * Added JSON output support (--format json) for 'fdb/stats-show'. + * Added JSON output support (--format json) for 'upcall/show'. v4.0.0 - xx xxx xxxx diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c index 8e4897202..b3b80c8f4 100644 --- a/ofproto/ofproto-dpif-upcall.c +++ b/ofproto/ofproto-dpif-upcall.c @@ -28,6 +28,7 @@ #include "openvswitch/dynamic-string.h" #include "fail-open.h" #include "guarded-list.h" +#include "openvswitch/json.h" #include "latch.h" #include "openvswitch/list.h" #include "netlink.h" @@ -3160,11 +3161,65 @@ dp_purge_cb(void *aux, unsigned pmd_id) udpif_resume_revalidators(udpif); } +static struct json * +upcall_unixctl_show_json(void) +{ + struct json *json_udpifs = json_object_create(); + struct udpif *udpif; + + LIST_FOR_EACH (udpif, list_node, &all_udpifs) { + struct json *json_revalidators = json_object_create(); + struct json *json_flows = json_object_create(); + struct json *json_udpif = json_object_create(); + uint64_t n_offloaded_flows; + unsigned int flow_limit; + bool ufid_enabled; + size_t i; + + atomic_read_relaxed(&udpif->flow_limit, &flow_limit); + ufid_enabled = udpif_use_ufid(udpif); + n_offloaded_flows = dpif_offload_flow_count(udpif->dpif); + + json_object_put(json_flows, "average", + json_integer_create(udpif->avg_n_flows)); + json_object_put(json_flows, "current", + json_integer_create(udpif_get_n_flows(udpif))); + json_object_put(json_flows, "limit", + json_integer_create(flow_limit)); + json_object_put(json_flows, "maximum", + json_integer_create(udpif->max_n_flows)); + json_object_put(json_flows, "offloaded", + json_integer_create(n_offloaded_flows)); + json_object_put(json_udpif, "dump-duration-ms", + json_integer_create(udpif->dump_duration)); + json_object_put(json_udpif, "flows", json_flows); + + for (i = 0; i < udpif->n_revalidators; i++) { + struct revalidator *revalidator = &udpif->revalidators[i]; + struct json *json_rv; + int j, elements = 0; + char *key; + + json_rv = json_object_create(); + key = xasprintf("%u", revalidator->id); + for (j = i; j < N_UMAPS; j += udpif->n_revalidators) { + elements += cmap_count(&udpif->ukeys[j].cmap); + } + json_object_put(json_rv, "keys", json_integer_create(elements)); + json_object_put_nocopy(json_revalidators, key, json_rv); + } + json_object_put(json_udpif, "revalidators", json_revalidators); + json_object_put(json_udpif, "ufid-enabled", + json_boolean_create(ufid_enabled)); + + json_object_put(json_udpifs, dpif_name(udpif->dpif), json_udpif); + } + return json_udpifs; +} + static void -upcall_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) +upcall_unixctl_show_text(struct ds *ds) { - struct ds ds = DS_EMPTY_INITIALIZER; uint64_t n_offloaded_flows; struct udpif *udpif; @@ -3176,23 +3231,23 @@ upcall_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED, atomic_read_relaxed(&udpif->flow_limit, &flow_limit); ufid_enabled = udpif_use_ufid(udpif); - ds_put_format(&ds, "%s:\n", dpif_name(udpif->dpif)); - ds_put_format(&ds, " flows : (current %lu)" + ds_put_format(ds, "%s:\n", dpif_name(udpif->dpif)); + ds_put_format(ds, " flows : (current %lu)" " (avg %u) (max %u) (limit %u)\n", udpif_get_n_flows(udpif), udpif->avg_n_flows, udpif->max_n_flows, flow_limit); n_offloaded_flows = dpif_offload_flow_count(udpif->dpif); if (n_offloaded_flows) { - ds_put_format(&ds, " offloaded flows : %"PRIu64"\n", + ds_put_format(ds, " offloaded flows : %"PRIu64"\n", n_offloaded_flows); } - ds_put_format(&ds, " dump duration : %lldms\n", udpif->dump_duration); - ds_put_format(&ds, " ufid enabled : "); + ds_put_format(ds, " dump duration : %lldms\n", udpif->dump_duration); + ds_put_format(ds, " ufid enabled : "); if (ufid_enabled) { - ds_put_format(&ds, "true\n"); + ds_put_format(ds, "true\n"); } else { - ds_put_format(&ds, "false\n"); + ds_put_format(ds, "false\n"); } - ds_put_char(&ds, '\n'); + ds_put_char(ds, '\n'); for (i = 0; i < udpif->n_revalidators; i++) { struct revalidator *revalidator = &udpif->revalidators[i]; @@ -3201,12 +3256,24 @@ upcall_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED, for (j = i; j < N_UMAPS; j += udpif->n_revalidators) { elements += cmap_count(&udpif->ukeys[j].cmap); } - ds_put_format(&ds, " %u: (keys %d)\n", revalidator->id, elements); + ds_put_format(ds, " %u: (keys %d)\n", revalidator->id, elements); } } +} - unixctl_command_reply(conn, ds_cstr(&ds)); - ds_destroy(&ds); +static void +upcall_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) +{ + if (unixctl_command_get_output_format(conn) == UNIXCTL_OUTPUT_FMT_JSON) { + unixctl_command_reply_json(conn, upcall_unixctl_show_json()); + } else { + struct ds ds = DS_EMPTY_INITIALIZER; + + upcall_unixctl_show_text(&ds); + unixctl_command_reply(conn, ds_cstr(&ds)); + ds_destroy(&ds); + } } /* Disable using the megaflows. diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index 207c61ad5..b7469bee2 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -13922,9 +13922,13 @@ AT_CLEANUP AT_SETUP([ofproto-dpif - Cleanup missing datapath flows]) -OVS_VSWITCHD_START +OVS_VSWITCHD_START([], [], [=override]) add_of_ports br0 1 2 +dnl Set to 1 revalidator thread early for deterministic output. +AT_CHECK([ovs-vsctl set open_vswitch . other_config:n-revalidator-threads=1]) +OVS_WAIT_UNTIL([ovs-appctl upcall/show | grep -c '(keys' | grep -q '^1$']) + m4_define([ICMP_PKT], [m4_join([,], [eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800)], [ipv4(src=10.10.10.2,dst=10.10.10.1,proto=1,tos=1,ttl=128,frag=no)], @@ -13945,6 +13949,49 @@ dnl Make sure the ukey exists. AT_CHECK([ovs-appctl upcall/show | grep '(keys' | awk '{print $3}' | \ grep -q '1)'], [0]) +dnl Add a second datapath to check the JSON output with multiple datapaths. +AT_CHECK([ovs-vsctl add-br br1 -- set bridge br1 datapath-type=netdev]) +OVS_WAIT_UNTIL([test $(ovs-appctl upcall/show | grep -c '^[[a-z]]*@') = 2]) + +dnl Check upcall/show JSON output has the expected structure. +AT_CHECK([ovs-appctl --format json --pretty upcall/show | dnl + sed 's/"dump-duration-ms": [[0-9]][[0-9]]*/"dump-duration-ms": /g' | dnl + sed 's/"average": [[0-9]][[0-9]]*/"average": /g' | dnl + sed 's/"current": [[0-9]][[0-9]]*/"current": /g' | dnl + sed 's/"limit": [[0-9]][[0-9]]*/"limit": /g' | dnl + sed 's/"maximum": [[0-9]][[0-9]]*/"maximum": /g' | dnl + sed 's/"keys": [[0-9]][[0-9]]*/"keys": /g' | dnl + sed 's/"[[0-9]][[0-9]]*": {/"": {/g'], [0], [dnl +{ + "dummy@ovs-dummy": { + "dump-duration-ms": , + "flows": { + "average": , + "current": , + "limit": , + "maximum": , + "offloaded": 0}, + "revalidators": { + "": { + "keys": }}, + "ufid-enabled": true}, + "netdev@ovs-netdev": { + "dump-duration-ms": , + "flows": { + "average": , + "current": , + "limit": , + "maximum": , + "offloaded": 0}, + "revalidators": { + "": { + "keys": }}, + "ufid-enabled": true}} +]) + +AT_CHECK([ovs-vsctl del-br br1]) +OVS_WAIT_UNTIL([test $(ovs-appctl upcall/show | grep -c '^[[a-z]]*@') = 1]) + dnl Delete all datapath flows, and make sure they are gone. AT_CHECK([ovs-appctl dpctl/del-flows]) AT_CHECK([ovs-appctl dpctl/dump-flows --names ], [0], [])