Add an option to ovs-ofctl utility so as to obtain colorized output in
tty, for easier reading. Currently, only the dump-flows command supports
colors.

A new `--color` option has been added to ovs-ofctl so as to indicate
whether color markers should be used or not. It can be set to `always`
(force colors), `never` (no colors) or `auto` (use colors only if output
is a tty). If provided without any value, it is the same as `auto`. If
the option is not provided at all, colors are disabled by default.

Examples:
This first call will output colorized flows:

    ovs-ofctl dump-flows br0 --color=always

These two calls will produce colorized output on a tty, but they will
not use color markers if the output is redirected to a file or piped
into another command:

    ovs-ofctl dump-flows br0 --color=auto
    ovs-ofctl dump-flows br0 --color

These two calls will not use color markers:

    ovs-ofctl dump-flows br0 --color=never
    ovs-ofctl dump-flows br0

The result of this option is stored into a variable which is forwarded
as a function argument until it reaches the functions that print the
elements of the flows.
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).

Shell color markers are hardcoded; a possible enhancement could consist
in parsing colors from a rc file or from a OVS_COLORS environment
variable.

This commit adds colors to the “left part” of printed flows (to flow
properties that are always present: `cookie`, `table`, timeouts, etc.).

Signed-off-by: Quentin Monnet <quentin.mon...@6wind.com>
---
 lib/dynamic-string.c          | 32 +++++++++++++++
 lib/dynamic-string.h          | 17 ++++++++
 lib/learning-switch.c         |  2 +-
 lib/ofp-print.c               | 73 +++++++++++++++++++++------------
 lib/ofp-print.h               |  8 ++--
 lib/vconn.c                   |  6 +--
 ovn/controller/ofctrl.c       |  8 ++--
 ovn/controller/pinctrl.c      |  2 +-
 third-party/ofp-tcpdump.patch |  2 +-
 utilities/ovs-ofctl.c         | 93 ++++++++++++++++++++++++++++++++-----------
 10 files changed, 180 insertions(+), 63 deletions(-)

diff --git a/lib/dynamic-string.c b/lib/dynamic-string.c
index a6c8f6c763e1..93f0f92987db 100644
--- a/lib/dynamic-string.c
+++ b/lib/dynamic-string.c
@@ -453,3 +453,35 @@ ds_chomp(struct ds *ds, int c)
         ds->string[--ds->length] = '\0';
     }
 }
+
+/* Colors: start a colorized text attribute on stdout using the SGR_START
+ * format; the attribute is specified by SGR_SEQ. */
+void
+ds_put_color_start(struct ds* string, char const *sgr_seq,
+                   int const color_option)
+{
+  if (!color_option || !sgr_seq) {
+    return;
+  }
+  ds_put_format(string, sgr_start, sgr_seq);
+}
+
+/* Restore the normal text attribute using the SGR_END string. */
+void
+ds_put_color_end(struct ds* string, int const color_option)
+{
+  if (!color_option) {
+    return;
+  }
+  ds_put_format(string, "%s", sgr_end);
+}
+
+/* Wrapper: enclose string s between SGR_SEQ and SGR_END. */
+void
+ds_put_color(struct ds* string, char const *s, char const *sgr_seq,
+             int const color_option)
+{
+        ds_put_color_start(string, sgr_seq, color_option);
+        ds_put_cstr(string, s);
+        ds_put_color_end(string, color_option);
+}
diff --git a/lib/dynamic-string.h b/lib/dynamic-string.h
index f1e0a368af32..9940b440b037 100644
--- a/lib/dynamic-string.h
+++ b/lib/dynamic-string.h
@@ -74,6 +74,12 @@ void ds_swap(struct ds *, struct ds *);
 
 int ds_last(const struct ds *);
 void ds_chomp(struct ds *, int c);
+void ds_put_color_start(struct ds* string, char const *sgr_seq,
+                        int const color_option);
+void ds_put_color_end(struct ds* string,
+                      int const color_option);
+void ds_put_color(struct ds* string, char const *s, char const *sgr_seq,
+                  int const color_option);
 
 /* Inline functions. */
 
@@ -90,4 +96,15 @@ 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 */
+
+/* Select Graphic Rendition (SGR, "\33[...m") strings.
+ * Also Erase in Line (EL) to Right ("\33[K"). */
+static const char *sgr_start = "\33[%sm\33[K";
+static const char *sgr_end   = "\33[m\33[K";
+
 #endif /* dynamic-string.h */
