svn commit: r202625 - in user/luigi/ipfw3-head/sys/netinet: . ipfw
Luigi Rizzo
luigi at FreeBSD.org
Tue Jan 19 13:33:54 UTC 2010
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;
More information about the svn-src-user
mailing list