Date: Wed, 13 Jan 2010 19:46:53 +0000 (UTC) From: Luigi Rizzo <luigi@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r202220 - in user/luigi/ipfw3-head: sbin/ipfw sys/netinet sys/netinet/ipfw Message-ID: <201001131946.o0DJkrFE005095@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201001131946.o0DJkrFE005095>