Skip site navigation (1)Skip section navigation (2)
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>