Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 28 Oct 2007 21:11:09 +0100
From:      "=?ISO-8859-1?Q?Ermal_Lu=E7i?=" <ermal.luci@gmail.com>
To:        freebsd-pf@freebsd.org, freebsd-net@freebsd.org
Subject:   Fwd: [PATCH] PF+dummynet
Message-ID:  <9a542da30710281311n7f8a6f29me02da90941d96ae5@mail.gmail.com>
In-Reply-To: <9a542da30710281013q642b5aa8k33c7836ee064242e@mail.gmail.com>
References:  <9a542da30710161409o4732a77bybdf4ba35d7491bb@mail.gmail.com> <200710171043.08126.max@love2party.net> <d5992baf0710171324n65c4b171l71db8aeac445b52d@mail.gmail.com> <9a542da30710211232v4d3c930fg8ea778a12f3f16cb@mail.gmail.com> <9a542da30710280617t11e668e2o4d122998192f71c@mail.gmail.com> <20071028095802.A61999@xorpc.icir.org> <9a542da30710281013q642b5aa8k33c7836ee064242e@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
Ok thanks to remko@ for hosting it!

You can find it here:
http://people.freebsd.org/~remko/patches/dummynet_pf.tar.gz

Please test and give feedback.

>
> > It gives full dummynet support in pf.conf syntax and removes dummynet
> > depndency to ipfw.
> >
> > You can configure a pipe/queue using the same ipfw syntax the only
> > difference is that i call those 'dnpipe'/'dnqueue' respectivley.
> > GRED/RED isn't currently finished but that is a pfctl addition so not
> > difficult.
> >
> > For dummynet i preserve ipfw style statistics so tools of ipfw can be
> > used here to.
> >
> > Since this is PF i preserved ALTQ priotitizing of ACK, meaning on ALTQ you do
> > pass in quick proto tcp from any to any flags S/SA queue(pri, que)
> >
> > You can do the same with dummynet queues only, since for pipes it
> > doesn't make much sense since they simulate a link. So yuo can do
> >
> > dnpipe 10 bandwidth 100Kbit
> > dnqueue 10 dnpipe 10 queue 100
> > dnqueue 20 dnpipe 10 queue 20
> >
> > pass in quick proto tcp from any to any flags S/SA dnqueue(10, 20)
> >
> >
> > Please test and give feedback.
>
> > _______________________________________________
> > freebsd-net@freebsd.org mailing list
> > http://lists.freebsd.org/mailman/listinfo/freebsd-net
> > To unsubscribe, send any mail to "freebsd-net-unsubscribe@freebsd.org"
>

[-- Attachment #2 --]
Index: contrib/pf/pfctl/parse.y
===================================================================
RCS file: /home/eri/repo/contrib/pf/pfctl/parse.y,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 parse.y
--- contrib/pf/pfctl/parse.y	21 Oct 2007 13:53:15 -0000	1.1.1.1
+++ contrib/pf/pfctl/parse.y	21 Oct 2007 19:03:49 -0000
@@ -45,6 +45,9 @@
 #include <altq/altq_priq.h>
 #include <altq/altq_hfsc.h>
 
+#include <netinet/ip_fw.h>
+#include <netinet/ip_dummynet.h>
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <netdb.h>
@@ -206,6 +209,9 @@
 	char			*tag;
 	char			*match_tag;
 	u_int8_t		 match_tag_not;
+	u_int32_t		 dnpipe;
+	u_int32_t		 pdnpipe;
+	u_int32_t		 dntype;
 	int			 rtableid;
 } filter_opts;
 
@@ -261,6 +267,8 @@
 
 
 struct node_hfsc_opts	hfsc_opts;
+struct dn_pipe		dnpipe_opts;
+struct dn_flow_set	dnqueue_opts;
 
 int	yyerror(const char *, ...);
 int	disallow_table(struct node_host *, const char *);
@@ -395,6 +403,8 @@
 		struct filter_opts	 filter_opts;
 		struct antispoof_opts	 antispoof_opts;
 		struct queue_opts	 queue_opts;
+		struct dn_pipe		 dnpipe_opts;
+		struct dn_flow_set	 dnqueue_opts;
 		struct scrub_opts	 scrub_opts;
 		struct table_opts	 table_opts;
 		struct pool_opts	 pool_opts;
@@ -421,6 +431,8 @@
 %token	BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY
 %token	ALTQ CBQ PRIQ HFSC BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT
 %token	QUEUE PRIORITY QLIMIT RTABLE
+%token	DNPIPE DNQUEUE GRED RED WEIGHT MASK DELAY BUCKETS PLR
+%token	SRCIP DSTIP SRCPORT DSTPORT SRCIP6 DSTIP6 FLOWID NOERROR
 %token	LOAD RULESET_OPTIMIZATION
 %token	STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
 %token	MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH
@@ -451,7 +463,7 @@
 %type	<v.gid>			gids gid_list gid_item
 %type	<v.route>		route
 %type	<v.redirection>		redirection redirpool
-%type	<v.string>		label string tag anchorname
+%type	<v.string>		label string tag anchorname 
 %type	<v.keep_state>		keep
 %type	<v.state_opt>		state_opt_spec state_opt_list state_opt_item
 %type	<v.logquick>		logquick quick log logopts logopt
@@ -462,6 +474,8 @@
 %type	<v.number>		cbqflags_list cbqflags_item
 %type	<v.number>		priqflags_list priqflags_item
 %type	<v.hfsc_opts>		hfscopts_list hfscopts_item hfsc_opts
+%type	<v.dnpipe_opts>		dnpipe_opts
+%type	<v.dnqueue_opts>	dnqueue_opts mask_specifier
 %type	<v.queue_bwspec>	bandwidth
 %type	<v.filter_opts>		filter_opts filter_opt filter_opts_l
 %type	<v.antispoof_opts>	antispoof_opts antispoof_opt antispoof_opts_l
@@ -483,6 +497,8 @@
 		| ruleset anchorrule '\n'
 		| ruleset loadrule '\n'
 		| ruleset altqif '\n'
+		| ruleset dummynetif '\n'
+		| ruleset dnqueuespec '\n'
 		| ruleset queuespec '\n'
 		| ruleset varset '\n'
 		| ruleset antispoof '\n'
@@ -1667,6 +1683,222 @@
 		}
 		;
 
