- 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.
This commit is contained in:
parent
bc62d44240
commit
6882bf4d92
@ -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>
|
||||
|
@ -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 *fs, char *prefix)
|
||||
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 *fs, char *prefix)
|
||||
}
|
||||
|
||||
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 *p, char *prefix)
|
||||
|
||||
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, int ac, char *av[])
|
||||
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, int ac, char *av[])
|
||||
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 @@ ipfw_config_pipe(int ac, char **av)
|
||||
--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]);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -154,6 +154,7 @@ enum tokens {
|
||||
TOK_BW,
|
||||
TOK_DELAY,
|
||||
TOK_PIPE_PROFILE,
|
||||
TOK_BURST,
|
||||
TOK_RED,
|
||||
TOK_GRED,
|
||||
TOK_DROPTAIL,
|
||||
|
@ -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
|
||||
|
@ -661,7 +661,7 @@ ready_event(struct dn_flow_queue *q, struct mbuf **head, struct mbuf **tail)
|
||||
* 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, struct mbuf **head, struct mbuf **tail)
|
||||
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 i)
|
||||
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 dn_flow_queue *q, int len)
|
||||
* 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, struct ip_fw_args *fwa)
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user