Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 19 Jan 2010 23:03:08 +0000 (UTC)
From:      Luigi Rizzo <luigi@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r202660 - in user/luigi/ipfw3-head: sbin/ipfw sys/netinet/ipfw
Message-ID:  <201001192303.o0JN38Q3033399@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: luigi
Date: Tue Jan 19 23:03:08 2010
New Revision: 202660
URL: http://svn.freebsd.org/changeset/base/202660

Log:
  fix reconfiguration (still dropping packets in the process)

Modified:
  user/luigi/ipfw3-head/sbin/ipfw/dummynet.c
  user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h
  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	Tue Jan 19 22:44:29 2010	(r202659)
+++ user/luigi/ipfw3-head/sbin/ipfw/dummynet.c	Tue Jan 19 23:03:08 2010	(r202660)
@@ -1104,8 +1104,10 @@ end_mask:
 			p->bandwidth = 0;
 	}
 	if (fs) {
+#if 0		/* XXX accept a 0 scheduler to keep the default */
 		if (fs->sched_nr == 0)
 			errx(EX_DATAERR, "sched must be > 0");
+#endif
 
 	    if (fs->flags & DN_QSIZE_IS_BYTES) {
 		size_t len;

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h	Tue Jan 19 22:44:29 2010	(r202659)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h	Tue Jan 19 23:03:08 2010	(r202660)
@@ -125,7 +125,7 @@ struct dn_sched {
  * if the refcount becomes 0
  */
 void dn_free_pkts(struct mbuf *mnext);
-struct new_queue *dn_delete_queue(struct new_queue *, int do_free);
+void dn_delete_queue(struct new_queue *, int do_free);
 int dn_enqueue(struct new_queue *q, struct mbuf* m, int drop);
 
 /*
@@ -145,8 +145,6 @@ dn_dequeue(struct new_queue *q)
 		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 */);
 	return m;
 }
 

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 22:44:29 2010	(r202659)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c	Tue Jan 19 23:03:08 2010	(r202660)
@@ -602,7 +602,7 @@ dummynet_io(struct mbuf **m0, int dir, s
 	if (fs->sched->fp->enqueue(si, q, m)) {
 		printf("%s dropped by enqueue\n", __FUNCTION__);
 		/* packet was dropped by enqueue() */
-		*m0 = NULL;
+		m = *m0 = NULL;
 		goto dropit;
 	}
 
@@ -646,7 +646,8 @@ done:
 dropit:
 	io_pkt_drop++;
 	DUMMYNET_UNLOCK();
-	FREE_PKT(m);
+	if (m)
+		FREE_PKT(m);
 	*m0 = NULL;
 	return (fs && (fs->fs.flags & DN_NOERROR)) ? 0 : ENOBUFS;
 }

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 22:44:29 2010	(r202659)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h	Tue Jan 19 23:03:08 2010	(r202660)
@@ -52,6 +52,18 @@ SLIST_HEAD(new_fsk_head, new_fsk);
 SLIST_HEAD(new_queue_head, new_queue);
 SLIST_HEAD(dn_sched_head, dn_sched);
 
+struct mq {	/* a basic queue of packets*/
+        struct mbuf *head, *tail;
+};
+
+static inline void
+set_oid(struct dn_id *o, int type, int len)
+{
+        o->type = type;
+        o->len = len;
+        o->subtype = 0;
+};
+
 /*
  * configuration and global data for a dummynet instance
  *
@@ -82,27 +94,23 @@ struct dn_parms {
 	int	fsk_count;
 	int	queue_count;
 
-	/* flowsets and schedulers are in hash tables, whose size
-	 * is programmable. fshash is looked up at every packet arrival
+	/* flowsets and schedulers are in hash tables, with 'hash_size'
+	 * buckets. fshash is looked up at every packet arrival
 	 * so better be generous if we expect many entries.
 	 */
 	struct dn_ht	*fshash;
 	struct dn_ht	*schedhash;
 	/* list of flowsets without a scheduler -- use sch_chain */
-	struct new_fsk_head	fsu;
+	struct new_fsk_head	fsu;	/* list of unlinked flowsets */
 	struct dn_sched_head	schedlist;	/* list of algorithms */
-};
 