diff --git a/lib/learning-switch.c b/lib/learning-switch.c
index 002b8181bcc5..961c9e66a25e 100644
--- a/lib/learning-switch.c
+++ b/lib/learning-switch.c
@@ -369,7 +369,7 @@ lswitch_process_packet(struct lswitch *sw, const struct 
ofpbuf *msg)
     } else if (type == OFPTYPE_FLOW_REMOVED) {
         /* Nothing to do. */
     } else if (VLOG_IS_DBG_ENABLED()) {
-        char *s = ofp_to_string(msg->data, msg->size, 2);
+        char *s = ofp_to_string(msg->data, msg->size, 2, 0);
         VLOG_DBG_RL(&rl, "%016llx: OpenFlow packet ignored: %s",
                     sw->datapath_id, s);
         free(s);
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 5af4bf0b4e21..3b495c2749df 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -1412,7 +1412,8 @@ ofp_print_hello(struct ds *string, const struct 
ofp_header *oh)
 }
 
 static void
-ofp_print_error_msg(struct ds *string, const struct ofp_header *oh)
+ofp_print_error_msg(struct ds *string, const struct ofp_header *oh,
+                    int const color_option)
 {
     size_t len = ntohs(oh->length);
     struct ofpbuf payload;
@@ -1431,7 +1432,7 @@ ofp_print_error_msg(struct ds *string, const struct 
ofp_header *oh)
     if (error == OFPERR_OFPHFC_INCOMPATIBLE || error == OFPERR_OFPHFC_EPERM) {
         ds_put_printable(string, payload.data, payload.size);
     } else {
-        s = ofp_to_string(payload.data, payload.size, 1);
+        s = ofp_to_string(payload.data, payload.size, 1, color_option);
         ds_put_cstr(string, s);
         free(s);
     }
@@ -1505,32 +1506,47 @@ ofp_print_flow_stats_request(struct ds *string, const 
struct ofp_header *oh)
 }
 
 void
-ofp_print_flow_stats(struct ds *string, struct ofputil_flow_stats *fs)
+ofp_print_flow_stats(struct ds *string, struct ofputil_flow_stats *fs,
+                     int const color_option)
 {
-    ds_put_format(string, " cookie=0x%"PRIx64", duration=",
-                  ntohll(fs->cookie));
+    ds_put_color(string, " cookie=", param_color, color_option);
+    ds_put_format(string, "0x%"PRIx64", ", ntohll(fs->cookie));
 
+    ds_put_color(string,  "duration=", param_color, color_option);
     ofp_print_duration(string, fs->duration_sec, fs->duration_nsec);
-    ds_put_format(string, ", table=%"PRIu8", ", fs->table_id);
-    ds_put_format(string, "n_packets=%"PRIu64", ", fs->packet_count);
-    ds_put_format(string, "n_bytes=%"PRIu64", ", fs->byte_count);
+    ds_put_cstr(string, ", ");
+
+    ds_put_color(string, "table=", param_color, color_option);
+    ds_put_format(string, "%"PRIu8", ", fs->table_id);
+
+    ds_put_color(string, "n_packets=", param_color, color_option);
+    ds_put_format(string, "%"PRIu64", ", fs->packet_count);
+
+    ds_put_color(string, "n_bytes=", param_color, color_option);
+    ds_put_format(string, "%"PRIu64", ", fs->byte_count);
+
     if (fs->idle_timeout != OFP_FLOW_PERMANENT) {
-        ds_put_format(string, "idle_timeout=%"PRIu16", ", fs->idle_timeout);
+        ds_put_color(string, "idle_timeout=", param_color, color_option);
+        ds_put_format(string, "%"PRIu16", ", fs->idle_timeout);
     }
     if (fs->hard_timeout != OFP_FLOW_PERMANENT) {
-        ds_put_format(string, "hard_timeout=%"PRIu16", ", fs->hard_timeout);
+        ds_put_color(string, "hard_timeout=", param_color, color_option);
+        ds_put_format(string, "%"PRIu16", ", fs->hard_timeout);
     }
     if (fs->flags) {
         ofp_print_flow_flags(string, fs->flags);
     }
     if (fs->importance != 0) {
-        ds_put_format(string, "importance=%"PRIu16", ", fs->importance);
+        ds_put_color(string, "importance=", param_color, color_option);
+        ds_put_format(string, "%"PRIu16", ", fs->importance);
     }
     if (fs->idle_age >= 0) {
-        ds_put_format(string, "idle_age=%d, ", fs->idle_age);
+        ds_put_color(string, "idle_age=", param_color, color_option);
+        ds_put_format(string, "%d, ", fs->idle_age);
     }
     if (fs->hard_age >= 0 && fs->hard_age != fs->duration_sec) {
-        ds_put_format(string, "hard_age=%d, ", fs->hard_age);
+        ds_put_color(string, "hard_age=", param_color, color_option);
+        ds_put_format(string, "%d, ", fs->hard_age);
     }
 
     match_format(&fs->match, string, fs->priority);
@@ -1538,12 +1554,13 @@ ofp_print_flow_stats(struct ds *string, struct 
ofputil_flow_stats *fs)
         ds_put_char(string, ' ');
     }
 
