From owner-svn-src-head@FreeBSD.ORG Wed Jun 24 22:57:08 2009 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 1E9221065675; Wed, 24 Jun 2009 22:57:08 +0000 (UTC) (envelope-from oleg@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 0ACC98FC1C; Wed, 24 Jun 2009 22:57:08 +0000 (UTC) (envelope-from oleg@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n5OMv7fc033003; Wed, 24 Jun 2009 22:57:07 GMT (envelope-from oleg@svn.freebsd.org) Received: (from oleg@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n5OMv71d032996; Wed, 24 Jun 2009 22:57:07 GMT (envelope-from oleg@svn.freebsd.org) Message-Id: <200906242257.n5OMv71d032996@svn.freebsd.org> From: Oleg Bulyzhin Date: Wed, 24 Jun 2009 22:57:07 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r194930 - in head: sbin/ipfw sys/netinet sys/netinet/ipfw X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2009 22:57:08 -0000 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 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 #include +#include +#include #include #include #include @@ -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