[spp] [PATCH 24/57] spp_vf: split command processing source file

x-fn-spp at sl.ntt-tx.co.jp x-fn-spp at sl.ntt-tx.co.jp
Thu Dec 28 05:55:31 CET 2017


From: Hiroyuki Nakamura <nakamura.hioryuki at po.ntt-tx.co.jp>

* For better maintainability,
  split 1 source file into 3 files(acceptance, decode, and utility).

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01 at as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi at lab.ntt.co.jp>
---
 src/vf/Makefile        |   2 +-
 src/vf/command_conn.c  | 136 ++++++++
 src/vf/command_conn.h  |  63 ++++
 src/vf/command_dec.c   | 433 +++++++++++++++++++++++++
 src/vf/command_dec.h   | 110 +++++++
 src/vf/command_proc.c  | 866 ++++++++++++++-----------------------------------
 src/vf/string_buffer.c |  90 +++++
 src/vf/string_buffer.h |  16 +
 8 files changed, 1097 insertions(+), 619 deletions(-)
 create mode 100644 src/vf/command_conn.c
 create mode 100644 src/vf/command_conn.h
 create mode 100644 src/vf/command_dec.c
 create mode 100644 src/vf/command_dec.h
 create mode 100644 src/vf/string_buffer.c
 create mode 100644 src/vf/string_buffer.h

diff --git a/src/vf/Makefile b/src/vf/Makefile
index 19617f6..1284733 100644
--- a/src/vf/Makefile
+++ b/src/vf/Makefile
@@ -40,7 +40,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 APP = spp_vf
 
 # all source are stored in SRCS-y
-SRCS-y := spp_vf.c spp_config.c classifier_mac.c spp_forward.c command_proc.c ringlatencystats.c ../shared/common.c
+SRCS-y := spp_vf.c spp_config.c classifier_mac.c spp_forward.c string_buffer.c command_conn.c command_dec.c command_proc.c ringlatencystats.c ../shared/common.c
 
 CFLAGS += $(WERROR_FLAGS) -O3
 CFLAGS += -I$(SRCDIR)/../shared
