svn commit: r202390 - in user/luigi/ipfw3-head: sbin/ipfw sys/netinet/ipfw

Luigi Rizzo luigi at FreeBSD.org
Fri Jan 15 16:24:58 UTC 2010


Author: luigi
Date: Fri Jan 15 16:24:58 2010
New Revision: 202390
URL: http://svn.freebsd.org/changeset/base/202390

Log:
  another batch of changes, now removals work as well.

Modified:
  user/luigi/ipfw3-head/sbin/ipfw/dummynet.c
  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/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	Fri Jan 15 16:21:32 2010	(r202389)
+++ user/luigi/ipfw3-head/sbin/ipfw/dummynet.c	Fri Jan 15 16:24:58 2010	(r202390)
@@ -295,49 +295,66 @@ print_extra_delay_parms(struct dn_pipe *
 }
 #endif
 
+static void
+flush_buf(char *buf)
+{
+	if (buf[0])
+		printf("%s\n", buf);
+	buf[0] = '\0';
+}
+	
 /*
+ * generic list routine. We expect objects in a specific order, i.e.
+ * pipe i (int queue); scheduler i; si(i) { flowsets() : queues }
  * filt is an array of sorted ranges whithin where we list
  */
 static void
 list_pipes(struct dn_id *oid, struct dn_id *end, int *filt)
 {
-    for (; oid != end; oid = O_NEXT(oid, oid->len)) {
-	struct new_pipe *p = (struct new_pipe *)oid;
-	//struct dn_flow_set *fs;
-	//struct dn_flow_queue *q;
-
-	double b = p->bandwidth;
-	char buf[30];
-	char prefix[80];
-	char burst[5 + 7];
-
-	if (oid->type != DN_PIPE)
-		continue;
-	/*
-	 * Print rate (or clocking interface)
-	 */
-	if (b == 0)
-		sprintf(buf, "unlimited");
-	else if (b >= 1000000)
-		sprintf(buf, "%7.3f Mbit/s", b/1000000);
-	else if (b >= 1000)
-		sprintf(buf, "%7.3f Kbit/s", b/1000);
-	else
-		sprintf(buf, "%7.3f bit/s ", b);
-
-	sprintf(prefix, "%05d: %s %4d ms ",
-		    p->pipe_nr, buf, p->delay);
+    char buf[80];	/* pending buffer */
+    buf[0] = '\0';
 
-	//	print_flowset_parms(&(p->fs), prefix);
-	printf("%s", prefix);
+    for (; oid != end; oid = O_NEXT(oid, oid->len)) {
+	/* XXX check oid->len */
+	if (oid->len < sizeof(*oid))
+		errx(1, "invalid oid len %d\n", oid->len);
+
+	switch (oid->type) {
+	case DN_PIPE: {
+	    struct new_pipe *p = (struct new_pipe *)oid;
+	    double b = p->bandwidth;
+	    char bwbuf[30];
+	    char burst[5 + 7];
+
+	    flush_buf(buf);
+	    /* data rate */
+	    if (b == 0)
+		sprintf(bwbuf, "unlimited");
+	    else if (b >= 1000000)
+		sprintf(bwbuf, "%7.3f Mbit/s", b/1000000);
+	    else if (b >= 1000)
+		sprintf(bwbuf, "%7.3f Kbit/s", b/1000);
+	    else
+		sprintf(bwbuf, "%7.3f bit/s ", b);
 
-	if (humanize_number(burst, sizeof(burst), p->burst,
+	    if (humanize_number(burst, sizeof(burst), p->burst,
 		    "Byte", HN_AUTOSCALE, 0) < 0 || co.verbose)
-		printf("\t burst: %ju Byte\n", p->burst);
-	else
-		printf("\t burst: %s\n", burst);
+		sprintf(burst, "%ju Byte\n", p->burst);
+	    sprintf(buf, "%05d: %s %4d ms burst %s",
+		p->pipe_nr, bwbuf, p->delay, burst);
+	    //	print_flowset_parms(&(p->fs), prefix);
+	    // print_extra_delay_parms(p);
+	    }
+	    break;
+	case DN_FS:
+	    flush_buf(buf);
+	    printf("XXX flowset unimplemented\n");
+	    break;
+	}
+    }
+    flush_buf(buf);
+}
 
-	// print_extra_delay_parms(p);
 #if 0
 		q = (struct dn_flow_queue *)(p+1);
 		list_queues(&(p->fs), q);
@@ -363,8 +380,6 @@ list_pipes(struct dn_id *oid, struct dn_
 		list_queues(fs, q);
 	}
 #endif
-    }
-}
 
 /*
  * Delete pipe, queue or scheduler i

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c	Fri Jan 15 16:21:32 2010	(r202389)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c	Fri Jan 15 16:24:58 2010	(r202390)
@@ -311,7 +311,6 @@ struct dn_ht {
         int buckets;            /* how many buckets */
         int entries;            /* how many entries */
         int ofs;	        /* offset of link field */
-	void *arg;		/* argument to the three functions */
         int (*hash)(uintptr_t, int, void *arg);
         int (*match)(void *_el, uintptr_t key, int, void *);
         void *(*new)(uintptr_t, int, void *);
@@ -327,7 +326,7 @@ struct dn_ht *
 dn_ht_init(struct dn_ht *ht, int buckets, int ofs,
         int (*h)(uintptr_t, int, void *),
         int (*match)(void *, uintptr_t, int, void *),
-	void *(*new)(uintptr_t, int, void *), void *arg)
+	void *(*new)(uintptr_t, int, void *))
 {
 	int l;
 
@@ -360,7 +359,6 @@ dn_ht_init(struct dn_ht *ht, int buckets
 		ht->hash = h;
 		ht->match = match;
 		ht->new = new;
-		ht->arg = arg;
 	}
 	return ht;
 }
