From nobody@FreeBSD.org  Sat Mar 22 10:00:10 2008
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 0E4A71065672
	for <freebsd-gnats-submit@FreeBSD.org>; Sat, 22 Mar 2008 10:00:10 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id 1CEB28FC16
	for <freebsd-gnats-submit@FreeBSD.org>; Sat, 22 Mar 2008 10:00:10 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.2/8.14.2) with ESMTP id m2MA04JQ054789
	for <freebsd-gnats-submit@FreeBSD.org>; Sat, 22 Mar 2008 10:00:04 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.2/8.14.1/Submit) id m2MA048T054788;
	Sat, 22 Mar 2008 10:00:04 GMT
	(envelope-from nobody)
Message-Id: <200803221000.m2MA048T054788@www.freebsd.org>
Date: Sat, 22 Mar 2008 10:00:04 GMT
From: "Alexander V. Shulikov" <shulikov@gmail.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: freebsd 7.0 panic with mpd
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         121955
>Category:       kern
>Synopsis:       [ipfw] [panic] freebsd 7.0 panic with mpd
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    oleg
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat Mar 22 10:10:01 UTC 2008
>Closed-Date:    Wed May 07 17:44:08 UTC 2008
>Last-Modified:  Wed May 07 17:44:08 UTC 2008
>Originator:     Alexander V. Shulikov
>Release:        7.0-RELEASE
>Organization:
ISP DonEC
>Environment:
FreeBSD hostname 7.0-RELEASE FreeBSD 7.0-RELEASE #0: Sat Mar 22 10:47:30 EET 2008     hostname:/usr/obj/usr/src/sys/kernconf  i386
>Description:
I use FreeBSD server as pptp server with mpd-5.0. Before 7.0 it work under FreeBSD 6.2+mpd-4.4. When I try update to FreeBSD 6.3 I received systems reboot in different intervals of time and no crash dumps.
Then I try configure new server on FreeBSD 7.0. Kernel was build with GENERIC config with turned of options COMPAT_FREEBSD5 and 6 and added IPFW, DUMMYNET, option HZ=1000 and some drivers with nodevice.
options         IPFIREWALL              #firewall
options         IPFIREWALL_DEFAULT_TO_ACCEPT    #allow everything by default
options         IPFIREWALL_FORWARD      #packet destination changes
options         IPDIVERT                #divert sockets
options         DUMMYNET
options         HZ=1000

With this kernel system works. But when I turned on mpd-5.0 and clients connecting to them after some time (3 min - 30 min) system or freeze with message:
Fault double fault:
eip = ..
esp = ..
or panic with crash dump.
# cat info.0
Dump header from device /dev/ad4s1b
  Architecture: i386
  Architecture Version: 2
  Dump Length: 65822720B (62 MB)
  Blocksize: 512
  Dumptime: Sat Mar 22 08:13:28 2008
  Hostname: uzbek.matrixhome.net
  Magic: FreeBSD Kernel Dump
  Version String: FreeBSD 7.0-RELEASE #0: Fri Mar 21 22:08:21 EET 2008
    hostname:/usr/obj/usr/src/sys/kernconf
  Panic String: double fault
  Dump Parity: 3717215795
  Bounds: 0
  Dump Status: good

# kgdb /root/debug/kernel.debug /var/crash/vmcore.0
[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 double fault:
eip = 0xc40914f5
esp = 0xe3ff4000
ebp = 0xe3ff40b4
cpuid = 0; apic id = 00
panic: double fault
cpuid = 0
Uptime: 3m43s
Physical memory: 1015 MB
Dumping 62 MB: 47 31 15

#0  doadump () at pcpu.h:195
195     pcpu.h: No such file or directory.
        in pcpu.h
(kgdb) backtrace
#0  doadump () at pcpu.h:195
#1  0xc05591c7 in boot (howto=260) at /usr/src/sys/kern/kern_shutdown.c:409
#2  0xc0559489 in panic (fmt=Variable "fmt" is not available.
) at /usr/src/sys/kern/kern_shutdown.c:563
#3  0xc079007b in dblfault_handler () at /usr/src/sys/i386/i386/trap.c:928
#4  0xc40914f5 in ?? ()
#5  0xc4238980 in ?? ()
#6  0xc40bc7e0 in ?? ()
.....there is many addresses, that I can't  find in *.debug with addr2line
#439 0x00000000 in ?? ()
#440 0xe3ff4a14 in ?? ()
#441 0xe3ff49fc in ?? ()
#442 0xc061495e in ipfw_chk (args=0xc4238ad4) at /usr/src/sys/netinet/ip_fw2.c:2659
Previous frame inner to this frame (corrupt stack?)

Then I rebuild kernel added:
options         NETGRAPH                # netgraph(4) system
options         NETGRAPH_DEBUG          # enable extra debugging, this
                                        # affects netgraph(4) and nodes
# Node types
options         NETGRAPH_CAR
options         NETGRAPH_IFACE
options         NETGRAPH_KSOCKET
options         NETGRAPH_NETFLOW
options         NETGRAPH_PPP
options         NETGRAPH_PPTPGRE
options         NETGRAPH_SOCKET
options         NETGRAPH_TCPMSS
options         NETGRAPH_TEE
options         NETGRAPH_VJC

After this kldstat:
# kldstat
Id Refs Address    Size     Name
 1   10 0xc0400000 533f50   kernel
 2    1 0xc0934000 6a32c    acpi.ko
 3    1 0xc3fcd000 3000     pflog.ko
 4    1 0xc3fd0000 33000    pf.ko
 5    1 0xc40dc000 4000     ng_mppc.ko
 6    1 0xc40e0000 2000     rc4.ko
 7    1 0xc415d000 2000     blank_saver.ko

And panic was:
# cat /var/crash/info.1
Dump header from device /dev/ad4s1b
  Architecture: i386
  Architecture Version: 2
  Dump Length: 61734912B (58 MB)
  Blocksize: 512
  Dumptime: Sat Mar 22 11:17:16 2008
  Hostname: uzbek.matrixhome.net
  Magic: FreeBSD Kernel Dump
  Version String: FreeBSD 7.0-RELEASE #0: Sat Mar 22 10:47:30 EET 2008
    hostname:/usr/obj/usr/src/sys/kernconf
  Panic String: double fault
  Dump Parity: 3313853732
  Bounds: 1
  Dump Status: good

# kgdb /usr/obj/usr/src/sys/uzbek/kernel.debug /var/crash/vmcore.1
[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 double fault:
eip = 0xc42bbdfb
esp = 0xe3fedff4
ebp = 0xe3fee030
cpuid = 0; apic id = 00
panic: double fault
cpuid = 0
Uptime: 7m16s
Physical memory: 1015 MB
Dumping 58 MB: (CTRL-C to abort)  43 (CTRL-C to abort)  27 (CTRL-C to abort)  11

#0  doadump () at pcpu.h:195
195     pcpu.h: No such file or directory.
        in pcpu.h
(kgdb) backtrace
#0  doadump () at pcpu.h:195
#1  0xc055a0b7 in boot (howto=260) at /usr/src/sys/kern/kern_shutdown.c:409
#2  0xc055a379 in panic (fmt=Variable "fmt" is not available.
) at /usr/src/sys/kern/kern_shutdown.c:563
#3  0xc07ac2ab in dblfault_handler () at /usr/src/sys/i386/i386/trap.c:928
#4  0xc42bbdfb in ?? ()
Cannot access memory at address 0xe3fedff4
(kgdb)


Some notes:
Server used for connecting 100-150 tunnels at one time. In system used ipfw and pf. ipfw for dummynet and count with net.inet.ip.fw.one_pass=0
pf for filtering, nat and scrub

The same system on FreeBSD 6.2-RELEASE-p11 (mpd-5.0, ipfw. pf) don't panic after 3 minutes.


I can't update my server from 6.2, because in this configuration I have troubles in 6.3 and in 7.0. System or freezes or panic and reboot.
>How-To-Repeat:
Read full description.
>Fix:


>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->freebsd-ipfw 
Responsible-Changed-By: remko 
Responsible-Changed-When: Sat Mar 22 10:43:15 UTC 2008 
Responsible-Changed-Why:  
Could be potentially something for ipfw (which is in the first gdb 
output). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=121955 