+dummynetif      : DNPIPE number dnpipe_opts dnqueue_opts        {
+                        struct dn_pipe p;
+
+                        if (check_rulestate(PFCTL_STATE_QUEUE))
+                                YYERROR;
+
+                        memset(&p, 0, sizeof(p));
+
+                        p.bandwidth = $3.bandwidth;
+                        p.delay = $3.delay;
+			p.pipe_nr = $2;
+                        memcpy(&p.fs, &$4,
+                                sizeof(p.fs));
+
+                        if(pfctl_add_dummynet(pf, &p))
+                                YYERROR;
+                }
+dnqueuespec     : DNQUEUE number DNPIPE number dnqueue_opts {
+		        struct dn_pipe p;
+
+                        if (check_rulestate(PFCTL_STATE_QUEUE)) 
+                                YYERROR;
+
+                        memset(&p, 0, sizeof(p));
+
+                        if ($4 == 0) {
+                                yyerror("pipe must be specified for queue");
+                                YYERROR;
+                        }
+			if ($2 == 0) {
+				yyerror("queue number must be greater than 0");
+				YYERROR;
+			}
+					
+                        memcpy(&p.fs, &$5, sizeof(p.fs));
+			p.fs.fs_nr = $2;
+                        p.fs.parent_nr = $4;
+			p.pipe_nr = 0;
+
+                        if (pfctl_add_dummynet(pf, &p)) {
+                                yyerror("errors in dnqueue definition");
+                                YYERROR;
+                        }
+                }
+                ;
+
+dnpipe_opts     :       /* XXX: fix this */ {
+	                bzero(&dnpipe_opts, sizeof dnpipe_opts);
+                }
+                        dnpipe_opts_l
+                       	{ $$ = dnpipe_opts; }
+                |	/* empty */ {
+                        bzero(&dnpipe_opts, sizeof dnpipe_opts);
+                        $$ = dnpipe_opts;
+                }
+                ;
+
+dnpipe_opts_l   : dnpipe_opts_l dnpipe_opt
+	        | dnpipe_opt
+                ;
+
+dnpipe_opt      : BANDWIDTH bandwidth   {
+                        dnpipe_opts.bandwidth = $2.bw_absolute;
+                }
+                | DELAY number          {
+                        if ($2 > 0 && $2 < 10001)
+                                dnpipe_opts.delay = $2;
+                        else {
+                                yyerror("delay needs argument 0..10000ms");
+                                YYERROR;
+                        }
+                }
+                ;
+
+dnqueue_opts    : /* XXX: fix this */ {
+		        bzero(&dnqueue_opts, sizeof dnqueue_opts);
+                }
+                    dnqueue_opts_l
+                        { $$ = dnqueue_opts; }
+                | /* empty */ {
+                        bzero(&queue_opts, sizeof queue_opts);
+                        $$ = dnqueue_opts;
+                }
+                ;
+
+dnqueue_opts_l  : dnqueue_opts_l dnqueue_opt
+		| dnqueue_opt
+                ;
+
+dnqueue_opt     : BUCKETS number       {
+		        if ($2 < 16 || $2 > 65535) {
+                                yyerror("buckets out of range: [16-65535]");
+                                YYERROR;
+                        }
+                        /*dnqueue_opts.marker |= DN_BUCKETS;*/
+                        dnqueue_opts.rq_size = $2;
+                }
+		| WEIGHT number			  {
+			if ($2 < 0 || $2 > 100)  { /* [0..100] is allowed */
+                                yyerror("weight must be in [0..100] range");
+                                YYERROR;
+                        }
+                        
+			dnqueue_opts.weight = $2;
+		}
+                | QUEUE STRING		 {
+                        double   bps;
+                        char    *cp;
+
+			bps = strtod($2, &cp);
+                        if (bps < 16 || bps > 65535) {
+                                yyerror("qlimit out of range [16..65535]");
+                                YYERROR;
+                        }
+
+                        if (cp != NULL) {
+                                if (!strcmp(cp, "B"))
+					dnqueue_opts.flags_fs |= 
+						DN_QSIZE_IS_BYTES;
+                                else if (!strcmp(cp, "KB")) {
+                                        bps *= 1024;
+					dnqueue_opts.flags_fs |= 
+						DN_QSIZE_IS_BYTES;
+                                } else if (*cp != '\0') {
+                                        yyerror("unknown unit %s", cp);
+                                        free($2);
+                                        YYERROR;
+                                }
+			} else 
+				dnqueue_opts.flags_fs &= 
+					~DN_QSIZE_IS_BYTES;
+                        free($2);
+
+                        dnqueue_opts.qsize = (u_int32_t)bps;
+                }
+                | PLR number                            {
+                        dnqueue_opts.plr = (int)$2*0x7fffffff ;
+                }
+                | MASK mask_specifier   {
+                        memcpy(&dnqueue_opts, &$2,
+                                sizeof(dnqueue_opts));
+                }
+                | RED string '/' number '/' number '/' string       {
+                        /* XXX: this not yet finished! */
+                        char    *e;
+                        double   p = strtod($2, &e);
+
+                        if (*e == '%') {
+                                p *= 0.01;
+                                e++;
+                        }
+                        if (*e) {
+                                yyerror("invalid: %s", $2);
+                                free($2);
+                                YYERROR;
+                        }
+                        p = floor(p * (UINT_MAX+1.0) + 0.5);
+                        if (p < 1.0 || p >= (UINT_MAX+1.0)) {
+                                yyerror("invalid: %s", $2);
+                                free($2);
+                                YYERROR;
+                        }
+                        free($2);
+                }
+                ;
+
+mask_specifier  : ALL                   {
+
+                        memset(&$$, 0, sizeof($$));
+
+                        $$.flow_mask.dst_ip = ~0;
+                        $$.flow_mask.src_ip = ~0;
+                        $$.flow_mask.dst_port = ~0;
+                        $$.flow_mask.src_port = ~0;
+                        $$.flow_mask.proto = ~0;
+                        n2mask(&$$.flow_mask.dst_ip6, 128);
+                        n2mask(&$$.flow_mask.src_ip6, 128);
+                        $$.flow_mask.flow_id6 = ~0;
+                        $$.flags_fs |= DN_HAVE_FLOW_MASK;
+                }
+                | DSTIP number             	{
+			$$.flow_mask.dst_ip = (uint32_t)$2;
+                        $$.flags_fs |= DN_HAVE_FLOW_MASK;
+                }
+                | SRCIP number	             {
+                        $$.flow_mask.src_ip = (uint32_t)$2;
+                        $$.flags_fs |= DN_HAVE_FLOW_MASK;
+                }
+                | DSTPORT number	           {
+                        $$.flow_mask.dst_port = (uint16_t)$2;
+                        $$.flags_fs |= DN_HAVE_FLOW_MASK;
+                }
+                | SRCPORT number	           {
+                        $$.flow_mask.src_port = (uint16_t)$2;
+                        $$.flags_fs |= DN_HAVE_FLOW_MASK;
+                }
+                | DSTIP6 '/' number 	           {
+                        n2mask(&$$.flow_mask.dst_ip6, $3);
+                        $$.flags_fs |= DN_HAVE_FLOW_MASK;
+                }
+                | SRCIP6 '/' number	            {
+                        n2mask(&$$.flow_mask.src_ip6, $3);
+                        $$.flags_fs |= DN_HAVE_FLOW_MASK;
+                }
+                | FLOWID number	            {
+                        $$.flow_mask.flow_id6 = (uint32_t)$2;
+                        $$.flags_fs |= DN_HAVE_FLOW_MASK;
+
+                }
+                | PROTO number 	             {
+                        $$.flow_mask.proto = (uint8_t)$2;
+                        $$.flags_fs |= DN_HAVE_FLOW_MASK;
+                }
+                | NOERROR       { $$.flags_fs |= DN_NOERROR; }
+                ;
+
 pfrule		: action dir logquick interface route af proto fromto
 		    filter_opts
 		{
@@ -2034,6 +2266,14 @@
 				free($9.queues.pqname);
 			}
 
+			if ($9.dnpipe) {
+				r.dnpipe = $9.dnpipe;
+				r.dntype = $9.dntype;
+			}
+			if ($9.pdnpipe && r.dntype == DN_IS_QUEUE) {
+				r.pdnpipe = $9.pdnpipe;
+			}
+
 			expand_rule(&r, $4, $5.host, $7, $8.src_os,
 			    $8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
 			    $9.uid, $9.gid, $9.icmpspec, "");
@@ -2123,6 +2363,27 @@
 			}
 			filter_opts.queues = $1;
 		}
+		| DNPIPE number			        {
+			filter_opts.dnpipe = $2;
+			filter_opts.dntype = DN_IS_PIPE;
+		}
+		| DNPIPE '(' number ')'			{
+			filter_opts.dnpipe = $3;
+			filter_opts.dntype = DN_IS_PIPE;
+		}
+		| DNQUEUE number			{
+			filter_opts.dnpipe = $2;
+			filter_opts.dntype = DN_IS_QUEUE;
+		}
+		| DNQUEUE '(' number comma number ')'	{
+			filter_opts.dnpipe = $3;
+			filter_opts.pdnpipe = $5;
+			filter_opts.dntype = DN_IS_QUEUE;
+		}
+		| DNQUEUE '(' number ')'		{
+			filter_opts.dnpipe = $3;
+			filter_opts.dntype = DN_IS_QUEUE;
+		}
 		| TAG string				{
 			filter_opts.tag = $2;
 		}
@@ -4110,6 +4371,11 @@
 		yyerror("keep state on block rules doesn't make sense");
 		problems++;
 	}
