svn commit: r185076 - in user/lstewart/dummynet_7.x: sbin/ipfw sys
sys/netinet
Lawrence Stewart
lstewart at FreeBSD.org
Tue Nov 18 17:35:05 PST 2008
Author: lstewart
Date: Wed Nov 19 01:35:04 2008
New Revision: 185076
URL: http://svn.freebsd.org/changeset/base/185076
Log:
Merge r184953 (DPD patch) from dummynet_8.x
Modified:
user/lstewart/dummynet_7.x/sbin/ipfw/ (props changed)
user/lstewart/dummynet_7.x/sbin/ipfw/Makefile
user/lstewart/dummynet_7.x/sbin/ipfw/ipfw.8
user/lstewart/dummynet_7.x/sbin/ipfw/ipfw2.c
user/lstewart/dummynet_7.x/sys/ (props changed)
user/lstewart/dummynet_7.x/sys/netinet/in.h
user/lstewart/dummynet_7.x/sys/netinet/ip_dummynet.c
user/lstewart/dummynet_7.x/sys/netinet/ip_dummynet.h
user/lstewart/dummynet_7.x/sys/netinet/raw_ip.c
Modified: user/lstewart/dummynet_7.x/sbin/ipfw/Makefile
==============================================================================
--- user/lstewart/dummynet_7.x/sbin/ipfw/Makefile Wed Nov 19 00:25:15 2008 (r185075)
+++ user/lstewart/dummynet_7.x/sbin/ipfw/Makefile Wed Nov 19 01:35:04 2008 (r185076)
@@ -5,4 +5,6 @@ SRCS= ipfw2.c
WARNS?= 0
MAN= ipfw.8
+CFLAGS+= -I../../sys
+
.include <bsd.prog.mk>
Modified: user/lstewart/dummynet_7.x/sbin/ipfw/ipfw.8
==============================================================================
--- user/lstewart/dummynet_7.x/sbin/ipfw/ipfw.8 Wed Nov 19 00:25:15 2008 (r185075)
+++ user/lstewart/dummynet_7.x/sbin/ipfw/ipfw.8 Wed Nov 19 01:35:04 2008 (r185076)
@@ -61,7 +61,7 @@
.Nm
.Op Fl s Op Ar field
.Brq Cm pipe | queue
-.Brq Cm delete | list | show
+.Brq Cm delete | zero | list | show
.Op Ar number ...
.Pp
.Nm
@@ -1962,6 +1962,20 @@ is a floating-point number between 0 and
loss, 1 meaning 100% loss.
The loss rate is internally represented on 31 bits.
.Pp
+.It Cm pls Ar packet-loss-set
+Packet loss set.
+Argument
+.Ar packet-loss-set
+is a comma-delimited string of the form 10,30-31,1000 identifying the specific
+packets entering a queue/pipe to drop. In the given example, the 10th, 30th,
+31st and 1000th packet to enter the pipe/queue would be dropped. Clearing the
+counters on a pipe will cause the
+.Ar packet-loss-set
+to be evaluated again from scratch. Use of this option mutually excludes use of
+the
+.Nm plr
+option.
+.Pp
.It Cm queue Brq Ar slots | size Ns Cm Kbytes
Queue size, in
.Ar slots
Modified: user/lstewart/dummynet_7.x/sbin/ipfw/ipfw2.c
==============================================================================
--- user/lstewart/dummynet_7.x/sbin/ipfw/ipfw2.c Wed Nov 19 00:25:15 2008 (r185075)
+++ user/lstewart/dummynet_7.x/sbin/ipfw/ipfw2.c Wed Nov 19 01:35:04 2008 (r185076)
@@ -83,6 +83,9 @@ int
comment_only, /* only print action and comment */
verbose;
+#define CHARPTR_IS_INT(X) \
+ (((unsigned int)(((unsigned char)(*(X)))) - (unsigned char)'0') < 11)
+
#define IP_MASK_ALL 0xffffffff
/*
* the following macro returns an error message if we run out of
@@ -128,6 +131,10 @@ int
printf("%u", (uint32_t)arg); \
} while (0)
+#define flush_range_array(PLS) \
+ if((PLS)->arr != NULL) \
+ free((PLS)->arr);
+
/*
* _s_x is a structure that stores a string <-> token pairs, used in
* various places in the parser. Entries are stored in arrays,
@@ -303,6 +310,7 @@ enum tokens {
TOK_COMMENT,
TOK_PLR,
+ TOK_PLS,
TOK_NOERROR,
TOK_BUCKETS,
TOK_DSTIP,
@@ -348,6 +356,7 @@ enum tokens {
struct _s_x dummynet_params[] = {
{ "plr", TOK_PLR },
+ { "pls", TOK_PLS },
{ "noerror", TOK_NOERROR },
{ "buckets", TOK_BUCKETS },
{ "dst-ip", TOK_DSTIP },
@@ -626,6 +635,151 @@ _substrcmp2(const char *str1, const char
}
/*
+ * Generates a string of the form "1,2,3,6-10,1000,1500-2000" from a specified
+ * range list. If the range list is too large to fit into the provided string
+ * buffer,"..." will be appended to the string to indicate there was more
+ * information that could not be displayed.
+ */
+static void
+gen_pls_str(char *str, u_int len, struct pls_range_array *ranges)
+{
+ struct pls_range *node;
+ u_int i = 0, stroffset = 0, ret = 0, str_truncated = 0;
+
+ for(; i < ranges->count; i++) {
+
+ if(ranges->arr[i].start == ranges->arr[i].end)
+ ret = snprintf(str + stroffset, len - stroffset, "%d,", ranges->arr[i].start);
+ else
+ ret = snprintf(str + stroffset, len - stroffset, "%d-%d,", ranges->arr[i].start, ranges->arr[i].end);
+
+ if(ret >= (len - stroffset)) {
+ str_truncated = 1;
+ break;
+ }
+
+ stroffset = strlen(str);
+ }
+
+ if(str_truncated) {
+ *(str+len-3) = '.';
+ *(str+len-2) = '.';
+ *(str+len-1) = '.';
+ *(str+len) = '\0';
+ }
+ else
+ /* remove the trailing comma from the list */
+ *(str+stroffset-1) = '\0';
+}
+
+/*
+ * This function parses a string of the form "1,2,6-10,3,1000,2000-1500" and turns it
+ * into an array of pls_range structs. The array is sorted in order of range start
+ * value from lowest to highest, and the range start and end values within a range struct
+ * are ordered from lowest to highest for consistency. In the example above,
+ * the range node list extracted from the parsed string would look like this:
+ *
+ * pls_range1.start = 1, pls_range1.end = 1
+ * pls_range2.start = 2, pls_range2.end = 2
+ * pls_range3.start = 3, pls_range3.end = 3
+ * pls_range4.start = 6, pls_range4.end = 10
+ * pls_range5.start = 1000, pls_range5.end = 1000
+ * pls_range6.start = 1500, pls_range6.end = 2000
+ */
+static int
+parse_pls_str(char *str, struct pls_range_array *ranges)
+{
+ char *ch, *tmpstr;
+ char tmp[16];
+ int i = 0, j = 0, comma_count = 0, arr_index = 0;
+ struct pls_range *current_range = NULL;
+
+ for(i = strlen(str), tmpstr = str; i >= 0; i--) {
+ ch = tmpstr++;
+ if(*ch == ',')
+ comma_count++;
+ }
+
+ ranges->size = comma_count + 1;
+ ranges->arr = (struct pls_range *)malloc(ranges->size * sizeof(struct pls_range));
+ bzero(ranges->arr, ranges->size * sizeof(struct pls_range));
+
+ if(ranges->arr == NULL)
+ return (ENOMEM);
+
+ for(i = strlen(str), tmpstr = str; i >= 0; i--) {
+ ch = tmpstr++;
+ memset(tmp, '\0', sizeof(tmp));
+
+ j = 0;
+
+ /* if the character is a number 0-9 */
+ while(CHARPTR_IS_INT(ch)) {
+ /* read until the number ends */
+ tmp[j++] = *ch;
+ ch = tmpstr++;
+ i--;
+ }
+
+ /*
+ * if we are at the end of a range, or the end of the string and
+ * we have a number stored in tmp
+ */
+ if((*ch == ',' && j > 0) || (i == 0 && j > 0)) {
+ if(ranges->arr[arr_index].start == 0) {
+ ranges->arr[arr_index].start = strtol(tmp, NULL, 10);
+ }
+
+ ranges->arr[arr_index].end = strtol(tmp, NULL, 10);
+
+ /*
+ * reorder the start and end of the range if they were
+ * specified out of order
+ */
+ if(ranges->arr[arr_index].end < ranges->arr[arr_index].start) {
+ u_int tmp = ranges->arr[arr_index].end;
+ ranges->arr[arr_index].end = ranges->arr[arr_index].start;
+ ranges->arr[arr_index].start = tmp;
+ }
+
+ arr_index++;
+ }
+ else if(*ch == '-' && j > 0) {
+ /*
+ * we are half way through parsing a range, so let's set
+ * create a new range and set its start value to the
+ * first number we parsed in the range
+ */
+ ranges->arr[arr_index].start = strtol(tmp, NULL, 10);
+ }
+ else {
+ flush_range_array(ranges);
+ return 1; /* failed parsing the string */
+ }
+ }
+
+ ranges->count = arr_index;
+
+ struct pls_range tmp_range;
+
+ /*
+ * bubble sort of the list to put them in numerical order of range start
+ * values
+ */
+ for(i = 0; i < ranges->count; i++) {
+ for(j = 1; j < ranges->count; j++) {
+ if(ranges->arr[j-1].start > ranges->arr[j].start) {
+ tmp_range = ranges->arr[j-1];
+ ranges->arr[j-1] = ranges->arr[j];
+ ranges->arr[j] = tmp_range;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
* prints one port, symbolic or numeric
*/
static void
@@ -2254,7 +2408,7 @@ print_flowset_parms(struct dn_flow_set *
{
int l;
char qs[30];
- char plr[30];
+ char pl[30];
char red[90]; /* Display RED parameters */
l = fs->qsize;
@@ -2266,9 +2420,13 @@ print_flowset_parms(struct dn_flow_set *
} else
sprintf(qs, "%3d sl.", l);
if (fs->plr)
- sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff));
+ sprintf(pl, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff));
+ else if (fs->pls.count > 0) {
+ sprintf(pl, "pls ");
+ gen_pls_str(pl+strlen(pl), sizeof(pl)-strlen(pl), &(fs->pls));
+ }
else
- plr[0] = '\0';
+ pl[0] = '\0';
if (fs->flags_fs & DN_IS_RED) /* RED parameters */
sprintf(red,
"\n\t %cRED w_q %f min_th %d max_th %d max_p %f",
@@ -2281,7 +2439,7 @@ print_flowset_parms(struct dn_flow_set *
sprintf(red, "droptail");
printf("%s %s%s %d queues (%d buckets) %s\n",
- prefix, qs, plr, fs->rq_elements, fs->rq_size, red);
+ prefix, qs, pl, fs->rq_elements, fs->rq_size, red);
}
static void
@@ -2309,7 +2467,7 @@ list_pipes(void *data, uint nbytes, int
/*
* compute length, as pipe have variable size
*/
- l = sizeof(*p) + p->fs.rq_elements * sizeof(*q);
+ l = sizeof(*p) + p->fs.rq_elements * sizeof(*q) + p->fs.pls.count * sizeof(struct pls_range);
next = (char *)p + l;
nbytes -= l;
@@ -2332,11 +2490,21 @@ list_pipes(void *data, uint nbytes, int
sprintf(prefix, "%05d: %s %4d ms ",
p->pipe_nr, buf, p->delay);
+
+ /*
+ * the pls array data is tucked in between the dn_pipe struct
+ * and fs queue data because the pointer isn't recalculated
+ * during the copy from kernel mem into userspace mem, we have
+ * to manually set the array pointer we work back from the end
+ * of the pipe's data boundary (calculated above as "next")
+ */
+ p->fs.pls.arr = next - (p->fs.pls.count * sizeof(struct pls_range)) - (p->fs.rq_elements * sizeof(*q));
+
print_flowset_parms(&(p->fs), prefix);
if (verbose)
printf(" V %20qd\n", p->V >> MY_M);
- q = (struct dn_flow_queue *)(p+1);
+ q = (struct dn_flow_queue *)(next - p->fs.rq_elements * sizeof(*q));
list_queues(&(p->fs), q);
}
for (fs = next; nbytes >= sizeof *fs; fs = next) {
@@ -4113,11 +4281,21 @@ config_pipe(int ac, char **av)
ac--; av++;
break;
+ case TOK_PLS:
+ NEED1("pls needs argument x,y-z\n");
+ if(parse_pls_str(av[0], &(p.fs.pls)))
+ errx(EX_DATAERR, "invalid packet loss set");
+ ac--; av++;
+ break;
+
case TOK_QUEUE:
NEED1("queue needs queue size\n");
end = NULL;
p.fs.qsize = strtoul(av[0], &end, 0);
- if (*end == 'K' || *end == 'k') {
+ if (*end == 'M' || *end == 'm') {
+ p.fs.flags_fs |= DN_QSIZE_IS_BYTES;
+ p.fs.qsize *= 1048576;
+ } else if (*end == 'K' || *end == 'k') {
p.fs.flags_fs |= DN_QSIZE_IS_BYTES;
p.fs.qsize *= 1024;
} else if (*end == 'B' ||
@@ -4374,6 +4552,9 @@ end_mask:
if (p.fs.qsize > limit)
errx(EX_DATAERR, "2 <= queue size <= %ld", limit);
}
+ if (p.fs.pls.count > 0 && p.fs.plr > 0) {
+ errx(EX_DATAERR, "plr and pls options are mutually exclusive");
+ }
if (p.fs.flags_fs & DN_IS_RED) {
size_t len;
int lookup_depth, avg_pkt_size;
@@ -5763,21 +5944,36 @@ done:
}
static void
-zero(int ac, char *av[], int optname /* IP_FW_ZERO or IP_FW_RESETLOG */)
+zero(int ac, char *av[], int optname /* IP_FW_ZERO or IP_FW_RESETLOG or IP_DUMMYNET_ZERO */)
{
uint32_t arg, saved_arg;
int failed = EX_OK;
- char const *name = optname == IP_FW_ZERO ? "ZERO" : "RESETLOG";
+ char const *name;
char const *errstr;
+ struct dn_pipe p;
+
+ if(optname == IP_FW_ZERO || optname == IP_DUMMYNET_ZERO)
+ name = "ZERO";
+ else
+ name = "RESETLOG";
av++; ac--;
+ memset(&p, 0, sizeof p);
+
if (!ac) {
/* clear all entries */
- if (do_cmd(optname, NULL, 0) < 0)
- err(EX_UNAVAILABLE, "setsockopt(IP_FW_%s)", name);
+ if (do_pipe)
+ failed = do_cmd(optname, &p, sizeof p);
+ else
+ failed = do_cmd(optname, NULL, 0);
+
+ if (failed < 0)
+ err(EX_UNAVAILABLE, "setsockopt(IP_%s_%s)",
+ do_pipe ? "DUMMYNET" : "FW", name);
+
if (!do_quiet)
- printf("%s.\n", optname == IP_FW_ZERO ?
+ printf("%s.\n", (optname == IP_FW_ZERO || optname == IP_DUMMYNET_ZERO) ?
"Accounting cleared":"Logging counts reset");
return;
@@ -5795,13 +5991,14 @@ zero(int ac, char *av[], int optname /*
arg |= (1 << 24) | ((use_set - 1) << 16);
av++;
ac--;
- if (do_cmd(optname, &arg, sizeof(arg))) {
- warn("rule %u: setsockopt(IP_FW_%s)",
- saved_arg, name);
+ p.pipe_nr = arg;
+ if (do_pipe ? do_cmd(optname, &p, sizeof p) : do_cmd(optname, &arg, sizeof(arg))) {
+ warn("%s %u: setsockopt(IP_%s_%s)", do_pipe ? "pipe" : "rule",
+ saved_arg, do_pipe ? "DUMMYNET" : "FW", name);
failed = EX_UNAVAILABLE;
} else if (!do_quiet)
printf("Entry %d %s.\n", saved_arg,
- optname == IP_FW_ZERO ?
+ (optname == IP_FW_ZERO || optname == IP_DUMMYNET_ZERO) ?
"cleared" : "logging count reset");
} else {
errx(EX_USAGE, "invalid rule number ``%s''", *av);
@@ -6294,6 +6491,8 @@ ipfw_main(int oldac, char **oldav)
delete(ac, av);
else if (_substrcmp(*av, "flush") == 0)
flush(do_force);
+ else if (do_pipe && _substrcmp(*av, "zero") == 0)
+ zero(ac, av, IP_DUMMYNET_ZERO);
else if (_substrcmp(*av, "zero") == 0)
zero(ac, av, IP_FW_ZERO);
else if (_substrcmp(*av, "resetlog") == 0)
Modified: user/lstewart/dummynet_7.x/sys/netinet/in.h
==============================================================================
--- user/lstewart/dummynet_7.x/sys/netinet/in.h Wed Nov 19 00:25:15 2008 (r185075)
+++ user/lstewart/dummynet_7.x/sys/netinet/in.h Wed Nov 19 01:35:04 2008 (r185076)
@@ -460,10 +460,11 @@ __END_DECLS
#define IP_DUMMYNET_DEL 61 /* delete a dummynet pipe from chain */
#define IP_DUMMYNET_FLUSH 62 /* flush dummynet */
#define IP_DUMMYNET_GET 64 /* get entire dummynet pipes */
+#define IP_DUMMYNET_ZERO 65 /* clear single/all dummynet counter(s) */
-#define IP_RECVTTL 65 /* bool; receive IP TTL w/dgram */
#define IP_MINTTL 66 /* minimum TTL for packet or drop */
#define IP_DONTFRAG 67 /* don't fragment packet */
+#define IP_RECVTTL 68 /* bool; receive IP TTL w/dgram */
/* IPv4 Source Filter Multicast API [RFC3678] */
#define IP_ADD_SOURCE_MEMBERSHIP 70 /* join a source-specific group */
Modified: user/lstewart/dummynet_7.x/sys/netinet/ip_dummynet.c
==============================================================================
--- user/lstewart/dummynet_7.x/sys/netinet/ip_dummynet.c Wed Nov 19 00:25:15 2008 (r185075)
+++ user/lstewart/dummynet_7.x/sys/netinet/ip_dummynet.c Wed Nov 19 01:35:04 2008 (r185076)
@@ -241,6 +241,10 @@ void dummynet_drain(void);
static ip_dn_io_t dummynet_io;
static void dn_rule_delete(void *);
+#define flush_range_array(PLS) \
+ if((PLS)->arr != NULL) \
+ free((PLS)->arr, M_DUMMYNET);
+
/*
* Heap management functions.
*
@@ -1313,6 +1317,23 @@ dummynet_io(struct mbuf **m0, int dir, s
q->tot_pkts++;
if (fs->plr && random() < fs->plr)
goto dropit; /* Random pkt drop. */
+ else {
+ while (fs->pls_index < fs->pls.count) {
+ if (q->tot_pkts >= fs->pls.arr[fs->pls_index].start) {
+ if (q->tot_pkts <=
+ fs->pls.arr[fs->pls_index].end)
+ goto dropit; /* Controlled pkt drop. */
+ else
+ fs->pls_index++;
+ }
+ else
+ /*
+ * q->tot_pkts is lower than the start of the
+ * current range, so let the packet through
+ */
+ break;
+ }
+ }
if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
if (q->len_bytes > fs->qsize)
goto dropit; /* Queue size overflow. */
@@ -1492,12 +1513,31 @@ purge_flow_set(struct dn_flow_set *fs, i
free(fs->w_q_lookup, M_DUMMYNET);
if (fs->rq != NULL)
free(fs->rq, M_DUMMYNET);
+ flush_range_array(&(fs->pls));
/* If this fs is not part of a pipe, free it. */
if (fs->pipe == NULL || fs != &(fs->pipe->fs))
free(fs, M_DUMMYNET);
}
}
+static void
+zero_flow_set(struct dn_flow_set *fs)
+{
+ int i;
+
+ DUMMYNET_LOCK_ASSERT();
+
+ fs->pls_index = 0;
+
+ for (i = 0; i <= fs->rq_size; i++) {
+ if (fs->rq[i] != NULL) {
+ fs->rq[i]->tot_pkts = 0;
+ fs->rq[i]->tot_bytes = 0;
+ fs->rq[i]->drops = 0;
+ }
+ }
+}
+
/*
* Dispose all packets queued on a pipe (not a flow_set).
* Also free all resources associated to a pipe, which is about
@@ -1693,12 +1733,31 @@ alloc_hash(struct dn_flow_set *x, struct
return 0 ;
}
+static int
+set_pls(struct pls_range_array *x, struct pls_range_array *src)
+{
+ flush_range_array(x);
+
+ MALLOC(x->arr, struct pls_range *, src->count * sizeof(struct pls_range), M_DUMMYNET, M_NOWAIT | M_ZERO);
+
+ if(x->arr == NULL)
+ return (ENOMEM);
+
+ x->count = x->size = src->count;
+ copyin(src->arr, x->arr, src->count * sizeof(struct pls_range));
+
+ return 0;
+}
+
+
static void
set_fs_parms(struct dn_flow_set *x, struct dn_flow_set *src)
{
x->flags_fs = src->flags_fs;
x->qsize = src->qsize;
x->plr = src->plr;
+ x->pls_index = 0;
+ set_pls(&(x->pls), &(src->pls));
x->flow_mask = src->flow_mask;
if (x->flags_fs & DN_QSIZE_IS_BYTES) {
if (x->qsize > pipe_byte_limit)
@@ -1985,16 +2044,63 @@ delete_pipe(struct dn_pipe *p)
}
/*
+ * Zeroes counters of a specified pipe/queue or all pipes/queues.
+ */
+static int
+zero_pipe(struct dn_pipe *p)
+{
+ struct dn_pipe *pipe;
+ struct dn_flow_set *fs;
+ int i;
+
+ DUMMYNET_LOCK();
+
+ if (p->pipe_nr > 0) {
+ pipe = locate_pipe(p->pipe_nr); /* locate pipe */
+ if (pipe == NULL) {
+ DUMMYNET_UNLOCK();
+ return (ENOENT); /* not found */
+ }
+ zero_flow_set(&pipe->fs);
+ } else {
+ /* zero all pipes */
+ for (i = 0; i < HASHSIZE; i++) {
+ SLIST_FOREACH(pipe, &pipehash[i], next) {
+ zero_flow_set(&pipe->fs);
+ }
+ SLIST_FOREACH(fs, &flowsethash[i], next) {
+ zero_flow_set(fs);
+ }
+ }
+ }
+
+ DUMMYNET_UNLOCK();
+
+ return 0 ;
+}
+
+static char *
+dn_copy_pls(struct pls_range_array *src_pls, char *bp)
+{
+ bcopy(src_pls->arr, bp, src_pls->count * sizeof(struct pls_range));
+
+ return (bp + src_pls->count * sizeof(struct pls_range));
+}
+
+/*
* helper function used to copy data from kernel in DUMMYNET_GET
*/
static char *
dn_copy_set(struct dn_flow_set *set, char *bp)
{
int i, copied = 0 ;
- struct dn_flow_queue *q, *qp = (struct dn_flow_queue *)bp;
DUMMYNET_LOCK_ASSERT();
+ bp = dn_copy_pls(&(set->pls), bp);
+
+ struct dn_flow_queue *q, *qp = (struct dn_flow_queue *)bp;
+
for (i = 0 ; i <= set->rq_size ; i++)
for (q = set->rq[i] ; q ; q = q->next, qp++ ) {
if (q->hash_slot != i)
@@ -2030,10 +2136,12 @@ dn_calc_size(void)
*/
for (i = 0; i < HASHSIZE; i++) {
SLIST_FOREACH(pipe, &pipehash[i], next)
- size += sizeof(*pipe) +
+ size += sizeof(*pipe) + pipe->fs.pls.count * sizeof(struct
+ pls_range) +
pipe->fs.rq_elements * sizeof(struct dn_flow_queue);
SLIST_FOREACH(fs, &flowsethash[i], next)
- size += sizeof (*fs) +
+ size += sizeof (*fs) + pipe->fs.pls.count * sizeof(struct
+ pls_range) +
fs->rq_elements * sizeof(struct dn_flow_queue);
}
return size;
@@ -2171,6 +2279,15 @@ ip_dn_ctl(struct sockopt *sopt)
error = delete_pipe(p);
break ;
+
+ case IP_DUMMYNET_ZERO :
+ p = &tmp_pipe ;
+ error = sooptcopyin(sopt, p, sizeof *p, sizeof *p);
+ if (error)
+ break ;
+
+ error = zero_pipe(p);
+ break ;
}
return error ;
}
Modified: user/lstewart/dummynet_7.x/sys/netinet/ip_dummynet.h
==============================================================================
--- user/lstewart/dummynet_7.x/sys/netinet/ip_dummynet.h Wed Nov 19 00:25:15 2008 (r185075)
+++ user/lstewart/dummynet_7.x/sys/netinet/ip_dummynet.h Wed Nov 19 01:35:04 2008 (r185076)
@@ -230,6 +230,17 @@ struct dn_flow_queue {
*/
} ;
+struct pls_range {
+ unsigned int start;
+ unsigned int end;
+};
+
+struct pls_range_array {
+ unsigned int size;
+ unsigned int count;
+ struct pls_range *arr;
+};
+
/*
* flow_set descriptor. Contains the "template" parameters for the
* queue configuration, and pointers to the hash table of dn_flow_queue's.
@@ -261,6 +272,8 @@ struct dn_flow_set {
int weight ; /* WFQ queue weight */
int qsize ; /* queue size in slots or bytes */
int plr ; /* pkt loss rate (2^31-1 means 100%) */
+ int pls_index ; /* index into pls array */
+ struct pls_range_array pls; /* pkt loss set as an array of pls_range structs */
struct ipfw_flow_id flow_mask ;
Modified: user/lstewart/dummynet_7.x/sys/netinet/raw_ip.c
==============================================================================
--- user/lstewart/dummynet_7.x/sys/netinet/raw_ip.c Wed Nov 19 00:25:15 2008 (r185075)
+++ user/lstewart/dummynet_7.x/sys/netinet/raw_ip.c Wed Nov 19 01:35:04 2008 (r185076)
@@ -529,6 +529,7 @@ rip_ctloutput(struct socket *so, struct
case IP_DUMMYNET_CONFIGURE:
case IP_DUMMYNET_DEL:
case IP_DUMMYNET_FLUSH:
+ case IP_DUMMYNET_ZERO:
if (ip_dn_ctl_ptr != NULL)
error = ip_dn_ctl_ptr(sopt);
else
More information about the svn-src-user
mailing list