svn commit: r202639 - user/luigi/ipfw3-head/sys/netinet/ipfw

Luigi Rizzo luigi at FreeBSD.org
Tue Jan 19 18:42:09 UTC 2010


Author: luigi
Date: Tue Jan 19 18:42:09 2010
New Revision: 202639
URL: http://svn.freebsd.org/changeset/base/202639

Log:
  snapshot

Modified:
  user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c
  user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.h
  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/sys/netinet/ipfw/dn_heap.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c	Tue Jan 19 18:25:49 2010	(r202638)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c	Tue Jan 19 18:42:09 2010	(r202639)
@@ -363,14 +363,25 @@ dn_ht_init(struct dn_ht *ht, int buckets
 	return ht;
 }
 
+/* dummy callback for dn_ht_free to unlink all */
+static int
+do_del(void *obj, void *arg)
+{
+	return DNHT_SCAN_DEL;
+}
+
 void
 dn_ht_free(struct dn_ht *ht, int flags)
 {
 	if (ht == NULL)
 		return;
-	if (ht->ht && ht->ht != (void *)(ht + 1))
-		free(ht->ht, M_DN_HEAP);
-	free(ht, M_DN_HEAP);
+	if (flags & DNHT_REMOVE) {
+		(void)dn_ht_scan(ht, do_del, NULL);
+	} else {
+		if (ht->ht && ht->ht != (void *)(ht + 1))
+			free(ht->ht, M_DN_HEAP);
+		free(ht, M_DN_HEAP);
+	}
 }
 
 int