@@ -377,19 +375,19 @@ dn_ht_free(struct dn_ht *ht, int flags)
 
 /* lookup and optionally create or delete element */
 void *
-dn_ht_find(struct dn_ht *ht, uintptr_t key, int flags)
+dn_ht_find(struct dn_ht *ht, uintptr_t key, int flags, void *arg)
 {
 	int i;
 	void **pp, *p;
 
 	i = (ht->buckets == 1) ? 0 :
-		(ht->hash(key, flags, ht->arg) % ht->buckets);
+		(ht->hash(key, flags, arg) % ht->buckets);
 	// 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)
 				break;
-		} else if (ht->match(p, key, flags, ht->arg)) /* found match */
+		} else if (ht->match(p, key, flags, arg)) /* found match */
 			break;
 	}
 	if (p) {
@@ -402,7 +400,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);
-		p = ht->new ? ht->new(key, flags, ht->arg) : (void *)key;
+		p = ht->new ? ht->new(key, flags, arg) : (void *)key;
 		// printf("%s new returns %p\n", __FUNCTION__, p);
 		if (p) {
 			ht->entries++;

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.h	Fri Jan 15 16:21:32 2010	(r202389)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.h	Fri Jan 15 16:24:58 2010	(r202390)
@@ -109,9 +109,8 @@ int heap_scan(struct dn_heap *, int (*)(
  * computation on each removal.
  *
  * dn_ht_init() initializes the table, setting the number of
- *	buckets, the offset of the link field, the main callbacks,
- *	and an extra argument passed to the callbacks together
- *	with 'flags' which is defined below. Callbacks are:
+ *	buckets, the offset of the link field, the main callbacks.
+ *	Callbacks are:
  * 
  *	hash(key, flags, arg) called to return a bucket index.
  *	match(obj, key, flags, arg) called to determine if key
@@ -125,6 +124,7 @@ int heap_scan(struct dn_heap *, int (*)(
  *
  * dn_ht_find() is the main lookup function, which can also be
  *	used to insert or delete elements in the hash table.
+ *	The final 'arg' is passed to all callbacks.
  *
  * dn_ht_scan() is used to invoke a callback on all entries of
  *	the heap, or possibly on just one bucket. The callback
@@ -157,11 +157,11 @@ struct dn_ht;	/* should be opaque */
 struct dn_ht *dn_ht_init(struct dn_ht *, int buckets, int ofs, 
         int (*hash)(uintptr_t, int, void *),
         int (*match)(void *, uintptr_t, int, void *),
-        void *(*new)(uintptr_t, int, void *), void *arg);
+        void *(*new)(uintptr_t, int, void *));
+void dn_ht_free(struct dn_ht *, int flags);
 
-void *dn_ht_find(struct dn_ht *, uintptr_t key, int flags);
+void *dn_ht_find(struct dn_ht *, uintptr_t, int, void *);
 int dn_ht_scan(struct dn_ht *, int (*)(void *, void *), void *);
-void dn_ht_free(struct dn_ht *, int flags);
 
 enum {  /* flags values.
 	 * first two are returned by the scan callback to indicate

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h	Fri Jan 15 16:21:32 2010	(r202389)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h	Fri Jan 15 16:24:58 2010	(r202390)
@@ -108,14 +108,13 @@ struct dn_sched {
 	int (*new_queue)(struct new_queue *q);
 	int (*free_queue)(struct new_queue *q);
 };
-SLIST_HEAD(dn_sched_head, dn_sched);
 
 /*
  * Additionally, dummynet exports some variables, functions and macros
  * to be used by schedulers.
  */
 /* delete a queue, which we assume nobody references */
-int dn_delete_queue(struct new_queue *q);
+int dn_delete_queue(void *, void *propagate);
 int dn_queue_packet(struct new_queue *q, struct mbuf* m, int drop);
 
 /*
@@ -129,10 +128,13 @@ dn_return_packet(struct new_queue *q)
 	KASSERT(m != NULL, ("empty queue to dn_return_packet"));
 	q->mq.head = m->m_nextpkt;
 	q->ni.length--;
-	q->si->ni.len_bytes -= m->m_pkthdr.len;
-	q->si->ni.len_bytes -= m->m_pkthdr.len;
+	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->mq.head == NULL && q->fs && q->fs->kflags & DN_DELETE)
-		dn_delete_queue(q);
+		dn_delete_queue(q, (void *)1 /* possibly flush flowset */);
 	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	Fri Jan 15 16:21:32 2010	(r202389)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c	Fri Jan 15 16:24:58 2010	(r202390)
@@ -105,16 +105,29 @@ extern	void (*bridge_dn_p)(struct mbuf *
 #ifdef SYSCTL_NODE
 SYSCTL_DECL(_net_inet);
 SYSCTL_DECL(_net_inet_ip);
-
 SYSCTL_NODE(_net_inet_ip, OID_AUTO, dummynet, CTLFLAG_RW, 0, "Dummynet");
+
+/* parameters */
 SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, hash_size,
     CTLFLAG_RW, &dn_cfg.hash_size, 0, "Default hash table size");
+SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, pipe_slot_limit,
+    CTLFLAG_RW, &dn_cfg.pipe_slot_limit, 0,
+    "Upper limit in slots for pipe queue.");
+SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, pipe_byte_limit,
+    CTLFLAG_RW, &dn_cfg.pipe_byte_limit, 0,
+    "Upper limit in bytes for pipe queue.");
+SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, io_fast,
+    CTLFLAG_RW, &dn_cfg.io_fast, 0, "Enable fast dummynet io.");
+
+/* RED parameters */
 SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_lookup_depth,
     CTLFLAG_RD, &dn_cfg.red_lookup_depth, 0, "Depth of RED lookup table");
 SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_avg_pkt_size,
     CTLFLAG_RD, &dn_cfg.red_avg_pkt_size, 0, "RED Medium packet size");
 SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_max_pkt_size,
     CTLFLAG_RD, &dn_cfg.red_max_pkt_size, 0, "RED Max packet size");