-    ds_put_cstr(string, "actions=");
+    ds_put_color(string, "actions=", actions_color, color_option);
     ofpacts_format(fs->ofpacts, fs->ofpacts_len, string);
 }
 
 static void
-ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh)
+ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh,
+                           int const color_option)
 {
     struct ofpbuf ofpacts;
     struct ofpbuf b;
@@ -1562,7 +1579,7 @@ ofp_print_flow_stats_reply(struct ds *string, const 
struct ofp_header *oh)
             break;
         }
         ds_put_char(string, '\n');
-        ofp_print_flow_stats(string, &fs);
+        ofp_print_flow_stats(string, &fs, color_option);
      }
     ofpbuf_uninit(&ofpacts);
 }
@@ -2937,7 +2954,8 @@ ofp_print_bundle_ctrl(struct ds *s, const struct 
ofp_header *oh)
 }
 
 static void
-ofp_print_bundle_add(struct ds *s, const struct ofp_header *oh, int verbosity)
+ofp_print_bundle_add(struct ds *s, const struct ofp_header *oh,
+                     int verbosity, int const color_option)
 {
     int error;
     struct ofputil_bundle_add_msg badd;
@@ -2954,7 +2972,8 @@ ofp_print_bundle_add(struct ds *s, const struct 
ofp_header *oh, int verbosity)
     ofp_print_bit_names(s, badd.flags, bundle_flags_to_name, ' ');
 
     ds_put_char(s, '\n');
-    char *msg = ofp_to_string(badd.msg, ntohs(badd.msg->length), verbosity);
+    char *msg = ofp_to_string(badd.msg, ntohs(badd.msg->length), verbosity,
+                              color_option);
     ds_put_and_free_cstr(s, msg);
 }
 
@@ -3072,7 +3091,7 @@ ofp_print_requestforward(struct ds *string, const struct 
ofp_header *oh)
 
 static void
 ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