diff --git a/src/vf/command_conn.c b/src/vf/command_conn.c
new file mode 100644
index 0000000..edd4d4c
--- /dev/null
+++ b/src/vf/command_conn.c
@@ -0,0 +1,136 @@
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <rte_log.h>
+#include <rte_branch_prediction.h>
+
+#include "string_buffer.h"
+#include "command_conn.h"
+
+#define RTE_LOGTYPE_SPP_COMMAND_PROC RTE_LOGTYPE_USER1
+
+/* one receive message size */
+#define MESSAGE_BUFFER_BLOCK_SIZE 2048
+
+/* controller's ip address */
+static char g_controller_ip[128] = "";
+
+/* controller's port number */
+static int g_controller_port = 0;
+
+/* initialize command connection */
+int
+spp_command_conn_init(const char *controller_ip, int controller_port)
+{
+	strcpy(g_controller_ip, controller_ip);
+	g_controller_port = controller_port;
+
+	return 0;
+}
+
+/* connect to controller */
+int
+spp_connect_to_controller(int *sock)
+{
+	static struct sockaddr_in controller_addr;
+	int ret = -1;
+	int sock_flg = 0;
+
+	if (likely(*sock >=0))
+		return 0;
+
+	/* create socket */
+	if (*sock < 0) {
+		RTE_LOG(INFO, SPP_COMMAND_PROC, "Creating socket...\n");
+		*sock = socket(AF_INET, SOCK_STREAM, 0);
+		if (*sock < 0) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC, 
+					"Cannot create tcp socket. errno=%d\n", errno);
+			return -1;
+		}
+
+		memset(&controller_addr, 0, sizeof(controller_addr));
+		controller_addr.sin_family = AF_INET;
+		controller_addr.sin_addr.s_addr = inet_addr(g_controller_ip);
+		controller_addr.sin_port = htons(g_controller_port);
+	}
+
+	/* connect to */
+	RTE_LOG(INFO, SPP_COMMAND_PROC, "Trying to connect ... socket=%d\n", *sock);
+	ret = connect(*sock, (struct sockaddr *)&controller_addr,
+			sizeof(controller_addr));
+	if (ret < 0) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"Cannot connect to controller. errno=%d\n", errno);
+		return -1;
+	}
+
+	RTE_LOG(INFO, SPP_COMMAND_PROC, "Connected\n");
+
+	/* set non-blocking */
+	sock_flg = fcntl(*sock, F_GETFL, 0);
+	fcntl(*sock, F_SETFL, sock_flg | O_NONBLOCK);
+
+	return 0;
+}
+
+/* receive message */
+int
+spp_receive_message(int *sock, char **strbuf)
+{
+	int ret = -1;
+	int n_rx = 0;
+	char *new_strbuf = NULL;
+
+	char rx_buf[MESSAGE_BUFFER_BLOCK_SIZE];
+	size_t rx_buf_sz = MESSAGE_BUFFER_BLOCK_SIZE;
+
+	ret = recv(*sock, rx_buf, rx_buf_sz, 0);
+	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Receive message. count=%d\n", ret);
+	if (ret <= 0) {
+		if (ret == 0) {
+			RTE_LOG(INFO, SPP_COMMAND_PROC,
+					"Controller has performed an shutdown.");
+		} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
+			/* no receive message */
+			return 0;
+		} else {
+			RTE_LOG(ERR, SPP_COMMAND_PROC,
+					"Receive failure. errno=%d\n", errno);
+		}
+
+		RTE_LOG(INFO, SPP_COMMAND_PROC, "Assume Server closed connection\n");
+		close(*sock);
+		*sock = -1;
+		return -1;
+	}
+
+	n_rx = ret;
+
+	new_strbuf = spp_strbuf_append(*strbuf, rx_buf, n_rx);
+	if (unlikely(new_strbuf == NULL)) {
+		return -1;
+	}
+
+	*strbuf = new_strbuf;
+
+	return n_rx;
+}
+
+/* send message */
+int
+spp_send_message(int *sock, const char* message, size_t message_len)
+{
+	int ret = -1;
+
+	ret = send(*sock, message, message_len, 0);
+	if (unlikely(ret == -1)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Send failure. ret=%d\n", ret);
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/src/vf/command_conn.h b/src/vf/command_conn.h
new file mode 100644
index 0000000..0136d75
--- /dev/null
+++ b/src/vf/command_conn.h
@@ -0,0 +1,63 @@
+#ifndef _COMMAND_CONN_H_
+#define _COMMAND_CONN_H_
+
+/**
+ * intialize command connection.
+ *
+ * @param controller_ip
+ *  controller listen ip address.
+ *
+ * @param controller_port
+ *  controller listen port number.
+ *
+ * @ret_val 0 succeeded.
+ * @ret_val -1 failed.
+ */
+int spp_command_conn_init(const char *controller_ip, int controller_port);
+
+/**
+ * connect to controller.
+ *
+ * @note bocking.
+ *
+ * @param sock
+ *  socket that connect to controller.
+ *
+ * @ret_val 0 succeeded.
+ * @ret_val -1 failed.
+ */
+int spp_connect_to_controller(int *sock);
+
+/**
+ * receive message.
+ *
+ * @note non-blocking.
+ *
+ * @param sock
+ *  socket that read data.
+ *
+ * @ret_val 0 succeeded.
+ * @ret_val -1 failed.
+ */
+int spp_receive_message(int *sock, char **msgbuf);
+
+/**
+ * send message.
+ *
+ * @note non-blocking.
+ *
+ * @param sock
+ *  socket that write data.
+ *
+ * @param message
+ *  send data.
+ *
+ * @param message_len
+ *  send data length.
+ *
+ * @ret_val 0 succeeded.
+ * @ret_val -1 failed.
+ */
+int spp_send_message(int *sock, const char* message, size_t message_len);
+
+#endif /* _COMMAND_CONN_H_ */
diff --git a/src/vf/command_dec.c b/src/vf/command_dec.c
new file mode 100644
index 0000000..85f935b
--- /dev/null
+++ b/src/vf/command_dec.c
@@ -0,0 +1,433 @@
+#include <unistd.h>
+#include <string.h>
+
+#include <rte_log.h>
+#include <rte_branch_prediction.h>
+
+#include <jansson.h>
+
+#include "spp_vf.h"
+#include "spp_config.h"
+#include "command_dec.h"
+
+#define RTE_LOGTYPE_SPP_COMMAND_PROC RTE_LOGTYPE_USER1
+
+/* command type string list
+	do it same as the order of enum command_type */
+static const char *COMMAND_TYPE_STRINGS[] = {
+#if 0 /* not supported yet */
+	"add",
+	"component",
+#endif
+	"classifier_table",
+	"flush",
+#if 0 /* not supported yet */
+	"forward",
+	"stop",
+#endif
+	"process",
+
+	/* termination */ "",
+};
+
+/* classifier type string list
+	do it same as the order of enum spp_classifier_type (spp_vf.h) */
+static const char *CLASSIFILER_TYPE_STRINGS[] = {
+	"none",
+	"mac",
+
+	/* termination */ "",
+};
+
+/* forward declaration */
+struct json_value_decode_rule;
+
+/* definition of decode procedure function */
+typedef int (*json_value_decode_proc)(
+		void *, 
+		const json_t *, 
+		const struct json_value_decode_rule *, 
+		struct spp_command_decode_error *);
+
+/* rule definition that decode json object to c-struct */
+struct json_value_decode_rule {
+	char name[SPP_CMD_NAME_BUFSZ];
+	json_type json_type;
+	size_t offset;
+	json_value_decode_proc decode_proc;
+
+	struct {
+		json_type json_type;
+		size_t element_sz;
+		size_t offset_num;
+		size_t offset_num_valid;
+	} array;
+};
+
+/* get output address for decoded json value */
+#define DR_GET_OUTPUT(output_base, rule__) ((char *)output_base + rule__->offset)
+
+/* set decode error */
+inline int
+set_decode_error(struct spp_command_decode_error *error,
+		int error_code,
+		const struct json_value_decode_rule *error_rule)
+{
+	error->code = error_code;
+
+	if (likely(error_rule != NULL))
+		strcpy(error->value_name, error_rule->name);
+
+	return error->code;
+}
+
+/* set decode error */
+inline int
+set_string_value_decode_error(struct spp_command_decode_error *error,
+		const char* value,
+		const struct json_value_decode_rule *error_rule)
+{
+	strcpy(error->value, value);
+	return set_decode_error(error, SPP_CMD_DERR_BAD_VALUE, error_rule);
+}
+
+/* helper */
+#define END_OF_DECODE_RULE {.name = ""},
+#define IS_END_OF_DECODE_RULE(rule) ((rule)->name[0] == '\0')
+
+/* definition helper that enum value decode procedure */
+#define DECODE_ENUM_VALUE(proc_name, enum_type, string_table)			\
+static int									\
+decode_##proc_name##_value(void *output, const json_t *value_obj,		\
+		const struct json_value_decode_rule *rule,			\
+		struct spp_command_decode_error *error)				\
+{										\
+	int i;									\
+	enum_type type;								\
+	const char *str_val = json_string_value(value_obj);			\
+										\
+	for (i = 0; string_table[i][0] != '\0'; ++i) {				\
+		if (unlikely(strcmp(str_val, string_table[i]) == 0)) {		\
+			type = i;						\
+			memcpy(output, &type, sizeof(enum_type));		\
+			return 0;						\
+		}								\
+	}									\
+										\
+	return set_string_value_decode_error(error, str_val, rule);		\
+}										\
+
+/* enum value decode procedure for "command_type" */
+DECODE_ENUM_VALUE(command_type, enum spp_command_type, COMMAND_TYPE_STRINGS)
+
+/* enum value decode procedure for "classifier_type" */
+DECODE_ENUM_VALUE(classifier_type, enum spp_classifier_type, CLASSIFILER_TYPE_STRINGS)
+
+#if 0 /* not supported yet */
+/* decode procedure for integer */
+static int
+decode_int_value(void *output, const json_t *value_obj,
+		__rte_unused const struct json_value_decode_rule *rule,
+		__rte_unused struct spp_command_decode_error *error)
+{
+	int val = json_integer_value(value_obj);
+	memcpy(output, &val, sizeof(int));
+
+	return 0;
+}
+
+/* decode procedure for string */
+static int
+decode_string_value(void *output, const json_t *value_obj,
+		__rte_unused const struct json_value_decode_rule *rule,
+		__rte_unused struct spp_command_decode_error *error)
+{
+	const char* str_val = json_string_value(value_obj);
+	strcpy(output, str_val);
+
+	return 0;
+}
+#endif
+
+/* decode procedure for mac address string */
+static int
+decode_mac_addr_str_value(void *output, const json_t *value_obj,
+		const struct json_value_decode_rule *rule,
+		struct spp_command_decode_error *error)
+{
+	int ret = -1;
+	const char* str_val = json_string_value(value_obj);
+
+	ret = spp_config_change_mac_str_to_int64(str_val);
+	if (unlikely(ret == -1)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad mac address string. val=%s\n",
+				str_val);
+		return set_string_value_decode_error(error, str_val, rule);
+	}
+
+	strcpy(output, str_val);
+
+	return 0;
+}
+
+/* decode procedure for spp_config_port_info */
+static int
+decode_port_value(void *output, const json_t *value_obj,
+		const struct json_value_decode_rule *rule,
+		struct spp_command_decode_error *error)
+{
+	int ret = -1;
+	const char* str_val = json_string_value(value_obj);
+	struct spp_config_port_info *port = (struct spp_config_port_info *)output;
+
+	if (strcmp(str_val, SPP_CMD_UNUSE) == 0) {
+		port->if_type = UNDEF;
+		port->if_no = 0;
+		return 0;
+	}
+
+	ret = spp_config_get_if_info(str_val, &port->if_type, &port->if_no);
+	if (unlikely(ret != 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad port. val=%s\n", str_val);
+		return set_string_value_decode_error(error, str_val, rule);
+	}
+
+	return 0;
+}
+
+/* decode json object */
+static int
+decode_json_object(void *output, const json_t *parent_obj,
+		const struct json_value_decode_rule *rules,
+		struct spp_command_decode_error *error)
+{
+	int ret = -1;
+	int i, n;
+	json_t *obj;
+	json_t *value_obj;
+	const struct json_value_decode_rule *rule;
+
+	void *sub_output;
+
+	for (i = 0; unlikely(! IS_END_OF_DECODE_RULE(&rules[i])); ++ i) {
+		rule = rules + i;
+
+		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Get one object. name=%s\n",
+				rule->name);
+
+		value_obj = json_object_get(parent_obj, rule->name);
+		if (unlikely(value_obj == NULL)) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC, "No parameter. "
+					"name=%s\n", rule->name);
+			return set_decode_error(error, SPP_CMD_DERR_NO_PARAM, rule);
+		} else if (unlikely(json_typeof(value_obj) != rule->json_type)) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value type. "
+					"name=%s\n", rule->name);
+			return set_decode_error(error, SPP_CMD_DERR_BAD_TYPE, rule);
+		}
+
+		switch (rule->json_type) {
+		case JSON_ARRAY:
+			RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Decode array. num=%lu\n",
+					json_array_size(value_obj));
+
+			*(int *)((char *)output + rule->array.offset_num) = 
+					(int)json_array_size(value_obj);
+
+			json_array_foreach(value_obj, n, obj) {
+				RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Decode array element. "
+						"index=%d\n", n);
+				
+				if (unlikely(json_typeof(obj) != rule->array.json_type)) {
+					RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value type. "
+							"name=%s, index=%d\n", rule->name, n);
+					return set_decode_error(error, SPP_CMD_DERR_BAD_TYPE, rule);
+				}
+
+				sub_output = DR_GET_OUTPUT(output, rule) + 
+						(rule->array.element_sz * n);
+				ret = (*rule->decode_proc)(sub_output, obj, rule, error);
+				if (unlikely(ret != 0)) {
+					RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value. "
+							"name=%s, index=%d\n", rule->name, n);
+					/* decode error is set in decode function */
+					return ret;
+				}
+
+				*(int *)((char *)output +
+						rule->array.offset_num_valid) = n + 1;
+			}
+			break;
+		default:
+			sub_output = DR_GET_OUTPUT(output, rule);
+			ret = (*rule->decode_proc)(sub_output, value_obj, rule, error);
+			if (unlikely(ret != 0)) {
+				RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value. "
+						"name=%s\n", rule->name);
+				/* decode error is set in decode function */
+				return ret;
+			}
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/* decode rule for command-base */
+const struct json_value_decode_rule DECODERULE_COMMAND_BASE[] = {
+	{
+		.name = "command",
+		.json_type = JSON_STRING,
+		.offset = offsetof(struct spp_command, type),
+		.decode_proc = decode_command_type_value,
+	},
+	END_OF_DECODE_RULE
+};
+
+#if 0 /* not supported yet */
+/* decode rule for add-command-spec */
+const struct json_value_decode_rule DECODERULE_ADD_COMMAND[] = {
+	{
+		.name = "ports",
+		.json_type = JSON_ARRAY,
+		.offset = offsetof(struct spp_command_add, ports),
+		.decode_proc = decode_port_value,
+
+		.array.element_sz = sizeof(struct spp_config_port_info),
+		.array.json_type = JSON_STRING,
+		.array.offset_num = offsetof(struct spp_command_add, num_port),
+	},
+	END_OF_DECODE_RULE
+};
+#endif
+
+/* decode rule for classifier-table-command-spec */
+const struct json_value_decode_rule DECODERULE_CLASSIFIER_TABLE_COMMAND[] = {
+	{
+		.name = "type",
+		.json_type = JSON_STRING,
+		.offset = offsetof(struct spp_command_classifier_table, type),
+		.decode_proc = decode_classifier_type_value,
+	},{
+		.name = "value",
+		.json_type = JSON_STRING,
+		.offset = offsetof(struct spp_command_classifier_table, value),
+		.decode_proc = decode_mac_addr_str_value,
+	},{
+		.name = "port",
+		.json_type = JSON_STRING,
+		.offset = offsetof(struct spp_command_classifier_table, port),
+		.decode_proc = decode_port_value,
+	},
+	END_OF_DECODE_RULE
+};
+
+/* decode procedure for command */
+static int
+decode_command_object(void* output, const json_t *parent_obj,
+		__rte_unused const struct json_value_decode_rule *rule,
+		struct spp_command_decode_error *error)
+{
+	int ret = -1;
+	struct spp_command *command = (struct spp_command *)output;
+	const struct json_value_decode_rule *spec_rules = NULL;
+
+	/* decode command-base */
+	ret = decode_json_object(command, parent_obj, DECODERULE_COMMAND_BASE, error);
+	if (unlikely(ret != 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad command. ret=%d\n", ret);
+		/* decode error is set in decode_json_object function */
+		return ret;
+	}
+
+	/* decode command-specific */
+	switch (command->type) {
+		case SPP_CMDTYPE_CLASSIFIER_TABLE:
+			spec_rules = DECODERULE_CLASSIFIER_TABLE_COMMAND;
+			break;
+
+		case SPP_CMDTYPE_FLUSH:
+			/* nothing specific */
+			break;
+
+		default:
+			/* unknown command */
+			RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown command. type=%d\n",
+					command->type);
+			return set_decode_error(error, SPP_CMD_DERR_UNKNOWN_COMMAND, rule);
+	}
+
+	if (likely(spec_rules != NULL)) {
+		ret = decode_json_object(&command->spec, parent_obj, spec_rules, error);
+		if (unlikely(ret != 0)) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad command. ret=%d\n", ret);
+			/* decode error is set in decode_json_object function */
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/* decode rule for command request */
+const struct json_value_decode_rule DECODERULE_REQUEST[] = {
+	{
+		.name = "commands",
+		.json_type = JSON_ARRAY,
+		.offset = offsetof(struct spp_command_request, commands),
+		.decode_proc = decode_command_object,
+
+		.array.element_sz = sizeof(struct spp_command),
+		.array.json_type = JSON_OBJECT,
+		.array.offset_num = offsetof(struct spp_command_request, num_command),
+		.array.offset_num_valid = offsetof(struct spp_command_request, num_valid_command),
+	},
+	END_OF_DECODE_RULE
+};
+
+/* decode request from no-null-terminated string */
+int
+spp_command_decode_request(struct spp_command_request *request, const char *request_str,
+		size_t request_str_len, struct spp_command_decode_error *error)
+{
+	int ret = -1;
+	int i;
+	json_t *top_obj;
+	json_error_t json_error;
+
+	/* parse json string */
+	top_obj = json_loadb(request_str, request_str_len, 0, &json_error);
+	if (unlikely(top_obj == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Cannot parse command request. "
+				"error=%s, request_str=%.*s\n", 
+				json_error.text, (int)request_str_len, request_str);
+		return set_decode_error(error, SPP_CMD_DERR_BAD_FORMAT, NULL);
+	}
+
+	/* decode request object */
+	ret = decode_json_object(request, top_obj, DECODERULE_REQUEST, error);
+	if (unlikely(ret != 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Cannot decode command request. "
+				"ret=%d, request_str=%.*s\n", 
+				ret, (int)request_str_len, request_str);
+		/* decode error is set in decode_json_object function */
+	}
+
+	/* free json object */
+	json_decref(top_obj);
+
+	/* check getter command */
+	for (i = 0; i < request->num_valid_command; ++i) {
+		switch (request->commands[i].type) {
+		case SPP_CMDTYPE_PROCESS:
+			request->is_requested_process = 1;
+			break;
+		default:
+			/* nothing to do */
+			break;
+		}
+	}
+
+	return ret;
+}
diff --git a/src/vf/command_dec.h b/src/vf/command_dec.h
new file mode 100644
index 0000000..25e1ea0
--- /dev/null
+++ b/src/vf/command_dec.h
@@ -0,0 +1,110 @@
+#ifndef _COMMAND_DEC_H_
+#define _COMMAND_DEC_H_
+
+/* max number of command per request */
+#define SPP_CMD_MAX_COMMANDS 32
+
+/* 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 128
+
+/* string that specify unused */
+#define SPP_CMD_UNUSE "unuse"
+
+/* component type */
+#define spp_component_type spp_core_type
+
+/* decode error code */
+enum spp_command_decode_error_code {
+	/* not use 0, in general 0 is ok */
+	SPP_CMD_DERR_BAD_FORMAT = 1,
+	SPP_CMD_DERR_UNKNOWN_COMMAND,
+	SPP_CMD_DERR_NO_PARAM,
+	SPP_CMD_DERR_BAD_TYPE,
+	SPP_CMD_DERR_BAD_VALUE,
+};
+
+/* command type
+	do it same as the order of COMMAND_TYPE_STRINGS */
+enum spp_command_type {
+#if 0 /* not supported yet yet */
+	SPP_CMDTYPE_ADD,
+	SPP_CMDTYPE_COMPONENT,
+#endif
+	SPP_CMDTYPE_CLASSIFIER_TABLE,
+	SPP_CMDTYPE_FLUSH,
+#if 0 /* not supported yet */
+	SPP_CMDTYPE_FORWARD,
+	SPP_CMDTYPE_STOP,
+#endif
+	SPP_CMDTYPE_PROCESS,
+};
+
+#if 0 /* not supported yet */
+/* "add" command parameters */
+struct spp_command_add {
+	int num_port;
+	struct spp_config_port_info ports[RTE_MAX_ETHPORTS];
+};
+
+/* "component" command specific parameters */
+struct spp_command_component {
+	enum spp_component_type type;
+	unsigned int core_id;
+	int num_rx_port;
+	int num_tx_port;
+	struct spp_config_port_info rx_ports[RTE_MAX_ETHPORTS];
+	struct spp_config_port_info tx_ports[RTE_MAX_ETHPORTS];
+};
+#endif
+
+/* "classifier_table" command specific parameters */
+struct spp_command_classifier_table {
+	enum spp_classifier_type type;
+	char value[SPP_CMD_VALUE_BUFSZ];
+	struct spp_config_port_info port;
+};
+
+/* "flush" command specific parameters */
+struct spp_command_flush {
+	/* nothing specific */
+};
+
+/* command parameters */
+struct spp_command {
+	enum spp_command_type type;
+
+	union {
+#if 0 /* not supported yet */
+		struct spp_command_add add;
+		struct spp_command_component component;
+#endif
+		struct spp_command_classifier_table classifier_table;
+		struct spp_command_flush flush;
+	} spec;
+};
+
+/* request parameters */
+struct spp_command_request {
+	int num_command;
+	int num_valid_command;
+	struct spp_command commands[SPP_CMD_MAX_COMMANDS];
+
+	int is_requested_process;
+};
+
+/* decode error information */
+struct spp_command_decode_error {
+	int code;
+	char value_name[SPP_CMD_NAME_BUFSZ];
+	char value[SPP_CMD_VALUE_BUFSZ];
+};
+
+/* decode request from no-null-terminated string */
+int spp_command_decode_request(struct spp_command_request *request,
+		const char *request_str, size_t request_str_len,
+		struct spp_command_decode_error *error);
+
+#endif /* _COMMAND_DEC_H_ */
diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index bec762e..097483c 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -1,12 +1,6 @@
 #include <unistd.h>
-#include <sys/types.h>
-#include <stdio.h>
 #include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <arpa/inet.h>
 
-#include <rte_common.h>
 #include <rte_log.h>
 #include <rte_branch_prediction.h>
 
@@ -14,723 +8,362 @@
 
 #include "spp_vf.h"
 #include "spp_config.h"
+#include "string_buffer.h"
+#include "command_conn.h"
+#include "command_dec.h"
 #include "command_proc.h"
 
 #define RTE_LOGTYPE_SPP_COMMAND_PROC RTE_LOGTYPE_USER1
 
+/* request message initial size */
+#define MESSAGE_BUFFER_BLOCK_SIZE 2048
 
-/*******************************************************************************
- *
- * operate connection with controller
- *
- ******************************************************************************/
-
-/* receive message buffer size */
-#define MESSAGE_BUFFER_BLOCK_SIZE 512
-
-/* controller's ip address */
-static char g_controller_ip[128] = "";
+/* command execution result code */
+enum command_result_code {
+	CRES_SUCCESS = 0,
+	CRES_FAILURE,
+	CRES_INVALID,
+};
 
-/* controller's port number */
-static int g_controller_port = 0;
+/* command execution result information */
+struct command_result {
+	int code;
+};
 
-/* allocate message buffer */
-inline char*
-msgbuf_allocate(size_t capacity)
+/* execute one command */
+static int
+execute_command(const struct spp_command *command)
 {
-	char* buf = (char *)malloc(capacity + sizeof(size_t));
-	if (unlikely(buf == NULL))
-		return NULL;
+	int ret = 0;
 
-	memset(buf, 0x00, capacity + sizeof(size_t));
-	*((size_t *)buf) = capacity;
+	switch (command->type) {
+	case SPP_CMDTYPE_CLASSIFIER_TABLE:
+		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Execute classifier_table command.");
+		ret = spp_update_classifier_table(
+				command->spec.classifier_table.type,
+				command->spec.classifier_table.value,
+				&command->spec.classifier_table.port);
+		break;
 
-	return buf + sizeof(size_t);
-}
+	case SPP_CMDTYPE_FLUSH:
+		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Execute flush command.");
+		ret = spp_flush();
+		break;
 
-/* free message buffer */
-inline void
-msgbuf_free(char* msgbuf)
-{
-	if (likely(msgbuf != NULL))
-		free(msgbuf - sizeof(size_t));
-}
+	case SPP_CMDTYPE_PROCESS:
+		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Process command is requested.");
+		/* nothing to do here */
+		break;
 
-/* get message buffer capacity */
-inline size_t
-msgbuf_get_capacity(const char *msgbuf)
-{
-	return *((const size_t *)(msgbuf - sizeof(size_t)));
+	default:
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown command. type=%d\n", command->type);
+		/* nothing to do here */
+		break;
+	}
+
+	return ret;
 }
 
-/* re-allocate message buffer */
-inline char*
-msgbuf_reallocate(char *msgbuf, size_t required_len)
+/* make decode error message for response */
+static const char *
+make_decode_error_message(const struct spp_command_decode_error *decode_error, char *message)
 {
-	size_t new_cap = msgbuf_get_capacity(msgbuf) * 2;
-	char *new_msgbuf = NULL;
+	switch (decode_error->code) {
+	case SPP_CMD_DERR_BAD_FORMAT:
+		sprintf(message, "bad message format");
+		break;
 
-	while (unlikely(new_cap <= required_len))
-		new_cap *= 2;
+	case SPP_CMD_DERR_UNKNOWN_COMMAND:
+		sprintf(message, "unknown command(%s)", decode_error->value);
+		break;
 
-	new_msgbuf = msgbuf_allocate(new_cap);
-	if (unlikely(new_msgbuf == NULL))
-		return NULL;
+	case SPP_CMD_DERR_NO_PARAM:
+		sprintf(message, "not enough parameter(%s)", decode_error->value_name);
+		break;
 
-	strcpy(new_msgbuf, msgbuf);
-	msgbuf_free(msgbuf);
+	case SPP_CMD_DERR_BAD_TYPE:
+		sprintf(message, "bad value type(%s)", decode_error->value_name);
+		break;
 
-	return new_msgbuf;
-}
+	case SPP_CMD_DERR_BAD_VALUE:
+		sprintf(message, "bad value(%s)", decode_error->value_name);
+		break;
 
-/* append message to buffer */
-inline char*
-msgbuf_append(char *msgbuf, const char *append, size_t append_len)
-{
-	size_t cap = msgbuf_get_capacity(msgbuf);
-	size_t len = strlen(msgbuf);
-	char *new_msgbuf = msgbuf;
-
-	if (unlikely(len + append_len >= cap)) {
-		new_msgbuf = msgbuf_reallocate(msgbuf, len + append_len);
-		if (unlikely(new_msgbuf == NULL))
-			return NULL;
+	default:
+		sprintf(message, "error occur");
+		break;
 	}
 
-	memcpy(new_msgbuf + len, append, append_len);
-	*(new_msgbuf + len + append_len) = '\0';
-
-	return new_msgbuf;
+	return message;
 }
 
-/* remove message from front */
-inline char*
-msgbuf_remove_front(char *msgbuf, size_t remove_len)
+/* create error result object form decode error information */
+inline json_t *
+create_result_object(const char* res_str)
 {
-	size_t len = strlen(msgbuf);
-	size_t new_len = len - remove_len;
-
-	if (likely(new_len == 0)) {
-		*msgbuf = '\0';
-		return msgbuf;
-	}
+	return json_pack("{ss}", "result", res_str);
+}
 
-	return memmove(msgbuf, msgbuf + remove_len, new_len + 1);
+/* create error result object form decode error information */
+inline json_t *
+create_error_result_object(const char* err_msg)
+{
+	return json_pack("{sss{ss}}", "result", "error", "error_details", 
+			"message", err_msg);
 }
 
-/* connect to controller */
+/*  */
 static int
-connect_to_controller(int *sock)
+append_response_decode_results_object(json_t *parent_obj,
+		const struct spp_command_request *request,
+		const struct spp_command_decode_error *decode_error)
 {
-	static struct sockaddr_in controller_addr;
 	int ret = -1;
-	int sock_flg = 0;
-
-	if (likely(*sock >=0))
-		return 0;
-
-	/* create socket */
-	if (*sock < 0) {
-		RTE_LOG(INFO, SPP_COMMAND_PROC, "Creating socket...\n");
-		*sock = socket(AF_INET, SOCK_STREAM, 0);
-		if (*sock < 0) {
-			RTE_LOG(ERR, SPP_COMMAND_PROC, 
-					"Cannot create tcp socket. errno=%d\n", errno);
+	int i;
+	json_t *results_obj;
+	char err_msg[128];
+
+	results_obj = json_array();
+	if (unlikely(results_obj == NULL))
+		return -1;
+
+	if (unlikely(decode_error->code == SPP_CMD_DERR_BAD_FORMAT)) {
+		/* create & append bad message format result */
+		ret = json_array_append_new(results_obj,
+				create_error_result_object(
+				make_decode_error_message(decode_error, err_msg)));
+		if (unlikely(ret != 0)) {
+			json_decref(results_obj);
 			return -1;
 		}
+	} else {
+		/* create & append results */
+		for (i = 0; i < request->num_command; ++i) {
+			ret = json_array_append_new(results_obj, create_result_object("invalid"));
+			if (unlikely(ret != 0)) {
+				json_decref(results_obj);
+				return -1;
+			}
+		}
 
-		memset(&controller_addr, 0, sizeof(controller_addr));
-		controller_addr.sin_family = AF_INET;
-		controller_addr.sin_addr.s_addr = inet_addr(g_controller_ip);
-		controller_addr.sin_port = htons(g_controller_port);
+		/* create & rewrite error result */
+		if (unlikely(request->num_command != request->num_valid_command)) {
+			ret = json_array_set_new(results_obj,
+					request->num_valid_command,
+					create_error_result_object(
+					make_decode_error_message(decode_error, err_msg)));
+			if (unlikely(ret != 0)) {
+				json_decref(results_obj);
+				return -1;
+			}
+		}
 	}
 
-	/* connect to */
-	RTE_LOG(INFO, SPP_COMMAND_PROC, "Trying to connect ... socket=%d\n", *sock);
-	ret = connect(*sock, (struct sockaddr *)&controller_addr,
-			sizeof(controller_addr));
-	if (ret < 0) {
-		RTE_LOG(ERR, SPP_COMMAND_PROC,
-				"Cannot connect to controller. errno=%d\n", errno);
+	/* set results object in parent object */
+	ret = json_object_set_new(parent_obj, "results", results_obj);
+	if (unlikely(ret != 0))
 		return -1;
-	}
-
-	RTE_LOG(INFO, SPP_COMMAND_PROC, "Connected\n");
-
-	/* set non-blocking */
-	sock_flg = fcntl(*sock, F_GETFL, 0);
-	fcntl(*sock, F_SETFL, sock_flg | O_NONBLOCK);
 
 	return 0;
 }
 
-/* receive message */
+/*  */
 static int
-receive_message(int *sock, char **msgbuf)
+append_response_command_results_object(json_t *parent_obj,
+		const struct spp_command_request *request,
+		const struct command_result *results)
 {
 	int ret = -1;
-	int n_rx = 0;
-	char *new_msgbuf = NULL;
-
-	char rx_buf[MESSAGE_BUFFER_BLOCK_SIZE];
-	size_t rx_buf_sz = MESSAGE_BUFFER_BLOCK_SIZE;
-
-	ret = recv(*sock, rx_buf, rx_buf_sz, 0);
-	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Receive message. count=%d\n", ret);
-	if (ret <= 0) {
-		if (ret == 0) {
-			RTE_LOG(INFO, SPP_COMMAND_PROC,
-					"Controller has performed an shutdown.");
-		} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
-			/* no receive message */
-			return 0;
-		} else {
-			RTE_LOG(ERR, SPP_COMMAND_PROC,
-					"Receive failure. errno=%d\n", errno);
-		}
+	int i;
+	json_t *results_obj, *res_obj;
 
-		RTE_LOG(INFO, SPP_COMMAND_PROC, "Assume Server closed connection\n");
-		close(*sock);
-		*sock = -1;
+	results_obj = json_array();
+	if (unlikely(results_obj == NULL))
 		return -1;
-	}
 
-	n_rx = ret;
+	/* create & append results */
+	for (i = 0; i < request->num_command; ++i) {
+		switch (results[i].code) {
+		case CRES_SUCCESS:
+			res_obj = create_result_object("success");
+			break;
+		case CRES_FAILURE:
+			res_obj = create_error_result_object("error occur");
+			break;
+		case CRES_INVALID: /* FALLTHROUGH */
+		default:
+			res_obj = create_result_object("invalid");
+			break;
+		}
 
-	new_msgbuf = msgbuf_append(*msgbuf, rx_buf, n_rx);
-	if (unlikely(new_msgbuf == NULL)) {
-		return -1;
+		ret = json_array_append_new(results_obj, res_obj);
+		if (unlikely(ret != 0)) {
+			json_decref(results_obj);
+			return -1;
+		}
 	}
 
-	*msgbuf = new_msgbuf;
-
-	return n_rx;
-}
-
-/* send message */
-static int
-send_message(int *sock, const char* message, size_t message_len)
-{
-	int ret = -1;
-
-	ret = send(*sock, message, message_len, 0);
-	if (unlikely(ret == -1)) {
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Send failure. ret=%d\n", ret);
+	/* set results object in parent object */
+	ret = json_object_set_new(parent_obj, "results", results_obj);
+	if (unlikely(ret != 0))
 		return -1;
-	}
 
 	return 0;
 }
 
-
-/*******************************************************************************
- *
- * process command request(json string)
- *
- ******************************************************************************/
-
-#define CMD_MAX_COMMANDS 32
-
-#define CMD_NAME_BUFSZ 32
-
-#define CMD_CLASSIFIER_TABLE_VALUE_BUFSZ 62
-
-#define CMD_UNUSE "unuse"
-
-#define component_type spp_core_type
-
-/* decode error code */
-enum decode_error_code {
-	DERR_BAD_FORMAT = 1,
-	DERR_UNKNOWN_COMMAND,
-	DERR_NO_PARAM,
-	DERR_BAD_TYPE,
-	DERR_BAD_VALUE,
-};
-
-/* command type
-	do it same as the order of COMMAND_TYPE_STRINGS */
-enum command_type {
-	CMDTYPE_ADD,
-	CMDTYPE_COMPONENT,
-	CMDTYPE_CLASSIFIER_TABLE,
-	CMDTYPE_FLUSH,
-	CMDTYPE_FORWARD,
-	CMDTYPE_STOP,
-
-	CMDTYPE_PROCESS,
-};
-
-/* command type string list
-	do it same as the order of enum command_type */
-static const char *COMMAND_TYPE_STRINGS[] = {
-	"add",
-	"component",
-	"classifier_table",
-	"flush",
-	"forward",
-	"stop",
-
-	/* termination */ "",
-};
-
-/* classifier type string list
-	do it same as the order of enum spp_classifier_type (spp_vf.h) */
-static const char *CLASSIFILER_TYPE_STRINGS[] = {
-	"none",
-	"mac",
-
-	/* termination */ "",
-};
-
-#if 0 /* not supported */
-/* "add" command parameters */
-struct add_command {
-	int num_port;
-	struct spp_config_port_info ports[RTE_MAX_ETHPORTS];
-};
-
-/* "component" command specific parameters */
-struct component_command {
-	enum component_type type;
-	unsigned int core_id;
-	int num_rx_port;
-	int num_tx_port;
-	struct spp_config_port_info rx_ports[RTE_MAX_ETHPORTS];
-	struct spp_config_port_info tx_ports[RTE_MAX_ETHPORTS];
-};
-#endif
-
-/* "classifier_table" command specific parameters */
-struct classifier_table_command {
-	enum spp_classifier_type type;
-	char value[CMD_CLASSIFIER_TABLE_VALUE_BUFSZ];
-	struct spp_config_port_info port;
-};
-
-/* "flush" command specific parameters */
-struct flush_command {
-	/* nothing specific */
-};
-
-/* command parameters */
-struct command {
-	enum command_type type;
-
-	union {
-#if 0 /* not supported */
-		struct add_command add;
-		struct component_command component;
-#endif
-		struct classifier_table_command classifier_table;
-		struct flush_command flush;
-	} spec;
-};
-
-/* request parameters */
-struct request {
-	int num_command;
-	int num_valid_command;
-	struct command commands[CMD_MAX_COMMANDS];
-};
-
-/* forward declaration */
-struct json_value_decode_rule;
-
-/* definition of decode procedure function */
-typedef int (*json_value_decode_proc)(void *, const json_t *, const struct json_value_decode_rule *);
-
-/* rule definition that decode json object to c-struct */
-struct json_value_decode_rule {
-	char name[CMD_NAME_BUFSZ];
-	json_type json_type;
-	size_t offset;
-	json_value_decode_proc decode_proc;
-
-	struct {
-		json_type json_type;
-		size_t element_sz;
-		size_t offset_num;
-		size_t offset_num_valid;
-	} array;
-};
-
-/* get output address for decoded json value */
-#define DR_GET_OUTPUT(output_base, rule__) ((char *)output_base + rule__->offset)
-
-/* helper */
-#define END_OF_DECODE_RULE {.name = ""},
-#define IS_END_OF_DECODE_RULE(rule) ((rule)->name[0] == '\0')
-
-/* definition helper that enum value decode procedure */
-#define DECODE_ENUM_VALUE(proc_name, enum_type, string_table)			\
-static int									\
-decode_##proc_name##_value(void *output, const json_t *value_obj,		\
-		__rte_unused const struct json_value_decode_rule *rule)		\
-{										\
-	int i;									\
-	enum_type type;								\
-	const char *str_val = json_string_value(value_obj);			\
-										\
-	for (i = 0; string_table[i][0] != '\0'; ++i) {				\
-		if (unlikely(strcmp(str_val, string_table[i]) == 0)) {		\
-			type = i;						\
-			memcpy(output, &type, sizeof(enum_type));		\
-			return 0;						\
-		}								\
-	}									\
-										\
-	return -1;								\
-}										\
-
-/* enum value decode procedure for "command_type" */
-DECODE_ENUM_VALUE(command_type, enum command_type, COMMAND_TYPE_STRINGS)
-
-/* enum value decode procedure for "classifier_type" */
-DECODE_ENUM_VALUE(classifier_type, enum spp_classifier_type, CLASSIFILER_TYPE_STRINGS)
-
-#if 0 /* not supported */
-/* decode procedure for integer */
+/* append process value to specified json object */
 static int
-decode_int_value(void *output, const json_t *value_obj,
-		__rte_unused const struct json_value_decode_rule *rule)
-{
-	int val = json_integer_value(value_obj);
-	memcpy(output, &val, sizeof(int));
-
-	return 0;
-}
-
-/* decode procedure for string */
-static int
-decode_string_value(void *output, const json_t *value_obj,
-		__rte_unused const struct json_value_decode_rule *rule)
-{
-	const char* str_val = json_string_value(value_obj);
-	strcpy(output, str_val);
-
-	return 0;
-}
-#endif
-
-/* decode procedure for mac address string */
-static int
-decode_mac_addr_str_value(void *output, const json_t *value_obj,
-		__rte_unused const struct json_value_decode_rule *rule)
+append_response_process_value(json_t *parent_obj)
 {
 	int ret = -1;
-	const char* str_val = json_string_value(value_obj);
+	json_t *proc_obj;
 
-	ret = spp_config_change_mac_str_to_int64(str_val);
-	if (unlikely(ret == -1)) {
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad mac address string. val=%s\n",
-				str_val);
-		return DERR_BAD_VALUE;
-	}
+	proc_obj = json_integer(spp_get_process_id());
+	if (unlikely(proc_obj == NULL))
+		return -1;
 
-	strcpy(output, str_val);
+	ret = json_object_set_new(parent_obj, "process", proc_obj);
+	if (unlikely(ret != 0))
+		return -1;
 
 	return 0;
 }
 
-/* decode procedure for spp_config_port_info */
-static int
-decode_port_value(void *output, const json_t *value_obj,
-		__rte_unused const struct json_value_decode_rule *rule)
+/* send response for decode error */
+static void
+send_decode_error_response(int *sock, const struct spp_command_request *request,
+		const struct spp_command_decode_error *decode_error)
 {
 	int ret = -1;
-	const char* str_val = json_string_value(value_obj);
-	struct spp_config_port_info *port = (struct spp_config_port_info *)output;
+	char *msg;
+	json_t *top_obj;
 
-	if (strcmp(str_val, CMD_UNUSE) == 0) {
-		port->if_type = UNDEF;
-		port->if_no = 0;
-		return 0;
+	top_obj = json_object();
+	if (unlikely(top_obj == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to make decode error response.");
+		return;
 	}
 
-	ret = spp_config_get_if_info(str_val, &port->if_type, &port->if_no);
+	/* create & append result array */
+	ret = append_response_decode_results_object(top_obj, request, decode_error);
 	if (unlikely(ret != 0)) {
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad port. val=%s\n", str_val);
-		return DERR_BAD_VALUE;
-	}
-
-	return 0;
-}
-
-/* decode json object */
-static int
-decode_json_object(void *output, const json_t *parent_obj,
-		const struct json_value_decode_rule *rules)
-{
-	int ret = -1;
-	int i, n;
-	json_t *obj;
-	json_t *value_obj;
-	const struct json_value_decode_rule *rule;
-
-	void *sub_output;
-
-	for (i = 0; unlikely(! IS_END_OF_DECODE_RULE(&rules[i])); ++ i) {
-		rule = rules + i;
-
-		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "get one object. name=%s\n",
-				rule->name);
-
-		value_obj = json_object_get(parent_obj, rule->name);
-		if (unlikely(value_obj == NULL)) {
-			RTE_LOG(ERR, SPP_COMMAND_PROC, "No parameter. "
-					"name=%s\n", rule->name);
-			return DERR_NO_PARAM;
-		} else if (unlikely(json_typeof(value_obj) != rule->json_type)) {
-			RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value type. "
-					"name=%s\n", rule->name);
-			return DERR_BAD_TYPE;
-		}
-
-		switch (rule->json_type) {
-		case JSON_ARRAY:
-			RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Decode array. num=%lu\n",
-					json_array_size(value_obj));
-
-			*(int *)((char *)output + rule->array.offset_num) = 
-					(int)json_array_size(value_obj);
-
-			json_array_foreach(value_obj, n, obj) {
-				RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Decode array element. "
-						"index=%d\n", n);
-				
-				if (unlikely(json_typeof(obj) != rule->array.json_type)) {
-					RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value type. "
-							"name=%s, index=%d\n", rule->name, n);
-					return DERR_BAD_TYPE;
-				}
-
-				sub_output = DR_GET_OUTPUT(output, rule) + 
-						(rule->array.element_sz * n);
-				ret = (*rule->decode_proc)(sub_output, obj, rule);
-				if (unlikely(ret != 0)) {
-					RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value. "
-							"name=%s, index=%d\n", rule->name, n);
-					return ret;
-				}
-			}
-			break;
-		default:
-			sub_output = DR_GET_OUTPUT(output, rule);
-			ret = (*rule->decode_proc)(sub_output, value_obj, rule);
-			if (unlikely(ret != 0)) {
-				RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value. "
-						"name=%s\n", rule->name);
-				return ret;
-			}
-			break;
-		}
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to make decode error response.");
+		json_decref(top_obj);
+		return;
 	}
 
