Signed-off-by: Ben Pfaff <b...@ovn.org>
---
 include/openvswitch/ofp-bundle.h     |  11 +-
 include/openvswitch/ofp-connection.h |  18 +-
 include/openvswitch/ofp-ipfix.h      |   5 +
 include/openvswitch/ofp-match.h      |   9 +-
 include/openvswitch/ofp-meter.h      |  12 +
 include/openvswitch/ofp-monitor.h    |   4 +
 include/openvswitch/ofp-port.h       |   3 +
 include/openvswitch/ofp-queue.h      |  14 +
 include/openvswitch/ofp-table.h      |   6 +
 lib/ofp-bundle.c                     |  70 +++
 lib/ofp-connection.c                 | 197 +++++++
 lib/ofp-ipfix.c                      |  51 ++
 lib/ofp-match.c                      |  59 +++
 lib/ofp-meter.c                      | 178 +++++++
 lib/ofp-monitor.c                    |  27 +
 lib/ofp-port.c                       | 145 ++++++
 lib/ofp-print.c                      | 976 ++---------------------------------
 lib/ofp-queue.c                      | 196 +++++++
 lib/ofp-table.c                      |  35 ++
 19 files changed, 1080 insertions(+), 936 deletions(-)

diff --git a/include/openvswitch/ofp-bundle.h b/include/openvswitch/ofp-bundle.h
index 78a44d6f0088..b4c29c0d9c43 100644
--- a/include/openvswitch/ofp-bundle.h
+++ b/include/openvswitch/ofp-bundle.h
@@ -36,9 +36,11 @@ struct ofputil_bundle_ctrl_msg {
 
 enum ofperr ofputil_decode_bundle_ctrl(const struct ofp_header *,
                                        struct ofputil_bundle_ctrl_msg *);
-
 struct ofpbuf *ofputil_encode_bundle_ctrl_request(
     enum ofp_version, struct ofputil_bundle_ctrl_msg *);
+void ofputil_format_bundle_ctrl_request(
+    struct ds *, const struct ofputil_bundle_ctrl_msg *);
+
 struct ofpbuf *ofputil_encode_bundle_ctrl_reply(
     const struct ofp_header *, struct ofputil_bundle_ctrl_msg *);
 
@@ -51,10 +53,15 @@ struct ofputil_bundle_add_msg {
 
 struct ofpbuf *ofputil_encode_bundle_add(enum ofp_version,
                                          struct ofputil_bundle_add_msg *);
-
 enum ofperr ofputil_decode_bundle_add(const struct ofp_header *,
                                       struct ofputil_bundle_add_msg *,
                                       enum ofptype *);
+void ofputil_format_bundle_add(struct ds *,
+                               const struct ofputil_bundle_add_msg *,
+                               const struct ofputil_port_map *,
+                               const struct ofputil_table_map *,
+                               int verbosity);
+
 
 /* Bundle message as produced by ofp-parse. */
 struct ofputil_bundle_msg {
diff --git a/include/openvswitch/ofp-connection.h 
b/include/openvswitch/ofp-connection.h
index 540ce9ed9b21..5fb143157d23 100644
--- a/include/openvswitch/ofp-connection.h
+++ b/include/openvswitch/ofp-connection.h
@@ -31,22 +31,26 @@ struct ofputil_role_request {
     uint64_t generation_id;
 };
 
+enum ofperr ofputil_decode_role_message(const struct ofp_header *,
+                                        struct ofputil_role_request *);
+void ofputil_format_role_message(struct ds *,
+                                 const struct ofputil_role_request *);
+struct ofpbuf *ofputil_encode_role_reply(const struct ofp_header *,
+                                         const struct ofputil_role_request *);
+
+/* Abstract OFPT_ROLE_STATUS. */
 struct ofputil_role_status {
     enum ofp12_controller_role role;
     enum ofp14_controller_role_reason reason;
     uint64_t generation_id;
 };
 
-enum ofperr ofputil_decode_role_message(const struct ofp_header *,
-                                        struct ofputil_role_request *);
-struct ofpbuf *ofputil_encode_role_reply(const struct ofp_header *,
-                                         const struct ofputil_role_request *);
-
 struct ofpbuf *ofputil_encode_role_status(const struct ofputil_role_status *,
                                           enum ofputil_protocol);
-
 enum ofperr ofputil_decode_role_status(const struct ofp_header *,
                                        struct ofputil_role_status *);
+void ofputil_format_role_status(struct ds *,
+                                const struct ofputil_role_status *);
 
 enum ofputil_async_msg_type {
     /* Standard asynchronous messages. */
@@ -79,6 +83,8 @@ struct ofpbuf *ofputil_encode_get_async_reply(
     const struct ofp_header *, const struct ofputil_async_cfg *);
 struct ofpbuf *ofputil_encode_set_async_config(
     const struct ofputil_async_cfg *, uint32_t oams, enum ofp_version);
+void ofputil_format_set_async_config(struct ds *,
+                                     const struct ofputil_async_cfg *);
 
 struct ofputil_async_cfg ofputil_async_cfg_default(enum ofp_version);
 
diff --git a/include/openvswitch/ofp-ipfix.h b/include/openvswitch/ofp-ipfix.h
index 75eefc005877..34ff2b9b20bf 100644
--- a/include/openvswitch/ofp-ipfix.h
+++ b/include/openvswitch/ofp-ipfix.h
@@ -19,6 +19,7 @@
 
 #include "openflow/openflow.h"
 
+struct ds;
 struct ofpbuf;
 struct ovs_list;
 
@@ -44,6 +45,10 @@ void ofputil_append_ipfix_stat(struct ovs_list *replies,
                               const struct ofputil_ipfix_stats *);
 size_t ofputil_count_ipfix_stats(const struct ofp_header *);
 int ofputil_pull_ipfix_stats(struct ofputil_ipfix_stats *, struct ofpbuf *msg);
+void ofputil_format_ipfix_stats_bridge(struct ds *,
+                                       const struct ofputil_ipfix_stats *);
+void ofputil_format_ipfix_stats_flow(struct ds *,
+                                     const struct ofputil_ipfix_stats *);
 
 #ifdef __cplusplus
 }
diff --git a/include/openvswitch/ofp-match.h b/include/openvswitch/ofp-match.h
index 6ed373e2bf4d..f279d46611f9 100644
--- a/include/openvswitch/ofp-match.h
+++ b/include/openvswitch/ofp-match.h
@@ -79,9 +79,12 @@ struct ofputil_tlv_table_reply {
 };
 
 struct ofpbuf *ofputil_encode_tlv_table_mod(enum ofp_version ofp_version,
-                                               struct ofputil_tlv_table_mod *);
-enum ofperr ofputil_decode_tlv_table_mod(const struct ofp_header *,
                                             struct ofputil_tlv_table_mod *);
+enum ofperr ofputil_decode_tlv_table_mod(const struct ofp_header *,
+                                         struct ofputil_tlv_table_mod *);
+void ofputil_format_tlv_table_mod(struct ds *,
+                                  const struct ofputil_tlv_table_mod *);
+
 struct ofpbuf *ofputil_encode_tlv_table_reply(
     const struct ofp_header *, struct ofputil_tlv_table_reply *);
 enum ofperr ofputil_decode_tlv_table_reply(
@@ -90,6 +93,8 @@ char *parse_ofp_tlv_table_mod_str(struct 
ofputil_tlv_table_mod *,
                                      uint16_t command, const char *string,
                                      enum ofputil_protocol *usable_protocols)
     OVS_WARN_UNUSED_RESULT;
+void ofputil_format_tlv_table_reply(struct ds *,
+                                    const struct ofputil_tlv_table_reply *);
 
 void ofputil_uninit_tlv_table(struct ovs_list *mappings);
 
diff --git a/include/openvswitch/ofp-meter.h b/include/openvswitch/ofp-meter.h
index 18267a6fa260..6776eae87e26 100644
--- a/include/openvswitch/ofp-meter.h
+++ b/include/openvswitch/ofp-meter.h
@@ -30,6 +30,8 @@ extern "C" {
 /* Type for meter_id in ofproto provider interface, UINT32_MAX if invalid. */
 typedef struct { uint32_t uint32; } ofproto_meter_id;
 
+void ofputil_format_meter_id(struct ds *s, uint32_t meter_id, char separator);
+
 /* Meter band configuration for all supported band types. */
 struct ofputil_meter_band {
     uint16_t type;
@@ -38,6 +40,9 @@ struct ofputil_meter_band {
     uint32_t burst_size;
 };
 
+void ofputil_format_meter_band(struct ds *, enum ofp13_meter_flags,
+                               const struct ofputil_meter_band *);
+
 struct ofputil_meter_band_stats {
     uint64_t packet_count;
     uint64_t byte_count;
@@ -55,6 +60,8 @@ void ofputil_append_meter_config(struct ovs_list *replies,
 int ofputil_decode_meter_config(struct ofpbuf *,
                                 struct ofputil_meter_config *,
                                 struct ofpbuf *bands);
+void ofputil_format_meter_config(struct ds *,
+                                 const struct ofputil_meter_config *);
 
 struct ofputil_meter_mod {
     uint16_t command;
@@ -70,6 +77,7 @@ char *parse_ofp_meter_mod_str(struct ofputil_meter_mod *, 
const char *string,
                               int command,
                               enum ofputil_protocol *usable_protocols)
     OVS_WARN_UNUSED_RESULT;
+void ofputil_format_meter_mod(struct ds *, const struct ofputil_meter_mod *);
 
 struct ofputil_meter_stats {
     uint32_t meter_id;
@@ -87,6 +95,8 @@ void ofputil_append_meter_stats(struct ovs_list *replies,
 int ofputil_decode_meter_stats(struct ofpbuf *,
                                struct ofputil_meter_stats *,
                                struct ofpbuf *bands);
+void ofputil_format_meter_stats(struct ds *,
+                                const struct ofputil_meter_stats *);
 
 struct ofputil_meter_features {
     uint32_t max_meters;        /* Maximum number of meters. */
@@ -102,6 +112,8 @@ struct ofpbuf *ofputil_encode_meter_features_reply(const 
struct
                                                    ofputil_meter_features *,
                                                    const struct ofp_header *
                                                    request);
+void ofputil_format_meter_features(struct ds *,
+                                   const struct ofputil_meter_features *);
 
 enum ofputil_meter_request_type {
     OFPUTIL_METER_FEATURES,
diff --git a/include/openvswitch/ofp-monitor.h 
b/include/openvswitch/ofp-monitor.h
index 47d0d0e89548..3edaeb53a16c 100644
--- a/include/openvswitch/ofp-monitor.h
+++ b/include/openvswitch/ofp-monitor.h
@@ -133,6 +133,10 @@ struct ofpbuf *ofputil_encode_requestforward(
     const struct ofputil_requestforward *, enum ofputil_protocol);
 enum ofperr ofputil_decode_requestforward(const struct ofp_header *,
                                           struct ofputil_requestforward *);
+void ofputil_format_requestforward(struct ds *, enum ofp_version,
+                                   const struct ofputil_requestforward *,
+                                   const struct ofputil_port_map *,
+                                   const struct ofputil_table_map *);
 void ofputil_destroy_requestforward(struct ofputil_requestforward *);
 
 #ifdef __cplusplus
diff --git a/include/openvswitch/ofp-port.h b/include/openvswitch/ofp-port.h
index 4286ba19d693..f1f36bf9c08a 100644
--- a/include/openvswitch/ofp-port.h
+++ b/include/openvswitch/ofp-port.h
@@ -169,6 +169,9 @@ void ofputil_append_port_stat(struct ovs_list *replies,
                               const struct ofputil_port_stats *ops);
 size_t ofputil_count_port_stats(const struct ofp_header *);
 int ofputil_decode_port_stats(struct ofputil_port_stats *, struct ofpbuf *msg);
+void ofputil_format_port_stats(struct ds *, const struct ofputil_port_stats *,
+                               const struct ofputil_port_map *);
+
 enum ofperr ofputil_decode_port_stats_request(const struct ofp_header *request,
                                               ofp_port_t *ofp10_port);
 
diff --git a/include/openvswitch/ofp-queue.h b/include/openvswitch/ofp-queue.h
index b0229685ba6d..51b98cda4cc7 100644
--- a/include/openvswitch/ofp-queue.h
+++ b/include/openvswitch/ofp-queue.h
@@ -19,7 +19,9 @@
 
 #include "openflow/openflow.h"
 
+struct ds;
 struct ofpbuf;
+struct ofputil_port_map;
 struct ovs_list;
 
 #ifdef __cplusplus
@@ -45,6 +47,8 @@ void ofputil_append_queue_get_config_reply(
 
 int ofputil_pull_queue_get_config_reply(struct ofpbuf *reply,
                                         struct ofputil_queue_config *);
+enum ofperr ofputil_queue_get_config_reply_format(
+    struct ds *, const struct ofp_header *, const struct ofputil_port_map *);
 
 struct ofputil_queue_stats_request {
     ofp_port_t port_no;           /* OFPP_ANY means "all ports". */
@@ -55,6 +59,9 @@ enum ofperr ofputil_decode_queue_stats_request(
     const struct ofp_header *, struct ofputil_queue_stats_request *);
 struct ofpbuf *ofputil_encode_queue_stats_request(
     enum ofp_version, const struct ofputil_queue_stats_request *);
+enum ofperr ofputil_queue_stats_request_format(
+    struct ds *, const struct ofp_header *,
+    const struct ofputil_port_map *);
 
 struct ofputil_queue_stats {
     ofp_port_t port_no;
@@ -74,6 +81,10 @@ size_t ofputil_count_queue_stats(const struct ofp_header *);
 int ofputil_decode_queue_stats(struct ofputil_queue_stats *, struct ofpbuf *);
 void ofputil_append_queue_stat(struct ovs_list *replies,
                                const struct ofputil_queue_stats *);
+enum ofperr ofputil_queue_stats_reply_format(struct ds *,
+                                             const struct ofp_header *,
+                                             const struct ofputil_port_map *,
+                                             int verbosity);
 
 /* Queue configuration request. */
 struct ofpbuf *ofputil_encode_queue_get_config_request(enum ofp_version,
@@ -82,6 +93,9 @@ struct ofpbuf *ofputil_encode_queue_get_config_request(enum 
ofp_version,
 enum ofperr ofputil_decode_queue_get_config_request(const struct ofp_header *,
                                                     ofp_port_t *port,
                                                     uint32_t *queue);
+enum ofperr ofputil_queue_get_config_request_format(
+    struct ds *, const struct ofp_header *,
+    const struct ofputil_port_map *);
 
 #ifdef __cplusplus
 }
diff --git a/include/openvswitch/ofp-table.h b/include/openvswitch/ofp-table.h
index e8260657f486..d06ccf5ce9e3 100644
--- a/include/openvswitch/ofp-table.h
+++ b/include/openvswitch/ofp-table.h
@@ -309,10 +309,16 @@ struct ofputil_table_status {
     struct ofputil_table_desc desc;   /* New table config. */
 };
 
+const char *ofp_table_reason_to_string(enum ofp14_table_reason,
+                                       char *reasonbuf, size_t bufsize);
+
 enum ofperr ofputil_decode_table_status(const struct ofp_header *,
                                         struct ofputil_table_status *);
 struct ofpbuf *ofputil_encode_table_status(const struct ofputil_table_status *,
                                            enum ofputil_protocol);
+void ofputil_format_table_status(struct ds *,
+                                 const struct ofputil_table_status *,
+                                 const struct ofputil_table_map *);
 
 #ifdef __cplusplus
 }
diff --git a/lib/ofp-bundle.c b/lib/ofp-bundle.c
index 8f07a30c51f7..0e9b46b2f224 100644
--- a/lib/ofp-bundle.c
+++ b/lib/ofp-bundle.c
@@ -19,6 +19,7 @@
 #include <errno.h>
 #include <stdlib.h>
 #include "openvswitch/ofp-parse.h"
+#include "openvswitch/ofp-print.h"
 #include "openvswitch/ofpbuf.h"
 #include "openvswitch/vlog.h"
 #include "util.h"
@@ -128,6 +129,57 @@ ofputil_encode_bundle_ctrl_request(enum ofp_version 
ofp_version,
     return request;
 }
 
+static const char *
+bundle_flags_to_name(uint32_t bit)
+{
+    switch (bit) {
+    case OFPBF_ATOMIC:
+        return "atomic";
+    case OFPBF_ORDERED:
+        return "ordered";
+    default:
+        return NULL;
+    }
+}
+
+void
+ofputil_format_bundle_ctrl_request(struct ds *s,
+                                   const struct ofputil_bundle_ctrl_msg *bctrl)
+{
+    ds_put_char(s, '\n');
+    ds_put_format(s, " bundle_id=%#"PRIx32" type=",  bctrl->bundle_id);
+    switch (bctrl->type) {
+    case OFPBCT_OPEN_REQUEST:
+        ds_put_cstr(s, "OPEN_REQUEST");
+        break;
+    case OFPBCT_OPEN_REPLY:
+        ds_put_cstr(s, "OPEN_REPLY");
+        break;
+    case OFPBCT_CLOSE_REQUEST:
+        ds_put_cstr(s, "CLOSE_REQUEST");
+        break;
+    case OFPBCT_CLOSE_REPLY:
+        ds_put_cstr(s, "CLOSE_REPLY");
+        break;
+    case OFPBCT_COMMIT_REQUEST:
+        ds_put_cstr(s, "COMMIT_REQUEST");
+        break;
+    case OFPBCT_COMMIT_REPLY:
+        ds_put_cstr(s, "COMMIT_REPLY");
+        break;
+    case OFPBCT_DISCARD_REQUEST:
+        ds_put_cstr(s, "DISCARD_REQUEST");
+        break;
+    case OFPBCT_DISCARD_REPLY:
+        ds_put_cstr(s, "DISCARD_REPLY");
+        break;
+    }
+
+    ds_put_cstr(s, " flags=");
+    ofp_print_bit_names(s, bctrl->flags, bundle_flags_to_name, ' ');
+}
+
+
 struct ofpbuf *
 ofputil_encode_bundle_ctrl_reply(const struct ofp_header *oh,
                                  struct ofputil_bundle_ctrl_msg *msg)
@@ -430,3 +482,21 @@ parse_ofp_bundle_file(const char *file_name,
     }
     return NULL;
 }
+
+void
+ofputil_format_bundle_add(struct ds *s,
+                          const struct ofputil_bundle_add_msg *badd,
+                          const struct ofputil_port_map *port_map,
+                          const struct ofputil_table_map *table_map,
+                          int verbosity)
+{
+    ds_put_char(s, '\n');
+    ds_put_format(s, " bundle_id=%#"PRIx32, badd->bundle_id);
+    ds_put_cstr(s, " flags=");
+    ofp_print_bit_names(s, badd->flags, bundle_flags_to_name, ' ');
+
+    ds_put_char(s, '\n');
+    char *msg = ofp_to_string(badd->msg, ntohs(badd->msg->length), port_map,
+                              table_map, verbosity);
+    ds_put_and_free_cstr(s, msg);
+}
diff --git a/lib/ofp-connection.c b/lib/ofp-connection.c
index 3e114ba77660..23b80ff39dc4 100644
--- a/lib/ofp-connection.c
+++ b/lib/ofp-connection.c
@@ -19,9 +19,13 @@
 #include "byte-order.h"
 #include "openflow/nicira-ext.h"
 #include "openvswitch/ofp-errors.h"
+#include "openvswitch/ofp-monitor.h"
 #include "openvswitch/ofp-msgs.h"
+#include "openvswitch/ofp-packet.h"
 #include "openvswitch/ofp-prop.h"
+#include "openvswitch/ofp-table.h"
 #include "openvswitch/ofpbuf.h"
+#include "openvswitch/type-props.h"
 #include "openvswitch/vlog.h"
 #include "util.h"
 
@@ -83,6 +87,43 @@ ofputil_decode_role_message(const struct ofp_header *oh,
     return 0;
 }
 
+static void
+format_role_generic(struct ds *string, enum ofp12_controller_role role,
+                    uint64_t generation_id)
+{
+    ds_put_cstr(string, " role=");
+
+    switch (role) {
+    case OFPCR12_ROLE_NOCHANGE:
+        ds_put_cstr(string, "nochange");
+        break;
+    case OFPCR12_ROLE_EQUAL:
+        ds_put_cstr(string, "equal"); /* OF 1.2 wording */
+        break;
+    case OFPCR12_ROLE_MASTER:
+        ds_put_cstr(string, "master");
+        break;
+    case OFPCR12_ROLE_SLAVE:
+        ds_put_cstr(string, "slave");
+        break;
+    default:
+        OVS_NOT_REACHED();
+    }
+
+    if (generation_id != UINT64_MAX) {
+        ds_put_format(string, " generation_id=%"PRIu64, generation_id);
+    }
+}
+
+void
+ofputil_format_role_message(struct ds *string,
+                            const struct ofputil_role_request *rr)
+{
+    format_role_generic(string, rr->role, (rr->have_generation_id
+                                           ? rr->generation_id
+                                           : UINT64_MAX));
+}
+
 /* Returns an encoded form of a role reply suitable for the "request" in a
  * buffer owned by the caller. */
 struct ofpbuf *
@@ -167,6 +208,31 @@ ofputil_decode_role_status(const struct ofp_header *oh,
 
     return 0;
 }
+
+void
+ofputil_format_role_status(struct ds *string,
+                           const struct ofputil_role_status *rs)
+{
+    format_role_generic(string, rs->role, rs->generation_id);
+
+    ds_put_cstr(string, " reason=");
+
+    switch (rs->reason) {
+    case OFPCRR_MASTER_REQUEST:
+        ds_put_cstr(string, "master_request");
+        break;
+    case OFPCRR_CONFIG:
+        ds_put_cstr(string, "configuration_changed");
+        break;
+    case OFPCRR_EXPERIMENTER:
+        ds_put_cstr(string, "experimenter_data_changed");
+        break;
+    case OFPCRR_N_REASONS:
+    default:
+        ds_put_cstr(string, "(unknown)");
+        break;
+    }
+}
 
 const char *
 ofputil_async_msg_type_to_string(enum ofputil_async_msg_type type)
@@ -493,6 +559,137 @@ ofputil_encode_set_async_config(const struct 
ofputil_async_cfg *ac,
     return request;
 }
 
+/* Returns a string form of 'reason'.  The return value is either a statically
+ * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
+ * 'bufsize' should be at least OFP_PORT_REASON_BUFSIZE. */
+#define OFP_PORT_REASON_BUFSIZE (INT_STRLEN(int) + 1)
+static const char *
+ofp_port_reason_to_string(enum ofp_port_reason reason,
+                          char *reasonbuf, size_t bufsize)
+{
+    switch (reason) {
+    case OFPPR_ADD:
+        return "add";
+
+    case OFPPR_DELETE:
+        return "delete";
+
+    case OFPPR_MODIFY:
+        return "modify";
+
+    case OFPPR_N_REASONS:
+    default:
+        snprintf(reasonbuf, bufsize, "%d", (int) reason);
+        return reasonbuf;
+    }
+}
+
+/* Returns a string form of 'reason'.  The return value is either a statically
+ * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
+ * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */
+static const char*
+ofp_role_reason_to_string(enum ofp14_controller_role_reason reason,
+                          char *reasonbuf, size_t bufsize)
+{
+    switch (reason) {
+    case OFPCRR_MASTER_REQUEST:
+        return "master_request";
+
+    case OFPCRR_CONFIG:
+        return "configuration_changed";
+
+    case OFPCRR_EXPERIMENTER:
+        return "experimenter_data_changed";
+
+    case OFPCRR_N_REASONS:
+    default:
+        snprintf(reasonbuf, bufsize, "%d", (int) reason);
+        return reasonbuf;
+    }
+}
+
+/* Returns a string form of 'reason'.  The return value is either a statically
+ * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
+ * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */
+static const char*
+ofp_requestforward_reason_to_string(enum ofp14_requestforward_reason reason,
+                                    char *reasonbuf, size_t bufsize)
+{
+    switch (reason) {
+    case OFPRFR_GROUP_MOD:
+        return "group_mod_request";
+
+    case OFPRFR_METER_MOD:
+        return "meter_mod_request";
+
+    case OFPRFR_N_REASONS:
+    default:
+        snprintf(reasonbuf, bufsize, "%d", (int) reason);
+        return reasonbuf;
+    }
+}
+
+static const char *
+ofp_async_config_reason_to_string(uint32_t reason,
+                                  enum ofputil_async_msg_type type,
+                                  char *reasonbuf, size_t bufsize)
+{
+    switch (type) {
+    case OAM_PACKET_IN:
+        return ofputil_packet_in_reason_to_string(reason, reasonbuf, bufsize);
+
+    case OAM_PORT_STATUS:
+        return ofp_port_reason_to_string(reason, reasonbuf, bufsize);
+
+    case OAM_FLOW_REMOVED:
+        return ofp_flow_removed_reason_to_string(reason, reasonbuf, bufsize);
+
+    case OAM_ROLE_STATUS:
+        return ofp_role_reason_to_string(reason, reasonbuf, bufsize);
+
+    case OAM_TABLE_STATUS:
+        return ofp_table_reason_to_string(reason, reasonbuf, bufsize);
+
+    case OAM_REQUESTFORWARD:
+        return ofp_requestforward_reason_to_string(reason, reasonbuf, bufsize);
+
+    case OAM_N_TYPES:
+    default:
+        return "Unknown asynchronous configuration message type";
+    }
+}
+
+void
+ofputil_format_set_async_config(struct ds *string,
+                                const struct ofputil_async_cfg *ac)
+{
+    for (int i = 0; i < 2; i++) {
+        ds_put_format(string, "\n %s:\n", i == 0 ? "master" : "slave");
+        for (uint32_t type = 0; type < OAM_N_TYPES; type++) {
+            ds_put_format(string, "%16s:",
+                          ofputil_async_msg_type_to_string(type));
+
+            uint32_t role = i == 0 ? ac->master[type] : ac->slave[type];
+            for (int j = 0; j < 32; j++) {
+                if (role & (1u << j)) {
+                    char reasonbuf[INT_STRLEN(int) + 1];
+                    const char *reason;
+
+                    reason = ofp_async_config_reason_to_string(
+                        j, type, reasonbuf, sizeof reasonbuf);
+                    if (reason[0]) {
+                        ds_put_format(string, " %s", reason);
+                    }
+                }
+            }
+            if (!role) {
+                ds_put_cstr(string, " (off)");
+            }
+            ds_put_char(string, '\n');
+        }
+    }
+}
+
 struct ofputil_async_cfg
 ofputil_async_cfg_default(enum ofp_version version)
 {
diff --git a/lib/ofp-ipfix.c b/lib/ofp-ipfix.c
index d710b5a4b225..0ffc4d9365fc 100644
--- a/lib/ofp-ipfix.c
+++ b/lib/ofp-ipfix.c
@@ -109,3 +109,54 @@ ofputil_count_ipfix_stats(const struct ofp_header *oh)
 
     return b.size / sizeof(struct ofputil_ipfix_stats);
 }
+
+static void
+print_ipfix_stat(struct ds *string, const char *leader, uint64_t stat,
+                 int more)
+{
+    ds_put_cstr(string, leader);
+    if (stat != UINT64_MAX) {
+        ds_put_format(string, "%"PRIu64, stat);
+    } else {
+        ds_put_char(string, '?');
+    }
+    if (more) {
+        ds_put_cstr(string, ", ");
+    } else {
+        ds_put_cstr(string, "\n");
+    }
+}
+
+static void
+format_ipfix_stats(struct ds *string, const struct ofputil_ipfix_stats *is,
+                   int indent)
+{
+    print_ipfix_stat(string, "flows=", is->total_flows, 1);
+    print_ipfix_stat(string, "current flows=", is->current_flows, 1);
+    print_ipfix_stat(string, "sampled pkts=", is->pkts, 1);
+    print_ipfix_stat(string, "ipv4 ok=", is->ipv4_pkts, 1);
+    print_ipfix_stat(string, "ipv6 ok=", is->ipv6_pkts, 1);
+    print_ipfix_stat(string, "tx pkts=", is->tx_pkts, 0);
+    ds_put_char_multiple(string, ' ', indent);
+    print_ipfix_stat(string, "pkts errs=", is->error_pkts, 1);
+    print_ipfix_stat(string, "ipv4 errs=", is->ipv4_error_pkts, 1);
+    print_ipfix_stat(string, "ipv6 errs=", is->ipv6_error_pkts, 1);
+    print_ipfix_stat(string, "tx errs=", is->tx_errors, 0);
+}
+
+void
+ofputil_format_ipfix_stats_bridge(struct ds *string,
+                                  const struct ofputil_ipfix_stats *is)
+{
+    ds_put_cstr(string, "\n  bridge ipfix: ");
+    format_ipfix_stats(string, is, 16);
+}
+
+void
+ofputil_format_ipfix_stats_flow(struct ds *string,
+                                const struct ofputil_ipfix_stats *is)
+{
+    ds_put_cstr(string, "  id");
+    ds_put_format(string, " %3"PRIuSIZE": ", (size_t) is->collector_set_id);
+    format_ipfix_stats(string, is, 10);
+}
diff --git a/lib/ofp-match.c b/lib/ofp-match.c
index acdf0b776640..f91d57f86f3f 100644
--- a/lib/ofp-match.c
+++ b/lib/ofp-match.c
@@ -724,6 +724,46 @@ ofputil_decode_tlv_table_mod(const struct ofp_header *oh,
                                         &ttm->mappings);
 }
 
+static void
+print_tlv_table(struct ds *s, const struct ovs_list *mappings)
+{
+    ds_put_cstr(s, " mapping table:\n");
+    ds_put_cstr(s, " class\ttype\tlength\tmatch field\n");
+    ds_put_cstr(s, " -----\t----\t------\t-----------");
+
+    const struct ofputil_tlv_map *map;
+    LIST_FOR_EACH (map, list_node, mappings) {
+        ds_put_char(s, '\n');
+        ds_put_format(s, " 0x%"PRIx16"\t0x%"PRIx8"\t%"PRIu8
+                      "\ttun_metadata%"PRIu16,
+                      map->option_class, map->option_type, map->option_len,
+                      map->index);
+    }
+}
+
+void
+ofputil_format_tlv_table_mod(struct ds *s,
+                             const struct ofputil_tlv_table_mod *ttm)
+{
+    ds_put_cstr(s, "\n ");
+
+    switch (ttm->command) {
+    case NXTTMC_ADD:
+        ds_put_cstr(s, "ADD");
+        break;
+    case NXTTMC_DELETE:
+        ds_put_cstr(s, "DEL");
+        break;
+    case NXTTMC_CLEAR:
+        ds_put_cstr(s, "CLEAR");
+        break;
+    }
+
+    if (ttm->command != NXTTMC_CLEAR) {
+        print_tlv_table(s, &ttm->mappings);
+    }
+}
+
 struct ofpbuf *
 ofputil_encode_tlv_table_reply(const struct ofp_header *oh,
                                   struct ofputil_tlv_table_reply *ttr)
@@ -795,6 +835,25 @@ parse_ofp_tlv_table_mod_str(struct ofputil_tlv_table_mod 
*ttm,
     return NULL;
 }
 
+void
+ofputil_format_tlv_table_reply(struct ds *s,
+                               const struct ofputil_tlv_table_reply *ttr)
+{
+    ds_put_char(s, '\n');
+
+    const struct ofputil_tlv_map *map;
+    int allocated_space = 0;
+    LIST_FOR_EACH (map, list_node, &ttr->mappings) {
+        allocated_space += map->option_len;
+    }
+
+    ds_put_format(s, " max option space=%"PRIu32" max fields=%"PRIu16"\n",
+                  ttr->max_option_space, ttr->max_fields);
+    ds_put_format(s, " allocated option space=%d\n", allocated_space);
+    ds_put_char(s, '\n');
+    print_tlv_table(s, &ttr->mappings);
+}
+
 void
 ofputil_uninit_tlv_table(struct ovs_list *mappings)
 {
diff --git a/lib/ofp-meter.c b/lib/ofp-meter.c
index 4f77f508d396..6395c0daa4ae 100644
--- a/lib/ofp-meter.c
+++ b/lib/ofp-meter.c
@@ -21,6 +21,7 @@
 #include "openvswitch/ofp-errors.h"
 #include "openvswitch/ofp-msgs.h"
 #include "openvswitch/ofp-parse.h"
+#include "openvswitch/ofp-print.h"
 #include "openvswitch/ofpbuf.h"
 #include "openvswitch/vlog.h"
 
@@ -28,6 +29,56 @@ VLOG_DEFINE_THIS_MODULE(ofp_meter);
 
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 
+void
+ofputil_format_meter_id(struct ds *s, uint32_t meter_id, char separator)
+{
+    if (meter_id <= OFPM13_MAX) {
+        ds_put_format(s, "meter%c%"PRIu32, separator, meter_id);
+    } else {
+        const char *name;
+        switch (meter_id) {
+        case OFPM13_SLOWPATH:
+            name = "slowpath";
+            break;
+        case OFPM13_CONTROLLER:
+            name = "controller";
+            break;
+        case OFPM13_ALL:
+            name = "all";
+            break;
+        default:
+            name = "unknown";
+        }
+        ds_put_format(s, "meter%c%s", separator, name);
+    }
+}
+
+void
+ofputil_format_meter_band(struct ds *s, enum ofp13_meter_flags flags,
+                          const struct ofputil_meter_band *mb)
+{
+    ds_put_cstr(s, "\ntype=");
+    switch (mb->type) {
+    case OFPMBT13_DROP:
+        ds_put_cstr(s, "drop");
+        break;
+    case OFPMBT13_DSCP_REMARK:
+        ds_put_cstr(s, "dscp_remark");
+        break;
+    default:
+        ds_put_format(s, "%u", mb->type);
+    }
+
+    ds_put_format(s, " rate=%"PRIu32, mb->rate);
+
+    if (flags & OFPMF13_BURST) {
+        ds_put_format(s, " burst_size=%"PRIu32, mb->burst_size);
+    }
+    if (mb->type == OFPMBT13_DSCP_REMARK) {
+        ds_put_format(s, " prec_level=%"PRIu8, mb->prec_level);
+    }
+}
+
 static enum ofperr
 ofputil_pull_bands(struct ofpbuf *msg, size_t len, uint16_t *n_bands,
                    struct ofpbuf *bands)
@@ -268,6 +319,46 @@ ofputil_decode_meter_config(struct ofpbuf *msg,
     return 0;
 }
 
+static void
+ofp_print_meter_flags(struct ds *s, enum ofp13_meter_flags flags)
+{
+    if (flags & OFPMF13_KBPS) {
+        ds_put_cstr(s, "kbps ");
+    }
+    if (flags & OFPMF13_PKTPS) {
+        ds_put_cstr(s, "pktps ");
+    }
+    if (flags & OFPMF13_BURST) {
+        ds_put_cstr(s, "burst ");
+    }
+    if (flags & OFPMF13_STATS) {
+        ds_put_cstr(s, "stats ");
+    }
+
+    flags &= ~(OFPMF13_KBPS | OFPMF13_PKTPS | OFPMF13_BURST | OFPMF13_STATS);
+    if (flags) {
+        ds_put_format(s, "flags:0x%"PRIx16" ", flags);
+    }
+}
+
+void
+ofputil_format_meter_config(struct ds *s,
+                            const struct ofputil_meter_config *mc)
+{
+    uint16_t i;
+
+    ofputil_format_meter_id(s, mc->meter_id, '=');
+    ds_put_char(s, ' ');
+
+    ofp_print_meter_flags(s, mc->flags);
+
+    ds_put_cstr(s, "bands=");
+    for (i = 0; i < mc->n_bands; ++i) {
+        ofputil_format_meter_band(s, mc->flags, &mc->bands[i]);
+    }
+    ds_put_char(s, '\n');
+}
+
 static enum ofperr
 ofputil_pull_band_stats(struct ofpbuf *msg, size_t len, uint16_t *n_bands,
                         struct ofpbuf *bands)
@@ -347,6 +438,28 @@ ofputil_decode_meter_stats(struct ofpbuf *msg,
     return 0;
 }
 
+void
+ofputil_format_meter_stats(struct ds *s, const struct ofputil_meter_stats *ms)
+{
+    uint16_t i;
+
+    ofputil_format_meter_id(s, ms->meter_id, ':');
+    ds_put_char(s, ' ');
+    ds_put_format(s, "flow_count:%"PRIu32" ", ms->flow_count);
+    ds_put_format(s, "packet_in_count:%"PRIu64" ", ms->packet_in_count);
+    ds_put_format(s, "byte_in_count:%"PRIu64" ", ms->byte_in_count);
+    ds_put_cstr(s, "duration:");
+    ofp_print_duration(s, ms->duration_sec, ms->duration_nsec);
+    ds_put_char(s, ' ');
+
+    ds_put_cstr(s, "bands:\n");
+    for (i = 0; i < ms->n_bands; ++i) {
+        ds_put_format(s, "%d: ", i);
+        ds_put_format(s, "packet_count:%"PRIu64" ", ms->bands[i].packet_count);
+        ds_put_format(s, "byte_count:%"PRIu64"\n", ms->bands[i].byte_count);
+    }
+}
+
 void
 ofputil_decode_meter_features(const struct ofp_header *oh,
                               struct ofputil_meter_features *mf)
@@ -379,6 +492,51 @@ ofputil_encode_meter_features_reply(const struct 
ofputil_meter_features *mf,
     return reply;
 }
 
+static const char *
+ofputil_meter_band_types_to_name(uint32_t bit)
+{
+    switch (bit) {
+    case 1 << OFPMBT13_DROP:          return "drop";
+    case 1 << OFPMBT13_DSCP_REMARK:   return "dscp_remark";
+    }
+
+    return NULL;
+}
+
+static const char *
+ofputil_meter_capabilities_to_name(uint32_t bit)
+{
+    enum ofp13_meter_flags flag = bit;
+
+    switch (flag) {
+    case OFPMF13_KBPS:    return "kbps";
+    case OFPMF13_PKTPS:   return "pktps";
+    case OFPMF13_BURST:   return "burst";
+    case OFPMF13_STATS:   return "stats";
+    }
+
+    return NULL;
+}
+
+void
+ofputil_format_meter_features(struct ds *s,
+                              const struct ofputil_meter_features *mf)
+{
+    ds_put_format(s, "\nmax_meter:%"PRIu32, mf->max_meters);
+    ds_put_format(s, " max_bands:%"PRIu8, mf->max_bands);
+    ds_put_format(s, " max_color:%"PRIu8"\n", mf->max_color);
+
+    ds_put_cstr(s, "band_types: ");
+    ofp_print_bit_names(s, mf->band_types,
+                        ofputil_meter_band_types_to_name, ' ');
+    ds_put_char(s, '\n');
+
+    ds_put_cstr(s, "capabilities: ");
+    ofp_print_bit_names(s, mf->capabilities,
+                        ofputil_meter_capabilities_to_name, ' ');
+    ds_put_char(s, '\n');
+}
+
 struct ofpbuf *
 ofputil_encode_meter_mod(enum ofp_version ofp_version,
                          const struct ofputil_meter_mod *mm)
@@ -628,3 +786,23 @@ parse_ofp_meter_mod_str(struct ofputil_meter_mod *mm, 
const char *str_,
 
     return error;
 }
+
+void
+ofputil_format_meter_mod(struct ds *s, const struct ofputil_meter_mod *mm)
+{
+    switch (mm->command) {
+    case OFPMC13_ADD:
+        ds_put_cstr(s, " ADD ");
+        break;
+    case OFPMC13_MODIFY:
+        ds_put_cstr(s, " MOD ");
+        break;
+    case OFPMC13_DELETE:
+        ds_put_cstr(s, " DEL ");
+        break;
+    default:
+        ds_put_format(s, " cmd:%d ", mm->command);
+    }
+
+    ofputil_format_meter_config(s, &mm->meter);
+}
diff --git a/lib/ofp-monitor.c b/lib/ofp-monitor.c
index 3d117cae8d11..3e02834a26a0 100644
--- a/lib/ofp-monitor.c
+++ b/lib/ofp-monitor.c
@@ -880,6 +880,33 @@ ofputil_decode_requestforward(const struct ofp_header 
*outer,
     return 0;
 }
 
+void
+ofputil_format_requestforward(struct ds *string,
+                              enum ofp_version ofp_version,
+                              const struct ofputil_requestforward *rf,
+                              const struct ofputil_port_map *port_map,
+                              const struct ofputil_table_map *table_map)
+{
+    ds_put_cstr(string, " reason=");
+
+    switch (rf->reason) {
+    case OFPRFR_GROUP_MOD:
+        ds_put_cstr(string, "group_mod");
+        ofputil_group_mod_format__(string, ofp_version, rf->group_mod,
+                                   port_map, table_map);
+        break;
+
+    case OFPRFR_METER_MOD:
+        ds_put_cstr(string, "meter_mod");
+        ofputil_format_meter_mod(string, rf->meter_mod);
+        break;
+
+    case OFPRFR_N_REASONS:
+        OVS_NOT_REACHED();
+    }
+}
+
+
 /* Frees the content of 'rf', which should have been initialized through a
  * successful call to ofputil_decode_requestforward(). */
 void
diff --git a/lib/ofp-port.c b/lib/ofp-port.c
index 4d39299ed7f5..eb5b910293b1 100644
--- a/lib/ofp-port.c
+++ b/lib/ofp-port.c
@@ -1815,6 +1815,151 @@ ofputil_decode_port_stats(struct ofputil_port_stats 
*ps, struct ofpbuf *msg)
     return OFPERR_OFPBRC_BAD_LEN;
 }
 
+static void
+print_port_stat(struct ds *string, const char *leader, uint64_t stat, int more)
+{
+    ds_put_cstr(string, leader);
+    if (stat != UINT64_MAX) {
+        ds_put_format(string, "%"PRIu64, stat);
+    } else {
+        ds_put_char(string, '?');
+    }
+    if (more) {
+        ds_put_cstr(string, ", ");
+    } else {
+        ds_put_cstr(string, "\n");
+    }
+}
+
+static void
+print_port_stat_cond(struct ds *string, const char *leader, uint64_t stat)
+{
+    if (stat != UINT64_MAX) {
+        ds_put_format(string, "%s%"PRIu64", ", leader, stat);
+    }
+}
+
+void
+ofputil_format_port_stats(struct ds *string,
+                          const struct ofputil_port_stats *ps,
+                          const struct ofputil_port_map *port_map)
+{
+    ds_put_cstr(string, "  port ");
+    if (ofp_to_u16(ps->port_no) < 10) {
+        ds_put_char(string, ' ');
+    }
+    ofputil_format_port(ps->port_no, port_map, string);
+
+    ds_put_cstr(string, ": rx ");
+    print_port_stat(string, "pkts=", ps->stats.rx_packets, 1);
+    print_port_stat(string, "bytes=", ps->stats.rx_bytes, 1);
+    print_port_stat(string, "drop=", ps->stats.rx_dropped, 1);
+    print_port_stat(string, "errs=", ps->stats.rx_errors, 1);
+    print_port_stat(string, "frame=", ps->stats.rx_frame_errors, 1);
+    print_port_stat(string, "over=", ps->stats.rx_over_errors, 1);
+    print_port_stat(string, "crc=", ps->stats.rx_crc_errors, 0);
+
+    ds_put_cstr(string, "           tx ");
+    print_port_stat(string, "pkts=", ps->stats.tx_packets, 1);
+    print_port_stat(string, "bytes=", ps->stats.tx_bytes, 1);
+    print_port_stat(string, "drop=", ps->stats.tx_dropped, 1);
+    print_port_stat(string, "errs=", ps->stats.tx_errors, 1);
+    print_port_stat(string, "coll=", ps->stats.collisions, 0);
+
+    if (ps->duration_sec != UINT32_MAX) {
+        ds_put_cstr(string, "           duration=");
+        ofp_print_duration(string, ps->duration_sec, ps->duration_nsec);
+        ds_put_char(string, '\n');
+    }
+    struct ds string_ext_stats = DS_EMPTY_INITIALIZER;
+
+    ds_init(&string_ext_stats);
+
+    print_port_stat_cond(&string_ext_stats, "1_to_64_packets=",
+                         ps->stats.rx_1_to_64_packets);
+    print_port_stat_cond(&string_ext_stats, "65_to_127_packets=",
+                         ps->stats.rx_65_to_127_packets);
+    print_port_stat_cond(&string_ext_stats, "128_to_255_packets=",
+                         ps->stats.rx_128_to_255_packets);
+    print_port_stat_cond(&string_ext_stats, "256_to_511_packets=",
+                         ps->stats.rx_256_to_511_packets);
+    print_port_stat_cond(&string_ext_stats, "512_to_1023_packets=",
+                         ps->stats.rx_512_to_1023_packets);
+    print_port_stat_cond(&string_ext_stats, "1024_to_1522_packets=",
+                         ps->stats.rx_1024_to_1522_packets);
+    print_port_stat_cond(&string_ext_stats, "1523_to_max_packets=",
+                         ps->stats.rx_1523_to_max_packets);
+    print_port_stat_cond(&string_ext_stats, "broadcast_packets=",
+                         ps->stats.rx_broadcast_packets);
+    print_port_stat_cond(&string_ext_stats, "undersized_errors=",
+                         ps->stats.rx_undersized_errors);
+    print_port_stat_cond(&string_ext_stats, "oversize_errors=",
+                         ps->stats.rx_oversize_errors);
+    print_port_stat_cond(&string_ext_stats, "rx_fragmented_errors=",
+                         ps->stats.rx_fragmented_errors);
+    print_port_stat_cond(&string_ext_stats, "rx_jabber_errors=",
+                         ps->stats.rx_jabber_errors);
+
+    if (string_ext_stats.length != 0) {
+        /* If at least one statistics counter is reported: */
+        ds_put_cstr(string, "           rx rfc2819 ");
+        ds_put_buffer(string, string_ext_stats.string,
+                      string_ext_stats.length);
+        ds_put_cstr(string, "\n");
+        ds_destroy(&string_ext_stats);
+    }
+
+    ds_init(&string_ext_stats);
+
+    print_port_stat_cond(&string_ext_stats, "1_to_64_packets=",
+                         ps->stats.tx_1_to_64_packets);
+    print_port_stat_cond(&string_ext_stats, "65_to_127_packets=",
+                         ps->stats.tx_65_to_127_packets);
+    print_port_stat_cond(&string_ext_stats, "128_to_255_packets=",
+                         ps->stats.tx_128_to_255_packets);
+    print_port_stat_cond(&string_ext_stats, "256_to_511_packets=",
+                         ps->stats.tx_256_to_511_packets);
+    print_port_stat_cond(&string_ext_stats, "512_to_1023_packets=",
+                         ps->stats.tx_512_to_1023_packets);
+    print_port_stat_cond(&string_ext_stats, "1024_to_1522_packets=",
+                         ps->stats.tx_1024_to_1522_packets);
+    print_port_stat_cond(&string_ext_stats, "1523_to_max_packets=",
+                         ps->stats.tx_1523_to_max_packets);
+    print_port_stat_cond(&string_ext_stats, "multicast_packets=",
+                         ps->stats.tx_multicast_packets);
+    print_port_stat_cond(&string_ext_stats, "broadcast_packets=",
+                         ps->stats.tx_broadcast_packets);
+
+    if (string_ext_stats.length != 0) {
+        /* If at least one statistics counter is reported: */
+        ds_put_cstr(string, "           tx rfc2819 ");
+        ds_put_buffer(string, string_ext_stats.string,
+                      string_ext_stats.length);
+        ds_put_cstr(string, "\n");
+        ds_destroy(&string_ext_stats);
+    }
+
+    if (ps->custom_stats.size) {
+        ds_put_cstr(string, "           CUSTOM Statistics");
+        for (int i = 0; i < ps->custom_stats.size; i++) {
+            /* 3 counters in the row */
+            if (ps->custom_stats.counters[i].name[0]) {
+                if (i % 3 == 0) {
+                    ds_put_cstr(string, "\n");
+                    ds_put_cstr(string, "                      ");
+                } else {
+                    ds_put_char(string, ' ');
+                }
+                ds_put_format(string, "%s=%"PRIu64",",
+                              ps->custom_stats.counters[i].name,
+                              ps->custom_stats.counters[i].value);
+            }
+        }
+        ds_put_cstr(string, "\n");
+    }
+}
+
+
 /* Parse a port status request message into a 16 bit OpenFlow 1.0
  * port number and stores the latter in '*ofp10_port'.
  * Returns 0 if successful, otherwise an OFPERR_* number. */
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 68e382471dbd..cf93d2e2cb38 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -64,7 +64,6 @@
 #include "util.h"
 #include "uuid.h"
 
-static void ofp_print_queue_name(struct ds *string, uint32_t port);
 static void ofp_print_error(struct ds *, enum ofperr);
 
 /* Returns a string that represents the contents of the Ethernet frame in the
@@ -320,256 +319,11 @@ ofp_print_table_status_message(struct ds *string, const 
struct ofp_header *oh,
                                const struct ofputil_table_map *table_map)
 {
     struct ofputil_table_status ts;
-    enum ofperr error;
-
-    error = ofputil_decode_table_status(oh, &ts);
-    if (error) {
-        return error;
-    }
-
-    if (ts.reason == OFPTR_VACANCY_DOWN) {
-        ds_put_format(string, " reason=VACANCY_DOWN");
-    } else if (ts.reason == OFPTR_VACANCY_UP) {
-        ds_put_format(string, " reason=VACANCY_UP");
-    }
-
-    ds_put_format(string, "\ntable_desc:-");
-    ofputil_table_desc_format(string, &ts.desc, table_map);
-
-    return 0;
-}
-
-static enum ofperr
-ofp_print_queue_get_config_request(struct ds *string,
-                                   const struct ofp_header *oh,
-                                   const struct ofputil_port_map *port_map)
-{
-    enum ofperr error;
-    ofp_port_t port;
-    uint32_t queue;
-
-    error = ofputil_decode_queue_get_config_request(oh, &port, &queue);
-    if (error) {
-        return error;
-    }
-
-    ds_put_cstr(string, " port=");
-    ofputil_format_port(port, port_map, string);
-
-    if (queue != OFPQ_ALL) {
-        ds_put_cstr(string, " queue=");
-        ofp_print_queue_name(string, queue);
-    }
-
-    return 0;
-}
-
-static void
-print_queue_rate(struct ds *string, const char *name, unsigned int rate)
-{
-    if (rate <= 1000) {
-        ds_put_format(string, " %s:%u.%u%%", name, rate / 10, rate % 10);
-    } else if (rate < UINT16_MAX) {
-        ds_put_format(string, " %s:(disabled)", name);
-    }
-}
-
-/* qsort comparison function. */
-static int
-compare_queues(const void *a_, const void *b_)
-{
-    const struct ofputil_queue_config *a = a_;
-    const struct ofputil_queue_config *b = b_;
-
-    uint16_t ap = ofp_to_u16(a->port);
-    uint16_t bp = ofp_to_u16(b->port);
-    if (ap != bp) {
-        return ap < bp ? -1 : 1;
-    }
-
-    uint32_t aq = a->queue;
-    uint32_t bq = b->queue;
-    return aq < bq ? -1 : aq > bq;
-}
-
-static enum ofperr
-ofp_print_queue_get_config_reply(struct ds *string,
-                                 const struct ofp_header *oh,
-                                 const struct ofputil_port_map *port_map)
-{
-    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
-
-    struct ofputil_queue_config *queues = NULL;
-    size_t allocated_queues = 0;
-    size_t n = 0;
-
-    int retval = 0;
-    for (;;) {
-        if (n >= allocated_queues) {
-            queues = x2nrealloc(queues, &allocated_queues, sizeof *queues);
-        }
-        retval = ofputil_pull_queue_get_config_reply(&b, &queues[n]);
-        if (retval) {
-            break;
-        }
-        n++;
-    }
-
-    qsort(queues, n, sizeof *queues, compare_queues);
-
-    ds_put_char(string, ' ');
-
-    ofp_port_t port = 0;
-    for (const struct ofputil_queue_config *q = queues; q < &queues[n]; q++) {
-        if (q->port != port) {
-            port = q->port;
-
-            ds_put_cstr(string, "port=");
-            ofputil_format_port(port, port_map, string);
-            ds_put_char(string, '\n');
-        }
-
-        ds_put_format(string, "queue %"PRIu32":", q->queue);
-        print_queue_rate(string, "min_rate", q->min_rate);
-        print_queue_rate(string, "max_rate", q->max_rate);
-        ds_put_char(string, '\n');
-    }
-
-    ds_chomp(string, ' ');
-    free(queues);
-
-    return retval != EOF ? retval : 0;
-}
-
-static void
-ofp_print_meter_flags(struct ds *s, uint16_t flags)
-{
-    if (flags & OFPMF13_KBPS) {
-        ds_put_cstr(s, "kbps ");
-    }
-    if (flags & OFPMF13_PKTPS) {
-        ds_put_cstr(s, "pktps ");
-    }
-    if (flags & OFPMF13_BURST) {
-        ds_put_cstr(s, "burst ");
-    }
-    if (flags & OFPMF13_STATS) {
-        ds_put_cstr(s, "stats ");
-    }
-
-    flags &= ~(OFPMF13_KBPS | OFPMF13_PKTPS | OFPMF13_BURST | OFPMF13_STATS);
-    if (flags) {
-        ds_put_format(s, "flags:0x%"PRIx16" ", flags);
-    }
-}
-
-static void
-ofp_print_meter_band(struct ds *s, uint16_t flags,
-                     const struct ofputil_meter_band *mb)
-{
-    ds_put_cstr(s, "\ntype=");
-    switch (mb->type) {
-    case OFPMBT13_DROP:
-        ds_put_cstr(s, "drop");
-        break;
-    case OFPMBT13_DSCP_REMARK:
-        ds_put_cstr(s, "dscp_remark");
-        break;
-    default:
-        ds_put_format(s, "%u", mb->type);
-    }
-
-    ds_put_format(s, " rate=%"PRIu32, mb->rate);
-
-    if (flags & OFPMF13_BURST) {
-        ds_put_format(s, " burst_size=%"PRIu32, mb->burst_size);
-    }
-    if (mb->type == OFPMBT13_DSCP_REMARK) {
-        ds_put_format(s, " prec_level=%"PRIu8, mb->prec_level);
-    }
-}
-
-static void
-ofp_print_meter_id(struct ds *s, uint32_t meter_id, char seperator)
-{
-    if (meter_id <= OFPM13_MAX) {
-        ds_put_format(s, "meter%c%"PRIu32, seperator, meter_id);
-    } else {
-        const char *name;
-        switch (meter_id) {
-        case OFPM13_SLOWPATH:
-            name = "slowpath";
-            break;
-        case OFPM13_CONTROLLER:
-            name = "controller";
-            break;
-        case OFPM13_ALL:
-            name = "all";
-            break;
-        default:
-            name = "unknown";
-        }
-        ds_put_format(s, "meter%c%s", seperator, name);
-    }
-}
-
-static void
-ofp_print_meter_stats(struct ds *s, const struct ofputil_meter_stats *ms)
-{
-    uint16_t i;
-
-    ofp_print_meter_id(s, ms->meter_id, ':');
-    ds_put_char(s, ' ');
-    ds_put_format(s, "flow_count:%"PRIu32" ", ms->flow_count);
-    ds_put_format(s, "packet_in_count:%"PRIu64" ", ms->packet_in_count);
-    ds_put_format(s, "byte_in_count:%"PRIu64" ", ms->byte_in_count);
-    ds_put_cstr(s, "duration:");
-    ofp_print_duration(s, ms->duration_sec, ms->duration_nsec);
-    ds_put_char(s, ' ');
-
-    ds_put_cstr(s, "bands:\n");
-    for (i = 0; i < ms->n_bands; ++i) {
-        ds_put_format(s, "%d: ", i);
-        ds_put_format(s, "packet_count:%"PRIu64" ", ms->bands[i].packet_count);
-        ds_put_format(s, "byte_count:%"PRIu64"\n", ms->bands[i].byte_count);
-    }
-}
-
-static void
-ofp_print_meter_config(struct ds *s, const struct ofputil_meter_config *mc)
-{
-    uint16_t i;
-
-    ofp_print_meter_id(s, mc->meter_id, '=');
-    ds_put_char(s, ' ');
-
-    ofp_print_meter_flags(s, mc->flags);
-
-    ds_put_cstr(s, "bands=");
-    for (i = 0; i < mc->n_bands; ++i) {
-        ofp_print_meter_band(s, mc->flags, &mc->bands[i]);
-    }
-    ds_put_char(s, '\n');
-}
-
-static void
-ofp_print_meter_mod__(struct ds *s, const struct ofputil_meter_mod *mm)
-{
-    switch (mm->command) {
-    case OFPMC13_ADD:
-        ds_put_cstr(s, " ADD ");
-        break;
-    case OFPMC13_MODIFY:
-        ds_put_cstr(s, " MOD ");
-        break;
-    case OFPMC13_DELETE:
-        ds_put_cstr(s, " DEL ");
-        break;
-    default:
-        ds_put_format(s, " cmd:%d ", mm->command);
+    enum ofperr error = ofputil_decode_table_status(oh, &ts);
+    if (!error) {
+        ofputil_format_table_status(string, &ts, table_map);
     }
-
-    ofp_print_meter_config(s, &mm->meter);
+    return error;
 }
 
 static enum ofperr
@@ -577,12 +331,11 @@ ofp_print_meter_mod(struct ds *s, const struct ofp_header 
*oh)
 {
     struct ofputil_meter_mod mm;
     struct ofpbuf bands;
-    enum ofperr error;
 
     ofpbuf_init(&bands, 64);
-    error = ofputil_decode_meter_mod(oh, &mm, &bands);
+    enum ofperr error = ofputil_decode_meter_mod(oh, &mm, &bands);
     if (!error) {
-        ofp_print_meter_mod__(s, &mm);
+        ofputil_format_meter_mod(s, &mm);
     }
     ofpbuf_uninit(&bands);
 
@@ -597,58 +350,17 @@ ofp_print_meter_stats_request(struct ds *s, const struct 
ofp_header *oh)
     ofputil_decode_meter_request(oh, &meter_id);
     ds_put_char(s, ' ');
 
-    ofp_print_meter_id(s, meter_id, '=');
+    ofputil_format_meter_id(s, meter_id, '=');
 
     return 0;
 }
 
-static const char *
-ofputil_meter_capabilities_to_name(uint32_t bit)
-{
-    enum ofp13_meter_flags flag = bit;
-
-    switch (flag) {
-    case OFPMF13_KBPS:    return "kbps";
-    case OFPMF13_PKTPS:   return "pktps";
-    case OFPMF13_BURST:   return "burst";
-    case OFPMF13_STATS:   return "stats";
-    }
-
-    return NULL;
-}
-
-static const char *
-ofputil_meter_band_types_to_name(uint32_t bit)
-{
-    switch (bit) {
-    case 1 << OFPMBT13_DROP:          return "drop";
-    case 1 << OFPMBT13_DSCP_REMARK:   return "dscp_remark";
-    }
-
-    return NULL;
-}
-
 static enum ofperr
 ofp_print_meter_features_reply(struct ds *s, const struct ofp_header *oh)
 {
     struct ofputil_meter_features mf;
-
     ofputil_decode_meter_features(oh, &mf);
-
-    ds_put_format(s, "\nmax_meter:%"PRIu32, mf.max_meters);
-    ds_put_format(s, " max_bands:%"PRIu8, mf.max_bands);
-    ds_put_format(s, " max_color:%"PRIu8"\n", mf.max_color);
-
-    ds_put_cstr(s, "band_types: ");
-    ofp_print_bit_names(s, mf.band_types,
-                        ofputil_meter_band_types_to_name, ' ');
-    ds_put_char(s, '\n');
-
-    ds_put_cstr(s, "capabilities: ");
-    ofp_print_bit_names(s, mf.capabilities,
-                        ofputil_meter_capabilities_to_name, ' ');
-    ds_put_char(s, '\n');
-
+    ofputil_format_meter_features(s, &mf);
     return 0;
 }
 
@@ -668,7 +380,7 @@ ofp_print_meter_config_reply(struct ds *s, const struct 
ofp_header *oh)
             break;
         }
         ds_put_char(s, '\n');
-        ofp_print_meter_config(s, &mc);
+        ofputil_format_meter_config(s, &mc);
     }
     ofpbuf_uninit(&bands);
 
@@ -691,7 +403,7 @@ ofp_print_meter_stats_reply(struct ds *s, const struct 
ofp_header *oh)
             break;
         }
         ds_put_char(s, '\n');
-        ofp_print_meter_stats(s, &ms);
+        ofputil_format_meter_stats(s, &ms);
     }
     ofpbuf_uninit(&bands);
 
@@ -810,30 +522,6 @@ ofp_print_aggregate_stats_reply(struct ds *string, const 
struct ofp_header *oh)
     return error;
 }
 
-static void
-print_port_stat(struct ds *string, const char *leader, uint64_t stat, int more)
-{
-    ds_put_cstr(string, leader);
-    if (stat != UINT64_MAX) {
-        ds_put_format(string, "%"PRIu64, stat);
-    } else {
-        ds_put_char(string, '?');
-    }
-    if (more) {
-        ds_put_cstr(string, ", ");
-    } else {
-        ds_put_cstr(string, "\n");
-    }
-}
-
-static void
-print_port_stat_cond(struct ds *string, const char *leader, uint64_t stat)
-{
-    if (stat != UINT64_MAX) {
-        ds_put_format(string, "%s%"PRIu64", ", leader, stat);
-    }
-}
-
 static enum ofperr
 ofp_print_ofpst_port_request(struct ds *string, const struct ofp_header *oh,
                              const struct ofputil_port_map *port_map)
@@ -857,8 +545,8 @@ ofp_print_ofpst_port_reply(struct ds *string, const struct 
ofp_header *oh,
                            const struct ofputil_port_map *port_map,
                            int verbosity)
 {
-    uint32_t i;
-    ds_put_format(string, " %"PRIuSIZE" ports\n", 
ofputil_count_port_stats(oh));
+    ds_put_format(string, " %"PRIuSIZE" ports\n",
+                  ofputil_count_port_stats(oh));
     if (verbosity < 1) {
         return 0;
     }
@@ -872,120 +560,7 @@ ofp_print_ofpst_port_reply(struct ds *string, const 
struct ofp_header *oh,
         if (retval) {
             return retval != EOF ? retval : 0;
         }
-
-        ds_put_cstr(string, "  port ");
-        if (ofp_to_u16(ps.port_no) < 10) {
-            ds_put_char(string, ' ');
-        }
-        ofputil_format_port(ps.port_no, port_map, string);
-
-        ds_put_cstr(string, ": rx ");
-        print_port_stat(string, "pkts=", ps.stats.rx_packets, 1);
-        print_port_stat(string, "bytes=", ps.stats.rx_bytes, 1);
-        print_port_stat(string, "drop=", ps.stats.rx_dropped, 1);
-        print_port_stat(string, "errs=", ps.stats.rx_errors, 1);
-        print_port_stat(string, "frame=", ps.stats.rx_frame_errors, 1);
-        print_port_stat(string, "over=", ps.stats.rx_over_errors, 1);
-        print_port_stat(string, "crc=", ps.stats.rx_crc_errors, 0);
-
-        ds_put_cstr(string, "           tx ");
-        print_port_stat(string, "pkts=", ps.stats.tx_packets, 1);
-        print_port_stat(string, "bytes=", ps.stats.tx_bytes, 1);
-        print_port_stat(string, "drop=", ps.stats.tx_dropped, 1);
-        print_port_stat(string, "errs=", ps.stats.tx_errors, 1);
-        print_port_stat(string, "coll=", ps.stats.collisions, 0);
-
-        if (ps.duration_sec != UINT32_MAX) {
-            ds_put_cstr(string, "           duration=");
-            ofp_print_duration(string, ps.duration_sec, ps.duration_nsec);
-            ds_put_char(string, '\n');
-        }
-        struct ds string_ext_stats = DS_EMPTY_INITIALIZER;
-
-        ds_init(&string_ext_stats);
-
-        print_port_stat_cond(&string_ext_stats, "1_to_64_packets=",
-                             ps.stats.rx_1_to_64_packets);
-        print_port_stat_cond(&string_ext_stats, "65_to_127_packets=",
-                             ps.stats.rx_65_to_127_packets);
-        print_port_stat_cond(&string_ext_stats, "128_to_255_packets=",
-                             ps.stats.rx_128_to_255_packets);
-        print_port_stat_cond(&string_ext_stats, "256_to_511_packets=",
-                             ps.stats.rx_256_to_511_packets);
-        print_port_stat_cond(&string_ext_stats, "512_to_1023_packets=",
-                             ps.stats.rx_512_to_1023_packets);
-        print_port_stat_cond(&string_ext_stats, "1024_to_1522_packets=",
-                             ps.stats.rx_1024_to_1522_packets);
-        print_port_stat_cond(&string_ext_stats, "1523_to_max_packets=",
-                             ps.stats.rx_1523_to_max_packets);
-        print_port_stat_cond(&string_ext_stats, "broadcast_packets=",
-                             ps.stats.rx_broadcast_packets);
-        print_port_stat_cond(&string_ext_stats, "undersized_errors=",
-                             ps.stats.rx_undersized_errors);
-        print_port_stat_cond(&string_ext_stats, "oversize_errors=",
-                             ps.stats.rx_oversize_errors);
-        print_port_stat_cond(&string_ext_stats, "rx_fragmented_errors=",
-                             ps.stats.rx_fragmented_errors);
-        print_port_stat_cond(&string_ext_stats, "rx_jabber_errors=",
-                             ps.stats.rx_jabber_errors);
-
-        if (string_ext_stats.length != 0) {
-            /* If at least one statistics counter is reported: */
-            ds_put_cstr(string, "           rx rfc2819 ");
-            ds_put_buffer(string, string_ext_stats.string,
-                          string_ext_stats.length);
-            ds_put_cstr(string, "\n");
-            ds_destroy(&string_ext_stats);
-        }
-
-        ds_init(&string_ext_stats);
-
-        print_port_stat_cond(&string_ext_stats, "1_to_64_packets=",
-                             ps.stats.tx_1_to_64_packets);
-        print_port_stat_cond(&string_ext_stats, "65_to_127_packets=",
-                             ps.stats.tx_65_to_127_packets);
-        print_port_stat_cond(&string_ext_stats, "128_to_255_packets=",
-                             ps.stats.tx_128_to_255_packets);
-        print_port_stat_cond(&string_ext_stats, "256_to_511_packets=",
-                             ps.stats.tx_256_to_511_packets);
-        print_port_stat_cond(&string_ext_stats, "512_to_1023_packets=",
-                             ps.stats.tx_512_to_1023_packets);
-        print_port_stat_cond(&string_ext_stats, "1024_to_1522_packets=",
-                             ps.stats.tx_1024_to_1522_packets);
-        print_port_stat_cond(&string_ext_stats, "1523_to_max_packets=",
-                             ps.stats.tx_1523_to_max_packets);
-        print_port_stat_cond(&string_ext_stats, "multicast_packets=",
-                             ps.stats.tx_multicast_packets);
-        print_port_stat_cond(&string_ext_stats, "broadcast_packets=",
-                             ps.stats.tx_broadcast_packets);
-
-        if (string_ext_stats.length != 0) {
-            /* If at least one statistics counter is reported: */
-            ds_put_cstr(string, "           tx rfc2819 ");
-            ds_put_buffer(string, string_ext_stats.string,
-                          string_ext_stats.length);
-            ds_put_cstr(string, "\n");
-            ds_destroy(&string_ext_stats);
-        }
-
-        if (ps.custom_stats.size) {
-            ds_put_cstr(string, "           CUSTOM Statistics");
-            for (i = 0; i < ps.custom_stats.size; i++) {
-                /* 3 counters in the row */
-                if (ps.custom_stats.counters[i].name[0]) {
-                    if (i % 3 == 0) {
-                        ds_put_cstr(string, "\n");
-                        ds_put_cstr(string, "                      ");
-                    } else {
-                        ds_put_char(string, ' ');
-                    }
-                    ds_put_format(string, "%s=%"PRIu64",",
-                                  ps.custom_stats.counters[i].name,
-                                  ps.custom_stats.counters[i].value);
-                }
-            }
-            ds_put_cstr(string, "\n");
-        }
+        ofputil_format_port_stats(string, &ps, port_map);
     }
 }
 
@@ -1018,77 +593,6 @@ ofp_print_table_stats_reply(struct ds *string, const 
struct ofp_header *oh,
     }
 }
 
-static void
-ofp_print_queue_name(struct ds *string, uint32_t queue_id)
-{
-    if (queue_id == OFPQ_ALL) {
-        ds_put_cstr(string, "ALL");
-    } else {
-        ds_put_format(string, "%"PRIu32, queue_id);
-    }
-}
-
-static enum ofperr
-ofp_print_ofpst_queue_request(struct ds *string, const struct ofp_header *oh,
-                              const struct ofputil_port_map *port_map)
-{
-    struct ofputil_queue_stats_request oqsr;
-    enum ofperr error;
-
-    error = ofputil_decode_queue_stats_request(oh, &oqsr);
-    if (error) {
-        return error;
-    }
-
-    ds_put_cstr(string, " port=");
-    ofputil_format_port(oqsr.port_no, port_map, string);
-
-    ds_put_cstr(string, " queue=");
-    ofp_print_queue_name(string, oqsr.queue_id);
-
-    return 0;
-}
-
-static enum ofperr
-ofp_print_ofpst_queue_reply(struct ds *string, const struct ofp_header *oh,
-                            const struct ofputil_port_map *port_map,
-                            int verbosity)
-{
-    ds_put_format(string, " %"PRIuSIZE" queues\n", 
ofputil_count_queue_stats(oh));
-    if (verbosity < 1) {
-        return 0;
-    }
-
-    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
-    for (;;) {
-        struct ofputil_queue_stats qs;
-        int retval;
-
-        retval = ofputil_decode_queue_stats(&qs, &b);
-        if (retval) {
-            return retval != EOF ? retval : 0;
-        }
-
-        ds_put_cstr(string, "  port ");
-        ofputil_format_port(qs.port_no, port_map, string);
-        ds_put_cstr(string, " queue ");
-        ofp_print_queue_name(string, qs.queue_id);
-        ds_put_cstr(string, ": ");
-
-        print_port_stat(string, "bytes=", qs.tx_bytes, 1);
-        print_port_stat(string, "pkts=", qs.tx_packets, 1);
-        print_port_stat(string, "errors=", qs.tx_errors, 1);
-
-        ds_put_cstr(string, "duration=");
-        if (qs.duration_sec != UINT32_MAX) {
-            ofp_print_duration(string, qs.duration_sec, qs.duration_nsec);
-        } else {
-            ds_put_char(string, '?');
-        }
-        ds_put_char(string, '\n');
-    }
-}
-
 static enum ofperr
 ofp_print_ofpst_port_desc_request(struct ds *string,
                                   const struct ofp_header *oh,
@@ -1150,82 +654,26 @@ ofp_print_echo(struct ds *string, const struct 
ofp_header *oh, int verbosity)
     return 0;
 }
 
-static void
-ofp_print_role_generic(struct ds *string, enum ofp12_controller_role role,
-                       uint64_t generation_id)
-{
-    ds_put_cstr(string, " role=");
-
-    switch (role) {
-    case OFPCR12_ROLE_NOCHANGE:
-        ds_put_cstr(string, "nochange");
-        break;
-    case OFPCR12_ROLE_EQUAL:
-        ds_put_cstr(string, "equal"); /* OF 1.2 wording */
-        break;
-    case OFPCR12_ROLE_MASTER:
-        ds_put_cstr(string, "master");
-        break;
-    case OFPCR12_ROLE_SLAVE:
-        ds_put_cstr(string, "slave");
-        break;
-    default:
-        OVS_NOT_REACHED();
-    }
-
-    if (generation_id != UINT64_MAX) {
-        ds_put_format(string, " generation_id=%"PRIu64, generation_id);
-    }
-}
-
 static enum ofperr
 ofp_print_role_message(struct ds *string, const struct ofp_header *oh)
 {
     struct ofputil_role_request rr;
-    enum ofperr error;
-
-    error = ofputil_decode_role_message(oh, &rr);
-    if (error) {
-        return error;
+    enum ofperr error = ofputil_decode_role_message(oh, &rr);
+    if (!error) {
+        ofputil_format_role_message(string, &rr);
     }
-
-    ofp_print_role_generic(string, rr.role, rr.have_generation_id ? 
rr.generation_id : UINT64_MAX);
-
-    return 0;
+    return error;
 }
 
 static enum ofperr
 ofp_print_role_status_message(struct ds *string, const struct ofp_header *oh)
 {
     struct ofputil_role_status rs;
-    enum ofperr error;
-
-    error = ofputil_decode_role_status(oh, &rs);
-    if (error) {
-        return error;
-    }
-
-    ofp_print_role_generic(string, rs.role, rs.generation_id);
-
-    ds_put_cstr(string, " reason=");
-
-    switch (rs.reason) {
-    case OFPCRR_MASTER_REQUEST:
-        ds_put_cstr(string, "master_request");
-        break;
-    case OFPCRR_CONFIG:
-        ds_put_cstr(string, "configuration_changed");
-        break;
-    case OFPCRR_EXPERIMENTER:
-        ds_put_cstr(string, "experimenter_data_changed");
-        break;
-    case OFPCRR_N_REASONS:
-    default:
-        ds_put_cstr(string, "(unknown)");
-        break;
+    enum ofperr error = ofputil_decode_role_status(oh, &rs);
+    if (!error) {
+        ofputil_format_role_status(string, &rs);
     }
-
-    return 0;
+    return error;
 }
 
 static enum ofperr
@@ -1260,128 +708,6 @@ ofp_print_nxt_set_packet_in_format(struct ds *string,
     return error;
 }
 
-/* Returns a string form of 'reason'.  The return value is either a statically
- * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
- * 'bufsize' should be at least OFP_PORT_REASON_BUFSIZE. */
-#define OFP_PORT_REASON_BUFSIZE (INT_STRLEN(int) + 1)
-static const char *
-ofp_port_reason_to_string(enum ofp_port_reason reason,
-                          char *reasonbuf, size_t bufsize)
-{
-    switch (reason) {
-    case OFPPR_ADD:
-        return "add";
-
-    case OFPPR_DELETE:
-        return "delete";
-
-    case OFPPR_MODIFY:
-        return "modify";
-
-    case OFPPR_N_REASONS:
-    default:
-        snprintf(reasonbuf, bufsize, "%d", (int) reason);
-        return reasonbuf;
-    }
-}
-
-/* Returns a string form of 'reason'.  The return value is either a statically
- * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
- * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */
-static const char*
-ofp_role_reason_to_string(enum ofp14_controller_role_reason reason,
-                          char *reasonbuf, size_t bufsize)
-{
-    switch (reason) {
-    case OFPCRR_MASTER_REQUEST:
-        return "master_request";
-
-    case OFPCRR_CONFIG:
-        return "configuration_changed";
-
-    case OFPCRR_EXPERIMENTER:
-        return "experimenter_data_changed";
-
-    case OFPCRR_N_REASONS:
-    default:
-        snprintf(reasonbuf, bufsize, "%d", (int) reason);
-        return reasonbuf;
-    }
-}
-
-/* Returns a string form of 'reason'.  The return value is either a statically
- * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
- * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */
-static const char*
-ofp_table_reason_to_string(enum ofp14_table_reason reason,
-                           char *reasonbuf, size_t bufsize)
-{
-    switch (reason) {
-    case OFPTR_VACANCY_DOWN:
-        return "vacancy_down";
-
-    case OFPTR_VACANCY_UP:
-        return "vacancy_up";
-
-    default:
-        snprintf(reasonbuf, bufsize, "%d", (int) reason);
-        return reasonbuf;
-    }
-}
-
-/* Returns a string form of 'reason'.  The return value is either a statically
- * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
- * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */
-static const char*
-ofp_requestforward_reason_to_string(enum ofp14_requestforward_reason reason,
-                                    char *reasonbuf, size_t bufsize)
-{
-    switch (reason) {
-    case OFPRFR_GROUP_MOD:
-        return "group_mod_request";
-
-    case OFPRFR_METER_MOD:
-        return "meter_mod_request";
-
-    case OFPRFR_N_REASONS:
-    default:
-        snprintf(reasonbuf, bufsize, "%d", (int) reason);
-        return reasonbuf;
-    }
-}
-
-static const char *
-ofp_async_config_reason_to_string(uint32_t reason,
-                                  enum ofputil_async_msg_type type,
-                                  char *reasonbuf, size_t bufsize)
-{
-    switch (type) {
-    case OAM_PACKET_IN:
-        return ofputil_packet_in_reason_to_string(reason, reasonbuf, bufsize);
-
-    case OAM_PORT_STATUS:
-        return ofp_port_reason_to_string(reason, reasonbuf, bufsize);
-
-    case OAM_FLOW_REMOVED:
-        return ofp_flow_removed_reason_to_string(reason, reasonbuf, bufsize);
-
-    case OAM_ROLE_STATUS:
-        return ofp_role_reason_to_string(reason, reasonbuf, bufsize);
-
-    case OAM_TABLE_STATUS:
-        return ofp_table_reason_to_string(reason, reasonbuf, bufsize);
-
-    case OAM_REQUESTFORWARD:
-        return ofp_requestforward_reason_to_string(reason, reasonbuf, bufsize);
-
-    case OAM_N_TYPES:
-    default:
-        return "Unknown asynchronous configuration message type";
-    }
-}
-
-
-#define OFP_ASYNC_CONFIG_REASON_BUFSIZE (INT_STRLEN(int) + 1)
 static enum ofperr
 ofp_print_set_async_config(struct ds *string, const struct ofp_header *oh,
                            enum ofptype ofptype)
@@ -1395,33 +721,7 @@ ofp_print_set_async_config(struct ds *string, const 
struct ofp_header *oh,
     if (error) {
         return error;
     }
-
-    for (int i = 0; i < 2; i++) {
-        ds_put_format(string, "\n %s:\n", i == 0 ? "master" : "slave");
-        for (uint32_t type = 0; type < OAM_N_TYPES; type++) {
-            ds_put_format(string, "%16s:",
-                          ofputil_async_msg_type_to_string(type));
-
-            uint32_t role = i == 0 ? ac.master[type] : ac.slave[type];
-            for (int j = 0; j < 32; j++) {
-                if (role & (1u << j)) {
-                    char reasonbuf[OFP_ASYNC_CONFIG_REASON_BUFSIZE];
-                    const char *reason;
-
-                    reason = ofp_async_config_reason_to_string(
-                        j, type, reasonbuf, sizeof reasonbuf);
-                    if (reason[0]) {
-                        ds_put_format(string, " %s", reason);
-                    }
-                }
-            }
-            if (!role) {
-                ds_put_cstr(string, " (off)");
-            }
-            ds_put_char(string, '\n');
-        }
-    }
-
+    ofputil_format_set_async_config(string, &ac);
     return 0;
 }
 
@@ -1541,19 +841,6 @@ ofp_print_table_desc_reply(struct ds *s, const struct 
ofp_header *oh,
     }
 }
 
-static const char *
-bundle_flags_to_name(uint32_t bit)
-{
-    switch (bit) {
-    case OFPBF_ATOMIC:
-        return "atomic";
-    case OFPBF_ORDERED:
-        return "ordered";
-    default:
-        return NULL;
-    }
-}
-
 static enum ofperr
 ofp_print_bundle_ctrl(struct ds *s, const struct ofp_header *oh)
 {
@@ -1564,40 +851,7 @@ ofp_print_bundle_ctrl(struct ds *s, const struct 
ofp_header *oh)
     if (error) {
         return error;
     }
-
-    ds_put_char(s, '\n');
-
-    ds_put_format(s, " bundle_id=%#"PRIx32" type=",  bctrl.bundle_id);
-    switch (bctrl.type) {
-    case OFPBCT_OPEN_REQUEST:
-        ds_put_cstr(s, "OPEN_REQUEST");
-        break;
-    case OFPBCT_OPEN_REPLY:
-        ds_put_cstr(s, "OPEN_REPLY");
-        break;
-    case OFPBCT_CLOSE_REQUEST:
-        ds_put_cstr(s, "CLOSE_REQUEST");
-        break;
-    case OFPBCT_CLOSE_REPLY:
-        ds_put_cstr(s, "CLOSE_REPLY");
-        break;
-    case OFPBCT_COMMIT_REQUEST:
-        ds_put_cstr(s, "COMMIT_REQUEST");
-        break;
-    case OFPBCT_COMMIT_REPLY:
-        ds_put_cstr(s, "COMMIT_REPLY");
-        break;
-    case OFPBCT_DISCARD_REQUEST:
-        ds_put_cstr(s, "DISCARD_REQUEST");
-        break;
-    case OFPBCT_DISCARD_REPLY:
-        ds_put_cstr(s, "DISCARD_REPLY");
-        break;
-    }
-
-    ds_put_cstr(s, " flags=");
-    ofp_print_bit_names(s, bctrl.flags, bundle_flags_to_name, ' ');
-
+    ofputil_format_bundle_ctrl_request(s, &bctrl);
     return 0;
 }
 
@@ -1607,106 +861,36 @@ ofp_print_bundle_add(struct ds *s, const struct 
ofp_header *oh,
                      const struct ofputil_table_map *table_map,
                      int verbosity)
 {
-    int error;
     struct ofputil_bundle_add_msg badd;
-
-    error = ofputil_decode_bundle_add(oh, &badd, NULL);
-    if (error) {
-        return error;
-    }
-
-    ds_put_char(s, '\n');
-    ds_put_format(s, " bundle_id=%#"PRIx32,  badd.bundle_id);
-    ds_put_cstr(s, " flags=");
-    ofp_print_bit_names(s, badd.flags, bundle_flags_to_name, ' ');
-
-    ds_put_char(s, '\n');
-    char *msg = ofp_to_string(badd.msg, ntohs(badd.msg->length), port_map,
-                              table_map, verbosity);
-    ds_put_and_free_cstr(s, msg);
-
-    return 0;
-}
-
-static void
-print_tlv_table(struct ds *s, struct ovs_list *mappings)
-{
-    struct ofputil_tlv_map *map;
-
-    ds_put_cstr(s, " mapping table:\n");
-    ds_put_cstr(s, " class\ttype\tlength\tmatch field\n");
-    ds_put_cstr(s, " -----\t----\t------\t-----------");
-
-    LIST_FOR_EACH (map, list_node, mappings) {
-        ds_put_char(s, '\n');
-        ds_put_format(s, " 
0x%"PRIx16"\t0x%"PRIx8"\t%"PRIu8"\ttun_metadata%"PRIu16,
-                      map->option_class, map->option_type, map->option_len,
-                      map->index);
+    int error = ofputil_decode_bundle_add(oh, &badd, NULL);
+    if (!error) {
+        ofputil_format_bundle_add(s, &badd, port_map, table_map, verbosity);
     }
+    return error;
 }
 
 static enum ofperr
 ofp_print_tlv_table_mod(struct ds *s, const struct ofp_header *oh)
 {
-    int error;
     struct ofputil_tlv_table_mod ttm;
-
-    error = ofputil_decode_tlv_table_mod(oh, &ttm);
-    if (error) {
-        return error;
-    }
-
-    ds_put_cstr(s, "\n ");
-
-    switch (ttm.command) {
-    case NXTTMC_ADD:
-        ds_put_cstr(s, "ADD");
-        break;
-    case NXTTMC_DELETE:
-        ds_put_cstr(s, "DEL");
-        break;
-    case NXTTMC_CLEAR:
-        ds_put_cstr(s, "CLEAR");
-        break;
-    }
-
-    if (ttm.command != NXTTMC_CLEAR) {
-        print_tlv_table(s, &ttm.mappings);
+    int error = ofputil_decode_tlv_table_mod(oh, &ttm);
+    if (!error) {
+        ofputil_format_tlv_table_mod(s, &ttm);
+        ofputil_uninit_tlv_table(&ttm.mappings);
     }
-
-    ofputil_uninit_tlv_table(&ttm.mappings);
-
-    return 0;
+    return error;
 }
 
 static enum ofperr
 ofp_print_tlv_table_reply(struct ds *s, const struct ofp_header *oh)
 {
-    int error;
     struct ofputil_tlv_table_reply ttr;
-    struct ofputil_tlv_map *map;
-    int allocated_space = 0;
-
-    error = ofputil_decode_tlv_table_reply(oh, &ttr);
-    if (error) {
-        return error;
-    }
-
-    ds_put_char(s, '\n');
-
-    LIST_FOR_EACH (map, list_node, &ttr.mappings) {
-        allocated_space += map->option_len;
+    int error = ofputil_decode_tlv_table_reply(oh, &ttr);
+    if (!error) {
+        ofputil_format_tlv_table_reply(s, &ttr);
+        ofputil_uninit_tlv_table(&ttr.mappings);
     }
-
-    ds_put_format(s, " max option space=%"PRIu32" max fields=%"PRIu16"\n",
-                  ttr.max_option_space, ttr.max_fields);
-    ds_put_format(s, " allocated option space=%d\n", allocated_space);
-    ds_put_char(s, '\n');
-    print_tlv_table(s, &ttr.mappings);
-
-    ofputil_uninit_tlv_table(&ttr.mappings);
-
-    return 0;
+    return error;
 }
 
 /* This function will print the request forward message. The reason for
@@ -1717,49 +901,13 @@ ofp_print_requestforward(struct ds *string, const struct 
ofp_header *oh,
                          const struct ofputil_table_map *table_map)
 {
     struct ofputil_requestforward rf;
-    enum ofperr error;
-
-    error = ofputil_decode_requestforward(oh, &rf);
-    if (error) {
-        return error;
-    }
-
-    ds_put_cstr(string, " reason=");
-
-    switch (rf.reason) {
-    case OFPRFR_GROUP_MOD:
-        ds_put_cstr(string, "group_mod");
-        ofputil_group_mod_format__(string, oh->version, rf.group_mod, port_map,
-                                   table_map);
-        break;
-
-    case OFPRFR_METER_MOD:
-        ds_put_cstr(string, "meter_mod");
-        ofp_print_meter_mod__(string, rf.meter_mod);
-        break;
-
-    case OFPRFR_N_REASONS:
-        OVS_NOT_REACHED();
-    }
-    ofputil_destroy_requestforward(&rf);
-
-    return 0;
-}
-
-static void
-print_ipfix_stat(struct ds *string, const char *leader, uint64_t stat, int 
more)
-{
-    ds_put_cstr(string, leader);
-    if (stat != UINT64_MAX) {
-        ds_put_format(string, "%"PRIu64, stat);
-    } else {
-        ds_put_char(string, '?');
-    }
-    if (more) {
-        ds_put_cstr(string, ", ");
-    } else {
-        ds_put_cstr(string, "\n");
+    enum ofperr error = ofputil_decode_requestforward(oh, &rf);
+    if (!error) {
+        ofputil_format_requestforward(string, oh->version,
+                                      &rf, port_map, table_map);
+        ofputil_destroy_requestforward(&rf);
     }
+    return error;
 }
 
 static enum ofperr
@@ -1774,19 +922,7 @@ ofp_print_nxst_ipfix_bridge_reply(struct ds *string, 
const struct ofp_header *oh
         if (retval) {
             return retval != EOF ? retval : 0;
         }
-
-        ds_put_cstr(string, "\n  bridge ipfix: ");
-        print_ipfix_stat(string, "flows=", is.total_flows, 1);
-        print_ipfix_stat(string, "current flows=", is.current_flows, 1);
-        print_ipfix_stat(string, "sampled pkts=", is.pkts, 1);
-        print_ipfix_stat(string, "ipv4 ok=", is.ipv4_pkts, 1);
-        print_ipfix_stat(string, "ipv6 ok=", is.ipv6_pkts, 1);
-        print_ipfix_stat(string, "tx pkts=", is.tx_pkts, 0);
-        ds_put_cstr(string, "                ");
-        print_ipfix_stat(string, "pkts errs=", is.error_pkts, 1);
-        print_ipfix_stat(string, "ipv4 errs=", is.ipv4_error_pkts, 1);
-        print_ipfix_stat(string, "ipv6 errs=", is.ipv6_error_pkts, 1);
-        print_ipfix_stat(string, "tx errs=", is.tx_errors, 0);
+        ofputil_format_ipfix_stats_bridge(string, &is);
     }
 }
 
@@ -1804,20 +940,7 @@ ofp_print_nxst_ipfix_flow_reply(struct ds *string, const 
struct ofp_header *oh)
         if (retval) {
             return retval != EOF ? retval : 0;
         }
-
-        ds_put_cstr(string, "  id");
-        ds_put_format(string, " %3"PRIuSIZE": ", (size_t) is.collector_set_id);
-        print_ipfix_stat(string, "flows=", is.total_flows, 1);
-        print_ipfix_stat(string, "current flows=", is.current_flows, 1);
-        print_ipfix_stat(string, "sampled pkts=", is.pkts, 1);
-        print_ipfix_stat(string, "ipv4 ok=", is.ipv4_pkts, 1);
-        print_ipfix_stat(string, "ipv6 ok=", is.ipv6_pkts, 1);
-        print_ipfix_stat(string, "tx pkts=", is.tx_pkts, 0);
-        ds_put_cstr(string, "          ");
-        print_ipfix_stat(string, "pkts errs=", is.error_pkts, 1);
-        print_ipfix_stat(string, "ipv4 errs=", is.ipv4_error_pkts, 1);
-        print_ipfix_stat(string, "ipv6 errs=", is.ipv6_error_pkts, 1);
-        print_ipfix_stat(string, "tx errs=", is.tx_errors, 0);
+        ofputil_format_ipfix_stats_flow(string, &is);
     }
 }
 
@@ -1926,10 +1049,10 @@ ofp_to_string__(const struct ofp_header *oh,
         break;
 
     case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:
-        return ofp_print_queue_get_config_request(string, oh, port_map);
+        return ofputil_queue_get_config_request_format(string, oh, port_map);
 
     case OFPTYPE_QUEUE_GET_CONFIG_REPLY:
-        return ofp_print_queue_get_config_reply(string, oh, port_map);
+        return ofputil_queue_get_config_reply_format(string, oh, port_map);
 
     case OFPTYPE_ROLE_REQUEST:
     case OFPTYPE_ROLE_REPLY:
@@ -1971,7 +1094,7 @@ ofp_to_string__(const struct ofp_header *oh,
         return ofp_print_ofpst_port_request(string, oh, port_map);
 
     case OFPTYPE_QUEUE_STATS_REQUEST:
-        return ofp_print_ofpst_queue_request(string, oh, port_map);
+        return ofputil_queue_stats_request_format(string, oh, port_map);
 
     case OFPTYPE_DESC_STATS_REPLY:
         return ofp_print_ofpst_desc_reply(string, oh);
@@ -1980,7 +1103,8 @@ ofp_to_string__(const struct ofp_header *oh,
         return ofp_print_flow_stats_reply(string, oh, port_map, table_map);
 
     case OFPTYPE_QUEUE_STATS_REPLY:
-        return ofp_print_ofpst_queue_reply(string, oh, port_map, verbosity);
+        return ofputil_queue_stats_reply_format(string, oh, port_map,
+                                                verbosity);
 
     case OFPTYPE_PORT_STATS_REPLY:
         return ofp_print_ofpst_port_reply(string, oh, port_map, verbosity);
diff --git a/lib/ofp-queue.c b/lib/ofp-queue.c
index b3f681b0d7bc..1c939878ec3e 100644
--- a/lib/ofp-queue.c
+++ b/lib/ofp-queue.c
@@ -19,6 +19,7 @@
 #include "byte-order.h"
 #include "flow.h"
 #include "openvswitch/ofp-msgs.h"
+#include "openvswitch/ofp-print.h"
 #include "openvswitch/ofp-port.h"
 #include "openvswitch/ofp-prop.h"
 #include "openvswitch/ofpbuf.h"
@@ -29,6 +30,18 @@ VLOG_DEFINE_THIS_MODULE(ofp_queue);
 
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 
+static void
+ofp_print_queue_name(struct ds *string, uint32_t queue_id)
+{
+    if (queue_id == OFPQ_ALL) {
+        ds_put_cstr(string, "ALL");
+    } else {
+        ds_put_format(string, "%"PRIu32, queue_id);
+    }
+}
+
+/* OFPT_QUEUE_GET_CONFIG request and reply. */
+
 /* Constructs and returns an OFPT_QUEUE_GET_CONFIG request for the specified
  * 'port' and 'queue', suitable for OpenFlow version 'version'.
  *
@@ -111,6 +124,31 @@ ofputil_decode_queue_get_config_request(const struct 
ofp_header *oh,
             : OFPERR_OFPQOFC_BAD_PORT);
 }
 
+enum ofperr
+ofputil_queue_get_config_request_format(
+    struct ds *string, const struct ofp_header *oh,
+    const struct ofputil_port_map *port_map)
+{
+    enum ofperr error;
+    ofp_port_t port;
+    uint32_t queue;
+
+    error = ofputil_decode_queue_get_config_request(oh, &port, &queue);
+    if (error) {
+        return error;
+    }
+
+    ds_put_cstr(string, " port=");
+    ofputil_format_port(port, port_map, string);
+
+    if (queue != OFPQ_ALL) {
+        ds_put_cstr(string, " queue=");
+        ofp_print_queue_name(string, queue);
+    }
+
+    return 0;
+}
+
 /* Constructs and returns the beginning of a reply to
  * OFPT_QUEUE_GET_CONFIG_REQUEST or OFPMP_QUEUE_DESC request 'oh'.  The caller
  * may append information about individual queues with
@@ -419,6 +457,83 @@ ofputil_pull_queue_get_config_reply(struct ofpbuf *msg,
         return ofputil_pull_queue_get_config_reply10(msg, queue);
     }
 }
+
+static void
+print_queue_rate(struct ds *string, const char *name, unsigned int rate)
+{
+    if (rate <= 1000) {
+        ds_put_format(string, " %s:%u.%u%%", name, rate / 10, rate % 10);
+    } else if (rate < UINT16_MAX) {
+        ds_put_format(string, " %s:(disabled)", name);
+    }
+}
+
+/* qsort comparison function. */
+static int
+compare_queues(const void *a_, const void *b_)
+{
+    const struct ofputil_queue_config *a = a_;
+    const struct ofputil_queue_config *b = b_;
+
+    uint16_t ap = ofp_to_u16(a->port);
+    uint16_t bp = ofp_to_u16(b->port);
+    if (ap != bp) {
+        return ap < bp ? -1 : 1;
+    }
+
+    uint32_t aq = a->queue;
+    uint32_t bq = b->queue;
+    return aq < bq ? -1 : aq > bq;
+}
+
+enum ofperr
+ofputil_queue_get_config_reply_format(struct ds *string,
+                                      const struct ofp_header *oh,
+                                      const struct ofputil_port_map *port_map)
+{
+    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
+
+    struct ofputil_queue_config *queues = NULL;
+    size_t allocated_queues = 0;
+    size_t n = 0;
+
+    int retval = 0;
+    for (;;) {
+        if (n >= allocated_queues) {
+            queues = x2nrealloc(queues, &allocated_queues, sizeof *queues);
+        }
+        retval = ofputil_pull_queue_get_config_reply(&b, &queues[n]);
+        if (retval) {
+            break;
+        }
+        n++;
+    }
+
+    qsort(queues, n, sizeof *queues, compare_queues);
+
+    ds_put_char(string, ' ');
+
+    ofp_port_t port = 0;
+    for (const struct ofputil_queue_config *q = queues; q < &queues[n]; q++) {
+        if (q->port != port) {
+            port = q->port;
+
+            ds_put_cstr(string, "port=");
+            ofputil_format_port(port, port_map, string);
+            ds_put_char(string, '\n');
+        }
+
+        ds_put_format(string, "queue %"PRIu32":", q->queue);
+        print_queue_rate(string, "min_rate", q->min_rate);
+        print_queue_rate(string, "max_rate", q->max_rate);
+        ds_put_char(string, '\n');
+    }
+
+    ds_chomp(string, ' ');
+    free(queues);
+
+    return retval != EOF ? retval : 0;
+}
 
 /* Parse a queue status request message into 'oqsr'.
  * Returns 0 if successful, otherwise an OFPERR_* number. */
@@ -495,6 +610,28 @@ ofputil_encode_queue_stats_request(
     return request;
 }
 
+enum ofperr
+ofputil_queue_stats_request_format(struct ds *string,
+                                   const struct ofp_header *oh,
+                                   const struct ofputil_port_map *port_map)
+{
+    struct ofputil_queue_stats_request oqsr;
+    enum ofperr error;
+
+    error = ofputil_decode_queue_stats_request(oh, &oqsr);
+    if (error) {
+        return error;
+    }
+
+    ds_put_cstr(string, " port=");
+    ofputil_format_port(oqsr.port_no, port_map, string);
+
+    ds_put_cstr(string, " queue=");
+    ofp_print_queue_name(string, oqsr.queue_id);
+
+    return 0;
+}
+
 /* Returns the number of queue stats elements in OFPTYPE_QUEUE_STATS_REPLY
  * message 'oh'. */
 size_t
@@ -726,3 +863,62 @@ ofputil_append_queue_stat(struct ovs_list *replies,
     }
 }
 
+static void
+print_queue_stat(struct ds *string, const char *leader, uint64_t stat,
+                 int more)
+{
+    ds_put_cstr(string, leader);
+    if (stat != UINT64_MAX) {
+        ds_put_format(string, "%"PRIu64, stat);
+    } else {
+        ds_put_char(string, '?');
+    }
+    if (more) {
+        ds_put_cstr(string, ", ");
+    } else {
+        ds_put_cstr(string, "\n");
+    }
+}
+
+enum ofperr
+ofputil_queue_stats_reply_format(struct ds *string,
+                                 const struct ofp_header *oh,
+                                 const struct ofputil_port_map *port_map,
+                                 int verbosity)
+{
+    ds_put_format(string, " %"PRIuSIZE" queues\n",
+                  ofputil_count_queue_stats(oh));
+    if (verbosity < 1) {
+        return 0;
+    }
+
+    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
+    for (;;) {
+        struct ofputil_queue_stats qs;
+        int retval;
+
+        retval = ofputil_decode_queue_stats(&qs, &b);
+        if (retval) {
+            return retval != EOF ? retval : 0;
+        }
+
+        ds_put_cstr(string, "  port ");
+        ofputil_format_port(qs.port_no, port_map, string);
+        ds_put_cstr(string, " queue ");
+        ofp_print_queue_name(string, qs.queue_id);
+        ds_put_cstr(string, ": ");
+
+        print_queue_stat(string, "bytes=", qs.tx_bytes, 1);
+        print_queue_stat(string, "pkts=", qs.tx_packets, 1);
+        print_queue_stat(string, "errors=", qs.tx_errors, 1);
+
+        ds_put_cstr(string, "duration=");
+        if (qs.duration_sec != UINT32_MAX) {
+            ofp_print_duration(string, qs.duration_sec, qs.duration_nsec);
+        } else {
+            ds_put_char(string, '?');
+        }
+        ds_put_char(string, '\n');
+    }
+}
+
diff --git a/lib/ofp-table.c b/lib/ofp-table.c
index 595a4384ddfa..5f14fcc3a9f3 100644
--- a/lib/ofp-table.c
+++ b/lib/ofp-table.c
@@ -1912,6 +1912,26 @@ ofputil_decode_table_stats_reply(struct ofpbuf *msg,
     }
 }
 
+/* Returns a string form of 'reason'.  The return value is either a statically
+ * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
+ * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */
+const char *
+ofp_table_reason_to_string(enum ofp14_table_reason reason,
+                           char *reasonbuf, size_t bufsize)
+{
+    switch (reason) {
+    case OFPTR_VACANCY_DOWN:
+        return "vacancy_down";
+
+    case OFPTR_VACANCY_UP:
+        return "vacancy_up";
+
+    default:
+        snprintf(reasonbuf, bufsize, "%d", (int) reason);
+        return reasonbuf;
+    }
+}
+
 static void
 ofputil_put_ofp14_table_desc(const struct ofputil_table_desc *td,
                              struct ofpbuf *b, enum ofp_version version)
@@ -1997,3 +2017,18 @@ ofputil_decode_table_status(const struct ofp_header *oh,
 
     return 0;
 }
+
+void
+ofputil_format_table_status(struct ds *string,
+                            const struct ofputil_table_status *ts,
+                            const struct ofputil_table_map *table_map)
+{
+    if (ts->reason == OFPTR_VACANCY_DOWN) {
+        ds_put_format(string, " reason=VACANCY_DOWN");
+    } else if (ts->reason == OFPTR_VACANCY_UP) {
+        ds_put_format(string, " reason=VACANCY_UP");
+    }
+
+    ds_put_format(string, "\ntable_desc:-");
+    ofputil_table_desc_format(string, &ts->desc, table_map);
+}
-- 
2.16.1

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to