1 #include <linux/config.h>
2 #include <linux/types.h>
3 #include <linux/kernel.h>
4 #include <linux/sched.h>
5 #include <linux/mm.h>
6 #include <linux/interrupt.h>
7 #include <linux/netdevice.h>
8 #include <linux/string.h>
9 #include <linux/skbuff.h>
10 #include <linux/proc_fs.h>
11 #include <linux/init.h>
12 #include <linux/ip.h>
13 #include <linux/inet.h>
14 #include <net/checksum.h>
15 
16 #include <asm/processor.h>
17 #include <asm/uaccess.h>
18 #include <asm/system.h>
19 
20 #include <net/profile.h>
21 
22 #ifdef CONFIG_NET_PROFILE
23 
24 atomic_t net_profile_active;
25 struct timeval net_profile_adjust;
26 
27 NET_PROFILE_DEFINE(total);
28 
29 struct net_profile_slot *net_profile_chain = &net_prof_total;
30 
31 #ifdef __alpha__
32 __u32 alpha_lo;
33 long alpha_hi;
34 
35 static void alpha_tick(unsigned long);
36 
37 static struct timer_list alpha_timer =
38 	{ NULL, NULL, 0, 0L, alpha_tick };
39 
alpha_tick(unsigned long dummy)40 void alpha_tick(unsigned long dummy)
41 {
42 	struct timeval dummy_stamp;
43 	net_profile_stamp(&dummy_stamp);
44 	alpha_timer.expires = jiffies + 4*HZ;
45 	add_timer(&alpha_timer);
46 }
47 
48 #endif
49 
net_profile_irq_adjust(struct timeval * entered,struct timeval * leaved)50 void net_profile_irq_adjust(struct timeval *entered, struct timeval* leaved)
51 {
52 	struct net_profile_slot *s;
53 
54 	net_profile_sub(entered, leaved);
55 	for (s = net_profile_chain; s; s = s->next) {
56 		if (s->active)
57 			net_profile_add(leaved, &s->irq);
58 	}
59 }
60 
61 
62 #ifdef CONFIG_PROC_FS
profile_read_proc(char * buffer,char ** start,off_t offset,int length,int * eof,void * data)63 static int profile_read_proc(char *buffer, char **start, off_t offset,
64 			     int length, int *eof, void *data)
65 {
66 	off_t pos=0;
67 	off_t begin=0;
68 	int len=0;
69 	struct net_profile_slot *s;
70 
71 	len+= sprintf(buffer, "Slot            Hits       Hi         Lo         OnIrqHi    OnIrqLo    Ufl\n");
72 
73 	if (offset == 0) {
74 		cli();
75 		net_prof_total.active = 1;
76 		atomic_inc(&net_profile_active);
77 		NET_PROFILE_LEAVE(total);
78 		sti();
79 	}
80 	for (s = net_profile_chain; s; s = s->next) {
81 		struct net_profile_slot tmp;
82 
83 		cli();
84 		tmp = *s;
85 
86 		/* Wrong, but pretty close to truth */
87 
88 		s->accumulator.tv_sec = 0;
89 		s->accumulator.tv_usec = 0;
90 		s->irq.tv_sec = 0;
91 		s->irq.tv_usec = 0;
92 		s->hits = 0;
93 		s->underflow = 0;
94 		/* Repair active count, it is possible, only if code has a bug */
95 		if (s->active) {
96 			s->active = 0;
97 			atomic_dec(&net_profile_active);
98 		}
99 		sti();
100 
101 		net_profile_sub(&tmp.irq, &tmp.accumulator);
102 
103 		len += sprintf(buffer+len,"%-15s %-10d %-10ld %-10lu %-10lu %-10lu %d/%d",
104 			       tmp.id,
105 			       tmp.hits,
106 			       tmp.accumulator.tv_sec,
107 			       tmp.accumulator.tv_usec,
108 			       tmp.irq.tv_sec,
109 			       tmp.irq.tv_usec,
110 			       tmp.underflow, tmp.active);
111 
112 			buffer[len++]='\n';
113 
114 			pos=begin+len;
115 			if(pos<offset) {
116 				len=0;
117 				begin=pos;
118 			}
119 			if(pos>offset+length)
120 				goto done;
121 	}
122 	*eof = 1;
123 
124 done:
125 	*start=buffer+(offset-begin);
126 	len-=(offset-begin);
127 	if(len>length)
128 		len=length;
129 	if (len < 0)
130 		len = 0;
131 	if (offset == 0) {
132 		cli();
133 		net_prof_total.active = 0;
134 		net_prof_total.hits = 0;
135 		net_profile_stamp(&net_prof_total.entered);
136 		sti();
137 	}
138 	return len;
139 }
140 #endif
141 
142 struct iphdr whitehole_iph;
143 int whitehole_count;
144 
whitehole_xmit(struct sk_buff * skb,struct net_device * dev)145 static int whitehole_xmit(struct sk_buff *skb, struct net_device *dev)
146 {
147 	struct net_device_stats *stats;
148 
149 	stats = (struct net_device_stats *)dev->priv;
150 	stats->tx_packets++;
151 	stats->tx_bytes+=skb->len;
152 
153 	dev_kfree_skb(skb);
154 	return 0;
155 }
156 
157 static void whitehole_inject(unsigned long);
158 int whitehole_init(struct net_device *dev);
159 
160 static struct timer_list whitehole_timer =
161 	{ NULL, NULL, 0, 0L, whitehole_inject };
162 
163 static struct net_device whitehole_dev = {
164 	"whitehole", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, whitehole_init, };
165 
whitehole_open(struct net_device * dev)166 static int whitehole_open(struct net_device *dev)
167 {
168 	whitehole_count = 100000;
169 	whitehole_timer.expires = jiffies + 5*HZ;
170 	add_timer(&whitehole_timer);
171 	return 0;
172 }
173 
whitehole_close(struct net_device * dev)174 static int whitehole_close(struct net_device *dev)
175 {
176 	del_timer(&whitehole_timer);
177 	return 0;
178 }
179 
whitehole_inject(unsigned long dummy)180 static void whitehole_inject(unsigned long dummy)
181 {
182 	struct net_device_stats *stats = (struct net_device_stats *)whitehole_dev.priv;
183 	extern int netdev_dropping;
184 
185 	do {
186 		struct iphdr *iph;
187 		struct sk_buff *skb = alloc_skb(128, GFP_ATOMIC);
188 		if (!skb)
189 			break;
190 		skb_reserve(skb, 32);
191 		iph = (struct iphdr*)skb_put(skb, sizeof(*iph));
192 		skb->mac.raw = ((u8*)iph) - 14;
193 		memcpy(iph, &whitehole_iph, sizeof(*iph));
194 		skb->protocol = __constant_htons(ETH_P_IP);
195 		skb->dev = &whitehole_dev;
196 		skb->pkt_type = PACKET_HOST;
197 		stats->rx_packets++;
198 		stats->rx_bytes += skb->len;
199 		netif_rx(skb);
200 		whitehole_count--;
201 	} while (netdev_dropping == 0 && whitehole_count>0);
202 	if (whitehole_count > 0) {
203 		whitehole_timer.expires = jiffies + 1;
204 		add_timer(&whitehole_timer);
205 	}
206 }
207 
whitehole_get_stats(struct net_device * dev)208 static struct net_device_stats *whitehole_get_stats(struct net_device *dev)
209 {
210 	struct net_device_stats *stats = (struct net_device_stats *) dev->priv;
211 	return stats;
212 }
213 
whitehole_init(struct net_device * dev)214 int __init whitehole_init(struct net_device *dev)
215 {
216 	dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
217 	if (dev->priv == NULL)
218 		return -ENOBUFS;
219 	memset(dev->priv, 0, sizeof(struct net_device_stats));
220 	dev->get_stats	= whitehole_get_stats;
221 	dev->hard_start_xmit = whitehole_xmit;
222 	dev->open = whitehole_open;
223 	dev->stop = whitehole_close;
224 	ether_setup(dev);
225 	dev->tx_queue_len = 0;
226 	dev->flags |= IFF_NOARP;
227 	dev->flags &= ~(IFF_BROADCAST|IFF_MULTICAST);
228 	dev->iflink = 0;
229 	whitehole_iph.ihl = 5;
230 	whitehole_iph.version = 4;
231 	whitehole_iph.ttl = 2;
232 	whitehole_iph.saddr = in_aton("193.233.7.21");
233 	whitehole_iph.daddr = in_aton("193.233.7.10");
234 	whitehole_iph.tot_len = htons(20);
235 	whitehole_iph.check = ip_compute_csum((void *)&whitehole_iph, 20);
236 	return 0;
237 }
238 
net_profile_register(struct net_profile_slot * slot)239 int net_profile_register(struct net_profile_slot *slot)
240 {
241 	cli();
242 	slot->next = net_profile_chain;
243 	net_profile_chain = slot;
244 	sti();
245 	return 0;
246 }
247 
net_profile_unregister(struct net_profile_slot * slot)248 int net_profile_unregister(struct net_profile_slot *slot)
249 {
250 	struct net_profile_slot **sp, *s;
251 
252 	for (sp = &net_profile_chain; (s = *sp) != NULL; sp = &s->next) {
253 		if (s == slot) {
254 			cli();
255 			*sp = s->next;
256 			sti();
257 			return 0;
258 		}
259 	}
260 	return -ESRCH;
261 }
262 
263 
net_profile_init(void)264 int __init net_profile_init(void)
265 {
266 	int i;
267 
268 #ifdef CONFIG_PROC_FS
269 	create_proc_read_entry("net/profile", 0, 0, profile_read_proc, NULL);
270 #endif
271 
272 	register_netdevice(&whitehole_dev);
273 
274 	printk("Evaluating net profiler cost ...");
275 #ifdef __alpha__
276 	alpha_tick(0);
277 #endif
278 	for (i=0; i<1024; i++) {
279 		NET_PROFILE_ENTER(total);
280 		NET_PROFILE_LEAVE(total);
281 	}
282 	if (net_prof_total.accumulator.tv_sec) {
283 		printk(" too high!\n");
284 	} else {
285 		net_profile_adjust.tv_usec = net_prof_total.accumulator.tv_usec>>10;
286 		printk("%ld units\n", net_profile_adjust.tv_usec);
287 	}
288 	net_prof_total.hits = 0;
289 	net_profile_stamp(&net_prof_total.entered);
290 	return 0;
291 }
292 
293 #endif
294