-	return 0;
-}
-
-/* decode rule for command-base */
-const struct json_value_decode_rule DECODERULE_COMMAND_BASE[] = {
-	{
-		.name = "command",
-		.json_type = JSON_STRING,
-		.offset = offsetof(struct command, type),
-		.decode_proc = decode_command_type_value,
-	},
-	END_OF_DECODE_RULE
-};
+	/* serialize */
+	msg = json_dumps(top_obj, JSON_INDENT(2));
+	json_decref(top_obj);
 
-#if 0 /* not supported */
-/* decode rule for add-command-spec */
-const struct json_value_decode_rule DECODERULE_ADD_COMMAND[] = {
-	{
-		.name = "ports",
-		.json_type = JSON_ARRAY,
-		.offset = offsetof(struct add_command, ports),
-		.decode_proc = decode_port_value,
-
-		.array.element_sz = sizeof(struct spp_config_port_info),
-		.array.json_type = JSON_STRING,
-		.array.offset_num = offsetof(struct add_command, num_port),
-	},
-	END_OF_DECODE_RULE
-};
-#endif
-
-/* decode rule for classifier-table-command-spec */
-const struct json_value_decode_rule DECODERULE_CLASSIFIER_TABLE_COMMAND[] = {
-	{
-		.name = "type",
-		.json_type = JSON_STRING,
-		.offset = offsetof(struct classifier_table_command, type),
-		.decode_proc = decode_classifier_type_value,
-	},{
-		.name = "value",
-		.json_type = JSON_STRING,
-		.offset = offsetof(struct classifier_table_command, value),
-		.decode_proc = decode_mac_addr_str_value,
-	},{
-		.name = "port",
-		.json_type = JSON_STRING,
-		.offset = offsetof(struct classifier_table_command, port),
-		.decode_proc = decode_port_value,
-	},
-	END_OF_DECODE_RULE
-};
-
-/* decode procedure for command */
-static int
-decode_command_object(void* output, const json_t *parent_obj,
-		__rte_unused const struct json_value_decode_rule *rule)
-{
-	int ret = -1;
-	struct command *command = (struct command *)output;
-	const struct json_value_decode_rule *spec_rules = NULL;
-
-	/* decode command-base */
-	ret = decode_json_object(command, parent_obj, DECODERULE_COMMAND_BASE);
+	/* send response to requester */
+	ret = spp_send_message(sock, msg, strlen(msg));
 	if (unlikely(ret != 0)) {
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad command. ret=%d\n", ret);
-		return ret;
-	}
-
-	/* decode command-specific */
-	switch (command->type) {
-		case CMDTYPE_CLASSIFIER_TABLE:
-			spec_rules = DECODERULE_CLASSIFIER_TABLE_COMMAND;
-			break;
-
-		case CMDTYPE_FLUSH:
-			/* nothing specific */
-			break;
-
-		default:
-			/* unknown command */
-			RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown command. type=%d\n",
-					command->type);
-			return DERR_UNKNOWN_COMMAND;
-	}
-
-	if (likely(spec_rules != NULL)) {
-		ret = decode_json_object(&command->spec, parent_obj, spec_rules);
-		if (unlikely(ret != 0)) {
-			RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad command. ret=%d\n", ret);
-			return ret;
-		}
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to send decode error response.");
+		/* not return */
 	}
 