-static inline void
-set_oid(struct dn_id *o, int type, int len)
-{
-	o->type = type;
-	o->len = len;
-	o->subtype = 0;
-};
-
-struct mq {	/* a basic queue of packets*/
-        struct mbuf *head, *tail;
+	/* if the upper half is busy doing something long,
+	 * can set the busy flag and we will enqueue packets in
+	 * a queue for later processing.
+	 */
+	int	busy;
+	struct	mq	pending;
+	
 };
 
 /*
@@ -116,31 +124,23 @@ struct delay_line {
 };
 
 /*
- * The kernel side of a flowset. In addition to the user parameters
- * and kernel flags, it is linked in a hash table of flowsets,
- * and in a list of children of their parent scheduler.
- * It also contains a hash table of children queues (or one, if
- * there is no flow_mask).
- * When we remove a flowset, mark as DN_DELETE so it can go away
- * when the hash table will be empty.
- * XXX refcnt is redundant, the info is already in qht->entries
- * If we want to add scheduler-specific parameters, we need to
+ * The kernel side of a flowset. It is linked in a hash table
+ * of flowsets, and in a list of children of their parent scheduler.
+ * qht is either the queue or (if HAVE_MASK) a hash table queues.
+ * XXX If we want to add scheduler-specific parameters, we need to
  * put them in external storage because the scheduler may not be
  * available when the fsk is created.
  */
 struct new_fsk { /* kernel side of a flowset */
 	struct new_fs fs;
 	SLIST_ENTRY(new_fsk) fsk_next;	/* hash chain list */
-	int kflags;			/* kernel-side flags */
 	int refcnt;		/* entries in qht */
 
-	/* hash table of queues. XXX if we have no flow_mask we could
-	 * avoid the hash table and just allocate one queue.
-	 */
+	/* hash table of queues, or just single queue */
 	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 */
+	// void *sched_info;	/* scheduler-specific info */
 };
 
 /*

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c	Tue Jan 19 22:44:29 2010	(r202659)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c	Tue Jan 19 23:03:08 2010	(r202660)
@@ -257,12 +257,12 @@ q_new(uintptr_t key, int flags, void *ar
 }
 
 /*
- * 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.
+ * Notify schedulers that a queue is going away.
+ * If (flags & DN_DELETE), also free the packets.
+ * The version for callbacks is called q_delete_cb().
  */
-struct new_queue *
-dn_delete_queue(struct new_queue *q, int do_free)
+void
+dn_delete_queue(struct new_queue *q, int flags)
 {
 	struct new_fsk *fs = q->fs;
 
@@ -271,21 +271,21 @@ dn_delete_queue(struct new_queue *q, int
 	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)
-		dn_free_pkts(q->mq.head);
-	free(q, M_DUMMYNET);
-	dn_cfg.queue_count--;
-	fs->refcnt--;
-	return NULL;
+	if (flags & DN_DELETE) {
+		if (q->mq.head)
+			dn_free_pkts(q->mq.head);
+		free(q, M_DUMMYNET);
+		dn_cfg.queue_count--;
+		fs->refcnt--;
+	}
 }
 
 static int
 q_delete_cb(void *q, void *arg)
 {
-	(void)dn_delete_queue(q, (int)(uintptr_t)arg);
-	return 0;
+	int flags = (int)(uintptr_t)arg;
+	dn_delete_queue(q, flags);
+	return (flags & DN_DELETE) ? DNHT_SCAN_DEL : 0;
 }
 
 /*
@@ -296,22 +296,26 @@ q_delete_cb(void *q, void *arg)
 static void
 qht_delete(struct new_fsk *fs, int flags)
 {
-	printf("+++ %s fs %d start\n", __FUNCTION__, fs->fs.fs_nr);
+	printf("+++ %s fs %d start flags %d qht %p\n",
+		__FUNCTION__, fs->fs.fs_nr, flags, fs->_qht);
 	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 {
+	if (fs->fs.flags & DN_HAVE_MASK) {
 		dn_ht_scan(fs->_qht, q_delete_cb, (void *)flags);
 		if (flags & DN_DELETE) {
 			dn_ht_free(fs->_qht, 0);
 			fs->_qht = NULL;
 		}
+	} else {
+		dn_delete_queue((struct new_queue *)(fs->_qht), flags);
+		if (flags & DN_DELETE)
+			fs->_qht = NULL;
 	}
 }
 
 /*
- * only called in the DN_MULTIQUEUE CASE so we can handle errors
+ * Find and possibly create the right queue for a MULTIQUEUE scheduler.
+ * We never call it for !MULTIQUEUE (when the queue is in the sch_inst).
  * in a better way.
  */
 struct new_queue *
