svn commit: r202083 - in user/luigi/ipfw3-head: sbin/ipfw sys/netinet/ipfw

Luigi Rizzo luigi at FreeBSD.org
Mon Jan 11 15:12:14 UTC 2010


Author: luigi
Date: Mon Jan 11 15:12:13 2010
New Revision: 202083
URL: http://svn.freebsd.org/changeset/base/202083

Log:
  data start flowing...

Modified:
  user/luigi/ipfw3-head/sbin/ipfw/dummynet.c
  user/luigi/ipfw3-head/sbin/ipfw/ipfw2.c
  user/luigi/ipfw3-head/sbin/ipfw/ipfw2.h
  user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_fifo.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	Mon Jan 11 12:35:16 2010	(r202082)
+++ user/luigi/ipfw3-head/sbin/ipfw/dummynet.c	Mon Jan 11 15:12:13 2010	(r202083)
@@ -288,65 +288,51 @@ print_extra_delay_parms(struct dn_pipe *
 		p->name, loss, p->samples_no);
 }
 #endif
-void
-ipfw_list_pipes(void *data, uint nbytes, int ac, char *av[])
-{
-#if 0
-	int rulenum;
-	void *next = data;
-	struct dn_pipe *p = (struct dn_pipe *) data;
-	struct dn_flow_set *fs;
-	struct dn_flow_queue *q;
-	int l;
 
-	if (ac > 0)
-		rulenum = strtoul(*av++, NULL, 10);
+/*
+ * filt is an array of sorted ranges whithin where we list
+ */
+static void
+list_pipes(struct dn_id *oid, struct dn_id *end, int *filt)
+{
+    for (; oid != end; oid = O_NEXT(oid, oid->len)) {
+	struct new_pipe *p = (struct new_pipe *)oid;
+	//struct dn_flow_set *fs;
+	//struct dn_flow_queue *q;
+
+	double b = p->bandwidth;
+	char buf[30];
+	char prefix[80];
+	char burst[5 + 7];
+
+	if (oid->type != DN_PIPE)
+		continue;
+	/*
+	 * Print rate (or clocking interface)
+	 */
+	if (b == 0)
+		sprintf(buf, "unlimited");
+	else if (b >= 1000000)
+		sprintf(buf, "%7.3f Mbit/s", b/1000000);
+	else if (b >= 1000)
+		sprintf(buf, "%7.3f Kbit/s", b/1000);
 	else
-		rulenum = 0;
-	for (; nbytes >= sizeof *p; p = (struct dn_pipe *)next) {
-		double b = p->bandwidth;
-		char buf[30];
-		char prefix[80];
-		char burst[5 + 7];
-
-		if (SLIST_NEXT(p, next) != (struct dn_pipe *)DN_IS_PIPE)
-			break;	/* done with pipes, now queues */
+		sprintf(buf, "%7.3f bit/s ", b);
 
-		/*
-		 * compute length, as pipe have variable size
-		 */
-		l = sizeof(*p) + p->fs.rq_elements * sizeof(*q);
-		next = (char *)p + l;
-		nbytes -= l;
-
-		if ((rulenum != 0 && rulenum != p->pipe_nr) || co.do_pipe == 2)
-			continue;
-
-		/*
-		 * Print rate (or clocking interface)
-		 */
-		if (b == 0)
-			sprintf(buf, "unlimited");
-		else if (b >= 1000000)
-			sprintf(buf, "%7.3f Mbit/s", b/1000000);
-		else if (b >= 1000)
-			sprintf(buf, "%7.3f Kbit/s", b/1000);
-		else
-			sprintf(buf, "%7.3f bit/s ", b);
-
-		sprintf(prefix, "%05d: %s %4d ms ",
+	sprintf(prefix, "%05d: %s %4d ms ",
 		    p->pipe_nr, buf, p->delay);
 
-		print_flowset_parms(&(p->fs), prefix);
+	//	print_flowset_parms(&(p->fs), prefix);
+	printf("%s", prefix);
 
-		if (humanize_number(burst, sizeof(burst), p->burst,
+	if (humanize_number(burst, sizeof(burst), p->burst,
 		    "Byte", HN_AUTOSCALE, 0) < 0 || co.verbose)
-			printf("\t burst: %ju Byte\n", p->burst);
-		else
-			printf("\t burst: %s\n", burst);
-
-		print_extra_delay_parms(p);
+		printf("\t burst: %ju Byte\n", p->burst);
+	else
+		printf("\t burst: %s\n", burst);
 
+	// print_extra_delay_parms(p);
+#if 0
 		q = (struct dn_flow_queue *)(p+1);
 		list_queues(&(p->fs), q);
 	}
@@ -371,6 +357,7 @@ ipfw_list_pipes(void *data, uint nbytes,
 		list_queues(fs, q);
 	}
 #endif
+    }
 }
 
 /*
@@ -549,7 +536,8 @@ read_bandwidth(char *arg, int *bandwidth
 			errx(EX_DATAERR, "bandwidth too large");
 
 		*bandwidth = bw;
-		if_name[0] = '\0';
+		if (if_name)
+			if_name[0] = '\0';
 	}
 }
 
@@ -807,6 +795,10 @@ ipfw_config_pipe(int ac, char **av)
 		mask = &sch->sched_mask;
 		break;
 	}
+	if (p)
+		p->bandwidth = -1;
+	if (p2)
+		p2->bandwidth = -1;
 
 	while (ac > 0) {
 		double d;
@@ -1198,3 +1190,36 @@ end_mask:
 	if (i)
 		err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE");
 }
+
+void
+dummynet_list(int ac, char *av[], int show_counters)
+{
+	struct dn_id oid , *x;
+	int ret, l = sizeof(oid);
+
+	oid.type = DN_CMD_GET;
+	oid.len = l;
+	oid.id = 0;
+	switch (co.do_pipe) {
+	case 1:
+		oid.subtype = DN_SCH;	/* list pipe */
+		break;
+	case 2:
+		oid.subtype = DN_FS;	/* list queue */
+		break;
+	}
+	ret = do_cmd(IP_DUMMYNET_GET, &oid, (uintptr_t)&l);
+	printf("%s returns %d need %d\n", __FUNCTION__, ret, oid.id);
+	if (ret != 0 || oid.id <= sizeof(oid))
+		return;
+	l = oid.id;
+	x = malloc(l);
+	if (x == NULL) {
+		err(1, "no memory in %s", __FUNCTION__);
+	}
+	*x = oid;
+	ret = do_cmd(IP_DUMMYNET_GET, x, (uintptr_t)&l);
+	printf("%s returns %d need %d\n", __FUNCTION__, ret, oid.id);
+	list_pipes(x, O_NEXT(x, l), NULL);
+	free(x);
+}

Modified: user/luigi/ipfw3-head/sbin/ipfw/ipfw2.c
==============================================================================
--- user/luigi/ipfw3-head/sbin/ipfw/ipfw2.c	Mon Jan 11 12:35:16 2010	(r202082)
+++ user/luigi/ipfw3-head/sbin/ipfw/ipfw2.c	Mon Jan 11 15:12:13 2010	(r202083)
@@ -1762,6 +1762,10 @@ ipfw_list(int ac, char *av[], int show_c
 		fprintf(stderr, "Testing only, list disabled\n");
 		return;
 	}
+	if (co.do_pipe) {
+		dummynet_list(ac, av, show_counters);
+		return;
+	}
 
 	ac--;
 	av++;
@@ -1778,11 +1782,6 @@ ipfw_list(int ac, char *av[], int show_c
 				co.do_pipe ? "DUMMYNET" : "FW");
 	}
 
-	if (co.do_pipe) {
-		ipfw_list_pipes(data, nbytes, ac, av);
-		goto done;
-	}
-
 	/*
 	 * Count static rules. They have variable size so we
 	 * need to scan the list to count them.

Modified: user/luigi/ipfw3-head/sbin/ipfw/ipfw2.h
==============================================================================
--- user/luigi/ipfw3-head/sbin/ipfw/ipfw2.h	Mon Jan 11 12:35:16 2010	(r202082)
+++ user/luigi/ipfw3-head/sbin/ipfw/ipfw2.h	Mon Jan 11 15:12:13 2010	(r202083)
@@ -265,7 +265,7 @@ u_int32_t altq_name_to_qid(const char *n
 void print_altq_cmd(struct _ipfw_insn_altq *altqptr);
 
 /* dummynet.c */
-void ipfw_list_pipes(void *data, uint nbytes, int ac, char *av[]);
+void dummynet_list(int ac, char *av[], int show_counters);
 int ipfw_delete_pipe(int pipe_or_queue, int n);
 
 /* ipv6.c */

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_fifo.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_fifo.c	Mon Jan 11 12:35:16 2010	(r202082)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched_fifo.c	Mon Jan 11 15:12:13 2010	(r202083)
@@ -91,12 +91,14 @@ fifo_enqueue(struct new_sch_inst *_si, s
     if (si->q == NULL) {
 	si->q = dn_create_queue(_si, f, id);
 	if (si->q == NULL) {
+	    printf("%s dn_create_queue failed\n", __FUNCTION__);
 	    FREE_PKT(m);
 	    return 1;
 	}
     }
     /* Now the si->q is valid, so insert the packet in this queue */
     if (dn_queue_packet(si->q, m)) {
+	    printf("%s dn_queue_packet failed\n", __FUNCTION__);
         /* packet was dropped */
         return 1;
     }

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c	Mon Jan 11 12:35:16 2010	(r202082)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c	Mon Jan 11 15:12:13 2010	(r202083)
@@ -249,7 +249,6 @@ dn_queue_packet(struct new_queue *q, str
 	/* Update statistics, then check reasons to drop pkt. */
 	q->tot_bytes += m->m_pkthdr.len;
 	q->tot_pkts++;
-
 	if (f->plr && random() < f->plr)
 		goto drop;
 	if (f->flags & DN_QSIZE_BYTES) {
@@ -442,6 +441,7 @@ create_si(struct new_schk *s, int slot)
 	int ret;
 	int l = sizeof(*si) + s->fp->sch_inst_len;
 
+printf("%s start slot %d\n", __FUNCTION__, slot);
 	si = malloc(l, M_DUMMYNET, M_NOWAIT | M_ZERO);
 
 	if (si == NULL)
@@ -467,6 +467,7 @@ create_si(struct new_schk *s, int slot)
         /* Put entry in front of the hash list of the parent. */
         SLIST_INSERT_HEAD(&s->ht[slot], si, next);
 	si->hash_slot = slot;
+	dn_cfg.si_count++;
 	return si;
 
 error:
@@ -483,6 +484,7 @@ find_sch_inst(struct new_schk *s, struct
     int i;
     struct ipfw_flow_id id_t;
     
+printf("%s start id %p\n", __FUNCTION__, id);
     if ( 0 == (s->sch.flags & DN_HAVE_MASK) ) {
 	i = 0;
         si = SLIST_FIRST(&s->ht[0]);
@@ -760,8 +762,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) ? DN_PIPEOFFSET : 0);
 	DUMMYNET_LOCK();
 	io_pkt++;
 	/* XXX locate_flowset could be optimised with a direct ref. */
@@ -793,6 +794,7 @@ dummynet_io(struct mbuf **m0, int dir, s
 	if (fs->kflags & DN_HAVE_MASK)
 		do_mask(&fs->fs.flow_mask, &(fwa->f_id));
 	if (sch->fp->enqueue(sch_inst, fs, m, &(fwa->f_id))) {
+		printf("%s dropped by enqueue\n", __FUNCTION__);
 		/* packet was dropped by enqueue() */
 		*m0 = NULL;
 		goto dropit;

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h	Mon Jan 11 12:35:16 2010	(r202082)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h	Mon Jan 11 15:12:13 2010	(r202083)
@@ -71,6 +71,12 @@ struct dn_parms {
 	struct timeval prev_t;
 	struct dn_heap	system_heap;
 
+	/* how many objects we have -- useful for reporting space */
+	int	schk_count;
+	int	si_count;
+	int	fsk_count;
+	int	queue_count;
+
 	int	hmask;	/* mask for hashsize, must be 2^n-1 */
 	/* fhash and schedhash are hmask+1 entries */
 	struct new_fsk_head	fsunlinked;
@@ -156,6 +162,7 @@ struct new_schk {
 	 */
 	int ht_slots; 	/* number of slots */
 	struct new_sch_inst_head *ht;
+	struct new_sch_inst_head h0;	/* used if malloc fails */
 
 	int kflags;
 

Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c	Mon Jan 11 12:35:16 2010	(r202082)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c	Mon Jan 11 15:12:13 2010	(r202083)
@@ -61,6 +61,13 @@ __FBSDID("$FreeBSD$");
 
 static int	ip_dn_ctl(struct sockopt *sopt);
 
+	/* which objects to copy */
+#define DN_C_PIPE 	0x01
+#define DN_C_SCH	0x02
+#define DN_C_SCH_INST	0x04
+#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);
@@ -139,6 +146,7 @@ destroy_si(struct new_sch_inst *si)
 		dn_delete_queue(q);
 	}
 	free(si, M_DUMMYNET);
+	dn_cfg.si_count--;
 	return 0;
 }
 
@@ -161,9 +169,23 @@ destroy_fs(struct new_fsk *fs)
 	fs->kflags |= DN_DELETE;
 	if (fs->refcnt != 0)
 		return;
+	dn_cfg.fsk_count--;
 	SLIST_REMOVE(&s->fsk_list, fs, new_fsk, sch_chain);
 }
 
+static struct new_fsk *
+create_fs(void)
+{
+	struct new_fsk *fs;
+
+	fs = malloc(sizeof(*fs), M_DUMMYNET, M_NOWAIT | M_ZERO);
+	if (fs) {
+		SLIST_INSERT_HEAD(&dn_cfg.fsunlinked, fs, next);
+		dn_cfg.fsk_count++;
+	}
+	return fs;
+}
+
 /*
  * helper for schedulers. Creates a queue
  */
@@ -180,7 +202,7 @@ dn_create_queue(struct new_sch_inst *si,
 		return NULL;
 	}
 
-	set_oid(&q->oid, DN_QUEUE, size, 0);
+	set_oid(&q->oid, DN_QUEUE, 0, size);
 	q->fs = fs;
 	q->si = si;
 	fs->refcnt++;
@@ -188,6 +210,7 @@ dn_create_queue(struct new_sch_inst *si,
 	if (si->sched->fp->new_queue)
 		si->sched->fp->new_queue(q);
 	SLIST_INSERT_HEAD(&si->ql_list, q, ql_next);
+	dn_cfg.queue_count++;
 	return q;
 }
 
@@ -206,13 +229,14 @@ dn_delete_queue(struct new_queue *q)
 		fs->sched->fp->free_queue(q);
 	free(q, M_DUMMYNET);
 	fs->refcnt--;
+	dn_cfg.queue_count--;
 	if (fs->refcnt == 0 && fs->kflags & DN_DELETE)
 		destroy_fs(fs);
 	return 0;
 }
 
 static struct new_schk *
-destroy_sched(struct new_schk *s, int del)
+destroy_schk(struct new_schk *s, int del)
 {
 	int i;
 	struct new_sch_inst *si;
@@ -228,9 +252,87 @@ destroy_sched(struct new_schk *s, int de
 	if (fp->destroy)
 		fp->destroy(s, 1);
 	free(s, M_DUMMYNET);
+	dn_cfg.schk_count--;
 	return NULL;
 }
 
+static struct new_schk *
+create_schk(struct dn_sched *fp)
+{
+	struct new_schk *s;
+	int l = sizeof(*s) + fp->schk_len;
+	
+	s = malloc(l, M_DUMMYNET, M_NOWAIT | M_ZERO);
+	if (s) {
+		set_oid(&s->pipe.oid, DN_PIPE, 0, sizeof(s->pipe));
+		s->fp = fp;
+		SLIST_INIT(&s->fsk_list);
+		/* use a default hash */
+		s->ht_slots = 1;
+		s->ht = &s->h0;
+		dn_cfg.schk_count++;
+	}
+	return s;
+}
+
+static int
+copy_obj(char **start, char *end, void *_o)
+{
+	struct dn_id *o = _o;
+
+	if (end - *start < o->len)
+		return 1;
+	bcopy(_o, *start, o->len);
+	*start += o->len;
+	return 0;
+}
+
+/* copy data, return 1 when full */
+static int
+copy_data(char **start, char *end, int flags)
+{
+    int i;
+
+    if (flags & (DN_C_PIPE | DN_C_SCH | DN_C_SCH_INST)) {
+	for (i = 0; i < dn_cfg.hmask+1; i++) {
+	    struct new_schk *s;
+	    SLIST_FOREACH(s, &dn_cfg.schedhash[i], next) {
+		if (flags & DN_C_PIPE) {
+		    printf("copy pipe %d len %d\n",
+			s->pipe.pipe_nr, s->pipe.oid.len);
+		    if (copy_obj(start, end, &s->pipe))
+			return 1;
+		}
+		if (flags & DN_C_SCH) {
+		    printf("copy sched %d\n", s->sch.sched_nr);
+		    if (copy_obj(start, end, &s->sch))
+			return 1;
+		}
+		if (flags & DN_C_SCH_INST) {
+		    printf("copy shc_inst %d\n", s->sch.sched_nr);
+			/* scan the hashtable */
+		}
+	    }
+	}
+    }
+    if (flags & (DN_C_FS)) {
+	struct new_fsk *fs;
+	for (i = 0; i < dn_cfg.hmask+1; i++) {
+	    SLIST_FOREACH(fs, &dn_cfg.fshash[i], next) {
+		printf("copy flowset %d\n", fs->fs.fs_nr);
+		if (copy_obj(start, end, &fs->fs))
+		    return 1;
+	    }
+	}
+	SLIST_FOREACH(fs, &dn_cfg.fsunlinked, next) {
+	    printf("copy flowset %d\n", fs->fs.fs_nr);
+	    if (copy_obj(start, end, &fs->fs))
+		return 1;
+	}
+    }
+    return 0;
+}
+
 /*
  * Delete all objects:
  * - mark as shutting down;
@@ -256,7 +358,7 @@ dummynet_flush(void)
 
 		while ( (s = SLIST_FIRST(sh)) != NULL) {
 			SLIST_REMOVE_HEAD(sh, next);
-			destroy_sched(s, 1 /* delete */);
+			destroy_schk(s, 1 /* delete */);
 		}
 	}
 
@@ -444,7 +546,7 @@ config_sched(struct new_sch *nsch, struc
 {
 	struct new_schk *s;
 	struct dn_sched *fp;
-	int i, l, is_new;
+	int i, is_new;
 	struct new_fsk_head fsk_list;
 
 	SLIST_INIT(&fsk_list);
@@ -466,23 +568,25 @@ config_sched(struct new_sch *nsch, struc
 	DUMMYNET_LOCK();
 	s = locate_scheduler(i);
 	printf("%s type %s old %p\n", __FUNCTION__, fp->name, s);
-	if (s && s->fp != fp)	/* type changed, hard delete */
-		s = destroy_sched(s, 1);
+	if (s && s->fp != fp) {	/* type changed, hard delete */
+		/* preserve old pipe ? */
+		s = destroy_schk(s, 1);
+	}
 	if (s) {
 		is_new = 0;
 	} else {
-		l = sizeof(*s) + fp->schk_len;
-		s = malloc(l, M_DUMMYNET, M_NOWAIT | M_ZERO);
+		s = create_schk(fp);
 		if (s == NULL)
 			return ENOMEM;
-		s->fp = fp;
-		SLIST_INIT(&s->fsk_list);
+		s->pipe.pipe_nr = i;
+		SLIST_INSERT_HEAD(&dn_cfg.schedhash[HASH(i)], s, next);
 		is_new = 1;
 	}
 	s->sch = *nsch;
 	s->cfg = arg;
-	if (is_new) {
-		SLIST_INSERT_HEAD(&dn_cfg.schedhash[HASH(i)], s, next);
+	/* initialize the hash table */
+	if (s->sch.flags & DN_HAVE_MASK) {
+	} else {
 	}
 	/* call init function  */
 	if (s->fp->config)
@@ -514,18 +618,26 @@ config_fs(struct new_fs *nfs, struct dn_
 	if (i <= 0 || i > DN_MAXID)
 		return EINVAL;
 	/* 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();
 	fs = ipdn_locate_flowset(i);
 
 	printf("%s %d old %p\n", __FUNCTION__, i, fs);
 	if (fs == NULL) {
-		fs = malloc(sizeof(*fs),
-			M_DUMMYNET, M_NOWAIT | M_ZERO);
+		fs = create_fs();
 		if (fs == NULL) {
 			DUMMYNET_UNLOCK();
 			return ENOMEM;
 		}
-		SLIST_INSERT_HEAD(&dn_cfg.fsunlinked, fs, next);
 	}
 	fs->fs = *nfs;	/* update config */
 	/* copy values, check if scheduler exists and mark active */
@@ -621,46 +733,69 @@ config_profile(struct new_profile *pf, s
 	return 0;
 }
 
-static size_t
-dn_calc_size(void)
-{
-    return 100;
-}
-
 static int
 dummynet_get(struct sockopt *sopt)
 {
-    int error=0;
-    char *buf, *bp ; /* bp is the "copy-pointer" */
-    size_t size ;
-    int i;
-
-    /* XXX lock held too long */
-    DUMMYNET_LOCK();
-    /*
-     * XXX: Ugly, but we need to allocate memory with M_WAITOK flag and we
-     *      cannot use this flag while holding a mutex.
-     */
-    for (i = 0; i < 10; i++) {
-	size = dn_calc_size();
-	DUMMYNET_UNLOCK();
-	buf = malloc(size, M_TEMP, M_WAITOK);
+    int have = 0, i, need, error;
+    char *start = NULL, *buf, *end;
+    size_t sopt_valsize;
+    struct dn_id cmd;
+    int to_copy = 0;
+
+    /* save original values */
+    sopt_valsize = sopt->sopt_valsize;
+    printf("%s have %d bytes\n", __FUNCTION__, sopt_valsize);
+
+    error = sooptcopyin(sopt, &cmd, sizeof(cmd), sizeof(cmd));
+    sopt->sopt_valsize = sopt_valsize;
+    if (error)
+	return error;
+    printf("%s cmd %d len %d\n", __FUNCTION__, cmd.type, cmd.len);
+    for (have = 0, i = 0; i < 10; i++) {
 	DUMMYNET_LOCK();
-	if (size >= dn_calc_size())
-		break;
-	free(buf, M_TEMP);
-	buf = NULL;
-    }
-    if (buf == NULL) {
+	switch (cmd.subtype) {
+	default:
+	    return EINVAL;
+	case DN_SCH:	/* pipe show */
+	    to_copy = DN_C_SCH | DN_C_PIPE;
+	    need = dn_cfg.schk_count *
+		(sizeof(struct new_sch) + sizeof(struct new_pipe));
+	    break;
+	case DN_FS:	/* queue show */
+	    to_copy = DN_C_FS;
+	    need = dn_cfg.fsk_count *
+		(sizeof(struct new_fs));
+	    break;
+	}
+	need += sizeof(cmd);
+	cmd.id = need;
+	printf("pass %d have %d need %d len %d\n",
+		i, have, need, sopt_valsize);
+	if (have >= need)
+	    break;
 	DUMMYNET_UNLOCK();
-	return ENOBUFS ;
+	if (start)
+	    free(start, M_DUMMYNET);
+	buf = NULL;
+	if (need > sopt_valsize)
+	    break;
+	have = need;
+	start = malloc(have, M_DUMMYNET, M_WAITOK | M_ZERO);
+	if (start == NULL)
+	    return ENOMEM;
     }
-    bp = buf;
+    if (start == NULL)
+        return sooptcopyout(sopt, &cmd, sizeof(cmd));
+    end = start + have;
+    sopt->sopt_valsize = sopt_valsize;
+    bcopy(&cmd, start, sizeof(cmd));
+    buf = start + sizeof(cmd);
+    /* start copying other objects */
+    copy_data(&buf, end, to_copy);
     DUMMYNET_UNLOCK();
-
-    error = sooptcopyout(sopt, buf, size);
-    free(buf, M_TEMP);
-    return error ;
+    error = sooptcopyout(sopt, start, buf - start);
+    free(start, M_DUMMYNET);
+    return error;
 }
 
 /*
@@ -699,8 +834,7 @@ ip_dn_ctl(struct sockopt *sopt)
 
 	case IP_DUMMYNET_CONFIGURE :
 	case IP_DUMMYNET_DEL :	/* remove a pipe or queue */
-		l = (sopt->sopt_dir == SOPT_SET) ? sopt->sopt_valsize :
-			*(int *)(sopt->sopt_valsize);
+		l = sopt->sopt_valsize;
 		if (l < 0 || l > 12000) {
 			printf("argument too large, %d\n", l);
 			break;


More information about the svn-src-user mailing list