-	return 0;
+	free(msg);
 }
 
-/* decode rule for command request */
-const struct json_value_decode_rule DECODERULE_REQUEST[] = {
-	{
-		.name = "commands",
-		.json_type = JSON_ARRAY,
-		.offset = offsetof(struct request, commands),
-		.decode_proc = decode_command_object,
-
-		.array.element_sz = sizeof(struct command),
-		.array.json_type = JSON_OBJECT,
-		.array.offset_num = offsetof(struct request, num_command),
-		.array.offset_num_valid = offsetof(struct request, num_valid_command),
-	},
-	END_OF_DECODE_RULE
-};
-
-/* decode request from no-null-terminated string */
-static int
-decode_request(struct request *request, const char *request_str, size_t request_str_len)
+/* send response for command execution result */
+static void
+send_command_result_response(int *sock, const struct spp_command_request *request,
+		const struct command_result *command_results)
 {
 	int ret = -1;
+	char *msg;
 	json_t *top_obj;
-	json_error_t json_error;
 
-	/* parse json string */
-	top_obj = json_loadb(request_str, request_str_len, 0, &json_error);
+	top_obj = json_object();
 	if (unlikely(top_obj == NULL)) {
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Cannot parse command request. "
-				"error=%s, request_str=%.*s\n", 
-				json_error.text, (int)request_str_len, request_str);
-		return DERR_BAD_FORMAT;
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to make command result response.");
+		return;
 	}
 