From: "Alexander Shulikov" <shulikov@gmail.com>
To: bug-followup@FreeBSD.org, shulikov@gmail.com
Cc:  
Subject: Re: kern/121955: [ipfw] [panic] freebsd 7.0 panic with mpd
Date: Mon, 24 Mar 2008 10:07:14 +0200

 I receive new dump with mpd-4.4 and FreeBSD 7.0-RELEASE:
 
 # kgdb /usr/obj/usr/src/sys/kkk/kernel.debug /var/crash/vmcore.2
 [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 double fault:
 eip = 0xc062ffa1
 esp = 0xe3fedf40
 ebp = 0xe3fee264
 cpuid = 0; apic id = 00
 panic: double fault
 cpuid = 0
 Uptime: 3m19s
 Physical memory: 1015 MB
 Dumping 62 MB: (CTRL-C to abort)  (CTRL-C to abort)  47 (CTRL-C to abort)  31 15
 
 #0  doadump () at pcpu.h:195
 195     pcpu.h: No such file or directory.
         in pcpu.h
 (kgdb) backtrace
 #0  doadump () at pcpu.h:195
 #1  0xc055a0b7 in boot (howto=260) at /usr/src/sys/kern/kern_shutdown.c:409
 #2  0xc055a379 in panic (fmt=Variable "fmt" is not available.
 ) at /usr/src/sys/kern/kern_shutdown.c:563
 #3  0xc07ac2ab in dblfault_handler () at /usr/src/sys/i386/i386/trap.c:928
 #4  0xc062ffa1 in ipfw_chk (args=0xe3fee27c) at
 /usr/src/sys/netinet/ip_fw2.c:2303
 #5  0xc0634771 in ipfw_check_out (arg=0x0, m0=0xe3fee380,
 ifp=0xc3c6bc00, dir=2, inp=0x0)
     at /usr/src/sys/netinet/ip_fw_pfil.c:251
 #6  0xc05f99f8 in pfil_run_hooks (ph=0xc0870ea0, mp=0xe3fee410,
 ifp=0xc3c6bc00, dir=2, inp=0x0) at /usr/src/sys/net/pfil.c:78
 #7  0xc0638ee2 in ip_output (m=0xc3f82600, opt=0x0, ro=0xe3fee3e4,
 flags=1, imo=0x0, inp=0x0)
     at /usr/src/sys/netinet/ip_output.c:438
 #8  0xc0628cf6 in dummynet_send (m=0xc3f82600) at
 /usr/src/sys/netinet/ip_dummynet.c:840
 #9  0xc062b23c in dummynet_io (m=0xc3f82600, dir=1, fwa=0xe3fee578) at
 /usr/src/sys/netinet/ip_dummynet.c:1373
 #10 0xc063489e in ipfw_check_out (arg=0x0, m0=0xe3fee67c,
 ifp=0xc3c6bc00, dir=2, inp=0x0)
     at /usr/src/sys/netinet/ip_fw_pfil.c:289
 #11 0xc05f99f8 in pfil_run_hooks (ph=0xc0870ea0, mp=0xe3fee70c,
 ifp=0xc3c6bc00, dir=2, inp=0x0) at /usr/src/sys/net/pfil.c:78
 #12 0xc0638ee2 in ip_output (m=0xc3f82600, opt=0x0, ro=0xe3fee6e0,
 flags=0, imo=0x0, inp=0x0)
     at /usr/src/sys/netinet/ip_output.c:438
 #13 0xc069aa55 in tcp_respond (tp=0x0, ipgen=0xc3f96031,
 th=0xc3f96045, m=0xc3f82600, ack=2416490148, seq=0, flags=Variable
 "flags" is not available.
 )
     at /usr/src/sys/netinet/tcp_subr.c:572
 #14 0xc0692ab6 in tcp_dropwithreset (m=0xc3f82600, th=0xc3f96045,
 tp=0x0, tlen=1, rstreason=3)
     at /usr/src/sys/netinet/tcp_input.c:2470
 #15 0xc0695933 in tcp_input (m=0xc3f82600, off0=20) at
 /usr/src/sys/netinet/tcp_input.c:851
 #16 0xc06375e8 in ip_input (m=0xc3f82600) at /usr/src/sys/netinet/ip_input.c:665
 #17 0xc05f8195 in netisr_dispatch (num=2, m=0xc3f82600) at
 /usr/src/sys/net/netisr.c:185
 #18 0xc0628d22 in dummynet_send (m=0xc3f82600) at
 /usr/src/sys/netinet/ip_dummynet.c:846
 #19 0xc062b23c in dummynet_io (m=0xc3f82600, dir=2, fwa=0xe3feea08) at
 /usr/src/sys/netinet/ip_dummynet.c:1373
 #20 0xc06345b7 in ipfw_check_in (arg=0x0, m0=0xe3feeb0c,
 ifp=0xc3c6bc00, dir=1, inp=0x0)
     at /usr/src/sys/netinet/ip_fw_pfil.c:163
 #21 0xc05f99f8 in pfil_run_hooks (ph=0xc0870ea0, mp=0xe3feeb64,
 ifp=0xc3c6bc00, dir=1, inp=0x0) at /usr/src/sys/net/pfil.c:78
 #22 0xc0637121 in ip_input (m=0xc3f82600) at /usr/src/sys/netinet/ip_input.c:417
 #23 0xc05f8195 in netisr_dispatch (num=2, m=0xc3f82600) at
 /usr/src/sys/net/netisr.c:185
 #24 0xc060d2c4 in ng_iface_rcvdata (hook=0xc3ee6400, item=0xc40917c0)
 at /usr/src/sys/netgraph/ng_iface.c:757
 #25 0xc060704d in ng_apply_item (node=0xc4097b00, item=0xc40917c0,
 rw=0) at /usr/src/sys/netgraph/ng_base.c:2483
 #26 0xc0609cb9 in ng_snd_item (item=0xc40917c0, flags=0) at
 /usr/src/sys/netgraph/ng_base.c:2411
 #27 0xc060704d in ng_apply_item (node=0xc4791c00, item=0xc40917c0,
 rw=0) at /usr/src/sys/netgraph/ng_base.c:2483
 #28 0xc0609cb9 in ng_snd_item (item=0xc40917c0, flags=0) at
 /usr/src/sys/netgraph/ng_base.c:2411
 #29 0xc060c049 in ng_car_rcvdata (hook=0xc429d900, item=0xc40917c0) at
 /usr/src/sys/netgraph/ng_car.c:368
 #30 0xc060704d in ng_apply_item (node=0xc4791d00, item=0xc40917c0,
 rw=0) at /usr/src/sys/netgraph/ng_base.c:2483
 #31 0xc0609cb9 in ng_snd_item (item=0xc40917c0, flags=0) at
 /usr/src/sys/netgraph/ng_base.c:2411
 #32 0xc060704d in ng_apply_item (node=0xc4791c00, item=0xc40917c0,
 rw=0) at /usr/src/sys/netgraph/ng_base.c:2483
 #33 0xc0609cb9 in ng_snd_item (item=0xc40917c0, flags=0) at
 /usr/src/sys/netgraph/ng_base.c:2411
 ---Type <return> to continue, or q <return> to quit---
 #34 0xc061a58d in ng_tcpmss_rcvdata (hook=0xc43ca800, item=0xc40917c0)
 at /usr/src/sys/netgraph/ng_tcpmss.c:346
 #35 0xc060704d in ng_apply_item (node=0xc474b800, item=0xc40917c0,
 rw=0) at /usr/src/sys/netgraph/ng_base.c:2483
 #36 0xc0609cb9 in ng_snd_item (item=0xc40917c0, flags=0) at
 /usr/src/sys/netgraph/ng_base.c:2411
 #37 0xc06029df in ng_netflow_rcvdata (hook=0xc42e2200,
 item=0xc40917c0) at /usr/src/sys/netgraph/netflow/ng_netflow.c:469
 #38 0xc060704d in ng_apply_item (node=0xc4287100, item=0xc40917c0,
 rw=0) at /usr/src/sys/netgraph/ng_base.c:2483
 #39 0xc0609cb9 in ng_snd_item (item=0xc40917c0, flags=0) at
 /usr/src/sys/netgraph/ng_base.c:2411
 #40 0xc0602cbc in ng_netflow_rcvdata (hook=0xc43c7c80,
 item=0xc40917c0) at /usr/src/sys/netgraph/netflow/ng_netflow.c:600
 #41 0xc060704d in ng_apply_item (node=0xc4287100, item=0xc40917c0,
 rw=0) at /usr/src/sys/netgraph/ng_base.c:2483
 #42 0xc0609cb9 in ng_snd_item (item=0xc40917c0, flags=0) at
 /usr/src/sys/netgraph/ng_base.c:2411
 #43 0xc06129fe in ng_ppp_proto_recv (node=0xc409db00, item=0xc40917c0,
 proto=33, linkNum=0)
     at /usr/src/sys/netgraph/ng_ppp.c:930
 #44 0xc0612af8 in ng_ppp_hcomp_recv (node=0xc409db00, item=0xc40917c0,
 proto=33, linkNum=0)
     at /usr/src/sys/netgraph/ng_ppp.c:1030
 #45 0xc0612c93 in ng_ppp_comp_recv (node=0xc409db00, item=0xc40917c0,
 proto=33, linkNum=0)
     at /usr/src/sys/netgraph/ng_ppp.c:1149
 #46 0xc0612d83 in ng_ppp_crypt_recv (node=0xc409db00, item=0xc40917c0,
 proto=33, linkNum=0)
     at /usr/src/sys/netgraph/ng_ppp.c:1249
 #47 0xc0615ea4 in ng_ppp_rcvdata (hook=0xc4070480, item=0xc40917c0) at
 /usr/src/sys/netgraph/ng_ppp.c:1504
 #48 0xc060704d in ng_apply_item (node=0xc409db00, item=0xc40917c0,
 rw=0) at /usr/src/sys/netgraph/ng_base.c:2483
 #49 0xc0609cb9 in ng_snd_item (item=0xc40917c0, flags=0) at
 /usr/src/sys/netgraph/ng_base.c:2411
 #50 0xc0618354 in ng_pptpgre_rcvdata (hook=0xc43c7b80,
 item=0xc40917c0) at /usr/src/sys/netgraph/ng_pptpgre.c:748
 #51 0xc060704d in ng_apply_item (node=0xc474be00, item=0xc40917c0,
 rw=0) at /usr/src/sys/netgraph/ng_base.c:2483
 #52 0xc0609cb9 in ng_snd_item (item=0xc40917c0, flags=0) at
 /usr/src/sys/netgraph/ng_base.c:2411
 #53 0xc060fa60 in ng_ksocket_incoming2 (node=0xc4784000, hook=0x0,
 arg1=0xc42aaad4, waitflag=1)
     at /usr/src/sys/netgraph/ng_ksocket.c:1149
 #54 0xc0609278 in ng_apply_item (node=0xc4784000, item=0xc4091280,
 rw=1) at /usr/src/sys/netgraph/ng_base.c:2559
 #55 0xc0609643 in ngintr () at /usr/src/sys/netgraph/ng_base.c:3403
 #56 0xc05f83f2 in swi_net (dummy=0x0) at /usr/src/sys/net/netisr.c:254
 #57 0xc053d2db in ithread_loop (arg=0xc3b04280) at
 /usr/src/sys/kern/kern_intr.c:1036
 #58 0xc053a0d9 in fork_exit (callout=0xc053d130 <ithread_loop>,
 arg=0xc3b04280, frame=0xe3fefd38)
     at /usr/src/sys/kern/kern_fork.c:781
 #59 0xc0794390 in fork_trampoline () at /usr/src/sys/i386/i386/exception.s:205
 (kgdb)

