Skip to contentSkip to conversation

2.4.8 frame diverter for modules

PATCH New Will 1 participant 1 message Aug 16, 2001

Subsystems (2)
lore
Share & tools
lore

Will

author
#0 lore raw

PATCH 1/1 2.4.8 frame diverter for modules

Here is a patch against 2.4.8 that implements support for diverting network frames to an arbitrary kernel module. It is similar to the user-level packet diverter except that it handles both incoming and outgoing packets, and the module can discard the packet if it wants to. There is also a callback when a packet is freed. This allows a modular way of doing low-level packet frobbing without going out to userland.

As noted in the code, it currently only supports 1 'diverter module', but it would be pretty easy to support more...

Comments? Anyone find this sort of thing useful besides us?

Signature · 2 lines
-Will  :: AD6XL :: http://www.loopfree.net/
 Orton :: finger [email protected] for GPG public key
include/linux/moddv.h +31 -0
diff -urP linux-clean/include/linux/moddv.h linux/include/linux/moddv.h
@@ -0,0 +1,31 @@
+#ifndef _MODDV_H_
+#define _MODDV_H_
+
+struct moddv_calls {
+	atomic_t unloading;
+	atomic_t usage;
+	int (*divert_tx)(struct sk_buff **, struct net_device **, struct packet_type **);
+	int (*divert_rx)(struct sk_buff **, struct net_device **, struct packet_type **);
+	void (*divert_bind)(struct net_device *, struct packet_type *);
+	void (*divert_free)(struct sk_buff *);
+};
+
+extern int register_divert_module(struct moddv_calls *);
+extern void unregister_divert_module( struct moddv_calls * );
+void mod_divert_inject_out( struct sk_buff *, struct net_device *);
+void mod_divert_inject_in( struct sk_buff *, struct net_device *, struct packet_type *);
+
+int handle_mod_divert_tx(struct sk_buff **, struct net_device **);
+int handle_mod_divert_rx(struct sk_buff **, struct net_device **, struct packet_type **);
+void mod_divert_skb_use(struct sk_buff *);
+void mod_divert_skb_unuse(struct sk_buff *);
+void mod_divert_init(void);
+
+extern struct moddv_calls *diverter;
+
+#define MDV_DISCARD 1
+#define MDV_HOLD    2
+#define MDV_CHAIN   3
+
+
+#endif  /* _MODDV_H_ */
include/linux/netdevice.h +3 -0
diff -urP linux-clean/include/linux/netdevice.h linux/include/linux/netdevice.h
@@ -418,6 +418,9 @@
 					 struct packet_type *);
 	void			*data;	/* Private to the packet type		*/
 	struct packet_type	*next;
+#ifdef CONFIG_MOD_DIVERT
+	void                    *divertPtr; /* Private ptr for the module diverter */
+#endif
 };
 
 
include/linux/skbuff.h +3 -0
diff -urP linux-clean/include/linux/skbuff.h linux/include/linux/skbuff.h
@@ -213,6 +213,9 @@
 #ifdef CONFIG_NET_SCHED
        __u32           tc_index;               /* traffic control index */
 #endif
+#ifdef CONFIG_MOD_DIVERT
+	void            *divertPtr1;
+#endif
 };
 
 #define SK_WMEM_MAX	65535
net/Config.in +1 -0
diff -urP linux-clean/net/Config.in linux/net/Config.in
@@ -64,6 +64,7 @@
    tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
    bool '802.2 LLC (EXPERIMENTAL)' CONFIG_LLC
    bool 'Frame Diverter (EXPERIMENTAL)' CONFIG_NET_DIVERT
+   bool 'Frame diverter for modules (EXPERIMENTAL)' CONFIG_MOD_DIVERT  
 #   if [ "$CONFIG_LLC" = "y" ]; then
 #      bool '  Netbeui (EXPERIMENTAL)' CONFIG_NETBEUI
 #   fi
