[ovs-dev] [PATCH 2/2] ovs-ofctl: complete color output for dump-flows command

Quentin Monnet quentin.monnet at 6wind.com
Tue Feb 2 08:22:56 UTC 2016


Add color output for flow match conditions and flow actions for
ovs-ofctl dump-flows command utility. More fields get colorized, but the
functioning of the `--color` option is left unchanged.

Signed-off-by: Quentin Monnet <quentin.monnet at 6wind.com>
---
 lib/bundle.c                 |  18 +-
 lib/bundle.h                 |   3 +-
 lib/dpif-netdev.c            |   2 +-
 lib/dynamic-string.h         |   9 +-
 lib/flow.c                   |   6 +-
 lib/flow.h                   |   3 +-
 lib/learn.c                  |  58 ++++--
 lib/learn.h                  |   3 +-
 lib/match.c                  | 287 ++++++++++++++++++-----------
 lib/match.h                  |   3 +-
 lib/meta-flow.c              |   7 +-
 lib/multipath.c              |   8 +-
 lib/multipath.h              |   3 +-
 lib/nx-match.c               |  17 +-
 lib/nx-match.h               |   9 +-
 lib/odp-util.c               |   6 +-
 lib/ofp-actions.c            | 427 ++++++++++++++++++++++++++++---------------
 lib/ofp-actions.h            |   3 +-
 lib/ofp-print.c              |  26 +--
 ofproto/ofproto-dpif-xlate.c |   2 +-
 ofproto/ofproto-dpif.c       |   4 +-
 ofproto/ofproto.c            |   2 +-
 ovn/controller/ofctrl.c      |   4 +-
 tests/test-ovn.c             |   2 +-
 utilities/ovs-ofctl.c        |   4 +-
 25 files changed, 584 insertions(+), 332 deletions(-)

diff --git a/lib/bundle.c b/lib/bundle.c
index 871a724e8a67..f35672d0e58e 100644
--- a/lib/bundle.c
+++ b/lib/bundle.c
@@ -279,7 +279,8 @@ bundle_parse_load(const char *s, struct ofpbuf *ofpacts)
 
 /* Appends a human-readable representation of 'nab' to 's'. */
 void
-bundle_format(const struct ofpact_bundle *bundle, struct ds *s)
+bundle_format(const struct ofpact_bundle *bundle, struct ds *s,
+              int const color_option)
 {
     const char *action, *fields, *algorithm;
     size_t i;
@@ -299,22 +300,27 @@ bundle_format(const struct ofpact_bundle *bundle, struct ds *s)
 
     action = bundle->dst.field ? "bundle_load" : "bundle";
 
-    ds_put_format(s, "%s(%s,%"PRIu16",%s,%s,", action, fields,
+    ds_put_color_start(s, paren_color, color_option);
+    ds_put_format(s, "%s(", action);
+    ds_put_color_end(s, color_option);
+    ds_put_format(s, "%s,%"PRIu16",%s,%s,", fields,
                   bundle->basis, algorithm, "ofport");
 
     if (bundle->dst.field) {
         mf_format_subfield(&bundle->dst, s);
-        ds_put_cstr(s, ",");
+        ds_put_char(s, ',');
     }
 
-    ds_put_cstr(s, "slaves:");
+    ds_put_color(s, "slaves:", param_color, color_option);
     for (i = 0; i < bundle->n_slaves; i++) {
         if (i) {
-            ds_put_cstr(s, ",");
+            ds_put_char(s, ',');
         }
 
         ofputil_format_port(bundle->slaves[i], s);
     }
 
-    ds_put_cstr(s, ")");
+    ds_put_color_start(s, paren_color, color_option);
+    ds_put_char(s, ')');
+    ds_put_color_end(s, color_option);
 }
diff --git a/lib/bundle.h b/lib/bundle.h
index a1f0ef2abb69..34d4bc2e6e20 100644
--- a/lib/bundle.h
+++ b/lib/bundle.h
@@ -47,6 +47,7 @@ enum ofperr bundle_check(const struct ofpact_bundle *, ofp_port_t max_ports,
 char *bundle_parse(const char *, struct ofpbuf *ofpacts) OVS_WARN_UNUSED_RESULT;
 char *bundle_parse_load(const char *, struct ofpbuf *ofpacts)
     OVS_WARN_UNUSED_RESULT;
-void bundle_format(const struct ofpact_bundle *, struct ds *);
+void bundle_format(const struct ofpact_bundle *, struct ds *,
+                   int const color_option);
 
 #endif /* bundle.h */
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 833174a0d4d0..36eca013af3a 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -2041,7 +2041,7 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd,
         ds_put_cstr(&ds, "flow_add: ");
         odp_format_ufid(ufid, &ds);
         ds_put_cstr(&ds, " ");
-        match_format(&match, &ds, OFP_DEFAULT_PRIORITY);
+        match_format(&match, &ds, OFP_DEFAULT_PRIORITY, 0);
         ds_put_cstr(&ds, ", actions:");
         format_odp_actions(&ds, actions, actions_len);
 
diff --git a/lib/dynamic-string.h b/lib/dynamic-string.h
index 9940b440b037..b6a18a14d670 100644
--- a/lib/dynamic-string.h
+++ b/lib/dynamic-string.h
@@ -98,9 +98,12 @@ ds_put_char(struct ds *ds, char c)
 
 /* Color codes. */
 static const char *actions_color = "01;31";  /* bold red */
-static const char *table_color   = "35";     /* magenta */
-static const char *param_color   = "32";     /* green */
-static const char *value_color   = "36";     /* cyan */
+static const char *drop_color    = "34";     /* blue */
+static const char *learn_color   = "31";     /* red */
+static const char *param_color   = "36";     /* cyan */
+static const char *paren_color   = "35";     /* magenta */
+static const char *special_color = "33";     /* yellow */
+static const char *value_color   = "32";     /* green */
 
 /* Select Graphic Rendition (SGR, "\33[...m") strings.
  * Also Erase in Line (EL) to Right ("\33[K"). */
diff --git a/lib/flow.c b/lib/flow.c
index 5668d0c5899e..2487ea0bf8d4 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -945,10 +945,12 @@ format_flags(struct ds *ds, const char *(*bit_to_string)(uint32_t),
 void
 format_flags_masked(struct ds *ds, const char *name,
                     const char *(*bit_to_string)(uint32_t), uint32_t flags,
-                    uint32_t mask, uint32_t max_mask)
+                    uint32_t mask, uint32_t max_mask, int const color_option)
 {
     if (name) {
+        ds_put_color_start(ds, param_color, color_option);
         ds_put_format(ds, "%s=", name);
+        ds_put_color_end(ds, color_option);
     }
 
     if (mask == max_mask) {
@@ -1181,7 +1183,7 @@ flow_format(struct ds *ds, const struct flow *flow)
         WC_UNMASK_FIELD(wc, metadata);
     }
 
-    match_format(&match, ds, OFP_DEFAULT_PRIORITY);
+    match_format(&match, ds, OFP_DEFAULT_PRIORITY, 0);
 }
 
 void
diff --git a/lib/flow.h b/lib/flow.h
index dc7130d7bbd3..b3ed50f69394 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -204,7 +204,8 @@ void format_flags(struct ds *ds, const char *(*bit_to_string)(uint32_t),
                   uint32_t flags, char del);
 void format_flags_masked(struct ds *ds, const char *name,
                          const char *(*bit_to_string)(uint32_t),
-                         uint32_t flags, uint32_t mask, uint32_t max_mask);
+                         uint32_t flags, uint32_t mask, uint32_t max_mask,
+                         int const color_option);
 int parse_flags(const char *s, const char *(*bit_to_string)(uint32_t),
                 char end, const char *field_name, char **res_string,
                 uint32_t *res_flags, uint32_t allowed, uint32_t *res_mask);
diff --git a/lib/learn.c b/lib/learn.c
index 66201d5016f0..c85df1545f27 100644
--- a/lib/learn.c
+++ b/lib/learn.c
@@ -408,37 +408,55 @@ learn_parse(char *arg, struct ofpbuf *ofpacts)
 /* Appends a description of 'learn' to 's', in the format that ovs-ofctl(8)
  * describes. */
 void
-learn_format(const struct ofpact_learn *learn, struct ds *s)
+learn_format(const struct ofpact_learn *learn, struct ds *s,
+             int const color_option)
 {
     const struct ofpact_learn_spec *spec;
     struct match match;
 
     match_init_catchall(&match);
 
-    ds_put_format(s, "learn(table=%"PRIu8, learn->table_id);
+    ds_put_color(s, "learn(", learn_color, color_option);
+    ds_put_color(s, "table=", special_color, color_option);
+    ds_put_format(s, "%"PRIu8, learn->table_id);
+
     if (learn->idle_timeout != OFP_FLOW_PERMANENT) {
-        ds_put_format(s, ",idle_timeout=%"PRIu16, learn->idle_timeout);
+        ds_put_char(s, ',');
+        ds_put_color(s, "idle_timeout=", param_color, color_option);
+        ds_put_format(s, "%"PRIu16, learn->idle_timeout);
     }
     if (learn->hard_timeout != OFP_FLOW_PERMANENT) {
-        ds_put_format(s, ",hard_timeout=%"PRIu16, learn->hard_timeout);
+        ds_put_char(s, ',');
+        ds_put_color(s, "hard_timeout=", param_color, color_option);
+        ds_put_format(s, "%"PRIu16, learn->hard_timeout);
     }
     if (learn->fin_idle_timeout) {
-        ds_put_format(s, ",fin_idle_timeout=%"PRIu16, learn->fin_idle_timeout);
+        ds_put_char(s, ',');
+        ds_put_color(s, "fin_idle_timeout=", param_color, color_option);
+        ds_put_format(s, "%"PRIu16, learn->fin_idle_timeout);
     }
     if (learn->fin_hard_timeout) {
-        ds_put_format(s, ",fin_hard_timeout=%"PRIu16, learn->fin_hard_timeout);
+        ds_put_char(s, ',');
+        ds_put_color(s, "fin_hard_timeout=", param_color, color_option);
+        ds_put_format(s, "%"PRIu16, learn->fin_hard_timeout);
     }
     if (learn->priority != OFP_DEFAULT_PRIORITY) {
-        ds_put_format(s, ",priority=%"PRIu16, learn->priority);
+        ds_put_char(s, ',');
+        ds_put_color(s, "priority=", special_color, color_option);
+        ds_put_format(s, "%"PRIu16, learn->priority);
     }
     if (learn->flags & NX_LEARN_F_SEND_FLOW_REM) {
-        ds_put_cstr(s, ",send_flow_rem");
+        ds_put_char(s, ',');
+        ds_put_color(s, "send_flow_rem", value_color, color_option);
     }
     if (learn->flags & NX_LEARN_F_DELETE_LEARNED) {
-        ds_put_cstr(s, ",delete_learned");
+        ds_put_char(s, ',');
+        ds_put_color(s, "delete_learned", value_color, color_option);
     }
     if (learn->cookie != 0) {
-        ds_put_format(s, ",cookie=%#"PRIx64, ntohll(learn->cookie));
+        ds_put_char(s, ',');
+        ds_put_color(s, "cookie=", param_color, color_option);
+        ds_put_format(s, "%#"PRIx64, ntohll(learn->cookie));
     }
 
     for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) {
@@ -454,43 +472,53 @@ learn_format(const struct ofpact_learn *learn, struct ds *s)
                 bitwise_copy(&spec->src_imm, sizeof spec->src_imm, 0,
                              &value, spec->dst.field->n_bytes, 0,
                              spec->dst.field->n_bits);
+                ds_put_color_start(s, param_color, color_option);
                 ds_put_format(s, "%s=", spec->dst.field->name);
+                ds_put_color_end(s, color_option);
                 mf_format(spec->dst.field, &value, NULL, s);
             } else {
+                ds_put_color_start(s, param_color, color_option);
                 mf_format_subfield(&spec->dst, s);
                 ds_put_char(s, '=');
+                ds_put_color_end(s, color_option);
                 mf_format_subvalue(&spec->src_imm, s);
             }
             break;
 
         case NX_LEARN_SRC_FIELD | NX_LEARN_DST_MATCH:
+            ds_put_color_start(s, value_color, color_option);
             mf_format_subfield(&spec->dst, s);
+            ds_put_color_end(s, color_option);
             if (spec->src.field != spec->dst.field ||
                 spec->src.ofs != spec->dst.ofs) {
+                ds_put_color_start(s, param_color, color_option);
                 ds_put_char(s, '=');
+                ds_put_color_end(s, color_option);
                 mf_format_subfield(&spec->src, s);
             }
             break;
 
         case NX_LEARN_SRC_IMMEDIATE | NX_LEARN_DST_LOAD:
-            ds_put_format(s, "load:");
+            ds_put_color(s, "load:", special_color, color_option);
             mf_format_subvalue(&spec->src_imm, s);
-            ds_put_cstr(s, "->");
+            ds_put_color(s, "->", special_color, color_option);
             mf_format_subfield(&spec->dst, s);
             break;
 
         case NX_LEARN_SRC_FIELD | NX_LEARN_DST_LOAD:
-            ds_put_cstr(s, "load:");
+            ds_put_color(s, "load:", special_color, color_option);
             mf_format_subfield(&spec->src, s);
-            ds_put_cstr(s, "->");
+            ds_put_color(s, "->", special_color, color_option);
             mf_format_subfield(&spec->dst, s);
             break;
 
         case NX_LEARN_SRC_FIELD | NX_LEARN_DST_OUTPUT:
-            ds_put_cstr(s, "output:");
+            ds_put_color(s, "output:", special_color, color_option);
             mf_format_subfield(&spec->src, s);
             break;
         }
     }