+
+/* time adjustment */
 SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_delta,
     CTLFLAG_RD, &tick_delta, 0, "Last vs standard tick difference (usec).");
 SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_delta_sum,
@@ -127,8 +140,16 @@ SYSCTL_LONG(_net_inet_ip_dummynet, OID_A
 SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_lost,
     CTLFLAG_RD, &tick_lost, 0,
     "Number of ticks coalesced by dummynet taskqueue.");
-SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, io_fast,
-    CTLFLAG_RW, &dn_cfg.io_fast, 0, "Enable fast dummynet io.");
+
+/* statistics */
+SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, schk_count,
+    CTLFLAG_RD, &dn_cfg.schk_count, 0, "Number of schedulers");
+SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, si_count,
+    CTLFLAG_RD, &dn_cfg.si_count, 0, "Number of scheduler instances");
+SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, fsk_count,
+    CTLFLAG_RD, &dn_cfg.fsk_count, 0, "Number of flowsets");
+SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, queue_count,
+    CTLFLAG_RD, &dn_cfg.queue_count, 0, "Number of queues");
 SYSCTL_ULONG(_net_inet_ip_dummynet, OID_AUTO, io_pkt,
     CTLFLAG_RD, &io_pkt, 0,
     "Number of packets passed to dummynet.");
@@ -138,10 +159,6 @@ SYSCTL_ULONG(_net_inet_ip_dummynet, OID_
 SYSCTL_ULONG(_net_inet_ip_dummynet, OID_AUTO, io_pkt_drop,
     CTLFLAG_RD, &io_pkt_drop, 0,
     "Number of packets dropped by dummynet.");
-SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, pipe_slot_limit,
-    CTLFLAG_RW, &dn_cfg.pipe_slot_limit, 0, "Upper limit in slots for pipe queue.");
-SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, pipe_byte_limit,
-    CTLFLAG_RW, &dn_cfg.pipe_byte_limit, 0, "Upper limit in bytes for pipe queue.");
 #endif
 
 struct mtx dummynet_mtx;
