From owner-svn-src-user@FreeBSD.ORG Thu Jan 7 18:11:03 2010 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 83A0710656C3; Thu, 7 Jan 2010 18:11:03 +0000 (UTC) (envelope-from luigi@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 7159D8FC20; Thu, 7 Jan 2010 18:11:03 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o07IB3IJ026438; Thu, 7 Jan 2010 18:11:03 GMT (envelope-from luigi@svn.freebsd.org) Received: (from luigi@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o07IB3pj026431; Thu, 7 Jan 2010 18:11:03 GMT (envelope-from luigi@svn.freebsd.org) Message-Id: <201001071811.o07IB3pj026431@svn.freebsd.org> From: Luigi Rizzo Date: Thu, 7 Jan 2010 18:11:03 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r201753 - in user/luigi/ipfw3-head: sbin/ipfw sys/netinet sys/netinet/ipfw X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 07 Jan 2010 18:11:03 -0000 Author: luigi Date: Thu Jan 7 18:11:03 2010 New Revision: 201753 URL: http://svn.freebsd.org/changeset/base/201753 Log: snapshot of today's changes (not working) Modified: user/luigi/ipfw3-head/sbin/ipfw/dummynet.c user/luigi/ipfw3-head/sbin/ipfw/ipfw2.h user/luigi/ipfw3-head/sbin/ipfw/main.c user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c 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 Thu Jan 7 17:46:25 2010 (r201752) +++ user/luigi/ipfw3-head/sbin/ipfw/dummynet.c Thu Jan 7 18:11:03 2010 (r201753) @@ -46,6 +46,7 @@ #include #include /* inet_ntoa */ + static struct _s_x dummynet_params[] = { { "plr", TOK_PLR }, { "noerror", TOK_NOERROR }, @@ -57,7 +58,9 @@ static struct _s_x dummynet_params[] = { { "proto", TOK_PROTO }, { "weight", TOK_WEIGHT }, { "all", TOK_ALL }, - { "mask", TOK_MASK }, + //{ "mask", TOK_MASK }, + { "sched_mask", TOK_SCHED_MASK }, + { "flow_mask", TOK_FLOW_MASK }, { "droptail", TOK_DROPTAIL }, { "red", TOK_RED }, { "gred", TOK_GRED }, @@ -65,7 +68,9 @@ static struct _s_x dummynet_params[] = { { "bandwidth", TOK_BW }, { "delay", TOK_DELAY }, { "pipe", TOK_PIPE }, - { "queue", TOK_QUEUE }, + { "queue", TOK_FLOWSET }, + { "flowset", TOK_FLOWSET }, + { "sched", TOK_SCHED }, { "flow-id", TOK_FLOWID}, { "dst-ipv6", TOK_DSTIP6}, { "dst-ip6", TOK_DSTIP6}, @@ -77,6 +82,21 @@ static struct _s_x dummynet_params[] = { { NULL, 0 } /* terminator */ }; +#define O_NEXT(p, len) ((void *)(char *)(p) + len) + +/* make room in the buffer and move the pointer forward */ +static void * +o_next(struct dn_id **o, int len, int type) +{ + void *ret = *o; + (*o)->len = len; + (*o)->type = type; + (*o)->subtype = 0; + (*o)->id = 0; + *o = O_NEXT(*o, len); + return ret; +} + static int sort_q(void *arg, const void *pa, const void *pb) { @@ -550,7 +570,9 @@ compare_points(const void *vp1, const vo #define ED_EFMT(s) EX_DATAERR,"error in %s at line %d: "#s,filename,lineno -static void +void +load_extra_delays(const char *filename, struct dn_pipe *p); +void load_extra_delays(const char *filename, struct dn_pipe *p) { char line[ED_MAX_LINE_LEN]; @@ -694,26 +716,62 @@ load_extra_delays(const char *filename, strncpy(p->name, profile_name, sizeof(p->name)); } +/* + * configuration of pipes, schedulers, flowsets. + * do_pipe = 1 -> pipe (1 pipe + 1 flowset + 1 FIFO + 1 WFQ) + * do_pipe = 2 -> flowset + * do_pipe = 3 -> sched + * pipe ==> + */ void ipfw_config_pipe(int ac, char **av) { - int samples[ED_MAX_SAMPLES_NO]; - struct dn_pipe p; - int i; + int i = -1; char *end; void *par = NULL; - - memset(&p, 0, sizeof p); - p.bandwidth = -1; + struct dn_id *buf, *base; + struct new_sch *sch = NULL, *sch2 = NULL; + struct new_pipe *p = NULL; + struct new_fs *fs = NULL; + struct ipfw_flow_id *mask = NULL; + int lmax = sizeof(*sch)*2 + sizeof(*p) + sizeof(*fs); + +fprintf(stderr, "configuring %d\n", co.do_pipe); + base = buf = calloc(1, lmax); + if (buf == NULL) { + errx(1, "no memory for pipe buffer"); + } av++; ac--; /* Pipe number */ if (ac && isdigit(**av)) { i = atoi(*av); av++; ac--; - if (co.do_pipe == 1) - p.pipe_nr = i; - else - p.fs.fs_nr = i; + } + if (i <= 0) + errx(EX_USAGE, "need a pipe/flowset/sched number"); + switch (co.do_pipe) { + case 1: + sch = o_next(&buf, sizeof(*sch), DN_SCH); + sch2 = o_next(&buf, sizeof(*sch2), DN_SCH); + p = o_next(&buf, sizeof(*p), DN_PIPE); + fs = o_next(&buf, sizeof(*fs), DN_FS); + mask = &sch->sched_mask; // XXX or both ? + p->pipe_nr = i + DN_PIPEOFFSET; + fs->fs_nr = i; + fs->sched_nr = i; + sch->sched_nr = i; + sch2->sched_nr = i + DN_PIPEOFFSET; + break; + case 2: /* flowset */ + fs = o_next(&buf, sizeof(*fs), DN_FS); + fs->fs_nr = i; + mask = &fs->flow_mask; + break; + case 3: /* scheduler */ + sch = o_next(&buf, sizeof(*sch), DN_SCH); + sch->sched_nr = i; + mask = &sch->sched_mask; // XXX or both ? + break; } while (ac > 0) { double d; @@ -722,41 +780,46 @@ ipfw_config_pipe(int ac, char **av) switch(tok) { case TOK_NOERROR: - p.fs.flags_fs |= DN_NOERROR; + NEED(fs, "noerror is only for pipes"); + fs->flags |= DN_NOERROR; break; case TOK_PLR: + NEED(fs, "plr is only for pipes"); NEED1("plr needs argument 0..1\n"); d = strtod(av[0], NULL); if (d > 1) d = 1; else if (d < 0) d = 0; - p.fs.plr = (int)(d*0x7fffffff); + fs->plr = (int)(d*0x7fffffff); ac--; av++; break; case TOK_QUEUE: + NEED(fs, "queue is only for pipes or flowsets"); NEED1("queue needs queue size\n"); end = NULL; - p.fs.qsize = strtoul(av[0], &end, 0); + fs->qsize = strtoul(av[0], &end, 0); if (*end == 'K' || *end == 'k') { - p.fs.flags_fs |= DN_QSIZE_IS_BYTES; - p.fs.qsize *= 1024; + fs->flags |= DN_QSIZE_IS_BYTES; + fs->qsize *= 1024; } else if (*end == 'B' || _substrcmp2(end, "by", "bytes") == 0) { - p.fs.flags_fs |= DN_QSIZE_IS_BYTES; + fs->flags |= DN_QSIZE_IS_BYTES; } ac--; av++; break; case TOK_BUCKETS: + NEED(fs, "buckets is only for pipes or flowsets"); NEED1("buckets needs argument\n"); - p.fs.rq_size = strtoul(av[0], NULL, 0); + // XXX fs->rq_size = strtoul(av[0], NULL, 0); ac--; av++; break; case TOK_MASK: + NEED(mask, "tok_mask"); NEED1("mask needs mask specifier\n"); /* * per-flow queue, mask is dst_ip, dst_port, @@ -764,7 +827,7 @@ ipfw_config_pipe(int ac, char **av) */ par = NULL; - bzero(&p.fs.flow_mask, sizeof(p.fs.flow_mask)); + bzero(mask, sizeof(*mask)); end = NULL; while (ac >= 1) { @@ -781,43 +844,43 @@ ipfw_config_pipe(int ac, char **av) /* * special case, all bits significant */ - p.fs.flow_mask.dst_ip = ~0; - p.fs.flow_mask.src_ip = ~0; - p.fs.flow_mask.dst_port = ~0; - p.fs.flow_mask.src_port = ~0; - p.fs.flow_mask.proto = ~0; - n2mask(&(p.fs.flow_mask.dst_ip6), 128); - n2mask(&(p.fs.flow_mask.src_ip6), 128); - p.fs.flow_mask.flow_id6 = ~0; - p.fs.flags_fs |= DN_HAVE_FLOW_MASK; + mask->dst_ip = ~0; + mask->src_ip = ~0; + mask->dst_port = ~0; + mask->src_port = ~0; + mask->proto = ~0; + n2mask(&mask->dst_ip6, 128); + n2mask(&mask->src_ip6, 128); + mask->flow_id6 = ~0; + fs->flags |= DN_HAVE_FLOW_MASK; goto end_mask; case TOK_DSTIP: - p32 = &p.fs.flow_mask.dst_ip; + p32 = &mask->dst_ip; break; case TOK_SRCIP: - p32 = &p.fs.flow_mask.src_ip; + p32 = &mask->src_ip; break; case TOK_DSTIP6: - pa6 = &(p.fs.flow_mask.dst_ip6); + pa6 = &mask->dst_ip6; break; case TOK_SRCIP6: - pa6 = &(p.fs.flow_mask.src_ip6); + pa6 = &mask->src_ip6; break; case TOK_FLOWID: - p20 = &p.fs.flow_mask.flow_id6; + p20 = &mask->flow_id6; break; case TOK_DSTPORT: - p16 = &p.fs.flow_mask.dst_port; + p16 = &mask->dst_port; break; case TOK_SRCPORT: - p16 = &p.fs.flow_mask.src_port; + p16 = &mask->src_port; break; case TOK_PROTO: @@ -857,19 +920,20 @@ ipfw_config_pipe(int ac, char **av) if (a > 0xFF) errx(EX_DATAERR, "proto mask must be 8 bit"); - p.fs.flow_mask.proto = (uint8_t)a; + fs->flow_mask.proto = (uint8_t)a; } if (a != 0) - p.fs.flags_fs |= DN_HAVE_FLOW_MASK; + fs->flags |= DN_HAVE_FLOW_MASK; ac--; av++; } /* end while, config masks */ end_mask: break; +#if 0 case TOK_RED: case TOK_GRED: NEED1("red/gred needs w_q/min_th/max_th/max_p\n"); - p.fs.flags_fs |= DN_IS_RED; + fs->flags |= DN_IS_RED; if (tok == TOK_GRED) p.fs.flags_fs |= DN_IS_GENTLE_RED; /* @@ -879,10 +943,10 @@ end_mask: double w_q = strtod(end, NULL); if (w_q > 1 || w_q <= 0) errx(EX_DATAERR, "0 < w_q <= 1"); - p.fs.w_q = (int) (w_q * (1 << SCALE_RED)); + fs->w_q = (int) (w_q * (1 << SCALE_RED)); } if ((end = strsep(&av[0], "/"))) { - p.fs.min_th = strtoul(end, &end, 0); + fs->min_th = strtoul(end, &end, 0); if (*end == 'K' || *end == 'k') p.fs.min_th *= 1024; } @@ -899,62 +963,66 @@ end_mask: } ac--; av++; break; +#endif case TOK_DROPTAIL: - p.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED); + NEED(fs, "droptail is only for flowsets"); + fs->flags &= ~(DN_IS_RED|DN_IS_GENTLE_RED); break; case TOK_BW: + NEED(p, "bw is only for pipe"); NEED1("bw needs bandwidth or interface\n"); - if (co.do_pipe != 1) - errx(EX_DATAERR, "bandwidth only valid for pipes"); - read_bandwidth(av[0], &p.bandwidth, p.if_name, sizeof(p.if_name)); + read_bandwidth(av[0], &p->bandwidth, p->if_name, sizeof(p->if_name)); ac--; av++; break; case TOK_DELAY: - if (co.do_pipe != 1) - errx(EX_DATAERR, "delay only valid for pipes"); + NEED(p, "delay is only for pipes"); NEED1("delay needs argument 0..10000ms\n"); - p.delay = strtoul(av[0], NULL, 0); + p->delay = strtoul(av[0], NULL, 0); ac--; av++; break; +#if 0 case TOK_WEIGHT: - if (co.do_pipe == 1) - errx(EX_DATAERR,"weight only valid for queues"); + NEED(fs, "weight is only for flowsets"); NEED1("weight needs argument 0..100\n"); - p.fs.weight = strtoul(av[0], &end, 0); + fs->weight = strtoul(av[0], &end, 0); ac--; av++; break; +#endif + case TOK_SCHED: case TOK_PIPE: - if (co.do_pipe == 1) - errx(EX_DATAERR,"pipe only valid for queues"); + NEED(fs, "pipe/sched"); NEED1("pipe needs pipe_number\n"); - p.fs.parent_nr = strtoul(av[0], &end, 0); + fs->sched_nr = strtoul(av[0], &end, 0); ac--; av++; break; +#if 0 case TOK_PIPE_PROFILE: + { + int samples[ED_MAX_SAMPLES_NO]; if (co.do_pipe != 1) errx(EX_DATAERR, "extra delay only valid for pipes"); NEED1("extra delay needs the file name\n"); p.samples = &samples[0]; load_extra_delays(av[0], &p); --ac; ++av; + } break; - +#endif case TOK_BURST: - if (co.do_pipe != 1) - errx(EX_DATAERR, "burst only valid for pipes"); + NEED(sch, "burst"); NEED1("burst needs argument\n"); errno = 0; - if (expand_number(av[0], (int64_t *)&p.burst) < 0) + if (expand_number(av[0], (int64_t *)&sch->burst) < 0) if (errno != ERANGE) errx(EX_DATAERR, "burst: invalid argument"); - if (errno || p.burst > (1ULL << 48) - 1) + if (errno || sch->burst > (1ULL << 48) - 1) errx(EX_DATAERR, "burst: out of range (0..2^48-1)"); ac--; av++; @@ -964,26 +1032,19 @@ end_mask: errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]); } } - if (co.do_pipe == 1) { - if (p.pipe_nr == 0) - errx(EX_DATAERR, "pipe_nr must be > 0"); - if (p.delay > 10000) - errx(EX_DATAERR, "delay must be < 10000"); - } else { /* co.do_pipe == 2, queue */ - if (p.fs.parent_nr == 0) - errx(EX_DATAERR, "pipe must be > 0"); - if (p.fs.weight >100) - errx(EX_DATAERR, "weight must be <= 100"); - } - /* check for bandwidth value */ - if (p.bandwidth == -1) { - p.bandwidth = 0; - if (p.samples_no > 0) - errx(EX_DATAERR, "profile requires a bandwidth limit"); + /* check validity of parameters */ + if (p) { + if (p->delay > 10000) + errx(EX_DATAERR, "delay must be < 10000"); + if (p->bandwidth == -1) + p->bandwidth = 0; } + if (fs) { + if (fs->sched_nr == 0) + errx(EX_DATAERR, "sched must be > 0"); - if (p.fs.flags_fs & DN_QSIZE_IS_BYTES) { + if (fs->flags & DN_QSIZE_IS_BYTES) { size_t len; long limit; @@ -991,9 +1052,9 @@ end_mask: if (sysctlbyname("net.inet.ip.dummynet.pipe_byte_limit", &limit, &len, NULL, 0) == -1) limit = 1024*1024; - if (p.fs.qsize > limit) + if (fs->qsize > limit) errx(EX_DATAERR, "queue size must be < %ldB", limit); - } else { + } else { size_t len; long limit; @@ -1001,9 +1062,11 @@ end_mask: if (sysctlbyname("net.inet.ip.dummynet.pipe_slot_limit", &limit, &len, NULL, 0) == -1) limit = 100; - if (p.fs.qsize > limit) + if (fs->qsize > limit) errx(EX_DATAERR, "2 <= queue size <= %ld", limit); + } } +#if 0 /* RED CONFIGURATION */ if (p.fs.flags_fs & DN_IS_RED) { size_t len; int lookup_depth, avg_pkt_size; @@ -1060,10 +1123,10 @@ end_mask: * NOTA: (3/w_q) is approx the value x so that * (1-w_q)^x < 10^-3. */ - w_q = ((double)p.fs.w_q) / (1 << SCALE_RED); + w_q = ((double)fs->w_q) / (1 << SCALE_RED); idle = s * 3. / w_q; - p.fs.lookup_step = (int)idle / lookup_depth; - if (!p.fs.lookup_step) + fs->lookup_step = (int)idle / lookup_depth; + if (!fs->lookup_step) p.fs.lookup_step = 1; weight = 1 - w_q; for (t = p.fs.lookup_step; t > 1; --t) @@ -1071,15 +1134,14 @@ end_mask: p.fs.lookup_weight = (int)(weight * (1 << SCALE_RED)); } if (p.samples_no <= 0) { - i = do_cmd(IP_DUMMYNET_CONFIGURE, &p, sizeof p); - } else { - struct dn_pipe_max pm; - int len = sizeof(pm); - - memcpy(&pm.pipe, &p, sizeof(pm.pipe)); - memcpy(&pm.samples, samples, sizeof(pm.samples)); - - i = do_cmd(IP_DUMMYNET_CONFIGURE, &pm, len); + struct new_profile *prof; + prof = o_next(&o, sizeof(*prof), DN_PROFILE); + i = do_cmd(IP_DUMMYNET_CONFIGURE, prof, sizeof *prof); + } else +#endif + { + i = do_cmd(IP_DUMMYNET_CONFIGURE, base, + (char *)buf - (char *)base); } if (i) Modified: user/luigi/ipfw3-head/sbin/ipfw/ipfw2.h ============================================================================== --- user/luigi/ipfw3-head/sbin/ipfw/ipfw2.h Thu Jan 7 17:46:25 2010 (r201752) +++ user/luigi/ipfw3-head/sbin/ipfw/ipfw2.h Thu Jan 7 18:11:03 2010 (r201753) @@ -35,7 +35,7 @@ struct cmdline_opts { int do_resolv; /* try to resolve all ip to names */ int do_time; /* Show time stamps */ int do_quiet; /* Be quiet in add and flush */ - int do_pipe; /* this cmd refers to a pipe */ + int do_pipe; /* this cmd refers to a pipe/queue/sched */ int do_nat; /* this cmd refers to a nat config */ int do_dynamic; /* display dynamic rules */ int do_expired; /* display expired dynamic rules */ @@ -83,6 +83,8 @@ enum tokens { TOK_COUNT, TOK_PIPE, TOK_QUEUE, + TOK_FLOWSET, + TOK_SCHED, TOK_DIVERT, TOK_TEE, TOK_NETGRAPH, @@ -151,6 +153,8 @@ enum tokens { TOK_SRCPORT, TOK_ALL, TOK_MASK, + TOK_FLOW_MASK, + TOK_SCHED_MASK, TOK_BW, TOK_DELAY, TOK_PIPE_PROFILE, @@ -192,6 +196,7 @@ enum tokens { * the following macro returns an error message if we run out of * arguments. */ +#define NEED(_p, msg) {if (!_p) errx(EX_USAGE, msg);} #define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);} unsigned long long align_uint64(const uint64_t *pll); Modified: user/luigi/ipfw3-head/sbin/ipfw/main.c ============================================================================== --- user/luigi/ipfw3-head/sbin/ipfw/main.c Thu Jan 7 17:46:25 2010 (r201752) +++ user/luigi/ipfw3-head/sbin/ipfw/main.c Thu Jan 7 18:11:03 2010 (r201753) @@ -304,6 +304,10 @@ ipfw_main(int oldac, char **oldav) co.do_pipe = 1; else if (_substrcmp(*av, "queue") == 0) co.do_pipe = 2; + else if (_substrcmp(*av, "flowset") == 0) + co.do_pipe = 2; + else if (_substrcmp(*av, "sched") == 0) + co.do_pipe = 3; else if (!strncmp(*av, "set", strlen(*av))) { if (ac > 1 && isdigit(av[1][0])) { co.use_set = strtonum(av[1], 0, resvd_set_number, Modified: user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h ============================================================================== --- user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h Thu Jan 7 17:46:25 2010 (r201752) +++ user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h Thu Jan 7 18:11:03 2010 (r201753) @@ -215,7 +215,7 @@ struct new_fs { * This struct is created a runtime. */ struct new_sch_inst { - struct dn_id sch_id; + struct dn_id oid; struct new_sch_inst *next; /* next item in the bucket */ @@ -250,7 +250,7 @@ struct new_sch_inst { * (plus there is a FIFO scheduler for each pipe) */ struct new_sch { - struct dn_id g; + struct dn_id id; /* these initial fields are set from the command line * sched N config mask M ... @@ -316,6 +316,14 @@ struct new_sch { // struct mtx sch_mtx; }; +/* + * "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. The value is not so important, but + * it should be known to userland as well so we can print it. + */ +#define DN_PIPEOFFSET 1000000 + /*---- old parameters ---*/ /* * The maximum hash table size for queues. This value must be a power Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c ============================================================================== --- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c Thu Jan 7 17:46:25 2010 (r201752) +++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c Thu Jan 7 18:11:03 2010 (r201753) @@ -1110,6 +1110,10 @@ ipdn_locate_pipe(int pipe_nr) * dummynet hook for packets. Below 'pipe' is a pipe or a queue * depending on whether WF2Q or fixed bw is used. * + * We use the argument to locate the flowset fs and the sched_set sch + * associated to it. The we apply flow_mask and sched_mask to + * determine the queue and scheduler instances. + * * pipe_nr pipe or queue the packet is destined for. * dir where shall we send the packet after dummynet. * m the mbuf with the packet @@ -1124,39 +1128,39 @@ dummynet_io(struct mbuf **m0, int dir, s struct dn_pkt_tag *pkt; struct m_tag *mtag; struct dn_flow_set *fs = NULL; - struct dn_pipe *pipe; + struct dn_pipe *pipe = NULL; uint64_t len = m->m_pkthdr.len; struct dn_flow_queue *q = NULL; - int is_pipe = fwa->rule.info & IPFW_IS_PIPE; + int fs_id = fwa->rule.info & IPFW_INFO_MASK; + int is_pipe = 0; + + if (fwa->rule.info & IPFW_IS_PIPE) + fs_id += DN_PIPEOFFSET; KASSERT(m->m_nextpkt == NULL, ("dummynet_io: mbuf queue passed to dummynet")); DUMMYNET_LOCK(); io_pkt++; - /* - * This is a dummynet rule, so we expect an O_PIPE or O_QUEUE rule. - */ - if (is_pipe) { - pipe = ipdn_locate_pipe(fwa->rule.info & IPFW_INFO_MASK); - if (pipe != NULL) - fs = &(pipe->fs); - } else - fs = ipdn_locate_flowset(fwa->rule.info & IPFW_INFO_MASK); + fs = ipdn_locate_flowset(fs_id); if (fs == NULL) goto dropit; /* This queue/pipe does not exist! */ - pipe = fs->pipe; - if (pipe == NULL) { /* Must be a queue, try find a matching pipe. */ - pipe = ipdn_locate_pipe(fs->parent_nr); - if (pipe != NULL) - fs->pipe = pipe; - else { - printf("dummynet: no pipe %d for queue %d, drop pkt\n", - fs->parent_nr, fs->fs_nr); +#if 0 + if (fs->sched_id != dn_cfg.id) { + /* configuration changed, update */ + int ret = reconfigure(fs); + if (ret) + goto dropit; + /* find again, just in case things changed */ + fs = ipdn_locate_flowset(fs_id); + if (fs == NULL) goto dropit; - } } + sch = fs->sched; + if (sch == NULL) + goto dropit; +#endif q = find_queue(fs, &(fwa->f_id)); if (q == NULL) goto dropit; /* Cannot allocate queue. */ @@ -1176,7 +1180,7 @@ dummynet_io(struct mbuf **m0, int dir, s if (fs->flags_fs & DN_IS_RED && red_drops(fs, q, len)) goto dropit; - /* XXX expensive to zero, see if we can remove it. */ + /* tag the mbuf */ mtag = m_tag_get(PACKET_TAG_DUMMYNET, sizeof(struct dn_pkt_tag), M_NOWAIT | M_ZERO); if (mtag == NULL) Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c ============================================================================== --- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c Thu Jan 7 17:46:25 2010 (r201752) +++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c Thu Jan 7 18:11:03 2010 (r201753) @@ -67,7 +67,6 @@ __FBSDID("$FreeBSD$"); //#include /* for ip6_input, ip6_output prototypes */ //#include -static int config_pipe(struct dn_pipe *p); static int ip_dn_ctl(struct sockopt *sopt); static struct callout dn_timeout; @@ -310,8 +309,26 @@ set_fs_parms(struct dn_flow_set *x, stru config_red(src, x); /* XXX should check errors */ } +static int +do_config(void *p, int l) +{ + struct dn_id *o = p; + + while (l && o->len > 0) { + l -= o->len; + o = (struct dn_id *)((char *)o + l); + } + return 0; +} + /* - * Setup pipe or queue parameters. + * Setup pipe or flowset parameters. + * 'pipe config' (pipe_nr > 0, fs_nr == 0) + * configures a pipe, a FIFO scheduler + flowset, and a WFQ scheduler. + * 'queue config' (pipe_nr == 0, fs_nr > 0) + * configures a flowset. + * 'sched config' (pipe_nr > 0, fs_nr > 0) + * (re)configures the WFQ scheduler for the pipe. */ static int config_pipe(struct dn_pipe *p) @@ -320,6 +337,9 @@ config_pipe(struct dn_pipe *p) struct dn_flow_queue *q; int i, error; + /* We need either a pipe number or a flow_set number. */ + if (p->pipe_nr == 0 && pfs->fs_nr == 0) + return (EINVAL); /* * The config program passes parameters as follows: * bw = bits/second (0 means no limits), @@ -329,15 +349,11 @@ config_pipe(struct dn_pipe *p) p->delay = (p->delay * hz) / 1000; /* Scale burst size: bytes -> bits * hz */ p->burst *= 8 * hz; - /* We need either a pipe number or a flow_set number. */ - if (p->pipe_nr == 0 && pfs->fs_nr == 0) - return (EINVAL); - if (p->pipe_nr != 0 && pfs->fs_nr != 0) - return (EINVAL); + + DUMMYNET_LOCK(); if (p->pipe_nr != 0) { /* this is a pipe */ struct dn_pipe *pipe; - DUMMYNET_LOCK(); pipe = ipdn_locate_pipe(p->pipe_nr); /* locate pipe */ if (pipe == NULL) { /* new pipe */ @@ -418,11 +434,9 @@ config_pipe(struct dn_pipe *p) SLIST_INSERT_HEAD(&pipehash[HASH(pipe->pipe_nr)], pipe, next); } - DUMMYNET_UNLOCK(); } else { /* config queue */ struct dn_flow_set *fs; - DUMMYNET_LOCK(); fs = ipdn_locate_flowset(pfs->fs_nr); /* locate flow_set */ if (fs == NULL) { /* new */ @@ -469,8 +483,8 @@ config_pipe(struct dn_pipe *p) SLIST_INSERT_HEAD(&flowsethash[HASH(fs->fs_nr)], fs, next); } - DUMMYNET_UNLOCK(); } + DUMMYNET_UNLOCK(); return (0); } @@ -719,6 +733,7 @@ ip_dn_ctl(struct sockopt *sopt) { int error; struct dn_pipe *p = NULL; + int l; error = priv_check(sopt->sopt_td, PRIV_NETINET_DUMMYNET); if (error) @@ -726,14 +741,9 @@ ip_dn_ctl(struct sockopt *sopt) /* Disallow sets in really-really secure mode. */ if (sopt->sopt_dir == SOPT_SET) { -#if __FreeBSD_version >= 500034 error = securelevel_ge(sopt->sopt_td->td_ucred, 3); if (error) return (error); -#else - if (securelevel >= 3) - return (EPERM); -#endif } switch (sopt->sopt_name) { @@ -751,13 +761,20 @@ ip_dn_ctl(struct sockopt *sopt) break ; case IP_DUMMYNET_CONFIGURE : - p = malloc(sizeof(struct dn_pipe_max), M_TEMP, M_WAITOK); - error = sooptcopyin(sopt, p, sizeof(struct dn_pipe_max), sizeof *p); + l = (sopt->sopt_dir == SOPT_SET) ? sopt->sopt_valsize : + *(int *)(sopt->sopt_valsize); + if (l < 0 || l > 12000) { + printf("argument too large, %d\n", l); + break; + } + printf("%s size %d\n", __FUNCTION__, l); + p = malloc(l, M_TEMP, M_WAITOK); + error = sooptcopyin(sopt, p, l, l); if (error) break ; - if (p->samples_no > 0) - p->samples = &(((struct dn_pipe_max *)p)->samples[0]); + error = do_config(p, l); + break; error = config_pipe(p); break ;