-	/* decode request object */
-	ret = decode_json_object(request, top_obj, DECODERULE_REQUEST);
+	/* create & append result array */
+	ret = append_response_command_results_object(top_obj, request, command_results);
 	if (unlikely(ret != 0)) {
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Cannot decode command request. "
-				"ret=%d, request_str=%.*s\n", 
-				ret, (int)request_str_len, request_str);
-		return ret;
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to make command result response.");
+		json_decref(top_obj);
+		return;
 	}
 
-	return 0;
-}
-
-/* execute one command */
-static int
-execute_command(const struct command *command)
-{
-	int ret = -1;
-
-	switch (command->type) {
-	case CMDTYPE_CLASSIFIER_TABLE:
-		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Execute classifier_table command.");
-		ret = spp_update_classifier_table(
-				command->spec.classifier_table.type,
-				command->spec.classifier_table.value,
-				&command->spec.classifier_table.port);
-		break;
-
-	case CMDTYPE_FLUSH:
-		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Execute flush command.");
-		ret = spp_flush();
-		break;
+	/* append process information value */
+	if (request->is_requested_process) {
+		ret = append_response_process_value(top_obj);
+		if (unlikely(ret != 0)) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to make command result response.");
+			json_decref(top_obj);
+			return;
+		}
+	}
 
-	case CMDTYPE_PROCESS:
-		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Execute process command.");
-		ret = spp_get_process_id();
-		break;
+	/* serialize */
+	msg = json_dumps(top_obj, JSON_INDENT(2));
+	json_decref(top_obj);
 
-	default:
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown command. type=%d\n", command->type);
-		ret = 0;
-		break;
+	/* send response to requester */
+	ret = spp_send_message(sock, msg, strlen(msg));
+	if (unlikely(ret != 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to send decode error response.");
+		/* not return */
 	}
 
-	return ret;
+	free(msg);
 }
 
 /* process command request from no-null-terminated string */
 static int
-process_request(const char *request_str, size_t request_str_len)
+process_request(int *sock, const char *request_str, size_t request_str_len)
 {
 	int ret = -1;
 	int i;
 
-	struct request request;
-	memset(&request, 0, sizeof(struct request));
+	struct spp_command_request request;
+	struct spp_command_decode_error decode_error;
+	struct command_result command_results[SPP_CMD_MAX_COMMANDS];
 
-	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Start command request processing. "
+	memset(&request, 0, sizeof(struct spp_command_request));
+	memset(&decode_error, 0, sizeof(struct spp_command_decode_error));
+	memset(command_results, 0, sizeof(command_results));
+
+	RTE_LOG(INFO, SPP_COMMAND_PROC, "Start command request processing. "
 			"request_str=%.*s\n", (int)request_str_len, request_str);
 
-	ret = decode_request(&request, request_str, request_str_len);
+	/* decode request message */
+	ret = spp_command_decode_request(
+			&request, request_str, request_str_len, &decode_error);
 	if (unlikely(ret != 0)) {
-		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Failed to process command request. "
-		"ret=%d\n", ret);
+		/* send error response */
+		send_decode_error_response(sock, &request, &decode_error);
+		RTE_LOG(INFO, SPP_COMMAND_PROC, "End command request processing.\n");
 		return ret;
 	}
 
-	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Decoded command request. "
+	RTE_LOG(INFO, 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 != 0)) {
+			command_results[i].code = CRES_FAILURE;
+
+			/* not execute remaining commands */
+			for (++i; i < request.num_command ; ++i)
+				command_results[i].code = CRES_INVALID;
+			break;
+		}
+
+		command_results[i].code = CRES_SUCCESS;
 	}
 
