svn commit: r202813 - in user/luigi/ipfw3-head: sbin/ipfw
sys/netinet sys/netinet/ipfw
Luigi Rizzo
luigi at FreeBSD.org
Fri Jan 22 16:23:01 UTC 2010
Author: luigi
Date: Fri Jan 22 16:23:00 2010
New Revision: 202813
URL: http://svn.freebsd.org/changeset/base/202813
Log:
GENERAL:
- rename flowset parameters to 'par[]'; the kernel does not need
to know what they represent, only the schedulers and the user
interface (perhaps);
- use -1 as default value for these parameters so we can preserve
the existing values on new commands;
- export ipdn_bound_var() as there are many places where we use them;
DN_SCHED_RR:
- use a circular queue to store flows (to be tested);
Modified:
user/luigi/ipfw3-head/sbin/ipfw/dummynet.c
user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h
user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h
user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_rr.c
user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_wf2q.c
user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c
Modified: user/luigi/ipfw3-head/sbin/ipfw/dummynet.c
==============================================================================
--- user/luigi/ipfw3-head/sbin/ipfw/dummynet.c Fri Jan 22 16:05:10 2010 (r202812)
+++ user/luigi/ipfw3-head/sbin/ipfw/dummynet.c Fri Jan 22 16:23:00 2010 (r202813)
@@ -242,9 +242,9 @@ print_flowset_parms(struct new_fs *fs, c
prefix, qs, plr, fs->oid.id, fs->buckets, red);
prefix[0] = '\0';
} else {
- printf("q%05d %s%s %d queues (%d buckets) %s sched %d\n",
+ printf("q%05d %s%s %d flows (%d buckets) %s sched %d weight %d\n",
fs->fs_nr, qs, plr, fs->oid.id, fs->buckets, red,
- fs->sched_nr);
+ fs->sched_nr, fs->par[0]);
if (fs->flags & DN_HAVE_MASK)
print_mask(&fs->flow_mask);
}
@@ -388,7 +388,7 @@ list_pipes(struct dn_id *oid, struct dn_
q = (struct dn_flow_queue *)(fs+1);
sprintf(prefix, "q%05d: weight %d sched %d ",
- fs->fs_nr, fs->weight, fs->parent_nr);
+ fs->fs_nr, fs->par[0], fs->parent_nr);
print_flowset_parms(fs, prefix);
list_queues(fs, q);
}
@@ -766,7 +766,7 @@ load_extra_delays(const char *filename,
void
ipfw_config_pipe(int ac, char **av)
{
- int i = -1;
+ int i, j;
char *end;
void *par = NULL;
struct dn_id *buf, *base;
@@ -790,13 +790,11 @@ ipfw_config_pipe(int ac, char **av)
/* Pipe number */
if (ac && isdigit(**av)) {
i = atoi(*av); av++; ac--;
- }
+ } else
+ i = -1;
if (i <= 0)
errx(EX_USAGE, "need a pipe/flowset/sched number");
- base = buf = calloc(1, lmax);
- if (buf == NULL) {
- errx(1, "no memory for buffer");
- }
+ base = buf = safe_calloc(1, lmax);
/* all commands start with a 'CONFIGURE' and a version */
o_next(&buf, sizeof(struct dn_id), DN_CMD_CONFIG);
base->id = DN_API_VERSION;
@@ -847,9 +845,15 @@ ipfw_config_pipe(int ac, char **av)
fs->sched_nr = i;
break;
}
+ /* set to -1 those fields for which we want to reuse existing
+ * values from the kernel.
+ * Also, *_nr and subtype = 0 mean reuse the value from the kernel.
+ * XXX todo: support reuse of the mask.
+ */
if (p)
p->bandwidth = -1;
-
+ for (j = 0; j < sizeof(fs->par)/sizeof(fs->par[0]); j++)
+ fs->par[j] = -1;
while (ac > 0) {
double d;
int tok = match_token(dummynet_params, *av);
@@ -1084,7 +1088,7 @@ end_mask:
case TOK_WEIGHT:
NEED(fs, "weight is only for flowsets");
NEED1("weight needs argument 0..100\n");
- fs->weight = strtoul(av[0], &end, 0);
+ fs->par[0] = strtol(av[0], &end, 0);
ac--; av++;
break;
Modified: user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h Fri Jan 22 16:05:10 2010 (r202812)
+++ user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h Fri Jan 22 16:23:00 2010 (r202813)
@@ -129,10 +129,8 @@ struct new_fs {
struct ipfw_flow_id flow_mask;
uint32_t sched_nr; /* the scheduler we attach to */
- /* generic scheduler parameters */
- int weight;
- int quantum;
- int par[4]; /* other parameters */
+ /* generic scheduler parameters. Leave them at -1 if unset */
+ int par[4];
};
/*
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h Fri Jan 22 16:05:10 2010 (r202812)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h Fri Jan 22 16:23:00 2010 (r202813)
@@ -122,6 +122,8 @@ struct dn_alg {
*/
void dn_free_pkts(struct mbuf *mnext);
int dn_enqueue(struct new_queue *q, struct mbuf* m, int drop);
+/* bound a variable between min and max */
+int ipdn_bound_var(int *v, int dflt, int lo, int hi, const char *msg);
/*
* Extract the head of a queue, update stats. Must be the very last
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_rr.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_rr.c Fri Jan 22 16:05:10 2010 (r202812)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_rr.c Fri Jan 22 16:23:00 2010 (r202813)
@@ -41,15 +41,13 @@
#define DN_SCHED_RR 3 // XXX Where?
-/* rr_queue is appended to a struct new_queue */
struct rr_queue {
- struct new_queue *parent; /* Pointer to standard queue */
+ struct new_queue q; /* Standard queue */
int status; /* 1: queue is in the list */
- TAILQ_ENTRY(rr_queue) entries; /* List of active queue */
int credit; /* Number of bytes to transmit */
int quantum; /* quantum * C */
+ struct rr_queue *qnext; /* */
};
-TAILQ_HEAD(rr_queue_head, rr_queue);
/* struct rr_schk contains global config parameters
* and is right after new_schk
@@ -60,55 +58,85 @@ struct rr_schk {
int q_bytes; /* Bytes per quantum */
};
-/* per-instance info, right after new_sch_inst */
+/* per-instance round robin list, right after new_sch_inst */
struct rr_si {
- struct rr_queue *pointer; /* Pointer to current queue */
- struct rr_queue_head q_list; /* List of queues */
- int queue_n; /* number of queues in the list */
+ struct rr_queue *head, *tail; /* Pointer to current queue */
};
+/* Append a queue to the rr list */
static inline void
-insert_queue(struct rr_queue *q, struct rr_si *si)
+rr_append(struct rr_queue *q, struct rr_si *si)
{
+ q->status = 1; /* mark as in-rr_list */
+ q->credit = q->quantum; /* initialize credit */
- if (TAILQ_EMPTY(&si->q_list)) { /* or si->queue_n == 0 */
- TAILQ_INSERT_HEAD(&si->q_list, q, entries);
- si->pointer = q;
- }
- else {
- TAILQ_INSERT_BEFORE(si->pointer, q, entries);
+ /* append to the tail */
+ if (si->head == NULL)
+ si->head = q;
+ else
+ si->tail->qnext = q;
+ si->tail = q; /* advance the tail pointer */
+ q->qnext = si->head; /* make it circular */
+}
+
+/* Remove the head queue from circular list. */
+static inline void
+rr_remove_head(struct rr_si *si)
+{
+ if (si->head == NULL)
+ return; /* empty queue */
+ si->head->status = 0;
+
+ if (si->head == si->tail) {
+ si->head = si->tail = NULL;
+ return;
}
- q->status = 1;
- si->queue_n++;
+
+ si->head = si->head->qnext;
+ si->tail->qnext = si->head;
}
+/* Remove a queue from circular list.
+ * XXX see if ti can be merge with remove_queue()
+ */
static inline void
-remove_queue(struct rr_queue *q, struct rr_si *si)
+remove_queue_q(struct rr_queue *q, struct rr_si *si)
{
- TAILQ_REMOVE(&si->q_list, q, entries);
+ struct rr_queue *prev;
+
+ if (q->status != 1)
+ return;
+ if (q == si->head)
+ return rr_remove_head(si);
+
+ prev = si->head;
+ while (prev) {
+ if (prev->qnext == q) {
+ prev->qnext = q->qnext;
+ if (q == si->tail)
+ si->tail = prev;
q->status = 0;
- si->queue_n--;
}
+ prev = prev->qnext;
+ }
+}
+
-static inline struct rr_queue *
+static inline void
next_pointer(struct rr_si *si)
{
- if (si->queue_n == 0) { /* XXX needed? */
- si->pointer = NULL;
- return NULL;
- }
- si->pointer = TAILQ_NEXT(si->pointer, entries);
- if (si->pointer == NULL)
- si->pointer = TAILQ_FIRST(&si->q_list);
+ if (si->head == NULL)
+ return; /* empty queue */
- return si->pointer;
+ si->head = si->head->qnext;
+ si->tail = si->tail->qnext;
}
static int
rr_enqueue(struct new_sch_inst *_si, struct new_queue *q, struct mbuf *m)
{
struct rr_si *si;
- struct rr_queue *alg_fq;
+ struct rr_queue *rrq;
if (m != q->mq.head) {
if (dn_enqueue(q, m, 0)) /* packet was dropped */
@@ -119,13 +147,13 @@ rr_enqueue(struct new_sch_inst *_si, str
/* If reach this point, queue q was idle */
si = (struct rr_si *)(_si + 1);
- alg_fq = (struct rr_queue *)(q+1);
+ rrq = (struct rr_queue *)q;
- if (alg_fq->status == 1) /* Queue is already in the queue list */
+ if (rrq->status == 1) /* Queue is already in the queue list */
return 0;
/* Insert the queue in the queue list */
- insert_queue(alg_fq, si);
+ rr_append(rrq, si);
return 0;
}
@@ -135,34 +163,26 @@ rr_dequeue(struct new_sch_inst *_si)
{
/* Access scheduler instance private data */
struct rr_si *si = (struct rr_si *)(_si + 1);
- struct mbuf *pkt;
- struct rr_queue *q;
- struct new_queue *_q;
+ struct rr_queue *rrq;
uint64_t len;
- if (si->queue_n == 0) /* scheduler empty */
- return NULL;
-
- while (si->queue_n > 0) {
- q = si->pointer;
- _q = q->parent;
- /* or use: _q = ((struct new_queue *)q) - 1; */
- si->pointer = next_pointer(si);
- if (_q->mq.head == NULL) {
+ while ( (rrq = si->head) ) {
+ struct mbuf *m = rrq->q.mq.head;
+ if ( m == NULL) {
/* empty queue, remove from list */
- remove_queue(q, si);
+ rr_remove_head(si);
continue;
}
- pkt = _q->mq.head;
- len = pkt->m_pkthdr.len;
+ len = m->m_pkthdr.len;
- if (len > q->credit) {
+ if (len > rrq->credit) {
/* Packet too big */
- q->credit += q->quantum;
+ rrq->credit += rrq->quantum;
/* Try next queue */
+ next_pointer(si);
} else {
- q->credit = q->credit - len + q->quantum;
- return dn_dequeue(_q);
+ rrq->credit -= len;
+ return dn_dequeue(&rrq->q);
}
}
@@ -189,9 +209,7 @@ rr_new_sched(struct new_sch_inst *_si)
struct rr_si *si = (struct rr_si *)(_si + 1);
printf("%s called\n", __FUNCTION__);
- si->pointer = NULL;
- si->queue_n = 0;
- TAILQ_INIT(&si->q_list);
+ si->head = si->tail = NULL;
return 0;
}
@@ -208,31 +226,27 @@ static int
rr_new_fsk(struct new_fsk *fs)
{
struct rr_schk *schk = (struct rr_schk *)(fs->sched + 1);
- printf("%s called\n", __FUNCTION__);
- if (fs->fs.quantum < schk->min_q)
- fs->fs.quantum = schk->min_q;
- else if (fs->fs.quantum > schk->max_q)
- fs->fs.quantum = schk->max_q;
+ ipdn_bound_var(&fs->fs.par[0], schk->min_q,
+ schk->min_q, schk->max_q, "RR quantum");
return 0;
}
static int
rr_new_queue(struct new_queue *_q)
{
- struct rr_queue *q = (struct rr_queue *)(_q + 1);
+ struct rr_queue *q = (struct rr_queue *)_q;
struct rr_schk *schk = (struct rr_schk *)(_q->_si->sched + 1);
printf("%s called, schk->quantum=%d\n", __FUNCTION__, schk->q_bytes);
_q->ni.oid.subtype = DN_SCHED_RR;
- q->quantum = _q->fs->fs.quantum * schk->q_bytes;
+ q->quantum = _q->fs->fs.par[0] * schk->q_bytes;
q->credit = q->quantum;
q->status = 0;
- q->parent = _q;
if (_q->mq.head != NULL) {
/* Queue NOT empty, insert in the queue list */
- insert_queue(q, (struct rr_si *)(_q->_si + 1));
+ rr_append(q, (struct rr_si *)(_q->_si + 1));
}
return 0;
}
@@ -240,14 +254,12 @@ rr_new_queue(struct new_queue *_q)
static int
rr_free_queue(struct new_queue *_q)
{
- struct rr_queue *q = (struct rr_queue *)(_q + 1);
+ struct rr_queue *q = (struct rr_queue *)_q;
printf("%s called\n", __FUNCTION__);
if (q->status == 1) {
struct rr_si *si = (struct rr_si *)(_q->_si + 1);
- remove_queue(q, si);
- if (si->pointer == q)
- si->pointer = next_pointer(si);
+ remove_queue_q(q, si);
}
return 0;
}
@@ -263,7 +275,7 @@ static struct dn_alg rr_desc = {
.flags = DN_MULTIQUEUE,
.si_datalen = sizeof(struct rr_si),
- .q_datalen = sizeof(struct rr_queue),
+ .q_datalen = sizeof(struct rr_queue) - sizeof(struct new_queue),
.enqueue = rr_enqueue,
.dequeue = rr_dequeue,
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_wf2q.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_wf2q.c Fri Jan 22 16:05:10 2010 (r202812)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_wf2q.c Fri Jan 22 16:23:00 2010 (r202813)
@@ -96,7 +96,7 @@ idle_check(struct wf2qp_si *si, int n, i
* mark it as 'unused' by the scheduler.
*/
alg_fq->S = alg_fq->F + 1; /* Mark timestamp as invalid. */
- si->sum -= q->fs->fs.weight; /* adjust sum of weights */
+ si->sum -= q->fs->fs.par[0]; /* adjust sum of weights */
}
}
@@ -121,12 +121,12 @@ wf2qp_enqueue(struct new_sch_inst *_si,
if (DN_KEY_LT(alg_fq->F, alg_fq->S)) {
/* F<S means timestamps are invalid ->brand new queue. */
alg_fq->S = si->V; /* init start time */
- si->sum += fs->fs.weight; /* add weight of new queue. */
+ si->sum += fs->fs.par[0]; /* add weight of new queue. */
} else { /* if it was idle then it was in the idle heap */
heap_extract(&si->idle_heap, q);
alg_fq->S = MAX64(alg_fq->F, si->V); /* compute new S */
}
- alg_fq->F = alg_fq->S + div64((len << MY_M), fs->fs.weight);
+ alg_fq->F = alg_fq->S + div64((len << MY_M), fs->fs.par[0]);
/* if nothing is backlogged, make sure this flow is eligible */
if (si->ne_heap.elements == 0 && si->sch_heap.elements == 0)
@@ -202,7 +202,7 @@ wf2qp_dequeue(struct new_sch_inst *_si)
} else { /* Still backlogged. */
/* Update F, store in neh or sch */
uint64_t len = q->mq.head->m_pkthdr.len;
- alg_fq->F += div64(len << MY_M, q->fs->fs.weight);
+ alg_fq->F += div64(len << MY_M, q->fs->fs.par[0]);
if (DN_KEY_LEQ(alg_fq->S, si->V)) {
heap_insert(sch, alg_fq->F, q);
} else {
@@ -258,10 +258,8 @@ static int
wf2qp_new_fsk(struct new_fsk *fs)
{
// printf("%s called\n", __FUNCTION__);
- if (fs->fs.weight < 1)
- fs->fs.weight = 1;
- else if (fs->fs.weight > 100)
- fs->fs.weight = 100;
+ ipdn_bound_var(&fs->fs.par[0], 1,
+ 1, 100, "WF2Q+ weight");
return 0;
}
@@ -294,7 +292,7 @@ wf2qp_free_queue(struct new_queue *q)
printf("%s called\n", __FUNCTION__);
if (alg_fq->S >= alg_fq->F + 1)
return 0; /* nothing to do, not in any heap */
- si->sum -= q->fs->fs.weight;
+ si->sum -= q->fs->fs.par[0];
/* extract from the heap. XXX TODO we may need to adjust V
* to make sure the invariants hold.
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c Fri Jan 22 16:05:10 2010 (r202812)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c Fri Jan 22 16:23:00 2010 (r202813)
@@ -36,8 +36,8 @@ __FBSDID("$FreeBSD$");
/* debug support */
#define ND(fmt, args...) do {} while (0)
-#define D(fmt, args...) printf("%s " fmt "\n", __FUNCTION__ , ## args)
-
+#define D(fmt, args...) printf("%s %d: " fmt "\n", \
+ __FUNCTION__ , __LINE__ , ## args)
#include <sys/param.h>
#include <sys/systm.h>
@@ -108,8 +108,8 @@ find_sched_type(int type, char *name)
return NULL; /* not found */
}
-static int
-bound_var(int *v, int dflt, int lo, int hi, const char *msg)
+int
+ipdn_bound_var(int *v, int dflt, int lo, int hi, const char *msg)
{
if (*v < lo) {
*v = dflt;
@@ -1044,15 +1044,15 @@ config_fs(struct new_fs *nfs, struct dn_
ND("flowset %d", i);
/* XXX other sanity checks */
if (nfs->flags & DN_QSIZE_BYTES) {
- bound_var(&nfs->qsize, 16384,
- 1500, dn_cfg.byte_limit, "queue byte size");
+ ipdn_bound_var(&nfs->qsize, 16384,
+ 1500, dn_cfg.byte_limit, NULL); // "queue byte size");
} else {
- bound_var(&nfs->qsize, 50,
- 1, dn_cfg.slot_limit, "queue slot size");
+ ipdn_bound_var(&nfs->qsize, 50,
+ 1, dn_cfg.slot_limit, NULL); // "queue slot size");
}
if (nfs->flags & DN_HAVE_MASK) {
/* make sure we have some buckets */
- bound_var(&nfs->buckets, dn_cfg.hash_size,
+ ipdn_bound_var(&nfs->buckets, dn_cfg.hash_size,
1, dn_cfg.max_hash_size, "flowset buckets");
} else {
nfs->buckets = 1; /* we only need 1 */
@@ -1062,23 +1062,30 @@ config_fs(struct new_fs *nfs, struct dn_
do { /* exit with break when done */
struct new_schk *s;
int flags = nfs->sched_nr ? DNHT_INSERT : 0;
+ int j;
+ int oldc = dn_cfg.fsk_count;
fs = dn_ht_find(dn_cfg.fshash, i, flags, NULL);
if (fs == NULL) {
D("missing sched for flowset %d", i);
break;
}
+ /* grab some defaults from the existing one */
if (nfs->sched_nr == 0) /* reuse */
nfs->sched_nr = fs->fs.sched_nr;
- dn_cfg.id++;
+ for (j = 0; j < sizeof(nfs->par)/sizeof(nfs->par[0]); j++) {
+ if (nfs->par[j] == -1) /* reuse */
+ nfs->par[j] = fs->fs.par[j];
+ }
if (bcmp(&fs->fs, nfs, sizeof(*nfs)) == 0) {
ND("flowset %d unchanged", i);
break; /* no change, nothing to do */
}
+ if (oldc != dn_cfg.fsk_count) /* new item */
+ dn_cfg.id++;
s = locate_scheduler(nfs->sched_nr);
/* detach from old scheduler if needed, preserving
* queues if we need to reattach. Then update the
* configuration, and possibly attach to the new sched.
- * XXX should print more on why the config has changed.
*/
D("fs %d changed sched %d@%p to %d@%p",
fs->fs.fs_nr,
@@ -1123,7 +1130,7 @@ config_sched(struct new_sch *_nsch, stru
return EINVAL;
/* make sure we have some buckets */
if (a.sch->flags & DN_HAVE_MASK)
- bound_var(&a.sch->buckets, dn_cfg.hash_size,
+ ipdn_bound_var(&a.sch->buckets, dn_cfg.hash_size,
1, dn_cfg.max_hash_size, "sched buckets");
/* XXX other sanity checks */
bzero(&p, sizeof(p));
More information about the svn-src-user
mailing list