svn commit: r202625 - in user/luigi/ipfw3-head/sys/netinet: . ipfw

Luigi Rizzo luigi at FreeBSD.org
Tue Jan 19 13:33:54 UTC 2010


Author: luigi
Date: Tue Jan 19 13:33:54 2010
New Revision: 202625
URL: http://svn.freebsd.org/changeset/base/202625

Log:
  revise the detach/reconfigure paths

Modified:
  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_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/ip_dummynet.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h	Tue Jan 19 13:33:31 2010	(r202624)
+++ user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h	Tue Jan 19 13:33:54 2010	(r202625)
@@ -259,7 +259,5 @@ flow using a number of heaps defined int
 #define DN_QSIZE_IS_BYTES	0x0008	/* queue size is measured in bytes */
 #define DN_NOERROR		0x0010	/* do not report ENOBUFS on drops  */
 #define	DN_HAS_PROFILE		0x0020	/* the pipe has a delay profile. */
-#define DN_IS_PIPE		0x4000
-#define DN_IS_QUEUE		0x8000
 
 #endif /* _IP_DUMMYNET_H */

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c	Tue Jan 19 13:33:31 2010	(r202624)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c	Tue Jan 19 13:33:54 2010	(r202625)
@@ -386,6 +386,8 @@ dn_ht_find(struct dn_ht *ht, uintptr_t k
 	int i;
 	void **pp, *p;
 
+	if (ht == NULL)	/* easy on an empty hash */
+		return NULL;
 	i = (ht->buckets == 1) ? 0 :
 		(ht->hash(key, flags, arg) % ht->buckets);
 	// printf("%s key %p in bucket %d\n", __FUNCTION__, (void *)key, i);

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h	Tue Jan 19 13:33:31 2010	(r202624)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h	Tue Jan 19 13:33:54 2010	(r202625)
@@ -94,9 +94,12 @@ struct dn_sched {
 	 *
 	 * new_queue	called to set the per-queue parameters,
 	 *	e.g. S and F, adjust sum of weights in the parent, etc.
+	 *	If the queue has packets in it, add them to the scheduler
+	 *	as well.
 	 *
 	 * free_queue	actions related to a queue removal, e.g. undo
-	 *	all the above.
+	 *	all the above. If the queue has data in it, also remove
+	 *	from the scheduler. This can e.g. happen during a reconfigure.
 	 */
 	int (*enqueue)(struct new_sch_inst *, struct new_queue *,
 		struct mbuf *);
@@ -120,7 +123,7 @@ struct dn_sched {
  * if do_free is set, propagate to the flowset and destroy it
  * if the refcount becomes 0
  */
-int dn_delete_queue(void *, void *do_free);
+struct new_queue *dn_delete_queue(struct new_queue *, int do_free);
 int dn_enqueue(struct new_queue *q, struct mbuf* m, int drop);
 
 /*
@@ -141,7 +144,7 @@ dn_dequeue(struct new_queue *q)
 		q->si->ni.len_bytes -= m->m_pkthdr.len;
 	}
 	if (q->mq.head == NULL && q->fs && q->fs->kflags & DN_DELETE)
-		dn_delete_queue(q, (void *)1 /* free if possible */);
+		(void)dn_delete_queue(q, 1 /* free if possible */);
 	return m;
 }
 

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 13:33:31 2010	(r202624)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_wf2q.c	Tue Jan 19 13:33:54 2010	(r202625)
@@ -111,15 +111,13 @@ wf2qp_enqueue(struct new_sch_inst *_si, 
     struct wf2qp_si *si = (struct wf2qp_si *)(_si + 1);
     struct wf2qp_queue *alg_fq;
     uint64_t len = m->m_pkthdr.len;
-    int q_was_idle;
 
-    q_was_idle = (q->mq.head == NULL);
-
-    if (dn_enqueue(q, m, 0)) /* packet was dropped */
-        return 1;
-
-    if (!q_was_idle)
-        return 0;
+    if (m != q->mq.head) {
+	if (dn_enqueue(q, m, 0)) /* packet was dropped */
+	    return 1;
+	if (m != q->mq.head)	/* queue was already busy */
+	    return 0;
+    }
 
     /* If reach this point, queue q was idle */ 
     alg_fq = (struct wf2qp_queue *)(q+1);
@@ -238,8 +236,8 @@ wf2qp_new_sched(struct new_sch_inst *_si
 
 	/* only idle-heap supports extract from middle */
 	if (heap_init(&si->idle_heap, 16, ofs) ||
-	    heap_init(&si->sch_heap, 16, -1) ||
-	    heap_init(&si->ne_heap, 16, -1)) {
+	    heap_init(&si->sch_heap, 16, ofs) ||
+	    heap_init(&si->ne_heap, 16, ofs)) {
 		heap_free(&si->ne_heap);
 		heap_free(&si->sch_heap);
 		heap_free(&si->idle_heap);
@@ -279,6 +277,9 @@ wf2qp_new_queue(struct new_queue *_q)
 	_q->ni.oid.subtype = DN_SCHED_WF2QP;
 	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);
+	}
 	return 0;
 }
 
@@ -286,11 +287,24 @@ 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);
     