-                struct ds *string, int verbosity)
+                struct ds *string, int verbosity, int const color_option)
 {
     const void *msg = oh;
 
@@ -3125,7 +3144,7 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw 
raw,
         break;
 
     case OFPTYPE_ERROR:
-        ofp_print_error_msg(string, oh);
+        ofp_print_error_msg(string, oh, color_option);
         break;
 
     case OFPTYPE_ECHO_REQUEST:
@@ -3260,7 +3279,7 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw 
raw,
 
     case OFPTYPE_FLOW_STATS_REPLY:
         ofp_print_stats(string, oh);
-        ofp_print_flow_stats_reply(string, oh);
+        ofp_print_flow_stats_reply(string, oh, color_option);
         break;
 
     case OFPTYPE_QUEUE_STATS_REPLY:
@@ -3339,7 +3358,7 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw 
raw,
         break;
 
     case OFPTYPE_BUNDLE_ADD_MESSAGE:
-        ofp_print_bundle_add(string, msg, verbosity);
+        ofp_print_bundle_add(string, msg, verbosity, color_option);
         break;
 
     case OFPTYPE_NXT_TLV_TABLE_MOD:
@@ -3361,7 +3380,8 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw 
raw,
  * verbosity and higher numbers increase verbosity.  The caller is responsible
  * for freeing the string. */
 char *
-ofp_to_string(const void *oh_, size_t len, int verbosity)
+ofp_to_string(const void *oh_, size_t len,
+              int verbosity, int const color_option)
 {
     struct ds string = DS_EMPTY_INITIALIZER;
     const struct ofp_header *oh = oh_;
@@ -3394,7 +3414,7 @@ ofp_to_string(const void *oh_, size_t len, int verbosity)
 
         error = ofpraw_decode(&raw, oh);
         if (!error) {
-            ofp_to_string__(oh, raw, &string, verbosity);
+            ofp_to_string__(oh, raw, &string, verbosity, color_option);
             if (verbosity >= 5) {
                 if (ds_last(&string) != '\n') {
                     ds_put_char(&string, '\n');
@@ -3424,9 +3444,10 @@ print_and_free(FILE *stream, char *string)
  * given 'verbosity' level.  0 is a minimal amount of verbosity and higher
  * numbers increase verbosity. */
 void
-ofp_print(FILE *stream, const void *oh, size_t len, int verbosity)
+ofp_print(FILE *stream, const void *oh, size_t len,
+          int verbosity, int const color_option)
 {
-    print_and_free(stream, ofp_to_string(oh, len, verbosity));
+    print_and_free(stream, ofp_to_string(oh, len, verbosity, color_option));
 }
 
 /* Dumps the contents of the Ethernet frame in the 'len' bytes starting at
diff --git a/lib/ofp-print.h b/lib/ofp-print.h
index bbac18bd98c5..af91565e6ccd 100644
--- a/lib/ofp-print.h
+++ b/lib/ofp-print.h
@@ -34,16 +34,18 @@ struct ofputil_table_stats;
 extern "C" {
 #endif
 
-void ofp_print(FILE *, const void *, size_t, int verbosity);
+void ofp_print(FILE *, const void *, size_t, int verbosity,
+               int const color_option);
 void ofp_print_packet(FILE *stream, const void *data, size_t len);
 
 void ofp10_match_print(struct ds *, const struct ofp10_match *, int verbosity);
 
-char *ofp_to_string(const void *, size_t, int verbosity);
+char *ofp_to_string(const void *, size_t, int verbosity,
+                    int const color_option);
 char *ofp10_match_to_string(const struct ofp10_match *, int verbosity);
 char *ofp_packet_to_string(const void *data, size_t len);
 
-void ofp_print_flow_stats(struct ds *, struct ofputil_flow_stats *);
+void ofp_print_flow_stats(struct ds *, struct ofputil_flow_stats *, int color);
 void ofp_print_version(const struct ofp_header *, struct ds *);
 void ofp_print_table_features(
     struct ds *, const struct ofputil_table_features *features,
diff --git a/lib/vconn.c b/lib/vconn.c
index d835943324e9..d21f5ae2bea4 100644
--- a/lib/vconn.c
+++ b/lib/vconn.c
@@ -495,7 +495,7 @@ vcs_recv_hello(struct vconn *vconn)
             ofpbuf_delete(b);
             return;
         } else {
-            char *s = ofp_to_string(b->data, b->size, 1);
+            char *s = ofp_to_string(b->data, b->size, 1, 0);
             VLOG_WARN_RL(&bad_ofmsg_rl,
                          "%s: received message while expecting hello: %s",
                          vconn->name, s);
@@ -641,7 +641,7 @@ do_recv(struct vconn *vconn, struct ofpbuf **msgp)
     if (!retval) {
         COVERAGE_INC(vconn_received);
         if (VLOG_IS_DBG_ENABLED()) {
-            char *s = ofp_to_string((*msgp)->data, (*msgp)->size, 1);
+            char *s = ofp_to_string((*msgp)->data, (*msgp)->size, 1, 0);
             VLOG_DBG_RL(&ofmsg_rl, "%s: received: %s", vconn->name, s);
             free(s);
         }
@@ -681,7 +681,7 @@ do_send(struct vconn *vconn, struct ofpbuf *msg)
         COVERAGE_INC(vconn_sent);
         retval = (vconn->vclass->send)(vconn, msg);
     } else {
-        char *s = ofp_to_string(msg->data, msg->size, 1);
+        char *s = ofp_to_string(msg->data, msg->size, 1, 0);
         retval = (vconn->vclass->send)(vconn, msg);
         if (retval != EAGAIN) {
             VLOG_DBG_RL(&ofmsg_rl, "%s: sent (%s): %s",
diff --git a/ovn/controller/ofctrl.c b/ovn/controller/ofctrl.c
index 3297fb397cce..e16d84a53d8e 100644
--- a/ovn/controller/ofctrl.c
+++ b/ovn/controller/ofctrl.c
@@ -223,7 +223,7 @@ recv_S_TLV_TABLE_REQUESTED(const struct ofp_header *oh, 
enum ofptype type)
                  ofperr_to_string(ofperr_decode_msg(oh, NULL)));
         goto error;
     } else {
-        char *s = ofp_to_string(oh, ntohs(oh->length), 1);
+        char *s = ofp_to_string(oh, ntohs(oh->length), 1, 0);
         VLOG_ERR("unexpected reply to TLV table request (%s)",
                  s);
         free(s);
@@ -279,7 +279,7 @@ recv_S_TLV_TABLE_MOD_SENT(const struct ofp_header *oh, enum 
ofptype type)
             goto error;
         }
     } else {
-        char *s = ofp_to_string(oh, ntohs(oh->length), 1);
+        char *s = ofp_to_string(oh, ntohs(oh->length), 1, 0);
         VLOG_ERR("unexpected reply to Geneve option allocation request (%s)",
                  s);
         free(s);
@@ -404,7 +404,7 @@ ofctrl_run(const struct ovsrec_bridge *br_int)
                 OVS_NOT_REACHED();
             }
         } else {
-            char *s = ofp_to_string(oh, ntohs(oh->length), 1);
+            char *s = ofp_to_string(oh, ntohs(oh->length), 1, 0);
             VLOG_WARN("could not decode OpenFlow message (%s): %s",
                       ofperr_to_string(error), s);
             free(s);
@@ -454,7 +454,7 @@ ofctrl_recv(const struct ofp_header *oh, enum ofptype type)
         if (VLOG_IS_DBG_ENABLED()) {
             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
 
-            char *s = ofp_to_string(oh, ntohs(oh->length), 2);
+            char *s = ofp_to_string(oh, ntohs(oh->length), 2, 0);
             VLOG_DBG_RL(&rl, "OpenFlow packet ignored: %s", s);
             free(s);
         }
diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c
index 360f38b666de..c679e34d9520 100644
--- a/ovn/controller/pinctrl.c
+++ b/ovn/controller/pinctrl.c
@@ -112,7 +112,7 @@ pinctrl_recv(struct controller_ctx *ctx, const struct 
ofp_header *oh,
         if (VLOG_IS_DBG_ENABLED()) {
             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
 
-            char *s = ofp_to_string(oh, ntohs(oh->length), 2);
+            char *s = ofp_to_string(oh, ntohs(oh->length), 2, 0);
 
             VLOG_DBG_RL(&rl, "OpenFlow packet ignored: %s", s);
             free(s);
diff --git a/third-party/ofp-tcpdump.patch b/third-party/ofp-tcpdump.patch
index 72d33b8777f3..37512ecaabee 100644
--- a/third-party/ofp-tcpdump.patch
+++ b/third-party/ofp-tcpdump.patch
@@ -103,7 +103,7 @@
 +    if (!TTEST2(*sp, ntohs(ofp->length)))
 +            goto trunc;
 +
-+    ofp_print(stdout, sp, length, vflag);
++    ofp_print(stdout, sp, length, vflag, 0);
 +    return;
 +
 +trunc:
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 96d6c89d92bf..acc1cd39a770 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -73,6 +73,9 @@ VLOG_DEFINE_THIS_MODULE(ofctl);
  */
 static bool bundle = false;
 
+/* --color: Use color markers. */
+static int color_option;
+
 /* --strict: Use strict matching for flow mod commands?  Additionally governs
  * use of nx_pull_match() instead of nx_pull_match_loose() in parse-nx-match.
  */
@@ -168,6 +171,7 @@ parse_options(int argc, char *argv[])
         OPT_RSORT,
         OPT_UNIXCTL,
         OPT_BUNDLE,
+        OPT_COLOR,
         DAEMON_OPTION_ENUMS,
         OFP_VERSION_OPTION_ENUMS,
         VLOG_OPTION_ENUMS
@@ -186,6 +190,7 @@ parse_options(int argc, char *argv[])
         {"help", no_argument, NULL, 'h'},
         {"option", no_argument, NULL, 'o'},
         {"bundle", no_argument, NULL, OPT_BUNDLE},
+        {"color", optional_argument, NULL, OPT_COLOR},
         DAEMON_LONG_OPTIONS,
         OFP_VERSION_LONG_OPTIONS,
         VLOG_LONG_OPTIONS,
@@ -287,6 +292,31 @@ parse_options(int argc, char *argv[])
             unixctl_path = optarg;
             break;
 
+        case OPT_COLOR:
+            if (optarg) {
+                if (!strcasecmp (optarg, "always")
+                    || !strcasecmp (optarg, "yes")
+                    || !strcasecmp (optarg, "force")) {
+                    color_option = 1;
+                }
+                else if (!strcasecmp (optarg, "never")
+                         || !strcasecmp (optarg, "no")
+                         || !strcasecmp (optarg, "none")) {
+                    color_option = 0;
+                }
+                else if (!strcasecmp (optarg, "auto")
+                         || !strcasecmp (optarg, "tty")
+                         || !strcasecmp (optarg, "if-tty")) {
+                    color_option = 2;
+                }
+                else {
+                    usage();
+                }
+            }
+            else
+                color_option = 2;
+        break;
+
         DAEMON_OPTION_HANDLERS
         OFP_VERSION_OPTION_HANDLERS
         VLOG_OPTION_HANDLERS
@@ -331,6 +361,13 @@ parse_options(int argc, char *argv[])
     allowed_protocols &= version_protocols;
     mask_allowed_ofp_versions(ofputil_protocols_to_version_bitmap(
                                   allowed_protocols));
+
+    /* If --color is set to 'auto', determine whether we need colors, i.e.
+     * whether standard output is a tty. */
+    char const *t = getenv("TERM");
+    if (color_option == 2) {
+      color_option = isatty(STDOUT_FILENO) && t && strcmp(t, "dumb") != 0;
+    }
 }
 
 static void
@@ -414,6 +451,7 @@ usage(void)
            "  --sort[=field]              sort in ascending order\n"
            "  --rsort[=field]             sort in descending order\n"
            "  --unixctl=SOCKET            set control socket name\n"
+           "  --color[=always|never|auto] use colors markers\n"
            "  -h, --help                  display this help message\n"
            "  -V, --version               display version information\n");
     exit(EXIT_SUCCESS);
@@ -553,7 +591,8 @@ dump_transaction(struct vconn *vconn, struct ofpbuf 
*request)
             if (send_xid == recv_xid) {
                 enum ofpraw raw;
 
-                ofp_print(stdout, reply->data, reply->size, verbosity + 1);
+                ofp_print(stdout, reply->data, reply->size, verbosity + 1,
+                          color_option);
 
                 ofpraw_decode(&raw, reply->data);
                 if (ofptype_from_ofpraw(raw) == OFPTYPE_ERROR) {
@@ -563,7 +602,7 @@ dump_transaction(struct vconn *vconn, struct ofpbuf 
*request)
                 } else {
                     ovs_fatal(0, "received bad reply: %s",
                               ofp_to_string(reply->data, reply->size,
-                                            verbosity + 1));
+                                            verbosity + 1, color_option));
                 }
             } else {
                 VLOG_DBG("received reply with xid %08"PRIx32" "
@@ -576,7 +615,8 @@ dump_transaction(struct vconn *vconn, struct ofpbuf 
*request)
 
         run(vconn_transact(vconn, request, &reply), "talking to %s",
             vconn_get_name(vconn));
-        ofp_print(stdout, reply->data, reply->size, verbosity + 1);
+        ofp_print(stdout, reply->data, reply->size, verbosity + 1,
+                  color_option);
         ofpbuf_delete(reply);
     }
 }
@@ -606,7 +646,8 @@ transact_multiple_noreply(struct vconn *vconn, struct 
ovs_list *requests)
     run(vconn_transact_multiple_noreply(vconn, requests, &reply),
         "talking to %s", vconn_get_name(vconn));
     if (reply) {
-        ofp_print(stderr, reply->data, reply->size, verbosity + 2);
+        ofp_print(stderr, reply->data, reply->size, verbosity + 2,
+                  color_option);
         exit(1);
     }
     ofpbuf_delete(reply);
@@ -615,7 +656,7 @@ transact_multiple_noreply(struct vconn *vconn, struct 
ovs_list *requests)
 static void
 bundle_error_reporter(const struct ofp_header *oh)
 {
-    ofp_print(stderr, oh, ntohs(oh->length), verbosity + 1);
+    ofp_print(stderr, oh, ntohs(oh->length), verbosity + 1, color_option);
     fflush(stderr);
 }
 
@@ -685,7 +726,7 @@ ofctl_show(struct ovs_cmdl_context *ctx)
     run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
 
     has_ports = ofputil_switch_features_has_ports(reply);
-    ofp_print(stdout, reply->data, reply->size, verbosity + 1);
+    ofp_print(stdout, reply->data, reply->size, verbosity + 1, color_option);
     ofpbuf_delete(reply);
 
     if (!has_ports) {
@@ -746,7 +787,8 @@ ofctl_dump_table_features(struct ovs_cmdl_context *ctx)
             if (error) {
                 ovs_fatal(0, "decode error: %s", ofperr_get_name(error));
             } else if (type == OFPTYPE_ERROR) {
-                ofp_print(stdout, reply->data, reply->size, verbosity + 1);
+                ofp_print(stdout, reply->data, reply->size, verbosity + 1,
+                          color_option);
                 done = true;
             } else if (type == OFPTYPE_TABLE_FEATURES_STATS_REPLY) {
                 done = !ofpmp_more(reply->data);
@@ -775,7 +817,7 @@ ofctl_dump_table_features(struct ovs_cmdl_context *ctx)
             } else {
                 ovs_fatal(0, "received bad reply: %s",
                           ofp_to_string(reply->data, reply->size,
-                                        verbosity + 1));
+                                        verbosity + 1, color_option));
             }
         } else {
             VLOG_DBG("received reply with xid %08"PRIx32" "
@@ -904,7 +946,7 @@ port_iterator_next(struct port_iterator *pi, struct 
ofputil_phy_port *pp)
             } else if (retval != EOF) {
                 ovs_fatal(0, "received bad reply: %s",
                           ofp_to_string(pi->reply->data, pi->reply->size,
-                                        verbosity + 1));
+                                        verbosity + 1, color_option));
             }
         }
 
