Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 13 Jan 2010 19:46:53 +0000 (UTC)
From:      Luigi Rizzo <luigi@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r202220 - in user/luigi/ipfw3-head: sbin/ipfw sys/netinet sys/netinet/ipfw
Message-ID:  <201001131946.o0DJkrFE005095@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: luigi
Date: Wed Jan 13 19:46:53 2010
New Revision: 202220
URL: http://svn.freebsd.org/changeset/base/202220

Log:
  basic glue and packet flow now operational

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_heap.c
  user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h
  user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_fifo.c
  user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_wf2q.c
  user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c
  user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h
  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	Wed Jan 13 19:25:03 2010	(r202219)
+++ user/luigi/ipfw3-head/sbin/ipfw/dummynet.c	Wed Jan 13 19:46:53 2010	(r202220)
@@ -739,8 +739,6 @@ ipfw_config_pipe(int ac, char **av)
 	struct dn_id *buf, *base;
 	struct new_sch *sch = NULL;
 	struct new_pipe *p = NULL;
-	struct new_sch *sch2 = NULL; /* the fifo scheduler */
-	struct new_pipe *p2 = NULL; /* the fifo pipe */
 	struct new_fs *fs = NULL;
 	struct new_profile *pf = NULL;
 	struct new_cmd *cmd = NULL;
@@ -766,21 +764,26 @@ ipfw_config_pipe(int ac, char **av)
 
 	switch (co.do_pipe) {
 	case 1:
+		/* the WFQ scheduler */
 		sch = o_next(&buf, sizeof(*sch), DN_SCH);
-		sch->sched_nr = i + DN_PIPEOFFSET;
-		sch->oid.subtype = DN_SCHED_FIFO;
-		p = o_next(&buf, sizeof(*p), DN_PIPE);
-		p->pipe_nr = i + DN_PIPEOFFSET;
+		sch->sched_nr = i;
+		sch->oid.subtype = DN_SCHED_WF2QP;
 		mask = &sch->sched_mask;
-		fs = o_next(&buf, sizeof(*fs), DN_FS);
-		fs->fs_nr = i + DN_PIPEOFFSET;
-		fs->sched_nr = i + DN_PIPEOFFSET;
+		/* XXX the FIFO scheduler is created from the WFQ one */
 
-		/* sch2 and p2 will be set later */
-		sch2 = o_next(&buf, sizeof(*sch2), DN_SCH);
-		sch2->oid.subtype = DN_SCHED_WF2QP;
-		p2 = o_next(&buf, sizeof(*p2), DN_PIPE);
+		/* the WFQ pipe */
+		p = o_next(&buf, sizeof(*p), DN_PIPE);
+		p->pipe_nr = i;
+		/* XXX the FIFO pipe is created from WFQ pipe */
 
+		/*
+		 * FIFO flowsets N+i are automatically created for
+		 * FIFO schedulers i, but we provide room to pass
+		 * queue parameters
+		 */
+		fs = o_next(&buf, sizeof(*fs), DN_FS);
+		fs->fs_nr = i + 2*DN_MAX_ID;
+		fs->sched_nr = i + DN_MAX_ID;
 		break;
 
 	case 2: /* flowset */
@@ -793,12 +796,14 @@ ipfw_config_pipe(int ac, char **av)
 		sch = o_next(&buf, sizeof(*sch), DN_SCH);
 		sch->sched_nr = i;
 		mask = &sch->sched_mask;
+		/* room in case we have a FIFO scheduler */
+		fs = o_next(&buf, sizeof(*fs), DN_FS);
+		fs->fs_nr = i + DN_MAX_ID;
+		fs->sched_nr = i;
 		break;
 	}
 	if (p)
 		p->bandwidth = -1;
-	if (p2)
-		p2->bandwidth = -1;
 
 	while (ac > 0) {
 		double d;
@@ -1175,15 +1180,6 @@ end_mask:
 		i = do_cmd(IP_DUMMYNET_CONFIGURE, prof, sizeof *prof);
 	} else
 #endif
-	if (sch2) {
-		*sch2 = *sch;
-		sch2->sched_nr = i;
-		sch2->oid.subtype = DN_SCHED_WF2QP;
-	}
-	if (p2) {
-		*p2 = *p;
-		p2->pipe_nr = i;
-	}
 	i = do_cmd(IP_DUMMYNET3, base,
 		(char *)buf - (char *)base);
 