@@ -437,7 +448,7 @@ dn_ht_scan(struct dn_ht *ht, int (*fn)(v
 		while ( (cur = *curp) != NULL) {
 			next = *(void **)((char *)cur + ht->ofs);
 			ret = fn(cur, arg);
-			if (ret & HEAP_SCAN_DEL) {
+			if (ret & DNHT_SCAN_DEL) {
 				printf("element %p removed\n", cur);
 				found++;
 				ht->entries--;
@@ -445,7 +456,7 @@ dn_ht_scan(struct dn_ht *ht, int (*fn)(v
 			} else {
 				curp = (void **)((char *)cur + ht->ofs);
 			}
-			if (ret & HEAP_SCAN_END)
+			if (ret & DNHT_SCAN_END)
 				return found;
 		}
 	}

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.h	Tue Jan 19 18:25:49 2010	(r202638)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.h	Tue Jan 19 18:42:09 2010	(r202639)
@@ -118,9 +118,9 @@ int heap_scan(struct dn_heap *, int (*)(
  *	new(key, flags, arg) optional, used to allocate a new
  *		object during insertions.
  *
- * dn_ht_free() frees the heap, optionally unlinking elements
- *	(XXX unlink is optional and serves only to avoid stale
- *	pointers in the objects. Probably useless.)
+ * dn_ht_free() frees the heap or unlink elements.
+ *	DNHT_REMOVE unlink elements, 0 frees the heap.
+ *	You need two calls to do both.
  *
  * dn_ht_find() is the main lookup function, which can also be
  *	used to insert or delete elements in the hash table.
@@ -175,7 +175,7 @@ enum {  /* flags values.
         DNHT_MATCH_PTR	= 0x0008,	/* match by pointer, not match() */
         DNHT_INSERT	= 0x0010,	/* insert if not found */
         DNHT_UNIQUE	= 0x0020,	/* report error if already there */
-        DNHT_REMOVE	= 0x0040,	/* remove on find */
+        DNHT_REMOVE	= 0x0040,	/* remove on find or dn_ht_free */
 }; 
 
 #endif /* _IP_DN_HEAP_H */

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h	Tue Jan 19 18:25:49 2010	(r202638)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h	Tue Jan 19 18:42:09 2010	(r202639)
@@ -91,6 +91,7 @@ struct dn_sched {
 	 * new_fsk	called when a flowset is linked to a scheduler,
 	 *	e.g. to validate parameters such as weights etc.
 	 * free_fsk	when a flowset is unlinked from a scheduler.
+	 *	(probably unnecessary)
 	 *
 	 * new_queue	called to set the per-queue parameters,
 	 *	e.g. S and F, adjust sum of weights in the parent, etc.
@@ -105,8 +106,8 @@ struct dn_sched {
 		struct mbuf *);
 	struct mbuf * (*dequeue)(struct new_sch_inst *);
 
-	int (*config)(struct new_schk *, int reconfigure);
-	int (*destroy)(struct new_schk*, int delete);
+	int (*config)(struct new_schk *);
+	int (*destroy)(struct new_schk*);
 	int (*new_sched)(struct new_sch_inst *);
 	int (*free_sched)(struct new_sch_inst *);
 	int (*new_fsk)(struct new_fsk *f);
@@ -123,6 +124,7 @@ struct dn_sched {
  * if do_free is set, propagate to the flowset and destroy it
  * if the refcount becomes 0
  */
+void dn_free_pkts(struct mbuf *mnext);
 struct new_queue *dn_delete_queue(struct new_queue *, int do_free);
 int dn_enqueue(struct new_queue *q, struct mbuf* m, int drop);
 
@@ -139,9 +141,9 @@ dn_dequeue(struct new_queue *q)
 	q->mq.head = m->m_nextpkt;
 	q->ni.length--;
 	q->ni.len_bytes -= m->m_pkthdr.len;
-	if (q->si) {
-		q->si->ni.length--;
-		q->si->ni.len_bytes -= m->m_pkthdr.len;
+	if (q->_si) {
+		q->_si->ni.length--;
+		q->_si->ni.len_bytes -= m->m_pkthdr.len;
 	}
 	if (q->mq.head == NULL && q->fs && q->fs->kflags & DN_DELETE)
 		(void)dn_delete_queue(q, 1 /* free if possible */);

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_fifo.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_fifo.c	Tue Jan 19 18:25:49 2010	(r202638)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_fifo.c	Tue Jan 19 18:42:09 2010	(r202639)
@@ -70,11 +70,20 @@ fifo_new_sched(struct new_sch_inst *si)
 	struct new_queue *q = (struct new_queue *)(si + 1);
 
         set_oid(&q->ni.oid, DN_QUEUE, sizeof(*q));
-	q->si = si;
+	q->_si = si;
 	q->fs = si->sched->fs;
 	return 0;
 }
 
+static int
+fifo_free_sched(struct new_sch_inst *si)
+{
+	struct new_queue *q = (struct new_queue *)(si + 1);
+	dn_free_pkts(q->mq.head);
+	bzero(q, sizeof(*q));
+	return 0;
+}
+
 /*
  * FIFO scheduler descriptor
  * contains the type of the scheduler, the name, the size of extra
@@ -89,6 +98,7 @@ static struct dn_sched fifo_desc = {
 	.enqueue = fifo_enqueue,
 	.dequeue = fifo_dequeue,
 	.new_sched = fifo_new_sched,
+	.free_sched = fifo_free_sched,
 };
 
 DECLARE_DNSCHED_MODULE(dn_fifo, &fifo_desc);

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_wf2q.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_wf2q.c	Tue Jan 19 18:25:49 2010	(r202638)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_wf2q.c	Tue Jan 19 18:42:09 2010	(r202639)
@@ -278,7 +278,7 @@ wf2qp_new_queue(struct new_queue *_q)
 	q->F = 0;	/* not strictly necessary */
 	q->S = q->F + 1;    /* mark timestamp as invalid. */
 	if (_q->mq.head != NULL) {
-		wf2qp_enqueue(_q->si, _q, _q->mq.head);
+		wf2qp_enqueue(_q->_si, _q, _q->mq.head);
 	}
 	return 0;
 }
@@ -287,7 +287,7 @@ static int
 wf2qp_free_queue(struct new_queue *q)
 {
 	struct wf2qp_queue *alg_fq = (struct wf2qp_queue *)(q + 1);
-	struct wf2qp_si *si = (struct wf2qp_si *)(q->si + 1);
+	struct wf2qp_si *si = (struct wf2qp_si *)(q->_si + 1);
     
 	printf("%s called\n", __FUNCTION__);
 	/* If the queue was valid, decrement the sum value */

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c	Tue Jan 19 18:25:49 2010	(r202638)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c	Tue Jan 19 18:42:09 2010	(r202639)
@@ -221,7 +221,7 @@ dn_enqueue(struct new_queue *q, struct m
 	uint64_t len;
 
 	f = &(q->fs->fs);
-	ni = &q->si->ni;
+	ni = &q->_si->ni;
 	len = m->m_pkthdr.len;
 	/* Update statistics, then check reasons to drop pkt. */
 	q->ni.tot_bytes += len;
@@ -577,7 +577,7 @@ dummynet_io(struct mbuf **m0, int dir, s
 		goto dropit;	/* This queue/pipe does not exist! */
 	if (fs->sched == NULL)	/* should not happen */
 		goto dropit;
-	/* find scheduler instance, possibly applying mask */
+	/* find scheduler instance, possibly applying sched_mask */
 	si = ipdn_si_find(fs->sched, &(fwa->f_id));
 	if (si == NULL)
 		goto dropit;

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h	Tue Jan 19 18:25:49 2010	(r202638)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h	Tue Jan 19 18:42:09 2010	(r202639)
@@ -144,18 +144,17 @@ struct new_fsk { /* kernel side of a flo
 };
 
 /*
- * q queue is created as a child of a flowset unless it belongs to
+ * A queue is created as a child of a flowset unless it belongs to
  * a !MULTIQUEUE scheduler. It is normally in a hash table in the
- * flowset.
- * When a scheduler is destroyed we notify all flowsets attached
- * to it so queues can be removed.
- * When a flowset is deleted we let the queue drain quietly, and
- * destroy the flowset when all queues are empty.
+ * flowset. fs always points to the parent flowset.
+ * si normally points to the sch_inst, unless the flowset has been
+ * detached from the scheduler -- in this case si == NULL and we
+ * should not enqueue.
  */
 struct new_queue {
 	struct new_inst ni;	/* oid, flow_id, stats */
 	struct mq mq;	/* packets queue */
-	struct new_sch_inst *si;	/* owner scheduler instance */
+	struct new_sch_inst *_si;	/* owner scheduler instance */
 	SLIST_ENTRY(new_queue) q_next; /* hash chain list for fs */
 	struct new_fsk *fs;		/* parent flowset. */
 	/* If fs->kflags & DN_DELETE, remove the queue when empty. */
@@ -171,7 +170,6 @@ struct new_queue {
  */
 struct new_schk {
 	struct new_sch sch;
-	int kflags;
 	struct dn_sched *fp;	/* Pointer to scheduler functions */
 	struct new_pipe pipe;	/* the pipe is embedded */
 	struct new_profile *profile;

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c	Tue Jan 19 18:25:49 2010	(r202638)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c	Tue Jan 19 18:42:09 2010	(r202639)
@@ -107,7 +107,7 @@ find_sched_type(int type, char *name)
  * Dispose a list of packet. Use a functions so if we need to do
  * more work, this is a central point to do it.
  */
-static void dn_free_pkts(struct mbuf *mnext)
+void dn_free_pkts(struct mbuf *mnext)
 {
         struct mbuf *m;
     
@@ -247,7 +247,7 @@ q_new(uintptr_t key, int flags, void *ar
 	if (fs->fs.flags & DN_HAVE_MASK)
 		q->ni.id = *(struct ipfw_flow_id *)key;
 	q->fs = fs;
-	q->si = template->si;
+	q->_si = template->_si;
 	fs->refcnt++;
 
 	if (fs->sched->fp->new_queue)
@@ -266,10 +266,11 @@ dn_delete_queue(struct new_queue *q, int
 {
 	struct new_fsk *fs = q->fs;
 
-	printf("    +++ %s fs %p si %p\n", __FUNCTION__, fs, q->si);
+	printf("    +++ %s fs %p si %p\n", __FUNCTION__, fs, q->_si);
 	/* notify the parent scheduler that the queue is going away */
 	if (fs && fs->sched->fp->free_queue)
 		fs->sched->fp->free_queue(q);
+	q->_si = NULL;
 	if (!do_free)
 		return q;
 	if (q->mq.head)
@@ -308,6 +309,40 @@ qht_delete(struct new_fsk *fs, int flags
 		}
 	}
 }
+
+/*
+ * only called in the DN_MULTIQUEUE CASE so we can handle errors
+ * in a better way.
+ */
+struct new_queue *
+ipdn_q_find(struct new_fsk *fs, struct new_sch_inst *si,
+	struct ipfw_flow_id *id)
+{
+	struct new_queue template;
+	template._si = si;
+	template.fs = fs;
+
+	if (fs->fs.flags & DN_HAVE_MASK) {
+		struct ipfw_flow_id masked_id;
+		if (fs->_qht == NULL) {
+			fs->_qht = dn_ht_init(NULL, fs->fs.buckets,
+				offsetof(struct new_queue, q_next),
+				q_hash, q_match, q_new);
+			if (fs->_qht == NULL)
+				return NULL;
+			fs->kflags &= ~DN_QHT_IS_Q;
+		}
+		masked_id = *id;
+		flow_id_mask(&fs->fs.flow_mask, &masked_id);
+		return dn_ht_find(fs->_qht, (uintptr_t)&masked_id,
+			DNHT_INSERT, &template);
+	} else {
+		if (fs->_qht == NULL)
+			fs->_qht = q_new(0, 0, &template);
+		fs->kflags |= DN_QHT_IS_Q;
+		return (struct new_queue *)fs->_qht;
+	}
+}
 /*--- end of queue hash table ---*/
 
 /*--- support functions for the sch_inst hashtable ----
@@ -380,7 +415,7 @@ error:
 }
 
 /*
- * Callback for the hashtable scan.
+ * callback from siht to delete all scheduler instances.
  * We assume that all flowset have been notified and do not
  * point to us anymore.
  * Remove si and delay line from the system heap, destroy all queues.
@@ -468,14 +503,15 @@ fsk_new(uintptr_t key, int flags, void *
 /*
  * Detach or destroy all flowsets in a list.
  * flags specifies what to do:
- * DN_DELETE	flush all queues
- * DN_DELETE_FS	DN_DELETE + destroy flowset
+ * DN_DELETE:	flush all queues
+ * DN_DELETE_FS:	DN_DELETE + destroy flowset
  *	DN_DELETE_FS implies DN_DELETE
  */
 static void
 fsk_detach_list(struct new_fsk_head *h, int flags)
 {
 	struct new_fsk *fs;
+	int n = 0;
 
 	if (flags & DN_DELETE_FS)
 		flags |= DN_DELETE;
@@ -485,15 +521,52 @@ fsk_detach_list(struct new_fsk_head *h, 
 		printf("   +++ %s child fs %d\n", __FUNCTION__, fs->fs.fs_nr);
 		/* detach queues from the scheduler and possibly drain them */
 		qht_delete(fs, flags);
+		if (fs->sched && fs->sched->fp->free_fsk)
+			fs->sched->fp->free_fsk(fs);
 		fs->sched = NULL;
 		if (flags & DN_DELETE_FS) {
 			bzero(fs, sizeof(fs));	/* safety */
 			free(fs, M_DUMMYNET);
+			dn_cfg.fsk_count--;
 		} else {
 			SLIST_INSERT_HEAD(&dn_cfg.fsu, fs, sch_chain);
 		}
 	}
+	printf("+++ %s done %d flowsets\n", __FUNCTION__, n);
 }
+
+/*
+ * called on 'queue X delete' -- removes the flowset from fshash,
+ * deletes all queues for the flowset, and removes the flowset.
+ * XXX note that fsk_detach_list also destroys a flowset.
+ */
+static int
+delete_fs(int i)
+{
+	struct new_fsk_head *h;
+	struct new_fsk *fs;
+
+	fs = dn_ht_find(dn_cfg.fshash, i, DNHT_REMOVE, NULL);
+	printf("%s fs %d found %p\n", __FUNCTION__, i, fs);
+	if (fs == NULL)
+		return EINVAL;
+
+	/* find the container list */
+	h = fs->sched ? &fs->sched->fsk_list : &dn_cfg.fsu;
+	SLIST_REMOVE(h, fs, new_fsk, sch_chain);
+
+	/* replica of the code in fsk_detach_list */
+	qht_delete(fs, DN_DELETE);
+	if (fs->sched && fs->sched->fp->free_fsk)
+		fs->sched->fp->free_fsk(fs);
+	fs->sched = NULL;
+	bzero(fs, sizeof(fs));  /* safety */ 
+	free(fs, M_DUMMYNET);
+	dn_cfg.fsk_count--;
+
+	return 0;
+}
+
 /*----- end of flowset hashtable support -------------*/
 
 /*------------------------------------------------------------
@@ -516,7 +589,7 @@ schk_match(void *obj, uintptr_t key, int
 	struct new_schk *s = ((struct new_schk *)obj);
 	int i = !(flags & DNHT_KEY_IS_OBJ) ? key :
 		((struct new_schk *)key)->sch.sched_nr;
-	return !(s->kflags & DN_DELETE) && (s->sch.sched_nr == i);
+	return (s->sch.sched_nr == i);
 }
 
 /*
@@ -550,6 +623,61 @@ schk_new(uintptr_t key, int flags, void 
 	return s;
 }
 
+/*
+ * Callback for sched delete. Notify all attached flowsets to
+ * detach from the scheduler, destroy the internal flowset, and
+ * all instances. The scheduler goes away too.
+ * arg is 0 (only detach flowsets and destroy instances)
+ * DN_DELETE (detach & delete queues, delete schk)
+ * or DN_DELETE_FS (delete queues and flowsets, delete schk)
+ */
+static int
+schk_delete_cb(void *obj, void *arg)
+{
+	struct new_schk *s = obj;
+	int i = s->sch.sched_nr;
+	int a = (int)arg;
+
+	printf(">>> %s sched %d arg %s%s\n",
+		__FUNCTION__, s->sch.sched_nr,
+		a&DN_DELETE ? "DEL ":"",
+		a&DN_DELETE_FS ? "DEL_FS":"");
+	fsk_detach_list(&s->fsk_list, arg ? DN_DELETE : 0);
+	/* no more flowset pointing to us now */
+	if (s->sch.flags & DN_HAVE_MASK) {
+		dn_ht_scan(s->siht, si_destroy, NULL);
+	} else if (s->siht)
+		si_destroy(s->siht, NULL);
+	s->siht = NULL;
+	if (s->fp->destroy)
+		s->fp->destroy(s);
+	bzero(s, sizeof(*s));
+	free(obj, M_DUMMYNET);
+	printf("<<< %s done sched %d destroyed\n", __FUNCTION__, i);
+	dn_cfg.schk_count--;
+	return DNHT_SCAN_DEL;
+}
+
+/*
+ * called on a 'sched X delete' command. Deletes a single scheduler.
+ * This is done by removing from the schedhash, unlinking all
+ * flowsets and deleting their traffic.
+ */
+static int
+delete_schk(int i)
+{
+	struct new_schk *s;
+
+	s = dn_ht_find(dn_cfg.schedhash, i, DNHT_REMOVE, NULL);
+	printf("%s sched %d %p\n", __FUNCTION__, i, s);
+	if (!s)
+		return EINVAL;
+	/* detach flowsets, delete traffic */
+	schk_delete_cb(s, (void*)(uintptr_t)DN_DELETE);
+	delete_fs(i + DN_MAX_ID);	/* remove internal pipe */
+	return 0;
+}
+
 /* callback to flush credit for the pipe */
 static int
 reset_credit(void *_si, void *arg)
@@ -570,39 +698,6 @@ schk_reset_credit(struct new_schk *s)
 		reset_credit(s->siht, NULL);
 }
 
-/*
- * Callback for sched delete. Notify all attached flowsets to
- * detach from the scheduler, destroy the internal flowset, and
- * all instances.
- * arg is 0 (only detach flowsets and destroy instances)
- * DN_DELETE (detach & delete queues, delete schk)
- * or DN_DELETE_FS (delete queues and flowsets, delete schk)
- */
-static int
-schk_delete_cb(void *obj, void *arg)
-{
-	struct new_schk *s = obj;
-
-	printf("+++ %s sched %d arg %d\n", __FUNCTION__, s->sch.sched_nr, (int)arg);
-	if (0 && arg && s->fs) {
-		/* remove the internal flowset from the hashtab */
-		dn_ht_find(dn_cfg.fshash, s->fs->fs.fs_nr, DNHT_REMOVE, NULL);
-	}
-	fsk_detach_list(&s->fsk_list, arg ? DN_DELETE : 0);
-	/* we should not have any flowset pointing to us now */
-	if (s->sch.flags & DN_HAVE_MASK) {
-		dn_ht_scan(s->siht, si_destroy, NULL);
-	} else if (s->siht)
-		si_destroy(s->siht, NULL);
-	s->siht = NULL;
-	if (arg) {
-		bzero(s, sizeof(*s));
-		free(obj, M_DUMMYNET);
-		dn_cfg.schk_count--;
-		return HEAP_SCAN_DEL;
-	} else
-		return 0;
-}
 /*--- end of schk hashtable support ---*/
 
 static int
@@ -628,6 +723,7 @@ struct copy_args {
 	char *end;
 	int flags;
 	int type;
+	int extra;	/* extra filtering */
 };
 
 static int
@@ -639,13 +735,13 @@ copy_data_helper(void *_o, void *_arg)
 		struct new_schk *s = _o;
 		if (a->flags & DN_C_PIPE) {
 			if (copy_obj(a->start, a->end, &s->pipe))
-				return HEAP_SCAN_END;
+				return DNHT_SCAN_END;
 			if (s->fs && copy_obj(a->start, a->end, &s->fs->fs))
-				return HEAP_SCAN_END;
+				return DNHT_SCAN_END;
 		}
 		if (a->flags & DN_C_SCH) {
 			if (copy_obj(a->start, a->end, &s->sch))
-				return HEAP_SCAN_END;
+				return DNHT_SCAN_END;
 		}
 		if (a->flags & DN_C_SCH_INST) {
 			printf("XXX todo: scan sched instances\n");
@@ -655,44 +751,14 @@ copy_data_helper(void *_o, void *_arg)
 		struct new_fsk *fs = _o;
 		struct new_fs *ufs =
 		    (struct new_fs *)(*a->start);
-		if (copy_obj(a->start, a->end, &fs->fs))
-			return HEAP_SCAN_END;
-		ufs->oid.id = fs->refcnt;
-	}
-	return 0;
-}
-
-
-
-/*
- * only called in the DN_MULTIQUEUE CASE so we can handle errors
- * in a better way.
- */
-struct new_queue *
-ipdn_q_find(struct new_fsk *fs, struct new_sch_inst *si,
-	struct ipfw_flow_id *id)
-{
-	struct new_queue template;
-	template.si = si;
-	template.fs = fs;
-
-	if (fs->fs.flags & DN_HAVE_MASK) {
-		if (fs->_qht == NULL) {
-			fs->_qht = dn_ht_init(NULL, fs->fs.buckets,
-				offsetof(struct new_queue, q_next),
-				q_hash, q_match, q_new);
-			if (fs->_qht == NULL)
-				return NULL;
-			fs->kflags &= ~DN_QHT_IS_Q;
+		/* if extra is set, only copy unlinked ones */
+		if (a->extra == 0 || fs->sched == NULL) {
+			if (copy_obj(a->start, a->end, &fs->fs))
+				return DNHT_SCAN_END;
+			ufs->oid.id = fs->refcnt;
 		}
-		return dn_ht_find(fs->_qht, (uintptr_t)id,
-			DNHT_INSERT, &template);
-	} else {
-		if (fs->_qht == NULL)
-			fs->_qht = q_new(0, 0, &template);
-		fs->kflags |= DN_QHT_IS_Q;
-		return (struct new_queue *)fs->_qht;
 	}
+	return 0;
 }
 
 static inline struct new_schk *
@@ -785,6 +851,8 @@ config_pipe(struct new_pipe *p, struct d
 		return EINVAL;
 	    }
 	    /* copy all parameters */
+	    s->pipe.oid = p->oid;
+	    s->pipe.pipe_nr = i;
 	    s->pipe.delay = p->delay;
 	    s->pipe.bandwidth = p->bandwidth;
 	    s->pipe.burst = p->burst;
@@ -839,8 +907,10 @@ config_fs(struct new_fs *nfs, struct dn_
 		if (fs == NULL)
 			break;
 		dn_cfg.id++;
-		if (bcmp(&fs->fs, nfs, sizeof(*nfs)) == 0)
+		if (bcmp(&fs->fs, nfs, sizeof(*nfs)) == 0) {
+			printf("%s no change\n", __FUNCTION__);
 			break; /* no change, nothing to do */
+		}
 		s = locate_scheduler(nfs->sched_nr);
 /* XXX TODO
 Configuration and reconfiguration handling.
@@ -900,15 +970,19 @@ A flowset with fs->sched != NULL and wit
 /*
  * configure a scheduler and its FIFO variant.
  * For !MULTIQUEUE schedulers, also set up the flowset.
+ *
+ * On reconfigurations (detected because s->fp is set),
+ * detach existing flowsets preserving traffic, preserve pipe,
+ * and delete the old scheduler creating a new one.
  */
 static int
 config_sched(struct new_sch *_nsch, struct dn_id *arg)
 {
 	struct new_schk *s;
 	struct schk_new_arg a; /* argument for schk_new */
-	int i, notify_fs = 0;
+	int i;
+	struct new_pipe p;	/* copy of oldpipe */
 
-	printf("%s start\n", __FUNCTION__);
 	a.sch = _nsch;
 	if (a.sch->oid.len != sizeof(*a.sch)) {
 		printf("%s: bad sched len\n", __FUNCTION__);
@@ -918,6 +992,7 @@ config_sched(struct new_sch *_nsch, stru
 	if (i <= 0 || i >= DN_MAX_ID)
 		return EINVAL;
 	/* XXX other sanity checks */
+	bzero(&p, sizeof(0));
 	DUMMYNET_LOCK();
 again: /* run twice, for wfq and fifo */
 	a.fp = find_sched_type(a.sch->oid.subtype, a.sch->type);
@@ -929,25 +1004,29 @@ again: /* run twice, for wfq and fifo */
 	}
 	a.sch->oid.subtype = a.fp->type;
 	s = dn_ht_find(dn_cfg.schedhash, i, DNHT_INSERT, &a);
+	printf("%s start i %d ty %s -> %s\n",
+		__FUNCTION__, i, a.sch->type,
+			s ? (s->fp?"old":"new"):"none");
 	if (s == NULL) {
 		DUMMYNET_UNLOCK();
 		printf("cannot allocate scheduler\n");
 		return ENOMEM;
 	}
+	/* preserve existing pipe if any */
+	if (p.pipe_nr)
+		s->pipe = p;
+	p.pipe_nr = 0;
 	dn_cfg.id++;
-	if (s->fp != NULL) {
-		/* Already existing -- remove from the heaps,
-		 * and detach flowsets from
-		 * the old one almost as in sched_delete, but
-		 * preserve traffic.
-		 * XXX what about the internal queue ?
-		 */
+	if (s->fp != NULL) { /* already existing. */
+		/* Detach flowsets, preserve pipe&queues. */
 		printf("sched %d type changed from %s to %s\n",
 			i, s->fp->name, a.fp->name);
+		p = s->pipe;
+		/* remove from the hash */
+		dn_ht_find(dn_cfg.schedhash, i, DNHT_REMOVE, NULL);
 		schk_delete_cb(s, NULL);
 		printf("schk_delete_cb done\n");
-		notify_fs = 1;
-		/* now we have nothing pointing to us */
+		goto again;
 	}
 	/* complete initialization */
 	s->sch = *a.sch;
@@ -969,7 +1048,7 @@ again: /* run twice, for wfq and fifo */
 	}
 	/* call init function after the flowset is created */
 	if (s->fp->config)
-		s->fp->config(s, 1);
+		s->fp->config(s);
 	update_fs(s);
 	if (i < DN_MAX_ID) { /* update the FIFO instance */
 		i += DN_MAX_ID;
@@ -1042,53 +1121,6 @@ config_profile(struct new_profile *pf, s
 	return 0;
 }
 
-/*
- * called on 'queue X delete' -- removes the flowset from fshash,
- * deletes all queues for the flowset, and removes the flowset.
- */
-static int
-delete_fs(int i)
-{
-	struct new_fsk_head *h;
-	struct new_fsk *fs;
-
-	fs = dn_ht_find(dn_cfg.fshash, i, DNHT_REMOVE, NULL);
-	printf("%s fs %d found %p\n", __FUNCTION__, i, fs);
-	if (fs == NULL)
-		return EINVAL;
-
-	/* find the container list */
-	h = fs->sched ? &fs->sched->fsk_list : &dn_cfg.fsu;
-	SLIST_REMOVE(h, fs, new_fsk, sch_chain);
-	dn_cfg.fsk_count--;
-	qht_delete(fs, 1);	/* get rid of the queues */
-	/* XXX possibly notify the event to the scheduler */
-	if (fs->sched && fs->sched->fp->free_fsk)
-		fs->sched->fp->free_fsk(fs);
-	fs->sched = NULL;
-	free(fs, M_DUMMYNET);
-	return 0;
-}
-
-/*
- * called on a 'sched X delete' command. Deletes a single scheduler.
- * This is done by removing from the schedhash, unlinking all
- * flowsets and deleting their traffic.
- */
-static int
-delete_schk(int i)
-{
-	struct new_schk *s;
-
-	s = dn_ht_find(dn_cfg.schedhash, i, DNHT_REMOVE, NULL);
-	printf("%s sched %d %p\n", __FUNCTION__, i, s);
-	if (!s)
-		return EINVAL;
-	/* detach flowsets, delete traffic */
-	schk_delete_cb(s, (void*)(uintptr_t)DN_DELETE);
-	delete_fs(i + DN_MAX_ID);	/* remove internal pipe */
-	return 0;
-}
 
 /*
  * Delete all objects:
@@ -1098,10 +1130,12 @@ dummynet_flush(void)
 {
 
 	DUMMYNET_LOCK();
-	/* all schedulers and related pipes/queues/flowsets */
+	/* delete all schedulers and related pipes/queues/flowsets */
 	dn_ht_scan(dn_cfg.schedhash, schk_delete_cb,
 		(void *)(uintptr_t)DN_DELETE_FS);
-	/* all remaining (unlinked) flowsets */
+	/* delete all remaining (unlinked) flowsets */
+	printf("%s still %d unlinked fs\n", __FUNCTION__, dn_cfg.fsk_count);
+	dn_ht_free(dn_cfg.fshash, DNHT_REMOVE);
 	fsk_detach_list(&dn_cfg.fsu, DN_DELETE_FS);
 	/* Reinitialize system heap... */
 	heap_init(&dn_cfg.evheap, 16, offsetof(struct dn_id, id));
@@ -1211,6 +1245,13 @@ compute_space(struct dn_id *cmd, int *to
 		break;
 	}
 	*to_copy = x;
+	printf("have %d.%d sched %d, %d.%d pipes %d, %d.%d flows %d, "
+		"%d.%d si %d, %d.%d queues %d\n",
+		dn_cfg.schk_count, sizeof(struct new_sch), DN_SCH,
+		dn_cfg.schk_count, sizeof(struct new_pipe), DN_PIPE,
+		dn_cfg.fsk_count, sizeof(struct new_fs), DN_FS,
+		dn_cfg.si_count, sizeof(struct new_inst), DN_SCH_I,
+		dn_cfg.queue_count, sizeof(struct new_queue), DN_QUEUE);
 	if (x & DN_C_SCH)
 		need += dn_cfg.schk_count * sizeof(struct new_sch);
 	if (x & DN_C_FS)
@@ -1278,9 +1319,15 @@ dummynet_get(struct sockopt *sopt)
 		a.start = &buf;
 		a.end = end;
 		a.flags = to_copy;
+		a.extra = 0;
+		printf("copy schedulers %d)\n",
+			dn_ht_entries(dn_cfg.schedhash));
 		a.type = DN_SCH;
 		dn_ht_scan(dn_cfg.schedhash, copy_data_helper, &a);
+		printf("copy unlinked flowsets %d\n",
+			dn_ht_entries(dn_cfg.fshash));
 		a.type = DN_FS;
+		a.extra = 1;
 		dn_ht_scan(dn_cfg.fshash, copy_data_helper, &a);
 	}
 	DUMMYNET_UNLOCK();


More information about the svn-src-user mailing list