Soft Patch Panel
 help / color / mirror / Atom feed
* [spp] [PATCH v2 1/7] spp_pcap: add command main
       [not found] <20190208084438.7952-1-x-fn-spp@sl.ntt-tx.co.jp>
@ 2019-02-08  8:44 ` x-fn-spp
  2019-02-08  8:44 ` [spp] [PATCH v2 2/7] spp_pcap: add command decode x-fn-spp
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 7+ messages in thread
From: x-fn-spp @ 2019-02-08  8:44 UTC (permalink / raw)
  To: ferruh.yigit, ogawa.yasufumi; +Cc: spp

From: Hideyuki Yamashita <yamashita.hideyuki@po.ntt-tx.co.jp>

Add command execution part for start, stop and status.

Signed-off-by: Hideyuki Yamashita <yamashita.hideyuki@po.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 src/pcap/command_proc.c | 976 ++++++++++++++++++++++++++++++++++++++++
 src/pcap/command_proc.h |  42 ++
 2 files changed, 1018 insertions(+)
 create mode 100644 src/pcap/command_proc.c
 create mode 100644 src/pcap/command_proc.h

diff --git a/src/pcap/command_proc.c b/src/pcap/command_proc.c
new file mode 100644
index 0000000..28c6b97
--- /dev/null
+++ b/src/pcap/command_proc.c
@@ -0,0 +1,976 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Nippon Telegraph and Telephone Corporation
+ */
+
+#include <unistd.h>
+#include <string.h>
+
+#include <rte_log.h>
+
+#include "string_buffer.h"
+#include "spp_pcap.h"
+#include "command_conn.h"
+#include "command_dec.h"
+#include "command_proc.h"
+
+#define RTE_LOGTYPE_SPP_COMMAND_PROC RTE_LOGTYPE_USER2
+
+/* request message initial size */
+#define CMD_RES_ERR_MSG_SIZE  128
+#define CMD_TAG_APPEND_SIZE   16
+#define CMD_REQ_BUF_INIT_SIZE 2048
+#define CMD_RES_BUF_INIT_SIZE 2048
+
+#define COMMAND_RESP_LIST_EMPTY { "", NULL }
+
+#define JSON_APPEND_COMMA(flg)    ((flg)?", ":"")
+#define JSON_APPEND_VALUE(format) "%s\"%s\": "format
+#define JSON_APPEND_ARRAY         "%s\"%s\": [ %s ]"
+#define JSON_APPEND_BLOCK         "%s\"%s\": { %s }"
+#define JSON_APPEND_BLOCK_NONAME  "%s%s{ %s }"
+
+/* command execution result type */
+enum command_result_type {
+	CMD_SUCCESS = 0,
+	CMD_FAILURE,
+	CMD_INVALID,
+};
+
+/* command execution result information */
+struct command_result {
+	/* Response code */
+	int code;
+
+	/* Response message */
+	char msg[SPP_CMD_NAME_BUFSZ];
+
+	/* Detailed response message */
+	char error_message[CMD_RES_ERR_MSG_SIZE];
+};
+
+/* command response list control structure */
+struct command_response_list {
+	/* JSON Tag name */
+	char tag_name[SPP_CMD_NAME_BUFSZ];
+
+	/* Pointer to handling function */
+	int (*func)(const char *name, char **output, void *tmp);
+};
+
+/* caputure status string list */
+const char *CAPTURE_STATUS_STRINGS[] = {
+	"idle",
+	"running",
+	"", /* termination */
+};
+
+/* get client id */
+static int
+spp_get_client_id(void)
+{
+	struct startup_param *startup_param;
+
+	spp_get_mng_data_addr(&startup_param, NULL, NULL, NULL, NULL);
+	return startup_param->client_id;
+}
+
+/**
+ * Iterate core information for number of available cores to
+ * append response for status command.
+ */
+static int
+spp_iterate_core_info(struct spp_iterate_core_params *params)
+{
+	int ret;
+	int lcore_id;
+
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (spp_get_core_status(lcore_id) == SPP_CORE_UNUSE)
+			continue;
+
+		ret = spp_pcap_get_core_status(lcore_id, params);
+		if (unlikely(ret != 0)) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC,
+					"Cannot iterate core information. "
+						"(core = %d)\n", lcore_id);
+			return SPP_RET_NG;
+		}
+	}
+
+	return SPP_RET_OK;
+}
+
+/* append a comma for JSON format */
+static int
+append_json_comma(char **output)
+{
+	*output = spp_strbuf_append(*output, ", ", strlen(", "));
+	if (unlikely(*output == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"JSON's comma failed to add.\n");
+		return SPP_RET_NG;
+	}
+
+	return SPP_RET_OK;
+}
+
+/**
+ * Append JSON formatted tag and its value to given `output` val. For example,
+ * `output` is `"core": 2` if the args of `name` is "core" and `value` is 2.
+ */
+static int
+append_json_uint_value(const char *name, char **output, unsigned int value)
+{
+	int len = strlen(*output);
+	/* extend the buffer */
+	*output = spp_strbuf_append(*output, "",
+			strlen(name) + CMD_TAG_APPEND_SIZE*2);
+	if (unlikely(*output == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"JSON's numeric format failed to add. "
+				"(name = %s, uint = %u)\n", name, value);
+		return SPP_RET_NG;
+	}
+
+	sprintf(&(*output)[len], JSON_APPEND_VALUE("%u"),
+			JSON_APPEND_COMMA(len), name, value);
+	return SPP_RET_OK;
+}
+
+/**
+ * Append JSON formatted tag and its value to given `output` val. For example,
+ * `output` is `"client-id": 1`
+ * if the args of `name` is "client-id" and `value` is 1.
+ */
+static int
+append_json_int_value(const char *name, char **output, int value)
+{
+	int len = strlen(*output);
+	/* extend the buffer */
+	*output = spp_strbuf_append(*output, "",
+			strlen(name) + CMD_TAG_APPEND_SIZE*2);
+	if (unlikely(*output == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"JSON's numeric format failed to add. "
+				"(name = %s, int = %d)\n", name, value);
+		return SPP_RET_NG;
+	}
+
+	sprintf(&(*output)[len], JSON_APPEND_VALUE("%d"),
+			JSON_APPEND_COMMA(len), name, value);
+	return SPP_RET_OK;
+}
+
+/**
+ * Append JSON formatted tag and its value to given `output` val. For example,
+ * `output` is `"port": "phy:0"`
+ *  if the args of `name` is "port" and  `str` is ”phy:0”.
+ */
+static int
+append_json_str_value(const char *name, char **output, const char *str)
+{
+	int len = strlen(*output);
+	/* extend the buffer */
+	*output = spp_strbuf_append(*output, "",
+			strlen(name) + strlen(str) + CMD_TAG_APPEND_SIZE);
+	if (unlikely(*output == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"JSON's string format failed to add. "
+				"(name = %s, str = %s)\n", name, str);
+		return SPP_RET_NG;
+	}
+
+	sprintf(&(*output)[len], JSON_APPEND_VALUE("\"%s\""),
+			JSON_APPEND_COMMA(len), name, str);
+	return SPP_RET_OK;
+}
+
+/**
+ * Append JSON formatted tag and its value to given `output` val. For example,
+ * `output` is `"results": [ { "result": "success" } ]`
+ * if the args of `name` is "results" and `str` is "{ "result": "success" }".
+ */
+static int
+append_json_array_brackets(const char *name, char **output, const char *str)
+{
+	int len = strlen(*output);
+	/* extend the buffer */
+	*output = spp_strbuf_append(*output, "",
+			strlen(name) + strlen(str) + CMD_TAG_APPEND_SIZE);
+	if (unlikely(*output == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"JSON's square bracket failed to add. "
+				"(name = %s, str = %s)\n", name, str);
+		return SPP_RET_NG;
+	}
+
+	sprintf(&(*output)[len], JSON_APPEND_ARRAY,
+			JSON_APPEND_COMMA(len), name, str);
+	return SPP_RET_OK;
+}
+
+/* append brackets of the blocks for JSON format */
+static int
+append_json_block_brackets(const char *name, char **output, const char *str)
+{
+	int len = strlen(*output);
+	/* extend the buffer */
+	*output = spp_strbuf_append(*output, "",
+			strlen(name) + strlen(str) + CMD_TAG_APPEND_SIZE);
+	if (unlikely(*output == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"JSON's curly bracket failed to add. "
+				"(name = %s, str = %s)\n", name, str);
+		return SPP_RET_NG;
+	}
+
+	if (name[0] == '\0')
+		sprintf(&(*output)[len], JSON_APPEND_BLOCK_NONAME,
+				JSON_APPEND_COMMA(len), name, str);
+	else
+		sprintf(&(*output)[len], JSON_APPEND_BLOCK,
+				JSON_APPEND_COMMA(len), name, str);
+	return SPP_RET_OK;
+}
+
+/* execute one command */
+static int
+execute_command(const struct spp_command *command)
+{
+	int ret = SPP_RET_OK;
+
+	switch (command->type) {
+	case CMD_CLIENT_ID:
+		RTE_LOG(INFO, SPP_COMMAND_PROC,
+				"Execute get_client_id command.\n");
+		break;
+
+	case CMD_STATUS:
+		RTE_LOG(INFO, SPP_COMMAND_PROC,
+				"Execute status command.\n");
+		break;
+
+	case CMD_EXIT:
+		RTE_LOG(INFO, SPP_COMMAND_PROC,
+				"Execute exit command.\n");
+		break;
+
+	case CMD_START:
+		RTE_LOG(INFO, SPP_COMMAND_PROC,
+				"Execute start command.\n");
+		break;
+
+	case CMD_STOP:
+		RTE_LOG(INFO, SPP_COMMAND_PROC,
+				"Execute stop command.\n");
+		break;
+	}
+
+	return ret;
+}
+
+/* parse error message for response */
+static const char *
+parse_error_message(
+		const struct spp_command_parse_error *parse_error,
+		char *message)
+{
+	switch (parse_error->code) {
+	case BAD_FORMAT:
+		sprintf(message, "bad message format");
+		break;
+
+	case UNKNOWN_COMMAND:
+		sprintf(message, "unknown command(%s)", parse_error->value);
+		break;
+
+	case NO_PARAM:
+		sprintf(message, "not enough parameter(%s)",
+				parse_error->value_name);
+		break;
+
+	case BAD_TYPE:
+		sprintf(message, "bad value type(%s)",
+				parse_error->value_name);
+		break;
+
+	case BAD_VALUE:
+		sprintf(message, "bad value(%s)", parse_error->value_name);
+		break;
+
+	default:
+		sprintf(message, "error occur");
+		break;
+	}
+
+	return message;
+}
+
+/* set the command result */
+static inline void
+set_command_results(struct command_result *result,
+		int code, const char *error_messege)
+{
+	result->code = code;
+	switch (code) {
+	case CMD_SUCCESS:
+		strcpy(result->msg, "success");
+		memset(result->error_message, 0x00, CMD_RES_ERR_MSG_SIZE);
+		break;
+	case CMD_FAILURE:
+		strcpy(result->msg, "error");
+		strcpy(result->error_message, error_messege);
+		break;
+	case CMD_INVALID: /* FALLTHROUGH */
+	default:
+		strcpy(result->msg, "invalid");
+		memset(result->error_message, 0x00, CMD_RES_ERR_MSG_SIZE);
+		break;
+	}
+}
+
+/* set parse error to command result */
+static void
+set_parse_error_to_results(struct command_result *results,
+		const struct spp_command_request *request,
+		const struct spp_command_parse_error *parse_error)
+{
+	int i;
+	const char *tmp_buff;
+	char error_messege[CMD_RES_ERR_MSG_SIZE];
+
+	for (i = 0; i < request->num_command; i++) {
+		if (parse_error->code == 0)
+			set_command_results(&results[i], CMD_SUCCESS, "");
+		else
+			set_command_results(&results[i], CMD_INVALID, "");
+	}
+
+	if (parse_error->code != 0) {
+		tmp_buff = parse_error_message(parse_error,
+				error_messege);
+		set_command_results(&results[request->num_valid_command],
+				CMD_FAILURE, tmp_buff);
+	}
+}
+
+/* append a command result for JSON format */
+static int
+append_result_value(const char *name, char **output, void *tmp)
+{
+	const struct command_result *result = tmp;
+	return append_json_str_value(name, output, result->msg);
+}
+
+/* append error details for JSON format */
+static int
+append_error_details_value(const char *name, char **output, void *tmp)
+{
+	int ret = SPP_RET_NG;
+	const struct command_result *result = tmp;
+	char *tmp_buff;
+	/* string is empty, except for errors */
+	if (result->error_message[0] == '\0')
+		return SPP_RET_OK;
+
+	tmp_buff = spp_strbuf_allocate(CMD_RES_BUF_INIT_SIZE);
+	if (unlikely(tmp_buff == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"allocate error. (name = %s)\n",
+				name);
+		return SPP_RET_NG;
+	}
+
+	ret = append_json_str_value("message", &tmp_buff,
+			result->error_message);
+	if (unlikely(ret < 0)) {
+		spp_strbuf_free(tmp_buff);
+		return SPP_RET_NG;
+	}
+
+	ret = append_json_block_brackets(name, output, tmp_buff);
+	spp_strbuf_free(tmp_buff);
+	return ret;
+}
+
+/* append a capture status for JSON format */
+static int
+append_capture_status_value(const char *name, char **output,
+		void *tmp __attribute__ ((unused)))
+{
+	int *capture_status = NULL;
+
+	spp_get_mng_data_addr(NULL, NULL, NULL, NULL, &capture_status);
+
+	return append_json_str_value(name, output,
+			CAPTURE_STATUS_STRINGS[*capture_status]);
+}
+
+/* append a client id for JSON format */
+static int
+append_client_id_value(const char *name, char **output,
+		void *tmp __attribute__ ((unused)))
+{
+	return append_json_int_value(name, output, spp_get_client_id());
+}
+
+/* append a block of port entry for JSON format */
+static int
+append_port_entry(char **output, const struct spp_port_index *port,
+		const enum spp_port_rxtx rxtx __attribute__ ((unused)))
+{
+	int ret = SPP_RET_NG;
+	char port_str[CMD_TAG_APPEND_SIZE];
+	char *tmp_buff = spp_strbuf_allocate(CMD_RES_BUF_INIT_SIZE);
+	if (unlikely(tmp_buff == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"allocate error. (name = port_block)\n");
+		return SPP_RET_NG;
+	}
+
+	spp_format_port_string(port_str, port->iface_type, port->iface_no);
+	ret = append_json_str_value("port", &tmp_buff, port_str);
+	if (unlikely(ret < SPP_RET_OK))
+		return SPP_RET_NG;
+
+	ret = append_json_block_brackets("", output, tmp_buff);
+	spp_strbuf_free(tmp_buff);
+	return ret;
+}
+
+/* append a list of port numbers for JSON format */
+static int
+append_port_array(const char *name, char **output, const int num,
+		const struct spp_port_index *ports,
+		const enum spp_port_rxtx rxtx)
+{
+	int ret = SPP_RET_NG;
+	int i = 0;
+	char *tmp_buff = spp_strbuf_allocate(CMD_RES_BUF_INIT_SIZE);
+	if (unlikely(tmp_buff == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"allocate error. (name = %s)\n",
+				name);
+		return SPP_RET_NG;
+	}
+
+	for (i = 0; i < num; i++) {
+		ret = append_port_entry(&tmp_buff, &ports[i], rxtx);
+		if (unlikely(ret < SPP_RET_OK))
+			return SPP_RET_NG;
+	}
+
+	ret = append_json_array_brackets(name, output, tmp_buff);
+	spp_strbuf_free(tmp_buff);
+	return ret;
+}
+
+/* append a secondary process type for JSON format */
+static int
+append_process_type_value(const char *name, char **output,
+		void *tmp __attribute__ ((unused)))
+{
+	return append_json_str_value(name, output, "pcap");
+}
+
+static int
+append_pcap_core_element_value(
+		struct spp_iterate_core_params *params,
+		const unsigned int lcore_id,
+		const char *name, const char *type,
+		const int num_rx,
+		const struct spp_port_index *rx_ports,
+		const int num_tx __attribute__ ((unused)),
+		const struct spp_port_index *tx_ports __attribute__ ((unused)))
+{
+	int ret = SPP_RET_NG;
+	int unuse_flg = 0;
+	char *buff, *tmp_buff;
+	buff = params->output;
+
+	/* there is not necessary data when "unuse" by type */
+	unuse_flg = strcmp(type, "unuse");
+	if (!unuse_flg)
+		return SPP_RET_OK;
+
+	tmp_buff = spp_strbuf_allocate(CMD_RES_BUF_INIT_SIZE);
+	if (unlikely(tmp_buff == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"allocate error. (lcore_id = %d, type = %s)\n",
+				lcore_id, type);
+		return ret;
+	}
+
+	ret = append_json_uint_value("core", &tmp_buff, lcore_id);
+	if (unlikely(ret < SPP_RET_OK))
+		return ret;
+
+	ret = append_json_str_value("role", &tmp_buff, type);
+	if (unlikely(ret < SPP_RET_OK))
+		return ret;
+
+	if (num_rx != 0)
+		ret = append_port_array("rx_port", &tmp_buff,
+				num_rx, rx_ports, SPP_PORT_RXTX_RX);
+	else
+		ret = append_json_str_value("filename", &tmp_buff, name);
+	if (unlikely(ret < 0))
+		return ret;
+
+	ret = append_json_block_brackets("", &buff, tmp_buff);
+	spp_strbuf_free(tmp_buff);
+	params->output = buff;
+	return ret;
+}
+
+/* append a list of core information for JSON format */
+static int
+append_core_value(const char *name, char **output,
+		void *tmp __attribute__ ((unused)))
+{
+	int ret = SPP_RET_NG;
+	struct spp_iterate_core_params itr_params;
+
+	char *tmp_buff = spp_strbuf_allocate(CMD_RES_BUF_INIT_SIZE);
+	if (unlikely(tmp_buff == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"allocate error. (name = %s)\n",
+				name);
+		return SPP_RET_NG;
+	}
+
+	itr_params.output = tmp_buff;
+	itr_params.element_proc = append_pcap_core_element_value;
+
+	ret = spp_iterate_core_info(&itr_params);
+	if (unlikely(ret != SPP_RET_OK)) {
+		spp_strbuf_free(itr_params.output);
+		return SPP_RET_NG;
+	}
+
+	ret = append_json_array_brackets(name, output, itr_params.output);
+	spp_strbuf_free(itr_params.output);
+	return ret;
+}
+
+/* append string of command response list for JSON format */
+static int
+append_response_list_value(char **output,
+		struct command_response_list *list,
+		void *tmp)
+{
+	int ret = SPP_RET_NG;
+	int i;
+	char *tmp_buff;
+	tmp_buff = spp_strbuf_allocate(CMD_RES_BUF_INIT_SIZE);
+	if (unlikely(tmp_buff == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"allocate error. (name = response_list)\n");
+		return SPP_RET_NG;
+	}
+
+	for (i = 0; list[i].tag_name[0] != '\0'; i++) {
+		tmp_buff[0] = '\0';
+		ret = list[i].func(list[i].tag_name, &tmp_buff, tmp);
+		if (unlikely(ret < SPP_RET_OK)) {
+			spp_strbuf_free(tmp_buff);
+			RTE_LOG(ERR, SPP_COMMAND_PROC,
+					"Failed to get reply string. "
+					"(tag = %s)\n", list[i].tag_name);
+			return SPP_RET_NG;
+		}
+
+		if (tmp_buff[0] == '\0')
+			continue;
+
+		if ((*output)[0] != '\0') {
+			ret = append_json_comma(output);
+			if (unlikely(ret < SPP_RET_OK)) {
+				spp_strbuf_free(tmp_buff);
+				RTE_LOG(ERR, SPP_COMMAND_PROC,
+						"Failed to add commas. "
+						"(tag = %s)\n",
+						list[i].tag_name);
+				return SPP_RET_NG;
+			}
+		}
+
+		*output = spp_strbuf_append(*output, tmp_buff,
+				strlen(tmp_buff));
+		if (unlikely(*output == NULL)) {
+			spp_strbuf_free(tmp_buff);
+			RTE_LOG(ERR, SPP_COMMAND_PROC,
+					"Failed to add reply string. "
+					"(tag = %s)\n",
+					list[i].tag_name);
+			return SPP_RET_NG;
+		}
+	}
+
+	spp_strbuf_free(tmp_buff);
+	return SPP_RET_OK;
+}
+
+/* termination constant of command response list */
+#define COMMAND_RESP_TAG_LIST_EMPTY { "", NULL }
+
+/* command response result string list */
+struct command_response_list response_result_list[] = {
+	{ "result",        append_result_value },
+	{ "error_details", append_error_details_value },
+	COMMAND_RESP_TAG_LIST_EMPTY
+};
+
+/* command response status information string list */
+struct command_response_list response_info_list[] = {
+	{ "client-id",        append_client_id_value },
+	{ "status",           append_capture_status_value },
+	{ "core",             append_core_value },
+	COMMAND_RESP_TAG_LIST_EMPTY
+};
+
+/* append a list of command results for JSON format. */
+static int
+append_command_results_value(const char *name, char **output,
+		int num, struct command_result *results)
+{
+	int ret = SPP_RET_NG;
+	int i;
+	char *tmp_buff1, *tmp_buff2;
+	tmp_buff1 = spp_strbuf_allocate(CMD_RES_BUF_INIT_SIZE);
+	if (unlikely(tmp_buff1 == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"allocate error. (name = %s, buff=1)\n",
+				name);
+		return SPP_RET_NG;
+	}
+
+	tmp_buff2 = spp_strbuf_allocate(CMD_RES_BUF_INIT_SIZE);
+	if (unlikely(tmp_buff2 == NULL)) {
+		spp_strbuf_free(tmp_buff1);
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"allocate error. (name = %s, buff=2)\n",
+				name);
+		return SPP_RET_NG;
+	}
+
+	for (i = 0; i < num; i++) {
+		tmp_buff1[0] = '\0';
+		ret = append_response_list_value(&tmp_buff1,
+				response_result_list, &results[i]);
+		if (unlikely(ret < 0)) {
+			spp_strbuf_free(tmp_buff1);
+			spp_strbuf_free(tmp_buff2);
+			return SPP_RET_NG;
+		}
+
+		ret = append_json_block_brackets("", &tmp_buff2, tmp_buff1);
+		if (unlikely(ret < 0)) {
+			spp_strbuf_free(tmp_buff1);
+			spp_strbuf_free(tmp_buff2);
+			return SPP_RET_NG;
+		}
+
+	}
+
+	ret = append_json_array_brackets(name, output, tmp_buff2);
+	spp_strbuf_free(tmp_buff1);
+	spp_strbuf_free(tmp_buff2);
+	return ret;
+}
+
+/* append a list of status information for JSON format. */
+static int
+append_info_value(const char *name, char **output)
+{
+	int ret = SPP_RET_NG;
+	char *tmp_buff = spp_strbuf_allocate(CMD_RES_BUF_INIT_SIZE);
+	if (unlikely(tmp_buff == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"allocate error. (name = %s)\n",
+				name);
+		return SPP_RET_NG;
+	}
+
+	ret = append_response_list_value(&tmp_buff,
+			response_info_list, NULL);
+	if (unlikely(ret < SPP_RET_OK)) {
+		spp_strbuf_free(tmp_buff);
+		return SPP_RET_NG;
+	}
+
+	ret = append_json_block_brackets(name, output, tmp_buff);
+	spp_strbuf_free(tmp_buff);
+	return ret;
+}
+
+/* send response for parse error */
+static void
+send_parse_error_response(int *sock,
+		const struct spp_command_request *request,
+		struct command_result *command_results)
+{
+	int ret = SPP_RET_NG;
+	char *msg, *tmp_buff;
+	tmp_buff = spp_strbuf_allocate(CMD_RES_BUF_INIT_SIZE);
+	if (unlikely(tmp_buff == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "allocate error. "
+				"(name = parse_error_response)\n");
+		return;
+	}
+
+	/* create & append result array */
+	ret = append_command_results_value("results", &tmp_buff,
+			request->num_command, command_results);
+	if (unlikely(ret < SPP_RET_OK)) {
+		spp_strbuf_free(tmp_buff);
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"Failed to make command result response.\n");
+		return;
+	}
+
+	msg = spp_strbuf_allocate(CMD_RES_BUF_INIT_SIZE);
+	if (unlikely(msg == NULL)) {
+		spp_strbuf_free(tmp_buff);
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "allocate error. "
+				"(name = parse_error_response)\n");
+		return;
+	}
+	ret = append_json_block_brackets("", &msg, tmp_buff);
+	spp_strbuf_free(tmp_buff);
+	if (unlikely(ret < SPP_RET_OK)) {
+		spp_strbuf_free(msg);
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"allocate error. (name = result_response)\n");
+		return;
+	}
+
+	RTE_LOG(DEBUG, SPP_COMMAND_PROC,
+			"Make command response (parse error). "
+			"response_str=\n%s\n", msg);
+
+	/* send response to requester */
+	ret = spp_send_message(sock, msg, strlen(msg));
+	if (unlikely(ret != SPP_RET_OK)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"Failed to send parse error response.\n");
+		/* not return */
+	}
+
+	spp_strbuf_free(msg);
+}
+
+/* send response for command execution result */
+static void
+send_command_result_response(int *sock,
+		const struct spp_command_request *request,
+		struct command_result *command_results)
+{
+	int ret = SPP_RET_NG;
+	char *msg, *tmp_buff;
+	int *capture_request = NULL;
+
+	tmp_buff = spp_strbuf_allocate(CMD_RES_BUF_INIT_SIZE);
+	if (unlikely(tmp_buff == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"allocate error. (name = result_response)\n");
+		return;
+	}
+
+	/* create & append result array */
+	ret = append_command_results_value("results", &tmp_buff,
+			request->num_command, command_results);
+	if (unlikely(ret < SPP_RET_OK)) {
+		spp_strbuf_free(tmp_buff);
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"Failed to make command result response.\n");
+		return;
+	}
+
+	/* append client id information value */
+	if (request->is_requested_client_id) {
+		ret = append_client_id_value("client_id", &tmp_buff, NULL);
+		if (unlikely(ret < SPP_RET_OK)) {
+			spp_strbuf_free(tmp_buff);
+			RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to make "
+					"client id response.\n");
+			return;
+		}
+		ret = append_process_type_value("process_type",
+							&tmp_buff, NULL);
+	}
+
+	/* append info value */
+	if (request->is_requested_status) {
+		ret = append_info_value("info", &tmp_buff);
+		if (unlikely(ret < SPP_RET_OK)) {
+			spp_strbuf_free(tmp_buff);
+			RTE_LOG(ERR, SPP_COMMAND_PROC,
+					"Failed to make status response.\n");
+			return;
+		}
+	}
+
+	/* pcap start command */
+	if (request->is_requested_start) {
+		spp_get_mng_data_addr(NULL, NULL, NULL,
+				      &capture_request, NULL);
+		*capture_request = SPP_CAPTURE_RUNNING;
+	}
+
+	/* pcap stop command */
+	if (request->is_requested_stop) {
+		spp_get_mng_data_addr(NULL, NULL, NULL,
+					&capture_request, NULL);
+		*capture_request = SPP_CAPTURE_IDLE;
+	}
+
+	msg = spp_strbuf_allocate(CMD_RES_BUF_INIT_SIZE);
+	if (unlikely(msg == NULL)) {
+		spp_strbuf_free(tmp_buff);
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"allocate error. (name = result_response)\n");
+		return;
+	}
+	ret = append_json_block_brackets("", &msg, tmp_buff);
+	spp_strbuf_free(tmp_buff);
+	if (unlikely(ret < SPP_RET_OK)) {
+		spp_strbuf_free(msg);
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"allocate error. (name = result_response)\n");
+		return;
+	}
+
+	RTE_LOG(DEBUG, SPP_COMMAND_PROC,
+			"Make command response (command result). "
+			"response_str=\n%s\n", msg);
+
+	/* send response to requester */
+	ret = spp_send_message(sock, msg, strlen(msg));
+	if (unlikely(ret != SPP_RET_OK)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+			"Failed to send command result response.\n");
+		/* not return */
+	}
+
+	spp_strbuf_free(msg);
+}
+
+/* process command request from no-null-terminated string */
+static int
+process_request(int *sock, const char *request_str, size_t request_str_len)
+{
+	int ret = SPP_RET_NG;
+	int i;
+
+	struct spp_command_request request;
+	struct spp_command_parse_error parse_error;
+	struct command_result command_results[SPP_CMD_MAX_COMMANDS];
+
+	memset(&request, 0, sizeof(struct spp_command_request));
+	memset(&parse_error, 0, sizeof(struct spp_command_parse_error));
+	memset(command_results, 0, sizeof(command_results));
+
+	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Start command request processing. "
+			"request_str=\n%.*s\n",
+			(int)request_str_len, request_str);
+
+	/* parse request message */
+	ret = spp_command_parse_request(
+			&request, request_str, request_str_len, &parse_error);
+	if (unlikely(ret != SPP_RET_OK)) {
+		/* send error response */
+		set_parse_error_to_results(command_results, &request,
+				&parse_error);
+		send_parse_error_response(sock, &request, command_results);
+		RTE_LOG(DEBUG, SPP_COMMAND_PROC,
+				"End command request processing.\n");
+		return SPP_RET_OK;
+	}
+
+	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Command request is valid. "
+			"num_command=%d, num_valid_command=%d\n",
+			request.num_command, request.num_valid_command);
+
+	/* execute commands */
+	for (i = 0; i < request.num_command ; ++i) {
+		ret = execute_command(request.commands + i);
+		if (unlikely(ret != SPP_RET_OK)) {
+			set_command_results(&command_results[i], CMD_FAILURE,
+					"error occur");
+
+			/* not execute remaining commands */
+			for (++i; i < request.num_command ; ++i)
+				set_command_results(&command_results[i],
+					CMD_INVALID, "");
+
+			break;
+		}
+
+		set_command_results(&command_results[i], CMD_SUCCESS, "");
+	}
+
+	if (request.is_requested_exit) {
+		/* Terminated by process exit command.                       */
+		/* Other route is normal end because it responds to command. */
+		set_command_results(&command_results[0], CMD_SUCCESS, "");
+		send_command_result_response(sock, &request, command_results);
+		RTE_LOG(INFO, SPP_COMMAND_PROC,
+				"Terminate process for exit.\n");
+		return SPP_RET_NG;
+	}
+
+	/* send response */
+	send_command_result_response(sock, &request, command_results);
+
+	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "End command request processing.\n");
+
+	return SPP_RET_OK;
+}
+
+/* initialize command processor. */
+int
+spp_command_proc_init(const char *controller_ip, int controller_port)
+{
+	return spp_command_conn_init(controller_ip, controller_port);
+}
+
+/* process command from controller. */
+int
+spp_command_proc_do(void)
+{
+	int ret = SPP_RET_NG;
+	int msg_ret = -1;
+
+	static int sock = -1;
+	static char *msgbuf;
+
+	if (unlikely(msgbuf == NULL)) {
+		msgbuf = spp_strbuf_allocate(CMD_REQ_BUF_INIT_SIZE);
+		if (unlikely(msgbuf == NULL)) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC,
+					"Cannot allocate memory "
+					"for receive data(init).\n");
+			return SPP_RET_NG;
+		}
+	}
+
+	ret = spp_connect_to_controller(&sock);
+	if (unlikely(ret != SPP_RET_OK))
+		return SPP_RET_OK;
+
+	msg_ret = spp_receive_message(&sock, &msgbuf);
+	if (unlikely(msg_ret <= 0)) {
+		if (likely(msg_ret == 0))
+			return SPP_RET_OK;
+		else if (unlikely(msg_ret == SPP_CONNERR_TEMPORARY))
+			return SPP_RET_OK;
+		else
+			return SPP_RET_NG;
+	}
+
+	ret = process_request(&sock, msgbuf, msg_ret);
+	spp_strbuf_remove_front(msgbuf, msg_ret);
+
+	return ret;
+}
diff --git a/src/pcap/command_proc.h b/src/pcap/command_proc.h
new file mode 100644
index 0000000..8094649
--- /dev/null
+++ b/src/pcap/command_proc.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Nippon Telegraph and Telephone Corporation
+ */
+
+#ifndef _SPP_PCAP_COMMAND_PROC_H_
+#define _SPP_PCAP_COMMAND_PROC_H_
+
+/**
+ * @file
+ * SPP Command processing
+ *
+ * Receive and process the command message, then send back the
+ * result JSON formatted data.
+ */
+
+#include "spp_proc.h"
+
+/**
+ * initialize command processor.
+ *
+ * @param controller_ip
+ *  The controller's ip address.
+ * @param controller_port
+ *  The controller's port number.
+ *
+ * @retval SPP_RET_OK succeeded.
+ * @retval SPP_RET_NG failed.
+ */
+int
+spp_command_proc_init(const char *controller_ip, int controller_port);
+
+/**
+ * process command from controller.
+ *
+ * @retval SPP_RET_OK succeeded.
+ * @retval SPP_RET_NG process termination is required.
+ *            (occurred connection failure, or received exit command)
+ */
+int
+spp_command_proc_do(void);
+
+#endif /* _SPP_PCAP_COMMAND_PROC_H_ */
-- 
2.17.1

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [spp] [PATCH v2 2/7] spp_pcap: add command decode
       [not found] <20190208084438.7952-1-x-fn-spp@sl.ntt-tx.co.jp>
  2019-02-08  8:44 ` [spp] [PATCH v2 1/7] spp_pcap: add command main x-fn-spp
@ 2019-02-08  8:44 ` x-fn-spp
  2019-02-08  8:44 ` [spp] [PATCH v2 3/7] spp_pcap: add management function x-fn-spp
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 7+ messages in thread
From: x-fn-spp @ 2019-02-08  8:44 UTC (permalink / raw)
  To: ferruh.yigit, ogawa.yasufumi; +Cc: spp

From: Hideyuki Yamashita <yamashita.hideyuki@po.ntt-tx.co.jp>

Add command decode part for start, stop and status.

Signed-off-by: Hideyuki Yamashita <yamashita.hideyuki@po.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 src/pcap/command_dec.c | 187 +++++++++++++++++++++++++++++++++++++++++
 src/pcap/command_dec.h | 110 ++++++++++++++++++++++++
 2 files changed, 297 insertions(+)
 create mode 100644 src/pcap/command_dec.c
 create mode 100644 src/pcap/command_dec.h

diff --git a/src/pcap/command_dec.c b/src/pcap/command_dec.c
new file mode 100644
index 0000000..943ab0f
--- /dev/null
+++ b/src/pcap/command_dec.c
@@ -0,0 +1,187 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Nippon Telegraph and Telephone Corporation
+ */
+
+#include <unistd.h>
+#include <string.h>
+
+#include <rte_ether.h>
+#include <rte_log.h>
+#include <rte_branch_prediction.h>
+
+#include "command_dec.h"
+
+#define RTE_LOGTYPE_SPP_COMMAND_DEC RTE_LOGTYPE_USER2
+
+/* set parse error */
+static inline int
+set_parse_error(struct spp_command_parse_error *error,
+		const int error_code, const char *error_name)
+{
+	error->code = error_code;
+
+	if (likely(error_name != NULL))
+		strcpy(error->value_name, error_name);
+
+	return error->code;
+}
+
+/* set parse error */
+static inline int
+set_string_value_parse_error(struct spp_command_parse_error *error,
+		const char *value, const char *error_name)
+{
+	strcpy(error->value, value);
+	return set_parse_error(error, BAD_VALUE, error_name);
+}
+
+/* Split command line parameter with spaces */
+static int
+parse_parameter_value(char *string, int max, int *argc, char *argv[])
+{
+	int cnt = 0;
+	const char *delim = " ";
+	char *argv_tok = NULL;
+	char *saveptr = NULL;
+
+	argv_tok = strtok_r(string, delim, &saveptr);
+	while (argv_tok != NULL) {
+		if (cnt >= max)
+			return SPP_RET_NG;
+		argv[cnt] = argv_tok;
+		cnt++;
+		argv_tok = strtok_r(NULL, delim, &saveptr);
+	}
+	*argc = cnt;
+
+	return SPP_RET_OK;
+}
+
+/* command list for parse */
+struct parse_command_list {
+	const char *name;       /* Command name */
+	int   param_min;        /* Min number of parameters */
+	int   param_max;        /* Max number of parameters */
+	int (*func)(struct spp_command_request *request, int argc,
+			char *argv[], struct spp_command_parse_error *error,
+			int maxargc);
+				/* Pointer to command handling function */
+	enum spp_command_type type;
+				/* Command type */
+};
+
+/* command list */
+static struct parse_command_list command_list_pcap[] = {
+	{ "_get_client_id", 1, 1, NULL, CMD_CLIENT_ID },
+	{ "status",	    1, 1, NULL, CMD_STATUS    },
+	{ "exit",           1, 1, NULL, CMD_EXIT      },
+	{ "start",          1, 1, NULL, CMD_START     },
+	{ "stop",           1, 1, NULL, CMD_STOP      },
+	{ "",               0, 0, NULL, 0 }  /* termination */
+};
+
+/* Parse command line parameters */
+static int
+parse_command_in_list(struct spp_command_request *request,
+			const char *request_str,
+			struct spp_command_parse_error *error)
+{
+	int ret = SPP_RET_OK;
+	int command_name_check = 0;
+	struct parse_command_list *list = NULL;
+	int i = 0;
+	int argc = 0;
+	char *argv[SPP_CMD_MAX_PARAMETERS];
+	char tmp_str[SPP_CMD_MAX_PARAMETERS*SPP_CMD_VALUE_BUFSZ];
+	memset(argv, 0x00, sizeof(argv));
+	memset(tmp_str, 0x00, sizeof(tmp_str));
+
+	strcpy(tmp_str, request_str);
+	ret = parse_parameter_value(tmp_str, SPP_CMD_MAX_PARAMETERS,
+			&argc, argv);
+	if (ret < SPP_RET_OK) {
+		RTE_LOG(ERR, SPP_COMMAND_DEC, "Parameter number over limit."
+				"request_str=%s\n", request_str);
+		return set_parse_error(error, BAD_FORMAT, NULL);
+	}
+	RTE_LOG(DEBUG, SPP_COMMAND_DEC, "Decode array. num=%d\n", argc);
+
+	for (i = 0; command_list_pcap[i].name[0] != '\0'; i++) {
+		list = &command_list_pcap[i];
+		if (strcmp(argv[0], list->name) != 0)
+			continue;
+
+		if (unlikely(argc < list->param_min) ||
+				unlikely(list->param_max < argc)) {
+			command_name_check = 1;
+			continue;
+		}
+
+		request->commands[0].type = command_list_pcap[i].type;
+		if (list->func != NULL)
+			return (*list->func)(request, argc, argv, error,
+							list->param_max);
+
+		return SPP_RET_OK;
+	}
+
+	if (command_name_check != 0) {
+		RTE_LOG(ERR, SPP_COMMAND_DEC, "Parameter number out of range."
+				"request_str=%s\n", request_str);
+		return set_parse_error(error, BAD_FORMAT, NULL);
+	}
+
+	RTE_LOG(ERR, SPP_COMMAND_DEC,
+			"Unknown command. command=%s, request_str=%s\n",
+			argv[0], request_str);
+	return set_string_value_parse_error(error, argv[0], "command");
+}
+
+/* parse request from no-null-terminated string */
+int
+spp_command_parse_request(
+		struct spp_command_request *request,
+		const char *request_str, size_t request_str_len,
+		struct spp_command_parse_error *error)
+{
+	int ret = SPP_RET_NG;
+	int i;
+
+	/* parse request */
+	request->num_command = 1;
+	ret = parse_command_in_list(request, request_str, error);
+	if (unlikely(ret != SPP_RET_OK)) {
+		RTE_LOG(ERR, SPP_COMMAND_DEC,
+				"Cannot parse command request. "
+				"ret=%d, request_str=%.*s\n",
+				ret, (int)request_str_len, request_str);
+		return ret;
+	}
+	request->num_valid_command = 1;
+
+	/* check getter command */
+	for (i = 0; i < request->num_valid_command; ++i) {
+		switch (request->commands[i].type) {
+		case CMD_CLIENT_ID:
+			request->is_requested_client_id = 1;
+			break;
+		case CMD_STATUS:
+			request->is_requested_status = 1;
+			break;
+		case CMD_EXIT:
+			request->is_requested_exit = 1;
+			break;
+		case CMD_START:
+			request->is_requested_start = 1;
+			break;
+		case CMD_STOP:
+			request->is_requested_stop = 1;
+			break;
+		default:
+			/* nothing to do */
+			break;
+		}
+	}
+
+	return ret;
+}
diff --git a/src/pcap/command_dec.h b/src/pcap/command_dec.h
new file mode 100644
index 0000000..0835382
--- /dev/null
+++ b/src/pcap/command_dec.h
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Nippon Telegraph and Telephone Corporation
+ */
+
+#ifndef _SPP_PCAP_COMMAND_DEC_H_
+#define _SPP_PCAP_COMMAND_DEC_H_
+
+/**
+ * @file
+ * SPP pcap command parse
+ *
+ * Decode and validate the command message string.
+ */
+
+#include "spp_proc.h"
+
+/** max number of command per request */
+#define SPP_CMD_MAX_COMMANDS 32
+
+/** maximum number of parameters per command */
+#define SPP_CMD_MAX_PARAMETERS 8
+
+/** command name string buffer size (include null char) */
+#define SPP_CMD_NAME_BUFSZ  32
+
+/** command value string buffer size (include null char) */
+#define SPP_CMD_VALUE_BUFSZ 111
+
+/** parse error code */
+enum spp_command_parse_error_code {
+	/* not use 0, in general 0 is OK */
+	BAD_FORMAT = 1,  /**< Wrong format */
+	UNKNOWN_COMMAND, /**< Unknown command */
+	NO_PARAM,        /**< No parameters */
+	BAD_TYPE,        /**< Wrong data type */
+	BAD_VALUE,       /**< Wrong value */
+};
+
+/**
+ * spp command type.
+ *
+ * @attention This enumerated type must have the same order of command_list
+ *            defined in command_dec_pcap.c
+ */
+enum spp_command_type {
+	/** get_client_id command */
+	CMD_CLIENT_ID,
+
+	/** status command */
+	CMD_STATUS,
+
+	/** exit command */
+	CMD_EXIT,
+
+	/** start command */
+	CMD_START,
+
+	/** stop command */
+	CMD_STOP,
+
+};
+
+/** command parameters */
+struct spp_command {
+	enum spp_command_type type; /**< Command type */
+};
+
+/** request parameters */
+struct spp_command_request {
+	int num_command;                /**< Number of accepted commands */
+	int num_valid_command;          /**< Number of executed commands */
+	struct spp_command commands[SPP_CMD_MAX_COMMANDS];
+					/**<Information of executed commands */
+
+	int is_requested_client_id;     /**< Id for get_client_id command */
+	int is_requested_status;        /**< Id for status command */
+	int is_requested_exit;          /**< Id for exit command */
+	int is_requested_start;         /**< Id for start command */
+	int is_requested_stop;          /**< Id for stop command */
+};
+
+/** parse error information */
+struct spp_command_parse_error {
+	int code;                            /**< Error code */
+	char value_name[SPP_CMD_NAME_BUFSZ]; /**< Error value name */
+	char value[SPP_CMD_VALUE_BUFSZ];     /**< Error value */
+};
+
+/**
+ * parse request from no-null-terminated string
+ *
+ * @param request
+ *  The pointer to struct spp_command_request.@n
+ *  The result value of decoding the command message.
+ * @param request_str
+ *  The pointer to requested command message.
+ * @param request_str_len
+ *  The length of requested command message.
+ * @param error
+ *  The pointer to struct spp_command_parse_error.@n
+ *  Detailed error information will be stored.
+ *
+ * @retval SPP_RET_OK succeeded.
+ * @retval !0 failed.
+ */
+int spp_command_parse_request(struct spp_command_request *request,
+		const char *request_str, size_t request_str_len,
+		struct spp_command_parse_error *error);
+
+#endif /* _COMMAND_DEC_H_ */
-- 
2.17.1

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [spp] [PATCH v2 3/7] spp_pcap: add management function
       [not found] <20190208084438.7952-1-x-fn-spp@sl.ntt-tx.co.jp>
  2019-02-08  8:44 ` [spp] [PATCH v2 1/7] spp_pcap: add command main x-fn-spp
  2019-02-08  8:44 ` [spp] [PATCH v2 2/7] spp_pcap: add command decode x-fn-spp
@ 2019-02-08  8:44 ` x-fn-spp
  2019-02-08  8:44 ` [spp] [PATCH v2 4/7] spp_pcap: add spp_pcap main function x-fn-spp
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 7+ messages in thread
From: x-fn-spp @ 2019-02-08  8:44 UTC (permalink / raw)
  To: ferruh.yigit, ogawa.yasufumi; +Cc: spp

From: Hideyuki Yamashita <yamashita.hideyuki@po.ntt-tx.co.jp>

Add data or interface management function for spp_pcap.

Signed-off-by: Hideyuki Yamashita <yamashita.hideyuki@po.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 src/pcap/spp_proc.c | 289 ++++++++++++++++++++++++++++++++
 src/pcap/spp_proc.h | 389 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 678 insertions(+)
 create mode 100644 src/pcap/spp_proc.c
 create mode 100644 src/pcap/spp_proc.h

diff --git a/src/pcap/spp_proc.c b/src/pcap/spp_proc.c
new file mode 100644
index 0000000..ab08337
--- /dev/null
+++ b/src/pcap/spp_proc.c
@@ -0,0 +1,289 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Nippon Telegraph and Telephone Corporation
+ */
+
+#include <unistd.h>
+#include <string.h>
+
+#include <rte_eth_ring.h>
+#include <rte_log.h>
+
+#include "spp_proc.h"
+
+#define RTE_LOGTYPE_SPP_PROC RTE_LOGTYPE_USER2
+
+/* Manage data to addoress */
+struct manage_data_addr_info {
+	struct startup_param	  *p_startup_param;
+	struct iface_info	  *p_iface_info;
+	struct core_mng_info	  *p_core_info;
+	int			  *p_capture_request;
+	int			  *p_capture_status;
+	unsigned int		  main_lcore_id;
+};
+
+/* Declare global variables */
+/* Logical core ID for main process */
+static struct manage_data_addr_info g_mng_data_addr;
+
+/* generation of the ring port */
+int
+add_ring_pmd(int ring_id)
+{
+	struct rte_ring *ring;
+	int ring_port_id;
+
+	/* Lookup ring of given id */
+	ring = rte_ring_lookup(get_rx_queue_name(ring_id));
+	if (unlikely(ring == NULL)) {
+		RTE_LOG(ERR, SPP_PROC,
+			"Cannot get RX ring - is server process running?\n");
+		return SPP_RET_NG;
+	}
+
+	/* Create ring pmd */
+	ring_port_id = rte_eth_from_ring(ring);
+	RTE_LOG(INFO, SPP_PROC, "ring port add. (no = %d / port = %d)\n",
+			ring_id, ring_port_id);
+	return ring_port_id;
+}
+
+/* Get core status */
+enum spp_core_status
+spp_get_core_status(unsigned int lcore_id)
+{
+	return (g_mng_data_addr.p_core_info + lcore_id)->status;
+}
+
+/**
+ * Check status of all of cores is same as given
+ *
+ * It returns SPP_RET_NG as status mismatch if status is not same.
+ * If core is in use, status will be checked.
+ */
+static int
+check_core_status(enum spp_core_status status)
+{
+	unsigned int lcore_id = 0;
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if ((g_mng_data_addr.p_core_info + lcore_id)->status !=
+								status) {
+			/* Status is mismatched */
+			return SPP_RET_NG;
+		}
+	}
+	return SPP_RET_OK;
+}
+
+int
+check_core_status_wait(enum spp_core_status status)
+{
+	int cnt = 0;
+	for (cnt = 0; cnt < SPP_CORE_STATUS_CHECK_MAX; cnt++) {
+		sleep(1);
+		int ret = check_core_status(status);
+		if (ret == 0)
+			return SPP_RET_OK;
+	}
+
+	RTE_LOG(ERR, SPP_PROC,
+			"Status check time out. (status = %d)\n", status);
+	return SPP_RET_NG;
+}
+
+/* Set core status */
+void
+set_core_status(unsigned int lcore_id,
+		enum spp_core_status status)
+{
+	(g_mng_data_addr.p_core_info + lcore_id)->status = status;
+}
+
+/* Set all core to given status */
+void
+set_all_core_status(enum spp_core_status status)
+{
+	unsigned int lcore_id = 0;
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		(g_mng_data_addr.p_core_info + lcore_id)->status = status;
+	}
+}
+
+/**
+ * Set all of component status to SPP_CORE_STOP_REQUEST if received signal
+ * is SIGTERM or SIGINT
+ */
+void
+stop_process(int signal)
+{
+	if (unlikely(signal != SIGTERM) &&
+			unlikely(signal != SIGINT)) {
+		return;
+	}
+
+	(g_mng_data_addr.p_core_info + g_mng_data_addr.main_lcore_id)->status =
+							SPP_CORE_STOP_REQUEST;
+	set_all_core_status(SPP_CORE_STOP_REQUEST);
+}
+
+/**
+ * Return port info of given type and num of interface
+ *
+ * It returns NULL value if given type is invalid.
+ */
+struct spp_port_info *
+get_iface_info(enum port_type iface_type, int iface_no)
+{
+	struct iface_info *iface_info = g_mng_data_addr.p_iface_info;
+
+	switch (iface_type) {
+	case PHY:
+		return &iface_info->nic[iface_no];
+	case RING:
+		return &iface_info->ring[iface_no];
+	default:
+		return NULL;
+	}
+}
+
+/**
+ * Initialize g_iface_info
+ *
+ * Clear g_iface_info and set initial value.
+ */
+static void
+init_iface_info(void)
+{
+	int port_cnt;  /* increment ether ports */
+	struct iface_info *p_iface_info = g_mng_data_addr.p_iface_info;
+	memset(p_iface_info, 0x00, sizeof(struct iface_info));
+	for (port_cnt = 0; port_cnt < RTE_MAX_ETHPORTS; port_cnt++) {
+		p_iface_info->nic[port_cnt].iface_type = UNDEF;
+		p_iface_info->nic[port_cnt].iface_no   = port_cnt;
+		p_iface_info->nic[port_cnt].dpdk_port  = -1;
+		p_iface_info->nic[port_cnt].class_id.vlantag.vid =
+				ETH_VLAN_ID_MAX;
+		p_iface_info->ring[port_cnt].iface_type = UNDEF;
+		p_iface_info->ring[port_cnt].iface_no   = port_cnt;
+		p_iface_info->ring[port_cnt].dpdk_port  = -1;
+		p_iface_info->ring[port_cnt].class_id.vlantag.vid =
+				ETH_VLAN_ID_MAX;
+	}
+}
+
+/* Initialize g_core_info */
+static void
+init_core_info(void)
+{
+	struct core_mng_info *p_core_info = g_mng_data_addr.p_core_info;
+	memset(p_core_info, 0x00,
+			sizeof(struct core_mng_info)*RTE_MAX_LCORE);
+	set_all_core_status(SPP_CORE_STOP);
+	*g_mng_data_addr.p_capture_request = SPP_CAPTURE_IDLE;
+	*g_mng_data_addr.p_capture_status = SPP_CAPTURE_IDLE;
+}
+
+/* Setup port info of port on host */
+static int
+set_nic_interface(void)
+{
+	int nic_cnt = 0;
+	struct iface_info *p_iface_info = g_mng_data_addr.p_iface_info;
+
+	/* NIC Setting */
+	p_iface_info->num_nic = rte_eth_dev_count_avail();
+	if (p_iface_info->num_nic > RTE_MAX_ETHPORTS)
+		p_iface_info->num_nic = RTE_MAX_ETHPORTS;
+
+	for (nic_cnt = 0; nic_cnt < p_iface_info->num_nic; nic_cnt++) {
+		p_iface_info->nic[nic_cnt].iface_type   = PHY;
+		p_iface_info->nic[nic_cnt].dpdk_port = nic_cnt;
+	}
+
+	return SPP_RET_OK;
+}
+
+/* Setup management info for spp_pcap */
+int
+init_mng_data(void)
+{
+	/* Initialize interface and core information */
+	init_iface_info();
+	init_core_info();
+
+	int ret_nic = set_nic_interface();
+	if (unlikely(ret_nic != SPP_RET_OK))
+		return SPP_RET_NG;
+
+	return SPP_RET_OK;
+}
+
+/**
+ * Generate a formatted string of combination from interface type and
+ * number and assign to given 'port'
+ */
+int spp_format_port_string(char *port, enum port_type iface_type, int iface_no)
+{
+	const char *iface_type_str;
+
+	switch (iface_type) {
+	case PHY:
+		iface_type_str = SPP_IFTYPE_NIC_STR;
+		break;
+	case RING:
+		iface_type_str = SPP_IFTYPE_RING_STR;
+		break;
+	default:
+		return SPP_RET_NG;
+	}
+
+	sprintf(port, "%s:%d", iface_type_str, iface_no);
+
+	return SPP_RET_OK;
+}
+
+/* Set mange data address */
+int spp_set_mng_data_addr(struct startup_param *startup_param_addr,
+			  struct iface_info *iface_addr,
+			  struct core_mng_info *core_mng_addr,
+			  int *capture_request_addr,
+			  int *capture_status_addr,
+			  unsigned int main_lcore_id)
+{
+	if (startup_param_addr == NULL || iface_addr == NULL ||
+			core_mng_addr == NULL ||
+			capture_request_addr == NULL ||
+			capture_status_addr == NULL ||
+			main_lcore_id == 0xffffffff)
+		return SPP_RET_NG;
+
+	g_mng_data_addr.p_startup_param = startup_param_addr;
+	g_mng_data_addr.p_iface_info = iface_addr;
+	g_mng_data_addr.p_core_info = core_mng_addr;
+	g_mng_data_addr.p_capture_request = capture_request_addr;
+	g_mng_data_addr.p_capture_status = capture_status_addr;
+	g_mng_data_addr.main_lcore_id = main_lcore_id;
+
+	return SPP_RET_OK;
+}
+
+/* Get manage data address */
+void spp_get_mng_data_addr(struct startup_param **startup_param_addr,
+			   struct iface_info **iface_addr,
+			   struct core_mng_info **core_mng_addr,
+			   int **capture_request_addr,
+			   int **capture_status_addr)
+{
+
+	if (startup_param_addr != NULL)
+		*startup_param_addr = g_mng_data_addr.p_startup_param;
+	if (iface_addr != NULL)
+		*iface_addr = g_mng_data_addr.p_iface_info;
+	if (core_mng_addr != NULL)
+		*core_mng_addr = g_mng_data_addr.p_core_info;
+	if (capture_request_addr != NULL)
+		*capture_request_addr = g_mng_data_addr.p_capture_request;
+	if (capture_status_addr != NULL)
+		*capture_status_addr = g_mng_data_addr.p_capture_status;
+
+}
diff --git a/src/pcap/spp_proc.h b/src/pcap/spp_proc.h
new file mode 100644
index 0000000..6da5c5e
--- /dev/null
+++ b/src/pcap/spp_proc.h
@@ -0,0 +1,389 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Nippon Telegraph and Telephone Corporation
+ */
+
+#ifndef _SPP_PROC_H_
+#define _SPP_PROC_H_
+
+/**
+ * @file
+ * SPP process
+ *
+ * SPP component common function.
+ */
+
+#include <netinet/in.h>
+#include "shared/common.h"
+
+/* Max number of core status check */
+#define SPP_CORE_STATUS_CHECK_MAX 5
+
+/** The length of shortest character string */
+#define SPP_MIN_STR_LEN   32
+
+/** The length of NAME string */
+#define SPP_NAME_STR_LEN  128
+
+/** Maximum number of port abilities available */
+#define SPP_PORT_ABILITY_MAX 4
+
+/** Identifier string for each interface */
+#define SPP_IFTYPE_NIC_STR   "phy"
+#define SPP_IFTYPE_RING_STR  "ring"
+
+/* State on core */
+enum spp_core_status {
+	SPP_CORE_UNUSE,        /**< Not used */
+	SPP_CORE_STOP,         /**< Stopped */
+	SPP_CORE_IDLE,         /**< Idling */
+	SPP_CORE_FORWARD,      /**< Forwarding  */
+	SPP_CORE_STOP_REQUEST, /**< Request stopping */
+	SPP_CORE_IDLE_REQUEST  /**< Request idling */
+};
+
+/* State on capture */
+enum spp_capture_status {
+	SPP_CAPTURE_IDLE,      /* Idling */
+	SPP_CAPTURE_RUNNING     /* Running */
+};
+
+enum spp_return_value {
+	SPP_RET_OK = 0,  /**< succeeded */
+	SPP_RET_NG = -1, /**< failed */
+};
+
+/**
+ * Port type (rx or tx) to indicate which direction packet goes
+ * (e.g. receiving or transmitting)
+ */
+enum spp_port_rxtx {
+	SPP_PORT_RXTX_NONE, /**< none */
+	SPP_PORT_RXTX_RX,   /**< rx port */
+	SPP_PORT_RXTX_TX,   /**< tx port */
+	SPP_PORT_RXTX_ALL,  /**< rx/tx port */
+};
+
+/* Process type for each component */
+enum spp_component_type {
+	SPP_COMPONENT_UNUSE,          /**< Not used */
+	SPP_COMPONENT_CLASSIFIER_MAC, /**< Classifier_mac */
+	SPP_COMPONENT_MERGE,          /**< Merger */
+	SPP_COMPONENT_FORWARD,        /**< Forwarder */
+	SPP_COMPONENT_MIRROR,         /**< Mirror */
+};
+
+/**
+ * Port ability operation which indicates vlan tag operation on the port
+ * (e.g. add vlan tag or delete vlan tag)
+ */
+enum spp_port_ability_ope {
+	SPP_PORT_ABILITY_OPE_NONE,        /**< none */
+	SPP_PORT_ABILITY_OPE_ADD_VLANTAG, /**< add VLAN tag */
+	SPP_PORT_ABILITY_OPE_DEL_VLANTAG, /**< delete VLAN tag */
+};
+
+/* getopt_long return value for long option */
+enum SPP_LONGOPT_RETVAL {
+	SPP_LONGOPT_RETVAL__ = 127,
+
+	/*
+	 * Return value definition for getopt_long()
+	 * Only for long option
+	 */
+	SPP_LONGOPT_RETVAL_CLIENT_ID,      /* --client-id       */
+	SPP_LONGOPT_RETVAL_OUTPUT,         /* --output          */
+	SPP_LONGOPT_RETVAL_LIMIT_FILE_SIZE /* --limit_file_size */
+};
+
+/* Interface information structure */
+struct spp_port_index {
+	enum port_type  iface_type; /**< Interface type (phy/ring) */
+	int             iface_no;   /**< Interface number */
+};
+
+/** VLAN tag information */
+struct spp_vlantag_info {
+	int vid; /**< VLAN ID */
+	int pcp; /**< Priority Code Point */
+	int tci; /**< Tag Control Information */
+};
+
+/**
+ * Data for each port ability which indicates vlantag related information
+ * for the port
+ */
+union spp_ability_data {
+	/** VLAN tag information */
+	struct spp_vlantag_info vlantag;
+};
+
+/** Port ability information */
+struct spp_port_ability {
+	enum spp_port_ability_ope ope; /**< Operation */
+	enum spp_port_rxtx rxtx;       /**< rx/tx identifier */
+	union spp_ability_data data;   /**< Port ability data */
+};
+
+/** Port class identifier for classifying */
+struct spp_port_class_identifier {
+	uint64_t mac_addr;                      /**< Mac address (binary) */
+	char     mac_addr_str[SPP_MIN_STR_LEN]; /**< Mac address (text) */
+	struct spp_vlantag_info vlantag;        /**< VLAN tag information */
+};
+
+/* Port info */
+struct spp_port_info {
+	enum port_type iface_type;      /**< Interface type (phy/vhost/ring) */
+	int            iface_no;        /**< Interface number */
+	int            dpdk_port;       /**< DPDK port number */
+	struct spp_port_class_identifier class_id;
+					/**< Port class identifier */
+	struct spp_port_ability ability[SPP_PORT_ABILITY_MAX];
+					/**< Port ability */
+};
+
+/* Component info */
+struct spp_component_info {
+	char name[SPP_NAME_STR_LEN];    /**< Component name */
+	enum spp_component_type type;   /**< Component type */
+	unsigned int lcore_id;          /**< Logical core ID for component */
+	int component_id;               /**< Component ID */
+	int num_rx_port;                /**< The number of rx ports */
+	int num_tx_port;                /**< The number of tx ports */
+	struct spp_port_info *rx_ports[RTE_MAX_ETHPORTS];
+					/**< Array of pointers to rx ports */
+	struct spp_port_info *tx_ports[RTE_MAX_ETHPORTS];
+					/**< Array of pointers to tx ports */
+};
+
+/* Manage given options as global variable */
+struct startup_param {
+	int client_id;		/* Client ID */
+	char server_ip[INET_ADDRSTRLEN];
+				/* IP address stiring of spp-ctl */
+	int server_port;	/* Port Number of spp-ctl */
+};
+
+/* Manage interfaces and port information as global variable */
+struct iface_info {
+	int num_nic;            /* The number of phy */
+	int num_ring;           /* The number of ring */
+	struct spp_port_info nic[RTE_MAX_ETHPORTS];
+				/* Port information of phy */
+	struct spp_port_info ring[RTE_MAX_ETHPORTS];
+				/* Port information of ring */
+};
+
+/* Manage core status and component information as global variable */
+struct core_mng_info {
+	/* Status of cpu core */
+	volatile enum spp_core_status status;
+};
+
+struct spp_iterate_core_params;
+/**
+ * definition of iterated core element procedure function
+ * which is member of spp_iterate_core_params structure.
+ * Above structure is used when listing core information
+ * (e.g) create resonse to status command.
+ */
+typedef int (*spp_iterate_core_element_proc)(
+		struct spp_iterate_core_params *params,
+		const unsigned int lcore_id,
+		const char *name,
+		const char *type,
+		const int num_rx,
+		const struct spp_port_index *rx_ports,
+		const int num_tx,
+		const struct spp_port_index *tx_ports);
+
+/**
+ * iterate core table parameters which is
+ * used when listing core table content
+ * (e.g.) create response to status command.
+ */
+struct spp_iterate_core_params {
+	/** Output buffer */
+	char *output;
+
+	/** The function for creating core information */
+	spp_iterate_core_element_proc element_proc;
+};
+
+/**
+ * added ring_pmd
+ *
+ * @param ring_id
+ *  added ring id.
+ *
+ * @retval 0~   ring_port_id.
+ * @retval -1   failed.
+ */
+int add_ring_pmd(int ring_id);
+
+/**
+ * Get core status
+ *
+ * @param lcore_id
+ *  Logical core ID.
+ *
+ * @return
+ *  Status of specified logical core.
+ */
+enum spp_core_status spp_get_core_status(unsigned int lcore_id);
+
+/**
+ * Run check_core_status() for SPP_CORE_STATUS_CHECK_MAX times with
+ * interval time (1sec)
+ *
+ * @param status
+ *  wait check status.
+ *
+ * @retval 0  succeeded.
+ * @retval -1 failed.
+ */
+int check_core_status_wait(enum spp_core_status status);
+
+/**
+ * Set core status
+ *
+ * @param lcore_id
+ *  Logical core ID.
+ * @param status
+ *  set status.
+ *
+ */
+void set_core_status(unsigned int lcore_id, enum spp_core_status status);
+
+/**
+ * Set all core status to given
+ *
+ * @param status
+ *  set status.
+ *
+ */
+void set_all_core_status(enum spp_core_status status);
+
+/**
+ * Set all of component status to SPP_CORE_STOP_REQUEST if received signal
+ * is SIGTERM or SIGINT
+ *
+ * @param signl
+ *  received signal.
+ *
+ */
+void stop_process(int signal);
+
+/**
+ * Return port info of given type and num of interface
+ *
+ * @param iface_type
+ *  Interface type to be validated.
+ * @param iface_no
+ *  Interface number to be validated.
+ *
+ * @retval !NULL  spp_port_info.
+ * @retval NULL   failed.
+ */
+struct spp_port_info *
+get_iface_info(enum port_type iface_type, int iface_no);
+
+/**
+ * Setup management info for spp_vf
+ */
+int init_mng_data(void);
+
+/**
+ * Get component type of target core
+ *
+ * @param lcore_id
+ *  Logical core ID.
+ *
+ * @return
+ *  Type of component executed on specified logical core
+ */
+enum spp_component_type
+spp_get_component_type(unsigned int lcore_id);
+
+/* Get core information which is in use */
+struct core_info *get_core_info(unsigned int lcore_id);
+
+/**
+ * Port type to string
+ *
+ * @param port
+ *  Character string of Port type to be converted.
+ * @param iface_type
+ *  port interface type
+ * @param iface_no
+ *  interface no
+ *
+ * @retval SPP_RET_OK succeeded.
+ * @retval SPP_RET_NG failed.
+ */
+int
+spp_format_port_string(char *port, enum port_type iface_type, int iface_no);
+
+/**
+ * Port type to string
+ *
+ * @param port
+ *  Character string of Port type to be converted.
+ * @param iface_type
+ *  port interface type
+ * @param iface_no
+ *  interface no
+ *
+ * @retval SPP_RET_OK succeeded.
+ * @retval SPP_RET_NG failed.
+ */
+int
+spp_format_port_string(char *port, enum port_type iface_type, int iface_no);
+
+/**
+ * Set mange data address
+ *
+ * @param startup_param_addr
+ *  g_startup_param address
+ * @param iface_addr
+ *  g_iface_info address
+ * @param core_mng_addr
+ *  g_core_info address
+ * @param capture_request_addr
+ *  g_capture_request address
+ * @param capture_status_addr
+ *  g_capture_status address
+ * @param main_lcore_id
+ *  main_lcore_id mask
+ *
+ * @retval SPP_RET_OK succeeded.
+ * @retval SPP_RET_NG failed.
+ */
+int spp_set_mng_data_addr(struct startup_param *startup_param_addr,
+			  struct iface_info *iface_addr,
+			  struct core_mng_info *core_mng_addr,
+			  int *capture_request_addr,
+			  int *capture_status_addr,
+			  unsigned int main_lcore_id);
+
+/**
+ * Get mange data address
+ *
+ * @param iface_addr
+ *  g_startup_param write address
+ * @param iface_addr
+ *  g_iface_info write address
+ * @param core_mng_addr
+ *  g_core_mng_info write address
+ * @param change_core_addr
+ *  g_capture_request write address
+ * @param change_component_addr
+ *  g_capture_status write address
+ */
+void spp_get_mng_data_addr(struct startup_param **startup_param_addr,
+			   struct iface_info **iface_addr,
+			   struct core_mng_info **core_mng_addr,
+			   int **capture_request_addr,
+			   int **capture_status_addr);
+
+#endif /* _SPP_PROC_H_ */
-- 
2.17.1

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [spp] [PATCH v2 4/7] spp_pcap: add spp_pcap main function
       [not found] <20190208084438.7952-1-x-fn-spp@sl.ntt-tx.co.jp>
                   ` (2 preceding siblings ...)
  2019-02-08  8:44 ` [spp] [PATCH v2 3/7] spp_pcap: add management function x-fn-spp
@ 2019-02-08  8:44 ` x-fn-spp
  2019-02-08  8:44 ` [spp] [PATCH v2 5/7] spp_pcap: add Makefile for spp_pcap x-fn-spp
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 7+ messages in thread
From: x-fn-spp @ 2019-02-08  8:44 UTC (permalink / raw)
  To: ferruh.yigit, ogawa.yasufumi; +Cc: spp

From: Hideyuki Yamashita <yamashita.hideyuki@po.ntt-tx.co.jp>

Add spp_pcap.c and spp_pcap.h which defines main functions for spp_pcap.

Signed-off-by: Hideyuki Yamashita <yamashita.hideyuki@po.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 src/pcap/spp_pcap.c | 1091 +++++++++++++++++++++++++++++++++++++++++++
 src/pcap/spp_pcap.h |   35 ++
 2 files changed, 1126 insertions(+)
 create mode 100644 src/pcap/spp_pcap.c
 create mode 100644 src/pcap/spp_pcap.h

diff --git a/src/pcap/spp_pcap.c b/src/pcap/spp_pcap.c
new file mode 100644
index 0000000..2716c01
--- /dev/null
+++ b/src/pcap/spp_pcap.c
@@ -0,0 +1,1091 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Nippon Telegraph and Telephone Corporation
+ */
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <getopt.h>
+#include <sys/stat.h>
+
+#include <rte_common.h>
+#include <rte_cycles.h>
+
+#include <lz4frame.h>
+
+#include "shared/common.h"
+#include "spp_proc.h"
+#include "spp_pcap.h"
+#include "command_proc.h"
+#include "command_dec.h"
+#include "spp_port.h"
+
+/* Declare global variables */
+#define RTE_LOGTYPE_SPP_PCAP RTE_LOGTYPE_USER2
+
+#define PCAP_FPATH_STRLEN 128
+#define PCAP_FNAME_STRLEN 64
+#define PCAP_FDATE_STRLEN 16
+/**
+ * The first 4 bytes 0xa1b2c3d4 constitute the magic number which is used to
+ * identify pcap files.
+ */
+#define TCPDUMP_MAGIC 0xa1b2c3d4
+/* constant which indicates major verions of libpcap file */
+#define PCAP_VERSION_MAJOR 2
+#define PCAP_VERSION_MINOR 4
+#define PCAP_SNAPLEN_MAX 65535
+/**
+ * pcap header value which indicates physical layer type.
+ * 1 means LINKTYPE_ETHERNET
+ */
+#define PCAP_LINKTYPE 1
+#define IN_CHUNK_SIZE (16*1024)
+#define DEFAULT_OUTPUT_DIR "/tmp"
+#define DEFAULT_FILE_LIMIT 1073741824 /* 1GiB */
+#define PORT_STR_SIZE 16
+#define RING_SIZE 8192
+/* macro */
+/* Ensure snaplen not to be over the maximum size */
+#define TRANCATE_SNAPLEN(a, b) (((a) < (b))?(a):(b))
+
+/* capture thread type */
+enum worker_thread_type {
+	PCAP_UNUSE,  /* Not used */
+	PCAP_RECEIVE,/* thread type receive */
+	PCAP_WRITE   /* thread type write */
+};
+
+/* compress file generate mode */
+enum comp_file_generate_mode {
+	INIT_MODE,   /**
+		       * initial generation mode which is used
+		       * when capture is started
+		       */
+	UPDATE_MODE, /**
+		       * update generation mode which is used
+		       * when capture file reached max size
+		       */
+	CLOSE_MODE   /* close mode which is used when capture is stopped */
+};
+
+/* capture thread name string  */
+const char *CAPTURE_THREAD_TYPE_STRINGS[] = {
+	"unuse",
+	"receive",
+	"write",
+	/* termination */ "",
+};
+
+/* lz4 preferences */
+static const LZ4F_preferences_t g_kprefs = {
+	{
+		LZ4F_max256KB,
+		LZ4F_blockLinked,
+		LZ4F_noContentChecksum,
+		LZ4F_frame,
+		0,                   /* unknown content size */
+		{ 0, 0},             /* reserved, must be set to 0 */
+	},
+	0,                           /* compression level; 0 == default */
+	0,                           /* autoflush */
+	{ 0, 0, 0, 0},               /* reserved, must be set to 0 */
+};
+
+/* pcap file header */
+struct __attribute__((__packed__)) pcap_header {
+	uint32_t magic_number;  /* magic number */
+	uint16_t version_major; /* major version number */
+	uint16_t version_minor; /* minor version number */
+	int32_t  thiszone;      /* GMT to local correction */
+	uint32_t sigfigs;       /* accuracy of timestamps */
+	uint32_t snaplen;       /* max length of captured packets, in octets */
+	uint32_t network;       /* data link type */
+};
+
+/* pcap packet header */
+struct pcap_packet_header {
+	uint32_t ts_sec;        /* time stamp seconds */
+	uint32_t ts_usec;       /* time stamp micro seconds */
+	uint32_t write_len;     /* write length */
+	uint32_t packet_len;    /* packet length */
+};
+
+/* Option for pcap. */
+struct pcap_option {
+	struct timespec start_time; /* start time */
+	uint64_t file_limit;        /* file size limit */
+	char compress_file_path[PCAP_FPATH_STRLEN]; /* file path */
+	char compress_file_date[PCAP_FDATE_STRLEN]; /* file name date */
+	struct spp_port_info port_cap;  /* capture port */
+	struct rte_ring *cap_ring;      /* RTE ring structure */
+};
+
+/**
+ * pcap management info which stores attributes
+ * (e.g. worker thread type, file number, pointer to writing file etc) per core
+ */
+struct pcap_mng_info {
+	volatile enum worker_thread_type type; /* thread type */
+	enum spp_capture_status status; /* thread status */
+	int thread_no;                 /* thread no */
+	int file_no;                   /* file no */
+	char compress_file_name[PCAP_FNAME_STRLEN]; /* lz4 file name */
+	LZ4F_compressionContext_t ctx; /* lz4 file Ccontext */
+	FILE *compress_fp;             /* lzf file pointer */
+	size_t outbuf_capacity;        /* compress date buffer size */
+	void *outbuff;                 /* compress date buffer */
+	uint64_t file_size;            /* file write size */
+};
+
+/* Logical core ID for main thread */
+static unsigned int g_main_lcore_id = 0xffffffff;
+
+/* Execution parameter of spp_pcap */
+static struct startup_param g_startup_param;
+
+/* Interface management information */
+static struct iface_info g_iface_info;
+
+/* Core management information */
+static struct core_mng_info g_core_info[RTE_MAX_LCORE];
+
+/* Packet capture request information */
+static int g_capture_request;
+
+/* Packet capture status information */
+static int g_capture_status;
+
+/* pcap option */
+static struct pcap_option g_pcap_option;
+
+/* pcap managed info */
+static struct pcap_mng_info g_pcap_info[RTE_MAX_LCORE];
+
+/* Print help message */
+static void
+usage(const char *progname)
+{
+	RTE_LOG(INFO, SPP_PCAP, "Usage: %s [EAL args] --"
+		" --client-id CLIENT_ID"
+		" -s SERVER_IP:SERVER_PORT"
+		" -i INPUT_PORT"
+		" [--output FILE_OUT_PUT_PATH]"
+		" [--limit_file_size LIMIT_FILE_SIZE]\n"
+		" --client-id CLIENT_ID   : My client ID\n"
+		" -s SERVER_IP:SERVER_PORT  : "
+				"Access information to the server\n"
+		" -i                        : capture port(phy,ring)\n"
+		" --output                  : file path(default:/tmp)\n"
+		" --limit_file_size         : "
+				"file limit size(default:1073741824 Byte)\n"
+		, progname);
+}
+
+/**
+ * Convert string of given client id to integer
+ *
+ * If succeeded, client id of integer is assigned to client_id and
+ * return SPP_RET_OK. Or return -SPP_RET_NG if failed.
+ */
+static int
+decode_client_id(const char *client_id_str, int *client_id)
+{
+	int id = 0;
+	char *endptr = NULL;
+
+	id = strtol(client_id_str, &endptr, 0);
+	if (unlikely(client_id_str == endptr) || unlikely(*endptr != '\0'))
+		return SPP_RET_NG;
+
+	if (id >= RTE_MAX_LCORE)
+		return SPP_RET_NG;
+
+	*client_id = id;
+	RTE_LOG(DEBUG, SPP_PCAP, "Set client id = %d\n", *client_id);
+	return SPP_RET_OK;
+}
+
+/* Parse options for server IP and port */
+static int
+parse_server_ip(const char *server_str, char *server_ip, int *server_port)
+{
+	const char delim[2] = ":";
+	unsigned int pos = 0;
+	int port = 0;
+	char *endptr = NULL;
+
+	pos = strcspn(server_str, delim);
+	if (pos >= strlen(server_str))
+		return SPP_RET_NG;
+
+	port = strtol(&server_str[pos+1], &endptr, 0);
+	if (unlikely(&server_str[pos+1] == endptr) || unlikely(*endptr != '\0'))
+		return SPP_RET_NG;
+
+	memcpy(server_ip, server_str, pos);
+	server_ip[pos] = '\0';
+	*server_port = port;
+	RTE_LOG(DEBUG, SPP_PCAP, "Set server IP   = %s\n", server_ip);
+	RTE_LOG(DEBUG, SPP_PCAP, "Set server port = %d\n", *server_port);
+	return SPP_RET_OK;
+}
+
+
+/* Decode options for limit file size */
+static int
+decode_limit_file_size(const char *limit_size_str, uint64_t *limit_size)
+{
+	uint64_t file_limit = 0;
+	char *endptr = NULL;
+
+	file_limit = strtoull(limit_size_str, &endptr, 10);
+	if (unlikely(limit_size_str == endptr) || unlikely(*endptr != '\0'))
+		return SPP_RET_NG;
+
+	*limit_size = file_limit;
+	RTE_LOG(DEBUG, SPP_PCAP, "Set limit file zise = %ld\n", *limit_size);
+	return SPP_RET_OK;
+}
+
+/* Decode options for port */
+static int
+decode_capture_port(const char *port_str, enum port_type *iface_type,
+			int *iface_no)
+{
+	enum port_type type = UNDEF;
+	const char *no_str = NULL;
+	char *endptr = NULL;
+
+	/* Find out which type of interface from resource UID */
+	if (strncmp(port_str, SPP_IFTYPE_NIC_STR ":",
+			strlen(SPP_IFTYPE_NIC_STR)+1) == 0) {
+		/* NIC */
+		type = PHY;
+		no_str = &port_str[strlen(SPP_IFTYPE_NIC_STR)+1];
+	} else if (strncmp(port_str, SPP_IFTYPE_RING_STR ":",
+			strlen(SPP_IFTYPE_RING_STR)+1) == 0) {
+		/* RING */
+		type = RING;
+		no_str = &port_str[strlen(SPP_IFTYPE_RING_STR)+1];
+	} else {
+		/* OTHER */
+		RTE_LOG(ERR, SPP_PCAP, "The interface that does not suppor. "
+					"(port = %s)\n", port_str);
+		return SPP_RET_NG;
+	}
+
+	/* Convert from string to number */
+	int ret_no = strtol(no_str, &endptr, 0);
+	if (unlikely(no_str == endptr) || unlikely(*endptr != '\0')) {
+		/* No IF number */
+		RTE_LOG(ERR, SPP_PCAP, "No interface number. (port = %s)\n",
+								port_str);
+		return SPP_RET_NG;
+	}
+
+	*iface_type = type;
+	*iface_no = ret_no;
+
+	RTE_LOG(DEBUG, SPP_PCAP, "Port = %s => Type = %d No = %d\n",
+					port_str, *iface_type, *iface_no);
+	return SPP_RET_OK;
+}
+
+/* Parse options for client app */
+static int
+parse_args(int argc, char *argv[])
+{
+	int cnt;
+	int proc_flg = 0;
+	int server_flg = 0;
+	int port_flg = 0;
+	int option_index, opt;
+	const int argcopt = argc;
+	char *argvopt[argcopt];
+	const char *progname = argv[0];
+	char port_str[PORT_STR_SIZE];
+	static struct option lgopts[] = {
+			{ "client-id",       required_argument, NULL,
+					SPP_LONGOPT_RETVAL_CLIENT_ID },
+			{ "output",          required_argument, NULL,
+					SPP_LONGOPT_RETVAL_OUTPUT },
+			{ "limit_file_size", required_argument, NULL,
+					SPP_LONGOPT_RETVAL_LIMIT_FILE_SIZE},
+			{ 0 },
+	};
+	/**
+	 * Save argv to argvopt to avoid losing the order of options
+	 * by getopt_long()
+	 */
+	for (cnt = 0; cnt < argcopt; cnt++)
+		argvopt[cnt] = argv[cnt];
+
+	/* Clear startup parameters */
+	memset(&g_startup_param, 0x00, sizeof(g_startup_param));
+
+	/* option parameters init */
+	memset(&g_pcap_option, 0x00, sizeof(g_pcap_option));
+	strcpy(g_pcap_option.compress_file_path, DEFAULT_OUTPUT_DIR);
+	g_pcap_option.file_limit = DEFAULT_FILE_LIMIT;
+
+	/* Check options of application */
+	optind = 0;
+	opterr = 0;
+	while ((opt = getopt_long(argc, argvopt, "i:s:", lgopts,
+			&option_index)) != EOF) {
+		switch (opt) {
+		case SPP_LONGOPT_RETVAL_CLIENT_ID:
+			if (decode_client_id(optarg,
+					&g_startup_param.client_id) !=
+								SPP_RET_OK) {
+				usage(progname);
+				return SPP_RET_NG;
+			}
+			proc_flg = 1;
+			break;
+		case SPP_LONGOPT_RETVAL_OUTPUT:
+			strcpy(g_pcap_option.compress_file_path, optarg);
+			struct stat statBuf;
+			if (g_pcap_option.compress_file_path[0] == '\0' ||
+						stat(optarg, &statBuf) != 0) {
+				usage(progname);
+				return SPP_RET_NG;
+			}
+			break;
+		case SPP_LONGOPT_RETVAL_LIMIT_FILE_SIZE:
+			if (decode_limit_file_size(optarg,
+						&g_pcap_option.file_limit) !=
+						SPP_RET_OK) {
+				usage(progname);
+				return SPP_RET_NG;
+			}
+			break;
+		case 'i':
+			strcpy(port_str, optarg);
+			if (decode_capture_port(optarg,
+					&g_pcap_option.port_cap.iface_type,
+					&g_pcap_option.port_cap.iface_no) !=
+					SPP_RET_OK) {
+				usage(progname);
+				return SPP_RET_NG;
+			}
+			port_flg = 1;
+			break;
+		case 's':
+			if (parse_server_ip(optarg, g_startup_param.server_ip,
+					&g_startup_param.server_port) !=
+								SPP_RET_OK) {
+				usage(progname);
+				return SPP_RET_NG;
+			}
+			server_flg = 1;
+			break;
+		default:
+			usage(progname);
+			return SPP_RET_NG;
+		}
+	}
+
+	/* Check mandatory parameters */
+	if ((proc_flg == 0) || (server_flg == 0) || (port_flg == 0)) {
+		usage(progname);
+		return SPP_RET_NG;
+	}
+
+	RTE_LOG(INFO, SPP_PCAP,
+			"app opts (client_id=%d,server=%s:%d,"
+			"port=%s,output=%s,limit_file_size=%ld)\n",
+			g_startup_param.client_id,
+			g_startup_param.server_ip,
+			g_startup_param.server_port,
+			port_str,
+			g_pcap_option.compress_file_path,
+			g_pcap_option.file_limit);
+	return SPP_RET_OK;
+}
+
+/* Pcap get core status */
+int
+spp_pcap_get_core_status(
+		unsigned int lcore_id,
+		struct spp_iterate_core_params *params)
+{
+	int ret = SPP_RET_NG;
+	char role_type[8];
+	struct pcap_mng_info *info = &g_pcap_info[lcore_id];
+	char name[PCAP_FPATH_STRLEN + PCAP_FDATE_STRLEN];
+	struct spp_port_index rx_ports[1];
+	int rx_num = 0;
+
+	RTE_LOG(DEBUG, SPP_PCAP, "status core[%d]\n", lcore_id);
+	if (info->type == PCAP_RECEIVE) {
+		memset(rx_ports, 0x00, sizeof(rx_ports));
+		rx_ports[0].iface_type = g_pcap_option.port_cap.iface_type;
+		rx_ports[0].iface_no   = g_pcap_option.port_cap.iface_no;
+		rx_num = 1;
+		strcpy(role_type, "receive");
+	}
+	if (info->type == PCAP_WRITE) {
+		memset(name, 0x00, sizeof(name));
+		if (info->compress_fp != NULL)
+			snprintf(name, sizeof(name) - 1, "%s/%s",
+					g_pcap_option.compress_file_path,
+					info->compress_file_name);
+		strcpy(role_type, "write");
+	}
+
+
+	/* Set the information with the function specified by the command. */
+	ret = (*params->element_proc)(
+		params, lcore_id,
+		name, role_type,
+		rx_num, rx_ports, 0, NULL);
+	if (unlikely(ret != 0))
+		return SPP_RET_NG;
+
+	return SPP_RET_OK;
+}
+
+/* write compressed data into file  */
+static int output_pcap_file(FILE *compress_fp, void *srcbuf, size_t write_len)
+{
+	size_t write_size;
+
+	if (write_len == 0)
+		return SPP_RET_OK;
+	write_size = fwrite(srcbuf, write_len, 1, compress_fp);
+	if (write_size != 1) {
+		RTE_LOG(ERR, SPP_PCAP, "file write error len=%lu\n",
+								write_len);
+		return SPP_RET_NG;
+	}
+	return SPP_RET_OK;
+}
+
+/* compress data & write file */
+static int output_lz4_pcap_file(struct pcap_mng_info *info,
+			       void *srcbuf,
+			       int src_len)
+{
+	size_t compress_len;
+
+	compress_len = LZ4F_compressUpdate(info->ctx, info->outbuff,
+				info->outbuf_capacity, srcbuf, src_len, NULL);
+	if (LZ4F_isError(compress_len)) {
+		RTE_LOG(ERR, SPP_PCAP, "Compression failed: error %zd\n",
+							compress_len);
+		return SPP_RET_NG;
+	}
+	RTE_LOG(DEBUG, SPP_PCAP, "src len=%d\n", src_len);
+	if (output_pcap_file(info->compress_fp, info->outbuff,
+						compress_len) != 0)
+		return SPP_RET_NG;
+
+	return SPP_RET_OK;
+}
+
+/**
+ * File compression operation. There are three mode.
+ * Open and update and close.
+ */
+static int file_compression_operation(struct pcap_mng_info *info,
+				   enum comp_file_generate_mode mode)
+{
+	struct pcap_header pcap_h;
+	size_t ctxCreation;
+	size_t headerSize;
+	size_t compress_len;
+	char temp_file[PCAP_FPATH_STRLEN + PCAP_FNAME_STRLEN];
+	char save_file[PCAP_FPATH_STRLEN + PCAP_FNAME_STRLEN];
+	const char *iface_type_str;
+
+	if (mode == INIT_MODE) { /* initial generation mode */
+		/* write buffer size get */
+		info->outbuf_capacity = LZ4F_compressBound(IN_CHUNK_SIZE,
+								&g_kprefs);
+		/* write buff allocation */
+		info->outbuff = malloc(info->outbuf_capacity);
+
+		/* Initialize pcap file name */
+		info->file_size = 0;
+		info->file_no = 1;
+		if (g_pcap_option.port_cap.iface_type == PHY)
+			iface_type_str = SPP_IFTYPE_NIC_STR;
+		else
+			iface_type_str = SPP_IFTYPE_RING_STR;
+		snprintf(info->compress_file_name,
+					PCAP_FNAME_STRLEN - 1,
+					"spp_pcap.%s.%s%d.%u.%u.pcap.lz4",
+					g_pcap_option.compress_file_date,
+					iface_type_str,
+					g_pcap_option.port_cap.iface_no,
+					info->thread_no,
+					info->file_no);
+	} else if (mode == UPDATE_MODE) { /* update generation mode */
+		/* old compress file close */
+		/* flush whatever remains within internal buffers */
+		compress_len = LZ4F_compressEnd(info->ctx, info->outbuff,
+					info->outbuf_capacity, NULL);
+		if (LZ4F_isError(compress_len)) {
+			RTE_LOG(ERR, SPP_PCAP, "Failed to end compression: "
+					"error %zd\n", compress_len);
+			fclose(info->compress_fp);
+			info->compress_fp = NULL;
+			free(info->outbuff);
+			return SPP_RET_NG;
+		}
+		if (output_pcap_file(info->compress_fp, info->outbuff,
+						compress_len) != SPP_RET_OK) {
+			fclose(info->compress_fp);
+			info->compress_fp = NULL;
+			free(info->outbuff);
+			return SPP_RET_NG;
+		}
+
+		/* flush remained data */
+		fclose(info->compress_fp);
+		info->compress_fp = NULL;
+
+		/* rename temporary file */
+		memset(temp_file, 0,
+			PCAP_FPATH_STRLEN + PCAP_FNAME_STRLEN);
+		memset(save_file, 0,
+			PCAP_FPATH_STRLEN + PCAP_FNAME_STRLEN);
+		snprintf(temp_file,
+		    (PCAP_FPATH_STRLEN + PCAP_FNAME_STRLEN) - 1,
+		    "%s/%s.tmp", g_pcap_option.compress_file_path,
+		    info->compress_file_name);
+		snprintf(save_file,
+		    (PCAP_FPATH_STRLEN + PCAP_FNAME_STRLEN) - 1,
+		    "%s/%s", g_pcap_option.compress_file_path,
+		    info->compress_file_name);
+		rename(temp_file, save_file);
+
+		/* Initialize pcap file name */
+		info->file_size = 0;
+		info->file_no++;
+		if (g_pcap_option.port_cap.iface_type == PHY)
+			iface_type_str = SPP_IFTYPE_NIC_STR;
+		else
+			iface_type_str = SPP_IFTYPE_RING_STR;
+		snprintf(info->compress_file_name,
+					PCAP_FNAME_STRLEN - 1,
+					"spp_pcap.%s.%s%d.%u.%u.pcap.lz4",
+					g_pcap_option.compress_file_date,
+					iface_type_str,
+					g_pcap_option.port_cap.iface_no,
+					info->thread_no,
+					info->file_no);
+	} else { /* close mode */
+		/* Close temporary file and rename to persistent */
+		if (info->compress_fp == NULL)
+			return SPP_RET_OK;
+		compress_len = LZ4F_compressEnd(info->ctx, info->outbuff,
+					info->outbuf_capacity, NULL);
+		if (LZ4F_isError(compress_len)) {
+			RTE_LOG(ERR, SPP_PCAP, "Failed to end compression: "
+					"error %zd\n", compress_len);
+		} else {
+			output_pcap_file(info->compress_fp, info->outbuff,
+								compress_len);
+			info->file_size += compress_len;
+		}
+		/* flush remained data */
+		fclose(info->compress_fp);
+
+		/* rename temporary file */
+		memset(temp_file, 0,
+			PCAP_FPATH_STRLEN + PCAP_FNAME_STRLEN);
+		memset(save_file, 0,
+			PCAP_FPATH_STRLEN + PCAP_FNAME_STRLEN);
+		snprintf(temp_file,
+		    (PCAP_FPATH_STRLEN + PCAP_FNAME_STRLEN) - 1,
+		    "%s/%s.tmp", g_pcap_option.compress_file_path,
+		    info->compress_file_name);
+		snprintf(save_file,
+		    (PCAP_FPATH_STRLEN + PCAP_FNAME_STRLEN) - 1,
+		    "%s/%s", g_pcap_option.compress_file_path,
+		    info->compress_file_name);
+		rename(temp_file, save_file);
+
+		info->compress_fp = NULL;
+		free(info->outbuff);
+		return SPP_RET_OK;
+	}
+
+	/* file open */
+	memset(temp_file, 0,
+		PCAP_FPATH_STRLEN + PCAP_FNAME_STRLEN);
+	snprintf(temp_file,
+		(PCAP_FPATH_STRLEN + PCAP_FNAME_STRLEN) - 1,
+		"%s/%s.tmp", g_pcap_option.compress_file_path,
+		info->compress_file_name);
+	RTE_LOG(INFO, SPP_PCAP, "open compress filename=%s\n", temp_file);
+	info->compress_fp = fopen(temp_file, "wb");
+	if (info->compress_fp == NULL) {
+		RTE_LOG(ERR, SPP_PCAP, "file open error! filename=%s\n",
+						info->compress_file_name);
+		free(info->outbuff);
+		return SPP_RET_NG;
+	}
+
+	/* init lz4 stream */
+	ctxCreation = LZ4F_createCompressionContext(&info->ctx, LZ4F_VERSION);
+	if (LZ4F_isError(ctxCreation)) {
+		RTE_LOG(ERR, SPP_PCAP, "LZ4F_createCompressionContext error "
+						"(%zd)\n", ctxCreation);
+		fclose(info->compress_fp);
+		info->compress_fp = NULL;
+		free(info->outbuff);
+		return SPP_RET_NG;
+	}
+
+	/* write compress frame header */
+	headerSize = LZ4F_compressBegin(info->ctx, info->outbuff,
+					info->outbuf_capacity, &g_kprefs);
+	if (LZ4F_isError(headerSize)) {
+		RTE_LOG(ERR, SPP_PCAP, "Failed to start compression: "
+					"error %zd\n", headerSize);
+		fclose(info->compress_fp);
+		info->compress_fp = NULL;
+		free(info->outbuff);
+		return SPP_RET_NG;
+	}
+	RTE_LOG(DEBUG, SPP_PCAP, "Buffer size is %zd bytes, header size %zd "
+			"bytes\n", info->outbuf_capacity, headerSize);
+	if (output_pcap_file(info->compress_fp, info->outbuff,
+						headerSize) != 0) {
+		fclose(info->compress_fp);
+		info->compress_fp = NULL;
+		free(info->outbuff);
+		return SPP_RET_NG;
+	}
+	info->file_size = headerSize;
+
+	/* init the common pcap header */
+	pcap_h.magic_number = TCPDUMP_MAGIC;
+	pcap_h.version_major = PCAP_VERSION_MAJOR;
+	pcap_h.version_minor = PCAP_VERSION_MINOR;
+	pcap_h.thiszone = 0;
+	pcap_h.sigfigs = 0;
+	pcap_h.snaplen = PCAP_SNAPLEN_MAX;
+	pcap_h.network = PCAP_LINKTYPE;
+
+	/* pcap header write */
+	if (output_lz4_pcap_file(info, &pcap_h, sizeof(struct pcap_header))
+							!= SPP_RET_OK) {
+		RTE_LOG(ERR, SPP_PCAP, "pcap header write  error!\n");
+		fclose(info->compress_fp);
+		info->compress_fp = NULL;
+		free(info->outbuff);
+		return SPP_RET_NG;
+	}
+
+	return SPP_RET_OK;
+}
+
+/* compress packet data */
+static int compress_file_packet(struct pcap_mng_info *info,
+				struct rte_mbuf *cap_pkt)
+{
+	unsigned int write_packet_length;
+	unsigned int packet_length;
+	struct timespec cap_time;
+	struct pcap_packet_header pcap_packet_h;
+	unsigned int remaining_bytes;
+	int bytes_to_write;
+
+	if (info->compress_fp == NULL)
+		return SPP_RET_OK;
+
+	/* capture file rool */
+	if (info->file_size > g_pcap_option.file_limit) {
+		if (file_compression_operation(info, UPDATE_MODE)
+							!= SPP_RET_OK)
+			return SPP_RET_NG;
+	}
+
+	/* cast to packet */
+	packet_length = rte_pktmbuf_pkt_len(cap_pkt);
+
+	/* truncate packet over the maximum length */
+	write_packet_length = TRANCATE_SNAPLEN(PCAP_SNAPLEN_MAX,
+							packet_length);
+
+	/* get time */
+	clock_gettime(CLOCK_REALTIME, &cap_time);
+
+	/* write block header */
+	pcap_packet_h.ts_sec = (int32_t)cap_time.tv_sec;
+	pcap_packet_h.ts_usec = (int32_t)(cap_time.tv_nsec / 1000);
+	pcap_packet_h.write_len = write_packet_length;
+	pcap_packet_h.packet_len = packet_length;
+
+	/* output to lz4_pcap_file */
+	if (output_lz4_pcap_file(info, &pcap_packet_h.ts_sec,
+			sizeof(struct pcap_packet_header)) != SPP_RET_OK) {
+		file_compression_operation(info, CLOSE_MODE);
+		return SPP_RET_NG;
+	}
+	info->file_size += sizeof(struct pcap_packet_header);
+
+	/* write content */
+	remaining_bytes = write_packet_length;
+	while (cap_pkt != NULL && remaining_bytes > 0) {
+		/* write file */
+		bytes_to_write = TRANCATE_SNAPLEN(
+					rte_pktmbuf_data_len(cap_pkt),
+					remaining_bytes);
+
+		/* output to lz4_pcap_file */
+		if (output_lz4_pcap_file(info,
+				rte_pktmbuf_mtod(cap_pkt, void*),
+						bytes_to_write) != 0) {
+			file_compression_operation(info, CLOSE_MODE);
+			return SPP_RET_NG;
+		}
+		cap_pkt = cap_pkt->next;
+		remaining_bytes -= bytes_to_write;
+		info->file_size += bytes_to_write;
+	}
+
+	return SPP_RET_OK;
+}
+
+/* receive thread */
+static int pcap_proc_receive(int lcore_id)
+{
+	struct timespec now_time;
+	struct tm l_time;
+	int buf;
+	int nb_rx = 0;
+	int nb_tx = 0;
+	struct spp_port_info *rx;
+	struct rte_mbuf *bufs[MAX_PKT_BURST];
+	struct pcap_mng_info *info = &g_pcap_info[lcore_id];
+	struct rte_ring *write_ring = g_pcap_option.cap_ring;
+
+	if (g_capture_request == SPP_CAPTURE_IDLE) {
+		if (info->status == SPP_CAPTURE_RUNNING) {
+			RTE_LOG(DEBUG, SPP_PCAP, "recive[%d], run->idle\n",
+								lcore_id);
+			info->status = SPP_CAPTURE_IDLE;
+			g_capture_status = SPP_CAPTURE_IDLE;
+		}
+		return SPP_RET_OK;
+	}
+	if (info->status == SPP_CAPTURE_IDLE) {
+		/* get time */
+		clock_gettime(CLOCK_REALTIME, &now_time);
+		memset(g_pcap_option.compress_file_date, 0, PCAP_FDATE_STRLEN);
+		localtime_r(&now_time.tv_sec, &l_time);
+		strftime(g_pcap_option.compress_file_date, PCAP_FDATE_STRLEN,
+					"%Y%m%d%H%M%S", &l_time);
+		info->status = SPP_CAPTURE_RUNNING;
+		g_capture_status = SPP_CAPTURE_RUNNING;
+		RTE_LOG(DEBUG, SPP_PCAP, "recive[%d], idle->run\n", lcore_id);
+		RTE_LOG(DEBUG, SPP_PCAP, "recive[%d], start time=%s\n",
+			lcore_id, g_pcap_option.compress_file_date);
+	}
+
+	/* Receive packets */
+	rx = &g_pcap_option.port_cap;
+
+	nb_rx = spp_eth_rx_burst(rx->dpdk_port, 0, bufs, MAX_PKT_BURST);
+	if (unlikely(nb_rx == 0))
+		return SPP_RET_OK;
+
+	/* Write ring packets */
+	nb_tx = rte_ring_enqueue_bulk(write_ring, (void *)bufs, nb_rx, NULL);
+
+	/* Discard remained packets to release mbuf */
+	if (unlikely(nb_tx < nb_rx)) {
+		RTE_LOG(ERR, SPP_PCAP, "drop packets(receve) %d\n",
+							(nb_rx - nb_tx));
+		for (buf = nb_tx; buf < nb_rx; buf++)
+			rte_pktmbuf_free(bufs[buf]);
+	}
+
+	return SPP_RET_OK;
+}
+
+/* write thread */
+static int pcap_proc_write(int lcore_id)
+{
+	int ret = SPP_RET_OK;
+	int buf;
+	int nb_rx = 0;
+	struct rte_mbuf *bufs[MAX_PKT_BURST];
+	struct rte_mbuf *mbuf = NULL;
+	struct pcap_mng_info *info = &g_pcap_info[lcore_id];
+	struct rte_ring *read_ring = g_pcap_option.cap_ring;
+
+	if (g_capture_status == SPP_CAPTURE_IDLE) {
+		if (info->status == SPP_CAPTURE_RUNNING) {
+			RTE_LOG(DEBUG, SPP_PCAP, "write[%d] run->idle\n",
+								lcore_id);
+			info->status = SPP_CAPTURE_IDLE;
+			if (file_compression_operation(info, CLOSE_MODE)
+							!= SPP_RET_OK)
+				return SPP_RET_NG;
+		}
+		return SPP_RET_OK;
+	}
+	if (info->status == SPP_CAPTURE_IDLE) {
+		RTE_LOG(DEBUG, SPP_PCAP, "write[%d] idle->run\n", lcore_id);
+		info->status = SPP_CAPTURE_RUNNING;
+		if (file_compression_operation(info, INIT_MODE)
+						!= SPP_RET_OK) {
+			info->status = SPP_CAPTURE_IDLE;
+			return SPP_RET_NG;
+		}
+	}
+
+	/* Read packets */
+	nb_rx =  rte_ring_dequeue_bulk(read_ring, (void *)bufs, MAX_PKT_BURST,
+									NULL);
+	if (unlikely(nb_rx == 0))
+		return SPP_RET_OK;
+
+	for (buf = 0; buf < nb_rx; buf++) {
+		mbuf = bufs[buf];
+		rte_prefetch0(rte_pktmbuf_mtod(mbuf, void *));
+		if (compress_file_packet(&g_pcap_info[lcore_id], mbuf)
+							!= SPP_RET_OK) {
+			RTE_LOG(ERR, SPP_PCAP, "capture file write error: "
+				"%d (%s)\n", errno, strerror(errno));
+			RTE_LOG(ERR, SPP_PCAP, "drop packets(write) %d\n",
+							(nb_rx - buf));
+			ret = SPP_RET_NG;
+			info->status = SPP_CAPTURE_IDLE;
+			file_compression_operation(info, CLOSE_MODE);
+			break;
+		}
+	}
+	/* mbuf free */
+	for (buf = 0; buf < nb_rx; buf++)
+		rte_pktmbuf_free(bufs[buf]);
+	return ret;
+}
+
+/* Main process of slave core */
+static int
+slave_main(void *arg __attribute__ ((unused)))
+{
+	int ret = SPP_RET_OK;
+	unsigned int lcore_id = rte_lcore_id();
+	struct pcap_mng_info *pcap_info = &g_pcap_info[lcore_id];
+
+	if (pcap_info->thread_no == 0) {
+		RTE_LOG(INFO, SPP_PCAP, "Core[%d] Start recive.\n", lcore_id);
+		pcap_info->type = PCAP_RECEIVE;
+	} else {
+		RTE_LOG(INFO, SPP_PCAP, "Core[%d] Start write(%d).\n",
+					lcore_id, pcap_info->thread_no);
+		pcap_info->type = PCAP_WRITE;
+	}
+	set_core_status(lcore_id, SPP_CORE_IDLE);
+
+	while (1) {
+		if (spp_get_core_status(lcore_id) == SPP_CORE_STOP_REQUEST) {
+			if (pcap_info->status == SPP_CAPTURE_IDLE)
+				break;
+			if (pcap_info->type == PCAP_RECEIVE)
+				g_capture_request = SPP_CAPTURE_IDLE;
+		}
+
+		if (pcap_info->type == PCAP_RECEIVE)
+			ret = pcap_proc_receive(lcore_id);
+		else
+			ret = pcap_proc_write(lcore_id);
+		if (unlikely(ret != SPP_RET_OK)) {
+			RTE_LOG(ERR, SPP_PCAP, "Core[%d] Thread Error.\n",
+								lcore_id);
+			break;
+		}
+	}
+
+	set_core_status(lcore_id, SPP_CORE_STOP);
+	RTE_LOG(INFO, SPP_PCAP, "Core[%d] End.\n", lcore_id);
+	return ret;
+}
+
+/**
+ * Main function
+ *
+ * Return SPP_RET_NG explicitly if error is occurred.
+ */
+int
+main(int argc, char *argv[])
+{
+	int ret = SPP_RET_NG;
+#ifdef SPP_DEMONIZE
+	/* Daemonize process */
+	int ret_daemon = daemon(0, 0);
+	if (unlikely(ret_daemon != 0)) {
+		RTE_LOG(ERR, SPP_PCAP, "daemonize is failed. (ret = %d)\n",
+				ret_daemon);
+		return ret_daemon;
+	}
+#endif
+
+	/* Signal handler registration (SIGTERM/SIGINT) */
+	signal(SIGTERM, stop_process);
+	signal(SIGINT,  stop_process);
+
+	while (1) {
+		int ret_eal = rte_eal_init(argc, argv);
+		if (unlikely(ret_eal < 0))
+			break;
+
+		argc -= ret_eal;
+		argv += ret_eal;
+
+		/* Parse spp_pcap specific parameters */
+		int ret_parse = parse_args(argc, argv);
+		if (unlikely(ret_parse != 0))
+			break;
+
+		/* Get lcore id of main thread to set its status after */
+		g_main_lcore_id = rte_lcore_id();
+
+		/* set manage address */
+		if (spp_set_mng_data_addr(&g_startup_param,
+					  &g_iface_info,
+					  g_core_info,
+					  &g_capture_request,
+					  &g_capture_status,
+					  g_main_lcore_id) < 0) {
+			RTE_LOG(ERR, SPP_PCAP,
+				"manage address set is failed.\n");
+			break;
+		}
+
+		int ret_mng = init_mng_data();
+		if (unlikely(ret_mng != 0))
+			break;
+
+		spp_port_ability_init();
+
+		/* Setup connection for accepting commands from controller */
+		int ret_command_init = spp_command_proc_init(
+				g_startup_param.server_ip,
+				g_startup_param.server_port);
+		if (unlikely(ret_command_init != SPP_RET_OK))
+			break;
+
+		/* capture port setup */
+		struct spp_port_info *port_cap = &g_pcap_option.port_cap;
+		struct spp_port_info *port_info = get_iface_info(
+						port_cap->iface_type,
+						port_cap->iface_no);
+		if (port_info == NULL) {
+			RTE_LOG(ERR, SPP_PCAP, "caputre port undefined.\n");
+			break;
+		}
+		if (port_cap->iface_type == PHY) {
+			if (port_info->iface_type != UNDEF)
+				port_cap->dpdk_port = port_info->dpdk_port;
+			else {
+				RTE_LOG(ERR, SPP_PCAP,
+					"caputre port undefined.(phy:%d)\n",
+							port_cap->iface_no);
+				break;
+			}
+		} else {
+			if (port_info->iface_type == UNDEF) {
+				ret = add_ring_pmd(port_info->iface_no);
+				if (ret == SPP_RET_NG) {
+					RTE_LOG(ERR, SPP_PCAP, "caputre port "
+						"undefined.(ring:%d)\n",
+						port_cap->iface_no);
+					break;
+				}
+				port_cap->dpdk_port = ret;
+			} else {
+				RTE_LOG(ERR, SPP_PCAP, "caputre port "
+						"undefined.(ring:%d)\n",
+						port_cap->iface_no);
+				break;
+			}
+		}
+		RTE_LOG(DEBUG, SPP_PCAP,
+				"Recv port type=%d, no=%d, port_id=%d\n",
+				port_cap->iface_type, port_cap->iface_no,
+				port_cap->dpdk_port);
+
+		/* create ring */
+		char ring_name[PORT_STR_SIZE];
+		memset(ring_name, 0x00, PORT_STR_SIZE);
+		snprintf(ring_name, PORT_STR_SIZE,  "cap_ring_%d",
+						g_startup_param.client_id);
+		g_pcap_option.cap_ring = rte_ring_create(ring_name,
+					rte_align32pow2(RING_SIZE),
+					rte_socket_id(), 0);
+		if (g_pcap_option.cap_ring == NULL) {
+			RTE_LOG(ERR, SPP_PCAP, "ring create error(%s).\n",
+						rte_strerror(rte_errno));
+			break;
+		}
+		RTE_LOG(DEBUG, SPP_PCAP, "Ring port name=%s, flags=0x%x\n",
+				g_pcap_option.cap_ring->name,
+				g_pcap_option.cap_ring->flags);
+
+		/* Start worker threads of recive or write */
+		unsigned int lcore_id = 0;
+		unsigned int thread_no = 0;
+		RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+			g_pcap_info[lcore_id].thread_no = thread_no++;
+			rte_eal_remote_launch(slave_main, NULL, lcore_id);
+		}
+
+		/* Set the status of main thread to idle */
+		g_core_info[g_main_lcore_id].status = SPP_CORE_IDLE;
+		int ret_wait = check_core_status_wait(SPP_CORE_IDLE);
+		if (unlikely(ret_wait != 0))
+			break;
+
+		/* Start secondary */
+		set_all_core_status(SPP_CORE_FORWARD);
+		RTE_LOG(INFO, SPP_PCAP, "[Press Ctrl-C to quit ...]\n");
+
+		/* Enter loop for accepting commands */
+		int ret_do = 0;
+		while (likely(g_core_info[g_main_lcore_id].status !=
+				SPP_CORE_STOP_REQUEST)) {
+			/* Receive command */
+			ret_do = spp_command_proc_do();
+			if (unlikely(ret_do != SPP_RET_OK))
+				break;
+
+			/*
+			 * Wait to avoid CPU overloaded.
+			 */
+			usleep(100);
+		}
+
+		if (unlikely(ret_do != SPP_RET_OK)) {
+			set_all_core_status(SPP_CORE_STOP_REQUEST);
+			break;
+		}
+
+		ret = SPP_RET_OK;
+		break;
+	}
+
+	/* Finalize to exit */
+	if (g_main_lcore_id == rte_lcore_id()) {
+		g_core_info[g_main_lcore_id].status = SPP_CORE_STOP;
+		int ret_core_end = check_core_status_wait(SPP_CORE_STOP);
+		if (unlikely(ret_core_end != 0))
+			RTE_LOG(ERR, SPP_PCAP, "Core did not stop.\n");
+
+		/* capture write ring free */
+		if (g_pcap_option.cap_ring != NULL)
+			rte_ring_free(g_pcap_option.cap_ring);
+	}
+
+
+	RTE_LOG(INFO, SPP_PCAP, "spp_pcap exit.\n");
+	return ret;
+}
diff --git a/src/pcap/spp_pcap.h b/src/pcap/spp_pcap.h
new file mode 100644
index 0000000..d282226
--- /dev/null
+++ b/src/pcap/spp_pcap.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Nippon Telegraph and Telephone Corporation
+ */
+
+#ifndef __SPP_PCAP_H__
+#define __SPP_PCAP_H__
+
+#include "spp_proc.h"
+
+/**
+ * @file
+ * SPP_PCAP main
+ *
+ * Main function of spp_pcap.
+ * This provides the function for initializing and starting the threads.
+ *
+ */
+
+/**
+ * Pcap get core status
+ *
+ * @param lcore_id
+ *  The logical core ID for forwarder and merger.
+ * @param params
+ *  The pointer to struct spp_iterate_core_params.@n
+ *  Detailed data of pcap status.
+ *
+ * @retval SPP_RET_OK succeeded.
+ * @retval SPP_RET_NG failed.
+ */
+int spp_pcap_get_core_status(
+		unsigned int lcore_id,
+		struct spp_iterate_core_params *params);
+
+#endif /* __SPP_PCAP_H__ */
-- 
2.17.1

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [spp] [PATCH v2 5/7] spp_pcap: add Makefile for spp_pcap
       [not found] <20190208084438.7952-1-x-fn-spp@sl.ntt-tx.co.jp>
                   ` (3 preceding siblings ...)
  2019-02-08  8:44 ` [spp] [PATCH v2 4/7] spp_pcap: add spp_pcap main function x-fn-spp
@ 2019-02-08  8:44 ` x-fn-spp
  2019-02-08  8:44 ` [spp] [PATCH v2 6/7] controller: add SppPcap class x-fn-spp
  2019-02-08  8:44 ` [spp] [PATCH v2 7/7] controller: add pcap command to SPP controller x-fn-spp
  6 siblings, 0 replies; 7+ messages in thread
