diff mbox series

[ovs-dev,v2] dpdk: Add commands to configure log levels.

Message ID 20200713080621.15204-1-david.marchand@redhat.com
State Accepted
Delegated to: Ilya Maximets
Headers show
Series [ovs-dev,v2] dpdk: Add commands to configure log levels. | expand

Commit Message

David Marchand July 13, 2020, 8:06 a.m. UTC
Enabling debug logs in dpdk can be a challenge to be sure of what is
actually enabled, add commands to list and change those log levels.
However, these commands do not help when tracking issues in dpdk init
itself: dump log levels right after init.

Example:
$ ovs-appctl dpdk/log-list
global log level is debug
id 0: lib.eal, level is info
id 1: lib.malloc, level is info
id 2: lib.ring, level is info
id 3: lib.mempool, level is info
id 4: lib.timer, level is info
id 5: pmd, level is info
[...]
id 37: pmd.net.bnxt.driver, level is notice
id 38: pmd.net.e1000.init, level is notice
id 39: pmd.net.e1000.driver, level is notice
id 40: pmd.net.enic, level is info
[...]

$ ovs-appctl dpdk/log-set debug pmd.*:notice
$ ovs-appctl dpdk/log-list
global log level is debug
id 0: lib.eal, level is debug
id 1: lib.malloc, level is debug
id 2: lib.ring, level is debug
id 3: lib.mempool, level is debug
id 4: lib.timer, level is debug
id 5: pmd, level is debug
[...]
id 37: pmd.net.bnxt.driver, level is notice
id 38: pmd.net.e1000.init, level is notice
id 39: pmd.net.e1000.driver, level is notice
id 40: pmd.net.enic, level is notice
[...]

Signed-off-by: David Marchand <david.marchand@redhat.com>
---
Changes since v1:
- added a NEWS entry,
- added a man section for DPDK commands,
- other comments,

---
 NEWS                       |   2 +
 lib/automake.mk            |   1 +
 lib/dpdk-unixctl.man       |  14 +++++
 lib/dpdk.c                 | 110 +++++++++++++++++++++++++++++++++++--
 vswitchd/ovs-vswitchd.8.in |   1 +
 5 files changed, 123 insertions(+), 5 deletions(-)
 create mode 100644 lib/dpdk-unixctl.man

Comments

Ilya Maximets July 17, 2020, 2:02 a.m. UTC | #1
On 7/13/20 10:06 AM, David Marchand wrote:
> Enabling debug logs in dpdk can be a challenge to be sure of what is
> actually enabled, add commands to list and change those log levels.
> However, these commands do not help when tracking issues in dpdk init
> itself: dump log levels right after init.
> 
> Example:
> $ ovs-appctl dpdk/log-list
> global log level is debug
> id 0: lib.eal, level is info
> id 1: lib.malloc, level is info
> id 2: lib.ring, level is info
> id 3: lib.mempool, level is info
> id 4: lib.timer, level is info
> id 5: pmd, level is info
> [...]
> id 37: pmd.net.bnxt.driver, level is notice
> id 38: pmd.net.e1000.init, level is notice
> id 39: pmd.net.e1000.driver, level is notice
> id 40: pmd.net.enic, level is info
> [...]
> 
> $ ovs-appctl dpdk/log-set debug pmd.*:notice
> $ ovs-appctl dpdk/log-list
> global log level is debug
> id 0: lib.eal, level is debug
> id 1: lib.malloc, level is debug
> id 2: lib.ring, level is debug
> id 3: lib.mempool, level is debug
> id 4: lib.timer, level is debug
> id 5: pmd, level is debug
> [...]
> id 37: pmd.net.bnxt.driver, level is notice
> id 38: pmd.net.e1000.init, level is notice
> id 39: pmd.net.e1000.driver, level is notice
> id 40: pmd.net.enic, level is notice
> [...]
> 
> Signed-off-by: David Marchand <david.marchand@redhat.com>
> ---
> Changes since v1:
> - added a NEWS entry,
> - added a man section for DPDK commands,
> - other comments,
> 

