svn commit: r202220 - in user/luigi/ipfw3-head: sbin/ipfw
sys/netinet sys/netinet/ipfw
Luigi Rizzo
luigi at FreeBSD.org
Wed Jan 13 19:46:53 UTC 2010
Author: luigi
Date: Wed Jan 13 19:46:53 2010
New Revision: 202220
URL: http://svn.freebsd.org/changeset/base/202220
Log:
basic glue and packet flow now operational
Modified:
user/luigi/ipfw3-head/sbin/ipfw/dummynet.c
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_fifo.c
user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_wf2q.c
user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c
user/luigi/ipfw3-head/sys/netinet/ipfw/ip_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 Wed Jan 13 19:25:03 2010 (r202219)
+++ user/luigi/ipfw3-head/sbin/ipfw/dummynet.c Wed Jan 13 19:46:53 2010 (r202220)
@@ -739,8 +739,6 @@ ipfw_config_pipe(int ac, char **av)
struct dn_id *buf, *base;
struct new_sch *sch = NULL;
struct new_pipe *p = NULL;
- struct new_sch *sch2 = NULL; /* the fifo scheduler */
- struct new_pipe *p2 = NULL; /* the fifo pipe */
struct new_fs *fs = NULL;
struct new_profile *pf = NULL;
struct new_cmd *cmd = NULL;
@@ -766,21 +764,26 @@ ipfw_config_pipe(int ac, char **av)
switch (co.do_pipe) {
case 1:
+ /* the WFQ scheduler */
sch = o_next(&buf, sizeof(*sch), DN_SCH);
- sch->sched_nr = i + DN_PIPEOFFSET;
- sch->oid.subtype = DN_SCHED_FIFO;
- p = o_next(&buf, sizeof(*p), DN_PIPE);
- p->pipe_nr = i + DN_PIPEOFFSET;
+ sch->sched_nr = i;
+ sch->oid.subtype = DN_SCHED_WF2QP;
mask = &sch->sched_mask;
- fs = o_next(&buf, sizeof(*fs), DN_FS);
- fs->fs_nr = i + DN_PIPEOFFSET;
- fs->sched_nr = i + DN_PIPEOFFSET;
+ /* XXX the FIFO scheduler is created from the WFQ one */
- /* sch2 and p2 will be set later */
- sch2 = o_next(&buf, sizeof(*sch2), DN_SCH);
- sch2->oid.subtype = DN_SCHED_WF2QP;
- p2 = o_next(&buf, sizeof(*p2), DN_PIPE);
+ /* the WFQ pipe */
+ p = o_next(&buf, sizeof(*p), DN_PIPE);
+ p->pipe_nr = i;
+ /* XXX the FIFO pipe is created from WFQ pipe */
+ /*
+ * FIFO flowsets N+i are automatically created for
+ * FIFO schedulers i, but we provide room to pass
+ * queue parameters
+ */
+ fs = o_next(&buf, sizeof(*fs), DN_FS);
+ fs->fs_nr = i + 2*DN_MAX_ID;
+ fs->sched_nr = i + DN_MAX_ID;
break;
case 2: /* flowset */
@@ -793,12 +796,14 @@ ipfw_config_pipe(int ac, char **av)
sch = o_next(&buf, sizeof(*sch), DN_SCH);
sch->sched_nr = i;
mask = &sch->sched_mask;
+ /* room in case we have a FIFO scheduler */
+ fs = o_next(&buf, sizeof(*fs), DN_FS);
+ fs->fs_nr = i + DN_MAX_ID;
+ fs->sched_nr = i;
break;
}
if (p)
p->bandwidth = -1;
- if (p2)
- p2->bandwidth = -1;
while (ac > 0) {
double d;
@@ -1175,15 +1180,6 @@ end_mask:
i = do_cmd(IP_DUMMYNET_CONFIGURE, prof, sizeof *prof);
} else
#endif
- if (sch2) {
- *sch2 = *sch;
- sch2->sched_nr = i;
- sch2->oid.subtype = DN_SCHED_WF2QP;
- }
- if (p2) {
- *p2 = *p;
- p2->pipe_nr = i;
- }
i = do_cmd(IP_DUMMYNET3, base,
(char *)buf - (char *)base);
Modified: user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h Wed Jan 13 19:25:03 2010 (r202219)
+++ user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h Wed Jan 13 19:46:53 2010 (r202220)
@@ -128,62 +128,48 @@ struct new_pipe {
};
/*
- * generic text string, in case we need one
- */
-struct new_text {
- struct dn_id oid;
- int len;
- char text[0]; /* len bytes, NUL terminated */
-};
-
-/*
- * A flowset, which is a template for queues.
+ * A flowset, which is a template for queues. Store here parameters
+ * from the command line: id, target scheduler, queue sizes, plr,
+ * flow masks, buckets for the queue hash, and possibly scheduler-
+ * specific parameters (weight, quantum and so on).
*/
struct new_fs {
struct dn_id oid;
-
- /* these initial fields are set from the command line
- * queue N config mask M pipe P buckets B plr PLR queue QSZ ...
- */
- int fs_nr; /* N, the flowset number */
- /* The flowset implicitly created for pipe N is N+offset */
-
- int qsize; /* QSZ, queue size in slots or bytes */
+ int fs_nr; /* the flowset number */
int flags; /* userland flags */
+ int qsize; /* queue size in slots or bytes */
+ int plr; /* PLR, pkt loss rate (2^31-1 means 100%) */
+ int buckets; /* buckets used for the queue hash table */
- /* Number of buckets used for the hash table in this fs. */
- int bucket; /* B */
- int plr ; /* PLR, pkt loss rate (2^31-1 means 100%) */
-
- /* mask to select the appropriate queue */
struct ipfw_flow_id flow_mask; /* M */
- int sched_nr; /* the scheduler we attach to */
+ int sched_nr; /* the scheduler we attach to */
/* generic scheduler parameters */
int weight;
- int slot_size;
+ int quantum;
+ int par[4]; /* other parameters */
};
/*
- * An instance descriptor has a type, a flow_id, flags and a few counters.
- * so we used this to pass information up to userland.
+ * new_inst collects flow_id and stats for queues and scheduler
+ * instances, and is used to pass these info to userland.
+ * oid.type/oid.subtype describe the object, oid.id is number
+ * of the parent object.
*/
struct new_inst {
struct dn_id oid;
struct ipfw_flow_id id;
- uint32_t parent_nr; /* sched or flowset nr */
uint32_t length; /* Queue lenght, in packets */
uint32_t len_bytes; /* Queue lenght, in bytes */
uint32_t drops;
- int hash_slot;
+ int hash_slot; /* XXX do we need it ? */
uint64_t tot_pkts; /* statistics counters */
uint64_t tot_bytes;
};
-/* Scheduler template
- * All scheduler are linked in a list, there is a 1-1 mapping between
- * 'ipfw sched XX ...' commands and sched XX
- * (plus there is a FIFO scheduler for each pipe)
+/*
+ * Scheduler template, mostly indicating the name, number,
+ * sched_mask and buckets.
*/
struct new_sch {
struct dn_id oid;
@@ -198,18 +184,13 @@ struct new_sch {
/*
- * "queue N" and "pipe N" accept 1<=N<=65535. To map the values in
- * the same namespace (which we search through a hash table) we add
- * an offset to 'pipe N' below.
- * 'queue' -> 1..0x0ffff , 'pipe': 0x10001-0x1ffff
+ * "queue N" and "pipe N" accept 1<=N<=65535.
+ * So valid names are from 1 to DN_MAXID-1
*/
-#define DN_MAXID 0x1ffff
-#define DN_PIPEOFFSET 0x10000
+#define DN_MAX_ID 0x10000
-/*---- old parameters ---*/
/*
- * The maximum hash table size for queues. This value must be a power
- * of 2.
+ * The maximum hash table size for queues (unused ?)
*/
#define DN_MAX_HASH_SIZE 65536
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c Wed Jan 13 19:25:03 2010 (r202219)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c Wed Jan 13 19:46:53 2010 (r202220)
@@ -384,7 +384,7 @@ dn_ht_find(struct dn_ht *ht, uintptr_t k
i = (ht->buckets == 1) ? 0 :
(ht->hash(key, flags, ht->arg) % ht->buckets);
- // log(1, "find %p in bucket %d\n", obj, i);
+ // 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)
@@ -401,7 +401,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);
+ // __FUNCTION__, i, ht->ofs);
p = ht->new ? ht->new(key, flags, ht->arg) : (void *)key;
// printf("%s new returns %p\n", __FUNCTION__, p);
if (p) {
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h Wed Jan 13 19:25:03 2010 (r202219)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h Wed Jan 13 19:46:53 2010 (r202220)
@@ -102,7 +102,7 @@ struct dn_sched {
int (*config)(struct new_schk *, int reconfigure);
int (*destroy)(struct new_schk*, int delete);
- int (*new_sched)(struct new_schk *, struct new_sch_inst *);
+ int (*new_sched)(struct new_sch_inst *);
int (*free_sched)(struct new_sch_inst *);
int (*new_queue)(struct new_queue *q);
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_fifo.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_fifo.c Wed Jan 13 19:25:03 2010 (r202219)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_fifo.c Wed Jan 13 19:46:53 2010 (r202220)
@@ -24,6 +24,7 @@
* SUCH DAMAGE.
*/
+#ifdef _KERNEL
#include <sys/malloc.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
@@ -34,11 +35,13 @@
#include <netinet/in.h>
#include <netinet/ip_var.h> /* ipfw_rule_ref */
#include <netinet/ip_fw.h> /* flow_id */
+#else
+#include "dn_test.h"
+#endif
#include <netinet/ip_dummynet.h>
#include <netinet/ipfw/dn_heap.h>
#include <netinet/ipfw/ip_dn_private.h>
#include <netinet/ipfw/dn_sched.h>
-
/*
* This file implements a FIFO scheduler.
* A FIFO scheduler is a simple scheduler algorithm that can be use to
@@ -58,11 +61,8 @@ static int
fifo_enqueue(struct new_sch_inst *_si, struct new_queue *q, struct mbuf *m)
{
int ret;
- struct new_fsk *fs = (struct new_fsk *)q; /* q contains the fs */
q = (struct new_queue *)(_si+1);
- q->fs = fs; // XXX revise
ret = dn_queue_packet(q, m, 0);
- q->fs = NULL;
if (ret) {
printf("%s dn_queue_packet dropped\n", __FUNCTION__);
return 1;
@@ -94,12 +94,16 @@ fifo_dequeue(struct new_sch_inst *_si)
}
static int
-fifo_new_sched(struct new_schk *s, struct new_sch_inst *_si)
+fifo_new_sched(struct new_sch_inst *si)
{
/* This scheduler instance only has a queue pointer. */
- struct new_queue *q = (struct new_queue *)(_si + 1);
+ struct new_queue *q = (struct new_queue *)(si + 1);
+
+ set_oid(&q->ni.oid, DN_QUEUE, 0, sizeof(*q));
+ // XXX SLIST_INSERT_HEAD(&si->ql_list, q, si_chain);
- q->si = _si;
+ q->si = si;
+ q->fs = si->sched->fs;
return 0;
}
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_wf2q.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_wf2q.c Wed Jan 13 19:25:03 2010 (r202219)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_wf2q.c Wed Jan 13 19:46:53 2010 (r202220)
@@ -56,12 +56,9 @@
*/
static int
-fifo_enqueue(struct new_sch_inst *_si, struct new_queue *q, struct mbuf *m)
+fifo_enqueue(struct new_sch_inst *si, struct new_queue *q, struct mbuf *m)
{
- struct new_fsk *fs = (struct new_fsk *)q;
- /* the queue is actually the flowset. */
- q = (struct new_queue *)(_si+1);
- q->fs = fs;
+ q = (struct new_queue *)(si+1);
if (dn_queue_packet(q, m, 0))
return 1;
@@ -96,12 +93,13 @@ fifo_dequeue(struct new_sch_inst *_si)
}
static int
-fifo_new_sched(struct new_schk *s, struct new_sch_inst *_si)
+wf2q_new_sched(struct new_sch_inst *si)
{
/* This scheduler instance only has a queue pointer. */
- struct new_queue *q = (struct new_queue *)(_si + 1);
+ struct new_queue *q = (struct new_queue *)(si + 1);
- q->si = _si;
+ q->si = si;
+ q->fs = si->sched->fs;
return 0;
}
@@ -120,7 +118,7 @@ static struct dn_sched fifo_desc = {
.enqueue = fifo_enqueue,
.dequeue = fifo_dequeue,
- .new_sched = fifo_new_sched,
+ .new_sched = wf2q_new_sched,
};
DECLARE_DNSCHED_MODULE(dn_wf2qp, &fifo_desc);
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c Wed Jan 13 19:25:03 2010 (r202219)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c Wed Jan 13 19:46:53 2010 (r202220)
@@ -561,7 +561,7 @@ dummynet_io(struct mbuf **m0, int dir, s
dn_key now; /* save a copy of curr_time */
int fs_id = (fwa->rule.info & IPFW_INFO_MASK) +
- ((fwa->rule.info & IPFW_IS_PIPE) ? DN_PIPEOFFSET : 0);
+ ((fwa->rule.info & IPFW_IS_PIPE) ? 2*DN_MAX_ID : 0);
DUMMYNET_LOCK();
io_pkt++;
now = curr_time;
@@ -588,7 +588,7 @@ dummynet_io(struct mbuf **m0, int dir, s
if (q == NULL)
goto dropit;
} else {
- q = (void *)fs;
+ q = NULL;
}
if (fs->sched->fp->enqueue(si, q, m)) {
printf("%s dropped by enqueue\n", __FUNCTION__);
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h Wed Jan 13 19:25:03 2010 (r202219)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h Wed Jan 13 19:46:53 2010 (r202220)
@@ -158,6 +158,7 @@ struct new_schk {
SLIST_ENTRY(new_schk) schk_next; /* hash chain list */
struct new_fsk_head fsk_list; /* all fsk linked to me */
+ struct new_fsk *fs; /* flowset for !MULTIQUEUE */
/* Hash table of all instances (through sched_mask) */
struct dn_ht *siht;
@@ -187,7 +188,6 @@ struct new_sch_inst {
/* kernel-side flags */
enum {
- DN_RECONFIGURE = 0x0001, /* (k) */
DN_DELETE = 0x0004, /* destroy when refcnt=0 */
DN_REENQUEUE = 0x0008, /* (k) */
DN_ACTIVE = 0x0010, /* (k) */
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c Wed Jan 13 19:25:03 2010 (r202219)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c Wed Jan 13 19:46:53 2010 (r202220)
@@ -67,11 +67,6 @@ static int ip_dn_ctl(struct sockopt *sop
#define DN_C_FS 0x08
#define DN_C_QUEUE 0x10
-static int config_pipe(struct new_pipe *p, struct dn_id *arg);
-static int config_profile(struct new_profile *p, struct dn_id *arg);
-static int config_fs(struct new_fs *p, struct dn_id *arg);
-static int config_sched(struct new_sch *p, struct dn_id *arg);
-
/* callout hooks. */
static struct callout dn_timeout;
static struct task dn_task;
@@ -239,6 +234,7 @@ 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;
@@ -253,7 +249,8 @@ si_new(uintptr_t key, int flags, void *a
si->dline.si = si;
if (s->fp->new_sched) {
- int ret = s->fp->new_sched(s, si);
+ int ret;
+ ret = s->fp->new_sched(si);
if (ret) {
printf("%s: new_sched error %d\n", __FUNCTION__, ret);
goto error;
@@ -506,67 +503,6 @@ dummynet_flush(void)
DUMMYNET_UNLOCK();
}
-/*
- * Main handler for configuration. Rules of the game:
- * - the first object is the command (config, delete, flush, ...)
- * - config_pipe must be issued after the corresponding config_sched
- * - parameters (DN_TXT) for an object must preceed the object
- * processed on a config_sched.
- */
-static int
-do_config(void *p, int l)
-{
- struct dn_id *next, *o;
- int err = 0;
- struct dn_id *arg = NULL;
-
- for (o = p; l >= sizeof(*o); o = next) {
- struct dn_id *prev = arg;
- if (o->len < sizeof(*o) || l < o->len) {
- printf("bad len o->len %d len %d\n", o->len, l);
- err = EINVAL;
- 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) {
- default:
- printf("cmd %d not implemented\n", o->type);
- break;
-
- case DN_CMD_CONFIGURE:
- break;
-
- case DN_CMD_FLUSH:
- dummynet_flush();
- break;
- case DN_TEXT: /* store argument the next block */
- prev = NULL;
- arg = o;
- break;
- case DN_PIPE:
- err = config_pipe((struct new_pipe *)o, arg);
- break;
- case DN_PROFILE:
- err = config_profile((struct new_profile *)o, arg);
- break;
- case DN_SCH:
- err = config_sched((struct new_sch *)o, arg);
- break;
- case DN_FS:
- err = config_fs((struct new_fs *)o, arg);
- break;
- }
- if (prev)
- arg = NULL;
- if (err != 0)
- break;
- }
- return err;
-}
static inline struct new_schk *
locate_scheduler(int i)
@@ -586,7 +522,29 @@ update_fs(struct new_schk *s)
}
/*
- * Setup pipe parameters.
+ * Configuration -- to preserve backward compatibility we use
+ * the following scheme (N is 65536)
+ * NUMBER SCHED PIPE FLOWSET
+ * 1 .. N-1 (1)WFQ (2)WFQ (3)queue
+ * N+1 .. 2N-1 (4)FIFO (5)FIFO (6)FIFO for sched 1..N-1
+ * 2N+1 .. 3N-1 -- -- (7)FIFO for sched N+1..2N-1
+ *
+ * "pipe i config" configures #1, #2 and #3
+ * "sched i config" configures #1 and possibly #6
+ * "queue i config" configures #3
+ * #1 is configured with 'pipe i config' or 'sched i config'
+ * #2 is configured with 'pipe i config', and created if not
+ * existing with 'sched i config'
+ * #3 is configured with 'queue i config'
+ * #4 is automatically configured after #1, can only be FIFO
+ * #5 is automatically configured after #2
+ * #6 is automatically created when #1 is !MULTIQUEUE,
+ * and can be updated.
+ * #7 is automatically configured after #2
+ */
+
+/*
+ * configure a pipe
*/
static int
config_pipe(struct new_pipe *p, struct dn_id *arg)
@@ -599,7 +557,7 @@ config_pipe(struct new_pipe *p, struct d
return EINVAL;
}
i = p->pipe_nr;
- if (i <= 0 || i > DN_MAXID)
+ if (i <= 0 || i >= DN_MAX_ID)
return EINVAL;
// printf("%s %d\n", __FUNCTION__, i);
/*
@@ -607,146 +565,162 @@ config_pipe(struct new_pipe *p, struct d
* bw = bits/second (0 means no limits),
* delay = ms, must be translated into ticks.
* qsize = slots/bytes
+ * burst ???
*/
p->delay = (p->delay * hz) / 1000;
/* Scale burst size: bytes -> bits * hz */
p->burst *= 8 * hz;
DUMMYNET_LOCK();
+ again:
s = locate_scheduler(i);
if (s == NULL) {
DUMMYNET_UNLOCK();
printf("%s sched %d not found\n", __FUNCTION__, i);
return EINVAL;
}
+ /* copy all parameters */
s->pipe.delay = p->delay;
s->pipe.bandwidth = p->bandwidth;
s->pipe.burst = p->burst;
schk_reset_credit(s);
+ if (i < DN_MAX_ID) { /* repeat for the FIFO pipe */
+ i += DN_MAX_ID;
+ goto again;
+ }
dn_cfg.id++;
DUMMYNET_UNLOCK();
return 0;
}
/*
- * Configure a scheduler possibly allocating it (and the pipe).
- * XXX check link to type etc.
+ * configure a flowset. Can be called from inside with locked=1,
+ */
+static struct new_fsk *
+config_fs(struct new_fs *nfs, struct dn_id *arg, int locked)
+{
+ struct new_fsk *fs;
+ struct new_schk *s;
+ int i;
+
+ if (nfs->oid.len < sizeof(*nfs)) {
+ printf("%s: short flowset\n", __FUNCTION__);
+ 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 */
+ if (nfs->flags & DN_QSIZE_IS_BYTES) {
+ if (nfs->qsize > dn_cfg.pipe_byte_limit)
+ nfs->qsize = dn_cfg.pipe_byte_limit;
+ } else {
+ if (nfs->qsize == 0)
+ nfs->qsize = 50;
+ if (nfs->qsize > dn_cfg.pipe_slot_limit)
+ nfs->qsize = dn_cfg.pipe_slot_limit;
+ }
+ if (!locked)
+ DUMMYNET_LOCK();
+again:
+ fs = dn_ht_find(dn_cfg.fshash, i, DNHT_INSERT);
+ if (fs == NULL)
+ goto done;
+ dn_cfg.id++;
+ fs->fs = *nfs; /* update config */
+ s = locate_scheduler(nfs->sched_nr);
+ if (fs->sched == NULL) { /* no scheduler before */
+ if (s) {
+ /* have a new scheduler, remove from unlinked */
+ fs->sched = s;
+ // XXX remove_from_unlinked(fs);
+ }
+ } else if (fs->sched != s) {
+ /* scheduler changed. Let it die and recreate */
+ fs->kflags |= DN_DELETE;
+ goto again;
+ }
+done:
+ if (!locked)
+ DUMMYNET_UNLOCK();
+ return fs;
+}
+
+/*
+ * configure a scheduler and its FIFO variant.
+ * For !MULTIQUEUE schedulers, also set up the flowset.
*/
static int
config_sched(struct new_sch *nsch, struct dn_id *arg)
{
struct new_schk *s;
struct dn_sched *fp;
- int i, is_new;
+ int i, notify_fs = 0;
if (nsch->oid.len != sizeof(*nsch)) {
printf("%s: bad sched len\n", __FUNCTION__);
return EINVAL;
}
i = nsch->sched_nr;
- if (i <= 0 || i > DN_MAXID)
+ if (i <= 0 || i >= DN_MAX_ID)
return EINVAL;
- // printf("%s i %d\n", __FUNCTION__, i);
/* 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);
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 for */
- DUMMYNET_LOCK();
- // printf("%s i %d before ht_find\n", __FUNCTION__, i);
+ 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);
- // printf("%s i %d after ht_find\n", __FUNCTION__, i);
if (s == NULL) {
+ DUMMYNET_UNLOCK();
printf("cannot allocate scheduler\n");
return ENOMEM;
}
- printf("%s type %s old %p\n", __FUNCTION__, fp->name, s);
- /* Handle the following cases
- * 1. non existing before:
- * initialize
- * 2. existing before, type changed
- * destroy queues, then #1
- * 3. existing before, same type.
- * update parameters and pipe
- */
- is_new = 0;
+ dn_cfg.id++;
if (s->fp == NULL) { /* new scheduler, nothing to clean up */
- is_new = 1;
- } else if (s->fp != fp) { /* type changed, flush queues. */
- // XXX we should reallocate the private data area.
- // how do we do it ?
- /* preserve old pipe */
- schk_flush(s);
+ notify_fs = 1;
+ } else if (s->fp != fp) {
+ printf("sched %d type changed from %s to %s"
+ " let it drain and reallocate\n",
+ i, s->fp->name, fp->name);
+ /* XXX detach flowsets */
+ s->kflags = DN_DELETE;
+ notify_fs = 1;
+ goto again;
}
/* complete initialization */
s->fp = fp;
s->cfg = arg;
- /* call init function */
+ // XXX schk_reset_credit(s);
+ /* create the internal flowset if needed */
+ if (!(s->fp->flags & DN_MULTIQUEUE) && !s->fs) {
+ struct new_fs fs;
+
+ bzero(&fs, sizeof(fs));
+ set_oid(&fs.oid, DN_FS, 0, sizeof(fs));
+ fs.fs_nr = i + DN_MAX_ID;
+ fs.sched_nr = i;
+ s->fs = config_fs(&fs, NULL, 1 /* locked */);
+ }
+ /* call init function after the flowset is created */
if (s->fp->config)
s->fp->config(s, 1);
- schk_reset_credit(s);
- if (is_new)
- update_fs(s);
- dn_cfg.id++;
- DUMMYNET_UNLOCK();
- return 0;
-}
-
-/*
- * response to a userland request to configure a flowset
- * XXX check the allocation of the private area
- */
-static int
-config_fs(struct new_fs *nfs, struct dn_id *arg)
-{
- struct new_fsk *fs;
- struct new_schk *s;
- int i;
-
- if (nfs->oid.len < sizeof(*nfs)) {
- printf("%s: short flowset\n", __FUNCTION__);
- return EINVAL;
- }
- i = nfs->fs_nr;
- if (i <= 0 || i > DN_MAXID)
- return EINVAL;
- printf("%s i %d\n", __FUNCTION__, i);
- /* XXX other sanity checks */
- if (nfs->flags & DN_QSIZE_IS_BYTES) {
- if (nfs->qsize > dn_cfg.pipe_byte_limit)
- nfs->qsize = dn_cfg.pipe_byte_limit;
- } else {
- if (nfs->qsize == 0)
- nfs->qsize = 50;
- if (nfs->qsize > dn_cfg.pipe_slot_limit)
- nfs->qsize = dn_cfg.pipe_slot_limit;
- }
-
- DUMMYNET_LOCK();
-again:
- fs = dn_ht_find(dn_cfg.fshash, i, DNHT_INSERT);
-
- if (fs == NULL) {
- DUMMYNET_UNLOCK();
- return ENOMEM;
- }
- fs->fs = *nfs; /* update config */
- s = locate_scheduler(nfs->sched_nr);
- if (fs->sched == NULL) { /* no scheduler before, link */
- if (s) {
- fs->sched = s;
- // XXX remove_from_unlinked(fs);
- }
- } else if (fs->sched != s) {
- /* scheduler changed. Mark old fs and recreate */
- fs->kflags |= DN_DELETE;
+ 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;
}
- dn_cfg.id++;
+ if (notify_fs)
+ update_fs(s);
DUMMYNET_UNLOCK();
return 0;
}
@@ -766,7 +740,7 @@ config_profile(struct new_profile *pf, s
return EINVAL;
}
i = pf->pipe_nr;
- if (i <= 0 || i > DN_MAXID)
+ if (i <= 0 || i >= DN_MAX_ID)
return EINVAL;
/* XXX other sanity checks */
@@ -814,6 +788,67 @@ config_profile(struct new_profile *pf, s
return 0;
}
+/*
+ * Main handler for configuration. Rules of the game:
+ * - the first object is the command (config, delete, flush, ...)
+ * - config_pipe must be issued after the corresponding config_sched
+ * - parameters (DN_TXT) for an object must preceed the object
+ * processed on a config_sched.
+ */
+static int
+do_config(void *p, int l)
+{
+ struct dn_id *next, *o;
+ int err = 0;
+ struct dn_id *arg = NULL;
+
+ for (o = p; l >= sizeof(*o); o = next) {
+ struct dn_id *prev = arg;
+ if (o->len < sizeof(*o) || l < o->len) {
+ printf("bad len o->len %d len %d\n", o->len, l);
+ err = EINVAL;
+ 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) {
+ default:
+ printf("cmd %d not implemented\n", o->type);
+ break;
+
+ case DN_CMD_CONFIGURE:
+ break;
+
+ case DN_CMD_FLUSH:
+ dummynet_flush();
+ break;
+ case DN_TEXT: /* store argument the next block */
+ prev = NULL;
+ arg = o;
+ break;
+ case DN_PIPE:
+ err = config_pipe((struct new_pipe *)o, arg);
+ break;
+ case DN_PROFILE:
+ err = config_profile((struct new_profile *)o, arg);
+ break;
+ case DN_SCH:
+ err = config_sched((struct new_sch *)o, arg);
+ break;
+ case DN_FS:
+ err = (NULL==config_fs((struct new_fs *)o, arg, 0));
+ break;
+ }
+ if (prev)
+ arg = NULL;
+ if (err != 0)
+ break;
+ }
+ return err;
+}
static int
compute_space(struct dn_id *cmd, int *to_copy)
{
@@ -975,15 +1010,18 @@ schk_hash(uintptr_t key, int flags, void
{
int i = ((flags & DNHT_KEY_IS_OBJ) == 0) ? key :
((struct new_schk *)key)->sch.sched_nr;
+ // printf("%s %d\n", __FUNCTION__, i);
return ( (i>>8)^(i>>4)^i );
}
static int
schk_match(void *obj, uintptr_t key, int flags, void *arg)
{
+ struct new_schk *s = ((struct new_schk *)obj);
int i = ((flags & DNHT_KEY_IS_OBJ) == 0) ? key :
((struct new_schk *)key)->sch.sched_nr;
- return ((struct new_schk *)obj)->sch.sched_nr == i;
+ // printf("%s s %p i %d\n", __FUNCTION__, s, i);
+ return !(s->kflags & DN_DELETE) && (s->sch.sched_nr == i);
}
/*
@@ -999,7 +1037,6 @@ schk_new(uintptr_t key, int flags, void
struct dn_sched *fp = (struct dn_sched *)sch->oid.id;
int l = sizeof(*s) + fp->schk_len;
-// printf("%s key %p fp %p\n", __FUNCTION__, sch, fp);
s = malloc(l, M_DUMMYNET, M_NOWAIT | M_ZERO);
if (s == NULL)
return NULL;
@@ -1038,7 +1075,7 @@ fsk_match(void *obj, uintptr_t key, int
struct new_fsk *fs = obj;
int i = ((flags & DNHT_KEY_IS_OBJ) == 0) ? key :
((struct new_fsk *)key)->fs.fs_nr;
- return !(fs->kflags & DN_DELETE) && fs->fs.fs_nr == i;
+ return !(fs->kflags & DN_DELETE) && (fs->fs.fs_nr == i);
}
static void *
@@ -1122,7 +1159,6 @@ dummynet_modevent(module_t mod, int type
switch (type) {
case MOD_LOAD:
- printf("%s MODLOAD\n", __FUNCTION__);
if (ip_dn_io_ptr) {
printf("DUMMYNET already loaded\n");
return EEXIST ;
@@ -1153,7 +1189,7 @@ load_descriptor(struct dn_sched *d)
if (d == NULL)
return 1; /* error */
- ip_dn_init(); /* just in case */
+ ip_dn_init(); /* just in case, we need the lock */
/* Check that mandatory funcs exists */
if (d->enqueue == NULL || d->dequeue == NULL) {
@@ -1173,7 +1209,6 @@ load_descriptor(struct dn_sched *d)
SLIST_INSERT_HEAD(&list_of_scheduler, d, next);
DUMMYNET_UNLOCK();
printf("dn_sched %s %sloaded\n", d->name, s ? "not ":"");
-
return s ? 1 : 0;
}
@@ -1196,7 +1231,8 @@ unload_descriptor(struct dn_sched *s)
break;
}
DUMMYNET_UNLOCK();
- return err; /* scheduler in use */
+ printf("dn_sched %s %sunloaded\n", s->name, err ? "not ":"");
+ return err;
}
int
More information about the svn-src-user
mailing list