svn commit: r194930 - in head: sbin/ipfw sys/netinet sys/netinet/ipfw

Oleg Bulyzhin oleg at FreeBSD.org
Wed Jun 24 22:57:08 UTC 2009


Author: oleg
Date: Wed Jun 24 22:57:07 2009
New Revision: 194930
URL: http://svn.freebsd.org/changeset/base/194930

Log:
  - fix dummynet 'fast' mode for WF2Q case.
  - fix printing of pipe profile data.
  - introduce new pipe parameter: 'burst' - how much data can be sent through
    pipe bypassing bandwidth limit.

Modified:
  head/sbin/ipfw/Makefile
  head/sbin/ipfw/dummynet.c
  head/sbin/ipfw/ipfw.8
  head/sbin/ipfw/ipfw2.h
  head/sys/netinet/ip_dummynet.h
  head/sys/netinet/ipfw/ip_dummynet.c

Modified: head/sbin/ipfw/Makefile
==============================================================================
--- head/sbin/ipfw/Makefile	Wed Jun 24 22:42:52 2009	(r194929)
+++ head/sbin/ipfw/Makefile	Wed Jun 24 22:57:07 2009	(r194930)
@@ -3,6 +3,7 @@
 PROG=	ipfw
 SRCS=	ipfw2.c dummynet.c ipv6.c main.c nat.c altq.c
 WARNS?=	2
+LDADD=	-lutil
 MAN=	ipfw.8
 
 .include <bsd.prog.mk>

Modified: head/sbin/ipfw/dummynet.c
==============================================================================
--- head/sbin/ipfw/dummynet.c	Wed Jun 24 22:42:52 2009	(r194929)
+++ head/sbin/ipfw/dummynet.c	Wed Jun 24 22:57:07 2009	(r194930)
@@ -32,6 +32,8 @@
 
 #include <ctype.h>
 #include <err.h>
+#include <errno.h>
+#include <libutil.h>
 #include <netdb.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -70,6 +72,7 @@ static struct _s_x dummynet_params[] = {
 	{ "src-ipv6",		TOK_SRCIP6},
 	{ "src-ip6",		TOK_SRCIP6},
 	{ "profile",		TOK_PIPE_PROFILE},
+	{ "burst",		TOK_BURST},
 	{ "dummynet-params",	TOK_NULL },
 	{ NULL, 0 }	/* terminator */
 };
@@ -236,7 +239,7 @@ print_flowset_parms(struct dn_flow_set *
 		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",
+		    "\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),
@@ -250,7 +253,7 @@ print_flowset_parms(struct dn_flow_set *
 }
 
 static void
-print_extra_delay_parms(struct dn_pipe *p, char *prefix)
+print_extra_delay_parms(struct dn_pipe *p)
 {
 	double loss;
 	if (p->samples_no <= 0)
@@ -258,8 +261,8 @@ print_extra_delay_parms(struct dn_pipe *
 
 	loss = p->loss_level;
 	loss /= p->samples_no;
-	printf("%s profile: name \"%s\" loss %f samples %d\n",
-		prefix, p->name, loss, p->samples_no);
+	printf("\t profile: name \"%s\" loss %f samples %d\n",
+		p->name, loss, p->samples_no);
 }
 
 void
@@ -280,6 +283,7 @@ ipfw_list_pipes(void *data, uint nbytes,
 		double b = p->bandwidth;
 		char buf[30];
 		char prefix[80];
+		char burst[5 + 7];
 
 		if (SLIST_NEXT(p, next) != (struct dn_pipe *)DN_IS_PIPE)
 			break;	/* done with pipes, now queues */
@@ -311,10 +315,16 @@ ipfw_list_pipes(void *data, uint nbytes,
 		sprintf(prefix, "%05d: %s %4d ms ",
 		    p->pipe_nr, buf, p->delay);
 
-		print_extra_delay_parms(p, prefix);
-
 		print_flowset_parms(&(p->fs), prefix);
 
+		if (humanize_number(burst, sizeof(burst), p->burst,
+		    "Byte", HN_AUTOSCALE, 0) < 0 || co.verbose)
+			printf("\t burst: %ju Byte\n", p->burst);
+		else
+			printf("\t burst: %s\n", burst);
+
+		print_extra_delay_parms(p);
+
 		q = (struct dn_flow_queue *)(p+1);
 		list_queues(&(p->fs), q);
 	}
@@ -933,6 +943,21 @@ end_mask:
 			--ac; ++av;
 			break;
 
+		case TOK_BURST:
+			if (co.do_pipe != 1)
+				errx(EX_DATAERR, "burst only valid for pipes");
+			NEED1("burst needs argument\n");
+			errno = 0;
+			if (expand_number(av[0], &p.burst) < 0)
+				if (errno != ERANGE)
+					errx(EX_DATAERR,
+					    "burst: invalid argument");
+			if (errno || p.burst > (1ULL << 48) - 1)
+				errx(EX_DATAERR,
+				    "burst: out of range (0..2^48-1)");
+			ac--; av++;
+			break;
+
 		default:
 			errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]);
 		}

Modified: head/sbin/ipfw/ipfw.8
==============================================================================
--- head/sbin/ipfw/ipfw.8	Wed Jun 24 22:42:52 2009	(r194929)
+++ head/sbin/ipfw/ipfw.8	Wed Jun 24 22:57:07 2009	(r194930)
@@ -1,7 +1,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd April 9, 2009
+.Dd June 24, 2009
 .Dt IPFW 8
 .Os
 .Sh NAME
@@ -1943,6 +1943,20 @@ to reduce
 the granularity to 1ms or less).
 Default value is 0, meaning no delay.
 .Pp
+.It Cm burst Ar size
+If the data rate exceeds the pipe bandwith limit
+(and pipe was idle long enough),
+.Ar size
+bytes of data is allowed to bypass the
+.Nm dummynet
+scheduler (i.e. it will be sent without shaping), then transmission rate
+will not exceed pipe bandwidth. Effective burst size calculated as follows:
+MAX(
+.Ar size
+,
+.Nm bw
+* pipe_idle_time).
+.Pp
 .It Cm profile Ar filename
 A file specifying the additional overhead incurred in the transmission
 of a packet on the link.

Modified: head/sbin/ipfw/ipfw2.h
==============================================================================
--- head/sbin/ipfw/ipfw2.h	Wed Jun 24 22:42:52 2009	(r194929)
+++ head/sbin/ipfw/ipfw2.h	Wed Jun 24 22:57:07 2009	(r194930)
@@ -154,6 +154,7 @@ enum tokens {
 	TOK_BW,
 	TOK_DELAY,
 	TOK_PIPE_PROFILE,
+	TOK_BURST,
 	TOK_RED,
 	TOK_GRED,
 	TOK_DROPTAIL,

Modified: head/sys/netinet/ip_dummynet.h
==============================================================================
--- head/sys/netinet/ip_dummynet.h	Wed Jun 24 22:42:52 2009	(r194929)
+++ head/sys/netinet/ip_dummynet.h	Wed Jun 24 22:57:07 2009	(r194930)
@@ -229,7 +229,7 @@ struct dn_flow_queue {
     int avg ;                   /* average queue length est. (scaled) */
     int count ;                 /* arrivals since last RED drop */
     int random ;                /* random value (scaled) */
-    dn_key q_time;		/* start of queue idle time */
+    dn_key idle_time;		/* start of queue idle time */
 
     /* WF2Q+ support */
     struct dn_flow_set *fs ;	/* parent flow set */
@@ -341,8 +341,10 @@ struct dn_pipe {		/* a pipe */
 
     /* Same as in dn_flow_queue, numbytes can become large */
     int64_t numbytes;		/* bits I can transmit (more or less). */
+    uint64_t burst;		/* burst size, scaled: bits * hz */
 
     dn_key sched_time ;		/* time pipe was scheduled in ready_heap */
+    dn_key idle_time;		/* start of pipe idle time */
 
     /*
      * When the tx clock come from an interface (if_name[0] != '\0'), its name

Modified: head/sys/netinet/ipfw/ip_dummynet.c
==============================================================================
--- head/sys/netinet/ipfw/ip_dummynet.c	Wed Jun 24 22:42:52 2009	(r194929)
+++ head/sys/netinet/ipfw/ip_dummynet.c	Wed Jun 24 22:57:07 2009	(r194930)
@@ -661,7 +661,7 @@ ready_event(struct dn_flow_queue *q, str
 		 * queue on error hoping next time we are luckier.
 		 */
 	} else		/* RED needs to know when the queue becomes empty. */
-		q->q_time = curr_time;
+		q->idle_time = curr_time;
 
 	/*
 	 * If the delay line was empty call transmit_event() now.
@@ -761,23 +761,26 @@ ready_event_wfq(struct dn_pipe *p, struc
 			break;
 		}
 	}
-	if (sch->elements == 0 && neh->elements == 0 && p->numbytes >= 0 &&
-	    p->idle_heap.elements > 0) {
+	if (sch->elements == 0 && neh->elements == 0 && p->numbytes >= 0) {
+		p->idle_time = curr_time;
 		/*
 		 * No traffic and no events scheduled.
 		 * We can get rid of idle-heap.
 		 */
-		int i;
+		if (p->idle_heap.elements > 0) {
+			int i;
 
-		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;
+			for (i = 0; i < p->idle_heap.elements; i++) {
+				struct dn_flow_queue *q;
+				
+				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;
 		}
-		p->sum = 0;
-		p->V = 0;
-		p->idle_heap.elements = 0;
 	}
 	/*
 	 * If we are getting clocks from dummynet (not a real interface) and
@@ -1042,7 +1045,7 @@ create_queue(struct dn_flow_set *fs, int
 	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;
+	q->numbytes = fs->pipe->burst + (io_fast ? fs->pipe->bandwidth : 0);
 	fs->rq[i] = q;
 	fs->rq_elements++;
 	return (q);
@@ -1204,7 +1207,7 @@ red_drops(struct dn_flow_set *fs, struct
 		 * XXX check wraps...
 		 */
 		if (q->avg) {
-			u_int t = (curr_time - q->q_time) / fs->lookup_step;
+			u_int t = (curr_time - q->idle_time) / fs->lookup_step;
 
 			q->avg = (t < fs->lookup_depth) ?
 			    SCALE_MUL(q->avg, fs->w_q_lookup[t]) : 0;
@@ -1401,9 +1404,30 @@ dummynet_io(struct mbuf **m0, int dir, s
 	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 (is_pipe) {			/* Fixed rate queues. */
+		if (q->idle_time < curr_time) {
+			/* Calculate available burst size. */
+			q->numbytes +=
+			    (curr_time - q->idle_time) * pipe->bandwidth;
+			if (q->numbytes > pipe->burst)
+				q->numbytes = pipe->burst;
+			if (io_fast)
+				q->numbytes += pipe->bandwidth;
+		}
+	} else {			/* WF2Q. */
+		if (pipe->idle_time < curr_time) {
+			/* Calculate available burst size. */
+			pipe->numbytes +=
+			    (curr_time - pipe->idle_time) * pipe->bandwidth;
+			if (pipe->numbytes > pipe->burst)
+				pipe->numbytes = pipe->burst;
+			if (io_fast)
+				pipe->numbytes += pipe->bandwidth;
+		}
+		pipe->idle_time = curr_time;
+	}
+	/* Necessary for both: fixed rate & WF2Q queues. */
+	q->idle_time = curr_time;
 
 	/*
 	 * If we reach this point the flow was previously idle, so we need
@@ -1731,6 +1755,8 @@ config_pipe(struct dn_pipe *p)
 	 * qsize = slots/bytes
 	 */
 	p->delay = (p->delay * hz) / 1000;
+	/* Scale burst size: bytes -> bits * hz */
+	p->burst *= 8 * hz;
 	/* We need either a pipe number or a flow_set number. */
 	if (p->pipe_nr == 0 && pfs->fs_nr == 0)
 		return (EINVAL);
@@ -1762,11 +1788,14 @@ config_pipe(struct dn_pipe *p)
 		} else
 			/* Flush accumulated credit for all queues. */
 			for (i = 0; i <= pipe->fs.rq_size; i++)
-				for (q = pipe->fs.rq[i]; q; q = q->next)
-					q->numbytes = io_fast ? p->bandwidth : 0;
+				for (q = pipe->fs.rq[i]; q; q = q->next) {
+					q->numbytes = p->burst +
+					    (io_fast ? p->bandwidth : 0);
+				}
 
 		pipe->bandwidth = p->bandwidth;
-		pipe->numbytes = 0;		/* just in case... */
+		pipe->burst = p->burst;
+		pipe->numbytes = pipe->burst + (io_fast ? pipe->bandwidth : 0);
 		bcopy(p->if_name, pipe->if_name, sizeof(p->if_name));
 		pipe->ifp = NULL;		/* reset interface ptr */
 		pipe->delay = p->delay;
@@ -2107,6 +2136,7 @@ dummynet_get(struct sockopt *sopt)
 		 */
 		bcopy(pipe, bp, sizeof(*pipe));
 		pipe_bp->delay = (pipe_bp->delay * 1000) / hz;
+		pipe_bp->burst /= 8 * hz;
 		/*
 		 * XXX the following is a hack based on ->next being the
 		 * first field in dn_pipe and dn_flow_set. The correct


More information about the svn-src-all mailing list