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