[ovs-dev] [PATCH] dpdk: Add commands to configure log levels.
Ilya Maximets
i.maximets at ovn.org
Wed Jul 1 22:05:02 UTC 2020
Hi!
Thanks for the patch. I think it migt be very useful to configure
log levels for parts of DPDK in runtime.
Comments inline.
Best regards, Ilya Maximets.
On 6/26/20 2:27 PM, 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.
Could you, please, provide some usage examples?
Maybe add some documentation about these commands. And a NEWS update
since this is a user visible change.
> This does not help when tracking issues in dpdk init itself: dump log
> levels right after init.
>
> Signed-off-by: David Marchand <david.marchand at redhat.com>
> ---
> lib/dpdk.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 113 insertions(+)
>
> diff --git a/lib/dpdk.c b/lib/dpdk.c
> index 31450d4708..98d0e2643e 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,102 @@ static cookie_io_functions_t dpdk_log_func = {
> .write = dpdk_log_write,
> };
>
> +static void
> +dpdk_unixctl_log_list(struct unixctl_conn *conn, int argc OVS_UNUSED,
> + const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
> +{
> + 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;
> + }
> +
> + rte_log_dump(stream);
This function is fine, however, I see that you're adding almost same function
do dump lcores in a later patch. Maybe we could rename this one to
'dpdk_unixctl_memstream' and pass 'rte_log_dump' function pointer via 'aux'
argument. This will allow us to easily add this kind of unixctl calls.
> + 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 logtypes level to "debug". */
Please, use single quotes if possible.
> + if (argc == 1) {
> + rte_log_set_level_pattern("*", RTE_LOG_DEBUG);
> + }
> + for (i = 1; i < argc; i++) {
> + 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) {
> + char *msg = xstrdup("invalid level");
Maybe it's good to print this invalid level too.
> +
> + unixctl_command_reply_error(conn, msg);
> + free(s);
> + free(msg);
> + return;
> + }
> +
> + if (rte_log_set_level_pattern(pattern, level) < 0) {
> + char *msg = xasprintf("cannot set log level for %s", argv[i]);
> +
> + unixctl_command_reply_error(conn, msg);
> + free(s);
> + free(msg);
> + return;
This 4 lines repeated twice. Maybe combine them somehow?
Something like this:
char *err_msg = NULL;
...
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, msg);
free(s);
free(msg);
return;
}
> + }
> + free(s);
> + }
> + unixctl_command_reply(conn, NULL);
> +}
> +
> static bool
> dpdk_init__(const struct smap *ovs_other_config)
> {
> @@ -423,8 +520,24 @@ dpdk_init__(const struct smap *ovs_other_config)
> VLOG_DBG("Could not dump memzone. Unable to open memstream: %s.",
> ovs_strerror(errno));
> }
> +
> + stream = open_memstream(&response, &size);
Can we use same memstrem for both memzones and log levels to avoid code
duplication? The error log message could say:
"Could not dump memzone and log levels. ...".
I guess, it could be:
fwrite(steam, "rte_memzone_dump:\n");
rte_memzone_dump(stream);
fwrite(steam, "rte_log_dump:\n");
rte_log_dump(stream);
fclose(stream);
VLOG_DBG("%s", response);
free(response);
> + if (stream) {
> + rte_log_dump(stream);
> + fclose(stream);
> + VLOG_DBG("rte_log_dump:\n%s", response);
> + free(response);
> + } else {
> + VLOG_DBG("Could not dump log levels. "
> + "Unable to open memstream: %s.", ovs_strerror(errno));
> + }
> }
>
> + unixctl_command_register("dpdk/log-list", "", 0, 0,
> + dpdk_unixctl_log_list, NULL);
> + unixctl_command_register("dpdk/log-set", "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;
>
>
More information about the dev
mailing list