Skip to content

Commit 4935e89

Browse files
JM1igsilya
authored andcommitted
ofproto: Add JSON output for 'dpif/show' command.
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 <code@jakobmeng.de> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
1 parent 379d036 commit 4935e89

File tree

3 files changed

+152
-14
lines changed

3 files changed

+152
-14
lines changed

NEWS

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Post-v3.3.0
66
* Added new option [-f|--format] to choose the output format, e.g. 'json'
77
or 'text' (by default).
88
* Added new option [--pretty] to print JSON output in a readable fashion.
9-
* 'list-commands' now supports output in JSON format.
9+
* 'dpif/show' and 'list-commands' now support output in JSON format.
1010
- Userspace datapath:
1111
* Conntrack now supports 'random' flag for selecting ports in a range
1212
while natting and 'persistent' flag for selection of the IP address

ofproto/ofproto-dpif.c

+111-13
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "fail-open.h"
2929
#include "guarded-list.h"
3030
#include "hmapx.h"
31+
#include "openvswitch/json.h"
3132
#include "lacp.h"
3233
#include "learn.h"
3334
#include "mac-learning.h"
@@ -6519,19 +6520,108 @@ dpif_set_support(struct dpif_backer_support *rt_support,
65196520
return changed;
65206521
}
65216522