Modified: user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h	Wed Jan 13 19:25:03 2010	(r202219)
+++ user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h	Wed Jan 13 19:46:53 2010	(r202220)
@@ -128,62 +128,48 @@ struct new_pipe {
 };
 
 /*
- * generic text string, in case we need one
- */
-struct new_text {
-	struct dn_id oid;
-	int len;
-	char text[0];	/* len bytes, NUL terminated */
-};
-
-/*
- * A flowset, which is a template for queues.
+ * A flowset, which is a template for queues. Store here parameters
+ * from the command line: id, target scheduler, queue sizes, plr,
+ * flow masks, buckets for the queue hash, and possibly scheduler-
+ * specific parameters (weight, quantum and so on).
  */
 struct new_fs {
 	struct dn_id oid;
-
-	/* these initial fields are set from the command line
-	 * queue N config mask M pipe P buckets B plr PLR queue QSZ ...
-	 */
-	int fs_nr;  /* N, the flowset number */
-	/* The flowset implicitly created for pipe N is N+offset */
-
-	int qsize; /* QSZ, queue size in slots or bytes */
+	int fs_nr;	/* the flowset number */
 	int flags;	/* userland flags */
+	int qsize;	/* queue size in slots or bytes */
+	int plr;	/* PLR, pkt loss rate (2^31-1 means 100%) */
+	int buckets;	/* buckets used for the queue hash table */
 
-	/* Number of buckets used for the hash table in this fs. */
-	int bucket;     /* B */
-	int plr ;       /* PLR, pkt loss rate (2^31-1 means 100%) */
-
-	/* mask to select the appropriate queue */
 	struct ipfw_flow_id flow_mask;  /* M */
-	int sched_nr;   /* the scheduler we attach to */
+	int sched_nr;	/* the scheduler we attach to */
 	/* generic scheduler parameters */
 	int weight;
-	int slot_size;
+	int quantum;
+	int par[4];	/* other parameters */
 };
 
 /*
- * An instance descriptor has a type, a flow_id, flags and a few counters.
- * so we used this to pass information up to userland.
+ * new_inst collects flow_id and stats for queues and scheduler
+ * instances, and is used to pass these info to userland.
+ * oid.type/oid.subtype describe the object, oid.id is number
+ * of the parent object.
  */
 struct new_inst {
 	struct dn_id oid;
 	struct	ipfw_flow_id	id;
-	uint32_t	parent_nr; /* sched or flowset nr */
 	uint32_t	length; /* Queue lenght, in packets */
 	uint32_t	len_bytes; /* Queue lenght, in bytes */
 	uint32_t	drops;
-	int		hash_slot;
+	int		hash_slot; /* XXX do we need it ? */
 	uint64_t	tot_pkts; /* statistics counters  */
 	uint64_t	tot_bytes;
 };
 
 