-	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Succeeded to process command request.\n");
+	/* send response */
+	send_command_result_response(sock, &request, command_results);
+
+	RTE_LOG(INFO, SPP_COMMAND_PROC, "End command request processing.\n");
 
 	return 0;
 }
@@ -739,10 +372,7 @@ process_request(const char *request_str, size_t request_str_len)
 int
 spp_command_proc_init(const char *controller_ip, int controller_port)
 {
-	strcpy(g_controller_ip, controller_ip);
-	g_controller_port = controller_port;
-
-	return 0;
+	return spp_command_conn_init(controller_ip, controller_port);
 }
 
 /* process command from controller. */
@@ -761,13 +391,13 @@ spp_command_proc_do(void)
 	static size_t lb_cnt = 0;
 
 	if (unlikely(msgbuf == NULL))
-		msgbuf = msgbuf_allocate(MESSAGE_BUFFER_BLOCK_SIZE);
+		msgbuf = spp_strbuf_allocate(MESSAGE_BUFFER_BLOCK_SIZE);
 
-	ret = connect_to_controller(&sock);
+	ret = spp_connect_to_controller(&sock);
 	if (unlikely(ret != 0))
 		return;
 
-	msg_ret = receive_message(&sock, &msgbuf);
+	msg_ret = spp_receive_message(&sock, &msgbuf);
 	if (likely(msg_ret <= 0)) {
 		return;
 	}