6523+
static struct json *
6524+
dpif_show_backer_json(struct json *backers, const struct dpif_backer *backer)
6525+
{
6526+
struct json *json_backer = json_object_create();
6527+
6528+
/* Add datapath as new JSON object using its name as key. */
6529+
json_object_put(backers, dpif_name(backer->dpif), json_backer);
6530+
6531+
/* Add datapath's stats under "stats" key. */
6532+
struct json *json_dp_stats = json_object_create();
6533+
struct dpif_dp_stats dp_stats;
6534+
6535+
dpif_get_dp_stats(backer->dpif, &dp_stats);
6536+
json_object_put_format(json_dp_stats, "hit", "%"PRIu64, dp_stats.n_hit);
6537+
json_object_put_format(json_dp_stats, "missed", "%"PRIu64,
6538+
dp_stats.n_missed);
6539+
json_object_put(json_backer, "stats", json_dp_stats);
6540+
6541+
/* Add datapath's bridges under "bridges" key. */
6542+
struct json *json_dp_bridges = json_object_create();
6543+
6544+
struct shash ofproto_shash = SHASH_INITIALIZER(&ofproto_shash);
6545+
free(get_ofprotos(&ofproto_shash));
6546+
6547+
struct shash_node *node;
6548+
SHASH_FOR_EACH (node, &ofproto_shash) {
6549+
struct ofproto_dpif *ofproto = node->data;
6550+
6551+
if (ofproto->backer != backer) {
6552+
continue;
6553+
}
6554+
6555+
/* Add bridge to "bridges" dictionary using its name as key. */
6556+
struct json *json_ofproto = json_object_create();
6557+
6558+
/* Add bridge ports to the current bridge dictionary. */
6559+
const struct shash_node *port;
6560+
SHASH_FOR_EACH (port, &ofproto->up.port_by_name) {
6561+
/* Add bridge port to a bridge's dict using port name as key. */
6562+
struct json *json_ofproto_port = json_object_create();
6563+
struct ofport *ofport = port->data;
6564+
6565+
/* Add OpenFlow port associated with a bridge port. */
6566+
json_object_put_format(json_ofproto_port, "ofport", "%"PRIu32,
6567+
ofport->ofp_port);
6568+
6569+
/* Add bridge port number. */
6570+
odp_port_t odp_port = ofp_port_to_odp_port(ofproto,
6571+
ofport->ofp_port);
6572+
if (odp_port != ODPP_NONE) {
6573+
json_object_put_format(json_ofproto_port, "port_no",
6574+
"%"PRIu32, odp_port);
6575+
} else {
6576+
json_object_put_string(json_ofproto_port, "port_no", "none");
6577+
}
6578+
6579+
/* Add type of a bridge port. */
6580+
json_object_put_string(json_ofproto_port, "type",
6581+
netdev_get_type(ofport->netdev));
6582+
6583+
/* Add config entries for a bridge port. */
6584+
6585+
struct smap config = SMAP_INITIALIZER(&config);
6586+
6587+
if (!netdev_get_config(ofport->netdev, &config)
6588+
&& smap_count(&config)) {
6589+
struct json *json_port_config = json_object_create();
6590+
struct smap_node *cfg_node;
6591+
6592+
SMAP_FOR_EACH (cfg_node, &config) {
6593+
json_object_put_string(json_port_config, cfg_node->key,
6594+
cfg_node->value);
6595+
}
6596+
json_object_put(json_ofproto_port, "config", json_port_config);
6597+
}
6598+
smap_destroy(&config);
6599+
6600+
json_object_put(json_ofproto, netdev_get_name(ofport->netdev),
6601+
json_ofproto_port);
6602+
} /* End of bridge port(s). */
6603+
6604+
json_object_put(json_dp_bridges, ofproto->up.name, json_ofproto);
6605+
} /* End of bridge(s). */
6606+
6607+
shash_destroy(&ofproto_shash);
6608+
6609+
json_object_put(json_backer, "bridges", json_dp_bridges);
6610+
return json_backer;
6611+
}
6612+
65226613
static void
6523-
dpif_show_backer(const struct dpif_backer *backer, struct ds *ds)
6614+
dpif_show_backer_text(const struct dpif_backer *backer, struct ds *ds)
65246615
{
6616+
struct shash ofproto_shash = SHASH_INITIALIZER(&ofproto_shash);
65256617
const struct shash_node **ofprotos;
65266618
struct dpif_dp_stats dp_stats;
6527-
struct shash ofproto_shash;
65286619
size_t i;
65296620

65306621
dpif_get_dp_stats(backer->dpif, &dp_stats);
65316622
ds_put_format(ds, "%s: hit:%"PRIu64" missed:%"PRIu64"\n",
65326623
dpif_name(backer->dpif), dp_stats.n_hit, dp_stats.n_missed);
65336624

6534-
shash_init(&ofproto_shash);
65356625
ofprotos = get_ofprotos(&ofproto_shash);
65366626
for (i = 0; i < shash_count(&ofproto_shash); i++) {
65376627
struct ofproto_dpif *ofproto = ofprotos[i]->data;
@@ -6587,18 +6677,26 @@ static void
65876677
ofproto_unixctl_dpif_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
65886678
const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
65896679
{
6590-
struct ds ds = DS_EMPTY_INITIALIZER;
6591-
const struct shash_node **backers;
6592-
int i;
6680+
if (unixctl_command_get_output_format(conn) == UNIXCTL_OUTPUT_FMT_JSON) {
6681+
struct json *backers = json_object_create();
6682+
const struct shash_node *backer;
65936683

6594-
backers = shash_sort(&all_dpif_backers);
6595-
for (i = 0; i < shash_count(&all_dpif_backers); i++) {
6596-
dpif_show_backer(backers[i]->data, &ds);
6597-
}
6598-
free(backers);
6684+
SHASH_FOR_EACH (backer, &all_dpif_backers) {
6685+
dpif_show_backer_json(backers, backer->data);
6686+
}
6687+
unixctl_command_reply_json(conn, backers);
6688+
} else {
6689+
const struct shash_node **backers = shash_sort(&all_dpif_backers);
6690+
struct ds ds = DS_EMPTY_INITIALIZER;
65996691

6600-
unixctl_command_reply(conn, ds_cstr(&ds));
6601-
ds_destroy(&ds);
6692+
for (int i = 0; i < shash_count(&all_dpif_backers); i++) {
6693+
dpif_show_backer_text(backers[i]->data, &ds);
6694+
}
6695+
free(backers);
6696+
6697+
unixctl_command_reply(conn, ds_cstr(&ds));
6698+
ds_destroy(&ds);
6699+
}
66026700
}
66036701

66046702
static void

tests/ofproto-dpif.at

+40
Original file line numberDiff line numberDiff line change
@@ -8879,6 +8879,46 @@ dummy@ovs-dummy: hit:0 missed:0
88798879
br1 65534/101: (dummy-internal)
88808880
p3 3/3: (dummy)
88818881
])
8882+
8883+
AT_CHECK([ovs-appctl --format json --pretty dpif/show], [0], [dnl
8884+
[{
8885+
"dummy@ovs-dummy": {
8886+
"bridges": {
8887+
"br0": {
8888+
"br0": {
8889+
"ofport": "65534",
8890+
"port_no": "100",
8891+
"type": "dummy-internal"},
8892+
"p1": {
8893+
"config": {
8894+
"n_rxq": "1",
8895+
"n_txq": "1",
8896+
"numa_id": "0"},
8897+
"ofport": "1",
8898+
"port_no": "1",
8899+
"type": "dummy-pmd"},
8900+
"p2": {
8901+
"config": {
8902+
"n_rxq": "1",
8903+
"n_txq": "1",
8904+
"numa_id": "0"},
8905+
"ofport": "2",
8906+
"port_no": "2",
8907+
"type": "dummy-pmd"}},
8908+
"br1": {
8909+
"br1": {
8910+
"ofport": "65534",
8911+
"port_no": "101",
8912+
"type": "dummy-internal"},
8913+
"p3": {
8914+
"ofport": "3",
8915+
"port_no": "3",
8916+
"type": "dummy"}}},
8917+
"stats": {
8918+
"hit": "0",
8919+
"missed": "0"}}}]
8920+
])
8921+
88828922
OVS_VSWITCHD_STOP
88838923
AT_CLEANUP
88848924

0 commit comments

Comments
 (0)