See bug: kern/121955
I have received panics with the same configuration of ipfw and dummynet in 6.3,
7.0-RELEASE, 7.0-STABLE.
But I don't received it in 6.2.
In all panics was corrupted stack.
I use mpd-5.0 for pptp connections and shape traffic with ng_car or dummynet
for different clients.
In 7.0-STABLE on netgraph was added patches, that decreasing using stack by
netgraph. And when I updated from 7.0-RELEASE to 7.0-STABLE, I received panic
rare. Not after 3-5 minutes, but after minimum 3 hours, maximum 2,5 days.
I saw cvsweb, and ip_dummynet in 6.2 and in 6.3.
Between it's two releases was done next changes:
Revision 1.93.2.6: download - view: text, markup, annotated - select for diffs
Wed Mar 21 17:25:15 2007 UTC (12 months, 1 week ago) by oleg
Branches: RELENG_6
CVS tags: RELENG_6_3_BP, RELENG_6_3_0_RELEASE, RELENG_6_3
Diff to: previous 1.93.2.5: preferred, colored; branchpoint 1.93: preferred,
colored; next MAIN 1.94: preferred, colored
Changes since revision 1.93.2.5: +481 -375 lines
MFC rev. 1.102-1.105
- style(9) cleanup
- Use separate thread for servicing dummynet(4).
Utilize taskqueue(9) API.
- Convert
net.inet.ip.dummynet.curr_time
net.inet.ip.dummynet.searches
net.inet.ip.dummynet.search_steps
to SYSCTL_LONG nodes. It will prevent frequent wrap around on 64bit archs.
- Implement simple mechanics for dummynet(4) internal time correction.
Under certain circumstances (system high load, dummynet lock contention, etc)
dummynet's tick counter can be significantly slower than it should be.
(I've observed up to 25% difference on one of my production servers).
Since this counter used for packet scheduling, it's accuracy is vital for
precise bandwidth limitation.
Introduce new sysctl nodes:
net.inet.ip.dummynet.
tick_lost - number of ticks coalesced by taskqueue thread.
tick_adjustment - number of time corrections done.
tick_diff - adjusted vs non-adjusted tick counter difference
tick_delta - last vs 'standard' tick differnece (usec).
tick_delta_sum - accumulated (and not corrected yet) time
difference (usec).
- Use non-recursive mutex. MTX_RECURSE is unnecessary since rev. 1.70
- Pay respect to net.isr.direct: use netisr_dispatch() instead of ip_input()
- purge_flow_set():
Do not leak memory while purging queues which are not bound to pipe.
Diff between files see in file.
After this changes (that mfced from 1.102-1.105) system became working unstable.
I think, that it's changes must be rereaded, because panics on my server with
6.3 or 7.0, 7.0-STABLE don't repeated in 6.2 with same configuration.
Last panics was:
# kgdb /root/29.03.08/kernel.debug /var/crash/vmcore.11
kgdb: kvm_nlist(_stopped_cpus):
kgdb: kvm_nlist(_stoppcbs):
[GDB will not be able to debug user-mode threads: /usr/lib/libthread_db.so:
Undefined symbol "ps_pglobal_lookup"]
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-marcel-freebsd".
Unread portion of the kernel message buffer:
Fatal trap 12: page fault while in kernel mode
fault virtual address = 0xf2a9864
fault code = supervisor read, page not present
instruction pointer = 0x20:0xc3f96a9f
stack pointer = 0x28:0xe4614a88
frame pointer = 0x28:0xe4614b7c
code segment = base 0x0, limit 0xfffff, type 0x1b
= DPL 0, pres 1, def32 1, gran 1
processor eflags = interrupt enabled, resume, IOPL = 0
current process = 40 (dummynet)
trap number = 12
panic: page fault
Uptime: 3h55m10s
Physical memory: 1015 MB
Dumping 173 MB: 158 142 126 110 94 78 62 46 30 14
#0 doadump () at pcpu.h:195
195 pcpu.h: No such file or directory.
in pcpu.h
(kgdb) bt
#0 doadump () at pcpu.h:195
#1 0xc056dbf3 in boot (howto=260) at /usr/src/sys/kern/kern_shutdown.c:409
#2 0xc056ddef in panic (fmt=Variable "fmt" is not available.
) at /usr/src/sys/kern/kern_shutdown.c:563
#3 0xc07bccac in trap_fatal (frame=0xe4614a48, eva=254449764) at
/usr/src/sys/i386/i386/trap.c:899
#4 0xc07bcf10 in trap_pfault (frame=0xe4614a48, usermode=0, eva=254449764) at
/usr/src/sys/i386/i386/trap.c:812
#5 0xc07bd869 in trap (frame=0xe4614a48) at /usr/src/sys/i386/i386/trap.c:490
#6 0xc07a786b in calltrap () at /usr/src/sys/i386/i386/exception.s:139
#7 0xc3f96a9f in ?? ()
Previous frame inner to this frame (corrupt stack?)
(kgdb)
# kgdb /root/29.03.08/kernel.debug /var/crash/vmcore.10
kgdb: kvm_nlist(_stopped_cpus):
kgdb: kvm_nlist(_stoppcbs):
[GDB will not be able to debug user-mode threads: /usr/lib/libthread_db.so:
Undefined symbol "ps_pglobal_lookup"]
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-marcel-freebsd".
Unread portion of the kernel message buffer:
Fatal trap 12: page fault while in kernel mode
fault virtual address = 0xcd
fault code = supervisor read, page not present
instruction pointer = 0x20:0xc3f8ba9f
stack pointer = 0x28:0xe4614a88
frame pointer = 0x28:0xe4614b7c
code segment = base 0x0, limit 0xfffff, type 0x1b
= DPL 0, pres 1, def32 1, gran 1
processor eflags = interrupt enabled, resume, IOPL = 0
current process = 40 (dummynet)
trap number = 12
panic: page fault
Uptime: 3h21m49s
Physical memory: 1015 MB
Dumping 171 MB: 156 140 124 108 92 76 60 44 28 12
#0 doadump () at pcpu.h:195
195 pcpu.h: No such file or directory.
in pcpu.h
(kgdb) bt
#0 doadump () at pcpu.h:195
#1 0xc056dbf3 in boot (howto=260) at /usr/src/sys/kern/kern_shutdown.c:409
#2 0xc056ddef in panic (fmt=Variable "fmt" is not available.
) at /usr/src/sys/kern/kern_shutdown.c:563
#3 0xc07bccac in trap_fatal (frame=0xe4614a48, eva=205) at
/usr/src/sys/i386/i386/trap.c:899
#4 0xc07bcf10 in trap_pfault (frame=0xe4614a48, usermode=0, eva=205) at
/usr/src/sys/i386/i386/trap.c:812
#5 0xc07bd869 in trap (frame=0xe4614a48) at /usr/src/sys/i386/i386/trap.c:490
#6 0xc07a786b in calltrap () at /usr/src/sys/i386/i386/exception.s:139
#7 0xc3f8ba9f in ?? ()
Previous frame inner to this frame (corrupt stack?)
(kgdb)
# kgdb /root/29.03.08/kernel.debug /var/crash/vmcore.9
kgdb: kvm_nlist(_stopped_cpus):
kgdb: kvm_nlist(_stoppcbs):
[GDB will not be able to debug user-mode threads: /usr/lib/libthread_db.so:
Undefined symbol "ps_pglobal_lookup"]
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-marcel-freebsd".
Unread portion of the kernel message buffer:
Fatal trap 12: page fault while in kernel mode
fault virtual address = 0xf4
fault code = supervisor read, page not present
instruction pointer = 0x20:0xc3f8ca9f
stack pointer = 0x28:0xe4614a88
frame pointer = 0x28:0xe4614b7c
code segment = base 0x0, limit 0xfffff, type 0x1b
= DPL 0, pres 1, def32 1, gran 1
processor eflags = interrupt enabled, resume, IOPL = 0
current process = 40 (dummynet)
trap number = 12
panic: page fault
Uptime: 2d19h13m24s
Physical memory: 1015 MB
Dumping 199 MB: 184 168 152 136 120 104 88 72 56 40 24 8
#0 doadump () at pcpu.h:195
195 pcpu.h: No such file or directory.
in pcpu.h
(kgdb) bt
#0 doadump () at pcpu.h:195
#1 0xc056dbf3 in boot (howto=260) at /usr/src/sys/kern/kern_shutdown.c:409
#2 0xc056ddef in panic (fmt=Variable "fmt" is not available.
) at /usr/src/sys/kern/kern_shutdown.c:563
#3 0xc07bccac in trap_fatal (frame=0xe4614a48, eva=244) at
/usr/src/sys/i386/i386/trap.c:899
#4 0xc07bcf10 in trap_pfault (frame=0xe4614a48, usermode=0, eva=244) at
/usr/src/sys/i386/i386/trap.c:812
#5 0xc07bd869 in trap (frame=0xe4614a48) at /usr/src/sys/i386/i386/trap.c:490
#6 0xc07a786b in calltrap () at /usr/src/sys/i386/i386/exception.s:139
#7 0xc3f8ca9f in ?? ()
Previous frame inner to this frame (corrupt stack?)
(kgdb)
# kgdb /root/29.03.08/kernel.debug /var/crash/vmcore.8
kgdb: kvm_nlist(_stopped_cpus):
kgdb: kvm_nlist(_stoppcbs):
[GDB will not be able to debug user-mode threads: /usr/lib/libthread_db.so:
Undefined symbol "ps_pglobal_lookup"]
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-marcel-freebsd".
Unread portion of the kernel message buffer:
Fatal trap 12: page fault while in kernel mode
fault virtual address = 0xc2
fault code = supervisor read, page not present
instruction pointer = 0x20:0xc3f93a9f
stack pointer = 0x28:0xe4614a88
frame pointer = 0x28:0xe4614b7c
code segment = base 0x0, limit 0xfffff, type 0x1b
= DPL 0, pres 1, def32 1, gran 1
processor eflags = interrupt enabled, resume, IOPL = 0
current process = 40 (dummynet)
trap number = 12
panic: page fault
Uptime: 11h35m35s
Physical memory: 1015 MB
Dumping 217 MB: 202 186 170 154 138 122 106 90 74 58 42 26 10
#0 doadump () at pcpu.h:195
195 pcpu.h: No such file or directory.
in pcpu.h
(kgdb) bt
#0 doadump () at pcpu.h:195
#1 0xc056dbf3 in boot (howto=260) at /usr/src/sys/kern/kern_shutdown.c:409
#2 0xc056ddef in panic (fmt=Variable "fmt" is not available.
) at /usr/src/sys/kern/kern_shutdown.c:563
#3 0xc07bccac in trap_fatal (frame=0xe4614a48, eva=194) at
/usr/src/sys/i386/i386/trap.c:899
#4 0xc07bcf10 in trap_pfault (frame=0xe4614a48, usermode=0, eva=194) at
/usr/src/sys/i386/i386/trap.c:812
#5 0xc07bd869 in trap (frame=0xe4614a48) at /usr/src/sys/i386/i386/trap.c:490
#6 0xc07a786b in calltrap () at /usr/src/sys/i386/i386/exception.s:139
#7 0xc3f93a9f in ?? ()
Previous frame inner to this frame (corrupt stack?)
(kgdb)
# kgdb /root/29.03.08/kernel.debug /var/crash/vmcore.7
kgdb: kvm_nlist(_stopped_cpus):
kgdb: kvm_nlist(_stoppcbs):
[GDB will not be able to debug user-mode threads: /usr/lib/libthread_db.so:
Undefined symbol "ps_pglobal_lookup"]
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-marcel-freebsd".
Unread portion of the kernel message buffer:
Fatal trap 12: page fault while in kernel mode
fault virtual address = 0xef
fault code = supervisor read, page not present
instruction pointer = 0x20:0xc3f85a9f
stack pointer = 0x28:0xe4614a88
frame pointer = 0x28:0xe4614b7c
code segment = base 0x0, limit 0xfffff, type 0x1b
= DPL 0, pres 1, def32 1, gran 1
processor eflags = interrupt enabled, resume, IOPL = 0
current process = 40 (dummynet)
trap number = 12
panic: page fault
Uptime: 1d1h54m1s
Physical memory: 1015 MB
Dumping 227 MB: 212 196 180 164 148 132 116 100 84 68 52 36 20 4
#0 doadump () at pcpu.h:195
195 pcpu.h: No such file or directory.
in pcpu.h
(kgdb) bt
#0 doadump () at pcpu.h:195
#1 0xc056dbf3 in boot (howto=260) at /usr/src/sys/kern/kern_shutdown.c:409
#2 0xc056ddef in panic (fmt=Variable "fmt" is not available.
) at /usr/src/sys/kern/kern_shutdown.c:563
#3 0xc07bccac in trap_fatal (frame=0xe4614a48, eva=239) at
/usr/src/sys/i386/i386/trap.c:899
#4 0xc07bcf10 in trap_pfault (frame=0xe4614a48, usermode=0, eva=239) at
/usr/src/sys/i386/i386/trap.c:812
#5 0xc07bd869 in trap (frame=0xe4614a48) at /usr/src/sys/i386/i386/trap.c:490
#6 0xc07a786b in calltrap () at /usr/src/sys/i386/i386/exception.s:139
#7 0xc3f85a9f in ?? ()
Previous frame inner to this frame (corrupt stack?)
(kgdb)
My sysctl.conf:
# cat /etc/sysctl.conf
net.inet.ip.fw.autoinc_step=1
net.inet.ip.intr_queue_maxlen=256
net.inet.ip.dummynet.hash_size=16384
net.inet.ip.fw.dyn_buckets=1024
net.inet.ip.fastforwarding=1
kern.ipc.somaxconn=2048
kern.ipc.nmbclusters=32768
net.inet.tcp.recvspace=65536
net.inet.tcp.sendspace=131072
net.inet.ip.fw.one_pass=0
Between panic I try change variables:
net.inet.ip.fw.one_pass to 1, but panic repetated after this
My system now:
FreeBSD myhost.mydom 7.0-STABLE FreeBSD 7.0-STABLE #0: Wed Mar 26 07:56:32 EET
2008 [EMAIL PROTECTED]:/usr/obj/usr/src/sys/myhost i386
-- реклама -----------------------------------------------------------
http://FREEhost.com.ua - доступный хостинг, домен в подарок--- ip_dummynet.c Sat Jul 29 11:24:12 2006
+++ ip_dummynet.c.6.3.c Fri Jan 18 22:50:55 2008
@@ -24,7 +24,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD: src/sys/netinet/ip_dummynet.c,v 1.93.2.5 2006/07/29 08:24:12 oleg Exp $
+ * $FreeBSD: src/sys/netinet/ip_dummynet.c,v 1.93.2.6 2007/03/21 17:25:15 oleg Exp $
*/
#define DUMMYNET_DEBUG
@@ -66,7 +66,9 @@
#include <sys/socketvar.h>
#include <sys/time.h>
#include <sys/sysctl.h>
+#include <sys/taskqueue.h>
#include <net/if.h>
+#include <net/netisr.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -91,7 +93,7 @@
static int dn_hash_size = 64 ; /* default hash size */
/* statistics on number of queue searches and search steps */
-static int searches, search_steps ;
+static long searches, search_steps ;
static int pipe_expire = 1 ; /* expire queue if empty */
static int dn_max_ratio = 16 ; /* max queues/buckets ratio */
@@ -99,6 +101,15 @@
static int red_avg_pkt_size = 512; /* RED - default medium packet size */
static int red_max_pkt_size = 1500; /* RED - default max packet size */
+static struct timeval prev_t, t;
+static long tick_last; /* Last tick duration (usec). */
+static long tick_delta; /* Last vs standard tick diff (usec). */
+static long tick_delta_sum; /* Accumulated tick difference (usec).*/
+static long tick_adjustment; /* Tick adjustments done. */
+static long tick_lost; /* Lost(coalesced) ticks number. */
+/* Adjusted vs non-adjusted curr_time difference (ticks). */
+static long tick_diff;
+
/*
* Three heaps contain queues and pipes that the scheduler handles:
*
@@ -134,31 +145,42 @@
extern void (*bridge_dn_p)(struct mbuf *, struct ifnet *);
#ifdef SYSCTL_NODE
-SYSCTL_NODE(_net_inet_ip, OID_AUTO, dummynet,
- CTLFLAG_RW, 0, "Dummynet");
+SYSCTL_NODE(_net_inet_ip, OID_AUTO, dummynet, CTLFLAG_RW, 0, "Dummynet");
SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, hash_size,
- CTLFLAG_RW, &dn_hash_size, 0, "Default hash table size");
-SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, curr_time,
- CTLFLAG_RD, &curr_time, 0, "Current tick");
+ CTLFLAG_RW, &dn_hash_size, 0, "Default hash table size");
+SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, curr_time,
+ CTLFLAG_RD, &curr_time, 0, "Current tick");
SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, ready_heap,
- CTLFLAG_RD, &ready_heap.size, 0, "Size of ready heap");
+ CTLFLAG_RD, &ready_heap.size, 0, "Size of ready heap");
SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, extract_heap,
- CTLFLAG_RD, &extract_heap.size, 0, "Size of extract heap");
-SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, searches,
- CTLFLAG_RD, &searches, 0, "Number of queue searches");
-SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, search_steps,
- CTLFLAG_RD, &search_steps, 0, "Number of queue search steps");
+ CTLFLAG_RD, &extract_heap.size, 0, "Size of extract heap");
+SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, searches,
+ CTLFLAG_RD, &searches, 0, "Number of queue searches");
+SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, search_steps,
+ CTLFLAG_RD, &search_steps, 0, "Number of queue search steps");
SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, expire,
- CTLFLAG_RW, &pipe_expire, 0, "Expire queue if empty");
+ CTLFLAG_RW, &pipe_expire, 0, "Expire queue if empty");
SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, max_chain_len,
- CTLFLAG_RW, &dn_max_ratio, 0,
- "Max ratio between dynamic queues and buckets");
+ CTLFLAG_RW, &dn_max_ratio, 0,
+ "Max ratio between dynamic queues and buckets");
SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_lookup_depth,
- CTLFLAG_RD, &red_lookup_depth, 0, "Depth of RED lookup table");
+ CTLFLAG_RD, &red_lookup_depth, 0, "Depth of RED lookup table");
SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_avg_pkt_size,
- CTLFLAG_RD, &red_avg_pkt_size, 0, "RED Medium packet size");
+ CTLFLAG_RD, &red_avg_pkt_size, 0, "RED Medium packet size");
SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_max_pkt_size,
- CTLFLAG_RD, &red_max_pkt_size, 0, "RED Max packet size");
+ CTLFLAG_RD, &red_max_pkt_size, 0, "RED Max packet size");
+SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_delta,
+ CTLFLAG_RD, &tick_delta, 0, "Last vs standard tick difference (usec).");
+SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_delta_sum,
+ CTLFLAG_RD, &tick_delta_sum, 0, "Accumulated tick difference (usec).");
+SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_adjustment,
+ CTLFLAG_RD, &tick_adjustment, 0, "Tick adjustments done.");
+SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_diff,
+ CTLFLAG_RD, &tick_diff, 0,
+ "Adjusted vs non-adjusted curr_time difference (ticks).");
+SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_lost,
+ CTLFLAG_RD, &tick_lost, 0,
+ "Number of ticks coalesced by dummynet taskqueue.");
#endif
#ifdef DUMMYNET_DEBUG
@@ -172,14 +194,13 @@
#define DPRINTF(X)
#endif
+static struct task dn_task;
+static struct taskqueue *dn_tq = NULL;
+static void dummynet_task(void *, int);
+
static struct mtx dummynet_mtx;
-/*
- * NB: Recursion is needed to deal with re-entry via ICMP. That is,
- * a packet may be dispatched via ip_input from dummynet_io and
- * re-enter through ip_output. Yech.
- */
#define DUMMYNET_LOCK_INIT() \
- mtx_init(&dummynet_mtx, "dummynet", NULL, MTX_DEF | MTX_RECURSE)
+ mtx_init(&dummynet_mtx, "dummynet", NULL, MTX_DEF)
#define DUMMYNET_LOCK_DESTROY() mtx_destroy(&dummynet_mtx)
#define DUMMYNET_LOCK() mtx_lock(&dummynet_mtx)
#define DUMMYNET_UNLOCK() mtx_unlock(&dummynet_mtx)
@@ -695,64 +716,118 @@
}
/*
- * This is called once per tick, or HZ times per second. It is used to
- * increment the current tick counter and schedule expired events.
+ * This is called one tick, after previous run. It is used to
+ * schedule next run.
*/
static void
dummynet(void * __unused unused)
{
- struct mbuf *head = NULL, *tail = NULL;
- struct dn_pipe *pipe;
- struct dn_heap *heaps[3];
- struct dn_heap *h;
- void *p; /* generic parameter to handler */
- int i;
+ taskqueue_enqueue(dn_tq, &dn_task);
+}
- heaps[0] = &ready_heap ; /* fixed-rate queues */
- heaps[1] = &wfq_ready_heap ; /* wfq queues */
- heaps[2] = &extract_heap ; /* delay line */
+/*
+ * The main dummynet processing function.
+ */
+static void
+dummynet_task(void *context, int pending)
+{
- DUMMYNET_LOCK();
- curr_time++ ;
- for (i=0; i < 3 ; i++) {
- h = heaps[i];
- while (h->elements > 0 && DN_KEY_LEQ(h->p[0].key, curr_time) ) {
- if (h->p[0].key > curr_time)
- printf("dummynet: warning, heap %d is %d ticks late\n",
- i, (int)(curr_time - h->p[0].key));
- p = h->p[0].object ; /* store a copy before heap_extract */
- heap_extract(h, NULL); /* need to extract before processing */
- if (i == 0)
- ready_event(p, &head, &tail);
- else if (i == 1) {
- struct dn_pipe *pipe = p;
- if (pipe->if_name[0] != '\0')
- printf("dummynet: bad ready_event_wfq for pipe %s\n",
- pipe->if_name);
- else
- ready_event_wfq(p, &head, &tail);
- } else
- transmit_event(p, &head, &tail);
- }
- }
- /* Sweep pipes trying to expire idle flow_queues. */
- for (i = 0; i < HASHSIZE; i++)
- SLIST_FOREACH(pipe, &pipehash[i], next)
- if (pipe->idle_heap.elements > 0 &&
- DN_KEY_LT(pipe->idle_heap.p[0].key, pipe->V) ) {
- struct dn_flow_queue *q = pipe->idle_heap.p[0].object;
-
- heap_extract(&(pipe->idle_heap), NULL);
- q->S = q->F + 1; /* Mark timestamp as invalid. */
- pipe->sum -= q->fs->weight;
+ struct mbuf *head = NULL, *tail = NULL;
+ struct dn_pipe *pipe;
+ struct dn_heap *heaps[3];
+ struct dn_heap *h;
+ void *p; /* generic parameter to handler */
+ int i;
+
+ NET_LOCK_GIANT();
+ DUMMYNET_LOCK();
+
+ heaps[0] = &ready_heap; /* fixed-rate queues */
+ heaps[1] = &wfq_ready_heap; /* wfq queues */
+ heaps[2] = &extract_heap; /* delay line */
+
+ /* Update number of lost(coalesced) ticks. */
+ tick_lost += pending - 1;
+
+ getmicrouptime(&t);
+ /* Last tick duration (usec). */
+ tick_last = (t.tv_sec - prev_t.tv_sec) * 1000000 +
+ (t.tv_usec - prev_t.tv_usec);
+ /* Last tick vs standard tick difference (usec). */
+ tick_delta = (tick_last * hz - 1000000) / hz;
+ /* Accumulated tick difference (usec). */
+ tick_delta_sum += tick_delta;
+
+ prev_t = t;
+
+ /*
+ * Adjust curr_time if accumulated tick difference greater than
+ * 'standard' tick. Since curr_time should be monotonically increasing,
+ * we do positive adjustment as required and throttle curr_time in
+ * case of negative adjustment.
+ */
+ curr_time++;
+ if (tick_delta_sum - tick >= 0) {
+ int diff = tick_delta_sum / tick;
+
+ curr_time += diff;
+ tick_diff += diff;
+ tick_delta_sum %= tick;
+ tick_adjustment++;
+ } else if (tick_delta_sum + tick <= 0) {
+ curr_time--;
+ tick_diff--;
+ tick_delta_sum += tick;
+ tick_adjustment++;
+ }
+
+ for (i = 0; i < 3; i++) {
+ h = heaps[i];
+ while (h->elements > 0 && DN_KEY_LEQ(h->p[0].key, curr_time)) {
+ if (h->p[0].key > curr_time)
+ printf("dummynet: warning, "
+ "heap %d is %d ticks late\n",
+ i, (int)(curr_time - h->p[0].key));
+ /* store a copy before heap_extract */
+ p = h->p[0].object;
+ /* need to extract before processing */
+ heap_extract(h, NULL);
+ if (i == 0)
+ ready_event(p, &head, &tail);
+ else if (i == 1) {
+ struct dn_pipe *pipe = p;
+ if (pipe->if_name[0] != '\0')
+ printf("dummynet: bad ready_event_wfq "
+ "for pipe %s\n", pipe->if_name);
+ else
+ ready_event_wfq(p, &head, &tail);
+ } else
+ transmit_event(p, &head, &tail);
}
+ }
- DUMMYNET_UNLOCK();
+ /* Sweep pipes trying to expire idle flow_queues. */
+ for (i = 0; i < HASHSIZE; i++)
+ SLIST_FOREACH(pipe, &pipehash[i], next)
+ if (pipe->idle_heap.elements > 0 &&
+ DN_KEY_LT(pipe->idle_heap.p[0].key, pipe->V)) {
+ struct dn_flow_queue *q =
+ pipe->idle_heap.p[0].object;
+
+ heap_extract(&(pipe->idle_heap), NULL);
+ /* Mark timestamp as invalid. */
+ q->S = q->F + 1;
+ pipe->sum -= q->fs->weight;
+ }
- if (head != NULL)
- dummynet_send(head);
+ DUMMYNET_UNLOCK();
+
+ if (head != NULL)
+ dummynet_send(head);
+
+ callout_reset(&dn_timeout, 1, dummynet, NULL);
- callout_reset(&dn_timeout, 1, dummynet, NULL);
+ NET_UNLOCK_GIANT();
}
static void
@@ -774,11 +849,11 @@
ip = mtod(m, struct ip *);
ip->ip_len = htons(ip->ip_len);
ip->ip_off = htons(ip->ip_off);
- ip_input(m);
+ netisr_dispatch(NETISR_IP, m);
break;
#ifdef INET6
case DN_TO_IP6_IN:
- ip6_input(m);
+ netisr_dispatch(NETISR_IPV6, m);
break;
case DN_TO_IP6_OUT:
@@ -1021,103 +1096,106 @@
static int
red_drops(struct dn_flow_set *fs, struct dn_flow_queue *q, int len)
{
- /*
- * RED algorithm
- *
- * RED calculates the average queue size (avg) using a low-pass filter
- * with an exponential weighted (w_q) moving average:
- * avg <- (1-w_q) * avg + w_q * q_size
- * where q_size is the queue length (measured in bytes or * packets).
- *
- * If q_size == 0, we compute the idle time for the link, and set
- * avg = (1 - w_q)^(idle/s)
- * where s is the time needed for transmitting a medium-sized packet.
- *
- * Now, if avg < min_th the packet is enqueued.
- * If avg > max_th the packet is dropped. Otherwise, the packet is
- * dropped with probability P function of avg.
- *
- */
+ /*
+ * RED algorithm
+ *
+ * RED calculates the average queue size (avg) using a low-pass filter
+ * with an exponential weighted (w_q) moving average:
+ * avg <- (1-w_q) * avg + w_q * q_size
+ * where q_size is the queue length (measured in bytes or * packets).
+ *
+ * If q_size == 0, we compute the idle time for the link, and set
+ * avg = (1 - w_q)^(idle/s)
+ * where s is the time needed for transmitting a medium-sized packet.
+ *
+ * Now, if avg < min_th the packet is enqueued.
+ * If avg > max_th the packet is dropped. Otherwise, the packet is
+ * dropped with probability P function of avg.
+ */
- int64_t p_b = 0;
- /* queue in bytes or packets ? */
- u_int q_size = (fs->flags_fs & DN_QSIZE_IS_BYTES) ? q->len_bytes : q->len;
+ int64_t p_b = 0;
- DPRINTF(("\ndummynet: %d q: %2u ", (int) curr_time, q_size));
+ /* Queue in bytes or packets? */
+ u_int q_size = (fs->flags_fs & DN_QSIZE_IS_BYTES) ?
+ q->len_bytes : q->len;
- /* average queue size estimation */
- if (q_size != 0) {
- /*
- * queue is not empty, avg <- avg + (q_size - avg) * w_q
- */
- int diff = SCALE(q_size) - q->avg;
- int64_t v = SCALE_MUL((int64_t) diff, (int64_t) fs->w_q);
+ DPRINTF(("\ndummynet: %d q: %2u ", (int)curr_time, q_size));
- q->avg += (int) v;
- } else {
- /*
- * queue is empty, find for how long the queue has been
- * empty and use a lookup table for computing
- * (1 - * w_q)^(idle_time/s) where s is the time to send a
- * (small) packet.
- * XXX check wraps...
- */
- if (q->avg) {
- u_int t = (curr_time - q->q_time) / fs->lookup_step;
+ /* Average queue size estimation. */
+ if (q_size != 0) {
+ /* Queue is not empty, avg <- avg + (q_size - avg) * w_q */
+ int diff = SCALE(q_size) - q->avg;
+ int64_t v = SCALE_MUL((int64_t)diff, (int64_t)fs->w_q);
- q->avg = (t < fs->lookup_depth) ?
- SCALE_MUL(q->avg, fs->w_q_lookup[t]) : 0;
+ q->avg += (int)v;
+ } else {
+ /*
+ * Queue is empty, find for how long the queue has been
+ * empty and use a lookup table for computing
+ * (1 - * w_q)^(idle_time/s) where s is the time to send a
+ * (small) packet.
+ * XXX check wraps...
+ */
+ if (q->avg) {
+ u_int t = (curr_time - q->q_time) / fs->lookup_step;
+
+ q->avg = (t < fs->lookup_depth) ?
+ SCALE_MUL(q->avg, fs->w_q_lookup[t]) : 0;
+ }
}
- }
- DPRINTF(("dummynet: avg: %u ", SCALE_VAL(q->avg)));
+ DPRINTF(("dummynet: avg: %u ", SCALE_VAL(q->avg)));
- /* should i drop ? */
-
- if (q->avg < fs->min_th) {
- q->count = -1;
- return 0; /* accept packet ; */
- }
- if (q->avg >= fs->max_th) { /* average queue >= max threshold */
- if (fs->flags_fs & DN_IS_GENTLE_RED) {
- /*
- * According to Gentle-RED, if avg is greater than max_th the
- * packet is dropped with a probability
- * p_b = c_3 * avg - c_4
- * where c_3 = (1 - max_p) / max_th, and c_4 = 1 - 2 * max_p
- */
- p_b = SCALE_MUL((int64_t) fs->c_3, (int64_t) q->avg) - fs->c_4;
- } else {
- q->count = -1;
- DPRINTF(("dummynet: - drop"));
- return 1 ;
+ /* Should i drop? */
+ if (q->avg < fs->min_th) {
+ q->count = -1;
+ return (0); /* accept packet */
}
- } else if (q->avg > fs->min_th) {
- /*
- * we compute p_b using the linear dropping function p_b = c_1 *
- * avg - c_2, where c_1 = max_p / (max_th - min_th), and c_2 =
- * max_p * min_th / (max_th - min_th)
- */
- p_b = SCALE_MUL((int64_t) fs->c_1, (int64_t) q->avg) - fs->c_2;
- }
- if (fs->flags_fs & DN_QSIZE_IS_BYTES)
- p_b = (p_b * len) / fs->max_pkt_size;
- if (++q->count == 0)
- q->random = random() & 0xffff;
- else {
- /*
- * q->count counts packets arrived since last drop, so a greater
- * value of q->count means a greater packet drop probability.
- */
- if (SCALE_MUL(p_b, SCALE((int64_t) q->count)) > q->random) {
- q->count = 0;
- DPRINTF(("dummynet: - red drop"));
- /* after a drop we calculate a new random value */
- q->random = random() & 0xffff;
- return 1; /* drop */
+ if (q->avg >= fs->max_th) { /* average queue >= max threshold */
+ if (fs->flags_fs & DN_IS_GENTLE_RED) {
+ /*
+ * According to Gentle-RED, if avg is greater than
+ * max_th the packet is dropped with a probability
+ * p_b = c_3 * avg - c_4
+ * where c_3 = (1 - max_p) / max_th
+ * c_4 = 1 - 2 * max_p
+ */
+ p_b = SCALE_MUL((int64_t)fs->c_3, (int64_t)q->avg) -
+ fs->c_4;
+ } else {
+ q->count = -1;
+ DPRINTF(("dummynet: - drop"));
+ return (1);
+ }
+ } else if (q->avg > fs->min_th) {
+ /*
+ * We compute p_b using the linear dropping function
+ * p_b = c_1 * avg - c_2
+ * where c_1 = max_p / (max_th - min_th)
+ * c_2 = max_p * min_th / (max_th - min_th)
+ */
+ p_b = SCALE_MUL((int64_t)fs->c_1, (int64_t)q->avg) - fs->c_2;
}
- }
- /* end of RED algorithm */
- return 0 ; /* accept */
+
+ if (fs->flags_fs & DN_QSIZE_IS_BYTES)
+ p_b = (p_b * len) / fs->max_pkt_size;
+ if (++q->count == 0)
+ q->random = random() & 0xffff;
+ else {
+ /*
+ * q->count counts packets arrived since last drop, so a greater
+ * value of q->count means a greater packet drop probability.
+ */
+ if (SCALE_MUL(p_b, SCALE((int64_t)q->count)) > q->random) {
+ q->count = 0;
+ DPRINTF(("dummynet: - red drop"));
+ /* After a drop we calculate a new random value. */
+ q->random = random() & 0xffff;
+ return (1); /* drop */
+ }
+ }
+ /* End of RED algorithm. */
+
+ return (0); /* accept */
}
static __inline struct dn_flow_set *
@@ -1353,36 +1431,37 @@
static void
purge_flow_set(struct dn_flow_set *fs, int all)
{
- struct dn_flow_queue *q, *qn ;
- int i ;
+ struct dn_flow_queue *q, *qn;
+ int i;
- DUMMYNET_LOCK_ASSERT();
+ DUMMYNET_LOCK_ASSERT();
- for (i = 0 ; i <= fs->rq_size ; i++ ) {
- for (q = fs->rq[i] ; q ; q = qn ) {
- struct mbuf *m, *mnext;
-
- mnext = q->head;
- while ((m = mnext) != NULL) {
- mnext = m->m_nextpkt;
- DN_FREE_PKT(m);
- }
- qn = q->next ;
- free(q, M_DUMMYNET);
+ for (i = 0; i <= fs->rq_size; i++) {
+ for (q = fs->rq[i]; q != NULL; q = qn) {
+ struct mbuf *m, *mnext;
+
+ mnext = q->head;
+ while ((m = mnext) != NULL) {
+ mnext = m->m_nextpkt;
+ DN_FREE_PKT(m);
+ }
+ qn = q->next;
+ free(q, M_DUMMYNET);
+ }
+ fs->rq[i] = NULL;
+ }
+
+ fs->rq_elements = 0;
+ if (all) {
+ /* RED - free lookup table. */
+ if (fs->w_q_lookup != NULL)
+ free(fs->w_q_lookup, M_DUMMYNET);
+ if (fs->rq != NULL)
+ free(fs->rq, M_DUMMYNET);
+ /* If this fs is not part of a pipe, free it. */
+ if (fs->pipe == NULL || fs != &(fs->pipe->fs))
+ free(fs, M_DUMMYNET);
}
- fs->rq[i] = NULL ;
- }
- fs->rq_elements = 0 ;
- if (all) {
- /* RED - free lookup table */
- if (fs->w_q_lookup)
- free(fs->w_q_lookup, M_DUMMYNET);
- if (fs->rq)
- free(fs->rq, M_DUMMYNET);
- /* if this fs is not part of a pipe, free it */
- if (fs->pipe && fs != &(fs->pipe->fs) )
- free(fs, M_DUMMYNET);
- }
}
/*
@@ -1502,52 +1581,57 @@
static int
config_red(struct dn_flow_set *p, struct dn_flow_set * x)
{
- int i;
+ int i;
- x->w_q = p->w_q;
- x->min_th = SCALE(p->min_th);
- x->max_th = SCALE(p->max_th);
- x->max_p = p->max_p;
-
- x->c_1 = p->max_p / (p->max_th - p->min_th);
- x->c_2 = SCALE_MUL(x->c_1, SCALE(p->min_th));
- if (x->flags_fs & DN_IS_GENTLE_RED) {
- x->c_3 = (SCALE(1) - p->max_p) / p->max_th;
- x->c_4 = (SCALE(1) - 2 * p->max_p);
- }
-
- /* if the lookup table already exist, free and create it again */
- if (x->w_q_lookup) {
- free(x->w_q_lookup, M_DUMMYNET);
- x->w_q_lookup = NULL ;
- }
- if (red_lookup_depth == 0) {
- printf("\ndummynet: net.inet.ip.dummynet.red_lookup_depth must be > 0\n");
- free(x, M_DUMMYNET);
- return EINVAL;
- }
- x->lookup_depth = red_lookup_depth;
- x->w_q_lookup = (u_int *) malloc(x->lookup_depth * sizeof(int),
+ x->w_q = p->w_q;
+ x->min_th = SCALE(p->min_th);
+ x->max_th = SCALE(p->max_th);
+ x->max_p = p->max_p;
+
+ x->c_1 = p->max_p / (p->max_th - p->min_th);
+ x->c_2 = SCALE_MUL(x->c_1, SCALE(p->min_th));
+
+ if (x->flags_fs & DN_IS_GENTLE_RED) {
+ x->c_3 = (SCALE(1) - p->max_p) / p->max_th;
+ x->c_4 = SCALE(1) - 2 * p->max_p;
+ }
+
+ /* If the lookup table already exist, free and create it again. */
+ if (x->w_q_lookup) {
+ free(x->w_q_lookup, M_DUMMYNET);
+ x->w_q_lookup = NULL;
+ }
+ if (red_lookup_depth == 0) {
+ printf("\ndummynet: net.inet.ip.dummynet.red_lookup_depth"
+ "must be > 0\n");
+ free(x, M_DUMMYNET);
+ return (EINVAL);
+ }
+ x->lookup_depth = red_lookup_depth;
+ x->w_q_lookup = (u_int *)malloc(x->lookup_depth * sizeof(int),
M_DUMMYNET, M_NOWAIT);
- if (x->w_q_lookup == NULL) {
- printf("dummynet: sorry, cannot allocate red lookup table\n");
- free(x, M_DUMMYNET);
- return ENOSPC;
- }
-
- /* fill the lookup table with (1 - w_q)^x */
- x->lookup_step = p->lookup_step ;
- x->lookup_weight = p->lookup_weight ;
- x->w_q_lookup[0] = SCALE(1) - x->w_q;
- for (i = 1; i < x->lookup_depth; i++)
- x->w_q_lookup[i] = SCALE_MUL(x->w_q_lookup[i - 1], x->lookup_weight);
- if (red_avg_pkt_size < 1)
- red_avg_pkt_size = 512 ;
- x->avg_pkt_size = red_avg_pkt_size ;
- if (red_max_pkt_size < 1)
- red_max_pkt_size = 1500 ;
- x->max_pkt_size = red_max_pkt_size ;
- return 0 ;
+ if (x->w_q_lookup == NULL) {
+ printf("dummynet: sorry, cannot allocate red lookup table\n");
+ free(x, M_DUMMYNET);
+ return(ENOSPC);
+ }
+
+ /* Fill the lookup table with (1 - w_q)^x */
+ x->lookup_step = p->lookup_step;
+ x->lookup_weight = p->lookup_weight;
+ x->w_q_lookup[0] = SCALE(1) - x->w_q;
+
+ for (i = 1; i < x->lookup_depth; i++)
+ x->w_q_lookup[i] =
+ SCALE_MUL(x->w_q_lookup[i - 1], x->lookup_weight);
+
+ if (red_avg_pkt_size < 1)
+ red_avg_pkt_size = 512;
+ x->avg_pkt_size = red_avg_pkt_size;
+ if (red_max_pkt_size < 1)
+ red_max_pkt_size = 1500;
+ x->max_pkt_size = red_max_pkt_size;
+ return (0);
}
static int
@@ -1578,137 +1662,146 @@
static void
set_fs_parms(struct dn_flow_set *x, struct dn_flow_set *src)
{
- x->flags_fs = src->flags_fs;
- x->qsize = src->qsize;
- x->plr = src->plr;
- x->flow_mask = src->flow_mask;
- if (x->flags_fs & DN_QSIZE_IS_BYTES) {
- if (x->qsize > 1024*1024)
- x->qsize = 1024*1024 ;
- } else {
- if (x->qsize == 0)
- x->qsize = 50 ;
- if (x->qsize > 100)
- x->qsize = 50 ;
- }
- /* configuring RED */
- if ( x->flags_fs & DN_IS_RED )
- config_red(src, x) ; /* XXX should check errors */
+ x->flags_fs = src->flags_fs;
+ x->qsize = src->qsize;
+ x->plr = src->plr;
+ x->flow_mask = src->flow_mask;
+ if (x->flags_fs & DN_QSIZE_IS_BYTES) {
+ if (x->qsize > 1024 * 1024)
+ x->qsize = 1024 * 1024;
+ } else {
+ if (x->qsize == 0)
+ x->qsize = 50;
+ if (x->qsize > 100)
+ x->qsize = 50;
+ }
+ /* Configuring RED. */
+ if (x->flags_fs & DN_IS_RED)
+ config_red(src, x); /* XXX should check errors */
}
/*
- * setup pipe or queue parameters.
+ * Setup pipe or queue parameters.
*/
-
static int
config_pipe(struct dn_pipe *p)
{
- struct dn_flow_set *pfs = &(p->fs);
- struct dn_flow_queue *q;
- int i, error;
-
- /*
- * The config program passes parameters as follows:
- * bw = bits/second (0 means no limits),
- * delay = ms, must be translated into ticks.
- * qsize = slots/bytes
- */
- p->delay = ( p->delay * hz ) / 1000 ;
- /* We need either a pipe number or a flow_set number */
- if (p->pipe_nr == 0 && pfs->fs_nr == 0)
- return EINVAL ;
- if (p->pipe_nr != 0 && pfs->fs_nr != 0)
- return EINVAL ;
- if (p->pipe_nr != 0) { /* this is a pipe */
- struct dn_pipe *pipe;
+ struct dn_flow_set *pfs = &(p->fs);
+ struct dn_flow_queue *q;
+ int i, error;
- DUMMYNET_LOCK();
- pipe = locate_pipe(p->pipe_nr); /* locate pipe */
-
- if (pipe == NULL) { /* new pipe */
- pipe = malloc(sizeof(struct dn_pipe), M_DUMMYNET,
- M_NOWAIT | M_ZERO);
- if (pipe == NULL) {
- DUMMYNET_UNLOCK();
- printf("dummynet: no memory for new pipe\n");
- return (ENOMEM);
- }
- pipe->pipe_nr = p->pipe_nr;
- pipe->fs.pipe = pipe ;
- /* idle_heap is the only one from which we extract from the middle.
- */
- pipe->idle_heap.size = pipe->idle_heap.elements = 0 ;
- pipe->idle_heap.offset=OFFSET_OF(struct dn_flow_queue, heap_pos);
- } else
- /* Flush accumulated credit for all queues */
- for (i = 0; i <= pipe->fs.rq_size; i++)
- for (q = pipe->fs.rq[i]; q; q = q->next)
- q->numbytes = 0;
-
- pipe->bandwidth = p->bandwidth ;
- pipe->numbytes = 0; /* just in case... */
- bcopy(p->if_name, pipe->if_name, sizeof(p->if_name) );
- pipe->ifp = NULL ; /* reset interface ptr */
- pipe->delay = p->delay ;
- set_fs_parms(&(pipe->fs), pfs);
-
-
- if (pipe->fs.rq == NULL) { /* a new pipe */
- error = alloc_hash(&(pipe->fs), pfs);
- if (error) {
+ /*
+ * The config program passes parameters as follows:
+ * bw = bits/second (0 means no limits),
+ * delay = ms, must be translated into ticks.
+ * qsize = slots/bytes
+ */
+ p->delay = (p->delay * hz) / 1000;
+ /* We need either a pipe number or a flow_set number. */
+ if (p->pipe_nr == 0 && pfs->fs_nr == 0)
+ return (EINVAL);
+ if (p->pipe_nr != 0 && pfs->fs_nr != 0)
+ return (EINVAL);
+ if (p->pipe_nr != 0) { /* this is a pipe */
+ struct dn_pipe *pipe;
+
+ DUMMYNET_LOCK();
+ pipe = locate_pipe(p->pipe_nr); /* locate pipe */
+
+ if (pipe == NULL) { /* new pipe */
+ pipe = malloc(sizeof(struct dn_pipe), M_DUMMYNET,
+ M_NOWAIT | M_ZERO);
+ if (pipe == NULL) {
+ DUMMYNET_UNLOCK();
+ printf("dummynet: no memory for new pipe\n");
+ return (ENOMEM);
+ }
+ pipe->pipe_nr = p->pipe_nr;
+ pipe->fs.pipe = pipe;
+ /*
+ * idle_heap is the only one from which
+ * we extract from the middle.
+ */
+ pipe->idle_heap.size = pipe->idle_heap.elements = 0;
+ pipe->idle_heap.offset =
+ OFFSET_OF(struct dn_flow_queue, heap_pos);
+ } else
+ /* Flush accumulated credit for all queues. */
+ for (i = 0; i <= pipe->fs.rq_size; i++)
+ for (q = pipe->fs.rq[i]; q; q = q->next)
+ q->numbytes = 0;
+
+ pipe->bandwidth = p->bandwidth;
+ pipe->numbytes = 0; /* just in case... */
+ bcopy(p->if_name, pipe->if_name, sizeof(p->if_name));
+ pipe->ifp = NULL; /* reset interface ptr */
+ pipe->delay = p->delay;
+ set_fs_parms(&(pipe->fs), pfs);
+
+ if (pipe->fs.rq == NULL) { /* a new pipe */
+ error = alloc_hash(&(pipe->fs), pfs);
+ if (error) {
+ DUMMYNET_UNLOCK();
+ free(pipe, M_DUMMYNET);
+ return (error);
+ }
+ SLIST_INSERT_HEAD(&pipehash[HASH(pipe->pipe_nr)],
+ pipe, next);
+ }
DUMMYNET_UNLOCK();
- free(pipe, M_DUMMYNET);
- return (error);
- }
- SLIST_INSERT_HEAD(&pipehash[HASH(pipe->pipe_nr)], pipe, next);
- }
- DUMMYNET_UNLOCK();
- } else { /* config queue */
- struct dn_flow_set *fs;
+ } else { /* config queue */
+ struct dn_flow_set *fs;
- DUMMYNET_LOCK();
- fs = locate_flowset(pfs->fs_nr); /* locate flow_set */
+ DUMMYNET_LOCK();
+ fs = locate_flowset(pfs->fs_nr); /* locate flow_set */
- if (fs == NULL) { /* new */
- if (pfs->parent_nr == 0) { /* need link to a pipe */
- DUMMYNET_UNLOCK();
- return EINVAL ;
- }
- fs = malloc(sizeof(struct dn_flow_set), M_DUMMYNET,
- M_NOWAIT|M_ZERO);
- if (fs == NULL) {
- DUMMYNET_UNLOCK();
- printf("dummynet: no memory for new flow_set\n");
- return (ENOMEM);
- }
- fs->fs_nr = pfs->fs_nr;
- fs->parent_nr = pfs->parent_nr;
- fs->weight = pfs->weight;
- if (fs->weight == 0)
- fs->weight = 1;
- else if (fs->weight > 100)
- fs->weight = 100;
- } else {
- /* Change parent pipe not allowed; must delete and recreate */
- if (pfs->parent_nr != 0 && fs->parent_nr != pfs->parent_nr) {
- DUMMYNET_UNLOCK();
- return EINVAL ;
- }
- }
- set_fs_parms(fs, pfs);
+ if (fs == NULL) { /* new */
+ if (pfs->parent_nr == 0) { /* need link to a pipe */
+ DUMMYNET_UNLOCK();
+ return (EINVAL);
+ }
+ fs = malloc(sizeof(struct dn_flow_set), M_DUMMYNET,
+ M_NOWAIT | M_ZERO);
+ if (fs == NULL) {
+ DUMMYNET_UNLOCK();
+ printf(
+ "dummynet: no memory for new flow_set\n");
+ return (ENOMEM);
+ }
+ fs->fs_nr = pfs->fs_nr;
+ fs->parent_nr = pfs->parent_nr;
+ fs->weight = pfs->weight;
+ if (fs->weight == 0)
+ fs->weight = 1;
+ else if (fs->weight > 100)
+ fs->weight = 100;
+ } else {
+ /*
+ * Change parent pipe not allowed;
+ * must delete and recreate.
+ */
+ if (pfs->parent_nr != 0 &&
+ fs->parent_nr != pfs->parent_nr) {
+ DUMMYNET_UNLOCK();
+ return (EINVAL);
+ }
+ }
+
+ set_fs_parms(fs, pfs);
- if (fs->rq == NULL) { /* a new flow_set */
- error = alloc_hash(fs, pfs);
- if (error) {
+ if (fs->rq == NULL) { /* a new flow_set */
+ error = alloc_hash(fs, pfs);
+ if (error) {
+ DUMMYNET_UNLOCK();
+ free(fs, M_DUMMYNET);
+ return (error);
+ }
+ SLIST_INSERT_HEAD(&flowsethash[HASH(fs->fs_nr)],
+ fs, next);
+ }
DUMMYNET_UNLOCK();
- free(fs, M_DUMMYNET);
- return (error);
- }
- SLIST_INSERT_HEAD(&flowsethash[HASH(fs->fs_nr)], fs, next);
}
- DUMMYNET_UNLOCK();
- }
- return 0 ;
+ return (0);
}
/*
@@ -2046,46 +2139,59 @@
static void
ip_dn_init(void)
{
- int i;
+ int i;
- if (bootverbose)
- printf("DUMMYNET with IPv6 initialized (040826)\n");
+ if (bootverbose)
+ printf("DUMMYNET with IPv6 initialized (040826)\n");
- DUMMYNET_LOCK_INIT();
+ DUMMYNET_LOCK_INIT();
- for (i = 0; i < HASHSIZE; i++) {
- SLIST_INIT(&pipehash[i]);
- SLIST_INIT(&flowsethash[i]);
- }
- ready_heap.size = ready_heap.elements = 0 ;
- ready_heap.offset = 0 ;
+ for (i = 0; i < HASHSIZE; i++) {
+ SLIST_INIT(&pipehash[i]);
+ SLIST_INIT(&flowsethash[i]);
+ }
+ ready_heap.size = ready_heap.elements = 0;
+ ready_heap.offset = 0;
+
+ wfq_ready_heap.size = wfq_ready_heap.elements = 0;
+ wfq_ready_heap.offset = 0;
- wfq_ready_heap.size = wfq_ready_heap.elements = 0 ;
- wfq_ready_heap.offset = 0 ;
+ extract_heap.size = extract_heap.elements = 0;
+ extract_heap.offset = 0;
- extract_heap.size = extract_heap.elements = 0 ;
- extract_heap.offset = 0 ;
+ ip_dn_ctl_ptr = ip_dn_ctl;
+ ip_dn_io_ptr = dummynet_io;
+ ip_dn_ruledel_ptr = dn_rule_delete;
- ip_dn_ctl_ptr = ip_dn_ctl;
- ip_dn_io_ptr = dummynet_io;
- ip_dn_ruledel_ptr = dn_rule_delete;
+ TASK_INIT(&dn_task, 0, dummynet_task, NULL);
+ dn_tq = taskqueue_create_fast("dummynet", M_NOWAIT,
+ taskqueue_thread_enqueue, &dn_tq);
+ taskqueue_start_threads(&dn_tq, 1, PI_NET, "dummynet");
- callout_init(&dn_timeout, NET_CALLOUT_MPSAFE);
- callout_reset(&dn_timeout, 1, dummynet, NULL);
+ callout_init(&dn_timeout, NET_CALLOUT_MPSAFE);
+ callout_reset(&dn_timeout, 1, dummynet, NULL);
+
+ /* Initialize curr_time adjustment mechanics. */
+ getmicrouptime(&prev_t);
}
#ifdef KLD_MODULE
static void
ip_dn_destroy(void)
{
- ip_dn_ctl_ptr = NULL;
- ip_dn_io_ptr = NULL;
- ip_dn_ruledel_ptr = NULL;
+ ip_dn_ctl_ptr = NULL;
+ ip_dn_io_ptr = NULL;
+ ip_dn_ruledel_ptr = NULL;
+
+ DUMMYNET_LOCK();
+ callout_stop(&dn_timeout);
+ DUMMYNET_UNLOCK();
+ taskqueue_drain(dn_tq, &dn_task);
+ taskqueue_free(dn_tq);
- callout_stop(&dn_timeout);
- dummynet_flush();
+ dummynet_flush();
- DUMMYNET_LOCK_DESTROY();
+ DUMMYNET_LOCK_DESTROY();
}
#endif /* KLD_MODULE */
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-ipfw
To unsubscribe, send any mail to "[EMAIL PROTECTED]"