+    ds_put_color_start(s, learn_color, color_option);
     ds_put_char(s, ')');
+    ds_put_color_end(s, color_option);
 }
diff --git a/lib/learn.h b/lib/learn.h
index 1bc00ff2ee30..036f0d0db468 100644
--- a/lib/learn.h
+++ b/lib/learn.h
@@ -39,6 +39,7 @@ void learn_execute(const struct ofpact_learn *, const struct flow *,
 void learn_mask(const struct ofpact_learn *, struct flow_wildcards *);
 
 char *learn_parse(char *, struct ofpbuf *ofpacts) OVS_WARN_UNUSED_RESULT;
-void learn_format(const struct ofpact_learn *, struct ds *);
+void learn_format(const struct ofpact_learn *, struct ds *,
+                  int const color_option);
 
 #endif /* learn.h */
diff --git a/lib/match.c b/lib/match.c
index 95d34bc7011f..49967631205b 100644
--- a/lib/match.c
+++ b/lib/match.c
@@ -864,11 +864,13 @@ match_init_hidden_fields(struct match *m)
 }
 
 static void
-format_eth_masked(struct ds *s, const char *name,
-                  const struct eth_addr eth, const struct eth_addr mask)
+format_eth_masked(struct ds *s, const char *name, const struct eth_addr eth,
+                  const struct eth_addr mask, int const color_option)
 {
     if (!eth_addr_is_zero(mask)) {
+        ds_put_color_start(s, param_color, color_option);
         ds_put_format(s, "%s=", name);
+        ds_put_color_end(s, color_option);
         eth_format_masked(eth, &mask, s);
         ds_put_char(s, ',');
     }
@@ -876,10 +878,12 @@ format_eth_masked(struct ds *s, const char *name,
 
 static void
 format_ip_netmask(struct ds *s, const char *name, ovs_be32 ip,
-                  ovs_be32 netmask)
+                  ovs_be32 netmask, int const color_option)
 {
     if (netmask) {
+        ds_put_color_start(s, param_color, color_option);
         ds_put_format(s, "%s=", name);
+        ds_put_color_end(s, color_option);
         ip_format_masked(ip, netmask, s);
         ds_put_char(s, ',');
     }
@@ -888,21 +892,25 @@ format_ip_netmask(struct ds *s, const char *name, ovs_be32 ip,
 static void
 format_ipv6_netmask(struct ds *s, const char *name,
                     const struct in6_addr *addr,
-                    const struct in6_addr *netmask)
+                    const struct in6_addr *netmask, int const color_option)
 {
     if (!ipv6_mask_is_any(netmask)) {
+        ds_put_color_start(s, param_color, color_option);
         ds_put_format(s, "%s=", name);
+        ds_put_color_end(s, color_option);
         ipv6_format_masked(addr, netmask, s);
         ds_put_char(s, ',');
     }
 }
 
 static void
-format_uint16_masked(struct ds *s, const char *name,
-                   uint16_t value, uint16_t mask)
+format_uint16_masked(struct ds *s, const char *name, uint16_t value,
+                     uint16_t mask, int const color_option)
 {
     if (mask != 0) {
+        ds_put_color_start(s, param_color, color_option);
         ds_put_format(s, "%s=", name);
+        ds_put_color_end(s, color_option);
         if (mask == UINT16_MAX) {
             ds_put_format(s, "%"PRIu16, value);
         } else {
@@ -913,11 +921,13 @@ format_uint16_masked(struct ds *s, const char *name,
 }
 
 static void
-format_be16_masked(struct ds *s, const char *name,
-                   ovs_be16 value, ovs_be16 mask)
+format_be16_masked(struct ds *s, const char *name, ovs_be16 value,
+                   ovs_be16 mask, int const color_option)
 {
     if (mask != htons(0)) {
+        ds_put_color_start(s, param_color, color_option);
         ds_put_format(s, "%s=", name);
+        ds_put_color_end(s, color_option);
         if (mask == OVS_BE16_MAX) {
             ds_put_format(s, "%"PRIu16, ntohs(value));
         } else {
@@ -929,11 +939,13 @@ format_be16_masked(struct ds *s, const char *name,
 }
 
 static void
-format_be32_masked(struct ds *s, const char *name,
-                   ovs_be32 value, ovs_be32 mask)
+format_be32_masked(struct ds *s, const char *name, ovs_be32 value,
+                   ovs_be32 mask, int const color_option)
 {
     if (mask != htonl(0)) {
+        ds_put_color_start(s, param_color, color_option);
         ds_put_format(s, "%s=", name);
+        ds_put_color_end(s, color_option);
         if (mask == OVS_BE32_MAX) {
             ds_put_format(s, "%"PRIu32, ntohl(value));
         } else {
@@ -945,11 +957,14 @@ format_be32_masked(struct ds *s, const char *name,
 }
 
 static void
-format_uint32_masked(struct ds *s, const char *name,
-                   uint32_t value, uint32_t mask)
+format_uint32_masked(struct ds *s, const char *name, uint32_t value,
+                     uint32_t mask, int const color_option)
 {
     if (mask) {
-        ds_put_format(s, "%s=%#"PRIx32, name, value);
+        ds_put_color_start(s, param_color, color_option);
+        ds_put_format(s, "%s=", name);
+        ds_put_color_end(s, color_option);
+        ds_put_format(s, "%#"PRIx32, value);
         if (mask != UINT32_MAX) {
             ds_put_format(s, "/%#"PRIx32, mask);
         }
@@ -958,11 +973,14 @@ format_uint32_masked(struct ds *s, const char *name,
 }
 
 static void
-format_be64_masked(struct ds *s, const char *name,
-                   ovs_be64 value, ovs_be64 mask)
+format_be64_masked(struct ds *s, const char *name, ovs_be64 value,
+                   ovs_be64 mask, int const color_option)
 {
     if (mask != htonll(0)) {
-        ds_put_format(s, "%s=%#"PRIx64, name, ntohll(value));
+        ds_put_color_start(s, param_color, color_option);
+        ds_put_format(s, "%s=", name);
+        ds_put_color_end(s, color_option);
+        ds_put_format(s, "%#"PRIx64, ntohll(value));
         if (mask != OVS_BE64_MAX) {
             ds_put_format(s, "/%#"PRIx64, ntohll(mask));
         }
@@ -971,22 +989,26 @@ format_be64_masked(struct ds *s, const char *name,
 }
 
 static void
-format_flow_tunnel(struct ds *s, const struct match *match)
+format_flow_tunnel(struct ds *s, const struct match *match,
+                   int const color_option)
 {
     const struct flow_wildcards *wc = &match->wc;
     const struct flow_tnl *tnl = &match->flow.tunnel;
 
-    format_be64_masked(s, "tun_id", tnl->tun_id, wc->masks.tunnel.tun_id);
-    format_ip_netmask(s, "tun_src", tnl->ip_src, wc->masks.tunnel.ip_src);
-    format_ip_netmask(s, "tun_dst", tnl->ip_dst, wc->masks.tunnel.ip_dst);
+    format_be64_masked(s, "tun_id", tnl->tun_id, wc->masks.tunnel.tun_id,
+                       color_option);
+    format_ip_netmask(s, "tun_src", tnl->ip_src, wc->masks.tunnel.ip_src,
+                      color_option);
+    format_ip_netmask(s, "tun_dst", tnl->ip_dst, wc->masks.tunnel.ip_dst,
+                      color_option);
     format_ipv6_netmask(s, "tun_ipv6_src", &tnl->ipv6_src,
-                        &wc->masks.tunnel.ipv6_src);
+                        &wc->masks.tunnel.ipv6_src, color_option);
     format_ipv6_netmask(s, "tun_ipv6_dst", &tnl->ipv6_dst,
-                        &wc->masks.tunnel.ipv6_dst);
+                        &wc->masks.tunnel.ipv6_dst, color_option);
 
     if (wc->masks.tunnel.gbp_id) {
         format_be16_masked(s, "tun_gbp_id", tnl->gbp_id,
-                           wc->masks.tunnel.gbp_id);
+                           wc->masks.tunnel.gbp_id, color_option);
     }
 
     if (wc->masks.tunnel.gbp_flags) {
@@ -1003,18 +1025,19 @@ format_flow_tunnel(struct ds *s, const struct match *match)
         format_flags_masked(s, "tun_flags", flow_tun_flag_to_string,
                             tnl->flags,
                             wc->masks.tunnel.flags & FLOW_TNL_F_MASK,
-                            FLOW_TNL_F_MASK);
+                            FLOW_TNL_F_MASK, color_option);
         ds_put_char(s, ',');
     }
     tun_metadata_match_format(s, match);
 }
 
 static void
-format_ct_label_masked(struct ds *s, const ovs_u128 *key, const ovs_u128 *mask)
+format_ct_label_masked(struct ds *s, const ovs_u128 *key, const ovs_u128 *mask,
+                       int const color_option)
 {
     if (!ovs_u128_is_zero(mask)) {
         ovs_be128 value = hton128(*key);
-        ds_put_format(s, "ct_label=");
+        ds_put_color(s, "ct_label=", param_color, color_option);
         ds_put_hex(s, &value, sizeof value);
         if (!is_all_ones(mask, sizeof(*mask))) {
             value = hton128(*mask);
@@ -1028,7 +1051,8 @@ format_ct_label_masked(struct ds *s, const ovs_u128 *key, const ovs_u128 *mask)
 /* Appends a string representation of 'match' to 's'.  If 'priority' is
  * different from OFP_DEFAULT_PRIORITY, includes it in 's'. */
 void
-match_format(const struct match *match, struct ds *s, int priority)
+match_format(const struct match *match, struct ds *s, int priority,
+             int const color_option)
 {
     const struct flow_wildcards *wc = &match->wc;
     size_t start_len = s->length;
@@ -1041,38 +1065,42 @@ match_format(const struct match *match, struct ds *s, int priority)
     BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35);
 
     if (priority != OFP_DEFAULT_PRIORITY) {
-        ds_put_format(s, "priority=%d,", priority);
+        ds_put_color(s, "priority=", special_color, color_option);
+        ds_put_format(s, "%d,", priority);
     }
 
-    format_uint32_masked(s, "pkt_mark", f->pkt_mark, wc->masks.pkt_mark);
+    format_uint32_masked(s, "pkt_mark", f->pkt_mark, wc->masks.pkt_mark,
+                         color_option);
 
     if (wc->masks.recirc_id) {
         format_uint32_masked(s, "recirc_id", f->recirc_id,
-                             wc->masks.recirc_id);
+                             wc->masks.recirc_id, color_option);
     }
 
     if (wc->masks.dp_hash) {
         format_uint32_masked(s, "dp_hash", f->dp_hash,
-                             wc->masks.dp_hash);
+                             wc->masks.dp_hash, color_option);
     }
 
     if (wc->masks.conj_id) {
-        ds_put_format(s, "conj_id=%"PRIu32",", f->conj_id);
+        ds_put_color(s, "conj_id=", param_color, color_option);
+        ds_put_format(s, "%"PRIu32",", f->conj_id);
     }
 
     if (wc->masks.skb_priority) {
-        ds_put_format(s, "skb_priority=%#"PRIx32",", f->skb_priority);
+        ds_put_color(s, "skb_priority=", param_color, color_option);
+        ds_put_format(s, "%#"PRIx32",", f->skb_priority);
     }
 
     if (wc->masks.actset_output) {
-        ds_put_cstr(s, "actset_output=");
+        ds_put_color(s, "actset_output=", param_color, color_option);
         ofputil_format_port(f->actset_output, s);
         ds_put_char(s, ',');
     }
 
     if (wc->masks.ct_state) {
         if (wc->masks.ct_state == UINT16_MAX) {
-            ds_put_cstr(s, "ct_state=");
+            ds_put_color(s, "ct_state=", param_color, color_option);
             if (f->ct_state) {
                 format_flags(s, ct_state_to_string, f->ct_state, '|');
             } else {
@@ -1080,21 +1108,25 @@ match_format(const struct match *match, struct ds *s, int priority)
             }
         } else {
             format_flags_masked(s, "ct_state", ct_state_to_string,
-                                f->ct_state, wc->masks.ct_state, UINT16_MAX);
+                                f->ct_state, wc->masks.ct_state, UINT16_MAX,
+                                color_option);
         }
         ds_put_char(s, ',');
     }
 
     if (wc->masks.ct_zone) {
-        format_uint16_masked(s, "ct_zone", f->ct_zone, wc->masks.ct_zone);
+        format_uint16_masked(s, "ct_zone", f->ct_zone, wc->masks.ct_zone,
+                             color_option);
     }
 
     if (wc->masks.ct_mark) {
-        format_uint32_masked(s, "ct_mark", f->ct_mark, wc->masks.ct_mark);
+        format_uint32_masked(s, "ct_mark", f->ct_mark, wc->masks.ct_mark,
+                             color_option);
     }
 
     if (!ovs_u128_is_zero(&wc->masks.ct_label)) {
-        format_ct_label_masked(s, &f->ct_label, &wc->masks.ct_label);
+        format_ct_label_masked(s, &f->ct_label, &wc->masks.ct_label,
+                               color_option);
     }
 
     if (wc->masks.dl_type) {
@@ -1103,48 +1135,48 @@ match_format(const struct match *match, struct ds *s, int priority)
             if (wc->masks.nw_proto) {
                 skip_proto = true;
                 if (f->nw_proto == IPPROTO_ICMP) {
-                    ds_put_cstr(s, "icmp,");
+                    ds_put_color(s, "icmp,", value_color, color_option);
                 } else if (f->nw_proto == IPPROTO_IGMP) {
-                    ds_put_cstr(s, "igmp,");
+                    ds_put_color(s, "igmp,", value_color, color_option);
                 } else if (f->nw_proto == IPPROTO_TCP) {
-                    ds_put_cstr(s, "tcp,");
+                    ds_put_color(s, "tcp,", value_color, color_option);
                 } else if (f->nw_proto == IPPROTO_UDP) {
-                    ds_put_cstr(s, "udp,");
+                    ds_put_color(s, "udp,", value_color, color_option);
                 } else if (f->nw_proto == IPPROTO_SCTP) {
-                    ds_put_cstr(s, "sctp,");
+                    ds_put_color(s, "sctp,", value_color, color_option);
                 } else {
-                    ds_put_cstr(s, "ip,");
+                    ds_put_color(s, "ip,", value_color, color_option);
                     skip_proto = false;
                 }
             } else {
-                ds_put_cstr(s, "ip,");
+                ds_put_color(s, "ip,", value_color, color_option);
             }
         } else if (f->dl_type == htons(ETH_TYPE_IPV6)) {
             if (wc->masks.nw_proto) {
                 skip_proto = true;
                 if (f->nw_proto == IPPROTO_ICMPV6) {
-                    ds_put_cstr(s, "icmp6,");
+                    ds_put_color(s, "icmp6,", value_color, color_option);
                 } else if (f->nw_proto == IPPROTO_TCP) {
-                    ds_put_cstr(s, "tcp6,");
+                    ds_put_color(s, "tcp6,", value_color, color_option);
                 } else if (f->nw_proto == IPPROTO_UDP) {
-                    ds_put_cstr(s, "udp6,");
+                    ds_put_color(s, "udp6,", value_color, color_option);
                 } else if (f->nw_proto == IPPROTO_SCTP) {
-                    ds_put_cstr(s, "sctp6,");
+                    ds_put_color(s, "sctp6,", value_color, color_option);
                 } else {
-                    ds_put_cstr(s, "ipv6,");
+                    ds_put_color(s, "ipv6,", value_color, color_option);
                     skip_proto = false;
                 }
             } else {
-                ds_put_cstr(s, "ipv6,");
+                ds_put_color(s, "ipv6,", value_color, color_option);
             }
         } else if (f->dl_type == htons(ETH_TYPE_ARP)) {
-            ds_put_cstr(s, "arp,");
+            ds_put_color(s, "arp,", value_color, color_option);
         } else if (f->dl_type == htons(ETH_TYPE_RARP)) {
-            ds_put_cstr(s, "rarp,");
+            ds_put_color(s, "rarp,", value_color, color_option);
         } else if (f->dl_type == htons(ETH_TYPE_MPLS)) {
-            ds_put_cstr(s, "mpls,");
+            ds_put_color(s, "mpls,", value_color, color_option);
         } else if (f->dl_type == htons(ETH_TYPE_MPLS_MCAST)) {
-            ds_put_cstr(s, "mplsm,");
+            ds_put_color(s, "mplsm,", value_color, color_option);
         } else {
             skip_type = false;
         }
@@ -1155,15 +1187,17 @@ match_format(const struct match *match, struct ds *s, int priority)
         if (snprintf(regname, REGNAME_LEN, "reg%d", i) >= REGNAME_LEN) {
             strcpy(regname, "reg?");
         }
-        format_uint32_masked(s, regname, f->regs[i], wc->masks.regs[i]);
+        format_uint32_masked(s, regname, f->regs[i], wc->masks.regs[i],
+                             color_option);
     }
 
-    format_flow_tunnel(s, match);
+    format_flow_tunnel(s, match, color_option);
 
-    format_be64_masked(s, "metadata", f->metadata, wc->masks.metadata);
+    format_be64_masked(s, "metadata", f->metadata, wc->masks.metadata,
+                       color_option);
 
     if (wc->masks.in_port.ofp_port) {
-        ds_put_cstr(s, "in_port=");
+        ds_put_color(s, "in_port=", value_color, color_option);
         ofputil_format_port(f->in_port.ofp_port, s);
         ds_put_char(s, ',');
     }
@@ -1177,32 +1211,37 @@ match_format(const struct match *match, struct ds *s, int priority)
             && (!pcp_mask || pcp_mask == htons(VLAN_PCP_MASK))
             && (vid_mask || pcp_mask)) {
             if (vid_mask) {
-                ds_put_format(s, "dl_vlan=%"PRIu16",",
-                              vlan_tci_to_vid(f->vlan_tci));
+                ds_put_color(s, "dl_vlan=", param_color, color_option);
+                ds_put_format(s, "%"PRIu16",", vlan_tci_to_vid(f->vlan_tci));
             }
             if (pcp_mask) {
-                ds_put_format(s, "dl_vlan_pcp=%d,",
-                              vlan_tci_to_pcp(f->vlan_tci));
+                ds_put_color(s, "dl_vlan_pcp=", param_color, color_option);
+                ds_put_format(s, "%d,", vlan_tci_to_pcp(f->vlan_tci));
             }
         } else if (wc->masks.vlan_tci == htons(0xffff)) {
-            ds_put_format(s, "vlan_tci=0x%04"PRIx16",", ntohs(f->vlan_tci));
+            ds_put_color(s, "vlan_tci=", param_color, color_option);
+            ds_put_format(s, "0x%04"PRIx16",", ntohs(f->vlan_tci));
         } else {
-            ds_put_format(s, "vlan_tci=0x%04"PRIx16"/0x%04"PRIx16",",
+            ds_put_color(s, "vlan_tci=", param_color, color_option);
+            ds_put_format(s, "0x%04"PRIx16"/0x%04"PRIx16",",
                           ntohs(f->vlan_tci), ntohs(wc->masks.vlan_tci));
         }
     }
-    format_eth_masked(s, "dl_src", f->dl_src, wc->masks.dl_src);
-    format_eth_masked(s, "dl_dst", f->dl_dst, wc->masks.dl_dst);
+    format_eth_masked(s, "dl_src", f->dl_src, wc->masks.dl_src, color_option);
+    format_eth_masked(s, "dl_dst", f->dl_dst, wc->masks.dl_dst, color_option);
     if (!skip_type && wc->masks.dl_type) {
-        ds_put_format(s, "dl_type=0x%04"PRIx16",", ntohs(f->dl_type));
+        ds_put_color(s, "dl_type=", param_color, color_option);
+        ds_put_format(s, "0x%04"PRIx16",", ntohs(f->dl_type));
     }
     if (f->dl_type == htons(ETH_TYPE_IPV6)) {
-        format_ipv6_netmask(s, "ipv6_src", &f->ipv6_src, &wc->masks.ipv6_src);
-        format_ipv6_netmask(s, "ipv6_dst", &f->ipv6_dst, &wc->masks.ipv6_dst);
+        format_ipv6_netmask(s, "ipv6_src", &f->ipv6_src, &wc->masks.ipv6_src,
+                            color_option);
+        format_ipv6_netmask(s, "ipv6_dst", &f->ipv6_dst, &wc->masks.ipv6_dst,
+                            color_option);
         if (wc->masks.ipv6_label) {
             if (wc->masks.ipv6_label == OVS_BE32_MAX) {
-                ds_put_format(s, "ipv6_label=0x%05"PRIx32",",
-                              ntohl(f->ipv6_label));
+                ds_put_color(s, "ipv6_label=", param_color, color_option);
+                ds_put_format(s, "0x%05"PRIx32",", ntohl(f->ipv6_label));
             } else {
                 ds_put_format(s, "ipv6_label=0x%05"PRIx32"/0x%05"PRIx32",",
                               ntohl(f->ipv6_label),
@@ -1211,95 +1250,121 @@ match_format(const struct match *match, struct ds *s, int priority)
         }
     } else if (f->dl_type == htons(ETH_TYPE_ARP) ||
                f->dl_type == htons(ETH_TYPE_RARP)) {
-        format_ip_netmask(s, "arp_spa", f->nw_src, wc->masks.nw_src);
-        format_ip_netmask(s, "arp_tpa", f->nw_dst, wc->masks.nw_dst);
+        format_ip_netmask(s, "arp_spa", f->nw_src, wc->masks.nw_src,
+                          color_option);
+        format_ip_netmask(s, "arp_tpa", f->nw_dst, wc->masks.nw_dst,
+                          color_option);
     } else {
-        format_ip_netmask(s, "nw_src", f->nw_src, wc->masks.nw_src);
-        format_ip_netmask(s, "nw_dst", f->nw_dst, wc->masks.nw_dst);
+        format_ip_netmask(s, "nw_src", f->nw_src, wc->masks.nw_src,
+                          color_option);
+        format_ip_netmask(s, "nw_dst", f->nw_dst, wc->masks.nw_dst,
+                          color_option);
     }
     if (!skip_proto && wc->masks.nw_proto) {
         if (f->dl_type == htons(ETH_TYPE_ARP) ||
             f->dl_type == htons(ETH_TYPE_RARP)) {
-            ds_put_format(s, "arp_op=%"PRIu8",", f->nw_proto);
+            ds_put_color(s, "arp_op=", param_color, color_option);
+            ds_put_format(s, "%"PRIu8",", f->nw_proto);
         } else {
-            ds_put_format(s, "nw_proto=%"PRIu8",", f->nw_proto);
+            ds_put_color(s, "nw_proto=", param_color, color_option);
+            ds_put_format(s, "%"PRIu8",", f->nw_proto);
         }
     }
     if (f->dl_type == htons(ETH_TYPE_ARP) ||
         f->dl_type == htons(ETH_TYPE_RARP)) {
-        format_eth_masked(s, "arp_sha", f->arp_sha, wc->masks.arp_sha);
-        format_eth_masked(s, "arp_tha", f->arp_tha, wc->masks.arp_tha);
+        format_eth_masked(s, "arp_sha", f->arp_sha, wc->masks.arp_sha,
+                          color_option);
+        format_eth_masked(s, "arp_tha", f->arp_tha, wc->masks.arp_tha,
+                          color_option);
     }
     if (wc->masks.nw_tos & IP_DSCP_MASK) {
-        ds_put_format(s, "nw_tos=%"PRIu8",", f->nw_tos & IP_DSCP_MASK);
+        ds_put_color(s, "nw_tos=", param_color, color_option);
+        ds_put_format(s, "%"PRIu8",", f->nw_tos & IP_DSCP_MASK);
     }
     if (wc->masks.nw_tos & IP_ECN_MASK) {
-        ds_put_format(s, "nw_ecn=%"PRIu8",", f->nw_tos & IP_ECN_MASK);
+        ds_put_color(s, "nw_ecn=", param_color, color_option);
+        ds_put_format(s, "%"PRIu8",", f->nw_tos & IP_ECN_MASK);
     }
     if (wc->masks.nw_ttl) {
-        ds_put_format(s, "nw_ttl=%"PRIu8",", f->nw_ttl);
+        ds_put_color(s, "nw_ttl=", param_color, color_option);
+        ds_put_format(s, "%"PRIu8",", f->nw_ttl);
     }
     if (wc->masks.mpls_lse[0] & htonl(MPLS_LABEL_MASK)) {
-        ds_put_format(s, "mpls_label=%"PRIu32",",
-                      mpls_lse_to_label(f->mpls_lse[0]));
+        ds_put_color(s, "mpls_label=", param_color, color_option);
+        ds_put_format(s, "%"PRIu32",", mpls_lse_to_label(f->mpls_lse[0]));
     }
     if (wc->masks.mpls_lse[0] & htonl(MPLS_TC_MASK)) {
-        ds_put_format(s, "mpls_tc=%"PRIu8",",
-                      mpls_lse_to_tc(f->mpls_lse[0]));
+        ds_put_color(s, "mpls_tc=", param_color, color_option);
+        ds_put_format(s, "%"PRIu8",", mpls_lse_to_tc(f->mpls_lse[0]));
     }
     if (wc->masks.mpls_lse[0] & htonl(MPLS_TTL_MASK)) {
-        ds_put_format(s, "mpls_ttl=%"PRIu8",",
-                      mpls_lse_to_ttl(f->mpls_lse[0]));
+        ds_put_color(s, "mpls_ttl=", param_color, color_option);
+        ds_put_format(s, "%"PRIu8",", mpls_lse_to_ttl(f->mpls_lse[0]));
     }
     if (wc->masks.mpls_lse[0] & htonl(MPLS_BOS_MASK)) {
-        ds_put_format(s, "mpls_bos=%"PRIu8",",
-                      mpls_lse_to_bos(f->mpls_lse[0]));
+        ds_put_color(s, "mpls_bos=", param_color, color_option);
+        ds_put_format(s, "%"PRIu8",", mpls_lse_to_bos(f->mpls_lse[0]));
     }
-    format_be32_masked(s, "mpls_lse1", f->mpls_lse[1], wc->masks.mpls_lse[1]);
-    format_be32_masked(s, "mpls_lse2", f->mpls_lse[2], wc->masks.mpls_lse[2]);
+    format_be32_masked(s, "mpls_lse1", f->mpls_lse[1], wc->masks.mpls_lse[1],
+                       color_option);
+    format_be32_masked(s, "mpls_lse2", f->mpls_lse[2], wc->masks.mpls_lse[2],
+                       color_option);
 
     switch (wc->masks.nw_frag) {
     case FLOW_NW_FRAG_ANY | FLOW_NW_FRAG_LATER:
-        ds_put_format(s, "nw_frag=%s,",
+        ds_put_color(s, "nw_frag=", param_color, color_option);
+        ds_put_format(s, "%s,",
                       f->nw_frag & FLOW_NW_FRAG_ANY
                       ? (f->nw_frag & FLOW_NW_FRAG_LATER ? "later" : "first")
                       : (f->nw_frag & FLOW_NW_FRAG_LATER ? "<error>" : "no"));
         break;
 
     case FLOW_NW_FRAG_ANY:
-        ds_put_format(s, "nw_frag=%s,",
+        ds_put_color(s, "nw_frag=", param_color, color_option);
+        ds_put_format(s, "%s,",
                       f->nw_frag & FLOW_NW_FRAG_ANY ? "yes" : "no");
         break;
 
     case FLOW_NW_FRAG_LATER:
-        ds_put_format(s, "nw_frag=%s,",
+        ds_put_color(s, "nw_frag=", param_color, color_option);
+        ds_put_format(s, "%s,",
                       f->nw_frag & FLOW_NW_FRAG_LATER ? "later" : "not_later");
         break;
     }
     if (f->dl_type == htons(ETH_TYPE_IP) &&
         f->nw_proto == IPPROTO_ICMP) {
-        format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src);
-        format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst);
+        format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src,
+                           color_option);
+        format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst,
+                           color_option);
     } else if (f->dl_type == htons(ETH_TYPE_IP) &&
                f->nw_proto == IPPROTO_IGMP) {
-        format_be16_masked(s, "igmp_type", f->tp_src, wc->masks.tp_src);
-        format_be16_masked(s, "igmp_code", f->tp_dst, wc->masks.tp_dst);
+        format_be16_masked(s, "igmp_type", f->tp_src, wc->masks.tp_src,
+                           color_option);
+        format_be16_masked(s, "igmp_code", f->tp_dst, wc->masks.tp_dst,
+                           color_option);
     } else if (f->dl_type == htons(ETH_TYPE_IPV6) &&
                f->nw_proto == IPPROTO_ICMPV6) {
-        format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src);
-        format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst);
+        format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src,
+                           color_option);
+        format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst,
+                           color_option);
         format_ipv6_netmask(s, "nd_target", &f->nd_target,
-                            &wc->masks.nd_target);
-        format_eth_masked(s, "nd_sll", f->arp_sha, wc->masks.arp_sha);
-        format_eth_masked(s, "nd_tll", f->arp_tha, wc->masks.arp_tha);
+                            &wc->masks.nd_target, color_option);
+        format_eth_masked(s, "nd_sll", f->arp_sha, wc->masks.arp_sha,
+                          color_option);
+        format_eth_masked(s, "nd_tll", f->arp_tha, wc->masks.arp_tha,
+                          color_option);
     } else {
-        format_be16_masked(s, "tp_src", f->tp_src, wc->masks.tp_src);
-        format_be16_masked(s, "tp_dst", f->tp_dst, wc->masks.tp_dst);
+        format_be16_masked(s, "tp_src", f->tp_src, wc->masks.tp_src,
+                           color_option);
+        format_be16_masked(s, "tp_dst", f->tp_dst, wc->masks.tp_dst,
+                           color_option);
     }
     if (is_ip_any(f) && f->nw_proto == IPPROTO_TCP && wc->masks.tcp_flags) {
         format_flags_masked(s, "tcp_flags", packet_tcp_flag_to_string,
                             ntohs(f->tcp_flags), TCP_FLAGS(wc->masks.tcp_flags),
-                            TCP_FLAGS(OVS_BE16_MAX));
+                            TCP_FLAGS(OVS_BE16_MAX), color_option);
     }
 
     if (s->length > start_len) {
@@ -1314,7 +1379,7 @@ char *
 match_to_string(const struct match *match, int priority)
 {
     struct ds s = DS_EMPTY_INITIALIZER;
-    match_format(match, &s, priority);
+    match_format(match, &s, priority, 0);
     return ds_steal_cstr(&s);
 }
 
@@ -1419,7 +1484,7 @@ minimatch_format(const struct minimatch *match, struct ds *s, int priority)
     struct match megamatch;
 
     minimatch_expand(match, &megamatch);
-    match_format(&megamatch, s, priority);
+    match_format(&megamatch, s, priority, 0);
 }
 
 /* Converts 'match' to a string and returns the string.  If 'priority' is
diff --git a/lib/match.h b/lib/match.h
index 650a203d3c64..d5b78402a09b 100644
--- a/lib/match.h
+++ b/lib/match.h
@@ -165,7 +165,8 @@ uint32_t match_hash(const struct match *, uint32_t basis);
 void match_init_hidden_fields(struct match *);
 bool match_has_default_hidden_fields(const struct match *);
 
-void match_format(const struct match *, struct ds *, int priority);
+void match_format(const struct match *, struct ds *, int priority,
+                  int const color_option);
 char *match_to_string(const struct match *, int priority);
 void match_print(const struct match *);
 
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index 6bd0b999ad4e..22f83fd457de 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -2352,21 +2352,22 @@ static void
 mf_format_tnl_flags_string(ovs_be16 value, ovs_be16 mask, struct ds *s)
 {
     format_flags_masked(s, NULL, flow_tun_flag_to_string, ntohs(value),
-                        ntohs(mask) & FLOW_TNL_PUB_F_MASK, FLOW_TNL_PUB_F_MASK);
+                        ntohs(mask) & FLOW_TNL_PUB_F_MASK, FLOW_TNL_PUB_F_MASK,
+                        0);
 }
 
 static void
 mf_format_tcp_flags_string(ovs_be16 value, ovs_be16 mask, struct ds *s)
 {
     format_flags_masked(s, NULL, packet_tcp_flag_to_string, ntohs(value),
-                        TCP_FLAGS(mask), TCP_FLAGS(OVS_BE16_MAX));
+                        TCP_FLAGS(mask), TCP_FLAGS(OVS_BE16_MAX), 0);
 }
 
 static void
 mf_format_ct_state_string(ovs_be32 value, ovs_be32 mask, struct ds *s)
 {
     format_flags_masked(s, NULL, ct_state_to_string, ntohl(value),
-                        ntohl(mask), UINT16_MAX);
+                        ntohl(mask), UINT16_MAX, 0);
 }
 
 /* Appends to 's' a string representation of field 'mf' whose value is in
diff --git a/lib/multipath.c b/lib/multipath.c
index 0a58c062c768..e5555d44236f 100644
--- a/lib/multipath.c
+++ b/lib/multipath.c
@@ -223,7 +223,8 @@ multipath_parse(struct ofpact_multipath *mp, const char *s_)
 /* Appends a description of 'mp' to 's', in the format that ovs-ofctl(8)
  * describes. */
 void
-multipath_format(const struct ofpact_multipath *mp, struct ds *s)
+multipath_format(const struct ofpact_multipath *mp, struct ds *s,
+                 int const color_option)
 {
     const char *fields, *algorithm;
 
@@ -246,9 +247,12 @@ multipath_format(const struct ofpact_multipath *mp, struct ds *s)
         algorithm = "<unknown>";
     }
 
-    ds_put_format(s, "multipath(%s,%"PRIu16",%s,%d,%"PRIu16",",
+    ds_put_format(s, "multipath(", paren_color, color_option);
+    ds_put_format(s, "%s,%"PRIu16",%s,%d,%"PRIu16",",
                   fields, mp->basis, algorithm, mp->max_link + 1,
                   mp->arg);
     mf_format_subfield(&mp->dst, s);
+    ds_put_color_start(s, paren_color, color_option);
     ds_put_char(s, ')');
+    ds_put_color_end(s, color_option);
 }
diff --git a/lib/multipath.h b/lib/multipath.h
index 180681ea4658..a7cb229900f9 100644
--- a/lib/multipath.h
+++ b/lib/multipath.h
@@ -38,6 +38,7 @@ void multipath_execute(const struct ofpact_multipath *, struct flow *,
 
 char *multipath_parse(struct ofpact_multipath *, const char *)
     OVS_WARN_UNUSED_RESULT;
-void multipath_format(const struct ofpact_multipath *, struct ds *);
+void multipath_format(const struct ofpact_multipath *, struct ds *,
+                      int const color_option);
 
 #endif /* multipath.h */
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 0f695f042cb4..baaa607eea9f 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -1600,11 +1600,12 @@ nxm_parse_reg_move(struct ofpact_reg_move *move, const char *s)
 /* nxm_format_reg_move(). */
 
 void
-nxm_format_reg_move(const struct ofpact_reg_move *move, struct ds *s)
+nxm_format_reg_move(const struct ofpact_reg_move *move, struct ds *s,
+                    int const color_option)
 {
-    ds_put_format(s, "move:");
+    ds_put_color(s, "move:", special_color, color_option);
     mf_format_subfield(&move->src, s);
-    ds_put_cstr(s, "->");
+    ds_put_color(s, "->", special_color, color_option);
     mf_format_subfield(&move->dst, s);
 }
 
@@ -1690,16 +1691,18 @@ nxm_parse_stack_action(struct ofpact_stack *stack_action, const char *s)
 }
 
 void
-nxm_format_stack_push(const struct ofpact_stack *push, struct ds *s)
+nxm_format_stack_push(const struct ofpact_stack *push, struct ds *s,
+                      int const color_option)
 {
-    ds_put_cstr(s, "push:");
+    ds_put_color(s, "push:", param_color, color_option);
     mf_format_subfield(&push->subfield, s);
 }
 
 void
-nxm_format_stack_pop(const struct ofpact_stack *pop, struct ds *s)
+nxm_format_stack_pop(const struct ofpact_stack *pop, struct ds *s,
+                     int const color_option)
 {
-    ds_put_cstr(s, "pop:");
+    ds_put_color(s, "pop:", param_color, color_option);
     mf_format_subfield(&pop->subfield, s);
 }
 
diff --git a/lib/nx-match.h b/lib/nx-match.h
index c663e54ce3de..283ea30737e3 100644
--- a/lib/nx-match.h
+++ b/lib/nx-match.h
@@ -102,7 +102,8 @@ void nx_format_field_name(enum mf_field_id, enum ofp_version, struct ds *);
 char *nxm_parse_reg_move(struct ofpact_reg_move *, const char *)
     OVS_WARN_UNUSED_RESULT;
 
-void nxm_format_reg_move(const struct ofpact_reg_move *, struct ds *);
+void nxm_format_reg_move(const struct ofpact_reg_move *, struct ds *,
+                         int const color_option);
 
 enum ofperr nxm_reg_move_check(const struct ofpact_reg_move *,
                                const struct flow *);
@@ -115,8 +116,10 @@ void nxm_reg_load(const struct mf_subfield *, uint64_t src_data,
 char *nxm_parse_stack_action(struct ofpact_stack *, const char *)
     OVS_WARN_UNUSED_RESULT;
 
-void nxm_format_stack_push(const struct ofpact_stack *, struct ds *);
-void nxm_format_stack_pop(const struct ofpact_stack *, struct ds *);
+void nxm_format_stack_push(const struct ofpact_stack *, struct ds *,
+                           int const color_option);
+void nxm_format_stack_pop(const struct ofpact_stack *, struct ds *,
+                          int const color_option);
 
 enum ofperr nxm_stack_push_check(const struct ofpact_stack *,
                                  const  struct flow *);
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 5cbead882ba6..f17ec4a52e2a 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -2282,7 +2282,7 @@ format_tun_flags(struct ds *ds, const char *name, uint16_t key,
         ds_put_char(ds, '(');
         if (mask) {
             format_flags_masked(ds, NULL, flow_tun_flag_to_string, key,
-                                *mask & FLOW_TNL_F_MASK, FLOW_TNL_F_MASK);
+                                *mask & FLOW_TNL_F_MASK, FLOW_TNL_F_MASK, 0);
         } else { /* Fully masked. */
             format_flags(ds, flow_tun_flag_to_string, key, '|');
         }
@@ -2725,7 +2725,7 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
             format_flags_masked(ds, NULL, odp_ct_state_to_string,
                                 nl_attr_get_u32(a),
                                 mask_empty(ma) ? 0 : nl_attr_get_u32(ma),
-                                UINT32_MAX);
+                                UINT32_MAX, 0);
         } else {
             format_flags(ds, odp_ct_state_to_string, nl_attr_get_u32(a), '|');
         }
@@ -2862,7 +2862,7 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
             format_flags_masked(ds, NULL, packet_tcp_flag_to_string,
                                 ntohs(nl_attr_get_be16(a)),
                                 TCP_FLAGS(nl_attr_get_be16(ma)),
-                                TCP_FLAGS(OVS_BE16_MAX));
+                                TCP_FLAGS(OVS_BE16_MAX), 0);
         } else {
             format_flags(ds, packet_tcp_flag_to_string,
                          ntohs(nl_attr_get_be16(a)), '|');
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index 9b7552635cbc..9a5a2f31e019 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -554,10 +554,12 @@ parse_OUTPUT(const char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_OUTPUT(const struct ofpact_output *a, struct ds *s)
+format_OUTPUT(const struct ofpact_output *a, struct ds *s,
+              int const color_option)
 {
     if (ofp_to_u16(a->port) < ofp_to_u16(OFPP_MAX)) {
-        ds_put_format(s, "output:%"PRIu16, a->port);
+        ds_put_color(s, "output:", special_color, color_option);
+        ds_put_format(s, "%"PRIu16, a->port);
     } else {
         ofputil_format_port(a->port, s);
         if (a->port == OFPP_CONTROLLER) {
@@ -596,9 +598,11 @@ parse_GROUP(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_GROUP(const struct ofpact_group *a, struct ds *s)
+format_GROUP(const struct ofpact_group *a, struct ds *s,
+             int const color_option)
 {
-    ds_put_format(s, "group:%"PRIu32, a->group_id);
+    ds_put_color(s, "group:", special_color, color_option);
+    ds_put_format(s, "%"PRIu32, a->group_id);
 }
 
 /* Action structure for NXAST_CONTROLLER.
@@ -711,29 +715,36 @@ parse_CONTROLLER(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_CONTROLLER(const struct ofpact_controller *a, struct ds *s)
+format_CONTROLLER(const struct ofpact_controller *a, struct ds *s,
+                  int const color_option)
 {
     if (a->reason == OFPR_ACTION && a->controller_id == 0) {
-        ds_put_format(s, "CONTROLLER:%"PRIu16, a->max_len);
+        ds_put_color(s, "CONTROLLER:", special_color, color_option);
+        ds_put_format(s, "%"PRIu16, a->max_len);
     } else {
         enum ofp_packet_in_reason reason = a->reason;
 
-        ds_put_cstr(s, "controller(");
+        ds_put_color(s, "controller(", paren_color, color_option);
         if (reason != OFPR_ACTION) {
             char reasonbuf[OFPUTIL_PACKET_IN_REASON_BUFSIZE];
 
-            ds_put_format(s, "reason=%s,",
+            ds_put_color(s, "reason=", param_color, color_option);
+            ds_put_format(s, "%s,",
                           ofputil_packet_in_reason_to_string(
                               reason, reasonbuf, sizeof reasonbuf));
         }
         if (a->max_len != UINT16_MAX) {
-            ds_put_format(s, "max_len=%"PRIu16",", a->max_len);
+            ds_put_color(s, "max_len=", param_color, color_option);
+            ds_put_format(s, "%"PRIu16",", a->max_len);
         }
         if (a->controller_id != 0) {
-            ds_put_format(s, "id=%"PRIu16",", a->controller_id);
+            ds_put_color(s, "id=", param_color, color_option);
+            ds_put_format(s, "%"PRIu16",", a->controller_id);
         }
         ds_chomp(s, ',');
+        ds_put_color_start(s, paren_color, color_option);
         ds_put_char(s, ')');
+        ds_put_color_end(s, color_option);
     }
 }
 
@@ -804,9 +815,10 @@ parse_ENQUEUE(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_ENQUEUE(const struct ofpact_enqueue *a, struct ds *s)
+format_ENQUEUE(const struct ofpact_enqueue *a, struct ds *s,
+               int const color_option)
 {
-    ds_put_format(s, "enqueue:");
+    ds_put_color(s, "enqueue:", param_color, color_option);
     ofputil_format_port(a->port, s);
     ds_put_format(s, ":%"PRIu32, a->queue);
 }
@@ -949,9 +961,10 @@ parse_OUTPUT_REG(const char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_OUTPUT_REG(const struct ofpact_output_reg *a, struct ds *s)
+format_OUTPUT_REG(const struct ofpact_output_reg *a, struct ds *s,
+                  int const color_option)
 {
-    ds_put_cstr(s, "output:");
+    ds_put_color(s, "output:", special_color, color_option);
     mf_format_subfield(&a->src, s);
 }
 
@@ -1162,9 +1175,10 @@ parse_bundle_load(const char *arg, struct ofpbuf *ofpacts)
 }
 
 static void
-format_BUNDLE(const struct ofpact_bundle *a, struct ds *s)
+format_BUNDLE(const struct ofpact_bundle *a, struct ds *s,
+              int const color_option)
 {
-    bundle_format(a, s);
+    bundle_format(a, s, color_option);
 }
 
 /* Set VLAN actions. */
@@ -1251,11 +1265,14 @@ parse_SET_VLAN_VID(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_SET_VLAN_VID(const struct ofpact_vlan_vid *a, struct ds *s)
+format_SET_VLAN_VID(const struct ofpact_vlan_vid *a, struct ds *s,
+                    int const color_option)
 {
-    ds_put_format(s, "%s:%"PRIu16,
-                  a->push_vlan_if_needed ? "mod_vlan_vid" : "set_vlan_vid",
-                  a->vlan_vid);
+    ds_put_color_start(s, param_color, color_option);
+    ds_put_format(s, "%s:",
+                  a->push_vlan_if_needed ? "mod_vlan_vid" : "set_vlan_vid");
+    ds_put_color_end(s, color_option);
+    ds_put_format(s, "%"PRIu16, a->vlan_vid);
 }
 
 /* Set PCP actions. */
@@ -1341,11 +1358,14 @@ parse_SET_VLAN_PCP(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_SET_VLAN_PCP(const struct ofpact_vlan_pcp *a, struct ds *s)
+format_SET_VLAN_PCP(const struct ofpact_vlan_pcp *a, struct ds *s,
+                   int const color_option)
 {
-    ds_put_format(s, "%s:%"PRIu8,
-                  a->push_vlan_if_needed ? "mod_vlan_pcp" : "set_vlan_pcp",
-                  a->vlan_pcp);
+    ds_put_color_start(s, param_color, color_option);
+    ds_put_format(s, "%s:",
+                  a->push_vlan_if_needed ? "mod_vlan_pcp" : "set_vlan_pcp");
+    ds_put_color_end(s, color_option);
+    ds_put_format(s, "%"PRIu8, a->vlan_pcp);
 }
 
 /* Strip VLAN actions. */
@@ -1391,11 +1411,13 @@ parse_pop_vlan(struct ofpbuf *ofpacts)
 }
 
 static void
-format_STRIP_VLAN(const struct ofpact_null *a, struct ds *s)
+format_STRIP_VLAN(const struct ofpact_null *a, struct ds *s,
+                  int const color_option)
 {
-    ds_put_cstr(s, (a->ofpact.raw == OFPAT_RAW11_POP_VLAN
-                    ? "pop_vlan"
-                    : "strip_vlan"));
+    ds_put_color(s, (a->ofpact.raw == OFPAT_RAW11_POP_VLAN
+                     ? "pop_vlan"
+                     : "strip_vlan"),
+                 value_color, color_option);
 }
 
 /* Push VLAN action. */
@@ -1449,10 +1471,12 @@ parse_PUSH_VLAN(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_PUSH_VLAN(const struct ofpact_null *a OVS_UNUSED, struct ds *s)
+format_PUSH_VLAN(const struct ofpact_null *a OVS_UNUSED, struct ds *s,
+                 int const color_option)
 {
     /* XXX 802.1AD case*/
-    ds_put_format(s, "push_vlan:%#"PRIx16, ETH_TYPE_VLAN_8021Q);
+    ds_put_color(s, "push_vlan:", param_color, color_option);
+    ds_put_format(s, "%#"PRIx16, ETH_TYPE_VLAN_8021Q);
 }
 
 /* Action structure for OFPAT10_SET_DL_SRC/DST and OFPAT11_SET_DL_SRC/DST. */
@@ -1532,15 +1556,19 @@ parse_SET_ETH_DST(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_SET_ETH_SRC(const struct ofpact_mac *a, struct ds *s)
+format_SET_ETH_SRC(const struct ofpact_mac *a, struct ds *s,
+                   int const color_option)
 {
-    ds_put_format(s, "mod_dl_src:"ETH_ADDR_FMT, ETH_ADDR_ARGS(a->mac));
+    ds_put_color(s, "mod_dl_src:", param_color, color_option);
+    ds_put_format(s, ETH_ADDR_FMT, ETH_ADDR_ARGS(a->mac));
 }
 
 static void
-format_SET_ETH_DST(const struct ofpact_mac *a, struct ds *s)
+format_SET_ETH_DST(const struct ofpact_mac *a, struct ds *s,
+                   int const color_option)
 {
-    ds_put_format(s, "mod_dl_dst:"ETH_ADDR_FMT, ETH_ADDR_ARGS(a->mac));
+    ds_put_color(s, "mod_dl_dst:", param_color, color_option);
+    ds_put_format(s, ETH_ADDR_FMT, ETH_ADDR_ARGS(a->mac));
 }
 
 /* Set IPv4 address actions. */
@@ -1608,15 +1636,19 @@ parse_SET_IPV4_DST(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_SET_IPV4_SRC(const struct ofpact_ipv4 *a, struct ds *s)
+format_SET_IPV4_SRC(const struct ofpact_ipv4 *a, struct ds *s,
+                    int const color_option)
 {
-    ds_put_format(s, "mod_nw_src:"IP_FMT, IP_ARGS(a->ipv4));
+    ds_put_color(s, "mod_nw_src:", param_color, color_option);
+    ds_put_format(s, IP_FMT, IP_ARGS(a->ipv4));
 }
 
 static void
-format_SET_IPV4_DST(const struct ofpact_ipv4 *a, struct ds *s)
+format_SET_IPV4_DST(const struct ofpact_ipv4 *a, struct ds *s,
+                    int const color_option)
 {
-    ds_put_format(s, "mod_nw_dst:"IP_FMT, IP_ARGS(a->ipv4));
+    ds_put_color(s, "mod_nw_dst:", param_color, color_option);
+    ds_put_format(s, IP_FMT, IP_ARGS(a->ipv4));
 }
 
 /* Set IPv4/v6 TOS actions. */
@@ -1666,9 +1698,11 @@ parse_SET_IP_DSCP(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_SET_IP_DSCP(const struct ofpact_dscp *a, struct ds *s)
+format_SET_IP_DSCP(const struct ofpact_dscp *a, struct ds *s,
+                   int const color_option)
 {
-    ds_put_format(s, "mod_nw_tos:%d", a->dscp);
+    ds_put_color(s, "mod_nw_tos:", param_color, color_option);
+    ds_put_format(s, "%d", a->dscp);
 }
 
 /* Set IPv4/v6 ECN actions. */
@@ -1720,9 +1754,11 @@ parse_SET_IP_ECN(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_SET_IP_ECN(const struct ofpact_ecn *a, struct ds *s)
+format_SET_IP_ECN(const struct ofpact_ecn *a, struct ds *s,
+                  int const color_option)
 {
-    ds_put_format(s, "mod_nw_ecn:%d", a->ecn);
+    ds_put_color(s, "mod_nw_ecn:", param_color, color_option);
+    ds_put_format(s, "%d", a->ecn);
 }
 
 /* Set IPv4/v6 TTL actions. */
@@ -1764,9 +1800,11 @@ parse_SET_IP_TTL(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_SET_IP_TTL(const struct ofpact_ip_ttl *a, struct ds *s)
+format_SET_IP_TTL(const struct ofpact_ip_ttl *a, struct ds *s,
+                  int const color_option)
 {
-    ds_put_format(s, "mod_nw_ttl:%d", a->ttl);
+    ds_put_color(s, "mod_nw_ttl:", param_color, color_option);
+    ds_put_format(s, "%d", a->ttl);
 }
 
 /* Set TCP/UDP/SCTP port actions. */
@@ -1847,15 +1885,19 @@ parse_SET_L4_DST_PORT(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_SET_L4_SRC_PORT(const struct ofpact_l4_port *a, struct ds *s)
+format_SET_L4_SRC_PORT(const struct ofpact_l4_port *a, struct ds *s,
+                       int const color_option)
 {
-    ds_put_format(s, "mod_tp_src:%d", a->port);
+    ds_put_color(s, "mod_tp_src:", param_color, color_option);
+    ds_put_format(s, "%d", a->port);
 }
 
 static void
-format_SET_L4_DST_PORT(const struct ofpact_l4_port *a, struct ds *s)
+format_SET_L4_DST_PORT(const struct ofpact_l4_port *a, struct ds *s,
+                       int const color_option)
 {
-    ds_put_format(s, "mod_tp_dst:%d", a->port);
+    ds_put_color(s, "mod_tp_dst:", param_color, color_option);
+    ds_put_format(s, "%d", a->port);
 }
 
 /* Action structure for OFPAT_COPY_FIELD. */
@@ -2162,9 +2204,10 @@ parse_REG_MOVE(const char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_REG_MOVE(const struct ofpact_reg_move *a, struct ds *s)
+format_REG_MOVE(const struct ofpact_reg_move *a, struct ds *s,
+                int const color_option)
 {
-    nxm_format_reg_move(a, s);
+    nxm_format_reg_move(a, s, color_option);
 }
 
 /* Action structure for OFPAT12_SET_FIELD. */
@@ -2743,7 +2786,8 @@ parse_reg_load(char *arg, struct ofpbuf *ofpacts)
 }
 
 static void
-format_SET_FIELD(const struct ofpact_set_field *a, struct ds *s)
+format_SET_FIELD(const struct ofpact_set_field *a, struct ds *s,
+                 int const color_option)
 {
     if (a->ofpact.raw == NXAST_RAW_REG_LOAD) {
         struct mf_subfield dst;
@@ -2751,15 +2795,18 @@ format_SET_FIELD(const struct ofpact_set_field *a, struct ds *s)
 
         dst.ofs = dst.n_bits = 0;
         while (next_load_segment(a, &dst, &value)) {
-            ds_put_format(s, "load:%#"PRIx64"->", value);
+            ds_put_color(s, "load:", special_color, color_option);
+            ds_put_format(s, "%#"PRIx64, value);
+            ds_put_color(s, "->", special_color, color_option);
             mf_format_subfield(&dst, s);
             ds_put_char(s, ',');
         }
         ds_chomp(s, ',');
     } else {
-        ds_put_cstr(s, "set_field:");
+        ds_put_color(s, "set_field:", special_color, color_option);
         mf_format(a->field, &a->value, &a->mask, s);
-        ds_put_format(s, "->%s", a->field->name);
+        ds_put_color(s, "->", special_color, color_option);
+        ds_put_format(s, "%s", a->field->name);
     }
 }
 
@@ -2884,15 +2931,17 @@ parse_STACK_POP(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_STACK_PUSH(const struct ofpact_stack *a, struct ds *s)
+format_STACK_PUSH(const struct ofpact_stack *a, struct ds *s,
+                  int const color_option)
 {
-    nxm_format_stack_push(a, s);
+    nxm_format_stack_push(a, s, color_option);
 }
 
 static void
-format_STACK_POP(const struct ofpact_stack *a, struct ds *s)
+format_STACK_POP(const struct ofpact_stack *a, struct ds *s,
+                 int const color_option)
 {
-    nxm_format_stack_pop(a, s);
+    nxm_format_stack_pop(a, s, color_option);
 }
 
 /* Action structure for NXAST_DEC_TTL_CNT_IDS.
@@ -3042,20 +3091,21 @@ parse_DEC_TTL(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_DEC_TTL(const struct ofpact_cnt_ids *a, struct ds *s)
+format_DEC_TTL(const struct ofpact_cnt_ids *a, struct ds *s,
+               int const color_option)
 {
     size_t i;
 
-    ds_put_cstr(s, "dec_ttl");
+    ds_put_color(s, "dec_ttl", paren_color, color_option);
     if (a->ofpact.raw == NXAST_RAW_DEC_TTL_CNT_IDS) {
-        ds_put_cstr(s, "(");
+        ds_put_color(s, "(", paren_color, color_option);
         for (i = 0; i < a->n_controllers; i++) {
             if (i) {
                 ds_put_cstr(s, ",");
             }
             ds_put_format(s, "%"PRIu16, a->cnt_ids[i]);
         }
-        ds_put_cstr(s, ")");
+        ds_put_color(s, ")", paren_color, color_option);
     }
 }
 
@@ -3097,9 +3147,12 @@ parse_SET_MPLS_LABEL(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_SET_MPLS_LABEL(const struct ofpact_mpls_label *a, struct ds *s)
+format_SET_MPLS_LABEL(const struct ofpact_mpls_label *a, struct ds *s,
+                      int const color_option)
 {
-    ds_put_format(s, "set_mpls_label(%"PRIu32")", ntohl(a->label));
+    ds_put_color(s, "set_mpls_label(", paren_color, color_option);
+    ds_put_format(s, "%"PRIu32, ntohl(a->label));
+    ds_put_color(s, ")", paren_color, color_option);
 }
 
 /* Set MPLS TC actions. */
@@ -3139,9 +3192,12 @@ parse_SET_MPLS_TC(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_SET_MPLS_TC(const struct ofpact_mpls_tc *a, struct ds *s)
+format_SET_MPLS_TC(const struct ofpact_mpls_tc *a, struct ds *s,
+                   int const color_option)
 {
-    ds_put_format(s, "set_mpls_ttl(%"PRIu8")", a->tc);
+    ds_put_color(s, "set_mpls_ttl(", paren_color, color_option);
+    ds_put_format(s, "%"PRIu8, a->tc);
+    ds_put_color(s, ")", paren_color, color_option);
 }
 
 /* Set MPLS TTL actions. */
@@ -3182,9 +3238,12 @@ parse_SET_MPLS_TTL(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_SET_MPLS_TTL(const struct ofpact_mpls_ttl *a, struct ds *s)
+format_SET_MPLS_TTL(const struct ofpact_mpls_ttl *a, struct ds *s,
+                    int const color_option)
 {
-    ds_put_format(s, "set_mpls_ttl(%"PRIu8")", a->ttl);
+    ds_put_color(s, "set_mpls_ttl(", paren_color, color_option);
+    ds_put_format(s, "%"PRIu8, a->ttl);
+    ds_put_color(s, ")", paren_color, color_option);
 }
 
 /* Decrement MPLS TTL actions. */
@@ -3212,9 +3271,10 @@ parse_DEC_MPLS_TTL(char *arg OVS_UNUSED, struct ofpbuf *ofpacts,
 }
 
 static void
-format_DEC_MPLS_TTL(const struct ofpact_null *a OVS_UNUSED, struct ds *s)
+format_DEC_MPLS_TTL(const struct ofpact_null *a OVS_UNUSED, struct ds *s,
+                    int const color_option)
 {
-    ds_put_cstr(s, "dec_mpls_ttl");
+    ds_put_color(s, "dec_mpls_ttl", value_color, color_option);
 }
 
 /* Push MPLS label action. */
@@ -3257,9 +3317,11 @@ parse_PUSH_MPLS(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_PUSH_MPLS(const struct ofpact_push_mpls *a, struct ds *s)
+format_PUSH_MPLS(const struct ofpact_push_mpls *a, struct ds *s,
+                 int const color_option)
 {
-    ds_put_format(s, "push_mpls:0x%04"PRIx16, ntohs(a->ethertype));
+    ds_put_color(s, "push_mpls:", param_color, color_option);
+    ds_put_format(s, "0x%04"PRIx16, ntohs(a->ethertype));
 }
 
 /* Pop MPLS label action. */
@@ -3295,9 +3357,11 @@ parse_POP_MPLS(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_POP_MPLS(const struct ofpact_pop_mpls *a, struct ds *s)
+format_POP_MPLS(const struct ofpact_pop_mpls *a, struct ds *s,
+                int const color_option)
 {
-    ds_put_format(s, "pop_mpls:0x%04"PRIx16, ntohs(a->ethertype));
+    ds_put_color(s, "pop_mpls:", param_color, color_option);
+    ds_put_format(s, "0x%04"PRIx16, ntohs(a->ethertype));
 }
 
 /* Set tunnel ID actions. */
@@ -3361,12 +3425,15 @@ parse_SET_TUNNEL(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_SET_TUNNEL(const struct ofpact_tunnel *a, struct ds *s)
+format_SET_TUNNEL(const struct ofpact_tunnel *a, struct ds *s,
+                  int const color_option)
 {
-    ds_put_format(s, "set_tunnel%s:%#"PRIx64,
+    ds_put_color_start(s, param_color, color_option);
+    ds_put_format(s, "set_tunnel%s:",
                   (a->tun_id > UINT32_MAX
-                   || a->ofpact.raw == NXAST_RAW_SET_TUNNEL64 ? "64" : ""),
-                  a->tun_id);
+                   || a->ofpact.raw == NXAST_RAW_SET_TUNNEL64 ? "64" : ""));
+    ds_put_color_end(s, color_option);
+    ds_put_format(s, "%#"PRIx64, a->tun_id);
 }
 
 /* Set queue action. */
@@ -3395,9 +3462,11 @@ parse_SET_QUEUE(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_SET_QUEUE(const struct ofpact_queue *a, struct ds *s)
+format_SET_QUEUE(const struct ofpact_queue *a, struct ds *s,
+                 int const color_option)
 {
-    ds_put_format(s, "set_queue:%"PRIu32, a->queue_id);
+    ds_put_color(s, "set_queue:", param_color, color_option);
+    ds_put_format(s, "%"PRIu32, a->queue_id);
 }
 
 /* Pop queue action. */
@@ -3425,9 +3494,10 @@ parse_POP_QUEUE(const char *arg OVS_UNUSED, struct ofpbuf *ofpacts,
 }
 
 static void
-format_POP_QUEUE(const struct ofpact_null *a OVS_UNUSED, struct ds *s)
+format_POP_QUEUE(const struct ofpact_null *a OVS_UNUSED, struct ds *s,
+                 int const color_option)
 {
-    ds_put_cstr(s, "pop_queue");
+    ds_put_color(s, "pop_queue", value_color, color_option);
 }
 
 /* Action structure for NXAST_FIN_TIMEOUT.
@@ -3514,17 +3584,22 @@ parse_FIN_TIMEOUT(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_FIN_TIMEOUT(const struct ofpact_fin_timeout *a, struct ds *s)
+format_FIN_TIMEOUT(const struct ofpact_fin_timeout *a, struct ds *s,
+                   int const color_option)
 {
-    ds_put_cstr(s, "fin_timeout(");
+    ds_put_color(s, "fin_timeout(", paren_color, color_option);
     if (a->fin_idle_timeout) {
-        ds_put_format(s, "idle_timeout=%"PRIu16",", a->fin_idle_timeout);
+        ds_put_color(s, "idle_timeout=", param_color, color_option);
+        ds_put_format(s, "%"PRIu16",", a->fin_idle_timeout);
     }
     if (a->fin_hard_timeout) {
-        ds_put_format(s, "hard_timeout=%"PRIu16",", a->fin_hard_timeout);
+        ds_put_color(s, "hard_timeout=", param_color, color_option);
+        ds_put_format(s, "%"PRIu16",", a->fin_hard_timeout);
     }
     ds_chomp(s, ',');
+    ds_put_color_start(s, paren_color, color_option);
     ds_put_char(s, ')');
+    ds_put_color_end(s, color_option);
 }
 
 /* Action structures for NXAST_RESUBMIT and NXAST_RESUBMIT_TABLE.
@@ -3672,13 +3747,14 @@ parse_RESUBMIT(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_RESUBMIT(const struct ofpact_resubmit *a, struct ds *s)
+format_RESUBMIT(const struct ofpact_resubmit *a, struct ds *s,
+                int const color_option)
 {
     if (a->in_port != OFPP_IN_PORT && a->table_id == 255) {
-        ds_put_cstr(s, "resubmit:");
+        ds_put_color(s, "resubmit:", special_color, color_option);
         ofputil_format_port(a->in_port, s);
     } else {
-        ds_put_format(s, "resubmit(");
+        ds_put_color(s, "resubmit(", paren_color, color_option);
         if (a->in_port != OFPP_IN_PORT) {
             ofputil_format_port(a->in_port, s);
         }
@@ -3686,7 +3762,9 @@ format_RESUBMIT(const struct ofpact_resubmit *a, struct ds *s)
         if (a->table_id != 255) {
             ds_put_format(s, "%"PRIu8, a->table_id);
         }
+        ds_put_color_start(s, paren_color, color_option);
         ds_put_char(s, ')');
+        ds_put_color_end(s, color_option);
     }
 }
 
@@ -4138,9 +4216,10 @@ parse_LEARN(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_LEARN(const struct ofpact_learn *a, struct ds *s)
+format_LEARN(const struct ofpact_learn *a, struct ds *s,
+             int const color_option)
 {
-    learn_format(a, s);
+    learn_format(a, s, color_option);
 }
 
 /* Action structure for NXAST_CONJUNCTION. */
@@ -4192,10 +4271,15 @@ encode_CONJUNCTION(const struct ofpact_conjunction *oc,
 }
 
 static void
-format_CONJUNCTION(const struct ofpact_conjunction *oc, struct ds *s)
+format_CONJUNCTION(const struct ofpact_conjunction *oc, struct ds *s,
+                   int const color_option)
 {
-    ds_put_format(s, "conjunction(%"PRIu32",%"PRIu8"/%"PRIu8")",
+    ds_put_color(s, "conjunction(", paren_color, color_option);
+    ds_put_format(s, "%"PRIu32",%"PRIu8"/%"PRIu8,
                   oc->id, oc->clause + 1, oc->n_clauses);
+    ds_put_color_start(s, paren_color, color_option);
+    ds_put_char(s, ')');
+    ds_put_color_end(s, color_option);
 }
 
 static char * OVS_WARN_UNUSED_RESULT
@@ -4343,9 +4427,10 @@ parse_MULTIPATH(const char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_MULTIPATH(const struct ofpact_multipath *a, struct ds *s)
+format_MULTIPATH(const struct ofpact_multipath *a, struct ds *s,
+                 int const color_option)
 {
-    multipath_format(a, s);
+    multipath_format(a, s, color_option);
 }
 
 /* Action structure for NXAST_NOTE.
@@ -4431,11 +4516,11 @@ parse_NOTE(const char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_NOTE(const struct ofpact_note *a, struct ds *s)
+format_NOTE(const struct ofpact_note *a, struct ds *s, int const color_option)
 {
     size_t i;
 
-    ds_put_cstr(s, "note:");
+    ds_put_color(s, "note:", param_color, color_option);
     for (i = 0; i < a->length; i++) {
         if (i) {
             ds_put_char(s, '.');
@@ -4469,9 +4554,10 @@ parse_EXIT(char *arg OVS_UNUSED, struct ofpbuf *ofpacts,
 }
 
 static void
-format_EXIT(const struct ofpact_null *a OVS_UNUSED, struct ds *s)
+format_EXIT(const struct ofpact_null *a OVS_UNUSED, struct ds *s,
+            int const color_option)
 {
-    ds_put_cstr(s, "exit");
+    ds_put_color(s, "exit", special_color, color_option);
 }
 
 /* Unroll xlate action. */
@@ -4493,10 +4579,17 @@ parse_UNROLL_XLATE(char *arg OVS_UNUSED, struct ofpbuf *ofpacts OVS_UNUSED,
 }
 
 static void
-format_UNROLL_XLATE(const struct ofpact_unroll_xlate *a, struct ds *s)
-{
-    ds_put_format(s, "unroll_xlate(table=%"PRIu8", cookie=%"PRIu64")",
-                  a->rule_table_id, ntohll(a->rule_cookie));
+format_UNROLL_XLATE(const struct ofpact_unroll_xlate *a, struct ds *s,
+                    int const color_option)
+{
+  ds_put_color(s, "unroll_xlate(", paren_color, color_option);
+  ds_put_color(s, "table=", special_color, color_option);
+  ds_put_format(s, "%"PRIu8", ", a->rule_table_id);
+  ds_put_color(s, "cookie=", param_color, color_option);
+  ds_put_format(s, "%"PRIu64, ntohll(a->rule_cookie));
+  ds_put_color_start(s, paren_color, color_option);
+  ds_put_char(s, ')');
+  ds_put_color_end(s, color_option);
 }
 
 /* Action structure for NXAST_SAMPLE.
@@ -4598,12 +4691,23 @@ parse_SAMPLE(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_SAMPLE(const struct ofpact_sample *a, struct ds *s)
+format_SAMPLE(const struct ofpact_sample *a, struct ds *s,
+              int const color_option)
 {
-    ds_put_format(s, "sample(probability=%"PRIu16",collector_set_id=%"PRIu32
-                  ",obs_domain_id=%"PRIu32",obs_point_id=%"PRIu32")",
-                  a->probability, a->collector_set_id,
-                  a->obs_domain_id, a->obs_point_id);
+    ds_put_color(s, "sample(", paren_color, color_option);
+
+    ds_put_color(s, "probability=", param_color, color_option);
+    ds_put_format(s, "%"PRIu16",", a->probability);
+    ds_put_color(s, "collector_set_id=", param_color, color_option);
+    ds_put_format(s, "%"PRIu32",", a->collector_set_id);
+    ds_put_color(s, "obs_domain_id=", param_color, color_option);
+    ds_put_format(s, "%"PRIu32",", a->obs_domain_id);
+    ds_put_color(s, "obs_point_id=", param_color, color_option);
+    ds_put_format(s, "%"PRIu32, a->obs_point_id);
+
+    ds_put_color_start(s, paren_color, color_option);
+    ds_put_char(s, ')');
+    ds_put_color_end(s, color_option);
 }
 
 /* debug_recirc instruction. */
@@ -4644,9 +4748,10 @@ parse_DEBUG_RECIRC(char *arg OVS_UNUSED, struct ofpbuf *ofpacts,
 }
 
 static void
-format_DEBUG_RECIRC(const struct ofpact_null *a OVS_UNUSED, struct ds *s)
+format_DEBUG_RECIRC(const struct ofpact_null *a OVS_UNUSED, struct ds *s,
+                    int const color_option)
 {
-    ds_put_cstr(s, "debug_recirc");
+    ds_put_color(s, "debug_recirc", value_color, color_option);
 }
 
 /* Action structure for NXAST_CT.
@@ -4960,52 +5065,61 @@ parse_CT(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_alg(int port, struct ds *s)
+format_alg(int port, struct ds *s, int const color_option)
 {
     if (port == IPPORT_FTP) {
-        ds_put_format(s, "alg=ftp,");
+        ds_put_color(s, "alg=", param_color, color_option);
+        ds_put_format(s, "ftp,");
     } else if (port) {
-        ds_put_format(s, "alg=%d,", port);
+        ds_put_color(s, "alg=", param_color, color_option);
+        ds_put_format(s, "%d,", port);
     }
 }
 
-static void format_NAT(const struct ofpact_nat *a, struct ds *ds);
+static void
+format_NAT(const struct ofpact_nat *a, struct ds *ds, int const color_option);
 
 static void
-format_CT(const struct ofpact_conntrack *a, struct ds *s)
+format_CT(const struct ofpact_conntrack *a, struct ds *s,
+          int const color_option)
 {
-    ds_put_cstr(s, "ct(");
+    ds_put_color(s, "ct(", paren_color, color_option);
     if (a->flags & NX_CT_F_COMMIT) {
-        ds_put_cstr(s, "commit,");
+        ds_put_color(s, "commit", value_color, color_option);
+        ds_put_char(s, ',');
     }
     if (a->recirc_table != NX_CT_RECIRC_NONE) {
-        ds_put_format(s, "table=%"PRIu8",", a->recirc_table);
+        ds_put_color(s, "table=", special_color, color_option);
+        ds_put_format(s, "%"PRIu8",", a->recirc_table);
     }
     if (a->zone_src.field) {
-        ds_put_format(s, "zone=");
+        ds_put_color(s, "zone=", param_color, color_option);
         mf_format_subfield(&a->zone_src, s);
         ds_put_char(s, ',');
     } else if (a->zone_imm) {
-        ds_put_format(s, "zone=%"PRIu16",", a->zone_imm);
+        ds_put_color(s, "zone=", param_color, color_option);
+        ds_put_format(s, "%"PRIu16",", a->zone_imm);
     }
     /* If the first action is a NAT action, format it outside of the 'exec'
      * envelope. */
     const struct ofpact *action = a->actions;
     size_t actions_len = ofpact_ct_get_action_len(a);
     if (actions_len && action->type == OFPACT_NAT) {
-        format_NAT(ofpact_get_NAT(action), s);
+        format_NAT(ofpact_get_NAT(action), s, color_option);
         ds_put_char(s, ',');
         actions_len -= OFPACT_ALIGN(action->len);
         action = ofpact_next(action);
     }
     if (actions_len) {
-        ds_put_cstr(s, "exec(");
-        ofpacts_format(action, actions_len, s);
-        ds_put_cstr(s, "),");
+        ds_put_color(s, "exec(", paren_color, color_option);
+        ofpacts_format(action, actions_len, s, color_option);
+        ds_put_color(s, "),", paren_color, color_option);
     }
-    format_alg(a->alg, s);
+    format_alg(a->alg, s, color_option);
     ds_chomp(s, ',');
+    ds_put_color_start(s, paren_color, color_option);
     ds_put_char(s, ')');
+    ds_put_color_end(s, color_option);
 }
 
 /* NAT action. */
@@ -5179,16 +5293,19 @@ decode_NXAST_RAW_NAT(const struct nx_action_nat *nan,
 }
 
 static void
-format_NAT(const struct ofpact_nat *a, struct ds *ds)
+format_NAT(const struct ofpact_nat *a, struct ds *ds, int const color_option)
 {
-    ds_put_cstr(ds, "nat");
+    ds_put_color(ds, "nat", paren_color, color_option);
 
     if (a->flags & (NX_NAT_F_SRC | NX_NAT_F_DST)) {
+        ds_put_color_start(ds, paren_color, color_option);
         ds_put_char(ds, '(');
-        ds_put_cstr(ds, a->flags & NX_NAT_F_SRC ? "src" : "dst");
+        ds_put_color_end(ds, color_option);
+        ds_put_color(ds, a->flags & NX_NAT_F_SRC ? "src" : "dst",
+                     param_color, color_option);
 
         if (a->range_af != AF_UNSPEC) {
-            ds_put_cstr(ds, "=");
+            ds_put_color(ds, "=", param_color, color_option);
 
             if (a->range_af == AF_INET) {
                 ds_put_format(ds, IP_FMT, IP_ARGS(a->range.addr.ipv4.min));
@@ -5222,17 +5339,19 @@ format_NAT(const struct ofpact_nat *a, struct ds *ds)
             ds_put_char(ds, ',');
 
             if (a->flags & NX_NAT_F_PERSISTENT) {
-                ds_put_cstr(ds, "persistent,");
+                ds_put_color(ds, "persistent,", value_color, color_option);
             }
             if (a->flags & NX_NAT_F_PROTO_HASH) {
-                ds_put_cstr(ds, "hash,");
+                ds_put_color(ds, "hash,", value_color, color_option);
             }
             if (a->flags & NX_NAT_F_PROTO_RANDOM) {
-                ds_put_cstr(ds, "random,");
+                ds_put_color(ds, "random,", value_color, color_option);
             }
         }
         ds_chomp(ds, ',');
+        ds_put_color_start(ds, paren_color, color_option);
         ds_put_char(ds, ')');
+        ds_put_color_end(ds, color_option);
     }
 }
 
@@ -5368,9 +5487,11 @@ parse_METER(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_METER(const struct ofpact_meter *a, struct ds *s)
+format_METER(const struct ofpact_meter *a, struct ds *s,
+             int const color_option)
 {
-    ds_put_format(s, "meter:%"PRIu32, a->meter_id);
+    ds_put_color(s, "meter:", param_color, color_option);
+    ds_put_format(s, "%"PRIu32, a->meter_id);
 }
 
 /* Clear-Actions instruction. */
@@ -5394,9 +5515,10 @@ parse_CLEAR_ACTIONS(char *arg OVS_UNUSED, struct ofpbuf *ofpacts,
 }
 
 static void
-format_CLEAR_ACTIONS(const struct ofpact_null *a OVS_UNUSED, struct ds *s)
+format_CLEAR_ACTIONS(const struct ofpact_null *a OVS_UNUSED, struct ds *s,
+                     int const color_option)
 {
-    ds_put_cstr(s, "clear_actions");
+    ds_put_color(s, "clear_actions", value_color, color_option);
 }
 
 /* Write-Actions instruction. */
@@ -5449,11 +5571,14 @@ parse_WRITE_ACTIONS(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_WRITE_ACTIONS(const struct ofpact_nest *a, struct ds *s)
+format_WRITE_ACTIONS(const struct ofpact_nest *a, struct ds *s,
+                     int const color_option)
 {
-    ds_put_cstr(s, "write_actions(");
-    ofpacts_format(a->actions, ofpact_nest_get_action_len(a), s);
+    ds_put_color(s, "write_actions(", paren_color, color_option);
+    ofpacts_format(a->actions, ofpact_nest_get_action_len(a), s, color_option);
+    ds_put_color_start(s, paren_color, color_option);
     ds_put_char(s, ')');
+    ds_put_color_end(s, color_option);
 }
 
 /* Action structure for NXAST_WRITE_METADATA.
@@ -5533,9 +5658,11 @@ parse_WRITE_METADATA(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_WRITE_METADATA(const struct ofpact_metadata *a, struct ds *s)
+format_WRITE_METADATA(const struct ofpact_metadata *a, struct ds *s,
+                      int const color_option)
 {
-    ds_put_format(s, "write_metadata:%#"PRIx64, ntohll(a->metadata));
+    ds_put_color(s, "write_metadata:", param_color, color_option);
+    ds_put_format(s, "%#"PRIx64, ntohll(a->metadata));
     if (a->mask != OVS_BE64_MAX) {
         ds_put_format(s, "/%#"PRIx64, ntohll(a->mask));
     }
@@ -5575,9 +5702,11 @@ parse_GOTO_TABLE(char *arg, struct ofpbuf *ofpacts,
 }
 
 static void
-format_GOTO_TABLE(const struct ofpact_goto_table *a, struct ds *s)
+format_GOTO_TABLE(const struct ofpact_goto_table *a, struct ds *s,
+                  int const color_option)
 {
-    ds_put_format(s, "goto_table:%"PRIu8, a->table_id);
+    ds_put_color(s, "goto_table:", param_color, color_option);
+    ds_put_format(s, "%"PRIu8, a->table_id);
 }
 
 static void
@@ -7215,12 +7344,12 @@ ofpacts_get_meter(const struct ofpact ofpacts[], size_t ofpacts_len)
 /* Formatting ofpacts. */
 
 static void
-ofpact_format(const struct ofpact *a, struct ds *s)
+ofpact_format(const struct ofpact *a, struct ds *s, int const c)
 {
     switch (a->type) {
 #define OFPACT(ENUM, STRUCT, MEMBER, NAME)                              \
         case OFPACT_##ENUM:                                             \
-            format_##ENUM(ALIGNED_CAST(const struct STRUCT *, a), s);   \
+            format_##ENUM(ALIGNED_CAST(const struct STRUCT *, a), s, c);\
             break;
         OFPACTS
 #undef OFPACT
@@ -7233,20 +7362,22 @@ ofpact_format(const struct ofpact *a, struct ds *s)
  * 'ofpacts' to 'string'. */
 void
 ofpacts_format(const struct ofpact *ofpacts, size_t ofpacts_len,
-               struct ds *string)
+               struct ds *string, int const color_option)
 {
     if (!ofpacts_len) {
+        ds_put_color_start(string, drop_color, color_option);
         ds_put_cstr(string, "drop");
+        ds_put_color_end(string, color_option);
     } else {
         const struct ofpact *a;
 
         OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
             if (a != ofpacts) {
-                ds_put_cstr(string, ",");
+                ds_put_char(string, ',');
             }
 
             /* XXX write-actions */
-            ofpact_format(a, string);
+            ofpact_format(a, string, color_option);
         }
     }
 }
diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
index 5dec177fbf1f..102d74eb9145 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -878,7 +878,8 @@ const struct mf_field *ofpact_get_mf_dst(const struct ofpact *ofpact);
 uint32_t ofpacts_get_meter(const struct ofpact[], size_t ofpacts_len);
 
 /* Formatting and parsing ofpacts. */
-void ofpacts_format(const struct ofpact[], size_t ofpacts_len, struct ds *);
+void ofpacts_format(const struct ofpact[], size_t ofpacts_len, struct ds *,
+                    int const color_option);
 char *ofpacts_parse_actions(const char *, struct ofpbuf *ofpacts,
                             enum ofputil_protocol *usable_protocols)
     OVS_WARN_UNUSED_RESULT;
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 3b495c2749df..1d09c955f2d4 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -120,7 +120,7 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
 
     ds_put_format(string, " total_len=%"PRIuSIZE" ", total_len);
 
-    match_format(&pin.flow_metadata, string, OFP_DEFAULT_PRIORITY);
+    match_format(&pin.flow_metadata, string, OFP_DEFAULT_PRIORITY, 0);
 
     ds_put_format(string, " (via %s)",
                   ofputil_packet_in_reason_to_string(pin.reason,
@@ -171,7 +171,7 @@ ofp_print_packet_out(struct ds *string, const struct ofp_header *oh,
     ofputil_format_port(po.in_port, string);
 
     ds_put_cstr(string, " actions=");
-    ofpacts_format(po.ofpacts, po.ofpacts_len, string);
+    ofpacts_format(po.ofpacts, po.ofpacts_len, string, 0);
 
     if (po.buffer_id == UINT32_MAX) {
         ds_put_format(string, " data_len=%"PRIuSIZE, po.packet_len);
@@ -780,7 +780,7 @@ ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh, int verbosity)
         /* nx_match_to_string() doesn't print priority. */
         need_priority = true;
     } else {
-        match_format(&fm.match, s, fm.priority);
+        match_format(&fm.match, s, fm.priority, 0);
 
         /* match_format() does print priority. */
         need_priority = false;
@@ -826,7 +826,7 @@ ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh, int verbosity)
     ofp_print_flow_flags(s, fm.flags);
 
     ds_put_cstr(s, "actions=");
-    ofpacts_format(fm.ofpacts, fm.ofpacts_len, s);
+    ofpacts_format(fm.ofpacts, fm.ofpacts_len, s, 0);
     ofpbuf_uninit(&ofpacts);
 }
 
@@ -901,7 +901,7 @@ ofp_print_flow_removed(struct ds *string, const struct ofp_header *oh)
     }
 
     ds_put_char(string, ' ');
-    match_format(&fr.match, string, fr.priority);
+    match_format(&fr.match, string, fr.priority, 0);
 
     ds_put_format(string, " reason=%s",
                   ofp_flow_removed_reason_to_string(fr.reason, reasonbuf,
@@ -1502,7 +1502,7 @@ ofp_print_flow_stats_request(struct ds *string, const struct ofp_header *oh)
     }
 
     ds_put_char(string, ' ');
-    match_format(&fsr.match, string, OFP_DEFAULT_PRIORITY);
+    match_format(&fsr.match, string, OFP_DEFAULT_PRIORITY, 0);
 }
 
 void
@@ -1516,7 +1516,7 @@ ofp_print_flow_stats(struct ds *string, struct ofputil_flow_stats *fs,
     ofp_print_duration(string, fs->duration_sec, fs->duration_nsec);
     ds_put_cstr(string, ", ");
 
-    ds_put_color(string, "table=", param_color, color_option);
+    ds_put_color(string, "table=", special_color, color_option);
     ds_put_format(string, "%"PRIu8", ", fs->table_id);
 
     ds_put_color(string, "n_packets=", param_color, color_option);
@@ -1549,13 +1549,13 @@ ofp_print_flow_stats(struct ds *string, struct ofputil_flow_stats *fs,
         ds_put_format(string, "%d, ", fs->hard_age);
     }
 
-    match_format(&fs->match, string, fs->priority);
+    match_format(&fs->match, string, fs->priority, color_option);
     if (string->string[string->length - 1] != ' ') {
         ds_put_char(string, ' ');
     }
 
     ds_put_color(string, "actions=", actions_color, color_option);
-    ofpacts_format(fs->ofpacts, fs->ofpacts_len, string);
+    ofpacts_format(fs->ofpacts, fs->ofpacts_len, string, color_option);
 }
 
 static void
@@ -2190,7 +2190,7 @@ ofp_print_nxst_flow_monitor_request(struct ds *string,
         }
 
         ds_put_char(string, ' ');
-        match_format(&request.match, string, OFP_DEFAULT_PRIORITY);
+        match_format(&request.match, string, OFP_DEFAULT_PRIORITY, 0);
         ds_chomp(string, ' ');
     }
 }
@@ -2255,14 +2255,14 @@ ofp_print_nxst_flow_monitor_reply(struct ds *string,
         ds_put_format(string, " cookie=%#"PRIx64, ntohll(update.cookie));
 
         ds_put_char(string, ' ');
-        match_format(update.match, string, OFP_DEFAULT_PRIORITY);
+        match_format(update.match, string, OFP_DEFAULT_PRIORITY, 0);
 
         if (update.ofpacts_len) {
             if (string->string[string->length - 1] != ' ') {
                 ds_put_char(string, ' ');
             }
             ds_put_cstr(string, "actions=");
-            ofpacts_format(update.ofpacts, update.ofpacts_len, string);
+            ofpacts_format(update.ofpacts, update.ofpacts_len, string, 0);
         }
     }
 }
@@ -2387,7 +2387,7 @@ ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type,
         }
 
         ds_put_cstr(s, "actions=");
-        ofpacts_format(bucket->ofpacts, bucket->ofpacts_len, s);
+        ofpacts_format(bucket->ofpacts, bucket->ofpacts_len, s, 0);
         ds_put_char(s, ',');
     }
 
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 1edc1b0e8762..0325ef423c1f 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -584,7 +584,7 @@ xlate_report_actions(struct xlate_ctx *ctx, const char *title,
 {
     if (OVS_UNLIKELY(ctx->xin->report_hook)) {
         struct ds s = DS_EMPTY_INITIALIZER;
-        ofpacts_format(ofpacts, ofpacts_len, &s);
+        ofpacts_format(ofpacts, ofpacts_len, &s, 0);
         xlate_report(ctx, "%s: %s", title, ds_cstr(&s));
         ds_destroy(&s);
     }
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 89e06aa9cf8f..cd82acf46293 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -4656,7 +4656,7 @@ trace_format_rule(struct ds *result, int level, const struct rule_dpif *rule)
 
     ds_put_char_multiple(result, '\t', level);
     ds_put_cstr(result, "OpenFlow actions=");
-    ofpacts_format(actions->ofpacts, actions->ofpacts_len, result);
+    ofpacts_format(actions->ofpacts, actions->ofpacts_len, result, 0);
     ds_put_char(result, '\n');
 }
 
@@ -4712,7 +4712,7 @@ trace_format_megaflow(struct ds *result, int level, const char *title,
     ds_put_char_multiple(result, '\t', level);
     ds_put_format(result, "%s: ", title);
     match_init(&match, trace->key, &trace->wc);
-    match_format(&match, result, OFP_DEFAULT_PRIORITY);
+    match_format(&match, result, OFP_DEFAULT_PRIORITY, 0);
     ds_put_char(result, '\n');
 }
 
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 3faf42ac8db1..b6e47cd9951f 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -4212,7 +4212,7 @@ flow_stats_ds(struct rule *rule, struct ds *results)
     ds_put_char(results, ',');
 
     ds_put_cstr(results, "actions=");
-    ofpacts_format(actions->ofpacts, actions->ofpacts_len, results);
+    ofpacts_format(actions->ofpacts, actions->ofpacts_len, results, 0);
 
     ds_put_cstr(results, "\n");
 }
diff --git a/ovn/controller/ofctrl.c b/ovn/controller/ofctrl.c
index e16d84a53d8e..70c7487507f2 100644
--- a/ovn/controller/ofctrl.c
+++ b/ovn/controller/ofctrl.c
@@ -534,9 +534,9 @@ ovn_flow_to_string(const struct ovn_flow *f)
     struct ds s = DS_EMPTY_INITIALIZER;
     ds_put_format(&s, "table_id=%"PRIu8", ", f->table_id);
     ds_put_format(&s, "priority=%"PRIu16", ", f->priority);
-    match_format(&f->match, &s, OFP_DEFAULT_PRIORITY);
+    match_format(&f->match, &s, OFP_DEFAULT_PRIORITY, 0);
     ds_put_cstr(&s, ", actions=");
-    ofpacts_format(f->ofpacts, f->ofpacts_len, &s);
+    ofpacts_format(f->ofpacts, f->ofpacts_len, &s, 0);
     return ds_steal_cstr(&s);
 }
 
diff --git a/tests/test-ovn.c b/tests/test-ovn.c
index 0a5136968d78..72e45946273e 100644
--- a/tests/test-ovn.c
+++ b/tests/test-ovn.c
@@ -1243,7 +1243,7 @@ test_parse_actions(struct ovs_cmdl_context *ctx OVS_UNUSED)
 
             ds_init(&output);
             ds_put_cstr(&output, "actions=");
-            ofpacts_format(ofpacts.data, ofpacts.size, &output);
+            ofpacts_format(ofpacts.data, ofpacts.size, &output, 0);
             ds_put_cstr(&output, ", prereqs=");
             if (prereqs) {
                 expr_format(prereqs, &output);
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index acc1cd39a770..39d79005257e 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -2744,7 +2744,7 @@ fte_version_format(const struct fte *fte, int index, struct ds *s)
     }
 
     ds_put_cstr(s, " actions=");
-    ofpacts_format(version->ofpacts, version->ofpacts_len, s);
+    ofpacts_format(version->ofpacts, version->ofpacts_len, s, 0);
 
     ds_put_char(s, '\n');
 }
@@ -3482,7 +3482,7 @@ ofctl_parse_actions__(const char *version_s, bool instructions)
         /* Print cls_rule. */
         ds_init(&s);
         ds_put_cstr(&s, "actions=");
-        ofpacts_format(ofpacts.data, ofpacts.size, &s);
+        ofpacts_format(ofpacts.data, ofpacts.size, &s, 0);
         puts(ds_cstr(&s));
         ds_destroy(&s);
 
-- 
1.9.1




More information about the dev mailing list