add patch to revert condition that can set RTT=0
[linux-2.6.git] / linux-2.6-690-web100.patch
1 diff -Naur linux-2.6.32-27.planetlab.i686.orig/Documentation/web100/locking.txt linux-2.6.32-27.planetlab.i686/Documentation/web100/locking.txt
2 --- linux-2.6.32-27.planetlab.i686.orig/Documentation/web100/locking.txt        1969-12-31 19:00:00.000000000 -0500
3 +++ linux-2.6.32-27.planetlab.i686/Documentation/web100/locking.txt     2011-11-16 16:51:06.764471232 -0500
4 @@ -0,0 +1,33 @@
5 +Web100 Locking Model for Linux 2.4
6 +John Heffner <jheffner@psc.edu>
7 +August 2, 2001
8 +
9 +
10 +1. Lookup Structures
11 +
12 +The connections entries are kept linked together simultaneously in a table
13 +and in a list.  Only entries in these structures can be looked up.  To
14 +protect these lookup structures, we have a single global reader-writer
15 +spinlock, web100_linkage_lock.  Since we grab the lock both from user space
16 +and in the bottom half, we must do a [read/write]_lock_bh.  As this disables
17 +the local BH's, this lock should *not* be held for very long.
18 +
19 +
20 +2. Data Integrity
21 +
22 +The statistics are protected by the sock's lock.  Any code modifying or
23 +reading the statistics should hold the sock lock while doing so.  We assume
24 +that if the socket is gone, the statistics should not be modified, so
25 +readers need not hold any lock.
26 +
27 +
28 +3. Statistics Destruction
29 +
30 +A statistics structure keeps a count of the number of references to it,
31 +wc_users.  When a lookup is performed, the reference count should be
32 +incremented (while the linkage lock is held) by calling web100_stats_use. 
33 +When the reference is no longer needed, decrement the count by calling
34 +web100_stats_unuse.  The latter function will free the statistics when there
35 +are no remaining references.  The lookup structures keep one reference.  The
36 +sock also keeps one, since the sock may be destroyed before it ever enters
37 +the ESTABLISHED state.
38 diff -Naur linux-2.6.32-27.planetlab.i686.orig/Documentation/web100/proc_interface.txt linux-2.6.32-27.planetlab.i686/Documentation/web100/proc_interface.txt
39 --- linux-2.6.32-27.planetlab.i686.orig/Documentation/web100/proc_interface.txt 1969-12-31 19:00:00.000000000 -0500
40 +++ linux-2.6.32-27.planetlab.i686/Documentation/web100/proc_interface.txt      2011-11-16 16:51:06.764471232 -0500
41 @@ -0,0 +1,102 @@
42 +WEB100 proc interface notes
43 +===========================
44 +
45 +The web100 modifications to the kernel collect information about the
46 +state of a TCP transfer in a kernel data structure that is linked
47 +out of the "sock" TCP structure in sock.h.  Please see
48 +"include/net/web100_stats.h" for the structure definition.
49 +
50 +The API for this structure is provided through the /proc interface.
51 +This document provides a brief description of this interface.  Please
52 +see fs/proc/web100.c for source code.
53 +
54 +First, kernel creates the /proc/web100 directory and the file
55 +/proc/web100/header at system boot time.
56 +
57 +Each new TCP connection is assigned a unique, unchanging number
58 +(similar to a pid), and its directory name is that number as ASCII
59 +decimal.  These directories persist for about sixty seconds after the
60 +connection is terminated (goes into a CLOSED or TIME_WAIT state).  The
61 +connection stats will not change after the connection is terminated.
62 +(So a connection whose state variable is TIME_WAIT is not necessarily
63 +still in TIME_WAIT.)  It should be noted that what is meant by a
64 +"connection" here is actually one side of a connection.  If a
65 +connection is created from the local host to the local host, two
66 +connection ID's will be created.
67 +
68 +When writing an application to read from the proc interface, it should be
69 +taken into consideration that the directories and their files can disappear at
70 +any time (they do so at an interrupt level).  So if a file open fails on a
71 +file you just looked up (say, with glob), that's probably normal and the
72 +program should handle it gracefully.
73 +
74 +Another seemingly strange thing that can happen is that stats for multiple
75 +connections with the same four-tuple can show up.  No more than one of the
76 +connections may be in any state but CLOSED or TIME_WAIT.  This behavior is
77 +correct, and should be handled as such.
78 +
79 +The algorithms governing the connection numbers are not yet final. 
80 +Currently, for simplification, it is only possible to have 32768
81 +connections.
82 +
83 +Inside each connection directory is an identical set of files.  One is
84 +spec-ascii, which contains the connection four-tuple in human-readable
85 +format.  One can, for example, see all outgoing ssh connections by executing
86 +"grep ':22$' /proc/web100/*/spec-ascii" from the command prompt.
87 +
88 +The remaining files provide access to states of TCP-KIS variables in
89 +local host byte-order.  Since the number, names, and contents of these
90 +files can and will change with releases, they are described in a
91 +header file -- /proc/web100/header.  A file named spec, which contains the
92 +variables describing the connection's four-tuple, should be present
93 +for any release.
94 +
95 +The header file is in human-readable format as follows:
96 +       <version>
97 +       
98 +       /<filename>
99 +       <varname> <offset> <type>
100 +       <varname> <offset> <type>
101 +       ...
102 +       
103 +       /<filename>
104 +       ...
105 +The filename is the name of the file inside each connection directory.  (The
106 +/ is prepended to make it clear it is a new file, not a new variable in the
107 +previous file.  There is also an empty line before each filename.)  Each
108 +file has an arbitrary number of variables, and there are an arbitrary number
109 +of files.  The type is an integer, and is currently defined something like:
110 +
111 +       enum {
112 +               WEB100_TYPE_INTEGER,
113 +               WEB100_TYPE_INTEGER32,
114 +               WEB100_TYPE_IP_ADDRESS,
115 +               WEB100_TYPE_COUNTER32,
116 +               WEB100_TYPE_GAUGE32,
117 +               WEB100_TYPE_UNSIGNED32,
118 +               WEB100_TYPE_TIME_TICKS,
119 +               WEB100_TYPE_COUNTER64,
120 +               WEB100_TYPE_UNSIGNED16
121 +       };
122 +
123 +in the kernel source file fs/proc/web100.c.  These correspond to
124 +MIB-II types.  (RFC2578)
125 +
126 +To read variables, seek to the appropriate offset, then read the appropriate
127 +amount of data.  (Length is implied by the type.)  Multiple variables may be
128 +read with a single read, and will be read atomically when doing so. 
129 +Currently, all variables are readable, but this may not be true in the
130 +future.
131 +
132 +To write variables, seek to the appropriate offset, and write the
133 +appropriate amount of data.  Only a single variable may be written at one
134 +time.  If variables must be atomically written, a variable should be used as
135 +a flag to signal that the write is done, and the kernel code depending on
136 +the variables should be written to handle this.
137 +
138 +See: http://www.web100.org
139 +Please send coments to prog@web100.org
140 +
141 +John Heffner, Matt Mathis, R. Reddy
142 +August 2000, Jan 2001
143 +
144 diff -Naur linux-2.6.32-27.planetlab.i686.orig/Documentation/web100/sysctl.txt linux-2.6.32-27.planetlab.i686/Documentation/web100/sysctl.txt
145 --- linux-2.6.32-27.planetlab.i686.orig/Documentation/web100/sysctl.txt 1969-12-31 19:00:00.000000000 -0500
146 +++ linux-2.6.32-27.planetlab.i686/Documentation/web100/sysctl.txt      2011-11-16 16:51:06.764471232 -0500
147 @@ -0,0 +1,24 @@
148 +Web100 sysctl variables
149 +John Heffner <jheffner@psc.edu>
150 +October 10, 2002
151 +
152 +net.ipv4.WAD_FloydAIMD
153 +       This value is used for WAD_FloydAIMD by a connection when its KIS
154 +       variable is 0.  This variable requires that private extenisons be
155 +       enabled.
156 +
157 +net.ipv4.WAD_IFQ
158 +       This value is used for WAD_IFQ by a connection when its KIS
159 +       variable is 0.  This variable requires that Net100 extensions be
160 +       enabled.
161 +
162 +net.ipv4.WAD_MaxBurst
163 +       This value is used for WAD_MaxBurst by a connection when its KIS
164 +       variable is 0.  This variable requires that Net100 extensions be
165 +       enabled.
166 +
167 +net.ipv4.web100_fperms
168 +       Sets the file permissions of the files in /proc/web100/*/
169 +
170 +net.ipv4.web100_gid
171 +       Sets the group of the files in /proc/web100/*/
172 diff -Naur linux-2.6.32-27.planetlab.i686.orig/fs/proc/Makefile linux-2.6.32-27.planetlab.i686/fs/proc/Makefile
173 --- linux-2.6.32-27.planetlab.i686.orig/fs/proc/Makefile        2011-11-16 16:51:07.757475369 -0500
174 +++ linux-2.6.32-27.planetlab.i686/fs/proc/Makefile     2011-11-16 16:51:06.202465318 -0500
175 @@ -26,3 +26,4 @@
176  proc-$(CONFIG_PROC_DEVICETREE) += proc_devtree.o
177  proc-$(CONFIG_PRINTK)  += kmsg.o
178  proc-$(CONFIG_PROC_PAGE_MONITOR)       += page.o
179 +proc-$(CONFIG_WEB100_STATS)    += web100.o
180 diff -Naur linux-2.6.32-27.planetlab.i686.orig/fs/proc/root.c linux-2.6.32-27.planetlab.i686/fs/proc/root.c
181 --- linux-2.6.32-27.planetlab.i686.orig/fs/proc/root.c  2011-11-16 16:51:07.757475369 -0500
182 +++ linux-2.6.32-27.planetlab.i686/fs/proc/root.c       2011-11-16 16:51:06.194471290 -0500
183 @@ -142,6 +142,10 @@
184         proc_mkdir("bus", NULL);
185         proc_sys_init();
186         proc_vx_init();
187 +
188 +#ifdef CONFIG_WEB100_STATS
189 +       proc_web100_init();
190 +#endif
191  }
192  
193  static int proc_root_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat
194 diff -Naur linux-2.6.32-27.planetlab.i686.orig/fs/proc/web100.c linux-2.6.32-27.planetlab.i686/fs/proc/web100.c
195 --- linux-2.6.32-27.planetlab.i686.orig/fs/proc/web100.c        1969-12-31 19:00:00.000000000 -0500
196 +++ linux-2.6.32-27.planetlab.i686/fs/proc/web100.c     2011-11-16 16:51:06.194471290 -0500
197 @@ -0,0 +1,1368 @@
198 +/*  
199 + *  fs/proc/web100.c
200 + *  
201 + * Copyright (C) 2001 Matt Mathis <mathis@psc.edu>
202 + * Copyright (C) 2001 John Heffner <jheffner@psc.edu>
203 + *
204 + * The Web 100 project.  See http://www.web100.org
205 + *
206 + * This program is free software; you can redistribute it and/or
207 + * modify it under the terms of the GNU General Public License
208 + * as published by the Free Software Foundation; either version
209 + * 2 of the License, or (at your option) any later version.
210 + *
211 + */
212 +
213 +#include <linux/proc_fs.h>
214 +#include <net/sock.h>
215 +#include <net/tcp.h>
216 +#include <net/web100.h>
217 +#include <linux/init.h>
218 +#include <linux/sysctl.h>
219 +#include <linux/mount.h>
220 +
221 +#include "internal.h"
222 +
223 +#define WEB100MIB_BLOCK_SIZE   PAGE_SIZE - 1024
224 +
225 +extern __u32 sysctl_wmem_default;
226 +extern __u32 sysctl_wmem_max;
227 +
228 +struct proc_dir_entry *proc_web100_dir;
229 +static struct proc_dir_entry *proc_web100_header;
230 +
231 +
232 +/*
233 + * Web100 variable reading/writing
234 + */
235 +
236 +enum web100_connection_inos {
237 +       PROC_CONN_SPEC_ASCII = 1,
238 +       PROC_CONN_SPEC,
239 +       PROC_CONN_READ,
240 +       PROC_CONN_TEST,
241 +       PROC_CONN_TUNE,
242 +       PROC_CONN_HIGH_INO              /* Keep at the end */
243 +};
244 +
245 +enum {
246 +       WEB100_TYPE_INTEGER = 0,
247 +       WEB100_TYPE_INTEGER32,
248 +       WEB100_TYPE_INET_ADDRESS_IPV4,
249 +       WEB100_TYPE_IP_ADDRESS = WEB100_TYPE_INET_ADDRESS_IPV4, /* Depricated */
250 +       WEB100_TYPE_COUNTER32,
251 +       WEB100_TYPE_GAUGE32,
252 +       WEB100_TYPE_UNSIGNED32,
253 +       WEB100_TYPE_TIME_TICKS,
254 +       WEB100_TYPE_COUNTER64,
255 +       WEB100_TYPE_INET_PORT_NUMBER,
256 +       WEB100_TYPE_UNSIGNED16 = WEB100_TYPE_INET_PORT_NUMBER, /* Depricated */
257 +       WEB100_TYPE_INET_ADDRESS,
258 +       WEB100_TYPE_INET_ADDRESS_IPV6,
259 +};
260 +
261 +struct web100_var;
262 +typedef int (*web100_rwfunc_t)(void *buf, struct web100stats *stats,
263 +                              struct web100_var *vp);
264 +
265 +/* The printed variable description should look something like this (in ASCII):
266 + * varname offset type
267 + * where offset is the offset into the file.
268 + */
269 +struct web100_var {
270 +       char *name;
271 +       __u32 type;
272 +       int len;
273 +       
274 +       web100_rwfunc_t read;
275 +       unsigned long read_data;        /* read handler-specific data */
276 +       
277 +       web100_rwfunc_t write;
278 +       unsigned long write_data;       /* write handler-specific data */
279 +       
280 +       struct web100_var *next;
281 +};
282 +
283 +struct web100_file {
284 +       int len;
285 +       char *name;
286 +       int low_ino;
287 +       mode_t mode;
288 +       
289 +       struct web100_var *first_var;
290 +};
291 +
292 +#define F(name,ino,perm) { sizeof (name) - 1, (name), (ino), (perm), NULL }
293 +static struct web100_file web100_file_arr[] = {
294 +       F("spec-ascii", PROC_CONN_SPEC_ASCII, S_IFREG | S_IRUGO),
295 +       F("spec", PROC_CONN_SPEC, S_IFREG | S_IRUGO),
296 +       F("read", PROC_CONN_READ, 0),
297 +       F("test", PROC_CONN_TEST, 0),
298 +       F("tune", PROC_CONN_TUNE, 0),
299 +       F(NULL, 0, 0) };
300 +#undef F
301 +#define WEB100_FILE_ARR_SIZE   (sizeof (web100_file_arr) / sizeof (struct web100_file))
302 +
303 +/* This works only if the array is built in the correct order. */
304 +static inline struct web100_file *web100_file_lookup(int ino) {
305 +       return &web100_file_arr[ino - 1];
306 +}
307 +
308 +static void add_var(struct web100_file *file, char *name, int type,
309 +       web100_rwfunc_t read, unsigned long read_data,
310 +       web100_rwfunc_t write, unsigned long write_data)
311 +{
312 +       struct web100_var *var;
313 +       
314 +       /* Again, assuming add_var is only called at init. */
315 +       if ((var = kmalloc(sizeof (struct web100_var), GFP_KERNEL)) == NULL)
316 +               panic("No memory available for Web100 var.\n");
317 +       
318 +       var->name = name;
319 +       var->type = type;
320 +       switch (type) {
321 +       case WEB100_TYPE_INET_PORT_NUMBER:
322 +               var->len = 2;
323 +               break;
324 +       case WEB100_TYPE_INTEGER:
325 +       case WEB100_TYPE_INTEGER32:
326 +       case WEB100_TYPE_COUNTER32:
327 +       case WEB100_TYPE_GAUGE32:
328 +       case WEB100_TYPE_UNSIGNED32:
329 +       case WEB100_TYPE_TIME_TICKS:
330 +               var->len = 4;
331 +               break;
332 +       case WEB100_TYPE_COUNTER64:
333 +               var->len = 8;
334 +               break;
335 +       case WEB100_TYPE_INET_ADDRESS:
336 +               var->len = 17;
337 +               break;
338 +       default:
339 +               printk("Web100: Warning: Adding variable of unknown type.\n");
340 +               var->len = 0;
341 +       }
342 +       
343 +       var->read = read;
344 +       var->read_data = read_data;
345 +       
346 +       var->write = write;
347 +       var->write_data = write_data;
348 +       
349 +       var->next = file->first_var;
350 +       file->first_var = var;
351 +}
352 +
353 +
354 +/*
355 + * proc filesystem routines
356 + */
357 +
358 +static struct inode *proc_web100_make_inode(struct super_block *sb, int ino)
359 +{
360 +       struct inode *inode;
361 +       
362 +       inode = new_inode(sb);
363 +       if (!inode)
364 +               goto out;
365 +       
366 +       inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
367 +       inode->i_ino = ino;
368 +       
369 +       inode->i_uid = 0;
370 +       inode->i_gid = 0;
371 +
372 +out:
373 +       return inode;
374 +}
375 +
376 +static inline ino_t ino_from_cid(int cid)
377 +{
378 +       return (cid << 8) | 0x80000000;
379 +}
380 +
381 +static inline ino_t ino_from_parts(ino_t dir_ino, __u16 low_ino)
382 +{
383 +       return (dir_ino & ~0xff) | low_ino;
384 +}
385 +
386 +static inline int cid_from_ino(ino_t ino)
387 +{
388 +       return (ino & 0x7fffff00) >> 8;
389 +}
390 +
391 +static inline int low_from_ino(ino_t ino)
392 +{
393 +       return ino & 0xff;
394 +}
395 +
396 +static int connection_file_open(struct inode *inode, struct file *file)
397 +{
398 +       int cid = cid_from_ino(inode->i_ino);
399 +       struct web100stats *stats;
400 +       
401 +       read_lock_bh(&web100_linkage_lock);
402 +       stats = web100stats_lookup(cid);
403 +       if (stats == NULL || stats->wc_dead) {
404 +               read_unlock_bh(&web100_linkage_lock);
405 +               return -ENOENT;
406 +       }
407 +       web100_stats_use(stats);
408 +       read_unlock_bh(&web100_linkage_lock);
409 +       
410 +       return 0;
411 +}
412 +
413 +static int connection_file_release(struct inode *inode, struct file *file)
414 +{
415 +       int cid = cid_from_ino(inode->i_ino);
416 +       struct web100stats *stats;
417 +       
418 +       read_lock_bh(&web100_linkage_lock);
419 +       stats = web100stats_lookup(cid);
420 +       if (stats == NULL) {
421 +               read_unlock_bh(&web100_linkage_lock);
422 +               return -ENOENT;
423 +       }
424 +       read_unlock_bh(&web100_linkage_lock);
425 +       web100_stats_unuse(stats);
426 +       
427 +       return 0;
428 +}
429 +
430 +/**  /proc/web100/<connection>/<binary variable files>  **/
431 +static ssize_t connection_file_rw(int read, struct file *file,
432 +       char *buf, size_t nbytes, loff_t *ppos)
433 +{
434 +       int low_ino = low_from_ino(file->f_dentry->d_inode->i_ino);
435 +       int cid = cid_from_ino(file->f_dentry->d_inode->i_ino);
436 +       struct web100stats *stats;
437 +       struct web100_file *fp;
438 +       struct web100_var *vp;
439 +       int pos;
440 +       int n;
441 +       int err;
442 +       web100_rwfunc_t rwfunc;
443 +       char *page;
444 +       
445 +       /* We're only going to let them read one page at a time.
446 +        * We shouldn't ever read more than a page, anyway, though.
447 +        */
448 +       if (nbytes > PAGE_SIZE)
449 +               nbytes = PAGE_SIZE;
450 +       
451 +       if (!access_ok(read ? VERIFY_WRITE : VERIFY_READ, buf, nbytes))
452 +               return -EFAULT;
453 +       
454 +       if ((page = (char *)__get_free_page(GFP_KERNEL)) == NULL)
455 +               return -ENOMEM;
456 +       
457 +       if (!read) {
458 +               if (copy_from_user(page, buf, nbytes))
459 +                       return -EFAULT;
460 +       }
461 +       
462 +       fp = web100_file_lookup(low_ino);
463 +       if (fp == NULL) {
464 +               printk("Unregistered Web100 file.\n");
465 +               return 0;
466 +       }
467 +       
468 +       read_lock_bh(&web100_linkage_lock);
469 +       stats = web100stats_lookup(cid);
470 +       read_unlock_bh(&web100_linkage_lock);
471 +       if (stats == NULL)
472 +               return -ENOENT;
473 +       
474 +       lock_sock(stats->wc_sk);
475 +       
476 +       /* TODO: seek in constant time, not linear.  -JWH */
477 +       pos = 0;
478 +       n = 0;
479 +       vp = fp->first_var;
480 +       while (vp && nbytes > n) {
481 +               if (pos > *ppos) {
482 +                       err = -ESPIPE;
483 +                       goto err_out;
484 +               }
485 +               if (pos == *ppos) {
486 +                       if (vp->len > nbytes - n)
487 +                               break;
488 +                       
489 +                       if (read)
490 +                               rwfunc = vp->read;
491 +                       else
492 +                               rwfunc = vp->write;
493 +                       if (rwfunc == NULL) {
494 +                               err = -EACCES;
495 +                               goto err_out;
496 +                       }
497 +                       
498 +                       err = rwfunc(page + n, stats, vp);
499 +                       
500 +                       if (err < 0)
501 +                               goto err_out;
502 +                       n += vp->len;
503 +                       *ppos += vp->len;
504 +               }
505 +               pos += vp->len;
506 +               vp = vp->next;
507 +       }
508 +       
509 +       release_sock(stats->wc_sk);
510 +       
511 +       if (read) {
512 +               if (copy_to_user(buf, page, n))
513 +                       return -EFAULT;
514 +       }
515 +       free_page((unsigned long)page);
516 +       
517 +       return n;
518 +
519 +err_out:
520 +       release_sock(stats->wc_sk);
521 +       
522 +       return err;
523 +}
524 +
525 +static ssize_t connection_file_read(struct file *file,
526 +       char *buf, size_t nbytes, loff_t *ppos)
527 +{
528 +       return connection_file_rw(1, file, buf, nbytes, ppos);
529 +}
530 +
531 +static ssize_t connection_file_write(struct file *file,
532 +       const char *buf, size_t nbytes, loff_t *ppos)
533 +{
534 +       return connection_file_rw(0, file, (char *)buf, nbytes, ppos);
535 +}
536 +
537 +static struct file_operations connection_file_fops = {
538 +       open:           connection_file_open,
539 +       release:        connection_file_release,
540 +       read:           connection_file_read,
541 +       write:          connection_file_write
542 +};
543 +
544 +
545 +static size_t v6addr_str(char *dest, short *addr)
546 +{
547 +       int start = -1, end = -1;
548 +       int i, j;
549 +       int pos;
550 +
551 +       /* Find longest subsequence of 0's in addr */
552 +       for (i = 0; i < 8; i++) {
553 +               if (addr[i] == 0) {
554 +                       for (j = i + 1; addr[j] == 0 && j < 8; j++);
555 +                       if (j - i > end - start) {
556 +                               end = j;
557 +                               start = i;
558 +                       }
559 +                       i = j;
560 +               }
561 +       }
562 +       if (end - start == 1)
563 +               start = -1;
564 +
565 +       pos = 0;
566 +       for (i = 0; i < 8; i++) {
567 +               if (i > 0)
568 +                       pos += sprintf(dest + pos, ":");
569 +               if (i == start) {
570 +                       pos += sprintf(dest + pos, ":");
571 +                       i += end - start - 1;
572 +               } else {
573 +                       pos += sprintf(dest + pos, "%hx", ntohs(addr[i]));
574 +               }
575 +       }
576 +
577 +       return pos;
578 +}
579 +
580 +/**  /proc/web100/<connection>/spec_ascii  **/
581 +static ssize_t connection_spec_ascii_read(struct file * file, char * buf,
582 +       size_t nbytes, loff_t *ppos)
583 +{
584 +       __u32 local_addr, remote_addr;
585 +       __u16 local_port, remote_port;
586 +       int cid;
587 +       struct web100stats *stats;
588 +       struct web100directs *vars;
589 +       char tmpbuf[100];
590 +       int len = 0;
591 +       
592 +       if (*ppos != 0)
593 +               return 0;
594 +       
595 +       cid = cid_from_ino(file->f_dentry->d_parent->d_inode->i_ino);
596 +       
597 +       read_lock_bh(&web100_linkage_lock);
598 +       stats = web100stats_lookup(cid);
599 +       read_unlock_bh(&web100_linkage_lock);
600 +       if (stats == NULL)
601 +               return -ENOENT;
602 +       vars = &stats->wc_vars;
603 +       
604 +       if (vars->LocalAddressType == WC_ADDRTYPE_IPV4) {
605 +               /* These values should not change while stats are linked.
606 +                * We don't need to lock the sock. */
607 +               local_addr = ntohl(vars->LocalAddress.v4addr);
608 +               remote_addr = ntohl(vars->RemAddress.v4addr);
609 +               local_port = vars->LocalPort;
610 +               remote_port = vars->RemPort;
611 +               
612 +               len = sprintf(tmpbuf, "%d.%d.%d.%d:%d %d.%d.%d.%d:%d\n",
613 +                       (local_addr >> 24) & 0xff,
614 +                       (local_addr >> 16) & 0xff,
615 +                       (local_addr >> 8) & 0xff,
616 +                       local_addr & 0xff,
617 +                       local_port,
618 +                       (remote_addr >> 24) & 0xff,
619 +                       (remote_addr >> 16) & 0xff,
620 +                       (remote_addr >> 8) & 0xff,
621 +                       remote_addr & 0xff,
622 +                       remote_port);
623 +       } else if (vars->LocalAddressType == WC_ADDRTYPE_IPV6) {
624 +               local_port = vars->LocalPort;
625 +               remote_port = vars->RemPort;
626 +               
627 +               len += v6addr_str(tmpbuf + len, (short *)&vars->LocalAddress.v6addr.addr);
628 +               len += sprintf(tmpbuf + len, ".%d ", local_port);
629 +               len += v6addr_str(tmpbuf + len, (short *)&vars->RemAddress.v6addr.addr);
630 +               len += sprintf(tmpbuf + len, ".%d\n", remote_port);
631 +       } else {
632 +               printk(KERN_ERR "connection_spec_ascii_read: LocalAddressType invalid\n");
633 +               return 0;
634 +       }
635 +       
636 +       len = len > nbytes ? nbytes : len;
637 +       if (copy_to_user(buf, tmpbuf, len))
638 +               return -EFAULT;
639 +       *ppos += len;
640 +       return len;
641 +}
642 +
643 +static struct file_operations connection_spec_ascii_fops = {
644 +       open:           connection_file_open,
645 +       release:        connection_file_release,
646 +       read:           connection_spec_ascii_read
647 +};
648 +
649 +
650 +/**  /proc/web100/<connection>/  **/
651 +static int connection_dir_readdir(struct file *filp,
652 +       void *dirent, filldir_t filldir)
653 +{
654 +       int i;
655 +       struct inode *inode = filp->f_dentry->d_inode;
656 +       struct web100_file *p;
657 +       
658 +       i = filp->f_pos;
659 +       switch (i) {
660 +       case 0:
661 +               if (filldir(dirent, ".", 1, i, inode->i_ino, DT_DIR) < 0)
662 +                       return 0;
663 +               i++;
664 +               filp->f_pos++;
665 +               /* fall through */
666 +       case 1:
667 +               if (filldir(dirent, "..", 2, i, proc_web100_dir->low_ino, DT_DIR) < 0)
668 +                       return 0;
669 +               i++;
670 +               filp->f_pos++;
671 +               /* fall through */
672 +       default:
673 +               i -= 2;
674 +               if (i >= WEB100_FILE_ARR_SIZE)
675 +                       return 1;
676 +               p = &web100_file_arr[i];
677 +               while (p->name) {
678 +                       if (filldir(dirent, p->name, p->len, filp->f_pos,
679 +                                   ino_from_parts(inode->i_ino, p->low_ino),
680 +                                   p->mode >> 12) < 0)
681 +                               return 0;
682 +                       filp->f_pos++;
683 +                       p++;
684 +               }
685 +       }
686 +       
687 +       return 1;
688 +}
689 +
690 +static struct dentry *connection_dir_lookup(struct inode *dir,
691 +       struct dentry *dentry, struct nameidata *nd)
692 +{
693 +       struct inode *inode;
694 +       struct web100_file *p;
695 +       struct web100stats *stats;
696 +       uid_t uid;
697 +       
698 +       inode = NULL;
699 +       for (p = &web100_file_arr[0]; p->name; p++) {
700 +               if (p->len != dentry->d_name.len)
701 +                       continue;
702 +               if (!memcmp(dentry->d_name.name, p->name, p->len))
703 +                       break;
704 +       }
705 +       if (!p->name)
706 +               return ERR_PTR(-ENOENT);
707 +       
708 +       read_lock_bh(&web100_linkage_lock);
709 +       if ((stats = web100stats_lookup(cid_from_ino(dir->i_ino))) == NULL) {
710 +               read_unlock_bh(&web100_linkage_lock);
711 +               printk("connection_dir_lookup: stats == NULL\n");
712 +               return ERR_PTR(-ENOENT);
713 +       }
714 +       uid = sock_i_uid(stats->wc_sk);
715 +       read_unlock_bh(&web100_linkage_lock);
716 +       
717 +       inode = proc_web100_make_inode(dir->i_sb, ino_from_parts(dir->i_ino, p->low_ino));
718 +       if (!inode)
719 +               return ERR_PTR(-ENOMEM);
720 +       inode->i_mode = p->mode ? p->mode : S_IFREG | sysctl_web100_fperms;
721 +       inode->i_uid = uid;
722 +       inode->i_gid = sysctl_web100_gid;
723 +       
724 +       switch (p->low_ino) {
725 +       case PROC_CONN_SPEC_ASCII:
726 +               inode->i_fop = &connection_spec_ascii_fops;
727 +               break;
728 +       case PROC_CONN_SPEC:
729 +       case PROC_CONN_READ:
730 +       case PROC_CONN_TEST:
731 +       case PROC_CONN_TUNE:
732 +               inode->i_fop = &connection_file_fops;
733 +               break;
734 +       default:
735 +               printk("Web100: impossible type (%d)\n", p->low_ino);
736 +               iput(inode);
737 +               return ERR_PTR(-EINVAL);
738 +       }
739 +       
740 +       d_add(dentry, inode);
741 +       return NULL;
742 +}
743 +
744 +static struct inode_operations connection_dir_iops = {
745 +       .lookup         = connection_dir_lookup
746 +};
747 +
748 +static struct file_operations connection_dir_fops = {
749 +       .readdir        = connection_dir_readdir
750 +};
751 +
752 +
753 +/**  /proc/web100/header  **/
754 +static ssize_t header_read(struct file * file, char * buf,
755 +       size_t nbytes, loff_t *ppos)
756 +{
757 +       int len = 0;
758 +       loff_t offset;
759 +       char *tmpbuf;
760 +       struct web100_file *fp;
761 +       struct web100_var *vp;
762 +       int n, tmp;
763 +       int i;
764 +       int ret = 0;
765 +       
766 +       /* We will assume the variable description list will not change
767 +        * after init.  (True at least right now.) Otherwise, we would have
768 +        * to have a lock on it.
769 +        */
770 +       
771 +       if ((tmpbuf = (char *)__get_free_page(GFP_KERNEL)) == NULL)
772 +               return -ENOMEM;
773 +       
774 +       offset = sprintf(tmpbuf, "%s\n", web100_version_string);
775 +       
776 +       for (i = 0; i < WEB100_FILE_ARR_SIZE; i++) {
777 +               int file_offset = 0;
778 +               
779 +               if ((fp = &web100_file_arr[i]) == NULL)
780 +                       continue;
781 +               
782 +               if (fp->first_var == NULL)
783 +                       continue;
784 +               
785 +               offset += sprintf(tmpbuf + offset, "\n/%s\n", fp->name);
786 +               
787 +               vp = fp->first_var;
788 +               while (vp) {
789 +                       if (offset > WEB100MIB_BLOCK_SIZE) {
790 +                               len += offset;
791 +                               if (*ppos < len) {
792 +                                       n = min(offset, min_t(loff_t, nbytes, len - *ppos));
793 +                                       if (copy_to_user(buf, tmpbuf + max_t(loff_t, *ppos - len + offset, 0), n))
794 +                                               return -EFAULT;
795 +                                       buf += n;
796 +                                       if (nbytes == n) {
797 +                                               *ppos += n;
798 +                                               ret = n;
799 +                                               goto out;
800 +                                       }
801 +                               }
802 +                               offset = 0;
803 +                       }
804 +                       
805 +                       offset += sprintf(tmpbuf + offset, "%s %d %d %d\n",
806 +                                         vp->name, file_offset, vp->type, vp->len);
807 +                       file_offset += vp->len;
808 +                       
809 +                       vp = vp->next;
810 +               }
811 +       }
812 +       len += offset;
813 +       if (*ppos < len) {
814 +               n = min(offset, min_t(loff_t, nbytes, len - *ppos));
815 +               if (copy_to_user(buf, tmpbuf + max_t(loff_t, *ppos - len + offset, 0), n))
816 +                       return -EFAULT;
817 +               if (nbytes <= len - *ppos) {
818 +                       *ppos += nbytes;
819 +                       ret = nbytes;
820 +                       goto out;
821 +               } else {
822 +                       tmp = len - *ppos;
823 +                       *ppos = len;
824 +                       ret = tmp;
825 +                       goto out;
826 +               }
827 +       }
828 +       
829 +out:
830 +       free_page((unsigned long)tmpbuf);
831 +       return ret;
832 +}
833 +
834 +static struct file_operations header_file_operations = {
835 +       read:           header_read
836 +};
837 +
838 +
839 +/**  /proc/web100/  **/
840 +#define FIRST_CONNECTION_ENTRY 256
841 +#define NUMBUF_LEN             11
842 +
843 +static int get_connection_list(int pos, int *cids, int max)
844 +{
845 +       struct web100stats *stats;
846 +       int n;
847 +       
848 +       pos -= FIRST_CONNECTION_ENTRY;
849 +       n = 0;
850 +       
851 +       read_lock_bh(&web100_linkage_lock);
852 +       
853 +       stats = web100stats_first;
854 +       while (stats && n < max) {
855 +               if (!stats->wc_dead) {
856 +                       if (pos <= 0)
857 +                               cids[n++] = stats->wc_cid;
858 +                       else
859 +                               pos--;
860 +               }
861 +               
862 +               stats = stats->wc_next;
863 +       }
864 +       
865 +       read_unlock_bh(&web100_linkage_lock);
866 +       
867 +       return n;
868 +}
869 +
870 +static int cid_to_str(int cid, char *buf)
871 +{
872 +       int len, tmp, i;
873 +       
874 +       if (cid == 0) { /* a special case */
875 +               len = 1;
876 +       } else {
877 +               tmp = cid;
878 +               for (len = 0; len < NUMBUF_LEN - 1 && tmp > 0; len++)
879 +                       tmp /= 10;
880 +       }
881 +       
882 +       for (i = 0; i < len; i++) {
883 +               buf[len - i - 1] = '0' + (cid % 10);
884 +               cid /= 10;
885 +       }
886 +       buf[len] = '\0';
887 +       
888 +       return len;
889 +}
890 +
891 +static int web100_dir_readdir(struct file *filp,
892 +       void *dirent, filldir_t filldir)
893 +{
894 +       int err;
895 +       unsigned n, i;
896 +       int *cids;
897 +       int len;
898 +       ino_t ino;
899 +       char name[NUMBUF_LEN];
900 +       int n_conns;
901 +       
902 +       if (filp->f_pos < FIRST_CONNECTION_ENTRY) {
903 +               if ((err = proc_readdir(filp, dirent, filldir)) < 0)
904 +                       return err;
905 +               filp->f_pos = FIRST_CONNECTION_ENTRY;
906 +       }
907 +       n_conns = WEB100_MAX_CONNS * 2;
908 +       do {
909 +               n_conns /= 2;
910 +               cids = kmalloc(n_conns * sizeof (int), GFP_KERNEL);
911 +       } while (cids == NULL && n_conns > 0);
912 +       if (cids == NULL)
913 +               return -ENOMEM;
914 +       n = get_connection_list(filp->f_pos, cids, n_conns);
915 +       
916 +       for (i = 0; i < n; i++) {
917 +               ino = ino_from_cid(cids[i]);
918 +               len = cid_to_str(cids[i], name);
919 +               if (filldir(dirent, name, len, filp->f_pos,
920 +                           ino, DT_DIR) < 0) {
921 +                       break;
922 +               }
923 +               filp->f_pos++;
924 +       }
925 +       
926 +       kfree(cids);
927 +       
928 +       return 0;
929 +}
930 +
931 +static inline struct dentry *web100_dir_dent(void)
932 +{
933 +       struct qstr qstr;
934 +       
935 +       qstr.name = "web100";
936 +       qstr.len = 6;
937 +       qstr.hash = full_name_hash(qstr.name, qstr.len);
938 +       
939 +       return d_lookup(proc_mnt->mnt_sb->s_root, &qstr);
940 +}
941 +
942 +void web100_proc_nlink_update(nlink_t nlink)
943 +{
944 +       struct dentry *dent;
945 +       
946 +       dent = web100_dir_dent();
947 +       if (dent)
948 +               dent->d_inode->i_nlink = nlink;
949 +       dput(dent);
950 +}
951 +
952 +int web100_proc_dointvec_update(ctl_table *ctl, int write,
953 +                               void *buffer, size_t *lenp, loff_t *ppos)
954 +{
955 +       unsigned n, i;
956 +       int *cids;
957 +       int err;
958 +       struct qstr qstr;
959 +       struct dentry *web100_dent, *conn_dent, *dent;
960 +       struct inode *inode;
961 +       struct web100_file *p;
962 +       char name[NUMBUF_LEN];
963 +       
964 +       if ((err = proc_dointvec(ctl, write, buffer, lenp, ppos)) != 0)
965 +               return err;
966 +       
967 +       if ((web100_dent = web100_dir_dent()) == NULL)
968 +               return 0;
969 +       
970 +       if ((cids = kmalloc(WEB100_MAX_CONNS * sizeof (int), GFP_KERNEL)) == NULL)
971 +               return -ENOMEM;
972 +       n = get_connection_list(FIRST_CONNECTION_ENTRY, cids, WEB100_MAX_CONNS);
973 +       for (i = 0; i < n; i++) {
974 +               qstr.len = cid_to_str(cids[i], name);
975 +               qstr.name = name;
976 +               qstr.hash = full_name_hash(qstr.name, qstr.len);
977 +               if ((conn_dent = d_lookup(web100_dent, &qstr)) != NULL) {
978 +                       for (p = &web100_file_arr[0]; p->name; p++) {
979 +                               qstr.name = p->name;
980 +                               qstr.len = p->len;
981 +                               qstr.hash = full_name_hash(qstr.name, qstr.len);
982 +                               if ((dent = d_lookup(conn_dent, &qstr)) != NULL) {
983 +                                       inode = dent->d_inode;
984 +                                       if ((inode->i_mode = p->mode) == 0)
985 +                                               inode->i_mode = S_IFREG | sysctl_web100_fperms;
986 +                                       inode->i_gid = sysctl_web100_gid;
987 +                                       dput(dent);
988 +                               }
989 +                       }
990 +                       dput(conn_dent);
991 +               }
992 +       }
993 +       dput(web100_dent);
994 +       kfree(cids);
995 +       
996 +       return 0;
997 +}
998 +
999 +static int web100_proc_connection_revalidate(struct dentry *dentry, struct nameidata *nd)
1000 +{
1001 +       int ret = 1;
1002 +       
1003 +       if (dentry->d_inode == NULL)
1004 +               return 0;
1005 +       read_lock_bh(&web100_linkage_lock);
1006 +       if (web100stats_lookup(cid_from_ino(dentry->d_inode->i_ino)) == NULL) {
1007 +               ret = 0;
1008 +               d_drop(dentry);
1009 +       }
1010 +       read_unlock_bh(&web100_linkage_lock);
1011 +       
1012 +       return ret;
1013 +}
1014 +
1015 +static struct dentry_operations web100_dir_dentry_operations = {
1016 +       d_revalidate:   web100_proc_connection_revalidate
1017 +};
1018 +
1019 +static struct dentry *web100_dir_lookup(struct inode *dir,
1020 +       struct dentry *dentry, struct nameidata *nd)
1021 +{
1022 +       char *name;
1023 +       int len;
1024 +       int cid;
1025 +       unsigned c;
1026 +       struct inode *inode;
1027 +       unsigned long ino;
1028 +       struct web100stats *stats;
1029 +       
1030 +       if (proc_lookup(dir, dentry, nd) == NULL)
1031 +               return NULL;
1032 +       
1033 +       cid = 0;
1034 +       name = (char *)(dentry->d_name.name);
1035 +       len = dentry->d_name.len;
1036 +       if (len <= 0)   /* I don't think this can happen */
1037 +               return ERR_PTR(-EINVAL);
1038 +       while (len-- > 0) {
1039 +               c = *name - '0';
1040 +               name++;
1041 +               cid *= 10;
1042 +               cid += c;
1043 +               if (c > 9 || c < 0 || (cid == 0 && len != 0) || cid >= WEB100_MAX_CONNS) {
1044 +                       cid = -1;
1045 +                       break;
1046 +               }
1047 +       }
1048 +       if (cid < 0)
1049 +               return ERR_PTR(-ENOENT);
1050 +       
1051 +       read_lock_bh(&web100_linkage_lock);
1052 +       stats = web100stats_lookup(cid);
1053 +       if (stats == NULL || stats->wc_dead) {
1054 +               read_unlock_bh(&web100_linkage_lock);
1055 +               return ERR_PTR(-ENOENT);
1056 +       }
1057 +       read_unlock_bh(&web100_linkage_lock);
1058 +       
1059 +       ino = ino_from_cid(cid);
1060 +       inode = proc_web100_make_inode(dir->i_sb, ino);
1061 +       if (inode == NULL)
1062 +               return ERR_PTR(-ENOMEM);
1063 +       inode->i_nlink = 2;
1064 +       inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
1065 +       inode->i_flags |= S_IMMUTABLE; /* ? */
1066 +       inode->i_op = &connection_dir_iops;
1067 +       inode->i_fop = &connection_dir_fops;
1068 +       
1069 +       dentry->d_op = &web100_dir_dentry_operations;
1070 +       d_add(dentry, inode);
1071 +       return NULL;
1072 +}
1073 +
1074 +static struct file_operations web100_dir_fops = {
1075 +       .readdir        = web100_dir_readdir
1076 +};
1077 +
1078 +static struct inode_operations web100_dir_iops = {
1079 +       .lookup         = web100_dir_lookup
1080 +};
1081 +
1082 +
1083 +/*
1084 + * Read/write handlers
1085 + */
1086 +
1087 +/* A read handler for reading directly from the stats */
1088 +/* read_data is the byte offset into struct web100stats */
1089 +static int read_stats(void *buf, struct web100stats *stats,
1090 +                          struct web100_var *vp)
1091 +{
1092 +       memcpy(buf, (char *)stats + vp->read_data, vp->len);
1093 +       
1094 +       return 0;
1095 +}
1096 +
1097 +/* A write handler for writing directly to the stats */
1098 +/* write_data is a byte offset into struct web100stats */
1099 +static int write_stats(void *buf, struct web100stats *stats,
1100 +                           struct web100_var *vp)
1101 +{
1102 +       memcpy((char *)stats + vp->read_data, buf, vp->len);
1103 +       
1104 +       return 0;
1105 +}
1106 +
1107 +int read_LimCwnd(void *buf, struct web100stats *stats, struct web100_var *vp)
1108 +{
1109 +       struct tcp_sock *tp = tcp_sk(stats->wc_sk);
1110 +       __u32 tmp = (__u32)(tp->snd_cwnd_clamp * tp->mss_cache);
1111 +
1112 +       memcpy(buf, &tmp, 4);
1113 +
1114 +       return 0;
1115 +}
1116 +
1117 +int write_LimCwnd(void *buf, struct web100stats *stats, struct web100_var *vp)
1118 +{
1119 +       struct tcp_sock *tp = tcp_sk(stats->wc_sk);
1120 +       
1121 +       tp->snd_cwnd_clamp = min(*(__u32 *)buf / tp->mss_cache, 65535U);
1122 +       
1123 +       return 0;
1124 +}
1125 +
1126 +int write_LimRwin(void *buf, struct web100stats *stats, struct web100_var *vp)
1127 +{
1128 +       __u32 val = *(__u32 *)buf;
1129 +       struct tcp_sock *tp = tcp_sk(stats->wc_sk);
1130 +       
1131 +       stats->wc_vars.LimRwin = tp->window_clamp =
1132 +               min(val, 65535U << tp->rx_opt.rcv_wscale);
1133 +       
1134 +       return 0;
1135 +}
1136 +
1137 +int write_Sndbuf(void *buf, struct web100stats *stats, struct web100_var *vp)
1138 +{
1139 +       int val;
1140 +       struct sock *sk = stats->wc_sk;
1141 +       
1142 +       memcpy(&val, buf, sizeof (int));
1143 +       
1144 +       sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
1145 +       sk->sk_sndbuf = max_t(int, SOCK_MIN_SNDBUF, min_t(int, sysctl_wmem_max, val));
1146 +       sk->sk_write_space(sk);
1147 +
1148 +       return 0;
1149 +}
1150 +
1151 +int write_Rcvbuf(void *buf, struct web100stats *stats, struct web100_var *vp)
1152 +{
1153 +       int val;
1154 +       struct sock *sk = stats->wc_sk;
1155 +       
1156 +       memcpy(&val, buf, sizeof (int));
1157 +       
1158 +       sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
1159 +       sk->sk_rcvbuf = max_t(int, SOCK_MIN_RCVBUF, min_t(int, sysctl_rmem_max, val));
1160 +       
1161 +       return 0;
1162 +}
1163 +
1164 +int write_State(void *buf, struct web100stats *stats, struct web100_var *vp)
1165 +{
1166 +       int val;
1167 +       struct sock *sk = stats->wc_sk;
1168 +       
1169 +       memcpy(&val, buf, sizeof (int));
1170 +       if (val != 12) /* deleteTCB, RFC 2012 */
1171 +               return -EINVAL;
1172 +       sk->sk_prot->disconnect(sk, 0);
1173 +       
1174 +       return 0;
1175 +}
1176 +
1177 +extern __u32 sysctl_wmem_default;
1178 +extern __u32 sysctl_rmem_default;
1179 +
1180 +/* A read handler for reading directly from the sk */
1181 +/* read_data is a byte offset into the sk */
1182 +static int read_sk(void *buf, struct web100stats *stats,
1183 +                         struct web100_var *vp)
1184 +{
1185 +       /* Fill data with 0's if the connection is gone. */
1186 +       if (stats->wc_sk == NULL)
1187 +               memset(buf, 0, vp->len);
1188 +       else
1189 +               memcpy(buf, (char *)(stats->wc_sk) + vp->read_data, vp->len);
1190 +       
1191 +       return 0;
1192 +}
1193 +
1194 +static int write_sk(void *buf, struct web100stats *stats, struct web100_var *vp)
1195 +{
1196 +       if (stats->wc_sk == NULL)
1197 +               return -EIO;
1198 +       else
1199 +               memcpy((char *)(stats->wc_sk) + vp->write_data, buf, vp->len);
1200 +       
1201 +       return 0;
1202 +}
1203 +
1204 +__u64 web100_mono_time()
1205 +{
1206 +#if 1
1207 +       struct timespec now;
1208 +       
1209 +       do_posix_clock_monotonic_gettime(&now);
1210 +       
1211 +       return 1000000ULL * (__u64)now.tv_sec + now.tv_nsec / 1000;
1212 +#else
1213 +       struct timeval now;
1214 +       static struct timeval before;
1215 +
1216 +       do_gettimeofday(&now);
1217 +
1218 +       /* assure monotonic, no matter what */
1219 +       if ((now.tv_sec > before.tv_sec) ||
1220 +           ((now.tv_sec == before.tv_sec) && (now.tv_usec > before.tv_usec))) {
1221 +               before = now;
1222 +       } else {
1223 +               before.tv_usec++;
1224 +               if (before.tv_usec >= 1000000) {
1225 +                       before.tv_usec -= 1000000;
1226 +                       before.tv_sec++;
1227 +               }
1228 +       }
1229 +       
1230 +       return (1000000ULL * (__u64)before.tv_sec + before.tv_usec);
1231 +#endif
1232 +}
1233 +
1234 +/* A read handler to get the low part of the current time in usec */
1235 +static int read_now(void *buf, struct web100stats *stats,
1236 +                         struct web100_var *vp)
1237 +{
1238 +       __u64 val;
1239 +
1240 +       val = web100_mono_time();
1241 +       val -= stats->wc_start_monotime;
1242 +       memcpy(buf, (char *)&val, vp->len);
1243 +
1244 +       return 0;
1245 +}
1246 +
1247 +#ifdef CONFIG_WEB100_NET100
1248 +static int write_mss(void *buf, struct web100stats *stats, struct web100_var *vp)
1249 +{
1250 +       struct sock *sk = stats->wc_sk;
1251 +       struct tcp_sock *tp;
1252 +       __u32 val = *(__u32 *)buf;
1253 +       
1254 +       if (sk == NULL)
1255 +               return -EIO;
1256 +       tp = tcp_sk(sk);
1257 +       
1258 +       if (val > tp->mss_cache)
1259 +               return -EINVAL;
1260 +       if (val < 1)
1261 +               return -EINVAL;
1262 +       
1263 +       tp->mss_cache = val;
1264 +       web100_update_mss(tp);
1265 +       
1266 +       return 0;
1267 +}
1268 +
1269 +static int write_CwndAdjust(void *buf, struct web100stats *stats, struct web100_var *vp)
1270 +{
1271 +       struct sock *sk = stats->wc_sk;
1272 +       struct tcp_sock *tp;
1273 +       
1274 +       if (sk == NULL)
1275 +               return -EIO;
1276 +       tp = tcp_sk(sk);
1277 +       
1278 +       memcpy(&stats->wc_vars.WAD_CwndAdjust, buf, 4);
1279 +       tp->snd_ssthresh = min_t(__u32, tp->snd_ssthresh,
1280 +                                tp->snd_cwnd + stats->wc_vars.WAD_CwndAdjust);
1281 +       
1282 +       return 0;
1283 +}
1284 +#endif
1285 +
1286 +#if 0
1287 +static int rw_noop(void *buf, struct web100stats *stats, struct web100_var *vp)
1288 +{
1289 +       return 0;
1290 +}
1291 +#endif
1292 +
1293 +/*
1294 + * init
1295 + */
1296 +
1297 +void __init proc_web100_init(void)
1298 +{
1299 +       /* Set up the proc files. */
1300 +       proc_web100_dir = proc_mkdir("web100", NULL);
1301 +       proc_web100_dir->proc_iops = &web100_dir_iops;
1302 +       proc_web100_dir->proc_fops = &web100_dir_fops;
1303 +       
1304 +       proc_web100_header = create_proc_entry("header", S_IFREG | S_IRUGO,
1305 +                                              proc_web100_dir);
1306 +       proc_web100_header->proc_fops = &header_file_operations;
1307 +       
1308 +       /* Set up the contents of the proc files. */
1309 +#define OFFSET_IN(type,var)    ((unsigned long)(&(((type *)NULL)->var)))
1310 +#define OFFSET_ST(field) ((unsigned long)(&(((struct web100stats *)NULL)->wc_vars.field)))
1311 +#define OFFSET_SK(field) ((unsigned long)(&(((struct sock *)NULL)->field)))
1312 +#define OFFSET_TP(field) ((unsigned long)(&(tcp_sk(NULL)->field)))
1313 +
1314 +#define ADD_RO_STATSVAR(ino,name,type) \
1315 +add_var(web100_file_lookup(ino), #name, type, \
1316 +       read_stats, OFFSET_ST(name), NULL, 0)
1317 +
1318 +#define ADD_RO_STATSRENAME(ino,name,type,var)  \
1319 +add_var(web100_file_lookup(ino), name, type, \
1320 +       read_stats, OFFSET_ST(var), NULL, 0)
1321 +
1322 +#define ADD_RO_STATSVAR_DEP(ino,name,type)     \
1323 +add_var(web100_file_lookup(ino), "_" #name, type, \
1324 +       read_stats, OFFSET_ST(name), NULL, 0)
1325 +
1326 +#define ADD_WO_STATSVAR(ino,name,type) \
1327 +add_var(web100_file_lookup(ino), #name, type, NULL, 0, \
1328 +       write_stats, OFFSET_ST(name))
1329 +
1330 +#define ADD_WO_STATSVAR_DEP(ino,name,type)     \
1331 +add_var(web100_file_lookup(ino), "_" #name, type, NULL, 0, \
1332 +       write_stats, OFFSET_ST(name))
1333 +
1334 +#define ADD_RW_STATSVAR(ino,name,type) \
1335 +add_var(web100_file_lookup(ino), #name, type, \
1336 +       read_stats, OFFSET_ST(name), \
1337 +       write_stats, OFFSET_ST(name))
1338 +
1339 +#define ADD_RW_STATSVAR_DEP(ino,name,type)     \
1340 +add_var(web100_file_lookup(ino), "_" #name, type, \
1341 +       read_stats, OFFSET_ST(name), \
1342 +       write_stats, OFFSET_ST(name))
1343 +
1344 +#define ADD_RO_SKVAR(ino,name,type,var) \
1345 +add_var(web100_file_lookup(ino), #name, type, \
1346 +       read_sk, OFFSET_SK(var), NULL, 0)
1347 +
1348 +#define ADD_RW_SKVAR(ino,name,type,var) \
1349 +add_var(web100_file_lookup(ino), #name, type, \
1350 +       read_sk, OFFSET_SK(var), write_sk, OFFSET_SK(var))
1351 +
1352 +#define ADD_RO_TPVAR(ino,name,type,var) \
1353 +add_var(web100_file_lookup(ino), #name, type, \
1354 +       read_sk, OFFSET_TP(var), write_sk, OFFSET_TP(var))
1355 +
1356 +#define ADD_NOOP(ino,name,type) \
1357 +add_var(web100_file_lookup(ino), #name, type, \
1358 +       rw_noop, 0, rw_noop, 0)
1359 +
1360 +       /* spec */
1361 +       ADD_RO_STATSVAR(PROC_CONN_SPEC, LocalAddressType, WEB100_TYPE_INTEGER);
1362 +       ADD_RO_STATSVAR(PROC_CONN_SPEC, LocalAddress, WEB100_TYPE_INET_ADDRESS);
1363 +       ADD_RO_STATSVAR(PROC_CONN_SPEC, LocalPort, WEB100_TYPE_INET_PORT_NUMBER);
1364 +       ADD_RO_STATSVAR(PROC_CONN_SPEC, RemAddress, WEB100_TYPE_INET_ADDRESS);
1365 +       ADD_RO_STATSVAR(PROC_CONN_SPEC, RemPort, WEB100_TYPE_INET_PORT_NUMBER);
1366 +       ADD_RO_STATSRENAME(PROC_CONN_SPEC, "_RemoteAddress", WEB100_TYPE_INET_ADDRESS, RemAddress);
1367 +       ADD_RO_STATSRENAME(PROC_CONN_SPEC, "_RemotePort", WEB100_TYPE_INET_PORT_NUMBER, RemPort);
1368 +       
1369 +       /* read */
1370 +       /* STATE */
1371 +       ADD_RO_STATSVAR(PROC_CONN_READ, State, WEB100_TYPE_INTEGER);
1372 +       ADD_RO_STATSVAR(PROC_CONN_READ, SACKEnabled, WEB100_TYPE_INTEGER);
1373 +       ADD_RO_STATSVAR(PROC_CONN_READ, TimestampsEnabled, WEB100_TYPE_INTEGER);
1374 +       ADD_RO_STATSVAR(PROC_CONN_READ, NagleEnabled, WEB100_TYPE_INTEGER);
1375 +       ADD_RO_STATSVAR(PROC_CONN_READ, ECNEnabled, WEB100_TYPE_INTEGER);
1376 +       ADD_RO_STATSVAR(PROC_CONN_READ, SndWinScale, WEB100_TYPE_INTEGER);
1377 +       ADD_RO_STATSVAR(PROC_CONN_READ, RcvWinScale, WEB100_TYPE_INTEGER);
1378 +       
1379 +       /* SYN OPTIONS */
1380 +       ADD_RO_STATSVAR(PROC_CONN_READ, ActiveOpen, WEB100_TYPE_INTEGER);
1381 +       ADD_RO_STATSVAR(PROC_CONN_READ, MSSRcvd, WEB100_TYPE_GAUGE32);
1382 +       ADD_RO_STATSVAR(PROC_CONN_READ, WinScaleRcvd, WEB100_TYPE_INTEGER);
1383 +       ADD_RO_STATSVAR(PROC_CONN_READ, WinScaleSent, WEB100_TYPE_INTEGER);
1384 +       
1385 +       /* DATA */
1386 +       ADD_RO_STATSVAR(PROC_CONN_READ, PktsOut, WEB100_TYPE_COUNTER32);
1387 +       ADD_RO_STATSVAR(PROC_CONN_READ, DataPktsOut, WEB100_TYPE_COUNTER32);
1388 +       ADD_RO_STATSVAR_DEP(PROC_CONN_READ, AckPktsOut, WEB100_TYPE_COUNTER32);
1389 +       ADD_RO_STATSVAR(PROC_CONN_READ, DataBytesOut, WEB100_TYPE_COUNTER64);
1390 +       ADD_RO_STATSVAR(PROC_CONN_READ, PktsIn, WEB100_TYPE_COUNTER32);
1391 +       ADD_RO_STATSVAR(PROC_CONN_READ, DataPktsIn, WEB100_TYPE_COUNTER32);
1392 +       ADD_RO_STATSVAR_DEP(PROC_CONN_READ, AckPktsIn, WEB100_TYPE_COUNTER32);
1393 +       ADD_RO_STATSVAR(PROC_CONN_READ, DataBytesIn, WEB100_TYPE_COUNTER64);
1394 +       ADD_RO_STATSVAR(PROC_CONN_READ, SndUna, WEB100_TYPE_COUNTER32);
1395 +       ADD_RO_STATSVAR(PROC_CONN_READ, SndNxt, WEB100_TYPE_UNSIGNED32);
1396 +       ADD_RO_STATSVAR(PROC_CONN_READ, SndMax, WEB100_TYPE_COUNTER32);
1397 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "_snd_una", WEB100_TYPE_COUNTER32, SndUna);
1398 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "_snd_nxt", WEB100_TYPE_COUNTER32, SndNxt);
1399 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "_snd_max", WEB100_TYPE_COUNTER32, SndMax);
1400 +       ADD_RO_STATSVAR(PROC_CONN_READ, ThruBytesAcked, WEB100_TYPE_COUNTER64);
1401 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "_ThruBytesSent", WEB100_TYPE_COUNTER64, ThruBytesAcked);
1402 +       ADD_RO_STATSVAR(PROC_CONN_READ, SndISS, WEB100_TYPE_COUNTER32);
1403 +       ADD_RO_STATSVAR_DEP(PROC_CONN_READ, SendWraps, WEB100_TYPE_COUNTER32);
1404 +       ADD_RO_STATSVAR(PROC_CONN_READ, RcvNxt, WEB100_TYPE_COUNTER32);
1405 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "_rcv_nxt", WEB100_TYPE_COUNTER32, RcvNxt);
1406 +       ADD_RO_STATSVAR(PROC_CONN_READ, ThruBytesReceived, WEB100_TYPE_COUNTER64);
1407 +       ADD_RO_STATSVAR(PROC_CONN_READ, RecvISS, WEB100_TYPE_COUNTER32);
1408 +       ADD_RO_STATSVAR_DEP(PROC_CONN_READ, RecvWraps, WEB100_TYPE_COUNTER32);
1409 +       ADD_RO_STATSVAR_DEP(PROC_CONN_READ, StartTime, WEB100_TYPE_INTEGER32);
1410 +       ADD_RO_STATSVAR(PROC_CONN_READ, StartTimeSec, WEB100_TYPE_INTEGER32);
1411 +       ADD_RO_STATSVAR(PROC_CONN_READ, StartTimeUsec, WEB100_TYPE_INTEGER32);
1412 +       add_var(web100_file_lookup(PROC_CONN_READ), "Duration", WEB100_TYPE_COUNTER64, read_now, 0, NULL, 0);
1413 +       add_var(web100_file_lookup(PROC_CONN_READ), "_CurrTime", WEB100_TYPE_COUNTER64, read_now, 0, NULL, 0);
1414 +
1415 +       /* SENDER CONGESTION */
1416 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "SndLimTransSender", WEB100_TYPE_COUNTER32, SndLimTrans[WC_SNDLIM_SENDER]);
1417 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "SndLimBytesSender", WEB100_TYPE_COUNTER64, SndLimBytes[WC_SNDLIM_SENDER]);
1418 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "SndLimTimeSender", WEB100_TYPE_COUNTER32, SndLimTime[WC_SNDLIM_SENDER]);
1419 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "SndLimTransCwnd", WEB100_TYPE_COUNTER32, SndLimTrans[WC_SNDLIM_CWND]);
1420 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "SndLimBytesCwnd", WEB100_TYPE_COUNTER64, SndLimBytes[WC_SNDLIM_CWND]);
1421 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "SndLimTimeCwnd", WEB100_TYPE_COUNTER32, SndLimTime[WC_SNDLIM_CWND]);
1422 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "SndLimTransRwin", WEB100_TYPE_COUNTER32, SndLimTrans[WC_SNDLIM_RWIN]);
1423 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "SndLimBytesRwin", WEB100_TYPE_COUNTER64, SndLimBytes[WC_SNDLIM_RWIN]);
1424 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "SndLimTimeRwin", WEB100_TYPE_COUNTER32, SndLimTime[WC_SNDLIM_RWIN]);
1425 +       ADD_RO_STATSVAR(PROC_CONN_READ, SlowStart, WEB100_TYPE_COUNTER32);
1426 +       ADD_RO_STATSVAR(PROC_CONN_READ, CongAvoid, WEB100_TYPE_COUNTER32);
1427 +       ADD_RO_STATSVAR(PROC_CONN_READ, CongestionSignals, WEB100_TYPE_COUNTER32);
1428 +       ADD_RO_STATSVAR(PROC_CONN_READ, OtherReductions, WEB100_TYPE_COUNTER32);
1429 +       ADD_RO_STATSVAR(PROC_CONN_READ, X_OtherReductionsCV, WEB100_TYPE_COUNTER32);
1430 +       ADD_RO_STATSVAR(PROC_CONN_READ, X_OtherReductionsCM, WEB100_TYPE_COUNTER32);
1431 +       ADD_RO_STATSVAR(PROC_CONN_READ, CongestionOverCount, WEB100_TYPE_COUNTER32);
1432 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "_Recoveries", WEB100_TYPE_COUNTER32, CongestionSignals);
1433 +       ADD_RO_STATSVAR(PROC_CONN_READ, CurCwnd, WEB100_TYPE_GAUGE32);
1434 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "_CurrentCwnd", WEB100_TYPE_GAUGE32, CurCwnd);
1435 +       ADD_RO_STATSVAR(PROC_CONN_READ, MaxCwnd, WEB100_TYPE_GAUGE32);
1436 +       ADD_RO_STATSVAR(PROC_CONN_READ, CurSsthresh, WEB100_TYPE_GAUGE32);
1437 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "_CurrentSsthresh", WEB100_TYPE_GAUGE32, CurSsthresh);
1438 +       add_var(web100_file_lookup(PROC_CONN_READ), "LimCwnd", WEB100_TYPE_GAUGE32, read_LimCwnd, 0, NULL, 0);
1439 +       ADD_RO_STATSVAR(PROC_CONN_READ, MaxSsthresh, WEB100_TYPE_GAUGE32);
1440 +       ADD_RO_STATSVAR(PROC_CONN_READ, MinSsthresh, WEB100_TYPE_GAUGE32);
1441 +
1442 +       /* SENDER PATH MODEL */
1443 +       ADD_RO_STATSVAR(PROC_CONN_READ, FastRetran, WEB100_TYPE_COUNTER32);
1444 +       ADD_RO_STATSVAR(PROC_CONN_READ, Timeouts, WEB100_TYPE_COUNTER32);
1445 +       ADD_RO_STATSVAR(PROC_CONN_READ, SubsequentTimeouts, WEB100_TYPE_COUNTER32);
1446 +       ADD_RO_STATSVAR(PROC_CONN_READ, CurTimeoutCount, WEB100_TYPE_GAUGE32);
1447 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "_CurrTimeoutCount", WEB100_TYPE_GAUGE32, CurTimeoutCount);
1448 +       ADD_RO_STATSVAR(PROC_CONN_READ, AbruptTimeouts, WEB100_TYPE_COUNTER32);
1449 +       ADD_RO_STATSVAR(PROC_CONN_READ, PktsRetrans, WEB100_TYPE_COUNTER32);
1450 +       ADD_RO_STATSVAR(PROC_CONN_READ, BytesRetrans, WEB100_TYPE_COUNTER32);
1451 +       ADD_RO_STATSVAR(PROC_CONN_READ, DupAcksIn, WEB100_TYPE_COUNTER32);
1452 +       ADD_RO_STATSVAR(PROC_CONN_READ, SACKsRcvd, WEB100_TYPE_COUNTER32);
1453 +       ADD_RO_STATSVAR(PROC_CONN_READ, SACKBlocksRcvd, WEB100_TYPE_COUNTER32);
1454 +       ADD_RO_STATSVAR(PROC_CONN_READ, PreCongSumCwnd, WEB100_TYPE_COUNTER32);
1455 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "_SumCwndAtCong", WEB100_TYPE_COUNTER32, PreCongSumCwnd);
1456 +       ADD_RO_STATSVAR(PROC_CONN_READ, PreCongSumRTT, WEB100_TYPE_COUNTER32);
1457 +       ADD_RO_STATSVAR_DEP(PROC_CONN_READ, PreCongCountRTT, WEB100_TYPE_COUNTER32);
1458 +       ADD_RO_STATSVAR(PROC_CONN_READ, PostCongSumRTT, WEB100_TYPE_COUNTER32);
1459 +       ADD_RO_STATSVAR(PROC_CONN_READ, PostCongCountRTT, WEB100_TYPE_COUNTER32);
1460 +       ADD_RO_STATSVAR(PROC_CONN_READ, ECERcvd, WEB100_TYPE_COUNTER32);
1461 +       ADD_RO_STATSVAR(PROC_CONN_READ, SendStall, WEB100_TYPE_COUNTER32);
1462 +       ADD_RO_STATSVAR(PROC_CONN_READ, QuenchRcvd, WEB100_TYPE_COUNTER32);
1463 +       ADD_RO_STATSVAR(PROC_CONN_READ, RetranThresh, WEB100_TYPE_GAUGE32);
1464 +       ADD_RO_STATSVAR(PROC_CONN_READ, NonRecovDA, WEB100_TYPE_COUNTER32);
1465 +       ADD_RO_STATSVAR(PROC_CONN_READ, AckAfterFR, WEB100_TYPE_COUNTER32);
1466 +       ADD_RO_STATSVAR(PROC_CONN_READ, DSACKDups, WEB100_TYPE_COUNTER32);
1467 +       ADD_RO_STATSVAR(PROC_CONN_READ, SampleRTT, WEB100_TYPE_GAUGE32);
1468 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "_SampledRTT", WEB100_TYPE_GAUGE32, SampleRTT);
1469 +       ADD_RO_STATSVAR(PROC_CONN_READ, SmoothedRTT, WEB100_TYPE_GAUGE32);
1470 +       ADD_RO_STATSVAR(PROC_CONN_READ, RTTVar, WEB100_TYPE_GAUGE32);
1471 +       ADD_RO_STATSVAR(PROC_CONN_READ, MaxRTT, WEB100_TYPE_GAUGE32);
1472 +       ADD_RO_STATSVAR(PROC_CONN_READ, MinRTT, WEB100_TYPE_GAUGE32);
1473 +       ADD_RO_STATSVAR(PROC_CONN_READ, SumRTT, WEB100_TYPE_COUNTER64);
1474 +       ADD_RO_STATSVAR(PROC_CONN_READ, CountRTT, WEB100_TYPE_COUNTER32);
1475 +       ADD_RO_STATSVAR(PROC_CONN_READ, CurRTO, WEB100_TYPE_GAUGE32);
1476 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "_CurrentRTO", WEB100_TYPE_GAUGE32, CurRTO);
1477 +       ADD_RO_STATSVAR(PROC_CONN_READ, MaxRTO, WEB100_TYPE_GAUGE32);
1478 +       ADD_RO_STATSVAR(PROC_CONN_READ, MinRTO, WEB100_TYPE_GAUGE32);
1479 +       ADD_RO_STATSVAR(PROC_CONN_READ, CurMSS, WEB100_TYPE_GAUGE32);
1480 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "_CurrentMSS", WEB100_TYPE_GAUGE32, CurMSS);
1481 +       ADD_RO_STATSVAR(PROC_CONN_READ, MaxMSS, WEB100_TYPE_GAUGE32);
1482 +       ADD_RO_STATSVAR(PROC_CONN_READ, MinMSS, WEB100_TYPE_GAUGE32);
1483 +
1484 +       /* SENDER BUFFER */
1485 +#define PROC_CONN_XTEST PROC_CONN_READ /* lazy */
1486 +       ADD_RO_SKVAR(PROC_CONN_READ, _Sndbuf, WEB100_TYPE_GAUGE32, sk_sndbuf);
1487 +       ADD_RO_SKVAR(PROC_CONN_READ, X_Sndbuf, WEB100_TYPE_GAUGE32, sk_sndbuf);
1488 +       ADD_RO_SKVAR(PROC_CONN_READ, X_Rcvbuf, WEB100_TYPE_GAUGE32, sk_rcvbuf);
1489 +       ADD_RO_STATSVAR(PROC_CONN_READ, CurRetxQueue, WEB100_TYPE_GAUGE32);
1490 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "_CurRetranQueue", WEB100_TYPE_GAUGE32, CurRetxQueue);
1491 +       ADD_RO_STATSVAR(PROC_CONN_READ, MaxRetxQueue, WEB100_TYPE_GAUGE32);
1492 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "_MaxRetranQueue", WEB100_TYPE_GAUGE32, MaxRetxQueue);
1493 +       ADD_RO_STATSVAR(PROC_CONN_READ, CurAppWQueue, WEB100_TYPE_GAUGE32);
1494 +       ADD_RO_STATSVAR(PROC_CONN_READ, MaxAppWQueue, WEB100_TYPE_GAUGE32);
1495 +       
1496 +       /* SENDER BUFFER TUNING - See below */
1497 +
1498 +       /* LOCAL RECEIVER */
1499 +       ADD_RO_STATSVAR(PROC_CONN_READ, CurRwinSent, WEB100_TYPE_GAUGE32);
1500 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "_CurrentRwinSent", WEB100_TYPE_GAUGE32, CurRwinSent);
1501 +       ADD_RO_STATSVAR(PROC_CONN_READ, MaxRwinSent, WEB100_TYPE_GAUGE32);
1502 +       ADD_RO_STATSVAR(PROC_CONN_READ, MinRwinSent, WEB100_TYPE_GAUGE32);
1503 +       ADD_RO_STATSVAR(PROC_CONN_READ, LimRwin, WEB100_TYPE_GAUGE32);
1504 +       ADD_RO_STATSVAR(PROC_CONN_READ, DupAcksOut, WEB100_TYPE_COUNTER32);
1505 +       ADD_RO_SKVAR(PROC_CONN_READ, _Rcvbuf, WEB100_TYPE_GAUGE32, sk_rcvbuf);
1506 +       ADD_RO_STATSVAR(PROC_CONN_READ, CurReasmQueue, WEB100_TYPE_GAUGE32);
1507 +       ADD_RO_STATSVAR(PROC_CONN_READ, MaxReasmQueue, WEB100_TYPE_GAUGE32);
1508 +       ADD_RO_STATSVAR(PROC_CONN_READ, CurAppRQueue, WEB100_TYPE_GAUGE32);
1509 +       ADD_RO_STATSVAR(PROC_CONN_READ, MaxAppRQueue, WEB100_TYPE_GAUGE32);
1510 +       ADD_RO_TPVAR(PROC_CONN_XTEST, X_rcv_ssthresh, WEB100_TYPE_GAUGE32, rcv_ssthresh);
1511 +       ADD_RO_TPVAR(PROC_CONN_XTEST, X_wnd_clamp, WEB100_TYPE_GAUGE32, window_clamp);
1512 +       ADD_RO_STATSVAR(PROC_CONN_XTEST, X_dbg1, WEB100_TYPE_GAUGE32);
1513 +       ADD_RO_STATSVAR(PROC_CONN_XTEST, X_dbg2, WEB100_TYPE_GAUGE32);
1514 +       ADD_RO_STATSVAR(PROC_CONN_XTEST, X_dbg3, WEB100_TYPE_GAUGE32);
1515 +       ADD_RO_STATSVAR(PROC_CONN_XTEST, X_dbg4, WEB100_TYPE_GAUGE32);
1516 +
1517 +       /* OBSERVED RECEIVER */
1518 +       ADD_RO_STATSVAR(PROC_CONN_READ, CurRwinRcvd, WEB100_TYPE_GAUGE32);
1519 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "_CurrentRwinRcvd", WEB100_TYPE_GAUGE32, CurRwinRcvd);
1520 +       ADD_RO_STATSVAR(PROC_CONN_READ, MaxRwinRcvd, WEB100_TYPE_GAUGE32);
1521 +       ADD_RO_STATSVAR(PROC_CONN_READ, MinRwinRcvd, WEB100_TYPE_GAUGE32);
1522 +
1523 +       /* CONNECTION ID */
1524 +       ADD_RO_STATSVAR(PROC_CONN_READ, LocalAddressType, WEB100_TYPE_INTEGER);
1525 +       ADD_RO_STATSVAR(PROC_CONN_READ, LocalAddress, WEB100_TYPE_INET_ADDRESS);
1526 +       ADD_RO_STATSVAR(PROC_CONN_READ, LocalPort, WEB100_TYPE_INET_PORT_NUMBER);
1527 +       ADD_RO_STATSVAR(PROC_CONN_READ, RemAddress, WEB100_TYPE_INET_ADDRESS);
1528 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "_RemoteAddress", WEB100_TYPE_INET_ADDRESS, RemAddress);
1529 +       ADD_RO_STATSVAR(PROC_CONN_READ, RemPort, WEB100_TYPE_INET_PORT_NUMBER);
1530 +       ADD_RO_STATSRENAME(PROC_CONN_READ, "_RemotePort", WEB100_TYPE_INET_PORT_NUMBER, RemPort);
1531 +       
1532 +       ADD_RO_STATSVAR(PROC_CONN_READ, X_RcvRTT, WEB100_TYPE_GAUGE32);
1533 +       
1534 +       /* tune */
1535 +       add_var(web100_file_lookup(PROC_CONN_TUNE), "LimCwnd",
1536 +               WEB100_TYPE_GAUGE32, read_LimCwnd, 0,
1537 +               write_LimCwnd, 0);
1538 +       add_var(web100_file_lookup(PROC_CONN_TUNE), "LimRwin",
1539 +               WEB100_TYPE_GAUGE32, read_stats, OFFSET_ST(LimRwin),
1540 +               write_LimRwin, 0);
1541 +       add_var(web100_file_lookup(PROC_CONN_TUNE), "X_Sndbuf",
1542 +               WEB100_TYPE_GAUGE32, read_sk, OFFSET_SK(sk_sndbuf),
1543 +               write_Sndbuf, 0);
1544 +       add_var(web100_file_lookup(PROC_CONN_TUNE), "X_Rcvbuf",
1545 +               WEB100_TYPE_GAUGE32, read_sk, OFFSET_SK(sk_rcvbuf),
1546 +               write_Rcvbuf, 0);
1547 +       add_var(web100_file_lookup(PROC_CONN_TUNE), "State",
1548 +               WEB100_TYPE_INTEGER, read_stats, OFFSET_ST(State),
1549 +               write_State, 0);
1550 +#ifdef CONFIG_WEB100_NET100
1551 +       add_var(web100_file_lookup(PROC_CONN_TUNE), "CurMSS",
1552 +               WEB100_TYPE_GAUGE32, read_stats, OFFSET_ST(CurMSS),
1553 +               write_mss, 0);
1554 +#endif
1555 +
1556 +#ifdef CONFIG_WEB100_NET100
1557 +       ADD_RW_STATSVAR(PROC_CONN_TUNE, WAD_IFQ, WEB100_TYPE_GAUGE32);
1558 +       ADD_RW_STATSVAR(PROC_CONN_TUNE, WAD_MaxBurst, WEB100_TYPE_GAUGE32);
1559 +       ADD_RW_STATSVAR(PROC_CONN_TUNE, WAD_MaxSsthresh, WEB100_TYPE_GAUGE32);
1560 +       ADD_RW_STATSVAR(PROC_CONN_TUNE, WAD_NoAI, WEB100_TYPE_INTEGER);
1561 +       add_var(web100_file_lookup(PROC_CONN_TUNE), "WAD_CwndAdjust",
1562 +               WEB100_TYPE_INTEGER32, read_stats, OFFSET_ST(WAD_CwndAdjust),
1563 +               write_CwndAdjust, 0);
1564 +#endif
1565 +}
1566 diff -Naur linux-2.6.32-27.planetlab.i686.orig/include/linux/netlink.h linux-2.6.32-27.planetlab.i686/include/linux/netlink.h
1567 --- linux-2.6.32-27.planetlab.i686.orig/include/linux/netlink.h 2011-11-16 16:51:07.258471024 -0500
1568 +++ linux-2.6.32-27.planetlab.i686/include/linux/netlink.h      2011-11-16 16:51:05.954471154 -0500
1569 @@ -24,6 +24,7 @@
1570  /* leave room for NETLINK_DM (DM Events) */
1571  #define NETLINK_SCSITRANSPORT  18      /* SCSI Transports */
1572  #define NETLINK_ECRYPTFS       19
1573 +#define NETLINK_WEB100         29
1574  
1575  #define MAX_LINKS 32           
1576  
1577 diff -Naur linux-2.6.32-27.planetlab.i686.orig/include/linux/proc_fs.h linux-2.6.32-27.planetlab.i686/include/linux/proc_fs.h
1578 --- linux-2.6.32-27.planetlab.i686.orig/include/linux/proc_fs.h 2011-11-16 16:51:07.251471052 -0500
1579 +++ linux-2.6.32-27.planetlab.i686/include/linux/proc_fs.h      2011-11-16 16:51:05.947470992 -0500
1580 @@ -105,6 +105,10 @@
1581  
1582  extern void proc_root_init(void);
1583  
1584 +#ifdef CONFIG_WEB100_STATS
1585 +extern void proc_web100_init(void);
1586 +#endif
1587 +
1588  void proc_flush_task(struct task_struct *task);
1589  
1590  extern struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
1591 diff -Naur linux-2.6.32-27.planetlab.i686.orig/include/linux/sysctl.h linux-2.6.32-27.planetlab.i686/include/linux/sysctl.h
1592 --- linux-2.6.32-27.planetlab.i686.orig/include/linux/sysctl.h  2011-11-16 16:51:07.289470904 -0500
1593 +++ linux-2.6.32-27.planetlab.i686/include/linux/sysctl.h       2011-11-16 16:51:05.985470940 -0500
1594 @@ -1007,6 +1007,10 @@
1595                                       void __user *, size_t *, loff_t *);
1596  extern int proc_do_large_bitmap(struct ctl_table *, int,
1597                                 void __user *, size_t *, loff_t *);
1598 +#ifdef CONFIG_WEB100_STATS
1599 +extern int web100_proc_dointvec_update(struct ctl_table *, int,
1600 +                                       void __user *, size_t *, loff_t *);
1601 +#endif
1602  
1603  extern int do_sysctl (int __user *name, int nlen,
1604                       void __user *oldval, size_t __user *oldlenp,
1605 diff -Naur linux-2.6.32-27.planetlab.i686.orig/include/linux/tcp.h linux-2.6.32-27.planetlab.i686/include/linux/tcp.h
1606 --- linux-2.6.32-27.planetlab.i686.orig/include/linux/tcp.h     2011-11-16 16:51:07.288470911 -0500
1607 +++ linux-2.6.32-27.planetlab.i686/include/linux/tcp.h  2011-11-16 16:51:05.983450204 -0500
1608 @@ -414,6 +414,10 @@
1609                 thin_dupack : 1,/* Fast retransmit on first dupack      */
1610                 unused      : 6;
1611  #endif
1612 +
1613 +#ifdef CONFIG_WEB100_STATS
1614 +       struct web100stats      *tcp_stats;
1615 +#endif
1616  };
1617  
1618  static inline struct tcp_sock *tcp_sk(const struct sock *sk)
1619 diff -Naur linux-2.6.32-27.planetlab.i686.orig/include/net/tcp.h linux-2.6.32-27.planetlab.i686/include/net/tcp.h
1620 --- linux-2.6.32-27.planetlab.i686.orig/include/net/tcp.h       2011-11-16 16:51:07.240470973 -0500
1621 +++ linux-2.6.32-27.planetlab.i686/include/net/tcp.h    2011-11-16 16:51:05.935471062 -0500
1622 @@ -45,6 +45,8 @@
1623  
1624  #include <linux/seq_file.h>
1625  
1626 +#include <net/web100.h>
1627 +
1628  extern struct inet_hashinfo tcp_hashinfo;
1629  
1630  extern struct percpu_counter tcp_orphan_count;
1631 @@ -242,6 +244,14 @@
1632  extern int sysctl_tcp_max_ssthresh;
1633  extern int sysctl_tcp_thin_linear_timeouts;
1634  extern int sysctl_tcp_thin_dupack;
1635 +#ifdef CONFIG_WEB100_NET100
1636 +extern int sysctl_WAD_IFQ;
1637 +extern int sysctl_WAD_MaxBurst;
1638 +#endif
1639 +#ifdef CONFIG_WEB100_STATS
1640 +extern int sysctl_web100_fperms;
1641 +extern int sysctl_web100_gid;
1642 +#endif
1643  
1644  extern atomic_t tcp_memory_allocated;
1645  extern struct percpu_counter tcp_sockets_allocated;
1646 @@ -834,6 +844,10 @@
1647   */
1648  static __inline__ __u32 tcp_max_burst(const struct tcp_sock *tp)
1649  {
1650 +#ifdef CONFIG_WEB100_NET100
1651 +       return max_t(int, tp->reordering,
1652 +                    NET100_WAD(tp, WAD_MaxBurst, sysctl_WAD_MaxBurst));
1653 +#endif
1654         return tp->reordering;
1655  }
1656  
1657 diff -Naur linux-2.6.32-27.planetlab.i686.orig/include/net/web100.h linux-2.6.32-27.planetlab.i686/include/net/web100.h
1658 --- linux-2.6.32-27.planetlab.i686.orig/include/net/web100.h    1969-12-31 19:00:00.000000000 -0500
1659 +++ linux-2.6.32-27.planetlab.i686/include/net/web100.h 2011-11-16 16:51:05.931471093 -0500
1660 @@ -0,0 +1,123 @@
1661 +/* 
1662 + *  include/net/web100.h
1663 + *  
1664 + * Copyright (C) 2001 Matt Mathis <mathis@psc.edu>
1665 + * Copyright (C) 2001 John Heffner <jheffner@psc.edu>
1666 + *
1667 + * The Web 100 project.  See http://www.web100.org
1668 + *
1669 + * This program is free software; you can redistribute it and/or
1670 + * modify it under the terms of the GNU General Public License
1671 + * as published by the Free Software Foundation; either version
1672 + * 2 of the License, or (at your option) any later version.
1673 + *
1674 + */
1675 +
1676 +#ifndef _WEB100_H
1677 +#define _WEB100_H
1678 +
1679 +#include <net/sock.h>
1680 +#include <net/web100_stats.h>
1681 +#include <linux/tcp.h>
1682 +
1683 +#ifdef CONFIG_WEB100_STATS
1684 +
1685 +#define WEB100_MAX_CONNS       (1<<15)
1686 +
1687 +#define WEB100_DELAY_MAX       HZ
1688 +
1689 +/* Netlink */
1690 +#define WC_NL_TYPE_CONNECT     0
1691 +#define WC_NL_TYPE_DISCONNECT  1
1692 +
1693 +struct web100_netlink_msg {
1694 +       int type;
1695 +       int cid;
1696 +};
1697 +
1698 +/* The syntax of this version string is subject to future changes */
1699 +extern char *web100_version_string;
1700 +
1701 +/* Stats structures */
1702 +extern struct web100stats *web100stats_arr[];
1703 +extern struct web100stats *web100stats_first;
1704 +
1705 +/* For locking the creation and destruction of stats structures. */
1706 +extern rwlock_t web100_linkage_lock;
1707 +
1708 +/* For /proc/web100 */
1709 +extern struct web100stats *web100stats_lookup(int cid);
1710 +
1711 +/* For the TCP code */
1712 +extern int  web100_stats_create(struct sock *sk);
1713 +extern void web100_stats_destroy(struct web100stats *stats);
1714 +extern void web100_stats_free(struct web100stats *stats);
1715 +extern void web100_stats_establish(struct sock *sk);
1716 +
1717 +extern void web100_tune_sndbuf_ack(struct sock *sk);
1718 +extern void web100_tune_sndbuf_snd(struct sock *sk);
1719 +extern void web100_tune_rcvbuf(struct sock *sk);
1720 +
1721 +extern void web100_update_snd_nxt(struct tcp_sock *tp);
1722 +extern void web100_update_snd_una(struct tcp_sock *tp);
1723 +extern void web100_update_rtt(struct sock *sk, unsigned long rtt_sample);
1724 +extern void web100_update_timeout(struct sock *sk);
1725 +extern void web100_update_mss(struct tcp_sock *tp);
1726 +extern void web100_update_cwnd(struct tcp_sock *tp);
1727 +extern void web100_update_rwin_rcvd(struct tcp_sock *tp);
1728 +extern void web100_update_sndlim(struct tcp_sock *tp, int why);
1729 +extern void web100_update_rcv_nxt(struct tcp_sock *tp);
1730 +extern void web100_update_rwin_sent(struct tcp_sock *tp);
1731 +extern void web100_update_congestion(struct tcp_sock *tp, int why);
1732 +extern void web100_update_segsend(struct sock *sk, int len, int pcount,
1733 +                                  __u32 seq, __u32 end_seq, int flags);
1734 +extern void web100_update_segrecv(struct tcp_sock *tp, struct sk_buff *skb);
1735 +extern void web100_update_rcvbuf(struct sock *sk, int rcvbuf);
1736 +extern void web100_update_writeq(struct sock *sk);
1737 +extern void web100_update_recvq(struct sock *sk);
1738 +extern void web100_update_ofoq(struct sock *sk);
1739 +
1740 +extern void web100_stats_init(void);
1741 +
1742 +/* For the IP code */
1743 +extern int web100_delay_output(struct sk_buff *skb, int (*output)(struct sk_buff *));
1744 +
1745 +extern __u64 web100_mono_time(void);
1746 +
1747 +/* You may have to hold web100_linkage_lock here to prevent
1748 +   stats from disappearing. */
1749 +static inline void web100_stats_use(struct web100stats *stats)
1750 +{
1751 +       atomic_inc(&stats->wc_users);
1752 +}
1753 +
1754 +/* You MUST NOT hold web100_linkage_lock here. */
1755 +static inline void web100_stats_unuse(struct web100stats *stats)
1756 +{
1757 +       if (atomic_dec_and_test(&stats->wc_users))
1758 +               web100_stats_free(stats);
1759 +}
1760 +
1761 +/* A mapping between Linux and Web100 states.  This could easily just
1762 + * be an array. */
1763 +static inline int web100_state(int state)
1764 +{
1765 +       switch (state) {
1766 +       case TCP_ESTABLISHED:   return WC_STATE_ESTABLISHED;
1767 +       case TCP_SYN_SENT:      return WC_STATE_SYNSENT;
1768 +       case TCP_SYN_RECV:      return WC_STATE_SYNRECEIVED;
1769 +       case TCP_FIN_WAIT1:     return WC_STATE_FINWAIT1;
1770 +       case TCP_FIN_WAIT2:     return WC_STATE_FINWAIT2;
1771 +       case TCP_TIME_WAIT:     return WC_STATE_TIMEWAIT;
1772 +       case TCP_CLOSE:         return WC_STATE_CLOSED;
1773 +       case TCP_CLOSE_WAIT:    return WC_STATE_CLOSEWAIT;
1774 +       case TCP_LAST_ACK:      return WC_STATE_LASTACK;
1775 +       case TCP_LISTEN:        return WC_STATE_LISTEN;
1776 +       case TCP_CLOSING:       return WC_STATE_CLOSING;
1777 +       default:                return 0;
1778 +       }
1779 +}
1780 +
1781 +#endif /* CONFIG_WEB100_STATS */
1782 +
1783 +#endif /* _WEB100_H */
1784 diff -Naur linux-2.6.32-27.planetlab.i686.orig/include/net/web100_stats.h linux-2.6.32-27.planetlab.i686/include/net/web100_stats.h
1785 --- linux-2.6.32-27.planetlab.i686.orig/include/net/web100_stats.h      1969-12-31 19:00:00.000000000 -0500
1786 +++ linux-2.6.32-27.planetlab.i686/include/net/web100_stats.h   2011-11-16 16:51:05.933470945 -0500
1787 @@ -0,0 +1,346 @@
1788 +/*
1789 + * include/net/web100_stats.h
1790 + *
1791 + * Copyright (C) 2001 Matt Mathis <mathis@psc.edu>
1792 + * Copyright (C) 2001 John Heffner <jheffner@psc.edu>
1793 + * Copyright (C) 2000 Jeff Semke <semke@psc.edu>
1794 + *
1795 + * The Web 100 project.  See http://www.web100.org
1796 + *
1797 + * This program is free software; you can redistribute it and/or
1798 + * modify it under the terms of the GNU General Public License
1799 + * as published by the Free Software Foundation; either version
1800 + * 2 of the License, or (at your option) any later version.
1801 + *
1802 + */
1803 +
1804 +/* TODO: make sure that the time duration states below include:
1805 +   Congestion Avoidance, Slow Start, Timeouts, Idle Application, and
1806 +   Window Limited cases */
1807 +/* TODO: Consider adding sysctl variable to enable/disable WC stats updates.
1808 +   Probably should still create stats structures if compiled with WC support,
1809 +   even if sysctl(wc) is turned off.  That would allow the stats to be updated
1810 +   if the sysctl(wc) is turned back on. */
1811 +/* TODO: Add all variables needed to do user-level auto-tuning, including
1812 +   writeable parameters */
1813 +
1814 +
1815 +#ifndef _WEB100_STATS_H
1816 +#define _WEB100_STATS_H
1817 +
1818 +enum wc_sndlim_states {
1819 +       WC_SNDLIM_NONE = -1,
1820 +       WC_SNDLIM_SENDER,
1821 +       WC_SNDLIM_CWND,
1822 +       WC_SNDLIM_RWIN,
1823 +       WC_SNDLIM_STARTUP,
1824 +       WC_SNDLIM_NSTATES       /* Keep at end */
1825 +};
1826 +
1827 +#ifndef CONFIG_WEB100_STATS
1828 +
1829 +#define WEB100_VAR_INC(tp,var)         do {} while (0)
1830 +#define WEB100_VAR_DEC(tp,var)         do {} while (0)
1831 +#define WEB100_VAR_SET(tp,var,val)     do {} while (0)
1832 +#define WEB100_VAR_ADD(tp,var,val)     do {} while (0)
1833 +#define WEB100_UPDATE_FUNC(tp,func)    do {} while (0)
1834 +#define NET100_WAD(tp, var, def)       (def)
1835 +
1836 +#else /* CONFIG_WEB100_STATS */ /* { */
1837 +
1838 +#include <linux/spinlock.h>
1839 +
1840 +#define WEB100_CHECK(tp,expr) \
1841 +       do { if ((tp)->tcp_stats) (expr); } while (0)
1842 +#define WEB100_VAR_INC(tp,var) \
1843 +       WEB100_CHECK(tp, ((tp)->tcp_stats->wc_vars.var)++)
1844 +#define WEB100_VAR_DEC(tp,var) \
1845 +       WEB100_CHECK(tp, ((tp)->tcp_stats->wc_vars.var)--)
1846 +#define WEB100_VAR_ADD(tp,var,val) \
1847 +       WEB100_CHECK(tp, ((tp)->tcp_stats->wc_vars.var) += (val))
1848 +#define WEB100_VAR_SET(tp,var,val) \
1849 +       WEB100_CHECK(tp, ((tp)->tcp_stats->wc_vars.var) = (val))
1850 +#define WEB100_UPDATE_FUNC(tp,func) \
1851 +       WEB100_CHECK(tp, func)
1852 +#ifdef CONFIG_WEB100_NET100
1853 +#define NET100_WAD(tp, var, def) \
1854 +       (((tp)->tcp_stats && (tp)->tcp_stats->wc_vars.var) ? (tp)->tcp_stats->wc_vars.var : (def))
1855 +#else
1856 +#define NET100_WAD(tp, var, def)       (def)
1857 +#endif
1858 +
1859 +/* SMIv2 types - RFC 1902 */
1860 +typedef __s32          INTEGER;
1861 +typedef INTEGER                Integer32;
1862 +typedef __u32          IpAddress;
1863 +typedef __u32          Counter32;
1864 +typedef __u32          Unsigned32;
1865 +typedef Unsigned32     Gauge32;
1866 +typedef __u32          TimeTicks;
1867 +typedef __u64          Counter64;
1868 +typedef __u16          Unsigned16;
1869 +
1870 +/* New inet address types specified in INET-ADDRESS-MIB */
1871 +typedef Unsigned16     InetPortNumber;
1872 +typedef enum {
1873 +       WC_ADDRTYPE_UNKNOWN = 0,
1874 +       WC_ADDRTYPE_IPV4,
1875 +       WC_ADDRTYPE_IPV6,
1876 +       WC_ADDRTYPE_DNS = 16
1877 +} InetAddressType;
1878 +typedef IpAddress      InetAddresIPv4;
1879 +typedef struct {
1880 +       __u8    addr[16];
1881 +       __u8    type;
1882 +} InetAddresIPv6;
1883 +typedef union {
1884 +       InetAddresIPv4  v4addr;
1885 +       InetAddresIPv6  v6addr;
1886 +} InetAddress;
1887 +
1888 +typedef enum {
1889 +       truthValueTrue = 1,
1890 +       truthValueFalse = 2
1891 +} TruthValue;
1892 +
1893 +enum wc_states {
1894 +       WC_STATE_CLOSED = 1,
1895 +       WC_STATE_LISTEN,
1896 +       WC_STATE_SYNSENT,
1897 +       WC_STATE_SYNRECEIVED,
1898 +       WC_STATE_ESTABLISHED,
1899 +       WC_STATE_FINWAIT1,
1900 +       WC_STATE_FINWAIT2,
1901 +       WC_STATE_CLOSEWAIT,
1902 +       WC_STATE_LASTACK,
1903 +       WC_STATE_CLOSING,
1904 +       WC_STATE_TIMEWAIT,
1905 +       WC_STATE_DELETECB
1906 +};
1907 +
1908 +enum wc_stunemodes {
1909 +       WC_STUNEMODE_DEFAULT = 0,       /* OS native */
1910 +       WC_STUNEMODE_SETSOCKOPT,        /* OS native setsockopt() */
1911 +       WC_STUNEMODE_FIXED,             /* Manual via the web100 API */
1912 +       WC_STUNEMODE_AUTO,
1913 +       WC_STUNEMODE_EXP1,
1914 +       WC_STUNEMODE_EXP2
1915 +};
1916 +
1917 +enum wc_rtunemodes {
1918 +       WC_RTUNEMODE_DEFAULT = 0,
1919 +       WC_RTUNEMODE_SETSOCKOPT,
1920 +       WC_RTUNEMODE_FIXED,
1921 +       WC_RTUNEMODE_AUTO,
1922 +       WC_RTUNEMODE_EXP1,
1923 +       WC_RTUNEMODE_EXP2
1924 +};
1925 +
1926 +enum wc_bufmodes {
1927 +       WC_BUFMODE_OS = 0,
1928 +       WC_BUFMODE_WEB100,
1929 +};
1930 +
1931 +enum {
1932 +       WC_SE_BELOW_DATA_WINDOW = 1,
1933 +       WC_SE_ABOVE_DATA_WINDOW,
1934 +       WC_SE_BELOW_ACK_WINDOW,
1935 +       WC_SE_ABOVE_ACK_WINDOW,
1936 +       WC_SE_BELOW_TSW_WINDOW,
1937 +       WC_SE_ABOVE_TSW_WINDOW,
1938 +       WC_SE_DATA_CHECKSUM
1939 +};
1940 +
1941 +
1942 +/*
1943 + * Variables that can be read and written directly.
1944 + * 
1945 + * Should contain most variables from TCP-KIS 0.1.  Commented feilds are
1946 + * either not implemented or have handlers and do not need struct storage.
1947 + */
1948 +struct web100directs {
1949 +       /* STATE */
1950 +       INTEGER         State;
1951 +       TruthValue      SACKEnabled;
1952 +       TruthValue      TimestampsEnabled;
1953 +       TruthValue      NagleEnabled;
1954 +       TruthValue      ECNEnabled;
1955 +       Integer32       SndWinScale;
1956 +       Integer32       RcvWinScale;
1957 +       
1958 +       /* SYN OPTIONS */
1959 +       INTEGER         ActiveOpen;
1960 +     /* Gauge32                MSSSent; */
1961 +       Gauge32         MSSRcvd;
1962 +       Integer32       WinScaleRcvd;
1963 +       Integer32       WinScaleSent;
1964 +     /* INTEGER                SACKokSent; */
1965 +     /* INTEGER                SACKokRcvd; */
1966 +     /* INTEGER                TimestampSent; */
1967 +     /* INTEGER                TimestampRcvd; */
1968 +       
1969 +       /* DATA */
1970 +       Counter32       PktsOut;
1971 +       Counter32       DataPktsOut;
1972 +       Counter32       AckPktsOut;             /* DEPRICATED */
1973 +       Counter64       DataBytesOut;
1974 +       Counter32       PktsIn;
1975 +       Counter32       DataPktsIn;
1976 +       Counter32       AckPktsIn;              /* DEPRICATED */
1977 +       Counter64       DataBytesIn;
1978 +     /* Counter32      SoftErrors; */
1979 +     /* INTEGER                SoftErrorReason; */
1980 +       Counter32       SndUna;
1981 +       Unsigned32      SndNxt;
1982 +       Counter32       SndMax;
1983 +       Counter64       ThruBytesAcked;
1984 +       Counter32       SndISS;                 /* SndInitial */
1985 +       Counter32       SendWraps;              /* DEPRICATED */
1986 +       Counter32       RcvNxt;
1987 +       Counter64       ThruBytesReceived;
1988 +       Counter32       RecvISS;                /* RecInitial */
1989 +       Counter32       RecvWraps;              /* DEPRICATED */
1990 +     /* Counter64      Duration; */
1991 +       Integer32       StartTime;              /* DEPRICATED */
1992 +       Integer32       StartTimeSec;
1993 +       Integer32       StartTimeUsec;
1994 +
1995 +       /* SENDER CONGESTION */
1996 +       Counter32       SndLimTrans[WC_SNDLIM_NSTATES];
1997 +       Counter32       SndLimTime[WC_SNDLIM_NSTATES];
1998 +       Counter64       SndLimBytes[WC_SNDLIM_NSTATES];
1999 +       Counter32       SlowStart;
2000 +       Counter32       CongAvoid;
2001 +       Counter32       CongestionSignals;
2002 +       Counter32       OtherReductions;
2003 +       Counter32       X_OtherReductionsCV;
2004 +       Counter32       X_OtherReductionsCM;
2005 +       Counter32       CongestionOverCount;
2006 +       Gauge32         CurCwnd;
2007 +       Gauge32         MaxCwnd;
2008 +     /* Gauge32                LimCwnd; */
2009 +       Gauge32         CurSsthresh;
2010 +       Gauge32         MaxSsthresh;
2011 +       Gauge32         MinSsthresh;
2012 +
2013 +       /* SENDER PATH MODEL */
2014 +       Counter32       FastRetran;
2015 +       Counter32       Timeouts;
2016 +       Counter32       SubsequentTimeouts;
2017 +       Gauge32         CurTimeoutCount;
2018 +       Counter32       AbruptTimeouts;
2019 +       Counter32       PktsRetrans;
2020 +       Counter32       BytesRetrans;
2021 +       Counter32       DupAcksIn;
2022 +       Counter32       SACKsRcvd;
2023 +       Counter32       SACKBlocksRcvd;
2024 +       Counter32       PreCongSumCwnd;
2025 +       Counter32       PreCongSumRTT;
2026 +       Counter32       PreCongCountRTT;        /* DEPRICATED */
2027 +       Counter32       PostCongSumRTT;
2028 +       Counter32       PostCongCountRTT;
2029 +     /* Counter32      ECNsignals; */
2030 +       Counter32       ECERcvd;
2031 +       Counter32       SendStall;
2032 +       Counter32       QuenchRcvd;
2033 +       Gauge32         RetranThresh;
2034 +     /* Counter32      SndDupAckEpisodes; */
2035 +     /* Counter64      SumBytesReordered; */
2036 +       Counter32       NonRecovDA;
2037 +       Counter32       AckAfterFR;
2038 +       Counter32       DSACKDups;
2039 +       Gauge32         SampleRTT;
2040 +       Gauge32         SmoothedRTT;
2041 +       Gauge32         RTTVar;
2042 +       Gauge32         MaxRTT;
2043 +       Gauge32         MinRTT;
2044 +       Counter64       SumRTT;
2045 +       Counter32       CountRTT;
2046 +       Gauge32         CurRTO;
2047 +       Gauge32         MaxRTO;
2048 +       Gauge32         MinRTO;
2049 +       Gauge32         CurMSS;
2050 +       Gauge32         MaxMSS;
2051 +       Gauge32         MinMSS;
2052 +
2053 +       /* LOCAL SENDER BUFFER */
2054 +       Gauge32         CurRetxQueue;
2055 +       Gauge32         MaxRetxQueue;
2056 +       Gauge32         CurAppWQueue;
2057 +       Gauge32         MaxAppWQueue;
2058 +
2059 +       /* LOCAL RECEIVER */
2060 +       Gauge32         CurRwinSent;
2061 +       Gauge32         MaxRwinSent;
2062 +       Gauge32         MinRwinSent;
2063 +       Integer32       LimRwin;
2064 +     /* Counter32      DupAckEpisodes; */
2065 +       Counter32       DupAcksOut;
2066 +     /* Counter32      CERcvd; */
2067 +     /* Counter32      ECNSent; */
2068 +     /* Counter32      ECNNonceRcvd; */
2069 +       Gauge32         CurReasmQueue;
2070 +       Gauge32         MaxReasmQueue;
2071 +       Gauge32         CurAppRQueue;
2072 +       Gauge32         MaxAppRQueue;
2073 +       Gauge32         X_rcv_ssthresh;
2074 +       Gauge32         X_wnd_clamp;
2075 +       Gauge32         X_dbg1;
2076 +       Gauge32         X_dbg2;
2077 +       Gauge32         X_dbg3;
2078 +       Gauge32         X_dbg4;
2079 +
2080 +       /* OBSERVED RECEIVER */
2081 +       Gauge32         CurRwinRcvd;
2082 +       Gauge32         MaxRwinRcvd;
2083 +       Gauge32         MinRwinRcvd;
2084 +
2085 +       /* CONNECTION ID */
2086 +       InetAddressType LocalAddressType;
2087 +       InetAddress     LocalAddress;
2088 +       InetPortNumber  LocalPort;
2089 +     /* InetAddressType        RemAddressType; */
2090 +       InetAddress     RemAddress;
2091 +       InetPortNumber  RemPort;
2092 +     /* Integer32      IdId; */
2093 +       
2094 +       Gauge32         X_RcvRTT;
2095 +       
2096 +#ifdef CONFIG_WEB100_NET100
2097 +       /* support for the NET100 Work Around Deamon (WAD) */
2098 +       Gauge32         WAD_IFQ;
2099 +       Gauge32         WAD_MaxBurst;
2100 +       Gauge32         WAD_MaxSsthresh;
2101 +       INTEGER         WAD_NoAI;
2102 +       Integer32       WAD_CwndAdjust;
2103 +#endif
2104 +};
2105 +
2106 +struct web100stats {
2107 +       int                     wc_cid;
2108 +       
2109 +       struct sock             *wc_sk;
2110 +       
2111 +       atomic_t                wc_users;
2112 +       __u8                    wc_dead;
2113 +       
2114 +       struct web100stats      *wc_next;
2115 +       struct web100stats      *wc_prev;
2116 +       
2117 +       struct web100stats      *wc_hash_next;
2118 +       struct web100stats      *wc_hash_prev;
2119 +       
2120 +       struct web100stats      *wc_death_next;
2121 +       
2122 +       int                     wc_limstate;
2123 +       __u64                   wc_limstate_bytes;
2124 +       __u64                   wc_limstate_time;
2125 +       
2126 +       __u64                   wc_start_monotime;
2127 +       
2128 +       struct web100directs    wc_vars;
2129 +};
2130 +
2131 +#endif /* CONFIG_WEB100_STATS */ /* } */
2132 +
2133 +#endif         /*_WEB100_STATS_H */
2134 diff -Naur linux-2.6.32-27.planetlab.i686.orig/Makefile linux-2.6.32-27.planetlab.i686/Makefile
2135 --- linux-2.6.32-27.planetlab.i686.orig/Makefile        2011-11-16 16:51:08.409611307 -0500
2136 +++ linux-2.6.32-27.planetlab.i686/Makefile     2011-11-16 16:51:06.773471236 -0500
2137 @@ -1,7 +1,7 @@
2138  VERSION = 2
2139  PATCHLEVEL = 6
2140  SUBLEVEL = 32
2141 -EXTRAVERSION =
2142 +EXTRAVERSION = -web100
2143  NAME = Man-Eating Seals of Antiquity
2144  RHEL_MAJOR = 6
2145  RHEL_MINOR = 1
2146 diff -Naur linux-2.6.32-27.planetlab.i686.orig/net/ipv4/Kconfig linux-2.6.32-27.planetlab.i686/net/ipv4/Kconfig
2147 --- linux-2.6.32-27.planetlab.i686.orig/net/ipv4/Kconfig        2011-11-16 16:51:07.412471138 -0500
2148 +++ linux-2.6.32-27.planetlab.i686/net/ipv4/Kconfig     2011-11-16 16:51:06.107470833 -0500
2149 @@ -627,6 +627,70 @@
2150  
2151           If unsure, say N.
2152  
2153 +menuconfig WEB100
2154 +       bool "IP: Web100 networking enhancements"
2155 +       depends on INET && EXPERIMENTAL
2156 +
2157 +if WEB100
2158 +
2159 +config WEB100_STATS
2160 +       bool "Web100: Extended TCP statistics"
2161 +       depends on WEB100
2162 +       ---help---
2163 +         Support for the Web100 implementation of the TCP extended stastics
2164 +         MIB (see http://www.web100.org/mib/).
2165 +
2166 +if WEB100_STATS
2167 +
2168 +config WEB100_FPERMS
2169 +       int "Web100:   Default file permissions"
2170 +       depends on WEB100_STATS
2171 +       default "384"
2172 +       ---help---
2173 +         This controls the default file permission bits on the Web100
2174 +         files in /proc/web100.  This value can be changed at runtime using
2175 +         the sysctl variable net.ipv4.web100_fperms.  Unless all users on
2176 +         the system are trusted, it is safest to limit both readability
2177 +         and writability to trusted users.
2178 +         
2179 +         Due to limitations of the kernel config scripts, this is a decimal
2180 +         value rather than octal.  Some common values:
2181 +         
2182 +           384 = 0600 = rw-------
2183 +           416 = 0640 = rw-r-----
2184 +           432 = 0660 = rw-rw----
2185 +           436 = 0664 = rw-rw-r--
2186 +           438 = 0666 = rw-rw-rw-
2187 +
2188 +config WEB100_GID
2189 +       int "Web100:   Default gid"
2190 +       depends on WEB100_STATS
2191 +       default "0"
2192 +       ---help---
2193 +         This will be the default group of the Web100 files in /proc/web100.
2194 +         It may be useful to create a "web100" group on your system, and set
2195 +         CONFIG_WEB100_FPERMS (above) with special group permissions.  This
2196 +         value can be changed at runtime using the sysctl variable
2197 +         net.ipv4.web100_gid.
2198 +
2199 +config WEB100_NET100
2200 +       bool "Web100:   Net100 extensions"
2201 +       depends on WEB100_STATS
2202 +       ---help---
2203 +         Enables certain "Net100" extensions to TCP that are controlled by
2204 +         writable MIB variables.  These controls may be particularly useful
2205 +         for specially tuning a flow on a long fast network.
2206 +
2207 +endif
2208 +
2209 +config WEB100_NETLINK
2210 +       bool "Web100: Netlink event notification service"
2211 +       depends on WEB100
2212 +       ---help---
2213 +         Required by the Net100 Work Around Daemon (WAD).
2214 +
2215 +endif
2216 +
2217  #
2218  # Emulab special
2219  #
2220 diff -Naur linux-2.6.32-27.planetlab.i686.orig/net/ipv4/Makefile linux-2.6.32-27.planetlab.i686/net/ipv4/Makefile
2221 --- linux-2.6.32-27.planetlab.i686.orig/net/ipv4/Makefile       2011-11-16 16:51:07.413470925 -0500
2222 +++ linux-2.6.32-27.planetlab.i686/net/ipv4/Makefile    2011-11-16 16:51:06.109471129 -0500
2223 @@ -32,6 +32,7 @@
2224  obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o
2225  obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o
2226  obj-$(CONFIG_IP_PNP) += ipconfig.o
2227 +obj-$(CONFIG_WEB100_STATS) += web100_stats.o
2228  obj-$(CONFIG_NETFILTER)        += netfilter.o netfilter/
2229  obj-$(CONFIG_INET_DIAG) += inet_diag.o 
2230  obj-$(CONFIG_INET_TCP_DIAG) += tcp_diag.o
2231 diff -Naur linux-2.6.32-27.planetlab.i686.orig/net/ipv4/sysctl_net_ipv4.c linux-2.6.32-27.planetlab.i686/net/ipv4/sysctl_net_ipv4.c
2232 --- linux-2.6.32-27.planetlab.i686.orig/net/ipv4/sysctl_net_ipv4.c      2011-11-16 16:51:07.413470925 -0500
2233 +++ linux-2.6.32-27.planetlab.i686/net/ipv4/sysctl_net_ipv4.c   2011-11-16 16:51:06.108471039 -0500
2234 @@ -719,6 +719,42 @@
2235                 .mode           = 0644,
2236                 .proc_handler   = proc_dointvec,
2237         },
2238 +#ifdef CONFIG_WEB100_NET100
2239 +       {
2240 +               .ctl_name       = CTL_UNNUMBERED,
2241 +               .procname       = "WAD_IFQ",
2242 +               .data           = &sysctl_WAD_IFQ,
2243 +               .maxlen         = sizeof(int),
2244 +               .mode           = 0644,
2245 +               .proc_handler   = &proc_dointvec,
2246 +       },
2247 +       {
2248 +               .ctl_name       = CTL_UNNUMBERED,
2249 +               .procname       = "WAD_MaxBurst",
2250 +               .data           = &sysctl_WAD_MaxBurst,
2251 +               .maxlen         = sizeof(int),
2252 +               .mode           = 0644,
2253 +               .proc_handler   = &proc_dointvec,
2254 +       },
2255 +#endif
2256 +#ifdef CONFIG_WEB100_STATS
2257 +       {
2258 +               .ctl_name       = CTL_UNNUMBERED,
2259 +               .procname       = "web100_fperms",
2260 +               .data           = &sysctl_web100_fperms,
2261 +               .maxlen         = sizeof(int),
2262 +               .mode           = 0644,
2263 +               .proc_handler   = &web100_proc_dointvec_update,
2264 +       },
2265 +       {
2266 +               .ctl_name       = CTL_UNNUMBERED,
2267 +               .procname       = "web100_gid",
2268 +               .data           = &sysctl_web100_gid,
2269 +               .maxlen         = sizeof(int),
2270 +               .mode           = 0644,
2271 +               .proc_handler   = &web100_proc_dointvec_update,
2272 +       },
2273 +#endif
2274         {
2275                 .ctl_name       = CTL_UNNUMBERED,
2276                 .procname       = "tcp_thin_linear_timeouts",
2277 diff -Naur linux-2.6.32-27.planetlab.i686.orig/net/ipv4/tcp.c linux-2.6.32-27.planetlab.i686/net/ipv4/tcp.c
2278 --- linux-2.6.32-27.planetlab.i686.orig/net/ipv4/tcp.c  2011-11-16 16:51:07.413470925 -0500
2279 +++ linux-2.6.32-27.planetlab.i686/net/ipv4/tcp.c       2011-11-16 16:51:06.108471039 -0500
2280 @@ -289,6 +289,16 @@
2281  EXPORT_SYMBOL(sysctl_tcp_rmem);
2282  EXPORT_SYMBOL(sysctl_tcp_wmem);
2283  
2284 +#ifdef CONFIG_WEB100_NET100
2285 +int sysctl_WAD_IFQ = 0;
2286 +int sysctl_WAD_MaxBurst = 3;
2287 +EXPORT_SYMBOL(sysctl_WAD_MaxBurst);
2288 +#endif
2289 +#ifdef CONFIG_WEB100_STATS
2290 +int sysctl_web100_fperms = CONFIG_WEB100_FPERMS;
2291 +int sysctl_web100_gid = CONFIG_WEB100_GID;
2292 +#endif
2293 +
2294  atomic_t tcp_memory_allocated; /* Current allocated memory. */
2295  EXPORT_SYMBOL(tcp_memory_allocated);
2296  
2297 @@ -835,8 +845,12 @@
2298  wait_for_sndbuf:
2299                 set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
2300  wait_for_memory:
2301 -               if (copied)
2302 +               if (copied) {
2303                         tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
2304 +#ifdef CONFIG_WEB100_STATS
2305 +                       web100_update_writeq(sk);
2306 +#endif
2307 +               }
2308  
2309                 if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
2310                         goto do_error;
2311 @@ -1084,8 +1098,12 @@
2312  wait_for_sndbuf:
2313                         set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
2314  wait_for_memory:
2315 -                       if (copied)
2316 +                       if (copied) {
2317                                 tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
2318 +#ifdef CONFIG_WEB100_STATS
2319 +                               web100_update_writeq(sk);
2320 +#endif
2321 +                       }
2322  
2323                         if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
2324                                 goto do_error;
2325 @@ -1452,6 +1470,9 @@
2326                                         *seq, TCP_SKB_CB(skb)->seq,
2327                                         tp->rcv_nxt, flags);
2328                 }
2329 +#ifdef CONFIG_WEB100_STATS
2330 +               web100_update_recvq(sk);
2331 +#endif
2332  
2333                 /* Well, if we have backlog, try to process it now yet. */
2334  
2335 @@ -1754,6 +1775,8 @@
2336  {
2337         int oldstate = sk->sk_state;
2338  
2339 +       WEB100_VAR_SET(tcp_sk(sk), State, web100_state(state));
2340 +
2341         switch (state) {
2342         case TCP_ESTABLISHED:
2343                 if (oldstate != TCP_ESTABLISHED)
2344 @@ -2138,6 +2161,7 @@
2345                 } else {
2346                         tp->nonagle &= ~TCP_NAGLE_OFF;
2347                 }
2348 +               WEB100_VAR_SET(tp, NagleEnabled, !tp->nonagle);
2349                 break;
2350  
2351         case TCP_THIN_LINEAR_TIMEOUTS:
2352 @@ -2174,6 +2198,7 @@
2353                                 tp->nonagle |= TCP_NAGLE_PUSH;
2354                         tcp_push_pending_frames(sk);
2355                 }
2356 +               WEB100_VAR_SET(tp, NagleEnabled, !tp->nonagle);
2357                 break;
2358  
2359         case TCP_KEEPIDLE:
2360 @@ -2996,6 +3021,10 @@
2361                tcp_hashinfo.ehash_size, tcp_hashinfo.bhash_size);
2362  
2363         tcp_register_congestion_control(&tcp_reno);
2364 +       
2365 +#ifdef CONFIG_WEB100_STATS
2366 +       web100_stats_init();
2367 +#endif
2368  }
2369  
2370  EXPORT_SYMBOL(tcp_close);
2371 diff -Naur linux-2.6.32-27.planetlab.i686.orig/net/ipv4/tcp_cong.c linux-2.6.32-27.planetlab.i686/net/ipv4/tcp_cong.c
2372 --- linux-2.6.32-27.planetlab.i686.orig/net/ipv4/tcp_cong.c     2011-11-16 16:51:07.414470925 -0500
2373 +++ linux-2.6.32-27.planetlab.i686/net/ipv4/tcp_cong.c  2011-11-16 16:51:06.109471129 -0500
2374 @@ -316,7 +316,8 @@
2375                 return;
2376  
2377         if (sysctl_tcp_max_ssthresh > 0 && tp->snd_cwnd > sysctl_tcp_max_ssthresh)
2378 -               cnt = sysctl_tcp_max_ssthresh >> 1;     /* limited slow start */
2379 +               /* limited slow start */
2380 +               cnt = NET100_WAD(tp, WAD_MaxSsthresh, sysctl_tcp_max_ssthresh) >> 1;
2381         else
2382                 cnt = tp->snd_cwnd;                     /* exponential increase */
2383  
2384 @@ -364,8 +365,10 @@
2385                 return;
2386  
2387         /* In "safe" area, increase. */
2388 -       if (tp->snd_cwnd <= tp->snd_ssthresh)
2389 +        if (tp->snd_cwnd <= tp->snd_ssthresh) {
2390                 tcp_slow_start(tp);
2391 +               WEB100_VAR_INC(tp, SlowStart);
2392 +       }
2393  
2394         /* In dangerous area, increase slowly. */
2395         else if (sysctl_tcp_abc) {
2396 @@ -377,8 +380,10 @@
2397                         if (tp->snd_cwnd < tp->snd_cwnd_clamp)
2398                                 tp->snd_cwnd++;
2399                 }
2400 +               WEB100_VAR_INC(tp, CongAvoid);
2401         } else {
2402                 tcp_cong_avoid_ai(tp, tp->snd_cwnd);
2403 +               WEB100_VAR_INC(tp, CongAvoid);
2404         }
2405  }
2406  EXPORT_SYMBOL_GPL(tcp_reno_cong_avoid);
2407 diff -Naur linux-2.6.32-27.planetlab.i686.orig/net/ipv4/tcp_input.c linux-2.6.32-27.planetlab.i686/net/ipv4/tcp_input.c
2408 --- linux-2.6.32-27.planetlab.i686.orig/net/ipv4/tcp_input.c    2011-11-16 16:51:07.412471138 -0500
2409 +++ linux-2.6.32-27.planetlab.i686/net/ipv4/tcp_input.c 2011-11-16 16:51:06.107470833 -0500
2410 @@ -461,6 +461,7 @@
2411  
2412         if (tp->rcv_rtt_est.rtt != new_sample)
2413                 tp->rcv_rtt_est.rtt = new_sample;
2414 +       WEB100_VAR_SET(tp, X_RcvRTT, ((1000000*tp->rcv_rtt_est.rtt)/HZ)>>3);
2415  }
2416  
2417  static inline void tcp_rcv_rtt_measure(struct tcp_sock *tp)
2418 @@ -597,6 +598,7 @@
2419  
2420         if (skb->len >= 128)
2421                 tcp_grow_window(sk, skb);
2422 +       WEB100_UPDATE_FUNC(tp, web100_update_rcv_nxt(tp));
2423  }
2424  
2425  /* Called to compute a smoothed rtt estimate. The data fed to this
2426 @@ -843,6 +845,7 @@
2427  
2428                 tcp_set_ca_state(sk, TCP_CA_CWR);
2429         }
2430 +       WEB100_UPDATE_FUNC(tp, web100_update_congestion(tp, 0));
2431  }
2432  
2433  /*
2434 @@ -886,6 +889,7 @@
2435             tp->reordering != dst_metric(dst, RTAX_REORDERING)) {
2436                 tcp_disable_fack(tp);
2437                 tp->reordering = dst_metric(dst, RTAX_REORDERING);
2438 +               WEB100_VAR_SET(tp, RetranThresh, tp->reordering);
2439         }
2440  
2441         if (dst_metric(dst, RTAX_RTT) == 0)
2442 @@ -946,6 +950,7 @@
2443                 int mib_idx;
2444  
2445                 tp->reordering = min(TCP_MAX_REORDERING, metric);
2446 +               WEB100_VAR_SET(tp, RetranThresh, tp->reordering);
2447  
2448                 /* This exciting event is worth to be remembered. 8) */
2449                 if (ts)
2450 @@ -1733,6 +1738,9 @@
2451         state.flag = 0;
2452         state.reord = tp->packets_out;
2453  
2454 +       WEB100_VAR_INC(tp, SACKsRcvd);
2455 +       WEB100_VAR_ADD(tp, SACKBlocksRcvd, num_sacks);
2456 +
2457         if (!tp->sacked_out) {
2458                 if (WARN_ON(tp->fackets_out))
2459                         tp->fackets_out = 0;
2460 @@ -2208,6 +2216,8 @@
2461         struct tcp_sock *tp = tcp_sk(sk);
2462         struct sk_buff *skb;
2463  
2464 +       WEB100_UPDATE_FUNC(tp, web100_update_congestion(tp, 0));
2465 +
2466         /* Reduce ssthresh if it has not yet been made inside this window. */
2467         if (icsk->icsk_ca_state <= TCP_CA_Disorder || tp->snd_una == tp->high_seq ||
2468             (icsk->icsk_ca_state == TCP_CA_Loss && !icsk->icsk_retransmits)) {
2469 @@ -2253,6 +2263,7 @@
2470  
2471         tp->reordering = min_t(unsigned int, tp->reordering,
2472                                sysctl_tcp_reordering);
2473 +       WEB100_VAR_SET(tp, RetranThresh, tp->reordering);
2474         tcp_set_ca_state(sk, TCP_CA_Loss);
2475         tp->high_seq = tp->snd_nxt;
2476         TCP_ECN_queue_cwr(tp);
2477 @@ -2580,8 +2591,19 @@
2478   */
2479  static inline void tcp_moderate_cwnd(struct tcp_sock *tp)
2480  {
2481 +#ifdef CONFIG_WEB100_STATS
2482 +       {
2483 +               u32 t = tcp_packets_in_flight(tp) + tcp_max_burst(tp);
2484 +               if (t < tp->snd_cwnd) {
2485 +                       tp->snd_cwnd = t;
2486 +                       WEB100_VAR_INC(tp, OtherReductions);
2487 +                       WEB100_VAR_INC(tp, X_OtherReductionsCM);
2488 +               }
2489 +       };
2490 +#else
2491         tp->snd_cwnd = min(tp->snd_cwnd,
2492                            tcp_packets_in_flight(tp) + tcp_max_burst(tp));
2493 +#endif
2494         tp->snd_cwnd_stamp = tcp_time_stamp;
2495  }
2496  
2497 @@ -2677,6 +2699,7 @@
2498         }
2499         tcp_moderate_cwnd(tp);
2500         tp->snd_cwnd_stamp = tcp_time_stamp;
2501 +       WEB100_VAR_INC(tp, CongestionOverCount);        /* XXX This is wrong. -JWH */
2502  }
2503  
2504  static inline int tcp_may_undo(struct tcp_sock *tp)
2505 @@ -3069,6 +3092,8 @@
2506                 tp->snd_cwnd_cnt = 0;
2507                 tcp_set_ca_state(sk, TCP_CA_Recovery);
2508                 fast_rexmit = 1;
2509 +               WEB100_UPDATE_FUNC(tp, web100_update_congestion(tp, 0));
2510 +               WEB100_VAR_INC(tp, FastRetran); /* WEB100_XXX */
2511         }
2512  
2513         if (do_lost || (tcp_is_fack(tp) && tcp_head_timedout(sk)))
2514 @@ -3082,6 +3107,7 @@
2515         tcp_rtt_estimator(sk, seq_rtt);
2516         tcp_set_rto(sk);
2517         inet_csk(sk)->icsk_backoff = 0;
2518 +       WEB100_UPDATE_FUNC(tcp_sk(sk), web100_update_rtt(sk, seq_rtt));
2519  }
2520  
2521  /* Read draft-ietf-tcplw-high-performance before mucking
2522 @@ -3140,6 +3166,27 @@
2523  static void tcp_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
2524  {
2525         const struct inet_connection_sock *icsk = inet_csk(sk);
2526 +#ifdef CONFIG_WEB100_STATS
2527 +       struct tcp_sock *tp = tcp_sk(sk);
2528 +       struct web100stats *stats = tp->tcp_stats;
2529 +       struct web100directs *vars = &stats->wc_vars;
2530 +       
2531 +       if (tp->snd_cwnd > tp->snd_cwnd_clamp) {
2532 +               tp->snd_cwnd--;
2533 +               return;
2534 +       }
2535 +       
2536 +#ifdef CONFIG_WEB100_NET100
2537 +       if (vars->WAD_NoAI) {
2538 +               tp->snd_cwnd += vars->WAD_CwndAdjust;
2539 +               vars->WAD_CwndAdjust = 0;
2540 +               tp->snd_cwnd_stamp = tcp_time_stamp;
2541 +               tp->snd_cwnd = min(tp->snd_cwnd, (__u32)tp->snd_cwnd_clamp);
2542 +               return;
2543 +       }
2544 +#endif
2545 +#endif 
2546 +       
2547         icsk->icsk_ca_ops->cong_avoid(sk, ack, in_flight);
2548         tcp_sk(sk)->snd_cwnd_stamp = tcp_time_stamp;
2549  }
2550 @@ -3428,10 +3475,12 @@
2551                                 tp->max_window = nwin;
2552                                 tcp_sync_mss(sk, inet_csk(sk)->icsk_pmtu_cookie);
2553                         }
2554 +                       WEB100_UPDATE_FUNC(tp, web100_update_rwin_rcvd(tp));
2555                 }
2556         }
2557  
2558         tp->snd_una = ack;
2559 +       WEB100_UPDATE_FUNC(tp, web100_update_snd_una(tp));
2560  
2561         return flag;
2562  }
2563 @@ -3623,6 +3672,7 @@
2564                  */
2565                 tcp_update_wl(tp, ack_seq);
2566                 tp->snd_una = ack;
2567 +               WEB100_UPDATE_FUNC(tp, web100_update_snd_una(tp));
2568                 flag |= FLAG_WIN_UPDATE;
2569  
2570                 tcp_ca_event(sk, CA_EVENT_FAST_ACK);
2571 @@ -3639,8 +3689,10 @@
2572                 if (TCP_SKB_CB(skb)->sacked)
2573                         flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una);
2574  
2575 -               if (TCP_ECN_rcv_ecn_echo(tp, tcp_hdr(skb)))
2576 +               if (TCP_ECN_rcv_ecn_echo(tp, tcp_hdr(skb))) {
2577                         flag |= FLAG_ECE;
2578 +                       WEB100_VAR_INC(tp, ECERcvd);
2579 +               }
2580  
2581                 tcp_ca_event(sk, CA_EVENT_SLOW_ACK);
2582         }
2583 @@ -4118,6 +4170,8 @@
2584  {
2585         struct tcp_sock *tp = tcp_sk(sk);
2586  
2587 +       WEB100_VAR_INC(tp, DupAcksOut);
2588 +
2589         if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq &&
2590             before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
2591                 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_DELAYEDACKLOST);
2592 @@ -4371,6 +4425,10 @@
2593  
2594                 tcp_fast_path_check(sk);
2595  
2596 +#ifdef CONFIG_WEB100_STATS
2597 +               web100_update_recvq(sk);
2598 +#endif
2599 +
2600                 if (eaten > 0)
2601                         __kfree_skb(skb);
2602                 else if (!sock_flag(sk, SOCK_DEAD))
2603 @@ -4425,6 +4483,9 @@
2604         SOCK_DEBUG(sk, "out of order segment: rcv_next %X seq %X - %X\n",
2605                    tp->rcv_nxt, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq);
2606  
2607 +#ifdef CONFIG_WEB100_STATS
2608 +       web100_update_recvq(sk);
2609 +#endif
2610         skb_set_owner_r(skb, sk);
2611  
2612         if (!skb_peek(&tp->out_of_order_queue)) {
2613 @@ -4778,6 +4839,8 @@
2614                 if (win_used < tp->snd_cwnd) {
2615                         tp->snd_ssthresh = tcp_current_ssthresh(sk);
2616                         tp->snd_cwnd = (tp->snd_cwnd + win_used) >> 1;
2617 +                       WEB100_VAR_INC(tp, OtherReductions);
2618 +                       WEB100_VAR_INC(tp, X_OtherReductionsCV);
2619                 }
2620                 tp->snd_cwnd_used = 0;
2621         }
2622 @@ -5308,6 +5371,9 @@
2623                                 tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
2624                         }
2625  
2626 +#ifdef CONFIG_WEB100_STATS
2627 +                       web100_update_recvq(sk);
2628 +#endif
2629                         tcp_event_data_recv(sk, skb);
2630  
2631                         if (TCP_SKB_CB(skb)->ack_seq != tp->snd_una) {
2632 @@ -5476,6 +5542,9 @@
2633                 tp->copied_seq = tp->rcv_nxt;
2634                 smp_mb();
2635                 tcp_set_state(sk, TCP_ESTABLISHED);
2636 +#ifdef CONFIG_WEB100_STATS
2637 +               web100_stats_establish(sk);
2638 +#endif
2639  
2640                 security_inet_conn_established(sk, skb);
2641  
2642 @@ -5694,6 +5763,9 @@
2643                                 smp_mb();
2644                                 tcp_set_state(sk, TCP_ESTABLISHED);
2645                                 sk->sk_state_change(sk);
2646 +#ifdef CONFIG_WEB100_STATS
2647 +                               web100_stats_establish(sk);
2648 +#endif
2649  
2650                                 /* Note, that this wakeup is only for marginal
2651                                  * crossed SYN case. Passively open sockets
2652 diff -Naur linux-2.6.32-27.planetlab.i686.orig/net/ipv4/tcp_ipv4.c linux-2.6.32-27.planetlab.i686/net/ipv4/tcp_ipv4.c
2653 --- linux-2.6.32-27.planetlab.i686.orig/net/ipv4/tcp_ipv4.c     2011-11-16 16:51:07.414470925 -0500
2654 +++ linux-2.6.32-27.planetlab.i686/net/ipv4/tcp_ipv4.c  2011-11-16 17:04:35.157317153 -0500
2655 @@ -243,6 +243,10 @@
2656                                                            inet->daddr,
2657                                                            inet->sport,
2658                                                            usin->sin_port);
2659 +       WEB100_VAR_SET(tp, SndISS, tp->write_seq);
2660 +       WEB100_VAR_SET(tp, SndMax, tp->write_seq);
2661 +       WEB100_VAR_SET(tp, SndNxt, tp->write_seq);
2662 +       WEB100_VAR_SET(tp, SndUna, tp->write_seq);
2663  
2664         inet->id = tp->write_seq ^ jiffies;
2665  
2666 @@ -381,6 +385,7 @@
2667  
2668         switch (type) {
2669         case ICMP_SOURCE_QUENCH:
2670 +               WEB100_VAR_INC(tp, QuenchRcvd);
2671                 /* Just silently ignore these. */
2672                 goto out;
2673         case ICMP_PARAMETERPROB:
2674 @@ -1373,6 +1378,13 @@
2675         newsk = tcp_create_openreq_child(sk, req, skb);
2676         if (!newsk)
2677                 goto exit_nonewsk;
2678 +#ifdef CONFIG_WEB100_STATS
2679 +       if (web100_stats_create(newsk)) {
2680 +               sk_free(newsk);
2681 +               goto exit;
2682 +       }
2683 +       tcp_sk(newsk)->tcp_stats->wc_vars.LocalAddressType = WC_ADDRTYPE_IPV4;
2684 +#endif
2685  
2686         newsk->sk_gso_type = SKB_GSO_TCPV4;
2687         sk_setup_caps(newsk, dst);
2688 @@ -1626,6 +1638,7 @@
2689         inet_rps_save_rxhash(sk, skb->rxhash);
2690  
2691         bh_lock_sock_nested(sk);
2692 +       WEB100_UPDATE_FUNC(tcp_sk(sk), web100_update_segrecv(tcp_sk(sk), skb));
2693         ret = 0;
2694         if (!sock_owned_by_user(sk)) {
2695  #ifdef CONFIG_NET_DMA
2696 @@ -1644,6 +1657,7 @@
2697                 bh_unlock_sock(sk);
2698                 goto discard_and_relse;
2699         }
2700 +       WEB100_UPDATE_FUNC(tcp_sk(sk), web100_update_cwnd(tcp_sk(sk)));
2701         bh_unlock_sock(sk);
2702  
2703         sock_put(sk);
2704 @@ -1837,6 +1851,16 @@
2705         sk->sk_sndbuf = sysctl_tcp_wmem[1];
2706         sk->sk_rcvbuf = sysctl_tcp_rmem[1];
2707  
2708 +#ifdef CONFIG_WEB100_STATS
2709 +       {
2710 +               int err;
2711 +               if ((err = web100_stats_create(sk))) {
2712 +                       return err;
2713 +               }
2714 +               tcp_sk(sk)->tcp_stats->wc_vars.LocalAddressType = WC_ADDRTYPE_IPV4;
2715 +       }
2716 +#endif
2717 +
2718         local_bh_disable();
2719         percpu_counter_inc(&tcp_sockets_allocated);
2720         local_bh_enable();
2721 @@ -1879,6 +1903,10 @@
2722         if (inet_csk(sk)->icsk_bind_hash)
2723                 inet_put_port(sk);
2724  
2725 +#ifdef CONFIG_WEB100_STATS
2726 +       web100_stats_destroy(tcp_sk(sk)->tcp_stats);
2727 +#endif
2728 +
2729         /*
2730          * If sendmsg cached page exists, toss it.
2731          */
2732 diff -Naur linux-2.6.32-27.planetlab.i686.orig/net/ipv4/tcp_minisocks.c linux-2.6.32-27.planetlab.i686/net/ipv4/tcp_minisocks.c
2733 --- linux-2.6.32-27.planetlab.i686.orig/net/ipv4/tcp_minisocks.c        2011-11-16 16:51:07.414470925 -0500
2734 +++ linux-2.6.32-27.planetlab.i686/net/ipv4/tcp_minisocks.c     2011-11-16 16:51:06.109471129 -0500
2735 @@ -337,6 +337,8 @@
2736                 } while (0);
2737  #endif
2738  
2739 +               WEB100_VAR_SET(tp, State, WC_STATE_TIMEWAIT);
2740 +               
2741                 /* Linkage updates. */
2742                 __inet_twsk_hashdance(tw, sk, &tcp_hashinfo);
2743  
2744 diff -Naur linux-2.6.32-27.planetlab.i686.orig/net/ipv4/tcp_output.c linux-2.6.32-27.planetlab.i686/net/ipv4/tcp_output.c
2745 --- linux-2.6.32-27.planetlab.i686.orig/net/ipv4/tcp_output.c   2011-11-16 16:51:07.409470962 -0500
2746 +++ linux-2.6.32-27.planetlab.i686/net/ipv4/tcp_output.c        2011-11-16 16:51:06.104471116 -0500
2747 @@ -67,6 +67,7 @@
2748  
2749         tcp_advance_send_head(sk, skb);
2750         tp->snd_nxt = TCP_SKB_CB(skb)->end_seq;
2751 +       WEB100_UPDATE_FUNC(tp, web100_update_snd_nxt(tp));
2752  
2753         /* Don't override Nagle indefinately with F-RTO */
2754         if (tp->frto_counter == 2)
2755 @@ -260,6 +261,7 @@
2756         }
2757         tp->rcv_wnd = new_win;
2758         tp->rcv_wup = tp->rcv_nxt;
2759 +       WEB100_UPDATE_FUNC(tp, web100_update_rwin_sent(tp));
2760  
2761         /* Make sure we do not exceed the maximum possible
2762          * scaled window.
2763 @@ -714,11 +716,32 @@
2764         if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq)
2765                 TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS);
2766  
2767 +#ifdef CONFIG_WEB100_STATS
2768 +       {
2769 +               /* If the skb isn't cloned, we can't reference it after
2770 +                * calling queue_xmit, so copy everything we need here. */
2771 +               int len = skb->len;
2772 +               int pcount = tcp_skb_pcount(skb);
2773 +               __u32 seq = TCP_SKB_CB(skb)->seq;
2774 +               __u32 end_seq = TCP_SKB_CB(skb)->end_seq;
2775 +               int flags = TCP_SKB_CB(skb)->flags;
2776 +               
2777 +               err = icsk->icsk_af_ops->queue_xmit(skb, 0);
2778 +               if (likely(err == 0))
2779 +                       WEB100_UPDATE_FUNC(tp, web100_update_segsend(sk, len, pcount,
2780 +                                              seq, end_seq, flags));
2781 +       }
2782 +#else
2783         err = icsk->icsk_af_ops->queue_xmit(skb, 0);
2784 +#endif
2785         if (likely(err <= 0))
2786                 return err;
2787  
2788 +#ifdef CONFIG_WEB100_NET100
2789 +       if (!NET100_WAD(tp, WAD_IFQ, sysctl_WAD_IFQ))
2790 +#endif
2791         tcp_enter_cwr(sk, 1);
2792 +       WEB100_VAR_INC(tp, SendStall);
2793  
2794         return net_xmit_eval(err);
2795  }
2796 @@ -1053,6 +1076,7 @@
2797         if (icsk->icsk_mtup.enabled)
2798                 mss_now = min(mss_now, tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_low));
2799         tp->mss_cache = mss_now;
2800 +       WEB100_UPDATE_FUNC(tp, web100_update_mss(tp));
2801  
2802         return mss_now;
2803  }
2804 @@ -1247,20 +1271,22 @@
2805   * should be put on the wire right now.  If so, it returns the number of
2806   * packets allowed by the congestion window.
2807   */
2808 -static unsigned int tcp_snd_test(struct sock *sk, struct sk_buff *skb,
2809 +static int tcp_snd_wait(struct sock *sk, struct sk_buff *skb,
2810                                  unsigned int cur_mss, int nonagle)
2811  {
2812         struct tcp_sock *tp = tcp_sk(sk);
2813 -       unsigned int cwnd_quota;
2814 +       int cwnd_quota;
2815  
2816         tcp_init_tso_segs(sk, skb, cur_mss);
2817  
2818         if (!tcp_nagle_test(tp, skb, cur_mss, nonagle))
2819 -               return 0;
2820 +               return -WC_SNDLIM_SENDER;
2821  
2822         cwnd_quota = tcp_cwnd_test(tp, skb);
2823 -       if (cwnd_quota && !tcp_snd_wnd_test(tp, skb, cur_mss))
2824 -               cwnd_quota = 0;
2825 +       if (!cwnd_quota)
2826 +               return -WC_SNDLIM_CWND;
2827 +       if (!tcp_snd_wnd_test(tp, skb, cur_mss))
2828 +               return -WC_SNDLIM_RWIN;
2829  
2830         return cwnd_quota;
2831  }
2832 @@ -1272,9 +1298,9 @@
2833         struct sk_buff *skb = tcp_send_head(sk);
2834  
2835         return (skb &&
2836 -               tcp_snd_test(sk, skb, tcp_current_mss(sk),
2837 +               tcp_snd_wait(sk, skb, tcp_current_mss(sk),
2838                              (tcp_skb_is_last(sk, skb) ?
2839 -                             tp->nonagle : TCP_NAGLE_PUSH)));
2840 +                             tp->nonagle : TCP_NAGLE_PUSH)) > 0);
2841  }
2842  
2843  /* Trim TSO SKB to LEN bytes, put the remaining data into a new packet
2844 @@ -1551,6 +1577,7 @@
2845         unsigned int tso_segs, sent_pkts;
2846         int cwnd_quota;
2847         int result;
2848 +       int why = WC_SNDLIM_NONE;
2849  
2850         sent_pkts = 0;
2851  
2852 @@ -1571,20 +1598,29 @@
2853                 BUG_ON(!tso_segs);
2854  
2855                 cwnd_quota = tcp_cwnd_test(tp, skb);
2856 -               if (!cwnd_quota)
2857 +               if (!cwnd_quota) {
2858 +                       why = WC_SNDLIM_CWND;
2859                         break;
2860 +               }
2861  
2862 -               if (unlikely(!tcp_snd_wnd_test(tp, skb, mss_now)))
2863 +               if (unlikely(!tcp_snd_wnd_test(tp, skb, mss_now))) {
2864 +                       why = WC_SNDLIM_RWIN;
2865                         break;
2866 +               }
2867  
2868                 if (tso_segs == 1) {
2869                         if (unlikely(!tcp_nagle_test(tp, skb, mss_now,
2870                                                      (tcp_skb_is_last(sk, skb) ?
2871 -                                                     nonagle : TCP_NAGLE_PUSH))))
2872 +                                                     nonagle : TCP_NAGLE_PUSH)))) {
2873 +                               why = WC_SNDLIM_SENDER;
2874                                 break;
2875 +                       }
2876                 } else {
2877 -                       if (!push_one && tcp_tso_should_defer(sk, skb))
2878 +                       if (!push_one && tcp_tso_should_defer(sk, skb)) {
2879 +                               /* XXX: is this sender or cwnd? */
2880 +                               why = WC_SNDLIM_SENDER;
2881                                 break;
2882 +                       }
2883                 }
2884  
2885                 limit = mss_now;
2886 @@ -1598,8 +1634,10 @@
2887  
2888                 TCP_SKB_CB(skb)->when = tcp_time_stamp;
2889  
2890 -               if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp)))
2891 +               if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp))) {
2892 +                       why = WC_SNDLIM_SENDER;
2893                         break;
2894 +               }
2895  
2896                 /* Advance the send_head.  This one is sent out.
2897                  * This call will increment packets_out.
2898 @@ -1612,6 +1650,9 @@
2899                 if (push_one)
2900                         break;
2901         }
2902 +       if (why == WC_SNDLIM_NONE)
2903 +               why = WC_SNDLIM_SENDER;
2904 +       WEB100_UPDATE_FUNC(tp, web100_update_sndlim(tp, why));
2905  
2906         if (likely(sent_pkts)) {
2907                 tcp_cwnd_validate(sk);
2908 @@ -1769,6 +1810,9 @@
2909                         window = free_space;
2910         }
2911  
2912 +       WEB100_VAR_SET(tp, X_dbg3, free_space);
2913 +       WEB100_VAR_SET(tp, X_dbg2, mss);
2914 +       WEB100_VAR_SET(tp, X_dbg1, window);
2915         return window;
2916  }
2917  
2918 @@ -2355,6 +2399,7 @@
2919         tp->snd_wnd = 0;
2920         tcp_init_wl(tp, 0);
2921         tp->snd_una = tp->write_seq;
2922 +       WEB100_VAR_SET(tp, SndUna, tp->snd_una);
2923         tp->snd_sml = tp->write_seq;
2924         tp->snd_up = tp->write_seq;
2925         tp->rcv_nxt = 0;
2926 @@ -2399,6 +2444,7 @@
2927          * in order to make this packet get counted in tcpOutSegs.
2928          */
2929         tp->snd_nxt = tp->write_seq;
2930 +       WEB100_UPDATE_FUNC(tp, web100_update_snd_nxt(tp));
2931         tp->pushed_seq = tp->write_seq;
2932         TCP_INC_STATS(sock_net(sk), TCP_MIB_ACTIVEOPENS);
2933  
2934 diff -Naur linux-2.6.32-27.planetlab.i686.orig/net/ipv4/tcp_timer.c linux-2.6.32-27.planetlab.i686/net/ipv4/tcp_timer.c
2935 --- linux-2.6.32-27.planetlab.i686.orig/net/ipv4/tcp_timer.c    2011-11-16 16:51:07.413470925 -0500
2936 +++ linux-2.6.32-27.planetlab.i686/net/ipv4/tcp_timer.c 2011-11-16 16:51:06.108471039 -0500
2937 @@ -349,6 +349,7 @@
2938                 }
2939                 NET_INC_STATS_BH(sock_net(sk), mib_idx);
2940         }
2941 +       WEB100_UPDATE_FUNC(tp, web100_update_timeout(sk));
2942  
2943         if (tcp_use_frto(sk)) {
2944                 tcp_enter_frto(sk);
2945 @@ -384,6 +385,7 @@
2946          * the 120 second clamps though!
2947          */
2948         icsk->icsk_backoff++;
2949 +       WEB100_VAR_SET(tcp_sk(sk), CurTimeoutCount, icsk->icsk_backoff);
2950         icsk->icsk_retransmits++;
2951  
2952  out_reset_timer:
2953 diff -Naur linux-2.6.32-27.planetlab.i686.orig/net/ipv4/web100_stats.c linux-2.6.32-27.planetlab.i686/net/ipv4/web100_stats.c
2954 --- linux-2.6.32-27.planetlab.i686.orig/net/ipv4/web100_stats.c 1969-12-31 19:00:00.000000000 -0500
2955 +++ linux-2.6.32-27.planetlab.i686/net/ipv4/web100_stats.c      2011-11-16 16:51:06.106470968 -0500
2956 @@ -0,0 +1,704 @@
2957 +/*     
2958 + * net/ipv4/web100_stats.c
2959 + *
2960 + * Copyright (C) 2001 Matt Mathis <mathis@psc.edu>
2961 + * Copyright (C) 2001 John Heffner <jheffner@psc.edu>
2962 + * Copyright (C) 2000 Jeffrey Semke <semke@psc.edu>
2963 + *
2964 + * The Web 100 project.  See http://www.web100.org
2965 + *
2966 + *     Functions for creating, destroying, and updating the Web100
2967 + *     statistics structure.
2968 + *
2969 + * This program is free software; you can redistribute it and/or
2970 + * modify it under the terms of the GNU General Public License
2971 + * as published by the Free Software Foundation; either version
2972 + * 2 of the License, or (at your option) any later version.
2973 + *
2974 + */
2975 +
2976 +#include <linux/types.h>
2977 +#include <linux/bootmem.h>
2978 +#include <linux/socket.h>
2979 +#include <net/web100.h>
2980 +#include <net/tcp.h>
2981 +#include <linux/string.h>
2982 +#include <linux/proc_fs.h>
2983 +#include <asm/atomic.h>
2984 +
2985 +#define WC_INF32       0xffffffff
2986 +
2987 +#define WC_DEATH_SLOTS 8
2988 +#define WC_PERSIST_TIME        60
2989 +
2990 +/* BEWARE: The release process updates the version string */
2991 +char *web100_version_string = "2.5.27 201001301335"
2992 +#ifdef CONFIG_WEB100_NET100
2993 +    " net100"
2994 +#endif
2995 +    ;
2996 +
2997 +static void death_cleanup(unsigned long dummy);
2998 +
2999 +/* Global stats reader-writer lock */
3000 +rwlock_t web100_linkage_lock = RW_LOCK_UNLOCKED;
3001 +
3002 +/* Data structures for tying together stats */
3003 +static int web100stats_next_cid;
3004 +static int web100stats_conn_num;
3005 +static int web100stats_htsize;
3006 +struct web100stats **web100stats_ht;
3007 +struct web100stats *web100stats_first = NULL;
3008 +
3009 +static struct web100stats *death_slots[WC_DEATH_SLOTS];
3010 +static int cur_death_slot;
3011 +static spinlock_t death_lock = SPIN_LOCK_UNLOCKED;
3012 +static struct timer_list stats_persist_timer = TIMER_INITIALIZER(death_cleanup, 0, 0);
3013 +static int ndeaths;
3014 +
3015 +#ifdef CONFIG_WEB100_NETLINK
3016 +static struct sock *web100_nlsock;
3017 +#endif
3018 +
3019 +extern struct proc_dir_entry *proc_web100_dir;
3020 +
3021 +
3022 +/*
3023 + * Structural maintainance
3024 + */
3025 +
3026 +static inline int web100stats_hash(int cid)
3027 +{
3028 +       return cid % web100stats_htsize;
3029 +}
3030 +
3031 +struct web100stats *web100stats_lookup(int cid)
3032 +{
3033 +       struct web100stats *stats;
3034 +       
3035 +       /* Let's ensure safety here.  It's not too expensive and may change. */
3036 +       if (cid < 0 || cid >= WEB100_MAX_CONNS)
3037 +               return NULL;
3038 +       
3039 +       stats = web100stats_ht[web100stats_hash(cid)];
3040 +       while (stats && stats->wc_cid != cid)
3041 +               stats = stats->wc_hash_next;
3042 +       return stats;
3043 +}
3044 +
3045 +/* This will get really slow as the cid space fills.  This can be done
3046 + * better, but it's just not worth it right now.
3047 + * The caller must hold the lock.
3048 + */
3049 +static int get_next_cid(void)
3050 +{
3051 +       int i;
3052 +       
3053 +       if (web100stats_conn_num >= WEB100_MAX_CONNS)
3054 +               return -1;
3055 +       
3056 +       i = web100stats_next_cid;
3057 +       do {
3058 +               if (web100stats_lookup(i) == NULL)
3059 +                       break;
3060 +               i = (i + 1) % WEB100_MAX_CONNS;
3061 +       } while (i != web100stats_next_cid);
3062 +       web100stats_next_cid = (i + 1) % WEB100_MAX_CONNS;
3063 +       
3064 +       return i;
3065 +}
3066 +
3067 +static void stats_link(struct web100stats *stats)
3068 +{
3069 +       int hash;
3070 +       
3071 +       write_lock_bh(&web100_linkage_lock);
3072 +       
3073 +       if ((stats->wc_cid = get_next_cid()) < 0) {
3074 +               write_unlock_bh(&web100_linkage_lock);
3075 +               return;
3076 +       }
3077 +       
3078 +       hash = web100stats_hash(stats->wc_cid);
3079 +       stats->wc_hash_next = web100stats_ht[hash];
3080 +       stats->wc_hash_prev = NULL;
3081 +       if (web100stats_ht[hash])
3082 +               web100stats_ht[hash]->wc_hash_prev = stats;
3083 +       web100stats_ht[hash] = stats;
3084 +       
3085 +       stats->wc_next = web100stats_first;
3086 +       stats->wc_prev = NULL;
3087 +       if (web100stats_first)
3088 +               web100stats_first->wc_prev = stats;
3089 +       web100stats_first = stats;
3090 +       
3091 +       web100stats_conn_num++;
3092 +       proc_web100_dir->nlink = web100stats_conn_num + 2;
3093 +       
3094 +       write_unlock_bh(&web100_linkage_lock);
3095 +}
3096 +
3097 +static void stats_unlink(struct web100stats *stats)
3098 +{
3099 +       int hash;
3100 +       
3101 +       write_lock_bh(&web100_linkage_lock);
3102 +       
3103 +       hash = web100stats_hash(stats->wc_cid);
3104 +       if (stats->wc_hash_next)
3105 +               stats->wc_hash_next->wc_hash_prev = stats->wc_hash_prev;
3106 +       if (stats->wc_hash_prev)
3107 +               stats->wc_hash_prev->wc_hash_next = stats->wc_hash_next;
3108 +       if (stats == web100stats_ht[hash])
3109 +               web100stats_ht[hash] = stats->wc_hash_next ?
3110 +                                       stats->wc_hash_next :
3111 +                                       stats->wc_hash_prev;
3112 +       
3113 +       if (stats->wc_next)
3114 +               stats->wc_next->wc_prev = stats->wc_prev;
3115 +       if (stats->wc_prev)
3116 +               stats->wc_prev->wc_next = stats->wc_next;
3117 +       if (stats == web100stats_first)
3118 +               web100stats_first = stats->wc_next ? stats->wc_next :
3119 +                                                     stats->wc_prev;
3120 +       
3121 +       web100stats_conn_num--;
3122 +       proc_web100_dir->nlink = web100stats_conn_num + 2;
3123 +       
3124 +       write_unlock_bh(&web100_linkage_lock);
3125 +}
3126 +
3127 +static void stats_persist(struct web100stats *stats)
3128 +{
3129 +       spin_lock_bh(&death_lock);
3130 +       
3131 +       stats->wc_death_next = death_slots[cur_death_slot];
3132 +       death_slots[cur_death_slot] = stats;
3133 +       if (ndeaths <= 0) {
3134 +               stats_persist_timer.expires = jiffies + WC_PERSIST_TIME * HZ / WC_DEATH_SLOTS;
3135 +               add_timer(&stats_persist_timer);
3136 +       }
3137 +       ndeaths++;
3138 +       
3139 +       spin_unlock_bh(&death_lock);
3140 +}
3141 +
3142 +static void death_cleanup(unsigned long dummy)
3143 +{
3144 +       struct web100stats *stats, *next;
3145 +       
3146 +       spin_lock_bh(&death_lock);
3147 +       
3148 +       cur_death_slot = (cur_death_slot + 1) % WC_DEATH_SLOTS;
3149 +       stats = death_slots[cur_death_slot];
3150 +       while (stats) {
3151 +               stats->wc_dead = 1;
3152 +               ndeaths--;
3153 +               next = stats->wc_death_next;
3154 +               web100_stats_unuse(stats);
3155 +               stats = next;
3156 +       }
3157 +       death_slots[cur_death_slot] = NULL;
3158 +
3159 +       if (ndeaths > 0) {
3160 +               stats_persist_timer.expires = jiffies + WC_PERSIST_TIME * HZ / WC_DEATH_SLOTS;
3161 +               add_timer(&stats_persist_timer);
3162 +       }
3163 +       
3164 +       spin_unlock_bh(&death_lock);
3165 +}
3166 +
3167 +
3168 +/* Tom Dunigan's (slightly modified) netlink code.  Notifies listening apps
3169 + * of Web100 events.
3170 + *
3171 + * NOTE: we are currently squatting on netlink family 10 (NETLINK_WEB100) in
3172 + * include/linux/netlink.h
3173 + */
3174 +
3175 +#ifdef CONFIG_WEB100_NETLINK
3176 +void web100_netlink_event(int type, int cid)
3177 +{
3178 +       struct web100_netlink_msg *msg;
3179 +       struct sk_buff *tmpskb;
3180 +       
3181 +       if (web100_nlsock == NULL)
3182 +               return;
3183 +       
3184 +       if ((tmpskb = alloc_skb((sizeof (struct web100_netlink_msg)), GFP_ATOMIC)) == NULL) {
3185 +               printk(KERN_INFO "web100_netlink_event: alloc_skb failure\n");
3186 +               return;
3187 +       }
3188 +       
3189 +       skb_put(tmpskb, sizeof (struct web100_netlink_msg));
3190 +       msg = (struct web100_netlink_msg *)tmpskb->data;
3191 +       msg->type = type;
3192 +       msg->cid = cid;
3193 +       netlink_broadcast(web100_nlsock, tmpskb, 0, ~0, GFP_ATOMIC);
3194 +}
3195 +#endif /* CONFIG_WEB100_NETLINK */
3196 +
3197 +extern __u32 sysctl_wmem_default;
3198 +extern __u32 sysctl_rmem_default;
3199 +
3200 +/* Called whenever a TCP/IPv4 sock is created.
3201 + * net/ipv4/tcp_ipv4.c: tcp_v4_syn_recv_sock,
3202 + *                     tcp_v4_init_sock
3203 + * Allocates a stats structure and initializes values.
3204 + */
3205 +int web100_stats_create(struct sock *sk)
3206 +{
3207 +       struct web100stats *stats;
3208 +       struct web100directs *vars;
3209 +       struct tcp_sock *tp = tcp_sk(sk);
3210 +       struct timeval tv;
3211 +       
3212 +       if ((stats = kmalloc(sizeof (struct web100stats), gfp_any())) == NULL)
3213 +               return -ENOMEM;
3214 +       tp->tcp_stats = stats;
3215 +       vars = &stats->wc_vars;
3216 +       
3217 +       memset(stats, 0, sizeof (struct web100stats));
3218 +       
3219 +       stats->wc_cid = -1;
3220 +       stats->wc_sk = sk;
3221 +       atomic_set(&stats->wc_users, 0);
3222 +       
3223 +       stats->wc_limstate = WC_SNDLIM_STARTUP;
3224 +       stats->wc_limstate_time = web100_mono_time();
3225 +       
3226 +       vars->NagleEnabled = !(tp->nonagle);
3227 +       vars->ActiveOpen = !in_interrupt();
3228 +       
3229 +       vars->SndUna = tp->snd_una;
3230 +       vars->SndNxt = tp->snd_nxt;
3231 +       vars->SndMax = tp->snd_nxt;
3232 +       vars->SndISS = tp->snd_nxt;
3233 +       
3234 +       do_gettimeofday(&tv);
3235 +       vars->StartTime = tv.tv_sec * 10 + tv.tv_usec / 100000;
3236 +       vars->StartTimeSec = tv.tv_sec;
3237 +       vars->StartTimeUsec = tv.tv_usec;
3238 +       stats->wc_start_monotime = web100_mono_time();
3239 +       
3240 +       vars->MinRTT = vars->MinRTO = vars->MinMSS = vars->MinRwinRcvd =
3241 +               vars->MinRwinSent = vars->MinSsthresh = WC_INF32;
3242 +       
3243 +       vars->LimRwin = tp->window_clamp;
3244 +       
3245 +       sock_hold(sk);
3246 +       web100_stats_use(stats);
3247 +       
3248 +       return 0;
3249 +}
3250 +
3251 +void web100_stats_destroy(struct web100stats *stats)
3252 +{
3253 +       /* Attribute final sndlim time. */
3254 +       web100_update_sndlim(tcp_sk(stats->wc_sk), stats->wc_limstate);
3255 +       
3256 +       if (stats->wc_cid >= 0) {
3257 +#ifdef CONFIG_WEB100_NETLINK
3258 +               web100_netlink_event(WC_NL_TYPE_DISCONNECT, stats->wc_cid);
3259 +#endif
3260 +               stats_persist(stats);
3261 +       } else {
3262 +               web100_stats_unuse(stats);
3263 +       }
3264 +}
3265 +
3266 +/* Do not call directly.  Called from web100_stats_unuse(). */
3267 +void web100_stats_free(struct web100stats *stats)
3268 +{
3269 +       if (stats->wc_cid >= 0) {
3270 +               stats_unlink(stats);
3271 +       }
3272 +       sock_put(stats->wc_sk);
3273 +       kfree(stats);
3274 +}
3275 +
3276 +extern __u32 sysctl_wmem_default;
3277 +extern __u32 sysctl_rmem_default;
3278 +
3279 +/* Called when a connection enters the ESTABLISHED state, and has all its
3280 + * state initialized.
3281 + * net/ipv4/tcp_input.c: tcp_rcv_state_process,
3282 + *                      tcp_rcv_synsent_state_process
3283 + * Here we link the statistics structure in so it is visible in the /proc
3284 + * fs, and do some final init.
3285 + */
3286 +void web100_stats_establish(struct sock *sk)
3287 +{
3288 +       struct inet_sock *inet = inet_sk(sk);
3289 +       struct tcp_sock *tp = tcp_sk(sk);
3290 +       struct web100stats *stats = tp->tcp_stats;
3291 +       struct web100directs *vars = &stats->wc_vars;
3292 +       
3293 +       if (stats == NULL)
3294 +               return;
3295 +       
3296 +       /* Let's set these here, since they can't change once the
3297 +        * connection is established.
3298 +        */
3299 +       vars->LocalPort = inet->num;
3300 +       vars->RemPort = ntohs(inet->dport);
3301 +       
3302 +       if (vars->LocalAddressType == WC_ADDRTYPE_IPV4) {
3303 +               vars->LocalAddress.v4addr = inet->rcv_saddr;
3304 +               vars->RemAddress.v4addr = inet->daddr;
3305 +       }
3306 +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3307 +       else if (vars->LocalAddressType == WC_ADDRTYPE_IPV6) {
3308 +               memcpy(&vars->LocalAddress.v6addr.addr, &(inet6_sk(sk)->saddr), 16);
3309 +               memcpy(&vars->RemAddress.v6addr.addr, &(inet6_sk(sk)->daddr), 16);
3310 +       }
3311 +#endif
3312 +       else {
3313 +               printk(KERN_ERR "Web100: LocalAddressType not valid.\n");
3314 +       }
3315 +       vars->LocalAddress.v6addr.type = vars->RemAddress.v6addr.type = vars->LocalAddressType;
3316 +       
3317 +       vars->SACKEnabled = tp->rx_opt.sack_ok;
3318 +       vars->TimestampsEnabled = tp->rx_opt.tstamp_ok;
3319 +#ifdef CONFIG_INET_ECN
3320 +       vars->ECNEnabled = tp->ecn_flags & TCP_ECN_OK;
3321 +#endif
3322 +       
3323 +       if (tp->rx_opt.wscale_ok) {
3324 +               vars->WinScaleRcvd = tp->rx_opt.snd_wscale;
3325 +               vars->WinScaleSent = tp->rx_opt.rcv_wscale;
3326 +       } else {
3327 +               vars->WinScaleRcvd = -1;
3328 +               vars->WinScaleSent = -1;
3329 +       }
3330 +       vars->SndWinScale = vars->WinScaleRcvd;
3331 +       vars->RcvWinScale = vars->WinScaleSent;
3332 +       
3333 +       vars->CurCwnd = tp->snd_cwnd * tp->mss_cache;
3334 +       vars->CurSsthresh = tp->snd_ssthresh * tp->mss_cache;
3335 +       web100_update_cwnd(tp);
3336 +       web100_update_rwin_rcvd(tp);
3337 +       web100_update_rwin_sent(tp);
3338 +       
3339 +       vars->RecvISS = vars->RcvNxt = tp->rcv_nxt;
3340 +       
3341 +       vars->RetranThresh = tp->reordering;
3342 +       
3343 +       vars->LimRwin = min_t(__u32, vars->LimRwin, 65355U << tp->rx_opt.rcv_wscale);
3344 +       
3345 +       stats_link(stats);
3346 +       
3347 +       web100_update_sndlim(tp, WC_SNDLIM_SENDER);
3348 +       
3349 +#ifdef CONFIG_WEB100_NETLINK
3350 +       web100_netlink_event(WC_NL_TYPE_CONNECT, stats->wc_cid);
3351 +#endif
3352 +}
3353 +
3354 +/*
3355 + * Statistics update functions
3356 + */
3357 +
3358 +void web100_update_snd_nxt(struct tcp_sock *tp)
3359 +{
3360 +       struct web100stats *stats = tp->tcp_stats;
3361 +       
3362 +       if (after(tp->snd_nxt, stats->wc_vars.SndMax)) {
3363 +               if (before(stats->wc_vars.SndMax, stats->wc_vars.SndISS) &&
3364 +                   after(tp->snd_nxt, stats->wc_vars.SndISS))
3365 +                       stats->wc_vars.SendWraps++;
3366 +               stats->wc_vars.SndMax = tp->snd_nxt;
3367 +       }
3368 +       stats->wc_vars.SndNxt = tp->snd_nxt;
3369 +}
3370 +
3371 +void web100_update_snd_una(struct tcp_sock *tp)
3372 +{
3373 +       struct web100stats *stats = tp->tcp_stats;
3374 +       
3375 +       stats->wc_vars.ThruBytesAcked += (__u32)(tp->snd_una - stats->wc_vars.SndUna);
3376 +       stats->wc_vars.SndUna = tp->snd_una;
3377 +}
3378 +
3379 +void web100_update_rtt(struct sock *sk, unsigned long rtt_sample)
3380 +{
3381 +       struct web100stats *stats = tcp_sk(sk)->tcp_stats;
3382 +        unsigned long rtt_sample_msec = rtt_sample * 1000 / HZ;
3383 +        __u32 rto;
3384 +       
3385 +       stats->wc_vars.SampleRTT = rtt_sample_msec;
3386 +
3387 +       if (rtt_sample_msec > stats->wc_vars.MaxRTT)
3388 +               stats->wc_vars.MaxRTT = rtt_sample_msec;
3389 +       if (rtt_sample_msec < stats->wc_vars.MinRTT)
3390 +               stats->wc_vars.MinRTT = rtt_sample_msec;
3391 +       
3392 +       stats->wc_vars.CountRTT++;
3393 +       stats->wc_vars.SumRTT += rtt_sample_msec;
3394 +
3395 +       if (stats->wc_vars.PreCongCountRTT != stats->wc_vars.PostCongCountRTT) {
3396 +               stats->wc_vars.PostCongCountRTT++;
3397 +               stats->wc_vars.PostCongSumRTT += rtt_sample_msec;
3398 +       }
3399 +       
3400 +       /* srtt is stored as 8 * the smoothed estimate */
3401 +       stats->wc_vars.SmoothedRTT =
3402 +               (tcp_sk(sk)->srtt >> 3) * 1000 / HZ;
3403 +       
3404 +       rto = inet_csk(sk)->icsk_rto * 1000 / HZ;
3405 +       if (rto > stats->wc_vars.MaxRTO)
3406 +               stats->wc_vars.MaxRTO = rto;
3407 +       if (rto < stats->wc_vars.MinRTO)
3408 +               stats->wc_vars.MinRTO = rto;
3409 +       stats->wc_vars.CurRTO = rto;
3410 +
3411 +       stats->wc_vars.CurTimeoutCount = 0;
3412 +       
3413 +       stats->wc_vars.RTTVar = (tcp_sk(sk)->rttvar >> 2) * 1000 / HZ;
3414 +}
3415 +
3416 +void web100_update_timeout(struct sock *sk) {
3417 +       struct web100stats *stats = tcp_sk(sk)->tcp_stats;
3418 +
3419 +       stats->wc_vars.CurTimeoutCount++;
3420 +       if (inet_csk(sk)->icsk_backoff)
3421 +               stats->wc_vars.SubsequentTimeouts++;
3422 +       else
3423 +               stats->wc_vars.Timeouts++;
3424 +       if (inet_csk(sk)->icsk_ca_state == TCP_CA_Open)
3425 +               stats->wc_vars.AbruptTimeouts++;
3426 +}
3427 +
3428 +void web100_update_mss(struct tcp_sock *tp)
3429 +{
3430 +       struct web100stats *stats = tp->tcp_stats;
3431 +       int mss = tp->mss_cache;
3432 +       
3433 +       stats->wc_vars.CurMSS = mss;
3434 +       if (mss > stats->wc_vars.MaxMSS)
3435 +               stats->wc_vars.MaxMSS = mss;
3436 +       if (mss < stats->wc_vars.MinMSS)
3437 +               stats->wc_vars.MinMSS = mss;
3438 +}
3439 +
3440 +void web100_update_cwnd(struct tcp_sock *tp)
3441 +{
3442 +       struct web100stats *stats = tp->tcp_stats;
3443 +       __u16 mss = tp->mss_cache;
3444 +       __u32 cwnd;
3445 +       __u32 ssthresh;
3446 +       
3447 +       if (mss == 0) {
3448 +               printk("Web100: web100_update_cwnd: mss == 0\n");
3449 +               return;
3450 +       }
3451 +       
3452 +       cwnd = min(WC_INF32 / mss, tp->snd_cwnd) * mss;
3453 +       stats->wc_vars.CurCwnd = cwnd;
3454 +       if (cwnd > stats->wc_vars.MaxCwnd)
3455 +               stats->wc_vars.MaxCwnd = cwnd;
3456 +       
3457 +       ssthresh = min(WC_INF32 / mss, tp->snd_ssthresh) * mss;
3458 +       stats->wc_vars.CurSsthresh = ssthresh;
3459 +       
3460 +       /* Discard initiail ssthresh set at infinity. */
3461 +       if (tp->snd_ssthresh >= 0x7ffffff) {
3462 +               return;
3463 +       }
3464 +       if (ssthresh > stats->wc_vars.MaxSsthresh)
3465 +               stats->wc_vars.MaxSsthresh = ssthresh;
3466 +       if (ssthresh < stats->wc_vars.MinSsthresh)
3467 +               stats->wc_vars.MinSsthresh = ssthresh;
3468 +}
3469 +
3470 +void web100_update_rwin_rcvd(struct tcp_sock *tp)
3471 +{
3472 +       struct web100stats *stats = tp->tcp_stats;
3473 +       __u32 win = tp->snd_wnd;
3474 +       
3475 +       stats->wc_vars.CurRwinRcvd = win;
3476 +       if (win > stats->wc_vars.MaxRwinRcvd)
3477 +               stats->wc_vars.MaxRwinRcvd = win;
3478 +       if (win < stats->wc_vars.MinRwinRcvd)
3479 +               stats->wc_vars.MinRwinRcvd = win;
3480 +}
3481 +
3482 +void web100_update_rwin_sent(struct tcp_sock *tp)
3483 +{
3484 +       struct web100stats *stats = tp->tcp_stats;
3485 +       __u32 win = tp->rcv_wnd;
3486 +
3487 +       /* Update our advertised window. */
3488 +       stats->wc_vars.CurRwinSent = win;
3489 +       if (win > stats->wc_vars.MaxRwinSent)
3490 +               stats->wc_vars.MaxRwinSent = win;
3491 +       if (win < stats->wc_vars.MinRwinSent)
3492 +               stats->wc_vars.MinRwinSent = win;
3493 +}
3494 +
3495 +
3496 +/* TODO: change this to a generic state machine instrument */
3497 +static void web100_state_update(struct tcp_sock *tp, int why, __u64 bytes)
3498 +{
3499 +       struct web100stats *stats = tp->tcp_stats;
3500 +       __u64 now;
3501 +       
3502 +       now = web100_mono_time();
3503 +       stats->wc_vars.SndLimTime[stats->wc_limstate] += now - stats->wc_limstate_time;
3504 +       stats->wc_limstate_time = now;
3505 +       
3506 +       stats->wc_vars.SndLimBytes[why] += bytes - stats->wc_limstate_bytes;
3507 +       stats->wc_limstate_bytes = bytes;
3508 +       
3509 +       if (stats->wc_limstate != why) {
3510 +               stats->wc_limstate = why;
3511 +               stats->wc_vars.SndLimTrans[why]++;
3512 +       }
3513 +}
3514 +
3515 +void web100_update_sndlim(struct tcp_sock *tp, int why)
3516 +{
3517 +       struct web100stats *stats = tp->tcp_stats;
3518 +       
3519 +       if (why < 0) {
3520 +               printk("web100_update_sndlim: BUG: why < 0\n");
3521 +               return;
3522 +       }
3523 +       
3524 +       web100_state_update(tp, why, stats->wc_vars.DataBytesOut);
3525 +       /* future instruments on other sender bottlenecks here... */
3526 +       /* if (!why) { why = ??? } */
3527 +       /* web100_state_update(tp, why, stats->wc_vars.DataBytesOut); */
3528 +}
3529 +
3530 +void web100_update_congestion(struct tcp_sock *tp, int why_dummy)
3531 +{
3532 +               struct web100stats *stats = tp->tcp_stats;
3533 +       
3534 +       stats->wc_vars.CongestionSignals++;
3535 +       stats->wc_vars.PreCongSumCwnd += stats->wc_vars.CurCwnd;
3536 +
3537 +       /* This may require more control flags */
3538 +       stats->wc_vars.PreCongCountRTT++;
3539 +       stats->wc_vars.PreCongSumRTT += stats->wc_vars.SampleRTT;
3540 +}
3541 +
3542 +/* Called from tcp_transmit_skb, whenever we push a segment onto the wire.
3543 + */
3544 +void web100_update_segsend(struct sock *sk, int len, int pcount,
3545 +                           __u32 seq, __u32 end_seq, int flags)
3546 +{
3547 +       struct web100stats *stats = tcp_sk(sk)->tcp_stats;
3548 +       
3549 +       /* We know we're sending a segment. */
3550 +       stats->wc_vars.PktsOut += pcount;
3551 +       
3552 +       /* We know the ack seq is rcv_nxt. web100_XXX bug compatible*/
3553 +       web100_update_rcv_nxt(tcp_sk(sk));
3554 +       
3555 +       /* A pure ACK contains no data; everything else is data. */
3556 +       if (len > 0) {
3557 +               stats->wc_vars.DataPktsOut += pcount;
3558 +               stats->wc_vars.DataBytesOut += len;
3559 +       } else {
3560 +               stats->wc_vars.AckPktsOut++;
3561 +       }
3562 +       
3563 +       /* Check for retransmission. */
3564 +       if (flags & TCPCB_FLAG_SYN) {
3565 +               if (inet_csk(sk)->icsk_retransmits)
3566 +                       stats->wc_vars.PktsRetrans++;
3567 +       } else if (before(seq, stats->wc_vars.SndMax)) {
3568 +               stats->wc_vars.PktsRetrans += pcount;
3569 +               stats->wc_vars.BytesRetrans += end_seq - seq;
3570 +       }
3571 +}
3572 +
3573 +void web100_update_segrecv(struct tcp_sock *tp, struct sk_buff *skb)
3574 +{
3575 +       struct web100directs *vars = &tp->tcp_stats->wc_vars;
3576 +       struct tcphdr *th = tcp_hdr(skb);
3577 +       
3578 +       vars->PktsIn++;
3579 +       if (skb->len == th->doff*4) {
3580 +               vars->AckPktsIn++;
3581 +               if (TCP_SKB_CB(skb)->ack_seq == tp->snd_una)
3582 +                       vars->DupAcksIn++;
3583 +       } else {
3584 +               vars->DataPktsIn++;
3585 +               vars->DataBytesIn += skb->len - th->doff*4;
3586 +       }
3587 +}
3588 +
3589 +void web100_update_rcv_nxt(struct tcp_sock *tp)
3590 +{
3591 +       struct web100stats *stats = tp->tcp_stats;
3592 +       
3593 +       if (before(stats->wc_vars.RcvNxt, stats->wc_vars.RecvISS) &&
3594 +            after(tp->rcv_nxt, stats->wc_vars.RecvISS))
3595 +               stats->wc_vars.RecvWraps++;
3596 +       stats->wc_vars.ThruBytesReceived += (__u32) (tp->rcv_nxt - stats->wc_vars.RcvNxt); /* XXX */
3597 +       stats->wc_vars.RcvNxt = tp->rcv_nxt;
3598 +}
3599 +
3600 +void web100_update_writeq(struct sock *sk)
3601 +{
3602 +       struct tcp_sock *tp = tcp_sk(sk);
3603 +       struct web100directs *vars = &tp->tcp_stats->wc_vars;
3604 +       int len = tp->write_seq - vars->SndMax;
3605 +       
3606 +       vars->CurAppWQueue = len;
3607 +       if (len > vars->MaxAppWQueue)
3608 +               vars->MaxAppWQueue = len;
3609 +}
3610 +
3611 +void web100_update_recvq(struct sock *sk)
3612 +{
3613 +       struct tcp_sock *tp = tcp_sk(sk);
3614 +       struct web100directs *vars = &tp->tcp_stats->wc_vars;
3615 +       int len1 = tp->rcv_nxt - tp->copied_seq;
3616 +       
3617 +       vars->CurAppRQueue = len1;
3618 +       if (vars->MaxAppRQueue < len1)
3619 +               vars->MaxAppRQueue = len1;
3620 +       
3621 +#if 0 /* FIXME!! */
3622 +       vars->CurReasmQueue = len2;
3623 +       if (vars->MaxReasmQueue < len2)
3624 +               vars->MaxReasmQueue = len2;
3625 +#endif
3626 +}
3627 +
3628 +
3629 +void __init web100_stats_init()
3630 +{
3631 +       int order;
3632 +       
3633 +       memset(death_slots, 0, sizeof (death_slots));
3634 +       
3635 +       web100stats_ht =
3636 +         (struct web100stats **)alloc_large_system_hash("TCP ESTATS",
3637 +                                                        sizeof (struct web100stats *),
3638 +                                                        tcp_hashinfo.ehash_size,
3639 +                                                        (num_physpages >= 128 * 1024) ?
3640 +                                                          13 : 15,
3641 +                                                        0, &order, NULL,
3642 +                                                        64 * 1024);
3643 +       web100stats_htsize = 1 << order;
3644 +       memset(web100stats_ht, 0, web100stats_htsize * sizeof (struct web100stats *));
3645 +       
3646 +#ifdef CONFIG_WEB100_NETLINK
3647 +       if ((web100_nlsock = netlink_kernel_create(&init_net, NETLINK_WEB100, 0, NULL, NULL, NULL)) == NULL)
3648 +               printk(KERN_ERR "web100_stats_init(): cannot initialize netlink socket\n");
3649 +#endif
3650 +       
3651 +       printk("Web100 %s: Initialization successful\n", web100_version_string);
3652 +}
3653 +
3654 +#ifdef CONFIG_IPV6_MODULE
3655 +EXPORT_SYMBOL(web100_stats_create);
3656 +EXPORT_SYMBOL(web100_stats_destroy);
3657 +EXPORT_SYMBOL(web100_update_segrecv);
3658 +EXPORT_SYMBOL(web100_update_cwnd);
3659 +EXPORT_SYMBOL(web100_update_writeq);
3660 +#endif
3661 diff -Naur linux-2.6.32-27.planetlab.i686.orig/net/ipv6/tcp_ipv6.c linux-2.6.32-27.planetlab.i686/net/ipv6/tcp_ipv6.c
3662 --- linux-2.6.32-27.planetlab.i686.orig/net/ipv6/tcp_ipv6.c     2011-11-16 16:51:07.402470961 -0500
3663 +++ linux-2.6.32-27.planetlab.i686/net/ipv6/tcp_ipv6.c  2011-11-16 17:06:57.467410360 -0500
3664 @@ -309,6 +309,11 @@
3665                                                              inet->sport,
3666                                                              inet->dport);
3667  
3668 +       WEB100_VAR_SET(tp, SndISS, tp->write_seq);
3669 +       WEB100_VAR_SET(tp, SndMax, tp->write_seq);
3670 +       WEB100_VAR_SET(tp, SndNxt, tp->write_seq);
3671 +       WEB100_VAR_SET(tp, SndUna, tp->write_seq);
3672 +       
3673         err = tcp_connect(sk);
3674         if (err)
3675                 goto late_failure;
3676 @@ -1370,6 +1375,13 @@
3677         newsk = tcp_create_openreq_child(sk, req, skb);
3678         if (newsk == NULL)
3679                 goto out_nonewsk;
3680 +#ifdef CONFIG_WEB100_STATS
3681 +       if (web100_stats_create(newsk)) {
3682 +               sk_free(newsk);
3683 +               goto out;
3684 +       }
3685 +       tcp_sk(newsk)->tcp_stats->wc_vars.LocalAddressType = WC_ADDRTYPE_IPV6;
3686 +#endif
3687  
3688         /*
3689          * No need to charge this sock to the relevant IPv6 refcnt debug socks
3690 @@ -1683,6 +1695,7 @@
3691         skb->dev = NULL;
3692  
3693         bh_lock_sock_nested(sk);
3694 +       WEB100_UPDATE_FUNC(tcp_sk(sk), web100_update_segrecv(tcp_sk(sk), skb));
3695         ret = 0;
3696         if (!sock_owned_by_user(sk)) {
3697  #ifdef CONFIG_NET_DMA
3698 @@ -1701,6 +1714,7 @@
3699                 bh_unlock_sock(sk);
3700                 goto discard_and_relse;
3701         }
3702 +       WEB100_UPDATE_FUNC(tcp_sk(sk), web100_update_cwnd(tcp_sk(sk)));
3703         bh_unlock_sock(sk);
3704  
3705         sock_put(sk);
3706 @@ -1881,6 +1895,16 @@
3707         sk->sk_sndbuf = sysctl_tcp_wmem[1];
3708         sk->sk_rcvbuf = sysctl_tcp_rmem[1];
3709  
3710 +#ifdef CONFIG_WEB100_STATS
3711 +       {
3712 +               int err;
3713 +               if ((err = web100_stats_create(sk))) {
3714 +                       return err;
3715 +               }
3716 +               tcp_sk(sk)->tcp_stats->wc_vars.LocalAddressType = WC_ADDRTYPE_IPV6;
3717 +       }
3718 +#endif
3719 +       
3720         local_bh_disable();
3721         percpu_counter_inc(&tcp_sockets_allocated);
3722         local_bh_enable();