diff options
Diffstat (limited to 'src/packet_io/flwd_packet_io_pcap.c')
| -rw-r--r-- | src/packet_io/flwd_packet_io_pcap.c | 428 |
1 files changed, 428 insertions, 0 deletions
diff --git a/src/packet_io/flwd_packet_io_pcap.c b/src/packet_io/flwd_packet_io_pcap.c new file mode 100644 index 0000000..adb584e --- /dev/null +++ b/src/packet_io/flwd_packet_io_pcap.c @@ -0,0 +1,428 @@ +#include "flowood.h" +#include "flowood_fun.h" +#include "flwd_net.h" +#include <pcap/pcap.h> +#include "MESA_list_queue.h" +#include "MESA_handle_logger.h" +#include "MESA_prof_load.h" +#include <sys/types.h> +#include <sys/socket.h> +#include <string.h> +#include <arpa/inet.h> +#include <assert.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <net/if_arp.h> +#include <net/if.h> + +#ifdef __cplusplus +/* ��Ҫ��̬dlopen��ȡ������, ʹ��C�淶 */ +extern "C" { +#endif + + +typedef struct { + pthread_t pid; + unsigned char thread_seq; + int sd_raw_eth; /* �ײ㷢��socket��� */ + struct sockaddr sock_addr; + MESA_lqueue_head pkt_queue; +}pcap_work_thread_t; + +typedef struct{ + char *__data_buf; /* mbuff������ͷָ�� */ + char *data_actual_ptr; /* ��ǰ����ʵ�ʴ洢������ָ�� */ + int __data_buf_max_len; /* mbuff��泤��, ��FLWD_LINK_MTU */ + int data_actual_len; /* ��ǰ������ʵ�ʴ洢�����ݳ��� */ +}pcap_mbuff_t; + +/* pcapģʽ�ڲ�����ṹ */ +typedef struct{ + int tot_thread_count; + pcap_t *pcap_dev_handle; + pcap_work_thread_t pcap_io_thread_para[FLWD_MAX_THREAD_NUM]; + pcap_mbuff_t pcap_send_buf[FLWD_MAX_THREAD_NUM]; /* ��������, ��ʼ��ʱ����, �Ժ�����ÿ�ζ�̬malloc/free */ +}flwd_device_handle_pcap_t; + +typedef struct{ + char *pkt_data; + int pkt_len; +}pcap_queue_item_t; + +/* 2012-04-10 LiJia add, ��ȡ����MAC��ַ +����: + device: �������� + mac: �洢MAC��ַ������,���Ϊ������, + ������MAC��ַΪ11:22:33:44:55:66,��mac[0]Ϊ0x11,mac[5]Ϊ0x66. +����ֵ: + 0: ���� + -1:���� +*/ +static int MESA_get_dev_mac(const char *device, unsigned char mac[6]) +{ + struct ifreq ifr; + int fd; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if(fd < 0) + { + return -1; + } + + memset(ifr.ifr_ifrn.ifrn_name, 0, sizeof(ifr.ifr_ifrn.ifrn_name)); + strncpy(ifr.ifr_ifrn.ifrn_name, device, sizeof(ifr.ifr_ifrn.ifrn_name)); + if(ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) + { + printf("Cann't get hwaddr of %s:%s\n", device, strerror(errno)); + goto err_exit; + } + + if(ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) + { + printf("'%s' is not ethernet interface!\n", device); + goto err_exit; + } + + memcpy(mac, ifr.ifr_ifru.ifru_addr.sa_data, 6); + + close(fd); + + return 0; + +err_exit: + close(fd); + return -1; +} + +static inline int flwd_pcap_dispatch_thread(flwd_device_handle_pcap_t *pcap_io_handle, const u_char *data) +{ + int to_work_thread_seq; + const flwd_eth_hdr_t *flwd_eth_hdr = (flwd_eth_hdr_t *)data; + const flwd_ipv4_hdr_t *flwd_ip_hdr; + + if(ETH_P_IP == ntohs(flwd_eth_hdr->h_proto)){ + flwd_ip_hdr = (flwd_ipv4_hdr_t *)(data + sizeof(flwd_eth_hdr_t)); + to_work_thread_seq = (flwd_ip_hdr->ip_src.s_addr ^ flwd_ip_hdr->ip_dst.s_addr) % pcap_io_handle->tot_thread_count; + }else{ + to_work_thread_seq = 0;/* ����Э��Ĭ����0���� */ + } + + return to_work_thread_seq; +} + + + +static pcap_mbuff_t *flwd_pcap_create_new_mbuff(u_char *data, int datalen) +{ + pcap_mbuff_t *pcap_mbuff; + + pcap_mbuff = (pcap_mbuff_t *)calloc(1, sizeof(pcap_mbuff_t)); + + pcap_mbuff->__data_buf = (char *)malloc(datalen + FLWD_VXLAN_OUTER_PACKET_LEN); /* Ԥ��vxlanͷ�� */ + pcap_mbuff->__data_buf_max_len = datalen + FLWD_VXLAN_OUTER_PACKET_LEN; + + + pcap_mbuff->data_actual_ptr = pcap_mbuff->__data_buf + FLWD_VXLAN_OUTER_PACKET_LEN; + pcap_mbuff->data_actual_len = datalen; + + memcpy(pcap_mbuff->data_actual_ptr, data, datalen); + + return pcap_mbuff; +} + + +static void flwd_pcap_pkt_handle(u_char *user, const struct pcap_pkthdr *hdr, const u_char *data) +{ + int to_work_thread_seq; + pcap_mbuff_t *pcap_mbuff; + flwd_device_handle_pcap_t *pcap_io_handle = (flwd_device_handle_pcap_t *)user; + + to_work_thread_seq = flwd_pcap_dispatch_thread(pcap_io_handle, data); + + pcap_mbuff = flwd_pcap_create_new_mbuff((u_char *)data, hdr->caplen); + + /* NOTE: �˴������������ӿ�, ��Ϊpcap_loop�ڶ������߳������Ŀռ�, ��Ӱ���������� */ + int ret = MESA_lqueue_join_tail(pcap_io_handle->pcap_io_thread_para[to_work_thread_seq].pkt_queue, &pcap_mbuff, sizeof(void *)); + if(ret < 0){ + free(pcap_mbuff->__data_buf); + free(pcap_mbuff); + printf("pcap io thread MESA_lqueue_join_tail() error, ret=%d\n", ret); + } + +} + +static int pcap_low_level_io_init(flwd_device_handle_t *global_dev_handle) +{ + int i; + char pcap_errbuf[PCAP_ERRBUF_SIZE]; + char str_tmp[128]; + struct bpf_program bpf_filter; + + flwd_device_handle_pcap_t *pcap_io_handle = (flwd_device_handle_pcap_t *)calloc(1, sizeof(flwd_device_handle_pcap_t)); + + pcap_io_handle->pcap_dev_handle = pcap_open_live(global_dev_handle->io_para.device_name, 4096, 1, 1, pcap_errbuf); + if(NULL == pcap_io_handle->pcap_dev_handle){ + flwd_log(RLOG_LV_FATAL, "pcap_open_live() error, %s\n", pcap_errbuf); + return -1; + } + /* TODO, set filter */ + if(global_dev_handle->io_para.pkt_filter != NULL){ + if(pcap_compile(pcap_io_handle->pcap_dev_handle, &bpf_filter, (char *)global_dev_handle->io_para.pkt_filter, 1, 0) < 0){ + flwd_log(RLOG_LV_FATAL, "pcap_compile() error, invalid pkt_filter: %s\n", global_dev_handle->io_para.pkt_filter); + return -1; + } + + pcap_setfilter(pcap_io_handle->pcap_dev_handle, &bpf_filter); + } + + pcap_setdirection(pcap_io_handle->pcap_dev_handle, PCAP_D_IN); /* ֻ���հ� */ + + for(i = 0; i < global_dev_handle->tot_thread_count; i++){ + pcap_io_handle->pcap_io_thread_para[i].thread_seq = i; + pcap_io_handle->pcap_send_buf[i].__data_buf = (char *)malloc(FLWD_LINK_MTU); + pcap_io_handle->pcap_send_buf[i].__data_buf_max_len = FLWD_LINK_MTU; + pcap_io_handle->pcap_io_thread_para[i].sd_raw_eth = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL)); + + snprintf(pcap_io_handle->pcap_io_thread_para[i].sock_addr.sa_data, + sizeof(pcap_io_handle->pcap_io_thread_para[i].sock_addr.sa_data), + "%s", global_dev_handle->io_para.device_name); + + pcap_io_handle->pcap_io_thread_para[i].pkt_queue = MESA_lqueue_create(1, 50000); + } + + MESA_load_profile_string_def(FLWD_CONFIG_FILE, g_packet_io_cfg_para[(int)global_dev_handle->io_para.topo_mode].cfg_file_section, "addr_para", str_tmp, 128, "#"); + if('#' == str_tmp[0]){ + flwd_log(RLOG_LV_FATAL, "get config %s->addr_para error!", g_packet_io_cfg_para[(int)global_dev_handle->io_para.topo_mode].cfg_file_section); + return -1; + } + if(inet_pton(AF_INET, str_tmp, &global_dev_handle->io_para.device_ip_net_order) <= 0){ + flwd_log(RLOG_LV_FATAL, "config %s->addr_para type invalid!", g_packet_io_cfg_para[(int)global_dev_handle->io_para.topo_mode].cfg_file_section); + return -1; + } + + MESA_load_profile_string_def(FLWD_CONFIG_FILE, g_packet_io_cfg_para[(int)global_dev_handle->io_para.topo_mode].cfg_file_section, "addr_mask", str_tmp, 128, "#"); + if('#' == str_tmp[0]){ + flwd_log(RLOG_LV_FATAL, "get config %s->addr_mask error!", g_packet_io_cfg_para[(int)global_dev_handle->io_para.topo_mode].cfg_file_section); + return -1; + } + if(inet_pton(AF_INET, str_tmp, &global_dev_handle->io_para.device_ip_mask_net_order) <= 0){ + flwd_log(RLOG_LV_FATAL, "config %s->addr_mask type invalid!", g_packet_io_cfg_para[(int)global_dev_handle->io_para.topo_mode].cfg_file_section); + return -1; + } + + MESA_load_profile_string_def(FLWD_CONFIG_FILE, g_packet_io_cfg_para[(int)global_dev_handle->io_para.topo_mode].cfg_file_section, "gateway_ip", str_tmp, 128, "#"); + if('#' == str_tmp[0]){ + flwd_log(RLOG_LV_FATAL, "get config %s->gateway_ip error!", g_packet_io_cfg_para[(int)global_dev_handle->io_para.topo_mode].cfg_file_section); + return -1; + } + if(inet_pton(AF_INET, str_tmp, &global_dev_handle->io_para.gateway_ip_net_order) <= 0){ + flwd_log(RLOG_LV_FATAL, "config %s->gateway_ip type invalid!", g_packet_io_cfg_para[(int)global_dev_handle->io_para.topo_mode].cfg_file_section); + return -1; + } + + + MESA_get_dev_mac(global_dev_handle->io_para.device_name, global_dev_handle->io_para.local_mac_addr); + + pcap_io_handle->tot_thread_count = global_dev_handle->tot_thread_count; + global_dev_handle->low_level_io_handle = (void *)pcap_io_handle; + + return 0; +} + +static int pcap_low_level_send(flwd_device_handle_t *global_dev_handle, int tid, void *mbuff) +{ + int ret; + pcap_mbuff_t *pcap_mbuff = (pcap_mbuff_t *)mbuff; + flwd_device_handle_pcap_t *pcap_io_handle = (flwd_device_handle_pcap_t *)global_dev_handle->low_level_io_handle; + + ret = sendto(pcap_io_handle->pcap_io_thread_para[tid].sd_raw_eth, + pcap_mbuff->data_actual_ptr, + pcap_mbuff->data_actual_len, + MSG_DONTWAIT, + (const struct sockaddr *)&pcap_io_handle->pcap_io_thread_para[tid].sock_addr, + sizeof(struct sockaddr)); + + return ret; +} + + + + +int low_level_pkt_recv(flwd_device_handle_t *g_dev_handle, int tid, void **mbuff) +{ + int ret, try_times; + pcap_mbuff_t *pcap_mbuff; + long recv_len; + flwd_device_handle_pcap_t *pcap_io_handle = (flwd_device_handle_pcap_t *)g_dev_handle->low_level_io_handle; + + recv_len = sizeof(void *); + + for(try_times = 0; try_times < 20; try_times++){ + /* NOTE: ��Ϊ��trylock, �dz�����ʧ��, �����������Լ��� */ + ret = MESA_lqueue_try_get_head(pcap_io_handle->pcap_io_thread_para[tid].pkt_queue, &pcap_mbuff, &recv_len); + switch(ret){
+ case 0: //OK + goto done; + break; + + case -5: //empty, no packet + return -1; + } + } + + if(ret < 0){ + return -1; + } + +done: + *mbuff = (void *)pcap_mbuff; + + return pcap_mbuff->data_actual_len; +} + +void low_level_pkt_free(flwd_device_handle_t *g_dev_handle, int tid, void *mbuff) +{ + pcap_mbuff_t *pcap_mbuff = (pcap_mbuff_t *)mbuff; + + free(pcap_mbuff->__data_buf); + free(pcap_mbuff); + + return; +} + + +void *low_level_mbuff_malloc(flwd_device_handle_t *g_dev_handle, int tid, int len) +{ + ///flwd_device_handle_pcap_t *pcap_io_handle = (flwd_device_handle_pcap_t *)g_dev_handle->low_level_io_handle; + + pcap_mbuff_t *mbuff = (pcap_mbuff_t *)malloc(sizeof(pcap_mbuff_t)); + + mbuff->__data_buf = (char *)malloc(FLWD_LINK_MTU); + mbuff->data_actual_ptr = mbuff->__data_buf + FLWD_VXLAN_OUTER_PACKET_LEN; + mbuff->__data_buf_max_len = FLWD_LINK_MTU; + mbuff->data_actual_len = 0; + + return (void *)mbuff; +} + +char *low_level_mbuff_mtod(void *mbuff) +{ + pcap_mbuff_t *pcap_mbuff = (pcap_mbuff_t *)mbuff; + + return (char *)pcap_mbuff->data_actual_ptr; +} + +void low_level_mbuff_free(struct __flwd_device_handle *h, int tid, void *mbuff) +{ + pcap_mbuff_t *pcap_mbuff = (pcap_mbuff_t *)mbuff; + + free(pcap_mbuff->__data_buf); + pcap_mbuff->data_actual_len = 0; + pcap_mbuff->__data_buf_max_len = 0; + free(mbuff); +} + +void low_level_mbuff_free_after_send(flwd_device_handle_t *g_dev_handle, int tid, void *mbuff) +{ + /* pcapģʽ�������Զ�free, �ٴε���������free���� */ + low_level_mbuff_free(g_dev_handle, tid, mbuff); +} + + +void low_level_mbuff_send_back(flwd_device_handle_t *g_dev_handle, int tid, void *mbuff) +{ + /* pcapģʽ��ʱ���û�עgdev���ݰ�, �պ��� */ + return; +} + +/* + ��mbuff����user_data����. + + return value: + ������ʼλ��; +*/ +char * low_level_mbuff_data_append(void *mbuff, const char *user_data, int user_data_len) +{ + pcap_mbuff_t *pcap_mbuff= (pcap_mbuff_t *)mbuff; + + assert(user_data_len <= pcap_mbuff->__data_buf_max_len - pcap_mbuff->data_actual_len); + + memcpy(pcap_mbuff->data_actual_ptr, user_data, user_data_len); + pcap_mbuff->data_actual_len += user_data_len; + + return (char *)pcap_mbuff->data_actual_ptr; +} + +/* ����ָ����ǰ�ƶ�N���ֽ�, ���ݳ����Զ�����N, ���������������ݰ�֮ǰ���������ͷ, ��vxlan */ +char *low_level_mbuff_data_forward(void *mbuff, int n) +{ + pcap_mbuff_t *pcap_mbuff = (pcap_mbuff_t *)mbuff; + + assert(n <= pcap_mbuff->data_actual_ptr - pcap_mbuff->__data_buf); + + pcap_mbuff->data_actual_ptr -= n; /* ��ǰ�ƶ� */ + pcap_mbuff->data_actual_len += n; + + return (char *)pcap_mbuff->data_actual_ptr; +} + + +/* ����ָ������ƶ�N���ֽ�, ���ݳ����Զ�����N, �����ǰ��������ݰ���ijЩ��ͷ����, ���ȥvxlanͷ�� */ +char * low_level_mbuff_data_rearward(void *mbuff, int n) +{ + pcap_mbuff_t *pcap_mbuff = (pcap_mbuff_t *)mbuff; + + assert(n <= pcap_mbuff->__data_buf_max_len - pcap_mbuff->data_actual_len); + + pcap_mbuff->data_actual_ptr += n; + pcap_mbuff->data_actual_len -= n; + + return pcap_mbuff->data_actual_ptr; +} + + + +int low_level_mbuff_get_pkt_len(void *mbuff) +{ + pcap_mbuff_t *pcap_mbuff = (pcap_mbuff_t *)mbuff; + + return pcap_mbuff->data_actual_len; +} + +void low_level_mbuff_set_pkt_len(void *mbuff, int pkt_len) +{ + pcap_mbuff_t *pcap_mbuff = (pcap_mbuff_t *)mbuff; + + pcap_mbuff->data_actual_len = pkt_len; +} + + +int low_level_send(flwd_device_handle_t *global_dev_handle, int tid, void *mbuff) +{ + return pcap_low_level_send(global_dev_handle, tid, mbuff); +} + +/* �˺���������������ѭ��, һֱ������ */ +void low_level_io_run(flwd_device_handle_t *global_io_handle) +{ + ///int i; + ///pthread_t pid; + + flwd_device_handle_pcap_t *pcap_io_handle = (flwd_device_handle_pcap_t *)global_io_handle->low_level_io_handle; + + while(1){ + pcap_loop(pcap_io_handle->pcap_dev_handle, -1, flwd_pcap_pkt_handle, (u_char *)pcap_io_handle); + } + + return; +} + +int low_level_io_init(flwd_device_handle_t *global_dev_handle) +{ + return pcap_low_level_io_init(global_dev_handle); +} + +#ifdef __cplusplus +} +#endif + |
