+diff --unified --recursive --new-file linux-2.6.15-rc6/include/linux/ring.h linux-2.6.15-rc6-1-686-smp-ring3/include/linux/ring.h
+--- linux-2.6.15-rc6/include/linux/ring.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15-rc6-1-686-smp-ring3/include/linux/ring.h 2005-12-24 00:24:01.000000000 +0100
+@@ -0,0 +1,107 @@
++/*
++ * Definitions for packet ring
++ *
++ * 2004 - Luca Deri <deri@ntop.org>
++ */
++#ifndef __RING_H
++#define __RING_H
++
++
++#define INCLUDE_MAC_INFO
++
++#ifdef INCLUDE_MAC_INFO
++#define SKB_DISPLACEMENT 14 /* Include MAC address information */
++#else
++#define SKB_DISPLACEMENT 0 /* Do NOT include MAC address information */
++#endif
++
++#define RING_MAGIC
++#define RING_MAGIC_VALUE 0x88
++#define RING_FLOWSLOT_VERSION 6
++#define RING_VERSION "3.1"
++
++#define SO_ADD_TO_CLUSTER 99
++#define SO_REMOVE_FROM_CLUSTER 100
++#define SO_SET_REFLECTOR 101
++
++/* *********************************** */
++
++#ifndef HAVE_PCAP
++struct pcap_pkthdr {
++ struct timeval ts; /* time stamp */
++ u_int32_t caplen; /* length of portion present */
++ u_int32_t len; /* length this packet (off wire) */
++};
++#endif
++
++/* *********************************** */
++
++enum cluster_type {
++ cluster_per_flow = 0,
++ cluster_round_robin
++};
++
++/* *********************************** */
++
++#define RING_MIN_SLOT_SIZE (60+sizeof(struct pcap_pkthdr))
++#define RING_MAX_SLOT_SIZE (1514+sizeof(struct pcap_pkthdr))
++
++/* *********************************** */
++
++typedef struct flowSlotInfo {
++ u_int16_t version, sample_rate;
++ u_int32_t tot_slots, slot_len, data_len, tot_mem;
++
++ u_int64_t tot_pkts, tot_lost;
++ u_int64_t tot_insert, tot_read;
++ u_int32_t insert_idx, remove_idx;
++} FlowSlotInfo;
++
++/* *********************************** */
++
++typedef struct flowSlot {
++#ifdef RING_MAGIC
++ u_char magic; /* It must alwasy be zero */
++#endif
++ u_char slot_state; /* 0=empty, 1=full */
++ u_char bucket; /* bucket[bucketLen] */
++} FlowSlot;
++
++/* *********************************** */
++
++#ifdef __KERNEL__
++
++FlowSlotInfo* getRingPtr(void);
++int allocateRing(char *deviceName, u_int numSlots,
++ u_int bucketLen, u_int sampleRate);
++unsigned int pollRing(struct file *fp, struct poll_table_struct * wait);
++void deallocateRing(void);
++
++/* ************************* */
++
++typedef int (*handle_ring_skb)(struct sk_buff *skb,
++ u_char recv_packet, u_char real_skb);
++extern handle_ring_skb get_skb_ring_handler(void);
++extern void set_skb_ring_handler(handle_ring_skb the_handler);
++extern void do_skb_ring_handler(struct sk_buff *skb,
++ u_char recv_packet, u_char real_skb);
++
++typedef int (*handle_ring_buffer)(struct net_device *dev,
++ char *data, int len);
++extern handle_ring_buffer get_buffer_ring_handler(void);
++extern void set_buffer_ring_handler(handle_ring_buffer the_handler);
++extern int do_buffer_ring_handler(struct net_device *dev,
++ char *data, int len);
++#endif /* __KERNEL__ */
++
++/* *********************************** */
++
++#define PF_RING 27 /* Packet Ring */
++#define SOCK_RING PF_RING
++
++/* ioctl() */
++#define SIORINGPOLL 0x8888
++
++/* *********************************** */
++
++#endif /* __RING_H */
+diff --unified --recursive --new-file linux-2.6.15-rc6/net/core/dev.c linux-2.6.15-rc6-1-686-smp-ring3/net/core/dev.c
+--- linux-2.6.15-rc6/net/core/dev.c 2005-12-19 01:36:54.000000000 +0100
++++ linux-2.6.15-rc6-1-686-smp-ring3/net/core/dev.c 2005-12-24 00:24:02.000000000 +0100
+@@ -115,6 +115,56 @@
+ #endif /* CONFIG_NET_RADIO */
+ #include <asm/current.h>
+
++#if defined (CONFIG_RING) || defined(CONFIG_RING_MODULE)
++
++/* #define RING_DEBUG */
++
++#include <linux/ring.h>
++#include <linux/version.h>
++
++static handle_ring_skb ring_handler = NULL;
++
++handle_ring_skb get_skb_ring_handler() { return(ring_handler); }
++
++void set_skb_ring_handler(handle_ring_skb the_handler) {
++ ring_handler = the_handler;
++}
++
++void do_skb_ring_handler(struct sk_buff *skb,
++ u_char recv_packet, u_char real_skb) {
++ if(ring_handler)
++ ring_handler(skb, recv_packet, real_skb);
++}
++
++/* ******************* */
++
++static handle_ring_buffer buffer_ring_handler = NULL;
++
++handle_ring_buffer get_buffer_ring_handler() { return(buffer_ring_handler); }
++
++void set_buffer_ring_handler(handle_ring_buffer the_handler) {
++ buffer_ring_handler = the_handler;
++}
++
++int do_buffer_ring_handler(struct net_device *dev, char *data, int len) {
++ if(buffer_ring_handler) {
++ buffer_ring_handler(dev, data, len);
++ return(1);
++ } else
++ return(0);
++}
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
++EXPORT_SYMBOL(get_skb_ring_handler);
++EXPORT_SYMBOL(set_skb_ring_handler);
++EXPORT_SYMBOL(do_skb_ring_handler);
++
++EXPORT_SYMBOL(get_buffer_ring_handler);
++EXPORT_SYMBOL(set_buffer_ring_handler);
++EXPORT_SYMBOL(do_buffer_ring_handler);
++#endif
++
++#endif
+ /*
+ * The list of packet types we will receive (as opposed to discard)
+ * and the routines to invoke.
+@@ -1296,6 +1346,10 @@
+ skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_EGRESS);
+ #endif
+ if (q->enqueue) {
++#if defined (CONFIG_RING) || defined(CONFIG_RING_MODULE)
++ if(ring_handler) ring_handler(skb, 0, 1);
++#endif /* CONFIG_RING */
++
+ /* Grab device queue */
+ spin_lock(&dev->queue_lock);
+
+@@ -1437,6 +1491,13 @@
+
+ preempt_disable();
+ err = netif_rx(skb);
++#if defined (CONFIG_RING) || defined(CONFIG_RING_MODULE)
++ if(ring_handler && ring_handler(skb, 1, 1)) {
++ /* The packet has been copied into a ring */
++ return(NET_RX_SUCCESS);
++ }
++#endif /* CONFIG_RING */
++
+ if (local_softirq_pending())
+ do_softirq();
+ preempt_enable();
+@@ -1582,6 +1643,13 @@
+ struct net_device *orig_dev;
+ int ret = NET_RX_DROP;
+ unsigned short type;
++#if defined (CONFIG_RING) || defined(CONFIG_RING_MODULE)
++ if(ring_handler && ring_handler(skb, 1, 1)) {
++ /* The packet has been copied into a ring */
++ return(NET_RX_SUCCESS);
++ }
++#endif /* CONFIG_RING */
++
+
+ /* if we've gotten here through NAPI, check netpoll */
+ if (skb->dev->poll && netpoll_rx(skb))
+diff --unified --recursive --new-file linux-2.6.15-rc6/net/Kconfig linux-2.6.15-rc6-1-686-smp-ring3/net/Kconfig
+--- linux-2.6.15-rc6/net/Kconfig 2005-12-19 01:36:54.000000000 +0100
++++ linux-2.6.15-rc6-1-686-smp-ring3/net/Kconfig 2005-12-24 00:24:02.000000000 +0100
+@@ -31,6 +31,7 @@
+ source "net/unix/Kconfig"
+ source "net/xfrm/Kconfig"
+
++source "net/ring/Kconfig"
+ config INET
+ bool "TCP/IP networking"
+ ---help---
+diff --unified --recursive --new-file linux-2.6.15-rc6/net/Makefile linux-2.6.15-rc6-1-686-smp-ring3/net/Makefile
+--- linux-2.6.15-rc6/net/Makefile 2005-12-19 01:36:54.000000000 +0100
++++ linux-2.6.15-rc6-1-686-smp-ring3/net/Makefile 2005-12-24 00:24:02.000000000 +0100
+@@ -42,6 +42,7 @@
+ obj-$(CONFIG_DECNET) += decnet/
+ obj-$(CONFIG_ECONET) += econet/
+ obj-$(CONFIG_VLAN_8021Q) += 8021q/
++obj-$(CONFIG_RING) += ring/
+ obj-$(CONFIG_IP_DCCP) += dccp/
+ obj-$(CONFIG_IP_SCTP) += sctp/
+ obj-$(CONFIG_IEEE80211) += ieee80211/
+diff --unified --recursive --new-file linux-2.6.15-rc6/net/ring/Kconfig linux-2.6.15-rc6-1-686-smp-ring3/net/ring/Kconfig
+--- linux-2.6.15-rc6/net/ring/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15-rc6-1-686-smp-ring3/net/ring/Kconfig 2005-12-24 00:24:02.000000000 +0100
+@@ -0,0 +1,14 @@
++config RING
++ tristate "PF_RING sockets (EXPERIMENTAL)"
++ depends on EXPERIMENTAL
++ ---help---
++ PF_RING socket family, optimized for packet capture.
++ If a PF_RING socket is bound to an adapter (via the bind() system
++ call), such adapter will be used in read-only mode until the socket
++ is destroyed. Whenever an incoming packet is received from the adapter
++ it will not passed to upper layers, but instead it is copied to a ring
++ buffer, which in turn is exported to user space applications via mmap.
++ Please refer to http://luca.ntop.org/Ring.pdf for more.
++
++ Say N unless you know what you are doing.
++
+diff --unified --recursive --new-file linux-2.6.15-rc6/net/ring/Makefile linux-2.6.15-rc6-1-686-smp-ring3/net/ring/Makefile
+--- linux-2.6.15-rc6/net/ring/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15-rc6-1-686-smp-ring3/net/ring/Makefile 2005-12-24 00:24:02.000000000 +0100
+@@ -0,0 +1,7 @@
++#
++# Makefile for the ring driver.
++#
++
++obj-m += ring.o
++
++ring-objs := ring_packet.o
+diff --unified --recursive --new-file linux-2.6.15-rc6/net/ring/ring_packet.c linux-2.6.15-rc6-1-686-smp-ring3/net/ring/ring_packet.c
+--- linux-2.6.15-rc6/net/ring/ring_packet.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15-rc6-1-686-smp-ring3/net/ring/ring_packet.c 2005-12-24 00:24:02.000000000 +0100
+@@ -0,0 +1,1568 @@
++/*
++ *
++ * (C) 2004-05 - Luca Deri <deri@ntop.org>
++ *
++ * This code includes contributions courtesy of
++ * - Jeff Randall <jrandall@nexvu.com>
++ * - Helmut Manck <helmut.manck@secunet.com>
++ * - Brad Doctor <brad@stillsecure.com>
++ * - Amit D. Chaudhary <amit_ml@rajgad.com>
++ *
++ */
++
++/*
++ TO DO:
++ add an entry inside the /proc filesystem
++*/
++
++#include <linux/version.h>
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/socket.h>
++#include <linux/skbuff.h>
++#include <linux/rtnetlink.h>
++#include <linux/in.h>
++#include <linux/in6.h>
++#include <linux/init.h>
++#include <linux/filter.h>
++#include <linux/ring.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
++#include <linux/list.h>
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
++#include <net/xfrm.h>
++#else
++#include <linux/poll.h>
++#endif
++#include <net/sock.h>
++#include <asm/io.h> /* needed for virt_to_phys() */
++
++/* #define RING_DEBUG */
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11))
++static inline int remap_page_range(struct vm_area_struct *vma,
++ unsigned long uvaddr,
++ unsigned long paddr,
++ unsigned long size,
++ pgprot_t prot) {
++ return(remap_pfn_range(vma, uvaddr, paddr >> PAGE_SHIFT,
++ size, prot));
++}
++#endif
++
++/* ************************************************* */
++
++#define CLUSTER_LEN 8
++
++struct ring_cluster {
++ u_short cluster_id; /* 0 = no cluster */
++ u_short num_cluster_elements;
++ enum cluster_type hashing_mode;
++ u_short hashing_id;
++ struct sock *sk[CLUSTER_LEN];
++ struct ring_cluster *next; /* NULL = last element of the cluster */
++};
++
++/* ************************************************* */
++
++struct ring_element {
++ struct list_head list;
++ struct sock *sk;
++};
++
++/* ************************************************* */
++
++struct ring_opt {
++ struct net_device *ring_netdev;
++
++ /* Cluster */
++ u_short cluster_id; /* 0 = no cluster */
++
++ /* Reflector */
++ struct net_device *reflector_dev;
++
++ /* Packet buffers */
++ unsigned long order;
++
++ /* Ring Slots */
++ unsigned long ring_memory;
++ FlowSlotInfo *slots_info; /* Basically it points to ring_memory */
++ char *ring_slots; /* Basically it points to ring_memory
++ +sizeof(FlowSlotInfo) */
++
++ /* Packet Sampling */
++ u_int pktToSample, sample_rate;
++
++ /* BPF Filter */
++ struct sk_filter *bpfFilter;
++
++ /* Locks */
++ atomic_t num_ring_slots_waiters;
++ wait_queue_head_t ring_slots_waitqueue;
++ rwlock_t ring_index_lock;
++
++ /* Indexes (Internal) */
++ u_int insert_page_id, insert_slot_id;
++};
++
++/* ************************************************* */
++
++/* List of all ring sockets. */
++static struct list_head ring_table;
++
++/* List of all clusters */
++static struct ring_cluster *ring_cluster_list;
++
++static rwlock_t ring_mgmt_lock = RW_LOCK_UNLOCKED;
++
++/* ********************************** */
++
++/* Forward */
++static struct proto_ops ring_ops;
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,11))
++static struct proto ring_proto;
++#endif
++
++static int skb_ring_handler(struct sk_buff *skb, u_char recv_packet,
++ u_char real_skb);
++static int buffer_ring_handler(struct net_device *dev, char *data, int len);
++static int remove_from_cluster(struct sock *sock, struct ring_opt *pfr);
++
++/* Extern */
++
++/* ********************************** */
++
++/* Defaults */
++static u_int bucket_len = 128, num_slots = 4096, sample_rate = 1,
++ transparent_mode = 1, enable_tx_capture = 0;
++
++MODULE_PARM(bucket_len, "i");
++MODULE_PARM_DESC(bucket_len, "Number of ring buckets");
++MODULE_PARM(num_slots, "i");
++MODULE_PARM_DESC(num_slots, "Number of ring slots");
++MODULE_PARM(sample_rate, "i");
++MODULE_PARM_DESC(sample_rate, "Ring packet sample rate");
++MODULE_PARM(transparent_mode, "i");
++MODULE_PARM_DESC(transparent_mode,
++ "Set to 1 to set transparent mode "
++ "(slower but backwards compatible)");
++MODULE_PARM(enable_tx_capture, "i");
++MODULE_PARM_DESC(enable_tx_capture, "Set to 1 to capture outgoing packets");
++
++/* ********************************** */
++
++#define MIN_QUEUED_PKTS 64
++#define MAX_QUEUE_LOOPS 64
++
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
++#define ring_sk_datatype(__sk) ((struct ring_opt *)__sk)
++#define ring_sk(__sk) ((__sk)->sk_protinfo)
++#else
++#define ring_sk_datatype(a) (a)
++#define ring_sk(__sk) ((__sk)->protinfo.pf_ring)
++#endif
++
++#define _rdtsc() ({ uint64_t x; asm volatile("rdtsc" : "=A" (x)); x; })
++
++/*
++ int dev_queue_xmit(struct sk_buff *skb)
++ skb->dev;
++ struct net_device *dev_get_by_name(const char *name)
++*/
++
++/* ********************************** */
++
++static void ring_sock_destruct(struct sock *sk) {
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
++ skb_queue_purge(&sk->sk_receive_queue);
++
++ if (!sock_flag(sk, SOCK_DEAD)) {
++#if defined(RING_DEBUG)
++ printk("Attempt to release alive ring socket: %p\n", sk);
++#endif
++ return;
++ }
++
++ BUG_TRAP(!atomic_read(&sk->sk_rmem_alloc));
++ BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc));
++#else
++
++ BUG_TRAP(atomic_read(&sk->rmem_alloc)==0);
++ BUG_TRAP(atomic_read(&sk->wmem_alloc)==0);
++
++ if (!sk->dead) {
++#if defined(RING_DEBUG)
++ printk("Attempt to release alive ring socket: %p\n", sk);
++#endif
++ return;
++ }
++#endif
++
++ kfree(ring_sk(sk));
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
++ MOD_DEC_USE_COUNT;
++#endif
++}
++
++/* ********************************** */
++/*
++ * ring_insert()
++ *
++ * store the sk in a new element and add it
++ * to the head of the list.
++ */
++static inline void ring_insert(struct sock *sk) {
++ struct ring_element *next;
++
++#if defined(RING_DEBUG)
++ printk("RING: ring_insert()\n");
++#endif
++
++ next = kmalloc(sizeof(struct ring_element), GFP_ATOMIC);
++ if(next != NULL) {
++ next->sk = sk;
++ write_lock_irq(&ring_mgmt_lock);
++ list_add(&next->list, &ring_table);
++ write_unlock_irq(&ring_mgmt_lock);
++ } else {
++ if (net_ratelimit())
++ printk("RING: could not kmalloc slot!!\n");
++ }
++}
++
++/* ********************************** */
++/*
++ * ring_remove()
++ *
++ * For each of the elements in the list:
++ * - check if this is the element we want to delete
++ * - if it is, remove it from the list, and free it.
++ *
++ * stop when we find the one we're looking for (break),
++ * or when we reach the end of the list.
++ */
++static inline void ring_remove(struct sock *sk) {
++ struct list_head *ptr;
++ struct ring_element *entry;
++
++
++ for(ptr = ring_table.next; ptr != &ring_table; ptr = ptr->next) {
++ entry = list_entry(ptr, struct ring_element, list);
++
++ if(entry->sk == sk) {
++ write_lock_irq(&ring_mgmt_lock);
++ list_del(ptr);
++ kfree(ptr);
++ write_unlock_irq(&ring_mgmt_lock);
++ break;
++ }
++ }
++
++}
++
++/* ********************************** */
++
++static u_int32_t num_queued_pkts(struct ring_opt *pfr) {
++
++ if(pfr->ring_slots != NULL) {
++
++ u_int32_t tot_insert = pfr->slots_info->insert_idx,
++#if defined(RING_DEBUG)
++ tot_read = pfr->slots_info->tot_read, tot_pkts;
++#else
++ tot_read = pfr->slots_info->tot_read;
++#endif
++
++ if(tot_insert >= tot_read) {
++#if defined(RING_DEBUG)
++ tot_pkts = tot_insert-tot_read;
++#endif
++ return(tot_insert-tot_read);
++ } else {
++#if defined(RING_DEBUG)
++ tot_pkts = ((u_int32_t)-1)+tot_insert-tot_read;
++#endif
++ return(((u_int32_t)-1)+tot_insert-tot_read);
++ }
++
++#if defined(RING_DEBUG)
++ printk("-> num_queued_pkts=%d [tot_insert=%d][tot_read=%d]\n",
++ tot_pkts, tot_insert, tot_read);
++#endif
++
++ } else
++ return(0);
++}
++
++/* ********************************** */
++
++static inline FlowSlot* get_insert_slot(struct ring_opt *pfr) {
++#if defined(RING_DEBUG)
++ printk("get_insert_slot(%d)\n", pfr->slots_info->insert_idx);
++#endif
++
++ if(pfr->ring_slots != NULL) {
++ FlowSlot *slot = (FlowSlot*)&(pfr->ring_slots[pfr->slots_info->insert_idx
++ *pfr->slots_info->slot_len]);
++ return(slot);
++ } else
++ return(NULL);
++}
++
++/* ********************************** */
++
++static inline FlowSlot* get_remove_slot(struct ring_opt *pfr) {
++#if defined(RING_DEBUG)
++ printk("get_remove_slot(%d)\n", pfr->slots_info->remove_idx);
++#endif
++
++ if(pfr->ring_slots != NULL)
++ return((FlowSlot*)&(pfr->ring_slots[pfr->slots_info->remove_idx*
++ pfr->slots_info->slot_len]));
++ else
++ return(NULL);
++}
++
++/* ********************************** */
++
++static void add_skb_to_ring(struct sk_buff *skb,
++ struct ring_opt *pfr,
++ u_char recv_packet,
++ u_char real_skb /* 1=skb 0=faked skb */) {
++ FlowSlot *theSlot;
++ int idx, displ;
++
++ if(recv_packet) {
++ /* Hack for identifying a packet received by the e1000 */
++ if(real_skb) {
++ displ = SKB_DISPLACEMENT;
++ } else
++ displ = 0; /* Received by the e1000 wrapper */
++ } else
++ displ = 0;
++
++ write_lock(&pfr->ring_index_lock);
++ pfr->slots_info->tot_pkts++;
++ write_unlock(&pfr->ring_index_lock);
++
++ /* BPF Filtering (from af_packet.c) */
++ if(pfr->bpfFilter != NULL) {
++ unsigned res = 1, len;
++
++ len = skb->len-skb->data_len;
++
++ write_lock(&pfr->ring_index_lock);
++ skb->data -= displ;
++ res = sk_run_filter(skb, pfr->bpfFilter->insns, pfr->bpfFilter->len);
++ skb->data += displ;
++ write_unlock(&pfr->ring_index_lock);
++
++ if(res == 0) {
++ /* Filter failed */
++
++#if defined(RING_DEBUG)
++ printk("add_skb_to_ring(skb): Filter failed [len=%d][tot=%llu]"
++ "[insertIdx=%d][pkt_type=%d][cloned=%d]\n",
++ (int)skb->len, pfr->slots_info->tot_pkts,
++ pfr->slots_info->insert_idx,
++ skb->pkt_type, skb->cloned);
++#endif
++
++ return;
++ }
++ }
++
++ /* ************************** */
++
++ if(pfr->sample_rate > 1) {
++ if(pfr->pktToSample == 0) {
++ write_lock(&pfr->ring_index_lock);
++ pfr->pktToSample = pfr->sample_rate;
++ write_unlock(&pfr->ring_index_lock);
++ } else {
++ write_lock(&pfr->ring_index_lock);
++ pfr->pktToSample--;
++ write_unlock(&pfr->ring_index_lock);
++
++#if defined(RING_DEBUG)
++ printk("add_skb_to_ring(skb): sampled packet [len=%d]"
++ "[tot=%llu][insertIdx=%d][pkt_type=%d][cloned=%d]\n",
++ (int)skb->len, pfr->slots_info->tot_pkts,
++ pfr->slots_info->insert_idx,
++ skb->pkt_type, skb->cloned);
++#endif
++ return;
++ }
++ }
++
++ /* ************************************* */
++
++ if((pfr->reflector_dev != NULL)
++ && (!netif_queue_stopped(pfr->reflector_dev))) {
++ int cpu = smp_processor_id();
++
++ /* increase reference counter so that this skb is not freed */
++ atomic_inc(&skb->users);
++
++ skb->data -= displ;
++
++ /* send it */
++ if (pfr->reflector_dev->xmit_lock_owner != cpu) {
++ spin_lock_bh(&pfr->reflector_dev->xmit_lock);
++ pfr->reflector_dev->xmit_lock_owner = cpu;
++ spin_unlock_bh(&pfr->reflector_dev->xmit_lock);
++
++ if (pfr->reflector_dev->hard_start_xmit(skb,
++ pfr->reflector_dev) == 0) {
++ spin_lock_bh(&pfr->reflector_dev->xmit_lock);
++ pfr->reflector_dev->xmit_lock_owner = -1;
++ skb->data += displ;
++ spin_unlock_bh(&pfr->reflector_dev->xmit_lock);
++#if defined(RING_DEBUG)
++ printk("++ hard_start_xmit succeeded\n");
++#endif
++ return; /* OK */
++ }
++
++ spin_lock_bh(&pfr->reflector_dev->xmit_lock);
++ pfr->reflector_dev->xmit_lock_owner = -1;
++ spin_unlock_bh(&pfr->reflector_dev->xmit_lock);
++ }
++
++#if defined(RING_DEBUG)
++ printk("++ hard_start_xmit failed\n");
++#endif
++ skb->data += displ;
++ return; /* -ENETDOWN */
++ }
++
++ /* ************************************* */
++
++#if defined(RING_DEBUG)
++ printk("add_skb_to_ring(skb) [len=%d][tot=%llu][insertIdx=%d]"
++ "[pkt_type=%d][cloned=%d]\n",
++ (int)skb->len, pfr->slots_info->tot_pkts,
++ pfr->slots_info->insert_idx,
++ skb->pkt_type, skb->cloned);
++#endif
++
++ idx = pfr->slots_info->insert_idx;
++ theSlot = get_insert_slot(pfr);
++
++ if((theSlot != NULL) && (theSlot->slot_state == 0)) {
++ struct pcap_pkthdr *hdr;
++ char *bucket;
++
++ /* Update Index */
++ idx++;
++
++ if(idx == pfr->slots_info->tot_slots) {
++ write_lock(&pfr->ring_index_lock);
++ pfr->slots_info->insert_idx = 0;
++ write_unlock(&pfr->ring_index_lock);
++ } else {
++ write_lock(&pfr->ring_index_lock);
++ pfr->slots_info->insert_idx = idx;
++ write_unlock(&pfr->ring_index_lock);
++ }
++
++ bucket = &theSlot->bucket;
++ hdr = (struct pcap_pkthdr*)bucket;
++
++ /* BD - API changed for time keeping */
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14))
++ if(skb->stamp.tv_sec == 0) do_gettimeofday(&skb->stamp);
++
++ hdr->ts.tv_sec = skb->stamp.tv_sec, hdr->ts.tv_usec = skb->stamp.tv_usec;
++#else
++ if(skb->tstamp.off_sec == 0) __net_timestamp(skb);
++
++ hdr->ts.tv_sec = skb->tstamp.off_sec, hdr->ts.tv_usec = skb->tstamp.off_usec;
++#endif
++
++ hdr->caplen = skb->len+displ;
++
++ if(hdr->caplen > pfr->slots_info->data_len)
++ hdr->caplen = pfr->slots_info->data_len;
++
++ hdr->len = skb->len+displ;
++ memcpy(&bucket[sizeof(struct pcap_pkthdr)],
++ skb->data-displ, hdr->caplen);
++
++#if defined(RING_DEBUG)
++ {
++ static unsigned int lastLoss = 0;
++
++ if(pfr->slots_info->tot_lost
++ && (lastLoss != pfr->slots_info->tot_lost)) {
++ printk("add_skb_to_ring(%d): [data_len=%d]"
++ "[hdr.caplen=%d][skb->len=%d]"
++ "[pcap_pkthdr=%d][removeIdx=%d]"
++ "[loss=%lu][page=%u][slot=%u]\n",
++ idx-1, pfr->slots_info->data_len, hdr->caplen, skb->len,
++ sizeof(struct pcap_pkthdr),
++ pfr->slots_info->remove_idx,
++ (long unsigned int)pfr->slots_info->tot_lost,
++ pfr->insert_page_id, pfr->insert_slot_id);
++
++ lastLoss = pfr->slots_info->tot_lost;
++ }
++ }
++#endif
++
++ write_lock(&pfr->ring_index_lock);
++ pfr->slots_info->tot_insert++;
++ theSlot->slot_state = 1;
++ write_unlock(&pfr->ring_index_lock);
++ } else {
++ write_lock(&pfr->ring_index_lock);
++ pfr->slots_info->tot_lost++;
++ write_unlock(&pfr->ring_index_lock);
++
++#if defined(RING_DEBUG)
++ printk("add_skb_to_ring(skb): packet lost [loss=%lu]"
++ "[removeIdx=%u][insertIdx=%u]\n",
++ (long unsigned int)pfr->slots_info->tot_lost,
++ pfr->slots_info->remove_idx, pfr->slots_info->insert_idx);
++#endif
++ }
++
++ /* wakeup in case of poll() */
++ if(waitqueue_active(&pfr->ring_slots_waitqueue))
++ wake_up_interruptible(&pfr->ring_slots_waitqueue);
++}
++
++/* ********************************** */
++
++static u_int hash_skb(struct ring_cluster *cluster_ptr,
++ struct sk_buff *skb, u_char recv_packet) {
++ u_int idx;
++ int displ;
++ struct iphdr *ip;
++
++ if(cluster_ptr->hashing_mode == cluster_round_robin) {
++ idx = cluster_ptr->hashing_id++;
++ } else {
++ /* Per-flow clustering */
++ if(skb->len > sizeof(struct iphdr)+sizeof(struct tcphdr)) {
++ if(recv_packet)
++ displ = 0;
++ else
++ displ = SKB_DISPLACEMENT;
++
++ /*
++ skb->data+displ
++
++ Always points to to the IP part of the packet
++ */
++
++ ip = (struct iphdr*)(skb->data+displ);
++
++ idx = ip->saddr+ip->daddr+ip->protocol;
++
++ if(ip->protocol == IPPROTO_TCP) {
++ struct tcphdr *tcp = (struct tcphdr*)(skb->data+displ
++ +sizeof(struct iphdr));
++ idx += tcp->source+tcp->dest;
++ } else if(ip->protocol == IPPROTO_UDP) {
++ struct udphdr *udp = (struct udphdr*)(skb->data+displ
++ +sizeof(struct iphdr));
++ idx += udp->source+udp->dest;
++ }
++ } else
++ idx = skb->len;
++ }
++
++ return(idx % cluster_ptr->num_cluster_elements);
++}
++
++/* ********************************** */
++
++static int skb_ring_handler(struct sk_buff *skb,
++ u_char recv_packet,
++ u_char real_skb /* 1=skb 0=faked skb */) {
++ struct sock *skElement;
++ int rc = 0;
++ struct list_head *ptr;
++ struct ring_cluster *cluster_ptr;
++
++#ifdef PROFILING
++ uint64_t rdt = _rdtsc(), rdt1, rdt2;
++#endif
++
++ if((!skb) /* Invalid skb */
++ || ((!enable_tx_capture) && (!recv_packet))) {
++ /*
++ An outgoing packet is about to be sent out
++ but we decided not to handle transmitted
++ packets.
++ */
++ return(0);
++ }
++
++#if defined(RING_DEBUG)
++ if(0) {
++ printk("skb_ring_handler() [len=%d][dev=%s]\n", skb->len,
++ skb->dev->name == NULL ? "<NULL>" : skb->dev->name);
++ }
++#endif
++
++#ifdef PROFILING
++ rdt1 = _rdtsc();
++#endif
++
++ /* [1] Check unclustered sockets */
++ for (ptr = ring_table.next; ptr != &ring_table; ptr = ptr->next) {
++ struct ring_opt *pfr;
++ struct ring_element *entry;
++
++ entry = list_entry(ptr, struct ring_element, list);
++
++ read_lock(&ring_mgmt_lock);
++ skElement = entry->sk;
++ pfr = ring_sk(skElement);
++ read_unlock(&ring_mgmt_lock);
++
++ if((pfr != NULL)
++ && (pfr->cluster_id == 0 /* No cluster */)
++ && (pfr->ring_slots != NULL)
++ && (pfr->ring_netdev == skb->dev)) {
++ /* We've found the ring where the packet can be stored */
++ read_lock(&ring_mgmt_lock);
++ add_skb_to_ring(skb, pfr, recv_packet, real_skb);
++ read_unlock(&ring_mgmt_lock);
++
++ rc = 1; /* Ring found: we've done our job */
++ }
++ }
++
++ /* [2] Check socket clusters */
++ cluster_ptr = ring_cluster_list;
++
++ while(cluster_ptr != NULL) {
++ struct ring_opt *pfr;
++
++ if(cluster_ptr->num_cluster_elements > 0) {
++ u_int skb_hash = hash_skb(cluster_ptr, skb, recv_packet);
++
++ read_lock(&ring_mgmt_lock);
++ skElement = cluster_ptr->sk[skb_hash];
++ read_unlock(&ring_mgmt_lock);
++
++ if(skElement != NULL) {
++ pfr = ring_sk(skElement);
++
++ if((pfr != NULL)
++ && (pfr->ring_slots != NULL)
++ && (pfr->ring_netdev == skb->dev)) {
++ /* We've found the ring where the packet can be stored */
++ read_lock(&ring_mgmt_lock);
++ add_skb_to_ring(skb, pfr, recv_packet, real_skb);
++ read_unlock(&ring_mgmt_lock);
++
++ rc = 1; /* Ring found: we've done our job */
++ }
++ }
++ }
++
++ cluster_ptr = cluster_ptr->next;
++ }
++
++#ifdef PROFILING
++ rdt1 = _rdtsc()-rdt1;
++#endif
++
++#ifdef PROFILING
++ rdt2 = _rdtsc();
++#endif
++
++ if(transparent_mode) rc = 0;
++
++ if((rc != 0) && real_skb)
++ dev_kfree_skb(skb); /* Free the skb */
++
++#ifdef PROFILING
++ rdt2 = _rdtsc()-rdt2;
++ rdt = _rdtsc()-rdt;
++
++#if defined(RING_DEBUG)
++ printk("# cycles: %d [lock costed %d %d%%][free costed %d %d%%]\n",
++ (int)rdt, rdt-rdt1,
++ (int)((float)((rdt-rdt1)*100)/(float)rdt),
++ rdt2,
++ (int)((float)(rdt2*100)/(float)rdt));
++#endif
++#endif
++
++ return(rc); /* 0 = packet not handled */
++}
++
++/* ********************************** */
++
++struct sk_buff skb;
++
++static int buffer_ring_handler(struct net_device *dev,
++ char *data, int len) {
++
++#if defined(RING_DEBUG)
++ printk("buffer_ring_handler: [dev=%s][len=%d]\n",
++ dev->name == NULL ? "<NULL>" : dev->name, len);
++#endif
++
++ /* BD - API changed for time keeping */
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14))
++ skb.dev = dev, skb.len = len, skb.data = data,
++ skb.data_len = len, skb.stamp.tv_sec = 0; /* Calculate the time */
++#else
++ skb.dev = dev, skb.len = len, skb.data = data,
++ skb.data_len = len, skb.tstamp.off_sec = 0; /* Calculate the time */
++#endif
++
++ skb_ring_handler(&skb, 1, 0 /* fake skb */);
++
++ return(0);
++}
++
++/* ********************************** */
++
++static int ring_create(struct socket *sock, int protocol) {
++ struct sock *sk;
++ struct ring_opt *pfr;
++ int err;
++
++#if defined(RING_DEBUG)
++ printk("RING: ring_create()\n");
++#endif
++
++ /* Are you root, superuser or so ? */
++ if(!capable(CAP_NET_ADMIN))
++ return -EPERM;
++
++ if(sock->type != SOCK_RAW)
++ return -ESOCKTNOSUPPORT;
++
++ if(protocol != htons(ETH_P_ALL))
++ return -EPROTONOSUPPORT;
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
++ MOD_INC_USE_COUNT;
++#endif
++
++ err = -ENOMEM;
++
++ // BD: -- broke this out to keep it more simple and clear as to what the
++ // options are.
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11))
++ sk = sk_alloc(PF_RING, GFP_KERNEL, 1, NULL);
++#else
++ // BD: API changed in 2.6.12, ref:
++ // http://svn.clkao.org/svnweb/linux/revision/?rev=28201
++ sk = sk_alloc(PF_RING, GFP_ATOMIC, &ring_proto, 1);
++#endif
++#else
++ /* Kernel 2.4 */
++ sk = sk_alloc(PF_RING, GFP_KERNEL, 1);
++#endif
++
++ if (sk == NULL)
++ goto out;
++
++ sock->ops = &ring_ops;
++ sock_init_data(sock, sk);
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11))
++ sk_set_owner(sk, THIS_MODULE);
++#endif
++#endif
++
++ err = -ENOMEM;
++ ring_sk(sk) = ring_sk_datatype(kmalloc(sizeof(*pfr), GFP_KERNEL));
++
++ if (!(pfr = ring_sk(sk))) {
++ sk_free(sk);
++ goto out;
++ }
++ memset(pfr, 0, sizeof(*pfr));
++ init_waitqueue_head(&pfr->ring_slots_waitqueue);
++ pfr->ring_index_lock = RW_LOCK_UNLOCKED;
++ atomic_set(&pfr->num_ring_slots_waiters, 0);
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
++ sk->sk_family = PF_RING;
++ sk->sk_destruct = ring_sock_destruct;
++#else
++ sk->family = PF_RING;
++ sk->destruct = ring_sock_destruct;
++ sk->num = protocol;
++#endif
++
++ ring_insert(sk);
++
++#if defined(RING_DEBUG)
++ printk("RING: ring_create() - created\n");
++#endif
++
++ return(0);
++ out:
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
++ MOD_DEC_USE_COUNT;
++#endif
++ return err;
++}
++
++/* *********************************************** */
++
++static int ring_release(struct socket *sock)
++{
++ struct sock *sk = sock->sk;
++ struct ring_opt *pfr = ring_sk(sk);
++
++ if(!sk)
++ return 0;
++
++#if defined(RING_DEBUG)
++ printk("RING: called ring_release\n");
++#endif
++
++#if defined(RING_DEBUG)
++ printk("RING: ring_release entered\n");
++#endif
++
++ ring_remove(sk);
++
++ sock_orphan(sk);
++ sock->sk = NULL;
++
++ /* Free the ring buffer */
++ if(pfr->ring_memory) {
++ struct page *page, *page_end;
++
++ page_end = virt_to_page(pfr->ring_memory + (PAGE_SIZE << pfr->order) - 1);
++ for(page = virt_to_page(pfr->ring_memory); page <= page_end; page++)
++ ClearPageReserved(page);
++
++ free_pages(pfr->ring_memory, pfr->order);
++ }
++
++ kfree(pfr);
++ ring_sk(sk) = NULL;
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
++ skb_queue_purge(&sk->sk_write_queue);
++#endif
++ sock_put(sk);
++
++#if defined(RING_DEBUG)
++ printk("RING: ring_release leaving\n");
++#endif
++
++ return 0;
++}
++
++/* ********************************** */
++/*
++ * We create a ring for this socket and bind it to the specified device
++ */
++static int packet_ring_bind(struct sock *sk, struct net_device *dev)
++{
++ u_int the_slot_len;
++ u_int32_t tot_mem;
++ struct ring_opt *pfr = ring_sk(sk);
++ struct page *page, *page_end;
++
++ if(!dev) return(-1);
++
++#if defined(RING_DEBUG)
++ printk("RING: packet_ring_bind(%s) called\n", dev->name);
++#endif
++
++ /* **********************************************
++
++ *************************************
++ * *
++ * FlowSlotInfo *
++ * *
++ ************************************* <-+
++ * FlowSlot * |
++ ************************************* |
++ * FlowSlot * |
++ ************************************* +- num_slots
++ * FlowSlot * |
++ ************************************* |
++ * FlowSlot * |
++ ************************************* <-+
++
++ ********************************************** */
++
++ the_slot_len = sizeof(u_char) /* flowSlot.slot_state */
++#ifdef RING_MAGIC
++ + sizeof(u_char)
++#endif
++ + sizeof(struct pcap_pkthdr)
++ + bucket_len /* flowSlot.bucket */;
++
++ tot_mem = sizeof(FlowSlotInfo) + num_slots*the_slot_len;
++
++ /*
++ Calculate the value of the order parameter used later.
++ See http://www.linuxjournal.com/article.php?sid=1133
++ */
++ for(pfr->order = 0;(PAGE_SIZE << pfr->order) < tot_mem; pfr->order++) ;
++
++ /*
++ We now try to allocate the memory as required. If we fail
++ we try to allocate a smaller amount or memory (hence a
++ smaller ring).
++ */
++ while((pfr->ring_memory = __get_free_pages(GFP_ATOMIC, pfr->order)) == 0)
++ if(pfr->order-- == 0)
++ break;
++
++ if(pfr->order == 0) {
++ printk("RING: ERROR not enough memory for ring\n");
++ return(-1);
++ } else {
++ printk("RING: succesfully allocated %lu KB [tot_mem=%d][order=%ld]\n",
++ PAGE_SIZE >> (10 - pfr->order), tot_mem, pfr->order);
++ }
++
++ tot_mem = PAGE_SIZE << pfr->order;
++ memset((char*)pfr->ring_memory, 0, tot_mem);
++
++ /* Now we need to reserve the pages */
++ page_end = virt_to_page(pfr->ring_memory + (PAGE_SIZE << pfr->order) - 1);
++ for(page = virt_to_page(pfr->ring_memory); page <= page_end; page++)
++ SetPageReserved(page);
++
++ pfr->slots_info = (FlowSlotInfo*)pfr->ring_memory;
++ pfr->ring_slots = (char*)(pfr->ring_memory+sizeof(FlowSlotInfo));
++
++ pfr->slots_info->version = RING_FLOWSLOT_VERSION;
++ pfr->slots_info->slot_len = the_slot_len;
++ pfr->slots_info->data_len = bucket_len;
++ pfr->slots_info->tot_slots = (tot_mem-sizeof(FlowSlotInfo))/the_slot_len;
++ pfr->slots_info->tot_mem = tot_mem;
++ pfr->slots_info->sample_rate = sample_rate;
++
++ printk("RING: allocated %d slots [slot_len=%d][tot_mem=%u]\n",
++ pfr->slots_info->tot_slots, pfr->slots_info->slot_len,
++ pfr->slots_info->tot_mem);
++
++#ifdef RING_MAGIC
++ {
++ int i;
++
++ for(i=0; i<pfr->slots_info->tot_slots; i++) {
++ unsigned long idx = i*pfr->slots_info->slot_len;
++ FlowSlot *slot = (FlowSlot*)&pfr->ring_slots[idx];
++ slot->magic = RING_MAGIC_VALUE; slot->slot_state = 0;
++ }
++ }
++#endif
++
++ pfr->insert_page_id = 1, pfr->insert_slot_id = 0;
++
++ /*
++ IMPORTANT
++ Leave this statement here as last one. In fact when
++ the ring_netdev != NULL the socket is ready to be used.
++ */
++ pfr->ring_netdev = dev;
++
++ return(0);
++}
++
++/* ************************************* */
++
++/* Bind to a device */
++static int ring_bind(struct socket *sock,
++ struct sockaddr *sa, int addr_len)
++{
++ struct sock *sk=sock->sk;
++ struct net_device *dev = NULL;
++
++#if defined(RING_DEBUG)
++ printk("RING: ring_bind() called\n");
++#endif
++
++ /*
++ * Check legality
++ */
++ if (addr_len != sizeof(struct sockaddr))
++ return -EINVAL;
++ if (sa->sa_family != PF_RING)
++ return -EINVAL;
++
++ /* Safety check: add trailing zero if missing */
++ sa->sa_data[sizeof(sa->sa_data)-1] = '\0';
++
++#if defined(RING_DEBUG)
++ printk("RING: searching device %s\n", sa->sa_data);
++#endif
++
++ if((dev = __dev_get_by_name(sa->sa_data)) == NULL) {
++#if defined(RING_DEBUG)
++ printk("RING: search failed\n");
++#endif
++ return(-EINVAL);
++ } else
++ return(packet_ring_bind(sk, dev));
++}
++
++/* ************************************* */
++
++static int ring_mmap(struct file *file,
++ struct socket *sock,
++ struct vm_area_struct *vma)
++{
++ struct sock *sk = sock->sk;
++ struct ring_opt *pfr = ring_sk(sk);
++ unsigned long size, start;
++ u_int pagesToMap;
++ char *ptr;
++
++#if defined(RING_DEBUG)
++ printk("RING: ring_mmap() called\n");
++#endif
++
++ if(pfr->ring_memory == 0) {
++#if defined(RING_DEBUG)
++ printk("RING: ring_mmap() failed: mapping area to an unbound socket\n");
++#endif
++ return -EINVAL;
++ }
++
++ size = (unsigned long)(vma->vm_end-vma->vm_start);
++
++ if(size % PAGE_SIZE) {
++#if defined(RING_DEBUG)
++ printk("RING: ring_mmap() failed: len is not multiple of PAGE_SIZE\n");
++#endif
++ return(-EINVAL);
++ }
++
++ /* if userspace tries to mmap beyond end of our buffer, fail */
++ if(size > pfr->slots_info->tot_mem) {
++#if defined(RING_DEBUG)
++ printk("proc_mmap() failed: area too large [%ld > %d]\n", size, pfr->slots_info->tot_mem);
++#endif
++ return(-EINVAL);
++ }
++
++ pagesToMap = size/PAGE_SIZE;
++
++#if defined(RING_DEBUG)
++ printk("RING: ring_mmap() called. %d pages to map\n", pagesToMap);
++#endif
++
++#if defined(RING_DEBUG)
++ printk("RING: mmap [slot_len=%d][tot_slots=%d] for ring on device %s\n",
++ pfr->slots_info->slot_len, pfr->slots_info->tot_slots,
++ pfr->ring_netdev->name);
++#endif
++
++ /* we do not want to have this area swapped out, lock it */
++ vma->vm_flags |= VM_LOCKED;
++ start = vma->vm_start;
++
++ /* Ring slots start from page 1 (page 0 is reserved for FlowSlotInfo) */
++ ptr = (char*)(start+PAGE_SIZE);
++
++ if(remap_page_range(
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
++ vma,
++#endif
++ start,
++ __pa(pfr->ring_memory),
++ PAGE_SIZE*pagesToMap, vma->vm_page_prot)) {
++#if defined(RING_DEBUG)
++ printk("remap_page_range() failed\n");
++#endif
++ return(-EAGAIN);
++ }
++
++#if defined(RING_DEBUG)
++ printk("proc_mmap(pagesToMap=%d): success.\n", pagesToMap);
++#endif
++
++ return 0;
++}
++
++/* ************************************* */
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
++static int ring_recvmsg(struct kiocb *iocb, struct socket *sock,
++ struct msghdr *msg, size_t len, int flags)
++#else
++ static int ring_recvmsg(struct socket *sock, struct msghdr *msg, int len,
++ int flags, struct scm_cookie *scm)
++#endif
++{
++ FlowSlot* slot;
++ struct ring_opt *pfr = ring_sk(sock->sk);
++ u_int32_t queued_pkts, num_loops = 0;
++
++#if defined(RING_DEBUG)
++ printk("ring_recvmsg called\n");
++#endif
++
++ slot = get_remove_slot(pfr);
++
++ while((queued_pkts = num_queued_pkts(pfr)) < MIN_QUEUED_PKTS) {
++ wait_event_interruptible(pfr->ring_slots_waitqueue, 1);
++
++#if defined(RING_DEBUG)
++ printk("-> ring_recvmsg returning %d [queued_pkts=%d][num_loops=%d]\n",
++ slot->slot_state, queued_pkts, num_loops);
++#endif
++
++ if(queued_pkts > 0) {
++ if(num_loops++ > MAX_QUEUE_LOOPS)
++ break;
++ }
++ }
++
++#if defined(RING_DEBUG)
++ if(slot != NULL)
++ printk("ring_recvmsg is returning [queued_pkts=%d][num_loops=%d]\n",
++ queued_pkts, num_loops);
++#endif
++
++ return(queued_pkts);
++}
++
++/* ************************************* */
++
++unsigned int ring_poll(struct file * file,
++ struct socket *sock, poll_table *wait)
++{
++ FlowSlot* slot;
++ struct ring_opt *pfr = ring_sk(sock->sk);
++
++#if defined(RING_DEBUG)
++ printk("poll called\n");
++#endif
++
++ slot = get_remove_slot(pfr);
++
++ if((slot != NULL) && (slot->slot_state == 0))
++ poll_wait(file, &pfr->ring_slots_waitqueue, wait);
++
++#if defined(RING_DEBUG)
++ printk("poll returning %d\n", slot->slot_state);
++#endif
++
++ if((slot != NULL) && (slot->slot_state == 1))
++ return(POLLIN | POLLRDNORM);
++ else
++ return(0);
++}
++
++/* ************************************* */
++
++int add_to_cluster_list(struct ring_cluster *el,
++ struct sock *sock) {
++
++ if(el->num_cluster_elements == CLUSTER_LEN)
++ return(-1); /* Cluster full */
++
++ ring_sk_datatype(ring_sk(sock))->cluster_id = el->cluster_id;
++ el->sk[el->num_cluster_elements] = sock;
++ el->num_cluster_elements++;
++ return(0);
++}
++
++/* ************************************* */
++
++int remove_from_cluster_list(struct ring_cluster *el,
++ struct sock *sock) {
++ int i, j;
++
++ for(i=0; i<CLUSTER_LEN; i++)
++ if(el->sk[i] == sock) {
++ el->num_cluster_elements--;
++
++ if(el->num_cluster_elements > 0) {
++ /* The cluster contains other elements */
++ for(j=i; j<CLUSTER_LEN-1; j++)
++ el->sk[j] = el->sk[j+1];
++
++ el->sk[CLUSTER_LEN-1] = NULL;
++ } else {
++ /* Empty cluster */
++ memset(el->sk, 0, sizeof(el->sk));
++ }
++
++ return(0);
++ }
++
++ return(-1); /* Not found */
++}
++
++/* ************************************* */
++
++static int remove_from_cluster(struct sock *sock,
++ struct ring_opt *pfr)
++{
++ struct ring_cluster *el;
++
++#if defined(RING_DEBUG)
++ printk("--> remove_from_cluster(%d)\n", pfr->cluster_id);
++#endif
++
++ if(pfr->cluster_id == 0 /* 0 = No Cluster */)
++ return(0); /* Noting to do */
++
++ el = ring_cluster_list;
++
++ while(el != NULL) {
++ if(el->cluster_id == pfr->cluster_id) {
++ return(remove_from_cluster_list(el, sock));
++ } else
++ el = el->next;
++ }
++
++ return(-EINVAL); /* Not found */
++}
++
++/* ************************************* */
++
++static int add_to_cluster(struct sock *sock,
++ struct ring_opt *pfr,
++ u_short cluster_id)
++{
++ struct ring_cluster *el;
++
++#ifndef RING_DEBUG
++ printk("--> add_to_cluster(%d)\n", cluster_id);
++#endif
++
++ if(cluster_id == 0 /* 0 = No Cluster */) return(-EINVAL);
++
++ if(pfr->cluster_id != 0)
++ remove_from_cluster(sock, pfr);
++
++ el = ring_cluster_list;
++
++ while(el != NULL) {
++ if(el->cluster_id == cluster_id) {
++ return(add_to_cluster_list(el, sock));
++ } else
++ el = el->next;
++ }
++
++ /* There's no existing cluster. We need to create one */
++ if((el = kmalloc(sizeof(struct ring_cluster), GFP_KERNEL)) == NULL)
++ return(-ENOMEM);
++
++ el->cluster_id = cluster_id;
++ el->num_cluster_elements = 1;
++ el->hashing_mode = cluster_per_flow; /* Default */
++ el->hashing_id = 0;
++
++ memset(el->sk, 0, sizeof(el->sk));
++ el->sk[0] = sock;
++ el->next = ring_cluster_list;
++ ring_cluster_list = el;
++ pfr->cluster_id = cluster_id;
++
++ return(0); /* 0 = OK */
++}
++
++/* ************************************* */
++
++/* Code taken/inspired from core/sock.c */
++static int ring_setsockopt(struct socket *sock,
++ int level, int optname,
++ char *optval, int optlen)
++{
++ struct ring_opt *pfr = ring_sk(sock->sk);
++ int val, found, ret = 0;
++ u_int cluster_id;
++ char devName[8];
++
++ if((optlen<sizeof(int)) || (pfr == NULL))
++ return(-EINVAL);
++
++ if (get_user(val, (int *)optval))
++ return -EFAULT;
++
++ found = 1;
++
++ switch(optname)
++ {
++ case SO_ATTACH_FILTER:
++ ret = -EINVAL;
++ if (optlen == sizeof(struct sock_fprog)) {
++ unsigned int fsize;
++ struct sock_fprog fprog;
++ struct sk_filter *filter;
++
++ ret = -EFAULT;
++
++ /*
++ NOTE
++
++ Do not call copy_from_user within a held
++ splinlock (e.g. ring_mgmt_lock) as this caused
++ problems when certain debugging was enabled under
++ 2.6.5 -- including hard lockups of the machine.
++ */
++ if(copy_from_user(&fprog, optval, sizeof(fprog)))
++ break;
++
++ fsize = sizeof(struct sock_filter) * fprog.len;
++ filter = kmalloc(fsize, GFP_KERNEL);
++
++ if(filter == NULL) {
++ ret = -ENOMEM;
++ break;
++ }
++
++ if(copy_from_user(filter->insns, fprog.filter, fsize))
++ break;
++
++ filter->len = fprog.len;
++
++ if(sk_chk_filter(filter->insns, filter->len) != 0) {
++ /* Bad filter specified */
++ kfree(filter);
++ pfr->bpfFilter = NULL;
++ break;
++ }
++
++ /* get the lock, set the filter, release the lock */
++ write_lock(&ring_mgmt_lock);
++ pfr->bpfFilter = filter;
++ write_unlock(&ring_mgmt_lock);
++ }
++ ret = 0;
++ break;
++
++ case SO_DETACH_FILTER:
++ write_lock(&ring_mgmt_lock);
++ found = 1;
++ if(pfr->bpfFilter != NULL) {
++ kfree(pfr->bpfFilter);
++ pfr->bpfFilter = NULL;
++ write_unlock(&ring_mgmt_lock);
++ break;
++ }
++ ret = -ENONET;
++ break;
++
++ case SO_ADD_TO_CLUSTER:
++ if (optlen!=sizeof(val))
++ return -EINVAL;
++
++ if (copy_from_user(&cluster_id, optval, sizeof(cluster_id)))
++ return -EFAULT;
++
++ write_lock(&ring_mgmt_lock);
++ ret = add_to_cluster(sock->sk, pfr, cluster_id);
++ write_unlock(&ring_mgmt_lock);
++ break;
++
++ case SO_REMOVE_FROM_CLUSTER:
++ write_lock(&ring_mgmt_lock);
++ ret = remove_from_cluster(sock->sk, pfr);
++ write_unlock(&ring_mgmt_lock);
++ break;
++
++ case SO_SET_REFLECTOR:
++ if(optlen >= (sizeof(devName)-1))
++ return -EINVAL;
++
++ if(optlen > 0) {
++ if(copy_from_user(devName, optval, optlen))
++ return -EFAULT;
++ }
++
++ devName[optlen] = '\0';
++
++#if defined(RING_DEBUG)
++ printk("+++ SO_SET_REFLECTOR(%s)\n", devName);
++#endif
++
++ write_lock(&ring_mgmt_lock);
++ pfr->reflector_dev = dev_get_by_name(devName);
++ write_unlock(&ring_mgmt_lock);
++
++#if defined(RING_DEBUG)
++ if(pfr->reflector_dev != NULL)
++ printk("SO_SET_REFLECTOR(%s): succeded\n", devName);
++ else
++ printk("SO_SET_REFLECTOR(%s): device unknown\n", devName);
++#endif
++ break;
++
++ default:
++ found = 0;
++ break;
++ }
++
++ if(found)
++ return(ret);
++ else
++ return(sock_setsockopt(sock, level, optname, optval, optlen));
++}
++
++/* ************************************* */
++
++static int ring_ioctl(struct socket *sock,
++ unsigned int cmd, unsigned long arg)
++{
++ switch(cmd)
++ {
++ case SIOCGIFFLAGS:
++ case SIOCSIFFLAGS:
++ case SIOCGIFCONF:
++ case SIOCGIFMETRIC:
++ case SIOCSIFMETRIC:
++ case SIOCGIFMEM:
++ case SIOCSIFMEM:
++ case SIOCGIFMTU:
++ case SIOCSIFMTU:
++ case SIOCSIFLINK:
++ case SIOCGIFHWADDR:
++ case SIOCSIFHWADDR:
++ case SIOCSIFMAP:
++ case SIOCGIFMAP:
++ case SIOCSIFSLAVE:
++ case SIOCGIFSLAVE:
++ case SIOCGIFINDEX:
++ case SIOCGIFNAME:
++ case SIOCGIFCOUNT:
++ case SIOCSIFHWBROADCAST:
++ return(dev_ioctl(cmd,(void *) arg));
++
++ default:
++ return -EOPNOTSUPP;
++ }
++
++ return 0;
++}
++
++/* ************************************* */
++
++static struct proto_ops ring_ops = {
++ .family = PF_RING,
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
++ .owner = THIS_MODULE,
++#endif
++
++ /* Operations that make no sense on ring sockets. */
++ .connect = sock_no_connect,
++ .socketpair = sock_no_socketpair,
++ .accept = sock_no_accept,
++ .getname = sock_no_getname,
++ .listen = sock_no_listen,
++ .shutdown = sock_no_shutdown,
++ .sendpage = sock_no_sendpage,
++ .sendmsg = sock_no_sendmsg,
++ .getsockopt = sock_no_getsockopt,
++
++ /* Now the operations that really occur. */
++ .release = ring_release,
++ .bind = ring_bind,
++ .mmap = ring_mmap,
++ .poll = ring_poll,
++ .setsockopt = ring_setsockopt,
++ .ioctl = ring_ioctl,
++ .recvmsg = ring_recvmsg,
++};
++
++/* ************************************ */
++
++static struct net_proto_family ring_family_ops = {
++ .family = PF_RING,
++ .create = ring_create,
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
++ .owner = THIS_MODULE,
++#endif
++};
++
++// BD: API changed in 2.6.12, ref:
++// http://svn.clkao.org/svnweb/linux/revision/?rev=28201
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,11))
++static struct proto ring_proto = {
++ .name = "PF_RING",
++ .owner = THIS_MODULE,
++ .obj_size = sizeof(struct sock),
++};
++#endif
++
++/* ************************************ */
++
++static void __exit ring_exit(void)
++{
++ struct list_head *ptr;
++ struct ring_element *entry;
++
++ for(ptr = ring_table.next; ptr != &ring_table; ptr = ptr->next) {
++ entry = list_entry(ptr, struct ring_element, list);
++ kfree(entry);
++ }
++
++ while(ring_cluster_list != NULL) {
++ struct ring_cluster *next = ring_cluster_list->next;
++ kfree(ring_cluster_list);
++ ring_cluster_list = next;
++ }
++
++ set_skb_ring_handler(NULL);
++ set_buffer_ring_handler(NULL);
++ sock_unregister(PF_RING);
++
++ printk("PF_RING shut down.\n");
++}
++
++/* ************************************ */
++
++static int __init ring_init(void)
++{
++ printk("Welcome to PF_RING %s\n(C) 2004-05 L.Deri <deri@ntop.org>\n",
++ RING_VERSION);
++
++ INIT_LIST_HEAD(&ring_table);
++ ring_cluster_list = NULL;
++
++ sock_register(&ring_family_ops);
++
++ set_skb_ring_handler(skb_ring_handler);
++ set_buffer_ring_handler(buffer_ring_handler);
++
++ if(get_buffer_ring_handler() != buffer_ring_handler) {
++ printk("PF_RING: set_buffer_ring_handler FAILED\n");
++
++ set_skb_ring_handler(NULL);
++ set_buffer_ring_handler(NULL);
++ sock_unregister(PF_RING);
++ return -1;
++ } else {
++ printk("PF_RING: bucket length %d bytes\n", bucket_len);
++ printk("PF_RING: ring slots %d\n", num_slots);
++ printk("PF_RING: sample rate %d [1=no sampling]\n", sample_rate);
++ printk("PF_RING: capture TX %s\n",
++ enable_tx_capture ? "Yes [RX+TX]" : "No [RX only]");
++ printk("PF_RING: transparent mode %s\n",
++ transparent_mode ? "Yes" : "No");
++
++ printk("PF_RING initialized correctly.\n");
++ return 0;
++ }
++}
++
++module_init(ring_init);
++module_exit(ring_exit);
++MODULE_LICENSE("GPL");
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
++MODULE_ALIAS_NETPROTO(PF_RING);
++#endif