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