Date: Tue, 19 Jan 2010 13:33:54 +0000 (UTC) From: Luigi Rizzo <luigi@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r202625 - in user/luigi/ipfw3-head/sys/netinet: . ipfw Message-ID: <201001191333.o0JDXsY8003738@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: luigi Date: Tue Jan 19 13:33:54 2010 New Revision: 202625 URL: http://svn.freebsd.org/changeset/base/202625 Log: revise the detach/reconfigure paths 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_sched.h 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_dn_private.h 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 19 13:33:31 2010 (r202624) +++ user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h Tue Jan 19 13:33:54 2010 (r202625) @@ -259,7 +259,5 @@ flow using a number of heaps defined int #define DN_QSIZE_IS_BYTES 0x0008 /* queue size is measured in bytes */ #define DN_NOERROR 0x0010 /* do not report ENOBUFS on drops */ #define DN_HAS_PROFILE 0x0020 /* the pipe has a delay profile. */ -#define DN_IS_PIPE 0x4000 -#define DN_IS_QUEUE 0x8000 #endif /* _IP_DUMMYNET_H */ Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c ============================================================================== --- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c Tue Jan 19 13:33:31 2010 (r202624) +++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c Tue Jan 19 13:33:54 2010 (r202625) @@ -386,6 +386,8 @@ dn_ht_find(struct dn_ht *ht, uintptr_t k int i; void **pp, *p; + if (ht == NULL) /* easy on an empty hash */ + return NULL; i = (ht->buckets == 1) ? 0 : (ht->hash(key, flags, arg) % ht->buckets); // printf("%s key %p in bucket %d\n", __FUNCTION__, (void *)key, i); Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h ============================================================================== --- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h Tue Jan 19 13:33:31 2010 (r202624) +++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h Tue Jan 19 13:33:54 2010 (r202625) @@ -94,9 +94,12 @@ struct dn_sched { * * new_queue called to set the per-queue parameters, * e.g. S and F, adjust sum of weights in the parent, etc. + * If the queue has packets in it, add them to the scheduler + * as well. * * free_queue actions related to a queue removal, e.g. undo - * all the above. + * all the above. If the queue has data in it, also remove + * from the scheduler. This can e.g. happen during a reconfigure. */ int (*enqueue)(struct new_sch_inst *, struct new_queue *, struct mbuf *); @@ -120,7 +123,7 @@ struct dn_sched { * if do_free is set, propagate to the flowset and destroy it * if the refcount becomes 0 */ -int dn_delete_queue(void *, void *do_free); +struct new_queue *dn_delete_queue(struct new_queue *, int do_free); int dn_enqueue(struct new_queue *q, struct mbuf* m, int drop); /* @@ -141,7 +144,7 @@ dn_dequeue(struct new_queue *q) 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, (void *)1 /* free if possible */); + (void)dn_delete_queue(q, 1 /* free if possible */); return m; } 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 19 13:33:31 2010 (r202624) +++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_wf2q.c Tue Jan 19 13:33:54 2010 (r202625) @@ -111,15 +111,13 @@ wf2qp_enqueue(struct new_sch_inst *_si, struct wf2qp_si *si = (struct wf2qp_si *)(_si + 1); struct wf2qp_queue *alg_fq; uint64_t len = m->m_pkthdr.len; - int q_was_idle; - q_was_idle = (q->mq.head == NULL); - - if (dn_enqueue(q, m, 0)) /* packet was dropped */ - return 1; - - if (!q_was_idle) - return 0; + if (m != q->mq.head) { + if (dn_enqueue(q, m, 0)) /* packet was dropped */ + return 1; + if (m != q->mq.head) /* queue was already busy */ + return 0; + } /* If reach this point, queue q was idle */ alg_fq = (struct wf2qp_queue *)(q+1); @@ -238,8 +236,8 @@ wf2qp_new_sched(struct new_sch_inst *_si /* only idle-heap supports extract from middle */ if (heap_init(&si->idle_heap, 16, ofs) || - heap_init(&si->sch_heap, 16, -1) || - heap_init(&si->ne_heap, 16, -1)) { + heap_init(&si->sch_heap, 16, ofs) || + heap_init(&si->ne_heap, 16, ofs)) { heap_free(&si->ne_heap); heap_free(&si->sch_heap); heap_free(&si->idle_heap); @@ -279,6 +277,9 @@ wf2qp_new_queue(struct new_queue *_q) _q->ni.oid.subtype = DN_SCHED_WF2QP; q->F = 0; /* not strictly necessary */ q->S = q->F + 1; /* mark timestamp as invalid. */ + if (_q->mq.head != NULL) { + wf2qp_enqueue(_q->si, _q, _q->mq.head); + } return 0; } @@ -286,11 +287,24 @@ static int wf2qp_free_queue(struct new_queue *q) { struct wf2qp_queue *alg_fq = (struct wf2qp_queue *)(q + 1); + struct wf2qp_si *si = (struct wf2qp_si *)(q->si + 1); + printf("%s called\n", __FUNCTION__); /* If the queue was valid, decrement the sum value */ - if (alg_fq->S != alg_fq->F + 1) { - struct wf2qp_si *si = (struct wf2qp_si *)(q->si + 1); - si->sum -= q->fs->fs.weight; + if (alg_fq->S == alg_fq->F + 1) + return 0; /* nothing to do, not in any heap */ + /* decrement the sum of weights */ + si->sum -= q->fs->fs.weight; + + /* extract from the heap. Note that we may need to adjust V + * to make sure the invariants hold. + */ + if (q->mq.head == NULL) { + heap_extract(&si->idle_heap, q); + } else if (DN_KEY_LT(si->V, alg_fq->S)) { + heap_extract(&si->ne_heap, q); + } else { + heap_extract(&si->sch_heap, q); } return 0; } 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 19 13:33:31 2010 (r202624) +++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c Tue Jan 19 13:33:54 2010 (r202625) @@ -545,6 +545,7 @@ tag_mbuf(struct mbuf *m, int dir, struct return 0; } + /* * dummynet hook for packets. * We use the argument to locate the flowset fs and the sched_set sch @@ -588,17 +589,7 @@ dummynet_io(struct mbuf **m0, int dir, s * We cannot pass si as an argument :( */ if (fs->sched->fp->flags & DN_MULTIQUEUE) { - struct new_queue template; - template.si = si; - template.fs = fs; - if (fs->fs.flags & DN_HAVE_MASK) { - q = dn_ht_find(fs->qht, (uintptr_t)&(fwa->f_id), - DNHT_INSERT, &template); - } else { /* qht is simply a queue */ - if (fs->qht == NULL) - fs->qht = q_new(0, 0, &template); - q = (struct new_queue *)fs->qht; - } + q = ipdn_q_find(fs, si, &(fwa->f_id)); if (q == NULL) goto dropit; } Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h ============================================================================== --- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h Tue Jan 19 13:33:31 2010 (r202624) +++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h Tue Jan 19 13:33:54 2010 (r202625) @@ -137,7 +137,7 @@ struct new_fsk { /* kernel side of a flo /* hash table of queues. XXX if we have no flow_mask we could * avoid the hash table and just allocate one queue. */ - struct dn_ht *qht; + struct dn_ht *_qht; struct new_schk *sched; /* Sched we are linked to */ SLIST_ENTRY(new_fsk) sch_chain; /* list of fsk attached to sched */ void *sched_info; /* scheduler-specific info */ @@ -207,9 +207,11 @@ struct new_sch_inst { /* kernel-side flags */ enum { DN_DELETE = 0x0004, /* destroy when refcnt=0 */ + DN_DELETE_FS = 0x0008, /* destroy when refcnt=0 */ DN_ACTIVE = 0x0010, /* object is in evheap */ DN_F_DLINE = 0x0020, /* object is a delay line */ DN_F_SCHI = 0x0030, /* object is a sched.instance */ + DN_QHT_IS_Q = 0x0100, /* in flowset, qht is a single queue */ }; extern struct dn_parms dn_cfg; @@ -218,8 +220,9 @@ int dummynet_io(struct mbuf **, int , st void dummynet_task(void *context, int pending); void dn_reschedule(void); -struct new_sch_inst *ipdn_si_find(struct new_schk *s, struct ipfw_flow_id *id); -void * q_new(uintptr_t key, int flags, void *arg); +struct new_queue *ipdn_q_find(struct new_fsk *fs, struct new_sch_inst *si, + struct ipfw_flow_id *id); +struct new_sch_inst *ipdn_si_find(struct new_schk *s, struct ipfw_flow_id *id); #endif /* _IP_DN_PRIVATE_H */ Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c ============================================================================== --- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c Tue Jan 19 13:33:31 2010 (r202624) +++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c Tue Jan 19 13:33:54 2010 (r202625) @@ -230,7 +230,7 @@ q_match(void *obj, uintptr_t key, int fl /* * create a new queue instance for the given 'key'. */ -void * +static void * q_new(uintptr_t key, int flags, void *arg) { struct new_queue *q, *template = arg; @@ -410,90 +410,92 @@ fsk_new(uintptr_t key, int flags, void * } return fs; } +/*----- end of flowset hashtable support -------------*/ -static int schk_del_cb(void *obj, void *arg); /* - * 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. + * Delete a queue. The version for callbacks is called q_delete_cb(). + * Call the 'free_queue' routine on the scheduler. + * If do_free is set, also free the packets. */ -static void -fsk_destroy(struct new_fsk *fs, int do_free) +struct new_queue * +dn_delete_queue(struct new_queue *q, int do_free) { - struct new_fsk_head *h; + struct new_fsk *fs = q->fs; - fs->kflags |= DN_DELETE; - if (fs->refcnt != 0) - return; - /* 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--; - if (fs->sched && fs->sched->fp->free_fsk) - fs->sched->fp->free_fsk(fs); - /* XXX possibly notify the event to the scheduler */ - if (fs->sched != NULL && (fs->sched->kflags & DN_DELETE) && - SLIST_FIRST(&fs->sched->fsk_list) == NULL) { - printf("scheduler %p should be deleted\n", fs->sched); - dn_ht_find(dn_cfg.schedhash, (uintptr_t)(fs->sched), - DNHT_KEY_IS_OBJ | DNHT_MATCH_PTR | DNHT_REMOVE, NULL); - schk_del_cb(fs->sched, NULL); - } - - fs->sched = NULL; - if (do_free) { - if (fs->qht) /* only if DN_HAVE_MASK */ - dn_ht_free(fs->qht, 0); - free(fs, M_DUMMYNET); - } + printf(" +++ %s fs %p si %p\n", __FUNCTION__, fs, q->si); + /* notify the parent scheduler that the queue is going away */ + if (fs && fs->sched->fp->free_queue) + fs->sched->fp->free_queue(q); + if (!do_free) + return q; + if (q->mq.head) + dn_free_pkts(q->mq.head); + free(q, M_DUMMYNET); + dn_cfg.queue_count--; + fs->refcnt--; + return NULL; +} + +static int +q_delete_cb(void *q, void *arg) +{ + (void)dn_delete_queue(q, (int)(uintptr_t)arg); + return 0; } -/*----- end of flowset hashtable support -------------*/ /* - * delete the queues in qht, consider the presence of a flow_mask + * calls dn_delete_queue/q_delete_cb on all queues, + * which notifies the parent scheduler and possibly drains packets. + * flags & DN_DELETE: drains queues and destroy qht; */ static void -delete_qht(struct new_fsk *fs) +qht_delete(struct new_fsk *fs, int flags) { - if (fs->fs.flags & DN_HAVE_MASK) - dn_ht_scan(fs->qht, dn_delete_queue, NULL); - else { - dn_delete_queue(fs->qht, NULL); - fs->qht = NULL; + printf("+++ %s fs %d start\n", __FUNCTION__, fs->fs.fs_nr); + if (!fs->_qht) + return; + if (fs->kflags & DN_QHT_IS_Q) { + fs->_qht = (struct dn_ht *)dn_delete_queue((struct new_queue *)(fs->_qht), flags); + } else { + dn_ht_scan(fs->_qht, q_delete_cb, (void *)flags); + if (flags & DN_DELETE) { + dn_ht_free(fs->_qht, 0); + fs->_qht = NULL; + } } } /* - * Destroy all flowsets in a list. Used when deleting a scheduler, + * Detach or 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 + * int_fs points to an internal flowset which must be handled differently. + * flags specifies what to do: + * DN_DELETE flush all queues + * DN_DELETE_FS DN_DELETE + destroy flowset + * DN_DELETE_FS implies DN_DELETE */ static void -fsk_destroy_list(struct new_fsk_head *h, struct new_fsk *int_fs) +fsk_detach_list(struct new_fsk_head *h, struct new_fsk *int_fs, int flags) { struct new_fsk *fs; + if (flags & DN_DELETE_FS) + flags |= DN_DELETE; + printf("+++ %s head %p flags %x\n", __FUNCTION__, h, flags); while ((fs = SLIST_FIRST(h))) { SLIST_REMOVE_HEAD(h, sch_chain); + printf(" +++ %s child fs %d\n", __FUNCTION__, fs->fs.fs_nr); if (fs == int_fs) { /* free the internal flowset. */ free(fs, M_DUMMYNET); dn_cfg.fsk_count--; continue; } - /* drain queues, but pass NULL so the fs is not deleted. - * We cannot destroy it from the callback or it - * would kill the hashtable as well. After the pass, - * refcnt is surely 0. - * If the flowset was marked delete, destroy it. - * otherwise move it to fsunlinked. - */ - delete_qht(fs); + /* detach queues from the scheduler and possibly drain them */ + qht_delete(fs, flags); fs->sched = NULL; - if (fs->kflags & DN_DELETE) { - if (fs->qht) - dn_ht_free(fs->qht, 0); + if (flags & DN_DELETE_FS) { + bzero(fs, sizeof(fs)); /* safety */ free(fs, M_DUMMYNET); } else { SLIST_INSERT_HEAD(&dn_cfg.fsu, fs, sch_chain); @@ -501,26 +503,6 @@ fsk_destroy_list(struct new_fsk_head *h, } } -/* - * Delete a queue (helper for the schedulers and callback) - */ -int -dn_delete_queue(void *_q, void *do_free) -{ - struct new_queue *q = _q; - struct new_fsk *fs = q->fs; - - 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--; - fs->refcnt--; - if (fs->refcnt == 0 && fs->kflags & DN_DELETE) - fsk_destroy(fs, (int)do_free); - return 0; -} /* callback to flush credit for the pipe */ static int @@ -600,49 +582,69 @@ copy_data_helper(void *_o, void *_arg) } /* - * Callback for sched delete. Tell all attached flowsets to - * remove their queues, unlink the flowsets. + * Callback for sched delete. Notify all attached flowsets to + * detach from the scheduler, destroy the internal flowset, and + * all instances. + * arg is 0 (only detach flowsets and destroy instances) + * DN_DELETE (detach & delete queues, delete schk) + * or DN_DELETE_FS (delete queues and flowsets, delete schk) */ static int -schk_del_cb(void *obj, void *arg) +schk_delete_cb(void *obj, void *arg) { struct new_schk *s = obj; - if (s->fs) { + printf("+++ %s sched %d arg %d\n", __FUNCTION__, s->sch.sched_nr, (int)arg); + if (arg && 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); + fsk_detach_list(&s->fsk_list, s->fs, arg ? DN_DELETE : 0); /* 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; + if (arg) { + free(obj, M_DUMMYNET); + dn_cfg.schk_count--; + return HEAP_SCAN_DEL; + } else + return 0; } + /* - * Delete all objects: + * only called in the DN_MULTIQUEUE CASE so we can handle errors + * in a better way. */ -static void -dummynet_flush(void) -{ - - DUMMYNET_LOCK(); - /* 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)); - - DUMMYNET_UNLOCK(); +struct new_queue * +ipdn_q_find(struct new_fsk *fs, struct new_sch_inst *si, + struct ipfw_flow_id *id) +{ + struct new_queue template; + template.si = si; + template.fs = fs; + + if (fs->fs.flags & DN_HAVE_MASK) { + if (fs->_qht == NULL) { + fs->_qht = dn_ht_init(NULL, fs->fs.buckets, + offsetof(struct new_queue, q_next), + q_hash, q_match, q_new); + if (fs->_qht == NULL) + return NULL; + fs->kflags &= ~DN_QHT_IS_Q; + } + return dn_ht_find(fs->_qht, (uintptr_t)id, + DNHT_INSERT, &template); + } else { + if (fs->_qht == NULL) + fs->_qht = q_new(0, 0, &template); + fs->kflags |= DN_QHT_IS_Q; + return (struct new_queue *)fs->_qht; + } } - static inline struct new_schk * locate_scheduler(int i) { @@ -664,6 +666,10 @@ update_fs(struct new_schk *s) SLIST_REMOVE(&dn_cfg.fsu, fs, new_fsk, sch_chain); fs->sched = s; SLIST_INSERT_HEAD(&s->fsk_list, fs, sch_chain); + if (!fs->_qht) + continue; + printf("+++ %s requeue from fs %d to sch %d\n", + __FUNCTION__, fs->fs.fs_nr, s->sch.sched_nr); } } @@ -780,6 +786,24 @@ config_fs(struct new_fs *nfs, struct dn_ dn_cfg.id++; if (bcmp(&fs->fs, nfs, sizeof(*nfs)) == 0) break; /* no change, nothing to do */ + s = locate_scheduler(nfs->sched_nr); +/* XXX TODO +Configuration and reconfiguration handling. +A new flowset, or one with fs->sched == NULL, has no queues. +- if it is still unattached we have nothing to do; +- if s != NULL, remove from unlinked and add to the children + of s, possibly creating the hash table (or we can postpone + it to when the first packet arrives); + +A flowset with fs->sched != NULL and with queues we have two options: +- if it becomes unlinked, then simply destroy the queues notifying + the old scheduler. +- if it becomes linked, we also need to re-enqueue the packets on + the new scheduler. + There are some easy cases (e.g. flow_mask unchanged) but + in general we should really work on every single packet. + */ + fs->fs = *nfs; /* update config */ /* * XXX note that if we modify some scheduler-specific @@ -787,8 +811,12 @@ config_fs(struct new_fs *nfs, struct dn_ * scheduler otherwise things might go really badly, * such as sum-of-weights mismatches. */ - s = locate_scheduler(nfs->sched_nr); if (fs->sched != NULL) { + /* XXX TODO: if the scheduler does not exist + * anymore, then all queues should be drained. + * If there is a new scheduler, then move + * queues from the old to the new one. + */ /* we had a scheduler before, let the flowset * die and create a new one with the new * parameters. @@ -805,14 +833,7 @@ config_fs(struct new_fs *nfs, struct dn_ SLIST_REMOVE(&dn_cfg.fsu, fs, new_fsk, sch_chain); fs->sched = s; SLIST_INSERT_HEAD(&s->fsk_list, fs, sch_chain); - /* only create the hash table if the scheduler supports - * multiple queues and we have a flow mask. - */ - if (s->fp->flags & DN_MULTIQUEUE && - fs->fs.flags & DN_HAVE_MASK) - fs->qht = dn_ht_init(NULL, nfs->buckets, - offsetof(struct new_queue, q_next), - q_hash, q_match, q_new); + /* _qht is initialized on first use */ if (s->fp->new_fsk) s->fp->new_fsk(fs); } while (0); @@ -830,7 +851,6 @@ config_sched(struct new_sch *_nsch, stru { struct new_schk *s; struct schk_new_arg a; /* argument for schk_new */ - struct new_fsk_head *pending = NULL; int i, notify_fs = 0; a.sch = _nsch; @@ -859,27 +879,21 @@ again: /* run twice, for wfq and fifo */ 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 != a.fp) { - printf("sched %d type changed from %s to %s" - " let it drain and reallocate\n", - i, s->fp->name, a.fp->name); - /* mark delete so it won't be matched. - * XXX todo: make it die when its queues are done. - * XXX otherwise do a real delete. - * XXX Reconfiguration should be done differently, - * removing packets from the old scheduler and - * requeueing to the new one. Otherwise we can have - * reordering and unwanted effects. + if (s->fp != NULL) { + /* in all other cases, remove from the heaps, + * and detach flowsets from + * the old one almost as in sched_delete, but + * preserve traffic. + * XXX what about the internal queue ? */ - s->kflags |= DN_DELETE; + printf("sched %d type changed from %s to %s\n", + i, s->fp->name, a.fp->name); + schk_delete_cb(s, NULL); notify_fs = 1; - pending = &s->fsk_list; - goto again; + /* now we have nothing pointing to us */ } /* complete initialization */ + s->sch = *a.sch; s->fp = a.fp; s->cfg = arg; // XXX schk_reset_credit(s); @@ -899,20 +913,7 @@ 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 (pending) { - struct new_fsk *fs; - /* XXX should do the requeue here */ - /* mark and clone flowsets for the old scheduler */ - SLIST_FOREACH(fs, pending, sch_chain) { - int dying = fs->kflags & DN_DELETE; - fs->kflags |= DN_DELETE; - if (!dying) /* clone if necessary */ - config_fs(&fs->fs, NULL, 1 /* locked */); - } - pending = NULL; - } - if (notify_fs) - update_fs(s); + update_fs(s); if (i < DN_MAX_ID) { /* update the FIFO instance */ i += DN_MAX_ID; a.sch->sched_nr = i; @@ -983,35 +984,70 @@ config_profile(struct new_profile *pf, s return 0; } +/* + * called on 'queue X delete' -- removes the flowset from fshash, + * deletes all queues for the flowset, and removes the flowset. + */ static int -del_fs(int i) +delete_fs(int i) { + struct new_fsk_head *h; struct new_fsk *fs; fs = dn_ht_find(dn_cfg.fshash, i, DNHT_REMOVE, NULL); printf("%s fs %d found %p\n", __FUNCTION__, i, fs); if (fs == NULL) return EINVAL; - // XXX not sure if we want to kill the queues now - if (0 && fs->qht) - dn_ht_scan(fs->qht, dn_delete_queue, NULL); - fsk_destroy(fs, 1 /* do free the object */); + + /* 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--; + qht_delete(fs, 1); /* get rid of the queues */ + /* XXX possibly notify the event to the scheduler */ + if (fs->sched && fs->sched->fp->free_fsk) + fs->sched->fp->free_fsk(fs); + fs->sched = NULL; + free(fs, M_DUMMYNET); return 0; } +/* + * called on a 'sched X delete' command. Deletes a single scheduler. + * This is done by removing from the schedhash, unlinking all + * flowsets and deleting their traffic. + */ static int -del_schk(int i) +delete_schk(int i) { struct new_schk *s; 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 { + if (!s) return EINVAL; - } + /* detach flowsets, delete traffic */ + schk_delete_cb(s, (void*)(uintptr_t)DN_DELETE); + return 0; +} + +/* + * Delete all objects: + */ +static void +dummynet_flush(void) +{ + + DUMMYNET_LOCK(); + /* all schedulers and related pipes/queues/flowsets */ + dn_ht_scan(dn_cfg.schedhash, schk_delete_cb, + (void *)(uintptr_t)DN_DELETE_FS); + /* all remaining (unlinked) flowsets */ + fsk_detach_list(&dn_cfg.fsu, NULL, DN_DELETE_FS); + /* Reinitialize system heap... */ + heap_init(&dn_cfg.evheap, 16, offsetof(struct dn_id, id)); + + DUMMYNET_UNLOCK(); } /* @@ -1025,7 +1061,7 @@ static int do_config(void *p, int l) { struct dn_id *next, *o; - int err = 0; + int err = 0, err2 = 0; struct dn_id *arg = NULL; for (o = p; l >= sizeof(*o); o = next) { @@ -1050,9 +1086,12 @@ do_config(void *p, int l) switch (o->subtype) { case DN_PIPE: /* delete base and derived schedulers */ - if ( (err = del_schk(o->id)) ) - break; - err = del_schk(o->id + DN_MAX_ID); + DUMMYNET_LOCK(); + err = delete_schk(o->id); + err2 = delete_schk(o->id + DN_MAX_ID); + DUMMYNET_UNLOCK(); + if (!err) + err = err2; break; default: @@ -1063,7 +1102,7 @@ do_config(void *p, int l) case DN_FS: err = (o->id < 1 || o->id >= DN_MAX_ID) ? - EINVAL : del_fs(o->id) ; + EINVAL : delete_fs(o->id) ; break; } break;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201001191333.o0JDXsY8003738>