patch-2.1.79 linux/net/core/profile.c

Next file: linux/net/core/rtnetlink.c
Previous file: linux/net/core/neighbour.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.78/linux/net/core/profile.c linux/net/core/profile.c
@@ -0,0 +1,304 @@
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/ip.h>
+#include <linux/inet.h>
+#include <net/checksum.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <net/profile.h>
+
+#ifdef CONFIG_NET_PROFILE
+
+atomic_t net_profile_active;
+struct timeval net_profile_adjust;
+
+NET_PROFILE_DEFINE(total);
+
+struct net_profile_slot *net_profile_chain = &net_prof_total;
+
+#ifdef __alpha__
+__u32 alpha_lo;
+long alpha_hi;
+
+static void alpha_tick(unsigned long);
+
+static struct timer_list alpha_timer =
+	{ NULL, NULL, 0, 0L, alpha_tick };
+
+void alpha_tick(unsigned long dummy)
+{
+	struct timeval dummy_stamp;
+	net_profile_stamp(&dummy_stamp);
+	alpha_timer.expires = jiffies + 4*HZ;
+	add_timer(&alpha_timer);
+}
+
+#endif
+
+void net_profile_irq_adjust(struct timeval *entered, struct timeval* leaved)
+{
+	struct net_profile_slot *s;
+
+	net_profile_sub(entered, leaved);
+	for (s = net_profile_chain; s; s = s->next) {
+		if (s->active)
+			net_profile_add(leaved, &s->irq);
+	}
+}
+
+
+#ifdef CONFIG_PROC_FS
+static int profile_read_proc(char *buffer, char **start, off_t offset,
+			     int length, int *eof, void *data)
+{
+	off_t pos=0;
+	off_t begin=0;
+	int len=0;
+	struct net_profile_slot *s;
+
+	len+= sprintf(buffer, "Slot            Hits       Hi         Lo         OnIrqHi    OnIrqLo    Ufl\n");
+
+	if (offset == 0) {
+		cli();
+		net_prof_total.active = 1;
+		atomic_inc(&net_profile_active);
+		NET_PROFILE_LEAVE(total);
+		sti();
+	}
+	for (s = net_profile_chain; s; s = s->next) {
+		struct net_profile_slot tmp;
+
+		cli();
+		tmp = *s;
+
+		/* Wrong, but pretty close to truth */
+
+		s->accumulator.tv_sec = 0;
+		s->accumulator.tv_usec = 0;
+		s->irq.tv_sec = 0;
+		s->irq.tv_usec = 0;
+		s->hits = 0;
+		s->underflow = 0;
+		/* Repair active count, it is possible, only if code has a bug */
+		if (s->active) {
+			s->active = 0;
+			atomic_dec(&net_profile_active);
+		}
+		sti();
+
+		net_profile_sub(&tmp.irq, &tmp.accumulator);
+
+		len += sprintf(buffer+len,"%-15s %-10d %-10ld %-10lu %-10lu %-10lu %d/%d",
+			       tmp.id,
+			       tmp.hits,
+			       tmp.accumulator.tv_sec,
+			       tmp.accumulator.tv_usec,
+			       tmp.irq.tv_sec,
+			       tmp.irq.tv_usec,
+			       tmp.underflow, tmp.active);
+
+			buffer[len++]='\n';
+		
+			pos=begin+len;
+			if(pos<offset) {
+				len=0;
+				begin=pos;
+			}
+			if(pos>offset+length)
+				goto done;
+	}
+	*eof = 1;
+
+done:
+	*start=buffer+(offset-begin);
+	len-=(offset-begin);
+	if(len>length)
+		len=length;
+	if (len < 0) {
+		len = 0;
+		printk(KERN_CRIT "Yep, guys... our template for proc_*_read is crappy :-)\n");
+	}
+	if (offset == 0) {
+		cli();
+		net_prof_total.active = 0;
+		net_prof_total.hits = 0;
+		net_profile_stamp(&net_prof_total.entered);
+		sti();
+	}
+	return len;
+}
+#endif
+
+struct iphdr whitehole_iph;
+int whitehole_count;
+
+static int whitehole_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct net_device_stats *stats;
+	dev_kfree_skb(skb, FREE_WRITE);
+	stats = (struct net_device_stats *)dev->priv;
+	stats->tx_packets++;
+	stats->tx_bytes+=skb->len;
+
+	return 0;
+}
+
+static void whitehole_inject(unsigned long);
+int whitehole_init(struct device *dev);
+
+static struct timer_list whitehole_timer =
+	{ NULL, NULL, 0, 0L, whitehole_inject };
+
+static struct device whitehole_dev = {
+	"whitehole", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, whitehole_init, };
+
+static int whitehole_open(struct device *dev)
+{
+	whitehole_count = 100000;
+	whitehole_timer.expires = jiffies + 5*HZ;
+	add_timer(&whitehole_timer);
+	return 0;
+}
+
+static int whitehole_close(struct device *dev)
+{
+	del_timer(&whitehole_timer);
+	return 0;
+}
+
+static void whitehole_inject(unsigned long dummy)
+{
+	struct net_device_stats *stats = (struct net_device_stats *)whitehole_dev.priv;
+	extern int netdev_dropping;
+
+	do {
+		struct iphdr *iph;
+		struct sk_buff *skb = alloc_skb(128, GFP_ATOMIC);
+		if (!skb)
+			break;
+		skb_reserve(skb, 32);
+		iph = (struct iphdr*)skb_put(skb, sizeof(*iph));
+		skb->mac.raw = ((u8*)iph) - 14;
+		memcpy(iph, &whitehole_iph, sizeof(*iph));
+		skb->protocol = __constant_htons(ETH_P_IP);
+		skb->dev = &whitehole_dev;
+		skb->pkt_type = PACKET_HOST;
+		stats->rx_packets++;
+		stats->rx_bytes += skb->len;
+		netif_rx(skb);
+		whitehole_count--;
+	} while (netdev_dropping == 0 && whitehole_count>0);
+	if (whitehole_count > 0) {
+		whitehole_timer.expires = jiffies + 1;
+		add_timer(&whitehole_timer);
+	}
+}
+
+static struct net_device_stats *whitehole_get_stats(struct device *dev)
+{
+	struct net_device_stats *stats = (struct net_device_stats *) dev->priv;
+	return stats;
+}
+
+__initfunc(int whitehole_init(struct device *dev))
+{
+	dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
+	if (dev->priv == NULL)
+		return -ENOBUFS;
+	memset(dev->priv, 0, sizeof(struct net_device_stats));
+	dev->get_stats	= whitehole_get_stats;
+	dev->hard_start_xmit = whitehole_xmit;
+	dev->open = whitehole_open;
+	dev->stop = whitehole_close;
+	ether_setup(dev);
+	dev->tx_queue_len = 0;
+	dev->flags |= IFF_NOARP;
+	dev->flags &= ~(IFF_BROADCAST|IFF_MULTICAST);
+	dev->iflink = 0;
+	whitehole_iph.ihl = 5;
+	whitehole_iph.version = 4;
+	whitehole_iph.ttl = 2;
+	whitehole_iph.saddr = in_aton("193.233.7.21");
+	whitehole_iph.daddr = in_aton("193.233.7.10");
+	whitehole_iph.tot_len = htons(20);
+	whitehole_iph.check = ip_compute_csum((void *)&whitehole_iph, 20);
+	return 0;
+}
+
+int net_profile_register(struct net_profile_slot *slot)
+{
+	cli();
+	slot->next = net_profile_chain;
+	net_profile_chain = slot;
+	sti();
+	return 0;
+}
+
+int net_profile_unregister(struct net_profile_slot *slot)
+{
+	struct net_profile_slot **sp, *s;
+
+	for (sp = &net_profile_chain; (s = *sp) != NULL; sp = &s->next) {
+		if (s == slot) {
+			cli();
+			*sp = s->next;
+			sti();
+			return 0;
+		}
+	}
+	return -ESRCH;
+}
+
+
+__initfunc(int net_profile_init(void))
+{
+	int i;
+
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *ent;
+
+	ent = create_proc_entry("net/profile", 0, 0);
+	ent->read_proc = profile_read_proc;
+#endif
+
+	register_netdevice(&whitehole_dev);
+
+	printk("Evaluating net profiler cost ...");
+#if CPU == 586 || CPU == 686
+	if (!(boot_cpu_data.x86_capability & 16)) {
+		panic("Sorry, you CPU does not support tsc. I am dying...\n");
+		return -1;
+	}
+#endif
+	start_bh_atomic();
+#ifdef __alpha__
+	alpha_tick(0);
+#endif
+	for (i=0; i<1024; i++) {
+		NET_PROFILE_ENTER(total);
+		NET_PROFILE_LEAVE(total);
+	}
+	if (net_prof_total.accumulator.tv_sec) {
+		printk(" too high!\n");
+	} else {
+		net_profile_adjust.tv_usec = net_prof_total.accumulator.tv_usec>>10;
+		printk("%ld units\n", net_profile_adjust.tv_usec);
+	}
+	net_prof_total.hits = 0;
+	net_profile_stamp(&net_prof_total.entered);
+	end_bh_atomic();
+	return 0;
+}
+
+#endif

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov