PF_RING patch for libpcap 0.8.1 (tested with 0.8.3) made by Georg Lukas This patch is based on work by Luca Deri (see http://luca.ntop.org/Ring.pdf for more details). diff -uNr libpcap-0.8.1/pcap-int.h libpcap-0.8.1-pfring/pcap-int.h --- libpcap-0.8.1/pcap-int.h 2003-12-15 02:42:24.000000000 +0100 +++ libpcap-0.8.1-pfring/pcap-int.h 2004-04-20 20:01:55.606526568 +0200 @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#) $Header: /tcpdump/master/libpcap/pcap-int.h,v 1.55.2.4 2003/12/15 01:42:24 guy Exp $ (LBL) + * @(#) $Header: /export/home/ntop-priv/ring/libpcap-0.8.1-ring/pcap-int.h,v 1.2 2004/02/06 14:13:11 deri Exp $ (LBL) */ #ifndef pcap_int_h @@ -46,6 +46,8 @@ #include #endif /* WIN32 */ +#define RING /* L.Deri */ + /* * Savefile */ @@ -93,6 +95,22 @@ #endif }; +/* **************************** */ + +#ifdef RING + +#include +#include +#include +#include + +#define PAGE_SIZE 4096 + +#define HAVE_PCAP +#include +#endif + + struct pcap { #ifdef WIN32 ADAPTER *adapter; @@ -121,6 +139,12 @@ u_char *bp; int cc; +#ifdef RING + char *ring_buffer, *slots_buffer; + int ring_fd; + FlowSlotInfo *slots_info; + u_int page_id, slot_id, pkts_per_page; +#endif /* * Place holder for pcap_next(). */ diff -uNr libpcap-0.8.1/pcap-linux.c libpcap-0.8.1-pfring/pcap-linux.c --- libpcap-0.8.1/pcap-linux.c 2003-11-21 11:20:46.000000000 +0100 +++ libpcap-0.8.1-pfring/pcap-linux.c 2004-04-20 20:01:55.609523112 +0200 @@ -27,7 +27,7 @@ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.98.2.4 2003/11/21 10:20:46 guy Exp $ (LBL)"; + "@(#) $Header: /export/home/ntop-priv/ring/libpcap-0.8.1-ring/pcap-linux.c,v 1.3 2004/02/06 14:13:11 deri Exp $ (LBL)"; #endif /* @@ -217,6 +217,20 @@ = { 1, &total_insn }; #endif +#define RING /* L.Deri */ + +#ifdef RING +static struct pcap_stat ringStats; +u_int numPollCalls = 0; + +unsigned long long rdtsc() { + unsigned long long a; + asm volatile("rdtsc":"=A" (a)); + return(a); +} + +#endif + /* * Get a handle for a live capture from the given device. You can * pass NULL as device to get all packages (without link level @@ -258,6 +272,73 @@ handle->snapshot = snaplen; handle->md.timeout = to_ms; +#ifdef RING + handle->ring_fd = socket(PF_RING, SOCK_RAW, htons(ETH_P_ALL)); + + if(handle->ring_fd > 0) { + struct sockaddr sa; + int rc; + u_int memSlotsLen; + + sa.sa_family = PF_RING; + snprintf(sa.sa_data, sizeof(sa.sa_data), "%s", device); + rc = bind(handle->ring_fd, (struct sockaddr *)&sa, sizeof(sa)); + + if(rc == 0) { + handle->ring_buffer = (char *)mmap(NULL, PAGE_SIZE, + PROT_READ|PROT_WRITE, + MAP_SHARED, + handle->ring_fd, 0); + + if(handle->ring_buffer == MAP_FAILED) { + sprintf(ebuf, "mmap() failed"); + return (NULL); + } + + handle->slots_info = (FlowSlotInfo *)handle->ring_buffer; + memSlotsLen = handle->slots_info->tot_num_pages*PAGE_SIZE; + munmap(handle->ring_buffer, PAGE_SIZE); + + handle->ring_buffer = (char *)mmap(NULL, memSlotsLen, + PROT_READ|PROT_WRITE, + MAP_SHARED, handle->ring_fd, 0); + + if(handle->ring_buffer == MAP_FAILED) { + sprintf(ebuf, "mmap() failed"); + return (NULL); + } + + handle->slots_info = (FlowSlotInfo *)handle->ring_buffer; + + /* Safety check */ + if(handle->slots_info->remove_idx >= handle->slots_info->tot_slots) + handle->slots_info->remove_idx = 0; + + handle->page_id = PAGE_SIZE, handle->slot_id = 0, + handle->pkts_per_page = 0; + + /* Set defaults */ + handle->linktype = DLT_EN10MB; + handle->offset = 2; + + printf("RING: tot_slots=%d/slot_len=%d/" + "insertIdx=%d/remove_idx=%d/dropped=%d\n", + handle->slots_info->tot_slots, + handle->slots_info->slot_len, + handle->slots_info->insert_idx, + handle->slots_info->remove_idx, + handle->slots_info->tot_lost); + + ringStats.ps_recv = handle->slots_info->tot_pkts; + ringStats.ps_drop = handle->slots_info->tot_lost; + + goto open_open_live_final; + } else { + close(handle->ring_fd); + /* Continue without ring support */ + } + } +#endif /* * NULL and "any" are special devices which give us the hint to * monitor all devices. @@ -397,6 +478,9 @@ return NULL; } +#ifdef RING + open_open_live_final: +#endif /* * "handle->fd" is a socket, so "select()" and "poll()" * should work on it. @@ -449,6 +533,59 @@ int packet_len, caplen; struct pcap_pkthdr pcap_header; +#ifdef RING + if(handle->ring_buffer != NULL) { + u_int idx, numRuns = 0; + FlowSlot *slot; + + /* + printf("page_id=%d - slot_id=%d\n", + handle->page_id, handle->slot_id); + */ + + slot = (FlowSlot*)&handle->ring_buffer[handle->page_id+handle->slot_id]; + + while(1) { + if(slot->slot_state == 1) { + char *bucket = &slot->bucket; + + handle->md.stat.ps_recv++; + callback(userdata, + (const struct pcap_pkthdr*)bucket, + (const u_char*)&bucket[sizeof(struct pcap_pkthdr)]); + slot->slot_state = 0; + + if(handle->slots_info->remove_idx >= + (handle->slots_info->tot_slots-1)) { + handle->slots_info->remove_idx = 0; + handle->page_id = PAGE_SIZE, handle->slot_id = 0, + handle->pkts_per_page = 0; + } else { + handle->slots_info->remove_idx++; + handle->pkts_per_page++, + handle->slot_id += handle->slots_info->slot_len; + + if(handle->pkts_per_page >= handle->slots_info->pkts_per_page) { + handle->page_id += PAGE_SIZE, handle->slot_id = 0, + handle->pkts_per_page = 0; + } + } + + return(1); + } else { + struct pollfd pfd; + + /* Sleep when nothing is happening */ + pfd.fd = handle->ring_fd; + pfd.events = POLLIN|POLLERR; + pfd.revents = 0; + poll(&pfd, 1, -1); + numPollCalls++; + } + } /* while() */ + } +#endif + #ifdef HAVE_PF_PACKET_SOCKETS /* * If this is a cooked device, leave extra room for a @@ -688,6 +825,17 @@ socklen_t len = sizeof (struct tpacket_stats); #endif +#ifdef RING + if(handle->ring_fd > 0) { + stats->ps_recv = handle->slots_info->tot_pkts-ringStats.ps_recv; + stats->ps_drop = handle->slots_info->tot_lost-ringStats.ps_drop; + + printf("RING: numPollCalls=%d [%.1f packets/call]\n", + numPollCalls, (float)stats->ps_recv/(float)numPollCalls); + return(0); + } +#endif + #ifdef HAVE_TPACKET_STATS /* * Try to get the packet counts from the kernel. @@ -879,6 +1027,11 @@ } } + +#ifdef RING + if(handle->ring_fd <= 0) can_filter_in_kernel = 0; +#endif + if (can_filter_in_kernel) { if ((err = set_kernel_filter(handle, &fcode)) == 0) {