diff options
Diffstat (limited to 'src/common/flwd_arp.c')
| -rw-r--r-- | src/common/flwd_arp.c | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/src/common/flwd_arp.c b/src/common/flwd_arp.c new file mode 100644 index 0000000..b593f09 --- /dev/null +++ b/src/common/flwd_arp.c @@ -0,0 +1,252 @@ +#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 <assert.h> +#include <stdio.h> +#include <unistd.h> +#include <pthread.h> +#include <string.h> +#include <assert.h> +#include <arpa/inet.h> +#include <netinet/tcp.h> +#include <netinet/udp.h> +#include <linux/if_arp.h> + +/* + ����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; +} + |