@@ -513,12 +530,6 @@ dummynet_send(struct mbuf *m)
 	}
 }
 
-struct new_fsk *
-ipdn_locate_flowset(int fs_nr)
-{
-	return dn_ht_find(dn_cfg.fshash, fs_nr, 0);
-}
-
 static inline int
 tag_mbuf(struct mbuf *m, int dir, struct ip_fw_args *fwa)
 {
@@ -557,7 +568,7 @@ dummynet_io(struct mbuf **m0, int dir, s
 	struct mbuf *m = *m0;
 	struct new_fsk *fs = NULL;
 	struct new_sch_inst *si;
-	struct new_queue *q;
+	struct new_queue *q = NULL;	/* default */
 	dn_key now; /* save a copy of curr_time */
 
 	int fs_id = (fwa->rule.info & IPFW_INFO_MASK) +
@@ -566,7 +577,7 @@ dummynet_io(struct mbuf **m0, int dir, s
 	io_pkt++;
 	now = curr_time;
 	/* XXX locate_flowset could be optimised with a direct ref. */
-	fs = ipdn_locate_flowset(fs_id);
+	fs = dn_ht_find(dn_cfg.fshash, fs_id, 0, NULL);
 	if (fs == NULL)
 		goto dropit;	/* This queue/pipe does not exist! */
 	if (fs->sched == NULL)	/* should not happen */
@@ -578,13 +589,16 @@ dummynet_io(struct mbuf **m0, int dir, s
 	if (tag_mbuf(m, dir, fwa))
 		goto dropit;
 	/*
-	 * if the scheduler has a single queue (e.g. FIFO) then
-	 * call directly with NULL queue. Otherwise find a queue
-	 * and pass it.
+	 * If the support multiple queues, find the right one
+	 * (otherwise it will be ignored by enqueue).
+	 * We cannot pass si as an argument :(
 	 */
 	if (fs->sched->fp->flags & DN_MULTIQUEUE) {
+		struct new_queue template;
+		template.si = si;
+		template.fs = fs;
 		q = dn_ht_find(fs->qht, (uintptr_t)&(fwa->f_id),
-			DNHT_INSERT);
+			DNHT_INSERT, &template);
 		if (q == NULL)
 			goto dropit;
 	} else {

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h	Fri Jan 15 16:21:32 2010	(r202389)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h	Fri Jan 15 16:24:58 2010	(r202390)
@@ -50,6 +50,7 @@ SLIST_HEAD(new_schk_head, new_schk);
 SLIST_HEAD(new_sch_inst_head, new_sch_inst);
 SLIST_HEAD(new_fsk_head, new_fsk);
 SLIST_HEAD(new_queue_head, new_queue);
+SLIST_HEAD(dn_sched_head, dn_sched);
 
 /*
  * global configuration parameters.
@@ -80,7 +81,8 @@ struct dn_parms {
 	struct dn_ht	*fshash;
 	struct dn_ht	*schedhash;
 	/* list of flowsets without a scheduler -- use sch_chain */
-	struct new_fsk_head	fsunlinked;
+	struct new_fsk_head	fsu;
+	struct dn_sched_head	schedlist;	/* list of algorithms */
 };
 
 static inline void
@@ -128,15 +130,19 @@ struct new_fsk { /* kernel side of a flo
 };
 
 /*
- * The child of a flowset, is in a hash table
+ * q 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.
  */
 struct new_queue {
 	struct new_inst ni;	/* oid, flow_id, stats */
 	struct mq mq;	/* packets queue */
-
-	SLIST_ENTRY(new_queue) ql__next; /* hash chain list */
-	SLIST_ENTRY(new_queue) si_chain; /* linked list to sch_inst */
 	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. */
 };

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c	Fri Jan 15 16:21:32 2010	(r202389)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c	Fri Jan 15 16:24:58 2010	(r202390)
@@ -1,6 +1,4 @@
 /*-
-	printf("XXX should delete all fs pointing to me\n");
-	printf("XXX should delete all fs pointing to me\n");
  * Copyright (c) 1998-2002,2010 Luigi Rizzo, Universita` di Pisa
  * Portions Copyright (c) 2000 Akamba Corp.
  * All rights reserved
@@ -69,7 +67,7 @@ static int	ip_dn_ctl(struct sockopt *sop
 #define DN_C_FS		0x08
 #define DN_C_QUEUE	0x10
 
-/* callout hooks. */
+/*---- callout hooks. ----*/
 static struct callout dn_timeout;
 static struct task	dn_task;
 static struct taskqueue	*dn_tq = NULL;
@@ -86,21 +84,19 @@ dn_reschedule(void)
 {
 	callout_reset(&dn_timeout, 1, dummynet, NULL);
 }
+/*----- end of callout hooks -----*/
 
-/*
- * Return a scheduler descriptor given the type or name.
- */
-static struct dn_sched_head    list_of_scheduler;
+/* Return a scheduler descriptor given the type or name. */
 static struct dn_sched *
-load_scheduler(int type, char *name)
+find_sched_type(int type, char *name)
 {
 	struct dn_sched *d = NULL;
 
-	SLIST_FOREACH(d, &list_of_scheduler, next) {
+	SLIST_FOREACH(d, &dn_cfg.schedlist, next) {
 		if (d->type == type || (name && !strcmp(d->name, name)))
 			return d;
 	}
-	return NULL; /* error */
+	return NULL; /* not found */
 }
 
 /*
@@ -196,9 +192,70 @@ flow_id_cmp(struct ipfw_flow_id *id1, st
 	/* Masks differ */
 	return 1;
 }
+/*--------- end of flow-id mask, hash and compare ---------*/
+
+/*--- support functions for the qht hashtable ----
+ * Entries are hashed by flow-id
+ */
+static int
+q_hash(uintptr_t key, int flags, void *arg)
+{
+	/* compute the hash slot from the flow id */
+	struct ipfw_flow_id *id = (flags & DNHT_KEY_IS_OBJ) ?
+		&((struct new_queue *)key)->ni.id :
+		(struct ipfw_flow_id *)key;
+	return flow_id_hash(id);
+}
+
+static int
+q_match(void *obj, uintptr_t key, int flags, void *arg)
+{
+	struct new_queue *o;
+	struct ipfw_flow_id *id2;
+
+	if (flags & DNHT_KEY_IS_OBJ) {
+		/* compare pointers */
+		id2 = &((struct new_queue *)key)->ni.id;
+	} else {
+		id2 = (struct ipfw_flow_id *)key;
+	}
+	o = (struct new_queue *)obj;
+	return flow_id_cmp(&o->ni.id,  id2) == 0;
+}
+
+/*
+ * create a new queue instance for the given 'key'
+ */
+static void *
+q_new(uintptr_t key, int flags, void *arg)
+{   
+	struct ipfw_flow_id *id = (struct ipfw_flow_id *)key;
+	struct new_queue *q, *template = arg;
+	struct new_fsk *fs = template->fs;
+	int size = sizeof(*q) + fs->sched->fp->queue_len;
+
+	q = malloc(size, M_DUMMYNET, M_NOWAIT | M_ZERO);
+	if (q == NULL) {
+		printf("%s: no memory for new queue\n", __FUNCTION__);
+		return NULL;
+	}
+
+	set_oid(&q->ni.oid, DN_QUEUE, 0, size);
+	q->ni.id = *id;
+	q->fs = fs;
+	q->si = template->si;
+	fs->refcnt++;
 
-/*--- support functions for the sch_inst hashtable ----*/
+	if (fs->sched->fp->new_queue)
+		fs->sched->fp->new_queue(q);
+	dn_cfg.queue_count++;
+	return q;
+}
 
+/*--- support functions for the sch_inst hashtable ----
+ *
+ * These are hashed by flow-id
+ */
 static int
 si_hash(uintptr_t key, int flags, void *arg)
 {
@@ -236,7 +293,6 @@ 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;
@@ -258,9 +314,6 @@ si_new(uintptr_t key, int flags, void *a
 			goto error;
 		}
 	}
-
-	/* Initialize list of queues attached here */
-	SLIST_INIT(&si->ql_list);
 	if (s->sch.flags & DN_HAVE_MASK)
 		si->ni.id = *(struct ipfw_flow_id *)key;
 
@@ -275,6 +328,8 @@ error:
 
 /*
  * Callback for the hashtable scan.
+ * 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
@@ -283,22 +338,19 @@ si_destroy(void *_si, void *arg)
 	struct new_sch_inst *si = _si;
 	struct new_schk *s = si->sched;
 	struct delay_line *dl = &si->dline;
-	struct new_queue *q;
 
-	if (si->kflags & DN_ACTIVE) /* is in the heap */
+	if (dl->oid.subtype) /* remove delay line from event heap */
+		heap_extract(&dn_cfg.evheap, dl);
+	dn_free_pkts(dl->mq.head);	/* drain delay line */
+	if (si->kflags & DN_ACTIVE) /* remove si from event heap */
 		heap_extract(&dn_cfg.evheap, si);
 	if (s->fp->free_sched)
 		s->fp->free_sched(si);
-	if (dl->oid.subtype) /* is in the heap */
-		heap_extract(&dn_cfg.evheap, dl);
-	dn_free_pkts(dl->mq.head);
-        while ( (q = SLIST_FIRST(&si->ql_list)) ) {
-		dn_delete_queue(q);
-	}
 	free(si, M_DUMMYNET);
 	dn_cfg.si_count--;
 	return 0;
 }
+/*---- end of sch_inst hashtable ---------------------*/
 
 /*
  * Find the scheduler instance for this packet. If we need to apply
@@ -316,103 +368,137 @@ ipdn_si_find(struct new_schk *s, struct 
 	} else {
 		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);
+		si = dn_ht_find(s->siht, (uintptr_t)&id_t, DNHT_INSERT, s);
 	}
 	return si;
 }
 
-/*---- support functions for flowset hash table ----*/
-/*
- * support to delete a flowset. Mark as delete,
- * then check refcnt and free when it becomes 0
+/*-------------------------------------------------------
+ * flowset hash (fshash) support. Entries are hashed by fs_nr.
+ * New allocations are put in the fsunlinked list, from which
+ * they are removed when they point to a specific scheduler.
  */
 static int
-fsk_destroy_cb(void *obj, void *arg)
+fsk_hash(uintptr_t key, int flags, void *arg)
+{
+	int i = ((flags & DNHT_KEY_IS_OBJ) == 0) ? 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)
 {
 	struct new_fsk *fs = obj;
-	struct new_schk *s = fs->sched;
+	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);
+}
 
-printf("%s fs %d sched %d %p refcnt %d\n", __FUNCTION__,
-	fs->fs.fs_nr,
-	fs->fs.sched_nr, s, fs->refcnt);
-	fs->kflags |= DN_DELETE;
-	if (fs->refcnt == 0) {
-		dn_cfg.fsk_count--;
-		// always in a list, possibly the unlinked
-		// SLIST_REMOVE(&s->fsk_list, fs, new_fsk, sch_chain);
-		fs->sched = NULL;
-		free(fs, M_DUMMYNET);
-		printf("%s free done\n", __FUNCTION__);
+static void *
+fsk_new(uintptr_t key, int flags, void *arg)
+{
+	struct new_fsk *fs;
+
+	fs = malloc(sizeof(*fs), M_DUMMYNET, M_NOWAIT | M_ZERO);
+	if (fs) {
+		dn_cfg.fsk_count++;
+		SLIST_INSERT_HEAD(&dn_cfg.fsu, fs, sch_chain);
 	}
-	return HEAP_SCAN_DEL;
+	return fs;
 }
 
-
 /*
- * helper for schedulers. Creates a queue
- * XXX actually, maybe only flowsets use this ?
+ * 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.
  */
-struct new_queue *
-dn_create_queue(struct new_sch_inst *si, struct new_fsk *fs,
-	struct ipfw_flow_id *id)
-{   
-	struct new_queue *q;
-	int size = sizeof(*q) + si->sched->fp->queue_len;
+static int
+fsk_destroy(struct new_fsk *fs)
+{
+	struct new_fsk_head *h;
 
-	q = malloc(size, M_DUMMYNET, M_NOWAIT | M_ZERO);
-	if (q == NULL) {
-		printf("dummynet: no memory for new queue\n");
-		return NULL;
-	}
+	fs->kflags |= DN_DELETE;
+	if (fs->refcnt != 0)
+		return 0;
+	/* 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--;
+	fs->sched = NULL;
+	if (fs->qht)
+		dn_ht_free(fs->qht, 0);
+	free(fs, M_DUMMYNET);
+	return 1; /* can remove from the ht */
+}
+/*----- end of flowset hashtable support -------------*/
 
-	set_oid(&q->ni.oid, DN_QUEUE, 0, size);
-	q->fs = fs;
-	q->si = si;
-	fs->refcnt++;
+/*
+ * 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
+ */
+static void
+fsk_destroy_list(struct new_fsk_head *h, struct new_fsk *int_fs)
+{
+	struct new_fsk *fs;
 
-	if (si->sched->fp->new_queue)
-		si->sched->fp->new_queue(q);
-	SLIST_INSERT_HEAD(&si->ql_list, q, si_chain);
-	dn_cfg.queue_count++;
-	return q;
+	while ((fs = SLIST_FIRST(h))) {
+		/* remember if the flowset is dying */
+		int dying;
+		if (h == &dn_cfg.fsu)
+			fs->kflags |= DN_DELETE;
+		dying = fs->kflags & DN_DELETE;
+		printf("%s unlink flowset %d\n",
+			__FUNCTION__, fs->fs.fs_nr);
+		SLIST_REMOVE_HEAD(h, sch_chain);
+		if (fs == int_fs) {
+			/* free the internal flowset.
+			 * XXX maybe do it same as others
+			 */
+			free(fs, M_DUMMYNET);
+			dn_cfg.fsk_count--;
+		} else if (fs->qht)
+			dn_ht_scan(fs->qht, dn_delete_queue, NULL);
+			
+		/* if not already gone, move to fsunlinked.
+		 * The internal fs is marked DN_DELETE so it
+		 * will go away. Also, we scan all flowsets
+		 * so we are guaranteed that those marked DN_DELETE
+		 * will be deleted.
+		 */
+		if (!dying) {
+			fs->sched = NULL;
+			SLIST_INSERT_HEAD(&dn_cfg.fsu, fs, sch_chain);
+		}
+	}
 }
 
 /*
- * Delete a queue (helper for the schedulers)
+ * Delete a queue (helper for the schedulers and callback)
+ * Call th
  */
 int
-dn_delete_queue(struct new_queue *q)
+dn_delete_queue(void *_q, void *foo)
 {
+	struct new_queue *q = _q;
 	struct new_fsk *fs = q->fs;
 
-	if (SLIST_FIRST(&q->si->ql_list))
-		SLIST_REMOVE(&q->si->ql_list, q, new_queue, si_chain);
 	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--;
-	if (fs) {
-		fs->refcnt--;
-		if (fs->refcnt == 0 && fs->kflags & DN_DELETE)
-			fsk_destroy_cb(fs, NULL);
-	}
+	fs->refcnt--;
+	if (fs->refcnt == 0 && fs->kflags & DN_DELETE)
+		fsk_destroy(fs);
 	return 0;
 }
 
-/* destroy all scheduler instances but not the main scheduler */
-static struct new_schk *
-schk_flush(struct new_schk *s)
-{
-
-	if (s->sch.flags & DN_HAVE_MASK) {
-		dn_ht_scan(s->siht, si_destroy, NULL);
-	} else if (s->siht)
-		si_destroy(s->siht, NULL);
-	return NULL;
-}
-
 /* callback to flush credit for the pipe */
 static int
 reset_credit(void *_si, void *arg)
@@ -470,6 +556,14 @@ copy_data_helper(void *_o, void *_arg)
 		if (a->flags & DN_C_SCH_INST) {
 			printf("XXX todo: scan sched instances\n");
 		}
+		if (a->flags & DN_C_FS) {
+			struct new_fsk *fs = _o;
+			if (copy_obj(a->start, a->end, &fs->fs))
+				return HEAP_SCAN_END;
+		}
+		if (a->flags & DN_C_QUEUE) {
+			printf("XXX todo: scan queue instances\n");
+		}
 	}
 	if (a->type == DN_FS) {	/* scanning flowsets */
 		struct new_fsk *fs = _o;
@@ -479,25 +573,29 @@ copy_data_helper(void *_o, void *_arg)
 	return 0;
 }
 
-/* callback for sched delete */
+/*
+ * callback for sched delete.
+ * Tell all attached flowsets to remove their queues,
+ * unlink the flowsets.
+ */
 static int
 schk_del_cb(void *obj, void *arg)
 {
 	struct new_schk *s = obj;
-	struct new_fsk *fs;
 
-	printf("%s start for %d %p\n", __FUNCTION__, s->sch.sched_nr, s);
-	schk_flush((struct new_schk *)obj);
-	printf("XXX should delete all fs pointing to me\n");
-	while ((fs = SLIST_FIRST(&s->fsk_list))) {
-		printf("%s unlink flowset %d from sched %d\n", __FUNCTION__,
-			fs->fs.fs_nr, s->sch.sched_nr);
-		SLIST_REMOVE_HEAD(&s->fsk_list, sch_chain);
-		fs->sched = NULL;
-		printf("	put flowset into fsunlinked\n");
-		SLIST_INSERT_HEAD(&dn_cfg.fsunlinked, fs, sch_chain);
+	if (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);
+	/* 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;
 }
 
@@ -509,12 +607,10 @@ dummynet_flush(void)
 {
 
 	DUMMYNET_LOCK();
-	printf("%s start\n", __FUNCTION__);
-	/* first mark flowsets as delete, then go after queues */
-	dn_ht_scan(dn_cfg.fshash, fsk_destroy_cb, 0);
-	printf("%s fsk_destroy_cb done\n", __FUNCTION__);
-	dn_ht_scan(dn_cfg.schedhash, schk_del_cb, 0);
-
+	/* 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));
 
@@ -525,7 +621,7 @@ dummynet_flush(void)
 static inline struct new_schk *
 locate_scheduler(int i)
 {
-	return dn_ht_find(dn_cfg.schedhash, i, 0);
+	return dn_ht_find(dn_cfg.schedhash, i, 0, NULL);
 }
 
 /* update all flowsets which may refer to this scheduler */
@@ -577,7 +673,6 @@ config_pipe(struct new_pipe *p, struct d
 	i = p->pipe_nr;
 	if (i <= 0 || i >= DN_MAX_ID)
 		return EINVAL;
-	// printf("%s %d\n", __FUNCTION__, i);
 	/*
 	 * The config program passes parameters as follows:
 	 * bw = bits/second (0 means no limits),
@@ -626,7 +721,6 @@ config_fs(struct new_fs *nfs, struct dn_
 		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 */
@@ -642,7 +736,7 @@ config_fs(struct new_fs *nfs, struct dn_
 	if (!locked)
 		DUMMYNET_LOCK();
 again:
-	fs = dn_ht_find(dn_cfg.fshash, i, DNHT_INSERT);
+	fs = dn_ht_find(dn_cfg.fshash, i, DNHT_INSERT, NULL);
 	if (fs == NULL)
 		goto done;
 	dn_cfg.id++;
@@ -650,9 +744,16 @@ again:
 	s = locate_scheduler(nfs->sched_nr);
 	if (fs->sched == NULL) { /* no scheduler before */
 		if (s) {
-			/* have a new scheduler, remove from unlinked */
+			/* have a new scheduler, remove from unlinked
+			 * and add to the list of children of s
+			 */
+			SLIST_REMOVE(&dn_cfg.fsu, fs, new_fsk, sch_chain);
 			fs->sched = s;
-			// XXX remove_from_unlinked(fs);
+			SLIST_INSERT_HEAD(&s->fsk_list, fs, sch_chain);
+			if (s->fp->flags & DN_MULTIQUEUE)
+				fs->qht = dn_ht_init(NULL, nfs->buckets,
+					offsetof(struct new_queue, q_next),
+					q_hash, q_match, q_new);
 		}
 	} else if (fs->sched != s) {
 		/* scheduler changed. Let it die and recreate */
@@ -686,23 +787,22 @@ config_sched(struct new_sch *nsch, struc
 	/* 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);
+	fp = find_sched_type(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 in schk_new() */
 	s = dn_ht_find(dn_cfg.schedhash, (uintptr_t)nsch,
-			DNHT_KEY_IS_OBJ | DNHT_INSERT);
+		DNHT_KEY_IS_OBJ | DNHT_INSERT, fp);
 	if (s == NULL) {
 		DUMMYNET_UNLOCK();
 		printf("cannot allocate scheduler\n");
 		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 != fp) {
@@ -731,14 +831,14 @@ 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 (notify_fs)
+		update_fs(s);
 	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;
 	}
-	if (notify_fs)
-		update_fs(s);
 	DUMMYNET_UNLOCK();
 	return 0;
 }
@@ -809,12 +909,13 @@ config_profile(struct new_profile *pf, s
 static int
 del_fs(int i)
 {
-	struct new_fsk *fs = dn_ht_find(dn_cfg.fshash, i, DNHT_REMOVE);
+	struct new_fsk *fs = dn_ht_find(dn_cfg.fshash, i, DNHT_REMOVE, NULL);
+
+	printf("%s fs %d found %p\n", __FUNCTION__, i, fs);
 	if (fs) {
-		fsk_destroy_cb(fs, NULL);
+		fsk_destroy(fs);
 		return 0;
 	} else {
-		printf("%s: %d not found\n", __FUNCTION__, i);
 		return EINVAL;
 	}
 }
@@ -822,12 +923,12 @@ del_fs(int i)
 static int
 del_schk(int i)
 {
-	struct new_schk *s = dn_ht_find(dn_cfg.schedhash, i, DNHT_REMOVE);
+	struct new_schk *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 {
-		printf("%s: %d not found\n", __FUNCTION__, i);
 		return EINVAL;
 	}
 }
@@ -854,8 +955,6 @@ do_config(void *p, int l)
 			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) {
@@ -869,13 +968,10 @@ do_config(void *p, int l)
 		case DN_CMD_DELETE:
 			switch (o->subtype) {
 			case DN_PIPE:
+				/* delete base and derived schedulers */
 				if ( (err = del_schk(o->id)) )
 					break;
-				if ( (err = del_schk(o->id) + DN_MAX_ID) )
-					break;
-				if ( (err = del_fs(o->id)) )
-					break;
-				if ( (err = del_fs(o->id) + DN_MAX_ID) )
+				if ( (err = del_schk(o->id + DN_MAX_ID)) )
 					break;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-user mailing list