From: Oleg Bulyzhin <oleg@FreeBSD.org>
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/121955: dummynet panics after 6.2
Date: Wed, 2 Apr 2008 20:47:47 +0400

 --rwEMma7ioTxnRzrJ
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 
 
 Please test attached patch and let me know if it changes anything for you.
 
 -- 
 Oleg.
 
 ================================================================
 === Oleg Bulyzhin -- OBUL-RIPN -- OBUL-RIPE -- oleg@rinet.ru ===
 ================================================================
 
 
 --rwEMma7ioTxnRzrJ
 Content-Type: text/x-diff; charset=us-ascii
 Content-Disposition: attachment; filename="dummynet_iofast.diff"
 
 Index: sys/netinet/ip_dummynet.h
 ===================================================================
 RCS file: /home/ncvs/src/sys/netinet/ip_dummynet.h,v
 retrieving revision 1.40
 diff -u -r1.40 ip_dummynet.h
 --- sys/netinet/ip_dummynet.h	17 Jun 2007 00:33:34 -0000	1.40
 +++ sys/netinet/ip_dummynet.h	27 Mar 2008 17:19:00 -0000
 @@ -343,7 +343,7 @@
  #ifdef _KERNEL
  typedef	int ip_dn_ctl_t(struct sockopt *); /* raw_ip.c */
  typedef	void ip_dn_ruledel_t(void *); /* ip_fw.c */
 -typedef	int ip_dn_io_t(struct mbuf *m, int dir, struct ip_fw_args *fwa);
 +typedef	int ip_dn_io_t(struct mbuf **m, int dir, struct ip_fw_args *fwa);
  extern	ip_dn_ctl_t *ip_dn_ctl_ptr;
  extern	ip_dn_ruledel_t *ip_dn_ruledel_ptr;
  extern	ip_dn_io_t *ip_dn_io_ptr;
 Index: sys/netinet/ip_dummynet.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/netinet/ip_dummynet.c,v
 retrieving revision 1.110
 diff -u -r1.110 ip_dummynet.c
 --- sys/netinet/ip_dummynet.c	7 Oct 2007 20:44:22 -0000	1.110
 +++ sys/netinet/ip_dummynet.c	27 Mar 2008 17:19:03 -0000
 @@ -56,6 +56,7 @@
   * include files marked with XXX are probably not needed
   */
  
 +#include <sys/limits.h>
  #include <sys/param.h>
  #include <sys/systm.h>
  #include <sys/malloc.h>
 @@ -110,6 +111,11 @@
  /* Adjusted vs non-adjusted curr_time difference (ticks). */
  static long tick_diff;
  
 +static int		io_fast;
 +static unsigned long	io_pkt;
 +static unsigned long	io_pkt_fast;
 +static unsigned long	io_pkt_drop;
 +
  /*
   * Three heaps contain queues and pipes that the scheduler handles:
   *
 @@ -181,6 +187,17 @@
  SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_lost,
      CTLFLAG_RD, &tick_lost, 0,
      "Number of ticks coalesced by dummynet taskqueue.");
 +SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, io_fast,
 +    CTLFLAG_RW, &io_fast, 0, "Enable fast dummynet io.");
 +SYSCTL_ULONG(_net_inet_ip_dummynet, OID_AUTO, io_pkt,
 +    CTLFLAG_RD, &io_pkt, 0,
 +    "Number of packets passed to dummynet.");
 +SYSCTL_ULONG(_net_inet_ip_dummynet, OID_AUTO, io_pkt_fast,
 +    CTLFLAG_RD, &io_pkt_fast, 0,
 +    "Number of packets bypassed dummynet scheduler.");
 +SYSCTL_ULONG(_net_inet_ip_dummynet, OID_AUTO, io_pkt_drop,
 +    CTLFLAG_RD, &io_pkt_drop, 0,
 +    "Number of packets dropped by dummynet.");
  #endif
  
  #ifdef DUMMYNET_DEBUG
 @@ -206,15 +223,15 @@
  #define	DUMMYNET_UNLOCK()	mtx_unlock(&dummynet_mtx)
  #define	DUMMYNET_LOCK_ASSERT()	mtx_assert(&dummynet_mtx, MA_OWNED)
  
 -static int config_pipe(struct dn_pipe *p);
 -static int ip_dn_ctl(struct sockopt *sopt);
 +static int	config_pipe(struct dn_pipe *p);
 +static int	ip_dn_ctl(struct sockopt *sopt);
  
 -static void dummynet(void *);
 -static void dummynet_flush(void);
 -static void dummynet_send(struct mbuf *);
 -void dummynet_drain(void);
 +static void	dummynet(void *);
 +static void	dummynet_flush(void);
 +static void	dummynet_send(struct mbuf *);
 +void		dummynet_drain(void);
  static ip_dn_io_t dummynet_io;
 -static void dn_rule_delete(void *);
 +static void	dn_rule_delete(void *);
  
  /*
   * Heap management functions.
 @@ -483,7 +500,7 @@
  	if ((m = pipe->head) != NULL) {
  		pkt = dn_tag_get(m);
  		/*
 -		 * XXX: Should check errors on heap_insert, by draining the
 +		 * XXX Should check errors on heap_insert, by draining the
  		 * whole pipe p and hoping in the future we are more successful.
  		 */
  		heap_insert(&extract_heap, pkt->output_time, pipe);
 @@ -496,8 +513,8 @@
   * either a pipe (WF2Q) or a flow_queue (per-flow queueing)
   */
  #define SET_TICKS(_m, q, p)	\
 -    ((_m)->m_pkthdr.len*8*hz - (q)->numbytes + p->bandwidth - 1 ) / \
 -	    p->bandwidth ;
 +    ((_m)->m_pkthdr.len * 8 * hz - (q)->numbytes + p->bandwidth - 1) / \
 +    p->bandwidth;
  
  /*
   * extract pkt from queue, compute output time (could be now)
 @@ -533,59 +550,61 @@
  static void
  ready_event(struct dn_flow_queue *q, struct mbuf **head, struct mbuf **tail)
  {
 -    struct mbuf *pkt;
 -    struct dn_pipe *p = q->fs->pipe ;
 -    int p_was_empty ;
 +	struct mbuf *pkt;
 +	struct dn_pipe *p = q->fs->pipe;
 +	int p_was_empty;
  
 -    DUMMYNET_LOCK_ASSERT();
 +	DUMMYNET_LOCK_ASSERT();
  
 -    if (p == NULL) {
 -	printf("dummynet: ready_event- pipe is gone\n");
 -	return ;
 -    }
 -    p_was_empty = (p->head == NULL) ;
 +	if (p == NULL) {
 +		printf("dummynet: ready_event- pipe is gone\n");
 +		return;
 +	}
 +	p_was_empty = (p->head == NULL);
  
 -    /*
 -     * schedule fixed-rate queues linked to this pipe:
 -     * Account for the bw accumulated since last scheduling, then
 -     * drain as many pkts as allowed by q->numbytes and move to
 -     * the delay line (in p) computing output time.
 -     * bandwidth==0 (no limit) means we can drain the whole queue,
 -     * setting len_scaled = 0 does the job.
 -     */
 -    q->numbytes += ( curr_time - q->sched_time ) * p->bandwidth;
 -    while ( (pkt = q->head) != NULL ) {
 -	int len = pkt->m_pkthdr.len;
 -	int len_scaled = p->bandwidth ? len*8*hz : 0 ;
 -	if (len_scaled > q->numbytes )
 -	    break ;
 -	q->numbytes -= len_scaled ;
 -	move_pkt(pkt, q, p, len);
 -    }
 -    /*
 -     * If we have more packets queued, schedule next ready event
 -     * (can only occur when bandwidth != 0, otherwise we would have
 -     * flushed the whole queue in the previous loop).
 -     * To this purpose we record the current time and compute how many
 -     * ticks to go for the finish time of the packet.
 -     */
 -    if ( (pkt = q->head) != NULL ) { /* this implies bandwidth != 0 */
 -	dn_key t = SET_TICKS(pkt, q, p); /* ticks i have to wait */
 -	q->sched_time = curr_time ;
 -	heap_insert(&ready_heap, curr_time + t, (void *)q );
 -	/* XXX should check errors on heap_insert, and drain the whole
 -	 * queue on error hoping next time we are luckier.
 +	/*
 +	 * Schedule fixed-rate queues linked to this pipe:
 +	 * account for the bw accumulated since last scheduling, then
 +	 * drain as many pkts as allowed by q->numbytes and move to
 +	 * the delay line (in p) computing output time.
 +	 * bandwidth==0 (no limit) means we can drain the whole queue,
 +	 * setting len_scaled = 0 does the job.
  	 */
 -    } else {	/* RED needs to know when the queue becomes empty */
 -	q->q_time = curr_time;
 -	q->numbytes = 0;
 -    }
 -    /*
 -     * If the delay line was empty call transmit_event() now.
 -     * Otherwise, the scheduler will take care of it.
 -     */
 -    if (p_was_empty)
 -	transmit_event(p, head, tail);
 +	q->numbytes += (curr_time - q->sched_time) * p->bandwidth;
 +	while ((pkt = q->head) != NULL) {
 +		int len = pkt->m_pkthdr.len;
 +		int len_scaled = p->bandwidth ? len * 8 * hz : 0;
 +
 +		if (len_scaled > q->numbytes)
 +			break;
 +		q->numbytes -= len_scaled;
 +		move_pkt(pkt, q, p, len);
 +	}
 +	/*
 +	 * If we have more packets queued, schedule next ready event
 +	 * (can only occur when bandwidth != 0, otherwise we would have
 +	 * flushed the whole queue in the previous loop).
 +	 * To this purpose we record the current time and compute how many
 +	 * ticks to go for the finish time of the packet.
 +	 */
 +	if ((pkt = q->head) != NULL) {	/* this implies bandwidth != 0 */
 +		dn_key t = SET_TICKS(pkt, q, p); /* ticks i have to wait */
 +
 +		q->sched_time = curr_time;
 +		heap_insert(&ready_heap, curr_time + t, (void *)q);
 +		/*
 +		 * XXX Should check errors on heap_insert, and drain the whole
 +		 * queue on error hoping next time we are luckier.
 +		 */
 +	} else		/* RED needs to know when the queue becomes empty. */
 +		q->q_time = curr_time;
 +
 +	/*
 +	 * If the delay line was empty call transmit_event() now.
 +	 * Otherwise, the scheduler will take care of it.
 +	 */
 +	if (p_was_empty)
 +		transmit_event(p, head, tail);
  }
  
  /*
 @@ -593,123 +612,147 @@
   * the queues at their start time, and enqueue into the delay line.
   * Packets are drained until p->numbytes < 0. As long as
   * len_scaled >= p->numbytes, the packet goes into the delay line
 - * with a deadline p->delay. For the last packet, if p->numbytes<0,
 + * with a deadline p->delay. For the last packet, if p->numbytes < 0,
   * there is an additional delay.
   */
  static void
  ready_event_wfq(struct dn_pipe *p, struct mbuf **head, struct mbuf **tail)
  {
 -    int p_was_empty = (p->head == NULL) ;
 -    struct dn_heap *sch = &(p->scheduler_heap);
 -    struct dn_heap *neh = &(p->not_eligible_heap) ;
 +	int p_was_empty = (p->head == NULL);
 +	struct dn_heap *sch = &(p->scheduler_heap);
 +	struct dn_heap *neh = &(p->not_eligible_heap);
 +	int64_t p_numbytes = p->numbytes;
  
 -    DUMMYNET_LOCK_ASSERT();
 -
 -    if (p->if_name[0] == 0) /* tx clock is simulated */
 -	p->numbytes += ( curr_time - p->sched_time ) * p->bandwidth;
 -    else { /* tx clock is for real, the ifq must be empty or this is a NOP */
 -	if (p->ifp && p->ifp->if_snd.ifq_head != NULL)
 -	    return ;
 -	else {
 -	    DPRINTF(("dummynet: pipe %d ready from %s --\n",
 -		p->pipe_nr, p->if_name));
 -	}
 -    }
 +	DUMMYNET_LOCK_ASSERT();
  
 -    /*
 -     * While we have backlogged traffic AND credit, we need to do
 -     * something on the queue.
 -     */
 -    while ( p->numbytes >=0 && (sch->elements>0 || neh->elements >0) ) {
 -	if (sch->elements > 0) { /* have some eligible pkts to send out */
 -	    struct dn_flow_queue *q = sch->p[0].object ;
 -	    struct mbuf *pkt = q->head;
 -	    struct dn_flow_set *fs = q->fs;
 -	    u_int64_t len = pkt->m_pkthdr.len;
 -	    int len_scaled = p->bandwidth ? len*8*hz : 0 ;
 -
 -	    heap_extract(sch, NULL); /* remove queue from heap */
 -	    p->numbytes -= len_scaled ;
 -	    move_pkt(pkt, q, p, len);
 -
 -	    p->V += (len<<MY_M) / p->sum ; /* update V */
 -	    q->S = q->F ; /* update start time */
 -	    if (q->len == 0) { /* Flow not backlogged any more */
 -		fs->backlogged-- ;
 -		heap_insert(&(p->idle_heap), q->F, q);
 -	    } else { /* still backlogged */
 +	if (p->if_name[0] == 0)		/* tx clock is simulated */
  		/*
 -		 * update F and position in backlogged queue, then
 -		 * put flow in not_eligible_heap (we will fix this later).
 +		 * Since result may not fit into p->numbytes (32bit) we
 +		 * are using 64bit var here.
  		 */
 -		len = (q->head)->m_pkthdr.len;
 -		q->F += (len<<MY_M)/(u_int64_t) fs->weight ;
 -		if (DN_KEY_LEQ(q->S, p->V))
 -		    heap_insert(neh, q->S, q);
 -		else
 -		    heap_insert(sch, q->F, q);
 -	    }
 +		p_numbytes += (curr_time - p->sched_time) * p->bandwidth;
 +	else {	/*
 +		 * tx clock is for real,
 +		 * the ifq must be empty or this is a NOP.
 +		 */
 +		if (p->ifp && p->ifp->if_snd.ifq_head != NULL)
 +			return;
 +		else {
 +			DPRINTF(("dummynet: pipe %d ready from %s --\n",
 +			    p->pipe_nr, p->if_name));
 +		}
  	}
 +
  	/*
 -	 * now compute V = max(V, min(S_i)). Remember that all elements in sch
 -	 * have by definition S_i <= V so if sch is not empty, V is surely
 -	 * the max and we must not update it. Conversely, if sch is empty
 -	 * we only need to look at neh.
 +	 * While we have backlogged traffic AND credit, we need to do
 +	 * something on the queue.
  	 */
 -	if (sch->elements == 0 && neh->elements > 0)
 -	    p->V = MAX64 ( p->V, neh->p[0].key );
 -	/* move from neh to sch any packets that have become eligible */
 -	while (neh->elements > 0 && DN_KEY_LEQ(neh->p[0].key, p->V) ) {
 -	    struct dn_flow_queue *q = neh->p[0].object ;
 -	    heap_extract(neh, NULL);
 -	    heap_insert(sch, q->F, q);
 +	while (p_numbytes >= 0 && (sch->elements > 0 || neh->elements > 0)) {
 +		if (sch->elements > 0) {
 +			/* Have some eligible pkts to send out. */
 +			struct dn_flow_queue *q = sch->p[0].object;
 +			struct mbuf *pkt = q->head;
 +			struct dn_flow_set *fs = q->fs;
 +			uint64_t len = pkt->m_pkthdr.len;
 +			int len_scaled = p->bandwidth ? len * 8 * hz : 0;
 +
 +			heap_extract(sch, NULL); /* Remove queue from heap. */
 +			p_numbytes -= len_scaled;
 +			move_pkt(pkt, q, p, len);
 +
 +			p->V += (len << MY_M) / p->sum;	/* Update V. */
 +			q->S = q->F;			/* Update start time. */
 +			if (q->len == 0) {
 +				/* Flow not backlogged any more. */
 +				fs->backlogged--;
 +				heap_insert(&(p->idle_heap), q->F, q);
 +			} else {
 +				/* Still backlogged. */
 +
 +				/*
 +				 * Update F and position in backlogged queue,
 +				 * then put flow in not_eligible_heap
 +				 * (we will fix this later).
 +				 */
 +				len = (q->head)->m_pkthdr.len;
 +				q->F += (len << MY_M) / (uint64_t)fs->weight;
 +				if (DN_KEY_LEQ(q->S, p->V))
 +					heap_insert(neh, q->S, q);
 +				else
 +					heap_insert(sch, q->F, q);
 +			}
 +		}
 +		/*
 +		 * Now compute V = max(V, min(S_i)). Remember that all elements
 +		 * in sch have by definition S_i <= V so if sch is not empty,
 +		 * V is surely the max and we must not update it. Conversely,
 +		 * if sch is empty we only need to look at neh.
 +		 */
 +		if (sch->elements == 0 && neh->elements > 0)
 +			p->V = MAX64(p->V, neh->p[0].key);
 +		/* Move from neh to sch any packets that have become eligible */
 +		while (neh->elements > 0 && DN_KEY_LEQ(neh->p[0].key, p->V)) {
 +			struct dn_flow_queue *q = neh->p[0].object;
 +			heap_extract(neh, NULL);
 +			heap_insert(sch, q->F, q);
 +		}
 +
 +		if (p->if_name[0] != '\0') { /* Tx clock is from a real thing */
 +			p_numbytes = -1;	/* Mark not ready for I/O. */
 +			break;
 +		}
  	}
 +	if (sch->elements == 0 && neh->elements == 0 && p_numbytes >= 0 &&
 +	    p->idle_heap.elements > 0) {
 +		/*
 +		 * No traffic and no events scheduled.
 +		 * We can get rid of idle-heap.
 +		 */
 +		int i;
  
 -	if (p->if_name[0] != '\0') {/* tx clock is from a real thing */
 -	    p->numbytes = -1 ; /* mark not ready for I/O */
 -	    break ;
 +		for (i = 0; i < p->idle_heap.elements; i++) {
 +			struct dn_flow_queue *q = p->idle_heap.p[i].object;
 +
 +			q->F = 0;
 +			q->S = q->F + 1;
 +		}
 +		p->sum = 0;
 +		p->V = 0;
 +		p->idle_heap.elements = 0;
  	}
 -    }
 -    if (sch->elements == 0 && neh->elements == 0 && p->numbytes >= 0
 -	    && p->idle_heap.elements > 0) {
  	/*
 -	 * no traffic and no events scheduled. We can get rid of idle-heap.
 +	 * If we are getting clocks from dummynet (not a real interface) and
 +	 * If we are under credit, schedule the next ready event.
 +	 * Also fix the delivery time of the last packet.
  	 */
 -	int i ;
 +	if (p->if_name[0]==0 && p_numbytes < 0) { /* This implies bw > 0. */
 +		dn_key t = 0;		/* Number of ticks i have to wait. */
  
 -	for (i = 0 ; i < p->idle_heap.elements ; i++) {
 -	    struct dn_flow_queue *q = p->idle_heap.p[i].object ;
 -
 -	    q->F = 0 ;
 -	    q->S = q->F + 1 ;
 +		if (p->bandwidth > 0)
 +			t = (p->bandwidth - 1 - p_numbytes) / p->bandwidth;
 +		dn_tag_get(p->tail)->output_time += t;
 +		p->sched_time = curr_time;
 +		heap_insert(&wfq_ready_heap, curr_time + t, (void *)p);
 +		/*
 +		 * XXX Should check errors on heap_insert, and drain the whole
 +		 * queue on error hoping next time we are luckier.
 +		 */
  	}
 -	p->sum = 0 ;
 -	p->V = 0 ;
 -	p->idle_heap.elements = 0 ;
 -    }
 -    /*
 -     * If we are getting clocks from dummynet (not a real interface) and
 -     * If we are under credit, schedule the next ready event.
 -     * Also fix the delivery time of the last packet.
 -     */
 -    if (p->if_name[0]==0 && p->numbytes < 0) { /* this implies bandwidth >0 */
 -	dn_key t=0 ; /* number of ticks i have to wait */
  
 -	if (p->bandwidth > 0)
 -	    t = ( p->bandwidth -1 - p->numbytes) / p->bandwidth ;
 -	dn_tag_get(p->tail)->output_time += t ;
 -	p->sched_time = curr_time ;
 -	heap_insert(&wfq_ready_heap, curr_time + t, (void *)p);
 -	/* XXX should check errors on heap_insert, and drain the whole
 -	 * queue on error hoping next time we are luckier.
 +	/* Fit (adjust if necessary) 64bit result into 32bit variable. */
 +	if (p_numbytes > INT_MAX)
 +		p->numbytes = INT_MAX;
 +	else if (p_numbytes < INT_MIN)
 +		p->numbytes = INT_MIN;
 +	else
 +		p->numbytes = p_numbytes;
 +
 +	/*
 +	 * If the delay line was empty call transmit_event() now.
 +	 * Otherwise, the scheduler will take care of it.
  	 */
 -    }
 -    /*
 -     * If the delay line was empty call transmit_event() now.
 -     * Otherwise, the scheduler will take care of it.
 -     */
 -    if (p_was_empty)
 -	transmit_event(p, head, tail);
 +	if (p_was_empty)
 +		transmit_event(p, head, tail);
  }
  
  /*
 @@ -924,29 +967,28 @@
  static struct dn_flow_queue *
  create_queue(struct dn_flow_set *fs, int i)
  {
 -    struct dn_flow_queue *q ;
 +	struct dn_flow_queue *q;
  
 -    if (fs->rq_elements > fs->rq_size * dn_max_ratio &&
 +	if (fs->rq_elements > fs->rq_size * dn_max_ratio &&
  	    expire_queues(fs) == 0) {
 -	/*
 -	 * No way to get room, use or create overflow queue.
 -	 */
 -	i = fs->rq_size ;
 -	if ( fs->rq[i] != NULL )
 -	    return fs->rq[i] ;
 -    }
 -    q = malloc(sizeof(*q), M_DUMMYNET, M_NOWAIT | M_ZERO);
 -    if (q == NULL) {
 -	printf("dummynet: sorry, cannot allocate queue for new flow\n");
 -	return NULL ;
 -    }
 -    q->fs = fs ;
 -    q->hash_slot = i ;
 -    q->next = fs->rq[i] ;
 -    q->S = q->F + 1;   /* hack - mark timestamp as invalid */
 -    fs->rq[i] = q ;
 -    fs->rq_elements++ ;
 -    return q ;
 +		/* No way to get room, use or create overflow queue. */
 +		i = fs->rq_size;
 +		if (fs->rq[i] != NULL)
 +		    return fs->rq[i];
 +	}
 +	q = malloc(sizeof(*q), M_DUMMYNET, M_NOWAIT | M_ZERO);
 +	if (q == NULL) {
 +		printf("dummynet: sorry, cannot allocate queue for new flow\n");
 +		return (NULL);
 +	}
 +	q->fs = fs;
 +	q->hash_slot = i;
 +	q->next = fs->rq[i];
 +	q->S = q->F + 1;	/* hack - mark timestamp as invalid. */
 +	q->numbytes = io_fast ? fs->pipe->bandwidth : 0;
 +	fs->rq[i] = q;
 +	fs->rq_elements++;
 +	return (q);
  }
  
  /*
 @@ -1200,185 +1242,201 @@
   * ifp		the 'ifp' parameter from the caller.
   *		NULL in ip_input, destination interface in ip_output,
   * rule		matching rule, in case of multiple passes
 - *
   */
  static int
 -dummynet_io(struct mbuf *m, int dir, struct ip_fw_args *fwa)
 +dummynet_io(struct mbuf **m0, int dir, struct ip_fw_args *fwa)
  {
 -    struct mbuf *head = NULL, *tail = NULL;
 -    struct dn_pkt_tag *pkt;
 -    struct m_tag *mtag;
 -    struct dn_flow_set *fs = NULL;
 -    struct dn_pipe *pipe ;
 -    u_int64_t len = m->m_pkthdr.len ;
 -    struct dn_flow_queue *q = NULL ;
 -    int is_pipe;
 -    ipfw_insn *cmd = ACTION_PTR(fwa->rule);
 -
 -    KASSERT(m->m_nextpkt == NULL,
 -	("dummynet_io: mbuf queue passed to dummynet"));
 -
 -    if (cmd->opcode == O_LOG)
 -	cmd += F_LEN(cmd);
 -    if (cmd->opcode == O_ALTQ)
 -	cmd += F_LEN(cmd);
 -    if (cmd->opcode == O_TAG)
 -	cmd += F_LEN(cmd);
 -    is_pipe = (cmd->opcode == O_PIPE);
 +	struct mbuf *m = *m0, *head = NULL, *tail = NULL;
 +	struct dn_pkt_tag *pkt;
 +	struct m_tag *mtag;
 +	struct dn_flow_set *fs = NULL;
 +	struct dn_pipe *pipe;
 +	uint64_t len = m->m_pkthdr.len;
 +	struct dn_flow_queue *q = NULL;
 +	int is_pipe;
 +	ipfw_insn *cmd = ACTION_PTR(fwa->rule);
 +
 +	KASSERT(m->m_nextpkt == NULL,
 +	    ("dummynet_io: mbuf queue passed to dummynet"));
 +
 +	if (cmd->opcode == O_LOG)
 +		cmd += F_LEN(cmd);
 +	if (cmd->opcode == O_ALTQ)
 +		cmd += F_LEN(cmd);
 +	if (cmd->opcode == O_TAG)
 +		cmd += F_LEN(cmd);
 +	is_pipe = (cmd->opcode == O_PIPE);
  
 -    DUMMYNET_LOCK();
 -    /*
 -     * This is a dummynet rule, so we expect an O_PIPE or O_QUEUE rule.
 -     *
 -     * XXXGL: probably the pipe->fs and fs->pipe logic here
 -     * below can be simplified.
 -     */
 -    if (is_pipe) {
 -	pipe = locate_pipe(fwa->cookie);
 -	if (pipe != NULL)
 -		fs = &(pipe->fs);
 -    } else
 -	fs = locate_flowset(fwa->cookie);
 +	DUMMYNET_LOCK();
 +	io_pkt++;
 +	/*
 +	 * This is a dummynet rule, so we expect an O_PIPE or O_QUEUE rule.
 +	 *
 +	 * XXXGL: probably the pipe->fs and fs->pipe logic here
 +	 * below can be simplified.
 +	 */
 +	if (is_pipe) {
 +		pipe = locate_pipe(fwa->cookie);
 +		if (pipe != NULL)
 +			fs = &(pipe->fs);
 +	} else
 +		fs = locate_flowset(fwa->cookie);
  
 -    if (fs == NULL)
 -	goto dropit;	/* This queue/pipe does not exist! */
 -    pipe = fs->pipe;
 -    if (pipe == NULL) { /* Must be a queue, try find a matching pipe. */
 -	pipe = locate_pipe(fs->parent_nr);
 -	if (pipe != NULL)
 -	    fs->pipe = pipe;
 -	else {
 -	    printf("dummynet: no pipe %d for queue %d, drop pkt\n",
 -		fs->parent_nr, fs->fs_nr);
 -	    goto dropit ;
 +	if (fs == NULL)
 +		goto dropit;	/* This queue/pipe does not exist! */
 +	pipe = fs->pipe;
 +	if (pipe == NULL) {	/* Must be a queue, try find a matching pipe. */
 +		pipe = locate_pipe(fs->parent_nr);
 +		if (pipe != NULL)
 +			fs->pipe = pipe;
 +		else {
 +			printf("dummynet: no pipe %d for queue %d, drop pkt\n",
 +			    fs->parent_nr, fs->fs_nr);
 +			goto dropit;
 +		}
  	}
 -    }
 -    q = find_queue(fs, &(fwa->f_id));
 -    if ( q == NULL )
 -	goto dropit ;		/* cannot allocate queue		*/
 -    /*
 -     * update statistics, then check reasons to drop pkt
 -     */
 -    q->tot_bytes += len ;
 -    q->tot_pkts++ ;
 -    if ( fs->plr && random() < fs->plr )
 -	goto dropit ;		/* random pkt drop			*/
 -    if ( fs->flags_fs & DN_QSIZE_IS_BYTES) {
 -    	if (q->len_bytes > fs->qsize)
 -	    goto dropit ;	/* queue size overflow			*/
 -    } else {
 -	if (q->len >= fs->qsize)
 -	    goto dropit ;	/* queue count overflow			*/
 -    }
 -    if ( fs->flags_fs & DN_IS_RED && red_drops(fs, q, len) )
 -	goto dropit ;
 -
 -    /* XXX expensive to zero, see if we can remove it*/
 -    mtag = m_tag_get(PACKET_TAG_DUMMYNET,
 -		sizeof(struct dn_pkt_tag), M_NOWAIT|M_ZERO);
 -    if ( mtag == NULL )
 -	goto dropit ;		/* cannot allocate packet header	*/
 -    m_tag_prepend(m, mtag);	/* attach to mbuf chain */
 -
 -    pkt = (struct dn_pkt_tag *)(mtag+1);
 -    /* ok, i can handle the pkt now... */
 -    /* build and enqueue packet + parameters */
 -    pkt->rule = fwa->rule ;
 -    pkt->dn_dir = dir ;
 -
 -    pkt->ifp = fwa->oif;
 +	q = find_queue(fs, &(fwa->f_id));
 +	if (q == NULL)
 +		goto dropit;		/* Cannot allocate queue. */
 +
 +	/* Update statistics, then check reasons to drop pkt. */
 +	q->tot_bytes += len;
 +	q->tot_pkts++;
 +	if (fs->plr && random() < fs->plr)
 +		goto dropit;		/* Random pkt drop. */
 +	if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
 +		if (q->len_bytes > fs->qsize)
 +			goto dropit;	/* Queue size overflow. */
 +	} else {
 +		if (q->len >= fs->qsize)
 +			goto dropit;	/* Queue count overflow. */
 +	}
 +	if (fs->flags_fs & DN_IS_RED && red_drops(fs, q, len))
 +		goto dropit;
  
 -    if (q->head == NULL)
 -	q->head = m;
 -    else
 -	q->tail->m_nextpkt = m;
 -    q->tail = m;
 -    q->len++;
 -    q->len_bytes += len ;
 +	/* XXX expensive to zero, see if we can remove it. */
 +	mtag = m_tag_get(PACKET_TAG_DUMMYNET,
 +	    sizeof(struct dn_pkt_tag), M_NOWAIT | M_ZERO);
 +	if (mtag == NULL)
 +		goto dropit;		/* Cannot allocate packet header. */
 +	m_tag_prepend(m, mtag);		/* Attach to mbuf chain. */
  
 -    if ( q->head != m )		/* flow was not idle, we are done */
 -	goto done;
 -    /*
 -     * If we reach this point the flow was previously idle, so we need
 -     * to schedule it. This involves different actions for fixed-rate or
 -     * WF2Q queues.
 -     */
 -    if (is_pipe) {
 +	pkt = (struct dn_pkt_tag *)(mtag + 1);
  	/*
 -	 * Fixed-rate queue: just insert into the ready_heap.
 +	 * Ok, i can handle the pkt now...
 +	 * Build and enqueue packet + parameters.
  	 */
 -	dn_key t = 0 ;
 -	if (pipe->bandwidth)
 -	    t = SET_TICKS(m, q, pipe);
 -	q->sched_time = curr_time ;
 -	if (t == 0)	/* must process it now */
 -	    ready_event(q, &head, &tail);
 +	pkt->rule = fwa->rule;
 +	pkt->dn_dir = dir;
 +
 +	pkt->ifp = fwa->oif;
 +
 +	if (q->head == NULL)
 +		q->head = m;
  	else
 -	    heap_insert(&ready_heap, curr_time + t , q );
 -    } else {
 -	/*
 -	 * WF2Q. First, compute start time S: if the flow was idle (S=F+1)
 -	 * set S to the virtual time V for the controlling pipe, and update
 -	 * the sum of weights for the pipe; otherwise, remove flow from
 -	 * idle_heap and set S to max(F,V).
 -	 * Second, compute finish time F = S + len/weight.
 -	 * Third, if pipe was idle, update V=max(S, V).
 -	 * Fourth, count one more backlogged flow.
 -	 */
 -	if (DN_KEY_GT(q->S, q->F)) { /* means timestamps are invalid */
 -	    q->S = pipe->V ;
 -	    pipe->sum += fs->weight ; /* add weight of new queue */
 -	} else {
 -	    heap_extract(&(pipe->idle_heap), q);
 -	    q->S = MAX64(q->F, pipe->V ) ;
 -	}
 -	q->F = q->S + ( len<<MY_M )/(u_int64_t) fs->weight;
 +		q->tail->m_nextpkt = m;
 +	q->tail = m;
 +	q->len++;
 +	q->len_bytes += len;
 +
 +	if (q->head != m)		/* Flow was not idle, we are done. */
 +		goto done;
 +
 +	if (q->q_time < curr_time)
 +		q->numbytes = io_fast ? fs->pipe->bandwidth : 0;
 +	q->q_time = curr_time;
  
 -	if (pipe->not_eligible_heap.elements == 0 &&
 -		pipe->scheduler_heap.elements == 0)
 -	    pipe->V = MAX64 ( q->S, pipe->V );
 -	fs->backlogged++ ;
  	/*
 -	 * Look at eligibility. A flow is not eligibile if S>V (when
 -	 * this happens, it means that there is some other flow already
 -	 * scheduled for the same pipe, so the scheduler_heap cannot be
 -	 * empty). If the flow is not eligible we just store it in the
 -	 * not_eligible_heap. Otherwise, we store in the scheduler_heap
 -	 * and possibly invoke ready_event_wfq() right now if there is
 -	 * leftover credit.
 -	 * Note that for all flows in scheduler_heap (SCH), S_i <= V,
 -	 * and for all flows in not_eligible_heap (NEH), S_i > V .
 -	 * So when we need to compute max( V, min(S_i) ) forall i in SCH+NEH,
 -	 * we only need to look into NEH.
 +	 * If we reach this point the flow was previously idle, so we need
 +	 * to schedule it. This involves different actions for fixed-rate or
 +	 * WF2Q queues.
  	 */
 -	if (DN_KEY_GT(q->S, pipe->V) ) { /* not eligible */
 -	    if (pipe->scheduler_heap.elements == 0)
 -		printf("dummynet: ++ ouch! not eligible but empty scheduler!\n");
 -	    heap_insert(&(pipe->not_eligible_heap), q->S, q);
 +	if (is_pipe) {
 +		/* Fixed-rate queue: just insert into the ready_heap. */
 +		dn_key t = 0;
 +
 +		if (pipe->bandwidth && m->m_pkthdr.len * 8 * hz > q->numbytes)
 +			t = SET_TICKS(m, q, pipe);
 +		q->sched_time = curr_time;
 +		if (t == 0)		/* Must process it now. */
 +			ready_event(q, &head, &tail);
 +		else
 +			heap_insert(&ready_heap, curr_time + t , q);
  	} else {
 -	    heap_insert(&(pipe->scheduler_heap), q->F, q);
 -	    if (pipe->numbytes >= 0) { /* pipe is idle */
 -		if (pipe->scheduler_heap.elements != 1)
 -		    printf("dummynet: OUCH! pipe should have been idle!\n");
 -		DPRINTF(("dummynet: waking up pipe %d at %d\n",
 -			pipe->pipe_nr, (int)(q->F >> MY_M)));
 -		pipe->sched_time = curr_time ;
 -		ready_event_wfq(pipe, &head, &tail);
 -	    }
 +		/*
 +		 * WF2Q. First, compute start time S: if the flow was
 +		 * idle (S = F + 1) set S to the virtual time V for the
 +		 * controlling pipe, and update the sum of weights for the pipe;
 +		 * otherwise, remove flow from idle_heap and set S to max(F,V).
 +		 * Second, compute finish time F = S + len / weight.
 +		 * Third, if pipe was idle, update V = max(S, V).
 +		 * Fourth, count one more backlogged flow.
 +		 */
 +		if (DN_KEY_GT(q->S, q->F)) { /* Means timestamps are invalid. */
 +			q->S = pipe->V;
 +			pipe->sum += fs->weight; /* Add weight of new queue. */
 +		} else {
 +			heap_extract(&(pipe->idle_heap), q);
 +			q->S = MAX64(q->F, pipe->V);
 +		}
 +		q->F = q->S + (len << MY_M) / (uint64_t)fs->weight;
 +
 +		if (pipe->not_eligible_heap.elements == 0 &&
 +		    pipe->scheduler_heap.elements == 0)
 +			pipe->V = MAX64(q->S, pipe->V);
 +		fs->backlogged++;
 +		/*
 +		 * Look at eligibility. A flow is not eligibile if S>V (when
 +		 * this happens, it means that there is some other flow already
 +		 * scheduled for the same pipe, so the scheduler_heap cannot be
 +		 * empty). If the flow is not eligible we just store it in the
 +		 * not_eligible_heap. Otherwise, we store in the scheduler_heap
 +		 * and possibly invoke ready_event_wfq() right now if there is
 +		 * leftover credit.
 +		 * Note that for all flows in scheduler_heap (SCH), S_i <= V,
 +		 * and for all flows in not_eligible_heap (NEH), S_i > V.
 +		 * So when we need to compute max(V, min(S_i)) forall i in
 +		 * SCH+NEH, we only need to look into NEH.
 +		 */
 +		if (DN_KEY_GT(q->S, pipe->V)) {		/* Not eligible. */
 +			if (pipe->scheduler_heap.elements == 0)
 +				printf("dummynet: ++ ouch! not eligible but empty scheduler!\n");
 +			heap_insert(&(pipe->not_eligible_heap), q->S, q);
 +		} else {
 +			heap_insert(&(pipe->scheduler_heap), q->F, q);
 +			if (pipe->numbytes >= 0) {	 /* Pipe is idle. */
 +				if (pipe->scheduler_heap.elements != 1)
 +					printf("dummynet: OUCH! pipe should have been idle!\n");
 +				DPRINTF(("dummynet: waking up pipe %d at %d\n",
 +				    pipe->pipe_nr, (int)(q->F >> MY_M)));
 +				pipe->sched_time = curr_time;
 +				ready_event_wfq(pipe, &head, &tail);
 +			}
 +		}
  	}
 -    }
  done:
 -    DUMMYNET_UNLOCK();
 -    if (head != NULL)
 -	dummynet_send(head);
 -    return 0;
 +	if (head == m && dir != DN_TO_IFB_FWD && dir != DN_TO_ETH_DEMUX &&
 +	    dir != DN_TO_ETH_OUT) {	/* Fast io. */
 +		io_pkt_fast++;
 +		if (m->m_nextpkt != NULL)
 +			printf("dummynet: fast io: pkt chain detected!\n");
 +		head = m->m_nextpkt = NULL;
 +	} else
 +		*m0 = NULL;		/* Normal io. */
 +
 +	DUMMYNET_UNLOCK();
 +	if (head != NULL)
 +		dummynet_send(head);
 +	return (0);
  
  dropit:
 -    if (q)
 -	q->drops++ ;
 -    DUMMYNET_UNLOCK();
 -    m_freem(m);
 -    return ( (fs && (fs->flags_fs & DN_NOERROR)) ? 0 : ENOBUFS);
 +	io_pkt_drop++;
 +	if (q)
 +		q->drops++;
 +	DUMMYNET_UNLOCK();
 +	m_freem(m);
 +	*m0 = NULL;
 +	return ((fs && (fs->flags_fs & DN_NOERROR)) ? 0 : ENOBUFS);
  }
  
  /*
 @@ -1696,7 +1754,7 @@
  			/* 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;
 +					q->numbytes = io_fast ? p->bandwidth : 0;
  
  		pipe->bandwidth = p->bandwidth;
  		pipe->numbytes = 0;		/* just in case... */
 Index: sys/netinet/ip_fw_pfil.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/netinet/ip_fw_pfil.c,v
 retrieving revision 1.25
 diff -u -r1.25 ip_fw_pfil.c
 --- sys/netinet/ip_fw_pfil.c	7 Oct 2007 20:44:23 -0000	1.25
 +++ sys/netinet/ip_fw_pfil.c	27 Mar 2008 17:19:10 -0000
 @@ -104,16 +104,6 @@
  
  	bzero(&args, sizeof(args));
  
 -	dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
 -	if (dn_tag != NULL){
 -		struct dn_pkt_tag *dt;
 -
 -		dt = (struct dn_pkt_tag *)(dn_tag+1);
 -		args.rule = dt->rule;
 -
 -		m_tag_delete(*m0, dn_tag);
 -	}
 -
  	ng_tag = (struct ng_ipfw_tag *)m_tag_locate(*m0, NGM_IPFW_COOKIE, 0,
  	    NULL);
  	if (ng_tag != NULL) {
 @@ -124,6 +114,16 @@
  	}
  
  again:
 +	dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
 +	if (dn_tag != NULL){
 +		struct dn_pkt_tag *dt;
 +
 +		dt = (struct dn_pkt_tag *)(dn_tag+1);
 +		args.rule = dt->rule;
 +
 +		m_tag_delete(*m0, dn_tag);
 +	}
 +
  	args.m = *m0;
  	args.inp = inp;
  	ipfw = ipfw_chk(&args);
 @@ -160,10 +160,11 @@
  		if (!DUMMYNET_LOADED)
  			goto drop;
  		if (mtod(*m0, struct ip *)->ip_v == 4)
 -			ip_dn_io_ptr(*m0, DN_TO_IP_IN, &args);
 +			ip_dn_io_ptr(m0, DN_TO_IP_IN, &args);
  		else if (mtod(*m0, struct ip *)->ip_v == 6)
 -			ip_dn_io_ptr(*m0, DN_TO_IP6_IN, &args);
 -		*m0 = NULL;
 +			ip_dn_io_ptr(m0, DN_TO_IP6_IN, &args);
 +		if (*m0 != NULL)
 +			goto again;
  		return 0;		/* packet consumed */
  
  	case IP_FW_TEE:
 @@ -225,16 +226,6 @@
  
  	bzero(&args, sizeof(args));
  
 -	dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
 -	if (dn_tag != NULL) {
 -		struct dn_pkt_tag *dt;
 -
 -		dt = (struct dn_pkt_tag *)(dn_tag+1);
 -		args.rule = dt->rule;
 -
 -		m_tag_delete(*m0, dn_tag);
 -	}
 -
  	ng_tag = (struct ng_ipfw_tag *)m_tag_locate(*m0, NGM_IPFW_COOKIE, 0,
  	    NULL);
  	if (ng_tag != NULL) {
 @@ -245,6 +236,16 @@
  	}
  
  again:
 +	dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
 +	if (dn_tag != NULL) {
 +		struct dn_pkt_tag *dt;
 +
 +		dt = (struct dn_pkt_tag *)(dn_tag+1);
 +		args.rule = dt->rule;
 +
 +		m_tag_delete(*m0, dn_tag);
 +	}
 +
  	args.m = *m0;
  	args.oif = ifp;
  	args.inp = inp;
 @@ -286,10 +287,11 @@
  		if (!DUMMYNET_LOADED)
  			break;
  		if (mtod(*m0, struct ip *)->ip_v == 4)
 -			ip_dn_io_ptr(*m0, DN_TO_IP_OUT, &args);
 +			ip_dn_io_ptr(m0, DN_TO_IP_OUT, &args);
  		else if (mtod(*m0, struct ip *)->ip_v == 6)
 -			ip_dn_io_ptr(*m0, DN_TO_IP6_OUT, &args);
 -		*m0 = NULL;
 +			ip_dn_io_ptr(m0, DN_TO_IP6_OUT, &args);
 +		if (*m0 != NULL)
 +			goto again;
  		return 0;		/* packet consumed */
  
  		break;
 Index: sys/net/if_bridge.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/net/if_bridge.c,v
 retrieving revision 1.103.2.3
 diff -u -r1.103.2.3 if_bridge.c
 --- sys/net/if_bridge.c	21 Dec 2007 05:29:15 -0000	1.103.2.3
 +++ sys/net/if_bridge.c	27 Mar 2008 17:19:15 -0000
 @@ -2982,7 +2982,7 @@
  			 * packet will return to us via bridge_dummynet().
  			 */
  			args.oif = ifp;
 -			ip_dn_io_ptr(*mp, DN_TO_IFB_FWD, &args);
 +			ip_dn_io_ptr(mp, DN_TO_IFB_FWD, &args);
  			return (error);
  		}
  
 Index: sys/net/if_ethersubr.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/net/if_ethersubr.c,v
 retrieving revision 1.236.2.1
 diff -u -r1.236.2.1 if_ethersubr.c
 --- sys/net/if_ethersubr.c	28 Oct 2007 16:24:16 -0000	1.236.2.1
 +++ sys/net/if_ethersubr.c	27 Mar 2008 17:19:18 -0000
 @@ -491,7 +491,7 @@
  			 */
  			*m0 = NULL ;
  		}
 -		ip_dn_io_ptr(m, dst ? DN_TO_ETH_OUT: DN_TO_ETH_DEMUX, &args);
 +		ip_dn_io_ptr(&m, dst ? DN_TO_ETH_OUT: DN_TO_ETH_DEMUX, &args);
  		return 0;
  	}
  	/*
 Index: sbin/ipfw/ipfw.8
 ===================================================================
 RCS file: /home/ncvs/src/sbin/ipfw/ipfw.8,v
 retrieving revision 1.203.2.1
 diff -u -r1.203.2.1 ipfw.8
 --- sbin/ipfw/ipfw.8	29 Nov 2007 18:42:15 -0000	1.203.2.1
 +++ sbin/ipfw/ipfw.8	27 Mar 2008 17:25:32 -0000
 @@ -1756,6 +1756,16 @@
  TCP connection, or from/to a given host, or entire subnet, or a
  protocol type, etc.
  .Pp
 +There are two modes of dummynet operation: normal and fast.
 +Normal mode tries to emulate real link: dummynet scheduler ensures packet will
 +not leave pipe faster than it would be on real link with given bandwidth.
 +Fast mode allows certain packets to bypass dummynet scheduler (if packet flow
 +does not exceed pipe's bandwidth). Thus fast mode requires less cpu cycles
 +per packet (in average) but packet latency can be significantly lower comparing
 +to real link with same bandwidth. Default is normal mode, fast mode can be
 +enabled by setting net.inet.ip.dummynet.io_fast sysctl(8) variable to non-zero
 +value.
 +.Pp
  Packets belonging to the same flow are then passed to either of two
  different objects, which implement the traffic regulation:
  .Bl -hang -offset XXXX
 @@ -2120,6 +2130,14 @@
  This value is used when no
  .Cm buckets
  option is specified when configuring a pipe/queue.
 +.It Em net.inet.ip.dummynet.io_fast : No 0
 +If set to non-zero value enables "fast" mode of dummynet operation (see above).
 +.It Em net.inet.ip.dummynet.io_pkt
 +Number of packets passed to by dummynet.
 +.It Em net.inet.ip.dummynet.io_pkt_drop
 +Number of packets dropped by dummynet.
 +.It Em net.inet.ip.dummynet.io_pkt_fast
 +Number of packets bypassed dummynet scheduler.
  .It Em net.inet.ip.dummynet.max_chain_len : No 16
  Target value for the maximum number of pipes/queues in a hash bucket.
  The product
 
 --rwEMma7ioTxnRzrJ--
 
State-Changed-From-To: open->patched 
State-Changed-By: oleg 
State-Changed-When: Fri Apr 25 10:20:48 UTC 2008 
State-Changed-Why:  
In private discussion PR author confirms that suggested patch did help. 



Responsible-Changed-From-To: freebsd-ipfw->oleg 
Responsible-Changed-By: oleg 
Responsible-Changed-When: Fri Apr 25 10:20:48 UTC 2008 
Responsible-Changed-Why:  
see above. 


http://www.freebsd.org/cgi/query-pr.cgi?pr=121955 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/121955: commit references a PR
Date: Fri, 25 Apr 2008 10:26:38 +0000 (UTC)

 oleg        2008-04-25 10:26:31 UTC
 
   FreeBSD src repository
 
   Modified files:        (Branch: RELENG_7)
     sys/netinet          ip_dummynet.h ip_dummynet.c ip_fw_pfil.c 
     sys/net              if_bridge.c if_ethersubr.c 
     sbin/ipfw            ipfw.8 
   Log:
   MFC:
   src/sys/netinet/ip_dummynet.h   1.41
   src/sys/netinet/ip_dummynet.c   1.111-1.114
   src/sys/netinet/ip_fw_pfil.c    1.26
   src/sys/net/if_bridge.c         1.107
   src/sys/net/if_ethersubr.c      1.240
   src/sbin/ipfw/ipfw.8            1.206
   
   - style(9) cleanup.
   - dummynet_io() declaration has changed.
   - Alter packet flow inside dummynet and introduce 'fast' mode of dummynet
     operation: allow certain packets to bypass dummynet scheduler. Benefits are:
     -- lower latency: if packet flow does not exceed pipe bandwidth, packets
        will not be (up to tick) delayed (due to dummynet's scheduler granularity).
     -- lower overhead: if packet avoids dummynet scheduler it shouldn't reenter
        ip stack later. Such packets can be fastforwarded.
     -- recursion (which can lead to kernel stack exhaution) eliminated. This fix
        long existed panic, which can be triggered this way:
           kldload dummynet
           sysctl net.inet.ip.fw.one_pass=0
           ipfw pipe 1 config bw 0
           for i in `jot 30`; do ipfw add 1 pipe 1 icmp from any to any; done
           ping -c 1 localhost
   - New sysctl nodes:
     net.inet.ip.dummynet.io_fast -        enables 'fast' dummynet io
     net.inet.ip.dummynet.io_pkt -         packets passed to dummynet
     net.inet.ip.dummynet.io_pkt_fast -    packets avoided dummynet scheduler
     net.inet.ip.dummynet.io_pkt_drop -    packets dropped by dummynet
   - Workaround p->numbytes overflow, which can result in infinite loop inside
     dummynet module (prerequisite is using queues with "fat" pipe).
   
   PR:     kern/113548 kern/121955
   
   Revision   Changes    Path
   1.203.2.4  +18 -0     src/sbin/ipfw/ipfw.8
   1.103.2.6  +1 -1      src/sys/net/if_bridge.c
   1.236.2.2  +1 -1      src/sys/net/if_ethersubr.c
   1.110.2.1  +395 -337  src/sys/netinet/ip_dummynet.c
   1.40.2.1   +1 -1      src/sys/netinet/ip_dummynet.h
   1.25.2.2   +28 -26    src/sys/netinet/ip_fw_pfil.c
 _______________________________________________
 cvs-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/cvs-all
 To unsubscribe, send any mail to "cvs-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/121955: commit references a PR
Date: Fri, 25 Apr 2008 10:29:32 +0000 (UTC)

 oleg        2008-04-25 10:29:26 UTC
 
   FreeBSD src repository
 
   Modified files:        (Branch: RELENG_6)
     sys/netinet          ip_dummynet.h ip_dummynet.c ip_fw_pfil.c 
     sys/net              if_bridge.c if_ethersubr.c 
     sbin/ipfw            ipfw.8 
   Log:
   MFC:
   src/sys/netinet/ip_dummynet.h   1.41
   src/sys/netinet/ip_dummynet.c   1.111-1.114
   src/sys/netinet/ip_fw_pfil.c    1.26
   src/sys/net/if_bridge.c         1.107
   src/sys/net/if_ethersubr.c      1.240
   src/sbin/ipfw/ipfw.8            1.206
   
   - style(9) cleanup.
   - dummynet_io() declaration has changed.
   - Alter packet flow inside dummynet and introduce 'fast' mode of dummynet
     operation: allow certain packets to bypass dummynet scheduler. Benefits are:
     -- lower latency: if packet flow does not exceed pipe bandwidth, packets
        will not be (up to tick) delayed (due to dummynet's scheduler granularity).
     -- lower overhead: if packet avoids dummynet scheduler it shouldn't reenter
        ip stack later. Such packets can be fastforwarded.
     -- recursion (which can lead to kernel stack exhaution) eliminated. This fix
        long existed panic, which can be triggered this way:
           kldload dummynet
           sysctl net.inet.ip.fw.one_pass=0
           ipfw pipe 1 config bw 0
           for i in `jot 30`; do ipfw add 1 pipe 1 icmp from any to any; done
           ping -c 1 localhost
   - New sysctl nodes:
     net.inet.ip.dummynet.io_fast -        enables 'fast' dummynet io
     net.inet.ip.dummynet.io_pkt -         packets passed to dummynet
     net.inet.ip.dummynet.io_pkt_fast -    packets avoided dummynet scheduler
     net.inet.ip.dummynet.io_pkt_drop -    packets dropped by dummynet
   - Workaround p->numbytes overflow, which can result in infinite loop inside
     dummynet module (prerequisite is using queues with "fat" pipe).
   
   PR:     kern/113548 kern/121955
   
   Revision    Changes    Path
   1.175.2.15  +18 -0     src/sbin/ipfw/ipfw.8
   1.11.2.55   +1 -1      src/sys/net/if_bridge.c
   1.193.2.16  +1 -1      src/sys/net/if_ethersubr.c
   1.93.2.7    +395 -337  src/sys/netinet/ip_dummynet.c
   1.36.2.3    +1 -1      src/sys/netinet/ip_dummynet.h
   1.19.2.4    +28 -26    src/sys/netinet/ip_fw_pfil.c
 _______________________________________________
 cvs-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/cvs-all
 To unsubscribe, send any mail to "cvs-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: oleg 
State-Changed-When: Wed May 7 17:43:33 UTC 2008 
State-Changed-Why:  
commited to RELENG_[67] 

http://www.freebsd.org/cgi/query-pr.cgi?pr=121955 
>Unformatted:
