xref: /freebsd/sys/net/altq/altq_red.c (revision d6b92ffa)
1 /*-
2  * Copyright (C) 1997-2003
3  *	Sony Computer Science Laboratories Inc.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 /*-
28  * Copyright (c) 1990-1994 Regents of the University of California.
29  * All rights reserved.
30  *
31  * Redistribution and use in source and binary forms, with or without
32  * modification, are permitted provided that the following conditions
33  * are met:
34  * 1. Redistributions of source code must retain the above copyright
35  *    notice, this list of conditions and the following disclaimer.
36  * 2. Redistributions in binary form must reproduce the above copyright
37  *    notice, this list of conditions and the following disclaimer in the
38  *    documentation and/or other materials provided with the distribution.
39  * 3. All advertising materials mentioning features or use of this software
40  *    must display the following acknowledgement:
41  *	This product includes software developed by the Computer Systems
42  *	Engineering Group at Lawrence Berkeley Laboratory.
43  * 4. Neither the name of the University nor of the Laboratory may be used
44  *    to endorse or promote products derived from this software without
45  *    specific prior written permission.
46  *
47  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57  * SUCH DAMAGE.
58  *
59  * $KAME: altq_red.c,v 1.18 2003/09/05 22:40:36 itojun Exp $
60  * $FreeBSD$
61  */
62 
63 #include "opt_altq.h"
64 #include "opt_inet.h"
65 #include "opt_inet6.h"
66 #ifdef ALTQ_RED	/* red is enabled by ALTQ_RED option in opt_altq.h */
67 
68 #include <sys/param.h>
69 #include <sys/malloc.h>
70 #include <sys/mbuf.h>
71 #include <sys/socket.h>
72 #include <sys/systm.h>
73 #include <sys/errno.h>
74 #if 1 /* ALTQ3_COMPAT */
75 #include <sys/sockio.h>
76 #include <sys/proc.h>
77 #include <sys/kernel.h>
78 #ifdef ALTQ_FLOWVALVE
79 #include <sys/queue.h>
80 #include <sys/time.h>
81 #endif
82 #endif /* ALTQ3_COMPAT */
83 
84 #include <net/if.h>
85 #include <net/if_var.h>
86 
87 #include <netinet/in.h>
88 #include <netinet/in_systm.h>
89 #include <netinet/ip.h>
90 #ifdef INET6
91 #include <netinet/ip6.h>
92 #endif
93 
94 #include <netpfil/pf/pf.h>
95 #include <netpfil/pf/pf_altq.h>
96 #include <netpfil/pf/pf_mtag.h>
97 #include <net/altq/altq.h>
98 #include <net/altq/altq_red.h>
99 #ifdef ALTQ3_COMPAT
100 #include <net/altq/altq_conf.h>
101 #ifdef ALTQ_FLOWVALVE
102 #include <net/altq/altq_flowvalve.h>
103 #endif
104 #endif
105 
106 /*
107  * ALTQ/RED (Random Early Detection) implementation using 32-bit
108  * fixed-point calculation.
109  *
110  * written by kjc using the ns code as a reference.
111  * you can learn more about red and ns from Sally's home page at
112  * http://www-nrg.ee.lbl.gov/floyd/
113  *
114  * most of the red parameter values are fixed in this implementation
115  * to prevent fixed-point overflow/underflow.
116  * if you change the parameters, watch out for overflow/underflow!
117  *
118  * the parameters used are recommended values by Sally.
119  * the corresponding ns config looks:
120  *	q_weight=0.00195
121  *	minthresh=5 maxthresh=15 queue-size=60
122  *	linterm=30
123  *	dropmech=drop-tail
124  *	bytes=false (can't be handled by 32-bit fixed-point)
125  *	doubleq=false dqthresh=false
126  *	wait=true
127  */
128 /*
129  * alternative red parameters for a slow link.
130  *
131  * assume the queue length becomes from zero to L and keeps L, it takes
132  * N packets for q_avg to reach 63% of L.
133  * when q_weight is 0.002, N is about 500 packets.
134  * for a slow link like dial-up, 500 packets takes more than 1 minute!
135  * when q_weight is 0.008, N is about 127 packets.
136  * when q_weight is 0.016, N is about 63 packets.
137  * bursts of 50 packets are allowed for 0.002, bursts of 25 packets
138  * are allowed for 0.016.
139  * see Sally's paper for more details.
140  */
141 /* normal red parameters */
142 #define	W_WEIGHT	512	/* inverse of weight of EWMA (511/512) */
143 				/* q_weight = 0.00195 */
144 
145 /* red parameters for a slow link */
146 #define	W_WEIGHT_1	128	/* inverse of weight of EWMA (127/128) */
147 				/* q_weight = 0.0078125 */
148 
149 /* red parameters for a very slow link (e.g., dialup) */
150 #define	W_WEIGHT_2	64	/* inverse of weight of EWMA (63/64) */
151 				/* q_weight = 0.015625 */
152 
153 /* fixed-point uses 12-bit decimal places */
154 #define	FP_SHIFT	12	/* fixed-point shift */
155 
156 /* red parameters for drop probability */
157 #define	INV_P_MAX	10	/* inverse of max drop probability */
158 #define	TH_MIN		5	/* min threshold */
159 #define	TH_MAX		15	/* max threshold */
160 
161 #define	RED_LIMIT	60	/* default max queue length */
162 #define	RED_STATS		/* collect statistics */
163 
164 /*
165  * our default policy for forced-drop is drop-tail.
166  * (in altq-1.1.2 or earlier, the default was random-drop.
167  * but it makes more sense to punish the cause of the surge.)
168  * to switch to the random-drop policy, define "RED_RANDOM_DROP".
169  */
170 
171 #ifdef ALTQ3_COMPAT
172 #ifdef ALTQ_FLOWVALVE
173 /*
174  * flow-valve is an extension to protect red from unresponsive flows
175  * and to promote end-to-end congestion control.
176  * flow-valve observes the average drop rates of the flows that have
177  * experienced packet drops in the recent past.
178  * when the average drop rate exceeds the threshold, the flow is
179  * blocked by the flow-valve.  the trapped flow should back off
180  * exponentially to escape from the flow-valve.
181  */
182 #ifdef RED_RANDOM_DROP
183 #error "random-drop can't be used with flow-valve!"
184 #endif
185 #endif /* ALTQ_FLOWVALVE */
186 
187 /* red_list keeps all red_queue_t's allocated. */
188 static red_queue_t *red_list = NULL;
189 
190 #endif /* ALTQ3_COMPAT */
191 
192 /* default red parameter values */
193 static int default_th_min = TH_MIN;
194 static int default_th_max = TH_MAX;
195 static int default_inv_pmax = INV_P_MAX;
196 
197 #ifdef ALTQ3_COMPAT
198 /* internal function prototypes */
199 static int red_enqueue(struct ifaltq *, struct mbuf *, struct altq_pktattr *);
200 static struct mbuf *red_dequeue(struct ifaltq *, int);
201 static int red_request(struct ifaltq *, int, void *);
202 static void red_purgeq(red_queue_t *);
203 static int red_detach(red_queue_t *);
204 #ifdef ALTQ_FLOWVALVE
205 static __inline struct fve *flowlist_lookup(struct flowvalve *,
206 			 struct altq_pktattr *, struct timeval *);
207 static __inline struct fve *flowlist_reclaim(struct flowvalve *,
208 					     struct altq_pktattr *);
209 static __inline void flowlist_move_to_head(struct flowvalve *, struct fve *);
210 static __inline int fv_p2f(struct flowvalve *, int);
211 #if 0 /* XXX: make the compiler happy (fv_alloc unused) */
212 static struct flowvalve *fv_alloc(struct red *);
213 #endif
214 static void fv_destroy(struct flowvalve *);
215 static int fv_checkflow(struct flowvalve *, struct altq_pktattr *,
216 			struct fve **);
217 static void fv_dropbyred(struct flowvalve *fv, struct altq_pktattr *,
218 			 struct fve *);
219 #endif
220 #endif /* ALTQ3_COMPAT */
221 
222 /*
223  * red support routines
224  */
225 red_t *
226 red_alloc(int weight, int inv_pmax, int th_min, int th_max, int flags,
227    int pkttime)
228 {
229 	red_t	*rp;
230 	int	 w, i;
231 	int	 npkts_per_sec;
232 
233 	rp = malloc(sizeof(red_t), M_DEVBUF, M_NOWAIT | M_ZERO);
234 	if (rp == NULL)
235 		return (NULL);
236 
237 	if (weight == 0)
238 		rp->red_weight = W_WEIGHT;
239 	else
240 		rp->red_weight = weight;
241 
242 	/* allocate weight table */
243 	rp->red_wtab = wtab_alloc(rp->red_weight);
244 	if (rp->red_wtab == NULL) {
245 		free(rp, M_DEVBUF);
246 		return (NULL);
247 	}
248 
249 	rp->red_avg = 0;
250 	rp->red_idle = 1;
251 
252 	if (inv_pmax == 0)
253 		rp->red_inv_pmax = default_inv_pmax;
254 	else
255 		rp->red_inv_pmax = inv_pmax;
256 	if (th_min == 0)
257 		rp->red_thmin = default_th_min;
258 	else
259 		rp->red_thmin = th_min;
260 	if (th_max == 0)
261 		rp->red_thmax = default_th_max;
262 	else
263 		rp->red_thmax = th_max;
264 
265 	rp->red_flags = flags;
266 
267 	if (pkttime == 0)
268 		/* default packet time: 1000 bytes / 10Mbps * 8 * 1000000 */
269 		rp->red_pkttime = 800;
270 	else
271 		rp->red_pkttime = pkttime;
272 
273 	if (weight == 0) {
274 		/* when the link is very slow, adjust red parameters */
275 		npkts_per_sec = 1000000 / rp->red_pkttime;
276 		if (npkts_per_sec < 50) {
277 			/* up to about 400Kbps */
278 			rp->red_weight = W_WEIGHT_2;
279 		} else if (npkts_per_sec < 300) {
280 			/* up to about 2.4Mbps */
281 			rp->red_weight = W_WEIGHT_1;
282 		}
283 	}
284 
285 	/* calculate wshift.  weight must be power of 2 */
286 	w = rp->red_weight;
287 	for (i = 0; w > 1; i++)
288 		w = w >> 1;
289 	rp->red_wshift = i;
290 	w = 1 << rp->red_wshift;
291 	if (w != rp->red_weight) {
292 		printf("invalid weight value %d for red! use %d\n",
293 		       rp->red_weight, w);
294 		rp->red_weight = w;
295 	}
296 
297 	/*
298 	 * thmin_s and thmax_s are scaled versions of th_min and th_max
299 	 * to be compared with avg.
300 	 */
301 	rp->red_thmin_s = rp->red_thmin << (rp->red_wshift + FP_SHIFT);
302 	rp->red_thmax_s = rp->red_thmax << (rp->red_wshift + FP_SHIFT);
303 
304 	/*
305 	 * precompute probability denominator
306 	 *  probd = (2 * (TH_MAX-TH_MIN) / pmax) in fixed-point
307 	 */
308 	rp->red_probd = (2 * (rp->red_thmax - rp->red_thmin)
309 			 * rp->red_inv_pmax) << FP_SHIFT;
310 
311 	microtime(&rp->red_last);
312 	return (rp);
313 }
314 
315 void
316 red_destroy(red_t *rp)
317 {
318 #ifdef ALTQ3_COMPAT
319 #ifdef ALTQ_FLOWVALVE
320 	if (rp->red_flowvalve != NULL)
321 		fv_destroy(rp->red_flowvalve);
322 #endif
323 #endif /* ALTQ3_COMPAT */
324 	wtab_destroy(rp->red_wtab);
325 	free(rp, M_DEVBUF);
326 }
327 
328 void
329 red_getstats(red_t *rp, struct redstats *sp)
330 {
331 	sp->q_avg		= rp->red_avg >> rp->red_wshift;
332 	sp->xmit_cnt		= rp->red_stats.xmit_cnt;
333 	sp->drop_cnt		= rp->red_stats.drop_cnt;
334 	sp->drop_forced		= rp->red_stats.drop_forced;
335 	sp->drop_unforced	= rp->red_stats.drop_unforced;
336 	sp->marked_packets	= rp->red_stats.marked_packets;
337 }
338 
339 int
340 red_addq(red_t *rp, class_queue_t *q, struct mbuf *m,
341     struct altq_pktattr *pktattr)
342 {
343 	int avg, droptype;
344 	int n;
345 #ifdef ALTQ3_COMPAT
346 #ifdef ALTQ_FLOWVALVE
347 	struct fve *fve = NULL;
348 
349 	if (rp->red_flowvalve != NULL && rp->red_flowvalve->fv_flows > 0)
350 		if (fv_checkflow(rp->red_flowvalve, pktattr, &fve)) {
351 			m_freem(m);
352 			return (-1);
353 		}
354 #endif
355 #endif /* ALTQ3_COMPAT */
356 
357 	avg = rp->red_avg;
358 
359 	/*
360 	 * if we were idle, we pretend that n packets arrived during
361 	 * the idle period.
362 	 */
363 	if (rp->red_idle) {
364 		struct timeval now;
365 		int t;
366 
367 		rp->red_idle = 0;
368 		microtime(&now);
369 		t = (now.tv_sec - rp->red_last.tv_sec);
370 		if (t > 60) {
371 			/*
372 			 * being idle for more than 1 minute, set avg to zero.
373 			 * this prevents t from overflow.
374 			 */
375 			avg = 0;
376 		} else {
377 			t = t * 1000000 + (now.tv_usec - rp->red_last.tv_usec);
378 			n = t / rp->red_pkttime - 1;
379 
380 			/* the following line does (avg = (1 - Wq)^n * avg) */
381 			if (n > 0)
382 				avg = (avg >> FP_SHIFT) *
383 				    pow_w(rp->red_wtab, n);
384 		}
385 	}
386 
387 	/* run estimator. (note: avg is scaled by WEIGHT in fixed-point) */
388 	avg += (qlen(q) << FP_SHIFT) - (avg >> rp->red_wshift);
389 	rp->red_avg = avg;		/* save the new value */
390 
391 	/*
392 	 * red_count keeps a tally of arriving traffic that has not
393 	 * been dropped.
394 	 */
395 	rp->red_count++;
396 
397 	/* see if we drop early */
398 	droptype = DTYPE_NODROP;
399 	if (avg >= rp->red_thmin_s && qlen(q) > 1) {
400 		if (avg >= rp->red_thmax_s) {
401 			/* avg >= th_max: forced drop */
402 			droptype = DTYPE_FORCED;
403 		} else if (rp->red_old == 0) {
404 			/* first exceeds th_min */
405 			rp->red_count = 1;
406 			rp->red_old = 1;
407 		} else if (drop_early((avg - rp->red_thmin_s) >> rp->red_wshift,
408 				      rp->red_probd, rp->red_count)) {
409 			/* mark or drop by red */
410 			if ((rp->red_flags & REDF_ECN) &&
411 			    mark_ecn(m, pktattr, rp->red_flags)) {
412 				/* successfully marked.  do not drop. */
413 				rp->red_count = 0;
414 #ifdef RED_STATS
415 				rp->red_stats.marked_packets++;
416 #endif
417 			} else {
418 				/* unforced drop by red */
419 				droptype = DTYPE_EARLY;
420 			}
421 		}
422 	} else {
423 		/* avg < th_min */
424 		rp->red_old = 0;
425 	}
426 
427 	/*
428 	 * if the queue length hits the hard limit, it's a forced drop.
429 	 */
430 	if (droptype == DTYPE_NODROP && qlen(q) >= qlimit(q))
431 		droptype = DTYPE_FORCED;
432 
433 #ifdef RED_RANDOM_DROP
434 	/* if successful or forced drop, enqueue this packet. */
435 	if (droptype != DTYPE_EARLY)
436 		_addq(q, m);
437 #else
438 	/* if successful, enqueue this packet. */
439 	if (droptype == DTYPE_NODROP)
440 		_addq(q, m);
441 #endif
442 	if (droptype != DTYPE_NODROP) {
443 		if (droptype == DTYPE_EARLY) {
444 			/* drop the incoming packet */
445 #ifdef RED_STATS
446 			rp->red_stats.drop_unforced++;
447 #endif
448 		} else {
449 			/* forced drop, select a victim packet in the queue. */
450 #ifdef RED_RANDOM_DROP
451 			m = _getq_random(q);
452 #endif
453 #ifdef RED_STATS
454 			rp->red_stats.drop_forced++;
455 #endif
456 		}
457 #ifdef RED_STATS
458 		PKTCNTR_ADD(&rp->red_stats.drop_cnt, m_pktlen(m));
459 #endif
460 		rp->red_count = 0;
461 #ifdef ALTQ3_COMPAT
462 #ifdef ALTQ_FLOWVALVE
463 		if (rp->red_flowvalve != NULL)
464 			fv_dropbyred(rp->red_flowvalve, pktattr, fve);
465 #endif
466 #endif /* ALTQ3_COMPAT */
467 		m_freem(m);
468 		return (-1);
469 	}
470 	/* successfully queued */
471 #ifdef RED_STATS
472 	PKTCNTR_ADD(&rp->red_stats.xmit_cnt, m_pktlen(m));
473 #endif
474 	return (0);
475 }
476 
477 /*
478  * early-drop probability is calculated as follows:
479  *   prob = p_max * (avg - th_min) / (th_max - th_min)
480  *   prob_a = prob / (2 - count*prob)
481  *	    = (avg-th_min) / (2*(th_max-th_min)*inv_p_max - count*(avg-th_min))
482  * here prob_a increases as successive undrop count increases.
483  * (prob_a starts from prob/2, becomes prob when (count == (1 / prob)),
484  * becomes 1 when (count >= (2 / prob))).
485  */
486 int
487 drop_early(int fp_len, int fp_probd, int count)
488 {
489 	int	d;		/* denominator of drop-probability */
490 
491 	d = fp_probd - count * fp_len;
492 	if (d <= 0)
493 		/* count exceeds the hard limit: drop or mark */
494 		return (1);
495 
496 	/*
497 	 * now the range of d is [1..600] in fixed-point. (when
498 	 * th_max-th_min=10 and p_max=1/30)
499 	 * drop probability = (avg - TH_MIN) / d
500 	 */
501 
502 	if ((arc4random() % d) < fp_len) {
503 		/* drop or mark */
504 		return (1);
505 	}
506 	/* no drop/mark */
507 	return (0);
508 }
509 
510 /*
511  * try to mark CE bit to the packet.
512  *    returns 1 if successfully marked, 0 otherwise.
513  */
514 int
515 mark_ecn(struct mbuf *m, struct altq_pktattr *pktattr, int flags)
516 {
517 	struct mbuf	*m0;
518 	struct pf_mtag	*at;
519 	void		*hdr;
520 
521 	at = pf_find_mtag(m);
522 	if (at != NULL) {
523 		hdr = at->hdr;
524 #ifdef ALTQ3_COMPAT
525 	} else if (pktattr != NULL) {
526 		af = pktattr->pattr_af;
527 		hdr = pktattr->pattr_hdr;
528 #endif /* ALTQ3_COMPAT */
529 	} else
530 		return (0);
531 
532 	/* verify that pattr_hdr is within the mbuf data */
533 	for (m0 = m; m0 != NULL; m0 = m0->m_next)
534 		if (((caddr_t)hdr >= m0->m_data) &&
535 		    ((caddr_t)hdr < m0->m_data + m0->m_len))
536 			break;
537 	if (m0 == NULL) {
538 		/* ick, tag info is stale */
539 		return (0);
540 	}
541 
542 	switch (((struct ip *)hdr)->ip_v) {
543 	case IPVERSION:
544 		if (flags & REDF_ECN4) {
545 			struct ip *ip = hdr;
546 			u_int8_t otos;
547 			int sum;
548 
549 			if (ip->ip_v != 4)
550 				return (0);	/* version mismatch! */
551 
552 			if ((ip->ip_tos & IPTOS_ECN_MASK) == IPTOS_ECN_NOTECT)
553 				return (0);	/* not-ECT */
554 			if ((ip->ip_tos & IPTOS_ECN_MASK) == IPTOS_ECN_CE)
555 				return (1);	/* already marked */
556 
557 			/*
558 			 * ecn-capable but not marked,
559 			 * mark CE and update checksum
560 			 */
561 			otos = ip->ip_tos;
562 			ip->ip_tos |= IPTOS_ECN_CE;
563 			/*
564 			 * update checksum (from RFC1624)
565 			 *	   HC' = ~(~HC + ~m + m')
566 			 */
567 			sum = ~ntohs(ip->ip_sum) & 0xffff;
568 			sum += (~otos & 0xffff) + ip->ip_tos;
569 			sum = (sum >> 16) + (sum & 0xffff);
570 			sum += (sum >> 16);  /* add carry */
571 			ip->ip_sum = htons(~sum & 0xffff);
572 			return (1);
573 		}
574 		break;
575 #ifdef INET6
576 	case (IPV6_VERSION >> 4):
577 		if (flags & REDF_ECN6) {
578 			struct ip6_hdr *ip6 = hdr;
579 			u_int32_t flowlabel;
580 
581 			flowlabel = ntohl(ip6->ip6_flow);
582 			if ((flowlabel >> 28) != 6)
583 				return (0);	/* version mismatch! */
584 			if ((flowlabel & (IPTOS_ECN_MASK << 20)) ==
585 			    (IPTOS_ECN_NOTECT << 20))
586 				return (0);	/* not-ECT */
587 			if ((flowlabel & (IPTOS_ECN_MASK << 20)) ==
588 			    (IPTOS_ECN_CE << 20))
589 				return (1);	/* already marked */
590 			/*
591 			 * ecn-capable but not marked,  mark CE
592 			 */
593 			flowlabel |= (IPTOS_ECN_CE << 20);
594 			ip6->ip6_flow = htonl(flowlabel);
595 			return (1);
596 		}
597 		break;
598 #endif  /* INET6 */
599 	}
600 
601 	/* not marked */
602 	return (0);
603 }
604 
605 struct mbuf *
606 red_getq(rp, q)
607 	red_t *rp;
608 	class_queue_t *q;
609 {
610 	struct mbuf *m;
611 
612 	if ((m = _getq(q)) == NULL) {
613 		if (rp->red_idle == 0) {
614 			rp->red_idle = 1;
615 			microtime(&rp->red_last);
616 		}
617 		return NULL;
618 	}
619 
620 	rp->red_idle = 0;
621 	return (m);
622 }
623 
624 /*
625  * helper routine to calibrate avg during idle.
626  * pow_w(wtab, n) returns (1 - Wq)^n in fixed-point
627  * here Wq = 1/weight and the code assumes Wq is close to zero.
628  *
629  * w_tab[n] holds ((1 - Wq)^(2^n)) in fixed-point.
630  */
631 static struct wtab *wtab_list = NULL;	/* pointer to wtab list */
632 
633 struct wtab *
634 wtab_alloc(int weight)
635 {
636 	struct wtab	*w;
637 	int		 i;
638 
639 	for (w = wtab_list; w != NULL; w = w->w_next)
640 		if (w->w_weight == weight) {
641 			w->w_refcount++;
642 			return (w);
643 		}
644 
645 	w = malloc(sizeof(struct wtab), M_DEVBUF, M_NOWAIT | M_ZERO);
646 	if (w == NULL)
647 		return (NULL);
648 	w->w_weight = weight;
649 	w->w_refcount = 1;
650 	w->w_next = wtab_list;
651 	wtab_list = w;
652 
653 	/* initialize the weight table */
654 	w->w_tab[0] = ((weight - 1) << FP_SHIFT) / weight;
655 	for (i = 1; i < 32; i++) {
656 		w->w_tab[i] = (w->w_tab[i-1] * w->w_tab[i-1]) >> FP_SHIFT;
657 		if (w->w_tab[i] == 0 && w->w_param_max == 0)
658 			w->w_param_max = 1 << i;
659 	}
660 
661 	return (w);
662 }
663 
664 int
665 wtab_destroy(struct wtab *w)
666 {
667 	struct wtab	*prev;
668 
669 	if (--w->w_refcount > 0)
670 		return (0);
671 
672 	if (wtab_list == w)
673 		wtab_list = w->w_next;
674 	else for (prev = wtab_list; prev->w_next != NULL; prev = prev->w_next)
675 		if (prev->w_next == w) {
676 			prev->w_next = w->w_next;
677 			break;
678 		}
679 
680 	free(w, M_DEVBUF);
681 	return (0);
682 }
683 
684 int32_t
685 pow_w(struct wtab *w, int n)
686 {
687 	int	i, bit;
688 	int32_t	val;
689 
690 	if (n >= w->w_param_max)
691 		return (0);
692 
693 	val = 1 << FP_SHIFT;
694 	if (n <= 0)
695 		return (val);
696 
697 	bit = 1;
698 	i = 0;
699 	while (n) {
700 		if (n & bit) {
701 			val = (val * w->w_tab[i]) >> FP_SHIFT;
702 			n &= ~bit;
703 		}
704 		i++;
705 		bit <<=  1;
706 	}
707 	return (val);
708 }
709 
710 #ifdef ALTQ3_COMPAT
711 /*
712  * red device interface
713  */
714 altqdev_decl(red);
715 
716 int
717 redopen(dev, flag, fmt, p)
718 	dev_t dev;
719 	int flag, fmt;
720 #if (__FreeBSD_version > 500000)
721 	struct thread *p;
722 #else
723 	struct proc *p;
724 #endif
725 {
726 	/* everything will be done when the queueing scheme is attached. */
727 	return 0;
728 }
729 
730 int
731 redclose(dev, flag, fmt, p)
732 	dev_t dev;
733 	int flag, fmt;
734 #if (__FreeBSD_version > 500000)
735 	struct thread *p;
736 #else
737 	struct proc *p;
738 #endif
739 {
740 	red_queue_t *rqp;
741 	int err, error = 0;
742 
743 	while ((rqp = red_list) != NULL) {
744 		/* destroy all */
745 		err = red_detach(rqp);
746 		if (err != 0 && error == 0)
747 			error = err;
748 	}
749 
750 	return error;
751 }
752 
753 int
754 redioctl(dev, cmd, addr, flag, p)
755 	dev_t dev;
756 	ioctlcmd_t cmd;
757 	caddr_t addr;
758 	int flag;
759 #if (__FreeBSD_version > 500000)
760 	struct thread *p;
761 #else
762 	struct proc *p;
763 #endif
764 {
765 	red_queue_t *rqp;
766 	struct red_interface *ifacep;
767 	struct ifnet *ifp;
768 	int	error = 0;
769 
770 	/* check super-user privilege */
771 	switch (cmd) {
772 	case RED_GETSTATS:
773 		break;
774 	default:
775 #if (__FreeBSD_version > 700000)
776 		if ((error = priv_check(p, PRIV_ALTQ_MANAGE)) != 0)
777 #elsif (__FreeBSD_version > 400000)
778 		if ((error = suser(p)) != 0)
779 #else
780 		if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
781 #endif
782 			return (error);
783 		break;
784 	}
785 
786 	switch (cmd) {
787 
788 	case RED_ENABLE:
789 		ifacep = (struct red_interface *)addr;
790 		if ((rqp = altq_lookup(ifacep->red_ifname, ALTQT_RED)) == NULL) {
791 			error = EBADF;
792 			break;
793 		}
794 		error = altq_enable(rqp->rq_ifq);
795 		break;
796 
797 	case RED_DISABLE:
798 		ifacep = (struct red_interface *)addr;
799 		if ((rqp = altq_lookup(ifacep->red_ifname, ALTQT_RED)) == NULL) {
800 			error = EBADF;
801 			break;
802 		}
803 		error = altq_disable(rqp->rq_ifq);
804 		break;
805 
806 	case RED_IF_ATTACH:
807 		ifp = ifunit(((struct red_interface *)addr)->red_ifname);
808 		if (ifp == NULL) {
809 			error = ENXIO;
810 			break;
811 		}
812 
813 		/* allocate and initialize red_queue_t */
814 		rqp = malloc(sizeof(red_queue_t), M_DEVBUF, M_WAITOK);
815 		if (rqp == NULL) {
816 			error = ENOMEM;
817 			break;
818 		}
819 		bzero(rqp, sizeof(red_queue_t));
820 
821 		rqp->rq_q = malloc(sizeof(class_queue_t),
822 		       M_DEVBUF, M_WAITOK);
823 		if (rqp->rq_q == NULL) {
824 			free(rqp, M_DEVBUF);
825 			error = ENOMEM;
826 			break;
827 		}
828 		bzero(rqp->rq_q, sizeof(class_queue_t));
829 
830 		rqp->rq_red = red_alloc(0, 0, 0, 0, 0, 0);
831 		if (rqp->rq_red == NULL) {
832 			free(rqp->rq_q, M_DEVBUF);
833 			free(rqp, M_DEVBUF);
834 			error = ENOMEM;
835 			break;
836 		}
837 
838 		rqp->rq_ifq = &ifp->if_snd;
839 		qtail(rqp->rq_q) = NULL;
840 		qlen(rqp->rq_q) = 0;
841 		qlimit(rqp->rq_q) = RED_LIMIT;
842 		qtype(rqp->rq_q) = Q_RED;
843 
844 		/*
845 		 * set RED to this ifnet structure.
846 		 */
847 		error = altq_attach(rqp->rq_ifq, ALTQT_RED, rqp,
848 				    red_enqueue, red_dequeue, red_request,
849 				    NULL, NULL);
850 		if (error) {
851 			red_destroy(rqp->rq_red);
852 			free(rqp->rq_q, M_DEVBUF);
853 			free(rqp, M_DEVBUF);
854 			break;
855 		}
856 
857 		/* add this state to the red list */
858 		rqp->rq_next = red_list;
859 		red_list = rqp;
860 		break;
861 
862 	case RED_IF_DETACH:
863 		ifacep = (struct red_interface *)addr;
864 		if ((rqp = altq_lookup(ifacep->red_ifname, ALTQT_RED)) == NULL) {
865 			error = EBADF;
866 			break;
867 		}
868 		error = red_detach(rqp);
869 		break;
870 
871 	case RED_GETSTATS:
872 		do {
873 			struct red_stats *q_stats;
874 			red_t *rp;
875 
876 			q_stats = (struct red_stats *)addr;
877 			if ((rqp = altq_lookup(q_stats->iface.red_ifname,
878 					     ALTQT_RED)) == NULL) {
879 				error = EBADF;
880 				break;
881 			}
882 
883 			q_stats->q_len 	   = qlen(rqp->rq_q);
884 			q_stats->q_limit   = qlimit(rqp->rq_q);
885 
886 			rp = rqp->rq_red;
887 			q_stats->q_avg 	   = rp->red_avg >> rp->red_wshift;
888 			q_stats->xmit_cnt  = rp->red_stats.xmit_cnt;
889 			q_stats->drop_cnt  = rp->red_stats.drop_cnt;
890 			q_stats->drop_forced   = rp->red_stats.drop_forced;
891 			q_stats->drop_unforced = rp->red_stats.drop_unforced;
892 			q_stats->marked_packets = rp->red_stats.marked_packets;
893 
894 			q_stats->weight		= rp->red_weight;
895 			q_stats->inv_pmax	= rp->red_inv_pmax;
896 			q_stats->th_min		= rp->red_thmin;
897 			q_stats->th_max		= rp->red_thmax;
898 
899 #ifdef ALTQ_FLOWVALVE
900 			if (rp->red_flowvalve != NULL) {
901 				struct flowvalve *fv = rp->red_flowvalve;
902 				q_stats->fv_flows    = fv->fv_flows;
903 				q_stats->fv_pass     = fv->fv_stats.pass;
904 				q_stats->fv_predrop  = fv->fv_stats.predrop;
905 				q_stats->fv_alloc    = fv->fv_stats.alloc;
906 				q_stats->fv_escape   = fv->fv_stats.escape;
907 			} else {
908 #endif /* ALTQ_FLOWVALVE */
909 				q_stats->fv_flows    = 0;
910 				q_stats->fv_pass     = 0;
911 				q_stats->fv_predrop  = 0;
912 				q_stats->fv_alloc    = 0;
913 				q_stats->fv_escape   = 0;
914 #ifdef ALTQ_FLOWVALVE
915 			}
916 #endif /* ALTQ_FLOWVALVE */
917 		} while (/*CONSTCOND*/ 0);
918 		break;
919 
920 	case RED_CONFIG:
921 		do {
922 			struct red_conf *fc;
923 			red_t *new;
924 			int s, limit;
925 
926 			fc = (struct red_conf *)addr;
927 			if ((rqp = altq_lookup(fc->iface.red_ifname,
928 					       ALTQT_RED)) == NULL) {
929 				error = EBADF;
930 				break;
931 			}
932 			new = red_alloc(fc->red_weight,
933 					fc->red_inv_pmax,
934 					fc->red_thmin,
935 					fc->red_thmax,
936 					fc->red_flags,
937 					fc->red_pkttime);
938 			if (new == NULL) {
939 				error = ENOMEM;
940 				break;
941 			}
942 
943 			s = splnet();
944 			red_purgeq(rqp);
945 			limit = fc->red_limit;
946 			if (limit < fc->red_thmax)
947 				limit = fc->red_thmax;
948 			qlimit(rqp->rq_q) = limit;
949 			fc->red_limit = limit;	/* write back the new value */
950 
951 			red_destroy(rqp->rq_red);
952 			rqp->rq_red = new;
953 
954 			splx(s);
955 
956 			/* write back new values */
957 			fc->red_limit = limit;
958 			fc->red_inv_pmax = rqp->rq_red->red_inv_pmax;
959 			fc->red_thmin = rqp->rq_red->red_thmin;
960 			fc->red_thmax = rqp->rq_red->red_thmax;
961 
962 		} while (/*CONSTCOND*/ 0);
963 		break;
964 
965 	case RED_SETDEFAULTS:
966 		do {
967 			struct redparams *rp;
968 
969 			rp = (struct redparams *)addr;
970 
971 			default_th_min = rp->th_min;
972 			default_th_max = rp->th_max;
973 			default_inv_pmax = rp->inv_pmax;
974 		} while (/*CONSTCOND*/ 0);
975 		break;
976 
977 	default:
978 		error = EINVAL;
979 		break;
980 	}
981 	return error;
982 }
983 
984 static int
985 red_detach(rqp)
986 	red_queue_t *rqp;
987 {
988 	red_queue_t *tmp;
989 	int error = 0;
990 
991 	if (ALTQ_IS_ENABLED(rqp->rq_ifq))
992 		altq_disable(rqp->rq_ifq);
993 
994 	if ((error = altq_detach(rqp->rq_ifq)))
995 		return (error);
996 
997 	if (red_list == rqp)
998 		red_list = rqp->rq_next;
999 	else {
1000 		for (tmp = red_list; tmp != NULL; tmp = tmp->rq_next)
1001 			if (tmp->rq_next == rqp) {
1002 				tmp->rq_next = rqp->rq_next;
1003 				break;
1004 			}
1005 		if (tmp == NULL)
1006 			printf("red_detach: no state found in red_list!\n");
1007 	}
1008 
1009 	red_destroy(rqp->rq_red);
1010 	free(rqp->rq_q, M_DEVBUF);
1011 	free(rqp, M_DEVBUF);
1012 	return (error);
1013 }
1014 
1015 /*
1016  * enqueue routine:
1017  *
1018  *	returns: 0 when successfully queued.
1019  *		 ENOBUFS when drop occurs.
1020  */
1021 static int
1022 red_enqueue(ifq, m, pktattr)
1023 	struct ifaltq *ifq;
1024 	struct mbuf *m;
1025 	struct altq_pktattr *pktattr;
1026 {
1027 	red_queue_t *rqp = (red_queue_t *)ifq->altq_disc;
1028 
1029 	IFQ_LOCK_ASSERT(ifq);
1030 
1031 	if (red_addq(rqp->rq_red, rqp->rq_q, m, pktattr) < 0)
1032 		return ENOBUFS;
1033 	ifq->ifq_len++;
1034 	return 0;
1035 }
1036 
1037 /*
1038  * dequeue routine:
1039  *	must be called in splimp.
1040  *
1041  *	returns: mbuf dequeued.
1042  *		 NULL when no packet is available in the queue.
1043  */
1044 
1045 static struct mbuf *
1046 red_dequeue(ifq, op)
1047 	struct ifaltq *ifq;
1048 	int op;
1049 {
1050 	red_queue_t *rqp = (red_queue_t *)ifq->altq_disc;
1051 	struct mbuf *m;
1052 
1053 	IFQ_LOCK_ASSERT(ifq);
1054 
1055 	if (op == ALTDQ_POLL)
1056 		return qhead(rqp->rq_q);
1057 
1058 	/* op == ALTDQ_REMOVE */
1059 	m =  red_getq(rqp->rq_red, rqp->rq_q);
1060 	if (m != NULL)
1061 		ifq->ifq_len--;
1062 	return (m);
1063 }
1064 
1065 static int
1066 red_request(ifq, req, arg)
1067 	struct ifaltq *ifq;
1068 	int req;
1069 	void *arg;
1070 {
1071 	red_queue_t *rqp = (red_queue_t *)ifq->altq_disc;
1072 
1073 	IFQ_LOCK_ASSERT(ifq);
1074 
1075 	switch (req) {
1076 	case ALTRQ_PURGE:
1077 		red_purgeq(rqp);
1078 		break;
1079 	}
1080 	return (0);
1081 }
1082 
1083 static void
1084 red_purgeq(rqp)
1085 	red_queue_t *rqp;
1086 {
1087 	_flushq(rqp->rq_q);
1088 	if (ALTQ_IS_ENABLED(rqp->rq_ifq))
1089 		rqp->rq_ifq->ifq_len = 0;
1090 }
1091 
1092 #ifdef ALTQ_FLOWVALVE
1093 
1094 #define	FV_PSHIFT	7	/* weight of average drop rate -- 1/128 */
1095 #define	FV_PSCALE(x)	((x) << FV_PSHIFT)
1096 #define	FV_PUNSCALE(x)	((x) >> FV_PSHIFT)
1097 #define	FV_FSHIFT	5	/* weight of average fraction -- 1/32 */
1098 #define	FV_FSCALE(x)	((x) << FV_FSHIFT)
1099 #define	FV_FUNSCALE(x)	((x) >> FV_FSHIFT)
1100 
1101 #define	FV_TIMER	(3 * hz)	/* timer value for garbage collector */
1102 #define	FV_FLOWLISTSIZE		64	/* how many flows in flowlist */
1103 
1104 #define	FV_N			10	/* update fve_f every FV_N packets */
1105 
1106 #define	FV_BACKOFFTHRESH	1  /* backoff threshold interval in second */
1107 #define	FV_TTHRESH		3  /* time threshold to delete fve */
1108 #define	FV_ALPHA		5  /* extra packet count */
1109 
1110 #define	FV_STATS
1111 
1112 #if (__FreeBSD_version > 300000)
1113 #define	FV_TIMESTAMP(tp)	getmicrotime(tp)
1114 #else
1115 #define	FV_TIMESTAMP(tp)	{ (*(tp)) = time; }
1116 #endif
1117 
1118 /*
1119  * Brtt table: 127 entry table to convert drop rate (p) to
1120  * the corresponding bandwidth fraction (f)
1121  * the following equation is implemented to use scaled values,
1122  * fve_p and fve_f, in the fixed point format.
1123  *
1124  *   Brtt(p) = 1 /(sqrt(4*p/3) + min(1,3*sqrt(p*6/8)) * p * (1+32 * p*p))
1125  *   f = Brtt(p) / (max_th + alpha)
1126  */
1127 #define	BRTT_SIZE	128
1128 #define	BRTT_SHIFT	12
1129 #define	BRTT_MASK	0x0007f000
1130 #define	BRTT_PMAX	(1 << (FV_PSHIFT + FP_SHIFT))
1131 
1132 const int brtt_tab[BRTT_SIZE] = {
1133 	0, 1262010, 877019, 703694, 598706, 525854, 471107, 427728,
1134 	392026, 361788, 335598, 312506, 291850, 273158, 256081, 240361,
1135 	225800, 212247, 199585, 187788, 178388, 169544, 161207, 153333,
1136 	145888, 138841, 132165, 125836, 119834, 114141, 108739, 103612,
1137 	98747, 94129, 89746, 85585, 81637, 77889, 74333, 70957,
1138 	67752, 64711, 61824, 59084, 56482, 54013, 51667, 49440,
1139 	47325, 45315, 43406, 41591, 39866, 38227, 36667, 35184,
1140 	33773, 32430, 31151, 29933, 28774, 27668, 26615, 25611,
1141 	24653, 23740, 22868, 22035, 21240, 20481, 19755, 19062,
1142 	18399, 17764, 17157, 16576, 16020, 15487, 14976, 14487,
1143 	14017, 13567, 13136, 12721, 12323, 11941, 11574, 11222,
1144 	10883, 10557, 10243, 9942, 9652, 9372, 9103, 8844,
1145 	8594, 8354, 8122, 7898, 7682, 7474, 7273, 7079,
1146 	6892, 6711, 6536, 6367, 6204, 6046, 5893, 5746,
1147 	5603, 5464, 5330, 5201, 5075, 4954, 4836, 4722,
1148 	4611, 4504, 4400, 4299, 4201, 4106, 4014, 3924
1149 };
1150 
1151 static __inline struct fve *
1152 flowlist_lookup(fv, pktattr, now)
1153 	struct flowvalve *fv;
1154 	struct altq_pktattr *pktattr;
1155 	struct timeval *now;
1156 {
1157 	struct fve *fve;
1158 	int flows;
1159 	struct ip *ip;
1160 #ifdef INET6
1161 	struct ip6_hdr *ip6;
1162 #endif
1163 	struct timeval tthresh;
1164 
1165 	if (pktattr == NULL)
1166 		return (NULL);
1167 
1168 	tthresh.tv_sec = now->tv_sec - FV_TTHRESH;
1169 	flows = 0;
1170 	/*
1171 	 * search the flow list
1172 	 */
1173 	switch (pktattr->pattr_af) {
1174 	case AF_INET:
1175 		ip = (struct ip *)pktattr->pattr_hdr;
1176 		TAILQ_FOREACH(fve, &fv->fv_flowlist, fve_lru){
1177 			if (fve->fve_lastdrop.tv_sec == 0)
1178 				break;
1179 			if (fve->fve_lastdrop.tv_sec < tthresh.tv_sec) {
1180 				fve->fve_lastdrop.tv_sec = 0;
1181 				break;
1182 			}
1183 			if (fve->fve_flow.flow_af == AF_INET &&
1184 			    fve->fve_flow.flow_ip.ip_src.s_addr ==
1185 			    ip->ip_src.s_addr &&
1186 			    fve->fve_flow.flow_ip.ip_dst.s_addr ==
1187 			    ip->ip_dst.s_addr)
1188 				return (fve);
1189 			flows++;
1190 		}
1191 		break;
1192 #ifdef INET6
1193 	case AF_INET6:
1194 		ip6 = (struct ip6_hdr *)pktattr->pattr_hdr;
1195 		TAILQ_FOREACH(fve, &fv->fv_flowlist, fve_lru){
1196 			if (fve->fve_lastdrop.tv_sec == 0)
1197 				break;
1198 			if (fve->fve_lastdrop.tv_sec < tthresh.tv_sec) {
1199 				fve->fve_lastdrop.tv_sec = 0;
1200 				break;
1201 			}
1202 			if (fve->fve_flow.flow_af == AF_INET6 &&
1203 			    IN6_ARE_ADDR_EQUAL(&fve->fve_flow.flow_ip6.ip6_src,
1204 					       &ip6->ip6_src) &&
1205 			    IN6_ARE_ADDR_EQUAL(&fve->fve_flow.flow_ip6.ip6_dst,
1206 					       &ip6->ip6_dst))
1207 				return (fve);
1208 			flows++;
1209 		}
1210 		break;
1211 #endif /* INET6 */
1212 
1213 	default:
1214 		/* unknown protocol.  no drop. */
1215 		return (NULL);
1216 	}
1217 	fv->fv_flows = flows;	/* save the number of active fve's */
1218 	return (NULL);
1219 }
1220 
1221 static __inline struct fve *
1222 flowlist_reclaim(fv, pktattr)
1223 	struct flowvalve *fv;
1224 	struct altq_pktattr *pktattr;
1225 {
1226 	struct fve *fve;
1227 	struct ip *ip;
1228 #ifdef INET6
1229 	struct ip6_hdr *ip6;
1230 #endif
1231 
1232 	/*
1233 	 * get an entry from the tail of the LRU list.
1234 	 */
1235 	fve = TAILQ_LAST(&fv->fv_flowlist, fv_flowhead);
1236 
1237 	switch (pktattr->pattr_af) {
1238 	case AF_INET:
1239 		ip = (struct ip *)pktattr->pattr_hdr;
1240 		fve->fve_flow.flow_af = AF_INET;
1241 		fve->fve_flow.flow_ip.ip_src = ip->ip_src;
1242 		fve->fve_flow.flow_ip.ip_dst = ip->ip_dst;
1243 		break;
1244 #ifdef INET6
1245 	case AF_INET6:
1246 		ip6 = (struct ip6_hdr *)pktattr->pattr_hdr;
1247 		fve->fve_flow.flow_af = AF_INET6;
1248 		fve->fve_flow.flow_ip6.ip6_src = ip6->ip6_src;
1249 		fve->fve_flow.flow_ip6.ip6_dst = ip6->ip6_dst;
1250 		break;
1251 #endif
1252 	}
1253 
1254 	fve->fve_state = Green;
1255 	fve->fve_p = 0.0;
1256 	fve->fve_f = 0.0;
1257 	fve->fve_ifseq = fv->fv_ifseq - 1;
1258 	fve->fve_count = 0;
1259 
1260 	fv->fv_flows++;
1261 #ifdef FV_STATS
1262 	fv->fv_stats.alloc++;
1263 #endif
1264 	return (fve);
1265 }
1266 
1267 static __inline void
1268 flowlist_move_to_head(fv, fve)
1269 	struct flowvalve *fv;
1270 	struct fve *fve;
1271 {
1272 	if (TAILQ_FIRST(&fv->fv_flowlist) != fve) {
1273 		TAILQ_REMOVE(&fv->fv_flowlist, fve, fve_lru);
1274 		TAILQ_INSERT_HEAD(&fv->fv_flowlist, fve, fve_lru);
1275 	}
1276 }
1277 
1278 #if 0 /* XXX: make the compiler happy (fv_alloc unused) */
1279 /*
1280  * allocate flowvalve structure
1281  */
1282 static struct flowvalve *
1283 fv_alloc(rp)
1284 	struct red *rp;
1285 {
1286 	struct flowvalve *fv;
1287 	struct fve *fve;
1288 	int i, num;
1289 
1290 	num = FV_FLOWLISTSIZE;
1291 	fv = malloc(sizeof(struct flowvalve),
1292 	       M_DEVBUF, M_WAITOK);
1293 	if (fv == NULL)
1294 		return (NULL);
1295 	bzero(fv, sizeof(struct flowvalve));
1296 
1297 	fv->fv_fves = malloc(sizeof(struct fve) * num,
1298 	       M_DEVBUF, M_WAITOK);
1299 	if (fv->fv_fves == NULL) {
1300 		free(fv, M_DEVBUF);
1301 		return (NULL);
1302 	}
1303 	bzero(fv->fv_fves, sizeof(struct fve) * num);
1304 
1305 	fv->fv_flows = 0;
1306 	TAILQ_INIT(&fv->fv_flowlist);
1307 	for (i = 0; i < num; i++) {
1308 		fve = &fv->fv_fves[i];
1309 		fve->fve_lastdrop.tv_sec = 0;
1310 		TAILQ_INSERT_TAIL(&fv->fv_flowlist, fve, fve_lru);
1311 	}
1312 
1313 	/* initialize drop rate threshold in scaled fixed-point */
1314 	fv->fv_pthresh = (FV_PSCALE(1) << FP_SHIFT) / rp->red_inv_pmax;
1315 
1316 	/* initialize drop rate to fraction table */
1317 	fv->fv_p2ftab = malloc(sizeof(int) * BRTT_SIZE,
1318 	       M_DEVBUF, M_WAITOK);
1319 	if (fv->fv_p2ftab == NULL) {
1320 		free(fv->fv_fves, M_DEVBUF);
1321 		free(fv, M_DEVBUF);
1322 		return (NULL);
1323 	}
1324 	/*
1325 	 * create the p2f table.
1326 	 * (shift is used to keep the precision)
1327 	 */
1328 	for (i = 1; i < BRTT_SIZE; i++) {
1329 		int f;
1330 
1331 		f = brtt_tab[i] << 8;
1332 		fv->fv_p2ftab[i] = (f / (rp->red_thmax + FV_ALPHA)) >> 8;
1333 	}
1334 
1335 	return (fv);
1336 }
1337 #endif
1338 
1339 static void fv_destroy(fv)
1340 	struct flowvalve *fv;
1341 {
1342 	free(fv->fv_p2ftab, M_DEVBUF);
1343 	free(fv->fv_fves, M_DEVBUF);
1344 	free(fv, M_DEVBUF);
1345 }
1346 
1347 static __inline int
1348 fv_p2f(fv, p)
1349 	struct flowvalve	*fv;
1350 	int	p;
1351 {
1352 	int val, f;
1353 
1354 	if (p >= BRTT_PMAX)
1355 		f = fv->fv_p2ftab[BRTT_SIZE-1];
1356 	else if ((val = (p & BRTT_MASK)))
1357 		f = fv->fv_p2ftab[(val >> BRTT_SHIFT)];
1358 	else
1359 		f = fv->fv_p2ftab[1];
1360 	return (f);
1361 }
1362 
1363 /*
1364  * check if an arriving packet should be pre-dropped.
1365  * called from red_addq() when a packet arrives.
1366  * returns 1 when the packet should be pre-dropped.
1367  * should be called in splimp.
1368  */
1369 static int
1370 fv_checkflow(fv, pktattr, fcache)
1371 	struct flowvalve *fv;
1372 	struct altq_pktattr *pktattr;
1373 	struct fve **fcache;
1374 {
1375 	struct fve *fve;
1376 	struct timeval now;
1377 
1378 	fv->fv_ifseq++;
1379 	FV_TIMESTAMP(&now);
1380 
1381 	if ((fve = flowlist_lookup(fv, pktattr, &now)) == NULL)
1382 		/* no matching entry in the flowlist */
1383 		return (0);
1384 
1385 	*fcache = fve;
1386 
1387 	/* update fraction f for every FV_N packets */
1388 	if (++fve->fve_count == FV_N) {
1389 		/*
1390 		 * f = Wf * N / (fv_ifseq - fve_ifseq) + (1 - Wf) * f
1391 		 */
1392 		fve->fve_f =
1393 			(FV_N << FP_SHIFT) / (fv->fv_ifseq - fve->fve_ifseq)
1394 			+ fve->fve_f - FV_FUNSCALE(fve->fve_f);
1395 		fve->fve_ifseq = fv->fv_ifseq;
1396 		fve->fve_count = 0;
1397 	}
1398 
1399 	/*
1400 	 * overpumping test
1401 	 */
1402 	if (fve->fve_state == Green && fve->fve_p > fv->fv_pthresh) {
1403 		int fthresh;
1404 
1405 		/* calculate a threshold */
1406 		fthresh = fv_p2f(fv, fve->fve_p);
1407 		if (fve->fve_f > fthresh)
1408 			fve->fve_state = Red;
1409 	}
1410 
1411 	if (fve->fve_state == Red) {
1412 		/*
1413 		 * backoff test
1414 		 */
1415 		if (now.tv_sec - fve->fve_lastdrop.tv_sec > FV_BACKOFFTHRESH) {
1416 			/* no drop for at least FV_BACKOFFTHRESH sec */
1417 			fve->fve_p = 0;
1418 			fve->fve_state = Green;
1419 #ifdef FV_STATS
1420 			fv->fv_stats.escape++;
1421 #endif
1422 		} else {
1423 			/* block this flow */
1424 			flowlist_move_to_head(fv, fve);
1425 			fve->fve_lastdrop = now;
1426 #ifdef FV_STATS
1427 			fv->fv_stats.predrop++;
1428 #endif
1429 			return (1);
1430 		}
1431 	}
1432 
1433 	/*
1434 	 * p = (1 - Wp) * p
1435 	 */
1436 	fve->fve_p -= FV_PUNSCALE(fve->fve_p);
1437 	if (fve->fve_p < 0)
1438 		fve->fve_p = 0;
1439 #ifdef FV_STATS
1440 	fv->fv_stats.pass++;
1441 #endif
1442 	return (0);
1443 }
1444 
1445 /*
1446  * called from red_addq when a packet is dropped by red.
1447  * should be called in splimp.
1448  */
1449 static void fv_dropbyred(fv, pktattr, fcache)
1450 	struct flowvalve *fv;
1451 	struct altq_pktattr *pktattr;
1452 	struct fve *fcache;
1453 {
1454 	struct fve *fve;
1455 	struct timeval now;
1456 
1457 	if (pktattr == NULL)
1458 		return;
1459 	FV_TIMESTAMP(&now);
1460 
1461 	if (fcache != NULL)
1462 		/* the fve of this packet is already cached */
1463 		fve = fcache;
1464 	else if ((fve = flowlist_lookup(fv, pktattr, &now)) == NULL)
1465 		fve = flowlist_reclaim(fv, pktattr);
1466 
1467 	flowlist_move_to_head(fv, fve);
1468 
1469 	/*
1470 	 * update p:  the following line cancels the update
1471 	 *	      in fv_checkflow() and calculate
1472 	 *	p = Wp + (1 - Wp) * p
1473 	 */
1474 	fve->fve_p = (1 << FP_SHIFT) + fve->fve_p;
1475 
1476 	fve->fve_lastdrop = now;
1477 }
1478 
1479 #endif /* ALTQ_FLOWVALVE */
1480 
1481 #ifdef KLD_MODULE
1482 
1483 static struct altqsw red_sw =
1484 	{"red", redopen, redclose, redioctl};
1485 
1486 ALTQ_MODULE(altq_red, ALTQT_RED, &red_sw);
1487 MODULE_VERSION(altq_red, 1);
1488 
1489 #endif /* KLD_MODULE */
1490 #endif /* ALTQ3_COMPAT */
1491 
1492 #endif /* ALTQ_RED */
1493