kernel patch

Robert Morris rtm at cag.lcs.mit.edu
Thu Jul 8 20:06:35 EDT 1999


I've appended a short script I used to make the kernel patch and the
patch itself. I'm not sure what to do with either -- I imagine we'll
soon have a subdirectory to hold release-building goodies. The patch
works fine with vanilla Linux 2.2.10; you can experience the resulting
kernel on cone.


#!/usr/local/bin/perl -w

# Make a patch file for a Linux kernel that adds our hooks.
# The resulting output can be used thus:
#  cd /usr/src/linux
#  patch -p0 -b < patch-file

# Directory of patched kernel source:
my $nd = "/opt1/rtm/linux-2.2.10";

# List of files that we modified and that should be patched.
# Each must be accompanied by a file.orig.
my @files = (
             "include/linux/netdevice.h",
             "net/core/dev.c",
             "net/sched/sch_generic.c",
             "net/netsyms.c"
             );

chdir($nd);

$| = 1;
my $f;
foreach $f (@files) {
    print "\nIndex: $f\n";
    system("diff -u ${f}.orig $f");
}



Index: include/linux/netdevice.h
--- include/linux/netdevice.h.orig	Sun May 16 21:28:41 1999
+++ include/linux/netdevice.h	Thu Jul  8 14:54:47 1999
@@ -349,6 +349,11 @@
 extern int		unregister_netdevice(struct device *dev);
 extern int 		register_netdevice_notifier(struct notifier_block *nb);
 extern int		unregister_netdevice_notifier(struct notifier_block *nb);
+extern int 		register_net_in(struct notifier_block *nb); /* Click */
+extern int		unregister_net_in(struct notifier_block *nb); /* Click */
+extern int 		register_net_out(struct notifier_block *nb); /* Click */
+extern int		unregister_net_out(struct notifier_block *nb); /* Click */
+extern void		ptype_dispatch(struct sk_buff *skb, unsigned short type); /* Click */
 extern int		dev_new_index(void);
 extern struct device	*dev_get_by_index(int ifindex);
 extern int		dev_restart(struct device *dev);

Index: net/core/dev.c
--- net/core/dev.c.orig	Thu Mar 25 12:23:34 1999
+++ net/core/dev.c	Thu Jul  8 14:52:10 1999
@@ -94,6 +94,8 @@
 extern int plip_init(void);
 #endif
 
+#include <asm/irq.h>
+
 NET_PROFILE_DEFINE(dev_queue_xmit)
 NET_PROFILE_DEFINE(net_bh)
 NET_PROFILE_DEFINE(net_bh_skb)
@@ -145,6 +147,9 @@
  
 static struct notifier_block *netdev_chain=NULL;
 
+/* input packet handlers -- might steal packets from net_bh(). for Click. */
+static struct notifier_block *net_in_chain = 0;
+
 /*
  *	Device drivers call our routines to queue packets here. We empty the
  *	queue in the bottom half handler.
@@ -503,6 +508,22 @@
 }
 
 /*
+ * Allow Click modules to ask to intercept input packets.
+ * Must add these to ../netsyms.c
+ */
+int
+register_net_in(struct notifier_block *nb)
+{
+  return(notifier_chain_register(&net_in_chain, nb));
+}
+
+int
+unregister_net_in(struct notifier_block *nb)
+{
+  return(notifier_chain_unregister(&net_in_chain, nb));
+}
+
+/*
  *	Support routine. Sends outgoing frames to any network
  *	taps currently in use.
  */
@@ -819,6 +840,84 @@
 }
 #endif
 
