/* 活跃IP地址管理模块, 接收IP发现子系统的IP, 来自MAAT-IP回调表, */ #include "flowood.h" #include "flowood_fun.h" #include "flwd_net.h" #include "MESA_handle_logger.h" #include "MESA_htable.h" #include #include #include #include #include #include #include #include /* TODO: 全网所有接入网关分配唯一的id, 从自然数1开始, 根据总数N分配每个接入网关使用的源端口范围, 如网关1使用10001-20000, 网关2使用20001-30000等等, IP是全局共享, 不同接入网关之间的端口按范围区分, 保证多机之间互不冲突! 每个接入网关内部再根据线程数量, 将本机可用端口分成THREAD_NUM份, 如网关1的线程1使用10001-12000, 网关1的线程2使用12001-14000, 等等. */ MESA_ATOMIC_T flwd_temp_active_ip_op_flag[FLWD_MAX_THREAD_NUM]; MESA_lqueue_head flwd_temp_active_ip_to_deal[FLWD_MAX_THREAD_NUM]; /* 结构: flwd_temp_to_deal_act_ip_t */ typedef struct{ flwd_ip_t active_ip_net_order; char is_valid; /* 1:usabel, add; 0:disable, del */ }flwd_temp_to_deal_act_ip_t; static void flwd_act_ip_htable_data_free(void *data); static unsigned short flwd_act_ip_mask_to_num(unsigned short mask_to_num) { int i; for(i = 0; i < 16; i++){ if(0 != (mask_to_num & 1)){ /* 一直右移, 直到最低位不为0为止 */ break; }else{ mask_to_num = mask_to_num >> 1; } } return mask_to_num; } static unsigned short flwd_act_ip_get_acc_gateway_num(void) { return flwd_act_ip_mask_to_num(FLWD_SPORT_ACC_ID_MASK); } unsigned short flwd_act_ip_get_usable_udp_sport_num(void) { return flwd_act_ip_mask_to_num(FLWD_UDP_SPORT_ACTUAL_PORT_MASK); } unsigned short flwd_act_ip_get_usable_tcp_sport_num(void) { return flwd_act_ip_mask_to_num(FLWD_TCP_SPORT_ACTUAL_PORT_MASK); } static int flwd_act_ip_get_tcp_usable_sport(int tid, unsigned short *begin_port, unsigned short *usable_count) { unsigned short this_gateway_begin_port; unsigned short this_thread_usable_tot_count; unsigned short this_gateway_usable_tot_count; this_gateway_usable_tot_count = flwd_act_ip_get_usable_tcp_sport_num(); /* NOTE: current_access_gateway_id为了方便理解, 从自然数1开始, 此处需要减1, 而线程id从0开始, 无需减1 */ /* gateway_id左移到最高位 */ this_gateway_begin_port = (((unsigned short)flwd_cfg_val.current_access_gateway_id - 1) << (FLWD_SPORT_ACC_ID_SHIFT_NUM)); this_thread_usable_tot_count = this_gateway_usable_tot_count/flwd_cfg_val.tot_thread_count; *usable_count = this_gateway_usable_tot_count/flwd_cfg_val.tot_thread_count; *begin_port = this_gateway_begin_port | (*usable_count) * tid; return 0; } static int flwd_act_ip_get_udp_usable_sport(int tid, unsigned short *begin_port, unsigned short *usable_count) { unsigned short this_gateway_begin_port; unsigned short this_thread_usable_tot_count; unsigned short this_gateway_usable_tot_count; this_gateway_usable_tot_count = flwd_act_ip_get_usable_udp_sport_num(); /* NOTE: current_access_gateway_id为了方便理解, 从自然数1开始, 此处需要减1, 而线程id从0开始, 无需减1 */ /* gateway_id左移到最高位 */ this_gateway_begin_port = (((unsigned short)flwd_cfg_val.current_access_gateway_id - 1) << (FLWD_SPORT_ACC_ID_SHIFT_NUM)); this_thread_usable_tot_count = this_gateway_usable_tot_count/flwd_cfg_val.tot_thread_count; *usable_count = this_gateway_usable_tot_count/flwd_cfg_val.tot_thread_count; *begin_port = this_gateway_begin_port | (*usable_count) * tid; return 0; } /* NOTE: 根据回调函数新增的活跃IP, 做为key插入htable, 根据当前接入网关的id, 接入网关总数, 及线程ID, 生成可用的端口列表. */ static flwd_active_ip_t *flwd_act_ip_create_new_node(int tid, const flwd_active_ip_t *act_ip_stack) { flwd_active_ip_t *act_ip_heap; unsigned short udp_begin_port, tcp_begin_port, tport; unsigned short udp_usable_count, tcp_usable_count; unsigned short i; MESA_list_count_t *list_node; act_ip_heap = (flwd_active_ip_t *)malloc(sizeof(flwd_active_ip_t)); memcpy(act_ip_heap, act_ip_stack, sizeof(flwd_active_ip_t)); MESA_list_init_head(&act_ip_heap->active_ip_list_node); act_ip_heap->active_ip_list_node.quiddity = act_ip_heap; /* 为了节约内存, 链表头也存储数据, 这样对于dynamic类型和仅有一个IP的static类型来说, 无需再新构造一个节点, quiddity执行自身结构体头部 */ /* TCP和UDP的端口分开存储使用, 可以扩展一个活跃IP的实际复用范围 */ MESA_list_count_init_head(&act_ip_heap->usable_tcp_sport_list_head); MESA_list_count_init_head(&act_ip_heap->usable_udp_sport_list_head); flwd_act_ip_get_udp_usable_sport(tid, &udp_begin_port, &udp_usable_count); for(i = 0; i < udp_usable_count; i++){ list_node = (MESA_list_count_t *)calloc(1, sizeof(MESA_list_count_t)); tport = udp_begin_port + i; tport |= (flwd_cfg_val.current_access_gateway_id << FLWD_SPORT_ACC_ID_SHIFT_NUM); tport = htons(tport); /* convert to net_order */ memcpy(&list_node->quiddity, &tport, sizeof(short)); /* 原来此处变量是指针, 直接复用内存地址, 存储2个字节的端口值, net_order */ MESA_list_count_add(&act_ip_heap->usable_udp_sport_list_head, list_node); } flwd_act_ip_get_tcp_usable_sport(tid, &tcp_begin_port, &tcp_usable_count); for(i = 0; i < tcp_usable_count; i++){ list_node = (MESA_list_count_t *)calloc(1, sizeof(MESA_list_count_t)); tport = tcp_begin_port + i; tport |= (flwd_cfg_val.current_access_gateway_id << FLWD_SPORT_ACC_ID_SHIFT_NUM); tport = htons(tport); /* convert to net_order */ memcpy(&list_node->quiddity, &tport, sizeof(short)); /* 原来此处变量是指针, 直接复用内存地址, 存储2个字节的端口值, net_order */ MESA_list_count_add(&act_ip_heap->usable_tcp_sport_list_head, list_node); } return act_ip_heap; } #if FLWD_ASYNC_LOCK_FREE /* NOTE: 此函数在包处理线程上下文中, 无锁模式处理新的活跃ip */ int flwd_act_ip_hash_proc(int tid, flwd_active_ip_t *act_ip_stack) { MESA_htable_handle flwd_act_htable; unsigned char *ip_key; unsigned int ip_key_size; flwd_active_ip_t *act_ip_heap; int ret; char ip_str[64]; if(flwd_likely(FLWD_IP_ADDR_TYPE_V4 == act_ip_stack->active_ip_net_order.addr_type)){ if(FLWD_IP_REGION_INLAND == act_ip_stack->ip_region_type){ flwd_act_htable = flwd_thread_val[tid].flwd_active_ipv4_pool_inland; }else{ flwd_act_htable = flwd_thread_val[tid].flwd_active_ipv4_pool_outland; } ip_key = (unsigned char *)&act_ip_stack->active_ip_net_order.addr_ipv4; ip_key_size = sizeof(int); inet_ntop(AF_INET, &act_ip_stack->active_ip_net_order.addr_ipv4, ip_str, 64); }else{ if(FLWD_IP_REGION_INLAND == act_ip_stack->ip_region_type){ flwd_act_htable = flwd_thread_val[tid].flwd_active_ipv6_pool_inland; }else{ flwd_act_htable = flwd_thread_val[tid].flwd_active_ipv6_pool_outland; } ip_key = (unsigned char *)&act_ip_stack->active_ip_net_order.addr_ipv6; ip_key_size = sizeof(struct in6_addr); inet_ntop(AF_INET6, &act_ip_stack->active_ip_net_order.addr_ipv6, ip_str, 64); } if(act_ip_stack->is_valid){ if(MESA_htable_search(flwd_act_htable, ip_key, ip_key_size) == NULL){ act_ip_heap = flwd_act_ip_create_new_node(tid, act_ip_stack); ret = MESA_htable_add(flwd_act_htable, ip_key, ip_key_size, act_ip_heap); if(ret < 0){ flwd_act_ip_htable_data_free(act_ip_heap); flwd_log(30, "add new active ip to htable fail, ret=%d\n", ret); }else{ flwd_log(10, "add new active ip:%s\n", ip_str); } }else{ ; /* already exist, do nothing. */ } }else{ /* */ MESA_htable_del(flwd_act_htable, ip_key, ip_key_size, NULL); flwd_log(10, "del old active ip:%s\n", ip_str); } return 0; } #endif static void flwd_act_ip_dynamic_update(const flwd_active_ip_t *stack_act_ip) { int i, ret; flwd_active_ip_t *heap_act_ip; unsigned int key_size; unsigned char *key; char ip_str[64]; if(FLWD_IP_ADDR_TYPE_V4 == stack_act_ip->active_ip_net_order.addr_type){ key = (unsigned char *)&stack_act_ip->active_ip_net_order.addr_ipv4; key_size = sizeof(int); }else{ key = (unsigned char *)&stack_act_ip->active_ip_net_order.addr_ipv6; key_size = sizeof(struct in6_addr); } for(i = 0; i < flwd_cfg_val.tot_thread_count; i++){ pthread_rwlock_wrlock(&flwd_thread_val[i].flwd_ip_pool_dynamic_rwlock); if(0 == stack_act_ip->is_valid){ MESA_htable_del(flwd_thread_val[i].flwd_ip_pool_dynamic_htable[stack_act_ip->active_ip_net_order.addr_type][stack_act_ip->ip_region_type], key, key_size, NULL); }else{ /* 如果是新增, 先找一下, htable中是否已经存在 */ heap_act_ip = (flwd_active_ip_t *)MESA_htable_search(flwd_thread_val[i].flwd_ip_pool_dynamic_htable[stack_act_ip->active_ip_net_order.addr_type][stack_act_ip->ip_region_type], key, key_size); if(heap_act_ip != NULL){ /* 活跃IP重复, do nonthing !! */ pthread_rwlock_unlock(&flwd_thread_val[i].flwd_ip_pool_dynamic_rwlock); return; } heap_act_ip = flwd_act_ip_create_new_node(i, stack_act_ip); ret = MESA_htable_add(flwd_thread_val[i].flwd_ip_pool_dynamic_htable[stack_act_ip->active_ip_net_order.addr_type][stack_act_ip->ip_region_type], key, key_size, heap_act_ip); assert(ret >= 0); flwd_log(10, "add dynamic ip pool addr:'%s'\n ", flwd_ipt_ntop_r(&stack_act_ip->active_ip_net_order, ip_str, 64)); } pthread_rwlock_unlock(&flwd_thread_val[i].flwd_ip_pool_dynamic_rwlock); } return; } /* 判断IP是否跟已有的重复(人工配置, 可能输入重复IP), 否则复用时也可能复用一样的IP和端口, 会出问题 */ static int flwd_static_ip_pool_is_dup(const flwd_active_ip_t *act_ip_head, const flwd_active_ip_t *stack_act_ip) { const MESA_list_t *in_list_node = &act_ip_head->active_ip_list_node; const flwd_active_ip_t *in_list_ipt; do{ in_list_ipt = (flwd_active_ip_t *)in_list_node->quiddity; if(flwd_ipt_equal(&in_list_ipt->active_ip_net_order, &stack_act_ip->active_ip_net_order) == 1){ return 1; } in_list_node = in_list_node->nextele; }while(in_list_node != &act_ip_head->active_ip_list_node); /* 双向循环链表, 防止死循环 */ return 0; } /* 静态IP池以group_id为key, IP_list为data */ static void flwd_act_ip_static_update(const flwd_active_ip_t *stack_act_ip) { int i, ret; flwd_active_ip_t *act_ip_head;/* htable中的ip节点 */ flwd_active_ip_t *heap_act_ip; /* 本次新增的ip */ char ip_str[64]; void *ip_static_htable; /* NOTE: 添加和删除IP时使用group_id查找ip_list, 然后再遍历; 但可用端口回收时, 只有IP和端口, 没有Group_id的概念, 在flwd_ip_pool_static_htable里, 使用两个不同的key, 索引同一个data, 即ip_list. update_cb使用group_id索引ip_list; sport_recycle使用ip地址索引ip_list; 为了防止万一group_id和ipv4地址冲突, 将group转为字符串模式, 前面加上GPID前缀, 这样保证key的长度都不一样, 肯定也不会冲突. */ unsigned char static_ip_group_key[64]; int static_ip_group_key_len = 64; flwd_policy_group_id_key_gen(stack_act_ip->policy_group_id, static_ip_group_key, &static_ip_group_key_len); for(i = 0; i < flwd_cfg_val.tot_thread_count; i++){ /* NOTE: 此函数处于maat回调线程上下文, 操作包处理线程的数据结构, 需要加锁! */ pthread_rwlock_wrlock(&flwd_thread_val[i].flwd_ip_pool_static_rwlock); ip_static_htable = flwd_thread_val[i].flwd_ip_pool_static_htable[stack_act_ip->active_ip_net_order.addr_type][stack_act_ip->ip_region_type]; if(0 == stack_act_ip->is_valid){ flwd_ip_pool_del(FLWD_ACT_IP_STATIC, ip_static_htable, stack_act_ip->policy_group_id, flwd_act_ip_htable_data_free, stack_act_ip); }else{ /* 如果是新增, 先找一下htable中是否已经存在 */ act_ip_head = (flwd_active_ip_t *)flwd_ip_pool_search(FLWD_ACT_IP_STATIC, ip_static_htable, (unsigned char *)static_ip_group_key, static_ip_group_key_len); if(act_ip_head != NULL){ /* group-list已存在, 判断IP是否跟已有的重复(人工配置, 可能输入重复IP), 否则复用时也可能复用一样的IP和端口, 会出问题 */ if(flwd_static_ip_pool_is_dup(act_ip_head, stack_act_ip) == 0){ heap_act_ip = flwd_act_ip_create_new_node(i, stack_act_ip); MESA_list_add(&act_ip_head->active_ip_list_node, &heap_act_ip->active_ip_list_node); /* 以ip为key, 再插入一次hash表, 用于端口回收时, 没有group_id, 也能靠ip找到对应的ip_list */ ret = MESA_htable_add(ip_static_htable, stack_act_ip->active_ip_net_order.addr_value, stack_act_ip->active_ip_net_order.addr_len, heap_act_ip); assert(ret >= 0); flwd_log(10, "add static ip pool addr:'%s'\n ", flwd_ipt_ntop_r(&stack_act_ip->active_ip_net_order, ip_str, 64)); }else{ flwd_log(20, "static ip pool %s is duplicated!\n ", flwd_ipt_ntop_r(&stack_act_ip->active_ip_net_order, ip_str, 64)); } }else{ /* 当前policy还没有IP, 第一个, 也就是链表的头节点, 直接用MESA_htable_add添加, */ heap_act_ip = flwd_act_ip_create_new_node(i, stack_act_ip); ret = MESA_htable_add(ip_static_htable, (unsigned char *)static_ip_group_key, static_ip_group_key_len, heap_act_ip); assert(ret >= 0); /* 以ip为key, 再插入一次hash表, 用于端口回收时, 没有group_id, 也能靠ip找到对应的ip_list */ ret = MESA_htable_add(ip_static_htable, stack_act_ip->active_ip_net_order.addr_value, stack_act_ip->active_ip_net_order.addr_len, heap_act_ip); if(ret < 0){ /* 可能是IP重复了! 可能是不同的组里包含了相同的IP地址! */ /* TODO, 这种情况怎么办?? 同一个IP属于不同的组, 可不可以?? */ //flwd_act_ip_htable_data_free(heap_act_ip); flwd_log(30, "add static ip pool addr:'%s' error, ret=%d\n ", flwd_ipt_ntop_r(&stack_act_ip->active_ip_net_order, ip_str, 64), ret); }else{ flwd_log(10, "add static ip pool addr:'%s'\n ", flwd_ipt_ntop_r(&stack_act_ip->active_ip_net_order, ip_str, 64)); } } } pthread_rwlock_unlock(&flwd_thread_val[i].flwd_ip_pool_static_rwlock); } return; } /* NOTE: 动态活跃IP以IP地址为key, data为flwd_active_ip_t, 只会有一个节点, active_ip_list_node指针都是空; 静态IP地址池的地址以策略组ID为key, data为flwd_active_ip_t的链表, 索引所有相同policy_id的IP; */ void flwd_act_ip_update(const flwd_active_ip_t *stack_act_ip) { if(FLWD_ACT_IP_DYNAMIC == stack_act_ip->ip_origin_type){ flwd_act_ip_dynamic_update(stack_act_ip); }else{ flwd_act_ip_static_update(stack_act_ip); } return; } #if FLWD_NO_ACTIVE_IP_DISCOVER /* 模拟活跃IP发现系统, 造一些假数据模拟 */ /* 数据库表格式: "id addr_type ipaddr port user_region(GDEV_IP) location is_valid op_time" "1 4 11.22.33.44 0 100 0 1 2018-06-03 11:11:11" */ static void flwd_phony_act_ipv4_gen(int is_valid, unsigned ip_addr, unsigned int group_id, flwd_ip_region_type_t region_type, flwd_active_ip_type_t origin_type) { int rand_num; flwd_active_ip_t stack_act_ip; rand_num = rand(); stack_act_ip.is_valid = is_valid; stack_act_ip.policy_group_id = group_id; stack_act_ip.ip_region_type = region_type; /* 单数ip为域内 */ stack_act_ip.ip_origin_type = origin_type; stack_act_ip.active_ip_net_order.addr_ipv4 = ip_addr; stack_act_ip.active_ip_net_order.addr_type = FLWD_IP_ADDR_TYPE_V4; stack_act_ip.active_ip_net_order.addr_len = sizeof(int); stack_act_ip.gdev_args.gdev_ip_net_order = 0x01010101; flwd_act_ip_update(&stack_act_ip); } static void *flwd_act_ip_phony_discoverer(void *arg) { int i = 0; time_t tstart; tstart = time(NULL); while(1){ for(i = 0; i < 100; i++){ flwd_phony_act_ipv4_gen(1, i, i, FLWD_IP_REGION_INLAND, FLWD_ACT_IP_DYNAMIC); flwd_phony_act_ipv4_gen(1, i, i, FLWD_IP_REGION_OUTLAND, FLWD_ACT_IP_DYNAMIC); flwd_phony_act_ipv4_gen(1, i, i, FLWD_IP_REGION_INLAND, FLWD_ACT_IP_STATIC); flwd_phony_act_ipv4_gen(1, i, i, FLWD_IP_REGION_OUTLAND, FLWD_ACT_IP_STATIC); } usleep(10); #if 1 for(i = 0; i < 100; i++){ flwd_phony_act_ipv4_gen(0, i, i, FLWD_IP_REGION_INLAND, FLWD_ACT_IP_DYNAMIC); flwd_phony_act_ipv4_gen(0, i, i, FLWD_IP_REGION_INLAND, FLWD_ACT_IP_STATIC); flwd_phony_act_ipv4_gen(0, i, i, FLWD_IP_REGION_OUTLAND, FLWD_ACT_IP_DYNAMIC); flwd_phony_act_ipv4_gen(0, i, i, FLWD_IP_REGION_OUTLAND, FLWD_ACT_IP_STATIC); } #endif if(tstart + 60 < time(NULL)){ sleep(5); exit(1); } } return NULL; } #endif static int flwd_act_ip_htable_key_cmp(const uchar * key1, uint size1, const uchar * key2, uint size2) { if(size1 != size2){ return -1; } return memcmp(key1, key2, size1); } static uint flwd_act_ip_htable_key2index(const MESA_htable_handle table, const uchar * key, uint size) { unsigned int hash = 131; unsigned seed = 13131; unsigned int i; for(i = 0; i < size; i++){ hash = hash * seed + *key++; } return hash; } static void flwd_act_ip_htable_data_free(void *data) { flwd_active_ip_t *act_ip = (flwd_active_ip_t *)data; MESA_list_count_t *list_node, *next_node; char ip_str[64]; while((0 == MESA_list_count_is_empty(&act_ip->usable_tcp_sport_list_head))){ list_node = act_ip->usable_tcp_sport_list_head.nextele; MESA_list_count_del(&act_ip->usable_tcp_sport_list_head, list_node); free(list_node); } while((0 == MESA_list_count_is_empty(&act_ip->usable_udp_sport_list_head))){ list_node = act_ip->usable_udp_sport_list_head.nextele; MESA_list_count_del(&act_ip->usable_udp_sport_list_head, list_node); free(list_node); } flwd_log(10, "del ip pool addr:'%s'\n ", flwd_ipt_ntop_r(&act_ip->active_ip_net_order, ip_str, 64)); memset(act_ip, 0xFE, sizeof(flwd_active_ip_t)); free(data); } static MESA_htable_handle flwd_act_ip_htable_create(void) { int opt_int; MESA_htable_handle htable; htable = MESA_htable_born(); assert(htable != NULL); opt_int = 0; /* 用外部的rwlock读写锁实现多线程安全, 比htable内部的互斥锁性能更好一些 */ MESA_htable_set_opt(htable, MHO_THREAD_SAFE, &opt_int, sizeof(int)); opt_int = 1024 * 32; MESA_htable_set_opt(htable, MHO_HASH_SLOT_SIZE, &opt_int, sizeof(int)); opt_int = 100000; MESA_htable_set_opt(htable, MHO_HASH_MAX_ELEMENT_NUM, &opt_int, sizeof(int)); opt_int = 0; /* 活跃IP回调表有超时删除机制, 靠redis回调实现, 不靠htable自身超时 */ MESA_htable_set_opt(htable, MHO_EXPIRE_TIME, &opt_int, sizeof(int)); MESA_htable_set_opt(htable, MHO_CBFUN_KEY_COMPARE, (void *)&flwd_act_ip_htable_key_cmp, sizeof(void *)); MESA_htable_set_opt(htable, MHO_CBFUN_KEY_TO_INDEX, (void *)&flwd_act_ip_htable_key2index, sizeof(void *)); MESA_htable_set_opt(htable, MHO_CBFUN_DATA_FREE, (void *)&flwd_act_ip_htable_data_free, sizeof(void *)); opt_int = 1; MESA_htable_set_opt(htable, MHO_AUTO_UPDATE_TIME, &opt_int, sizeof(int)); opt_int = 0; MESA_htable_set_opt(htable, MHO_SCREEN_PRINT_CTRL, &opt_int, sizeof(int)); /* search时加的是读锁, 只能用FIFO模式, LRU模式内部有写操作 */ opt_int = HASH_ELIMINATE_ALGO_FIFO; MESA_htable_set_opt(htable, MHO_ELIMIMINATE_TYPE, &opt_int, sizeof(int)); opt_int = 100; MESA_htable_set_opt(htable, MHO_HASH_LIST_COLLIDE_THRESHOLD, &opt_int, sizeof(int)); char *err_log = (char *)"./flwd_hash_collide.log"; MESA_htable_set_opt(htable, MHO_HASH_LOG_FILE, (void *)err_log, strlen(err_log)); int ret = MESA_htable_mature(htable); assert(ret >= 0); return htable; } /* TODO: 对于SNAT来说, act_ip就是IP发现子系统回传的IP, 用于外网; 对于DNAT来说, act_ip是接入网关网卡多个ip, 因为只用一个ip最多就65535个端口可用, 在配置文件中增加网关虚拟动态ip起始地址和数量: [TOPO_ACC_LINK_USER] gateway_slave_ip_range = 10.0.9.100 gateway_slave_ip_num = 10 意思是从10.0.9.100开始, 到10.0.9.109都是接入网关用来访问真实内部服务器的ip, 要处理这些IP的arp请求, 回复应答包. */ int flwd_access_active_ip_init(void) { int i; int v4_or_v6, in_or_out; for(i = 0; i < flwd_cfg_val.tot_thread_count; i++){ flwd_temp_active_ip_to_deal[i] = MESA_lqueue_create(0, 1000); /* 异步任务队列本身无锁, 靠原子变量互斥 */ MESA_ATOMIC_SET(flwd_temp_active_ip_op_flag[i], 0); #if 0 flwd_thread_val[i].flwd_active_ipv4_pool_inland = flwd_act_ip_htable_create(); flwd_thread_val[i].flwd_active_ipv4_pool_outland = flwd_act_ip_htable_create(); flwd_thread_val[i].flwd_active_ipv6_pool_inland = flwd_act_ip_htable_create(); flwd_thread_val[i].flwd_active_ipv6_pool_outland = flwd_act_ip_htable_create(); flwd_thread_val[i].flwd_static_ipv4_pool_inland = flwd_act_ip_htable_create(); flwd_thread_val[i].flwd_static_ipv4_pool_outland = flwd_act_ip_htable_create(); flwd_thread_val[i].flwd_static_ipv6_pool_inland = flwd_act_ip_htable_create(); flwd_thread_val[i].flwd_static_ipv6_pool_outland = flwd_act_ip_htable_create(); #else for(v4_or_v6 = 0; v4_or_v6 <= 1; v4_or_v6++){ for(in_or_out = 0; in_or_out <= 1; in_or_out++){ flwd_thread_val[i].flwd_ip_pool_dynamic_htable[v4_or_v6][in_or_out] = flwd_act_ip_htable_create(); flwd_thread_val[i].flwd_ip_pool_static_htable[v4_or_v6][in_or_out] = flwd_act_ip_htable_create(); } } pthread_rwlock_init(&flwd_thread_val[i].flwd_ip_pool_dynamic_rwlock, NULL); pthread_rwlock_init(&flwd_thread_val[i].flwd_ip_pool_static_rwlock, NULL); #endif } #if FLWD_NO_ACTIVE_IP_DISCOVER pthread_t pid; pthread_create(&pid, NULL, flwd_act_ip_phony_discoverer, NULL); #endif return 0; }