svn commit: r202174 - in user/luigi/ipfw3-head/sys/netinet: . ipfw
Luigi Rizzo
luigi at FreeBSD.org
Tue Jan 12 21:27:38 UTC 2010
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;
More information about the svn-src-user
mailing list