+	if (r->rt && r->dnpipe) {
+		yyerror("route-to/dup-to/fastroute/reply-to with dummynet "
+			"doesn't make sense");
+		problems++;
+	}
 	return (-problems);
 }
 
@@ -4896,23 +5162,32 @@
 		{ "bitmask",		BITMASK},
 		{ "block",		BLOCK},
 		{ "block-policy",	BLOCKPOLICY},
+		{ "buckets",		BUCKETS},
 		{ "cbq",		CBQ},
 		{ "code",		CODE},
 		{ "crop",		FRAGCROP},
 		{ "debug",		DEBUG},
+		{ "delay",		DELAY},
+		{ "dnpipe", 		DNPIPE},
+		{ "dnqueue",		DNQUEUE},
 		{ "drop",		DROP},
 		{ "drop-ovl",		FRAGDROP},
+		{ "dst-ip",		DSTIP},
+		{ "dst-ip6",		DSTIP6},
 		{ "dup-to",		DUPTO},
+		{ "dst-port",		DSTPORT},
 		{ "fastroute",		FASTROUTE},
 		{ "file",		FILENAME},
 		{ "fingerprints",	FINGERPRINTS},
 		{ "flags",		FLAGS},
 		{ "floating",		FLOATING},
+		{ "flow-id",		FLOWID},
 		{ "flush",		FLUSH},
 		{ "for",		FOR},
 		{ "fragment",		FRAGMENT},
 		{ "from",		FROM},
 		{ "global",		GLOBAL},
+		{ "gred",		GRED},
 		{ "group",		GROUP},
 		{ "hfsc",		HFSC},
 		{ "hostid",		HOSTID},
@@ -4929,6 +5204,7 @@
 		{ "load",		LOAD},
 		{ "log",		LOG},
 		{ "loginterface",	LOGINTERFACE},
+		{ "mask",		MASK},
 		{ "max",		MAXIMUM},
 		{ "max-mss",		MAXMSS},
 		{ "max-src-conn",	MAXSRCCONN},
@@ -4943,12 +5219,14 @@
 		{ "no-df",		NODF},
 		{ "no-route",		NOROUTE},
 		{ "no-sync",		NOSYNC},
+		{ "noerror",		NOERROR},
 		{ "on",			ON},
 		{ "optimization",	OPTIMIZATION},
 		{ "os",			OS},
 		{ "out",		OUT},
 		{ "overload",		OVERLOAD},
 		{ "pass",		PASS},
+		{ "plr",		PLR},
 		{ "port",		PORT},
 		{ "priority",		PRIORITY},
 		{ "priq",		PRIQ},
@@ -4963,6 +5241,7 @@
 		{ "rdr-anchor",		RDRANCHOR},
 		{ "realtime",		REALTIME},
 		{ "reassemble",		REASSEMBLE},
+		{ "red",		RED},
 		{ "reply-to",		REPLYTO},
 		{ "require-order",	REQUIREORDER},
 		{ "return",		RETURN},
@@ -4980,6 +5259,9 @@
 		{ "skip",		SKIP},
 		{ "source-hash",	SOURCEHASH},
 		{ "source-track",	SOURCETRACK},
+		{ "src-ip",		SRCIP},
+		{ "src-ip6", 		SRCIP6},
+		{ "src-port",		SRCPORT},
 		{ "state",		STATE},
 		{ "state-policy",	STATEPOLICY},
 		{ "static-port",	STATICPORT},
@@ -4996,6 +5278,7 @@
 		{ "upperlimit",		UPPERLIMIT},
 		{ "urpf-failed",	URPFFAILED},
 		{ "user",		USER},
+		{ "weight",		WEIGHT},
 	};
 	const struct keywords	*p;
 
@@ -5524,3 +5807,23 @@
 
 	return (0);
 }
+
+/* n2mask sets n bits of the mask */
+static void
+n2mask(struct in6_addr *mask, int n)
+{
+        static int      minimask[9] =
+            { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
+        u_char          *p;
+
+        memset(mask, 0, sizeof(struct in6_addr));
+        p = (u_char *) mask;
+        for (; n > 0; p++, n -= 8) {
+                if (n >= 8)
+                        *p = 0xff;
+                else
+                        *p = minimask[n];
+        }
+        return;
+}
+
Index: contrib/pf/pfctl/pfctl.c
===================================================================
RCS file: /home/eri/repo/contrib/pf/pfctl/pfctl.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 pfctl.c
--- contrib/pf/pfctl/pfctl.c	21 Oct 2007 13:53:15 -0000	1.1.1.1
+++ contrib/pf/pfctl/pfctl.c	21 Oct 2007 19:03:49 -0000
@@ -46,6 +46,9 @@
 #include <altq/altq.h>
 #include <sys/sysctl.h>
 
+#include <netinet/ip_fw.h>
+#include <netinet/ip_dummynet.h>
+
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -71,6 +74,7 @@
 int	 pfctl_clear_rules(int, int, char *);
 int	 pfctl_clear_nat(int, int, char *);
 int	 pfctl_clear_altq(int, int);
+int	 pfctl_clear_dummynet(int, int);
 int	 pfctl_clear_src_nodes(int, int);
 int	 pfctl_clear_states(int, const char *, int);
 void	 pfctl_addrprefix(char *, struct pf_addr *);
@@ -95,6 +99,7 @@
 int	 pfctl_show_limits(int, int);
 void	 pfctl_debug(int, u_int32_t, int);
 int	 pfctl_test_altqsupport(int, int);
+int	 pfctl_test_dummynetsupport(int, int);
 int	 pfctl_show_anchors(int, int, char *);
 int	 pfctl_ruleset_trans(struct pfctl *, char *, struct pf_anchor *);
 int	 pfctl_load_ruleset(struct pfctl *, char *,
@@ -122,6 +127,9 @@
 int		 loadopt;
 int		 altqsupport;
 
+int 		 dummynetsupport;
+int 		 dnsock;
+
 int		 dev = -1;
 int		 first_title = 1;
 int		 labels = 0;
@@ -207,12 +215,12 @@
 };
 
 static const char *clearopt_list[] = {
-	"nat", "queue", "rules", "Sources",
+	"nat", "queue", "dummynet", "rules", "Sources",
 	"state", "info", "Tables", "osfp", "all", NULL
 };
 
 static const char *showopt_list[] = {
-	"nat", "queue", "rules", "Anchors", "Sources", "state", "info",
+	"nat", "queue", "dummynet", "rules", "Anchors", "Sources", "state", "info",
 	"Interfaces", "labels", "timeouts", "memory", "Tables", "osfp",
 	"all", NULL
 };
@@ -367,6 +375,21 @@
 }
 
 int
+pfctl_clear_dummynet(int dnsock, int opts)
+{
+       if (!dummynetsupport)
+               return (-1);
+       if (setsockopt(dnsock, IPPROTO_IP, IP_DUMMYNET_FLUSH, NULL, 0) < 0) {
+               err(1,"setsockopt(IP_DUMMYNET_FLUSH)");
+               return (1);
+       }
+
+       if ((opts & PF_OPT_QUIET) == 0)
+               fprintf(stderr, "DUMMYNET cleared\n");
+       return (0);
+}
+
+int
 pfctl_clear_src_nodes(int dev, int opts)
 {
 	if (ioctl(dev, DIOCCLRSRCNODES))
@@ -1348,6 +1371,24 @@
 }
 
 int
+pfctl_add_dummynet(struct pfctl *pf, struct dn_pipe *p)
+{
+       if (dummynetsupport &&
+           (loadopt & PFCTL_FLAG_DUMMYNET) != 0) {
+               if ((pf->opts & PF_OPT_NOACTION) == 0) {
+                       if (setsockopt(dnsock, IPPROTO_IP, IP_DUMMYNET_CONFIGURE,
+                               p, sizeof(*p)) < 0) {
+                               errx(1, "DUMMYNET configure");
+                       }
+               }
+        }
+	if (pf->opts & PF_OPT_VERBOSE) 
+	       print_dummynet(p);
+
+       return (0);
+}
+
+int
 pfctl_rules(int dev, char *filename, FILE *fin, int opts, int optimize,
     char *anchorname, struct pfr_buffer *trans)
 {
@@ -1914,6 +1955,21 @@
 }
 
 int
