Date: Fri, 22 Jan 2010 16:23:00 +0000 (UTC) From: Luigi Rizzo <luigi@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r202813 - in user/luigi/ipfw3-head: sbin/ipfw sys/netinet sys/netinet/ipfw Message-ID: <201001221623.o0MGN0vv021613@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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));
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201001221623.o0MGN0vv021613>