+/*
+ * Hand a packet to the ordinary Linux protocol stack.
+ * Broke this out from net_bh() so that Click can call it.
+ * Always frees the skb one way or another.
+ *
+ * skb->pkt_type needs to be set to PACKET_{BROADCAST,MULTICAST,OTHERHOST}
+ * maybe skb->mac.raw must point to ether header.
+ * skb->protocol must be set to a htons(ETHERTYPE_?).
+ * skb->data must point to the ethernet payload (e.g. the IP header).
+ * skb->nh.raw must point to the ethernet payload also.
+ */
+void
+ptype_dispatch(struct sk_buff *skb, unsigned short type)
+{
+	struct packet_type *ptype;
+	struct packet_type *pt_prev;
+
+		/*
+		 *	We got a packet ID.  Now loop over the "known protocols"
+		 * 	list. There are two lists. The ptype_all list of taps (normally empty)
+		 *	and the main protocol list which is hashed perfectly for normal protocols.
+		 */
+
+		pt_prev = NULL;
+		for (ptype = ptype_all; ptype!=NULL; ptype=ptype->next)
+		{
+			if (!ptype->dev || ptype->dev == skb->dev) {
+				if(pt_prev)
+				{
+					struct sk_buff *skb2=skb_clone(skb, GFP_ATOMIC);
+					if(skb2)
+						pt_prev->func(skb2,skb->dev, pt_prev);
+				}
+				pt_prev=ptype;
+			}
+		}
+
+		for (ptype = ptype_base[ntohs(type)&15]; ptype != NULL; ptype = ptype->next) 
+		{
+			if (ptype->type == type && (!ptype->dev || ptype->dev==skb->dev))
+			{
+				/*
+				 *	We already have a match queued. Deliver
+				 *	to it and then remember the new match
+				 */
+				if(pt_prev)
+				{
+					struct sk_buff *skb2;
+
+					skb2=skb_clone(skb, GFP_ATOMIC);
+
+					/*
+					 *	Kick the protocol handler. This should be fast
+					 *	and efficient code.
+					 */
+
+					if(skb2)
+						pt_prev->func(skb2, skb->dev, pt_prev);
+				}
+				/* Remember the current last to do */
+				pt_prev=ptype;
+			}
+		} /* End of protocol list loop */
+
+		/*
+		 *	Is there a last item to send to ?
+		 */
+
+		if(pt_prev)
+			pt_prev->func(skb, skb->dev, pt_prev);
+		/*
+		 * 	Has an unknown packet has been received ?
+		 */
+	 
+		else {
+			kfree_skb(skb);
+		}
+}
 
 /*
  *	When we are called the queue is ready to grab, the interrupts are
@@ -827,13 +926,13 @@
  *	This is run as a bottom half after an interrupt handler that does
  *	mark_bh(NET_BH);
  */
