summaryrefslogtreecommitdiff
path: root/src/common/flwd_arp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/flwd_arp.c')
-rw-r--r--src/common/flwd_arp.c252
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;
+}
+