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>