#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 #include /* 对于SNAT, 首包肯定是客户端发出, access网关记录下客户端的mac, 不必每次发包都查询ARP, 用空间换时间. 对于DNAT, 首包是外部主机发出, 访问内部服务器, 可能目标主机MAC还没有, 需要主动发起ARP查询, ARP采用异步模式, 第一次查询肯定没结果, 先把当前包丢弃, 待得到ARP应答后, 存储于nat_info, 后续的包就不必再查. */ static const unsigned char G_BROADCAST_MAC_ADDR[ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; /* 广播MAC */ static void flwd_arp_query_ipv4(int tid, unsigned int dip_net, flwd_device_handle_t *io_handle) { int ret; void *send_mbuff = io_handle->low_level_mbuff_malloc(io_handle, tid, sizeof(flwd_eth_hdr_t) + sizeof(flwd_arp_hdr_t)); char *unsend_data_ptr = io_handle->low_level_mbuff_mtod(send_mbuff); flwd_eth_hdr_t *ehdr = (flwd_eth_hdr_t *)unsend_data_ptr; memcpy(ehdr->h_source, io_handle->io_para.local_mac_addr, ETH_ALEN); memcpy(ehdr->h_dest, G_BROADCAST_MAC_ADDR, ETH_ALEN); ehdr->h_proto = htons(ETH_P_ARP); flwd_arp_hdr_t *arphdr = (flwd_arp_hdr_t *)(unsend_data_ptr + sizeof(flwd_eth_hdr_t)); arphdr->ar_hrd = htons(ARPHRD_ETHER); arphdr->ar_pro = htons(ETH_P_IP); arphdr->ar_hln = ETH_ALEN; arphdr->ar_pln = sizeof(int); arphdr->ar_op = htons(ARPOP_REQUEST); memcpy(arphdr->ar_sha, io_handle->io_para.local_mac_addr, ETH_ALEN); memcpy(arphdr->ar_spa, &io_handle->io_para.device_ip_net_order, sizeof(int)); memset(arphdr->ar_tha, 0, ETH_ALEN); memcpy(arphdr->ar_tpa, &dip_net, sizeof(int)); io_handle->low_level_mbuff_set_pkt_len(send_mbuff, sizeof(flwd_eth_hdr_t) + sizeof(flwd_arp_hdr_t)); ret = io_handle->low_level_send(io_handle, tid, send_mbuff); if(ret < 0){ flwd_log(30, "send arp query packet error! ret = %d.\n", ret); }else{ char ip_str[16]; inet_ntop(AF_INET, &dip_net, ip_str, 16); flwd_log(10, "send arp query dip:%s.\n", ip_str); } } static void flwd_arp_net_query(int tid, const flwd_ip_t *dip_union, flwd_device_handle_t *io_handle) { if(FLWD_IP_ADDR_TYPE_V4 == dip_union->addr_type){ flwd_arp_query_ipv4(tid, dip_union->addr_ipv4, io_handle); }else{ /* TODO, IPv6 <---> ARP, IPv6邻居发现协议 */ assert(0); } } /* 根据当前数据包的真实目标IP, 和本地地址, 判断二层ethernetMAC地址, 应该使用哪个IP? */ static unsigned int flwd_judge_layer2_dipv4(unsigned int real_target_ip_net, flwd_device_handle_t *io_handle) { unsigned int real_target_ip_host = ntohl(real_target_ip_net); unsigned int local_ip_mask_host = ntohl(io_handle->io_para.device_ip_mask_net_order); unsigned int local_ip_host = ntohl(io_handle->io_para.device_ip_net_order); if((real_target_ip_host & local_ip_mask_host) == (local_ip_host & local_ip_mask_host)){ /* 目标IP在同一个网段, 直接使用目标IP, 查询ARP表 */ return real_target_ip_net; } /* 目标IP不在同一个网段, 需要跨越三层设备, 使用网关的IP查询ARP表 */ return io_handle->io_para.gateway_ip_net_order; } static struct in6_addr * flwd_judge_layer2_dipv6(struct in6_addr *real_target_ip_net, flwd_device_handle_t *io_handle) { /* TODO, IPv6 */ return real_target_ip_net; } int flwd_arp_table_query(int tid, flwd_ip_t *target_ip, flwd_device_handle_t *io_handle, unsigned char result_mac[6]) { unsigned char *res; #if FLWD_NO_ACTIVE_ARP_QUERY /* 172.16.1.201, 10.0.6.201 */ static unsigned char acc_to_fwd_gateway_mac[6] = {0x74, 0x86,0x7a,0xd0,0x12,0xfc}; /* 172.16.1.229, 10.0.6.229 */ static unsigned char fwd_to_acc_gateway_mac[6] = {0x74, 0x86, 0x7A, 0xD0, 0x1B, 0x30}; if(0xC90110AC == target_ip->addr_ipv4){ memcpy(result_mac, acc_to_fwd_gateway_mac, 6); return 0; }else if(0xE50110AC == target_ip->addr_ipv4){ memcpy(result_mac, fwd_to_acc_gateway_mac, 6); return 0; }else{ abort(); } #else unsigned char *hkey; unsigned int hkey_size; unsigned int local_net_dipv4; if(FLWD_IP_ADDR_TYPE_V4 == target_ip->addr_type){ local_net_dipv4 = flwd_judge_layer2_dipv4(target_ip->addr_ipv4, io_handle); hkey = (unsigned char *)&local_net_dipv4; hkey_size = sizeof(int); target_ip->addr_ipv4 = local_net_dipv4; }else{ struct in6_addr *local_net_dip6 = flwd_judge_layer2_dipv6(&target_ip->addr_ipv6, io_handle); hkey = (unsigned char *)local_net_dip6; hkey_size = sizeof(struct in6_addr); } pthread_rwlock_rdlock(&flwd_global_val.flwd_arp_htable_rwlock); res = (unsigned char *)MESA_htable_search(flwd_global_val.flwd_arp_table, hkey, hkey_size); if(res != NULL){ memcpy(result_mac, res, 6); /* 在锁保护区域内, 先将查到的结果保存下来, 可能立刻就被其他线程更新, 或者超时淘汰了! */ } pthread_rwlock_unlock(&flwd_global_val.flwd_arp_htable_rwlock); if(NULL == res){ flwd_arp_net_query(tid, target_ip, io_handle); /* 如果查不到, 主动向网络目标发送一次查询包 */ return -1; } #endif return 0; } void flwd_arp_response_update(const flwd_arp_hdr_t *arp_hdr) { unsigned char *res_mac = (unsigned char *)malloc(ETH_ALEN); int ret; memcpy(res_mac, arp_hdr->ar_sha, ETH_ALEN); pthread_rwlock_wrlock(&flwd_global_val.flwd_arp_htable_rwlock); ret = MESA_htable_add(flwd_global_val.flwd_arp_table, arp_hdr->ar_spa, sizeof(int), res_mac); pthread_rwlock_unlock(&flwd_global_val.flwd_arp_htable_rwlock); if(ret < 0){ free(res_mac); } } static int flwd_arp_htable_key_cmp(const uchar * key1, uint size1, const uchar * key2, uint size2) { if(size1 != size2){ return (int)size1 - (int)size2; } return memcmp(key1, key2, size1); } static uint flwd_arp_htable_key2index(const MESA_htable_handle table, const uchar * key, uint size) { uint i; uint seed = 13131; // 31 131 1313 13131 131313 etc.. uint hash = 31; for(i = 0; i < size; i++){ hash = hash * seed + (*key++); } return hash; } static void flwd_arp_htable_data_free(void *data) { free(data); } int flwd_arp_table_init(void) { int opt_int; MESA_htable_handle htable = MESA_htable_born(); opt_int = 0; /* 外部使用读写锁保护, htable用无锁模式 */ 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 = 10000; MESA_htable_set_opt(htable, MHO_HASH_MAX_ELEMENT_NUM, &opt_int, sizeof(int)); opt_int = 120; MESA_htable_set_opt(htable, MHO_EXPIRE_TIME, &opt_int, sizeof(int)); opt_int = HASH_ELIMINATE_ALGO_FIFO; MESA_htable_set_opt(htable, MHO_ELIMIMINATE_TYPE, &opt_int, sizeof(int)); MESA_htable_set_opt(htable, MHO_CBFUN_KEY_COMPARE, (void *)&flwd_arp_htable_key_cmp, sizeof(void *)); MESA_htable_set_opt(htable, MHO_CBFUN_KEY_TO_INDEX, (void *)&flwd_arp_htable_key2index, sizeof(void *)); MESA_htable_set_opt(htable, MHO_CBFUN_DATA_FREE, (void *)&flwd_arp_htable_data_free, sizeof(void *)); ////MESA_htable_set_opt(htable, MHO_CBFUN_DATA_EXPIRE_NOTIFY, (void *)&flwd_access_nat_htable_data_expire_notify, 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)); opt_int = 100; MESA_htable_set_opt(htable, MHO_HASH_LIST_COLLIDE_THRESHOLD, &opt_int, sizeof(int)); char *err_log = (char *)"./log/flwd_arp_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); flwd_global_val.flwd_arp_table = htable; pthread_rwlock_init(&flwd_global_val.flwd_arp_htable_rwlock, NULL); return 0; }