diff options
author | sharath reddy <bs.reddy@huawei.com> | 2019-06-04 11:53:49 +0530 |
---|---|---|
committer | sharath reddy <bs.reddy@huawei.com> | 2019-06-04 20:38:30 +0530 |
commit | 2a42ad20b9730706ad371ae3787d4597c4e42276 (patch) | |
tree | fa01cd312586ea007468e7233f94c0ce53d75873 /stacks/lwip_stack/lwip_src/ip_module | |
parent | a826fe833d3f2a8fe2673fa05811fe1a22baf045 (diff) |
Feature: 19.04 part-2DMM-2
Change-Id: I0b52a6bb67c25c7955d58e29eb81a3cc9efea9e9
Signed-off-by: sharath reddy <bs.reddy@huawei.com>
Diffstat (limited to 'stacks/lwip_stack/lwip_src/ip_module')
-rw-r--r-- | stacks/lwip_stack/lwip_src/ip_module/configuration_reader.c | 1039 | ||||
-rw-r--r-- | stacks/lwip_stack/lwip_src/ip_module/container_ip.c | 1117 | ||||
-rw-r--r-- | stacks/lwip_stack/lwip_src/ip_module/ip_module_api.c | 356 | ||||
-rw-r--r-- | stacks/lwip_stack/lwip_src/ip_module/network.c | 1093 | ||||
-rw-r--r-- | stacks/lwip_stack/lwip_src/ip_module/trp_rb_tree.c | 563 |
5 files changed, 4168 insertions, 0 deletions
diff --git a/stacks/lwip_stack/lwip_src/ip_module/configuration_reader.c b/stacks/lwip_stack/lwip_src/ip_module/configuration_reader.c new file mode 100644 index 0000000..46bdc08 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/ip_module/configuration_reader.c @@ -0,0 +1,1039 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include <unistd.h> +#include <sys/wait.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <netinet/in.h> +#include <time.h> +#include <pthread.h> +#include <sys/types.h> +#include <stddef.h> +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include "configuration_reader.h" +#include "container_ip.h" +#include "network.h" +#include "nstack_log.h" +#include "nstack_securec.h" +#include "json.h" +#include "spl_tcpip.h" + +#include "types.h" +#include "nsfw_mgr_com_api.h" +#include "nsfw_base_linux_api.h" +#include "nsfw_maintain_api.h" + +NSTACK_STATIC struct config_data g_ip_module_buff; +NSTACK_STATIC struct config_data *g_config_data; +NSTACK_STATIC char ip_module_unix_socket[IP_MODULE_MAX_PATH_LEN + 1]; +NSTACK_STATIC char ip_module_unix_socket_dir_path[IP_MODULE_MAX_PATH_LEN + 1]; +//static unsigned long int g_thread_id = 0; + +#define MAX_CONNECTION_NUMBER 5 +#define TCP_OOS_LEN_MAX 250 + +NSTACK_STATIC int read_configuration(); +NSTACK_STATIC int unix_socket_listen(const char *servername); +NSTACK_STATIC int process_query(); + +/***************************************************************************** +* Prototype : is_digit_str +* Description : check if a string contains only digit +* Input : char *input +* Output : 1 for yes, 0 for no +* Return Value : int +* Calls : +* Called By : get_main_pid +* +*****************************************************************************/ +NSTACK_STATIC int is_digit_str(char *input) +{ + if (NULL == input || '\0' == input[0]) + { + return 0; + } + + while (*input) + { + if (*input > '9' || *input < '0') + { + return 0; + } + input++; + } + + return 1; +} + +/***************************************************************************** +* Prototype : process_query +* Description : ./nStackCtrl -a query +* Input : none +* Output : none +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +NSTACK_STATIC int process_query() +{ + int retval; + + if (0 == g_config_data->param.type[0]) + { + return process_post(NULL, IP_MODULE_ALL, IP_MODULE_OPERATE_QUERY); + } + + /*name & p are freed inside process_post */ + if (0 == strcmp(g_config_data->param.type, IP_MODULE_TYPE_PORT)) + { + struct ip_action_param *p = malloc(sizeof(struct ip_action_param)); + if (p == NULL) + { + NSOPR_LOGERR("name allocation failed!"); + NSOPR_SET_ERRINFO(NSCRTL_ERR, "mem alloc error!"); + return -1; + } + + retval = + memset_s(p, sizeof(struct ip_action_param), 0, + sizeof(struct ip_action_param)); + if (EOK != retval) + { + NSOPR_LOGERR("MEMSET_S failed]ret=%d", retval); + NSOPR_SET_ERRINFO(NSCRTL_ERR, "MEMSET_S error!"); + free(p); + return -1; + } + + retval = + strcpy_s(p->container_id, sizeof(p->container_id), + g_config_data->param.container_id); + if (EOK != retval) + { + NSOPR_LOGERR("STRCPY_S failed]ret=%d", retval); + NSOPR_SET_ERRINFO(NSCRTL_ERR, "STRCPY_S error!"); + free(p); + return -1; + } + + retval = + strcpy_s(p->port_name, sizeof(p->port_name), + g_config_data->param.name); + if (EOK != retval) + { + NSOPR_LOGERR("STRCPY_S failed]ret=%d", retval); + NSOPR_SET_ERRINFO(NSCRTL_ERR, "STRCPY_S error!"); + free(p); + return -1; + } + + return process_post((void *) p, IP_MODULE_IP, + IP_MODULE_OPERATE_QUERY); + } + else if (0 == strcmp(g_config_data->param.type, IP_MODULE_TYPE_NETWORK)) + { + if (0 == g_config_data->param.name[0]) + { + return process_post(NULL, IP_MODULE_NETWORK_ALL, + IP_MODULE_OPERATE_QUERY); + } + else + { + char *name = malloc(sizeof(g_config_data->param.name)); + if (NULL == name) + { + NSOPR_LOGERR("name allocation failed!"); + NSOPR_SET_ERRINFO(NSCRTL_ERR, "mem alloc error!"); + return -1; + } + + retval = + memset_s(name, sizeof(g_config_data->param.name), 0, + sizeof(g_config_data->param.name)); + if (EOK != retval) + { + NSOPR_LOGERR("MEMSET_S failed]ret=%d", retval); + NSOPR_SET_ERRINFO(NSCRTL_ERR, "MEMSET_S error!"); + free(name); + return -1; + } + + retval = + strcpy_s(name, sizeof(g_config_data->param.name), + g_config_data->param.name); + if (EOK != retval) + { + NSOPR_LOGERR("STRCPY_S failed]ret=%d", retval); + NSOPR_SET_ERRINFO(NSCRTL_ERR, "STRCPY_S error!"); + free(name); + return -1; + } + + return process_post((void *) name, IP_MODULE_NETWORK, + IP_MODULE_OPERATE_QUERY); + } + } + else if (0 == strcmp(g_config_data->param.type, IP_MODULE_TYPE_IP)) + { + if (0 == g_config_data->param.name[0]) + { + return process_post(NULL, IP_MODULE_IP_ALL, + IP_MODULE_OPERATE_QUERY); + } + else + { + NSOPR_SET_ERRINFO(NSCRTL_INPUT_ERR, "input error!"); + } + } + else + { + NSOPR_SET_ERRINFO(NSCRTL_INPUT_ERR, "input error!"); + } + + return -1; +} + +int read_ipmoduleoperatesetnet_configuration() +{ + if (strcmp(g_config_data->param.type, IP_MODULE_TYPE_SETLOG) == 0) + { + if (NSCRTL_OK == + setlog_level_value(g_config_data->param.name, + g_config_data->param.value)) + { + NSOPR_LOGDBG("set log level ok!"); + } + else + { + NSOPR_SET_ERRINFO(NSCRTL_INPUT_ERR, "input error!"); + } + } + else if (strcmp(g_config_data->param.type, TCP_MODULE_TYPE_SET_OOS_LEN) == + 0) + { + if (is_digit_str(g_config_data->param.value) == 0) + { + NSOPR_SET_ERRINFO(NSCRTL_INPUT_ERR, + "Invalid value:value must be digital and smaller than %u]value=\"%s\"", + TCP_OOS_LEN_MAX, g_config_data->param.value); + return 0; + } + + unsigned int value_len = strlen(g_config_data->param.value); + if ((value_len >= 2) && (g_config_data->param.value[0] == '0')) + { + NSOPR_SET_ERRINFO(NSCRTL_INPUT_ERR, + "Invalid value:value cannot start with 0"); + return 0; + } + } + else + { + NSOPR_SET_ERRINFO(NSCRTL_INPUT_ERR, "input error!"); + } + + return 0; +} + +/***************************************************************************** +* Prototype : read_version +* Description : Query Version by nStackCtrl +* Input : None +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int read_version() +{ + int retVal; + json_object *version = json_object_new_object(); + + if (NULL == version) + { + NSOPR_SET_ERRINFO(NSCRTL_ERR, "internal error for version=NULL!"); + return NSCRTL_ERR; + } + + json_object_object_add(version, "moudle", + json_object_new_string(NSTACK_GETVER_MODULE)); + json_object_object_add(version, "version", + json_object_new_string(NSTACK_GETVER_VERSION)); + json_object_object_add(version, "buildtime", + json_object_new_string(NSTACK_GETVER_BUILDTIME)); + + json_object *version_array = json_object_new_array(); + if (NULL == version_array) + { + json_object_put(version); + NSOPR_SET_ERRINFO(NSCRTL_ERR, + "internal error for version_array=NULL!"); + return NSCRTL_ERR; + } + + retVal = json_object_array_add(version_array, version); + + if (0 != retVal) + { + json_object_put(version_array); + json_object_put(version); + NSOPR_SET_ERRINFO(NSCRTL_ERR, + "internal error for json_object_array_add failed!"); + return NSCRTL_ERR; + } + + const char *str = json_object_to_json_string(version_array); + + if (NULL == str) + { + json_object_put(version_array); + NSOPR_SET_ERRINFO(NSCRTL_ERR, "internal error for str=NULL!"); + return NSCRTL_ERR; + } + + size_t str_len = strlen(str); + if (str_len >= sizeof(get_config_data()->json_buff)) + { + json_object_put(version_array); + NSOPR_SET_ERRINFO(NSCRTL_ERR, "internal error!"); + return NSCRTL_ERR; + } + + retVal = + strncpy_s(get_config_data()->json_buff, + sizeof(get_config_data()->json_buff), str, str_len); + if (EOK != retVal) + { + json_object_put(version_array); + NSOPR_SET_ERRINFO(NSCRTL_ERR, "STRNCPY_S error!"); + return NSCRTL_ERR; + } + + json_object_put(version_array); + return NSCRTL_OK; +} + +void reset_config_data(void) +{ + int retval = memset_s(g_config_data, sizeof(struct config_data), 0, + sizeof(struct config_data)); + if (EOK != retval) + { + printf("MEMSET_S failed]retval=%d.\n", retval); + exit(1); + } +} + +int get_network_json_data() +{ + strcpy_s(g_config_data->param.type, sizeof(g_config_data->param.type), + "network"); + g_config_data->param.action = IP_MODULE_OPERATE_ADD; + + char *tmp_config_path; + tmp_config_path = realpath("./network_data_tonStack.json", NULL); + if (!tmp_config_path) + { + NSTCP_LOGINF("Warning! It use the second search path ../configure"); + tmp_config_path = + realpath("../configure/network_data_tonStack.json", NULL); + } + + if (!tmp_config_path) + { + return 1; + } + + int fp = open(tmp_config_path, O_RDONLY); + if (-1 == fp) + { + free(tmp_config_path); + NSTCP_LOGINF("network file open failed.\n"); + exit(1); + } + free(tmp_config_path); + + int nread = read(fp, g_config_data->json_buff, + sizeof(g_config_data->json_buff) - 1); + if (nread <= 0) + { + close(fp); + NSTCP_LOGINF("read failed %d.\n", nread); + exit(1); + } + + /* though MEMSET_S is done above, MEMSET_S can be removed */ + g_config_data->json_buff[nread] = '\0'; + close(fp); + + struct network_configuration *network = NULL; + struct network_configuration *tmp = NULL; + + /* input shouldnot be same with return */ + network = parse_network_json(g_config_data->json_buff, NULL); + if (!network) + { + NSTCP_LOGINF("Invalid network data!"); + NSOPR_SET_ERRINFO(NSCRTL_INPUT_ERR, "Invalid network data!"); + return -1; + } + + /* run process_post for each network, not only the head node */ + while (network) + { + tmp = network; + network = network->next; + int retval = + add_network_configuration((struct network_configuration *) tmp); + + /* When network exceeds max number, just log warning at operation.log */ + if (retval == NSCRTL_NETWORK_COUNT_EXCEED) + { + NSTCP_LOGINF + ("Warning!! Network count exceed max allowed number]max=%d", + MAX_NETWORK_COUNT); + } + else + { + + NSTCP_LOGINF("add_network_configuration %d", retval); + NSOPR_SET_ERRINFO(retval, "add_network_configuration return %d", + retval); + } + + if (!retval) + { + /*init DPDK eth */ + if ((retval = init_new_network_configuration()) != ERR_OK) + { + NSTCP_LOGINF("process_configuration failed! %d", retval); + free_network_configuration((struct network_configuration *) + tmp, IP_MODULE_TRUE); + NSOPR_SET_ERRINFO(retval, + "init_new_network_configuration return %d", + retval); + return -1; + } + } + } + NSTCP_LOGINF("Get_network_json_data done!"); + + return 0; +} + +int get_ip_json_data() +{ + NSTCP_LOGINF("get_ip_json_data start!"); + + strcpy_s(g_config_data->param.type, sizeof(g_config_data->param.type), + "ip"); + g_config_data->param.action = IP_MODULE_OPERATE_ADD; + + char *tmp_config_path; + tmp_config_path = realpath("./ip_data.json", NULL); + if (!tmp_config_path) + { + NSTCP_LOGINF("Warning! It use the second search path ../configure"); + tmp_config_path = realpath("../configure/ip_data.json", NULL); + } + + if (!tmp_config_path) + { + return 1; + } + + int fp = open(tmp_config_path, O_RDONLY); + if (-1 == fp) + { + free(tmp_config_path); + NSTCP_LOGINF("network file open failed\n"); + exit(1); + } + free(tmp_config_path); + + int nread = read(fp, g_config_data->json_buff, + sizeof(g_config_data->json_buff) - 1); + if (nread <= 0) + { + close(fp); + NSTCP_LOGINF("read failed %d.\n", nread); + exit(1); + } + + /* though MEMSET_S is done above, MEMSET_S can be removed */ + g_config_data->json_buff[nread] = '\0'; + close(fp); + + struct container_ip *container = + parse_container_ip_json(g_config_data->json_buff); + if (container) + { + int retval = add_container(container); + + NSTCP_LOGINF("add_container %d", retval); + NSOPR_SET_ERRINFO(retval, "add_container return %d", retval); + } + else + { + NSTCP_LOGINF("Invalid IP config data!"); + NSOPR_SET_ERRINFO(NSCRTL_INPUT_ERR, "Invalid IP config data!"); + return -1; + } + NSTCP_LOGINF("get_ip_json_data done!"); + + return 0; +} + +int read_ipmoduleoperateadd_configuration() +{ + struct network_configuration *tmp = NULL; + if (strcmp(g_config_data->param.type, IP_MODULE_TYPE_IP) == 0) + { + struct container_ip *container = + parse_container_ip_json(g_config_data->json_buff); + if (container) + { + return process_post((void *) container, IP_MODULE_IP, + IP_MODULE_OPERATE_ADD); + } + else + { + NSOPR_LOGERR("Invalid IP config data!"); + NSOPR_SET_ERRINFO(NSCRTL_INPUT_ERR, "Invalid IP config data!"); + return -1; + } + } + else if (strcmp(g_config_data->param.type, IP_MODULE_TYPE_NETWORK) == 0) + { + struct network_configuration *network = NULL; + + //Read network.json + + /* input shouldnot be same with return */ + network = parse_network_json(g_config_data->json_buff, NULL); + if (!network) + { + NSOPR_LOGERR("Invalid network data!"); + NSOPR_SET_ERRINFO(NSCRTL_INPUT_ERR, "Invalid network data!"); + return -1; + } + + /* run process_post for each network, not only the head node */ + while (network) + { + tmp = network; + network = network->next; + int ret = process_post((void *) tmp, IP_MODULE_NETWORK, + IP_MODULE_OPERATE_ADD); + if (ret == -1) + { + NSOPR_LOGERR("process_configuration failed!"); + return -1; + } + } + return 0; + } + else + { + NSOPR_SET_ERRINFO(NSCRTL_INPUT_ERR, "input error!"); + return -1; + } +} + +int read_ipmoduleoperatedel_configuration() +{ + int retval; + + if (strcmp(g_config_data->param.type, IP_MODULE_TYPE_IP) == 0) + { + struct ip_action_param *p = malloc(sizeof(struct ip_action_param)); + if (NULL == p) + { + NSOPR_LOGERR("ip_action_param allocation failed!"); + NSOPR_SET_ERRINFO(NSCRTL_ERR, "mem alloc error!"); + return -1; + } + + retval = + memset_s(p, sizeof(struct ip_action_param), 0, + sizeof(struct ip_action_param)); + if (EOK != retval) + { + NSOPR_LOGERR("MEMSET_S failed]ret=%d", retval); + NSOPR_SET_ERRINFO(NSCRTL_ERR, "MEMSET_S error!"); + free(p); + return -1; + } + + retval = + strcpy_s(p->container_id, sizeof(p->container_id), + g_config_data->param.container_id); + if (EOK != retval) + { + NSOPR_LOGERR("STRCPY_S failed]ret=%d", retval); + NSOPR_SET_ERRINFO(NSCRTL_ERR, "STRCPY_S error!"); + free(p); + return -1; + } + + retval = + strcpy_s(p->port_name, sizeof(p->port_name), + g_config_data->param.name); + if (EOK != retval) + { + NSOPR_LOGERR("STRCPY_S failed]ret=%d", retval); + NSOPR_SET_ERRINFO(NSCRTL_ERR, "STRCPY_S error!"); + free(p); + return -1; + } + + return process_post((void *) p, IP_MODULE_IP, IP_MODULE_OPERATE_DEL); + } + else if (strcmp(g_config_data->param.type, IP_MODULE_TYPE_NETWORK) == 0) + { + char *name = malloc(sizeof(g_config_data->param.name)); + if (name == NULL) + { + NSOPR_LOGERR("name allocation failed!"); + NSOPR_SET_ERRINFO(NSCRTL_ERR, "mem alloc error!"); + return -1; + } + + retval = + memset_s(name, sizeof(g_config_data->param.name), 0, + sizeof(g_config_data->param.name)); + if (EOK != retval) + { + NSOPR_LOGERR("MEMSET_S failed]ret=%d", retval); + NSOPR_SET_ERRINFO(NSCRTL_ERR, "MEMSET_S error!"); + free(name); + return -1; + } + + retval = + strcpy_s(name, sizeof(g_config_data->param.name), + g_config_data->param.name); + if (EOK != retval) + { + NSOPR_LOGERR("STRCPY_S failed]ret=%d", retval); + NSOPR_SET_ERRINFO(NSCRTL_ERR, "STRCPY_S error!"); + free(name); + return -1; + } + + return process_post((void *) name, IP_MODULE_NETWORK, + IP_MODULE_OPERATE_DEL); + } + else + { + NSOPR_SET_ERRINFO(NSCRTL_INPUT_ERR, "input error!"); + return -1; + } +} + +NSTACK_STATIC int read_configuration() +{ + int retval = -1; + //u64 traceid = 0; + + /* initialise default memory */ + g_config_data->param.error = NSCRTL_OK; + + /* Make sure error_desc is inited to null string */ + g_config_data->param.error_desc[0] = '\0'; + + //traceid = g_config_data->param.traceid; + + NSOPR_LOGINF + ("g_config_data]type=%s,name=%s,value=%s,container_id=%s,action=%d,Json_buf=%s, traceid=%llu", + g_config_data->param.type, g_config_data->param.name, + g_config_data->param.value, g_config_data->param.container_id, + g_config_data->param.action, g_config_data->json_buff, + g_config_data->param.traceid); + + retval = + memset_s(g_config_data->param.error_desc, + sizeof(g_config_data->param.error_desc), 0, + sizeof(g_config_data->param.error_desc)); + if (0 != retval) + { + NSOPR_SET_ERRINFO(NSCRTL_ERR, "ERR:internal error, MEMSET_S failed]"); + return -1; + } + + switch (g_config_data->param.action) + { + case IP_MODULE_OPERATE_DEL: + { + retval = read_ipmoduleoperatedel_configuration(); + break; + } + case IP_MODULE_OPERATE_QUERY: + { + retval = process_query(); + break; + } + case IP_MODULE_OPERATE_ADD: + { + retval = read_ipmoduleoperateadd_configuration(); + break; + } + case IP_MODULE_OPERATE_SET: + retval = read_ipmoduleoperatesetnet_configuration(); + break; + case IP_MODULE_GET_VERSION: + { + retval = read_version(); + break; + } + + default: + { + retval = -1; //here, must set retval to -1 + NSOPR_SET_ERRINFO(NSCRTL_INPUT_ERR, "input error!"); + break; + } + } + + return retval; +} + +NSTACK_STATIC int unix_socket_listen(const char *servername) +{ + int fd, retval; + unsigned int len; + struct stat st; + struct sockaddr_un un; + + if (stat(ip_module_unix_socket_dir_path, &st) == 0) + { + NSOPR_LOGDBG(" /directory is present"); + } + else + { + NSOPR_LOGERR(" /var/run/nStack/ directory is not present "); + return (-1); + } + + if ((fd = nsfw_base_socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + { + return -1; + } + + retval = unlink(servername); /* in case it already exists */ + if (0 != retval) + { + NSOPR_LOGWAR("unlink failed]retval=%d,errno=%d", retval, errno); + } + + retval = memset_s(&un, sizeof(un), 0, sizeof(un)); + if (EOK != retval) + { + (void) nsfw_base_close(fd); + NSOPR_LOGERR("MEMSET_S failed]ret=%d", retval); + return -1; + } + + un.sun_family = AF_UNIX; + retval = strcpy_s(un.sun_path, sizeof(un.sun_path), servername); + if (EOK != retval) + { + (void) nsfw_base_close(fd); + NSOPR_LOGERR("STRCPY_S failed]ret=%d", retval); + return -1; + } + + len = + (unsigned int) (offsetof(struct sockaddr_un, sun_path) + + strlen(servername)); + + if (nsfw_base_bind(fd, (struct sockaddr *) &un, len) < 0) + { + (void) nsfw_base_close(fd); + return -1; + } + else + { + if (nsfw_base_listen(fd, MAX_CONNECTION_NUMBER) < 0) + { + (void) nsfw_base_close(fd); + return -1; + } + else + { + return fd; + } + } +} + +/***************************************************************************** +* Prototype : read_fn +* Description : process new ip module msg +* Input : i32 fd +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +void read_fn(i32 fd) +{ + ssize_t size; + ssize_t offset = 0; + size_t left = MAX_IP_MODULE_BUFF_SIZE; + while (left > 0) + { + size = nsfw_base_recv(fd, (char *) g_config_data + offset, left, 0); + if (size > 0) + { + offset += size; + left -= (size_t) size; + } + else + { + NSOPR_LOGERR("Error when recieving]errno=%d,err_string=%s", errno, + strerror(errno)); + break; + } + } + + if (left != 0) + { + (void) nsfw_base_close(fd); + return; + } + + (void) read_configuration(); // if it returns -1, the err desc info will be wrote to g_config_data, so no need to check return value. + + offset = 0; + left = MAX_IP_MODULE_BUFF_SIZE; + while (left > 0) + { + size = + nsfw_base_send(fd, (char *) g_config_data + offset, left, + MSG_NOSIGNAL); + + if (size > 0) + { + offset += size; + left -= (size_t) size; + } + else + { + NSOPR_LOGERR("Error when Sending data]errno=%d", errno); + break; + } + } + + (void) nsfw_base_close(fd); + return; +} + +/***************************************************************************** +* Prototype : ip_module_new_msg +* Description : recv new config message +* Input : i32 epfd +* i32 fd +* u32 events +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int ip_module_new_msg(i32 epfd, i32 fd, u32 events) +{ + if ((events & EPOLLERR) || (events & EPOLLHUP) || (!(events & EPOLLIN))) + { + nsfw_mgr_unreg_sock_fun(fd); + (void) nsfw_base_close(fd); + return TRUE; + } + + nsfw_mgr_unreg_sock_fun(fd); + read_fn(fd); + return TRUE; +} + +int init_ip_module_unix_socket_path() +{ + const char *directory = "/var/log/nStack"; + const char *home_dir = getenv("HOME"); + + if (getuid() != 0 && home_dir != NULL) + directory = home_dir; + + if (strcpy_s + (ip_module_unix_socket_dir_path, IP_MODULE_MAX_PATH_LEN, + directory) < 0) + { + NSOPR_LOGERR("STRCPY_S fail]"); + return -1; + } + + if (strcat_s + (ip_module_unix_socket_dir_path, IP_MODULE_MAX_PATH_LEN, + "/ip_module") < 0) + { + NSOPR_LOGERR("STRCAT_S fail]"); + return -1; + } + + if (strcpy_s + (ip_module_unix_socket, IP_MODULE_MAX_PATH_LEN, + ip_module_unix_socket_dir_path) < 0) + { + NSOPR_LOGERR("STRCPY_S fail]"); + return -1; + } + + if (strcat_s + (ip_module_unix_socket, IP_MODULE_MAX_PATH_LEN, + "/ip_module_unix_sock") < 0) + { + NSOPR_LOGERR("STRCAT_S fail]"); + return -1; + } + + NSOPR_LOGINF("ip_module_unix_socket=%s", ip_module_unix_socket); + NSOPR_LOGINF("ip_module_unix_socket_dir_path=%s", + ip_module_unix_socket_dir_path); + return 0; +} + +/***************************************************************************** +* Prototype : ip_module_new_connection +* Description : recv new connect for network config +* Input : i32 epfd +* i32 fd +* u32 events +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int ip_module_new_connection(i32 epfd, i32 fd, u32 events) +{ + if ((events & EPOLLERR) || (events & EPOLLHUP) || (!(events & EPOLLIN))) + { + (void) nsfw_base_close(fd); + NSFW_LOGINF("listen disconnect!]epfd=%d,listen=%d,event=0x%x", epfd, + fd, events); + nsfw_mgr_unreg_sock_fun(fd); + + if (init_ip_module_unix_socket_path() < 0) + { + NSFW_LOGERR + ("Error when init path]epfd=%d,listen_fd=%d,event=0x%x", epfd, + fd, events); + return FALSE; + } + + i32 listen_fd = unix_socket_listen(ip_module_unix_socket); + if (listen_fd < 0) + { + NSFW_LOGERR + ("get listen_fd faied!]epfd=%d,listen_fd=%d,event=0x%x", epfd, + fd, events); + return FALSE; + } + + if (FALSE == + nsfw_mgr_reg_sock_fun(listen_fd, ip_module_new_connection)) + { + (void) nsfw_base_close(listen_fd); + return FALSE; + } + return TRUE; + } + + struct sockaddr in_addr; + socklen_t in_len; + int infd; + in_len = sizeof in_addr; + + while (1) + { + infd = nsfw_base_accept(fd, &in_addr, &in_len); + if (infd == -1) + { + break; + } + + if (FALSE == nsfw_mgr_reg_sock_fun(infd, ip_module_new_msg)) + { + NSFW_LOGINF("accept new fd but reg failed]new_mgr_fd=%d", infd); + return FALSE; + } + NSFW_LOGINF("accept new fd]new_mgr_fd=%d", infd); + } + + return TRUE; +} + +int init_configuration_reader() +{ + int error_number = 0; + INITPOL_LOGINF("CONFIGURATION", "init_configuration_reader", NULL_STRING, + LOG_INVALID_VALUE, MODULE_INIT_START); + g_config_data = &g_ip_module_buff; + + if (init_ip_module_unix_socket_path() < 0) + { + INITPOL_LOGERR("CONFIGURATION", "init_configuration_reader", + "Error when init path", LOG_INVALID_VALUE, + MODULE_INIT_FAIL); + return -1; + } + + i32 listen_fd = unix_socket_listen(ip_module_unix_socket); + if (listen_fd < 0) + { + error_number = errno; + INITPOL_LOGERR("CONFIGURATION", "init_configuration_reader", + "when listening ip_module_unix_socket", error_number, + MODULE_INIT_FAIL); + return -1; + } + + NSOPR_LOGINF("start mgr_com module!]listern_fd=%d", listen_fd); + + if (FALSE == nsfw_mgr_reg_sock_fun(listen_fd, ip_module_new_connection)) + { + (void) nsfw_base_close(listen_fd); + NSOPR_LOGERR("nsfw_mgr_reg_sock_fun failed]listen_fd=%d", listen_fd); + return -1; + } + + INITPOL_LOGINF("CONFIGURATION", "init_configuration_reader", NULL_STRING, + LOG_INVALID_VALUE, MODULE_INIT_SUCCESS); + return 0; +} + +struct config_data *get_config_data() +{ + return g_config_data; +} diff --git a/stacks/lwip_stack/lwip_src/ip_module/container_ip.c b/stacks/lwip_stack/lwip_src/ip_module/container_ip.c new file mode 100644 index 0000000..1cbcfb3 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/ip_module/container_ip.c @@ -0,0 +1,1117 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include "lwip/inet.h" +#include "trp_rb_tree.h" +#include "container_ip.h" +#include "network.h" +#include "netif.h" +#include "nstack_log.h" +#include "nstack_securec.h" +#include "config_common.h" +#include "igmp.h" +#include "spl_def.h" +#include "stackx_ip_addr.h" +#include "nsfw_hal_api.h" +#include "spl_hal.h" + +struct container_list g_container_list = { 0 }; +static trp_rb_root_t g_container_ip_root = { 0 }; //only handled in tcpip thread, no need protect it with a lock +static trp_rb_root_t g_container_multicast_root = { 0 }; //only handled in tcpip thread, no need protect it with a lock + +static void free_container_port(struct container_port *port, + bool_t only_free); + +/*unsigned int value is typecasted into void * pointer and passed as argument to +this function. so the value can never be > 0xFFFFFFFF. so can suppress the warning*/ + +static int ip_compare(trp_key_t left, trp_key_t right) +{ + //return (int)((unsigned long)left - (unsigned long)right); + + if (left > right) + { + return 1; + } + else if (left < right) + { + return -1; + } + else + { + return 0; + } +} + +NSTACK_STATIC bool_t is_container_ok(struct container_ip * container) +{ + if (!container->ports_list) + { + return 0; + } + + return 1; +} + +NSTACK_STATIC void +add_port(struct container_ip *container, struct container_port *port) +{ + if (port->ip_cidr_list) + { + port->next = container->ports_list; + container->ports_list = port; + } + else + { + free_container_port(port, IP_MODULE_TRUE); + } +} + +static void +add_ip_cidr(struct container_port *port, + struct container_port_ip_cidr *ip_cidr) +{ + if (!ip_cidr) + { + return; + } + + ip_cidr->next = port->ip_cidr_list; + port->ip_cidr_list = ip_cidr; + return; +} + +NSTACK_STATIC void +add_multilcast_ip(struct container_port *port, + struct container_multicast_id *muticastIP) +{ + if (!muticastIP) + { + return; + } + + muticastIP->next = port->multicast_list; + port->multicast_list = muticastIP; + return; +} + +NSTACK_STATIC void +free_container_port_ip_cidr(struct container_port_ip_cidr *ip_cidr, + bool_t only_free) +{ + output_api *api = get_output_api(); + struct container_port_ip_cidr *ip_cidr_tmp = NULL; + + while (ip_cidr) + { + ip_cidr_tmp = ip_cidr; + ip_cidr = ip_cidr_tmp->next; + if (!only_free) + { + if (api->del_netif_ip) + { + struct network_configuration *network = + get_network_by_ip_with_tree(ip_cidr_tmp->ip); + if (network) + { + if (network->phy_net->bond_name[0] != 0) + { + (void) api->del_netif_ip(network->phy_net->bond_name, ip_cidr_tmp->ip); //fails only when netif_name not exist, no side effect so don't check return value. + } + else + { + (void) api->del_netif_ip(network->phy_net-> + header->nic_name, + ip_cidr_tmp->ip); + } + } + else + { + NSOPR_LOGERR("can't find network by]IP=%u", + ip_cidr_tmp->ip); + } + } + + trp_rb_erase((void *) (u64_t) ip_cidr_tmp->ip, + &g_container_ip_root, ip_compare); + } + + free(ip_cidr_tmp); + ip_cidr_tmp = NULL; + } +} + +static void +free_container_multicast(struct container_multicast_id *multicast, + bool_t only_free) +{ + struct container_multicast_id *tmp = NULL; + + while (multicast) + { + tmp = multicast; + multicast = multicast->next; + if (!only_free) + { + trp_rb_erase((void *) (u64_t) tmp->ip, + &g_container_multicast_root, ip_compare); + } + + free(tmp); + tmp = NULL; + } +} + +static void free_container_port(struct container_port *port, bool_t only_free) +{ + struct container_port *port_tmp = NULL; + struct container_port *port_curr = port; + + while (port_curr) + { + port_tmp = port_curr; + port_curr = port_tmp->next; + + free_container_multicast(port_tmp->multicast_list, only_free); + free_container_port_ip_cidr(port_tmp->ip_cidr_list, only_free); + + if (port_tmp->buffer) + { + free_port_buffer(port_tmp->buffer); + port_tmp->buffer = NULL; + } + + free(port_tmp); + port_tmp = NULL; + } +} + +void free_container(struct container_ip *container, bool_t only_free) +{ + struct container_ip *container_tmp = NULL; + struct container_ip *container_curr = container; + + while (container_curr) + { + container_tmp = container_curr; + container_curr = container_tmp->next; + if (container_tmp->ports_list) + { + free_container_port(container_tmp->ports_list, only_free); + } + + free(container_tmp); + container_tmp = NULL; + } +} + +struct container_port *parse_port_obj(struct json_object *port_obj) +{ + int retval; + struct json_object *port_name_obj = NULL; + struct json_object *ip_cidr_list_obj = NULL; + struct json_object *mcIDObj = NULL; + + if (!port_obj) + { + NSOPR_LOGERR("port_obj is null"); + return NULL; + } + + struct container_port *port = malloc(sizeof(struct container_port)); + if (!port) + { + NSOPR_LOGERR("malloc failed"); + return NULL; + } + + retval = + memset_s(port, sizeof(struct container_port), 0, + sizeof(struct container_port)); + if (EOK != retval) + { + NSOPR_LOGERR("MEMSET_S failed]ret=%d", retval); + free(port); + return NULL; + } + + json_object_object_get_ex(port_obj, "port_name", &port_name_obj); + if (port_name_obj) + { + const char *port_name = json_object_get_string(port_name_obj); + if ((NULL == port_name) + || (strlen(port_name) >= IP_MODULE_MAX_NAME_LEN)) + { + NSOPR_LOGERR("port name is not ok"); + goto RETURN_ERROR; + } + + retval = + strcpy_s(port->port_name, sizeof(port->port_name), port_name); + + if (EOK != retval) + { + NSOPR_LOGERR("STRCPY_S failed]ret=%d", retval); + goto RETURN_ERROR; + } + } + + json_object_object_get_ex(port_obj, "ip_cidr", &ip_cidr_list_obj); + if (ip_cidr_list_obj) + { + int j; + int ip_cidr_num = json_object_array_length(ip_cidr_list_obj); + for (j = 0; j < ip_cidr_num; ++j) + { + struct json_object *ip_cidr_obj = + json_object_array_get_idx(ip_cidr_list_obj, j); + if (ip_cidr_obj) + { + char tmp[IP_MODULE_LENGTH_32] = { 0 }; + struct container_port_ip_cidr *port_ip_cidr = + malloc(sizeof(struct container_port_ip_cidr)); + if (NULL == port_ip_cidr) + { + NSOPR_LOGERR("malloc failed"); + goto RETURN_ERROR; + } + + retval = + memset_s(port_ip_cidr, + sizeof(struct container_port_ip_cidr), 0, + sizeof(struct container_port_ip_cidr)); + if (EOK != retval) + { + NSOPR_LOGERR("MEMSET_S failed]ret=%d", retval); + free(port_ip_cidr); + port_ip_cidr = NULL; + goto RETURN_ERROR; + } + + const char *ip_cidr = json_object_get_string(ip_cidr_obj); + if ((NULL == ip_cidr) || (ip_cidr[0] == 0)) + { + NSOPR_LOGERR("ip_cidr is not ok"); + free(port_ip_cidr); + port_ip_cidr = NULL; + goto RETURN_ERROR; + } + + const char *sub = strstr(ip_cidr, "/"); + if ((NULL == sub) + || (sizeof(tmp) - 1 < (unsigned int) (sub - ip_cidr)) + || (strlen(sub) > sizeof(tmp) - 1)) + { + NSOPR_LOGERR + ("Error : Ipaddress notation must be in ip cidr notation!"); + free(port_ip_cidr); + port_ip_cidr = NULL; + goto RETURN_ERROR; + } + + retval = + strncpy_s(tmp, sizeof(tmp), ip_cidr, + (size_t) (sub - ip_cidr)); + if (EOK != retval) + { + NSOPR_LOGERR("STRNCPY_S failed]ret=%d", retval); + free(port_ip_cidr); + port_ip_cidr = NULL; + goto RETURN_ERROR; + } + + struct in_addr addr; + int iRet; + retval = memset_s(&addr, sizeof(addr), 0, sizeof(addr)); + if (EOK != retval) + { + NSOPR_LOGERR("MEMSET_S failed]ret=%d", retval); + free(port_ip_cidr); + port_ip_cidr = NULL; + goto RETURN_ERROR; + } + + iRet = spl_inet_aton(tmp, &addr); + if (0 == iRet) + { + NSOPR_LOGERR("spl_inet_aton failed"); + free(port_ip_cidr); + port_ip_cidr = NULL; + goto RETURN_ERROR; + } + + port_ip_cidr->ip = addr.s_addr; + iRet = atoi(sub + 1); + if ((iRet <= 0) || (iRet > IP_MODULE_LENGTH_32)) + { + NSOPR_LOGERR("IP mask length is not correct"); + free(port_ip_cidr); + port_ip_cidr = NULL; + goto RETURN_ERROR; + } + + port_ip_cidr->mask_len = (unsigned int) iRet; + add_ip_cidr(port, port_ip_cidr); + } + } + } + + json_object_object_get_ex(port_obj, "multicast_id", &mcIDObj); + if (mcIDObj) + { + int j; + int arrLen = json_object_array_length(mcIDObj); + if (0 == arrLen) + { + NSOPR_LOGERR("arrLen is 0"); + goto RETURN_ERROR; + } + + for (j = 0; j < arrLen; ++j) + { + struct json_object *elemObj = + json_object_array_get_idx(mcIDObj, j); + + if (elemObj) + { + struct json_object *tObj = NULL; + const char *tStr; + int ret; + struct in_addr addr; + + struct container_multicast_id *mcID = + malloc(sizeof(struct container_multicast_id)); + if (NULL == mcID) + { + NSOPR_LOGERR("Can't alloc container multicast id"); + goto RETURN_ERROR; + } + + json_object_object_get_ex(elemObj, "group_ip", &tObj); + if (NULL == tObj) + { + NSOPR_LOGERR("No group_IP"); + free(mcID); + mcID = NULL; + goto RETURN_ERROR; + } + + tStr = json_object_get_string(tObj); + if (NULL == tStr) + { + NSOPR_LOGERR("Get Multiple cast group IP Failed"); + free(mcID); + mcID = NULL; + goto RETURN_ERROR; + } + + ret = spl_inet_aton(tStr, &addr); + if (0 == ret) + { + NSOPR_LOGERR("Parse group IP Failed"); + free(mcID); + mcID = NULL; + goto RETURN_ERROR; + } + + mcID->ip = addr.s_addr; + add_multilcast_ip(port, mcID); + } + } + } + + const char *port_json = json_object_get_string(port_obj); + if ((NULL == port_json) || (0 == strlen(port_json))) + { + NSOPR_LOGERR("json_object_get_string failed"); + goto RETURN_ERROR; + } + + port->buffer = malloc_port_buffer(); + if (!port->buffer) + { + goto RETURN_ERROR; + } + + retval = + strcpy_s(get_port_json(port), IP_MODULE_PORT_JSON_LEN, port_json); + if (EOK != retval) + { + NSOPR_LOGERR("STRCPY_S failed]ret=%d", retval); + goto RETURN_ERROR; + } + + return port; + RETURN_ERROR: + free_container_port(port, IP_MODULE_TRUE); + return NULL; +} + +struct container_ip *parse_container_ip_json(char *param) +{ + int retval; + struct json_object *obj = json_tokener_parse(param); + struct json_object *container_id_obj = NULL; + struct json_object *ports_list_obj = NULL; + + if (!obj) + { + return NULL; + } + + struct container_ip *container = malloc(sizeof(struct container_ip)); + if (container == NULL) + { + json_object_put(obj); + return NULL; + } + + retval = + memset_s(container, sizeof(struct container_ip), 0, + sizeof(struct container_ip)); + if (EOK != retval) + { + NSOPR_LOGERR("MEMSET_S failed]ret=%d", retval); + goto RETURN_ERROR; + } + + json_object_object_get_ex(obj, "containerID", &container_id_obj); + if (container_id_obj) + { + const char *container_id = json_object_get_string(container_id_obj); + if ((container_id == NULL) || (container_id[0] == 0) + || (strlen(container_id) >= IP_MODULE_MAX_NAME_LEN)) + { + goto RETURN_ERROR; + } + + retval = + memset_s(container->container_id, sizeof(container->container_id), + 0, sizeof(container->container_id)); + if (EOK != retval) + { + NSOPR_LOGERR("MEMSET_S failed]ret=%d", retval); + goto RETURN_ERROR; + } + + retval = + strcpy_s(container->container_id, sizeof(container->container_id), + container_id); + + if (EOK != retval) + { + NSOPR_LOGERR("STRCPY_S failed]ret=%d", retval); + goto RETURN_ERROR; + } + } + else + { + /* this mandatory parameter */ + NSOPR_LOGWAR("json_object_object_get_ex containerID failed"); + } + + json_object_object_get_ex(obj, "ports_list", &ports_list_obj); + if (ports_list_obj) + { + int i; + int port_num = json_object_array_length(ports_list_obj); + + if (port_num == 0) + { + /* this mandatory parameter */ + goto RETURN_ERROR; + } + + for (i = 0; i < port_num; i++) + { + struct json_object *port_obj = + json_object_array_get_idx(ports_list_obj, i); + struct container_port *port = parse_port_obj(port_obj); + if (!port) + { + goto RETURN_ERROR; + } + + add_port(container, port); + } + } + else + { + /* mandatory parameter */ + goto RETURN_ERROR; + } + + /* Check if this function is required, or needs more check inside this function, + as some of them are alraedy validated + */ + if (!is_container_ok(container)) + { + goto RETURN_ERROR; + } + + json_object_put(obj); + return container; + + RETURN_ERROR: + json_object_put(obj); + free_container(container, IP_MODULE_TRUE); + return NULL; +} + +bool_t is_ip_match_netif(unsigned int ip, char *netif_name) +{ + if (!netif_name) + { + return 0; + } + + if (trp_rb_search((void *) (u64_t) ip, &g_container_ip_root, ip_compare)) + { + struct network_configuration *network = + get_network_by_ip_with_tree(ip); + if (network && network->phy_net && network->phy_net->header) + { + if (0 == + strncmp(netif_name, network->phy_net->header->nic_name, + HAL_MAX_NIC_NAME_LEN)) + { + return 1; + } + } + } + + return 0; +} + +inline bool_t is_ip_exist(unsigned int ip) +{ + if (trp_rb_search((void *) (u64_t) ip, &g_container_ip_root, ip_compare)) + { + return 1; + } + + return 0; +} + +int validate_addcontainerconfig(struct container_ip *container) +{ + struct container_port *port; + struct container_ip *old = + get_container_by_container_id(container->container_id); + struct container_port *tmp = container->ports_list; + + if (old) + { + struct container_port *last = NULL; + + while (tmp) + { + if (get_port(container->container_id, tmp->port_name)) + { + NSOPR_LOGERR("port=%s already exists!", tmp->port_name); + return NSCRTL_RD_EXIST; + } + + last = tmp; + tmp = tmp->next; + } + + (void) last; + } + + /* check if port_name duplicates in one json configuration */ + tmp = container->ports_list; + while (tmp) + { + if (get_port_from_container(tmp)) + { + NSOPR_LOGERR("port=%s duplicates!", tmp->port_name); + return NSCRTL_RD_EXIST; + } + + tmp = tmp->next; + } + + bool_t is_nstack_dpdk_port; + struct container_port **ref = &container->ports_list; + while ((port = *ref)) + { + is_nstack_dpdk_port = 1; + struct container_port_ip_cidr *ip_cidr = port->ip_cidr_list; + while (ip_cidr) + { + struct network_configuration *network = + get_network_by_ip_with_tree(ip_cidr->ip); + if (network && (0 == strcmp(network->type_name, "nstack-dpdk"))) + { + struct netif *pnetif; + if (get_netif_by_ip(ip_cidr->ip)) + { + NSOPR_LOGERR("ip exists]IP=0x%08x", ip_cidr->ip); + return NSCRTL_RD_EXIST; + } + + if (network->phy_net->bond_name[0] != 0) + { + pnetif = + find_netif_by_if_name(network->phy_net->bond_name); + } + else + { + pnetif = + find_netif_by_if_name(network->phy_net-> + header->nic_name); + } + + if (!pnetif) + { + NSOPR_LOGERR("can't find netif, network json:%s", + get_network_json(network)); + return NSCRTL_ERR; + } + + if (0 == port->port_name[0]) + { + NSOPR_LOGINF + ("ip=0x%08x is in nstack dpdk network, but port_name is null, json:%s", + ip_cidr->ip, get_port_json(port)); + is_nstack_dpdk_port = 0; + break; + } + } + else + { + NSOPR_LOGINF("port %s is not in nstack dpdk network, json:%s", + port->port_name, get_port_json(port)); + is_nstack_dpdk_port = 0; + break; + } + + ip_cidr = ip_cidr->next; + } + + /* only use nstack dpdk port */ + if (is_nstack_dpdk_port) + { + ref = &port->next; + } + else + { + *ref = port->next; + port->next = NULL; + free_container_port(port, IP_MODULE_TRUE); + } + } + + return (!container->ports_list) ? NSCRTL_FREE_ALL_PORT : NSCRTL_OK; +} + +/* get the num of IPs in a container , which in a certain subnet */ +extern struct network_list g_network_list; +extern inline int is_in_subnet(unsigned int ip, struct ip_subnet *subnet); +NSTACK_STATIC inline int get_network_ip_count + (struct container_ip *container, struct ip_subnet *subnet) +{ + int ip_count = 0; + struct container_port *port_list = NULL; + struct container_ip *ci = container; + + while (ci) + { + port_list = ci->ports_list; + while (port_list) + { + struct container_port_ip_cidr *ip_list = port_list->ip_cidr_list; + while (ip_list) + { + if (!is_in_subnet(ip_list->ip, subnet)) + { + ip_count++; + } + + ip_list = ip_list->next; + } + + port_list = port_list->next; + } + + ci = ci->next; + } + + return ip_count; +} + +int check_ip_count(struct container_ip *container) +{ + int cur_count = 0; + int new_count = 0; + + if (NULL == container) + { + return 1; + } + + struct network_configuration *network = g_network_list.header; + while (network) + { + cur_count = + get_network_ip_count(g_container_list.header, network->ip_subnet); + new_count = get_network_ip_count(container, network->ip_subnet); + + if ((cur_count > MAX_NETWORK_IP_COUNT) + || (new_count > MAX_NETWORK_IP_COUNT) + || (cur_count + new_count > MAX_NETWORK_IP_COUNT)) + { + NSOPR_LOGERR + ("reach ip addr max count]network=%s, max=%d, current=%d, new=%d.", + network->network_name, MAX_NETWORK_IP_COUNT, cur_count, + new_count); + return 0; + } + + network = network->next; + } + + return 1; +} + +int +match_groupaddr(struct container_multicast_id *multi_list, + spl_ip_addr_t * groupaddr) +{ + struct container_multicast_id *group_info = multi_list; + + while (group_info) + { + if (group_info->ip == groupaddr->addr) + { + return 1; + } + + group_info = group_info->next; + } + + return 0; +} + +int add_container(struct container_ip *container) +{ + int retVal = 0; + + /* need to check if any of the netif operation failed, then we should return fail */ + retVal = validate_addcontainerconfig(container); + if (retVal != NSCRTL_OK) + { + free_container(container, IP_MODULE_TRUE); + return (NSCRTL_FREE_ALL_PORT == retVal) ? NSCRTL_OK : retVal; + } + + /* control max network and ipaddress count */ + if (!check_ip_count(container)) + { + free_container(container, IP_MODULE_TRUE); + return NSCRTL_IP_COUNT_EXCEED; + } + + struct container_port *last = NULL; + struct container_ip *old = + get_container_by_container_id(container->container_id); + if (old) + { + struct container_port *tmp = container->ports_list; + while (tmp) + { + /* here we don't need to check "if tmp->port_name == NULL", as validate_addcontainerconfig() has done this. */ + if (get_port(container->container_id, tmp->port_name)) + { + free_container(container, IP_MODULE_TRUE); + NSOPR_LOGERR("port exist!"); + return NSCRTL_RD_EXIST; + } + + last = tmp; + tmp = tmp->next; + } + } + else + { + container->next = g_container_list.header; + g_container_list.header = container; + } + + output_api *api = get_output_api(); + struct container_port *port = container->ports_list; + while (port) + { + struct container_port_ip_cidr *ip_cidr = port->ip_cidr_list; + while (ip_cidr) + { + if (api->add_netif_ip) + { + struct network_configuration *network = + get_network_by_ip_with_tree(ip_cidr->ip); + if (network) + { + unsigned int mask = ~0; + mask = + (mask << + (IP_MODULE_SUBNET_MASK_LEN - ip_cidr->mask_len)); + mask = spl_htonl(mask); + if (network->phy_net->bond_name[0] != 0) + { + (void) api->add_netif_ip(network->phy_net->bond_name, ip_cidr->ip, mask); //no need to check return value, validate_addcontainerconfig() has been checked parameters. + } + else + { + (void) api->add_netif_ip(network->phy_net-> + header->nic_name, + ip_cidr->ip, mask); + } + } + else + { + NSOPR_LOGERR("can't find network by]IP=%u,port_name=%s", + ip_cidr->ip, port->port_name); + } + } + + retVal = + trp_rb_insert((void *) (u64_t) ip_cidr->ip, (void *) port, + &g_container_ip_root, ip_compare); + + if (0 != retVal) + { + NSOPR_LOGERR("trp_rb_insert failed]ip_cidr->ip=%u", + ip_cidr->ip); + } + + ip_cidr = ip_cidr->next; + } + port = port->next; + } + + if (old) + { + if (last) + { + last->next = old->ports_list; + old->ports_list = container->ports_list; + } + + container->ports_list = NULL; + free_container(container, IP_MODULE_FALSE); + } + + return NSCRTL_OK; +} + +struct container_ip *get_container_by_container_id(char *container_id) +{ + if (NULL == container_id) + { + NSOPR_LOGERR("Param input container ID is NULL"); + return NULL; + } + + struct container_ip *container = g_container_list.header; + while (container) + { + if (0 == strcmp(container->container_id, container_id)) + { + return container; + } + + container = container->next; + } + + return NULL; +} + +/***************************************************************************** +* Prototype : getIpCfgAll +* Description : Get All ip configurations +* Input : char * +* size_t +* Output : char * patern:[***,***,***] +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int getIpCfgAll(char *jsonBuf, size_t size) +{ + int retval; + + if (NULL == jsonBuf) + { + return NSCRTL_ERR; + } + + if (size < 2) + { + NSOPR_LOGERR("get all ip cfg error, buffer is not enough."); + return NSCRTL_STATUS_ERR; + } + + char bfirstData = 1; + *jsonBuf = '['; + jsonBuf = jsonBuf + 1; + + /*need another two char to keep [and ] */ + size_t len = size - 2; + size_t strsize = 0; + struct container_port *port = NULL; + struct container_ip *container = g_container_list.header; + while (container) + { + port = container->ports_list; + while (port) + { + if (NULL == port->buffer) + { + port = port->next; + continue; + } + + strsize = strlen(get_port_json(port)) + 1; + + /*always reserve 1 char */ + if ((strsize > 0) && (strsize < len)) + { + if (bfirstData) + { + bfirstData = 0; + } + else + { + *jsonBuf = ','; + jsonBuf = jsonBuf + 1; + len = len - 1; + } + + retval = strcpy_s(jsonBuf, len, get_port_json(port)); + if (EOK != retval) + { + NSOPR_LOGERR("STRCPY_S failed]ret=%d", retval); + return NSCRTL_ERR; + } + + len = len - strlen(get_port_json(port)); + jsonBuf = jsonBuf + strlen(get_port_json(port)); + } + else + { + NSOPR_LOGERR("get all ip cfg error, buffer is not enough."); + return NSCRTL_STATUS_ERR; + } + + port = port->next; + } + + container = container->next; + } + + *jsonBuf = ']'; + return 0; +} + +int del_port(char *container_id, char *port_name) +{ + struct container_port *port = NULL; + struct container_port **ref = NULL; + struct container_ip *container = NULL; + struct container_ip **container_ref = &g_container_list.header; + + while ((container = *container_ref)) + { + NSOPR_LOGDBG("container->container_id=%s,container_id=%p", + container->container_id, container_id); + if (strcmp(container->container_id, container_id) == 0) + { + ref = &container->ports_list; + while ((port = *ref)) + { + if (strcmp(port_name, port->port_name) == 0) + { + *ref = port->next; + port->next = NULL; + free_container_port(port, IP_MODULE_FALSE); + return 0; + } + + ref = &port->next; + } + + break; + } + + container_ref = &container->next; + } + + return NSCRTL_RD_NOT_EXIST; +} + +struct container_port *get_port(char *container_id, char *port_name) +{ + struct container_port *port = NULL; + struct container_ip *container = g_container_list.header; + + while (container) + { + if (strcmp(container->container_id, container_id) == 0) + { + port = container->ports_list; + while (port) + { + if (strcmp(port_name, port->port_name) == 0) + { + return port; + } + + port = port->next; + } + } + + container = container->next; + } + + return NULL; +} + +struct container_port *get_port_from_container(struct container_port *port) +{ + char *port_name = port->port_name; + struct container_port *tmp = port->next; + + while (tmp) + { + if (strcmp(port_name, tmp->port_name) == 0) + { + return tmp; + } + + tmp = tmp->next; + } + + return NULL; +} diff --git a/stacks/lwip_stack/lwip_src/ip_module/ip_module_api.c b/stacks/lwip_stack/lwip_src/ip_module/ip_module_api.c new file mode 100644 index 0000000..d7ba054 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/ip_module/ip_module_api.c @@ -0,0 +1,356 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include <stdlib.h> +#include <string.h> +#include "inet.h" +#include "spl_ip_addr.h" +#include "ip_module_api.h" +#include "container_ip.h" +#include "network.h" +#include "config_common.h" +#include "configuration_reader.h" +#include "nstack_log.h" +#include "nstack_securec.h" +#include "spl_hal.h" +#include "stackx_spl_share.h" +#include "stackx/spl_api.h" +#include "stackx_common.h" +#include "spl_tcpip.h" + +static output_api g_output_api = { 0 }; + +void regist_output_api(output_api * api) +{ + if (NULL == api) + { + NSOPR_LOGERR("error!!!param api==NULL]"); + return; + } + + g_output_api = *api; +} + +output_api *get_output_api() +{ + return &g_output_api; +} + +int +process_post(void *arg, ip_module_type Type, + ip_module_operate_type operate_type) +{ + /* only when add network, in other words: + only when (IP_MODULE_NETWORK == Type) && (IP_MODULE_OPERATE_ADD == operate_type), + process_configuration() is called in read_fn thread itself. + other cases, will post_to tcpip_thread to handle them. + + tips: when add network, it need to post msg(add netif) to tcpip thread and wait a sem, + but after the msg is handled by tcpip thread, the sem could be post. + so adding netword is handled in read_fn thread, can't be moved to tcpip thread. + + But we should know, many global and static variables maybe not safe(netif,sc_dpdk etc.), + because they can be visited by multi-thread. */ + if ((IP_MODULE_NETWORK == Type) + && (IP_MODULE_OPERATE_ADD == operate_type)) + { + return process_configuration(arg, Type, operate_type); + } + + if (g_output_api.post_to) + { + int retval = g_output_api.post_to(arg, Type, operate_type); + if ((post_ip_module_msg == g_output_api.post_to) && (retval != ERR_OK) + && (arg != NULL)) + { + if ((IP_MODULE_IP == Type) + && (IP_MODULE_OPERATE_ADD == operate_type)) + { + free_container((struct container_ip *) arg, IP_MODULE_TRUE); + } + else + { + free(arg); + } + + arg = NULL; + NSOPR_LOGERR("post failed]ret=%d", retval); + NSOPR_SET_ERRINFO(NSCRTL_INPUT_ERR, "process_post failed!"); + } + + return retval; + } + else + { + NSOPR_LOGERR("g_output_api.post_to==NULL"); + NSOPR_SET_ERRINFO(NSCRTL_ERR, + "ERR:internal error, g_output_api.post_to==NULL]"); + return -1; + } +} + +/* arg can be NULL, no need check */ +int +process_configuration(void *arg, ip_module_type Type, + ip_module_operate_type operate_type) +{ + NSOPR_LOGINF("precoess begin]arg=%p,action=%d,type=%d", arg, operate_type, + Type); + int retval = 0; + + switch (Type) + { + case IP_MODULE_NETWORK: + switch (operate_type) + { + case IP_MODULE_OPERATE_ADD: + retval = + add_network_configuration((struct + network_configuration *) + arg); + + /* When network exceeds max number, just log warning at operation.log */ + if (retval == NSCRTL_NETWORK_COUNT_EXCEED) + { + NSOPR_LOGWAR + ("Warning!! Network count exceed max allowed number]max=%d", + MAX_NETWORK_COUNT); + } + else + { + NSOPR_SET_ERRINFO(retval, + "add_network_configuration return %d", + retval); + } + + if (!retval) + { + /*init DPDK eth */ + if ((retval = + init_new_network_configuration()) != ERR_OK) + { + free_network_configuration((struct + network_configuration + *) arg, + IP_MODULE_TRUE); + NSOPR_SET_ERRINFO(retval, + "init_new_network_configuration return %d", + retval); + } + } + break; + case IP_MODULE_OPERATE_DEL: + { + retval = del_network_by_name((char *) arg); + NSOPR_SET_ERRINFO(retval, + "del_network_by_name return %d", + retval); + free(arg); + arg = NULL; + } + break; + case IP_MODULE_OPERATE_QUERY: + { + struct network_configuration *network = + get_network_by_name((char *) arg); + if (!network) + { + retval = NSCRTL_RD_NOT_EXIST; + NSOPR_SET_ERRINFO(retval, + "get_network_by_name return %d", + retval); + } + else + { + if (strlen(get_network_json(network)) > + sizeof(get_config_data()->json_buff) - 1) + { + NSOPR_LOGERR + ("length of network->network_json too big]len=%u", + strlen(get_network_json(network))); + NSOPR_SET_ERRINFO(NSCRTL_ERR, + "ERR:internal error, buf is not enough]"); + retval = NSCRTL_ERR; + } + + retval = + strcpy_s(get_config_data()->json_buff, + sizeof(get_config_data()->json_buff), + get_network_json(network)); + if (EOK != retval) + { + NSOPR_LOGERR("STRCPY_S failed]ret=%d", + retval); + NSOPR_SET_ERRINFO(NSCRTL_ERR, + "ERR:internal error, STRCPY_S failed]ret=%d", + retval); + retval = NSCRTL_ERR; + } + + } + + free(arg); + arg = NULL; + } + break; + default: + break; + } + + break; + case IP_MODULE_IP: + switch (operate_type) + { + case IP_MODULE_OPERATE_ADD: + retval = add_container((struct container_ip *) arg); + NSOPR_SET_ERRINFO(retval, "add_container return %d", + retval); + break; + case IP_MODULE_OPERATE_DEL: + { + struct ip_action_param *p = + (struct ip_action_param *) arg; + retval = del_port(p->container_id, p->port_name); + NSOPR_SET_ERRINFO(retval, "del_port return %d", + retval); + free(arg); + arg = NULL; + } + break; + case IP_MODULE_OPERATE_QUERY: + { + struct ip_action_param *p = + (struct ip_action_param *) arg; + struct container_port *port = + get_port(p->container_id, p->port_name); + if (!port) + { + retval = NSCRTL_RD_NOT_EXIST; + NSOPR_SET_ERRINFO(retval, "get_port return %d", + retval); + } + else + { + if (strlen(get_port_json(port)) > + sizeof(get_config_data()->json_buff) - 1) + { + NSOPR_LOGERR + ("length of network->network_json too big]len=%u", + strlen(get_port_json(port))); + retval = NSCRTL_ERR; + } + + retval = + strcpy_s(get_config_data()->json_buff, + sizeof(get_config_data()->json_buff), + get_port_json(port)); + if (EOK != retval) + { + NSOPR_LOGERR("STRCPY_S failed]ret=%d", + retval); + retval = NSCRTL_ERR; + } + + } + + free(arg); + arg = NULL; + } + break; + default: + break; + } + + break; + case IP_MODULE_NETWORK_ALL: + if (operate_type == IP_MODULE_OPERATE_QUERY) + { + retval = + get_network_all(get_config_data()->json_buff, + sizeof(get_config_data()->json_buff)); + NSOPR_SET_ERRINFO(retval, "get_network_all return %d", + retval); + } + + break; + + case IP_MODULE_IP_ALL: + if (operate_type == IP_MODULE_OPERATE_QUERY) + { + retval = + getIpCfgAll(get_config_data()->json_buff, + sizeof(get_config_data()->json_buff)); + NSOPR_SET_ERRINFO(retval, "getIpCfgAll return %d", retval); + } + + break; + + case IP_MODULE_ALL: + if (operate_type == IP_MODULE_OPERATE_QUERY) + { + NSOPR_LOGERR + ("---------- IP_MODULE_ALL query is not implemented --------------"); + NSOPR_SET_ERRINFO(NSCRTL_ERR, + "ERR:This query interface is not implemented. ErrCode:%d", + NSCRTL_ERR); + } + + break; + + default: + break; + } + + NSOPR_LOGINF("process finished]result=%d", retval); + + return retval; +} + +void ip_subnet_print(struct ip_subnet *subnet) +{ + spl_ip_addr_t ipAddr; + + if (subnet == NULL) + { + return; + } + + ipAddr.addr = spl_htonl(subnet->subnet); + NSPOL_LOGINF(IP_DEBUG, "]\t Subnet=%s/%u", spl_inet_ntoa(ipAddr), + subnet->mask_len); +} + +port_buffer *malloc_port_buffer() +{ + port_buffer *buffer = malloc(sizeof(port_buffer)); + return buffer; +} + +void free_port_buffer(port_buffer * buffer) +{ + free(buffer); +} + +network_buffer *malloc_network_buffer() +{ + network_buffer *buffer = malloc(sizeof(network_buffer)); + return buffer; +} + +void free_network_buffer(network_buffer * buffer) +{ + free(buffer); +} diff --git a/stacks/lwip_stack/lwip_src/ip_module/network.c b/stacks/lwip_stack/lwip_src/ip_module/network.c new file mode 100644 index 0000000..d34c6a9 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/ip_module/network.c @@ -0,0 +1,1093 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include <stdio.h> +#include <sys/socket.h> +#include <string.h> +#include "json.h" +#include "trp_rb_tree.h" +#include "network.h" +#include "nstack_log.h" +#include "config_common.h" +#include "stackx_spl_share.h" +#include "stackx/spl_api.h" +#include "sharedmemory.h" +#include "nstack_securec.h" +#include "spl_hal.h" +#include "inet.h" + +struct network_list g_network_list = { 0 }; + +extern struct stackx_port_zone *p_stackx_port_zone; +extern u32 spl_hal_is_nic_exist(const char *name); + +static bool_t is_phy_net_ok(struct phy_net *pst_phy_net) +{ + if (!pst_phy_net || !pst_phy_net->header) + { + NSOPR_LOGERR("phy_net is not ok"); + return 0; + } + + return 1; +} + +static bool_t +is_network_configuration_ok(struct network_configuration *network) +{ + while (network) + { + if (!is_phy_net_ok(network->phy_net)) + { + return 0; + } + + network = network->next; + } + + return 1; +} + +static void +add_ref_nic(struct phy_net *pst_phy_net, struct ref_nic *pst_ref_nic) +{ + pst_ref_nic->next = pst_phy_net->header; + pst_phy_net->header = pst_ref_nic; +} + +static void free_ref_nic(struct ref_nic *pst_ref_nic) +{ + struct ref_nic *nic = pst_ref_nic; + struct ref_nic *tmp = NULL; + + while (nic) + { + tmp = nic; + nic = tmp->next; + free(tmp); + } +} + +static void free_phy_net(struct phy_net *pst_phy_net) +{ + if (pst_phy_net) + { + free_ref_nic(pst_phy_net->header); + free(pst_phy_net); + } +} + +static void free_ip_subnet(struct ip_subnet *subnet, bool_t only_free) +{ + struct ip_subnet *tmp = NULL; + + while (subnet) + { + tmp = subnet; + subnet = subnet->next; + free(tmp); + } +} + +void +free_network_configuration(struct network_configuration *network, + bool_t only_free) +{ + if (network) + { + free_ip_subnet(network->ip_subnet, only_free); + free_phy_net(network->phy_net); + + if (network->buffer) + { + free_network_buffer(network->buffer); + network->buffer = NULL; + } + + free(network); + } +} + +inline int is_in_subnet(unsigned int ip, struct ip_subnet *subnet) +{ + unsigned int mask = ~0; + unsigned int seg_ip, seg; + + mask = mask << (IP_MODULE_SUBNET_MASK_LEN - subnet->mask_len); + + seg_ip = ip & mask; + seg = subnet->subnet & mask; + + return seg_ip != seg ? 1 : 0; +} + +inline struct network_configuration *get_network_by_ip_with_tree(unsigned int + ip) +{ + unsigned int h_ip = spl_ntohl(ip); + struct network_configuration *p = g_network_list.header; + + while (p) + { + if (!is_in_subnet(h_ip, p->ip_subnet)) + { + return p; + } + + p = p->next; + } + + return NULL; +} + +struct network_configuration *get_network_by_name(char *name) +{ + struct network_configuration *network = g_network_list.header; + + while (network) + { + if (strcasecmp(name, network->network_name) == 0) + { + return network; + } + + network = network->next; + } + + return NULL; +} + +struct network_configuration *get_network_by_nic_name(char *name) +{ + if (NULL == name) + { + return NULL; + } + + struct ref_nic *refnic = NULL; + struct phy_net *phynet = NULL; + struct network_configuration *network = g_network_list.header; + while (network) + { + phynet = network->phy_net; + if (phynet) + { + if ((phynet->bond_mode != -1) + && strcmp(name, phynet->bond_name) == 0) + { + return network; + } + + refnic = phynet->header; + while (refnic) + { + if (strcmp(name, refnic->nic_name) == 0) + { + return network; + } + + refnic = refnic->next; + } + } + + network = network->next; + } + + return NULL; +} + +struct network_configuration *get_network_by_name_from_json(struct + network_configuration + *network) +{ + char *name = network->network_name; + struct network_configuration *tmp = network->next; + + while (tmp) + { + if (strcasecmp(name, tmp->network_name) == 0) + { + return tmp; + } + + tmp = tmp->next; + } + + return NULL; +} + +NSTACK_STATIC inline int get_network_count() +{ + int count = 0; + struct network_configuration *network = g_network_list.header; + + while (network) + { + count++; + network = network->next; + } + + return count; +} + +int get_network_all(char *jsonBuf, size_t size) +{ + if (NULL == jsonBuf) + { + return NSCRTL_ERR; + } + + if (size < 2) + { + NSOPR_LOGERR("get all ip cfg error, buffer is not enough."); + return NSCRTL_STATUS_ERR; + } + + int retVal; + char bfirstData = 1; + *jsonBuf = '['; + jsonBuf = jsonBuf + 1; + + size_t len = size - 2; // strlen("[]") + size_t strsize = 0; + struct network_configuration *network = g_network_list.header; + while (network) + { + if (NULL == network->buffer) + { + network = network->next; + continue; + } + + if (bfirstData) + { + bfirstData = 0; + } + else + { + *jsonBuf = ','; + jsonBuf = jsonBuf + 1; + len = len - 1; + } + + strsize = strlen(get_network_json(network)) + 1; + if ((strsize > 0) && (strsize < len)) + { + retVal = strcpy_s(jsonBuf, len, get_network_json(network)); + if (EOK != retVal) + { + NSOPR_LOGERR("STRCPY_S failed]ret=%d.", retVal); + return NSCRTL_STATUS_ERR; + } + + len = len - strlen(get_network_json(network)); + jsonBuf = jsonBuf + strlen(get_network_json(network)); + } + else + { + NSOPR_LOGERR("get all network cfg error, buffer is not enough."); + return NSCRTL_STATUS_ERR; + } + + network = network->next; + } + + *jsonBuf = ']'; + return 0; +} + +int nic_already_bind(const char *nic_name) +{ + struct ref_nic *pnic = NULL; + struct network_configuration *pnetwork = g_network_list.header; + + while (pnetwork) + { + pnic = pnetwork->phy_net->header; + while (pnic) + { + if (0 == strcmp(pnic->nic_name, nic_name)) + { + return 1; + } + + pnic = pnic->next; + } + + pnetwork = pnetwork->next; + } + + return 0; +} + +int nic_already_init(const char *nic_name) +{ + unsigned int i; + + for (i = 0; i < p_stackx_port_zone->port_num; i++) + { + if (0 == + strcmp(p_stackx_port_zone->stackx_one_port[i].linux_ip.if_name, + nic_name)) + { + return 1; + } + } + + return 0; +} + +extern struct stackx_port_info *head_used_port_list; +int +bonded_nic_already_bind(struct network_configuration *pnetwork, + const char *nic_name) +{ + struct stackx_port_info *p_port_list = head_used_port_list; + + while (p_port_list) + { + if (0 == strcmp(p_port_list->linux_ip.if_name, nic_name)) + { + return 1; + } + + p_port_list = p_port_list->next_use_port; + } + + struct ref_nic *pnic = NULL; + + while (pnetwork) + { + if (pnetwork->phy_net->bond_mode == -1) + { + pnic = pnetwork->phy_net->header; + if (0 == strcmp(pnic->nic_name, nic_name)) + { + return 1; + } + } + + pnetwork = pnetwork->next; + } + + return 0; +} + +extern struct bond_ports_info bond_ports_array; +int +nic_already_bond(struct network_configuration *pnetwork, const char *nic_name) +{ + u8_t i, j; + struct bond_set *s; + + for (i = 0; i < bond_ports_array.cnt; i++) + { + s = &bond_ports_array.ports[i]; + for (j = 0; j < s->slave_port_cnt; j++) + { + if (strcmp(s->slave_ports[j], nic_name) == 0) + { + return 1; + } + } + } + + struct ref_nic *pnic = NULL; + + while (pnetwork) + { + if (pnetwork->phy_net->bond_mode != -1) + { + pnic = pnetwork->phy_net->header; + while (pnic) + { + if (0 == strcmp(pnic->nic_name, nic_name)) + { + return 1; + } + + pnic = pnic->next; + } + } + + pnetwork = pnetwork->next; + } + + return 0; +} + +/* add network to list in descending sort */ +void add_network_to_list(struct network_configuration *network) +{ + struct network_configuration *curr = g_network_list.header; + struct network_configuration *prev = NULL; + + network->next = NULL; + + while (curr) + { + if (network->ip_subnet->mask_len >= curr->ip_subnet->mask_len) + { + break; + } + + prev = curr; + curr = curr->next; + } + + if (NULL == prev) + { + network->next = curr; + g_network_list.header = network; + } + else + { + network->next = prev->next; + prev->next = network; + } +} + +int +add_network_configuration(struct network_configuration + *pst_network_configuration) +{ + struct network_configuration *tmp = pst_network_configuration; + struct ref_nic *pheader; + + if (tmp) + { + if (get_network_by_name(tmp->network_name) + || get_network_by_name_from_json(tmp)) + { + NSOPR_LOGERR("network exists or duplicates]network_name=%s", + tmp->network_name); + free_network_configuration(pst_network_configuration, + IP_MODULE_TRUE); + return NSCRTL_RD_EXIST; + } + + if (strcasecmp("nstack-dpdk", tmp->type_name) != 0) + { + NSOPR_LOGWAR("illegal network type]type_name=%s", tmp->type_name); + } + + /* control max network and ipaddress count */ + if (get_network_count() >= MAX_NETWORK_COUNT) + { + NSOPR_LOGERR("network reach]max_count=%d", MAX_NETWORK_COUNT); + free_network_configuration(pst_network_configuration, + IP_MODULE_TRUE); + return NSCRTL_NETWORK_COUNT_EXCEED; + } + + /* If nic is not existed or not initiated, return error */ + pheader = tmp->phy_net->header; + while (pheader) + { + if (!spl_hal_is_nic_exist(pheader->nic_name) + && !nic_already_init(pheader->nic_name) + && strncmp(tmp->nic_type_name, "vhost", strlen("vhost"))) + { + NSOPR_LOGERR("Invalid configuration %s not exist Error! ", + pheader->nic_name); + free_network_configuration(pst_network_configuration, + IP_MODULE_TRUE); + return NSCRTL_RD_NOT_EXIST; + } + + pheader = pheader->next; + } + + /* if a bonded nic has been inited in a non-bond network, return error */ + if (tmp->phy_net->bond_mode != -1) + { + pheader = tmp->phy_net->header; + while (pheader) + { + if (bonded_nic_already_bind + (pst_network_configuration, pheader->nic_name)) + { + NSOPR_LOGERR("Invalid configuration %s already bind! ", + pheader->nic_name); + free_network_configuration(pst_network_configuration, + IP_MODULE_TRUE); + return NSCRTL_INPUT_ERR; + } + + pheader = pheader->next; + } + } + + /* if a non-bond nic has been inited in a bonded network, return error */ + if (tmp->phy_net->bond_mode == -1) + { + pheader = tmp->phy_net->header; + while (pheader) + { + if (nic_already_bond + (pst_network_configuration, pheader->nic_name)) + { + NSOPR_LOGERR("Invalid configuration %s already bind! ", + pheader->nic_name); + free_network_configuration(pst_network_configuration, + IP_MODULE_TRUE); + return NSCRTL_INPUT_ERR; + } + + pheader = pheader->next; + } + } + } + else + { + NSOPR_LOGERR("Invalid network configuration!"); + return NSCRTL_INPUT_ERR; + } + + /*looping through each node has move to read_ipmoduleoperateadd_configuration */ + ip_subnet_print(tmp->ip_subnet); + add_network_to_list(tmp); + + return NSCRTL_OK; +} + +struct network_configuration *parse_network_obj(struct json_object + *network_obj) +{ + int retVal; + struct network_configuration *pst_network_configuration = NULL; + struct json_object *network_name_obj = NULL, *args_obj = NULL, *phy_obj = + NULL, *type_name_obj = NULL; + struct json_object *ref_nic_list_obj = NULL, *bond_mode_obj = + NULL, *bond_name_obj = NULL, *ipam_obj = NULL; + struct json_object *subnet_obj = NULL, *nic_type_obj = NULL; + + if (!network_obj) + { + NSOPR_LOGERR("network_obj is null"); + goto RETURN_ERROR; + } + + pst_network_configuration = malloc(sizeof(struct network_configuration)); + if (NULL == pst_network_configuration) + { + NSOPR_LOGERR("malloc failed"); + goto RETURN_ERROR; + } + + retVal = + memset_s(pst_network_configuration, + sizeof(struct network_configuration), 0, + sizeof(struct network_configuration)); + if (EOK != retVal) + { + NSOPR_LOGERR("MEMSET_S failed]ret=%d.", retVal); + goto RETURN_ERROR; + } + + json_object_object_get_ex(network_obj, "name", &network_name_obj); + if (network_name_obj) + { + const char *network_name = json_object_get_string(network_name_obj); + if ((NULL == network_name) || (network_name[0] == 0) + || (strlen(network_name) >= IP_MODULE_MAX_NAME_LEN)) + { + NSOPR_LOGERR("network_name is not ok"); + goto RETURN_ERROR; + } + + retVal = + strcpy_s(pst_network_configuration->network_name, + sizeof(pst_network_configuration->network_name), + network_name); + + if (EOK != retVal) + { + NSOPR_LOGERR("STRCPY_S failed]ret=%d.", retVal); + goto RETURN_ERROR; + } + } + else + { + NSOPR_LOGERR("name is not ok"); + goto RETURN_ERROR; + } + + json_object_object_get_ex(network_obj, "type", &type_name_obj); + if (type_name_obj) + { + const char *type_name = json_object_get_string(type_name_obj); + if ((NULL == type_name) || (type_name[0] == 0) + || (strlen(type_name) >= IP_MODULE_MAX_NAME_LEN)) + { + NSOPR_LOGERR("type parse error"); + goto RETURN_ERROR; + } + + retVal = + strcpy_s(pst_network_configuration->type_name, + sizeof(pst_network_configuration->type_name), type_name); + + if (EOK != retVal) + { + NSOPR_LOGERR("STRCPY_S failed]ret=%d", retVal); + goto RETURN_ERROR; + } + } + else + { + NSOPR_LOGERR("type is not ok"); + goto RETURN_ERROR; + } + + json_object_object_get_ex(network_obj, "args", &args_obj); + if (args_obj) + { + json_object_object_get_ex(args_obj, "phynet", &phy_obj); + if (phy_obj) + { + struct phy_net *pst_phy_net = malloc(sizeof(struct phy_net)); + if (NULL == pst_phy_net) + { + NSOPR_LOGERR("malloc failed"); + goto RETURN_ERROR; + } + + retVal = + memset_s(pst_phy_net, sizeof(struct phy_net), 0, + sizeof(struct phy_net)); + if (EOK != retVal) + { + NSOPR_LOGERR("MEMSET_S failed]ret=%d", retVal); + free_phy_net(pst_phy_net); + goto RETURN_ERROR; + } + + json_object_object_get_ex(phy_obj, "nic_type", &nic_type_obj); /*lint !e534 no need to check return value */ + if (nic_type_obj) + { + const char *nic_type_name = + json_object_get_string(nic_type_obj); + if (strcmp(nic_type_name, "pci") != 0 + && strcmp(nic_type_name, "vhost") != 0) + { + NSOPR_LOGERR("unsupported nic_type]nic_type=%s", + nic_type_name); + goto RETURN_ERROR; + } + + retVal = + strcpy_s(pst_network_configuration->nic_type_name, + sizeof(pst_network_configuration->nic_type_name), + nic_type_name); + if (EOK != retVal) + { + NSOPR_LOGERR("strcpy_s failed]ret=%d", retVal); + goto RETURN_ERROR; + } + } + else + { + NSOPR_LOGINF + ("nic_type not specified, use default type]defaul nic_type=pci"); + retVal = + strcpy_s(pst_network_configuration->nic_type_name, + sizeof(pst_network_configuration->nic_type_name), + "pci"); + if (EOK != retVal) + { + NSOPR_LOGERR("strcpy_s failed]ret=%d", retVal); + goto RETURN_ERROR; + } + } + + json_object_object_get_ex(phy_obj, "ref_nic", &ref_nic_list_obj); + if (ref_nic_list_obj) + { + int j; + int ref_nic_num = json_object_array_length(ref_nic_list_obj); + if (0 == ref_nic_num) + { + NSOPR_LOGERR("ref_nic is empty"); + free_phy_net(pst_phy_net); + goto RETURN_ERROR; + } + + for (j = ref_nic_num - 1; j >= 0; j--) + { + struct json_object *ref_nic_obj = + json_object_array_get_idx(ref_nic_list_obj, j); + if (ref_nic_obj) + { + const char *nic_name = + json_object_get_string(ref_nic_obj); + if ((NULL == nic_name) || (nic_name[0] == 0) + || (strlen(nic_name) >= HAL_MAX_NIC_NAME_LEN)) + { + NSOPR_LOGERR("nic_name is not ok"); + free_phy_net(pst_phy_net); + goto RETURN_ERROR; + } + + struct ref_nic *pst_ref_nic = + malloc(sizeof(struct ref_nic)); + if (NULL == pst_ref_nic) + { + NSOPR_LOGERR("malloc failed"); + free_phy_net(pst_phy_net); + goto RETURN_ERROR; + } + + retVal = + memset_s(pst_ref_nic, sizeof(struct ref_nic), 0, + sizeof(struct ref_nic)); + if (EOK != retVal) + { + NSOPR_LOGERR("MEMSET_S failed]ret=%d.", retVal); + free(pst_ref_nic); + pst_ref_nic = NULL; + free_phy_net(pst_phy_net); + goto RETURN_ERROR; + } + + retVal = + strcpy_s(pst_ref_nic->nic_name, + sizeof(pst_ref_nic->nic_name), nic_name); + + if (EOK != retVal) + { + NSOPR_LOGERR("STRCPY_S failed]ret=%d.", retVal); + free(pst_ref_nic); + free_phy_net(pst_phy_net); + goto RETURN_ERROR; + } + + add_ref_nic(pst_phy_net, pst_ref_nic); + } + } + } + else + { + NSOPR_LOGERR("ref_nic is not ok"); + free_phy_net(pst_phy_net); + goto RETURN_ERROR; + } + + json_object_object_get_ex(phy_obj, "bond_mode", &bond_mode_obj); + if (bond_mode_obj) + { + pst_phy_net->bond_mode = json_object_get_int(bond_mode_obj); + if (pst_phy_net->bond_mode != -1) + { + json_object_object_get_ex(phy_obj, "bond_name", + &bond_name_obj); + if (bond_name_obj) + { + const char *bond_name = + json_object_get_string(bond_name_obj); + if ((NULL == bond_name) + || (strlen(bond_name) >= IP_MODULE_MAX_NAME_LEN)) + { + NSOPR_LOGERR("bond_name is not ok"); + free_phy_net(pst_phy_net); + goto RETURN_ERROR; + } + + retVal = + memset_s(pst_phy_net->bond_name, + sizeof(pst_phy_net->bond_name), 0, + sizeof(pst_phy_net->bond_name)); + + if (EOK != retVal) + { + NSOPR_LOGERR("MEMSET_S failed]ret=%d.", retVal); + free_phy_net(pst_phy_net); + goto RETURN_ERROR; + } + + retVal = + strncpy_s(pst_phy_net->bond_name, + sizeof(pst_phy_net->bond_name), + bond_name, strlen(bond_name)); + + if (EOK != retVal) + { + NSOPR_LOGERR("STRNCPY_S failed]retVal=%d", + retVal); + free_phy_net(pst_phy_net); + goto RETURN_ERROR; + } + } + else + { + NSOPR_LOGERR("bond_name is not ok"); + free_phy_net(pst_phy_net); + goto RETURN_ERROR; + } + } + } + else + { + pst_phy_net->bond_mode = -1; + } + + pst_network_configuration->phy_net = pst_phy_net; + } + else + { + NSOPR_LOGERR("phy_net is not ok"); + goto RETURN_ERROR; + } + } + else + { + NSOPR_LOGERR("args is not ok"); + goto RETURN_ERROR; + } + + json_object_object_get_ex(network_obj, "ipam", &ipam_obj); + if (ipam_obj) + { + json_object_object_get_ex(ipam_obj, "subnet", &subnet_obj); + if (subnet_obj) + { + int iRet; + char tmp[IP_MODULE_LENGTH_32] = { 0 }; + const char *subnet = json_object_get_string(subnet_obj); + struct in_addr addr; + + retVal = memset_s(&addr, sizeof(addr), 0, sizeof(addr)); + if (EOK != retVal) + { + NSOPR_LOGERR("MEMSET_S failed]ret=%d.", retVal); + goto RETURN_ERROR; + } + + if ((NULL == subnet) || (subnet[0] == 0) + || (strlen(subnet) > IP_MODULE_LENGTH_32)) + { + NSOPR_LOGERR("subnet is not ok"); + goto RETURN_ERROR; + } + + const char *sub = strstr(subnet, "/"); + if ((NULL == sub) + || (sizeof(tmp) - 1 <= (unsigned int) (sub - subnet)) + || (strlen(sub) >= sizeof(tmp) - 1)) + { + NSOPR_LOGERR("subnet is not ok"); + goto RETURN_ERROR; + } + + iRet = + strncpy_s(tmp, sizeof(tmp), subnet, (size_t) (sub - subnet)); + if (EOK != iRet) + { + NSOPR_LOGERR("STRNCPY_S failed]ret=%d", iRet); + goto RETURN_ERROR; + } + + iRet = spl_inet_aton(tmp, &addr); + if (0 == iRet) + { + NSOPR_LOGERR("subnet is not ok"); + goto RETURN_ERROR; + } + + pst_network_configuration->ip_subnet = + (struct ip_subnet *) malloc(sizeof(struct ip_subnet)); + if (!pst_network_configuration->ip_subnet) + { + NSOPR_LOGERR("malloc failed"); + goto RETURN_ERROR; + } + + retVal = + memset_s(pst_network_configuration->ip_subnet, + sizeof(struct ip_subnet), 0, + sizeof(struct ip_subnet)); + if (EOK != retVal) + { + NSOPR_LOGERR("MEMSET_S failed]ret=%d.", retVal); + goto RETURN_ERROR; + } + + pst_network_configuration->ip_subnet->next = NULL; + pst_network_configuration->ip_subnet->subnet = + spl_ntohl(addr.s_addr); + + iRet = atoi(sub + 1); + if ((iRet < 0) || (iRet > IP_MODULE_LENGTH_32)) + { + NSOPR_LOGERR("mask is not ok"); + goto RETURN_ERROR; + } + + pst_network_configuration->ip_subnet->mask_len = + (unsigned int) iRet; + } + else + { + NSOPR_LOGERR("subnet is not ok"); + goto RETURN_ERROR; + } + } + else + { + NSOPR_LOGERR("ipam is not ok"); + goto RETURN_ERROR; + } + + const char *network_json = json_object_get_string(network_obj); + if ((NULL == network_json) || (network_json[0] == 0)) + { + NSOPR_LOGERR("json_object_get_string failed"); + goto RETURN_ERROR; + } + + pst_network_configuration->buffer = malloc_network_buffer(); + if (!pst_network_configuration->buffer) + { + NSOPR_LOGERR("malloc_network_buffer failed"); + goto RETURN_ERROR; + } + + retVal = + strcpy_s(get_network_json(pst_network_configuration), + IP_MODULE_NETWORK_JSON_LEN, network_json); + if (EOK != retVal) + { + NSOPR_LOGERR("STRCPY_S failed]ret=%d.", retVal); + goto RETURN_ERROR; + } + + return pst_network_configuration; + + RETURN_ERROR: + if (pst_network_configuration) + { + free_network_configuration(pst_network_configuration, IP_MODULE_TRUE); + pst_network_configuration = NULL; + } + + return NULL; +} + +struct network_configuration *parse_network_json(char *param, + struct network_configuration + *pnetwork_list) +{ + struct json_object *obj = json_tokener_parse(param); + struct network_configuration *pst_network_configuration = NULL; + + if (!obj) + { + NSOPR_LOGERR("parse error"); + return NULL; + } + + int network_num = json_object_array_length(obj); + if (0 == network_num) + { + json_object_put(obj); + return NULL; + } + + int i; + for (i = 0; i < network_num; i++) + { + struct json_object *network_obj = json_object_array_get_idx(obj, i); + if (network_obj) + { + pst_network_configuration = parse_network_obj(network_obj); + if (!pst_network_configuration) + { + NSOPR_LOGERR("parse_network_obj error"); + goto RETURN_ERROR; + } + + pst_network_configuration->next = pnetwork_list; + pnetwork_list = pst_network_configuration; + pst_network_configuration = NULL; + } + else + { + NSOPR_LOGERR("network_obj is NULL"); + goto RETURN_ERROR; + } + } + + if (pnetwork_list) + { + if (!is_network_configuration_ok(pnetwork_list)) + { + NSOPR_LOGERR("network_configuration is not ok"); + goto RETURN_ERROR; + } + } + + json_object_put(obj); + return pnetwork_list; + + RETURN_ERROR: + free_network_configuration(pnetwork_list, IP_MODULE_TRUE); + json_object_put(obj); + return NULL; +} + +int del_network_by_name(char *name) +{ + struct network_configuration *network = NULL; + struct network_configuration **ref = &g_network_list.header; + + while ((network = *ref)) + { + if (strcasecmp(name, network->network_name) == 0) + { + *ref = network->next; + network->next = NULL; + + free_network_configuration(network, IP_MODULE_FALSE); + return 0; + } + + ref = &network->next; + } + + return NSCRTL_RD_NOT_EXIST; +} + +int is_in_same_network(unsigned int src_ip, unsigned int dst_ip) +{ + if (src_ip == dst_ip) + { + return 1; + } + + struct network_configuration *src = get_network_by_ip_with_tree(src_ip); + struct network_configuration *dst = get_network_by_ip_with_tree(dst_ip); + if (src && (src == dst)) + { + return 1; + } + + return 0; +} + +struct network_configuration *get_network_list() +{ + return g_network_list.header; +} diff --git a/stacks/lwip_stack/lwip_src/ip_module/trp_rb_tree.c b/stacks/lwip_stack/lwip_src/ip_module/trp_rb_tree.c new file mode 100644 index 0000000..4f129d4 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/ip_module/trp_rb_tree.c @@ -0,0 +1,563 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "trp_rb_tree.h" + +NSTACK_STATIC void +__rb_rotate_left(struct trp_rb_node *X, struct trp_rb_root *root) +{ + /************************** + * rotate Node X to left * + **************************/ + + struct trp_rb_node *Y = X->rb_right; + + /* estblish X->Right link */ + X->rb_right = Y->rb_left; + if (Y->rb_left != NULL) + Y->rb_left->rb_parent = X; + + /* estblish Y->Parent link */ + Y->rb_parent = X->rb_parent; + if (X->rb_parent) + { + if (X == X->rb_parent->rb_left) + X->rb_parent->rb_left = Y; + else + X->rb_parent->rb_right = Y; + } + else + { + root->rb_node = Y; + } + + /* link X and Y */ + Y->rb_left = X; + X->rb_parent = Y; + + return; +} + +NSTACK_STATIC void +__rb_rotate_right(struct trp_rb_node *X, struct trp_rb_root *root) +{ + /**************************** + * rotate Node X to right * + ****************************/ + + struct trp_rb_node *Y = X->rb_left; + + /* estblish X->Left link */ + X->rb_left = Y->rb_right; + if (Y->rb_right != NULL) + Y->rb_right->rb_parent = X; + + /* estblish Y->Parent link */ + Y->rb_parent = X->rb_parent; + if (X->rb_parent) + { + if (X == X->rb_parent->rb_right) + X->rb_parent->rb_right = Y; + else + X->rb_parent->rb_left = Y; + } + else + { + root->rb_node = Y; + } + + /* link X and Y */ + Y->rb_right = X; + X->rb_parent = Y; + + return; +} + +/* X, Y are for application */ +NSTACK_STATIC void +__rb_erase_color(struct trp_rb_node *X, struct trp_rb_node *Parent, + struct trp_rb_root *root) +{ + /************************************* + * maintain red-black tree balance * + * after deleting node X * + *************************************/ + + while (X != root->rb_node && (!X || X->color == RB_BLACK)) + { + + if (Parent == NULL) + { + break; + } + + if (X == Parent->rb_left) + { + struct trp_rb_node *W = Parent->rb_right; + if (W->color == RB_RED) + { + W->color = RB_BLACK; + Parent->color = RB_RED; /* Parent != NIL? */ + __rb_rotate_left(Parent, root); + W = Parent->rb_right; + } + + if ((!W->rb_left || W->rb_left->color == RB_BLACK) + && (!W->rb_right || W->rb_right->color == RB_BLACK)) + { + W->color = RB_RED; + X = Parent; + Parent = X->rb_parent; + } + else + { + if (!W->rb_right || W->rb_right->color == RB_BLACK) + { + if (W->rb_left != NULL) + W->rb_left->color = RB_BLACK; + W->color = RB_RED; + __rb_rotate_right(W, root); + W = Parent->rb_right; + } + + W->color = Parent->color; + Parent->color = RB_BLACK; + if (W->rb_right->color != RB_BLACK) + { + W->rb_right->color = RB_BLACK; + } + __rb_rotate_left(Parent, root); + X = root->rb_node; + break; + } + } + else + { + + struct trp_rb_node *W = Parent->rb_left; + if (W->color == RB_RED) + { + W->color = RB_BLACK; + Parent->color = RB_RED; /* Parent != NIL? */ + __rb_rotate_right(Parent, root); + W = Parent->rb_left; + } + + if ((!W->rb_left || (W->rb_left->color == RB_BLACK)) + && (!W->rb_right || (W->rb_right->color == RB_BLACK))) + { + W->color = RB_RED; + X = Parent; + Parent = X->rb_parent; + } + else + { + if (!W->rb_left || (W->rb_left->color == RB_BLACK)) + { + if (W->rb_right != NULL) + W->rb_right->color = RB_BLACK; + W->color = RB_RED; + __rb_rotate_left(W, root); + W = Parent->rb_left; + } + + W->color = Parent->color; + Parent->color = RB_BLACK; + if (W->rb_left->color != RB_BLACK) + { + W->rb_left->color = RB_BLACK; + } + __rb_rotate_right(Parent, root); + X = root->rb_node; + break; + } + } + } + + if (X) + { + X->color = RB_BLACK; + } + + return; +} + +static void rb_insert_color(struct trp_rb_node *X, struct trp_rb_root *root) +{ + /************************************* + * maintain red-black tree balance * + * after inserting node X * + *************************************/ + + /* check red-black properties */ + while (X != root->rb_node && X->rb_parent->color == RB_RED) + { + /* we have a violation */ + if (X->rb_parent == X->rb_parent->rb_parent->rb_left) + { + struct trp_rb_node *Y = X->rb_parent->rb_parent->rb_right; + if (Y && Y->color == RB_RED) + { + + /* uncle is red */ + X->rb_parent->color = RB_BLACK; + Y->color = RB_BLACK; + X->rb_parent->rb_parent->color = RB_RED; + X = X->rb_parent->rb_parent; + } + else + { + + /* uncle is black */ + if (X == X->rb_parent->rb_right) + { + /* make X a left child */ + X = X->rb_parent; + __rb_rotate_left(X, root); + } + + /* recolor and rotate */ + X->rb_parent->color = RB_BLACK; + X->rb_parent->rb_parent->color = RB_RED; + __rb_rotate_right(X->rb_parent->rb_parent, root); + } + } + else + { + + /* miror image of above code */ + struct trp_rb_node *Y = X->rb_parent->rb_parent->rb_left; + if (Y && (Y->color == RB_RED)) + { + + /* uncle is red */ + X->rb_parent->color = RB_BLACK; + Y->color = RB_BLACK; + X->rb_parent->rb_parent->color = RB_RED; + X = X->rb_parent->rb_parent; + } + else + { + + /* uncle is black */ + if (X == X->rb_parent->rb_left) + { + X = X->rb_parent; + __rb_rotate_right(X, root); + } + X->rb_parent->color = RB_BLACK; + X->rb_parent->rb_parent->color = RB_RED; + __rb_rotate_left(X->rb_parent->rb_parent, root); + } + } + } + + root->rb_node->color = RB_BLACK; + + return; +} + +static void rb_erase(struct trp_rb_node *node, struct trp_rb_root *root) +{ + struct trp_rb_node *child, *parent; + unsigned int color; + + if (!node->rb_left) + { + child = node->rb_right; + } + else if (!node->rb_right) + { + child = node->rb_left; + } + else + { + struct trp_rb_node *old = node, *left; + + node = node->rb_right; + while ((left = node->rb_left) != NULL) + { + node = left; + } + + if (old->rb_parent) + { + if (old->rb_parent->rb_left == old) + { + old->rb_parent->rb_left = node; + } + else + { + old->rb_parent->rb_right = node; + } + } + else + { + root->rb_node = node; + } + + child = node->rb_right; + parent = node->rb_parent; + color = node->color; + + if (parent == old) + { + parent = node; + } + else + { + if (child) + { + child->rb_parent = parent; + } + + parent->rb_left = child; + + node->rb_right = old->rb_right; + old->rb_right->rb_parent = node; + } + + node->color = old->color; + node->rb_parent = old->rb_parent; + node->rb_left = old->rb_left; + old->rb_left->rb_parent = node; + + if (color == RB_BLACK) + { + __rb_erase_color(child, parent, root); + } + + return; + + } + + parent = node->rb_parent; + color = node->color; + + if (child) + { + child->rb_parent = parent; + } + + if (parent) + { + if (parent->rb_left == node) + { + parent->rb_left = child; + } + else + { + parent->rb_right = child; + } + } + else + { + root->rb_node = child; + } + + if (color == RB_BLACK) + { + __rb_erase_color(child, parent, root); + } + + return; +} + +NSTACK_STATIC trp_rb_node_t *rb_new_node(trp_key_t key, trp_data_t data, + trp_rb_node_t * parent + /*, key_compare key_compare_fn */ ) +{ + trp_rb_node_t *node = (trp_rb_node_t *) malloc(sizeof(trp_rb_node_t)); + if (!node) + { + return NULL; + } + node->key = key; + node->data = data; + node->rb_parent = parent; + node->rb_left = node->rb_right = NULL; + node->color = RB_RED; + /*node->key_compare_fn = key_compare_fn; */ + return node; +} + +int +trp_rb_insert(trp_key_t key, trp_data_t data, trp_rb_root_t * root, + key_compare key_compare_fn) +{ + trp_rb_node_t *node = root->rb_node, *parent = NULL; + int ret = 0; /* CID 24640 */ + while (node) + { + parent = node; + ret = key_compare_fn(node->key, key); + if (0 < ret) + { + node = node->rb_left; + } + else if (0 > ret) + { + node = node->rb_right; + } + else + { + return -1; + } + } + + node = rb_new_node(key, data, parent /*, key_compare_fn */ ); + if (!node) + { + return -1; + } + + if (parent) + { + if (ret > 0) + { + parent->rb_left = node; + } + else + { + parent->rb_right = node; + } + } + else + { + root->rb_node = node; + } + + rb_insert_color(node, root); + return 0; +} + +int +trp_rb_insert_allow_same_key(trp_key_t key, trp_data_t data, + trp_rb_root_t * root, key_compare key_compare_fn) +{ + trp_rb_node_t *node = root->rb_node, *parent = NULL; + int ret = 0; /*CID 24638 */ + while (node) + { + parent = node; + ret = key_compare_fn(node->key, key); + if (0 < ret) + { + node = node->rb_left; + } + else + { + node = node->rb_right; + } + } + + node = rb_new_node(key, data, parent /*, key_compare_fn */ ); + if (!node) + { + return -1; + } + + if (parent) + { + if (ret > 0) + { + parent->rb_left = node; + } + else + { + parent->rb_right = node; + } + } + else + { + root->rb_node = node; + } + + rb_insert_color(node, root); + return 0; +} + +NSTACK_STATIC trp_rb_node_t *trp_rb_search_inorder(trp_key_t key, + trp_data_t data, + trp_rb_node_t * node, + int *count, + key_compare key_compare_fn) +{ + if (!node) + { + return NULL; + } + + int ret = key_compare_fn(node->key, key);; + if (0 == ret && data == node->data) + { + return node; + } + + if ((NULL == count) || (0 >= --(*count))) + { + return NULL; + } + + trp_rb_node_t *ret_node = + trp_rb_search_inorder(key, data, node->rb_left, count, + key_compare_fn); + if (ret_node) + { + return ret_node; + } + + ret_node = + trp_rb_search_inorder(key, data, node->rb_right, count, + key_compare_fn); + return ret_node; +} + +void +trp_rb_erase_with_data(trp_key_t key, trp_data_t data, trp_rb_root_t * root, + int count, key_compare key_compare_fn) +{ + trp_rb_node_t *node; + /* recursion operation need depth protect */ + if (! + (node = + trp_rb_search_inorder(key, data, root->rb_node, &count, + key_compare_fn))) + { + return; + } + + rb_erase(node, root); + free(node); + node = NULL; +} + +void +trp_rb_erase(trp_key_t key, trp_rb_root_t * root, key_compare key_compare_fn) +{ + trp_rb_node_t *node; + if (!(node = trp_rb_search(key, root, key_compare_fn))) + { + return; + } + + rb_erase(node, root); + free(node); + node = NULL; +} |