From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail04.ics.ntt-tx.co.jp (mail05.ics.ntt-tx.co.jp [210.232.35.69]) by dpdk.org (Postfix) with ESMTP id 13B6B3237 for ; Thu, 28 Dec 2017 05:56:10 +0100 (CET) Received: from gwchk03.silk.ntt-tx.co.jp (gwchk03.silk.ntt-tx.co.jp [10.107.0.111]) by mail04.ics.ntt-tx.co.jp (unknown) with ESMTP id vBS4u9xB025174 for unknown; Thu, 28 Dec 2017 13:56:09 +0900 Received: (from root@localhost) by gwchk03.silk.ntt-tx.co.jp (unknown) id vBS4u79f027323 for unknown; Thu, 28 Dec 2017 13:56:07 +0900 Received: from gwchk.silk.ntt-tx.co.jp [10.107.0.110] by gwchk03.silk.ntt-tx.co.jp with ESMTP id PAA27310; Thu, 28 Dec 2017 13:56:06 +0900 Received: from imss03.silk.ntt-tx.co.jp (localhost [127.0.0.1]) by imss03.silk.ntt-tx.co.jp (unknown) with ESMTP id vBS4u6dU011049 for unknown; Thu, 28 Dec 2017 13:56:06 +0900 Received: from mgate01.silk.ntt-tx.co.jp (smtp02.silk.ntt-tx.co.jp [10.107.0.37]) by imss03.silk.ntt-tx.co.jp (unknown) with ESMTP id vBS4u6iV011023 for unknown; Thu, 28 Dec 2017 13:56:06 +0900 Message-Id: <201712280456.vBS4u6iV011023@imss03.silk.ntt-tx.co.jp> Received: from localhost by mgate01.silk.ntt-tx.co.jp (unknown) id vBS4u4aw025622 ; Thu, 28 Dec 2017 13:56:05 +0900 From: x-fn-spp@sl.ntt-tx.co.jp To: spp@dpdk.org Date: Thu, 28 Dec 2017 13:55:31 +0900 X-Mailer: git-send-email 1.9.1 In-Reply-To: <4aae78ff-3b6c-cdfe-a8b7-24ec08b73935@lab.ntt.co.jp> References: <4aae78ff-3b6c-cdfe-a8b7-24ec08b73935@lab.ntt.co.jp> X-TM-AS-MML: No Subject: [spp] [PATCH 24/57] spp_vf: split command processing source file X-BeenThere: spp@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Soft Patch Panel List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 28 Dec 2017 04:56:14 -0000 From: Hiroyuki Nakamura * For better maintainability, split 1 source file into 3 files(acceptance, decode, and utility). Signed-off-by: Daiki Yamashita Signed-off-by: Yasufum Ogawa --- 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 +#include +#include +#include +#include + +#include +#include + +#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 +#include + +#include +#include + +#include + +#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 -#include -#include #include -#include -#include -#include -#include #include #include @@ -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 +#include + +#include + +#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