@@ -926,7 +968,7 @@ port_iterator_next(struct port_iterator *pi, struct 
ofputil_phy_port *pp)
             || type != OFPTYPE_PORT_DESC_STATS_REPLY) {
             ovs_fatal(0, "received bad reply: %s",
                       ofp_to_string(pi->reply->data, pi->reply->size,
-                                    verbosity + 1));
+                                    verbosity + 1, color_option));
         }
 
         pi->more = (ofpmp_flags(oh) & OFPSF_REPLY_MORE) != 0;
@@ -1018,7 +1060,7 @@ try_set_protocol(struct vconn *vconn, enum 
ofputil_protocol want,
         run(vconn_transact_noreply(vconn, request, &reply),
             "talking to %s", vconn_get_name(vconn));
         if (reply) {
-            char *s = ofp_to_string(reply->data, reply->size, 2);
+            char *s = ofp_to_string(reply->data, reply->size, 2, color_option);
             VLOG_DBG("%s: failed to set protocol, switch replied: %s",
                      vconn_get_name(vconn), s);
             free(s);
@@ -1181,7 +1223,7 @@ ofctl_dump_flows(struct ovs_cmdl_context *ctx)
         ds_init(&s);
         for (i = 0; i < n_fses; i++) {
             ds_clear(&s);
-            ofp_print_flow_stats(&s, &fses[i]);
+            ofp_print_flow_stats(&s, &fses[i], color_option);
             puts(ds_cstr(&s));
         }
         ds_destroy(&s);
@@ -1516,7 +1558,7 @@ ofctl_send(struct unixctl_conn *conn, int argc,
         }
 
         fprintf(stderr, "send: ");
-        ofp_print(stderr, msg->data, msg->size, verbosity);
+        ofp_print(stderr, msg->data, msg->size, verbosity, color_option);
 
         error = vconn_send_block(vconn, msg);
         if (error) {
@@ -1666,7 +1708,7 @@ monitor_vconn(struct vconn *vconn, bool 
reply_to_echo_requests)
             }
 
             ofptype_decode(&type, b->data);
-            ofp_print(stderr, b->data, b->size, verbosity + 2);
+            ofp_print(stderr, b->data, b->size, verbosity + 2, color_option);
             fflush(stderr);
 
             switch ((int) type) {
@@ -1783,7 +1825,8 @@ ofctl_monitor(struct ovs_cmdl_context *ctx)
             run(vconn_transact_noreply(vconn, spif, &reply),
                 "talking to %s", vconn_get_name(vconn));
             if (reply) {
-                char *s = ofp_to_string(reply->data, reply->size, 2);
+                char *s = ofp_to_string(reply->data, reply->size, 2,
+                                        color_option);
                 VLOG_DBG("%s: failed to set packet in format to nxm, 
controller"
                         " replied: %s. Falling back to the switch default.",
                         vconn_get_name(vconn), s);
@@ -1996,7 +2039,7 @@ fetch_table_desc(struct vconn *vconn, struct 
ofputil_table_mod *tm,
                 || type != OFPTYPE_TABLE_DESC_REPLY) {
                 ovs_fatal(0, "received bad reply: %s",
                           ofp_to_string(reply->data, reply->size,
-                                        verbosity + 1));
+                                        verbosity + 1, color_option));
             }
             flags = ofpmp_flags(oh);
             done = !(flags & OFPSF_REPLY_MORE);
@@ -2163,7 +2206,7 @@ ofctl_ofp_parse(struct ovs_cmdl_context *ctx)
             ovs_fatal(0, "%s: unexpected end of file mid-message", filename);
         }
 
-        ofp_print(stdout, b.data, b.size, verbosity + 2);
+        ofp_print(stdout, b.data, b.size, verbosity + 2, color_option);
     }
     ofpbuf_uninit(&b);
 
