e012ca39f0
SVN-Revision: 2755
1834 lines
48 KiB
Diff
1834 lines
48 KiB
Diff
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
|