Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 19 Nov 2008 01:35:04 +0000 (UTC)
From:      Lawrence Stewart <lstewart@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r185076 - in user/lstewart/dummynet_7.x: sbin/ipfw sys sys/netinet
Message-ID:  <200811190135.mAJ1Z47o099891@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200811190135.mAJ1Z47o099891>