@@ -2250,7 +2293,8 @@ ofctl_ofp_parse_pcap(struct ovs_cmdl_context *ctx)
                     printf(IP_FMT".%"PRIu16" > "IP_FMT".%"PRIu16":\n",
                            IP_ARGS(flow.nw_src), ntohs(flow.tp_src),
                            IP_ARGS(flow.nw_dst), ntohs(flow.tp_dst));
-                    ofp_print(stdout, dp_packet_data(payload), length, 
verbosity + 1);
+                    ofp_print(stdout, dp_packet_data(payload), length,
+                              verbosity + 1, color_option);
                     dp_packet_pull(payload, length);
                 }
             }
@@ -2294,9 +2338,10 @@ ofctl_ping(struct ovs_cmdl_context *ctx)
             || reply->size != payload
             || memcmp(request->msg, reply->msg, payload)) {
             printf("Reply does not match request.  Request:\n");
-            ofp_print(stdout, request, request->size, verbosity + 2);
+            ofp_print(stdout, request, request->size, verbosity + 2,
+                      color_option);
             printf("Reply:\n");
-            ofp_print(stdout, reply, reply->size, verbosity + 2);
+            ofp_print(stdout, reply, reply->size, verbosity + 2, color_option);
         }
         printf("%"PRIu32" bytes from %s: xid=%08"PRIx32" time=%.1f ms\n",
                reply->size, ctx->argv[1], ntohl(rpy_hdr->xid),
@@ -2847,7 +2892,7 @@ recv_flow_stats_reply(struct vconn *vconn, ovs_be32 
send_xid,
             if (error || type != OFPTYPE_FLOW_STATS_REPLY) {
                 ovs_fatal(0, "received bad reply: %s",
                           ofp_to_string(reply->data, reply->size,
-                                        verbosity + 1));
+                                        verbosity + 1, color_option));
             }
         }
 
