[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