From: x-fn-spp @ 2019-02-08  8:44 UTC (permalink / raw)
  To: ferruh.yigit, ogawa.yasufumi; +Cc: spp

From: Hideyuki Yamashita <yamashita.hideyuki@po.ntt-tx.co.jp>

Add Makefile for spp_pcap.

Signed-off-by: Hideyuki Yamashita <yamashita.hideyuki@po.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 src/Makefile      |  1 +
 src/pcap/Makefile | 36 ++++++++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+)
 create mode 100644 src/pcap/Makefile

diff --git a/src/Makefile b/src/Makefile
index 4cf7ef4..cab80db 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -42,5 +42,6 @@ DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += primary
 DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += nfv
 DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += vf
 DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += mirror
+DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += pcap
 
 include $(RTE_SDK)/mk/rte.extsubdir.mk
diff --git a/src/pcap/Makefile b/src/pcap/Makefile
new file mode 100644
index 0000000..298e2b7
--- /dev/null
+++ b/src/pcap/Makefile
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Nippon Telegraph and Telephone Corporation
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overridden by command line or environment
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = spp_pcap
+
+# all source are stored in SRCS-y
+SRCS-y := spp_pcap.c
+SRCS-y += spp_proc.c
+SRCS-y += command_proc.c command_dec.c
+SRCS-y += ../shared/common.c
+SRCS-y += ../vf/common/command_conn.c ../vf/common/spp_port.c
+SRCS-y += ../vf/common/ringlatencystats.c ../vf/common/string_buffer.c
+SRCS-y += /usr/lib/x86_64-linux-gnu/liblz4.a
+
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += $(WERROR_FLAGS) -O3 -MMD
+CFLAGS += -I$(SRCDIR)/../
+CFLAGS += -I$(SRCDIR)/../vf/common
+CFLAGS += -I$(SRCDIR)/../shared
+#CFLAGS += -DSPP_DEMONIZE
+#CFLAGS += -DSPP_RINGLATENCYSTATS_ENABLE
+
+ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
+LDLIBS += -lrte_pmd_ring
+LDLIBS += -lrte_pmd_vhost
+endif
+
+include $(RTE_SDK)/mk/rte.extapp.mk
-- 
2.17.1

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [spp] [PATCH v2 6/7] controller: add SppPcap class
       [not found] <20190208084438.7952-1-x-fn-spp@sl.ntt-tx.co.jp>
                   ` (4 preceding siblings ...)
  2019-02-08  8:44 ` [spp] [PATCH v2 5/7] spp_pcap: add Makefile for spp_pcap x-fn-spp
