From 7b1e219c80f5fe44a8f015a369e57ba7d2bc39cc Mon Sep 17 00:00:00 2001 From: sharath Date: Mon, 13 Aug 2018 19:28:26 +0530 Subject: Feat : LWIP integration part2 Change-Id: I2431581d611659beb9b9b4d6d95d6985e53a8061 Signed-off-by: sharath --- .../lwip_src/ip_module/configuration_reader.c | 1045 +++++++++++++++++ .../lwip_stack/lwip_src/ip_module/container_ip.c | 1168 ++++++++++++++++++++ .../lwip_stack/lwip_src/ip_module/ip_module_api.c | 347 ++++++ stacks/lwip_stack/lwip_src/ip_module/network.c | 1127 +++++++++++++++++++ stacks/lwip_stack/lwip_src/ip_module/trp_rb_tree.c | 563 ++++++++++ 5 files changed, 4250 insertions(+) create mode 100644 stacks/lwip_stack/lwip_src/ip_module/configuration_reader.c create mode 100644 stacks/lwip_stack/lwip_src/ip_module/container_ip.c create mode 100644 stacks/lwip_stack/lwip_src/ip_module/ip_module_api.c create mode 100644 stacks/lwip_stack/lwip_src/ip_module/network.c create mode 100644 stacks/lwip_stack/lwip_src/ip_module/trp_rb_tree.c (limited to 'stacks/lwip_stack/lwip_src/ip_module') 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..2b71e07 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/ip_module/configuration_reader.c @@ -0,0 +1,1045 @@ +/* +* +* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 +#include +#include +#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) + { + exit (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) + { + exit (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; + } + + const char *old_hbt_cnt = "6"; + const char *new_hbt_cnt = "60"; + nsfw_set_soft_para (NSFW_PROC_MASTER, NSFW_HBT_COUNT_PARAM, + (void *) new_hbt_cnt, sizeof (u16)); + (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. + nsfw_set_soft_para (NSFW_PROC_MASTER, NSFW_HBT_COUNT_PARAM, + (void *) old_hbt_cnt, sizeof (u16)); + + 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/run"; + 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 ("RTP", "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 ("RTP", "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 ("RTP", "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 ("RTP", "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..3cbe9b9 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/ip_module/container_ip.c @@ -0,0 +1,1168 @@ +/* +* +* 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 +#include +#include +#include +#include +#include +#include +#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 "nstack_rd_mng.h" +#include "config_common.h" +#include "igmp.h" +#include "spl_def.h" +#include "stackx_ip_addr.h" +#include "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; + } +} + +/*note:::the ip must be local order*/ +void +container_multicast_rd (unsigned int ip, int op) +{ + rd_ip_data rd_ip = { 0 }; + int ret = 0; + + rd_ip.addr = ip; + rd_ip.masklen = 32; + if (0 == op) + { + ret = nstack_rd_ip_node_insert ("nstack-dpdk", &rd_ip); + } + else + { + ret = nstack_rd_ip_node_delete (&rd_ip); + } + + if (0 != ret) + { + NSOPR_LOGERR ("nstack rd multicast ip:0x%x %s fail", ip, + (0 == op ? "insert" : "delete")); + } + else + { + NSOPR_LOGDBG ("nstack rd multicast ip:0x%x %s success", ip, + (0 == op ? "insert" : "delete")); + } + + return; +} + +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) + { + /*note:::multicast ip is network, need to change to local order, delete multicast ip from rd. */ + container_multicast_rd (spl_ntohl (tmp->ip), 1); + + 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 */ + goto RETURN_ERROR; + } + + 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..0ae61ed --- /dev/null +++ b/stacks/lwip_stack/lwip_src/ip_module/ip_module_api.c @@ -0,0 +1,347 @@ +/* +* +* 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 +#include +#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..83fbb7c --- /dev/null +++ b/stacks/lwip_stack/lwip_src/ip_module/network.c @@ -0,0 +1,1127 @@ +/* +* +* 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 +#include +#include +#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 "nstack_rd_mng.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 rd*/ +void +network_rd_proc (struct network_configuration *network, int op) +{ + struct ip_subnet *ptsubnet = NULL; + struct network_configuration *pn = NULL; + rd_ip_data rd_ip = { 0 }; + int ret = 0; + + pn = network; + + while (pn) + { + if (0 == strcmp ("nstack-dpdk", pn->type_name)) + { + ptsubnet = network->ip_subnet; + while (ptsubnet) + { + rd_ip.addr = ptsubnet->subnet; + rd_ip.masklen = ptsubnet->mask_len; + if (0 == op) + { + ret = nstack_rd_ip_node_insert (network->type_name, &rd_ip); + } + else + { + ret = nstack_rd_ip_node_delete (&rd_ip); + } + + if (0 != ret) + { + NSOPR_LOGERR ("nstack rd subnet:0x%x, masklen:0x%x %s fail", + rd_ip.addr, rd_ip.masklen, + (0 == op ? "insert" : "delete")); + } + else + { + NSOPR_LOGDBG + ("nstack rd subnet:0x%x, masklen:0x%x %s success", + rd_ip.addr, rd_ip.masklen, + (0 == op ? "insert" : "delete")); + } + + ptsubnet = ptsubnet->next; + } + } + + pn = pn->next; + } + + return; +} + +/* 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; + + /*add network to rd */ + network_rd_proc (network, 0); + + 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)) + { + 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; + + 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, "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; + + /*delete netework from rd */ + network_rd_proc (network, 1); + + 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..1990f52 --- /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 +#include +#include +#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; +} -- cgit 1.2.3-korg