From patchwork Thu Nov 16 10:41:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakob Meng X-Patchwork-Id: 1864680 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=NaTiJWne; 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 4SWGmz1YXsz1yRR for ; Thu, 16 Nov 2023 21:41:55 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 5A8E883224; Thu, 16 Nov 2023 10:41:53 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 5A8E883224 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=NaTiJWne X-Virus-Scanned: amavisd-new at osuosl.org 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 NlE3cnopbJxf; Thu, 16 Nov 2023 10:41:51 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp1.osuosl.org (Postfix) with ESMTPS id 0C49B82E95; Thu, 16 Nov 2023 10:41:50 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 0C49B82E95 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id DACECC0DD5; Thu, 16 Nov 2023 10:41:48 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 13FCAC0DD5 for ; Thu, 16 Nov 2023 10:41:48 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id E2D2141BDD for ; Thu, 16 Nov 2023 10:41:47 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org E2D2141BDD Authentication-Results: smtp4.osuosl.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=NaTiJWne X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Fzxr2JM3bWsR for ; Thu, 16 Nov 2023 10:41:45 +0000 (UTC) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by smtp4.osuosl.org (Postfix) with ESMTPS id 9857141BA2 for ; Thu, 16 Nov 2023 10:41:45 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 9857141BA2 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1700131304; 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=vxvhGKQEnEoM6qNU31SuqSJoVH5s7Cra8dyucZmsWj0=; b=NaTiJWneWexZmfLeYEgeK2dnCzT1iApNvclUEXIT9nSkYEvygK/45gAazBT4+RP1RXBtZM qtFSuWsbiJ+P1LosiG1ltsi3rnyg8Od8K8vDd1+7hAiNRzwn858PEqwWIqL2UTcXe3jaId giHbKj5cD1ESSIt7rXKn/vakFbwt7HI= Received: from mail-lf1-f71.google.com (mail-lf1-f71.google.com [209.85.167.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-641-VyADvHrKN3Kz_-lxjn1Ybw-1; Thu, 16 Nov 2023 05:41:42 -0500 X-MC-Unique: VyADvHrKN3Kz_-lxjn1Ybw-1 Received: by mail-lf1-f71.google.com with SMTP id 2adb3069b0e04-507a3ae32beso631146e87.2 for ; Thu, 16 Nov 2023 02:41:42 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1700131301; x=1700736101; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=vxvhGKQEnEoM6qNU31SuqSJoVH5s7Cra8dyucZmsWj0=; b=awQTM4PKEF71SSx32iZY/qb5ibcskAhRDhxDVHXxjODu2Wip03KAlvYaX6hR/eIGLd s5rKgQHHUpeinl7tJZLUydtZZCWEN2JWrcsS4KqARF7QEUJYEc+N+309j50x38Qydf2G 8f8hP5vXz47IXPcAp3HY/ovcKg7ggUIQwfEjxaHRpa8crXEm4DMHVox7YhKw9QVASJrk ItmzQ+AlNPTAVA6OcF0lY/Qt1ysT/xZNhgG//6/Iq7R5Ot6H+mu9KZbDegt+DO/T6Yrz uvRaywfdzSayeDWzkQ779oAhdrH+HRXHx8PP7Hn+ZSG6aPxoll99jA+rarj44frk5Uyl dlOw== X-Gm-Message-State: AOJu0Yz59t/Ed9e6dv700Dt7b73yf2vjqYD2EO5hB75FAiG5jOSVOEg3 qhaWfhq6oPQ1QbUNZIKYZcK8yXjzsULR+0gSTIVS+ifi7DMSoTLyKvsPMCds5usTZkBSSoUEHrd DH1uywYnFs5d1f71VUXYqk7lfnrDTMCNnllJ7KCuBv366Dm1FDdHKeREVJR8gKfP/Jks= X-Received: by 2002:a2e:83c8:0:b0:2c6:f625:cc61 with SMTP id s8-20020a2e83c8000000b002c6f625cc61mr5772014ljh.31.1700131301202; Thu, 16 Nov 2023 02:41:41 -0800 (PST) X-Google-Smtp-Source: AGHT+IE8SCbrBjg6FaIX1jmxCUarAPLVwb8YYMSoS/SE+jg1JRh+75QeMgGDPcvCPBb+5I0RNkuo8Q== X-Received: by 2002:a2e:83c8:0:b0:2c6:f625:cc61 with SMTP id s8-20020a2e83c8000000b002c6f625cc61mr5771986ljh.31.1700131300584; Thu, 16 Nov 2023 02:41:40 -0800 (PST) Received: from positronik4lide.redhat.com ([87.122.56.153]) by smtp.gmail.com with ESMTPSA id n10-20020a05600c304a00b004080f0376a0sm2937210wmh.42.2023.11.16.02.41.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Nov 2023 02:41:40 -0800 (PST) From: jmeng@redhat.com To: dev@openvswitch.org, i.maximets@ovn.org, echaudro@redhat.com, ktraynor@redhat.com, aconole@redhat.com, rjarry@redhat.com Date: Thu, 16 Nov 2023 11:41:15 +0100 Message-Id: <20231116104120.25676-2-jmeng@redhat.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231116104120.25676-1-jmeng@redhat.com> References: <20231116104120.25676-1-jmeng@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH v4 1/6] Add global option for JSON output to ovs-appctl. 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: Jakob Meng For monitoring systems such as Prometheus it would be beneficial if OVS would expose statistics in a machine-readable format. This patch introduces support for different output formats to ovs-xxx tools. They gain a global option '-f,--format' which allows users to request JSON instead of plain-text for humans. An example call implemented in a later patch is 'ovs-appctl --format json dpif/show'. For that it is necessary to change the JSON-RPC API lib/unixctl.* which ovs-xxx tools use to communicate with ovs-vswitchd across unix sockets. It now allows to transport the requested output format besides the command and its args. This change has been implemented in a backward compatible way. One can use an updated client (ovs-appctl) with an old server (ovs-vswitchd) and vice versa. Of course, JSON output only works when both sides have been updated. Previously, the command was copied to the 'method' parameter in JSON-RPC while the args were copied to the 'params' parameter. Without any other means to transport parameters via JSON-RPC left, the meaning of 'method' and 'params' had to be changed: 'method' will now be 'execute/v1' when an output format other than 'text' is requested. In that case, the first parameter of the JSON array 'params' will now be the designated command, the second one the output format and the rest will be command args. unixctl_command_register() in lib/unixctl.* has been cloned as unixctl_command_register_fmt() in order to demonstrate the new API. The latter will be replaced with the former in a later patch. The new function gained an int argument called 'output_fmts' with which commands have to announce their support for output formats. Function type unixctl_cb_func in lib/unixctl.h has gained a new arg 'enum ovs_output_fmt fmt'. For now, it has been added as a comment only for the huge changes reason mentioned earlier. The output format which is passed via unix socket to ovs-vswitchd will be converted into a value of type 'enum ovs_output_fmt' in lib/unixctl.c and then passed to said 'fmt' arg of the choosen command handler (in a future patch). When a requested output format is not supported by a command, then process_command() in lib/unixctl.c will return an error. This patch does not yet pass the choosen output format to commands. Doing so requires changes to all unixctl_command_register() calls and all command callbacks. To improve readibility those changes have been split out into a follow up patch. Respectively, whenever an output format other than 'text' is choosen for ovs-xxx tools, they will fail. By default, the output format is plain-text as before. In popular tools like kubectl the option for output control is usually called '-o|--output' instead of '-f,--format'. But ovs-appctl already has an short option '-o' which prints the available ovs-appctl options ('--option'). The now choosen name also better alines with ovsdb-client where '-f,--format' controls output formatting. Reported-at: https://bugzilla.redhat.com/1824861 Signed-off-by: Jakob Meng --- NEWS | 2 + lib/command-line.c | 36 ++++++ lib/command-line.h | 10 ++ lib/dpctl.h | 4 + lib/unixctl.c | 249 +++++++++++++++++++++++++++++++---------- lib/unixctl.h | 17 ++- tests/pmd.at | 5 + utilities/ovs-appctl.c | 67 ++++++++--- utilities/ovs-dpctl.c | 1 + 9 files changed, 319 insertions(+), 72 deletions(-) diff --git a/NEWS b/NEWS index 43aea97b5..12a895629 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,8 @@ Post-v3.2.0 a.k.a. 'configured' values, can be found in the 'status' column of the Interface table, i.e. with 'ovs-vsctl get interface <..> status'. Reported names adjusted accordingly. + * Added new option [-f|--format] to choose the output format, e.g. 'json' + or 'text' (by default). v3.2.0 - 17 Aug 2023 diff --git a/lib/command-line.c b/lib/command-line.c index 967f4f5d5..775e0430a 100644 --- a/lib/command-line.c +++ b/lib/command-line.c @@ -24,6 +24,7 @@ #include "ovs-thread.h" #include "util.h" #include "openvswitch/vlog.h" +#include "openvswitch/json.h" VLOG_DEFINE_THIS_MODULE(command_line); @@ -53,6 +54,41 @@ ovs_cmdl_long_options_to_short_options(const struct option options[]) return xstrdup(short_options); } +const char * +ovs_output_fmt_to_string(enum ovs_output_fmt fmt) +{ + switch (fmt) { + case OVS_OUTPUT_FMT_TEXT: + return "text"; + + case OVS_OUTPUT_FMT_JSON: + return "json"; + + default: + return NULL; + } +} + +struct json * +ovs_output_fmt_to_json(enum ovs_output_fmt fmt) +{ + const char *string = ovs_output_fmt_to_string(fmt); + return string ? json_string_create(string) : NULL; +} + +bool +ovs_output_fmt_from_string(const char *string, enum ovs_output_fmt *fmt) +{ + if (!strcmp(string, "text")) { + *fmt = OVS_OUTPUT_FMT_TEXT; + } else if (!strcmp(string, "json")) { + *fmt = OVS_OUTPUT_FMT_JSON; + } else { + return false; + } + return true; +} + static char * OVS_WARN_UNUSED_RESULT build_short_options(const struct option *long_options) { diff --git a/lib/command-line.h b/lib/command-line.h index fc2a2690f..494274cec 100644 --- a/lib/command-line.h +++ b/lib/command-line.h @@ -20,6 +20,7 @@ /* Utilities for command-line parsing. */ #include "compiler.h" +#include struct option; @@ -46,6 +47,15 @@ struct ovs_cmdl_command { char *ovs_cmdl_long_options_to_short_options(const struct option *options); +enum ovs_output_fmt { + OVS_OUTPUT_FMT_TEXT = 1 << 0, + OVS_OUTPUT_FMT_JSON = 1 << 1 +}; + +const char *ovs_output_fmt_to_string(enum ovs_output_fmt); +struct json *ovs_output_fmt_to_json(enum ovs_output_fmt); +bool ovs_output_fmt_from_string(const char *, enum ovs_output_fmt *); + struct ovs_cmdl_parsed_option { const struct option *o; char *arg; diff --git a/lib/dpctl.h b/lib/dpctl.h index 9d0052152..1c9b2409f 100644 --- a/lib/dpctl.h +++ b/lib/dpctl.h @@ -19,6 +19,7 @@ #include #include "compiler.h" +#include "command-line.h" struct dpctl_params { /* True if it is called by ovs-appctl command. */ @@ -42,6 +43,9 @@ struct dpctl_params { /* --names: Use port names in output? */ bool names; + /* Output format. */ + enum ovs_output_fmt format; + /* Callback for printing. This function is called from dpctl_run_command() * to output data. The 'aux' parameter is set to the 'aux' * member. The 'error' parameter is true if 'string' is an error diff --git a/lib/unixctl.c b/lib/unixctl.c index 103357ee9..5de59f339 100644 --- a/lib/unixctl.c +++ b/lib/unixctl.c @@ -21,7 +21,6 @@ #include "coverage.h" #include "dirs.h" #include "openvswitch/dynamic-string.h" -#include "openvswitch/json.h" #include "jsonrpc.h" #include "openvswitch/list.h" #include "openvswitch/poll-loop.h" @@ -39,6 +38,7 @@ COVERAGE_DEFINE(unixctl_replied); struct unixctl_command { const char *usage; int min_args, max_args; + int output_fmts; unixctl_cb_func *cb; void *aux; }; @@ -63,6 +63,8 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); static struct shash commands = SHASH_INITIALIZER(&commands); +static const char *rpc_marker = "execute/v1"; + static void unixctl_list_commands(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) @@ -109,6 +111,28 @@ void unixctl_command_register(const char *name, const char *usage, int min_args, int max_args, unixctl_cb_func *cb, void *aux) +{ + unixctl_command_register_fmt(name, usage, min_args, max_args, + OVS_OUTPUT_FMT_TEXT, cb, aux); +} + +/* Registers a unixctl command with the given 'name'. 'usage' describes the + * arguments to the command; it is used only for presentation to the user in + * "list-commands" output. (If 'usage' is NULL, then the command is hidden.) + * 'output_fmts' is a bitmap that defines what output formats a command + * supports, e.g. OVS_OUTPUT_FMT_TEXT | OVS_OUTPUT_FMT_JSON. + * + * 'cb' is called when the command is received. It is passed an array + * containing the command name and arguments, plus a copy of 'aux'. Normally + * 'cb' should reply by calling unixctl_command_reply() or + * unixctl_command_reply_error() before it returns, but if the command cannot + * be handled immediately then it can defer the reply until later. A given + * connection can only process a single request at a time, so a reply must be + * made eventually to avoid blocking that connection. */ +void +unixctl_command_register_fmt(const char *name, const char *usage, + int min_args, int max_args, int output_fmts, + unixctl_cb_func *cb, void *aux) { struct unixctl_command *command; struct unixctl_command *lookup = shash_find_data(&commands, name); @@ -123,41 +147,48 @@ unixctl_command_register(const char *name, const char *usage, command->usage = usage; command->min_args = min_args; command->max_args = max_args; + command->output_fmts = output_fmts; command->cb = cb; command->aux = aux; shash_add(&commands, name, command); } -static void -unixctl_command_reply__(struct unixctl_conn *conn, - bool success, const char *body) +static struct json * +json_string_create__(const char *body) { - struct json *body_json; - struct jsonrpc_msg *reply; - - COVERAGE_INC(unixctl_replied); - ovs_assert(conn->request_id); - if (!body) { body = ""; } if (body[0] && body[strlen(body) - 1] != '\n') { - body_json = json_string_create_nocopy(xasprintf("%s\n", body)); + return json_string_create_nocopy(xasprintf("%s\n", body)); } else { - body_json = json_string_create(body); + return json_string_create(body); } +} + +/* Takes ownership of 'body'. */ +static void +unixctl_command_reply__(struct unixctl_conn *conn, + bool success, struct json *body) +{ + struct jsonrpc_msg *reply; + + COVERAGE_INC(unixctl_replied); + ovs_assert(conn->request_id); if (success) { - reply = jsonrpc_create_reply(body_json, conn->request_id); + reply = jsonrpc_create_reply(body, conn->request_id); } else { - reply = jsonrpc_create_error(body_json, conn->request_id); + reply = jsonrpc_create_error(body, conn->request_id); } if (VLOG_IS_DBG_ENABLED()) { char *id = json_to_string(conn->request_id, 0); + char *msg = json_to_string(body, 0); VLOG_DBG("replying with %s, id=%s: \"%s\"", - success ? "success" : "error", id, body); + success ? "success" : "error", id, msg); + free(msg); free(id); } @@ -170,22 +201,34 @@ unixctl_command_reply__(struct unixctl_conn *conn, /* Replies to the active unixctl connection 'conn'. 'result' is sent to the * client indicating the command was processed successfully. Only one call to - * unixctl_command_reply() or unixctl_command_reply_error() may be made per - * request. */ + * unixctl_command_reply(), unixctl_command_reply_error() or + * unixctl_command_reply_json() may be made per request. */ void unixctl_command_reply(struct unixctl_conn *conn, const char *result) { - unixctl_command_reply__(conn, true, result); + unixctl_command_reply__(conn, true, json_string_create__(result)); } /* Replies to the active unixctl connection 'conn'. 'error' is sent to the - * client indicating an error occurred processing the command. Only one call to - * unixctl_command_reply() or unixctl_command_reply_error() may be made per - * request. */ + * client indicating an error occurred processing the command. Only one call + * to unixctl_command_reply(), unixctl_command_reply_error() or + * unixctl_command_reply_json() may be made per request. */ void unixctl_command_reply_error(struct unixctl_conn *conn, const char *error) { - unixctl_command_reply__(conn, false, error); + unixctl_command_reply__(conn, false, json_string_create__(error)); +} + +/* Replies to the active unixctl connection 'conn'. 'result' is sent to the + * client indicating the command was processed successfully. Only one call to + * unixctl_command_reply(), unixctl_command_reply_error() or + * unixctl_command_reply_json() may be made per request. + * + * Takes ownership of 'body'. */ +void +unixctl_command_reply_json(struct unixctl_conn *conn, struct json *body) +{ + unixctl_command_reply__(conn, true, body); } /* Creates a unixctl server listening on 'path', which for POSIX may be: @@ -266,6 +309,11 @@ process_command(struct unixctl_conn *conn, struct jsonrpc_msg *request) struct unixctl_command *command; struct json_array *params; + const char *method; + enum ovs_output_fmt fmt; + struct svec argv = SVEC_EMPTY_INITIALIZER; + int args_offset; + bool plain_rpc; COVERAGE_INC(unixctl_received); conn->request_id = json_clone(request->id); @@ -279,45 +327,95 @@ process_command(struct unixctl_conn *conn, struct jsonrpc_msg *request) free(id_s); } + /* The JSON-RPC API requires an indirection in order to allow transporting + * additional data like the output format besides command and args. For + * backward compatibility with older clients the plain RPC is still + * supported. */ + plain_rpc = strcmp(request->method, rpc_marker); + args_offset = plain_rpc ? 0 : 2; + params = json_array(request->params); - command = shash_find_data(&commands, request->method); + if (!plain_rpc && (params->n < 2)) { + error = xasprintf("JSON-RPC API mismatch: Unexpected # of params:"\ + " %"PRIuSIZE, params->n); + goto error; + } + + for (size_t i = 0; i < params->n; i++) { + if (params->elems[i]->type != JSON_STRING) { + error = xasprintf("command has non-string argument: %s", + json_to_string(params->elems[i], 0)); + goto error; + } + } + + /* Extract method name. */ + method = plain_rpc ? request->method : json_string(params->elems[0]); + + /* Extract output format. */ + if (plain_rpc) { + fmt = OVS_OUTPUT_FMT_TEXT; + } else { + if (!ovs_output_fmt_from_string(json_string(params->elems[1]), &fmt)) { + error = xasprintf("invalid output format: %s", + json_string(params->elems[1])); + goto error; + } + } + + /* Find command with method name. */ + command = shash_find_data(&commands, method); + + /* Verify that method call complies with command requirements. */ if (!command) { error = xasprintf("\"%s\" is not a valid command (use " "\"list-commands\" to see a list of valid commands)", - request->method); - } else if (params->n < command->min_args) { + method); + goto error; + } else if ((params->n - args_offset) < command->min_args) { error = xasprintf("\"%s\" command requires at least %d arguments", - request->method, command->min_args); - } else if (params->n > command->max_args) { + method, command->min_args); + goto error; + } else if ((params->n - args_offset) > command->max_args) { error = xasprintf("\"%s\" command takes at most %d arguments", - request->method, command->max_args); - } else { - struct svec argv = SVEC_EMPTY_INITIALIZER; - int i; - - svec_add(&argv, request->method); - for (i = 0; i < params->n; i++) { - if (params->elems[i]->type != JSON_STRING) { - error = xasprintf("\"%s\" command has non-string argument", - request->method); - break; - } - svec_add(&argv, json_string(params->elems[i])); - } - svec_terminate(&argv); - - if (!error) { - command->cb(conn, argv.n, (const char **) argv.names, - command->aux); - } + method, command->max_args); + goto error; + } else if ((!command->output_fmts && fmt != OVS_OUTPUT_FMT_TEXT) || + (command->output_fmts && !(fmt & command->output_fmts))) + { + error = xasprintf("\"%s\" command does not support output format"\ + " \"%s\" %d %d", method, + ovs_output_fmt_to_string(fmt), command->output_fmts, + fmt); + goto error; + } - svec_destroy(&argv); + /* FIXME: Remove this check once output format will be passed to the + * command handler below. */ + if (fmt != OVS_OUTPUT_FMT_TEXT) { + error = xasprintf("output format \"%s\" has not been implemented yet", + ovs_output_fmt_to_string(fmt)); + goto error; } - if (error) { - unixctl_command_reply_error(conn, error); - free(error); + /* Extract command args. */ + svec_add(&argv, method); + for (size_t i = args_offset; i < params->n; i++) { + svec_add(&argv, json_string(params->elems[i])); } + svec_terminate(&argv); + + /* FIXME: Output format will be passed as 'fmt' to the command in later + * patch. */ + command->cb(conn, argv.n, (const char **) argv.names, /* fmt, */ + command->aux); + + svec_destroy(&argv); + + return; +error: + unixctl_command_reply_error(conn, error); + free(error); } static int @@ -483,21 +581,43 @@ unixctl_client_create(const char *path, struct jsonrpc **client) * '*err' if not NULL. */ int unixctl_client_transact(struct jsonrpc *client, const char *command, int argc, - char *argv[], char **result, char **err) + char *argv[], enum ovs_output_fmt fmt, + char **result, char **err) { struct jsonrpc_msg *request, *reply; struct json **json_args, *params; int error, i; + /* The JSON-RPC API requires an indirection in order to allow transporting + * additional data like the output format besides command and args. For + * backward compatibility with older servers the plain RPC is still + * supported. */ + bool plain_rpc = (fmt == OVS_OUTPUT_FMT_TEXT); *result = NULL; *err = NULL; - json_args = xmalloc(argc * sizeof *json_args); - for (i = 0; i < argc; i++) { - json_args[i] = json_string_create(argv[i]); + if (plain_rpc) { + json_args = xmalloc(argc * sizeof *json_args); + for (i = 0; i < argc; i++) { + json_args[i] = json_string_create(argv[i]); + } + + params = json_array_create(json_args, argc); + request = jsonrpc_create_request(command, params, NULL); + } else { + json_args = xmalloc((argc + 2) * sizeof *json_args); + json_args[0] = json_string_create(command); + json_args[1] = ovs_output_fmt_to_json(fmt); + for (i = 0; i < argc; i++) { + json_args[i + 2] = json_string_create(argv[i]); + } + + params = json_array_create(json_args, argc + 2); + + /* Use a versioned command to ensure that both server and client + * use the same JSON-RPC API. */ + request = jsonrpc_create_request(rpc_marker, params, NULL); } - params = json_array_create(json_args, argc); - request = jsonrpc_create_request(command, params, NULL); error = jsonrpc_transact_block(client, request, &reply); if (error) { @@ -508,7 +628,17 @@ unixctl_client_transact(struct jsonrpc *client, const char *command, int argc, if (reply->error) { if (reply->error->type == JSON_STRING) { - *err = xstrdup(json_string(reply->error)); + /* Catch incompatible server and return helpful error msg. */ + char *plain_rpc_error = xasprintf("\"%s\" is not a valid command", + rpc_marker); + if (!strncmp(plain_rpc_error, json_string(reply->error), + strlen(plain_rpc_error))) { + *err = xstrdup("JSON RPC reply indicates incompatible server. " + "Please upgrade server side to newer version."); + } else { + *err = xstrdup(json_string(reply->error)); + } + free(plain_rpc_error); } else { VLOG_WARN("%s: unexpected error type in JSON RPC reply: %s", jsonrpc_get_name(client), @@ -518,6 +648,9 @@ unixctl_client_transact(struct jsonrpc *client, const char *command, int argc, } else if (reply->result) { if (reply->result->type == JSON_STRING) { *result = xstrdup(json_string(reply->result)); + } else if (reply->result->type == JSON_OBJECT || + reply->result->type == JSON_ARRAY) { + *result = json_to_string(reply->result, 0); } else { VLOG_WARN("%s: unexpected result type in JSON rpc reply: %s", jsonrpc_get_name(client), diff --git a/lib/unixctl.h b/lib/unixctl.h index 4562dbc49..896ecb062 100644 --- a/lib/unixctl.h +++ b/lib/unixctl.h @@ -17,6 +17,9 @@ #ifndef UNIXCTL_H #define UNIXCTL_H 1 +#include "openvswitch/json.h" +#include "command-line.h" + #ifdef __cplusplus extern "C" { #endif @@ -36,17 +39,29 @@ int unixctl_client_create(const char *path, struct jsonrpc **client); int unixctl_client_transact(struct jsonrpc *client, const char *command, int argc, char *argv[], + enum ovs_output_fmt fmt, char **result, char **error); /* Command registration. */ struct unixctl_conn; +/* FIXME: Output format will be passed as 'fmt' to the command in later patch. + */ typedef void unixctl_cb_func(struct unixctl_conn *, - int argc, const char *argv[], void *aux); + int argc, const char *argv[], + /* enum ovs_output_fmt fmt, */ void *aux); +/* FIXME: unixctl_command_register() will be replaced with + * unixctl_command_register_fmt() in a later patch of this series. It + * is kept temporarily to reduce the amount of changes in this patch. */ void unixctl_command_register(const char *name, const char *usage, int min_args, int max_args, unixctl_cb_func *cb, void *aux); +void unixctl_command_register_fmt(const char *name, const char *usage, + int min_args, int max_args, int output_fmts, + unixctl_cb_func *cb, void *aux); void unixctl_command_reply_error(struct unixctl_conn *, const char *error); void unixctl_command_reply(struct unixctl_conn *, const char *body); +void unixctl_command_reply_json(struct unixctl_conn *, + struct json *body); #ifdef __cplusplus } diff --git a/tests/pmd.at b/tests/pmd.at index 06cc90477..3fcda13fd 100644 --- a/tests/pmd.at +++ b/tests/pmd.at @@ -93,6 +93,11 @@ pmd thread numa_id core_id : overhead: NOT AVAIL ]) +AT_CHECK([ovs-appctl --format json dpif-netdev/pmd-rxq-show], [2], [], [dnl +"dpif-netdev/pmd-rxq-show" command does not support output format "json" 1 2 +ovs-appctl: ovs-vswitchd: server returned an error +]) + AT_CHECK([ovs-appctl dpif/show], [0], [dnl dummy@ovs-dummy: hit:0 missed:0 br0: diff --git a/utilities/ovs-appctl.c b/utilities/ovs-appctl.c index ba0c172e6..feff1be0b 100644 --- a/utilities/ovs-appctl.c +++ b/utilities/ovs-appctl.c @@ -34,7 +34,16 @@ #include "openvswitch/vlog.h" static void usage(void); -static const char *parse_command_line(int argc, char *argv[]); + +/* Parsed command line args. */ +struct cmdl_args { + enum ovs_output_fmt format; + char *target; +}; + +static struct cmdl_args *cmdl_args_create(void); +static void cmdl_args_destroy(struct cmdl_args *); +static struct cmdl_args *parse_command_line(int argc, char *argv[]); static struct jsonrpc *connect_to_target(const char *target); int @@ -43,30 +52,30 @@ main(int argc, char *argv[]) char *cmd_result, *cmd_error; struct jsonrpc *client; char *cmd, **cmd_argv; - const char *target; + struct cmdl_args *args; int cmd_argc; int error; set_program_name(argv[0]); /* Parse command line and connect to target. */ - target = parse_command_line(argc, argv); - client = connect_to_target(target); + args = parse_command_line(argc, argv); + client = connect_to_target(args->target); /* Transact request and process reply. */ cmd = argv[optind++]; cmd_argc = argc - optind; cmd_argv = cmd_argc ? argv + optind : NULL; error = unixctl_client_transact(client, cmd, cmd_argc, cmd_argv, - &cmd_result, &cmd_error); + args->format, &cmd_result, &cmd_error); if (error) { - ovs_fatal(error, "%s: transaction error", target); + ovs_fatal(error, "%s: transaction error", args->target); } if (cmd_error) { jsonrpc_close(client); fputs(cmd_error, stderr); - ovs_error(0, "%s: server returned an error", target); + ovs_error(0, "%s: server returned an error", args->target); exit(2); } else if (cmd_result) { fputs(cmd_result, stdout); @@ -74,6 +83,7 @@ main(int argc, char *argv[]) OVS_NOT_REACHED(); } + cmdl_args_destroy(args); jsonrpc_close(client); free(cmd_result); free(cmd_error); @@ -101,13 +111,34 @@ Common commands:\n\ vlog/reopen Make the program reopen its log file\n\ Other options:\n\ --timeout=SECS wait at most SECS seconds for a response\n\ + -f, --format=FMT Output format. One of: 'json', or 'text'\n\ + ('text', by default)\n\ -h, --help Print this helpful information\n\ -V, --version Display ovs-appctl version information\n", program_name, program_name); exit(EXIT_SUCCESS); } -static const char * +static struct cmdl_args * +cmdl_args_create(void) { + struct cmdl_args *args = xmalloc(sizeof *args); + + args->format = OVS_OUTPUT_FMT_TEXT; + args->target = NULL; + + return args; +} + +static void +cmdl_args_destroy(struct cmdl_args *args) { + if (args->target) { + free(args->target); + } + + free(args); +} + +static struct cmdl_args * parse_command_line(int argc, char *argv[]) { enum { @@ -117,6 +148,7 @@ parse_command_line(int argc, char *argv[]) static const struct option long_options[] = { {"target", required_argument, NULL, 't'}, {"execute", no_argument, NULL, 'e'}, + {"format", required_argument, NULL, 'f'}, {"help", no_argument, NULL, 'h'}, {"option", no_argument, NULL, 'o'}, {"version", no_argument, NULL, 'V'}, @@ -126,11 +158,11 @@ parse_command_line(int argc, char *argv[]) }; char *short_options_ = ovs_cmdl_long_options_to_short_options(long_options); char *short_options = xasprintf("+%s", short_options_); - const char *target; + + struct cmdl_args *args = cmdl_args_create(); int e_options; unsigned int timeout = 0; - target = NULL; e_options = 0; for (;;) { int option; @@ -141,10 +173,10 @@ parse_command_line(int argc, char *argv[]) } switch (option) { case 't': - if (target) { + if (args->target) { ovs_fatal(0, "-t or --target may be specified only once"); } - target = optarg; + args->target = xstrdup(optarg); break; case 'e': @@ -157,6 +189,12 @@ parse_command_line(int argc, char *argv[]) } break; + case 'f': + if (!ovs_output_fmt_from_string(optarg, &args->format)) { + ovs_fatal(0, "value %s on -f or --format is invalid", optarg); + } + break; + case 'h': usage(); break; @@ -194,7 +232,10 @@ parse_command_line(int argc, char *argv[]) "(use --help for help)"); } - return target ? target : "ovs-vswitchd"; + if (!args->target) { + args->target = xstrdup("ovs-vswitchd"); + } + return args; } static struct jsonrpc * diff --git a/utilities/ovs-dpctl.c b/utilities/ovs-dpctl.c index 56d7a942b..30104ddb2 100644 --- a/utilities/ovs-dpctl.c +++ b/utilities/ovs-dpctl.c @@ -63,6 +63,7 @@ main(int argc, char *argv[]) fatal_ignore_sigpipe(); dpctl_p.is_appctl = false; + dpctl_p.format = OVS_OUTPUT_FMT_TEXT; dpctl_p.output = dpctl_print; dpctl_p.usage = usage; From patchwork Thu Nov 16 10:41:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakob Meng X-Patchwork-Id: 1864681 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=GKPtejTW; 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 4SWGn25Y87z1yRR for ; Thu, 16 Nov 2023 21:41:58 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id E687C83332; Thu, 16 Nov 2023 10:41:56 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org E687C83332 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=GKPtejTW X-Virus-Scanned: amavisd-new at osuosl.org 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 TRMYTQpMmWLi; Thu, 16 Nov 2023 10:41:53 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp1.osuosl.org (Postfix) with ESMTPS id 645A8831F2; Thu, 16 Nov 2023 10:41:51 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 645A8831F2 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 8A3DDC0DDB; Thu, 16 Nov 2023 10:41:49 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 4AFBEC0DD5 for ; Thu, 16 Nov 2023 10:41:48 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 1931A40BFB for ; Thu, 16 Nov 2023 10:41:48 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 1931A40BFB Authentication-Results: smtp2.osuosl.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=GKPtejTW X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id On3nllY-8wt9 for ; Thu, 16 Nov 2023 10:41:46 +0000 (UTC) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by smtp2.osuosl.org (Postfix) with ESMTPS id C1E90404F1 for ; Thu, 16 Nov 2023 10:41:45 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org C1E90404F1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1700131304; 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=OYNHXiqGum7tDqzqeYu2mQsqk1sZ95yn3FaVDsAv1BE=; b=GKPtejTWtKn7FxVRV+JG930NpOd0PERq9ClCRtJ+2LsCNfOeeD2eIrQPeWQyTwm6ZBZhjs kyVVaghvifFL1CytM9c4J+DG/z61rdUSxECFcjFzVPwUnS6+Lvo6V5qL5z+Ul//H0+x+XQ q1EmTqyFnIi67DTXkW8eWqRhEt93p+Y= Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-320-_6EUFpwjP5-1fG1AAB2uyg-1; Thu, 16 Nov 2023 05:41:43 -0500 X-MC-Unique: _6EUFpwjP5-1fG1AAB2uyg-1 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-4084e263ec4so3783245e9.2 for ; Thu, 16 Nov 2023 02:41:43 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1700131302; x=1700736102; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=OYNHXiqGum7tDqzqeYu2mQsqk1sZ95yn3FaVDsAv1BE=; b=haIh8aP5c4EtOt8ln+HLYf+EJoxnv47R3NkHS7OuQsi24eOAj53V8ZcaF/YzzpRVvs ukk5OYIJUOdex0dq0/V4NXVRWyOggR7r14VmfqfvctPgM3IrkepFh5arcoZ6jm5bWETj 7mKMMiizCHmHpOqRD0PGoe9gAs/teX5zWanGu4dYumSD8G2lIwqZfvEZKBGTXjdjigQ9 7HxCLgVHAF3jyBli1WQHh14Yia7++dHUSLmnddHH6blm8RgzGmPf72Sb6kefVwgxNGPU 8RZTE/+T4t2F1TuYOcfJlSblpCVDWnufHt6p3ZaRGu1wHGMqE+Fv4nMcsdLwxibR5jKZ YuLQ== X-Gm-Message-State: AOJu0YzYBAXeQXmhseCzNWr3AVR2wv02zSiaawmWxwDFlVE5ss8uuoUw l7HyDv+572MaTbH+coobBPafszSxvB3z4eNe4mZ5s5z6DvZ8n/xeI5cx+gba3dvWOhtj22FSv5S sEOTFt58as6RalpB9qGjvUg+H/8dAhEFosh0G80dEO/xPM5f65NBmdrCu5MWHFfwJdt8= X-Received: by 2002:a05:600c:4503:b0:40a:20f3:d11a with SMTP id t3-20020a05600c450300b0040a20f3d11amr13706337wmo.2.1700131302034; Thu, 16 Nov 2023 02:41:42 -0800 (PST) X-Google-Smtp-Source: AGHT+IFPHBZcmRCohNrct5QYtRMzttD7YQIJQv0z/ftZXxZ4iXqXTaaLEUGTwbbhw1pKUB6YXlVOmQ== X-Received: by 2002:a05:600c:4503:b0:40a:20f3:d11a with SMTP id t3-20020a05600c450300b0040a20f3d11amr13706314wmo.2.1700131301623; Thu, 16 Nov 2023 02:41:41 -0800 (PST) Received: from positronik4lide.redhat.com ([87.122.56.153]) by smtp.gmail.com with ESMTPSA id n10-20020a05600c304a00b004080f0376a0sm2937210wmh.42.2023.11.16.02.41.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Nov 2023 02:41:41 -0800 (PST) From: jmeng@redhat.com To: dev@openvswitch.org, i.maximets@ovn.org, echaudro@redhat.com, ktraynor@redhat.com, aconole@redhat.com, rjarry@redhat.com Date: Thu, 16 Nov 2023 11:41:16 +0100 Message-Id: <20231116104120.25676-3-jmeng@redhat.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231116104120.25676-1-jmeng@redhat.com> References: <20231116104120.25676-1-jmeng@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH v4 2/6] python: Add global option for JSON output to Python tools. 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: Jakob Meng This patch introduces support for different output formats to the Python code, as did the previous commit for ovs-xxx tools like 'ovs-appctl --format json dpif/show'. In particular, tests/appctl.py gains a global option '-f,--format' which allows users to request JSON instead of plain-text for humans. This patch does not yet pass the choosen output format to commands. Doing so requires changes to all command_register() calls and all command callbacks. To improve readibility those changes have been split out into a follow up patch. Respectively, whenever an output format other than 'text' is choosen for tests/appctl.py, the script will fail. Reported-at: https://bugzilla.redhat.com/1824861 Signed-off-by: Jakob Meng --- NEWS | 2 + python/ovs/unixctl/__init__.py | 39 +++++++++++++++--- python/ovs/unixctl/client.py | 20 +++++++-- python/ovs/unixctl/server.py | 74 +++++++++++++++++++++++----------- python/ovs/util.py | 9 +++++ tests/appctl.py | 7 +++- tests/unixctl-py.at | 7 ++++ 7 files changed, 126 insertions(+), 32 deletions(-) diff --git a/NEWS b/NEWS index 12a895629..fc77a1613 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,8 @@ Post-v3.2.0 Reported names adjusted accordingly. * Added new option [-f|--format] to choose the output format, e.g. 'json' or 'text' (by default). + - Python: + * Added support for choosing the output format, e.g. 'json' or 'text'. v3.2.0 - 17 Aug 2023 diff --git a/python/ovs/unixctl/__init__.py b/python/ovs/unixctl/__init__.py index 8ee312943..6d9bd5715 100644 --- a/python/ovs/unixctl/__init__.py +++ b/python/ovs/unixctl/__init__.py @@ -20,10 +20,14 @@ commands = {} class _UnixctlCommand(object): - def __init__(self, usage, min_args, max_args, callback, aux): + # FIXME: Output format will be passed as 'output_fmts' to the command in + # later patch. + def __init__(self, usage, min_args, max_args, # FIXME: output_fmts, + callback, aux): self.usage = usage self.min_args = min_args self.max_args = max_args + # FIXME: self.output_fmts = output_fmts self.callback = callback self.aux = aux @@ -42,10 +46,13 @@ def _unixctl_help(conn, unused_argv, unused_aux): conn.reply(reply) -def command_register(name, usage, min_args, max_args, callback, aux): +def command_register_fmt(name, usage, min_args, max_args, output_fmts, + callback, aux): """ Registers a command with the given 'name' to be exposed by the UnixctlServer. 'usage' describes the arguments to the command; it is used - only for presentation to the user in "help" output. + only for presentation to the user in "help" output. 'output_fmts' is a + bitmap that defines what output formats a command supports, e.g. + OVS_OUTPUT_FMT_TEXT | OVS_OUTPUT_FMT_JSON. 'callback' is called when the command is received. It is passed a UnixctlConnection object, the list of arguments as unicode strings, and @@ -63,8 +70,30 @@ def command_register(name, usage, min_args, max_args, callback, aux): assert callable(callback) if name not in commands: - commands[name] = _UnixctlCommand(usage, min_args, max_args, callback, - aux) + commands[name] = _UnixctlCommand(usage, min_args, max_args, + # FIXME: output_fmts, + callback, aux) + + +# FIXME: command_register() will be replaced with command_register_fmt() in a +# later patch of this series. It is is kept temporarily to reduce the +# amount of changes in this patch. +def command_register(name, usage, min_args, max_args, callback, aux): + """ Registers a command with the given 'name' to be exposed by the + UnixctlServer. 'usage' describes the arguments to the command; it is used + only for presentation to the user in "help" output. + + 'callback' is called when the command is received. It is passed a + UnixctlConnection object, the list of arguments as unicode strings, and + 'aux'. Normally 'callback' should reply by calling + UnixctlConnection.reply() or UnixctlConnection.reply_error() before it + returns, but if the command cannot be handled immediately, then it can + defer the reply until later. A given connection can only process a single + request at a time, so a reply must be made eventually to avoid blocking + that connection.""" + + command_register_fmt(name, usage, min_args, max_args, + ovs.util.OutputFormat.TEXT, callback, aux) def socket_name_from_target(target): diff --git a/python/ovs/unixctl/client.py b/python/ovs/unixctl/client.py index 8283f99bb..29a5f3df9 100644 --- a/python/ovs/unixctl/client.py +++ b/python/ovs/unixctl/client.py @@ -26,13 +26,20 @@ class UnixctlClient(object): assert isinstance(conn, ovs.jsonrpc.Connection) self._conn = conn - def transact(self, command, argv): + def transact(self, command, argv, fmt): assert isinstance(command, str) assert isinstance(argv, list) for arg in argv: assert isinstance(arg, str) + assert isinstance(fmt, ovs.util.OutputFormat) + plain_rpc = (fmt == ovs.util.OutputFormat.TEXT) + + if plain_rpc: + request = ovs.jsonrpc.Message.create_request(command, argv) + else: + request = ovs.jsonrpc.Message.create_request( + "execute/v1", [command, fmt.name.lower()] + argv) - request = ovs.jsonrpc.Message.create_request(command, argv) error, reply = self._conn.transact_block(request) if error: @@ -41,7 +48,14 @@ class UnixctlClient(object): return error, None, None if reply.error is not None: - return 0, str(reply.error), None + plain_rpc_error = ('"%s" is not a valid command' % + ovs.util.RPC_MARKER) + if str(reply.error).startswith(plain_rpc_error): + return 0, "JSON RPC reply indicates incompatible "\ + "server. Please upgrade server side to "\ + "newer version.", None + else: + return 0, str(reply.error), None else: assert reply.result is not None return 0, None, str(reply.result) diff --git a/python/ovs/unixctl/server.py b/python/ovs/unixctl/server.py index b9cb52fad..5e92bc570 100644 --- a/python/ovs/unixctl/server.py +++ b/python/ovs/unixctl/server.py @@ -104,30 +104,57 @@ class UnixctlConnection(object): self._request_id = request.id - error = None - params = request.params - method = request.method - command = ovs.unixctl.commands.get(method) - if command is None: - error = '"%s" is not a valid command' % method - elif len(params) < command.min_args: - error = '"%s" command requires at least %d arguments' \ - % (method, command.min_args) - elif len(params) > command.max_args: - error = '"%s" command takes at most %d arguments' \ - % (method, command.max_args) - else: - for param in params: - if not isinstance(param, str): - error = '"%s" command has non-string argument' % method - break + try: + plain_rpc = request.method != ovs.util.RPC_MARKER + args_offset = 0 if plain_rpc else 2 - if error is None: - unicode_params = [str(p) for p in params] - command.callback(self, unicode_params, command.aux) + if not plain_rpc and len(request.params) < 2: + raise ValueError( + "JSON-RPC API mismatch: Unexpected # of params: %d" + % len(request.params)) - if error: - self.reply_error(error) + for param in request.params: + if not isinstance(param, str): + raise ValueError( + "command has non-string argument: %s" % param) + + method = request.method if plain_rpc else request.params[0] + if plain_rpc: + fmt = ovs.util.OutputFormat.TEXT + else: + fmt = ovs.util.OutputFormat[request.params[1].upper()] + params = request.params[args_offset:] + + command = ovs.unixctl.commands.get(method) + if command is None: + raise ValueError('"%s" is not a valid command' % method) + elif len(params) < command.min_args: + raise ValueError( + '"%s" command requires at least %d arguments' + % (method, command.min_args)) + elif len(params) > command.max_args: + raise ValueError( + '"%s" command takes at most %d arguments' + % (method, command.max_args)) + # FIXME: Uncomment when command.output_fmts is available + # elif fmt not in command.output_fmts: + # raise ValueError('"%s" command does not support output format' + # ' "%s" %d %d' % (method, fmt.name.lower(), + # command.output_fmts, fmt)) + + # FIXME: Remove this check once output format will be passed to the + # command handler below. + if fmt != ovs.util.OutputFormat.TEXT: + raise ValueError( + 'output format "%s" has not been implemented yet' + % fmt.name.lower()) + + unicode_params = [str(p) for p in params] + command.callback(self, unicode_params, # FIXME: fmt, + command.aux) + + except Exception as e: + self.reply_error(str(e)) def _unixctl_version(conn, unused_argv, version): @@ -207,7 +234,8 @@ class UnixctlServer(object): % path) return error, None - ovs.unixctl.command_register("version", "", 0, 0, _unixctl_version, + ovs.unixctl.command_register("version", "", 0, 0, + _unixctl_version, version) return 0, UnixctlServer(listener) diff --git a/python/ovs/util.py b/python/ovs/util.py index 3dba022f8..75ba4ee12 100644 --- a/python/ovs/util.py +++ b/python/ovs/util.py @@ -15,9 +15,18 @@ import os import os.path import sys +import enum PROGRAM_NAME = os.path.basename(sys.argv[0]) EOF = -1 +RPC_MARKER = "execute/v1" + + +@enum.unique +# FIXME: Use @enum.verify(enum.NAMED_FLAGS) from Python 3.11 when available. +class OutputFormat(enum.IntFlag): + TEXT = 1 << 0 + JSON = 1 << 1 def abs_file_name(dir_, file_name): diff --git a/tests/appctl.py b/tests/appctl.py index b85b364fa..42f96b2a3 100644 --- a/tests/appctl.py +++ b/tests/appctl.py @@ -49,6 +49,10 @@ def main(): help="Arguments to the command.") parser.add_argument("-T", "--timeout", metavar="SECS", help="wait at most SECS seconds for a response") + parser.add_argument("-f", "--format", metavar="FMT", + help="Output format.", default="text", + choices=[fmt.name.lower() + for fmt in ovs.util.OutputFormat]) args = parser.parse_args() signal_alarm(int(args.timeout) if args.timeout else None) @@ -56,7 +60,8 @@ def main(): ovs.vlog.Vlog.init() target = args.target client = connect_to_target(target) - err_no, error, result = client.transact(args.command, args.argv) + err_no, error, result = client.transact( + args.command, args.argv, ovs.util.OutputFormat[args.format.upper()]) client.close() if err_no: diff --git a/tests/unixctl-py.at b/tests/unixctl-py.at index 724006118..c149268af 100644 --- a/tests/unixctl-py.at +++ b/tests/unixctl-py.at @@ -65,6 +65,13 @@ AT_CHECK([head -1 stderr], [0], [dnl sed 's/ovs-appctl/appctl.py/' stderr > experr AT_CHECK([PYAPPCTL_PY bond/hash mac vlan basis extra], [2], [], [experr]) +AT_CHECK([APPCTL --format json dpif-netdev/pmd-rxq-show], [2], [], [stderr]) +AT_CHECK([head -1 stderr], [0], [dnl +"dpif-netdev/pmd-rxq-show" command does not support output format "json" 1 2 +]) +sed 's/ovs-appctl/appctl.py/' stderr > experr +AT_CHECK([PYAPPCTL_PY --format json dpif-netdev/pmd-rxq-show], [2], [], [experr]) + OVS_VSWITCHD_STOP AT_CLEANUP From patchwork Thu Nov 16 10:41:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakob Meng X-Patchwork-Id: 1864685 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=QnCFj76X; 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 4SWGnL3m44z1yRR for ; Thu, 16 Nov 2023 21:42:14 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 984F34252B; Thu, 16 Nov 2023 10:42:12 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 984F34252B 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=QnCFj76X X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id fZcKne3LBNw3; Thu, 16 Nov 2023 10:42:04 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp4.osuosl.org (Postfix) with ESMTPS id F10A04250C; Thu, 16 Nov 2023 10:42:01 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org F10A04250C Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id BFA18C0071; Thu, 16 Nov 2023 10:42:01 +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 1C5F5C0DD5 for ; Thu, 16 Nov 2023 10:42:00 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 51E1683295 for ; Thu, 16 Nov 2023 10:41:59 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 51E1683295 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=QnCFj76X X-Virus-Scanned: amavisd-new at osuosl.org 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 Dnwrz3r77hU6 for ; Thu, 16 Nov 2023 10:41:51 +0000 (UTC) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by smtp1.osuosl.org (Postfix) with ESMTPS id 0C1C1831F1 for ; Thu, 16 Nov 2023 10:41:50 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 0C1C1831F1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1700131310; 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=Ao/8uHFH7jZEAxKGpU4NCKDtC8eacrJx68mdMlU042I=; b=QnCFj76XEBQAXNfpy4EEnVtN8BFHIY0H91bwm6C9GJT6cOFdgQolZOgkh/cQMUjIEOBSyX zr6IrLMMyWe8KmK3moz4QQnd0sVUSZ55Ki6Q+rMZhUZsV2SEGREkZdPYQ1Sq3kWpOYkLoQ n3Jy2TtJ8q6nA96ooHwFs3Qlg7vDfvs= Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-690-R8eqPUjHPD6s2brb99B0YQ-1; Thu, 16 Nov 2023 05:41:45 -0500 X-MC-Unique: R8eqPUjHPD6s2brb99B0YQ-1 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-408f9cee5e8so3500165e9.0 for ; Thu, 16 Nov 2023 02:41:45 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1700131304; x=1700736104; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=4Ywyso134c8byhEnweaaUOAV6kerCm6w7OYWv1jj4pk=; b=EaCmu8EFrRB9B+tkwHOXztft1TebQa4Gf02wQyWizjI1t53nl+2vqppFcZMBcRjElv pk9SOFu8/bas3I+T0GLLKWj7hTjr2u9U6mOyhVhHBvljN7KMN4ci6QxddY7nWjOJ+Hwf aeXr/mKc38vWVLs/c3v2wZoBTztphLovARANAnh9/F8Mmk73fLmfPb7mcgIcQhbjTmeU ttzENug+zCTPr480BKlQxspOqvFSUNkIqFsdGK11uN+Hg805D0db/0vCHXMaOPQUaJup zddjtQHoluqMqCX3Grfpu4pWLA+62dWxBBiR49g7DkhWg+2+o4RGbdpkEVkITqlAR4ZN fdbQ== X-Gm-Message-State: AOJu0Yy4dJbZLRMOdKQxkyEIl6QYhkDFZNv6PQIWMVb/cA/c5qq3J6PY 4l+lsg2oRV2JcPqyTrJs7IQ8sjcDu0bNcalXRGdgpimkYlrfe0HJS99pRbGW3U3lXqMRwQdjdun 7Z3Nt18yelJ5E1VPpOUVhisgphtWzIgq2g2mMkpQC1AlBqTTix/8cUzVnvwLQH0OQDGs= X-Received: by 2002:a05:600c:524e:b0:408:3ea0:3026 with SMTP id fc14-20020a05600c524e00b004083ea03026mr12232079wmb.11.1700131303870; Thu, 16 Nov 2023 02:41:43 -0800 (PST) X-Google-Smtp-Source: AGHT+IHvsL5mChlXEDxldFrRoxagQTNCMasv2H/695rTu1Wj6S22cB2A2heaGMM83U8nsUZtU5ikrQ== X-Received: by 2002:a05:600c:524e:b0:408:3ea0:3026 with SMTP id fc14-20020a05600c524e00b004083ea03026mr12232043wmb.11.1700131302820; Thu, 16 Nov 2023 02:41:42 -0800 (PST) Received: from positronik4lide.redhat.com ([87.122.56.153]) by smtp.gmail.com with ESMTPSA id n10-20020a05600c304a00b004080f0376a0sm2937210wmh.42.2023.11.16.02.41.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Nov 2023 02:41:42 -0800 (PST) From: jmeng@redhat.com To: dev@openvswitch.org, i.maximets@ovn.org, echaudro@redhat.com, ktraynor@redhat.com, aconole@redhat.com, rjarry@redhat.com Date: Thu, 16 Nov 2023 11:41:17 +0100 Message-Id: <20231116104120.25676-4-jmeng@redhat.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231116104120.25676-1-jmeng@redhat.com> References: <20231116104120.25676-1-jmeng@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH v4 3/6] Migrate commands to extended unixctl API. 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: Jakob Meng Previous commits introduced support different output formats to ovs-xxx tools and its Python equivalents. However, the commands were not yet migrated to the updated {unixctl_}command_register() functions and unixctl_cb_func function type in order to highlight the API changes only. This patch accomplishes this command migration in a single sweep. It replaces the old functions {unixctl_}command_register() in lib/unixctl.* and python/ovs/unixctl/__init__.py with their extended variants featuring the new 'output_fmts' parameter. All command registrations have been updated to announce what output formats each commands supports. No new output formats have been added, i.e. all commands still support OVS_OUTPUT_FMT_TEXT only. All command callbacks gained a 'enum ovs_output_fmt fmt OVS_UNUSED' argument to conform with the updated function type unixctl_cb_func in lib/unixctl.h. Without any new output formats being added, it is always ignored for now. Reported-at: https://bugzilla.redhat.com/1824861 Signed-off-by: Jakob Meng --- lib/bfd.c | 16 +++- lib/cfm.c | 13 +++- lib/coverage.c | 11 ++- lib/dpctl.c | 129 ++++++++++++++++++++------------- lib/dpdk.c | 15 ++-- lib/dpif-netdev-perf.c | 1 + lib/dpif-netdev-perf.h | 1 + lib/dpif-netdev.c | 84 ++++++++++++--------- lib/dpif-netlink.c | 6 +- lib/lacp.c | 7 +- lib/memory.c | 5 +- lib/netdev-dpdk.c | 16 +++- lib/netdev-dummy.c | 30 +++++--- lib/netdev-native-tnl.c | 4 +- lib/netdev-native-tnl.h | 4 +- lib/netdev-vport.c | 1 + lib/odp-execute.c | 10 ++- lib/ovs-lldp.c | 16 ++-- lib/ovs-router.c | 26 ++++--- lib/rstp.c | 22 +++--- lib/stopwatch.c | 10 ++- lib/stp.c | 20 ++--- lib/timeval.c | 13 ++-- lib/tnl-neigh-cache.c | 35 +++++---- lib/tnl-ports.c | 6 +- lib/unixctl.c | 52 +++---------- lib/unixctl.h | 12 +-- lib/vlog.c | 46 ++++++++---- ofproto/bond.c | 32 +++++--- ofproto/ofproto-dpif-trace.c | 10 ++- ofproto/ofproto-dpif-upcall.c | 81 +++++++++++++++------ ofproto/ofproto-dpif.c | 64 +++++++++++----- ofproto/ofproto.c | 10 ++- ofproto/tunnel.c | 4 +- ovsdb/file.c | 4 +- ovsdb/ovsdb-client.c | 40 ++++++---- ovsdb/ovsdb-server.c | 122 +++++++++++++++++++++++-------- ovsdb/ovsdb.c | 4 +- ovsdb/raft.c | 28 ++++--- python/ovs/unixctl/__init__.py | 40 ++-------- python/ovs/unixctl/server.py | 22 ++---- python/ovs/vlog.py | 12 ++- tests/test-netflow.c | 4 +- tests/test-sflow.c | 4 +- tests/test-unixctl.c | 33 ++++++--- tests/test-unixctl.py | 25 ++++--- utilities/ovs-ofctl.c | 43 +++++++---- vswitchd/bridge.c | 25 +++++-- vswitchd/ovs-vswitchd.c | 5 +- 49 files changed, 760 insertions(+), 463 deletions(-) diff --git a/lib/bfd.c b/lib/bfd.c index 9698576d0..05d150878 100644 --- a/lib/bfd.c +++ b/lib/bfd.c @@ -267,9 +267,13 @@ static void bfd_status_changed(struct bfd *) OVS_REQUIRES(mutex); static void bfd_forwarding_if_rx_update(struct bfd *) OVS_REQUIRES(mutex); static void bfd_unixctl_show(struct unixctl_conn *, int argc, - const char *argv[], void *aux OVS_UNUSED); + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED); static void bfd_unixctl_set_forwarding_override(struct unixctl_conn *, int argc, const char *argv[], + enum ovs_output_fmt fmt + OVS_UNUSED, void *aux OVS_UNUSED); static void log_msg(enum vlog_level, const struct msg *, const char *message, const struct bfd *) OVS_REQUIRES(mutex); @@ -339,9 +343,10 @@ void bfd_init(void) { unixctl_command_register("bfd/show", "[interface]", 0, 1, - bfd_unixctl_show, NULL); + OVS_OUTPUT_FMT_TEXT, bfd_unixctl_show, NULL); unixctl_command_register("bfd/set-forwarding", "[interface] normal|false|true", 1, 2, + OVS_OUTPUT_FMT_TEXT, bfd_unixctl_set_forwarding_override, NULL); } @@ -1311,7 +1316,8 @@ bfd_put_details(struct ds *ds, const struct bfd *bfd) OVS_REQUIRES(mutex) static void bfd_unixctl_show(struct unixctl_conn *conn, int argc, const char *argv[], - void *aux OVS_UNUSED) OVS_EXCLUDED(mutex) + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) + OVS_EXCLUDED(mutex) { struct ds ds = DS_EMPTY_INITIALIZER; struct bfd *bfd; @@ -1340,7 +1346,9 @@ out: static void bfd_unixctl_set_forwarding_override(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) OVS_EXCLUDED(mutex) { const char *forward_str = argv[argc - 1]; diff --git a/lib/cfm.c b/lib/cfm.c index c3742f3de..4f1598983 100644 --- a/lib/cfm.c +++ b/lib/cfm.c @@ -327,10 +327,12 @@ lookup_remote_mp(const struct cfm *cfm, uint64_t mpid) OVS_REQUIRES(mutex) void cfm_init(void) { - unixctl_command_register("cfm/show", "[interface]", 0, 1, cfm_unixctl_show, + unixctl_command_register("cfm/show", "[interface]", 0, 1, + OVS_OUTPUT_FMT_TEXT, cfm_unixctl_show, NULL); unixctl_command_register("cfm/set-fault", "[interface] normal|false|true", - 1, 2, cfm_unixctl_set_fault, NULL); + 1, 2, OVS_OUTPUT_FMT_TEXT, cfm_unixctl_set_fault, + NULL); } /* Records the status change and changes the global connectivity seq. */ @@ -1061,7 +1063,8 @@ cfm_print_details(struct ds *ds, struct cfm *cfm) OVS_REQUIRES(mutex) static void cfm_unixctl_show(struct unixctl_conn *conn, int argc, const char *argv[], - void *aux OVS_UNUSED) OVS_EXCLUDED(mutex) + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) + OVS_EXCLUDED(mutex) { struct ds ds = DS_EMPTY_INITIALIZER; struct cfm *cfm; @@ -1088,7 +1091,9 @@ out: static void cfm_unixctl_set_fault(struct unixctl_conn *conn, int argc, const char *argv[], - void *aux OVS_UNUSED) OVS_EXCLUDED(mutex) + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) + OVS_EXCLUDED(mutex) { const char *fault_str = argv[argc - 1]; int fault_override; diff --git a/lib/coverage.c b/lib/coverage.c index a95b6aa25..f32550fc3 100644 --- a/lib/coverage.c +++ b/lib/coverage.c @@ -61,7 +61,9 @@ coverage_counter_register(struct coverage_counter* counter) static void coverage_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct svec lines; char *reply; @@ -76,7 +78,9 @@ coverage_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED, static void coverage_unixctl_read_counter(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { unsigned long long count; char *reply; @@ -96,9 +100,10 @@ coverage_unixctl_read_counter(struct unixctl_conn *conn, int argc OVS_UNUSED, void coverage_init(void) { - unixctl_command_register("coverage/show", "", 0, 0, + unixctl_command_register("coverage/show", "", 0, 0, OVS_OUTPUT_FMT_TEXT, coverage_unixctl_show, NULL); unixctl_command_register("coverage/read-counter", "COUNTER", 1, 1, + OVS_OUTPUT_FMT_TEXT, coverage_unixctl_read_counter, NULL); } diff --git a/lib/dpctl.c b/lib/dpctl.c index cd12625a1..2de6daad1 100644 --- a/lib/dpctl.c +++ b/lib/dpctl.c @@ -66,6 +66,7 @@ struct dpctl_command { const char *usage; int min_args; int max_args; + int output_fmts; dpctl_command_handler *handler; enum { DP_RO, DP_RW} mode; }; @@ -2990,69 +2991,93 @@ out: } static const struct dpctl_command all_commands[] = { - { "add-dp", "dp [iface...]", 1, INT_MAX, dpctl_add_dp, DP_RW }, - { "del-dp", "dp", 1, 1, dpctl_del_dp, DP_RW }, - { "add-if", "dp iface...", 2, INT_MAX, dpctl_add_if, DP_RW }, - { "del-if", "dp iface...", 2, INT_MAX, dpctl_del_if, DP_RW }, - { "set-if", "dp iface...", 2, INT_MAX, dpctl_set_if, DP_RW }, - { "dump-dps", "", 0, 0, dpctl_dump_dps, DP_RO }, - { "show", "[-s] [dp...]", 0, INT_MAX, dpctl_show, DP_RO }, + { "add-dp", "dp [iface...]", 1, INT_MAX, OVS_OUTPUT_FMT_TEXT, + dpctl_add_dp, DP_RW }, + { "del-dp", "dp", 1, 1, OVS_OUTPUT_FMT_TEXT, dpctl_del_dp, DP_RW }, + { "add-if", "dp iface...", 2, INT_MAX, OVS_OUTPUT_FMT_TEXT, dpctl_add_if, + DP_RW }, + { "del-if", "dp iface...", 2, INT_MAX, OVS_OUTPUT_FMT_TEXT, dpctl_del_if, + DP_RW }, + { "set-if", "dp iface...", 2, INT_MAX, OVS_OUTPUT_FMT_TEXT, dpctl_set_if, + DP_RW }, + { "dump-dps", "", 0, 0, OVS_OUTPUT_FMT_TEXT, dpctl_dump_dps, DP_RO }, + { "show", "[-s] [dp...]", 0, INT_MAX, OVS_OUTPUT_FMT_TEXT, dpctl_show, + DP_RO }, { "dump-flows", "[-m] [--names] [dp] [filter=..] [type=..] [pmd=..]", - 0, 6, dpctl_dump_flows, DP_RO }, - { "add-flow", "[dp] flow actions", 2, 3, dpctl_add_flow, DP_RW }, - { "mod-flow", "[dp] flow actions", 2, 3, dpctl_mod_flow, DP_RW }, - { "get-flow", "[dp] ufid", 1, 2, dpctl_get_flow, DP_RO }, - { "del-flow", "[dp] flow", 1, 2, dpctl_del_flow, DP_RW }, - { "add-flows", "[dp] file", 1, 2, dpctl_process_flows, DP_RW }, - { "mod-flows", "[dp] file", 1, 2, dpctl_process_flows, DP_RW }, - { "del-flows", "[dp] [file]", 0, 2, dpctl_del_flows, DP_RW }, + 0, 6, OVS_OUTPUT_FMT_TEXT, dpctl_dump_flows, DP_RO }, + { "add-flow", "[dp] flow actions", 2, 3, OVS_OUTPUT_FMT_TEXT, + dpctl_add_flow, DP_RW }, + { "mod-flow", "[dp] flow actions", 2, 3, OVS_OUTPUT_FMT_TEXT, + dpctl_mod_flow, DP_RW }, + { "get-flow", "[dp] ufid", 1, 2, OVS_OUTPUT_FMT_TEXT, dpctl_get_flow, + DP_RO }, + { "del-flow", "[dp] flow", 1, 2, OVS_OUTPUT_FMT_TEXT, dpctl_del_flow, + DP_RW }, + { "add-flows", "[dp] file", 1, 2, OVS_OUTPUT_FMT_TEXT, + dpctl_process_flows, DP_RW }, + { "mod-flows", "[dp] file", 1, 2, OVS_OUTPUT_FMT_TEXT, + dpctl_process_flows, DP_RW }, + { "del-flows", "[dp] [file]", 0, 2, OVS_OUTPUT_FMT_TEXT, dpctl_del_flows, + DP_RW }, { "offload-stats-show", "[dp]", - 0, 1, dpctl_offload_stats_show, DP_RO }, + 0, 1, OVS_OUTPUT_FMT_TEXT, dpctl_offload_stats_show, DP_RO }, { "dump-conntrack", "[-m] [-s] [dp] [zone=N]", - 0, 4, dpctl_dump_conntrack, DP_RO }, + 0, 4, OVS_OUTPUT_FMT_TEXT, dpctl_dump_conntrack, DP_RO }, { "dump-conntrack-exp", "[dp] [zone=N]", - 0, 2, dpctl_dump_conntrack_exp, DP_RO }, + 0, 2, OVS_OUTPUT_FMT_TEXT, dpctl_dump_conntrack_exp, DP_RO }, { "flush-conntrack", "[dp] [zone=N] [ct-orig-tuple] [ct-reply-tuple]", - 0, 4, dpctl_flush_conntrack, DP_RW }, - { "cache-get-size", "[dp]", 0, 1, dpctl_cache_get_size, DP_RO }, - { "cache-set-size", "dp cache ", 3, 3, dpctl_cache_set_size, DP_RW }, + 0, 4, OVS_OUTPUT_FMT_TEXT, dpctl_flush_conntrack, DP_RW }, + { "cache-get-size", "[dp]", 0, 1, OVS_OUTPUT_FMT_TEXT, + dpctl_cache_get_size, DP_RO }, + { "cache-set-size", "dp cache ", 3, 3, OVS_OUTPUT_FMT_TEXT, + dpctl_cache_set_size, DP_RW }, { "ct-stats-show", "[dp] [zone=N]", - 0, 3, dpctl_ct_stats_show, DP_RO }, - { "ct-bkts", "[dp] [gt=N]", 0, 2, dpctl_ct_bkts, DP_RO }, - { "ct-set-maxconns", "[dp] maxconns", 1, 2, dpctl_ct_set_maxconns, - DP_RW }, - { "ct-get-maxconns", "[dp]", 0, 1, dpctl_ct_get_maxconns, DP_RO }, - { "ct-get-nconns", "[dp]", 0, 1, dpctl_ct_get_nconns, DP_RO }, - { "ct-enable-tcp-seq-chk", "[dp]", 0, 1, dpctl_ct_enable_tcp_seq_chk, - DP_RW }, - { "ct-disable-tcp-seq-chk", "[dp]", 0, 1, dpctl_ct_disable_tcp_seq_chk, - DP_RW }, - { "ct-get-tcp-seq-chk", "[dp]", 0, 1, dpctl_ct_get_tcp_seq_chk, DP_RO }, + 0, 3, OVS_OUTPUT_FMT_TEXT, dpctl_ct_stats_show, DP_RO }, + { "ct-bkts", "[dp] [gt=N]", 0, 2, OVS_OUTPUT_FMT_TEXT, dpctl_ct_bkts, + DP_RO }, + { "ct-set-maxconns", "[dp] maxconns", 1, 2, OVS_OUTPUT_FMT_TEXT, + dpctl_ct_set_maxconns, DP_RW }, + { "ct-get-maxconns", "[dp]", 0, 1, OVS_OUTPUT_FMT_TEXT, + dpctl_ct_get_maxconns, DP_RO }, + { "ct-get-nconns", "[dp]", 0, 1, OVS_OUTPUT_FMT_TEXT, dpctl_ct_get_nconns, + DP_RO }, + { "ct-enable-tcp-seq-chk", "[dp]", 0, 1, OVS_OUTPUT_FMT_TEXT, + dpctl_ct_enable_tcp_seq_chk, DP_RW }, + { "ct-disable-tcp-seq-chk", "[dp]", 0, 1, OVS_OUTPUT_FMT_TEXT, + dpctl_ct_disable_tcp_seq_chk, DP_RW }, + { "ct-get-tcp-seq-chk", "[dp]", 0, 1, OVS_OUTPUT_FMT_TEXT, + dpctl_ct_get_tcp_seq_chk, DP_RO }, { "ct-set-limits", "[dp] [default=L] [zone=N,limit=L]...", 1, INT_MAX, - dpctl_ct_set_limits, DP_RO }, - { "ct-del-limits", "[dp] zone=N1[,N2]...", 1, 2, dpctl_ct_del_limits, - DP_RO }, - { "ct-get-limits", "[dp] [zone=N1[,N2]...]", 0, 2, dpctl_ct_get_limits, - DP_RO }, - { "ct-get-sweep-interval", "[dp]", 0, 1, dpctl_ct_get_sweep, DP_RO }, - { "ct-set-sweep-interval", "[dp] ms", 1, 2, dpctl_ct_set_sweep, DP_RW }, - { "ipf-set-enabled", "[dp] v4|v6", 1, 2, dpctl_ipf_set_enabled, DP_RW }, - { "ipf-set-disabled", "[dp] v4|v6", 1, 2, dpctl_ipf_set_disabled, DP_RW }, + OVS_OUTPUT_FMT_TEXT, dpctl_ct_set_limits, DP_RO }, + { "ct-del-limits", "[dp] zone=N1[,N2]...", 1, 2, OVS_OUTPUT_FMT_TEXT, + dpctl_ct_del_limits, DP_RO }, + { "ct-get-limits", "[dp] [zone=N1[,N2]...]", 0, 2, OVS_OUTPUT_FMT_TEXT, + dpctl_ct_get_limits, DP_RO }, + { "ct-get-sweep-interval", "[dp]", 0, 1, OVS_OUTPUT_FMT_TEXT, + dpctl_ct_get_sweep, DP_RO }, + { "ct-set-sweep-interval", "[dp] ms", 1, 2, OVS_OUTPUT_FMT_TEXT, + dpctl_ct_set_sweep, DP_RW }, + { "ipf-set-enabled", "[dp] v4|v6", 1, 2, OVS_OUTPUT_FMT_TEXT, + dpctl_ipf_set_enabled, DP_RW }, + { "ipf-set-disabled", "[dp] v4|v6", 1, 2, OVS_OUTPUT_FMT_TEXT, + dpctl_ipf_set_disabled, DP_RW }, { "ipf-set-min-frag", "[dp] v4|v6 minfragment", 2, 3, - dpctl_ipf_set_min_frag, DP_RW }, + OVS_OUTPUT_FMT_TEXT, dpctl_ipf_set_min_frag, DP_RW }, { "ipf-set-max-nfrags", "[dp] maxfrags", 1, 2, - dpctl_ipf_set_max_nfrags, DP_RW }, - { "ipf-get-status", "[dp]", 0, 1, dpctl_ct_ipf_get_status, - DP_RO }, - { "help", "", 0, INT_MAX, dpctl_help, DP_RO }, - { "list-commands", "", 0, INT_MAX, dpctl_list_commands, DP_RO }, + OVS_OUTPUT_FMT_TEXT, dpctl_ipf_set_max_nfrags, DP_RW }, + { "ipf-get-status", "[dp]", 0, 1, OVS_OUTPUT_FMT_TEXT, + dpctl_ct_ipf_get_status, DP_RO }, + { "help", "", 0, INT_MAX, OVS_OUTPUT_FMT_TEXT, dpctl_help, DP_RO }, + { "list-commands", "", 0, INT_MAX, OVS_OUTPUT_FMT_TEXT, + dpctl_list_commands, DP_RO }, /* Undocumented commands for testing. */ - { "parse-actions", "actions", 1, INT_MAX, dpctl_parse_actions, DP_RO }, + { "parse-actions", "actions", 1, INT_MAX, OVS_OUTPUT_FMT_TEXT, + dpctl_parse_actions, DP_RO }, { "normalize-actions", "actions", - 2, INT_MAX, dpctl_normalize_actions, DP_RO }, + 2, INT_MAX, OVS_OUTPUT_FMT_TEXT, dpctl_normalize_actions, DP_RO }, - { NULL, NULL, 0, 0, NULL, DP_RO }, + { NULL, NULL, 0, 0, 0, NULL, DP_RO }, }; static const struct dpctl_command *get_all_dpctl_commands(void) @@ -3111,7 +3136,7 @@ dpctl_unixctl_print(void *userdata, bool error OVS_UNUSED, const char *msg) static void dpctl_unixctl_handler(struct unixctl_conn *conn, int argc, const char *argv[], - void *aux) + enum ovs_output_fmt fmt, void *aux) { struct ds ds = DS_EMPTY_INITIALIZER; bool error = false; @@ -3120,6 +3145,7 @@ dpctl_unixctl_handler(struct unixctl_conn *conn, int argc, const char *argv[], .is_appctl = true, .output = dpctl_unixctl_print, .aux = &ds, + .format = fmt, }; /* Parse options (like getopt). Unfortunately it does @@ -3208,6 +3234,7 @@ dpctl_unixctl_register(void) p->usage, p->min_args, p->max_args, + p->output_fmts, dpctl_unixctl_handler, p->handler); free(cmd_name); diff --git a/lib/dpdk.c b/lib/dpdk.c index d76d53f8f..4e71a8234 100644 --- a/lib/dpdk.c +++ b/lib/dpdk.c @@ -213,7 +213,8 @@ static cookie_io_functions_t dpdk_log_func = { static void dpdk_unixctl_mem_stream(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *aux) { void (*callback)(FILE *) = aux; char *response = NULL; @@ -260,6 +261,7 @@ dpdk_parse_log_level(const char *s) static void dpdk_unixctl_log_set(struct unixctl_conn *conn, int argc, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { int i; @@ -427,14 +429,15 @@ dpdk_init__(const struct smap *ovs_other_config) } } - unixctl_command_register("dpdk/lcore-list", "", 0, 0, - dpdk_unixctl_mem_stream, rte_lcore_dump); - unixctl_command_register("dpdk/log-list", "", 0, 0, + unixctl_command_register("dpdk/lcore-list", "", 0, 0, OVS_OUTPUT_FMT_TEXT, + dpdk_unixctl_mem_stream, rte_lcore_dump); + unixctl_command_register("dpdk/log-list", "", 0, 0, OVS_OUTPUT_FMT_TEXT, dpdk_unixctl_mem_stream, rte_log_dump); unixctl_command_register("dpdk/log-set", "{level | pattern:level}", 0, - INT_MAX, dpdk_unixctl_log_set, NULL); + INT_MAX, OVS_OUTPUT_FMT_TEXT, + dpdk_unixctl_log_set, NULL); unixctl_command_register("dpdk/get-malloc-stats", "", 0, 0, - dpdk_unixctl_mem_stream, + OVS_OUTPUT_FMT_TEXT, dpdk_unixctl_mem_stream, malloc_dump_stats_wrapper); /* We are called from the main thread here */ diff --git a/lib/dpif-netdev-perf.c b/lib/dpif-netdev-perf.c index 79ea5e3be..23e735ef0 100644 --- a/lib/dpif-netdev-perf.c +++ b/lib/dpif-netdev-perf.c @@ -706,6 +706,7 @@ pmd_perf_log_susp_iteration_neighborhood(struct pmd_perf_stats *s) void pmd_perf_log_set_cmd(struct unixctl_conn *conn, int argc, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { unsigned int it_before, it_after, us_thr, q_thr; diff --git a/lib/dpif-netdev-perf.h b/lib/dpif-netdev-perf.h index 84beced15..1e5cddbac 100644 --- a/lib/dpif-netdev-perf.h +++ b/lib/dpif-netdev-perf.h @@ -432,6 +432,7 @@ void pmd_perf_format_ms_history(struct ds *str, struct pmd_perf_stats *s, int n_ms); void pmd_perf_log_set_cmd(struct unixctl_conn *conn, int argc, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED); #ifdef __cplusplus diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index b8f065d1d..1e59f044d 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -1010,6 +1010,7 @@ sorted_poll_thread_list(struct dp_netdev *dp, static void dpif_netdev_subtable_lookup_get(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct ds reply = DS_EMPTY_INITIALIZER; @@ -1021,7 +1022,9 @@ dpif_netdev_subtable_lookup_get(struct unixctl_conn *conn, int argc OVS_UNUSED, static void dpif_netdev_subtable_lookup_set(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { /* This function requires 2 parameters (argv[1] and argv[2]) to execute. * argv[1] is subtable name @@ -1101,7 +1104,9 @@ dpif_netdev_subtable_lookup_set(struct unixctl_conn *conn, int argc OVS_UNUSED, static void dpif_netdev_impl_get(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct ds reply = DS_EMPTY_INITIALIZER; struct shash_node *node; @@ -1125,7 +1130,8 @@ dpif_netdev_impl_get(struct unixctl_conn *conn, int argc OVS_UNUSED, static void dpif_netdev_impl_set(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { /* This function requires just one parameter, the DPIF name. */ const char *dpif_name = argv[1]; @@ -1187,6 +1193,7 @@ dpif_netdev_impl_set(struct unixctl_conn *conn, int argc OVS_UNUSED, static void dpif_miniflow_extract_impl_get(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct ds reply = DS_EMPTY_INITIALIZER; @@ -1211,7 +1218,9 @@ dpif_miniflow_extract_impl_get(struct unixctl_conn *conn, int argc OVS_UNUSED, static void dpif_miniflow_extract_impl_set(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { /* This command takes some optional and mandatory arguments. The function * here first parses all of the options, saving results in local variables. @@ -1400,7 +1409,9 @@ error: static void dpif_netdev_pmd_rebalance(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct ds reply = DS_EMPTY_INITIALIZER; struct dp_netdev *dp = NULL; @@ -1430,7 +1441,7 @@ dpif_netdev_pmd_rebalance(struct unixctl_conn *conn, int argc, static void dpif_netdev_pmd_info(struct unixctl_conn *conn, int argc, const char *argv[], - void *aux) + enum ovs_output_fmt fmt OVS_UNUSED, void *aux) { struct ds reply = DS_EMPTY_INITIALIZER; struct dp_netdev_pmd_thread **pmd_list; @@ -1529,9 +1540,8 @@ dpif_netdev_pmd_info(struct unixctl_conn *conn, int argc, const char *argv[], } static void -pmd_perf_show_cmd(struct unixctl_conn *conn, int argc, - const char *argv[], - void *aux OVS_UNUSED) +pmd_perf_show_cmd(struct unixctl_conn *conn, int argc, const char *argv[], + enum ovs_output_fmt fmt, void *aux OVS_UNUSED) { struct pmd_perf_params par; long int it_hist = 0, ms_hist = 0; @@ -1567,12 +1577,13 @@ pmd_perf_show_cmd(struct unixctl_conn *conn, int argc, par.iter_hist_len = it_hist; par.ms_hist_len = ms_hist; par.command_type = PMD_INFO_PERF_SHOW; - dpif_netdev_pmd_info(conn, argc, argv, &par); + dpif_netdev_pmd_info(conn, argc, argv, fmt, &par); } static void -dpif_netdev_bond_show(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) +dpif_netdev_bond_show(struct unixctl_conn *conn, int argc, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct ds reply = DS_EMPTY_INITIALIZER; struct dp_netdev *dp = NULL; @@ -1622,60 +1633,60 @@ dpif_netdev_init(void) sleep_aux = PMD_INFO_SLEEP_SHOW; unixctl_command_register("dpif-netdev/pmd-stats-show", "[-pmd core] [dp]", - 0, 3, dpif_netdev_pmd_info, + 0, 3, OVS_OUTPUT_FMT_TEXT, dpif_netdev_pmd_info, (void *)&show_aux); unixctl_command_register("dpif-netdev/pmd-stats-clear", "[-pmd core] [dp]", - 0, 3, dpif_netdev_pmd_info, + 0, 3, OVS_OUTPUT_FMT_TEXT, dpif_netdev_pmd_info, (void *)&clear_aux); unixctl_command_register("dpif-netdev/pmd-rxq-show", "[-pmd core] " "[-secs secs] [dp]", - 0, 5, dpif_netdev_pmd_info, + 0, 5, OVS_OUTPUT_FMT_TEXT, dpif_netdev_pmd_info, (void *)&poll_aux); unixctl_command_register("dpif-netdev/pmd-sleep-show", "[dp]", - 0, 1, dpif_netdev_pmd_info, + 0, 1, OVS_OUTPUT_FMT_TEXT, dpif_netdev_pmd_info, (void *)&sleep_aux); unixctl_command_register("dpif-netdev/pmd-perf-show", "[-nh] [-it iter-history-len]" " [-ms ms-history-len]" " [-pmd core] [dp]", - 0, 8, pmd_perf_show_cmd, + 0, 8, OVS_OUTPUT_FMT_TEXT, pmd_perf_show_cmd, NULL); unixctl_command_register("dpif-netdev/pmd-rxq-rebalance", "[dp]", - 0, 1, dpif_netdev_pmd_rebalance, - NULL); + 0, 1, OVS_OUTPUT_FMT_TEXT, + dpif_netdev_pmd_rebalance, NULL); unixctl_command_register("dpif-netdev/pmd-perf-log-set", "on|off [-b before] [-a after] [-e|-ne] " "[-us usec] [-q qlen]", - 0, 10, pmd_perf_log_set_cmd, + 0, 10, OVS_OUTPUT_FMT_TEXT, pmd_perf_log_set_cmd, NULL); unixctl_command_register("dpif-netdev/bond-show", "[dp]", - 0, 1, dpif_netdev_bond_show, + 0, 1, OVS_OUTPUT_FMT_TEXT, dpif_netdev_bond_show, NULL); unixctl_command_register("dpif-netdev/subtable-lookup-prio-set", "[lookup_func] [prio]", - 2, 2, dpif_netdev_subtable_lookup_set, - NULL); + 2, 2, OVS_OUTPUT_FMT_TEXT, + dpif_netdev_subtable_lookup_set, NULL); unixctl_command_register("dpif-netdev/subtable-lookup-info-get", "", - 0, 0, dpif_netdev_subtable_lookup_get, - NULL); + 0, 0, OVS_OUTPUT_FMT_TEXT, + dpif_netdev_subtable_lookup_get, NULL); unixctl_command_register("dpif-netdev/subtable-lookup-prio-get", NULL, - 0, 0, dpif_netdev_subtable_lookup_get, - NULL); + 0, 0, OVS_OUTPUT_FMT_TEXT, + dpif_netdev_subtable_lookup_get, NULL); unixctl_command_register("dpif-netdev/dpif-impl-set", "dpif_implementation_name", - 1, 1, dpif_netdev_impl_set, + 1, 1, OVS_OUTPUT_FMT_TEXT, dpif_netdev_impl_set, NULL); unixctl_command_register("dpif-netdev/dpif-impl-get", "", - 0, 0, dpif_netdev_impl_get, + 0, 0, OVS_OUTPUT_FMT_TEXT, dpif_netdev_impl_get, NULL); unixctl_command_register("dpif-netdev/miniflow-parser-set", "[-pmd core] miniflow_implementation_name" " [study_pkt_cnt]", - 1, 5, dpif_miniflow_extract_impl_set, - NULL); + 1, 5, OVS_OUTPUT_FMT_TEXT, + dpif_miniflow_extract_impl_set, NULL); unixctl_command_register("dpif-netdev/miniflow-parser-get", "", - 0, 0, dpif_miniflow_extract_impl_get, - NULL); + 0, 0, OVS_OUTPUT_FMT_TEXT, + dpif_miniflow_extract_impl_get, NULL); return 0; } @@ -9837,7 +9848,9 @@ const struct dpif_class dpif_netdev_class = { static void dpif_dummy_change_port_number(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct dp_netdev_port *port; struct dp_netdev *dp; @@ -9933,7 +9946,8 @@ dpif_dummy_register(enum dummy_level level) unixctl_command_register("dpif-dummy/change-port-number", "dp port new-number", - 3, 3, dpif_dummy_change_port_number, NULL); + 3, 3, OVS_OUTPUT_FMT_TEXT, + dpif_dummy_change_port_number, NULL); } /* Datapath Classifier. */ diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index 9194971d3..1b0771c4c 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -124,7 +124,9 @@ dpif_netlink_set_features(struct dpif *dpif_, uint32_t new_features); static void dpif_netlink_unixctl_dispatch_mode(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux); + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux); struct dpif_netlink_flow { /* Generic Netlink header. */ @@ -4651,6 +4653,7 @@ dpif_netlink_init(void) ovs_tunnels_out_of_tree = dpif_netlink_rtnl_probe_oot_tunnels(); unixctl_command_register("dpif-netlink/dispatch-mode", "", 0, 0, + OVS_OUTPUT_FMT_TEXT, dpif_netlink_unixctl_dispatch_mode, NULL); ovsthread_once_done(&once); @@ -5304,6 +5307,7 @@ static void dpif_netlink_unixctl_dispatch_mode(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct ds reply = DS_EMPTY_INITIALIZER; diff --git a/lib/lacp.c b/lib/lacp.c index 3252f17eb..9923efb72 100644 --- a/lib/lacp.c +++ b/lib/lacp.c @@ -225,10 +225,11 @@ parse_lacp_packet(const struct dp_packet *p, enum pdu_subtype *subtype) void lacp_init(void) { - unixctl_command_register("lacp/show", "[port]", 0, 1, + unixctl_command_register("lacp/show", "[port]", 0, 1, OVS_OUTPUT_FMT_TEXT, lacp_unixctl_show, NULL); unixctl_command_register("lacp/show-stats", "[port]", 0, 1, - lacp_unixctl_show_stats, NULL); + OVS_OUTPUT_FMT_TEXT, lacp_unixctl_show_stats, + NULL); } static void @@ -1114,6 +1115,7 @@ lacp_print_stats(struct ds *ds, struct lacp *lacp) OVS_REQUIRES(mutex) static void lacp_unixctl_show(struct unixctl_conn *conn, int argc, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) OVS_EXCLUDED(mutex) { struct ds ds = DS_EMPTY_INITIALIZER; @@ -1144,6 +1146,7 @@ static void lacp_unixctl_show_stats(struct unixctl_conn *conn, int argc, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) OVS_EXCLUDED(mutex) { struct ds ds = DS_EMPTY_INITIALIZER; diff --git a/lib/memory.c b/lib/memory.c index da97476c6..cd6950aa3 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -160,7 +160,8 @@ memory_report(const struct simap *usage) static void memory_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { conns = xrealloc(conns, (n_conns + 1) * sizeof *conns); conns[n_conns++] = conn; @@ -173,7 +174,7 @@ memory_init(void) if (!inited) { inited = true; - unixctl_command_register("memory/show", "", 0, 0, + unixctl_command_register("memory/show", "", 0, 0, OVS_OUTPUT_FMT_TEXT, memory_unixctl_show, NULL); next_check = time_boot_msec() + MEMORY_CHECK_INTERVAL; diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c index 29f2b280d..46f584a55 100644 --- a/lib/netdev-dpdk.c +++ b/lib/netdev-dpdk.c @@ -4265,7 +4265,9 @@ netdev_dpdk_set_admin_state__(struct netdev_dpdk *dev, bool admin_state) static void netdev_dpdk_set_admin_state(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { bool up; @@ -4310,7 +4312,9 @@ netdev_dpdk_set_admin_state(struct unixctl_conn *conn, int argc, static void netdev_dpdk_detach(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct ds used_interfaces = DS_EMPTY_INITIALIZER; struct rte_eth_dev_info dev_info; @@ -4377,6 +4381,7 @@ error: static void netdev_dpdk_get_mempool_info(struct unixctl_conn *conn, int argc, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { size_t size; @@ -4889,19 +4894,22 @@ netdev_dpdk_class_init(void) ovs_thread_create("dpdk_watchdog", dpdk_watchdog, NULL); unixctl_command_register("netdev-dpdk/set-admin-state", "[netdev] up|down", 1, 2, + OVS_OUTPUT_FMT_TEXT, netdev_dpdk_set_admin_state, NULL); unixctl_command_register("netdev-dpdk/detach", "pci address of device", 1, 1, + OVS_OUTPUT_FMT_TEXT, netdev_dpdk_detach, NULL); unixctl_command_register("netdev-dpdk/get-mempool-info", - "[netdev]", 0, 1, + "[netdev]", 0, 1, OVS_OUTPUT_FMT_TEXT, netdev_dpdk_get_mempool_info, NULL); ret = rte_eth_dev_callback_register(RTE_ETH_ALL, RTE_ETH_EVENT_INTR_RESET, - dpdk_eth_event_callback, NULL); + dpdk_eth_event_callback, + NULL); if (ret != 0) { VLOG_ERR("Ethernet device callback register error: %s", rte_strerror(-ret)); diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c index fe82317d7..c235eb034 100644 --- a/lib/netdev-dummy.c +++ b/lib/netdev-dummy.c @@ -1859,7 +1859,8 @@ netdev_dummy_queue_packet(struct netdev_dummy *dummy, struct dp_packet *packet, static void netdev_dummy_receive(struct unixctl_conn *conn, - int argc, const char *argv[], void *aux OVS_UNUSED) + int argc, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct netdev_dummy *dummy_dev; struct netdev *netdev; @@ -1942,7 +1943,9 @@ netdev_dummy_set_admin_state__(struct netdev_dummy *dev, bool admin_state) static void netdev_dummy_set_admin_state(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { bool up; @@ -2008,7 +2011,9 @@ display_conn_state__(struct ds *s, const char *name, static void netdev_dummy_conn_state(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { enum dummy_netdev_conn_state state = CONN_STATE_UNKNOWN; struct ds s; @@ -2050,7 +2055,9 @@ netdev_dummy_conn_state(struct unixctl_conn *conn, int argc, static void netdev_dummy_ip4addr(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct netdev *netdev = netdev_from_name(argv[1]); @@ -2075,7 +2082,8 @@ netdev_dummy_ip4addr(struct unixctl_conn *conn, int argc OVS_UNUSED, static void netdev_dummy_ip6addr(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct netdev *netdev = netdev_from_name(argv[1]); @@ -2127,18 +2135,20 @@ netdev_dummy_register(enum dummy_level level) { unixctl_command_register("netdev-dummy/receive", "name [--qid queue_id] packet|flow [--len packet_len]", - 2, INT_MAX, netdev_dummy_receive, NULL); + 2, INT_MAX, OVS_OUTPUT_FMT_TEXT, + netdev_dummy_receive, NULL); unixctl_command_register("netdev-dummy/set-admin-state", - "[netdev] up|down", 1, 2, + "[netdev] up|down", 1, 2, OVS_OUTPUT_FMT_TEXT, netdev_dummy_set_admin_state, NULL); unixctl_command_register("netdev-dummy/conn-state", - "[netdev]", 0, 1, + "[netdev]", 0, 1, OVS_OUTPUT_FMT_TEXT, netdev_dummy_conn_state, NULL); unixctl_command_register("netdev-dummy/ip4addr", "[netdev] ipaddr/mask-prefix-len", 2, 2, - netdev_dummy_ip4addr, NULL); + OVS_OUTPUT_FMT_TEXT, netdev_dummy_ip4addr, + NULL); unixctl_command_register("netdev-dummy/ip6addr", - "[netdev] ip6addr", 2, 2, + "[netdev] ip6addr", 2, 2, OVS_OUTPUT_FMT_TEXT, netdev_dummy_ip6addr, NULL); if (level == DUMMY_OVERRIDE_ALL) { diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c index a0682c70f..95fb56333 100644 --- a/lib/netdev-native-tnl.c +++ b/lib/netdev-native-tnl.c @@ -1181,7 +1181,9 @@ netdev_geneve_build_header(const struct netdev *netdev, void netdev_tnl_egress_port_range(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { int val1, val2; diff --git a/lib/netdev-native-tnl.h b/lib/netdev-native-tnl.h index eb55dd041..e5d067d97 100644 --- a/lib/netdev-native-tnl.h +++ b/lib/netdev-native-tnl.h @@ -142,5 +142,7 @@ netdev_tnl_push_ip_header(struct dp_packet *packet, const void *header, int size, int *ip_tot_size, ovs_be32 ipv6_label); void netdev_tnl_egress_port_range(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED); + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED); #endif diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index 60caa02fb..1acd0e5bf 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -1389,6 +1389,7 @@ netdev_vport_tunnel_register(void) } unixctl_command_register("tnl/egress_port_range", "min max", 0, 2, + OVS_OUTPUT_FMT_TEXT, netdev_tnl_egress_port_range, NULL); ovsthread_once_done(&once); diff --git a/lib/odp-execute.c b/lib/odp-execute.c index eb03b57c4..230bd26a8 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -916,7 +916,8 @@ odp_actions_impl_set(const char *name) static void action_impl_set(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct ds reply = DS_EMPTY_INITIALIZER; @@ -936,7 +937,8 @@ action_impl_set(struct unixctl_conn *conn, int argc OVS_UNUSED, static void action_impl_show(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct ds reply = DS_EMPTY_INITIALIZER; @@ -949,10 +951,10 @@ static void odp_execute_unixctl_init(void) { unixctl_command_register("odp-execute/action-impl-set", "name", - 1, 1, action_impl_set, + 1, 1, OVS_OUTPUT_FMT_TEXT, action_impl_set, NULL); unixctl_command_register("odp-execute/action-impl-show", "", - 0, 0, action_impl_show, + 0, 0, OVS_OUTPUT_FMT_TEXT, action_impl_show, NULL); } diff --git a/lib/ovs-lldp.c b/lib/ovs-lldp.c index 2d13e971e..8dbc037a5 100644 --- a/lib/ovs-lldp.c +++ b/lib/ovs-lldp.c @@ -326,7 +326,8 @@ aa_print_isid_status(struct ds *ds, struct lldp *lldp) OVS_REQUIRES(mutex) static void aa_unixctl_status(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) OVS_EXCLUDED(mutex) { struct lldp *lldp; @@ -345,7 +346,8 @@ aa_unixctl_status(struct unixctl_conn *conn, int argc OVS_UNUSED, static void aa_unixctl_show_isid(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) OVS_EXCLUDED(mutex) { struct lldp *lldp; @@ -364,7 +366,8 @@ aa_unixctl_show_isid(struct unixctl_conn *conn, int argc OVS_UNUSED, static void aa_unixctl_statistics(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) OVS_EXCLUDED(mutex) { struct ds ds = DS_EMPTY_INITIALIZER; @@ -644,11 +647,12 @@ void lldp_init(void) { unixctl_command_register("autoattach/status", "[bridge]", 0, 1, - aa_unixctl_status, NULL); + OVS_OUTPUT_FMT_TEXT, aa_unixctl_status, NULL); unixctl_command_register("autoattach/show-isid", "[bridge]", 0, 1, - aa_unixctl_show_isid, NULL); + OVS_OUTPUT_FMT_TEXT, aa_unixctl_show_isid, NULL); unixctl_command_register("autoattach/statistics", "[bridge]", 0, 1, - aa_unixctl_statistics, NULL); + OVS_OUTPUT_FMT_TEXT, aa_unixctl_statistics, + NULL); } /* Returns true if 'lldp' should process packets from 'flow'. Sets diff --git a/lib/ovs-router.c b/lib/ovs-router.c index 7c04bb0e6..993bc452e 100644 --- a/lib/ovs-router.c +++ b/lib/ovs-router.c @@ -389,8 +389,8 @@ scan_ipv4_route(const char *s, ovs_be32 *addr, unsigned int *plen) } static void -ovs_router_add(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) +ovs_router_add(struct unixctl_conn *conn, int argc, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct in6_addr src6 = in6addr_any; struct in6_addr gw6 = in6addr_any; @@ -463,7 +463,8 @@ ovs_router_add(struct unixctl_conn *conn, int argc, static void ovs_router_del(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct in6_addr ip6; uint32_t mark = 0; @@ -494,7 +495,8 @@ ovs_router_del(struct unixctl_conn *conn, int argc OVS_UNUSED, static void ovs_router_show(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct ovs_router_entry *rt; struct ds ds = DS_EMPTY_INITIALIZER; @@ -534,8 +536,9 @@ ovs_router_show(struct unixctl_conn *conn, int argc OVS_UNUSED, } static void -ovs_router_lookup_cmd(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) +ovs_router_lookup_cmd(struct unixctl_conn *conn, int argc, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct in6_addr gw, src = in6addr_any; char iface[IFNAMSIZ]; @@ -605,14 +608,15 @@ ovs_router_init(void) unixctl_command_register("ovs/route/add", "ip/plen output_bridge [gw] " "[pkt_mark=mark] [src=src_ip]", - 2, 5, ovs_router_add, NULL); + 2, 5, OVS_OUTPUT_FMT_TEXT, ovs_router_add, + NULL); unixctl_command_register("ovs/route/show", "", 0, 0, - ovs_router_show, NULL); + OVS_OUTPUT_FMT_TEXT, ovs_router_show, NULL); unixctl_command_register("ovs/route/del", "ip/plen " - "[pkt_mark=mark]", 1, 2, ovs_router_del, - NULL); + "[pkt_mark=mark]", 1, 2, OVS_OUTPUT_FMT_TEXT, + ovs_router_del, NULL); unixctl_command_register("ovs/route/lookup", "ip_addr " - "[pkt_mark=mark]", 1, 2, + "[pkt_mark=mark]", 1, 2, OVS_OUTPUT_FMT_TEXT, ovs_router_lookup_cmd, NULL); ovsthread_once_done(&once); } diff --git a/lib/rstp.c b/lib/rstp.c index 2f01966f7..0f5a0e91d 100644 --- a/lib/rstp.c +++ b/lib/rstp.c @@ -129,9 +129,11 @@ static struct rstp_port *rstp_get_root_port__(const struct rstp *rstp) static rstp_identifier rstp_get_root_id__(const struct rstp *rstp) OVS_REQUIRES(rstp_mutex); static void rstp_unixctl_tcn(struct unixctl_conn *, int argc, - const char *argv[], void *aux); + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux); static void rstp_unixctl_show(struct unixctl_conn *, int argc, - const char *argv[], void *aux); + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux); const char * rstp_state_name(enum rstp_state state) @@ -248,10 +250,10 @@ void rstp_init(void) OVS_EXCLUDED(rstp_mutex) { - unixctl_command_register("rstp/tcn", "[bridge]", 0, 1, rstp_unixctl_tcn, - NULL); - unixctl_command_register("rstp/show", "[bridge]", 0, 1, rstp_unixctl_show, - NULL); + unixctl_command_register("rstp/tcn", "[bridge]", 0, 1, + OVS_OUTPUT_FMT_TEXT, rstp_unixctl_tcn, NULL); + unixctl_command_register("rstp/show", "[bridge]", 0, 1, + OVS_OUTPUT_FMT_TEXT, rstp_unixctl_show, NULL); } /* Creates and returns a new RSTP instance that initially has no ports. */ @@ -1550,8 +1552,8 @@ rstp_find(const char *name) } static void -rstp_unixctl_tcn(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) +rstp_unixctl_tcn(struct unixctl_conn *conn, int argc, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) OVS_EXCLUDED(rstp_mutex) { ovs_mutex_lock(&rstp_mutex); @@ -1651,8 +1653,8 @@ rstp_print_details(struct ds *ds, const struct rstp *rstp) } static void -rstp_unixctl_show(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) +rstp_unixctl_show(struct unixctl_conn *conn, int argc, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) OVS_EXCLUDED(rstp_mutex) { struct ds ds = DS_EMPTY_INITIALIZER; diff --git a/lib/stopwatch.c b/lib/stopwatch.c index ec567603b..70fcc2979 100644 --- a/lib/stopwatch.c +++ b/lib/stopwatch.c @@ -314,7 +314,8 @@ stopwatch_show_protected(int argc, const char *argv[], struct ds *s) static void stopwatch_show(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct ds s = DS_EMPTY_INITIALIZER; bool success; @@ -351,7 +352,8 @@ stopwatch_packet_write(struct stopwatch_packet *pkt) static void stopwatch_reset(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct stopwatch_packet *pkt = stopwatch_packet_create(OP_RESET); if (argc > 1) { @@ -488,9 +490,9 @@ static void do_init_stopwatch(void) { unixctl_command_register("stopwatch/show", "[NAME]", 0, 1, - stopwatch_show, NULL); + OVS_OUTPUT_FMT_TEXT, stopwatch_show, NULL); unixctl_command_register("stopwatch/reset", "[NAME]", 0, 1, - stopwatch_reset, NULL); + OVS_OUTPUT_FMT_TEXT, stopwatch_reset, NULL); guarded_list_init(&stopwatch_commands); latch_init(&stopwatch_latch); stopwatch_thread_id = ovs_thread_create( diff --git a/lib/stp.c b/lib/stp.c index f37337992..0d1b6b053 100644 --- a/lib/stp.c +++ b/lib/stp.c @@ -233,9 +233,11 @@ static bool stp_timer_expired(struct stp_timer *, int elapsed, int timeout); static void stp_send_bpdu(struct stp_port *, const void *, size_t) OVS_REQUIRES(mutex); static void stp_unixctl_tcn(struct unixctl_conn *, int argc, - const char *argv[], void *aux); + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux); static void stp_unixctl_show(struct unixctl_conn *, int argc, - const char *argv[], void *aux); + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux); void stp_init(void) @@ -249,10 +251,10 @@ stp_init(void) * the call back function, but for now this is what we have. */ ovs_mutex_init_recursive(&mutex); - unixctl_command_register("stp/tcn", "[bridge]", 0, 1, stp_unixctl_tcn, - NULL); + unixctl_command_register("stp/tcn", "[bridge]", 0, 1, + OVS_OUTPUT_FMT_TEXT, stp_unixctl_tcn, NULL); unixctl_command_register("stp/show", "[bridge]", 0, 1, - stp_unixctl_show, NULL); + OVS_OUTPUT_FMT_TEXT, stp_unixctl_show, NULL); ovsthread_once_done(&once); } } @@ -1611,8 +1613,8 @@ stp_find(const char *name) OVS_REQUIRES(mutex) } static void -stp_unixctl_tcn(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) +stp_unixctl_tcn(struct unixctl_conn *conn, int argc, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { ovs_mutex_lock(&mutex); if (argc > 1) { @@ -1702,8 +1704,8 @@ stp_print_details(struct ds *ds, const struct stp *stp) } static void -stp_unixctl_show(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) +stp_unixctl_show(struct unixctl_conn *conn, int argc, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; diff --git a/lib/timeval.c b/lib/timeval.c index 193c7bab1..5efe9da20 100644 --- a/lib/timeval.c +++ b/lib/timeval.c @@ -765,8 +765,9 @@ get_cpu_usage(void) * advancing, except due to later calls to "time/warp". */ static void timeval_stop_cb(struct unixctl_conn *conn, - int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, - void *aux OVS_UNUSED) + int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { ovs_mutex_lock(&monotonic_clock.mutex); atomic_store_relaxed(&monotonic_clock.slow_path, true); @@ -789,7 +790,8 @@ timeval_stop_cb(struct unixctl_conn *conn, * Does not affect wall clock readings. */ static void timeval_warp_cb(struct unixctl_conn *conn, - int argc OVS_UNUSED, const char *argv[], void *aux OVS_UNUSED) + int argc OVS_UNUSED, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { long long int total_warp = argc > 2 ? atoll(argv[1]) : 0; long long int msecs = argc > 2 ? atoll(argv[2]) : atoll(argv[1]); @@ -818,9 +820,10 @@ void timeval_dummy_register(void) { timewarp_enabled = true; - unixctl_command_register("time/stop", "", 0, 0, timeval_stop_cb, NULL); + unixctl_command_register("time/stop", "", 0, 0, OVS_OUTPUT_FMT_TEXT, + timeval_stop_cb, NULL); unixctl_command_register("time/warp", "[large_msecs] msecs", 1, 2, - timeval_warp_cb, NULL); + OVS_OUTPUT_FMT_TEXT, timeval_warp_cb, NULL); } diff --git a/lib/tnl-neigh-cache.c b/lib/tnl-neigh-cache.c index bdff1debc..b8aeee29a 100644 --- a/lib/tnl-neigh-cache.c +++ b/lib/tnl-neigh-cache.c @@ -273,7 +273,9 @@ tnl_neigh_flush(const char br_name[IFNAMSIZ]) static void tnl_neigh_cache_flush(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct tnl_neigh_entry *neigh; bool changed = false; @@ -291,8 +293,9 @@ tnl_neigh_cache_flush(struct unixctl_conn *conn, int argc OVS_UNUSED, } static void -tnl_neigh_cache_aging(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) +tnl_neigh_cache_aging(struct unixctl_conn *conn, int argc, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { long long int new_exp, curr_exp; struct tnl_neigh_entry *neigh; @@ -348,7 +351,8 @@ lookup_any(const char *host_name, struct in6_addr *address) static void tnl_neigh_cache_add(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { const char *br_name = argv[1]; struct eth_addr mac; @@ -370,7 +374,9 @@ tnl_neigh_cache_add(struct unixctl_conn *conn, int argc OVS_UNUSED, static void tnl_neigh_cache_show(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; struct tnl_neigh_entry *neigh; @@ -404,20 +410,23 @@ void tnl_neigh_cache_init(void) { atomic_init(&neigh_aging, NEIGH_ENTRY_DEFAULT_IDLE_TIME_MS); - unixctl_command_register("tnl/arp/show", "", 0, 0, + unixctl_command_register("tnl/arp/show", "", 0, 0, OVS_OUTPUT_FMT_TEXT, tnl_neigh_cache_show, NULL); unixctl_command_register("tnl/arp/set", "BRIDGE IP MAC", 3, 3, - tnl_neigh_cache_add, NULL); + OVS_OUTPUT_FMT_TEXT, tnl_neigh_cache_add, NULL); unixctl_command_register("tnl/arp/flush", "", 0, 0, - tnl_neigh_cache_flush, NULL); + OVS_OUTPUT_FMT_TEXT, tnl_neigh_cache_flush, + NULL); unixctl_command_register("tnl/arp/aging", "[SECS]", 0, 1, - tnl_neigh_cache_aging, NULL); + OVS_OUTPUT_FMT_TEXT, tnl_neigh_cache_aging, + NULL); unixctl_command_register("tnl/neigh/show", "", 0, 0, - tnl_neigh_cache_show, NULL); + OVS_OUTPUT_FMT_TEXT, tnl_neigh_cache_show, NULL); unixctl_command_register("tnl/neigh/set", "BRIDGE IP MAC", 3, 3, - tnl_neigh_cache_add, NULL); - unixctl_command_register("tnl/neigh/flush", "", 0, 0, + OVS_OUTPUT_FMT_TEXT, tnl_neigh_cache_add, NULL); + unixctl_command_register("tnl/neigh/flush", "", 0, 0, OVS_OUTPUT_FMT_TEXT, tnl_neigh_cache_flush, NULL); unixctl_command_register("tnl/neigh/aging", "[SECS]", 0, 1, - tnl_neigh_cache_aging, NULL); + OVS_OUTPUT_FMT_TEXT, tnl_neigh_cache_aging, + NULL); } diff --git a/lib/tnl-ports.c b/lib/tnl-ports.c index f16409a0b..9e3d7064a 100644 --- a/lib/tnl-ports.c +++ b/lib/tnl-ports.c @@ -354,7 +354,8 @@ tnl_port_show_v(struct ds *ds) static void tnl_port_show(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; struct tnl_port *p; @@ -523,5 +524,6 @@ tnl_port_map_init(void) classifier_init(&cls, flow_segment_u64s); ovs_list_init(&addr_list); ovs_list_init(&port_list); - unixctl_command_register("tnl/ports/show", "-v", 0, 1, tnl_port_show, NULL); + unixctl_command_register("tnl/ports/show", "-v", 0, 1, + OVS_OUTPUT_FMT_TEXT, tnl_port_show, NULL); } diff --git a/lib/unixctl.c b/lib/unixctl.c index 5de59f339..c82a5e92d 100644 --- a/lib/unixctl.c +++ b/lib/unixctl.c @@ -67,7 +67,8 @@ static const char *rpc_marker = "execute/v1"; static void unixctl_list_commands(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; const struct shash_node **nodes = shash_sort(&commands); @@ -91,31 +92,12 @@ unixctl_list_commands(struct unixctl_conn *conn, int argc OVS_UNUSED, static void unixctl_version(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { unixctl_command_reply(conn, ovs_get_program_version()); } -/* Registers a unixctl command with the given 'name'. 'usage' describes the - * arguments to the command; it is used only for presentation to the user in - * "list-commands" output. (If 'usage' is NULL, then the command is hidden.) - * - * 'cb' is called when the command is received. It is passed an array - * containing the command name and arguments, plus a copy of 'aux'. Normally - * 'cb' should reply by calling unixctl_command_reply() or - * unixctl_command_reply_error() before it returns, but if the command cannot - * be handled immediately then it can defer the reply until later. A given - * connection can only process a single request at a time, so a reply must be - * made eventually to avoid blocking that connection. */ -void -unixctl_command_register(const char *name, const char *usage, - int min_args, int max_args, - unixctl_cb_func *cb, void *aux) -{ - unixctl_command_register_fmt(name, usage, min_args, max_args, - OVS_OUTPUT_FMT_TEXT, cb, aux); -} - /* Registers a unixctl command with the given 'name'. 'usage' describes the * arguments to the command; it is used only for presentation to the user in * "list-commands" output. (If 'usage' is NULL, then the command is hidden.) @@ -130,9 +112,9 @@ unixctl_command_register(const char *name, const char *usage, * connection can only process a single request at a time, so a reply must be * made eventually to avoid blocking that connection. */ void -unixctl_command_register_fmt(const char *name, const char *usage, - int min_args, int max_args, int output_fmts, - unixctl_cb_func *cb, void *aux) +unixctl_command_register(const char *name, const char *usage, + int min_args, int max_args, int output_fmts, + unixctl_cb_func *cb, void *aux) { struct unixctl_command *command; struct unixctl_command *lookup = shash_find_data(&commands, name); @@ -290,9 +272,10 @@ unixctl_server_create(const char *path, struct unixctl_server **serverp) return error; } - unixctl_command_register("list-commands", "", 0, 0, unixctl_list_commands, - NULL); - unixctl_command_register("version", "", 0, 0, unixctl_version, NULL); + unixctl_command_register("list-commands", "", 0, 0, OVS_OUTPUT_FMT_TEXT, + unixctl_list_commands, NULL); + unixctl_command_register("version", "", 0, 0, OVS_OUTPUT_FMT_TEXT, + unixctl_version, NULL); struct unixctl_server *server = xmalloc(sizeof *server); server->listener = listener; @@ -390,14 +373,6 @@ process_command(struct unixctl_conn *conn, struct jsonrpc_msg *request) goto error; } - /* FIXME: Remove this check once output format will be passed to the - * command handler below. */ - if (fmt != OVS_OUTPUT_FMT_TEXT) { - error = xasprintf("output format \"%s\" has not been implemented yet", - ovs_output_fmt_to_string(fmt)); - goto error; - } - /* Extract command args. */ svec_add(&argv, method); for (size_t i = args_offset; i < params->n; i++) { @@ -405,10 +380,7 @@ process_command(struct unixctl_conn *conn, struct jsonrpc_msg *request) } svec_terminate(&argv); - /* FIXME: Output format will be passed as 'fmt' to the command in later - * patch. */ - command->cb(conn, argv.n, (const char **) argv.names, /* fmt, */ - command->aux); + command->cb(conn, argv.n, (const char **) argv.names, fmt, command->aux); svec_destroy(&argv); diff --git a/lib/unixctl.h b/lib/unixctl.h index 896ecb062..4b8193d9d 100644 --- a/lib/unixctl.h +++ b/lib/unixctl.h @@ -44,20 +44,12 @@ int unixctl_client_transact(struct jsonrpc *client, /* Command registration. */ struct unixctl_conn; -/* FIXME: Output format will be passed as 'fmt' to the command in later patch. - */ typedef void unixctl_cb_func(struct unixctl_conn *, int argc, const char *argv[], - /* enum ovs_output_fmt fmt, */ void *aux); -/* FIXME: unixctl_command_register() will be replaced with - * unixctl_command_register_fmt() in a later patch of this series. It - * is kept temporarily to reduce the amount of changes in this patch. */ + enum ovs_output_fmt fmt, void *aux); void unixctl_command_register(const char *name, const char *usage, - int min_args, int max_args, + int min_args, int max_args, int output_fmts, unixctl_cb_func *cb, void *aux); -void unixctl_command_register_fmt(const char *name, const char *usage, - int min_args, int max_args, int output_fmts, - unixctl_cb_func *cb, void *aux); void unixctl_command_reply_error(struct unixctl_conn *, const char *error); void unixctl_command_reply(struct unixctl_conn *, const char *body); void unixctl_command_reply_json(struct unixctl_conn *, diff --git a/lib/vlog.c b/lib/vlog.c index b2653142f..a8ab97b1b 100644 --- a/lib/vlog.c +++ b/lib/vlog.c @@ -689,6 +689,7 @@ vlog_facility_exists(const char* facility, int *value) static void vlog_unixctl_set(struct unixctl_conn *conn, int argc, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { int i; @@ -710,7 +711,8 @@ vlog_unixctl_set(struct unixctl_conn *conn, int argc, const char *argv[], static void vlog_unixctl_list(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { char *msg = vlog_get_levels(); unixctl_command_reply(conn, msg); @@ -719,7 +721,9 @@ vlog_unixctl_list(struct unixctl_conn *conn, int argc OVS_UNUSED, static void vlog_unixctl_list_pattern(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { char *msg; @@ -730,7 +734,9 @@ vlog_unixctl_list_pattern(struct unixctl_conn *conn, int argc OVS_UNUSED, static void vlog_unixctl_reopen(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { bool has_log_file; @@ -752,7 +758,9 @@ vlog_unixctl_reopen(struct unixctl_conn *conn, int argc OVS_UNUSED, static void vlog_unixctl_close(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { ovs_mutex_lock(&log_file_mutex); if (log_fd >= 0) { @@ -811,14 +819,18 @@ set_rate_limits(struct unixctl_conn *conn, int argc, static void vlog_enable_rate_limit(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { set_rate_limits(conn, argc, argv, true); } static void vlog_disable_rate_limit(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { set_rate_limits(conn, argc, argv, false); } @@ -860,20 +872,24 @@ vlog_init(void) free(s); } - unixctl_command_register( - "vlog/set", "{spec | PATTERN:destination:pattern}", - 0, INT_MAX, vlog_unixctl_set, NULL); - unixctl_command_register("vlog/list", "", 0, 0, vlog_unixctl_list, - NULL); + unixctl_command_register("vlog/set", + "{spec | PATTERN:destination:pattern}", + 0, INT_MAX, OVS_OUTPUT_FMT_TEXT, + vlog_unixctl_set, NULL); + unixctl_command_register("vlog/list", "", 0, 0, OVS_OUTPUT_FMT_TEXT, + vlog_unixctl_list, NULL); unixctl_command_register("vlog/list-pattern", "", 0, 0, + OVS_OUTPUT_FMT_TEXT, vlog_unixctl_list_pattern, NULL); unixctl_command_register("vlog/enable-rate-limit", "[module]...", - 0, INT_MAX, vlog_enable_rate_limit, NULL); + 0, INT_MAX, OVS_OUTPUT_FMT_TEXT, + vlog_enable_rate_limit, NULL); unixctl_command_register("vlog/disable-rate-limit", "[module]...", - 0, INT_MAX, vlog_disable_rate_limit, NULL); - unixctl_command_register("vlog/reopen", "", 0, 0, + 0, INT_MAX, OVS_OUTPUT_FMT_TEXT, + vlog_disable_rate_limit, NULL); + unixctl_command_register("vlog/reopen", "", 0, 0, OVS_OUTPUT_FMT_TEXT, vlog_unixctl_reopen, NULL); - unixctl_command_register("vlog/close", "", 0, 0, + unixctl_command_register("vlog/close", "", 0, 0, OVS_OUTPUT_FMT_TEXT, vlog_unixctl_close, NULL); ovs_rwlock_rdlock(&pattern_rwlock); diff --git a/ofproto/bond.c b/ofproto/bond.c index cfdf44f85..fcab5f932 100644 --- a/ofproto/bond.c +++ b/ofproto/bond.c @@ -1472,6 +1472,7 @@ bond_lookup_member(struct bond *bond, const char *member_name) static void bond_unixctl_list(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; @@ -1617,6 +1618,7 @@ bond_print_details(struct ds *ds, const struct bond *bond) static void bond_unixctl_show(struct unixctl_conn *conn, int argc, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; @@ -1648,6 +1650,7 @@ out: static void bond_unixctl_migrate(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { const char *bond_s = argv[1]; @@ -1701,6 +1704,7 @@ out: static void bond_unixctl_set_active_member(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { const char *bond_s = argv[1]; @@ -1773,6 +1777,7 @@ out: static void bond_unixctl_enable_member(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { enable_member(conn, argv, true); @@ -1781,6 +1786,7 @@ bond_unixctl_enable_member(struct unixctl_conn *conn, static void bond_unixctl_disable_member(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { enable_member(conn, argv, false); @@ -1788,6 +1794,7 @@ bond_unixctl_disable_member(struct unixctl_conn *conn, static void bond_unixctl_hash(struct unixctl_conn *conn, int argc, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { const char *mac_s = argv[1]; @@ -1831,27 +1838,34 @@ bond_unixctl_hash(struct unixctl_conn *conn, int argc, const char *argv[], void bond_init(void) { - unixctl_command_register("bond/list", "", 0, 0, bond_unixctl_list, NULL); - unixctl_command_register("bond/show", "[port]", 0, 1, bond_unixctl_show, - NULL); + unixctl_command_register("bond/list", "", 0, 0, OVS_OUTPUT_FMT_TEXT, + bond_unixctl_list, NULL); + unixctl_command_register("bond/show", "[port]", 0, 1, OVS_OUTPUT_FMT_TEXT, + bond_unixctl_show, NULL); unixctl_command_register("bond/migrate", "port hash member", 3, 3, - bond_unixctl_migrate, NULL); + OVS_OUTPUT_FMT_TEXT, bond_unixctl_migrate, NULL); unixctl_command_register("bond/set-active-member", "port member", 2, 2, + OVS_OUTPUT_FMT_TEXT, bond_unixctl_set_active_member, NULL); unixctl_command_register("bond/enable-member", "port member", 2, 2, - bond_unixctl_enable_member, NULL); + OVS_OUTPUT_FMT_TEXT, bond_unixctl_enable_member, + NULL); unixctl_command_register("bond/disable-member", "port member", 2, 2, - bond_unixctl_disable_member, NULL); + OVS_OUTPUT_FMT_TEXT, bond_unixctl_disable_member, + NULL); unixctl_command_register("bond/hash", "mac [vlan] [basis]", 1, 3, - bond_unixctl_hash, NULL); + OVS_OUTPUT_FMT_TEXT, bond_unixctl_hash, NULL); /* Backward-compatibility command names. */ unixctl_command_register("bond/set-active-slave", NULL, 2, 2, + OVS_OUTPUT_FMT_TEXT, bond_unixctl_set_active_member, NULL); unixctl_command_register("bond/enable-slave", NULL, 2, 2, - bond_unixctl_enable_member, NULL); + OVS_OUTPUT_FMT_TEXT, bond_unixctl_enable_member, + NULL); unixctl_command_register("bond/disable-slave", NULL, 2, 2, - bond_unixctl_disable_member, NULL); + OVS_OUTPUT_FMT_TEXT, bond_unixctl_disable_member, + NULL); } static void diff --git a/ofproto/ofproto-dpif-trace.c b/ofproto/ofproto-dpif-trace.c index 527e2f17e..da31ff55b 100644 --- a/ofproto/ofproto-dpif-trace.c +++ b/ofproto/ofproto-dpif-trace.c @@ -471,6 +471,7 @@ free_ct_states(struct ovs_list *ct_states) static void ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct ofproto_dpif *ofproto; @@ -500,7 +501,9 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[], static void ofproto_unixctl_trace_actions(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { enum ofputil_protocol usable_protocols; struct ofproto_dpif *ofproto; @@ -870,12 +873,13 @@ ofproto_dpif_trace_init(void) unixctl_command_register( "ofproto/trace", "{[dp_name] odp_flow | bridge br_flow} [OPTIONS...] " - "[-generate|packet]", 1, INT_MAX, ofproto_unixctl_trace, NULL); + "[-generate|packet]", 1, INT_MAX, OVS_OUTPUT_FMT_TEXT, + ofproto_unixctl_trace, NULL); unixctl_command_register( "ofproto/trace-packet-out", "[-consistent] {[dp_name] odp_flow | bridge br_flow} [OPTIONS...] " "[-generate|packet] actions", - 2, INT_MAX, ofproto_unixctl_trace_actions, NULL); + 2, INT_MAX, OVS_OUTPUT_FMT_TEXT, ofproto_unixctl_trace_actions, NULL); } void diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c index cc10f57b5..4bd0ce870 100644 --- a/ofproto/ofproto-dpif-upcall.c +++ b/ofproto/ofproto-dpif-upcall.c @@ -354,25 +354,38 @@ static void revalidator_pause(struct revalidator *); static void revalidator_sweep(struct revalidator *); static void revalidator_purge(struct revalidator *); static void upcall_unixctl_show(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux); + const char *argv[], + enum ovs_output_fmt fmt, + void *aux); static void upcall_unixctl_disable_megaflows(struct unixctl_conn *, int argc, - const char *argv[], void *aux); + const char *argv[], + enum ovs_output_fmt fmt, + void *aux); static void upcall_unixctl_enable_megaflows(struct unixctl_conn *, int argc, - const char *argv[], void *aux); + const char *argv[], + enum ovs_output_fmt fmt, + void *aux); static void upcall_unixctl_disable_ufid(struct unixctl_conn *, int argc, - const char *argv[], void *aux); + const char *argv[], + enum ovs_output_fmt fmt, void *aux); static void upcall_unixctl_enable_ufid(struct unixctl_conn *, int argc, - const char *argv[], void *aux); + const char *argv[], + enum ovs_output_fmt fmt, void *aux); static void upcall_unixctl_set_flow_limit(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux); + const char *argv[], + enum ovs_output_fmt fmt, void *aux); static void upcall_unixctl_dump_wait(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux); + const char *argv[], + enum ovs_output_fmt fmt, void *aux); static void upcall_unixctl_purge(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux); + const char *argv[], enum ovs_output_fmt fmt, + void *aux); static void upcall_unixctl_pause(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux); + const char *argv[], enum ovs_output_fmt fmt, + void *aux); static void upcall_unixctl_resume(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux); + const char *argv[], enum ovs_output_fmt fmt, + void *aux); static struct udpif_key *ukey_create_from_upcall(struct upcall *, struct flow_wildcards *); @@ -430,26 +443,36 @@ udpif_init(void) { static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; if (ovsthread_once_start(&once)) { - unixctl_command_register("upcall/show", "", 0, 0, upcall_unixctl_show, + unixctl_command_register("upcall/show", "", 0, 0, OVS_OUTPUT_FMT_TEXT, + upcall_unixctl_show, NULL); unixctl_command_register("upcall/disable-megaflows", "", 0, 0, + OVS_OUTPUT_FMT_TEXT, upcall_unixctl_disable_megaflows, NULL); unixctl_command_register("upcall/enable-megaflows", "", 0, 0, + OVS_OUTPUT_FMT_TEXT, upcall_unixctl_enable_megaflows, NULL); unixctl_command_register("upcall/disable-ufid", "", 0, 0, + OVS_OUTPUT_FMT_TEXT, upcall_unixctl_disable_ufid, NULL); unixctl_command_register("upcall/enable-ufid", "", 0, 0, + OVS_OUTPUT_FMT_TEXT, upcall_unixctl_enable_ufid, NULL); unixctl_command_register("upcall/set-flow-limit", "flow-limit-number", - 1, 1, upcall_unixctl_set_flow_limit, NULL); + 1, 1, OVS_OUTPUT_FMT_TEXT, + upcall_unixctl_set_flow_limit, NULL); unixctl_command_register("revalidator/wait", "", 0, 0, + OVS_OUTPUT_FMT_TEXT, upcall_unixctl_dump_wait, NULL); unixctl_command_register("revalidator/purge", "", 0, 0, - upcall_unixctl_purge, NULL); + OVS_OUTPUT_FMT_TEXT, upcall_unixctl_purge, + NULL); unixctl_command_register("revalidator/pause", NULL, 0, 0, - upcall_unixctl_pause, NULL); + OVS_OUTPUT_FMT_TEXT, upcall_unixctl_pause, + NULL); unixctl_command_register("revalidator/resume", NULL, 0, 0, - upcall_unixctl_resume, NULL); + OVS_OUTPUT_FMT_TEXT, upcall_unixctl_resume, + NULL); ovsthread_once_done(&once); } } @@ -3072,7 +3095,9 @@ dp_purge_cb(void *aux, unsigned pmd_id) static void upcall_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; uint64_t n_offloaded_flows; @@ -3126,6 +3151,7 @@ static void upcall_unixctl_disable_megaflows(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { atomic_store_relaxed(&enable_megaflows, false); @@ -3141,6 +3167,7 @@ static void upcall_unixctl_enable_megaflows(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { atomic_store_relaxed(&enable_megaflows, true); @@ -3154,7 +3181,9 @@ upcall_unixctl_enable_megaflows(struct unixctl_conn *conn, * documented in the man page. */ static void upcall_unixctl_disable_ufid(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { atomic_store_relaxed(&enable_ufid, false); unixctl_command_reply(conn, "Datapath dumping tersely using UFID disabled"); @@ -3166,7 +3195,9 @@ upcall_unixctl_disable_ufid(struct unixctl_conn *conn, int argc OVS_UNUSED, * in the man page. */ static void upcall_unixctl_enable_ufid(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { atomic_store_relaxed(&enable_ufid, true); unixctl_command_reply(conn, "Datapath dumping tersely using UFID enabled " @@ -3181,6 +3212,7 @@ static void upcall_unixctl_set_flow_limit(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; @@ -3199,6 +3231,7 @@ static void upcall_unixctl_dump_wait(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { if (ovs_list_is_singleton(&all_udpifs)) { @@ -3217,7 +3250,9 @@ upcall_unixctl_dump_wait(struct unixctl_conn *conn, static void upcall_unixctl_purge(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct udpif *udpif; @@ -3241,7 +3276,9 @@ upcall_unixctl_purge(struct unixctl_conn *conn, int argc OVS_UNUSED, static void upcall_unixctl_pause(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct udpif *udpif; @@ -3253,7 +3290,9 @@ upcall_unixctl_pause(struct unixctl_conn *conn, int argc OVS_UNUSED, static void upcall_unixctl_resume(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct udpif *udpif; diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index ba5706f6a..516ec6280 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -5832,7 +5832,9 @@ ofproto_dpif_lookup_by_uuid(const struct uuid *uuid) static void ofproto_unixctl_fdb_flush(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct ofproto_dpif *ofproto; @@ -5859,7 +5861,9 @@ ofproto_unixctl_fdb_flush(struct unixctl_conn *conn, int argc, static void ofproto_unixctl_mcast_snooping_flush(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct ofproto_dpif *ofproto; @@ -5897,7 +5901,9 @@ ofbundle_get_a_port(const struct ofbundle *bundle) static void ofproto_unixctl_fdb_show(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; const struct ofproto_dpif *ofproto; @@ -5933,7 +5939,9 @@ ofproto_unixctl_fdb_show(struct unixctl_conn *conn, int argc OVS_UNUSED, static void ofproto_unixctl_fdb_add(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { const struct ofproto_dpif *ofproto; const struct mac_entry *mac_entry; @@ -5998,7 +6006,9 @@ ofproto_unixctl_fdb_add(struct unixctl_conn *conn, int argc OVS_UNUSED, static void ofproto_unixctl_fdb_delete(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { const struct ofproto_dpif *ofproto; const char *br_name = argv[1]; @@ -6024,7 +6034,9 @@ ofproto_unixctl_fdb_delete(struct unixctl_conn *conn, int argc OVS_UNUSED, static void ofproto_unixctl_fdb_stats_clear(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct ofproto_dpif *ofproto; @@ -6051,7 +6063,9 @@ ofproto_unixctl_fdb_stats_clear(struct unixctl_conn *conn, int argc, static void ofproto_unixctl_fdb_stats_show(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; const struct ofproto_dpif *ofproto; @@ -6092,6 +6106,7 @@ static void ofproto_unixctl_mcast_snooping_show(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; @@ -6164,6 +6179,7 @@ get_ofprotos(struct shash *ofproto_shash) static void ofproto_unixctl_dpif_dump_dps(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; @@ -6410,7 +6426,9 @@ dpif_show_backer(const struct dpif_backer *backer, struct ds *ds) static void ofproto_unixctl_dpif_show(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; const struct shash_node **backers; @@ -6429,6 +6447,7 @@ ofproto_unixctl_dpif_show(struct unixctl_conn *conn, int argc OVS_UNUSED, static void ofproto_unixctl_dpif_dump_flows(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { const struct ofproto_dpif *ofproto; @@ -6523,6 +6542,7 @@ ofproto_unixctl_dpif_dump_flows(struct unixctl_conn *conn, static void ofproto_unixctl_dpif_show_dp_features(struct unixctl_conn *conn, int argc, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; @@ -6542,6 +6562,7 @@ ofproto_unixctl_dpif_show_dp_features(struct unixctl_conn *conn, static void ofproto_unixctl_dpif_set_dp_features(struct unixctl_conn *conn, int argc, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; @@ -6578,31 +6599,40 @@ ofproto_unixctl_init(void) registered = true; unixctl_command_register("fdb/add", "bridge port vlan mac", 4, 4, - ofproto_unixctl_fdb_add, NULL); + OVS_OUTPUT_FMT_TEXT, ofproto_unixctl_fdb_add, + NULL); unixctl_command_register("fdb/del", "bridge vlan mac", 3, 3, - ofproto_unixctl_fdb_delete, NULL); + OVS_OUTPUT_FMT_TEXT, ofproto_unixctl_fdb_delete, + NULL); unixctl_command_register("fdb/flush", "[bridge]", 0, 1, - ofproto_unixctl_fdb_flush, NULL); - unixctl_command_register("fdb/show", "bridge", 1, 1, + OVS_OUTPUT_FMT_TEXT, ofproto_unixctl_fdb_flush, + NULL); + unixctl_command_register("fdb/show", "bridge", 1, 1, OVS_OUTPUT_FMT_TEXT, ofproto_unixctl_fdb_show, NULL); unixctl_command_register("fdb/stats-clear", "[bridge]", 0, 1, + OVS_OUTPUT_FMT_TEXT, ofproto_unixctl_fdb_stats_clear, NULL); unixctl_command_register("fdb/stats-show", "bridge", 1, 1, + OVS_OUTPUT_FMT_TEXT, ofproto_unixctl_fdb_stats_show, NULL); unixctl_command_register("mdb/flush", "[bridge]", 0, 1, + OVS_OUTPUT_FMT_TEXT, ofproto_unixctl_mcast_snooping_flush, NULL); - unixctl_command_register("mdb/show", "bridge", 1, 1, + unixctl_command_register("mdb/show", "bridge", 1, 1, OVS_OUTPUT_FMT_TEXT, ofproto_unixctl_mcast_snooping_show, NULL); - unixctl_command_register("dpif/dump-dps", "", 0, 0, + unixctl_command_register("dpif/dump-dps", "", 0, 0, OVS_OUTPUT_FMT_TEXT, ofproto_unixctl_dpif_dump_dps, NULL); - unixctl_command_register("dpif/show", "", 0, 0, ofproto_unixctl_dpif_show, - NULL); + unixctl_command_register("dpif/show", "", 0, 0, OVS_OUTPUT_FMT_TEXT, + ofproto_unixctl_dpif_show, NULL); unixctl_command_register("dpif/show-dp-features", "bridge", 1, 1, + OVS_OUTPUT_FMT_TEXT, ofproto_unixctl_dpif_show_dp_features, NULL); unixctl_command_register("dpif/dump-flows", "[-m] [--names | --no-names] bridge", 1, INT_MAX, + OVS_OUTPUT_FMT_TEXT, ofproto_unixctl_dpif_dump_flows, NULL); - unixctl_command_register("dpif/set-dp-features", "bridge", 1, 3 , + unixctl_command_register("dpif/set-dp-features", "bridge", 1, 3, + OVS_OUTPUT_FMT_TEXT, ofproto_unixctl_dpif_set_dp_features, NULL); } diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index e78c80d11..3eb880f84 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -6366,7 +6366,7 @@ handle_flow_mod__(struct ofproto *ofproto, const struct ofputil_flow_mod *fm, error = ofproto_flow_mod_start(ofproto, &ofm); if (!error) { ofproto_bump_tables_version(ofproto); - error = ofproto_flow_mod_finish(ofproto, &ofm, req); + error = ofproto_flow_mod_finish(ofproto, &ofm, req); ofmonitor_flush(ofproto->connmgr); } ovs_mutex_unlock(&ofproto_mutex); @@ -8437,7 +8437,7 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags) /* Send error referring to the original message. */ ofconn_send_error(ofconn, be->msg, error); error = OFPERR_OFPBFC_MSG_FAILED; - + /* 2. Revert. Undo all the changes made above. */ LIST_FOR_EACH_REVERSE_CONTINUE(be, node, &bundle->msg_list) { if (be->type == OFPTYPE_FLOW_MOD) { @@ -9453,7 +9453,9 @@ ofproto_lookup(const char *name) static void ofproto_unixctl_list(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct ofproto *ofproto; struct ds results; @@ -9475,7 +9477,7 @@ ofproto_unixctl_init(void) } registered = true; - unixctl_command_register("ofproto/list", "", 0, 0, + unixctl_command_register("ofproto/list", "", 0, 0, OVS_OUTPUT_FMT_TEXT, ofproto_unixctl_list, NULL); } diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c index 3455ed233..a17414833 100644 --- a/ofproto/tunnel.c +++ b/ofproto/tunnel.c @@ -141,7 +141,7 @@ ofproto_tunnel_init(void) if (ovsthread_once_start(&once)) { fat_rwlock_init(&rwlock); unixctl_command_register("ofproto/list-tunnels", "", 0, 0, - tnl_unixctl_list, NULL); + OVS_OUTPUT_FMT_TEXT, tnl_unixctl_list, NULL); ovsthread_once_done(&once); } } @@ -756,7 +756,7 @@ tnl_port_build_header(const struct ofport_dpif *ofport, static void tnl_unixctl_list(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, - void *aux OVS_UNUSED) + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct ds reply = DS_EMPTY_INITIALIZER; diff --git a/ovsdb/file.c b/ovsdb/file.c index 8bd1d4af3..9b60785e2 100644 --- a/ovsdb/file.c +++ b/ovsdb/file.c @@ -62,6 +62,7 @@ static bool use_column_diff = true; static void ovsdb_file_column_diff_enable(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *arg OVS_UNUSED) { use_column_diff = true; @@ -76,7 +77,8 @@ ovsdb_file_column_diff_disable(void) } use_column_diff = false; unixctl_command_register("ovsdb/file/column-diff-enable", "", - 0, 0, ovsdb_file_column_diff_enable, NULL); + 0, 0, OVS_OUTPUT_FMT_TEXT, + ovsdb_file_column_diff_enable, NULL); } static struct ovsdb_error * diff --git a/ovsdb/ovsdb-client.c b/ovsdb/ovsdb-client.c index 7249805ba..50de20ee1 100644 --- a/ovsdb/ovsdb-client.c +++ b/ovsdb/ovsdb-client.c @@ -1253,7 +1253,8 @@ parse_monitor_columns(char *arg, const char *server, const char *database, static void ovsdb_client_exit(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *exiting_) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *exiting_) { bool *exiting = exiting_; *exiting = true; @@ -1262,7 +1263,8 @@ ovsdb_client_exit(struct unixctl_conn *conn, int argc OVS_UNUSED, static void ovsdb_client_block(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *blocked_) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *blocked_) { bool *blocked = blocked_; @@ -1276,7 +1278,8 @@ ovsdb_client_block(struct unixctl_conn *conn, int argc OVS_UNUSED, static void ovsdb_client_unblock(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *blocked_) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *blocked_) { bool *blocked = blocked_; @@ -1290,7 +1293,8 @@ ovsdb_client_unblock(struct unixctl_conn *conn, int argc OVS_UNUSED, static void ovsdb_client_cond_change(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *rpc_) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *rpc_) { struct jsonrpc *rpc = rpc_; struct json *monitor_cond_update_requests = json_object_create(); @@ -1404,13 +1408,16 @@ do_monitor__(struct jsonrpc *rpc, const char *database, ovs_fatal(error, "failed to create unixctl server"); } - unixctl_command_register("exit", "", 0, 0, + unixctl_command_register("exit", "", 0, 0, OVS_OUTPUT_FMT_TEXT, ovsdb_client_exit, &exiting); unixctl_command_register("ovsdb-client/block", "", 0, 0, - ovsdb_client_block, &blocked); + OVS_OUTPUT_FMT_TEXT, ovsdb_client_block, + &blocked); unixctl_command_register("ovsdb-client/unblock", "", 0, 0, - ovsdb_client_unblock, &blocked); + OVS_OUTPUT_FMT_TEXT, ovsdb_client_unblock, + &blocked); unixctl_command_register("ovsdb-client/cond_change", "TABLE COND", 2, 2, + OVS_OUTPUT_FMT_TEXT, ovsdb_client_cond_change, rpc); } else { unixctl = NULL; @@ -2244,7 +2251,9 @@ create_lock_request(struct ovsdb_client_lock_req *lock_req) static void ovsdb_client_lock(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *lock_req_) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *lock_req_) { struct ovsdb_client_lock_req *lock_req = lock_req_; lock_req_init(lock_req, "lock", argv[1]); @@ -2253,7 +2262,9 @@ ovsdb_client_lock(struct unixctl_conn *conn, int argc OVS_UNUSED, static void ovsdb_client_unlock(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *lock_req_) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *lock_req_) { struct ovsdb_client_lock_req *lock_req = lock_req_; lock_req_init(lock_req, "unlock", argv[1]); @@ -2262,7 +2273,8 @@ ovsdb_client_unlock(struct unixctl_conn *conn, int argc OVS_UNUSED, static void ovsdb_client_steal(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *lock_req_) + const char *argv[], enum ovs_output_fmt fmt OVS_UNUSED, + void *lock_req_) { struct ovsdb_client_lock_req *lock_req = lock_req_; lock_req_init(lock_req, "steal", argv[1]); @@ -2292,13 +2304,13 @@ do_lock(struct jsonrpc *rpc, const char *method, const char *lock) ovs_fatal(error, "failed to create unixctl server"); } - unixctl_command_register("unlock", "LOCK", 1, 1, + unixctl_command_register("unlock", "LOCK", 1, 1, OVS_OUTPUT_FMT_TEXT, ovsdb_client_unlock, &lock_req); - unixctl_command_register("steal", "LOCK", 1, 1, + unixctl_command_register("steal", "LOCK", 1, 1, OVS_OUTPUT_FMT_TEXT, ovsdb_client_steal, &lock_req); - unixctl_command_register("lock", "LOCK", 1, 1, + unixctl_command_register("lock", "LOCK", 1, 1, OVS_OUTPUT_FMT_TEXT, ovsdb_client_lock, &lock_req); - unixctl_command_register("exit", "", 0, 0, + unixctl_command_register("exit", "", 0, 0, OVS_OUTPUT_FMT_TEXT, ovsdb_client_exit, &exiting); } else { unixctl = NULL; diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c index 4d29043f4..e3b7abaf9 100644 --- a/ovsdb/ovsdb-server.c +++ b/ovsdb/ovsdb-server.c @@ -431,70 +431,94 @@ main(int argc, char *argv[]) VLOG_INFO("%s (Open vSwitch) %s", program_name, VERSION); } - unixctl_command_register("exit", "", 0, 0, ovsdb_server_exit, &exiting); + unixctl_command_register("exit", "", 0, 0, OVS_OUTPUT_FMT_TEXT, + ovsdb_server_exit, &exiting); unixctl_command_register("ovsdb-server/compact", "", 0, 1, - ovsdb_server_compact, &all_dbs); + OVS_OUTPUT_FMT_TEXT, ovsdb_server_compact, + &all_dbs); unixctl_command_register("ovsdb-server/memory-trim-on-compaction", - "on|off", 1, 1, + "on|off", 1, 1, OVS_OUTPUT_FMT_TEXT, ovsdb_server_memory_trim_on_compaction, NULL); unixctl_command_register("ovsdb-server/reconnect", "", 0, 0, - ovsdb_server_reconnect, jsonrpc); + OVS_OUTPUT_FMT_TEXT, ovsdb_server_reconnect, + jsonrpc); unixctl_command_register("ovsdb-server/add-remote", "REMOTE", 1, 1, - ovsdb_server_add_remote, &server_config); + OVS_OUTPUT_FMT_TEXT, ovsdb_server_add_remote, + &server_config); unixctl_command_register("ovsdb-server/remove-remote", "REMOTE", 1, 1, - ovsdb_server_remove_remote, &server_config); + OVS_OUTPUT_FMT_TEXT, ovsdb_server_remove_remote, + &server_config); unixctl_command_register("ovsdb-server/list-remotes", "", 0, 0, - ovsdb_server_list_remotes, &remotes); + OVS_OUTPUT_FMT_TEXT, ovsdb_server_list_remotes, + &remotes); unixctl_command_register("ovsdb-server/add-db", "DB", 1, 1, - ovsdb_server_add_database, &server_config); + OVS_OUTPUT_FMT_TEXT, ovsdb_server_add_database, + &server_config); unixctl_command_register("ovsdb-server/remove-db", "DB", 1, 1, - ovsdb_server_remove_database, &server_config); + OVS_OUTPUT_FMT_TEXT, ovsdb_server_remove_database, + &server_config); unixctl_command_register("ovsdb-server/list-dbs", "", 0, 0, - ovsdb_server_list_databases, &all_dbs); + OVS_OUTPUT_FMT_TEXT, ovsdb_server_list_databases, + &all_dbs); unixctl_command_register("ovsdb-server/tlog-set", "DB:TABLE on|off", - 2, 2, ovsdb_server_tlog_set, &all_dbs); + 2, 2, OVS_OUTPUT_FMT_TEXT, ovsdb_server_tlog_set, + &all_dbs); unixctl_command_register("ovsdb-server/tlog-list", "", - 0, 0, ovsdb_server_tlog_list, &all_dbs); + 0, 0, OVS_OUTPUT_FMT_TEXT, + ovsdb_server_tlog_list, &all_dbs); unixctl_command_register("ovsdb-server/perf-counters-show", "", 0, 0, + OVS_OUTPUT_FMT_TEXT, ovsdb_server_perf_counters_show, NULL); unixctl_command_register("ovsdb-server/perf-counters-clear", "", 0, 0, + OVS_OUTPUT_FMT_TEXT, ovsdb_server_perf_counters_clear, NULL); unixctl_command_register("ovsdb-server/set-active-ovsdb-server", "", 1, 1, + OVS_OUTPUT_FMT_TEXT, ovsdb_server_set_active_ovsdb_server, &server_config); unixctl_command_register("ovsdb-server/get-active-ovsdb-server", "", 0, 0, + OVS_OUTPUT_FMT_TEXT, ovsdb_server_get_active_ovsdb_server, &server_config); unixctl_command_register("ovsdb-server/connect-active-ovsdb-server", "", - 0, 0, ovsdb_server_connect_active_ovsdb_server, + 0, 0, OVS_OUTPUT_FMT_TEXT, + ovsdb_server_connect_active_ovsdb_server, &server_config); unixctl_command_register("ovsdb-server/disconnect-active-ovsdb-server", "", - 0, 0, ovsdb_server_disconnect_active_ovsdb_server, + 0, 0, OVS_OUTPUT_FMT_TEXT, + ovsdb_server_disconnect_active_ovsdb_server, &server_config); unixctl_command_register( "ovsdb-server/set-active-ovsdb-server-probe-interval", "", 1, 1, + OVS_OUTPUT_FMT_TEXT, ovsdb_server_set_active_ovsdb_server_probe_interval, &server_config); unixctl_command_register( "ovsdb-server/set-relay-source-probe-interval", "", 1, 1, + OVS_OUTPUT_FMT_TEXT, ovsdb_server_set_relay_source_interval, &server_config); unixctl_command_register("ovsdb-server/set-sync-exclude-tables", "", - 0, 1, ovsdb_server_set_sync_exclude_tables, + 0, 1, OVS_OUTPUT_FMT_TEXT, + ovsdb_server_set_sync_exclude_tables, &server_config); unixctl_command_register("ovsdb-server/get-sync-exclude-tables", "", - 0, 0, ovsdb_server_get_sync_exclude_tables, + 0, 0, OVS_OUTPUT_FMT_TEXT, + ovsdb_server_get_sync_exclude_tables, NULL); unixctl_command_register("ovsdb-server/sync-status", "", - 0, 0, ovsdb_server_get_sync_status, + 0, 0, OVS_OUTPUT_FMT_TEXT, + ovsdb_server_get_sync_status, &server_config); unixctl_command_register("ovsdb-server/get-db-storage-status", "DB", 1, 1, + OVS_OUTPUT_FMT_TEXT, ovsdb_server_get_db_storage_status, &server_config); /* Simulate the behavior of OVS release prior to version 2.5 that * does not support the monitor_cond method. */ unixctl_command_register("ovsdb-server/disable-monitor-cond", "", 0, 0, + OVS_OUTPUT_FMT_TEXT, ovsdb_server_disable_monitor_cond, jsonrpc); if (is_backup) { @@ -1404,6 +1428,7 @@ report_error_if_changed(char *error, char **last_errorp) static void ovsdb_server_set_active_ovsdb_server(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *config_) { struct server_config *config = config_; @@ -1421,6 +1446,7 @@ static void ovsdb_server_get_active_ovsdb_server(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *config_ ) { struct server_config *config = config_; @@ -1432,6 +1458,7 @@ static void ovsdb_server_connect_active_ovsdb_server(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *config_) { struct server_config *config = config_; @@ -1457,6 +1484,7 @@ static void ovsdb_server_disconnect_active_ovsdb_server(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *config_) { struct server_config *config = config_; @@ -1469,9 +1497,11 @@ ovsdb_server_disconnect_active_ovsdb_server(struct unixctl_conn *conn, static void ovsdb_server_set_active_ovsdb_server_probe_interval(struct unixctl_conn *conn, - int argc OVS_UNUSED, - const char *argv[], - void *config_) + int argc OVS_UNUSED, + const char *argv[], + enum ovs_output_fmt fmt + OVS_UNUSED, + void *config_) { struct server_config *config = config_; @@ -1493,6 +1523,7 @@ static void ovsdb_server_set_relay_source_interval(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *config_) { struct server_config *config = config_; @@ -1513,6 +1544,7 @@ static void ovsdb_server_set_sync_exclude_tables(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *config_) { struct server_config *config = config_; @@ -1539,6 +1571,7 @@ static void ovsdb_server_get_sync_exclude_tables(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *arg_ OVS_UNUSED) { char *reply = get_excluded_tables(); @@ -1549,6 +1582,7 @@ ovsdb_server_get_sync_exclude_tables(struct unixctl_conn *conn, static void ovsdb_server_exit(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *exiting_) { bool *exiting = exiting_; @@ -1559,6 +1593,7 @@ ovsdb_server_exit(struct unixctl_conn *conn, int argc OVS_UNUSED, static void ovsdb_server_perf_counters_show(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *arg_ OVS_UNUSED) { char *s = perf_counters_to_string(); @@ -1570,6 +1605,7 @@ ovsdb_server_perf_counters_show(struct unixctl_conn *conn, int argc OVS_UNUSED, static void ovsdb_server_perf_counters_clear(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *arg_ OVS_UNUSED) { perf_counters_clear(); @@ -1583,6 +1619,7 @@ static void ovsdb_server_disable_monitor_cond(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *jsonrpc_) { struct ovsdb_jsonrpc_server *jsonrpc = jsonrpc_; @@ -1595,7 +1632,8 @@ ovsdb_server_disable_monitor_cond(struct unixctl_conn *conn, static void ovsdb_server_compact(struct unixctl_conn *conn, int argc, - const char *argv[], void *dbs_) + const char *argv[], enum ovs_output_fmt fmt OVS_UNUSED, + void *dbs_) { const char *db_name = argc < 2 ? NULL : argv[1]; struct shash *all_dbs = dbs_; @@ -1658,6 +1696,7 @@ static void ovsdb_server_memory_trim_on_compaction(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *arg OVS_UNUSED) { bool old_trim_memory = trim_memory; @@ -1689,7 +1728,9 @@ ovsdb_server_memory_trim_on_compaction(struct unixctl_conn *conn, * connections and reconnect. */ static void ovsdb_server_reconnect(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *jsonrpc_) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *jsonrpc_) { struct ovsdb_jsonrpc_server *jsonrpc = jsonrpc_; ovsdb_jsonrpc_server_reconnect( @@ -1701,7 +1742,9 @@ ovsdb_server_reconnect(struct unixctl_conn *conn, int argc OVS_UNUSED, * ovsdb-server services. */ static void ovsdb_server_add_remote(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *config_) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *config_) { struct server_config *config = config_; const char *remote = argv[1]; @@ -1730,7 +1773,9 @@ ovsdb_server_add_remote(struct unixctl_conn *conn, int argc OVS_UNUSED, * that ovsdb-server services. */ static void ovsdb_server_remove_remote(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *config_) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *config_) { struct server_config *config = config_; struct sset_node *node; @@ -1748,7 +1793,9 @@ ovsdb_server_remove_remote(struct unixctl_conn *conn, int argc OVS_UNUSED, /* "ovsdb-server/list-remotes": outputs a list of configured rmeotes. */ static void ovsdb_server_list_remotes(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *remotes_) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *remotes_) { struct sset *remotes = remotes_; const char **list, **p; @@ -1770,7 +1817,9 @@ ovsdb_server_list_remotes(struct unixctl_conn *conn, int argc OVS_UNUSED, /* "ovsdb-server/add-db DB": adds the DB to ovsdb-server. */ static void ovsdb_server_add_database(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *config_) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *config_) { struct server_config *config = config_; const char *filename = argv[1]; @@ -1812,7 +1861,9 @@ remove_db(struct server_config *config, struct shash_node *node, char *comment) static void ovsdb_server_remove_database(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *config_) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *config_) { struct server_config *config = config_; struct shash_node *node; @@ -1834,7 +1885,9 @@ ovsdb_server_remove_database(struct unixctl_conn *conn, int argc OVS_UNUSED, static void ovsdb_server_list_databases(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *all_dbs_) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *all_dbs_) { struct shash *all_dbs = all_dbs_; const struct shash_node **nodes; @@ -1859,7 +1912,9 @@ ovsdb_server_list_databases(struct unixctl_conn *conn, int argc OVS_UNUSED, static void ovsdb_server_tlog_set(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *all_dbs_) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *all_dbs_) { struct shash *all_dbs = all_dbs_; const char *name_ = argv[1]; @@ -1905,7 +1960,9 @@ out: static void ovsdb_server_tlog_list(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *all_dbs_) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *all_dbs_) { const struct shash_node **db_nodes; struct ds s = DS_EMPTY_INITIALIZER; @@ -1940,7 +1997,9 @@ ovsdb_server_tlog_list(struct unixctl_conn *conn, int argc OVS_UNUSED, static void ovsdb_server_get_sync_status(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *config_) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *config_) { struct server_config *config = config_; bool is_backup = *config->is_backup; @@ -1960,6 +2019,7 @@ static void ovsdb_server_get_db_storage_status(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *config_) { struct server_config *config = config_; diff --git a/ovsdb/ovsdb.c b/ovsdb/ovsdb.c index f67b836d7..28914fdb0 100644 --- a/ovsdb/ovsdb.c +++ b/ovsdb/ovsdb.c @@ -186,6 +186,7 @@ static bool use_no_data_conversion = true; static void ovsdb_no_data_conversion_enable(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *arg OVS_UNUSED) { use_no_data_conversion = true; @@ -200,7 +201,8 @@ ovsdb_no_data_conversion_disable(void) } use_no_data_conversion = false; unixctl_command_register("ovsdb/file/no-data-conversion-enable", "", - 0, 0, ovsdb_no_data_conversion_enable, NULL); + 0, 0, OVS_OUTPUT_FMT_TEXT, + ovsdb_no_data_conversion_enable, NULL); } /* Returns true if the database storage allows conversion records without diff --git a/ovsdb/raft.c b/ovsdb/raft.c index 8effd9ad1..a7d6e5a09 100644 --- a/ovsdb/raft.c +++ b/ovsdb/raft.c @@ -4603,6 +4603,7 @@ raft_lookup_by_name(const char *name) static void raft_unixctl_cid(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct raft *raft = raft_lookup_by_name(argv[1]); @@ -4620,6 +4621,7 @@ raft_unixctl_cid(struct unixctl_conn *conn, static void raft_unixctl_sid(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct raft *raft = raft_lookup_by_name(argv[1]); @@ -4651,6 +4653,7 @@ raft_put_sid(const char *title, const struct uuid *sid, static void raft_unixctl_status(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { struct raft *raft = raft_lookup_by_name(argv[1]); @@ -4809,7 +4812,8 @@ raft_unixctl_leave__(struct unixctl_conn *conn, struct raft *raft) static void raft_unixctl_leave(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct raft *raft = raft_lookup_by_name(argv[1]); if (!raft) { @@ -4845,7 +4849,8 @@ raft_lookup_server_best_match(struct raft *raft, const char *id) static void raft_unixctl_kick(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { const char *cluster_name = argv[1]; const char *server_name = argv[2]; @@ -4918,6 +4923,7 @@ raft_log_election_timer(struct raft *raft) static void raft_unixctl_change_election_timer(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { const char *cluster_name = argv[1]; @@ -4972,6 +4978,7 @@ raft_unixctl_change_election_timer(struct unixctl_conn *conn, static void raft_unixctl_set_backlog_threshold(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { const char *cluster_name = argv[1]; @@ -5008,6 +5015,7 @@ raft_unixctl_set_backlog_threshold(struct unixctl_conn *conn, static void raft_unixctl_failure_test(struct unixctl_conn *conn OVS_UNUSED, int argc OVS_UNUSED, const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { const char *test = argv[1]; @@ -5062,22 +5070,24 @@ raft_init(void) if (!ovsthread_once_start(&once)) { return; } - unixctl_command_register("cluster/cid", "DB", 1, 1, + unixctl_command_register("cluster/cid", "DB", 1, 1, OVS_OUTPUT_FMT_TEXT, raft_unixctl_cid, NULL); - unixctl_command_register("cluster/sid", "DB", 1, 1, + unixctl_command_register("cluster/sid", "DB", 1, 1, OVS_OUTPUT_FMT_TEXT, raft_unixctl_sid, NULL); - unixctl_command_register("cluster/status", "DB", 1, 1, + unixctl_command_register("cluster/status", "DB", 1, 1, OVS_OUTPUT_FMT_TEXT, raft_unixctl_status, NULL); - unixctl_command_register("cluster/leave", "DB", 1, 1, + unixctl_command_register("cluster/leave", "DB", 1, 1, OVS_OUTPUT_FMT_TEXT, raft_unixctl_leave, NULL); unixctl_command_register("cluster/kick", "DB SERVER", 2, 2, - raft_unixctl_kick, NULL); + OVS_OUTPUT_FMT_TEXT, raft_unixctl_kick, NULL); unixctl_command_register("cluster/change-election-timer", "DB TIME", 2, 2, + OVS_OUTPUT_FMT_TEXT, raft_unixctl_change_election_timer, NULL); unixctl_command_register("cluster/set-backlog-threshold", - "DB N_MSGS N_BYTES", 3, 3, + "DB N_MSGS N_BYTES", 3, 3, OVS_OUTPUT_FMT_TEXT, raft_unixctl_set_backlog_threshold, NULL); unixctl_command_register("cluster/failure-test", "FAILURE SCENARIO", 1, 1, - raft_unixctl_failure_test, NULL); + OVS_OUTPUT_FMT_TEXT, raft_unixctl_failure_test, + NULL); ovsthread_once_done(&once); } diff --git a/python/ovs/unixctl/__init__.py b/python/ovs/unixctl/__init__.py index 6d9bd5715..ebbd28487 100644 --- a/python/ovs/unixctl/__init__.py +++ b/python/ovs/unixctl/__init__.py @@ -20,19 +20,16 @@ commands = {} class _UnixctlCommand(object): - # FIXME: Output format will be passed as 'output_fmts' to the command in - # later patch. - def __init__(self, usage, min_args, max_args, # FIXME: output_fmts, - callback, aux): + def __init__(self, usage, min_args, max_args, output_fmts, callback, aux): self.usage = usage self.min_args = min_args self.max_args = max_args - # FIXME: self.output_fmts = output_fmts + self.output_fmts = output_fmts self.callback = callback self.aux = aux -def _unixctl_help(conn, unused_argv, unused_aux): +def _unixctl_help(conn, unused_argv, unused_fmt, unused_aux): reply = "The available commands are:\n" command_names = sorted(commands.keys()) for name in command_names: @@ -46,8 +43,8 @@ def _unixctl_help(conn, unused_argv, unused_aux): conn.reply(reply) -def command_register_fmt(name, usage, min_args, max_args, output_fmts, - callback, aux): +def command_register(name, usage, min_args, max_args, output_fmts, callback, + aux): """ Registers a command with the given 'name' to be exposed by the UnixctlServer. 'usage' describes the arguments to the command; it is used only for presentation to the user in "help" output. 'output_fmts' is a @@ -71,29 +68,7 @@ def command_register_fmt(name, usage, min_args, max_args, output_fmts, if name not in commands: commands[name] = _UnixctlCommand(usage, min_args, max_args, - # FIXME: output_fmts, - callback, aux) - - -# FIXME: command_register() will be replaced with command_register_fmt() in a -# later patch of this series. It is is kept temporarily to reduce the -# amount of changes in this patch. -def command_register(name, usage, min_args, max_args, callback, aux): - """ Registers a command with the given 'name' to be exposed by the - UnixctlServer. 'usage' describes the arguments to the command; it is used - only for presentation to the user in "help" output. - - 'callback' is called when the command is received. It is passed a - UnixctlConnection object, the list of arguments as unicode strings, and - 'aux'. Normally 'callback' should reply by calling - UnixctlConnection.reply() or UnixctlConnection.reply_error() before it - returns, but if the command cannot be handled immediately, then it can - defer the reply until later. A given connection can only process a single - request at a time, so a reply must be made eventually to avoid blocking - that connection.""" - - command_register_fmt(name, usage, min_args, max_args, - ovs.util.OutputFormat.TEXT, callback, aux) + output_fmts, callback, aux) def socket_name_from_target(target): @@ -114,4 +89,5 @@ def socket_name_from_target(target): return 0, "%s/%s.%d.ctl" % (ovs.dirs.RUNDIR, target, pid) -command_register("help", "", 0, 0, _unixctl_help, None) +command_register("help", "", 0, 0, ovs.util.OutputFormat.TEXT, + _unixctl_help, None) diff --git a/python/ovs/unixctl/server.py b/python/ovs/unixctl/server.py index 5e92bc570..849739e89 100644 --- a/python/ovs/unixctl/server.py +++ b/python/ovs/unixctl/server.py @@ -136,28 +136,19 @@ class UnixctlConnection(object): raise ValueError( '"%s" command takes at most %d arguments' % (method, command.max_args)) - # FIXME: Uncomment when command.output_fmts is available - # elif fmt not in command.output_fmts: - # raise ValueError('"%s" command does not support output format' - # ' "%s" %d %d' % (method, fmt.name.lower(), - # command.output_fmts, fmt)) - - # FIXME: Remove this check once output format will be passed to the - # command handler below. - if fmt != ovs.util.OutputFormat.TEXT: - raise ValueError( - 'output format "%s" has not been implemented yet' - % fmt.name.lower()) + elif fmt not in command.output_fmts: + raise ValueError('"%s" command does not support output format' + ' "%s" %d %d' % (method, fmt.name.lower(), + command.output_fmts, fmt)) unicode_params = [str(p) for p in params] - command.callback(self, unicode_params, # FIXME: fmt, - command.aux) + command.callback(self, unicode_params, fmt, command.aux) except Exception as e: self.reply_error(str(e)) -def _unixctl_version(conn, unused_argv, version): +def _unixctl_version(conn, unused_argv, unused_fmt, version): assert isinstance(conn, UnixctlConnection) version = "%s (Open vSwitch) %s" % (ovs.util.PROGRAM_NAME, version) conn.reply(version) @@ -235,6 +226,7 @@ class UnixctlServer(object): return error, None ovs.unixctl.command_register("version", "", 0, 0, + ovs.util.OutputFormat.TEXT, _unixctl_version, version) diff --git a/python/ovs/vlog.py b/python/ovs/vlog.py index 61f5928db..ba8701040 100644 --- a/python/ovs/vlog.py +++ b/python/ovs/vlog.py @@ -237,8 +237,10 @@ class Vlog(object): logger.disabled = True ovs.unixctl.command_register("vlog/reopen", "", 0, 0, + ovs.util.OutputFormat.TEXT, Vlog._unixctl_vlog_reopen, None) ovs.unixctl.command_register("vlog/close", "", 0, 0, + ovs.util.OutputFormat.TEXT, Vlog._unixctl_vlog_close, None) try: # Windows limitation on Python 2, sys.maxsize is a long number @@ -248,8 +250,10 @@ class Vlog(object): except AttributeError: maxsize_int = sys.maxsize ovs.unixctl.command_register("vlog/set", "spec", 1, maxsize_int, + ovs.util.OutputFormat.TEXT, Vlog._unixctl_vlog_set, None) ovs.unixctl.command_register("vlog/list", "", 0, 0, + ovs.util.OutputFormat.TEXT, Vlog._unixctl_vlog_list, None) @staticmethod @@ -406,7 +410,7 @@ class Vlog(object): Vlog.__file_handler.close() @staticmethod - def _unixctl_vlog_reopen(conn, unused_argv, unused_aux): + def _unixctl_vlog_reopen(conn, unused_argv, unused_fmt, unused_aux): if Vlog.__log_file: Vlog.reopen_log_file() conn.reply(None) @@ -414,7 +418,7 @@ class Vlog(object): conn.reply("Logging to file not configured") @staticmethod - def _unixctl_vlog_close(conn, unused_argv, unused_aux): + def _unixctl_vlog_close(conn, unused_argv, unused_fmt, unused_aux): if Vlog.__log_file: if sys.platform != 'win32': logger = logging.getLogger("file") @@ -424,7 +428,7 @@ class Vlog(object): conn.reply(None) @staticmethod - def _unixctl_vlog_set(conn, argv, unused_aux): + def _unixctl_vlog_set(conn, argv, unused_fmt, unused_aux): for arg in argv: msg = Vlog.set_levels_from_string(arg) if msg: @@ -433,7 +437,7 @@ class Vlog(object): conn.reply(None) @staticmethod - def _unixctl_vlog_list(conn, unused_argv, unused_aux): + def _unixctl_vlog_list(conn, unused_argv, unused_fmt, unused_aux): conn.reply(Vlog.get_levels()) diff --git a/tests/test-netflow.c b/tests/test-netflow.c index 7f89cfcae..b808cb9fd 100644 --- a/tests/test-netflow.c +++ b/tests/test-netflow.c @@ -201,7 +201,8 @@ test_netflow_main(int argc, char *argv[]) if (error) { ovs_fatal(error, "failed to create unixctl server"); } - unixctl_command_register("exit", "", 0, 0, test_netflow_exit, &exiting); + unixctl_command_register("exit", "", 0, 0, OVS_OUTPUT_FMT_TEXT, + test_netflow_exit, &exiting); daemonize_complete(); @@ -294,6 +295,7 @@ usage(void) static void test_netflow_exit(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *exiting_) { bool *exiting = exiting_; diff --git a/tests/test-sflow.c b/tests/test-sflow.c index 3c617bdd1..82ef66178 100644 --- a/tests/test-sflow.c +++ b/tests/test-sflow.c @@ -715,7 +715,8 @@ test_sflow_main(int argc, char *argv[]) if (error) { ovs_fatal(error, "failed to create unixctl server"); } - unixctl_command_register("exit", "", 0, 0, test_sflow_exit, &exiting); + unixctl_command_register("exit", "", 0, 0, OVS_OUTPUT_FMT_TEXT, + test_sflow_exit, &exiting); daemonize_complete(); @@ -804,6 +805,7 @@ usage(void) static void test_sflow_exit(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *exiting_) { bool *exiting = exiting_; diff --git a/tests/test-unixctl.c b/tests/test-unixctl.c index 9e8982789..e344a8203 100644 --- a/tests/test-unixctl.c +++ b/tests/test-unixctl.c @@ -33,7 +33,9 @@ OVS_NO_RETURN static void usage(void); static void test_unixctl_exit(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *exiting_) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *exiting_) { bool *exiting = exiting_; *exiting = true; @@ -42,21 +44,26 @@ test_unixctl_exit(struct unixctl_conn *conn, int argc OVS_UNUSED, static void test_unixctl_echo(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { unixctl_command_reply(conn, argv[1]); } static void test_unixctl_echo_error(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { unixctl_command_reply_error(conn, argv[1]); } static void test_unixctl_log(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *aux OVS_UNUSED) { VLOG_INFO("%s", argv[1]); unixctl_command_reply(conn, NULL); @@ -64,7 +71,9 @@ test_unixctl_log(struct unixctl_conn *conn, int argc OVS_UNUSED, static void test_unixctl_block(struct unixctl_conn *conn OVS_UNUSED, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { VLOG_INFO("%s", argv[1]); unixctl_command_reply(conn, NULL); @@ -88,12 +97,16 @@ test_unixctl_main(int argc, char *argv[]) if (retval) { exit(EXIT_FAILURE); } - unixctl_command_register("exit", "", 0, 0, test_unixctl_exit, &exiting); - unixctl_command_register("echo", "ARG", 1, 1, test_unixctl_echo, NULL); - unixctl_command_register("echo_error", "ARG", 1, 1, + unixctl_command_register("exit", "", 0, 0, OVS_OUTPUT_FMT_TEXT, + test_unixctl_exit, &exiting); + unixctl_command_register("echo", "ARG", 1, 1, OVS_OUTPUT_FMT_TEXT, + test_unixctl_echo, NULL); + unixctl_command_register("echo_error", "ARG", 1, 1, OVS_OUTPUT_FMT_TEXT, test_unixctl_echo_error, NULL); - unixctl_command_register("log", "ARG", 1, 1, test_unixctl_log, NULL); - unixctl_command_register("block", "", 0, 0, test_unixctl_block, NULL); + unixctl_command_register("log", "ARG", 1, 1, OVS_OUTPUT_FMT_TEXT, + test_unixctl_log, NULL); + unixctl_command_register("block", "", 0, 0, OVS_OUTPUT_FMT_TEXT, + test_unixctl_block, NULL); daemonize_complete(); VLOG_INFO("Entering run loop."); diff --git a/tests/test-unixctl.py b/tests/test-unixctl.py index 4fa27b09f..b5fe12eb7 100644 --- a/tests/test-unixctl.py +++ b/tests/test-unixctl.py @@ -17,12 +17,13 @@ import argparse import ovs.daemon import ovs.unixctl import ovs.unixctl.server +import ovs.util vlog = ovs.vlog.Vlog("test-unixctl") exiting = False -def unixctl_exit(conn, unused_argv, aux): +def unixctl_exit(conn, unused_argv, unused_fmt, aux): assert aux == "aux_exit" global exiting @@ -30,22 +31,22 @@ def unixctl_exit(conn, unused_argv, aux): conn.reply(None) -def unixctl_echo(conn, argv, aux): +def unixctl_echo(conn, argv, unused_fmt, aux): assert aux == "aux_echo" conn.reply(str(argv)) -def unixctl_echo_error(conn, argv, aux): +def unixctl_echo_error(conn, argv, unused_fmt, aux): assert aux == "aux_echo_error" conn.reply_error(str(argv)) -def unixctl_log(conn, argv, unused_aux): +def unixctl_log(conn, argv, unused_fmt, unused_aux): vlog.info(str(argv[0])) conn.reply(None) -def unixctl_block(conn, unused_argv, unused_aux): +def unixctl_block(conn, unused_argv, unused_fmt, unused_aux): pass @@ -66,13 +67,19 @@ def main(): ovs.util.ovs_fatal(error, "could not create unixctl server at %s" % args.unixctl, vlog) - ovs.unixctl.command_register("exit", "", 0, 0, unixctl_exit, "aux_exit") - ovs.unixctl.command_register("echo", "[arg ...]", 1, 2, unixctl_echo, + ovs.unixctl.command_register("exit", "", 0, 0, ovs.util.OutputFormat.TEXT, + unixctl_exit, "aux_exit") + ovs.unixctl.command_register("echo", "[arg ...]", 1, 2, + ovs.util.OutputFormat.TEXT, unixctl_echo, "aux_echo") - ovs.unixctl.command_register("log", "[arg ...]", 1, 2, unixctl_log, None) + ovs.unixctl.command_register("log", "[arg ...]", 1, 2, + ovs.util.OutputFormat.TEXT, unixctl_log, + None) ovs.unixctl.command_register("echo_error", "[arg ...]", 1, 2, + ovs.util.OutputFormat.TEXT, unixctl_echo_error, "aux_echo_error") - ovs.unixctl.command_register("block", "", 0, 0, unixctl_block, None) + ovs.unixctl.command_register("block", "", 0, 0, ovs.util.OutputFormat.TEXT, + unixctl_block, None) ovs.daemon.daemonize_complete() vlog.info("Entering run loop.") diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 24d0941cf..4bf398492 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -524,7 +524,8 @@ usage(void) static void ofctl_exit(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *exiting_) + const char *argv[] OVS_UNUSED, enum ovs_output_fmt fmt OVS_UNUSED, + void *exiting_) { bool *exiting = exiting_; *exiting = true; @@ -1935,7 +1936,8 @@ openflow_from_hex(const char *hex, struct ofpbuf **msgp) static void ofctl_send(struct unixctl_conn *conn, int argc, - const char *argv[], void *vconn_) + const char *argv[], enum ovs_output_fmt fmt OVS_UNUSED, + void *vconn_) { struct vconn *vconn = vconn_; struct ds reply; @@ -1981,7 +1983,8 @@ ofctl_send(struct unixctl_conn *conn, int argc, static void unixctl_packet_out(struct unixctl_conn *conn, int OVS_UNUSED argc, - const char *argv[], void *vconn_) + const char *argv[], enum ovs_output_fmt fmt OVS_UNUSED, + void *vconn_) { struct vconn *vconn = vconn_; enum ofputil_protocol protocol @@ -2042,7 +2045,8 @@ struct barrier_aux { static void ofctl_barrier(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *aux_) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, void *aux_) { struct barrier_aux *aux = aux_; struct ofpbuf *msg; @@ -2065,7 +2069,8 @@ ofctl_barrier(struct unixctl_conn *conn, int argc OVS_UNUSED, static void ofctl_set_output_file(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { int fd; @@ -2083,7 +2088,9 @@ ofctl_set_output_file(struct unixctl_conn *conn, int argc OVS_UNUSED, static void ofctl_block(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *blocked_) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *blocked_) { bool *blocked = blocked_; @@ -2097,7 +2104,9 @@ ofctl_block(struct unixctl_conn *conn, int argc OVS_UNUSED, static void ofctl_unblock(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *blocked_) + const char *argv[] OVS_UNUSED, + enum ovs_output_fmt fmt OVS_UNUSED, + void *blocked_) { bool *blocked = blocked_; @@ -2132,19 +2141,21 @@ monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests, if (error) { ovs_fatal(error, "failed to create unixctl server"); } - unixctl_command_register("exit", "", 0, 0, ofctl_exit, &exiting); + unixctl_command_register("exit", "", 0, 0, OVS_OUTPUT_FMT_TEXT, + ofctl_exit, &exiting); unixctl_command_register("ofctl/send", "OFMSG...", 1, INT_MAX, - ofctl_send, vconn); + OVS_OUTPUT_FMT_TEXT, ofctl_send, vconn); unixctl_command_register("ofctl/packet-out", "\"in_port= packet= actions=...\"", 1, 1, - unixctl_packet_out, vconn); - unixctl_command_register("ofctl/barrier", "", 0, 0, + OVS_OUTPUT_FMT_TEXT, unixctl_packet_out, vconn); + unixctl_command_register("ofctl/barrier", "", 0, 0, OVS_OUTPUT_FMT_TEXT, ofctl_barrier, &barrier_aux); unixctl_command_register("ofctl/set-output-file", "FILE", 1, 1, - ofctl_set_output_file, NULL); - - unixctl_command_register("ofctl/block", "", 0, 0, ofctl_block, &blocked); - unixctl_command_register("ofctl/unblock", "", 0, 0, ofctl_unblock, - &blocked); + OVS_OUTPUT_FMT_TEXT, ofctl_set_output_file, + NULL); + unixctl_command_register("ofctl/block", "", 0, 0, OVS_OUTPUT_FMT_TEXT, + ofctl_block, &blocked); + unixctl_command_register("ofctl/unblock", "", 0, 0, OVS_OUTPUT_FMT_TEXT, + ofctl_unblock, &blocked); daemonize_complete(); diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index e9110c1d8..fda873ac9 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -513,13 +513,16 @@ bridge_init(const char *remote) /* Register unixctl commands. */ unixctl_command_register("qos/show-types", "interface", 1, 1, - qos_unixctl_show_types, NULL); + OVS_OUTPUT_FMT_TEXT, qos_unixctl_show_types, + NULL); unixctl_command_register("qos/show", "interface", 1, 1, - qos_unixctl_show, NULL); + OVS_OUTPUT_FMT_TEXT, qos_unixctl_show, NULL); unixctl_command_register("bridge/dump-flows", "[--offload-stats] bridge", - 1, 2, bridge_unixctl_dump_flows, NULL); + 1, 2, OVS_OUTPUT_FMT_TEXT, + bridge_unixctl_dump_flows, NULL); unixctl_command_register("bridge/reconnect", "[bridge]", 0, 1, - bridge_unixctl_reconnect, NULL); + OVS_OUTPUT_FMT_TEXT, bridge_unixctl_reconnect, + NULL); lacp_init(); bond_init(); cfm_init(); @@ -3466,7 +3469,8 @@ qos_unixctl_show_queue(unsigned int queue_id, static void qos_unixctl_show_types(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; struct sset types = SSET_INITIALIZER(&types); @@ -3504,7 +3508,8 @@ qos_unixctl_show_types(struct unixctl_conn *conn, int argc OVS_UNUSED, static void qos_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; struct smap smap = SMAP_INITIALIZER(&smap); @@ -3624,7 +3629,9 @@ bridge_lookup(const char *name) * stack, including those normally hidden. */ static void bridge_unixctl_dump_flows(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct bridge *br; struct ds results; @@ -3654,7 +3661,9 @@ bridge_unixctl_dump_flows(struct unixctl_conn *conn, int argc, * drop their controller connections and reconnect. */ static void bridge_unixctl_reconnect(struct unixctl_conn *conn, int argc, - const char *argv[], void *aux OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, + void *aux OVS_UNUSED) { struct bridge *br; if (argc > 1) { diff --git a/vswitchd/ovs-vswitchd.c b/vswitchd/ovs-vswitchd.c index 273af9f5d..74b755778 100644 --- a/vswitchd/ovs-vswitchd.c +++ b/vswitchd/ovs-vswitchd.c @@ -111,7 +111,7 @@ main(int argc, char *argv[]) exit(EXIT_FAILURE); } unixctl_command_register("exit", "[--cleanup]", 0, 1, - ovs_vswitchd_exit, NULL); + OVS_OUTPUT_FMT_TEXT, ovs_vswitchd_exit, NULL); bridge_init(remote); free(remote); @@ -308,7 +308,8 @@ usage(void) static void ovs_vswitchd_exit(struct unixctl_conn *conn, int argc, - const char *argv[], void *args OVS_UNUSED) + const char *argv[], + enum ovs_output_fmt fmt OVS_UNUSED, void *args OVS_UNUSED) { exit_args.n_conns++; exit_args.conns = xrealloc(exit_args.conns, From patchwork Thu Nov 16 10:41:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakob Meng X-Patchwork-Id: 1864682 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=LYTXa+qw; 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 4SWGn55k1Fz1yRR for ; Thu, 16 Nov 2023 21:42:01 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 48ABD832E6; Thu, 16 Nov 2023 10:41:57 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 48ABD832E6 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=LYTXa+qw X-Virus-Scanned: amavisd-new at osuosl.org 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 sxqINzeQPUbg; Thu, 16 Nov 2023 10:41:55 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTPS id DABD5832D1; Thu, 16 Nov 2023 10:41:53 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org DABD5832D1 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id D0135C0DE1; Thu, 16 Nov 2023 10:41:50 +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 8C9C8C0DDC for ; Thu, 16 Nov 2023 10:41:49 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 54B7B6F656 for ; Thu, 16 Nov 2023 10:41:49 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 54B7B6F656 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=LYTXa+qw 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 d_V_khrR9hPb for ; Thu, 16 Nov 2023 10:41:48 +0000 (UTC) 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 0E59B6F57B for ; Thu, 16 Nov 2023 10:41:47 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 0E59B6F57B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1700131306; 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=Jpw4pJ0qIHODbJGc7/B4ukEMBkOjtPYSh3rzKrd6qGs=; b=LYTXa+qwYUBKp2EEAPv0tdJLrqNXkzAMrjBMGI5jOGoPgCpzQnRnFFDT/SDC97/6rstA9q p/x4k166/S+921RhsM52VzQ/d3VWs9K51PzXFn7FZO1K2pIOSEnSIfWQ24lzbbLvmTqng9 w/C2+PpZDEAUmvnJFOvyz/uPc0yZrzE= Received: from mail-lj1-f197.google.com (mail-lj1-f197.google.com [209.85.208.197]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-213-Pq0QZfFEMAi6Ii5H55ZBzw-1; Thu, 16 Nov 2023 05:41:45 -0500 X-MC-Unique: Pq0QZfFEMAi6Ii5H55ZBzw-1 Received: by mail-lj1-f197.google.com with SMTP id 38308e7fff4ca-2c50257772bso5340811fa.3 for ; Thu, 16 Nov 2023 02:41:45 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1700131304; x=1700736104; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Jpw4pJ0qIHODbJGc7/B4ukEMBkOjtPYSh3rzKrd6qGs=; b=MhGCWrpDEt9YBFUXVyjJ7xFU24bxDSMvN6jp87cSk3DQ/wrmNEMkBVdkZczop+3Q/A xbPn0iPiXK2mr9FgbcKm8myYmDk6RPtc2JiqoxqM3kZJWmo16OPrMyO0sFrAfvdkEmfb qMk9JhBQA7UBx+Z8ewjkMrg9Wrj3q9A+kaSXbM3IaPXKoU9EOqzyNDtUBSpWRtnW4ypm y4JUmtq89peh7awBk+7kmAgroRNATACLr8fH3oWEiavSQMpvJoEjCUjI2SZQGc2ekxB+ UksqgsfFmtxgX3XH7eObH4qjXGwCuBt7zAvTEkaPuRgxQMTAfTExDQlFgN2e2uDj2wE3 dcyw== X-Gm-Message-State: AOJu0YwkTy5dcI0u0Pby5ygdX70wrZBYVNV4nG9wgk4DOGlzKhySV1C0 brVjU2z5CFGHGk6BSbzrnJVxyeKIk3/j+MgQs4hTmZaoRT6vZkRAvC7xGQ5F8pWYRvgndGwfCvV VOLgjFBwGl02WlgM8YQ2PQKxnjNQUPca3v4r4jvh2ihhsgIaEx65z7wKDJc/zVFXYR3Q= X-Received: by 2002:a2e:7013:0:b0:2c5:23e3:ed11 with SMTP id l19-20020a2e7013000000b002c523e3ed11mr7035617ljc.30.1700131304032; Thu, 16 Nov 2023 02:41:44 -0800 (PST) X-Google-Smtp-Source: AGHT+IFYdNRlEXMu6TK3MjM77/ldDyKj93GqHwIF5itXlpK5vABKLmAekMchng+IasZ5Jy1wOSSNfQ== X-Received: by 2002:a2e:7013:0:b0:2c5:23e3:ed11 with SMTP id l19-20020a2e7013000000b002c523e3ed11mr7035602ljc.30.1700131303739; Thu, 16 Nov 2023 02:41:43 -0800 (PST) Received: from positronik4lide.redhat.com ([87.122.56.153]) by smtp.gmail.com with ESMTPSA id n10-20020a05600c304a00b004080f0376a0sm2937210wmh.42.2023.11.16.02.41.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Nov 2023 02:41:43 -0800 (PST) From: jmeng@redhat.com To: dev@openvswitch.org, i.maximets@ovn.org, echaudro@redhat.com, ktraynor@redhat.com, aconole@redhat.com, rjarry@redhat.com Date: Thu, 16 Nov 2023 11:41:18 +0100 Message-Id: <20231116104120.25676-5-jmeng@redhat.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231116104120.25676-1-jmeng@redhat.com> References: <20231116104120.25676-1-jmeng@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH v4 4/6] ofproto: Add JSON output for 'dpif/show' command. 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: Jakob Meng The 'dpif/show' command now supports machine-readable JSON output in addition to the plain-text output for humans. An example would be: ovs-appctl --format json dpif/show Reported-at: https://bugzilla.redhat.com/1824861 Signed-off-by: Jakob Meng --- ofproto/ofproto-dpif.c | 129 ++++++++++++++++++++++++++++++++++++----- tests/pmd.at | 28 +++++++++ 2 files changed, 144 insertions(+), 13 deletions(-) diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 516ec6280..eedf65e07 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -20,6 +20,7 @@ #include "bond.h" #include "bundle.h" #include "byte-order.h" +#include "command-line.h" #include "connectivity.h" #include "connmgr.h" #include "coverage.h" @@ -6360,8 +6361,103 @@ done: return changed; } +static struct json * +dpif_show_backer_json(const struct dpif_backer *backer) +{ + struct json *json_backer = json_object_create(); + + /* Add dpif name to JSON. */ + json_object_put_string(json_backer, "name", dpif_name(backer->dpif)); + + /* Add dpif stats to JSON. */ + struct dpif_dp_stats dp_stats; + dpif_get_dp_stats(backer->dpif, &dp_stats); + struct json *json_dp_stats = json_object_create(); + json_object_put_format(json_dp_stats, "n_hit", "%"PRIu64, dp_stats.n_hit); + json_object_put_format(json_dp_stats, "n_missed", "%"PRIu64, + dp_stats.n_missed); + json_object_put(json_backer, "stats", json_dp_stats); + + /* Add ofprotos to JSON. */ + struct json *json_ofprotos = json_array_create_empty(); + struct shash ofproto_shash; + shash_init(&ofproto_shash); + const struct shash_node **ofprotos = get_ofprotos(&ofproto_shash); + for (size_t i = 0; i < shash_count(&ofproto_shash); i++) { + struct ofproto_dpif *ofproto = ofprotos[i]->data; + + if (ofproto->backer != backer) { + continue; + } + + struct json *json_ofproto = json_object_create(); + + /* Add ofproto name to JSON array. */ + json_object_put_string(json_ofproto, "name", ofproto->up.name); + + /* Add ofproto ports to JSON array. */ + struct json *json_ofproto_ports = json_array_create_empty(); + const struct shash_node **ports; + ports = shash_sort(&ofproto->up.port_by_name); + for (size_t j = 0; j < shash_count(&ofproto->up.port_by_name); j++) { + const struct shash_node *port = ports[j]; + struct ofport *ofport = port->data; + + struct json * json_ofproto_port = json_object_create(); + /* Add ofproto port netdev name to JSON sub array. */ + json_object_put_string(json_ofproto_port, "netdev_name", + netdev_get_name(ofport->netdev)); + /* Add ofproto port ofp port to JSON sub array. */ + json_object_put_format(json_ofproto_port, "ofp_port", "%u", + ofport->ofp_port); + + /* Add ofproto port odp port to JSON sub array. */ + odp_port_t odp_port = ofp_port_to_odp_port(ofproto, + ofport->ofp_port); + if (odp_port != ODPP_NONE) { + json_object_put_format(json_ofproto_port, "odp_port", + "%"PRIu32, odp_port); + } else { + json_object_put_string(json_ofproto_port, "odp_port", "none"); + } + + /* Add ofproto port netdev type to JSON sub array. */ + json_object_put_string(json_ofproto_port, "netdev_type", + netdev_get_type(ofport->netdev)); + + /* Add ofproto port config to JSON sub array. */ + struct json *json_port_config = json_object_create(); + struct smap config; + smap_init(&config); + if (!netdev_get_config(ofport->netdev, &config)) { + struct smap_node *node; + + SMAP_FOR_EACH (node, &config) { + json_object_put_string(json_port_config, node->key, + node->value); + } + } + smap_destroy(&config); + json_object_put(json_ofproto_port, "netdev_config", + json_port_config); + + json_array_add(json_ofproto_ports, json_ofproto_port); + } /* End of ofproto port(s). */ + + free(ports); + json_object_put(json_ofproto, "ports", json_ofproto_ports); + + json_array_add(json_ofprotos, json_ofproto); + } /* End of ofproto(s). */ + shash_destroy(&ofproto_shash); + free(ofprotos); + + json_object_put(json_backer, "ofprotos", json_ofprotos); + return json_backer; +} + static void -dpif_show_backer(const struct dpif_backer *backer, struct ds *ds) +dpif_show_backer_text(const struct dpif_backer *backer, struct ds *ds) { const struct shash_node **ofprotos; struct dpif_dp_stats dp_stats; @@ -6427,21 +6523,27 @@ dpif_show_backer(const struct dpif_backer *backer, struct ds *ds) static void ofproto_unixctl_dpif_show(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, - enum ovs_output_fmt fmt OVS_UNUSED, - void *aux OVS_UNUSED) + enum ovs_output_fmt fmt, void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; - const struct shash_node **backers; - int i; - backers = shash_sort(&all_dpif_backers); - for (i = 0; i < shash_count(&all_dpif_backers); i++) { - dpif_show_backer(backers[i]->data, &ds); - } - free(backers); + if (fmt == OVS_OUTPUT_FMT_JSON) { + struct json *backers = json_array_create_empty(); + const struct shash_node *backer; + SHASH_FOR_EACH (backer, &all_dpif_backers) { + json_array_add(backers, dpif_show_backer_json(backer->data)); + } + unixctl_command_reply_json(conn, backers); + } else { + const struct shash_node **backers = shash_sort(&all_dpif_backers); + for (int i = 0; i < shash_count(&all_dpif_backers); i++) { + dpif_show_backer_text(backers[i]->data, &ds); + } + free(backers); - unixctl_command_reply(conn, ds_cstr(&ds)); - ds_destroy(&ds); + unixctl_command_reply(conn, ds_cstr(&ds)); + ds_destroy(&ds); + } } static void @@ -6622,7 +6724,8 @@ ofproto_unixctl_init(void) ofproto_unixctl_mcast_snooping_show, NULL); unixctl_command_register("dpif/dump-dps", "", 0, 0, OVS_OUTPUT_FMT_TEXT, ofproto_unixctl_dpif_dump_dps, NULL); - unixctl_command_register("dpif/show", "", 0, 0, OVS_OUTPUT_FMT_TEXT, + unixctl_command_register("dpif/show", "", 0, 0, + OVS_OUTPUT_FMT_TEXT | OVS_OUTPUT_FMT_JSON, ofproto_unixctl_dpif_show, NULL); unixctl_command_register("dpif/show-dp-features", "bridge", 1, 1, OVS_OUTPUT_FMT_TEXT, diff --git a/tests/pmd.at b/tests/pmd.at index 3fcda13fd..de2dc0974 100644 --- a/tests/pmd.at +++ b/tests/pmd.at @@ -105,6 +105,34 @@ dummy@ovs-dummy: hit:0 missed:0 p0 1/1: (dummy-pmd: n_rxq=1, n_txq=1, numa_id=0) ]) +AT_CHECK([ovs-appctl --format json dpif/show], [0], [dnl +[[ + { + "name": "dummy@ovs-dummy", + "ofprotos": [ + { + "name": "br0", + "ports": [ + { + "netdev_config": { + }, + "netdev_name": "br0", + "netdev_type": "dummy-internal", + "odp_port": "100", + "ofp_port": "65534"}, + { + "netdev_config": { + "n_rxq": "1", + "n_txq": "1", + "numa_id": "0"}, + "netdev_name": "p0", + "netdev_type": "dummy-pmd", + "odp_port": "1", + "ofp_port": "1"}]}], + "stats": { + "n_hit": "0", + "n_missed": "0"}}]]]) + OVS_VSWITCHD_STOP AT_CLEANUP From patchwork Thu Nov 16 10:41:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakob Meng X-Patchwork-Id: 1864683 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=UrSGM+l0; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.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 4SWGn90vT1z1yRR for ; Thu, 16 Nov 2023 21:42:05 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 96290833DB; Thu, 16 Nov 2023 10:42:01 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 96290833DB 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=UrSGM+l0 X-Virus-Scanned: amavisd-new at osuosl.org 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 irOaTV3T74sp; Thu, 16 Nov 2023 10:41:59 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTPS id C5A558330B; Thu, 16 Nov 2023 10:41:55 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org C5A558330B Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 8883FC0DE4; Thu, 16 Nov 2023 10:41:51 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) by lists.linuxfoundation.org (Postfix) with ESMTP id EB265C0DDA for ; Thu, 16 Nov 2023 10:41:49 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id B889B42202 for ; Thu, 16 Nov 2023 10:41:49 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org B889B42202 Authentication-Results: smtp4.osuosl.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=UrSGM+l0 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id PwQpRjgpwG2j for ; Thu, 16 Nov 2023 10:41:49 +0000 (UTC) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by smtp4.osuosl.org (Postfix) with ESMTPS id CCC1441BDD for ; Thu, 16 Nov 2023 10:41:48 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org CCC1441BDD DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1700131307; 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=gG3KqaBNj1bPWp8hgOfMJ1oxOY+1zYnkjfejuLoexck=; b=UrSGM+l07QkQIdEYdrfNebjqVesayqeK67bZ6AiTO5s06GhtJpUetMbgqKJVAKC6kmXPU/ EC1UetW+uWs0lCvlPSesFjHybX/k9nLxgSHRSU7kypfxbpDRU0iZ/9nmFH/zib0+CMNAD2 ICPtcEzWg1uQ/dLL5nw6TOBhDCpfirE= Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-607-w898wKbRNsGR1fm0AXn53g-1; Thu, 16 Nov 2023 05:41:46 -0500 X-MC-Unique: w898wKbRNsGR1fm0AXn53g-1 Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-40a5290e259so3425715e9.2 for ; Thu, 16 Nov 2023 02:41:46 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1700131305; x=1700736105; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=gG3KqaBNj1bPWp8hgOfMJ1oxOY+1zYnkjfejuLoexck=; b=GTXJ4QT/xKdhNsdP4qsqznE3u70Xws/4jUyFD0jeBZ/yzsU0xaqtr1LFPaCnSn7w75 6FeICpg6MEfw9fxm2HjFsgPPnCev1yj5+SdivIs1h47wqpzu4WppqScyheeSGHPbIoO7 7Dy9qDrxWzB3Xs72wuhvIOwUF79AIYyPdi15JkIL9kgGt7Lmpk3Ce0YYN8pxocCPUB7v Zdb1Lmo7EJ7SCJKo4OHeh5c3KSyJSpE/kora+MUfFMcx8IQ3uOcVpR83MrEjqMvxI6lk IjrXwUAi3Uo0Uok33rnTVcZ19dumZ4IRc2C6ByRx4h9l8Vi33VeBUP9L/SWHKdR4nCMv uDwg== X-Gm-Message-State: AOJu0Yw2j+A/IhvrH85UGjhYH+cIP0kLlzVcgdHdBTNA1tEjr4LVq4hj Md5grHdJuc6sO6X7n4oAYDzep/LW7kQ4LEE4NMxwgV6GIXqrt8fq54tO0TkSmqt8Ul7zUlI8bjR w4pYir1ZN3k+HxFI7Ow3/R42qHVr/GaA6++y5jcXx2w75yhozK9WnHmUnHbEVcepE2iA= X-Received: by 2002:a05:600c:202:b0:404:4b6f:d705 with SMTP id 2-20020a05600c020200b004044b6fd705mr13020886wmi.17.1700131305071; Thu, 16 Nov 2023 02:41:45 -0800 (PST) X-Google-Smtp-Source: AGHT+IF6GdnJOAfHruFvm9oKNNFGSPwCfJ56SP/qczlSpFOEiPy5m/LsogkrjcNEQUfo8ayb6Ns1Dg== X-Received: by 2002:a05:600c:202:b0:404:4b6f:d705 with SMTP id 2-20020a05600c020200b004044b6fd705mr13020862wmi.17.1700131304589; Thu, 16 Nov 2023 02:41:44 -0800 (PST) Received: from positronik4lide.redhat.com ([87.122.56.153]) by smtp.gmail.com with ESMTPSA id n10-20020a05600c304a00b004080f0376a0sm2937210wmh.42.2023.11.16.02.41.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Nov 2023 02:41:44 -0800 (PST) From: jmeng@redhat.com To: dev@openvswitch.org, i.maximets@ovn.org, echaudro@redhat.com, ktraynor@redhat.com, aconole@redhat.com, rjarry@redhat.com Date: Thu, 16 Nov 2023 11:41:19 +0100 Message-Id: <20231116104120.25676-6-jmeng@redhat.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231116104120.25676-1-jmeng@redhat.com> References: <20231116104120.25676-1-jmeng@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH v4 5/6] appctl: Add option '--pretty' for pretty-printing JSON output. 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: Jakob Meng Signed-off-by: Jakob Meng --- NEWS | 3 +++ lib/unixctl.c | 4 ++-- lib/unixctl.h | 2 +- tests/pmd.at | 2 +- utilities/ovs-appctl.c | 19 +++++++++++++++++-- 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index fc77a1613..1796895a7 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,9 @@ Post-v3.2.0 Reported names adjusted accordingly. * Added new option [-f|--format] to choose the output format, e.g. 'json' or 'text' (by default). + * Added new option [--pretty] to print JSON output in a readable fashion. + E.g. members of objects and elements of arrays are printed one per line, + with indentation. - Python: * Added support for choosing the output format, e.g. 'json' or 'text'. diff --git a/lib/unixctl.c b/lib/unixctl.c index c82a5e92d..e7edbb154 100644 --- a/lib/unixctl.c +++ b/lib/unixctl.c @@ -553,7 +553,7 @@ unixctl_client_create(const char *path, struct jsonrpc **client) * '*err' if not NULL. */ int unixctl_client_transact(struct jsonrpc *client, const char *command, int argc, - char *argv[], enum ovs_output_fmt fmt, + char *argv[], enum ovs_output_fmt fmt, int fmt_flags, char **result, char **err) { struct jsonrpc_msg *request, *reply; @@ -622,7 +622,7 @@ unixctl_client_transact(struct jsonrpc *client, const char *command, int argc, *result = xstrdup(json_string(reply->result)); } else if (reply->result->type == JSON_OBJECT || reply->result->type == JSON_ARRAY) { - *result = json_to_string(reply->result, 0); + *result = json_to_string(reply->result, fmt_flags); } else { VLOG_WARN("%s: unexpected result type in JSON rpc reply: %s", jsonrpc_get_name(client), diff --git a/lib/unixctl.h b/lib/unixctl.h index 4b8193d9d..33d0152e5 100644 --- a/lib/unixctl.h +++ b/lib/unixctl.h @@ -39,7 +39,7 @@ int unixctl_client_create(const char *path, struct jsonrpc **client); int unixctl_client_transact(struct jsonrpc *client, const char *command, int argc, char *argv[], - enum ovs_output_fmt fmt, + enum ovs_output_fmt fmt, int fmt_flags, char **result, char **error); /* Command registration. */ diff --git a/tests/pmd.at b/tests/pmd.at index de2dc0974..21d59bf63 100644 --- a/tests/pmd.at +++ b/tests/pmd.at @@ -105,7 +105,7 @@ dummy@ovs-dummy: hit:0 missed:0 p0 1/1: (dummy-pmd: n_rxq=1, n_txq=1, numa_id=0) ]) -AT_CHECK([ovs-appctl --format json dpif/show], [0], [dnl +AT_CHECK([ovs-appctl --format json --pretty dpif/show], [0], [dnl [[ { "name": "dummy@ovs-dummy", diff --git a/utilities/ovs-appctl.c b/utilities/ovs-appctl.c index feff1be0b..606f293c5 100644 --- a/utilities/ovs-appctl.c +++ b/utilities/ovs-appctl.c @@ -26,6 +26,7 @@ #include "daemon.h" #include "dirs.h" #include "openvswitch/dynamic-string.h" +#include "openvswitch/json.h" #include "jsonrpc.h" #include "process.h" #include "timeval.h" @@ -38,6 +39,7 @@ static void usage(void); /* Parsed command line args. */ struct cmdl_args { enum ovs_output_fmt format; + int format_flags; char *target; }; @@ -67,7 +69,8 @@ main(int argc, char *argv[]) cmd_argc = argc - optind; cmd_argv = cmd_argc ? argv + optind : NULL; error = unixctl_client_transact(client, cmd, cmd_argc, cmd_argv, - args->format, &cmd_result, &cmd_error); + args->format, args->format_flags, + &cmd_result, &cmd_error); if (error) { ovs_fatal(error, "%s: transaction error", args->target); } @@ -113,6 +116,11 @@ Other options:\n\ --timeout=SECS wait at most SECS seconds for a response\n\ -f, --format=FMT Output format. One of: 'json', or 'text'\n\ ('text', by default)\n\ + --pretty By default, JSON in output is printed as compactly as\n\ + possible. This option causes JSON in output to be\n\ + printed in a more readable fashion. Members of objects\n\ + and elements of arrays are printed one per line, with\n\ + indentation.\n\ -h, --help Print this helpful information\n\ -V, --version Display ovs-appctl version information\n", program_name, program_name); @@ -124,6 +132,7 @@ cmdl_args_create(void) { struct cmdl_args *args = xmalloc(sizeof *args); args->format = OVS_OUTPUT_FMT_TEXT; + args->format_flags = 0; args->target = NULL; return args; @@ -143,7 +152,8 @@ parse_command_line(int argc, char *argv[]) { enum { OPT_START = UCHAR_MAX + 1, - VLOG_OPTION_ENUMS + OPT_PRETTY, + VLOG_OPTION_ENUMS, }; static const struct option long_options[] = { {"target", required_argument, NULL, 't'}, @@ -151,6 +161,7 @@ parse_command_line(int argc, char *argv[]) {"format", required_argument, NULL, 'f'}, {"help", no_argument, NULL, 'h'}, {"option", no_argument, NULL, 'o'}, + {"pretty", no_argument, NULL, OPT_PRETTY}, {"version", no_argument, NULL, 'V'}, {"timeout", required_argument, NULL, 'T'}, VLOG_LONG_OPTIONS, @@ -203,6 +214,10 @@ parse_command_line(int argc, char *argv[]) ovs_cmdl_print_options(long_options); exit(EXIT_SUCCESS); + case OPT_PRETTY: + args->format_flags |= JSSF_PRETTY | JSSF_SORT; + break; + case 'T': if (!str_to_uint(optarg, 10, &timeout) || !timeout) { ovs_fatal(0, "value %s on -T or --timeout is invalid", optarg); From patchwork Thu Nov 16 10:41:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakob Meng X-Patchwork-Id: 1864684 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=VryxRaTF; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::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 4SWGnB69wsz1yRR for ; Thu, 16 Nov 2023 21:42:06 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 1133F426CA; Thu, 16 Nov 2023 10:42:04 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 1133F426CA 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=VryxRaTF X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 0cS85oHQNzGY; Thu, 16 Nov 2023 10:42:00 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp4.osuosl.org (Postfix) with ESMTPS id 42AAD42527; Thu, 16 Nov 2023 10:41:58 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 42AAD42527 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 84E1CC008C; Thu, 16 Nov 2023 10:41:54 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id DB04EC0DD7 for ; Thu, 16 Nov 2023 10:41:52 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 510B683294 for ; Thu, 16 Nov 2023 10:41:52 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 510B683294 Authentication-Results: smtp1.osuosl.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=VryxRaTF X-Virus-Scanned: amavisd-new at osuosl.org 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 dA02LduMWZor for ; Thu, 16 Nov 2023 10:41:50 +0000 (UTC) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by smtp1.osuosl.org (Postfix) with ESMTPS id 4785E8322A for ; Thu, 16 Nov 2023 10:41:50 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 4785E8322A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1700131309; 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=BJeKw6RVJYM638q2HUr9qlq/y4BDgRvaff0cKkQvBWM=; b=VryxRaTFaTmsMwTDl32OQtRDxbTZ9qT82eT1K34Vm1uM1Q+Ay0GB8z1lsiXzReF905B0r6 Avs0PKvClYewwGI4f5mPwshvlqYMHdz5iDGDJ6daS9gIdcGntxBsA17/x7NoWJW6EwEFyv vEtOdqRWCwx2x8qr8ufmsT5CuFV3FGM= Received: from mail-lj1-f198.google.com (mail-lj1-f198.google.com [209.85.208.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-75-mXzhBF6zONGx88UH-PVMcQ-1; Thu, 16 Nov 2023 05:41:47 -0500 X-MC-Unique: mXzhBF6zONGx88UH-PVMcQ-1 Received: by mail-lj1-f198.google.com with SMTP id 38308e7fff4ca-2c6f33ee403so5581191fa.2 for ; Thu, 16 Nov 2023 02:41:47 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1700131306; x=1700736106; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=BJeKw6RVJYM638q2HUr9qlq/y4BDgRvaff0cKkQvBWM=; b=LSK4t70T861gjWLo3uSq9JvFRMlNPC6Mp+RPEkzjrS+3qXvXCGOzaACTw6YOjhrW/c sU42EaMP9lkMaqDy0bKkmdSdzL7ZSAqfkemAJD5CuJiw6YYdfW25Ez7I40cMGF2Ztam6 iOwJ4l+IoTUKy3kh2x3bBb0OB7NKrYp44CcqazxVO6aH6WMICsh4BW2uu6B2An31UjQx hTOA0qJk4O/cZOHPwqisnItSskms0ss8DrG2L7dd+LLXKWTC1GuvZC8D0+czYXe6ZxKL Z2f0JdF0XoTK/l0slzlIQuqoL0OgK0BUwXXvlzRzGSFyDAoV+DK+R8gLBDFomnq79v1t +qRg== X-Gm-Message-State: AOJu0YyQK7Ssl4c8t8zmdcbMvuZuAY5k7WBxTPTM+ULgCqb8GQ/bPLWm ZB9Z6fGmZTIz0tFoWq1RqAFn7e20oy+TFIXksZBbqH1ghbvt2tsT41z9GXi1iJNuHB7GzKepfIP ZgFhybc/mYvt3BRC3dcmqXxbB9JO+hjw+EkdrCrQS9VW5x+WiTV4D737Bpvgauuqxucw= X-Received: by 2002:a2e:a4cb:0:b0:2c5:5926:de52 with SMTP id p11-20020a2ea4cb000000b002c55926de52mr5061894ljm.53.1700131305939; Thu, 16 Nov 2023 02:41:45 -0800 (PST) X-Google-Smtp-Source: AGHT+IFsKh0+NnsxJhcsiy6aPlj78Q6m5PbGDPCnzc02+E3zdD0XUgC6gu96ssAxgxpWcrY3iN4GAg== X-Received: by 2002:a2e:a4cb:0:b0:2c5:5926:de52 with SMTP id p11-20020a2ea4cb000000b002c55926de52mr5061871ljm.53.1700131305489; Thu, 16 Nov 2023 02:41:45 -0800 (PST) Received: from positronik4lide.redhat.com ([87.122.56.153]) by smtp.gmail.com with ESMTPSA id n10-20020a05600c304a00b004080f0376a0sm2937210wmh.42.2023.11.16.02.41.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Nov 2023 02:41:45 -0800 (PST) From: jmeng@redhat.com To: dev@openvswitch.org, i.maximets@ovn.org, echaudro@redhat.com, ktraynor@redhat.com, aconole@redhat.com, rjarry@redhat.com Date: Thu, 16 Nov 2023 11:41:20 +0100 Message-Id: <20231116104120.25676-7-jmeng@redhat.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231116104120.25676-1-jmeng@redhat.com> References: <20231116104120.25676-1-jmeng@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH v4 6/6] unixctl: Pass output format as command args via JSON-RPC API. 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: Jakob Meng A previous patch had changed the JSON-RPC API in lib/unixctl.* (and its Python counterpart) in order to allow transporting the requested output format from ovs-xxx tools to ovs-vswitchd across unix sockets: The meaning of 'method' and 'params' had be changed: 'method' would be 'execute/v1' when an output format other than 'text' is requested. In that case, the first parameter of the JSON array 'params' would be the designated command, the second one the output format and the rest will be command args. That change allowed to transport the output format in a backward compatible way: One could use an updated client (ovs-appctl) with an old server (ovs-vswitchd) and vice versa. Of course, JSON output would only work when both sides have been updated. This patch reverts the JSON-RPC API to the old behaviour: The command will be copied to JSON-RPC's 'method' parameter while command args will be copied to the 'params' parameter. The client will inject the output format into the command args and the server will parse and remove it before passing the args to the command callback. The advantage of this (old) approach is a simpler JSON-RPC API but at the cost of inferior usability: ovs-xxx tools are no longer able to detect missing JSON support at the server side. Old servers will simply pass the output format as an arg to the command which would then result in an error such as 'command takes at most ... arguments' or a non-\ uniform error from the command callback. Signed-off-by: Jakob Meng --- lib/unixctl.c | 147 ++++++++++++++++------------------- python/ovs/unixctl/client.py | 19 ++--- python/ovs/unixctl/server.py | 37 ++++----- python/ovs/util.py | 1 - 4 files changed, 91 insertions(+), 113 deletions(-) diff --git a/lib/unixctl.c b/lib/unixctl.c index e7edbb154..1eaf6edb0 100644 --- a/lib/unixctl.c +++ b/lib/unixctl.c @@ -63,8 +63,6 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); static struct shash commands = SHASH_INITIALIZER(&commands); -static const char *rpc_marker = "execute/v1"; - static void unixctl_list_commands(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, @@ -292,11 +290,9 @@ process_command(struct unixctl_conn *conn, struct jsonrpc_msg *request) struct unixctl_command *command; struct json_array *params; - const char *method; - enum ovs_output_fmt fmt; + enum ovs_output_fmt fmt = OVS_OUTPUT_FMT_TEXT; struct svec argv = SVEC_EMPTY_INITIALIZER; - int args_offset; - bool plain_rpc; + int argc; COVERAGE_INC(unixctl_received); conn->request_id = json_clone(request->id); @@ -310,20 +306,9 @@ process_command(struct unixctl_conn *conn, struct jsonrpc_msg *request) free(id_s); } - /* The JSON-RPC API requires an indirection in order to allow transporting - * additional data like the output format besides command and args. For - * backward compatibility with older clients the plain RPC is still - * supported. */ - plain_rpc = strcmp(request->method, rpc_marker); - args_offset = plain_rpc ? 0 : 2; - params = json_array(request->params); - if (!plain_rpc && (params->n < 2)) { - error = xasprintf("JSON-RPC API mismatch: Unexpected # of params:"\ - " %"PRIuSIZE, params->n); - goto error; - } + /* Verify type of arguments. */ for (size_t i = 0; i < params->n; i++) { if (params->elems[i]->type != JSON_STRING) { error = xasprintf("command has non-string argument: %s", @@ -332,54 +317,70 @@ process_command(struct unixctl_conn *conn, struct jsonrpc_msg *request) } } - /* Extract method name. */ - method = plain_rpc ? request->method : json_string(params->elems[0]); + argc = params->n; - /* Extract output format. */ - if (plain_rpc) { - fmt = OVS_OUTPUT_FMT_TEXT; - } else { - if (!ovs_output_fmt_from_string(json_string(params->elems[1]), &fmt)) { - error = xasprintf("invalid output format: %s", - json_string(params->elems[1])); - goto error; + /* Extract and process command args. */ + svec_add(&argv, request->method); + for (size_t i = 0; i < params->n; i++) { + if (!strcmp(json_string(params->elems[i]), "-f") || + !strcmp(json_string(params->elems[i]), "--format")) + { + /* Parse output format argument. */ + + if ((i + 1) == (params->n)) { + error = xasprintf("option requires an argument -- %s", + json_string(params->elems[i])); + goto error; + } + + /* Move index to option argument. */ + i++; + + if (!ovs_output_fmt_from_string(json_string(params->elems[i]), + &fmt)) + { + error = xasprintf("option %s has invalid value %s", + json_string(params->elems[i - 1]), + json_string(params->elems[i])); + goto error; + } + + argc -= 2; + } else { + /* Pass other arguments to command. */ + svec_add(&argv, json_string(params->elems[i])); } } + svec_terminate(&argv); /* Find command with method name. */ - command = shash_find_data(&commands, method); + command = shash_find_data(&commands, request->method); /* Verify that method call complies with command requirements. */ if (!command) { error = xasprintf("\"%s\" is not a valid command (use " "\"list-commands\" to see a list of valid commands)", - method); + request->method); goto error; - } else if ((params->n - args_offset) < command->min_args) { + } else if (argc < command->min_args) { error = xasprintf("\"%s\" command requires at least %d arguments", - method, command->min_args); + request->method, command->min_args); goto error; - } else if ((params->n - args_offset) > command->max_args) { + } else if (argc > command->max_args) { error = xasprintf("\"%s\" command takes at most %d arguments", - method, command->max_args); + request->method, command->max_args); goto error; } else if ((!command->output_fmts && fmt != OVS_OUTPUT_FMT_TEXT) || (command->output_fmts && !(fmt & command->output_fmts))) { error = xasprintf("\"%s\" command does not support output format"\ - " \"%s\" %d %d", method, - ovs_output_fmt_to_string(fmt), command->output_fmts, + " \"%s\" %d %d", request->method, + ovs_output_fmt_to_string(fmt), + command->output_fmts, fmt); goto error; } - /* Extract command args. */ - svec_add(&argv, method); - for (size_t i = args_offset; i < params->n; i++) { - svec_add(&argv, json_string(params->elems[i])); - } - svec_terminate(&argv); - command->cb(conn, argv.n, (const char **) argv.names, fmt, command->aux); svec_destroy(&argv); @@ -387,6 +388,9 @@ process_command(struct unixctl_conn *conn, struct jsonrpc_msg *request) return; error: unixctl_command_reply_error(conn, error); + if (!svec_is_empty(&argv)) { + svec_destroy(&argv); + } free(error); } @@ -558,39 +562,32 @@ unixctl_client_transact(struct jsonrpc *client, const char *command, int argc, { struct jsonrpc_msg *request, *reply; struct json **json_args, *params; - int error, i; - /* The JSON-RPC API requires an indirection in order to allow transporting - * additional data like the output format besides command and args. For - * backward compatibility with older servers the plain RPC is still - * supported. */ - bool plain_rpc = (fmt == OVS_OUTPUT_FMT_TEXT); + int error, i, argcx = 0; + + if (fmt != OVS_OUTPUT_FMT_TEXT) { + argcx += 2; + } *result = NULL; *err = NULL; - if (plain_rpc) { - json_args = xmalloc(argc * sizeof *json_args); - for (i = 0; i < argc; i++) { - json_args[i] = json_string_create(argv[i]); - } - - params = json_array_create(json_args, argc); - request = jsonrpc_create_request(command, params, NULL); - } else { - json_args = xmalloc((argc + 2) * sizeof *json_args); - json_args[0] = json_string_create(command); - json_args[1] = ovs_output_fmt_to_json(fmt); - for (i = 0; i < argc; i++) { - json_args[i + 2] = json_string_create(argv[i]); - } - - params = json_array_create(json_args, argc + 2); + json_args = xmalloc((argc + argcx) * sizeof *json_args); + for (i = 0; i < argc; i++) { + json_args[i] = json_string_create(argv[i]); + } - /* Use a versioned command to ensure that both server and client - * use the same JSON-RPC API. */ - request = jsonrpc_create_request(rpc_marker, params, NULL); + /* Pass output format for non-text only to keep compatibility with old + servers. */ + if (fmt != OVS_OUTPUT_FMT_TEXT) { + json_args[i] = json_string_create("--format"); + ++i; + json_args[i] = ovs_output_fmt_to_json(fmt); + ++i; } + params = json_array_create(json_args, argc + argcx); + request = jsonrpc_create_request(command, params, NULL); + error = jsonrpc_transact_block(client, request, &reply); if (error) { VLOG_WARN("error communicating with %s: %s", jsonrpc_get_name(client), @@ -600,17 +597,7 @@ unixctl_client_transact(struct jsonrpc *client, const char *command, int argc, if (reply->error) { if (reply->error->type == JSON_STRING) { - /* Catch incompatible server and return helpful error msg. */ - char *plain_rpc_error = xasprintf("\"%s\" is not a valid command", - rpc_marker); - if (!strncmp(plain_rpc_error, json_string(reply->error), - strlen(plain_rpc_error))) { - *err = xstrdup("JSON RPC reply indicates incompatible server. " - "Please upgrade server side to newer version."); - } else { - *err = xstrdup(json_string(reply->error)); - } - free(plain_rpc_error); + *err = xstrdup(json_string(reply->error)); } else { VLOG_WARN("%s: unexpected error type in JSON RPC reply: %s", jsonrpc_get_name(client), diff --git a/python/ovs/unixctl/client.py b/python/ovs/unixctl/client.py index 29a5f3df9..bd690d099 100644 --- a/python/ovs/unixctl/client.py +++ b/python/ovs/unixctl/client.py @@ -32,13 +32,11 @@ class UnixctlClient(object): for arg in argv: assert isinstance(arg, str) assert isinstance(fmt, ovs.util.OutputFormat) - plain_rpc = (fmt == ovs.util.OutputFormat.TEXT) - if plain_rpc: - request = ovs.jsonrpc.Message.create_request(command, argv) - else: - request = ovs.jsonrpc.Message.create_request( - "execute/v1", [command, fmt.name.lower()] + argv) + request = ovs.jsonrpc.Message.create_request( + command, + argv + ([] if (fmt == ovs.util.OutputFormat.TEXT) + else ["--format", fmt.name.lower()])) error, reply = self._conn.transact_block(request) @@ -48,14 +46,7 @@ class UnixctlClient(object): return error, None, None if reply.error is not None: - plain_rpc_error = ('"%s" is not a valid command' % - ovs.util.RPC_MARKER) - if str(reply.error).startswith(plain_rpc_error): - return 0, "JSON RPC reply indicates incompatible "\ - "server. Please upgrade server side to "\ - "newer version.", None - else: - return 0, str(reply.error), None + return 0, str(reply.error), None else: assert reply.result is not None return 0, None, str(reply.result) diff --git a/python/ovs/unixctl/server.py b/python/ovs/unixctl/server.py index 849739e89..2db855948 100644 --- a/python/ovs/unixctl/server.py +++ b/python/ovs/unixctl/server.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import argparse import copy import errno import os @@ -105,34 +106,32 @@ class UnixctlConnection(object): self._request_id = request.id try: - plain_rpc = request.method != ovs.util.RPC_MARKER - args_offset = 0 if plain_rpc else 2 - - if not plain_rpc and len(request.params) < 2: - raise ValueError( - "JSON-RPC API mismatch: Unexpected # of params: %d" - % len(request.params)) - for param in request.params: if not isinstance(param, str): raise ValueError( "command has non-string argument: %s" % param) - method = request.method if plain_rpc else request.params[0] - if plain_rpc: - fmt = ovs.util.OutputFormat.TEXT - else: - fmt = ovs.util.OutputFormat[request.params[1].upper()] - params = request.params[args_offset:] + params = request.params + + parser = argparse.ArgumentParser() + parser.add_argument("argv", nargs="*") + parser.add_argument("-f", "--format", + default="text", + choices=[fmt.name.lower() + for fmt in ovs.util.OutputFormat]) + args = parser.parse_args(params) + fmt = ovs.util.OutputFormat[args.format.upper()] + method = request.method command = ovs.unixctl.commands.get(method) + if command is None: raise ValueError('"%s" is not a valid command' % method) - elif len(params) < command.min_args: + elif len(args.argv) < command.min_args: raise ValueError( '"%s" command requires at least %d arguments' % (method, command.min_args)) - elif len(params) > command.max_args: + elif len(args.argv) > command.max_args: raise ValueError( '"%s" command takes at most %d arguments' % (method, command.max_args)) @@ -141,8 +140,10 @@ class UnixctlConnection(object): ' "%s" %d %d' % (method, fmt.name.lower(), command.output_fmts, fmt)) - unicode_params = [str(p) for p in params] - command.callback(self, unicode_params, fmt, command.aux) + command.callback(self, + args.argv, + fmt, + command.aux) except Exception as e: self.reply_error(str(e)) diff --git a/python/ovs/util.py b/python/ovs/util.py index 75ba4ee12..272ca683d 100644 --- a/python/ovs/util.py +++ b/python/ovs/util.py @@ -19,7 +19,6 @@ import enum PROGRAM_NAME = os.path.basename(sys.argv[0]) EOF = -1 -RPC_MARKER = "execute/v1" @enum.unique