Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 12 Jan 2010 21:27:38 +0000 (UTC)
From:      Luigi Rizzo <luigi@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r202174 - in user/luigi/ipfw3-head/sys/netinet: . ipfw
Message-ID:  <201001122127.o0CLRcKU005321@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: luigi
Date: Tue Jan 12 21:27:38 2010
New Revision: 202174
URL: http://svn.freebsd.org/changeset/base/202174

Log:
  snapshot for today

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_heap.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_dummynet.c

Modified: user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h	Tue Jan 12 21:17:36 2010	(r202173)
+++ user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h	Tue Jan 12 21:27:38 2010	(r202174)
@@ -46,8 +46,7 @@ struct dn_id {
 	uint16_t	len;	/* total len including this header */
 	uint8_t		type;
 	uint8_t		subtype;
-	uint32_t	id;	/* identifier in the sequence */
-	struct dn_id 	*next;	/* link field, for kernel */
+	uintptr_t	id;	/* generic id or pointer */
 };
 
 /*
@@ -189,7 +188,7 @@ struct new_inst {
 struct new_sch {
 	struct dn_id oid;
 	int sched_nr; /* N, scheduler number */
-	int bucket; /* number of buckets for the instances */
+	int buckets; /* number of buckets for the instances */
 	int flags;	/* have_mask, ... */
 
 	char type[16];	/* null terminated */

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c	Tue Jan 12 21:17:36 2010	(r202173)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c	Tue Jan 12 21:27:38 2010	(r202174)
@@ -77,14 +77,14 @@ heap_init(struct dn_heap *h, int new_siz
 	struct dn_heap_entry *p;
 
 	if (h->size >= new_size ) {
-		printf("%s: Bogus call, have %d want %d\n",
+		printf("--- %s: Bogus call, have %d want %d\n",
 			__func__, h->size, new_size);
 		return 0;
 	}
 	new_size = (new_size + HEAP_INCREMENT ) & ~HEAP_INCREMENT;
 	p = malloc(new_size * sizeof(*p), M_DN_HEAP, M_NOWAIT);
 	if (p == NULL) {
-		printf("%s, resize %d failed\n", __func__, new_size );
+		printf("--- %s, resize %d failed\n", __func__, new_size );
 		return 1; /* error */
 	}
 	if (h->size > 0) {
@@ -159,7 +159,7 @@ heap_extract(struct dn_heap *h, void *ob
 	int child, father, max = h->elements - 1;
 
 	if (max < 0) {
-		printf("%s: empty heap 0x%p\n", __FUNCTION__, h);
+		printf("--- %s: empty heap 0x%p\n", __FUNCTION__, h);
 		return;
 	}
 	if (obj == NULL)
@@ -309,8 +309,9 @@ dn_ht_init(struct dn_ht *ht, int buckets
 {
 	int l;
 
+	// printf("%s buckets %d ofs %d\n", __FUNCTION__, buckets, ofs);
 	if (h == NULL || match == NULL) {
-		printf("missing hash or match function");
+		printf("--- missing hash or match function");
 		return NULL;
 	}
 	if (buckets < 1 || buckets > 65536)
@@ -328,7 +329,7 @@ dn_ht_init(struct dn_ht *ht, int buckets
 	}
 	if (ht == NULL) {
 		l = sizeof(*ht) + buckets * sizeof(void **);
-		ht = malloc(l, M_DN_HEAP, M_NOWAIT);
+		ht = malloc(l, M_DN_HEAP, M_NOWAIT | M_ZERO);
 	}
 	if (ht) {
 		ht->ht = (void **)(ht + 1);
@@ -353,7 +354,10 @@ dn_ht_find(struct dn_ht *ht, uintptr_t k
 		(ht->hash(key, flags, ht->arg) % ht->buckets);
 	// log(1, "find %p in bucket %d\n", obj, i);
 	for (pp = &ht->ht[i]; (p = *pp); pp = (void **)((char *)p + ht->ofs)) {
-		if (ht->match(p, key, flags, ht->arg))
+		if (flags & DNHT_MATCH_PTR) {
+			if (key == (uintptr_t)p)
+				break;
+		} else if (ht->match(p, key, flags, ht->arg)) /* found match */
 			break;
 	}
 	if (p) {
@@ -364,7 +368,10 @@ dn_ht_find(struct dn_ht *ht, uintptr_t k
 			ht->entries--;
 		}
 	} 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;
+		// printf("%s new returns %p\n", __FUNCTION__, p);
 		if (p) {
 			ht->entries++;
 			*(void **)((char *)p + ht->ofs) = ht->ht[i];
@@ -374,24 +381,33 @@ dn_ht_find(struct dn_ht *ht, uintptr_t k
 	return p;
 }
 
+/*
+ * do a scan with the option to delete the object. Extract next before
+ * running the callback because the element may be destroyed there.
+ */
 int
 dn_ht_scan(struct dn_ht *ht, int (*fn)(void *, void *), void *arg)
 {
 	int i, ret, found = 0;
-	void *p, **prev;
+	void **curp, *cur, *next;
 
+	// printf("%p ht %p fn %p\n", __FUNCTION__, ht, fn);
+	if (ht == NULL || fn == NULL)
+		return 0;
 	for (i = 0; i < ht->buckets; i++) {
-		prev = &ht->ht[i];
-		while ( (p = *prev) != NULL) {
-			ret = fn(p, arg);
+		curp = &ht->ht[i];
+		while ( (cur = *curp) != NULL) {
+			next = *(void **)((char *)cur + ht->ofs);
+			ret = fn(cur, arg);
 			if (ret & HEAP_SCAN_DEL) {
 				found++;
 				ht->entries--;
-				*prev = *(void **)((char *)p + ht->ofs);
+				*curp = next;
+			} else {
+				curp = (void **)((char *)cur + ht->ofs);
 			}
 			if (ret & HEAP_SCAN_END)
 				return found;
-			prev = (void **)((char *)p + ht->ofs);
 		}
 	}
 	return found;
@@ -437,11 +453,11 @@ char *strings[] = {
 	NULL,
 };
 
-int doprint(void *_x, uintptr_t arg)
+int doprint(void *_x, void *arg)
 {
 	struct x *x = _x;
 	printf("found element <%s>\n", x->buf);
-	return arg;
+	return (int)arg;
 }
 
 static void

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.h	Tue Jan 12 21:17:36 2010	(r202173)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.h	Tue Jan 12 21:27:38 2010	(r202174)
@@ -110,9 +110,10 @@ enum {  /* flags values.
         DNHT_SCAN_DEL	= 0x0001,
         DNHT_SCAN_END	= 0x0002,
         DNHT_KEY_IS_OBJ	= 0x0004,	/* key is the obj pointer */
-        DNHT_INSERT	= 0x0008,	/* insert if not found */
-        DNHT_UNIQUE	= 0x0010,	/* report error if already there */
-        DNHT_REMOVE	= 0x0020,	/* remove on find */
+        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 */
 }; 
 int dn_ht_scan(struct dn_ht *, int (*)(void *, void *), void *);
 

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 12 21:17:36 2010	(r202173)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_fifo.c	Tue Jan 12 21:27:38 2010	(r202174)
@@ -36,7 +36,6 @@
 #include <netinet/ip_fw.h>	/* flow_id */
 #include <netinet/ip_dummynet.h>
 #include <netinet/ipfw/dn_heap.h>
-//#include <netinet/ipfw/ip_fw_private.h>
 #include <netinet/ipfw/ip_dn_private.h>
 #include <netinet/ipfw/dn_sched.h>
 
@@ -55,27 +54,20 @@
  *
  */
 
-/* A scheduler instance of a FIFO scheduler requires only a queue. */
-struct fifo_si {
-	struct new_queue *q;
-};
-
 static int 
 fifo_enqueue(struct new_sch_inst *_si, struct new_queue *q, struct mbuf *m)
 {
-    /* the queue is actually embedded here */
-    q = (struct new_queue *)(_si+1);
-    if (dn_queue_packet(q, m)) {
-	    printf("%s dn_queue_packet failed\n", __FUNCTION__);
-        /* packet was dropped */
-        return 1;
-    }
-
-    /* Ok, the packet is now in the queue.
-     * The dequeue() function will be called when the scheduler
-     * instance has credit to transmit packets
-     */
-    return 0;
+	int ret;
+	struct new_fsk *fs = (struct new_fsk *)q; /* q contains the fs */
+	q = (struct new_queue *)(_si+1);
+	q->fs = fs;
+	ret = dn_queue_packet(q, m);
+	q->fs = NULL;
+	if (ret) {
+		printf("%s dn_queue_packet dropped\n", __FUNCTION__);
+		return 1;
+	}
+	return 0;
 }
 
 static struct mbuf *
@@ -93,10 +85,9 @@ fifo_dequeue(struct new_sch_inst *_si)
      */
     
     /* Access scheduler instance private data */
-    struct fifo_si *si = (struct fifo_si *)(_si + 1);
-    struct new_queue *q = si->q;
+    struct new_queue *q = (struct new_queue *)(_si + 1);
 
-    if (q == NULL || q->mq.head == NULL)
+    if (q->mq.head == NULL)
         return NULL;
 
     return dn_return_packet(q);

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 12 21:17:36 2010	(r202173)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_wf2q.c	Tue Jan 12 21:27:38 2010	(r202174)
@@ -37,7 +37,6 @@
 #include <netinet/ip_fw.h>	/* flow_id */
 #include <netinet/ip_dummynet.h>
 #include <netinet/ipfw/dn_heap.h>
-//#include <netinet/ipfw/ip_fw_private.h>
 #include <netinet/ipfw/ip_dn_private.h>
 #include <netinet/ipfw/dn_sched.h>
 
@@ -56,16 +55,13 @@
  *
  */
 
-/* A scheduler instance of a FIFO scheduler requires only a queue. */
-struct fifo_si {
-	struct new_queue *q;
-};
-
 static int 
 fifo_enqueue(struct new_sch_inst *_si, struct new_queue *q, struct mbuf *m)
 {
-    /* the queue is actually embedded here */
+    struct new_fsk *fs = (struct new_fsk *)q;
+    /* the queue is actually the flowset. */
     q = (struct new_queue *)(_si+1);
+    q->fs = fs;
     if (dn_queue_packet(q, m)) {
 	    printf("%s dn_queue_packet failed\n", __FUNCTION__);
         /* packet was dropped */
@@ -94,10 +90,9 @@ fifo_dequeue(struct new_sch_inst *_si)
      */
     
     /* Access scheduler instance private data */
-    struct fifo_si *si = (struct fifo_si *)(_si + 1);
-    struct new_queue *q = si->q;
+    struct new_queue *q = (struct new_queue *)(_si + 1);
 
-    if (q == NULL || q->mq.head == NULL)
+    if (q->mq.head == NULL)
         return NULL;
 
     return dn_return_packet(q);

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 12 21:17:36 2010	(r202173)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c	Tue Jan 12 21:27:38 2010	(r202174)
@@ -237,10 +237,13 @@ mq_append(struct mq *q, struct mbuf *m)
 int
 dn_queue_packet(struct new_queue *q, struct mbuf* m)
 {   
-	struct new_fs *f = &(q->fs->fs);
-	struct new_inst *ni = &q->si->ni;
-	uint64_t len = m->m_pkthdr.len;
-
+	struct new_fs *f;
+	struct new_inst *ni;
+	uint64_t len;
+
+	f = &(q->fs->fs);
+	ni = &q->si->ni;
+	len = m->m_pkthdr.len;
 	/* Update statistics, then check reasons to drop pkt. */
 	q->ni.tot_bytes += len;
 	q->ni.tot_pkts++;
@@ -622,7 +625,7 @@ dummynet_io(struct mbuf **m0, int dir, s
 		if (q == NULL)
 			goto dropit;
 	} else {
-		q = NULL;
+		q = (void *)fs;
 	}
 	if (fs->sched->fp->enqueue(si, q, m)) {
 		printf("%s dropped by enqueue\n", __FUNCTION__);

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c	Tue Jan 12 21:17:36 2010	(r202173)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c	Tue Jan 12 21:27:38 2010	(r202174)
@@ -147,36 +147,26 @@ flow_id_mask(struct ipfw_flow_id *mask, 
 static int
 flow_id_hash(struct ipfw_flow_id *id)
 {
-    int i;
-    int is_v6 = IS_IP6_FLOW_ID(id);
+    uint32_t i;
 
-#define M 0xffff
-    if (is_v6) {
+    if (IS_IP6_FLOW_ID(id)) {
 	uint32_t *d = (uint32_t *)&id->dst_ip6;
 	uint32_t *s = (uint32_t *)&id->src_ip6;
-        i = (d[0] & M) ^ (d[1] & M) ^
-            (d[2] & M) ^ (d[3] & M) ^
-       
-            ((d[0] >> 15) & M) ^ ((d[1] >> 15) & M) ^
-            ((d[2] >> 15) & M) ^ ((d[3] >> 15) & M) ^
-            
-            ((s[0] << 1) & M) ^ ((s[1] << 1) & M) ^
-            ((s[2] << 1) & M) ^ ((s[3] << 1) & M) ^
-   
-            ((s[0] << 16) & M) ^ ((s[1] << 16) & M) ^
-            ((s[2] << 16) & M) ^ ((s[3] << 16) & M) ^
-        
+        i = (d[0]      ) ^ (d[1])       ^
+            (d[2]      ) ^ (d[3])       ^
+            (d[0] >> 15) ^ (d[1] >> 15) ^
+            (d[2] >> 15) ^ (d[3] >> 15) ^
+            (s[0] <<  1) ^ (s[1] <<  1) ^
+            (s[2] <<  1) ^ (s[3] <<  1) ^
+            (s[0] << 16) ^ (s[1] << 16) ^
+            (s[2] << 16) ^ (s[3] << 16) ^
             (id->dst_port << 1) ^ (id->src_port) ^
             (id->proto ) ^ (id->flow_id6);
     } else {
-        i = ( (id->dst_ip) & M ) ^
-            ( (id->dst_ip >> 15) & M ) ^
-            ( (id->src_ip << 1) & M ) ^
-            ( (id->src_ip >> 16 ) & M ) ^
-            (id->dst_port << 1) ^ (id->src_port) ^
-            (id->proto );
+        i = (id->dst_ip)        ^ (id->dst_ip >> 15) ^
+            (id->src_ip << 1)   ^ (id->src_ip >> 16) ^
+            (id->dst_port << 1) ^ (id->src_port)     ^ (id->proto);
     }
-#undef M
     return i;
 }
 
@@ -212,6 +202,32 @@ flow_id_cmp(struct ipfw_flow_id *id1, st
 
 /*--- support functions for the sch_inst hashtable ----*/
 
+static int
+si_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_sch_inst *)key)->ni.id :
+		(struct ipfw_flow_id *)key;
+	return flow_id_hash(id);
+}
+
+static int
+si_match(void *obj, uintptr_t key, int flags, void *arg)
+{
+	struct new_sch_inst *o;
+	struct ipfw_flow_id *id2;
+
+	if (flags & DNHT_KEY_IS_OBJ) {
+		/* compare pointers */
+		id2 = &((struct new_sch_inst *)key)->ni.id;
+	} else {
+		id2 = (struct ipfw_flow_id *)key;
+	}
+	o = (struct new_sch_inst *)obj;
+	return flow_id_cmp(&o->ni.id,  id2) == 0;
+}
+
 /*
  * create a new instance for the given 'key'
  * Allocate memory for instance, delay line and scheduler private data.
@@ -247,7 +263,7 @@ si_new(uintptr_t key, int flags, void *a
 	/* 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;
+		si->ni.id = *(struct ipfw_flow_id *)key;
 
 	dn_cfg.si_count++;
 	return si;
@@ -259,9 +275,8 @@ error:
 }
 
 /*
- * Delete a scheduler instance and all the queues. This is a callback
- * for the hashtable scan.
- * Also remove from the system heap.
+ * Callback for the hashtable scan.
+ * Remove si and delay line from the system heap, destroy all queues.
  */
 static int
 si_destroy(void *_si, void *arg)
@@ -313,34 +328,23 @@ ipdn_si_find(struct new_schk *s, struct 
  * support to delete a flowset. Mark as delete,
  * then check refcnt and free when it becomes 0
  */
-static void
-destroy_fs(struct new_fsk *fs)
+static int
+destroy_fs(void *obj, void *arg)
 {
+	struct new_fsk *fs = obj;
 	struct new_schk *s = fs->sched;
 
 	fs->kflags |= DN_DELETE;
-	if (fs->refcnt != 0)
-		return;
-	fs->sched = NULL;
-	dn_cfg.fsk_count--;
-	SLIST_REMOVE(&s->fsk_list, fs, new_fsk, sch_chain);
-}
-
-static struct new_fsk *
-create_fs(void)
-{
-	struct new_fsk *fs;
-
-	// XXX we could use the hashtable support
-	fs = malloc(sizeof(*fs), M_DUMMYNET, M_NOWAIT | M_ZERO);
-	if (fs) {
-		dn_ht_find(dn_cfg.fshash, (uintptr_t)fs,
-			DNHT_KEY_IS_OBJ | DNHT_INSERT | DNHT_UNIQUE);
-		dn_cfg.fsk_count++;
+	if (fs->refcnt == 0) {
+		fs->sched = NULL;
+		dn_cfg.fsk_count--;
+		SLIST_REMOVE(&s->fsk_list, fs, new_fsk, sch_chain);
+		free(fs, M_DUMMYNET);
 	}
-	return fs;
+	return HEAP_SCAN_DEL;
 }
 
+
 /*
  * helper for schedulers. Creates a queue
  * XXX actually, maybe only flowsets use this ?
@@ -382,82 +386,51 @@ dn_delete_queue(struct new_queue *q, int
 		SLIST_REMOVE(&q->si->ql_list, q, new_queue, ql_next);
 	if (q->mq.head)
 		dn_free_pkts(q->mq.head);
-	if (fs->sched->fp->free_queue)
+	if (fs && fs->sched->fp->free_queue)
 		fs->sched->fp->free_queue(q);
 	free(q, M_DUMMYNET);
-	fs->refcnt--;
 	dn_cfg.queue_count--;
-	if (fs->refcnt == 0 && fs->kflags & DN_DELETE)
-		destroy_fs(fs);
+	if (fs) {
+		fs->refcnt--;
+		if (fs->refcnt == 0 && fs->kflags & DN_DELETE)
+			destroy_fs(fs, NULL);
+	}
 	return 0;
 }
 
+/* destroy all scheduler instances but not the main scheduler */
 static struct new_schk *
-destroy_schk(struct new_schk *s)
+schk_flush(struct new_schk *s)
 {
-	struct dn_sched *fp = s->fp;
 
-	dn_ht_scan(s->siht, si_destroy, NULL);
-	if (fp->destroy)
-		fp->destroy(s, 1);
-	free(s, M_DUMMYNET);
-	dn_cfg.schk_count--;
+	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;
 }
 
-
-static int
-si_hash(uintptr_t key, int flags, void *arg)
-{
-	struct ipfw_flow_id *id = (flags & DNHT_KEY_IS_OBJ) ?
-		&((struct new_sch_inst *)key)->ni.id :
-		(struct ipfw_flow_id *)key;
-	return flow_id_hash(id);
-}
-
-
+/* callback to flush credit for the pipe */
 static int
-si_match(void *obj, uintptr_t key, int flags, void *arg)
+reset_credit(void *_si, void *arg)
 {
-	struct new_sch_inst *o;
-	struct ipfw_flow_id *id2;
+	struct new_sch_inst *si = _si;
+	struct new_pipe *p = &si->sched->pipe;
 
-	if (flags & DNHT_KEY_IS_OBJ) {
-		id2 = &((struct new_sch_inst *)key)->ni.id;
-	} else {
-		id2 = (struct ipfw_flow_id *)key;
-	}
-	o = (struct new_sch_inst *)obj;
-	return flow_id_cmp(&o->ni.id,  id2) == 0;
+	si->credit = p->burst + (dn_cfg.io_fast ?  p->bandwidth : 0);
+	return 0;
 }
 
-static struct new_schk *
-create_schk(struct dn_sched *fp, struct new_sch *sch)
+static void
+schk_reset_credit(struct new_schk *s)
 {
-	struct new_schk *s;
-	int l = sizeof(*s) + fp->schk_len;
-	
-	s = malloc(l, M_DUMMYNET, M_NOWAIT | M_ZERO);
-	if (s) {
-		set_oid(&s->pipe.oid, DN_PIPE, 0, sizeof(s->pipe));
-		s->fp = fp;
-		SLIST_INIT(&s->fsk_list);
-		/* initialize the hash table if needed. Otherwise,
-		 * ht points to the single instance we own
-		 */
-		if (sch->flags & DN_HAVE_MASK) {
-			s->siht = dn_ht_init(NULL, s->sch.buckets,
-				offsetof(struct new_sch_inst, si_next),
-				si_hash, /* hash */
-				si_match,/* MATCH */
-				si_new, /* new */
-				s /* arg */ );
-		}
-		dn_cfg.schk_count++;
-	}
-	return 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);
 }
 
+
 static int
 copy_obj(char **start, char *end, void *_o)
 {
@@ -493,7 +466,7 @@ copy_data_helper(void *_o, void *_arg)
 				return HEAP_SCAN_END;
 		}
 		if (a->flags & DN_C_SCH_INST) {
-			printf("scan sched instances");
+			printf("XXX todo: scan sched instances\n");
 		}
 	}
 	if (a->type == DN_FS) {	/* scanning flowsets */
@@ -504,24 +477,27 @@ copy_data_helper(void *_o, void *_arg)
 	return 0;
 }
 
+/* callback for sched delete */
+static int
+schk_del_cb(void *obj, void *arg)
+{
+	schk_flush((struct new_schk *)obj);
+	free(obj, M_DUMMYNET);
+	return HEAP_SCAN_DEL;
+}
+
 /*
  * Delete all objects:
- * - mark as shutting down;
- * - delete the heap;
- * - scan scheduler instances and remove all queues.
- * - remove all schedulers.
- * - remove all flowsets
  */
 static void
 dummynet_flush(void)
 {
 
 	DUMMYNET_LOCK();
-
-	/* Free all schedulers. Instances only go away this way. */
-	/* XXX implement delete functions */
-	dn_ht_scan(dn_cfg.schedhash, NULL, 0);
-	dn_ht_scan(dn_cfg.fshash, NULL, 0);
+	printf("%s start\n", __FUNCTION__);
+	/* first mark flowsets as delete, then go after queues */
+	dn_ht_scan(dn_cfg.fshash, destroy_fs, 0);
+	dn_ht_scan(dn_cfg.schedhash, schk_del_cb, 0);
 
 	/* Reinitialize system heap... */
 	heap_init(&dn_cfg.system_heap, 16);
@@ -592,7 +568,8 @@ do_config(void *p, int l)
 	return err;
 }
 
-static struct new_schk *
+static inline
+struct new_schk *
 locate_scheduler(int i)
 {
 	return dn_ht_find(dn_cfg.schedhash, i, 0);
@@ -602,46 +579,20 @@ locate_scheduler(int i)
 static void
 update_fs(struct new_schk *s)
 {
+	printf("%s to be implemented\n", __FUNCTION__);
 #if 0 // XXX to be completed
-	struct new_fsk *fs, *tmp;
-	/* first, scan the existing ones */
-	SLIST_FOREACH(fs, &s->fsk_list, sch_chain) {
-		fs->sched = s;
-		// XXX do we re-run the config ?
-	}
-	/* XXX we need a list of unlinked schedulers to
-	 * optimize this step */
-	SLIST_FOREACH_SAFE(fs, &dn_cfg.fshash, next, tmp) {
-		if (fs->fs.sched_nr != s->sch.sched_nr)
-			continue;
-		fs->sched = s;
-		dn_ht_remove(dn_cfg.fsunlinked, fs, 0);
-		SLIST_INSERT_HEAD(&s->fsk_list, fs, sch_chain);
-		dn_ht_find(dn_cfg.fsunlinked, fs, 0);
-		SLIST_INSERT_HEAD(&dn_cfg.fshash[HASH(fs->fs.fs_nr)], fs, next);
-		// XXX do we re-run the config ?
-	}
+	scan the children of s and see if they still apply.
+	scan fsunlinked and link all schedulers to s;
 #endif
 }
 
-/* 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);
-	return 0;
-}
-
 /*
  * Setup pipe parameters.
  */
 static int
 config_pipe(struct new_pipe *p, struct dn_id *arg)
 {
-	struct new_schk *sch;
+	struct new_schk *s;
 	int i;
 
 	if (p->oid.len < sizeof(*p)) {
@@ -663,17 +614,16 @@ config_pipe(struct new_pipe *p, struct d
 	p->burst *= 8 * hz;
 
 	DUMMYNET_LOCK();
-	sch = locate_scheduler(i);
-	if (sch == NULL) {
+	s = locate_scheduler(i);
+	if (s == NULL) {
 		DUMMYNET_UNLOCK();
-		printf("%s invalid scheduler number %d\n", __FUNCTION__,
-			i);
+		printf("%s sched %d not found\n", __FUNCTION__, i);
 		return EINVAL;
 	}
-	sch->pipe.delay = p->delay;
-	sch->pipe.bandwidth = p->bandwidth;
-	sch->pipe.burst = p->burst;
-	dn_ht_scan(sch->siht, reset_credit, NULL);
+	s->pipe.delay = p->delay;
+	s->pipe.bandwidth = p->bandwidth;
+	s->pipe.burst = p->burst;
+	schk_reset_credit(s);
 	dn_cfg.id++;
 	DUMMYNET_UNLOCK();
 	return 0;
@@ -689,9 +639,6 @@ config_sched(struct new_sch *nsch, struc
 	struct new_schk *s;
 	struct dn_sched *fp;
 	int i, is_new;
-	struct new_fsk_head fsk_list;
-
-	SLIST_INIT(&fsk_list);
 
 	if (nsch->oid.len != sizeof(*nsch)) {
 		printf("%s: bad sched len\n", __FUNCTION__);
@@ -700,6 +647,7 @@ config_sched(struct new_sch *nsch, struc
 	i = nsch->sched_nr;
 	if (i <= 0 || i > DN_MAXID)
 		return EINVAL;
+	printf("%s i %d\n", __FUNCTION__, i);
 	/* XXX other sanity checks */
 	fp = load_scheduler(nsch->oid.subtype, nsch->type);
 	if (fp == NULL) {
@@ -707,40 +655,41 @@ config_sched(struct new_sch *nsch, struc
 		return EINVAL;
 	}
 	nsch->oid.subtype = fp->type;
+	nsch->oid.id = (uintptr_t)fp;	/* used for  */
 	DUMMYNET_LOCK();
-	s = locate_scheduler(i);
+	// printf("%s i %d before ht_find\n", __FUNCTION__, i);
+	s = dn_ht_find(dn_cfg.schedhash, (uintptr_t)nsch,
+			DNHT_KEY_IS_OBJ | DNHT_INSERT);
+	// printf("%s i %d after ht_find\n", __FUNCTION__, i);
+	if (s == NULL) {
+		printf("cannot allocate scheduler\n");
+		return ENOMEM;
+	}
 	printf("%s type %s old %p\n", __FUNCTION__, fp->name, s);
 	/* Handle the following cases
 	 * 1. non existing before:
-	 *	create and setup
+	 *	initialize
 	 * 2. existing before, type changed
-	 *	destroy (perhaps preserve pipe), then #1
+	 *	destroy queues, then #1
 	 * 3. existing before, same type.
 	 *	update parameters and pipe
 	 */
-	if (s && s->fp != fp) {	/* type changed, hard delete */
-		dn_ht_find(dn_cfg.schedhash, (uintptr_t)s,
-			DNHT_KEY_IS_OBJ | DNHT_REMOVE);
-		/* preserve old pipe ? */
-		s = destroy_schk(s);
-	}
-	if (s) { /* case 3 */
-		is_new = 0;
-	} else { /* case 1 */
-		s = create_schk(fp, nsch);
-		if (s == NULL)
-			return ENOMEM;
-		s->pipe.pipe_nr = i;
-		dn_ht_find(dn_cfg.schedhash, (uintptr_t)s,
-			DNHT_KEY_IS_OBJ | DNHT_INSERT);
+	is_new = 0;
+	if (s->fp == NULL) { /* new scheduler, nothing to clean up */
 		is_new = 1;
+	} else if (s->fp != fp) { /* type changed, flush queues. */
+		// XXX we should reallocate the private data area.
+		// how do we do it ?
+		/* preserve old pipe ? */
+		schk_flush(s);
 	}
-	s->sch = *nsch;
+	/* complete initialization */
+	s->fp = fp;
 	s->cfg = arg;
 	/* call init function  */
 	if (s->fp->config)
-		s->fp->config(s, is_new);
-	dn_ht_scan(s->siht, reset_credit, NULL);
+		s->fp->config(s, 1);
+	schk_reset_credit(s);
 	if (is_new)
 		update_fs(s);
 	dn_cfg.id++;
@@ -757,7 +706,7 @@ config_fs(struct new_fs *nfs, struct dn_
 {
 	struct new_fsk *fs;
 	struct new_schk *s;
-	int i, s_changed;
+	int i;
 
 	if (nfs->oid.len < sizeof(*nfs)) {
 		printf("%s: short flowset\n", __FUNCTION__);
@@ -766,6 +715,7 @@ config_fs(struct new_fs *nfs, struct dn_
 	i = nfs->fs_nr;
 	if (i <= 0 || i > DN_MAXID)
 		return EINVAL;
+	printf("%s i %d\n", __FUNCTION__, i);
 	/* XXX other sanity checks */
         if (nfs->flags & DN_QSIZE_IS_BYTES) {
                 if (nfs->qsize > dn_cfg.pipe_byte_limit)
@@ -778,31 +728,25 @@ config_fs(struct new_fs *nfs, struct dn_
         }
 
 	DUMMYNET_LOCK();
-	fs = ipdn_locate_flowset(i);
+again:
+	fs =  dn_ht_find(dn_cfg.fshash, i, DNHT_INSERT);
 
 	if (fs == NULL) {
-		fs = create_fs();
-		if (fs == NULL) {
-			DUMMYNET_UNLOCK();
-			return ENOMEM;
-		}
+		DUMMYNET_UNLOCK();
+		return ENOMEM;
 	}
 	fs->fs = *nfs;	/* update config */
-	/* copy values, check if scheduler exists and mark active */
 	s = locate_scheduler(nfs->sched_nr);
-	s_changed = s == NULL || fs->sched == NULL || fs->sched->fp != s->fp;
-	/*
-	 * Handle the following cases
-	 * 1. same scheduler as before (either none or the same)
-	 *	do nothing
-	 * 2. No scheduler before, have one now:
-	 *	link to the new scheduler
-	 * 3. scheduler before, none now
-	 *	leave the queues with the old scheduler ?
-	 *	in case, simply remove them from the fht
-	 * 4. scheduler before, different one now
-	 *	do #3 then #2
-	 */
+	if (fs->sched == NULL) { /* no scheduler before, link */
+		if (s) {
+			fs->sched = s;
+			// XXX remove_from_unlinked(fs);
+		}
+	} else if (fs->sched != s) {
+		/* scheduler changed. Mark old fs and recreate */
+		fs->kflags |= DN_DELETE;
+		goto again;
+	}
 	dn_cfg.id++;
 	DUMMYNET_UNLOCK();
 	return 0;
@@ -1020,6 +964,12 @@ ip_dn_ctl(struct sockopt *sopt)
     return error ;
 }
 
+/*
+ * Scheduler hash. When searching by index we pass sched_nr,
+ * otherwise we pass struct new_sch * which is the first field in
+ * struct new_schk so we can cast it. We need this info during the
+ * create phase, where we put the dn_sched * in oid.id
+ */
 static int
 schk_hash(uintptr_t key, int flags, void *arg)
 {
@@ -1029,6 +979,53 @@ schk_hash(uintptr_t key, int flags, void
 }
 
 static int
+schk_match(void *obj, uintptr_t key, int flags, void *arg)
+{
+	int i = ((flags & DNHT_KEY_IS_OBJ) == 0) ? key :
+		((struct new_schk *)key)->sch.sched_nr;
+	return ((struct new_schk *)obj)->sch.sched_nr == i;
+}
+
+/*
+ * Create the entry and intialize with the sched hash if needed.
+ * XXX how do we tell between an old and a brand new thing ?
+ * perhaps do not initialize s->fp ?
+ */
+static void *
+schk_new(uintptr_t key, int flags, void *arg)
+{
+	struct new_schk *s;
+	struct new_sch *sch = (struct new_sch *)key;
+	struct dn_sched *fp = (struct dn_sched *)sch->oid.id;
+	int l = sizeof(*s) + fp->schk_len;
+	
+// printf("%s key %p fp %p\n", __FUNCTION__, sch, fp);
+	s = malloc(l, M_DUMMYNET, M_NOWAIT | M_ZERO);
+	if (s == NULL)
+		return NULL;
+	set_oid(&s->pipe.oid, DN_PIPE, 0, sizeof(s->pipe));
+	s->sch = *sch; // copy initial values
+	s->pipe.pipe_nr = sch->sched_nr;
+	SLIST_INIT(&s->fsk_list);
+	/* initialize the hash table if needed. Otherwise,
+	 * ht points to the single instance we own
+	 */
+	if (sch->flags & DN_HAVE_MASK) {
+		s->siht = dn_ht_init(NULL, s->sch.buckets,
+			offsetof(struct new_sch_inst, si_next),
+			si_hash, /* hash */
+			si_match,/* MATCH */
+			si_new, /* new */
+			s /* arg */ );
+	}
+	dn_cfg.schk_count++;
+	return s;
+}
+
+/*
+ * flowset hash support
+ */
+static int
 fsk_hash(uintptr_t key, int flags, void *arg)
 {
 	int i = ((flags & DNHT_KEY_IS_OBJ) == 0) ? key :
@@ -1037,6 +1034,28 @@ fsk_hash(uintptr_t key, int flags, void 
 	return ( (i>>8)^(i>>4)^i );
 }
 
+/* matck skips those marked as deleted */
+static int
+fsk_match(void *obj, uintptr_t key, int flags, void *arg)
+{
+	struct new_fsk *fs = obj;
+	int i = ((flags & DNHT_KEY_IS_OBJ) == 0) ? key :
+		((struct new_fsk *)key)->fs.fs_nr;
+	return !(fs->kflags & DN_DELETE) && fs->fs.fs_nr == i;
+}
+
+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.fsunlinked, fs, sch_chain);
+	return fs;
+}
+
 static void
 ip_dn_init(void)
 {
@@ -1048,19 +1067,16 @@ ip_dn_init(void)
 	if (bootverbose)
 		printf("DUMMYNET with IPv6 initialized (100131)\n");
 
-	/* create hash tables */
+	/* create hash tables for schedulers and flowsets.
+	 * In both we search by key and by pointer.
+	 * Insertion in schedhash uses externally allocated objects.
+	 */
 	dn_cfg.schedhash = dn_ht_init(NULL, dn_cfg.buckets,
 		offsetof(struct new_schk, schk_next),
-		schk_hash,
-		NULL, /* match */
-		NULL, /* new */
-		NULL);
+		schk_hash, schk_match, schk_new, NULL);
 	dn_cfg.fshash = dn_ht_init(NULL, dn_cfg.buckets,
 		offsetof(struct new_fsk, fsk_next),
-		fsk_hash,
-		NULL, /* match */
-		NULL, /* new */
-		NULL);
+		fsk_hash, fsk_match, fsk_new, NULL);
 
 	SLIST_INIT(&dn_cfg.fsunlinked);
 	SLIST_INIT(&list_of_scheduler);
@@ -1109,8 +1125,8 @@ dummynet_modevent(module_t mod, int type
 	switch (type) {
 	case MOD_LOAD:
 		if (ip_dn_io_ptr) {
-		    printf("DUMMYNET already loaded\n");
-		    return EEXIST ;
+			printf("DUMMYNET already loaded\n");
+			return EEXIST ;
 		}
 		ip_dn_init();
 		break;
@@ -1171,7 +1187,6 @@ unload_descriptor(struct dn_sched *s)
 	printf("%s %s called\n", __FUNCTION__, s->name);
 
 	DUMMYNET_LOCK();
-
 	SLIST_FOREACH_SAFE(r, &list_of_scheduler, next, tmp) {
 		if (strcmp(s->name, r->name) != 0)
 			continue;



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