@ 2019-02-08  8:44 ` x-fn-spp
  2019-02-08  8:44 ` [spp] [PATCH v2 7/7] controller: add pcap command to SPP controller x-fn-spp
  6 siblings, 0 replies; 7+ messages in thread
From: x-fn-spp @ 2019-02-08  8:44 UTC (permalink / raw)
  To: ferruh.yigit, ogawa.yasufumi; +Cc: spp

From: Hideyuki Yamashita <yamashita.hideyuki@po.ntt-tx.co.jp>

This update is to add SppPcap class behaviour as a client for spp-ctl.
An instance of the class is intended to be used from do_pcap() and
complete_pcap() methods of Shell class in 'spp.py'.

Signed-off-by: Hideyuki Yamashita <yamashita.hideyuki@po.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 src/controller/commands/pcap.py | 230 ++++++++++++++++++++++++++++++++
 1 file changed, 230 insertions(+)
 create mode 100644 src/controller/commands/pcap.py

diff --git a/src/controller/commands/pcap.py b/src/controller/commands/pcap.py
new file mode 100644
index 0000000..89a1a5f
--- /dev/null
+++ b/src/controller/commands/pcap.py
@@ -0,0 +1,230 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2019 Nippon Telegraph and Telephone Corporation
+
+
+class SppPcap(object):
+    """Exec spp_pcap command.
+
+    SppPcap class is intended to be used in Shell class as a delegator
+    for running 'pcap' command.
+
+    'self.command()' is called from do_pcap() and 'self.complete()' is called
+    from complete_() of both of which is defined in Shell.
+    """
+
+    # All of commands and sub-commands used for validation and completion.
+    PCAP_CMDS = {
+            'status': None,
+            'start': None,
+            'stop': None,
+            'exit': None}
+
+    WORKER_TYPES = ['receive', 'write']
+
+    def __init__(self, spp_ctl_cli, sec_id, use_cache=False):
+        self.spp_ctl_cli = spp_ctl_cli
+        self.sec_id = sec_id
+
+        # Update 'self.worker_names' and 'self.unused_core_ids' each time
+        # 'self.run()' is called if it is 'False'.
+        # True to 'True' if you do not wait for spp_pcap's response.
+        self.use_cache = use_cache
+
+        # Names and core IDs of worker threads
+        pcap_status = self._get_status(self.sec_id)
+
+        core_ids = pcap_status['core_ids']
+        for wk in pcap_status['workers']:
+            if wk['core_id'] in core_ids:
+                core_ids.remove(wk['core_id'])
+        self.unused_core_ids = core_ids  # used while completion to exclude
+
+        self.workers = pcap_status['workers']
+        self.worker_names = [attr['role'] for attr in pcap_status['workers']]
+
+    def run(self, cmdline):
+        """Called from do_sec() to Send command to secondary process."""
+
+        # update status each time if configured not to use cache
+        if self.use_cache is False:
+            pcap_status = self._get_status(self.sec_id)
+
+            core_ids = pcap_status['core_ids']
+            for wk in pcap_status['workers']:
+                if wk['core_id'] in core_ids:
+                    core_ids.remove(wk['core_id'])
+            self.unused_core_ids = core_ids  # used while completion to exclude
+
+            self.workers = pcap_status['workers']
+            self.worker_names = [attr['role']
+                                 for attr in pcap_status['workers']]
+
+        cmd = cmdline.split(' ')[0]
+        params = cmdline.split(' ')[1:]
+
+        if cmd == 'status':
+            res = self.spp_ctl_cli.get('pcaps/%d' % self.sec_id)
+            if res is not None:
+                error_codes = self.spp_ctl_cli.rest_common_error_codes
+                if res.status_code == 200:
+                    self.print_status(res.json())
+                elif res.status_code in error_codes:
+                    pass
+                else:
+                    print('Error: unknown response.')
+
+        elif cmd == 'start':
+            req_params = {'action': 'start'}
+            res = self.spp_ctl_cli.put('pcaps/%d/capture'
+                                       % (self.sec_id), req_params)
+            if res is not None:
+                error_codes = self.spp_ctl_cli.rest_common_error_codes
+                if res.status_code == 204:
+                    print("Start packet capture.")
+                elif res.status_code in error_codes:
+                    pass
+                else:
+                    print('Error: unknown response.')
+
+        elif cmd == 'stop':
+            req_params = {'action': 'stop'}
+            res = self.spp_ctl_cli.put('pcaps/%d/capture'
+                                       % (self.sec_id), req_params)
+            if res is not None:
+                error_codes = self.spp_ctl_cli.rest_common_error_codes
+                if res.status_code == 204:
+                    print("Stop packet capture.")
+                elif res.status_code in error_codes:
+                    pass
+                else:
+                    print('Error: unknown response.')
+
+        elif cmd == 'exit':
+            res = self.spp_ctl_cli.delete('pcaps/%d' % (self.sec_id))
+            if res is not None:
+                error_codes = self.spp_ctl_cli.rest_common_error_codes
+                if res.status_code == 204:
+                    print("Exit pcap %d." % (self.sec_id))
+                elif res.status_code in error_codes:
+                    pass
+                else:
+                    print('Error: unknown response.')
+
+        else:
+            print('Invalid command "%s".' % cmd)
+
+    def print_status(self, json_obj):
+        """Parse and print message from SPP PCAP.
+
+        Print status received from spp_pcap.
+
+          spp > pcap 1; status
+            - client-id: 3
+            - satus: running
+            - core:2, receive
+              - rx: phy:0
+            - core:3, write
+              - file: /tmp/spp_pcap.20181108110600.phy0.1.1.pcap
+            - core:4, write
+              - file: /tmp/spp_pcap.20181108110600.phy0.2.1.pcap
+            - core:5, write
+              - file: /tmp/spp_pcap.20181108110600.phy0.3.1.pcap
+            ...
+
+        """
+
+        # client id and status
+        print('  - client-id: %d' % json_obj['client-id'])
+        print('  - status: %s' % json_obj['status'])
+
+        # Core
+        for worker in json_obj['core']:
+            if 'role' in worker.keys():
+                print("  - core:%d %s" % (
+                        worker['core'], worker['role']))
+
+                if worker['role'] == 'receive':
+                    pt = worker['rx_port'][0]['port']
+                    msg = '    - %s:%s'
+                    print(msg % ('rx', pt))
+                else:
+                    print('    - filename: %s' % worker['filename'])
+
+    def complete(self, sec_ids, text, line, begidx, endidx):
+        """Completion for spp_pcap commands.
+
+        Called from complete_pcap() to complete.
+        """
+
+        try:
+            completions = []
+            tokens = line.split(';')
+
+            if len(tokens) == 2:
+                sub_tokens = tokens[1].split(' ')
+
+                if len(sub_tokens) == 1:
+                    if not (sub_tokens[0] in self.PCAP_CMDS.keys()):
+                        completions = self._compl_first_tokens(sub_tokens[0])
+                else:
+                    if sub_tokens[0] == 'status':
+                        if len(sub_tokens) < 2:
+                            if 'status'.startswith(sub_tokens[1]):
+                                completions = ['status']
+
+                    elif sub_tokens[0] == 'start':
+                        if len(sub_tokens) < 2:
+                            if 'start'.startswith(sub_tokens[1]):
+                                completions = ['start']
+
+                    elif sub_tokens[0] == 'stop':
+                        if len(sub_tokens) < 2:
+                            if 'stop'.startswith(sub_tokens[1]):
+                                completions = ['stop']
+            return completions
+        except Exception as e:
+            print(e)
+
+    def _compl_first_tokens(self, token):
+        res = []
+        for kw in self.PCAP_CMDS.keys():
+            if kw.startswith(token):
+                res.append(kw)
+        return res
+
+    def _get_status(self, sec_id):
+        """Get status of spp_pcap.
+
+        To update status of the instance of SppPcap, get the status from
+        spp-ctl. This method returns the result as a dict. For considering
+        behaviour of spp_pcap, it is enough to return worker's name and core
+        IDs as the status, but might need to be update for future updates.
+
+        # return worker's role and used core IDs, and all of core IDs.
+        {
+          'workers': [
+            {'role': 'receive', 'core_id': 5},
+            {'role': 'write', 'core_id': 6},
+            ...
+          ],
+          'core_ids': [5, 6, 7, ...]
+        }
+
+        """
+
+        status = {'workers': [], 'core_ids': []}
+        res = self.spp_ctl_cli.get('pcaps/%d' % self.sec_id)
+        if res is not None:
+            if res.status_code == 200:
+                json_obj = res.json()
+
+                if 'core' in json_obj.keys():
+                    for wk in json_obj['core']:
+                        if 'core' in wk.keys():
+                            if 'role' in wk.keys():
+                                status['workers'].append(
+                                        {'role': wk['role'],
+                                         'core_id': wk['core']})
+                            status['core_ids'].append(wk['core'])
+
+        return status
-- 
2.17.1

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [spp] [PATCH v2 7/7] controller: add pcap command to SPP controller
       [not found] <20190208084438.7952-1-x-fn-spp@sl.ntt-tx.co.jp>
                   ` (5 preceding siblings ...)
  2019-02-08  8:44 ` [spp] [PATCH v2 6/7] controller: add SppPcap class x-fn-spp
