svn commit: r202390 - in user/luigi/ipfw3-head: sbin/ipfw
sys/netinet/ipfw
Luigi Rizzo
luigi at FreeBSD.org
Fri Jan 15 16:24:58 UTC 2010
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 ***
More information about the svn-src-user
mailing list