Date: Fri, 15 Jan 2010 16:24:58 +0000 (UTC) From: Luigi Rizzo <luigi@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r202390 - in user/luigi/ipfw3-head: sbin/ipfw sys/netinet/ipfw Message-ID: <201001151624.o0FGOwtx025874@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201001151624.o0FGOwtx025874>