@ 2019-02-08  8:44 ` x-fn-spp
  6 siblings, 0 replies; 7+ messages in thread
From: x-fn-spp @ 2019-02-08  8:44 UTC (permalink / raw)
  To: ferruh.yigit, ogawa.yasufumi; +Cc: spp

From: Hideyuki Yamashita <yamashita.hideyuki@po.ntt-tx.co.jp>

This update is to 'pcap' command to Shell class for managing
spp_pcap from SPP CLI. Spp_pcap might have several instances, and
deciding which of ones is also similar to other secondary processes.
'pcap' command consists of an indicator and actual command. Here is
an example.

  spp > pcap 3; start

In this example, indicator 'pcap 3;' is before spp_pcap's command
'capture start'. The number in indicator is a secondary ID actually,
so you cannot assign the same ID of others.

You can refer the usage of 'pcap' command with 'help' command.

  spp > help pcap

Signed-off-by: Hideyuki Yamashita <yamashita.hideyuki@po.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 src/controller/shell.py | 87 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 84 insertions(+), 3 deletions(-)

diff --git a/src/controller/shell.py b/src/controller/shell.py
index f1381b7..a695833 100644
--- a/src/controller/shell.py
+++ b/src/controller/shell.py
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2015-2016 Intel Corporation
+# Copyright(c) 2015-2019 Intel Corporation
 
 from __future__ import absolute_import
 
@@ -11,6 +11,7 @@ from .commands import server
 from .commands import topo
 from .commands import vf
 from .commands import mirror
+from .commands import pcap
 import os
 import re
 import readline
@@ -116,6 +117,10 @@ class Shell(cmd.Cmd, object):
             self.secondaries['mirror'][sec_id] = mirror.SppMirror(
                     self.spp_ctl_cli, sec_id)
 
+        self.spp_pcaps = {}
+        for sec_id in self.get_sec_ids('pcap'):
+            self.spp_pcaps[sec_id] = pcap.SppPcap(self.spp_ctl_cli, sec_id)
+
     # Called everytime after running command. `stop` is returned from `do_*`
     # method and SPP CLI is terminated if it is True. It means that only
     # `do_bye` and  `do_exit` return True.
@@ -149,7 +154,7 @@ class Shell(cmd.Cmd, object):
     def get_sec_ids(self, ptype):
         """Return a list of IDs of running secondary processes.
 
-        'ptype' is 'nfv', 'vf' or 'mirror'.
+        'ptype' is 'nfv', 'vf' or 'mirror' or 'pcap'.
         """
 
         ids = []
@@ -176,6 +181,7 @@ class Shell(cmd.Cmd, object):
                 sec_obj['nfv'] = []
                 sec_obj['vf'] = []
                 sec_obj['mirror'] = []
+                sec_obj['pcap'] = []
 
                 for proc_obj in proc_objs:
                     if proc_obj['type'] == 'primary':
@@ -192,7 +198,7 @@ class Shell(cmd.Cmd, object):
                 print('- secondary:')
                 print('  - processes:')
                 cnt = 1
-                for pt in ['nfv', 'vf', 'mirror']:
+                for pt in ['nfv', 'vf', 'mirror', 'pcap']:
                     for obj in sec_obj[pt]:
                         print('    %d: %s:%s' %
                               (cnt, obj['type'], obj['client-id']))
@@ -575,6 +581,81 @@ class Shell(cmd.Cmd, object):
                 return self.secondaries['mirror'][idx].complete(
                         self.get_sec_ids('mirror'), text, line, begidx, endidx)
 
+    def do_pcap(self, cmd):
+        """Send a command to spp_pcap.
+
+        spp_pcap is a secondary process for duplicating incoming
+        packets to be used as similar to TaaS in OpenStack. This
+        command has four sub commands.
+          * status
+          * start
+          * stop
+          * exit
+
+        Each of sub commands other than 'status' takes several parameters
+        for detailed operations. Notice that 'start' for launching a worker
+        is replaced with 'stop' for terminating. 'exit' for spp_pcap
+        terminating.
+
+        Examples:
+
+        # (1) show status of worker threads and resources
+        spp > pcap 1; status
+
+        # (2) launch capture thread
+        spp > pcap 1; start
+
+        # (3) terminate capture thread
+        spp > pcap 1; stop
+
+        # (4) terminate spp_pcap secondaryd
+        spp > pcap 1; exit
+        """
+
+        # remove unwanted spaces to avoid invalid command error
+        tmparg = self.clean_cmd(cmd)
+        cmds = tmparg.split(';')
+        if len(cmds) < 2:
+            print("Required an ID and ';' before the command.")
+        elif str.isdigit(cmds[0]):
+            self.spp_pcaps[int(cmds[0])].run(cmds[1])
+        else:
+            print('Invalid command: %s' % tmparg)
+
+    def complete_pcap(self, text, line, begidx, endidx):
+        """Completion for pcap command"""
+
+        line = self.clean_cmd(line)
+
+        tokens = line.split(';')
+        if len(tokens) == 1:
+            # Add SppPcap of sec_id if it is not exist
+            sec_ids = self.get_sec_ids('pcap')
+            for idx in sec_ids:
+                if self.spp_pcaps[idx] is None:
+                    self.spp_pcaps[idx] = pcap.SppPcap(self.spp_ctl_cli, idx)
+
+            if len(line.split()) == 1:
+                res = [str(i)+';' for i in sec_ids]
+            else:
+                if not (';' in line):
+                    res = [str(i)+';'
+                           for i in sec_ids
+                           if (str(i)+';').startswith(text)]
+            return res
+        elif len(tokens) == 2:
+            # Split tokens like as from 'pcap 1' to ['pcap', '1']
+            first_tokens = tokens[0].split(' ')
+            if len(first_tokens) == 2:
+                idx = int(first_tokens[1])
+
+                # Add SppPcap of sec_id if it is not exist
+                if self.spp_pcaps[idx] is None:
+                    self.spp_pcaps[idx] = pcap.SppPcap(self.spp_ctl_cli, idx)
+
+                return self.spp_pcaps[idx].complete(
+                        self.get_sec_ids('pcap'), text, line, begidx, endidx)
+
     def do_record(self, fname):
         """Save commands as a recipe file.
 
-- 
2.17.1

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2019-02-08  8:46 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20190208084438.7952-1-x-fn-spp@sl.ntt-tx.co.jp>
2019-02-08  8:44 ` [spp] [PATCH v2 1/7] spp_pcap: add command main x-fn-spp
2019-02-08  8:44 ` [spp] [PATCH v2 2/7] spp_pcap: add command decode x-fn-spp
2019-02-08  8:44 ` [spp] [PATCH v2 3/7] spp_pcap: add management function x-fn-spp
2019-02-08  8:44 ` [spp] [PATCH v2 4/7] spp_pcap: add spp_pcap main function x-fn-spp
2019-02-08  8:44 ` [spp] [PATCH v2 5/7] spp_pcap: add Makefile for spp_pcap x-fn-spp
2019-02-08  8:44 ` [spp] [PATCH v2 6/7] controller: add SppPcap class x-fn-spp
2019-02-08  8:44 ` [spp] [PATCH v2 7/7] controller: add pcap command to SPP controller x-fn-spp

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).