@@ -319,6 +323,7 @@ ipdn_q_find(struct new_fsk *fs, struct n
 	struct ipfw_flow_id *id)
 {
 	struct new_queue template;
+
 	template._si = si;
 	template.fs = fs;
 
@@ -330,7 +335,6 @@ ipdn_q_find(struct new_fsk *fs, struct n
 				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);
@@ -339,7 +343,6 @@ ipdn_q_find(struct new_fsk *fs, struct n
 	} else {
 		if (fs->_qht == NULL)
 			fs->_qht = q_new(0, 0, &template);
-		fs->kflags |= DN_QHT_IS_Q;
 		return (struct new_queue *)fs->_qht;
 	}
 }
@@ -395,12 +398,9 @@ si_new(uintptr_t key, int flags, void *a
 	si->sched = s;
 	si->dline.si = si;
 
-	if (s->fp->new_sched) {
-		int ret = s->fp->new_sched(si);
-		if (ret) {
-			printf("%s: new_sched error %d\n", __FUNCTION__, ret);
-			goto error;
-		}
+	if (s->fp->new_sched && s->fp->new_sched(si)) {
+		printf("%s: new_sched error\n", __FUNCTION__);
+		goto error;
 	}
 	if (s->sch.flags & DN_HAVE_MASK)
 		si->ni.id = *(struct ipfw_flow_id *)key;
@@ -415,10 +415,10 @@ error:
 }
 
 /*
- * callback from siht to delete all scheduler instances.
+ * Callback from siht to delete all scheduler instances. Remove
+ * si and delay line from the system heap, destroy all queues.
  * 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.
  */
 static int
 si_destroy(void *_si, void *arg)
@@ -434,6 +434,7 @@ si_destroy(void *_si, void *arg)
 		heap_extract(&dn_cfg.evheap, si);
 	if (s->fp->free_sched)
 		s->fp->free_sched(si);
+	bzero(si, sizeof(*si));	/* safety */
 	free(si, M_DUMMYNET);
 	dn_cfg.si_count--;
 	return 0;
@@ -446,18 +447,37 @@ si_destroy(void *_si, void *arg)
 struct new_sch_inst *
 ipdn_si_find(struct new_schk *s, struct ipfw_flow_id *id)
 {
-	struct new_sch_inst *si;
 
-	if (!(s->sch.flags & DN_HAVE_MASK)) {
-		if (s->siht == NULL)
-			s->siht = si_new((uintptr_t)id, 0, s);
-		si = (struct new_sch_inst *)s->siht;
-	} else {
+	if (s->sch.flags & DN_HAVE_MASK) {
 		struct ipfw_flow_id id_t = *id;
 		flow_id_mask(&s->sch.sched_mask, &id_t);
-		si = dn_ht_find(s->siht, (uintptr_t)&id_t, DNHT_INSERT, s);
+		return dn_ht_find(s->siht, (uintptr_t)&id_t,
+			DNHT_INSERT, s);
+	} else {
+		if (s->siht == NULL)
+			s->siht = si_new((uintptr_t)id, 0, s);
+		return (struct new_sch_inst *)s->siht;
 	}
-	return si;
+}
+
+/* callback to flush credit for the scheduler instance */
+static int
+si_reset_credit(void *_si, void *arg)
+{
+	struct new_sch_inst *si = _si;
+	struct new_pipe *p = &si->sched->pipe;
+
+	si->credit = p->burst + (dn_cfg.io_fast ?  p->bandwidth : 0);
+	return 0;
+}
+
+static void
+schk_reset_credit(struct new_schk *s)
+{
+	if (s->sch.flags & DN_HAVE_MASK)
+		dn_ht_scan(s->siht, si_reset_credit, NULL);
+	else if (s->siht)
+		si_reset_credit(s->siht, NULL);
 }
 /*---- end of sch_inst hashtable ---------------------*/
 
@@ -469,13 +489,12 @@ ipdn_si_find(struct new_schk *s, struct 
 static int
 fsk_hash(uintptr_t key, int flags, void *arg)
 {
-	int i = ((flags & DNHT_KEY_IS_OBJ) == 0) ? key :
+	int i = !(flags & DNHT_KEY_IS_OBJ) ? key :
 		((struct new_fsk *)key)->fs.fs_nr;
 
 	return ( (i>>8)^(i>>4)^i );
 }
 
-/* match skips entries those marked as deleted */
 static int
 fsk_match(void *obj, uintptr_t key, int flags, void *arg)
 {
@@ -483,7 +502,7 @@ fsk_match(void *obj, uintptr_t key, int 
 	int i = !(flags & DNHT_KEY_IS_OBJ) ? key :
 		((struct new_fsk *)key)->fs.fs_nr;
 
-	return !(fs->kflags & DN_DELETE) && (fs->fs.fs_nr == i);
+	return (fs->fs.fs_nr == i);
 }
 
 static void *
@@ -500,18 +519,27 @@ fsk_new(uintptr_t key, int flags, void *
 	return fs;
 }
 
-/* detach flowset from its current scheduler */
+/*
+ * detach flowset from its current scheduler. Flags as follows:
+ * DN_DETACH removes from the fsk_list
+ * DN_DELETE deletes individual queues
+ * DN_DELETE_FS destroys the flowset (otherwise goes in unlinked).
+ */
 static void
 fsk_detach(struct new_fsk *fs, int flags)
 {
 	if (flags & DN_DELETE_FS)
 		flags |= DN_DELETE;
+	printf("%s fs %d from sched %d flags %s %s %s\n",
+		__FUNCTION__, fs->fs.fs_nr, fs->fs.sched_nr,
+		(flags & DN_DELETE_FS) ? "DEL_FS":"",
+		(flags & DN_DELETE) ? "DEL":"",
+		(flags & DN_DETACH) ? "DET":"");
 	if (flags & DN_DETACH) { /* detach from the list */
 		struct new_fsk_head *h;
 		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, flags);
 	if (fs->sched && fs->sched->fp->free_fsk)
 		fs->sched->fp->free_fsk(fs);
@@ -536,7 +564,7 @@ static void
 fsk_detach_list(struct new_fsk_head *h, int flags)
 {
 	struct new_fsk *fs;
-	int n = 0;
+	int n = 0; /* only for stats */
 
 	printf("+++ %s head %p flags %x\n", __FUNCTION__, h, flags);
 	while ((fs = SLIST_FIRST(h))) {
@@ -552,16 +580,23 @@ fsk_detach_list(struct new_fsk_head *h, 
  * XXX note that fsk_detach_list also destroys a flowset.
  */
 static int
-delete_fs(int i)
+delete_fs(int i, int locked)
 {
 	struct new_fsk *fs;
+	int err = 0;
 
+	if (!locked)
+		DUMMYNET_LOCK();
 	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;
-	fsk_detach(fs, DN_DETACH | DN_DELETE_FS);
-	return 0;
+	if (fs) {
+		fsk_detach(fs, DN_DETACH | DN_DELETE_FS);
+		err = 0;
+	} else
+		err = EINVAL;
+	if (!locked)
+		DUMMYNET_UNLOCK();
+	return err;
 }
 
 /*----- end of flowset hashtable support -------------*/
@@ -671,29 +706,10 @@ delete_schk(int i)
 		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)
-{
-	struct new_sch_inst *si = _si;
-	struct new_pipe *p = &si->sched->pipe;
-
-	si->credit = p->burst + (dn_cfg.io_fast ?  p->bandwidth : 0);
+	delete_fs(i + DN_MAX_ID, 1);	/* remove internal pipe */
 	return 0;
 }
 
-static void
-schk_reset_credit(struct new_schk *s)
-{
-	if (s->sch.flags & DN_HAVE_MASK)
-		dn_ht_scan(s->siht, reset_credit, NULL);
-	else if (s->siht)
-		reset_credit(s->siht, NULL);
-}
 
 /*--- end of schk hashtable support ---*/
 
@@ -912,6 +928,14 @@ config_fs(struct new_fs *nfs, struct dn_
 	    fs = dn_ht_find(dn_cfg.fshash, i, DNHT_INSERT, NULL);
 	    if (fs == NULL)
 		break;
+	    if (nfs->sched_nr == 0) {
+		printf("reuse existing number %d\n", fs->fs.sched_nr);
+		if (fs->fs.sched_nr == 0) {
+			fs = NULL;
+			break;
+		}
+		nfs->sched_nr = fs->fs.sched_nr;
+	    }
 	    dn_cfg.id++;
 	    if (bcmp(&fs->fs, nfs, sizeof(*nfs)) == 0) {
 		printf("%s no change\n", __FUNCTION__);
@@ -924,6 +948,7 @@ config_fs(struct new_fs *nfs, struct dn_
 	     */
 	    if (fs->sched) {
 		int flags = s ? DN_DETACH : (DN_DETACH | DN_DELETE);
+		flags |= DN_DELETE; /* XXX temporary */
 		fsk_detach(fs, flags);
 	    }
 	    fs->fs = *nfs; /* copy configuration */
@@ -1139,7 +1164,6 @@ do_config(void *p, int l)
 		l -= o->len;
 		next = (struct dn_id *)((char *)o + o->len);
 		err = 0;
-		DUMMYNET_LOCK();
 		switch (o->type) {
 		default:
 			printf("cmd %d not implemented\n", o->type);
@@ -1152,8 +1176,10 @@ do_config(void *p, int l)
 			switch (o->subtype) {
 			case DN_PIPE:
 				/* delete base and derived schedulers */
+				DUMMYNET_LOCK();
 				err = delete_schk(o->id);
 				err2 = delete_schk(o->id + DN_MAX_ID);
+				DUMMYNET_UNLOCK();
 				if (!err)
 					err = err2;
 				break;
@@ -1166,13 +1192,15 @@ do_config(void *p, int l)
 
 			case DN_FS:
 				err = (o->id < 1 || o->id >= DN_MAX_ID) ?
-					EINVAL : delete_fs(o->id) ;
+					EINVAL : delete_fs(o->id, 0) ;
 				break;
 			}
 			break;
 
 		case DN_CMD_FLUSH:
+			DUMMYNET_LOCK();
 			dummynet_flush();
+			DUMMYNET_UNLOCK();
 			break;
 		case DN_TEXT:	/* store argument the next block */
 			prev = NULL;
@@ -1191,7 +1219,6 @@ do_config(void *p, int l)
 			err = (NULL==config_fs((struct new_fs *)o, arg, 0));
 			break;
 		}
-		DUMMYNET_UNLOCK();
 		if (prev)
 			arg = NULL;
 		if (err != 0)



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