- 
+
 void net_bh(void)
 {
-	struct packet_type *ptype;
-	struct packet_type *pt_prev;
-	unsigned short type;
 	unsigned long start_time = jiffies;
+	unsigned short type;
+        unsigned long long c0;
+        unsigned int cli_flags;
 #ifdef CONFIG_CPU_IS_SLOW
 	static unsigned long start_busy = 0;
 	static unsigned long ave_busy = 0;
@@ -932,66 +1031,16 @@
 		handle_bridge(skb, type); 
 #endif
 
-		/*
-		 *	We got a packet ID.  Now loop over the "known protocols"
-		 * 	list. There are two lists. The ptype_all list of taps (normally empty)
-		 *	and the main protocol list which is hashed perfectly for normal protocols.
-		 */
-
-		pt_prev = NULL;
-		for (ptype = ptype_all; ptype!=NULL; ptype=ptype->next)
-		{
-			if (!ptype->dev || ptype->dev == skb->dev) {
-				if(pt_prev)
-				{
-					struct sk_buff *skb2=skb_clone(skb, GFP_ATOMIC);
-					if(skb2)
-						pt_prev->func(skb2,skb->dev, pt_prev);
-				}
-				pt_prev=ptype;
-			}
-		}
-
-		for (ptype = ptype_base[ntohs(type)&15]; ptype != NULL; ptype = ptype->next) 
-		{
-			if (ptype->type == type && (!ptype->dev || ptype->dev==skb->dev))
-			{
-				/*
-				 *	We already have a match queued. Deliver
-				 *	to it and then remember the new match
-				 */
-				if(pt_prev)
-				{
-					struct sk_buff *skb2;
-
-					skb2=skb_clone(skb, GFP_ATOMIC);
-
-					/*
-					 *	Kick the protocol handler. This should be fast
-					 *	and efficient code.
-					 */
-
-					if(skb2)
-						pt_prev->func(skb2, skb->dev, pt_prev);
-				}
-				/* Remember the current last to do */
-				pt_prev=ptype;
-			}
-		} /* End of protocol list loop */
-
-		/*
-		 *	Is there a last item to send to ?
-		 */
+                /* does Click want to steal this packet? */
+                if(notifier_call_chain(&net_in_chain, 0, skb) & NOTIFY_STOP_MASK)
+                  continue;
+
+                /*
+                 * Ordinary Linux dispatch based on packet type.
+                 * Moved into a function so Click can call it.
+                 */
+                ptype_dispatch(skb, type);
 
-		if(pt_prev)
-			pt_prev->func(skb, skb->dev, pt_prev);
-		/*
-		 * 	Has an unknown packet has been received ?
-		 */
-	 
-		else {
-			kfree_skb(skb);
-		}
   	}	/* End of queue loop */
   	
   	/*
@@ -1019,11 +1068,13 @@
 	netdev_dropping = 0;
 #endif
 	NET_PROFILE_LEAVE(net_bh);
+
 	return;
 
 net_bh_break:
 	mark_bh(NET_BH);
 	NET_PROFILE_LEAVE(net_bh);
+
 	return;
 }
 

Index: net/sched/sch_generic.c
--- net/sched/sch_generic.c.orig	Sun Mar 21 10:22:00 1999
+++ net/sched/sch_generic.c	Thu Jul  8 14:52:29 1999
@@ -76,6 +76,24 @@
 	return q->q.qlen;
 }
 
+/*
+ * Click hooks to be notified when a network device
+ * is idle and could send a packet.
+ */
+static struct notifier_block *net_out_chain = 0;
+
+int
+register_net_out(struct notifier_block *nb)
+{
+  return(notifier_chain_register(&net_out_chain, nb));
+}
+
+int
+unregister_net_out(struct notifier_block *nb)
+{
+  return(notifier_chain_unregister(&net_out_chain, nb));
+}
+
 /* Scan transmission queue and kick devices.
 
    Deficiency: slow devices (ppp) and fast ones (100Mb ethernet)
@@ -93,9 +111,14 @@
 	hp = &qdisc_head.forw;
 	while ((h = *hp) != &qdisc_head) {
 		int res = -1;
+                int res1 = -1;
 		struct Qdisc *q = (struct Qdisc*)h;
 		struct device *dev = q->dev;
 
+                /* Click */
+                if(dev->tbusy == 0)
+                  res1 = notifier_call_chain(&net_out_chain, 0, dev);
+
 		while (!dev->tbusy && (res = qdisc_restart(dev)) < 0)
 			/* NOTHING */;
 
@@ -108,7 +131,7 @@
 		   No problem, we will unlink it during the next round.
 		 */
 
-		if (res == 0 && *hp == h) {
+		if (res1 == 0 && res == 0 && *hp == h) {
 			*hp = h->forw;
 			h->forw = NULL;
 			continue;

Index: net/netsyms.c
--- net/netsyms.c.orig	Sat Apr 24 20:51:48 1999
+++ net/netsyms.c	Thu Jul  8 14:51:52 1999
@@ -431,6 +431,13 @@
 EXPORT_SYMBOL(register_netdevice_notifier);
 EXPORT_SYMBOL(unregister_netdevice_notifier);
 
+/* Click */
+EXPORT_SYMBOL(register_net_in);
+EXPORT_SYMBOL(unregister_net_in);
+EXPORT_SYMBOL(register_net_out);
+EXPORT_SYMBOL(unregister_net_out);
+EXPORT_SYMBOL(ptype_dispatch);
+
 /* support for loadable net drivers */
 #ifdef CONFIG_NET
 EXPORT_SYMBOL(loopback_dev);



More information about the click mailing list