Applied.  Thanks!

Best regards, Ilya Maximets.
diff mbox series

Patch

diff --git a/NEWS b/NEWS
index e52e862e1e..243ddeb562 100644
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,8 @@  Post-v2.13.0
      * Add hardware offload support for matching IPv6 protocol (experimental).
      * Add hardware offload support for set of IPv6 src/dst/ttl
        and tunnel push-output actions (experimental).
+     * Add 'ovs-appctl dpdk/log-list' and 'ovs-appctl dpdk/log-set' commands
+       to list and change log levels in DPDK components.
    - Linux datapath:
      * Support for kernel versions up to 5.5.x.
    - AF_XDP:
diff --git a/lib/automake.mk b/lib/automake.mk
index 86940ccd2f..d2dd03d120 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -519,6 +519,7 @@  MAN_FRAGMENTS += \
 	lib/daemon-syn.man \
 	lib/db-ctl-base.man \
 	lib/dpctl.man \
+	lib/dpdk-unixctl.man \
 	lib/memory-unixctl.man \
 	lib/netdev-dpdk-unixctl.man \
 	lib/dpif-netdev-unixctl.man \
diff --git a/lib/dpdk-unixctl.man b/lib/dpdk-unixctl.man
new file mode 100644
index 0000000000..2d6d576f24
--- /dev/null
+++ b/lib/dpdk-unixctl.man
@@ -0,0 +1,14 @@ 
+.SS "DPDK COMMANDS"
+These commands manage DPDK components.
+.IP "\fBdpdk/log-list\fR"
+Lists all DPDK components that emit logs and their logging levels.
+.IP "\fBdpdk/log-set\fR [\fIspec\fR]"
+Sets DPDK components logging level. Without any \fIspec\fR, sets the logging
+\fBlevel\fR for all DPDK components to \fBdebug\fR. Otherwise, \fIspec\fR is a
+list of words separated by spaces: a word can be either a logging \fBlevel\fR
+(\fBemergency\fR, \fBalert\fR, \fBcritical\fR, \fBerror\fR, \fBwarning\fR,
+\fBnotice\fR, \fBinfo\fR or \fBdebug\fR) or a \fBpattern\fR matching DPDK
+components (see \fBdpdk/log-list\fR command on \fBovs\-appctl\fR(8)) separated
+by a colon from the logging \fBlevel\fR to apply.
+.RE
+.
diff --git a/lib/dpdk.c b/lib/dpdk.c
index 31450d4708..c603430d14 100644
--- a/lib/dpdk.c
+++ b/lib/dpdk.c
@@ -36,6 +36,7 @@ 
 #include "ovs-numa.h"
 #include "smap.h"
 #include "svec.h"
+#include "unixctl.h"
 #include "util.h"
 #include "vswitch-idl.h"
 
@@ -261,6 +262,99 @@  static cookie_io_functions_t dpdk_log_func = {
     .write = dpdk_log_write,
 };
 