net/core/Makefile +1 -0
diff -urP linux-clean/net/core/Makefile linux/net/core/Makefile
@@ -24,6 +24,7 @@
 obj-$(CONFIG_NET) += dev.o dev_mcast.o dst.o neighbour.o rtnetlink.o utils.o
 
 obj-$(CONFIG_NETFILTER) += netfilter.o
+obj-$(CONFIG_MOD_DIVERT) += moddv.o
 obj-$(CONFIG_NET_DIVERT) += dv.o
 obj-$(CONFIG_NET_PROFILE) += profile.o
 
net/core/dev.c +31 -3
diff -urP linux-clean/net/core/dev.c linux/net/core/dev.c
@@ -103,6 +103,9 @@
 #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO)
 #include <linux/wireless.h>		/* Note : will define WIRELESS_EXT */
 #endif	/* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
+#ifdef CONFIG_MOD_DIVERT
+#include <linux/moddv.h>
+#endif /* CONFIG_MOD_DIVERT */
 #ifdef CONFIG_PLIP
 extern int plip_init(void);
 #endif
@@ -152,8 +155,13 @@
  *		86DD	IPv6
  */
 
+#ifdef CONFIG_MOD_DIVERT
+struct packet_type *ptype_base[16];		/* 16 way hashed list */
+struct packet_type *ptype_all = NULL;		/* Taps */
+#else  /* !CONFIG_MOD_DIVERT */
 static struct packet_type *ptype_base[16];		/* 16 way hashed list */
 static struct packet_type *ptype_all = NULL;		/* Taps */
+#endif /* !CONFIG_MOD_DIVERT */
 
 #ifdef OFFLINE_SAMPLE
 static void sample_queue(unsigned long dummy);
@@ -987,6 +995,12 @@
 			return -ENOMEM;
 	}
 
+	/* call the module diverter */
+#ifdef CONFIG_MOD_DIVERT
+	if (handle_mod_divert_tx(&skb, &dev))
+		return NET_XMIT_SUCCESS;
+#endif
+
 	/* Grab device queue */
 	spin_lock_bh(&dev->queue_lock);
 	q = dev->qdisc;
@@ -1475,6 +1489,10 @@
 							deliver_to_old_ones(pt_prev, skb, 0);
 						else {
 							atomic_inc(&skb->users);
+#ifdef CONFIG_MOD_DIVERT
+							if (handle_mod_divert_rx(&skb, &rx_dev, &pt_prev))
+								goto DEAD_PACKET;
+#endif /* CONFIG_MOD_DIVERT */
 							pt_prev->func(skb,
 								      skb->dev,
 								      pt_prev);
@@ -1487,12 +1505,19 @@
 			if (pt_prev) {
 				if (!pt_prev->data)
 					deliver_to_old_ones(pt_prev, skb, 1);
-				else
+				else {
+#ifdef CONFIG_MOD_DIVERT
+					if (handle_mod_divert_rx(&skb, &rx_dev, &pt_prev))
+						goto DEAD_PACKET;
+#endif /* CONFIG_MOD_DIVERT */
 					pt_prev->func(skb, skb->dev, pt_prev);
+				}
 			} else
 				kfree_skb(skb);
 		}
-
+#ifdef CONFIG_MOD_DIVERT
+DEAD_PACKET:
+#endif
 		dev_put(rx_dev);
 
 		if (bugdet-- < 0 || jiffies - start_time > 1)
@@ -2783,7 +2808,10 @@
 	 */
 	 
 	net_device_init();
-
+	
+#ifdef CONFIG_MOD_DIVERT
+	mod_divert_init();
+#endif /* CONFIG_MOD_DIVERT */
 	return 0;
 }
 
net/core/moddv.c +239 -0

239 lines not on this page · raw message

net/core/skbuff.c +27 -0
diff -urP linux-clean/net/core/skbuff.c linux/net/core/skbuff.c
@@ -51,6 +51,9 @@
 #include <linux/cache.h>
 #include <linux/init.h>
 #include <linux/highmem.h>