+pfctl_test_dummynetsupport(int dnsock, int opts)
+{
+       struct dn_pipe p;
+       socklen_t       len;
+
+       if (getsockopt(dnsock, IPPROTO_IP, IP_DUMMYNET_GET, &p,
+                       &len) < 0) {
+               if (!(opts & (PF_OPT_QUIET|PF_OPT_NOACTION)))
+                       fprintf(stderr, "DUMMYNET not loaded\n");
+               return (0);
+       }
+       return (1);
+}
+
+int
 pfctl_show_anchors(int dev, int opts, char *anchorname)
 {
 	struct pfioc_ruleset	 pr;
@@ -1978,7 +2034,7 @@
 		usage();
 
 	while ((ch = getopt(argc, argv,
-	    "a:AdD:eqf:F:ghi:k:K:mnNOo::p:rRs:t:T:vx:z")) != -1) {
+	    "a:AdDP:eqf:F:ghi:k:K:mnNOo::p:rRs:t:T:vx:z")) != -1) {
 		switch (ch) {
 		case 'a':
 			anchoropt = optarg;
@@ -2050,6 +2106,9 @@
 		case 'A':
 			loadopt |= PFCTL_FLAG_ALTQ;
 			break;
+		case 'P':
+			loadopt |= PFCTL_FLAG_DUMMYNET;
+			break;
 		case 'R':
 			loadopt |= PFCTL_FLAG_FILTER;
 			break;
@@ -2164,6 +2223,11 @@
 		if (dev == -1)
 			err(1, "%s", pf_device);
 		altqsupport = pfctl_test_altqsupport(dev, opts);
+
+		dnsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+		if (dnsock < 0)
+			err(1, "socket");
+		dummynetsupport = pfctl_test_dummynetsupport(dnsock, opts);
 	} else {
 		dev = open(pf_device, O_RDONLY);
 		if (dev >= 0)
@@ -2176,6 +2240,10 @@
 #else
 		altqsupport = 1;
 #endif
+                dnsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+                if (dnsock < 0)
+                        err(1, "socket");
+                dummynetsupport = pfctl_test_dummynetsupport(dnsock, opts);
 	}
 
 	if (opts & PF_OPT_DISABLE)
@@ -2205,6 +2273,9 @@
 			pfctl_show_altq(dev, ifaceopt, opts,
 			    opts & PF_OPT_VERBOSE2);
 			break;
+		case 'd':
+			pfctl_show_dummynet(dnsock, opts);
+			break;
 		case 's':
 			pfctl_show_states(dev, ifaceopt, opts);
 			break;
@@ -2227,6 +2298,7 @@
 			pfctl_show_nat(dev, opts, anchorname);
 			pfctl_show_rules(dev, path, opts, 0, anchorname, 0);
 			pfctl_show_altq(dev, ifaceopt, opts, 0);
+			pfctl_show_dummynet(dnsock, opts);
 			pfctl_show_states(dev, ifaceopt, opts);
 			pfctl_show_src_nodes(dev, opts);
 			pfctl_show_status(dev, opts);
@@ -2268,6 +2340,9 @@
 		case 'q':
 			pfctl_clear_altq(dev, opts);
 			break;
+		case 'd':
+			pfctl_clear_dummynet(dnsock, opts);
+			break;
 		case 's':
 			pfctl_clear_states(dev, ifaceopt, opts);
 			break;
@@ -2283,6 +2358,7 @@
 			pfctl_clear_tables(anchorname, opts);
 			if (!*anchorname) {
 				pfctl_clear_altq(dev, opts);
+				pfctl_clear_dummynet(dnsock, opts);
 				pfctl_clear_states(dev, ifaceopt, opts);
 				pfctl_clear_src_nodes(dev, opts);
 				pfctl_clear_stats(dev, opts);
Index: contrib/pf/pfctl/pfctl.h
===================================================================
RCS file: /home/eri/repo/contrib/pf/pfctl/pfctl.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 pfctl.h
--- contrib/pf/pfctl/pfctl.h	21 Oct 2007 13:53:15 -0000	1.1.1.1
+++ contrib/pf/pfctl/pfctl.h	21 Oct 2007 19:03:49 -0000
@@ -85,6 +85,7 @@
 int	 pfctl_command_tables(int, char *[], char *, const char *, char *,
 	    const char *, int);
 int	 pfctl_show_altq(int, const char *, int, int);
+int	 pfctl_show_dummynet(int, int);
 void	 warn_namespace_collision(const char *);
 int	 pfctl_show_ifaces(const char *, int);
 FILE	*pfctl_fopen(const char *, const char *);
Index: contrib/pf/pfctl/pfctl_dn.c
===================================================================
RCS file: contrib/pf/pfctl/pfctl_dn.c
diff -N contrib/pf/pfctl/pfctl_dn.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/pf/pfctl/pfctl_dn.c	21 Oct 2007 19:03:32 -0000
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 2007 Ermal Luçi
+ * Copyright (c) 2002-2003 Luigi Rizzo
+ * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
+ * Copyright (c) 1994 Ugen J.S.Antsilevich
+ *
+ * Idea and grammar partially left from:
+ * Copyright (c) 1993 Daniel Boulet
+ *
+ * Redistribution and use in source forms, with and without modification,
+ * are permitted provided that this entire comment appears intact.
+ *
+ * Redistribution in binary form may occur without any restrictions.
+ * Obviously, it would be nice if you gave credit where credit is due
+ * but requiring it would be too onerous.
+ *
+ * This software is provided ``AS IS'' without any warranties of any kind.
+ *
+ * NEW command line interface for IP firewall facility
+ *
+ */
+
+/*
+ * Most of this is derived from ipfw(8) code.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <net/pfvar.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+
+#include <netinet/ip_fw.h>
+#include <netinet/ip_dummynet.h>
+
+#include "pfctl_parser.h"
+#include "pfctl.h"
+
+static int do_sort,
+	   verbose;
+
+static int sort_q(const void *, const void *);
+static void
+list_queues(struct dn_flow_set *, struct dn_flow_queue *);
+static void
+print_flowset_parms(struct dn_flow_set *, char *);
+static void
+list_pipes(void *, uint );
+
+static int
+sort_q(const void *pa, const void *pb)
+{
+        int rev = (0);
+        int field = rev ? -do_sort : do_sort;
+        long long res = 0;
+        const struct dn_flow_queue *a = pa;
+        const struct dn_flow_queue *b = pb;
+
+        switch (field) {
+        case 1: /* pkts */
+                res = a->len - b->len;
+                break;
+        case 2: /* bytes */
+                res = a->len_bytes - b->len_bytes;
+                break;
+
+        case 3: /* tot pkts */
+                res = a->tot_pkts - b->tot_pkts;
+                break;
+
+        case 4: /* tot bytes */
+                res = a->tot_bytes - b->tot_bytes;
+                break;
+        }
+        if (res < 0)
+                res = -1;
+        if (res > 0)
+                res = 1;
+        return (int)(rev ? res : -res);
+}
+
+static void
+list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q)
+{
+        int l;
+        int index_printed, indexes = 0;
+        char buff[255];
+        struct protoent *pe;
+
+        if (fs->rq_elements == 0)
+                return;
+
+        if (do_sort != 0)
+                heapsort(q, fs->rq_elements, sizeof *q, sort_q);
+
+        /* Print IPv4 flows */
+        index_printed = 0;
+        for (l = 0; l < fs->rq_elements; l++) {
+                struct in_addr ina;
+
+                /* XXX: Should check for IPv4 flows */
+                if (IS_IP6_FLOW_ID(&(q[l].id)))
+                        continue;
+
+                if (!index_printed) {
+                        index_printed = 1;
+                        if (indexes > 0)        /* currently a no-op */
+                                printf("\n");
+                        indexes++;
+                        printf("    "
+                            "mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
+                            fs->flow_mask.proto,
+                            fs->flow_mask.src_ip, fs->flow_mask.src_port,
+                            fs->flow_mask.dst_ip, fs->flow_mask.dst_port);
+
+                        printf("BKT Prot ___Source IP/port____ "
+                            "____Dest. IP/port____ "
+                            "Tot_pkt/bytes Pkt/Byte Drp\n");
+                }
+
+                printf("%3d ", q[l].hash_slot);
+                pe = getprotobynumber(q[l].id.proto);
+                if (pe)
+                        printf("%-4s ", pe->p_name);
+                else
+                        printf("%4u ", q[l].id.proto);
+                ina.s_addr = htonl(q[l].id.src_ip);
+                printf("%15s/%-5d ",
+                    inet_ntoa(ina), q[l].id.src_port);
+                ina.s_addr = htonl(q[l].id.dst_ip);
+                printf("%15s/%-5d ",
+                    inet_ntoa(ina), q[l].id.dst_port);
+                printf("%4qu %8qu %2u %4u %3u\n",
+                    q[l].tot_pkts, q[l].tot_bytes,
+                    q[l].len, q[l].len_bytes, q[l].drops);
+                if (verbose)
+                        printf("   S %20qd  F %20qd\n",
+                            q[l].S, q[l].F);
+        }
+
+        /* Print IPv6 flows */
+        index_printed = 0;
+        for (l = 0; l < fs->rq_elements; l++) {
+                if (!IS_IP6_FLOW_ID(&(q[l].id)))
+                        continue;
+
+                if (!index_printed) {
+                        index_printed = 1;
+                        if (indexes > 0)
+                                printf("\n");
+                       indexes++;
+                        printf("\n        mask: proto: 0x%02x, flow_id: 0x%08x,  ",
+                            fs->flow_mask.proto, fs->flow_mask.flow_id6);
+                        inet_ntop(AF_INET6, &(fs->flow_mask.src_ip6),
+                            buff, sizeof(buff));
+                        printf("%s/0x%04x -> ", buff, fs->flow_mask.src_port);
+                        inet_ntop( AF_INET6, &(fs->flow_mask.dst_ip6),
+                            buff, sizeof(buff) );
+                        printf("%s/0x%04x\n", buff, fs->flow_mask.dst_port);
+
+                        printf("BKT ___Prot___ _flow-id_ "
+                            "______________Source IPv6/port_______________ "
+                            "_______________Dest. IPv6/port_______________ "
+                            "Tot_pkt/bytes Pkt/Byte Drp\n");
+                }
+                printf("%3d ", q[l].hash_slot);
+                pe = getprotobynumber(q[l].id.proto);
+                if (pe != NULL)
+                        printf("%9s ", pe->p_name);
+                else
+                        printf("%9u ", q[l].id.proto);
+                printf("%7d  %39s/%-5d ", q[l].id.flow_id6,
+                    inet_ntop(AF_INET6, &(q[l].id.src_ip6), buff, sizeof(buff)),
+                    q[l].id.src_port);
+                printf(" %39s/%-5d ",
+                    inet_ntop(AF_INET6, &(q[l].id.dst_ip6), buff, sizeof(buff)),
+                    q[l].id.dst_port);
+                printf(" %4qu %8qu %2u %4u %3u\n",
+                    q[l].tot_pkts, q[l].tot_bytes,
+                    q[l].len, q[l].len_bytes, q[l].drops);
+                if (verbose)
+                        printf("   S %20qd  F %20qd\n", q[l].S, q[l].F);
+        }
+}
+
+static void
+print_flowset_parms(struct dn_flow_set *fs, char *prefix)
+{
+        int l;
+        char qs[30];
+        char plr[30];
+        char red[90];   /* Display RED parameters */
+
+        l = fs->qsize;
+        if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
+                if (l >= 8192)
+                        sprintf(qs, "%d KB", l / 1024);
+                else
+                        sprintf(qs, "%d B", l);
+        } else
+                sprintf(qs, "%3d sl.", l);
+        if (fs->plr)
+                sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff));
+        else
+                plr[0] = '\0';
+        if (fs->flags_fs & DN_IS_RED)   /* RED parameters */
+                sprintf(red,
+                    "\n\t  %cRED w_q %f min_th %d max_th %d max_p %f",
+                    (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ',
+                    1.0 * fs->w_q / (double)(1 << SCALE_RED),
+                    SCALE_VAL(fs->min_th),
+                    SCALE_VAL(fs->max_th),
+                    1.0 * fs->max_p / (double)(1 << SCALE_RED));
+        else
+                sprintf(red, "droptail");
+
+        printf("%s %s%s %d queues (%d buckets) %s\n",
+            prefix, qs, plr, fs->rq_elements, fs->rq_size, red);
+}
+
+
+static void
+list_pipes(void *data, uint nbytes)
+{
+        void *next = data;
+        struct dn_pipe *p = (struct dn_pipe *) data;
+        struct dn_flow_set *fs;
+        struct dn_flow_queue *q;
+        int l;
+
+        for (; nbytes >= sizeof *p; p = (struct dn_pipe *)next) {
+                double b = p->bandwidth;
+                char buf[30];
+                char prefix[80];
+
+                if (SLIST_NEXT(p, next) != (struct dn_pipe *)DN_IS_PIPE)
+                        break;  /* done with pipes, now queues */
+
+                /*
+                 * compute length, as pipe have variable size
+                 */
+                l = sizeof(*p) + p->fs.rq_elements * sizeof(*q);
+                next = (char *)p + l;
+                nbytes -= l;
+
+                /*
+                 * Print rate (or clocking interface)
+                 */
+                if (p->if_name[0] != '\0')
+                       sprintf(buf, "%s", p->if_name);
+                else if (b == 0)
+                        sprintf(buf, "unlimited");
+                else if (b >= 1000000)
+                        sprintf(buf, "%7.3f Mbit/s", b/1000000);
+                else if (b >= 1000)
+                        sprintf(buf, "%7.3f Kbit/s", b/1000);
+                else
+                        sprintf(buf, "%7.3f bit/s ", b);
+
+                sprintf(prefix, "%05d: %s %4d ms ",
+                    p->pipe_nr, buf, p->delay);
+                print_flowset_parms(&(p->fs), prefix);
+                if (verbose)
+                        printf("   V %20qd\n", p->V >> MY_M);
+
+                q = (struct dn_flow_queue *)(p+1);
+                list_queues(&(p->fs), q);
+        }
+        for (fs = next; nbytes >= sizeof *fs; fs = next) {
+                char prefix[80];
+
+                if (SLIST_NEXT(fs, next) != (struct dn_flow_set *)DN_IS_QUEUE)
+                        break;
+                l = sizeof(*fs) + fs->rq_elements * sizeof(*q);
+                next = (char *)fs + l;
+                nbytes -= l;
+#if 0
+                if (rulenum != 0 && ((rulenum != fs->fs_nr && do_pipe == 2) ||
+                    (rulenum != fs->parent_nr && do_pipe == 1))) {
+                        continue;
+                }
+#endif
+                q = (struct dn_flow_queue *)(fs+1);
+                sprintf(prefix, "q%05d: weight %d pipe %d ",
+                    fs->fs_nr, fs->weight, fs->parent_nr);
+                print_flowset_parms(fs, prefix);
+                list_queues(fs, q);
+        }
+}
+
+void
+print_dummynet(struct dn_pipe *p)
+{
+	char buff[255];
+
+	if (p->pipe_nr != 0) { /* This is a pipe */
+		printf("dnpipe %d", p->pipe_nr);
+		if (p->bandwidth) 
+			printf(" bandwidth %dMb", p->bandwidth/1000000);
+	        else if (p->bandwidth >= 1000)
+         	        printf(" bandwidth %dKb", p->bandwidth/1000);
+	        else 
+                       	printf(" bandwidth %db ", p->bandwidth);
+		if (p->delay > 0)
+			printf(" delay %d", p->delay);
+	} else {
+		printf("dnqueue %d dnpipe %d", p->fs.fs_nr, p->fs.parent_nr);
+		if (p->fs.weight)
+			printf(" weight %d", p->fs.weight);
+	}
+
+	if (p->fs.rq_size > 15)
+		printf(" buckets %d", p->fs.rq_size);
+	if (p->fs.flags_fs & DN_QSIZE_IS_BYTES) {
+                if (p->fs.qsize >= 8192)
+                        printf(" queue %dKB",  p->fs.qsize / 1024);
+                else if (p->fs.qsize > 0)
+                        printf(" queue %dB", p->fs.qsize);
+        } else
+		if (p->fs.qsize > 0)
+	                printf(" queue %3d", p->fs.qsize);
+        if (p->fs.plr > 0)
+                printf(" plr %f", 1.0 * p->fs.plr / (double)(0x7fffffff));
+
+	if (p->fs.flow_mask.proto && p->fs.flow_mask.dst_ip && 
+		p->fs.flow_mask.src_ip && p->fs.flow_mask.dst_port && 
+		p->fs.flow_mask.src_port &&
+		p->fs.flow_mask.flow_id6)
+		printf(" mask all");
+	else  if (p->fs.flow_mask.proto || p->fs.flow_mask.dst_ip || 
+		p->fs.flow_mask.src_ip || p->fs.flow_mask.dst_port || 
+		p->fs.flow_mask.src_port ||
+		p->fs.flow_mask.flow_id6) {
+		printf("\n\t mask: ");
+	if (p->fs.flow_mask.proto)
+		printf(" proto 0x%02x", p->fs.flow_mask.proto);
+	if (p->fs.flow_mask.src_ip)
+		printf(" src-ip 0x%08x", p->fs.flow_mask.src_ip);
+	if (p->fs.flow_mask.src_port)
+		printf(" src-port 0x%04x", p->fs.flow_mask.src_port);
+	if (p->fs.flow_mask.dst_ip)
+		printf(" dst-ip 0x%08x", p->fs.flow_mask.dst_ip);
+	if (p->fs.flow_mask.dst_port)
+		printf(" dst-port 0x%04x", p->fs.flow_mask.dst_port);
+	if (p->fs.flow_mask.flow_id6)
+		printf(" dst-port 0x%08x", p->fs.flow_mask.flow_id6);
+	}
+	if (p->fs.flags_fs & DN_NOERROR)
+		printf(" noerror");
+
+	printf("\n");	
+}
+
+int
+pfctl_show_dummynet(int dnsock, int opts)
+{
+        void *data = NULL;
+        int nbytes, nalloc = 1024;
+
+	if (opts & PF_OPT_VERBOSE)
+		verbose = 1;
+	else 
+		verbose = 0;
+	
+	nbytes = nalloc;
+        while (nbytes >= nalloc) {
+                nalloc = nalloc * 2 + 200;
+                nbytes = nalloc;
+                if ((data = realloc(data, nbytes)) == NULL)
+                        err(1, "realloc");
+                if (getsockopt(dnsock, IPPROTO_IP, IP_DUMMYNET_GET, data,
+                        (socklen_t *)&nbytes) < 0) {
+                        free(data);
+                        err(1, "getsockopt(IP_DUMMYNET_GET)");
+		}
+        }
+	
+        list_pipes(data, nbytes);
+	
+	return (0);
+
+}
Index: contrib/pf/pfctl/pfctl_parser.c
===================================================================
RCS file: /home/eri/repo/contrib/pf/pfctl/pfctl_parser.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 pfctl_parser.c
--- contrib/pf/pfctl/pfctl_parser.c	21 Oct 2007 13:53:15 -0000	1.1.1.1
+++ contrib/pf/pfctl/pfctl_parser.c	21 Oct 2007 19:03:49 -0000
@@ -48,6 +48,9 @@
 #include <net/pfvar.h>
 #include <arpa/inet.h>
 
