From patchwork Thu Dec 5 17:31:23 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Power, Ciara" X-Patchwork-Id: 63603 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 8F87CA04F2; Thu, 5 Dec 2019 18:34:18 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 249E11BF8D; Thu, 5 Dec 2019 18:34:13 +0100 (CET) Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by dpdk.org (Postfix) with ESMTP id 3FB9C1BF7D for ; Thu, 5 Dec 2019 18:34:10 +0100 (CET) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga104.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 05 Dec 2019 09:34:09 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.69,282,1571727600"; d="scan'208";a="223711800" Received: from silpixa00399953.ir.intel.com (HELO silpixa00399953.ger.corp.intel.com) ([10.237.222.53]) by orsmga002.jf.intel.com with ESMTP; 05 Dec 2019 09:34:08 -0800 From: Ciara Power To: dev@dpdk.org Cc: Bruce Richardson , Ciara Power Date: Thu, 5 Dec 2019 17:31:23 +0000 Message-Id: <20191205173128.64543-2-ciara.power@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191205173128.64543-1-ciara.power@intel.com> References: <20191205173128.64543-1-ciara.power@intel.com> Subject: [dpdk-dev] [RFC 1/6] process-info: introduce process-info library X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Bruce Richardson This patch introduces the process_info library. The library does socket and connection management on a local unix socket, and allows the calling of callback functions on receipt of a message from a connected client. Signed-off-by: Bruce Richardson Signed-off-by: Ciara Power --- The library is not yet initialised to run, this will come in a later patch integrating with the EAL library. --- config/common_base | 5 + lib/Makefile | 1 + lib/librte_process_info/Makefile | 26 ++ lib/librte_process_info/meson.build | 8 + lib/librte_process_info/process_info.c | 231 ++++++++++++++++++ lib/librte_process_info/rte_process_info.h | 25 ++ .../rte_process_info_version.map | 6 + lib/meson.build | 1 + mk/rte.app.mk | 1 + 9 files changed, 304 insertions(+) create mode 100644 lib/librte_process_info/Makefile create mode 100644 lib/librte_process_info/meson.build create mode 100644 lib/librte_process_info/process_info.c create mode 100644 lib/librte_process_info/rte_process_info.h create mode 100644 lib/librte_process_info/rte_process_info_version.map diff --git a/config/common_base b/config/common_base index 7dec7ed45..5f49b934f 100644 --- a/config/common_base +++ b/config/common_base @@ -1093,3 +1093,8 @@ CONFIG_RTE_APP_CRYPTO_PERF=y # Compile the eventdev application # CONFIG_RTE_APP_EVENTDEV=y + +# +# Compile the process_info library +# +CONFIG_RTE_LIBRTE_PROCESS_INFO=y diff --git a/lib/Makefile b/lib/Makefile index 46b91ae1a..466cd04ef 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -4,6 +4,7 @@ include $(RTE_SDK)/mk/rte.vars.mk DIRS-$(CONFIG_RTE_LIBRTE_KVARGS) += librte_kvargs +DIRS-$(CONFIG_RTE_LIBRTE_PROCESS_INFO) += librte_process_info DIRS-$(CONFIG_RTE_LIBRTE_EAL) += librte_eal DEPDIRS-librte_eal := librte_kvargs DIRS-$(CONFIG_RTE_LIBRTE_PCI) += librte_pci diff --git a/lib/librte_process_info/Makefile b/lib/librte_process_info/Makefile new file mode 100644 index 000000000..67b9a9f20 --- /dev/null +++ b/lib/librte_process_info/Makefile @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2019 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# library name +LIB = librte_process_info.a + +CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3 +CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include +CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include/arch/$(ARCH_DIR)/ +CFLAGS += -pthread +LDLIBS += -pthread + +EXPORT_MAP := rte_process_info_version.map + +LIBABIVER := 1 + +# all source are stored in SRCS-y +SRCS-$(CONFIG_RTE_LIBRTE_KVARGS) := process_info.c + +# install includes +INCS := rte_process_info.h +SYMLINK-y-include := $(INCS) + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/lib/librte_process_info/meson.build b/lib/librte_process_info/meson.build new file mode 100644 index 000000000..42850e816 --- /dev/null +++ b/lib/librte_process_info/meson.build @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2019 Intel Corporation + +includes = [global_inc] +includes += include_directories('../librte_eal/common/include/arch/' + arch_subdir) + +sources = files('process_info.c') +headers = files('rte_process_info.h') diff --git a/lib/librte_process_info/process_info.c b/lib/librte_process_info/process_info.c new file mode 100644 index 000000000..3959e24fa --- /dev/null +++ b/lib/librte_process_info/process_info.c @@ -0,0 +1,231 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2019 Intel Corporation + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "rte_process_info.h" + +#define MAX_CMD_LEN 56 + +static int +list_commands(const char *cmd __rte_unused, const char *params __rte_unused, + char *buffer, int buf_len); + +struct cmd_callback { + char cmd[MAX_CMD_LEN]; + process_info_cb fn; +}; + +static int sock = -1; +static struct sockaddr_un sun; +static char process_info_log_error[1024]; +static struct cmd_callback callbacks[PROCESS_INFO_MAX_CALLBACKS] = { + { .cmd = "/", .fn = list_commands }, +}; +static int num_callbacks = 1; +static rte_spinlock_t callback_sl = RTE_SPINLOCK_INITIALIZER; + +/* we won't link against libbsd, so just always use DPDKs-specific version */ +#ifndef strlcpy +#define strlcpy rte_strlcpy +#endif + +int +rte_process_info_register(const char *cmd, process_info_cb fn) +{ + int i = 0; + + if (strlen(cmd) >= MAX_CMD_LEN || fn == NULL) + return -EINVAL; + if (num_callbacks >= PROCESS_INFO_MAX_CALLBACKS) + return -ENOENT; + if (cmd[0] != '/') + return -EINVAL; + + rte_spinlock_lock(&callback_sl); + while (i < num_callbacks && strcmp(cmd, callbacks[i].cmd) > 0) + i++; + if (i != num_callbacks) + memmove(callbacks + i + 1, callbacks + i, + sizeof(struct cmd_callback) * (num_callbacks - i)); + + strlcpy(callbacks[i].cmd, cmd, MAX_CMD_LEN); + callbacks[i].fn = fn; + num_callbacks++; + rte_spinlock_unlock(&callback_sl); + + return 0; +} + +static int +list_commands(const char *cmd __rte_unused, const char *params __rte_unused, + char *buffer, int buf_len) +{ + int i, used = 0; + + used += strlcpy(buffer, "[", buf_len); + for (i = 0; i < num_callbacks; i++) + used += snprintf(buffer + used, buf_len - used, "\"%s\",", + callbacks[i].cmd); + buffer[used - 1] = ']'; + return used; +} + +static void +perform_command(process_info_cb fn, const char *cmd, const char *param, int s) +{ + char out_buf[1024 * 12]; + + int used = snprintf(out_buf, + sizeof(out_buf), "{\"%s\":", cmd); + int ret = fn(cmd, param, out_buf + used, sizeof(out_buf) - used); + if (ret < 0) { + used += strlcpy(out_buf + used, "null}\n", + sizeof(out_buf) - used); + if (write(s, out_buf, used) < 0) + perror("Error writing to socket"); + return; + } + used += ret; + used += strlcpy(out_buf + used, "}\n", sizeof(out_buf) - used); + if (write(s, out_buf, used) < 0) + perror("Error writing to socket"); +} + +static int +unknown_command(const char *cmd __rte_unused, const char *params __rte_unused, + char *buffer, int buf_len) +{ + return snprintf(buffer, buf_len, "null"); +} + +static void * +client_handler(void *sock_id) +{ + int s = (int)(uintptr_t)sock_id; + char buffer[1024]; + + /* receive data is not null terminated */ + int bytes = read(s, buffer, sizeof(buffer)); + buffer[bytes] = 0; + + while (bytes > 0) { + const char *cmd = strtok(buffer, ","); + const char *param = strtok(NULL, ","); + process_info_cb fn = unknown_command; + int i; + + rte_spinlock_lock(&callback_sl); + for (i = 0; i < num_callbacks; i++) + if (strcmp(cmd, callbacks[i].cmd) == 0) { + fn = callbacks[i].fn; + break; + } + + rte_spinlock_unlock(&callback_sl); + perform_command(fn, cmd, param, s); + + bytes = read(s, buffer, sizeof(buffer)); + buffer[bytes] = 0; + } + close(s); + return NULL; +} + +static void * +socket_listener(void *unused __rte_unused) +{ + while (1) { + pthread_t th; + int s = accept(sock, NULL, NULL); + if (s < 0) { + snprintf(process_info_log_error, + sizeof(process_info_log_error), + "Error with accept, process_info thread" + " quitting\n"); + return NULL; + } + pthread_create(&th, NULL, client_handler, (void *)(uintptr_t)s); + pthread_detach(th); + } + return NULL; +} + +static inline char * +get_socket_path(const char *runtime_dir) +{ + static char path[PATH_MAX]; + + if (strlen(runtime_dir) == 0) + snprintf(path, sizeof(path), "/tmp/dpdk_process_info.%d", + getpid()); + else + snprintf(path, sizeof(path), "%s/process_info.%d", + runtime_dir, getpid()); + return path; +} + +static void +unlink_socket(void) +{ + if (sun.sun_path[0]) + unlink(sun.sun_path); +} + +int +rte_process_info_init(const char *runtime_dir, const char **err_str) +{ + pthread_t t; + + sock = socket(AF_UNIX, SOCK_SEQPACKET, 0); + if (sock < 0) { + snprintf(process_info_log_error, sizeof(process_info_log_error), + "Error with socket creation, %s", + strerror(errno)); + *err_str = process_info_log_error; + return -1; + } + + sun.sun_family = AF_UNIX; + if (strlcpy(sun.sun_path, get_socket_path(runtime_dir), + sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) { + snprintf(process_info_log_error, sizeof(process_info_log_error), + "Error with socket binding, path too long"); + goto error; + } + if (bind(sock, (void *)&sun, sizeof(sun)) < 0) { + snprintf(process_info_log_error, sizeof(process_info_log_error), + "Error binding socket: %s", + strerror(errno)); + sun.sun_path[0] = 0; + goto error; + } + + if (listen(sock, 1) < 0) { + snprintf(process_info_log_error, sizeof(process_info_log_error), + "Error calling listen for socket: %s", + strerror(errno)); + goto error; + } + + pthread_create(&t, NULL, socket_listener, NULL); + atexit(unlink_socket); + + return 0; + +error: + close(sock); + unlink_socket(); + sock = -1; + *err_str = process_info_log_error; + return -1; +} diff --git a/lib/librte_process_info/rte_process_info.h b/lib/librte_process_info/rte_process_info.h new file mode 100644 index 000000000..d8d86ef57 --- /dev/null +++ b/lib/librte_process_info/rte_process_info.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2019 Intel Corporation + */ + +#ifndef _RTE_PROCESS_INFO_H_ +#define _RTE_PROCESS_INFO_H_ + +#include +#include + +#define PROCESS_INFO_MAX_CALLBACKS 64 + +/* callback returns json data in buffer, up to buf_len long. + * returns length of buffer used on success, negative on error. + */ +typedef int (*process_info_cb)(const char *cmd, const char *params, + char *buffer, int buf_len); + +__rte_experimental +int rte_process_info_register(const char *cmd, process_info_cb fn); + +__rte_experimental +int rte_process_info_init(const char *runtime_dir, const char **err_str); + +#endif diff --git a/lib/librte_process_info/rte_process_info_version.map b/lib/librte_process_info/rte_process_info_version.map new file mode 100644 index 000000000..7e6f68d5a --- /dev/null +++ b/lib/librte_process_info/rte_process_info_version.map @@ -0,0 +1,6 @@ +EXPERIMENTAL { + global: + rte_process_info_init; + rte_process_info_register; + local: *; +}; diff --git a/lib/meson.build b/lib/meson.build index 6ceb5e756..fe11a02c8 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -10,6 +10,7 @@ # core libs which are widely reused, so their deps are kept to a minimum. libraries = [ 'kvargs', # eal depends on kvargs + 'process_info', # basic info querying capability about dpdk processes 'eal', # everything depends on eal 'ring', 'mempool', 'mbuf', 'net', 'meter', 'ethdev', 'pci', # core 'cmdline', diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 05ea034b9..3c61cbb67 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -77,6 +77,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_HASH) += -lrte_hash _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMBER) += -lrte_member _LDLIBS-$(CONFIG_RTE_LIBRTE_VHOST) += -lrte_vhost _LDLIBS-$(CONFIG_RTE_LIBRTE_KVARGS) += -lrte_kvargs +_LDLIBS-$(CONFIG_RTE_LIBRTE_PROCESS_INFO) += -lrte_process_info _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF) += -lrte_mbuf _LDLIBS-$(CONFIG_RTE_LIBRTE_NET) += -lrte_net _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER) += -lrte_ethdev