+static void
+dpdk_unixctl_mem_stream(struct unixctl_conn *conn, int argc OVS_UNUSED,
+                        const char *argv[] OVS_UNUSED, void *aux)
+{
+    void (*callback)(FILE *) = aux;
+    char *response = NULL;
+    FILE *stream;
+    size_t size;
+
+    stream = open_memstream(&response, &size);
+    if (!stream) {
+        response = xasprintf("Unable to open memstream: %s.",
+                             ovs_strerror(errno));
+        unixctl_command_reply_error(conn, response);
+        goto out;
+    }
+
+    callback(stream);
+    fclose(stream);
+    unixctl_command_reply(conn, response);
+out:
+    free(response);
+}
+
+static int
+dpdk_parse_log_level(const char *s)
+{
+    static const char * const levels[] = {
+        [RTE_LOG_EMERG]   = "emergency",
+        [RTE_LOG_ALERT]   = "alert",
+        [RTE_LOG_CRIT]    = "critical",
+        [RTE_LOG_ERR]     = "error",
+        [RTE_LOG_WARNING] = "warning",
+        [RTE_LOG_NOTICE]  = "notice",
+        [RTE_LOG_INFO]    = "info",
+        [RTE_LOG_DEBUG]   = "debug",
+    };
+    int i;
+
+    for (i = 1; i < ARRAY_SIZE(levels); ++i) {
+        if (!strcmp(s, levels[i])) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+static void
+dpdk_unixctl_log_set(struct unixctl_conn *conn, int argc, const char *argv[],
+                     void *aux OVS_UNUSED)
+{
+    int i;
+
+    /* With no argument, set all components level to 'debug'. */
+    if (argc == 1) {
+        rte_log_set_level_pattern("*", RTE_LOG_DEBUG);
+    }
+    for (i = 1; i < argc; i++) {
+        char *err_msg = NULL;
+        char *level_string;
+        char *pattern;
+        char *s;
+        int level;
+
+        s = xstrdup(argv[i]);
+        level_string = strchr(s, ':');
+        if (level_string == NULL) {
+            pattern = "*";
+            level_string = s;
+        } else {
+            pattern = s;
+            level_string[0] = '\0';
+            level_string++;
+        }
+
+        level = dpdk_parse_log_level(level_string);
+        if (level == -1) {
+            err_msg = xasprintf("invalid log level: '%s'", level_string);
+        } else if (rte_log_set_level_pattern(pattern, level) < 0) {
+            err_msg = xasprintf("cannot set log level for '%s'", argv[i]);
+        }
+
+        if (err_msg) {
+            unixctl_command_reply_error(conn, err_msg);
+            free(err_msg);
+            free(s);
+            return;
+        }
+        free(s);
+    }
+    unixctl_command_reply(conn, NULL);
+}
+
 static bool
 dpdk_init__(const struct smap *ovs_other_config)
 {
@@ -413,18 +507,24 @@  dpdk_init__(const struct smap *ovs_other_config)
         FILE *stream = open_memstream(&response, &size);
 
         if (stream) {
+            fprintf(stream, "rte_memzone_dump:\n");
             rte_memzone_dump(stream);
+            fprintf(stream, "rte_log_dump:\n");
+            rte_log_dump(stream);
             fclose(stream);
-            if (size) {
-                VLOG_DBG("rte_memzone_dump:\n%s", response);
-            }
+            VLOG_DBG("%s", response);
             free(response);
         } else {
-            VLOG_DBG("Could not dump memzone. Unable to open memstream: %s.",
-                     ovs_strerror(errno));
+            VLOG_DBG("Could not dump memzone and log levels. "
+                     "Unable to open memstream: %s.", ovs_strerror(errno));
         }
     }
 
+    unixctl_command_register("dpdk/log-list", "", 0, 0,
+                             dpdk_unixctl_mem_stream, rte_log_dump);
+    unixctl_command_register("dpdk/log-set", "{level | pattern:level}", 0,
+                             INT_MAX, dpdk_unixctl_log_set, NULL);
+
     /* We are called from the main thread here */
     RTE_PER_LCORE(_lcore_id) = NON_PMD_CORE_ID;
 
diff --git a/vswitchd/ovs-vswitchd.8.in b/vswitchd/ovs-vswitchd.8.in
index 0ad8bd2bc4..c064529289 100644
--- a/vswitchd/ovs-vswitchd.8.in
+++ b/vswitchd/ovs-vswitchd.8.in
@@ -272,6 +272,7 @@  type).
 ..
 .so lib/dpctl.man
 .
+.so lib/dpdk-unixctl.man
 .so lib/dpif-netdev-unixctl.man
 .so lib/netdev-dpdk-unixctl.man
 .so ofproto/ofproto-dpif-unixctl.man