+#include <netinet/ip_fw.h>
+#include <netinet/ip_dummynet.h>
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -981,6 +984,12 @@
 	}
 	if (r->label[0])
 		printf(" label \"%s\"", r->label);
+	if (r->dnpipe && r->pdnpipe)
+	       printf(" dnqueue(%d, %d)", r->dnpipe, r->pdnpipe);
+	else if (r->dnpipe)	
+		printf(" %s %d", 
+			r->dntype == DN_IS_PIPE ? "dnpipe" : "dnqueue",
+			r->dnpipe);
 	if (r->qname[0] && r->pqname[0])
 		printf(" queue(%s, %s)", r->qname, r->pqname);
 	else if (r->qname[0])
Index: contrib/pf/pfctl/pfctl_parser.h
===================================================================
RCS file: /home/eri/repo/contrib/pf/pfctl/pfctl_parser.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 pfctl_parser.h
--- contrib/pf/pfctl/pfctl_parser.h	21 Oct 2007 13:53:15 -0000	1.1.1.1
+++ contrib/pf/pfctl/pfctl_parser.h	21 Oct 2007 19:03:49 -0000
@@ -67,6 +67,7 @@
 }
 
 struct pfr_buffer;	/* forward definition */
+struct dn_pipe;
 
 
 struct pfctl {
@@ -217,6 +218,7 @@
 
 int	pfctl_add_rule(struct pfctl *, struct pf_rule *, const char *);
 int	pfctl_add_altq(struct pfctl *, struct pf_altq *);
+int 	pfctl_add_dummynet(struct pfctl *, struct dn_pipe *);
 int	pfctl_add_pool(struct pfctl *, struct pf_pool *, sa_family_t);
 void	pfctl_move_pool(struct pf_pool *, struct pf_pool *);
 void	pfctl_clear_pool(struct pf_pool *);
@@ -244,6 +246,8 @@
 int	eval_pfqueue(struct pfctl *, struct pf_altq *, struct node_queue_bw *,
 	    struct node_queue_opt *);
 
+void	print_dummynet(struct dn_pipe *);
+
 void	 print_altq(const struct pf_altq *, unsigned, struct node_queue_bw *,
 	    struct node_queue_opt *);
 void	 print_queue(const struct pf_altq *, unsigned, struct node_queue_bw *,
@@ -286,6 +290,7 @@
 #define PFCTL_FLAG_OPTION	0x08
 #define PFCTL_FLAG_ALTQ		0x10
 #define PFCTL_FLAG_TABLE	0x20
+#define	PFCTL_FLAG_DUMMYNET	0x40
 
 extern const struct pf_timeout pf_timeouts[];
 
Index: sbin/pfctl/Makefile
===================================================================
RCS file: /home/eri/repo/sbin/pfctl/Makefile,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 Makefile
--- sbin/pfctl/Makefile	21 Oct 2007 13:54:16 -0000	1.1.1.1
+++ sbin/pfctl/Makefile	21 Oct 2007 19:03:49 -0000
@@ -11,6 +11,7 @@
 SRCS+= pfctl_osfp.c pfctl_radix.c pfctl_table.c pfctl_qstats.c
 SRCS+= pfctl_optimize.c
 SRCS+= pf_ruleset.c
+SRCS+= pfctl_dn.c
 
 CFLAGS+= -Wall -Wmissing-prototypes -Wno-uninitialized
 CFLAGS+= -Wstrict-prototypes -I${.CURDIR}/../../contrib/pf/pfctl
Index: sys/contrib/pf/net/pf.c
===================================================================
RCS file: /home/eri/repo/sys/contrib/pf/net/pf.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 pf.c
--- sys/contrib/pf/net/pf.c	21 Oct 2007 13:54:56 -0000	1.1.1.1
+++ sys/contrib/pf/net/pf.c	21 Oct 2007 19:03:49 -0000
@@ -6718,6 +6719,7 @@
 	int			 off, dirndx, pqid = 0;
 
 #ifdef __FreeBSD__
+	struct ip_fw_args	 dnflow;
 	PF_LOCK();
 #endif
 	if (!pf_status.running)
@@ -6744,6 +6746,7 @@
 		PF_UNLOCK();
 		return (PF_PASS);
 	}
+	
 #else
 	if (pd.pf_mtag->flags & PF_TAG_GENERATED)
 		return (PF_PASS);
@@ -6827,6 +6830,13 @@
 		struct tcphdr	th;
 
 		pd.hdr.tcp = &th;
+
+#ifdef __FreeBSD__
+                dnflow.f_id.flags = th.th_flags;
+                dnflow.f_id.dst_port = th.th_dport;
+                dnflow.f_id.src_port = th.th_sport;
+#endif
+
 		if (!pf_pull_hdr(m, off, &th, sizeof(th),
 		    &action, &reason, AF_INET)) {
 			log = action != PF_PASS;
@@ -6868,6 +6878,12 @@
 		struct udphdr	uh;
 
 		pd.hdr.udp = &uh;
+
+#ifdef __FreeBSD__
+                dnflow.f_id.dst_port = uh.uh_dport;
+                dnflow.f_id.src_port = uh.uh_sport;
+#endif
+
 		if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
 		    &action, &reason, AF_INET)) {
 			log = action != PF_PASS;
@@ -6909,6 +6925,7 @@
 		struct icmp	ih;
 
 		pd.hdr.icmp = &ih;
+
 		if (!pf_pull_hdr(m, off, &ih, ICMP_MINLEN,
 		    &action, &reason, AF_INET)) {
 			log = action != PF_PASS;
@@ -7083,6 +7100,33 @@
 		pf_route(m0, r, dir, ifp, s, &pd);
 
 #ifdef __FreeBSD__
+	if (r->dnpipe && ip_dn_io_ptr != NULL) {
+			struct ip_fw dummyrule;
+
+      			dummyrule.cmd->opcode = 
+				r->dntype == DN_IS_PIPE ? O_PIPE : O_QUEUE;
+			dummyrule.act_ofs = 0;
+			dummyrule.cmd_len = 1;
+			if (action == PF_PASS && (
+				pqid || (pd.tos & IPTOS_LOWDELAY))) 
+				dnflow.cookie = r->pdnpipe;
+			else 
+				dnflow.cookie = r->dnpipe;
+                	dnflow.rule = &dummyrule;
+                	dnflow.f_id.addr_type = 4; /* IPv4 type */
+                	dnflow.f_id.proto = pd.proto;
+			PF_UNLOCK();
+			
+			h = mtod(*m0, struct ip *);
+			NTOHS(h->ip_len);
+			NTOHS(h->ip_off);
+			ip_dn_io_ptr(*m0, 
+				dir == PF_IN ? DN_TO_IP_IN : DN_TO_IP_OUT, 
+				&dnflow);
+			*m0 = NULL;
+			return (action);
+		}
+	
 	PF_UNLOCK();
 #endif
 
@@ -7111,6 +7155,7 @@
 	int			 off, terminal = 0, dirndx, rh_cnt = 0;
 
 #ifdef __FreeBSD__
+	struct ip_fw_args	 dnflow;
 	PF_LOCK();
 #endif
 
@@ -7286,6 +7331,12 @@
 		struct tcphdr	th;
 
 		pd.hdr.tcp = &th;
+#ifdef __FreeBSD__
+                dnflow.f_id.flags = th.th_flags;
+                dnflow.f_id.dst_port = th.th_dport;
+                dnflow.f_id.src_port = th.th_sport;
+#endif
+
 		if (!pf_pull_hdr(m, off, &th, sizeof(th),
 		    &action, &reason, AF_INET6)) {
 			log = action != PF_PASS;
@@ -7326,6 +7377,11 @@
 		struct udphdr	uh;
 
 		pd.hdr.udp = &uh;
+#ifdef __FreeBSD__
+                dnflow.f_id.dst_port = uh.uh_dport;
+                dnflow.f_id.src_port = uh.uh_sport;
+#endif
+
 		if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
 		    &action, &reason, AF_INET6)) {
 			log = action != PF_PASS;
@@ -7539,8 +7595,33 @@
 		pf_route6(m0, r, dir, ifp, s, &pd);
 
 #ifdef __FreeBSD__
+	if (r->dnpipe && ip_dn_io_ptr != NULL) {
+			struct ip_fw dummyrule;
+
+      			dummyrule.cmd->opcode = 
+				r->dntype == DN_IS_PIPE ? O_PIPE : O_QUEUE;
+			dummyrule.act_ofs = 0;
+			dummyrule.cmd_len = 1;
+			if (action == PF_PASS && (
+				pd.tos & IPTOS_LOWDELAY)) 
+				dnflow.cookie = r->pdnpipe;
+			else 
+				dnflow.cookie = r->dnpipe;
+                	dnflow.rule = &dummyrule;
+                	dnflow.f_id.addr_type = 6; /* IPv4 type */
+                	dnflow.f_id.proto = pd.proto;
+			PF_UNLOCK();
+			
+			ip_dn_io_ptr(*m0, 
+				dir == PF_IN ? DN_TO_IP6_IN : DN_TO_IP6_OUT, 
+				&dnflow);
+			*m0 = NULL;
+			return (action);
+		}
+	
 	PF_UNLOCK();
 #endif
+
 	return (action);
 }
 #endif /* INET6 */
Index: sys/contrib/pf/net/pf_ioctl.c
===================================================================
RCS file: /home/eri/repo/sys/contrib/pf/net/pf_ioctl.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 pf_ioctl.c
--- sys/contrib/pf/net/pf_ioctl.c	21 Oct 2007 13:54:56 -0000	1.1.1.1
+++ sys/contrib/pf/net/pf_ioctl.c	21 Oct 2007 19:03:49 -0000
@@ -3522,8 +3522,16 @@
 	 * byte order. 
 	 */
 	struct ip *h = NULL;
+	struct m_tag *dn_tag;
 	int chk;
 
+        dn_tag = m_tag_find(*m, PACKET_TAG_DUMMYNET, NULL);
+	if (dn_tag != NULL && 
+		((struct dn_pkt_tag *)(dn_tag+1))->dn_dir == DN_TO_IP_IN) {
+		m_tag_delete(*m, dn_tag);
+                return (PF_PASS);
+        }
+
 	if ((*m)->m_pkthdr.len >= (int)sizeof(struct ip)) {
 		/* if m_pkthdr.len is less than ip header, pf will handle. */
 		h = mtod(*m, struct ip *);
@@ -3557,6 +3565,7 @@
 	 * byte order. 
 	 */
 	struct ip *h = NULL;
+	struct m_tag *dn_tag;
 	int chk;
 
 	/* We need a proper CSUM befor we start (s. OpenBSD ip_output) */
@@ -3564,6 +3573,14 @@
 		in_delayed_cksum(*m);
 		(*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
 	}
+	
+	dn_tag = m_tag_find(*m, PACKET_TAG_DUMMYNET, NULL);
+	if (dn_tag != NULL && 
+		((struct dn_pkt_tag *)(dn_tag+1))->dn_dir == DN_TO_IP_OUT) {
+		m_tag_delete(*m, dn_tag);
+                return (PF_PASS);
+        }
+	
 	if ((*m)->m_pkthdr.len >= (int)sizeof(*h)) {
 		/* if m_pkthdr.len is less than ip header, pf will handle. */
 		h = mtod(*m, struct ip *);
@@ -3593,6 +3610,14 @@
 	 * IPv6 is not affected by ip_len/ip_off byte order changes.
 	 */
 	int chk;
+	struct m_tag *dn_tag;
+	
+	dn_tag = m_tag_find(*m, PACKET_TAG_DUMMYNET, NULL);
+	if (dn_tag != NULL && 
+		((struct dn_pkt_tag *)(dn_tag+1))->dn_dir == DN_TO_IP6_IN) {
+		m_tag_delete(*m, dn_tag);
+                return (PF_PASS);
+        }
 
 	/*
 	 * In case of loopback traffic IPv6 uses the real interface in
@@ -3616,6 +3641,14 @@
 	 * IPv6 does not affected ip_len/ip_off byte order changes.
 	 */
 	int chk;
+	struct m_tag *dn_tag;
+
+	dn_tag = m_tag_find(*m, PACKET_TAG_DUMMYNET, NULL);
+	if (dn_tag != NULL && 
+		((struct dn_pkt_tag *)(dn_tag+1))->dn_dir == DN_TO_IP6_OUT) {
+		m_tag_delete(*m, dn_tag);
+                return (PF_PASS);
+        }
 
 	/* We need a proper CSUM befor we start (s. OpenBSD ip_output) */
 	if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
Index: sys/contrib/pf/net/pfvar.h
===================================================================
RCS file: /home/eri/repo/sys/contrib/pf/net/pfvar.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 pfvar.h
--- sys/contrib/pf/net/pfvar.h	21 Oct 2007 13:54:56 -0000	1.1.1.1
+++ sys/contrib/pf/net/pfvar.h	21 Oct 2007 19:03:49 -0000
@@ -57,6 +57,9 @@
 
 #ifdef __FreeBSD__
 #include <netinet/in.h>
+
+#include <netinet/ip_fw.h>
+#include <netinet/ip_dummynet.h>
 #endif
 
 #include <netinet/tcp_fsm.h>
@@ -632,6 +635,9 @@
 	}			 max_src_conn_rate;
 	u_int32_t		 qid;
 	u_int32_t		 pqid;
+	u_int32_t		 dnpipe;
+	u_int32_t		 pdnpipe;
+	u_int32_t		 dntype;
 	u_int32_t		 rt_listid;
 	u_int32_t		 nr;
 	u_int32_t		 prob;
Index: sys/netinet/ip_dummynet.c
===================================================================
RCS file: /home/eri/repo/sys/netinet/ip_dummynet.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 ip_dummynet.c
--- sys/netinet/ip_dummynet.c	21 Oct 2007 13:55:36 -0000	1.1.1.1
+++ sys/netinet/ip_dummynet.c	21 Oct 2007 19:03:49 -0000
@@ -84,6 +84,9 @@
 #include <netinet/ip6.h>       /* for ip6_input, ip6_output prototypes */
 #include <netinet6/ip6_var.h>
 
+
+static struct ip_fw default_rule ;
+
 /*
  * We keep a private variable for the simulation time, but we could
  * probably use an existing one ("softticks" in sys/kern/kern_timeout.c)
@@ -214,7 +217,6 @@
 static void dummynet_send(struct mbuf *);
 void dummynet_drain(void);
 static ip_dn_io_t dummynet_io;
-static void dn_rule_delete(void *);
 
 /*
  * Heap management functions.
@@ -1490,7 +1492,6 @@
 	DUMMYNET_UNLOCK();
 }
 
-extern struct ip_fw *ip_fw_default_rule ;
 static void
 dn_rule_delete_fs(struct dn_flow_set *fs, void *r)
 {
@@ -1503,7 +1504,7 @@
 	    for (m = q->head ; m ; m = m->m_nextpkt ) {
 		struct dn_pkt_tag *pkt = dn_tag_get(m) ;
 		if (pkt->rule == r)
-		    pkt->rule = ip_fw_default_rule ;
+		    pkt->rule = &default_rule ;
 	    }
 }
 /*
@@ -1536,7 +1537,7 @@
 		for (m = pipe->head ; m ; m = m->m_nextpkt ) {
 			pkt = dn_tag_get(m);
 			if (pkt->rule == r)
-				pkt->rule = ip_fw_default_rule;
+				pkt->rule = &default_rule;
 		}
 	}
     DUMMYNET_UNLOCK();
@@ -2129,7 +2130,20 @@
 
 	ip_dn_ctl_ptr = ip_dn_ctl;
 	ip_dn_io_ptr = dummynet_io;
-	ip_dn_ruledel_ptr = dn_rule_delete;
+
+	bzero(&default_rule, sizeof default_rule);
+
+        default_rule.act_ofs = 0;
+        default_rule.rulenum = IPFW_DEFAULT_RULE;
+        default_rule.cmd_len = 1;
+        default_rule.set = RESVD_SET;
+
+        default_rule.cmd[0].len = 1;
+        default_rule.cmd[0].opcode =
+#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT
+                                1 ? O_ACCEPT :
+#endif
+                                O_DENY;
 
 	TASK_INIT(&dn_task, 0, dummynet_task, NULL);
 	dn_tq = taskqueue_create_fast("dummynet", M_NOWAIT,
@@ -2149,7 +2163,6 @@
 {
 	ip_dn_ctl_ptr = NULL;
 	ip_dn_io_ptr = NULL;
-	ip_dn_ruledel_ptr = NULL;
 
 	DUMMYNET_LOCK();
 	callout_stop(&dn_timeout);
@@ -2197,5 +2210,4 @@
 	NULL
 };
 DECLARE_MODULE(dummynet, dummynet_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
-MODULE_DEPEND(dummynet, ipfw, 2, 2, 2);
 MODULE_VERSION(dummynet, 1);
Index: sys/netinet/ip_dummynet.h
===================================================================
RCS file: /home/eri/repo/sys/netinet/ip_dummynet.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 ip_dummynet.h
--- sys/netinet/ip_dummynet.h	21 Oct 2007 13:55:36 -0000	1.1.1.1
+++ sys/netinet/ip_dummynet.h	21 Oct 2007 19:03:49 -0000
@@ -342,13 +342,13 @@
 
 #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);
 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;
 #define	DUMMYNET_LOADED	(ip_dn_io_ptr != NULL)
 
+void dn_rule_delete(void *);
+
 /*
  * Return the IPFW rule associated with the dummynet tag; if any.
  * Make sure that the dummynet tag is not reused by lower layers.
Index: sys/netinet/ip_fw.h
===================================================================
RCS file: /home/eri/repo/sys/netinet/ip_fw.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 ip_fw.h
--- sys/netinet/ip_fw.h	21 Oct 2007 13:55:36 -0000	1.1.1.1
+++ sys/netinet/ip_fw.h	21 Oct 2007 19:03:49 -0000
@@ -615,5 +615,7 @@
 extern	ip_fw_chk_t	*ip_fw_chk_ptr;
 #define	IPFW_LOADED	(ip_fw_chk_ptr != NULL)
 
+#define IPFW_DEFAULT_RULE       65535
+
 #endif /* _KERNEL */
 #endif /* _IPFW2_H */
Index: sys/netinet/ip_fw2.c
===================================================================
RCS file: /home/eri/repo/sys/netinet/ip_fw2.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 ip_fw2.c
--- sys/netinet/ip_fw2.c	21 Oct 2007 13:55:36 -0000	1.1.1.1
+++ sys/netinet/ip_fw2.c	21 Oct 2007 19:03:49 -0000
@@ -122,7 +122,6 @@
 
 static struct callout ipfw_timeout;
 static uma_zone_t ipfw_dyn_rule_zone;
-#define	IPFW_DEFAULT_RULE	65535
 
 /*
  * Data structure to cache our ucred related
@@ -3828,7 +3827,7 @@
 	while ((rule = head) != NULL) {
 		head = head->next;
 		if (DUMMYNET_LOADED)
-			ip_dn_ruledel_ptr(rule);
+			dn_rule_delete(rule);
 		free(rule, M_IPFW);
 	}
 }
Index: sys/netinet/ip_fw_pfil.c
===================================================================
RCS file: /home/eri/repo/sys/netinet/ip_fw_pfil.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 ip_fw_pfil.c
--- sys/netinet/ip_fw_pfil.c	21 Oct 2007 13:55:36 -0000	1.1.1.1
+++ sys/netinet/ip_fw_pfil.c	21 Oct 2007 19:03:49 -0000
@@ -72,9 +72,6 @@
 
 int ipfw_chg_hook(SYSCTL_HANDLER_ARGS);
 
-/* Dummynet hooks. */
-ip_dn_ruledel_t	*ip_dn_ruledel_ptr = NULL;
-
 /* Divert hooks. */
 ip_divert_packet_t *ip_divert_ptr = NULL;
 

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?9a542da30710281311n7f8a6f29me02da90941d96ae5>