@@ -784,9 +414,9 @@ spp_command_proc_do(void)
 
 		if (likely(lb_cnt != 0) && unlikely(rb_cnt == lb_cnt)) {
 			msg_len += (i + 1);
-			ret = process_request(msgbuf, msg_len);
+			ret = process_request(&sock, msgbuf, msg_len);
 
-			msgbuf_remove_front(msgbuf, msg_len);
+			spp_strbuf_remove_front(msgbuf, msg_len);
 			msg_ret = 0;
 			msg_len = 0;
 			rb_cnt = 0;
diff --git a/src/vf/string_buffer.c b/src/vf/string_buffer.c
new file mode 100644
index 0000000..535d050
--- /dev/null
+++ b/src/vf/string_buffer.c
@@ -0,0 +1,90 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_branch_prediction.h>
+
+#include "string_buffer.h"
+
+/* get message buffer capacity */
+inline size_t
+strbuf_get_capacity(const char *strbuf)
+{
+	return *((const size_t *)(strbuf - sizeof(size_t)));
+}
+
+/* re-allocate message buffer */
+inline char*
+strbuf_reallocate(char *strbuf, size_t required_len)
+{
+	size_t new_cap = strbuf_get_capacity(strbuf) * 2;
+	char *new_strbuf = NULL;
+
+	while (unlikely(new_cap <= required_len))
+		new_cap *= 2;
+
+	new_strbuf = spp_strbuf_allocate(new_cap);
+	if (unlikely(new_strbuf == NULL))
+		return NULL;
+
+	strcpy(new_strbuf, strbuf);
+	spp_strbuf_free(strbuf);
+
+	return new_strbuf;
+}
+
+/* allocate message buffer */
+char*
+spp_strbuf_allocate(size_t capacity)
+{
+	char* buf = (char *)malloc(capacity + sizeof(size_t));
+	if (unlikely(buf == NULL))
+		return NULL;
+
+	memset(buf, 0x00, capacity + sizeof(size_t));
+	*((size_t *)buf) = capacity;
+
+	return buf + sizeof(size_t);
+}
+
+/* free message buffer */
+void
+spp_strbuf_free(char* strbuf)
+{
+	if (likely(strbuf != NULL))
+		free(strbuf - sizeof(size_t));
+}
+
+/* append message to buffer */
+char*
+spp_strbuf_append(char *strbuf, const char *append, size_t append_len)
+{
+	size_t cap = strbuf_get_capacity(strbuf);
+	size_t len = strlen(strbuf);
+	char *new_strbuf = strbuf;
+
+	if (unlikely(len + append_len >= cap)) {
+		new_strbuf = strbuf_reallocate(strbuf, len + append_len);
+		if (unlikely(new_strbuf == NULL))
+			return NULL;
+	}
+
+	memcpy(new_strbuf + len, append, append_len);
+	*(new_strbuf + len + append_len) = '\0';
+
+	return new_strbuf;
+}
+
+/* remove message from front */
+char*
+spp_strbuf_remove_front(char *strbuf, size_t remove_len)
+{
+	size_t len = strlen(strbuf);
+	size_t new_len = len - remove_len;
+
+	if (likely(new_len == 0)) {
+		*strbuf = '\0';
+		return strbuf;
+	}
+
+	return memmove(strbuf, strbuf + remove_len, new_len + 1);
+}
diff --git a/src/vf/string_buffer.h b/src/vf/string_buffer.h
new file mode 100644
index 0000000..adc52ef
--- /dev/null
+++ b/src/vf/string_buffer.h
@@ -0,0 +1,16 @@
+#ifndef _STRING_BUFFER_H_
+#define _STRING_BUFFER_H_
+
+/* allocate message buffer */
+char* spp_strbuf_allocate(size_t capacity);
+
+/* free message buffer */
+void spp_strbuf_free(char* strbuf);
+
+/* append message to buffer */
+char* spp_strbuf_append(char *strbuf, const char *append, size_t append_len);
+
+/* remove message from front */
+char* spp_strbuf_remove_front(char *strbuf, size_t remove_len);
+
+#endif /* _STRING_BUFFER_H_ */
-- 
1.9.1



More information about the spp mailing list