+	printf("%s called\n", __FUNCTION__);
 	/* If the queue was valid, decrement the sum value */
-	if (alg_fq->S != alg_fq->F + 1) {
-		struct wf2qp_si *si = (struct wf2qp_si *)(q->si + 1);
-		si->sum -= q->fs->fs.weight;
+	if (alg_fq->S == alg_fq->F + 1)
+		return 0;	/* nothing to do, not in any heap */
+	/* decrement the sum of weights */
+	si->sum -= q->fs->fs.weight;
+
+	/* extract from the heap. Note that we may need to adjust V
+	 * to make sure the invariants hold.
+	 */
+	if (q->mq.head == NULL) {
+		heap_extract(&si->idle_heap, q);
+	} else if (DN_KEY_LT(si->V, alg_fq->S)) {
+		heap_extract(&si->ne_heap, q);
+	} else {
+		heap_extract(&si->sch_heap, q);
 	}
 	return 0;
 }

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 13:33:31 2010	(r202624)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c	Tue Jan 19 13:33:54 2010	(r202625)
@@ -545,6 +545,7 @@ tag_mbuf(struct mbuf *m, int dir, struct
 	return 0;
 }
 
+
 /*
  * dummynet hook for packets.
  * We use the argument to locate the flowset fs and the sched_set sch
@@ -588,17 +589,7 @@ dummynet_io(struct mbuf **m0, int dir, s
 	 * We cannot pass si as an argument :(
 	 */
 	if (fs->sched->fp->flags & DN_MULTIQUEUE) {
-		struct new_queue template;
-		template.si = si;
-		template.fs = fs;
-		if (fs->fs.flags & DN_HAVE_MASK) {
-			q = dn_ht_find(fs->qht, (uintptr_t)&(fwa->f_id),
-				DNHT_INSERT, &template);
-		} else { /* qht is simply a queue */
-			if (fs->qht == NULL)
-				fs->qht = q_new(0, 0, &template);
-			q = (struct new_queue *)fs->qht;
-		}
+		q = ipdn_q_find(fs, si, &(fwa->f_id));
 		if (q == 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 13:33:31 2010	(r202624)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h	Tue Jan 19 13:33:54 2010	(r202625)
@@ -137,7 +137,7 @@ struct new_fsk { /* kernel side of a flo
 	/* hash table of queues. XXX if we have no flow_mask we could
 	 * avoid the hash table and just allocate one queue.
 	 */
-	struct dn_ht	*qht;
+	struct dn_ht	*_qht;
 	struct new_schk *sched;		/* Sched we are linked to */
 	SLIST_ENTRY(new_fsk) sch_chain;	/* list of fsk attached to sched */
 	void *sched_info;	/* scheduler-specific info */
@@ -207,9 +207,11 @@ struct new_sch_inst {
 /* kernel-side flags */
 enum {
 	DN_DELETE	= 0x0004, /* destroy when refcnt=0 */
+	DN_DELETE_FS	= 0x0008, /* destroy when refcnt=0 */
 	DN_ACTIVE	= 0x0010, /* object is in evheap */
 	DN_F_DLINE	= 0x0020, /* object is a delay line */
 	DN_F_SCHI	= 0x0030, /* object is a sched.instance */
+	DN_QHT_IS_Q	= 0x0100, /* in flowset, qht is a single queue */
 };
 
 extern struct dn_parms dn_cfg;
@@ -218,8 +220,9 @@ int dummynet_io(struct mbuf **, int , st
 void dummynet_task(void *context, int pending);
 void dn_reschedule(void);
 
-struct new_sch_inst *ipdn_si_find(struct new_schk *s, struct ipfw_flow_id *id);
-void * q_new(uintptr_t key, int flags, void *arg);
+struct new_queue *ipdn_q_find(struct new_fsk *fs, struct new_sch_inst *si,
+        struct ipfw_flow_id *id);
 
+struct new_sch_inst *ipdn_si_find(struct new_schk *s, struct ipfw_flow_id *id);
 
 #endif /* _IP_DN_PRIVATE_H */

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c	Tue Jan 19 13:33:31 2010	(r202624)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c	Tue Jan 19 13:33:54 2010	(r202625)
@@ -230,7 +230,7 @@ q_match(void *obj, uintptr_t key, int fl
 /*
  * create a new queue instance for the given 'key'.
  */
-void *
+static void *
 q_new(uintptr_t key, int flags, void *arg)
 {   
 	struct new_queue *q, *template = arg;
@@ -410,90 +410,92 @@ fsk_new(uintptr_t key, int flags, void *
 	}
 	return fs;
 }
+/*----- end of flowset hashtable support -------------*/
 
-static int schk_del_cb(void *obj, void *arg);
 /*
- * delete a flowset. Mark as delete, and free all when no refcount.
- * Return 1 if freed, o otherwise.
- * Removal from the hashtable must be done outside this function.
+ * Delete a queue. The version for callbacks is called q_delete_cb().
+ * Call the 'free_queue' routine on the scheduler.
+ * If do_free is set, also free the packets.
  */
-static void
-fsk_destroy(struct new_fsk *fs, int do_free)
+struct new_queue *
+dn_delete_queue(struct new_queue *q, int do_free)
 {
-	struct new_fsk_head *h;
+	struct new_fsk *fs = q->fs;
 
-	fs->kflags |= DN_DELETE;
-	if (fs->refcnt != 0)
-		return;
-	/* 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--;
-	if (fs->sched && fs->sched->fp->free_fsk)
-		fs->sched->fp->free_fsk(fs);
-	/* XXX possibly notify the event to the scheduler */
-	if (fs->sched != NULL && (fs->sched->kflags & DN_DELETE) &&
-	    SLIST_FIRST(&fs->sched->fsk_list) == NULL) {
-		printf("scheduler %p should be deleted\n", fs->sched);
-		dn_ht_find(dn_cfg.schedhash, (uintptr_t)(fs->sched),
-		    DNHT_KEY_IS_OBJ | DNHT_MATCH_PTR | DNHT_REMOVE, NULL);
-		schk_del_cb(fs->sched, NULL);
-	}
-		
-	fs->sched = NULL;
-	if (do_free) {
-		if (fs->qht) /* only if DN_HAVE_MASK */
-			dn_ht_free(fs->qht, 0);
-		free(fs, M_DUMMYNET);
-	}
+	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);
+	if (!do_free)
+		return q;
+	if (q->mq.head)
+		dn_free_pkts(q->mq.head);
+	free(q, M_DUMMYNET);
+	dn_cfg.queue_count--;
+	fs->refcnt--;
+	return NULL;
+}
+
+static int
+q_delete_cb(void *q, void *arg)
+{
+	(void)dn_delete_queue(q, (int)(uintptr_t)arg);
+	return 0;
 }
-/*----- end of flowset hashtable support -------------*/
 
 /*
- * delete the queues in qht, consider the presence of a flow_mask
+ * calls dn_delete_queue/q_delete_cb on all queues,
+ * which notifies the parent scheduler and possibly drains packets.
+ * flags & DN_DELETE: drains queues and destroy qht;
  */
 static void
-delete_qht(struct new_fsk *fs)
+qht_delete(struct new_fsk *fs, int flags)
 {
-	if (fs->fs.flags & DN_HAVE_MASK)
-		dn_ht_scan(fs->qht, dn_delete_queue, NULL);
-	else {
-		dn_delete_queue(fs->qht, NULL);
-		fs->qht = NULL;
+	printf("+++ %s fs %d start\n", __FUNCTION__, fs->fs.fs_nr);
+	if (!fs->_qht)
+		return;
+	if (fs->kflags & DN_QHT_IS_Q) {
+		fs->_qht = (struct dn_ht *)dn_delete_queue((struct new_queue *)(fs->_qht), flags);
+	} else {
+		dn_ht_scan(fs->_qht, q_delete_cb, (void *)flags);
+		if (flags & DN_DELETE) {
+			dn_ht_free(fs->_qht, 0);
+			fs->_qht = NULL;
+		}
 	}
 }
 
 /*
- * Destroy all flowsets in a list. Used when deleting a scheduler,
+ * Detach or destroy all flowsets in a list. Used when deleting a scheduler,
  * or for all those in fsunlinked.
- * For 'ipfw queue flush' we need a callback.
- * (for those
+ * int_fs points to an internal flowset which must be handled differently.
+ * flags specifies what to do:
+ * DN_DELETE	flush all queues
+ * DN_DELETE_FS	DN_DELETE + destroy flowset
+ *	DN_DELETE_FS implies DN_DELETE
  */
 static void
-fsk_destroy_list(struct new_fsk_head *h, struct new_fsk *int_fs)
+fsk_detach_list(struct new_fsk_head *h, struct new_fsk *int_fs, int flags)
 {
 	struct new_fsk *fs;
 
+	if (flags & DN_DELETE_FS)
+		flags |= DN_DELETE;
+	printf("+++ %s head %p flags %x\n", __FUNCTION__, h, flags);
 	while ((fs = SLIST_FIRST(h))) {
 		SLIST_REMOVE_HEAD(h, sch_chain);
+		printf("   +++ %s child fs %d\n", __FUNCTION__, fs->fs.fs_nr);
 		if (fs == int_fs) {
 			/* free the internal flowset. */
 			free(fs, M_DUMMYNET);
 			dn_cfg.fsk_count--;
 			continue;
 		}
-		/* drain queues, but pass NULL so the fs is not deleted.
-		 * We cannot destroy it from the callback or it
-		 * would kill the hashtable as well. After the pass,
-		 * refcnt is surely 0.
-		 * If the flowset was marked delete, destroy it.
-		 * otherwise move it to fsunlinked.
-		 */
-		delete_qht(fs);
+		/* detach queues from the scheduler and possibly drain them */
+		qht_delete(fs, flags);
 		fs->sched = NULL;
-		if (fs->kflags & DN_DELETE) {
-			if (fs->qht)
-				dn_ht_free(fs->qht, 0);
+		if (flags & DN_DELETE_FS) {
+			bzero(fs, sizeof(fs));	/* safety */
 			free(fs, M_DUMMYNET);
 		} else {
 			SLIST_INSERT_HEAD(&dn_cfg.fsu, fs, sch_chain);
@@ -501,26 +503,6 @@ fsk_destroy_list(struct new_fsk_head *h,
 	}
 }
 
-/*
- * Delete a queue (helper for the schedulers and callback)
- */
-int
-dn_delete_queue(void *_q, void *do_free)
-{
-	struct new_queue *q = _q;
-	struct new_fsk *fs = q->fs;
-
-	if (q->mq.head)
-		dn_free_pkts(q->mq.head);
-	if (fs && fs->sched->fp->free_queue)
-		fs->sched->fp->free_queue(q);
-	free(q, M_DUMMYNET);
-	dn_cfg.queue_count--;
-	fs->refcnt--;
-	if (fs->refcnt == 0 && fs->kflags & DN_DELETE)
-		fsk_destroy(fs, (int)do_free);
-	return 0;
-}
 
 /* callback to flush credit for the pipe */
 static int
@@ -600,49 +582,69 @@ copy_data_helper(void *_o, void *_arg)
 }
 
 /*
- * Callback for sched delete. Tell all attached flowsets to
- * remove their queues, unlink the flowsets.
+ * 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_del_cb(void *obj, void *arg)
+schk_delete_cb(void *obj, void *arg)
 {
 	struct new_schk *s = obj;
 
-	if (s->fs) {
+	printf("+++ %s sched %d arg %d\n", __FUNCTION__, s->sch.sched_nr, (int)arg);
+	if (arg && s->fs) {
 		/* remove the internal flowset from the hashtab */
 		dn_ht_find(dn_cfg.fshash, s->fs->fs.fs_nr, DNHT_REMOVE, NULL);
-		s->fs->kflags |= DN_DELETE;
 	}
-	fsk_destroy_list(&s->fsk_list, s->fs);
+	fsk_detach_list(&s->fsk_list, s->fs, 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);
-	free(obj, M_DUMMYNET);
-	dn_cfg.schk_count--;
-	return HEAP_SCAN_DEL;
+	if (arg) {
+		free(obj, M_DUMMYNET);
+		dn_cfg.schk_count--;
+		return HEAP_SCAN_DEL;
+	} else
+		return 0;
 }
 
+
 /*
- * Delete all objects:
+ * only called in the DN_MULTIQUEUE CASE so we can handle errors
+ * in a better way.
  */
-static void
-dummynet_flush(void)
-{
-
-	DUMMYNET_LOCK();
-	/* all schedulers and related pipes/queues/flowsets */
-	dn_ht_scan(dn_cfg.schedhash, schk_del_cb, NULL);
-	/* all remaining (unlinked) flowsets */
-	fsk_destroy_list(&dn_cfg.fsu, NULL);
-	/* Reinitialize system heap... */
-	heap_init(&dn_cfg.evheap, 16, offsetof(struct dn_id, id));
-
-	DUMMYNET_UNLOCK();
+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;
+		}
+		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;
+	}
 }
 
-
 static inline struct new_schk *
 locate_scheduler(int i)
 {
@@ -664,6 +666,10 @@ update_fs(struct new_schk *s)
 		SLIST_REMOVE(&dn_cfg.fsu, fs, new_fsk, sch_chain);
 		fs->sched = s;
 		SLIST_INSERT_HEAD(&s->fsk_list, fs, sch_chain);
+		if (!fs->_qht)
+			continue;
+		printf("+++ %s requeue from fs %d to sch %d\n",
+			__FUNCTION__, fs->fs.fs_nr, s->sch.sched_nr);
 	}
 }
 
@@ -780,6 +786,24 @@ config_fs(struct new_fs *nfs, struct dn_
 		dn_cfg.id++;
 		if (bcmp(&fs->fs, nfs, sizeof(*nfs)) == 0)
 			break; /* no change, nothing to do */
+		s = locate_scheduler(nfs->sched_nr);
+/* XXX TODO
+Configuration and reconfiguration handling.
+A new flowset, or one with fs->sched == NULL, has no queues.
+- if it is still unattached we have nothing to do;
+- if s != NULL, remove from unlinked and add to the children
+  of s, possibly creating the hash table (or we can postpone
+  it to when the first packet arrives);
+
+A flowset with fs->sched != NULL and with queues we have two options:
+- if it becomes unlinked, then simply destroy the queues notifying
+  the old scheduler.
+- if it becomes linked, we also need to re-enqueue the packets on
+  the new scheduler.
+  There are some easy cases (e.g. flow_mask unchanged) but
+  in general we should really work on every single packet.
+ */
+  
 		fs->fs = *nfs;	/* update config */
 		/*
 		 * XXX note that if we modify some scheduler-specific
@@ -787,8 +811,12 @@ config_fs(struct new_fs *nfs, struct dn_
 		 * scheduler otherwise things might go really badly,
 		 * such as sum-of-weights mismatches.
 		 */
-		s = locate_scheduler(nfs->sched_nr);
 		if (fs->sched != NULL) {
+			/* XXX TODO: if the scheduler does not exist
+			 * anymore, then all queues should be drained.
+			 * If there is a new scheduler, then move
+			 * queues from the old to the new one.
+			 */
 			/* we had a scheduler before, let the flowset
 			 * die and create a new one with the new
 			 * parameters.
@@ -805,14 +833,7 @@ config_fs(struct new_fs *nfs, struct dn_
 		SLIST_REMOVE(&dn_cfg.fsu, fs, new_fsk, sch_chain);
 		fs->sched = s;
 		SLIST_INSERT_HEAD(&s->fsk_list, fs, sch_chain);
-		/* only create the hash table if the scheduler supports
-		 * multiple queues and we have a flow mask.
-		 */
-		if (s->fp->flags & DN_MULTIQUEUE &&
-			    fs->fs.flags & DN_HAVE_MASK)
-			fs->qht = dn_ht_init(NULL, nfs->buckets,
-				offsetof(struct new_queue, q_next),
-				q_hash, q_match, q_new);
+		/* _qht is initialized on first use */
 		if (s->fp->new_fsk)
 			s->fp->new_fsk(fs);
 	} while (0);
@@ -830,7 +851,6 @@ config_sched(struct new_sch *_nsch, stru
 {
 	struct new_schk *s;
 	struct schk_new_arg a; /* argument for schk_new */
-	struct new_fsk_head *pending = NULL;
 	int i, notify_fs = 0;
 
 	a.sch = _nsch;
@@ -859,27 +879,21 @@ again: /* run twice, for wfq and fifo */
 		return ENOMEM;
 	}
 	dn_cfg.id++;
-	notify_fs = 0;
-	if (s->fp == NULL) { /* new scheduler, nothing to clean up */
-		notify_fs = 1;
-	} else if (s->fp != a.fp) {
-		printf("sched %d type changed from %s to %s"
-			" let it drain and reallocate\n",
-			i, s->fp->name, a.fp->name);
-		/* mark delete so it won't be matched.
-		 * XXX todo: make it die when its queues are done.
-		 * XXX otherwise do a real delete.
-		 * XXX Reconfiguration should be done differently,
-		 * removing packets from the old scheduler and
-		 * requeueing to the new one. Otherwise we can have
-		 * reordering and unwanted effects.
+	if (s->fp != NULL) {
+		/* in all other cases, 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 ?
 		 */
-		s->kflags |= DN_DELETE;
+		printf("sched %d type changed from %s to %s\n",
+			i, s->fp->name, a.fp->name);
+		schk_delete_cb(s, NULL);
 		notify_fs = 1;
-		pending = &s->fsk_list;
-		goto again;
+		/* now we have nothing pointing to us */
 	}
 	/* complete initialization */
+	s->sch = *a.sch;
 	s->fp = a.fp;
 	s->cfg = arg;
 	// XXX schk_reset_credit(s);
@@ -899,20 +913,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);
-	if (pending) {
-		struct new_fsk *fs;
-		/* XXX should do the requeue here */
-		/* mark and clone flowsets for the old scheduler */
-		SLIST_FOREACH(fs, pending, sch_chain) {
-			int dying = fs->kflags & DN_DELETE;
-			fs->kflags |= DN_DELETE;
-			if (!dying)	/* clone if necessary */
-				config_fs(&fs->fs, NULL, 1 /* locked */);
-		}
-		pending = NULL;
-	}
-	if (notify_fs)
-		update_fs(s);
+	update_fs(s);
 	if (i < DN_MAX_ID) { /* update the FIFO instance */
 		i += DN_MAX_ID;
 		a.sch->sched_nr = i;
@@ -983,35 +984,70 @@ 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
-del_fs(int i)
+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;
-	// XXX not sure if we want to kill the queues now
-	if (0 && fs->qht)
-		dn_ht_scan(fs->qht, dn_delete_queue, NULL);
-	fsk_destroy(fs, 1 /* do free the object */);
+
+	/* 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
-del_schk(int i)
+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) {
-		schk_del_cb(s, NULL);
-		return 0;
-	} else {
+	if (!s)
 		return EINVAL;
-	}
+	/* detach flowsets, delete traffic */
+	schk_delete_cb(s, (void*)(uintptr_t)DN_DELETE);
+	return 0;
+}
+
+/*
+ * Delete all objects:
+ */
+static void
+dummynet_flush(void)
+{
+
+	DUMMYNET_LOCK();
+	/* 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 */
+	fsk_detach_list(&dn_cfg.fsu, NULL, DN_DELETE_FS);
+	/* Reinitialize system heap... */
+	heap_init(&dn_cfg.evheap, 16, offsetof(struct dn_id, id));
+
+	DUMMYNET_UNLOCK();
 }
 
 /*
@@ -1025,7 +1061,7 @@ static int
 do_config(void *p, int l)
 {
 	struct dn_id *next, *o;
-	int err = 0;
+	int err = 0, err2 = 0;
 	struct dn_id *arg = NULL;
 
 	for (o = p; l >= sizeof(*o); o = next) {
@@ -1050,9 +1086,12 @@ do_config(void *p, int l)
 			switch (o->subtype) {
 			case DN_PIPE:
 				/* delete base and derived schedulers */
-				if ( (err = del_schk(o->id)) )
-					break;
-				err = del_schk(o->id + DN_MAX_ID);
+				DUMMYNET_LOCK();
+				err = delete_schk(o->id);
+				err2 = delete_schk(o->id + DN_MAX_ID);
+				DUMMYNET_UNLOCK();
+				if (!err)
+					err = err2;
 				break;
 
 			default:
@@ -1063,7 +1102,7 @@ do_config(void *p, int l)
 
 			case DN_FS:
 				err = (o->id < 1 || o->id >= DN_MAX_ID) ?
-					EINVAL : del_fs(o->id) ;
+					EINVAL : delete_fs(o->id) ;
 				break;
 			}
 			break;


More information about the svn-src-user mailing list