+#ifdef CONFIG_MOD_DIVERT
+#include <linux/moddv.h>
+#endif /* CONFIG_MOD_DIVERT */
 
 #include <net/ip.h>
 #include <net/protocol.h>
@@ -209,6 +212,9 @@
 	atomic_set(&(skb_shinfo(skb)->dataref), 1);
 	skb_shinfo(skb)->nr_frags = 0;
 	skb_shinfo(skb)->frag_list = NULL;
+#ifdef CONFIG_MOD_DIVERT
+	skb->divertPtr1 = NULL;
+#endif
 	return skb;
 
 nodata:
@@ -250,6 +256,9 @@
 #ifdef CONFIG_NET_SCHED
 	skb->tc_index = 0;
 #endif
+#ifdef CONFIG_MOD_DIVERT
+	skb->divertPtr1 = NULL;
+#endif /* CONFIG_MOD_DIVERT */
 }
 
 static void skb_drop_fraglist(struct sk_buff *skb)
@@ -275,6 +284,9 @@
 
 static void skb_release_data(struct sk_buff *skb)
 {
+#ifdef CONFIG_MOD_DIVERT
+	if (skb->head) {
+#endif
 	if (!skb->cloned ||
 	    atomic_dec_and_test(&(skb_shinfo(skb)->dataref))) {
 		if (skb_shinfo(skb)->nr_frags) {
@@ -288,6 +300,9 @@
 
 		kfree(skb->head);
 	}
+#ifdef CONFIG_MOD_DIVERT
+	}
+#endif
 }
 
 /*
@@ -316,7 +331,12 @@
 		BUG();
 	}
 
+#ifdef CONFIG_MOD_DIVERT
+	if (skb->dst)
+		dst_release(skb->dst);
+#else
 	dst_release(skb->dst);
+#endif
 	if(skb->destructor) {
 		if (in_irq()) {
 			printk(KERN_WARNING "Warning: kfree_skb on hard IRQ %p\n",
@@ -327,6 +347,10 @@
 #ifdef CONFIG_NETFILTER
 	nf_conntrack_put(skb->nfct);
 #endif
+#ifdef CONFIG_MOD_DIVERT
+	if (skb->divertPtr1)
+		mod_divert_skb_unuse(skb);
+#endif /* CONFIG_MOD_DIVERT */
 	skb_headerinit(skb, NULL, 0);  /* clean state */
 	kfree_skbmem(skb);
 }
@@ -404,6 +428,9 @@
 	skb->cloned = 1;
 #ifdef CONFIG_NETFILTER
 	nf_conntrack_get(skb->nfct);
+#endif
+#ifdef CONFIG_MOD_DIVERT
+	n->divertPtr1 = NULL;
 #endif
 	return n;
 }
net/netsyms.c +8 -0
diff -urP linux-clean/net/netsyms.c linux/net/netsyms.c
@@ -34,6 +34,9 @@
 #ifdef CONFIG_NET_DIVERT
 #include <linux/divert.h>
 #endif /* CONFIG_NET_DIVERT */
+#ifdef CONFIG_MOD_DIVERT
+#include <linux/moddv.h>
+#endif /* CONFIG_MOD_DIVERT */
 
 #ifdef CONFIG_NET
 extern __u32 sysctl_wmem_max;
@@ -230,6 +233,11 @@
 EXPORT_SYMBOL(free_divert_blk);
 EXPORT_SYMBOL(divert_ioctl);
 #endif /* CONFIG_NET_DIVERT */
+
+#ifdef CONFIG_MOD_DIVERT
+EXPORT_SYMBOL_NOVERS(register_divert_module);
+EXPORT_SYMBOL_NOVERS(unregister_divert_module);
+#endif /* CONFIG_MOD_DIVERT */
 
 #ifdef CONFIG_INET
 /* Internet layer registration */