#include "flowood.h" #include "flowood_fun.h" #include "flwd_net.h" #include "MESA_htable.h" #include "MESA_list_queue.h" #include "MESA_handle_logger.h" #include "MESA_list_count.h" #include #include #include #include #include #include #include #include #include typedef struct{ char region_str[FLWD_REGION_STR_LEN_MAX]; unsigned int vlan_id; unsigned int conn_forward_gateway_array[FLWD_NETWORK_NxM_MAX]; /* 相连的所有转发网关IP, 网络序 */ int conn_forward_gateway_array_num; }flwd_network_gdev_data_t; /* NOTE: GDEV和FWD之间是NxM关系, 通过本配置表, 告之access网关, 对于一个选择了的活跃IP, 应该借助哪个FWD网关通过哪个GDEV发出去. active_IP: access---->forwad---->gdev---->INTERNET. config: region vlan gdev_redirect_ip forward_manage_ip forward_feedback_ip region: 地域编码, 按省区别; vlan : 防止一个局点内的GDEV和froward可能不通, 如跨机房、跨机柜、跨VLAN等等, 增加这个标识; gdev_redirect_ip: GDEV的回流口IP forward_manage_ip: 转发网关管理口IP forward_feedback_ip: 转发网关单独数据回传口IP 此配置全网一份, 和access网关切分端口的配置, 要全网同步, 不允许单机独立修改!!!! */ static int flwd_network_gdev_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_network_gdev_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_network_gdev_data_free(void *data) { assert(0); /* 程序运行时用远不会free, 就不能走到这里, 死掉!!! */ } /* NOTE: 此htable用gdev_ip做为key, flwd_network_gdev_data_t结构为data, 用来查找去往哪个gdev, 可以通过哪些forward. */ static MESA_htable_handle flwd_create_network_gdev_table(void) { int opt_int; MESA_htable_handle htable; htable = MESA_htable_born(); assert(htable != NULL); opt_int = 0; /* 初始化后不再改动, 无锁模式 */ MESA_htable_set_opt(htable, MHO_THREAD_SAFE, &opt_int, sizeof(int)); opt_int = 1024; MESA_htable_set_opt(htable, MHO_HASH_SLOT_SIZE, &opt_int, sizeof(int)); opt_int = 1000; MESA_htable_set_opt(htable, MHO_HASH_MAX_ELEMENT_NUM, &opt_int, sizeof(int)); opt_int = 0; MESA_htable_set_opt(htable, MHO_EXPIRE_TIME, &opt_int, sizeof(int)); /* 不淘汰 */ opt_int = HASH_ELIMINATE_ALGO_FIFO; /* 多线程无锁模式必须FIFO */ MESA_htable_set_opt(htable, MHO_ELIMIMINATE_TYPE, &opt_int, sizeof(int)); MESA_htable_set_opt(htable, MHO_CBFUN_KEY_COMPARE, (void *)&flwd_network_gdev_key_cmp, sizeof(void *)); MESA_htable_set_opt(htable, MHO_CBFUN_KEY_TO_INDEX, (void *)&flwd_network_gdev_key2index, sizeof(void *)); MESA_htable_set_opt(htable, MHO_CBFUN_DATA_FREE, (void *)&flwd_network_gdev_data_free, sizeof(void *)); opt_int = 0; 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)); 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; } /* pattern: #region vlan_id gdev_redirect_ip */ static int flwd_network_gdev_cfg_parse(void) { FILE *fp; char __raw_line_buf[1024]; char line_buf[1024]; const char *delim = "\t "; char *save_ptr; flwd_network_gdev_data_t *tmp_data; char *section, *region_str, *gdev_ip_str; unsigned int hkey; int ret; fp = fopen("./conf/ip_reuse/network_gdev.cfg", "r"); if(NULL == fp){ return -1; } while(fgets(__raw_line_buf, 1024, fp)){ if('#' ==__raw_line_buf[0]){ continue; } memcpy(line_buf, __raw_line_buf, 1024); flwd_del_last_rn(line_buf, 1024); tmp_data = (flwd_network_gdev_data_t *)calloc(1, sizeof(flwd_network_gdev_data_t)); /* region */ section = strtok_r(line_buf, delim, &save_ptr); if(NULL == section){ return -1; } strncpy(tmp_data->region_str, section, FLWD_REGION_STR_LEN_MAX-1); region_str = section; /* vlan_id */ section = strtok_r(NULL, delim, &save_ptr); if(NULL == section){ return -1; } tmp_data->vlan_id = (unsigned int)atoi(section); /* gdev_redirect_ip */ section = strtok_r(NULL, delim, &save_ptr); if(NULL == section){ return -1; } if(inet_pton(AF_INET, section, &hkey) <= 0){ return -1; } gdev_ip_str = section; ret = MESA_htable_add(flwd_global_val.flwd_network_conn_table, (const uchar *)&hkey, sizeof(int), tmp_data); if(ret >= 0){ flwd_log(10, "parse network_gdev.cfg, %s\t%u\t%s\n", region_str, tmp_data->vlan_id, gdev_ip_str); }else{ flwd_log(30, "parse network_gdev.cfg error, %s\n", __raw_line_buf); } while(strtok_r(NULL, delim, &save_ptr)); } fclose(fp); return 0; } static int flwd_network_gdev_fwd_relate_cb(const uchar * key, uint size, void * data, void * user) { flwd_network_gdev_data_t *hdata = (flwd_network_gdev_data_t *)data; flwd_network_gdev_data_t *tmp_fwd_data = (flwd_network_gdev_data_t *)user; if(strlen(hdata->region_str) != strlen(tmp_fwd_data->region_str)){ return ITERATE_CB_RET_CONTINUE_FLAG; /* MESA_htable_iterate_bytime无法返回回调函数的值, 这里用个trick, 把conn_forward_gateway_array_num=2就是找到了, 否则是1 */ } if(strncmp(hdata->region_str, tmp_fwd_data->region_str,strlen(hdata->region_str)) != 0){ return ITERATE_CB_RET_CONTINUE_FLAG; } if(hdata->vlan_id != tmp_fwd_data->vlan_id){ return ITERATE_CB_RET_CONTINUE_FLAG; } tmp_fwd_data->conn_forward_gateway_array_num = 2; /* bingo! */ if(hdata->conn_forward_gateway_array_num >= FLWD_NETWORK_NxM_MAX){ assert(0); } hdata->conn_forward_gateway_array[hdata->conn_forward_gateway_array_num] = tmp_fwd_data->conn_forward_gateway_array[0]; hdata->conn_forward_gateway_array_num++; /* NOTE: 切记!!! 就算找到了在一个网络中的GDEV, 此处也不能中断callback, 因为一个网络内还有其他符合条件的GDEV, 要全遍历一遍 */ return ITERATE_CB_RET_CONTINUE_FLAG; } static void flwd_network_gdev_fwd_relate(flwd_network_gdev_data_t *tmp_data) { /* 在完整的 */ MESA_htable_iterate_bytime(flwd_global_val.flwd_network_conn_table, ITERATE_TYPE_OLDEST_FIRST, flwd_network_gdev_fwd_relate_cb, tmp_data); return ; } /* #region vlan_id forward_ip */ static int flwd_network_forward_cfg_parse(void) { FILE *fp; char line_buf[1024]; const char *delim = "\t "; char *save_ptr; flwd_network_gdev_data_t tmp_data; char *section; char *forward_ip; fp = fopen("./conf/ip_reuse/network_forward.cfg", "r"); if(NULL == fp){ return -1; } while(fgets(line_buf, 1024, fp)){ if('#' ==line_buf[0]){ continue; } flwd_del_last_rn(line_buf, 1024); memset(&tmp_data, 0, sizeof(flwd_network_gdev_data_t)); section = strtok_r(line_buf, delim, &save_ptr); if(NULL == section){ return -1; } strncpy(tmp_data.region_str, section, FLWD_REGION_STR_LEN_MAX-1); section = strtok_r(NULL, delim, &save_ptr); if(NULL == section){ return -1; } tmp_data.vlan_id = (unsigned int)atoi(section); section = strtok_r(NULL, delim, &save_ptr); if(NULL == section){ return -1; } if(inet_pton(AF_INET, section, &tmp_data.conn_forward_gateway_array[0]) <= 0){ /* 复用一下数组0, 临时存储 forward_ip */ return -1; } forward_ip = section; tmp_data.conn_forward_gateway_array_num = 1; flwd_network_gdev_fwd_relate(&tmp_data); /* MESA_htable_iterate_bytime无法返回回调函数的值, 这里用个trick, 把conn_forward_gateway_array_num=2就是找到了, 否则是1 */ if(2 != tmp_data.conn_forward_gateway_array_num){ flwd_log(30, "can't found related gdev ip in network_gdev.cfg, network_forward.cfg->forward ip:%s\n", forward_ip); return -1; }else{ flwd_log(10, "parse network_gdev.cfg->%s\n", forward_ip); } while(strtok_r(NULL, delim, &save_ptr)); } fclose(fp); return 0; } /* TODO, ///根据选择的活跃IP所在的GDEV_IP或ID, 查关联表, 确定应该从哪个FWD发出 在一个局点来说, 接入网关给任意一个转发网关, 都能通达所有的INLINE-DEVICE, 随机或按IP地址求余总数即可. */ unsigned int flwd_search_fwd_ip_by_gdev_ip(unsigned int gdev_ip_net_order) { flwd_network_gdev_data_t *hdata; char ip_str[16]; int rnd_num; hdata = (flwd_network_gdev_data_t *)MESA_htable_search(flwd_global_val.flwd_network_conn_table, (unsigned char *)&gdev_ip_net_order, sizeof(int)); if(NULL == hdata){ inet_ntop(AF_INET, &gdev_ip_net_order, ip_str, 16); flwd_log(30, "not found gdev ip %s in network_gdev.cfg\n", ip_str); return -1; } /* NxM拓扑关系, 都可联调, 随机挑选一个转发网关 */ rnd_num = rand() % hdata->conn_forward_gateway_array_num; return hdata->conn_forward_gateway_array[rnd_num]; /* TODO: 写一个gdev_ip和FWD数据口IP的静态关联表, 或者开启一个rip路由协议, 自动广播, 自动管理. 测试时先手动写死, 实际就是10.0.6.201的em1虚拟IP地址: 172.16.1.201. */ //inet_pton(AF_INET, "10.0.6.201", &gdev_ip_net_order); //inet_pton(AF_INET, "172.16.1.201", &gdev_ip_net_order); //inet_pton(AF_INET, "47.74.128.220", &gdev_ip_net_order); //return gdev_ip_net_order; } int flwd_network_conn_init(void) { flwd_global_val.flwd_network_conn_table = flwd_create_network_gdev_table(); /* NOTE, 必须先调用flwd_network_gdev_cfg_parse, 添加到htable中, 才能再调用flwd_network_forward_cfg_parse */ if(flwd_network_gdev_cfg_parse() < 0){ flwd_log(30, "flwd_network_gdev_cfg_parse error!\n"); return -1; } /* NOTE, 必须先调用flwd_network_gdev_cfg_parse, 添加到htable中, 才能再调用flwd_network_forward_cfg_parse */ if(flwd_network_forward_cfg_parse() < 0){ flwd_log(30, "flwd_network_forward_cfg_parse error!\n"); return -1; } return 0; }