-/* Scheduler template
- * All scheduler are linked in a list, there is a 1-1 mapping between
- * 'ipfw sched XX ...' commands and sched XX
- * (plus there is a FIFO scheduler for each pipe)
+/*
+ * Scheduler template, mostly indicating the name, number,
+ * sched_mask and buckets.
  */
 struct new_sch {
 	struct dn_id oid;
@@ -198,18 +184,13 @@ struct new_sch {
 
 
 /*
- * "queue N" and "pipe N" accept 1<=N<=65535. To map the values in
- * the same namespace (which we search through a hash table) we add
- * an offset to 'pipe N' below.
- * 'queue' -> 1..0x0ffff , 'pipe': 0x10001-0x1ffff
+ * "queue N" and "pipe N" accept 1<=N<=65535.
+ * So valid names are from 1 to DN_MAXID-1
  */
-#define	DN_MAXID	0x1ffff
-#define	DN_PIPEOFFSET	0x10000
+#define	DN_MAX_ID	0x10000
 
-/*---- old parameters ---*/
 /*
- * The maximum hash table size for queues.  This value must be a power
- * of 2.
+ * The maximum hash table size for queues (unused ?)
  */
 #define DN_MAX_HASH_SIZE 65536
 

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c	Wed Jan 13 19:25:03 2010	(r202219)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c	Wed Jan 13 19:46:53 2010	(r202220)
@@ -384,7 +384,7 @@ dn_ht_find(struct dn_ht *ht, uintptr_t k
 
 	i = (ht->buckets == 1) ? 0 :
 		(ht->hash(key, flags, ht->arg) % ht->buckets);
-	// log(1, "find %p in bucket %d\n", obj, i);
+	// printf("%s key %p in bucket %d\n", __FUNCTION__, (void *)key, i);
 	for (pp = &ht->ht[i]; (p = *pp); pp = (void **)((char *)p + ht->ofs)) {
 		if (flags & DNHT_MATCH_PTR) {
 			if (key == (uintptr_t)p)
@@ -401,7 +401,7 @@ dn_ht_find(struct dn_ht *ht, uintptr_t k
 		}
 	} else if (flags & DNHT_INSERT) {
 		// printf("%s before calling new, bucket %d ofs %d\n",
-		// 	__FUNCTION__, i, ht->ofs);
+		//	__FUNCTION__, i, ht->ofs);
 		p = ht->new ? ht->new(key, flags, ht->arg) : (void *)key;
 		// printf("%s new returns %p\n", __FUNCTION__, p);
 		if (p) {

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h	Wed Jan 13 19:25:03 2010	(r202219)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h	Wed Jan 13 19:46:53 2010	(r202220)
@@ -102,7 +102,7 @@ struct dn_sched {
 	int (*config)(struct new_schk *, int reconfigure);
 	int (*destroy)(struct new_schk*, int delete);
 
-	int (*new_sched)(struct new_schk *, struct new_sch_inst *);
+	int (*new_sched)(struct new_sch_inst *);
 	int (*free_sched)(struct new_sch_inst *);
 
 	int (*new_queue)(struct new_queue *q);

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_fifo.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_fifo.c	Wed Jan 13 19:25:03 2010	(r202219)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_fifo.c	Wed Jan 13 19:46:53 2010	(r202220)
@@ -24,6 +24,7 @@
  * SUCH DAMAGE.
  */
 
+#ifdef _KERNEL
 #include <sys/malloc.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
@@ -34,11 +35,13 @@
 #include <netinet/in.h>
 #include <netinet/ip_var.h>		/* ipfw_rule_ref */
 #include <netinet/ip_fw.h>	/* flow_id */
+#else
+#include "dn_test.h"
+#endif
 #include <netinet/ip_dummynet.h>
 #include <netinet/ipfw/dn_heap.h>
 #include <netinet/ipfw/ip_dn_private.h>
 #include <netinet/ipfw/dn_sched.h>
-
 /*
  * This file implements a FIFO scheduler.
  * A FIFO scheduler is a simple scheduler algorithm that can be use to
@@ -58,11 +61,8 @@ static int 
 fifo_enqueue(struct new_sch_inst *_si, struct new_queue *q, struct mbuf *m)
 {
 	int ret;
-	struct new_fsk *fs = (struct new_fsk *)q; /* q contains the fs */
 	q = (struct new_queue *)(_si+1);
-	q->fs = fs; // XXX revise
 	ret = dn_queue_packet(q, m, 0);
-	q->fs = NULL;
 	if (ret) {
 		printf("%s dn_queue_packet dropped\n", __FUNCTION__);
 		return 1;
@@ -94,12 +94,16 @@ fifo_dequeue(struct new_sch_inst *_si)
 }
 
 static int
-fifo_new_sched(struct new_schk *s, struct new_sch_inst *_si)
+fifo_new_sched(struct new_sch_inst *si)
 {
 	/* This scheduler instance only has a queue pointer. */
-	struct new_queue *q = (struct new_queue *)(_si + 1);
+	struct new_queue *q = (struct new_queue *)(si + 1);
+
+        set_oid(&q->ni.oid, DN_QUEUE, 0, sizeof(*q));
+	// XXX       SLIST_INSERT_HEAD(&si->ql_list, q, si_chain);
 
-	q->si = _si;
+	q->si = si;
+	q->fs = si->sched->fs;
 	return 0;
 }
 

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_wf2q.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_wf2q.c	Wed Jan 13 19:25:03 2010	(r202219)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_wf2q.c	Wed Jan 13 19:46:53 2010	(r202220)
@@ -56,12 +56,9 @@
  */
 
 static int 
-fifo_enqueue(struct new_sch_inst *_si, struct new_queue *q, struct mbuf *m)
+fifo_enqueue(struct new_sch_inst *si, struct new_queue *q, struct mbuf *m)
 {
-    struct new_fsk *fs = (struct new_fsk *)q;
-    /* the queue is actually the flowset. */
-    q = (struct new_queue *)(_si+1);
-    q->fs = fs;
+    q = (struct new_queue *)(si+1);
     if (dn_queue_packet(q, m, 0))
         return 1;
 
@@ -96,12 +93,13 @@ fifo_dequeue(struct new_sch_inst *_si)
 }
 
 static int
-fifo_new_sched(struct new_schk *s, struct new_sch_inst *_si)
+wf2q_new_sched(struct new_sch_inst *si)
 {
 	/* This scheduler instance only has a queue pointer. */
-	struct new_queue *q = (struct new_queue *)(_si + 1);
+	struct new_queue *q = (struct new_queue *)(si + 1);
 
-	q->si = _si;
+	q->si = si;
+	q->fs = si->sched->fs;
 	return 0;
 }
 
@@ -120,7 +118,7 @@ static struct dn_sched fifo_desc = {
     .enqueue = fifo_enqueue,
     .dequeue = fifo_dequeue,
 
-    .new_sched = fifo_new_sched,
+    .new_sched = wf2q_new_sched,
 };
 
 DECLARE_DNSCHED_MODULE(dn_wf2qp, &fifo_desc);

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c	Wed Jan 13 19:25:03 2010	(r202219)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c	Wed Jan 13 19:46:53 2010	(r202220)
@@ -561,7 +561,7 @@ dummynet_io(struct mbuf **m0, int dir, s
 	dn_key now; /* save a copy of curr_time */
 
 	int fs_id = (fwa->rule.info & IPFW_INFO_MASK) +
-		((fwa->rule.info & IPFW_IS_PIPE) ? DN_PIPEOFFSET : 0);
+		((fwa->rule.info & IPFW_IS_PIPE) ? 2*DN_MAX_ID : 0);
 	DUMMYNET_LOCK();
 	io_pkt++;
 	now = curr_time;
@@ -588,7 +588,7 @@ dummynet_io(struct mbuf **m0, int dir, s
 		if (q == NULL)
 			goto dropit;
 	} else {
-		q = (void *)fs;
+		q = NULL;
 	}
 	if (fs->sched->fp->enqueue(si, q, m)) {
 		printf("%s dropped by enqueue\n", __FUNCTION__);

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h	Wed Jan 13 19:25:03 2010	(r202219)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h	Wed Jan 13 19:46:53 2010	(r202220)
@@ -158,6 +158,7 @@ struct new_schk {
 	SLIST_ENTRY(new_schk) schk_next;  /* hash chain list */
 
 	struct new_fsk_head fsk_list;  /* all fsk linked to me */
+	struct new_fsk *fs;	/* flowset for !MULTIQUEUE */
 
 	/* Hash table of all instances (through sched_mask) */
 	struct dn_ht	*siht;
@@ -187,7 +188,6 @@ struct new_sch_inst {
 
 /* kernel-side flags */
 enum {
-    DN_RECONFIGURE          = 0x0001, /* (k) */
     DN_DELETE               = 0x0004, /* destroy when refcnt=0 */
     DN_REENQUEUE            = 0x0008, /* (k) */
     DN_ACTIVE               = 0x0010, /* (k) */

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c	Wed Jan 13 19:25:03 2010	(r202219)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c	Wed Jan 13 19:46:53 2010	(r202220)
@@ -67,11 +67,6 @@ static int	ip_dn_ctl(struct sockopt *sop
 #define DN_C_FS		0x08
 #define DN_C_QUEUE	0x10
 
-static int config_pipe(struct new_pipe *p, struct dn_id *arg);
-static int config_profile(struct new_profile *p, struct dn_id *arg);
-static int config_fs(struct new_fs *p, struct dn_id *arg);
-static int config_sched(struct new_sch *p, struct dn_id *arg);
-
 /* callout hooks. */
 static struct callout dn_timeout;
 static struct task	dn_task;
@@ -239,6 +234,7 @@ si_new(uintptr_t key, int flags, void *a
 	struct new_sch_inst *si;
 	int l = sizeof(*si) + s->fp->sch_inst_len;
 
+	// printf("%s for sched %d len %d\n", __FUNCTION__, s->sch.sched_nr, l);
 	si = malloc(l, M_DUMMYNET, M_NOWAIT | M_ZERO);
 	if (si == NULL)
 		goto error;
@@ -253,7 +249,8 @@ si_new(uintptr_t key, int flags, void *a
 	si->dline.si = si;
 
 	if (s->fp->new_sched) {
-		int ret = s->fp->new_sched(s, si);
+		int ret;
+		ret = s->fp->new_sched(si);
 		if (ret) {
 			printf("%s: new_sched error %d\n", __FUNCTION__, ret);
 			goto error;
@@ -506,67 +503,6 @@ dummynet_flush(void)
 	DUMMYNET_UNLOCK();
 }
 
-/*
- * Main handler for configuration. Rules of the game:
- * - the first object is the command (config, delete, flush, ...)
- * - config_pipe must be issued after the corresponding config_sched
- * - parameters (DN_TXT) for an object must preceed the object
- *   processed on a config_sched.
- */
-static int
-do_config(void *p, int l)
-{
-	struct dn_id *next, *o;
-	int err = 0;
-	struct dn_id *arg = NULL;
-
-	for (o = p; l >= sizeof(*o); o = next) {
-		struct dn_id *prev = arg;
-		if (o->len < sizeof(*o) || l < o->len) {
-			printf("bad len o->len %d len %d\n", o->len, l);
-			err = EINVAL;
-			break;
-		}
-		l -= o->len;
-		printf("%s cmd %d len %d left %d\n",
-			__FUNCTION__, o->type, o->len, l);
-		next = (struct dn_id *)((char *)o + o->len);
-		err = 0;
-		switch (o->type) {
-		default:
-			printf("cmd %d not implemented\n", o->type);
-			break;
-
-		case DN_CMD_CONFIGURE:
-			break;
-
-		case DN_CMD_FLUSH:
-			dummynet_flush();
-			break;
-		case DN_TEXT:	/* store argument the next block */
-			prev = NULL;
-			arg = o;
-			break;
-		case DN_PIPE:
-			err = config_pipe((struct new_pipe *)o, arg);
-			break;
-		case DN_PROFILE:
-			err = config_profile((struct new_profile *)o, arg);
-			break;
-		case DN_SCH:
-			err = config_sched((struct new_sch *)o, arg);
-			break;
-		case DN_FS:
-			err = config_fs((struct new_fs *)o, arg);
-			break;
-		}
-		if (prev)
-			arg = NULL;
-		if (err != 0)
-			break;
-	}
-	return err;
-}
 
 static inline struct new_schk *
 locate_scheduler(int i)
@@ -586,7 +522,29 @@ update_fs(struct new_schk *s)
 }
 
 /*
- * Setup pipe parameters.
+ * Configuration -- to preserve backward compatibility we use
+ * the following scheme (N is 65536)
+ *	NUMBER		SCHED	PIPE	FLOWSET
+ *	   1 ..  N-1	(1)WFQ	(2)WFQ	(3)queue
+ *	 N+1 .. 2N-1	(4)FIFO (5)FIFO	(6)FIFO for sched 1..N-1
+ *	2N+1 .. 3N-1	--	--	(7)FIFO for sched N+1..2N-1
+ *
+ * "pipe i config" configures #1, #2 and #3
+ * "sched i config" configures #1 and possibly #6
+ * "queue i config" configures #3
+ * #1 is configured with 'pipe i config' or 'sched i config'
+ * #2 is configured with 'pipe i config', and created if not
+ *	existing with 'sched i config'
+ * #3 is configured with 'queue i config'
+ * #4 is automatically configured after #1, can only be FIFO
+ * #5 is automatically configured after #2
+ * #6 is automatically created when #1 is !MULTIQUEUE,
+ *	and can be updated.
+ * #7 is automatically configured after #2
+ */
+
+/*
+ * configure a pipe
  */
 static int
 config_pipe(struct new_pipe *p, struct dn_id *arg)
@@ -599,7 +557,7 @@ config_pipe(struct new_pipe *p, struct d
 		return EINVAL;
 	}
 	i = p->pipe_nr;
-	if (i <= 0 || i > DN_MAXID)
+	if (i <= 0 || i >= DN_MAX_ID)
 		return EINVAL;
 	// printf("%s %d\n", __FUNCTION__, i);
 	/*
@@ -607,146 +565,162 @@ config_pipe(struct new_pipe *p, struct d
 	 * bw = bits/second (0 means no limits),
 	 * delay = ms, must be translated into ticks.
 	 * qsize = slots/bytes
+	 * burst ???
 	 */
 	p->delay = (p->delay * hz) / 1000;
 	/* Scale burst size: bytes -> bits * hz */
 	p->burst *= 8 * hz;
 
 	DUMMYNET_LOCK();
+ again:
 	s = locate_scheduler(i);
 	if (s == NULL) {
 		DUMMYNET_UNLOCK();
 		printf("%s sched %d not found\n", __FUNCTION__, i);
 		return EINVAL;
 	}
+	/* copy all parameters */
 	s->pipe.delay = p->delay;
 	s->pipe.bandwidth = p->bandwidth;
 	s->pipe.burst = p->burst;
 	schk_reset_credit(s);
+	if (i < DN_MAX_ID) {	/* repeat for the FIFO pipe */
+		i += DN_MAX_ID;
+		goto again;
+	}
 	dn_cfg.id++;
 	DUMMYNET_UNLOCK();
 	return 0;
 }
 
 /*
- * Configure a scheduler possibly allocating it (and the pipe).
- * XXX check link to type etc.
+ * configure a flowset. Can be called from inside with locked=1,
+ */
+static struct new_fsk *
+config_fs(struct new_fs *nfs, struct dn_id *arg, int locked)
+{
+	struct new_fsk *fs;
+	struct new_schk *s;
+	int i;
+
+	if (nfs->oid.len < sizeof(*nfs)) {
+		printf("%s: short flowset\n", __FUNCTION__);
+		return NULL;
+	}
+	i = nfs->fs_nr;
+	// printf("%s fs %d sched %d\n", __FUNCTION__, i, nfs->sched_nr);
+	if (i <= 0 || i >= 3*DN_MAX_ID)
+		return NULL;
+	/* XXX other sanity checks */
+        if (nfs->flags & DN_QSIZE_IS_BYTES) {
+                if (nfs->qsize > dn_cfg.pipe_byte_limit)
+                        nfs->qsize = dn_cfg.pipe_byte_limit;
+        } else {
+                if (nfs->qsize == 0)
+                        nfs->qsize = 50;
+                if (nfs->qsize > dn_cfg.pipe_slot_limit)
+                        nfs->qsize = dn_cfg.pipe_slot_limit;
+        }
+	if (!locked)
+		DUMMYNET_LOCK();
+again:
+	fs = dn_ht_find(dn_cfg.fshash, i, DNHT_INSERT);
+	if (fs == NULL)
+		goto done;
+	dn_cfg.id++;
+	fs->fs = *nfs;	/* update config */
+	s = locate_scheduler(nfs->sched_nr);
+	if (fs->sched == NULL) { /* no scheduler before */
+		if (s) {
+			/* have a new scheduler, remove from unlinked */
+			fs->sched = s;
+			// XXX remove_from_unlinked(fs);
+		}
+	} else if (fs->sched != s) {
+		/* scheduler changed. Let it die and recreate */
+		fs->kflags |= DN_DELETE;
+		goto again;
+	}
+done:
+	if (!locked)
+		DUMMYNET_UNLOCK();
+	return fs;
+}
+
+/*
+ * configure a scheduler and its FIFO variant.
+ * For !MULTIQUEUE schedulers, also set up the flowset.
  */
 static int
 config_sched(struct new_sch *nsch, struct dn_id *arg)
 {
 	struct new_schk *s;
 	struct dn_sched *fp;
-	int i, is_new;
+	int i, notify_fs = 0;
 
 	if (nsch->oid.len != sizeof(*nsch)) {
 		printf("%s: bad sched len\n", __FUNCTION__);
 		return EINVAL;
 	}
 	i = nsch->sched_nr;
-	if (i <= 0 || i > DN_MAXID)
+	if (i <= 0 || i >= DN_MAX_ID)
 		return EINVAL;
-	// printf("%s i %d\n", __FUNCTION__, i);
 	/* XXX other sanity checks */
+	DUMMYNET_LOCK();
+again: /* run twice, for wfq and fifo */
+	// printf("%s i %d\n", __FUNCTION__, i);
 	fp = load_scheduler(nsch->oid.subtype, nsch->type);
 	if (fp == NULL) {
+		DUMMYNET_UNLOCK();
 		printf("invalid scheduler type %d\n", nsch->oid.subtype);
 		return EINVAL;
 	}
 	nsch->oid.subtype = fp->type;
-	nsch->oid.id = (uintptr_t)fp;	/* used for  */
-	DUMMYNET_LOCK();
-	// printf("%s i %d before ht_find\n", __FUNCTION__, i);
+	nsch->oid.id = (uintptr_t)fp;	/* used in schk_new() */
 	s = dn_ht_find(dn_cfg.schedhash, (uintptr_t)nsch,
 			DNHT_KEY_IS_OBJ | DNHT_INSERT);
-	// printf("%s i %d after ht_find\n", __FUNCTION__, i);
 	if (s == NULL) {
+		DUMMYNET_UNLOCK();
 		printf("cannot allocate scheduler\n");
 		return ENOMEM;
 	}
-	printf("%s type %s old %p\n", __FUNCTION__, fp->name, s);
-	/* Handle the following cases
-	 * 1. non existing before:
-	 *	initialize
-	 * 2. existing before, type changed
-	 *	destroy queues, then #1
-	 * 3. existing before, same type.
-	 *	update parameters and pipe
-	 */
-	is_new = 0;
+	dn_cfg.id++;
 	if (s->fp == NULL) { /* new scheduler, nothing to clean up */
-		is_new = 1;
-	} else if (s->fp != fp) { /* type changed, flush queues. */
-		// XXX we should reallocate the private data area.
-		// how do we do it ?
-		/* preserve old pipe */
-		schk_flush(s);
+		notify_fs = 1;
+	} else if (s->fp != fp) {
+		printf("sched %d type changed from %s to %s"
+			" let it drain and reallocate\n",
+			i, s->fp->name, fp->name);
+		/* XXX detach flowsets */
+		s->kflags = DN_DELETE;
+		notify_fs = 1;
+		goto again;
 	}
 	/* complete initialization */
 	s->fp = fp;
 	s->cfg = arg;
-	/* call init function  */
+	// XXX schk_reset_credit(s);
+	/* create the internal flowset if needed */
+	if (!(s->fp->flags & DN_MULTIQUEUE) && !s->fs) {
+		struct new_fs fs;
+
+		bzero(&fs, sizeof(fs));
+		set_oid(&fs.oid, DN_FS, 0, sizeof(fs));
+		fs.fs_nr = i + DN_MAX_ID;
+		fs.sched_nr = i;
+		s->fs = config_fs(&fs, NULL, 1 /* locked */);
+	}
+	/* call init function after the flowset is created */
 	if (s->fp->config)
 		s->fp->config(s, 1);
-	schk_reset_credit(s);
-	if (is_new)
-		update_fs(s);
-	dn_cfg.id++;
-	DUMMYNET_UNLOCK();
-	return 0;
-}
-
-/*
- * response to a userland request to configure a flowset
- * XXX check the allocation of the private area
- */
-static int
-config_fs(struct new_fs *nfs, struct dn_id *arg)
-{
-	struct new_fsk *fs;
-	struct new_schk *s;
-	int i;
-
-	if (nfs->oid.len < sizeof(*nfs)) {
-		printf("%s: short flowset\n", __FUNCTION__);
-		return EINVAL;
-	}
-	i = nfs->fs_nr;
-	if (i <= 0 || i > DN_MAXID)
-		return EINVAL;
-	printf("%s i %d\n", __FUNCTION__, i);
-	/* XXX other sanity checks */
-        if (nfs->flags & DN_QSIZE_IS_BYTES) {
-                if (nfs->qsize > dn_cfg.pipe_byte_limit)
-                        nfs->qsize = dn_cfg.pipe_byte_limit;
-        } else {
-                if (nfs->qsize == 0)
-                        nfs->qsize = 50;
-                if (nfs->qsize > dn_cfg.pipe_slot_limit)
-                        nfs->qsize = dn_cfg.pipe_slot_limit;
-        }
-
-	DUMMYNET_LOCK();
-again:
-	fs =  dn_ht_find(dn_cfg.fshash, i, DNHT_INSERT);
-
-	if (fs == NULL) {
-		DUMMYNET_UNLOCK();
-		return ENOMEM;
-	}
-	fs->fs = *nfs;	/* update config */
-	s = locate_scheduler(nfs->sched_nr);
-	if (fs->sched == NULL) { /* no scheduler before, link */
-		if (s) {
-			fs->sched = s;
-			// XXX remove_from_unlinked(fs);
-		}
-	} else if (fs->sched != s) {
-		/* scheduler changed. Mark old fs and recreate */
-		fs->kflags |= DN_DELETE;
+	if (i < DN_MAX_ID) { /* update the FIFO instance */
+		i += DN_MAX_ID;
+		nsch->sched_nr = i;
+		nsch->oid.subtype = DN_SCHED_FIFO;
 		goto again;
 	}
-	dn_cfg.id++;
+	if (notify_fs)
+		update_fs(s);
 	DUMMYNET_UNLOCK();
 	return 0;
 }
@@ -766,7 +740,7 @@ config_profile(struct new_profile *pf, s
 		return EINVAL;
 	}
 	i = pf->pipe_nr;
-	if (i <= 0 || i > DN_MAXID)
+	if (i <= 0 || i >= DN_MAX_ID)
 		return EINVAL;
 	/* XXX other sanity checks */
 
@@ -814,6 +788,67 @@ config_profile(struct new_profile *pf, s
 	return 0;
 }
 
+/*
+ * Main handler for configuration. Rules of the game:
+ * - the first object is the command (config, delete, flush, ...)
+ * - config_pipe must be issued after the corresponding config_sched
+ * - parameters (DN_TXT) for an object must preceed the object
+ *   processed on a config_sched.
+ */
+static int
+do_config(void *p, int l)
+{
+	struct dn_id *next, *o;
+	int err = 0;
+	struct dn_id *arg = NULL;
+
+	for (o = p; l >= sizeof(*o); o = next) {
+		struct dn_id *prev = arg;
+		if (o->len < sizeof(*o) || l < o->len) {
+			printf("bad len o->len %d len %d\n", o->len, l);
+			err = EINVAL;
+			break;
+		}
+		l -= o->len;
+		printf("%s cmd %d len %d left %d\n",
+			__FUNCTION__, o->type, o->len, l);
+		next = (struct dn_id *)((char *)o + o->len);
+		err = 0;
+		switch (o->type) {
+		default:
+			printf("cmd %d not implemented\n", o->type);
+			break;
+
+		case DN_CMD_CONFIGURE:
+			break;
+
+		case DN_CMD_FLUSH:
+			dummynet_flush();
+			break;
+		case DN_TEXT:	/* store argument the next block */
+			prev = NULL;
+			arg = o;
+			break;
+		case DN_PIPE:
+			err = config_pipe((struct new_pipe *)o, arg);
+			break;
+		case DN_PROFILE:
+			err = config_profile((struct new_profile *)o, arg);
+			break;
+		case DN_SCH:
+			err = config_sched((struct new_sch *)o, arg);
+			break;
+		case DN_FS:
+			err = (NULL==config_fs((struct new_fs *)o, arg, 0));
+			break;
+		}
+		if (prev)
+			arg = NULL;
+		if (err != 0)
+			break;
+	}
+	return err;
+}
 static int
 compute_space(struct dn_id *cmd, int *to_copy)
 {
@@ -975,15 +1010,18 @@ schk_hash(uintptr_t key, int flags, void
 {
 	int i = ((flags & DNHT_KEY_IS_OBJ) == 0) ? key :
 		((struct new_schk *)key)->sch.sched_nr;
+	// printf("%s %d\n", __FUNCTION__, i);
 	return ( (i>>8)^(i>>4)^i );
 }
 
 static int
 schk_match(void *obj, uintptr_t key, int flags, void *arg)
 {
+	struct new_schk *s = ((struct new_schk *)obj);
 	int i = ((flags & DNHT_KEY_IS_OBJ) == 0) ? key :
 		((struct new_schk *)key)->sch.sched_nr;
-	return ((struct new_schk *)obj)->sch.sched_nr == i;
+	// printf("%s s %p i %d\n", __FUNCTION__, s, i);
+	return !(s->kflags & DN_DELETE) && (s->sch.sched_nr == i);
 }
 
 /*
@@ -999,7 +1037,6 @@ schk_new(uintptr_t key, int flags, void 
 	struct dn_sched *fp = (struct dn_sched *)sch->oid.id;
 	int l = sizeof(*s) + fp->schk_len;
 	
-// printf("%s key %p fp %p\n", __FUNCTION__, sch, fp);
 	s = malloc(l, M_DUMMYNET, M_NOWAIT | M_ZERO);
 	if (s == NULL)
 		return NULL;
@@ -1038,7 +1075,7 @@ fsk_match(void *obj, uintptr_t key, int 
 	struct new_fsk *fs = obj;
 	int i = ((flags & DNHT_KEY_IS_OBJ) == 0) ? key :
 		((struct new_fsk *)key)->fs.fs_nr;
-	return !(fs->kflags & DN_DELETE) && fs->fs.fs_nr == i;
+	return !(fs->kflags & DN_DELETE) && (fs->fs.fs_nr == i);
 }
 
 static void *
@@ -1122,7 +1159,6 @@ dummynet_modevent(module_t mod, int type
 
 	switch (type) {
 	case MOD_LOAD:
-		printf("%s MODLOAD\n", __FUNCTION__);
 		if (ip_dn_io_ptr) {
 			printf("DUMMYNET already loaded\n");
 			return EEXIST ;
@@ -1153,7 +1189,7 @@ load_descriptor(struct dn_sched *d)
 
 	if (d == NULL)
 		return 1; /* error */
-	ip_dn_init();	/* just in case */
+	ip_dn_init();	/* just in case, we need the lock */
 
 	/* Check that mandatory funcs exists */
 	if (d->enqueue == NULL || d->dequeue == NULL) {
@@ -1173,7 +1209,6 @@ load_descriptor(struct dn_sched *d)
 		SLIST_INSERT_HEAD(&list_of_scheduler, d, next);
 	DUMMYNET_UNLOCK();
 	printf("dn_sched %s %sloaded\n", d->name, s ? "not ":"");
-
 	return s ? 1 : 0;
 }
 
@@ -1196,7 +1231,8 @@ unload_descriptor(struct dn_sched *s)
 		break;
 	}
 	DUMMYNET_UNLOCK();
-	return err; /* scheduler in use */
+	printf("dn_sched %s %sunloaded\n", s->name, err ? "not ":"");
+	return err;
 }
 
 int



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201001131946.o0DJkrFE005095>