Add color output for flow actions for ovs-ofctl dump-flows command
utility, by calling ds_put_color() instead of ds_put_format() in the
functions responsible for printing the actions.

This also causes the option to be propagated upward to the other callers
of those functions (partially implemented, to be completed if colors are
to be provided for other commands / tools).

Signed-off-by: Quentin Monnet <quentin.mon...@6wind.com>
---
 lib/bundle.c                 |  19 +-
 lib/bundle.h                 |   3 +-
 lib/learn.c                  |  59 ++++--
 lib/learn.h                  |   3 +-
 lib/multipath.c              |   9 +-
 lib/multipath.h              |   3 +-
 lib/nx-match.c               |  18 +-
 lib/nx-match.h               |   9 +-
 lib/ofp-actions.c            | 428 ++++++++++++++++++++++++++++---------------
 lib/ofp-actions.h            |   3 +-
 lib/ofp-print.c              |  10 +-
 ofproto/ofproto-dpif-xlate.c |   2 +-
 ofproto/ofproto-dpif.c       |   2 +-
 ofproto/ofproto.c            |   2 +-
 ovn/controller/ofctrl.c      |   2 +-
 tests/test-ovn.c             |   2 +-
 utilities/ovs-ofctl.c        |   4 +-
 17 files changed, 381 insertions(+), 197 deletions(-)

diff --git a/lib/bundle.c b/lib/bundle.c
index 871a724e8a67..bfe6c861c9c2 100644
--- a/lib/bundle.c
+++ b/lib/bundle.c
@@ -20,6 +20,7 @@
 #include <arpa/inet.h>
 #include <inttypes.h>
 
+#include "colors.h"
 #include "dynamic-string.h"
 #include "multipath.h"
 #include "meta-flow.h"
@@ -279,7 +280,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 +301,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/learn.c b/lib/learn.c
index 66201d5016f0..e88930f06ef4 100644
--- a/lib/learn.c
+++ b/lib/learn.c
@@ -19,6 +19,7 @@
 #include "learn.h"
 
 #include "byte-order.h"
+#include "colors.h"
 #include "dynamic-string.h"
 #include "match.h"
 #include "meta-flow.h"
@@ -408,37 +409,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 +473,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/multipath.c b/lib/multipath.c
index 0a58c062c768..5a12984e8fdc 100644
--- a/lib/multipath.c
+++ b/lib/multipath.c
@@ -21,6 +21,7 @@
 #include <inttypes.h>
 #include <sys/types.h>
 #include <netinet/in.h>
+#include "colors.h"
 #include "dynamic-string.h"
 #include "nx-match.h"
 #include "ofp-actions.h"
@@ -223,7 +224,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 +248,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_color(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..b09f2b9ed642 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -21,6 +21,7 @@
 #include <netinet/icmp6.h>
 
 #include "classifier.h"
+#include "colors.h"
 #include "dynamic-string.h"
 #include "hmap.h"
 #include "meta-flow.h"
@@ -1600,11 +1601,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 +1692,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/ofp-actions.c b/lib/ofp-actions.c
index 9b7552635cbc..67869fc875fd 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -20,6 +20,7 @@
 #include "ofp-actions.h"
 #include "bundle.h"
 #include "byte-order.h"
+#include "colors.h"
 #include "compiler.h"
 #include "dummy.h"
 #include "dynamic-string.h"
@@ -554,10 +555,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 +599,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 +716,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 +816,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 +962,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 +1176,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 +1266,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 +1359,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 +1412,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 +1472,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 +1557,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 +1637,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 +1699,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 +1755,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 +1801,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 +1886,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 +2205,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 +2787,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 +2796,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 +2932,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 +3092,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 +3148,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 +3193,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 +3239,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 +3272,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 +3318,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 +3358,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 +3426,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 +3463,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 +3495,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 +3585,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 +3748,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 +3763,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 +4217,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 +4272,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 +4428,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 +4517,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 +4555,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 +4580,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 +4692,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 +4749,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 +5066,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 +5294,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 +5340,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 +5488,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 +5516,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 +5572,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 +5659,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 +5703,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 +7345,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 +7363,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 5f638193dda0..64ee0032a4f8 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -172,7 +172,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);
@@ -827,7 +827,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);
 }
 
@@ -1556,7 +1556,7 @@ ofp_print_flow_stats(struct ds *string, struct 
ofputil_flow_stats *fs,
     }
 
     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
@@ -2263,7 +2263,7 @@ ofp_print_nxst_flow_monitor_reply(struct ds *string,
                 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);
         }
     }
 }
@@ -2388,7 +2388,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 a6ea0679d8f1..bc68dad1965d 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 eb540c38faca..a3b3709bbf36 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');
 }
 
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index e1efedbbe5d3..adbe66d3e31c 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -4209,7 +4209,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 02018be47c03..70c7487507f2 100644
--- a/ovn/controller/ofctrl.c
+++ b/ovn/controller/ofctrl.c
@@ -536,7 +536,7 @@ ovn_flow_to_string(const struct ovn_flow *f)
     ds_put_format(&s, "priority=%"PRIu16", ", f->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 ae2787c3894b..7227b42db519 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 4f822ee54037..5d851fec2f58 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -2748,7 +2748,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');
 }
@@ -3486,7 +3486,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

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to