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