xref: /freebsd/sbin/ipfw/dummynet.c (revision b3aaa0cc21c63d388230c7ef2a80abd631ff20d5)
1 /*
2  * Copyright (c) 2002-2003 Luigi Rizzo
3  * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
4  * Copyright (c) 1994 Ugen J.S.Antsilevich
5  *
6  * Idea and grammar partially left from:
7  * Copyright (c) 1993 Daniel Boulet
8  *
9  * Redistribution and use in source forms, with and without modification,
10  * are permitted provided that this entire comment appears intact.
11  *
12  * Redistribution in binary form may occur without any restrictions.
13  * Obviously, it would be nice if you gave credit where credit is due
14  * but requiring it would be too onerous.
15  *
16  * This software is provided ``AS IS'' without any warranties of any kind.
17  *
18  * NEW command line interface for IP firewall facility
19  *
20  * $FreeBSD$
21  *
22  * dummynet support
23  */
24 
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/queue.h>
28 /* XXX there are several sysctl leftover here */
29 #include <sys/sysctl.h>
30 
31 #include "ipfw2.h"
32 
33 #include <ctype.h>
34 #include <err.h>
35 #include <netdb.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sysexits.h>
40 
41 #include <net/if.h>
42 #include <netinet/in.h>
43 #include <netinet/ip_fw.h>
44 #include <netinet/ip_dummynet.h>
45 #include <arpa/inet.h>	/* inet_ntoa */
46 
47 static struct _s_x dummynet_params[] = {
48 	{ "plr",		TOK_PLR },
49 	{ "noerror",		TOK_NOERROR },
50 	{ "buckets",		TOK_BUCKETS },
51 	{ "dst-ip",		TOK_DSTIP },
52 	{ "src-ip",		TOK_SRCIP },
53 	{ "dst-port",		TOK_DSTPORT },
54 	{ "src-port",		TOK_SRCPORT },
55 	{ "proto",		TOK_PROTO },
56 	{ "weight",		TOK_WEIGHT },
57 	{ "all",		TOK_ALL },
58 	{ "mask",		TOK_MASK },
59 	{ "droptail",		TOK_DROPTAIL },
60 	{ "red",		TOK_RED },
61 	{ "gred",		TOK_GRED },
62 	{ "bw",			TOK_BW },
63 	{ "bandwidth",		TOK_BW },
64 	{ "delay",		TOK_DELAY },
65 	{ "pipe",		TOK_PIPE },
66 	{ "queue",		TOK_QUEUE },
67 	{ "flow-id",		TOK_FLOWID},
68 	{ "dst-ipv6",		TOK_DSTIP6},
69 	{ "dst-ip6",		TOK_DSTIP6},
70 	{ "src-ipv6",		TOK_SRCIP6},
71 	{ "src-ip6",		TOK_SRCIP6},
72 	{ "dummynet-params",	TOK_NULL },
73 	{ NULL, 0 }	/* terminator */
74 };
75 
76 static int
77 sort_q(const void *pa, const void *pb)
78 {
79 	int rev = (co.do_sort < 0);
80 	int field = rev ? -co.do_sort : co.do_sort;
81 	long long res = 0;
82 	const struct dn_flow_queue *a = pa;
83 	const struct dn_flow_queue *b = pb;
84 
85 	switch (field) {
86 	case 1: /* pkts */
87 		res = a->len - b->len;
88 		break;
89 	case 2: /* bytes */
90 		res = a->len_bytes - b->len_bytes;
91 		break;
92 
93 	case 3: /* tot pkts */
94 		res = a->tot_pkts - b->tot_pkts;
95 		break;
96 
97 	case 4: /* tot bytes */
98 		res = a->tot_bytes - b->tot_bytes;
99 		break;
100 	}
101 	if (res < 0)
102 		res = -1;
103 	if (res > 0)
104 		res = 1;
105 	return (int)(rev ? res : -res);
106 }
107 
108 static void
109 list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q)
110 {
111 	int l;
112 	int index_printed, indexes = 0;
113 	char buff[255];
114 	struct protoent *pe;
115 
116 	if (fs->rq_elements == 0)
117 		return;
118 
119 	if (co.do_sort != 0)
120 		heapsort(q, fs->rq_elements, sizeof *q, sort_q);
121 
122 	/* Print IPv4 flows */
123 	index_printed = 0;
124 	for (l = 0; l < fs->rq_elements; l++) {
125 		struct in_addr ina;
126 
127 		/* XXX: Should check for IPv4 flows */
128 		if (IS_IP6_FLOW_ID(&(q[l].id)))
129 			continue;
130 
131 		if (!index_printed) {
132 			index_printed = 1;
133 			if (indexes > 0)	/* currently a no-op */
134 				printf("\n");
135 			indexes++;
136 			printf("    "
137 			    "mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
138 			    fs->flow_mask.proto,
139 			    fs->flow_mask.src_ip, fs->flow_mask.src_port,
140 			    fs->flow_mask.dst_ip, fs->flow_mask.dst_port);
141 
142 			printf("BKT Prot ___Source IP/port____ "
143 			    "____Dest. IP/port____ "
144 			    "Tot_pkt/bytes Pkt/Byte Drp\n");
145 		}
146 
147 		printf("%3d ", q[l].hash_slot);
148 		pe = getprotobynumber(q[l].id.proto);
149 		if (pe)
150 			printf("%-4s ", pe->p_name);
151 		else
152 			printf("%4u ", q[l].id.proto);
153 		ina.s_addr = htonl(q[l].id.src_ip);
154 		printf("%15s/%-5d ",
155 		    inet_ntoa(ina), q[l].id.src_port);
156 		ina.s_addr = htonl(q[l].id.dst_ip);
157 		printf("%15s/%-5d ",
158 		    inet_ntoa(ina), q[l].id.dst_port);
159 		printf("%4llu %8llu %2u %4u %3u\n",
160 		    align_uint64(&q[l].tot_pkts),
161 		    align_uint64(&q[l].tot_bytes),
162 		    q[l].len, q[l].len_bytes, q[l].drops);
163 		if (co.verbose)
164 			printf("   S %20llu  F %20llu\n",
165 			    align_uint64(&q[l].S), align_uint64(&q[l].F));
166 	}
167 
168 	/* Print IPv6 flows */
169 	index_printed = 0;
170 	for (l = 0; l < fs->rq_elements; l++) {
171 		if (!IS_IP6_FLOW_ID(&(q[l].id)))
172 			continue;
173 
174 		if (!index_printed) {
175 			index_printed = 1;
176 			if (indexes > 0)
177 				printf("\n");
178 			indexes++;
179 			printf("\n        mask: proto: 0x%02x, flow_id: 0x%08x,  ",
180 			    fs->flow_mask.proto, fs->flow_mask.flow_id6);
181 			inet_ntop(AF_INET6, &(fs->flow_mask.src_ip6),
182 			    buff, sizeof(buff));
183 			printf("%s/0x%04x -> ", buff, fs->flow_mask.src_port);
184 			inet_ntop( AF_INET6, &(fs->flow_mask.dst_ip6),
185 			    buff, sizeof(buff) );
186 			printf("%s/0x%04x\n", buff, fs->flow_mask.dst_port);
187 
188 			printf("BKT ___Prot___ _flow-id_ "
189 			    "______________Source IPv6/port_______________ "
190 			    "_______________Dest. IPv6/port_______________ "
191 			    "Tot_pkt/bytes Pkt/Byte Drp\n");
192 		}
193 		printf("%3d ", q[l].hash_slot);
194 		pe = getprotobynumber(q[l].id.proto);
195 		if (pe != NULL)
196 			printf("%9s ", pe->p_name);
197 		else
198 			printf("%9u ", q[l].id.proto);
199 		printf("%7d  %39s/%-5d ", q[l].id.flow_id6,
200 		    inet_ntop(AF_INET6, &(q[l].id.src_ip6), buff, sizeof(buff)),
201 		    q[l].id.src_port);
202 		printf(" %39s/%-5d ",
203 		    inet_ntop(AF_INET6, &(q[l].id.dst_ip6), buff, sizeof(buff)),
204 		    q[l].id.dst_port);
205 		printf(" %4llu %8llu %2u %4u %3u\n",
206 		    align_uint64(&q[l].tot_pkts),
207 		    align_uint64(&q[l].tot_bytes),
208 		    q[l].len, q[l].len_bytes, q[l].drops);
209 		if (co.verbose)
210 			printf("   S %20llu  F %20llu\n",
211 			    align_uint64(&q[l].S),
212 			    align_uint64(&q[l].F));
213 	}
214 }
215 
216 static void
217 print_flowset_parms(struct dn_flow_set *fs, char *prefix)
218 {
219 	int l;
220 	char qs[30];
221 	char plr[30];
222 	char red[90];	/* Display RED parameters */
223 
224 	l = fs->qsize;
225 	if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
226 		if (l >= 8192)
227 			sprintf(qs, "%d KB", l / 1024);
228 		else
229 			sprintf(qs, "%d B", l);
230 	} else
231 		sprintf(qs, "%3d sl.", l);
232 	if (fs->plr)
233 		sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff));
234 	else
235 		plr[0] = '\0';
236 	if (fs->flags_fs & DN_IS_RED)	/* RED parameters */
237 		sprintf(red,
238 		    "\n\t  %cRED w_q %f min_th %d max_th %d max_p %f",
239 		    (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ',
240 		    1.0 * fs->w_q / (double)(1 << SCALE_RED),
241 		    SCALE_VAL(fs->min_th),
242 		    SCALE_VAL(fs->max_th),
243 		    1.0 * fs->max_p / (double)(1 << SCALE_RED));
244 	else
245 		sprintf(red, "droptail");
246 
247 	printf("%s %s%s %d queues (%d buckets) %s\n",
248 	    prefix, qs, plr, fs->rq_elements, fs->rq_size, red);
249 }
250 
251 void
252 ipfw_list_pipes(void *data, uint nbytes, int ac, char *av[])
253 {
254 	int rulenum;
255 	void *next = data;
256 	struct dn_pipe *p = (struct dn_pipe *) data;
257 	struct dn_flow_set *fs;
258 	struct dn_flow_queue *q;
259 	int l;
260 
261 	if (ac > 0)
262 		rulenum = strtoul(*av++, NULL, 10);
263 	else
264 		rulenum = 0;
265 	for (; nbytes >= sizeof *p; p = (struct dn_pipe *)next) {
266 		double b = p->bandwidth;
267 		char buf[30];
268 		char prefix[80];
269 
270 		if (SLIST_NEXT(p, next) != (struct dn_pipe *)DN_IS_PIPE)
271 			break;	/* done with pipes, now queues */
272 
273 		/*
274 		 * compute length, as pipe have variable size
275 		 */
276 		l = sizeof(*p) + p->fs.rq_elements * sizeof(*q);
277 		next = (char *)p + l;
278 		nbytes -= l;
279 
280 		if ((rulenum != 0 && rulenum != p->pipe_nr) || co.do_pipe == 2)
281 			continue;
282 
283 		/*
284 		 * Print rate (or clocking interface)
285 		 */
286 		if (p->if_name[0] != '\0')
287 			sprintf(buf, "%s", p->if_name);
288 		else if (b == 0)
289 			sprintf(buf, "unlimited");
290 		else if (b >= 1000000)
291 			sprintf(buf, "%7.3f Mbit/s", b/1000000);
292 		else if (b >= 1000)
293 			sprintf(buf, "%7.3f Kbit/s", b/1000);
294 		else
295 			sprintf(buf, "%7.3f bit/s ", b);
296 
297 		sprintf(prefix, "%05d: %s %4d ms ",
298 		    p->pipe_nr, buf, p->delay);
299 		print_flowset_parms(&(p->fs), prefix);
300 		if (co.verbose)
301 			printf("   V %20llu\n", align_uint64(&p->V) >> MY_M);
302 
303 		q = (struct dn_flow_queue *)(p+1);
304 		list_queues(&(p->fs), q);
305 	}
306 	for (fs = next; nbytes >= sizeof *fs; fs = next) {
307 		char prefix[80];
308 
309 		if (SLIST_NEXT(fs, next) != (struct dn_flow_set *)DN_IS_QUEUE)
310 			break;
311 		l = sizeof(*fs) + fs->rq_elements * sizeof(*q);
312 		next = (char *)fs + l;
313 		nbytes -= l;
314 
315 		if (rulenum != 0 && ((rulenum != fs->fs_nr && co.do_pipe == 2) ||
316 		    (rulenum != fs->parent_nr && co.do_pipe == 1))) {
317 			continue;
318 		}
319 
320 		q = (struct dn_flow_queue *)(fs+1);
321 		sprintf(prefix, "q%05d: weight %d pipe %d ",
322 		    fs->fs_nr, fs->weight, fs->parent_nr);
323 		print_flowset_parms(fs, prefix);
324 		list_queues(fs, q);
325 	}
326 }
327 
328 /*
329  * Delete pipe or queue i
330  */
331 int
332 ipfw_delete_pipe(int pipe_or_queue, int i)
333 {
334 	struct dn_pipe p;
335 
336 	memset(&p, 0, sizeof p);
337 	if (pipe_or_queue == 1)
338 		p.pipe_nr = i;		/* pipe */
339 	else
340 		p.fs.fs_nr = i;		/* queue */
341 	i = do_cmd(IP_DUMMYNET_DEL, &p, sizeof p);
342 	if (i) {
343 		i = 1;
344 		warn("rule %u: setsockopt(IP_DUMMYNET_DEL)", i);
345 	}
346 	return i;
347 }
348 
349 void
350 ipfw_config_pipe(int ac, char **av)
351 {
352 	struct dn_pipe p;
353 	int i;
354 	char *end;
355 	void *par = NULL;
356 
357 	memset(&p, 0, sizeof p);
358 
359 	av++; ac--;
360 	/* Pipe number */
361 	if (ac && isdigit(**av)) {
362 		i = atoi(*av); av++; ac--;
363 		if (co.do_pipe == 1)
364 			p.pipe_nr = i;
365 		else
366 			p.fs.fs_nr = i;
367 	}
368 	while (ac > 0) {
369 		double d;
370 		int tok = match_token(dummynet_params, *av);
371 		ac--; av++;
372 
373 		switch(tok) {
374 		case TOK_NOERROR:
375 			p.fs.flags_fs |= DN_NOERROR;
376 			break;
377 
378 		case TOK_PLR:
379 			NEED1("plr needs argument 0..1\n");
380 			d = strtod(av[0], NULL);
381 			if (d > 1)
382 				d = 1;
383 			else if (d < 0)
384 				d = 0;
385 			p.fs.plr = (int)(d*0x7fffffff);
386 			ac--; av++;
387 			break;
388 
389 		case TOK_QUEUE:
390 			NEED1("queue needs queue size\n");
391 			end = NULL;
392 			p.fs.qsize = strtoul(av[0], &end, 0);
393 			if (*end == 'K' || *end == 'k') {
394 				p.fs.flags_fs |= DN_QSIZE_IS_BYTES;
395 				p.fs.qsize *= 1024;
396 			} else if (*end == 'B' ||
397 			    _substrcmp2(end, "by", "bytes") == 0) {
398 				p.fs.flags_fs |= DN_QSIZE_IS_BYTES;
399 			}
400 			ac--; av++;
401 			break;
402 
403 		case TOK_BUCKETS:
404 			NEED1("buckets needs argument\n");
405 			p.fs.rq_size = strtoul(av[0], NULL, 0);
406 			ac--; av++;
407 			break;
408 
409 		case TOK_MASK:
410 			NEED1("mask needs mask specifier\n");
411 			/*
412 			 * per-flow queue, mask is dst_ip, dst_port,
413 			 * src_ip, src_port, proto measured in bits
414 			 */
415 			par = NULL;
416 
417 			bzero(&p.fs.flow_mask, sizeof(p.fs.flow_mask));
418 			end = NULL;
419 
420 			while (ac >= 1) {
421 			    uint32_t *p32 = NULL;
422 			    uint16_t *p16 = NULL;
423 			    uint32_t *p20 = NULL;
424 			    struct in6_addr *pa6 = NULL;
425 			    uint32_t a;
426 
427 			    tok = match_token(dummynet_params, *av);
428 			    ac--; av++;
429 			    switch(tok) {
430 			    case TOK_ALL:
431 				    /*
432 				     * special case, all bits significant
433 				     */
434 				    p.fs.flow_mask.dst_ip = ~0;
435 				    p.fs.flow_mask.src_ip = ~0;
436 				    p.fs.flow_mask.dst_port = ~0;
437 				    p.fs.flow_mask.src_port = ~0;
438 				    p.fs.flow_mask.proto = ~0;
439 				    n2mask(&(p.fs.flow_mask.dst_ip6), 128);
440 				    n2mask(&(p.fs.flow_mask.src_ip6), 128);
441 				    p.fs.flow_mask.flow_id6 = ~0;
442 				    p.fs.flags_fs |= DN_HAVE_FLOW_MASK;
443 				    goto end_mask;
444 
445 			    case TOK_DSTIP:
446 				    p32 = &p.fs.flow_mask.dst_ip;
447 				    break;
448 
449 			    case TOK_SRCIP:
450 				    p32 = &p.fs.flow_mask.src_ip;
451 				    break;
452 
453 			    case TOK_DSTIP6:
454 				    pa6 = &(p.fs.flow_mask.dst_ip6);
455 				    break;
456 
457 			    case TOK_SRCIP6:
458 				    pa6 = &(p.fs.flow_mask.src_ip6);
459 				    break;
460 
461 			    case TOK_FLOWID:
462 				    p20 = &p.fs.flow_mask.flow_id6;
463 				    break;
464 
465 			    case TOK_DSTPORT:
466 				    p16 = &p.fs.flow_mask.dst_port;
467 				    break;
468 
469 			    case TOK_SRCPORT:
470 				    p16 = &p.fs.flow_mask.src_port;
471 				    break;
472 
473 			    case TOK_PROTO:
474 				    break;
475 
476 			    default:
477 				    ac++; av--; /* backtrack */
478 				    goto end_mask;
479 			    }
480 			    if (ac < 1)
481 				    errx(EX_USAGE, "mask: value missing");
482 			    if (*av[0] == '/') {
483 				    a = strtoul(av[0]+1, &end, 0);
484 				    if (pa6 == NULL)
485 					    a = (a == 32) ? ~0 : (1 << a) - 1;
486 			    } else
487 				    a = strtoul(av[0], &end, 0);
488 			    if (p32 != NULL)
489 				    *p32 = a;
490 			    else if (p16 != NULL) {
491 				    if (a > 0xFFFF)
492 					    errx(EX_DATAERR,
493 						"port mask must be 16 bit");
494 				    *p16 = (uint16_t)a;
495 			    } else if (p20 != NULL) {
496 				    if (a > 0xfffff)
497 					errx(EX_DATAERR,
498 					    "flow_id mask must be 20 bit");
499 				    *p20 = (uint32_t)a;
500 			    } else if (pa6 != NULL) {
501 				    if (a > 128)
502 					errx(EX_DATAERR,
503 					    "in6addr invalid mask len");
504 				    else
505 					n2mask(pa6, a);
506 			    } else {
507 				    if (a > 0xFF)
508 					    errx(EX_DATAERR,
509 						"proto mask must be 8 bit");
510 				    p.fs.flow_mask.proto = (uint8_t)a;
511 			    }
512 			    if (a != 0)
513 				    p.fs.flags_fs |= DN_HAVE_FLOW_MASK;
514 			    ac--; av++;
515 			} /* end while, config masks */
516 end_mask:
517 			break;
518 
519 		case TOK_RED:
520 		case TOK_GRED:
521 			NEED1("red/gred needs w_q/min_th/max_th/max_p\n");
522 			p.fs.flags_fs |= DN_IS_RED;
523 			if (tok == TOK_GRED)
524 				p.fs.flags_fs |= DN_IS_GENTLE_RED;
525 			/*
526 			 * the format for parameters is w_q/min_th/max_th/max_p
527 			 */
528 			if ((end = strsep(&av[0], "/"))) {
529 			    double w_q = strtod(end, NULL);
530 			    if (w_q > 1 || w_q <= 0)
531 				errx(EX_DATAERR, "0 < w_q <= 1");
532 			    p.fs.w_q = (int) (w_q * (1 << SCALE_RED));
533 			}
534 			if ((end = strsep(&av[0], "/"))) {
535 			    p.fs.min_th = strtoul(end, &end, 0);
536 			    if (*end == 'K' || *end == 'k')
537 				p.fs.min_th *= 1024;
538 			}
539 			if ((end = strsep(&av[0], "/"))) {
540 			    p.fs.max_th = strtoul(end, &end, 0);
541 			    if (*end == 'K' || *end == 'k')
542 				p.fs.max_th *= 1024;
543 			}
544 			if ((end = strsep(&av[0], "/"))) {
545 			    double max_p = strtod(end, NULL);
546 			    if (max_p > 1 || max_p <= 0)
547 				errx(EX_DATAERR, "0 < max_p <= 1");
548 			    p.fs.max_p = (int)(max_p * (1 << SCALE_RED));
549 			}
550 			ac--; av++;
551 			break;
552 
553 		case TOK_DROPTAIL:
554 			p.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED);
555 			break;
556 
557 		case TOK_BW:
558 			NEED1("bw needs bandwidth or interface\n");
559 			if (co.do_pipe != 1)
560 			    errx(EX_DATAERR, "bandwidth only valid for pipes");
561 			/*
562 			 * set clocking interface or bandwidth value
563 			 */
564 			if (av[0][0] >= 'a' && av[0][0] <= 'z') {
565 			    int l = sizeof(p.if_name)-1;
566 			    /* interface name */
567 			    strncpy(p.if_name, av[0], l);
568 			    p.if_name[l] = '\0';
569 			    p.bandwidth = 0;
570 			} else {
571 			    p.if_name[0] = '\0';
572 			    p.bandwidth = strtoul(av[0], &end, 0);
573 			    if (*end == 'K' || *end == 'k') {
574 				end++;
575 				p.bandwidth *= 1000;
576 			    } else if (*end == 'M') {
577 				end++;
578 				p.bandwidth *= 1000000;
579 			    }
580 			    if ((*end == 'B' &&
581 				  _substrcmp2(end, "Bi", "Bit/s") != 0) ||
582 			        _substrcmp2(end, "by", "bytes") == 0)
583 				p.bandwidth *= 8;
584 			    if (p.bandwidth < 0)
585 				errx(EX_DATAERR, "bandwidth too large");
586 			}
587 			ac--; av++;
588 			break;
589 
590 		case TOK_DELAY:
591 			if (co.do_pipe != 1)
592 				errx(EX_DATAERR, "delay only valid for pipes");
593 			NEED1("delay needs argument 0..10000ms\n");
594 			p.delay = strtoul(av[0], NULL, 0);
595 			ac--; av++;
596 			break;
597 
598 		case TOK_WEIGHT:
599 			if (co.do_pipe == 1)
600 				errx(EX_DATAERR,"weight only valid for queues");
601 			NEED1("weight needs argument 0..100\n");
602 			p.fs.weight = strtoul(av[0], &end, 0);
603 			ac--; av++;
604 			break;
605 
606 		case TOK_PIPE:
607 			if (co.do_pipe == 1)
608 				errx(EX_DATAERR,"pipe only valid for queues");
609 			NEED1("pipe needs pipe_number\n");
610 			p.fs.parent_nr = strtoul(av[0], &end, 0);
611 			ac--; av++;
612 			break;
613 
614 		default:
615 			errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]);
616 		}
617 	}
618 	if (co.do_pipe == 1) {
619 		if (p.pipe_nr == 0)
620 			errx(EX_DATAERR, "pipe_nr must be > 0");
621 		if (p.delay > 10000)
622 			errx(EX_DATAERR, "delay must be < 10000");
623 	} else { /* co.do_pipe == 2, queue */
624 		if (p.fs.parent_nr == 0)
625 			errx(EX_DATAERR, "pipe must be > 0");
626 		if (p.fs.weight >100)
627 			errx(EX_DATAERR, "weight must be <= 100");
628 	}
629 	if (p.fs.flags_fs & DN_QSIZE_IS_BYTES) {
630 		size_t len;
631 		long limit;
632 
633 		len = sizeof(limit);
634 		if (sysctlbyname("net.inet.ip.dummynet.pipe_byte_limit",
635 			&limit, &len, NULL, 0) == -1)
636 			limit = 1024*1024;
637 		if (p.fs.qsize > limit)
638 			errx(EX_DATAERR, "queue size must be < %ldB", limit);
639 	} else {
640 		size_t len;
641 		long limit;
642 
643 		len = sizeof(limit);
644 		if (sysctlbyname("net.inet.ip.dummynet.pipe_slot_limit",
645 			&limit, &len, NULL, 0) == -1)
646 			limit = 100;
647 		if (p.fs.qsize > limit)
648 			errx(EX_DATAERR, "2 <= queue size <= %ld", limit);
649 	}
650 	if (p.fs.flags_fs & DN_IS_RED) {
651 		size_t len;
652 		int lookup_depth, avg_pkt_size;
653 		double s, idle, weight, w_q;
654 		struct clockinfo ck;
655 		int t;
656 
657 		if (p.fs.min_th >= p.fs.max_th)
658 		    errx(EX_DATAERR, "min_th %d must be < than max_th %d",
659 			p.fs.min_th, p.fs.max_th);
660 		if (p.fs.max_th == 0)
661 		    errx(EX_DATAERR, "max_th must be > 0");
662 
663 		len = sizeof(int);
664 		if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
665 			&lookup_depth, &len, NULL, 0) == -1)
666 		    errx(1, "sysctlbyname(\"%s\")",
667 			"net.inet.ip.dummynet.red_lookup_depth");
668 		if (lookup_depth == 0)
669 		    errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth"
670 			" must be greater than zero");
671 
672 		len = sizeof(int);
673 		if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
674 			&avg_pkt_size, &len, NULL, 0) == -1)
675 
676 		    errx(1, "sysctlbyname(\"%s\")",
677 			"net.inet.ip.dummynet.red_avg_pkt_size");
678 		if (avg_pkt_size == 0)
679 			errx(EX_DATAERR,
680 			    "net.inet.ip.dummynet.red_avg_pkt_size must"
681 			    " be greater than zero");
682 
683 		len = sizeof(struct clockinfo);
684 		if (sysctlbyname("kern.clockrate", &ck, &len, NULL, 0) == -1)
685 			errx(1, "sysctlbyname(\"%s\")", "kern.clockrate");
686 
687 		/*
688 		 * Ticks needed for sending a medium-sized packet.
689 		 * Unfortunately, when we are configuring a WF2Q+ queue, we
690 		 * do not have bandwidth information, because that is stored
691 		 * in the parent pipe, and also we have multiple queues
692 		 * competing for it. So we set s=0, which is not very
693 		 * correct. But on the other hand, why do we want RED with
694 		 * WF2Q+ ?
695 		 */
696 		if (p.bandwidth==0) /* this is a WF2Q+ queue */
697 			s = 0;
698 		else
699 			s = (double)ck.hz * avg_pkt_size * 8 / p.bandwidth;
700 
701 		/*
702 		 * max idle time (in ticks) before avg queue size becomes 0.
703 		 * NOTA:  (3/w_q) is approx the value x so that
704 		 * (1-w_q)^x < 10^-3.
705 		 */
706 		w_q = ((double)p.fs.w_q) / (1 << SCALE_RED);
707 		idle = s * 3. / w_q;
708 		p.fs.lookup_step = (int)idle / lookup_depth;
709 		if (!p.fs.lookup_step)
710 			p.fs.lookup_step = 1;
711 		weight = 1 - w_q;
712 		for (t = p.fs.lookup_step; t > 1; --t)
713 			weight *= 1 - w_q;
714 		p.fs.lookup_weight = (int)(weight * (1 << SCALE_RED));
715 	}
716 	i = do_cmd(IP_DUMMYNET_CONFIGURE, &p, sizeof p);
717 	if (i)
718 		err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE");
719 }
720