From: Dima Chumak <[email protected]>

The 'fdb/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 --pretty fdb/show br-phy
  [
    {
      "static": true,
      "mac": "e4:8c:07:08:00:02",
      "port": 2,
      "vlan": 0
    },
    {
      "age": 14,
      "mac": "e4:8c:07:08:00:03",
      "port": 3,
      "vlan": 0
    }
  ]

Signed-off-by: Dima Chumak <[email protected]>
Acked-by: Roi Dayan <[email protected]>
---

Notes:
    v6
    - Move hmap_count under lock.
    - Assert if item count does not match.
    - Change test to use regex * instead of \+.
    
    v5
    - Forgot to remove the wrong string output of age static.
    - Added test case for static entry. The two testsuite case numbers are 1279 
1282.
    
    v4
    - Make sure not to set more entries than allocated in json output.
    - Fix json output to have either boolean static or integer age and not mix 
the types.
    
    v3
    - Fix assert. No need to call json_destroy() after 
unixctl_command_reply_json() as it takes
      ownership of the allocated body.
    
    v2
    - Fix sparse check error.
    - Add case checking fdb/show json output.

 ofproto/ofproto-dpif.c | 90 ++++++++++++++++++++++++++++++++++--------
 tests/ofproto-dpif.at  | 42 ++++++++++++++++++++
 2 files changed, 116 insertions(+), 16 deletions(-)

diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index bf43d5d4bc59..25b1d932259f 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -6151,20 +6151,12 @@ 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)
+ofproto_unixctl_fdb_show_text(const struct ofproto_dpif *ofproto,
+                              struct ds *ds)
 {
-    struct ds ds = DS_EMPTY_INITIALIZER;
-    const struct ofproto_dpif *ofproto;
     const struct mac_entry *e;
 
-    ofproto = ofproto_dpif_lookup_by_name(argv[1]);
-    if (!ofproto) {
-        unixctl_command_reply_error(conn, "no such bridge");
-        return;
-    }
-
-    ds_put_cstr(&ds, " port  VLAN  MAC                Age\n");
+    ds_put_cstr(ds, " port  VLAN  MAC                Age\n");
     ovs_rwlock_rdlock(&ofproto->ml->rwlock);
     LIST_FOR_EACH (e, lru_node, &ofproto->ml->lrus) {
         struct ofbundle *bundle = mac_entry_get_port(ofproto->ml, e);
@@ -6173,17 +6165,83 @@ ofproto_unixctl_fdb_show(struct unixctl_conn *conn, int 
argc OVS_UNUSED,
 
         ofputil_port_to_string(ofbundle_get_a_port(bundle)->up.ofp_port,
                 NULL, name, sizeof name);
-        ds_put_format(&ds, "%5s  %4d  "ETH_ADDR_FMT"  ",
+        ds_put_format(ds, "%5s  %4d  "ETH_ADDR_FMT"  ",
                 name, e->vlan, ETH_ADDR_ARGS(e->mac));
         if (MAC_ENTRY_AGE_STATIC_ENTRY == age) {
-            ds_put_format(&ds, "static\n");
+            ds_put_format(ds, "static\n");
         } else {
-            ds_put_format(&ds, "%3d\n", age);
+            ds_put_format(ds, "%3d\n", age);
         }
     }
     ovs_rwlock_unlock(&ofproto->ml->rwlock);
-    unixctl_command_reply(conn, ds_cstr(&ds));
-    ds_destroy(&ds);
+}
+
+static void
+ofproto_unixctl_fdb_show_json(const struct ofproto_dpif *ofproto,
+                              struct json **fdb_entries)
+{
+    struct json **json_entries = NULL;
+    const struct mac_entry *entry;
+    size_t num_entries;
+    int i = 0;
+
+    ovs_rwlock_rdlock(&ofproto->ml->rwlock);
+
+    num_entries = hmap_count(&ofproto->ml->table);
+    if (!num_entries) {
+        goto done_unlock;
+    }
+
+    json_entries = xmalloc(num_entries * sizeof *json_entries);
+
+    LIST_FOR_EACH (entry, lru_node, &ofproto->ml->lrus) {
+        struct ofbundle *bundle = mac_entry_get_port(ofproto->ml, entry);
+        struct ofport_dpif *port = ofbundle_get_a_port(bundle);
+        struct json *json_entry = json_object_create();
+        int age = mac_entry_age(ofproto->ml, entry);
+
+        ovs_assert(i < num_entries);
+        json_object_put(json_entry, "port",
+                        json_integer_create(
+                            (OVS_FORCE long long) port->up.ofp_port));
+        json_object_put(json_entry, "vlan", json_integer_create(entry->vlan));
+        json_object_put_format(json_entry, "mac", ETH_ADDR_FMT,
+                               ETH_ADDR_ARGS(entry->mac));
+        if (MAC_ENTRY_AGE_STATIC_ENTRY == age) {
+            json_object_put(json_entry, "static", json_boolean_create(true));
+        } else {
+            json_object_put(json_entry, "age", json_integer_create(age));
+        }
+        json_entries[i++] = json_entry;
+    }
+done_unlock:
+    ovs_rwlock_unlock(&ofproto->ml->rwlock);
+    *fdb_entries = json_array_create(json_entries, i);
+}
+
+static void
+ofproto_unixctl_fdb_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
+                          const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
+{
+    const struct ofproto_dpif *ofproto = ofproto_dpif_lookup_by_name(argv[1]);
+
+    if (!ofproto) {
+        unixctl_command_reply_error(conn, "no such bridge");
+        return;
+    }
+
+    if (unixctl_command_get_output_format(conn) == UNIXCTL_OUTPUT_FMT_JSON) {
+        struct json *fdb_entries;
+
+        ofproto_unixctl_fdb_show_json(ofproto, &fdb_entries);
+        unixctl_command_reply_json(conn, fdb_entries);
+    } else {
+        struct ds ds = DS_EMPTY_INITIALIZER;
+
+        ofproto_unixctl_fdb_show_text(ofproto, &ds);
+        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 fa5f148b4c28..e0ae42d77c7e 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -7100,6 +7100,22 @@ AT_CHECK_UNQUOTED([ovs-appctl fdb/show br0 | sed 
's/[[0-9]]\{1,\}$/?/'], [0], [d
     1     0  50:54:00:00:00:06    ?
 ])
 
+dnl Check json output.
+AT_CHECK([ovs-appctl --format json --pretty fdb/show br0 \
+          | sed 's/"age": [[0-9]]*/"age": ?/g'], [0], [dnl
+[[
+  {
+    "age": ?,
+    "mac": "50:54:00:00:00:05",
+    "port": 3,
+    "vlan": 0},
+  {
+    "age": ?,
+    "mac": "50:54:00:00:00:06",
+    "port": 1,
+    "vlan": 0}]]
+])
+
 # Trace a packet arrival that updates the first learned MAC entry.
 OFPROTO_TRACE(
   [ovs-dummy],
@@ -7708,6 +7724,32 @@ AT_CHECK_UNQUOTED([ovs-appctl fdb/show br0 | sed 's/ 
*[[0-9]]\{1,\}$//' | grep -
     2     0  50:54:00:00:02:02  static
 ])
 
+dnl Check json output.
+AT_CHECK([ovs-appctl --format json --pretty fdb/show br0 \
+          | sed 's/"age": [[0-9]]\+/"age": ?/g'], [0], [dnl
+[[
+  {
+    "age": ?,
+    "mac": "50:54:00:00:00:01",
+    "port": 1,
+    "vlan": 0},
+  {
+    "age": ?,
+    "mac": "50:54:00:00:00:02",
+    "port": 2,
+    "vlan": 0},
+  {
+    "mac": "50:54:00:00:01:01",
+    "port": 1,
+    "static": true,
+    "vlan": 0},
+  {
+    "mac": "50:54:00:00:02:02",
+    "port": 2,
+    "static": true,
+    "vlan": 0}]]
+])
+
 dnl Remove static mac entry.
 AT_CHECK([ovs-appctl fdb/del br0 0 50:54:00:00:01:01])
 
-- 
2.21.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to