#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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(posoffset+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); 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 & X86_FEATURE_TSC)) { printk(KERN_ERR "Sorry, your CPU does not support TSC. Net profiler disabled.\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