On 7/4/24 16:09, [email protected] wrote:
> From: Jakob Meng <[email protected]>
>
> 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 <[email protected]>
> ---
> NEWS | 2 +-
> ofproto/ofproto-dpif.c | 127 ++++++++++++++++++++++++++++++++++++-----
> tests/ofproto-dpif.at | 40 +++++++++++++
> 3 files changed, 154 insertions(+), 15 deletions(-)
>
> diff --git a/NEWS b/NEWS
> index 8c59a4979..4803566f5 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -6,7 +6,7 @@ Post-v3.3.0
> * 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.
> - * 'list-commands' now supports output in JSON format.
> + * 'dpif/show' and 'list-commands' now support output in JSON format.
> - Python:
> * Added support for different output formats like 'json' to appctl.py
> and
> Python's unixctl classes.
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index fcd7cd753..52d9b0c5b 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -28,6 +28,7 @@
> #include "fail-open.h"
> #include "guarded-list.h"
> #include "hmapx.h"
> +#include "json.h"
openvswitch/json.h will suffice.
> #include "lacp.h"
> #include "learn.h"
> #include "mac-learning.h"
> @@ -6519,19 +6520,109 @@ done:
> return changed;
> }
>
> -static void
> -dpif_show_backer(const struct dpif_backer *backer, struct ds *ds)
> +static struct json *
> +dpif_show_backer_json(struct json *backers, const struct dpif_backer *backer)
> {
> + struct json *json_backer = json_object_create();
> +
> + /* Add datapath as new JSON object using its name as key. */
> + json_object_put(backers, dpif_name(backer->dpif), json_backer);
> +
> + /* Add datapath's stats under "stats" key. */
> + struct json *json_dp_stats = json_object_create();
> + struct dpif_dp_stats dp_stats;
> +
> + dpif_get_dp_stats(backer->dpif, &dp_stats);
> + json_object_put_format(json_dp_stats, "hit", "%"PRIu64, dp_stats.n_hit);
> + json_object_put_format(json_dp_stats, "missed", "%"PRIu64,
> + dp_stats.n_missed);
> + json_object_put(json_backer, "stats", json_dp_stats);
> +
> + /* Add datapath's bridges under "bridges" key. */
> + struct json *json_dp_bridges = json_object_create();
> +
> + struct shash ofproto_shash = SHASH_INITIALIZER(&ofproto_shash);
> + free(get_ofprotos(&ofproto_shash));
> +
> + struct shash_node *node;
> + SHASH_FOR_EACH (node, &ofproto_shash) {
> + struct ofproto_dpif *ofproto = node->data;
> +
> + if (ofproto->backer != backer) {
> + continue;
> + }
> +
> + /* Add bridge to "bridges" dictionary using its name as key. */
> + struct json *json_ofproto = json_object_create();
> +
> + /* Add bridge ports to the current bridge dictionary. */
> + const struct shash_node *port;
> + SHASH_FOR_EACH (port, &ofproto->up.port_by_name) {
> + /* Add bridge port to a bridge's dict using port name as key. */
> + struct ofport *ofport = port->data;
> + struct json *json_ofproto_port = json_object_create();
Reverse x-mass tree.
> +
> + /* Add OpenFlow port associated with a bridge port. */
> + json_object_put_format(json_ofproto_port, "ofport", "%"PRIu32,
> + ofport->ofp_port);
> +
> + /* Add bridge port number. */
> + 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, "port_no",
> + "%"PRIu32, odp_port);
> + } else {
> + json_object_put_string(json_ofproto_port, "port_no", "none");
> + }
> +
> + /* Add type of a bridge port. */
> + json_object_put_string(json_ofproto_port, "type",
> + netdev_get_type(ofport->netdev));
> +
> + /* Add config entries for a bridge port. */
> +
> + struct smap config = SMAP_INITIALIZER(&config);
An empty line.
> + if (!netdev_get_config(ofport->netdev, &config)
> + && smap_count(&config))
> + {
'{' should be on a previous line.
> + struct json *json_port_config = json_object_create();
> + struct smap_node *cfg_node;
> +
> + SMAP_FOR_EACH (cfg_node, &config) {
> + json_object_put_string(json_port_config, cfg_node->key,
> + cfg_node->value);
> + }
> + json_object_put(json_ofproto_port, "config",
> json_port_config);
> + }
> + smap_destroy(&config);
> +
> +
One too mnay empty lines.
> + json_object_put(json_ofproto, netdev_get_name(ofport->netdev),
> + json_ofproto_port);
> + } /* End of bridge port(s). */
> +
> + json_object_put(json_dp_bridges, ofproto->up.name, json_ofproto);
> + } /* End of bridge(s). */
> +
> + shash_destroy(&ofproto_shash);
> +
> + json_object_put(json_backer, "bridges", json_dp_bridges);
> + return json_backer;
> +}
> +
> +static void
> +dpif_show_backer_text(const struct dpif_backer *backer, struct ds *ds)
> +{
> + struct shash ofproto_shash = SHASH_INITIALIZER(&ofproto_shash);
> const struct shash_node **ofprotos;
> struct dpif_dp_stats dp_stats;
> - struct shash ofproto_shash;
> size_t i;
>
> dpif_get_dp_stats(backer->dpif, &dp_stats);
> ds_put_format(ds, "%s: hit:%"PRIu64" missed:%"PRIu64"\n",
> dpif_name(backer->dpif), dp_stats.n_hit,
> dp_stats.n_missed);
>
> - shash_init(&ofproto_shash);
> ofprotos = get_ofprotos(&ofproto_shash);
> for (i = 0; i < shash_count(&ofproto_shash); i++) {
> struct ofproto_dpif *ofproto = ofprotos[i]->data;
> @@ -6587,18 +6678,26 @@ static void
> ofproto_unixctl_dpif_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
> const char *argv[] OVS_UNUSED, void *aux
> OVS_UNUSED)
> {
> - struct ds ds = DS_EMPTY_INITIALIZER;
> - const struct shash_node **backers;
> - int i;
> + if (unixctl_command_get_output_format(conn) == UNIXCTL_OUTPUT_FMT_JSON) {
> + struct json *backers = json_object_create();
> + const struct shash_node *backer;
>
> - backers = shash_sort(&all_dpif_backers);
> - for (i = 0; i < shash_count(&all_dpif_backers); i++) {
> - dpif_show_backer(backers[i]->data, &ds);
> + SHASH_FOR_EACH (backer, &all_dpif_backers) {
> + dpif_show_backer_json(backers, backer->data);
> + }
> + unixctl_command_reply_json(conn, backers);
> + } else {
> + const struct shash_node **backers = shash_sort(&all_dpif_backers);
> + struct ds ds = DS_EMPTY_INITIALIZER;
> +
> + 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);
> }
> - free(backers);
> -
> - unixctl_command_reply(conn, ds_cstr(&ds));
> - ds_destroy(&ds);
> }
>
> static void
> diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
> index 0b23fd6c5..30ef0468c 100644
> --- a/tests/ofproto-dpif.at
> +++ b/tests/ofproto-dpif.at
> @@ -8879,6 +8879,46 @@ dummy@ovs-dummy: hit:0 missed:0
> br1 65534/101: (dummy-internal)
> p3 3/3: (dummy)
> ])
> +
> +AT_CHECK([ovs-appctl --format json --pretty dpif/show], [0], [dnl
> +[{
> + "dummy@ovs-dummy": {
> + "bridges": {
> + "br0": {
> + "br0": {
> + "ofport": "65534",
> + "port_no": "100",
> + "type": "dummy-internal"},
> + "p1": {
> + "config": {
> + "n_rxq": "1",
> + "n_txq": "1",
> + "numa_id": "0"},
> + "ofport": "1",
> + "port_no": "1",
> + "type": "dummy-pmd"},
> + "p2": {
> + "config": {
> + "n_rxq": "1",
> + "n_txq": "1",
> + "numa_id": "0"},
> + "ofport": "2",
> + "port_no": "2",
> + "type": "dummy-pmd"}},
> + "br1": {
> + "br1": {
> + "ofport": "65534",
> + "port_no": "101",
> + "type": "dummy-internal"},
> + "p3": {
> + "ofport": "3",
> + "port_no": "3",
> + "type": "dummy"}}},
> + "stats": {
> + "hit": "0",
> + "missed": "0"}}}]
> +])
> +
> OVS_VSWITCHD_STOP
> AT_CLEANUP
>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev