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
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to