@@ -3210,7 +3255,7 @@ ofctl_parse_flows__(struct ofputil_flow_mod *fms, size_t 
n_fms,
         struct ofpbuf *msg;
 
         msg = ofputil_encode_flow_mod(fm, protocol);
-        ofp_print(stdout, msg->data, msg->size, verbosity);
+        ofp_print(stdout, msg->data, msg->size, verbosity, color_option);
         ofpbuf_delete(msg);
 
         free(CONST_CAST(struct ofpact *, fm->ofpacts));
@@ -3843,7 +3888,7 @@ ofctl_ofp_print(struct ovs_cmdl_context *ctx)
     if (ofpbuf_put_hex(&packet, buffer, NULL)[0] != '\0') {
         ovs_fatal(0, "trailing garbage following hex bytes");
     }
-    ofp_print(stdout, packet.data, packet.size, verbosity);
+    ofp_print(stdout, packet.data, packet.size, verbosity, color_option);
     ofpbuf_uninit(&packet);
     ds_destroy(&line);
 }
@@ -3858,7 +3903,7 @@ ofctl_encode_hello(struct ovs_cmdl_context *ctx)
 
     hello = ofputil_encode_hello(bitmap);
     ovs_hex_dump(stdout, hello->data, hello->size, 0, false);
-    ofp_print(stdout, hello->data, hello->size, verbosity);
+    ofp_print(stdout, hello->data, hello->size, verbosity, color_option);
     ofpbuf_delete(hello);
 }
 
-- 
1.9.1

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

Reply via email to