Openwrt/openwrt/package/libpcap/patches/110-pf_ring.patch

614 lines
16 KiB
Diff
Raw Normal View History

diff -urN libpcap.old/pcap-int.h libpcap.dev/pcap-int.h
--- libpcap.old/pcap-int.h 2003-12-15 02:42:24.000000000 +0100
+++ libpcap.dev/pcap-int.h 2005-10-22 23:20:12.220060500 +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/PF_RING/userland/libpcap-0.8.1-ring/pcap-int.h,v 1.2 2004/11/25 09:58:00 deri Exp $ (LBL)
*/
#ifndef pcap_int_h
@@ -46,6 +46,8 @@
#include <packet32.h>
#endif /* WIN32 */
+#define RING /* L.Deri */
+
/*
* Savefile
*/
@@ -93,6 +95,57 @@
#endif
};
+/* **************************** */
+
+#ifdef RING
+
+#include <unistd.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <sys/poll.h>
+
+#define PAGE_SIZE 4096
+
+#define HAVE_PCAP
+#include <linux/ring.h>
+#endif
+
+#ifdef RING
+
+#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */
+
+struct e1000_rx_desc {
+ u_int64_t buffer_addr; /* Address of the descriptor's data buffer */
+ u_int16_t length; /* Length of data DMAed into data buffer */
+ u_int16_t csum; /* Packet checksum */
+ u_int8_t status; /* Descriptor status */
+ u_int8_t errors; /* Descriptor Errors */
+ u_int16_t special;
+};
+
+/* Transmit Descriptor */
+struct e1000_tx_desc {
+ u_int64_t buffer_addr; /* Address of the descriptor's data buffer */
+ union {
+ u_int32_t data;
+ struct {
+ u_int16_t length; /* Data buffer length */
+ u_int8_t cso; /* Checksum offset */
+ u_int8_t cmd; /* Descriptor control */
+ } flags;
+ } lower;
+ union {
+ u_int32_t data;
+ struct {
+ u_int8_t status; /* Descriptor status */
+ u_int8_t css; /* Checksum start */
+ u_int16_t special;
+ } fields;
+ } upper;
+};
+
+#endif
+
struct pcap {
#ifdef WIN32
ADAPTER *adapter;
@@ -121,6 +174,14 @@
u_char *bp;
int cc;
+#ifdef RING
+ /* PF_RING */
+ char *ring_buffer, *ring_slots;
+ int ring_fd;
+ FlowSlotInfo *slots_info;
+ u_int page_id, slot_id, pkts_per_page;
+ u_int poll_sleep;
+#endif
/*
* Place holder for pcap_next().
*/
diff -urN libpcap.old/pcap-linux.c libpcap.dev/pcap-linux.c
--- libpcap.old/pcap-linux.c 2003-11-21 11:20:46.000000000 +0100
+++ libpcap.dev/pcap-linux.c 2005-10-22 23:43:59.726120250 +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/PF_RING/userland/libpcap-0.8.1-ring/pcap-linux.c,v 1.2 2004/11/25 09:58:00 deri Exp $ (LBL)";
#endif
/*
@@ -83,7 +83,7 @@
#ifdef HAVE_DAG_API
#include "pcap-dag.h"
#endif /* HAVE_DAG_API */
-
+
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
@@ -217,6 +217,83 @@
= { 1, &total_insn };
#endif
+#define RING /* L.Deri */
+#define SAFE_RING_MODE /*
+ Copy the bucket in order to avoid kernel
+ crash if the application faults
+ */
+
+#ifdef RING
+unsigned char *write_register;
+static struct pcap_stat ringStats;
+u_long numPollCalls = 0, numReadCalls = 0;
+
+#define POLL_SLEEP_STEP 10 /* ns = 0.1 ms */
+#define POLL_SLEEP_MIN POLL_SLEEP_STEP
+#define POLL_SLEEP_MAX 1000 /* ns */
+#define POLL_QUEUE_MIN_LEN 500 /* # packets */
+
+#ifdef SAFE_RING_MODE
+static char staticBucket[2048];
+#endif
+
+
+/* ******************************* */
+
+int pcap_set_cluster(pcap_t *handle, u_int clusterId) {
+ return(handle->ring_fd ? setsockopt(handle->ring_fd, 0, SO_ADD_TO_CLUSTER,
+ &clusterId, sizeof(clusterId)): -1);
+}
+
+/* ******************************* */
+
+int pcap_remove_from_cluster(pcap_t *handle) {
+ return(handle->ring_fd ?
+ setsockopt(handle->ring_fd, 0, SO_REMOVE_FROM_CLUSTER, NULL, 0) : -1);
+}
+
+/* ******************************* */
+
+int pcap_set_reflector(pcap_t *handle, char *reflectorDevice) {
+ return(handle->ring_fd ?
+ setsockopt(handle->ring_fd, 0, SO_SET_REFLECTOR,
+ &reflectorDevice, strlen(reflectorDevice)) : -1);
+}
+
+/* ******************************* */
+
+static int set_if_promisc(const char *device, int set_promisc) {
+ int sock_fd;
+ struct ifreq ifr;
+
+ if(device == NULL) return(-3);
+
+ sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if(sock_fd <= 0) return(-1);
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+ if(ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) {
+ close(sock_fd);
+ return(-2);
+ }
+
+ if(set_promisc) {
+ if((ifr.ifr_flags & IFF_PROMISC) == 0) ifr.ifr_flags |= IFF_PROMISC;
+ } else {
+ /* Remove promisc */
+ if((ifr.ifr_flags & IFF_PROMISC) != 0) ifr.ifr_flags &= ~IFF_PROMISC;
+ }
+
+ if(ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1)
+ return(-1);
+
+ close(sock_fd);
+ return(0);
+}
+
+#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 +335,138 @@
handle->snapshot = snaplen;
handle->md.timeout = to_ms;
+#ifdef RING
+ handle->ring_fd = handle->fd = socket(PF_RING, SOCK_RAW, htons(ETH_P_ALL));
+
+ printf("Open RING [fd=%d]\n", handle->ring_fd);
+
+ if(handle->ring_fd > 0) {
+ struct sockaddr sa;
+ int rc;
+ u_int memSlotsLen;
+
+ err = 0;
+ 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->md.device = strdup(device);
+ 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;
+ if(handle->slots_info->version != RING_FLOWSLOT_VERSION) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "Wrong RING version: "
+ "kernel is %i, libpcap was compiled with %i\n",
+ handle->slots_info->version, RING_FLOWSLOT_VERSION);
+ return (NULL);
+ }
+ memSlotsLen = handle->slots_info->tot_mem;
+ 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;
+ handle->ring_slots = (char *)(handle->ring_buffer+sizeof(FlowSlotInfo));
+
+ /* 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;
+
+ if(0) {
+ int i;
+
+ for(i=0; i<handle->slots_info->tot_slots; i++) {
+ unsigned long idx = i*handle->slots_info->slot_len;
+ FlowSlot *slot = (FlowSlot*)&handle->ring_slots[idx];
+
+ printf("RING: Setting RING_MAGIC_VALUE into slot %d [displacement=%lu]\n", i, idx);
+ slot->magic = RING_MAGIC_VALUE; slot->slot_state = 0;
+ printf("RING: slot[%d]: magic=%d, slot_state=%d\n",
+ slot->magic, slot->slot_state);
+ }
+ }
+
+
+ /* Set defaults */
+ handle->linktype = DLT_EN10MB;
+ handle->offset = 2;
+
+ printf("RING (%s): tot_slots=%d/slot_len=%d/"
+ "insertIdx=%d/remove_idx=%d/dropped=%d\n",
+ device,
+ 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_read;
+ ringStats.ps_drop = handle->slots_info->tot_lost;
+
+ if(promisc) {
+ struct ifreq ifr;
+
+ err = 0;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+ if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "ioctl: %s", pcap_strerror(errno));
+ err = 1;
+ }
+
+ if(err == 0) {
+ if ((ifr.ifr_flags & IFF_PROMISC) == 0) {
+ /*
+ * Promiscuous mode isn't currently on,
+ * so turn it on, and remember that
+ * we should turn it off when the
+ * pcap_t is closed.
+ */
+
+ ifr.ifr_flags |= IFF_PROMISC;
+ if (ioctl(handle->fd, SIOCSIFFLAGS, &ifr) == -1) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "ioctl: %s", pcap_strerror(errno));
+ err = 1;
+ }
+ }
+
+ if(err == 0)
+ handle->md.clear_promisc = 1;
+ }
+ }
+
+ if(err == 0)
+ goto open_open_live_final;
+ }
+
+ /* Don't put 'else' above... */
+ 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 +606,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 +661,120 @@
int packet_len, caplen;
struct pcap_pkthdr pcap_header;
+#ifdef RING
+ if(handle->ring_buffer != NULL) {
+ u_int idx, numRuns = 0, ptrAddr;
+ FlowSlot *slot;
+
+ slot = (FlowSlot*)&handle->ring_slots[handle->slots_info->remove_idx*handle->slots_info->slot_len];
+
+ while(1) {
+ u_int32_t queuedPkts;
+
+ if(handle->slots_info->tot_insert >= handle->slots_info->tot_read)
+ queuedPkts = handle->slots_info->tot_insert - handle->slots_info->tot_read;
+ else
+ queuedPkts = handle->slots_info->tot_slots + handle->slots_info->tot_insert - handle->slots_info->tot_read;
+
+ if(queuedPkts && (slot->slot_state == 1)) {
+ char *bucket = &slot->bucket;
+
+#ifdef RING_MAGIC
+ if(slot->magic != RING_MAGIC_VALUE) {
+ printf("==>> Bad Magic [remove_idx=%u][insert_idx=%u][ptrAddr=%u]\n",
+ handle->slots_info->remove_idx,
+ handle->slots_info->insert_idx,
+ ptrAddr);
+ slot->magic = RING_MAGIC_VALUE;
+ }
+#endif
+
+
+ handle->md.stat.ps_recv++;
+
+#ifdef SAFE_RING_MODE
+ {
+ struct pcap_pkthdr *hdr = (struct pcap_pkthdr*)bucket;
+ int bktLen = hdr->caplen;
+
+ if(bktLen > sizeof(staticBucket))
+ bktLen = sizeof(staticBucket);
+
+ memcpy(staticBucket, &bucket[sizeof(struct pcap_pkthdr)], bktLen);
+
+#ifdef RING_DEBUG
+ printf("==>> [remove_idx=%u][insert_idx=%u][ptrAddr=%u]\n",
+ handle->slots_info->remove_idx,
+ handle->slots_info->insert_idx,
+ ptrAddr);
+#endif
+
+ callback(userdata, hdr, staticBucket);
+ }
+#else
+ callback(userdata,
+ (const struct pcap_pkthdr*)bucket,
+ (const u_char*)&bucket[sizeof(struct pcap_pkthdr)]);
+#endif
+
+ 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;
+ }
+
+ handle->slots_info->tot_read++;
+ slot->slot_state = 0;
+
+ return(1);
+ } else {
+ struct pollfd pfd;
+ int rc;
+
+ /* Sleep when nothing is happening */
+ pfd.fd = handle->ring_fd;
+ pfd.events = POLLIN|POLLERR;
+ pfd.revents = 0;
+
+#ifdef RING_DEBUG
+ printf("==>> poll [remove_idx=%u][insert_idx=%u][loss=%d][queuedPkts=%u]"
+ "[slot_state=%d][tot_insert=%u][tot_read=%u]\n",
+ handle->slots_info->remove_idx,
+ handle->slots_info->insert_idx,
+ handle->slots_info->tot_lost,
+ queuedPkts, slot->slot_state,
+ handle->slots_info->tot_insert,
+ handle->slots_info->tot_read);
+ #endif
+
+#ifdef RING_DEBUG
+ printf("==>> poll @ [remove_idx=%u][slot_id=%u]\n", handle->slots_info->remove_idx, handle->slot_id);
+#endif
+ errno = 0;
+ rc = poll(&pfd, 1, -1);
+#ifdef RING_DEBUG
+ printf("==>> poll returned %d [%s][errno=%d][break_loop=%d]\n",
+ rc, strerror(errno), errno, handle->break_loop);
+#endif
+ numPollCalls++;
+
+ if(rc == -1) {
+ if(errno == EINTR) {
+ if(handle->break_loop) {
+ handle->break_loop = 0;
+ return(-2);
+ } else
+ return(0);
+ } else
+ return(-1);
+ }
+ }
+ } /* while() */
+ }
+#endif
+
#ifdef HAVE_PF_PACKET_SOCKETS
/*
* If this is a cooked device, leave extra room for a
@@ -688,6 +1014,22 @@
socklen_t len = sizeof (struct tpacket_stats);
#endif
+#ifdef RING
+ if(handle->ring_fd > 0) {
+ stats->ps_recv = handle->slots_info->tot_read-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);
+ printf("RING: [tot_pkts=%u][tot_read=%u][tot_lost=%u]\n",
+ handle->slots_info->tot_pkts,
+ handle->slots_info->tot_read,
+ handle->slots_info->tot_lost);
+
+ return(0);
+ }
+#endif
+
#ifdef HAVE_TPACKET_STATS
/*
* Try to get the packet counts from the kernel.
@@ -879,6 +1221,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)
{
@@ -1348,7 +1695,7 @@
memset(&mr, 0, sizeof(mr));
mr.mr_ifindex = device_id;
mr.mr_type = PACKET_MR_PROMISC;
- if (setsockopt(sock_fd, SOL_PACKET,
+ if (setsockopt(sock_fd, 0 /* SOL_PACKET */,
PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) == -1)
{
snprintf(ebuf, PCAP_ERRBUF_SIZE,
@@ -1425,10 +1772,11 @@
/* Any pending errors, e.g., network is down? */
- if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
- snprintf(ebuf, PCAP_ERRBUF_SIZE,
- "getsockopt: %s", pcap_strerror(errno));
- return -2;
+ if ((getsockopt(fd, PF_RING, SO_ERROR, &err, &errlen) == -1)
+ && (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1)) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "getsockopt: %s", pcap_strerror(errno));
+ return -2;
}
if (err > 0) {
@@ -1482,6 +1830,13 @@
struct pcap *p, *prevp;
struct ifreq ifr;
+#ifdef RING
+ if(handle->ring_buffer != NULL) {
+ munmap(handle->ring_buffer, handle->slots_info->tot_mem);
+ handle->ring_buffer = NULL;
+ }
+#endif
+
if (handle->md.clear_promisc) {
/*
* We put the interface into promiscuous mode; take
@@ -1698,11 +2053,11 @@
}
/* Any pending errors, e.g., network is down? */
-
- if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
- snprintf(ebuf, PCAP_ERRBUF_SIZE,
- "getsockopt: %s", pcap_strerror(errno));
- return -1;
+ if((getsockopt(fd, PF_RING, SO_ERROR, &err, &errlen) == -1)
+ && (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1)) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "getsockopt: %s", pcap_strerror(errno));
+ return -1;
}
if (err > 0) {
@@ -1924,8 +2279,11 @@
* the filtering done in userland even if it could have been
* done in the kernel.
*/
- if (setsockopt(handle->fd, SOL_SOCKET, SO_ATTACH_FILTER,
- &total_fcode, sizeof(total_fcode)) == 0) {
+ printf("pcap[setsockopt(%d)]\n", 0);
+ if (setsockopt(handle->fd, 0 /* SOL_SOCKET */,
+ SO_ATTACH_FILTER,
+ &total_fcode,
+ sizeof(total_fcode)) == 0) {
char drain[1];
/*
@@ -1933,6 +2291,9 @@
*/
total_filter_on = 1;
+#ifdef RING
+ if(!handle->ring_fd) {
+#endif
/*
* Save the socket's current mode, and put it in
* non-blocking mode; we drain it by reading packets
@@ -1955,12 +2316,15 @@
return -2;
}
}
- }
+#ifdef RING
+ }
+#endif
+}
/*
* Now attach the new filter.
*/
- ret = setsockopt(handle->fd, SOL_SOCKET, SO_ATTACH_FILTER,
+ ret = setsockopt(handle->fd, 0 /* SOL_SOCKET */, SO_ATTACH_FILTER,
fcode, sizeof(*fcode));
if (ret == -1 && total_filter_on) {
/*
@@ -1993,7 +2357,8 @@
/* setsockopt() barfs unless it get a dummy parameter */
int dummy;
- return setsockopt(handle->fd, SOL_SOCKET, SO_DETACH_FILTER,
- &dummy, sizeof(dummy));
+ return setsockopt(handle->fd, handle->ring_fd > 0 ? PF_RING : SOL_SOCKET,
+ SO_DETACH_FILTER,
+ &dummy, sizeof(dummy));
}
#endif