xref: /dflybsd-src/sys/net/altq/altq_rmclass.c (revision 0c77d800c94ec83950e07dd52477a62e83705385)
10f506cedSSascha Wildner /*	@(#)rm_class.c  1.48     97/12/05 SMI	*/
24d723e5aSJoerg Sonnenberger /*	$KAME: altq_rmclass.c,v 1.18 2003/11/06 06:32:53 kjc Exp $	*/
34d723e5aSJoerg Sonnenberger 
44d723e5aSJoerg Sonnenberger /*
54d723e5aSJoerg Sonnenberger  * Copyright (c) 1991-1997 Regents of the University of California.
64d723e5aSJoerg Sonnenberger  * All rights reserved.
74d723e5aSJoerg Sonnenberger  *
84d723e5aSJoerg Sonnenberger  * Redistribution and use in source and binary forms, with or without
94d723e5aSJoerg Sonnenberger  * modification, are permitted provided that the following conditions
104d723e5aSJoerg Sonnenberger  * are met:
114d723e5aSJoerg Sonnenberger  * 1. Redistributions of source code must retain the above copyright
124d723e5aSJoerg Sonnenberger  *    notice, this list of conditions and the following disclaimer.
134d723e5aSJoerg Sonnenberger  * 2. Redistributions in binary form must reproduce the above copyright
144d723e5aSJoerg Sonnenberger  *    notice, this list of conditions and the following disclaimer in the
154d723e5aSJoerg Sonnenberger  *    documentation and/or other materials provided with the distribution.
164d723e5aSJoerg Sonnenberger  * 3. All advertising materials mentioning features or use of this software
174d723e5aSJoerg Sonnenberger  *    must display the following acknowledgement:
184d723e5aSJoerg Sonnenberger  *      This product includes software developed by the Network Research
194d723e5aSJoerg Sonnenberger  *      Group at Lawrence Berkeley Laboratory.
204d723e5aSJoerg Sonnenberger  * 4. Neither the name of the University nor of the Laboratory may be used
214d723e5aSJoerg Sonnenberger  *    to endorse or promote products derived from this software without
224d723e5aSJoerg Sonnenberger  *    specific prior written permission.
234d723e5aSJoerg Sonnenberger  *
244d723e5aSJoerg Sonnenberger  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
254d723e5aSJoerg Sonnenberger  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
264d723e5aSJoerg Sonnenberger  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
274d723e5aSJoerg Sonnenberger  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
284d723e5aSJoerg Sonnenberger  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
294d723e5aSJoerg Sonnenberger  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
304d723e5aSJoerg Sonnenberger  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
314d723e5aSJoerg Sonnenberger  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
324d723e5aSJoerg Sonnenberger  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
334d723e5aSJoerg Sonnenberger  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
344d723e5aSJoerg Sonnenberger  * SUCH DAMAGE.
354d723e5aSJoerg Sonnenberger  *
364d723e5aSJoerg Sonnenberger  * LBL code modified by speer@eng.sun.com, May 1977.
374d723e5aSJoerg Sonnenberger  * For questions and/or comments, please send mail to cbq@ee.lbl.gov
384d723e5aSJoerg Sonnenberger  */
394d723e5aSJoerg Sonnenberger 
404d723e5aSJoerg Sonnenberger #include "opt_altq.h"
414d723e5aSJoerg Sonnenberger #include "opt_inet.h"
424d723e5aSJoerg Sonnenberger #include "opt_inet6.h"
434d723e5aSJoerg Sonnenberger 
444d723e5aSJoerg Sonnenberger #ifdef ALTQ_CBQ	/* cbq is enabled by ALTQ_CBQ option in opt_altq.h */
454d723e5aSJoerg Sonnenberger 
464d723e5aSJoerg Sonnenberger #include <sys/param.h>
474d723e5aSJoerg Sonnenberger #include <sys/malloc.h>
484d723e5aSJoerg Sonnenberger #include <sys/mbuf.h>
494d723e5aSJoerg Sonnenberger #include <sys/socket.h>
504d723e5aSJoerg Sonnenberger #include <sys/systm.h>
514d723e5aSJoerg Sonnenberger #include <sys/callout.h>
524d723e5aSJoerg Sonnenberger #include <sys/errno.h>
534d723e5aSJoerg Sonnenberger #include <sys/time.h>
549c095379SMatthew Dillon #include <sys/thread.h>
554d723e5aSJoerg Sonnenberger 
564d723e5aSJoerg Sonnenberger #include <net/if.h>
574d723e5aSJoerg Sonnenberger 
584d723e5aSJoerg Sonnenberger #include <net/altq/altq.h>
594d723e5aSJoerg Sonnenberger #include <net/altq/altq_rmclass.h>
604d723e5aSJoerg Sonnenberger #include <net/altq/altq_rmclass_debug.h>
614d723e5aSJoerg Sonnenberger #include <net/altq/altq_red.h>
624d723e5aSJoerg Sonnenberger #include <net/altq/altq_rio.h>
634d723e5aSJoerg Sonnenberger 
649c095379SMatthew Dillon #include <sys/thread2.h>
659c095379SMatthew Dillon 
664d723e5aSJoerg Sonnenberger #ifdef CBQ_TRACE
674d723e5aSJoerg Sonnenberger static struct cbqtrace cbqtrace_buffer[NCBQTRACE+1];
684d723e5aSJoerg Sonnenberger static struct cbqtrace *cbqtrace_ptr = NULL;
694d723e5aSJoerg Sonnenberger static int cbqtrace_count;
704d723e5aSJoerg Sonnenberger #endif
714d723e5aSJoerg Sonnenberger 
724d723e5aSJoerg Sonnenberger /*
734d723e5aSJoerg Sonnenberger  * Local Macros
744d723e5aSJoerg Sonnenberger  */
754d723e5aSJoerg Sonnenberger 
764d723e5aSJoerg Sonnenberger #define	reset_cutoff(ifd)	{ ifd->cutoff_ = RM_MAXDEPTH; }
774d723e5aSJoerg Sonnenberger 
784d723e5aSJoerg Sonnenberger /*
794d723e5aSJoerg Sonnenberger  * Local routines.
804d723e5aSJoerg Sonnenberger  */
814d723e5aSJoerg Sonnenberger 
824d723e5aSJoerg Sonnenberger static int	rmc_satisfied(struct rm_class *, struct timeval *);
834d723e5aSJoerg Sonnenberger static void	rmc_wrr_set_weights(struct rm_ifdat *);
844d723e5aSJoerg Sonnenberger static void	rmc_depth_compute(struct rm_class *);
854d723e5aSJoerg Sonnenberger static void	rmc_depth_recompute(rm_class_t *);
864d723e5aSJoerg Sonnenberger 
874d723e5aSJoerg Sonnenberger static struct mbuf *_rmc_wrr_dequeue_next(struct rm_ifdat *, int);
884d723e5aSJoerg Sonnenberger static struct mbuf *_rmc_prr_dequeue_next(struct rm_ifdat *, int);
894d723e5aSJoerg Sonnenberger 
904d723e5aSJoerg Sonnenberger static int	_rmc_addq(rm_class_t *, struct mbuf *);
914d723e5aSJoerg Sonnenberger static void	_rmc_dropq(rm_class_t *);
924d723e5aSJoerg Sonnenberger static struct mbuf *_rmc_getq(rm_class_t *);
934d723e5aSJoerg Sonnenberger static struct mbuf *_rmc_pollq(rm_class_t *);
944d723e5aSJoerg Sonnenberger 
954d723e5aSJoerg Sonnenberger static int	rmc_under_limit(struct rm_class *, struct timeval *);
964d723e5aSJoerg Sonnenberger static void	rmc_tl_satisfied(struct rm_ifdat *, struct timeval *);
974d723e5aSJoerg Sonnenberger static void	rmc_drop_action(struct rm_class *);
984d723e5aSJoerg Sonnenberger static void	rmc_restart(void *);
994d723e5aSJoerg Sonnenberger static void	rmc_root_overlimit(struct rm_class *, struct rm_class *);
1004d723e5aSJoerg Sonnenberger 
1014d723e5aSJoerg Sonnenberger #define	BORROW_OFFTIME
1024d723e5aSJoerg Sonnenberger /*
1034d723e5aSJoerg Sonnenberger  * BORROW_OFFTIME (experimental):
1044d723e5aSJoerg Sonnenberger  * borrow the offtime of the class borrowing from.
1054d723e5aSJoerg Sonnenberger  * the reason is that when its own offtime is set, the class is unable
1064d723e5aSJoerg Sonnenberger  * to borrow much, especially when cutoff is taking effect.
1074d723e5aSJoerg Sonnenberger  * but when the borrowed class is overloaded (advidle is close to minidle),
1084d723e5aSJoerg Sonnenberger  * use the borrowing class's offtime to avoid overload.
1094d723e5aSJoerg Sonnenberger  */
1104d723e5aSJoerg Sonnenberger #define	ADJUST_CUTOFF
1114d723e5aSJoerg Sonnenberger /*
1124d723e5aSJoerg Sonnenberger  * ADJUST_CUTOFF (experimental):
1134d723e5aSJoerg Sonnenberger  * if no underlimit class is found due to cutoff, increase cutoff and
1144d723e5aSJoerg Sonnenberger  * retry the scheduling loop.
1154d723e5aSJoerg Sonnenberger  * also, don't invoke delay_actions while cutoff is taking effect,
1164d723e5aSJoerg Sonnenberger  * since a sleeping class won't have a chance to be scheduled in the
1174d723e5aSJoerg Sonnenberger  * next loop.
1184d723e5aSJoerg Sonnenberger  *
1194d723e5aSJoerg Sonnenberger  * now heuristics for setting the top-level variable (cutoff_) becomes:
1204d723e5aSJoerg Sonnenberger  *	1. if a packet arrives for a not-overlimit class, set cutoff
1214d723e5aSJoerg Sonnenberger  *	   to the depth of the class.
1224d723e5aSJoerg Sonnenberger  *	2. if cutoff is i, and a packet arrives for an overlimit class
1234d723e5aSJoerg Sonnenberger  *	   with an underlimit ancestor at a lower level than i (say j),
1244d723e5aSJoerg Sonnenberger  *	   then set cutoff to j.
1254d723e5aSJoerg Sonnenberger  *	3. at scheduling a packet, if there is no underlimit class
1264d723e5aSJoerg Sonnenberger  *	   due to the current cutoff level, increase cutoff by 1 and
1274d723e5aSJoerg Sonnenberger  *	   then try to schedule again.
1284d723e5aSJoerg Sonnenberger  */
1294d723e5aSJoerg Sonnenberger 
1304d723e5aSJoerg Sonnenberger /*
1314d723e5aSJoerg Sonnenberger  * rm_class_t *
1324d723e5aSJoerg Sonnenberger  * rmc_newclass(...) - Create a new resource management class at priority
1334d723e5aSJoerg Sonnenberger  * 'pri' on the interface given by 'ifd'.
1344d723e5aSJoerg Sonnenberger  *
1354d723e5aSJoerg Sonnenberger  * nsecPerByte  is the data rate of the interface in nanoseconds/byte.
1364d723e5aSJoerg Sonnenberger  *              E.g., 800 for a 10Mb/s ethernet.  If the class gets less
1374d723e5aSJoerg Sonnenberger  *              than 100% of the bandwidth, this number should be the
1384d723e5aSJoerg Sonnenberger  *              'effective' rate for the class.  Let f be the
1394d723e5aSJoerg Sonnenberger  *              bandwidth fraction allocated to this class, and let
1404d723e5aSJoerg Sonnenberger  *              nsPerByte be the data rate of the output link in
1414d723e5aSJoerg Sonnenberger  *              nanoseconds/byte.  Then nsecPerByte is set to
1424d723e5aSJoerg Sonnenberger  *              nsPerByte / f.  E.g., 1600 (= 800 / .5)
1434d723e5aSJoerg Sonnenberger  *              for a class that gets 50% of an ethernet's bandwidth.
1444d723e5aSJoerg Sonnenberger  *
1454d723e5aSJoerg Sonnenberger  * action       the routine to call when the class is over limit.
1464d723e5aSJoerg Sonnenberger  *
1474d723e5aSJoerg Sonnenberger  * maxq         max allowable queue size for class (in packets).
1484d723e5aSJoerg Sonnenberger  *
1494d723e5aSJoerg Sonnenberger  * parent       parent class pointer.
1504d723e5aSJoerg Sonnenberger  *
1514d723e5aSJoerg Sonnenberger  * borrow       class to borrow from (should be either 'parent' or null).
1524d723e5aSJoerg Sonnenberger  *
1534d723e5aSJoerg Sonnenberger  * maxidle      max value allowed for class 'idle' time estimate (this
1544d723e5aSJoerg Sonnenberger  *              parameter determines how large an initial burst of packets
1554d723e5aSJoerg Sonnenberger  *              can be before overlimit action is invoked.
1564d723e5aSJoerg Sonnenberger  *
1574d723e5aSJoerg Sonnenberger  * offtime      how long 'delay' action will delay when class goes over
1584d723e5aSJoerg Sonnenberger  *              limit (this parameter determines the steady-state burst
1594d723e5aSJoerg Sonnenberger  *              size when a class is running over its limit).
1604d723e5aSJoerg Sonnenberger  *
1614d723e5aSJoerg Sonnenberger  * Maxidle and offtime have to be computed from the following:  If the
1624d723e5aSJoerg Sonnenberger  * average packet size is s, the bandwidth fraction allocated to this
1634d723e5aSJoerg Sonnenberger  * class is f, we want to allow b packet bursts, and the gain of the
1644d723e5aSJoerg Sonnenberger  * averaging filter is g (= 1 - 2^(-RM_FILTER_GAIN)), then:
1654d723e5aSJoerg Sonnenberger  *
1664d723e5aSJoerg Sonnenberger  *   ptime = s * nsPerByte * (1 - f) / f
1674d723e5aSJoerg Sonnenberger  *   maxidle = ptime * (1 - g^b) / g^b
1684d723e5aSJoerg Sonnenberger  *   minidle = -ptime * (1 / (f - 1))
1694d723e5aSJoerg Sonnenberger  *   offtime = ptime * (1 + 1/(1 - g) * (1 - g^(b - 1)) / g^(b - 1)
1704d723e5aSJoerg Sonnenberger  *
1714d723e5aSJoerg Sonnenberger  * Operationally, it's convenient to specify maxidle & offtime in units
1724d723e5aSJoerg Sonnenberger  * independent of the link bandwidth so the maxidle & offtime passed to
1734d723e5aSJoerg Sonnenberger  * this routine are the above values multiplied by 8*f/(1000*nsPerByte).
1744d723e5aSJoerg Sonnenberger  * (The constant factor is a scale factor needed to make the parameters
1754d723e5aSJoerg Sonnenberger  * integers.  This scaling also means that the 'unscaled' values of
1764d723e5aSJoerg Sonnenberger  * maxidle*nsecPerByte/8 and offtime*nsecPerByte/8 will be in microseconds,
1774d723e5aSJoerg Sonnenberger  * not nanoseconds.)  Also note that the 'idle' filter computation keeps
1784d723e5aSJoerg Sonnenberger  * an estimate scaled upward by 2^RM_FILTER_GAIN so the passed value of
1794d723e5aSJoerg Sonnenberger  * maxidle also must be scaled upward by this value.  Thus, the passed
1804d723e5aSJoerg Sonnenberger  * values for maxidle and offtime can be computed as follows:
1814d723e5aSJoerg Sonnenberger  *
1824d723e5aSJoerg Sonnenberger  * maxidle = maxidle * 2^RM_FILTER_GAIN * 8 / (1000 * nsecPerByte)
1834d723e5aSJoerg Sonnenberger  * offtime = offtime * 8 / (1000 * nsecPerByte)
1844d723e5aSJoerg Sonnenberger  *
1854d723e5aSJoerg Sonnenberger  * When USE_HRTIME is employed, then maxidle and offtime become:
1864d723e5aSJoerg Sonnenberger  * 	maxidle = maxilde * (8.0 / nsecPerByte);
1874d723e5aSJoerg Sonnenberger  * 	offtime = offtime * (8.0 / nsecPerByte);
1884d723e5aSJoerg Sonnenberger  */
1894d723e5aSJoerg Sonnenberger struct rm_class *
1904d723e5aSJoerg Sonnenberger rmc_newclass(int pri, struct rm_ifdat *ifd, u_int nsecPerByte,
1914d723e5aSJoerg Sonnenberger 	     void (*action)(rm_class_t *, rm_class_t *), int maxq,
1924d723e5aSJoerg Sonnenberger 	     struct rm_class *parent, struct rm_class *borrow, u_int maxidle,
1934d723e5aSJoerg Sonnenberger 	     int minidle, u_int offtime, int pktsize, int flags)
1944d723e5aSJoerg Sonnenberger {
1954d723e5aSJoerg Sonnenberger 	struct rm_class *cl;
1964d723e5aSJoerg Sonnenberger 	struct rm_class *peer;
1974d723e5aSJoerg Sonnenberger 
1984d723e5aSJoerg Sonnenberger 	if (pri >= RM_MAXPRIO)
1994d723e5aSJoerg Sonnenberger 		return (NULL);
2004d723e5aSJoerg Sonnenberger #ifndef ALTQ_RED
2014d723e5aSJoerg Sonnenberger 	if (flags & RMCF_RED) {
2024d723e5aSJoerg Sonnenberger #ifdef ALTQ_DEBUG
2034b1cf444SSascha Wildner 		kprintf("rmc_newclass: RED not configured for CBQ!\n");
2044d723e5aSJoerg Sonnenberger #endif
2054d723e5aSJoerg Sonnenberger 		return (NULL);
2064d723e5aSJoerg Sonnenberger 	}
2074d723e5aSJoerg Sonnenberger #endif
2084d723e5aSJoerg Sonnenberger #ifndef ALTQ_RIO
2094d723e5aSJoerg Sonnenberger 	if (flags & RMCF_RIO) {
2104d723e5aSJoerg Sonnenberger #ifdef ALTQ_DEBUG
2114b1cf444SSascha Wildner 		kprintf("rmc_newclass: RIO not configured for CBQ!\n");
2124d723e5aSJoerg Sonnenberger #endif
2134d723e5aSJoerg Sonnenberger 		return (NULL);
2144d723e5aSJoerg Sonnenberger 	}
2154d723e5aSJoerg Sonnenberger #endif
2164d723e5aSJoerg Sonnenberger 
217efda3bd0SMatthew Dillon 	cl = kmalloc(sizeof(*cl), M_ALTQ, M_WAITOK | M_ZERO);
2184d723e5aSJoerg Sonnenberger 	callout_init(&cl->callout_);
219efda3bd0SMatthew Dillon 	cl->q_ = kmalloc(sizeof(*cl->q_), M_ALTQ, M_WAITOK | M_ZERO);
2204d723e5aSJoerg Sonnenberger 
2214d723e5aSJoerg Sonnenberger 	/*
2224d723e5aSJoerg Sonnenberger 	 * Class initialization.
2234d723e5aSJoerg Sonnenberger 	 */
2244d723e5aSJoerg Sonnenberger 	cl->children_ = NULL;
2254d723e5aSJoerg Sonnenberger 	cl->parent_ = parent;
2264d723e5aSJoerg Sonnenberger 	cl->borrow_ = borrow;
2274d723e5aSJoerg Sonnenberger 	cl->leaf_ = 1;
2284d723e5aSJoerg Sonnenberger 	cl->ifdat_ = ifd;
2294d723e5aSJoerg Sonnenberger 	cl->pri_ = pri;
2304d723e5aSJoerg Sonnenberger 	cl->allotment_ = RM_NS_PER_SEC / nsecPerByte; /* Bytes per sec */
2314d723e5aSJoerg Sonnenberger 	cl->depth_ = 0;
2324d723e5aSJoerg Sonnenberger 	cl->qthresh_ = 0;
2334d723e5aSJoerg Sonnenberger 	cl->ns_per_byte_ = nsecPerByte;
2344d723e5aSJoerg Sonnenberger 
2354d723e5aSJoerg Sonnenberger 	qlimit(cl->q_) = maxq;
2364d723e5aSJoerg Sonnenberger 	qtype(cl->q_) = Q_DROPHEAD;
2374d723e5aSJoerg Sonnenberger 	qlen(cl->q_) = 0;
2384d723e5aSJoerg Sonnenberger 	cl->flags_ = flags;
2394d723e5aSJoerg Sonnenberger 
2404d723e5aSJoerg Sonnenberger #if 1 /* minidle is also scaled in ALTQ */
2414d723e5aSJoerg Sonnenberger 	cl->minidle_ = (minidle * (int)nsecPerByte) / 8;
2424d723e5aSJoerg Sonnenberger 	if (cl->minidle_ > 0)
2434d723e5aSJoerg Sonnenberger 		cl->minidle_ = 0;
2444d723e5aSJoerg Sonnenberger #else
2454d723e5aSJoerg Sonnenberger 	cl->minidle_ = minidle;
2464d723e5aSJoerg Sonnenberger #endif
2474d723e5aSJoerg Sonnenberger 	cl->maxidle_ = (maxidle * nsecPerByte) / 8;
2484d723e5aSJoerg Sonnenberger 	if (cl->maxidle_ == 0)
2494d723e5aSJoerg Sonnenberger 		cl->maxidle_ = 1;
2504d723e5aSJoerg Sonnenberger #if 1 /* offtime is also scaled in ALTQ */
2514d723e5aSJoerg Sonnenberger 	cl->avgidle_ = cl->maxidle_;
2524d723e5aSJoerg Sonnenberger 	cl->offtime_ = ((offtime * nsecPerByte) / 8) >> RM_FILTER_GAIN;
2534d723e5aSJoerg Sonnenberger 	if (cl->offtime_ == 0)
2544d723e5aSJoerg Sonnenberger 		cl->offtime_ = 1;
2554d723e5aSJoerg Sonnenberger #else
2564d723e5aSJoerg Sonnenberger 	cl->avgidle_ = 0;
2574d723e5aSJoerg Sonnenberger 	cl->offtime_ = (offtime * nsecPerByte) / 8;
2584d723e5aSJoerg Sonnenberger #endif
2594d723e5aSJoerg Sonnenberger 	cl->overlimit = action;
2604d723e5aSJoerg Sonnenberger 
2614d723e5aSJoerg Sonnenberger #ifdef ALTQ_RED
2624d723e5aSJoerg Sonnenberger 	if (flags & (RMCF_RED|RMCF_RIO)) {
2634d723e5aSJoerg Sonnenberger 		int red_flags, red_pkttime;
2644d723e5aSJoerg Sonnenberger 
2654d723e5aSJoerg Sonnenberger 		red_flags = 0;
2664d723e5aSJoerg Sonnenberger 		if (flags & RMCF_ECN)
2674d723e5aSJoerg Sonnenberger 			red_flags |= REDF_ECN;
2684d723e5aSJoerg Sonnenberger #ifdef ALTQ_RIO
2694d723e5aSJoerg Sonnenberger 		if (flags & RMCF_CLEARDSCP)
2704d723e5aSJoerg Sonnenberger 			red_flags |= RIOF_CLEARDSCP;
2714d723e5aSJoerg Sonnenberger #endif
2724d723e5aSJoerg Sonnenberger 		red_pkttime = nsecPerByte * pktsize  / 1000;
2734d723e5aSJoerg Sonnenberger 
2744d723e5aSJoerg Sonnenberger 		if (flags & RMCF_RED) {
2754d723e5aSJoerg Sonnenberger 			cl->red_ = red_alloc(0, 0,
2764d723e5aSJoerg Sonnenberger 			    qlimit(cl->q_) * 10/100,
2774d723e5aSJoerg Sonnenberger 			    qlimit(cl->q_) * 30/100,
2784d723e5aSJoerg Sonnenberger 			    red_flags, red_pkttime);
2794d723e5aSJoerg Sonnenberger 			if (cl->red_ != NULL)
2804d723e5aSJoerg Sonnenberger 				qtype(cl->q_) = Q_RED;
2814d723e5aSJoerg Sonnenberger 		}
2824d723e5aSJoerg Sonnenberger #ifdef ALTQ_RIO
2834d723e5aSJoerg Sonnenberger 		else {
2844d723e5aSJoerg Sonnenberger 			cl->red_ = (red_t *)rio_alloc(0, NULL,
2854d723e5aSJoerg Sonnenberger 						      red_flags, red_pkttime);
2864d723e5aSJoerg Sonnenberger 			if (cl->red_ != NULL)
2874d723e5aSJoerg Sonnenberger 				qtype(cl->q_) = Q_RIO;
2884d723e5aSJoerg Sonnenberger 		}
2894d723e5aSJoerg Sonnenberger #endif
2904d723e5aSJoerg Sonnenberger 	}
2914d723e5aSJoerg Sonnenberger #endif /* ALTQ_RED */
2924d723e5aSJoerg Sonnenberger 
2934d723e5aSJoerg Sonnenberger 	/*
2944d723e5aSJoerg Sonnenberger 	 * put the class into the class tree
2954d723e5aSJoerg Sonnenberger 	 */
2960b31d406SSascha Wildner 	crit_enter();
2974d723e5aSJoerg Sonnenberger 	if ((peer = ifd->active_[pri]) != NULL) {
2984d723e5aSJoerg Sonnenberger 		/* find the last class at this pri */
2994d723e5aSJoerg Sonnenberger 		cl->peer_ = peer;
3004d723e5aSJoerg Sonnenberger 		while (peer->peer_ != ifd->active_[pri])
3014d723e5aSJoerg Sonnenberger 			peer = peer->peer_;
3024d723e5aSJoerg Sonnenberger 		peer->peer_ = cl;
3034d723e5aSJoerg Sonnenberger 	} else {
3044d723e5aSJoerg Sonnenberger 		ifd->active_[pri] = cl;
3054d723e5aSJoerg Sonnenberger 		cl->peer_ = cl;
3064d723e5aSJoerg Sonnenberger 	}
3074d723e5aSJoerg Sonnenberger 
3084d723e5aSJoerg Sonnenberger 	if (cl->parent_) {
3094d723e5aSJoerg Sonnenberger 		cl->next_ = parent->children_;
3104d723e5aSJoerg Sonnenberger 		parent->children_ = cl;
3114d723e5aSJoerg Sonnenberger 		parent->leaf_ = 0;
3124d723e5aSJoerg Sonnenberger 	}
3134d723e5aSJoerg Sonnenberger 
3144d723e5aSJoerg Sonnenberger 	/*
3154d723e5aSJoerg Sonnenberger 	 * Compute the depth of this class and its ancestors in the class
3164d723e5aSJoerg Sonnenberger 	 * hierarchy.
3174d723e5aSJoerg Sonnenberger 	 */
3184d723e5aSJoerg Sonnenberger 	rmc_depth_compute(cl);
3194d723e5aSJoerg Sonnenberger 
3204d723e5aSJoerg Sonnenberger 	/*
3214d723e5aSJoerg Sonnenberger 	 * If CBQ's WRR is enabled, then initialize the class WRR state.
3224d723e5aSJoerg Sonnenberger 	 */
3234d723e5aSJoerg Sonnenberger 	if (ifd->wrr_) {
3244d723e5aSJoerg Sonnenberger 		ifd->num_[pri]++;
3254d723e5aSJoerg Sonnenberger 		ifd->alloc_[pri] += cl->allotment_;
3264d723e5aSJoerg Sonnenberger 		rmc_wrr_set_weights(ifd);
3274d723e5aSJoerg Sonnenberger 	}
3280b31d406SSascha Wildner 	crit_exit();
3294d723e5aSJoerg Sonnenberger 	return (cl);
3304d723e5aSJoerg Sonnenberger }
3314d723e5aSJoerg Sonnenberger 
3324d723e5aSJoerg Sonnenberger int
3334d723e5aSJoerg Sonnenberger rmc_modclass(struct rm_class *cl, u_int nsecPerByte, int maxq, u_int maxidle,
3344d723e5aSJoerg Sonnenberger 	     int minidle, u_int offtime, int pktsize)
3354d723e5aSJoerg Sonnenberger {
3364d723e5aSJoerg Sonnenberger 	struct rm_ifdat *ifd;
3374d723e5aSJoerg Sonnenberger 	u_int old_allotment;
3384d723e5aSJoerg Sonnenberger 
3394d723e5aSJoerg Sonnenberger 	ifd = cl->ifdat_;
3404d723e5aSJoerg Sonnenberger 	old_allotment = cl->allotment_;
3414d723e5aSJoerg Sonnenberger 
3420b31d406SSascha Wildner 	crit_enter();
3434d723e5aSJoerg Sonnenberger 	cl->allotment_ = RM_NS_PER_SEC / nsecPerByte; /* Bytes per sec */
3444d723e5aSJoerg Sonnenberger 	cl->qthresh_ = 0;
3454d723e5aSJoerg Sonnenberger 	cl->ns_per_byte_ = nsecPerByte;
3464d723e5aSJoerg Sonnenberger 
3474d723e5aSJoerg Sonnenberger 	qlimit(cl->q_) = maxq;
3484d723e5aSJoerg Sonnenberger 
3494d723e5aSJoerg Sonnenberger #if 1 /* minidle is also scaled in ALTQ */
3504d723e5aSJoerg Sonnenberger 	cl->minidle_ = (minidle * nsecPerByte) / 8;
3514d723e5aSJoerg Sonnenberger 	if (cl->minidle_ > 0)
3524d723e5aSJoerg Sonnenberger 		cl->minidle_ = 0;
3534d723e5aSJoerg Sonnenberger #else
3544d723e5aSJoerg Sonnenberger 	cl->minidle_ = minidle;
3554d723e5aSJoerg Sonnenberger #endif
3564d723e5aSJoerg Sonnenberger 	cl->maxidle_ = (maxidle * nsecPerByte) / 8;
3574d723e5aSJoerg Sonnenberger 	if (cl->maxidle_ == 0)
3584d723e5aSJoerg Sonnenberger 		cl->maxidle_ = 1;
3594d723e5aSJoerg Sonnenberger #if 1 /* offtime is also scaled in ALTQ */
3604d723e5aSJoerg Sonnenberger 	cl->avgidle_ = cl->maxidle_;
3614d723e5aSJoerg Sonnenberger 	cl->offtime_ = ((offtime * nsecPerByte) / 8) >> RM_FILTER_GAIN;
3624d723e5aSJoerg Sonnenberger 	if (cl->offtime_ == 0)
3634d723e5aSJoerg Sonnenberger 		cl->offtime_ = 1;
3644d723e5aSJoerg Sonnenberger #else
3654d723e5aSJoerg Sonnenberger 	cl->avgidle_ = 0;
3664d723e5aSJoerg Sonnenberger 	cl->offtime_ = (offtime * nsecPerByte) / 8;
3674d723e5aSJoerg Sonnenberger #endif
3684d723e5aSJoerg Sonnenberger 
3694d723e5aSJoerg Sonnenberger 	/*
3704d723e5aSJoerg Sonnenberger 	 * If CBQ's WRR is enabled, then initialize the class WRR state.
3714d723e5aSJoerg Sonnenberger 	 */
3724d723e5aSJoerg Sonnenberger 	if (ifd->wrr_) {
3734d723e5aSJoerg Sonnenberger 		ifd->alloc_[cl->pri_] += cl->allotment_ - old_allotment;
3744d723e5aSJoerg Sonnenberger 		rmc_wrr_set_weights(ifd);
3754d723e5aSJoerg Sonnenberger 	}
3760b31d406SSascha Wildner 	crit_exit();
3774d723e5aSJoerg Sonnenberger 	return (0);
3784d723e5aSJoerg Sonnenberger }
3794d723e5aSJoerg Sonnenberger 
3804d723e5aSJoerg Sonnenberger /*
3814d723e5aSJoerg Sonnenberger  * static void
3824d723e5aSJoerg Sonnenberger  * rmc_wrr_set_weights(struct rm_ifdat *ifdat) - This function computes
3834d723e5aSJoerg Sonnenberger  *	the appropriate run robin weights for the CBQ weighted round robin
3844d723e5aSJoerg Sonnenberger  *	algorithm.
3854d723e5aSJoerg Sonnenberger  *
3864d723e5aSJoerg Sonnenberger  *	Returns: NONE
3874d723e5aSJoerg Sonnenberger  */
3884d723e5aSJoerg Sonnenberger 
3894d723e5aSJoerg Sonnenberger static void
3904d723e5aSJoerg Sonnenberger rmc_wrr_set_weights(struct rm_ifdat *ifd)
3914d723e5aSJoerg Sonnenberger {
3924d723e5aSJoerg Sonnenberger 	int i;
3934d723e5aSJoerg Sonnenberger 	struct rm_class *cl, *clh;
3944d723e5aSJoerg Sonnenberger 
3954d723e5aSJoerg Sonnenberger 	for (i = 0; i < RM_MAXPRIO; i++) {
3964d723e5aSJoerg Sonnenberger 		/*
3974d723e5aSJoerg Sonnenberger 		 * This is inverted from that of the simulator to
3984d723e5aSJoerg Sonnenberger 		 * maintain precision.
3994d723e5aSJoerg Sonnenberger 		 */
4004d723e5aSJoerg Sonnenberger 		if (ifd->num_[i] == 0)
4014d723e5aSJoerg Sonnenberger 			ifd->M_[i] = 0;
4024d723e5aSJoerg Sonnenberger 		else
4034d723e5aSJoerg Sonnenberger 			ifd->M_[i] = ifd->alloc_[i] /
4044d723e5aSJoerg Sonnenberger 				(ifd->num_[i] * ifd->maxpkt_);
4054d723e5aSJoerg Sonnenberger 		/*
4064d723e5aSJoerg Sonnenberger 		 * Compute the weighted allotment for each class.
4074d723e5aSJoerg Sonnenberger 		 * This takes the expensive div instruction out
4084d723e5aSJoerg Sonnenberger 		 * of the main loop for the wrr scheduling path.
4094d723e5aSJoerg Sonnenberger 		 * These only get recomputed when a class comes or
4104d723e5aSJoerg Sonnenberger 		 * goes.
4114d723e5aSJoerg Sonnenberger 		 */
4124d723e5aSJoerg Sonnenberger 		if (ifd->active_[i] != NULL) {
4134d723e5aSJoerg Sonnenberger 			clh = cl = ifd->active_[i];
4144d723e5aSJoerg Sonnenberger 			do {
4154d723e5aSJoerg Sonnenberger 				/* safe-guard for slow link or alloc_ == 0 */
4164d723e5aSJoerg Sonnenberger 				if (ifd->M_[i] == 0)
4174d723e5aSJoerg Sonnenberger 					cl->w_allotment_ = 0;
4184d723e5aSJoerg Sonnenberger 				else
4194d723e5aSJoerg Sonnenberger 					cl->w_allotment_ = cl->allotment_ /
4204d723e5aSJoerg Sonnenberger 						ifd->M_[i];
4214d723e5aSJoerg Sonnenberger 				cl = cl->peer_;
4224d723e5aSJoerg Sonnenberger 			} while ((cl != NULL) && (cl != clh));
4234d723e5aSJoerg Sonnenberger 		}
4244d723e5aSJoerg Sonnenberger 	}
4254d723e5aSJoerg Sonnenberger }
4264d723e5aSJoerg Sonnenberger 
4274d723e5aSJoerg Sonnenberger int
4284d723e5aSJoerg Sonnenberger rmc_get_weight(struct rm_ifdat *ifd, int pri)
4294d723e5aSJoerg Sonnenberger {
4304d723e5aSJoerg Sonnenberger 	if ((pri >= 0) && (pri < RM_MAXPRIO))
4314d723e5aSJoerg Sonnenberger 		return (ifd->M_[pri]);
4324d723e5aSJoerg Sonnenberger 	else
4334d723e5aSJoerg Sonnenberger 		return (0);
4344d723e5aSJoerg Sonnenberger }
4354d723e5aSJoerg Sonnenberger 
4364d723e5aSJoerg Sonnenberger /*
4374d723e5aSJoerg Sonnenberger  * static void
4384d723e5aSJoerg Sonnenberger  * rmc_depth_compute(struct rm_class *cl) - This function computes the
4394d723e5aSJoerg Sonnenberger  *	appropriate depth of class 'cl' and its ancestors.
4404d723e5aSJoerg Sonnenberger  *
4414d723e5aSJoerg Sonnenberger  *	Returns:	NONE
4424d723e5aSJoerg Sonnenberger  */
4434d723e5aSJoerg Sonnenberger 
4444d723e5aSJoerg Sonnenberger static void
4454d723e5aSJoerg Sonnenberger rmc_depth_compute(struct rm_class *cl)
4464d723e5aSJoerg Sonnenberger {
4474d723e5aSJoerg Sonnenberger 	rm_class_t *t = cl, *p;
4484d723e5aSJoerg Sonnenberger 
4494d723e5aSJoerg Sonnenberger 	/*
4504d723e5aSJoerg Sonnenberger 	 * Recompute the depth for the branch of the tree.
4514d723e5aSJoerg Sonnenberger 	 */
4524d723e5aSJoerg Sonnenberger 	while (t != NULL) {
4534d723e5aSJoerg Sonnenberger 		p = t->parent_;
4544d723e5aSJoerg Sonnenberger 		if (p && (t->depth_ >= p->depth_)) {
4554d723e5aSJoerg Sonnenberger 			p->depth_ = t->depth_ + 1;
4564d723e5aSJoerg Sonnenberger 			t = p;
4574d723e5aSJoerg Sonnenberger 		} else
4584d723e5aSJoerg Sonnenberger 			t = NULL;
4594d723e5aSJoerg Sonnenberger 	}
4604d723e5aSJoerg Sonnenberger }
4614d723e5aSJoerg Sonnenberger 
4624d723e5aSJoerg Sonnenberger /*
4634d723e5aSJoerg Sonnenberger  * static void
4644d723e5aSJoerg Sonnenberger  * rmc_depth_recompute(struct rm_class *cl) - This function re-computes
4654d723e5aSJoerg Sonnenberger  *	the depth of the tree after a class has been deleted.
4664d723e5aSJoerg Sonnenberger  *
4674d723e5aSJoerg Sonnenberger  *	Returns:	NONE
4684d723e5aSJoerg Sonnenberger  */
4694d723e5aSJoerg Sonnenberger 
4704d723e5aSJoerg Sonnenberger static void
4714d723e5aSJoerg Sonnenberger rmc_depth_recompute(rm_class_t *cl)
4724d723e5aSJoerg Sonnenberger {
4734d723e5aSJoerg Sonnenberger #if 1 /* ALTQ */
4744d723e5aSJoerg Sonnenberger 	rm_class_t *p, *t;
4754d723e5aSJoerg Sonnenberger 
4764d723e5aSJoerg Sonnenberger 	p = cl;
4774d723e5aSJoerg Sonnenberger 	while (p != NULL) {
4784d723e5aSJoerg Sonnenberger 		if ((t = p->children_) == NULL) {
4794d723e5aSJoerg Sonnenberger 			p->depth_ = 0;
4804d723e5aSJoerg Sonnenberger 		} else {
4814d723e5aSJoerg Sonnenberger 			int cdepth = 0;
4824d723e5aSJoerg Sonnenberger 
4834d723e5aSJoerg Sonnenberger 			while (t != NULL) {
4844d723e5aSJoerg Sonnenberger 				if (t->depth_ > cdepth)
4854d723e5aSJoerg Sonnenberger 					cdepth = t->depth_;
4864d723e5aSJoerg Sonnenberger 				t = t->next_;
4874d723e5aSJoerg Sonnenberger 			}
4884d723e5aSJoerg Sonnenberger 
4894d723e5aSJoerg Sonnenberger 			if (p->depth_ == cdepth + 1)
4904d723e5aSJoerg Sonnenberger 				/* no change to this parent */
4914d723e5aSJoerg Sonnenberger 				return;
4924d723e5aSJoerg Sonnenberger 
4934d723e5aSJoerg Sonnenberger 			p->depth_ = cdepth + 1;
4944d723e5aSJoerg Sonnenberger 		}
4954d723e5aSJoerg Sonnenberger 
4964d723e5aSJoerg Sonnenberger 		p = p->parent_;
4974d723e5aSJoerg Sonnenberger 	}
4984d723e5aSJoerg Sonnenberger #else
4994d723e5aSJoerg Sonnenberger 	rm_class_t	*t;
5004d723e5aSJoerg Sonnenberger 
5014d723e5aSJoerg Sonnenberger 	if (cl->depth_ >= 1) {
5024d723e5aSJoerg Sonnenberger 		if (cl->children_ == NULL) {
5034d723e5aSJoerg Sonnenberger 			cl->depth_ = 0;
5044d723e5aSJoerg Sonnenberger 		} else if ((t = cl->children_) != NULL) {
5054d723e5aSJoerg Sonnenberger 			while (t != NULL) {
5064d723e5aSJoerg Sonnenberger 				if (t->children_ != NULL)
5074d723e5aSJoerg Sonnenberger 					rmc_depth_recompute(t);
5084d723e5aSJoerg Sonnenberger 				t = t->next_;
5094d723e5aSJoerg Sonnenberger 			}
5104d723e5aSJoerg Sonnenberger 		} else
5114d723e5aSJoerg Sonnenberger 			rmc_depth_compute(cl);
5124d723e5aSJoerg Sonnenberger 	}
5134d723e5aSJoerg Sonnenberger #endif
5144d723e5aSJoerg Sonnenberger }
5154d723e5aSJoerg Sonnenberger 
5164d723e5aSJoerg Sonnenberger /*
5174d723e5aSJoerg Sonnenberger  * void
5184d723e5aSJoerg Sonnenberger  * rmc_delete_class(struct rm_ifdat *ifdat, struct rm_class *cl) - This
5194d723e5aSJoerg Sonnenberger  *	function deletes a class from the link-sharing structure and frees
5204d723e5aSJoerg Sonnenberger  *	all resources associated with the class.
5214d723e5aSJoerg Sonnenberger  *
5224d723e5aSJoerg Sonnenberger  *	Returns: NONE
5234d723e5aSJoerg Sonnenberger  */
5244d723e5aSJoerg Sonnenberger 
5254d723e5aSJoerg Sonnenberger void
5264d723e5aSJoerg Sonnenberger rmc_delete_class(struct rm_ifdat *ifd, struct rm_class *cl)
5274d723e5aSJoerg Sonnenberger {
5284d723e5aSJoerg Sonnenberger 	struct rm_class *p, *head, *previous;
5294d723e5aSJoerg Sonnenberger 
5304d723e5aSJoerg Sonnenberger 	KKASSERT(cl->children_ == NULL);
5314d723e5aSJoerg Sonnenberger 
5324d723e5aSJoerg Sonnenberger 	if (cl->sleeping_)
5334d723e5aSJoerg Sonnenberger 		callout_stop(&cl->callout_);
5344d723e5aSJoerg Sonnenberger 
5350b31d406SSascha Wildner 	crit_enter();
536f96a3201SSepherosa Ziehau 
537f96a3201SSepherosa Ziehau 	if (ifd->pollcache_ == cl)
538f96a3201SSepherosa Ziehau 		ifd->pollcache_ = NULL;
539f96a3201SSepherosa Ziehau 
5404d723e5aSJoerg Sonnenberger 	/*
5414d723e5aSJoerg Sonnenberger 	 * Free packets in the packet queue.
5424d723e5aSJoerg Sonnenberger 	 * XXX - this may not be a desired behavior.  Packets should be
5434d723e5aSJoerg Sonnenberger 	 *		re-queued.
5444d723e5aSJoerg Sonnenberger 	 */
5454d723e5aSJoerg Sonnenberger 	rmc_dropall(cl);
5464d723e5aSJoerg Sonnenberger 
5474d723e5aSJoerg Sonnenberger 	/*
5484d723e5aSJoerg Sonnenberger 	 * If the class has a parent, then remove the class from the
5494d723e5aSJoerg Sonnenberger 	 * class from the parent's children chain.
5504d723e5aSJoerg Sonnenberger 	 */
5514d723e5aSJoerg Sonnenberger 	if (cl->parent_ != NULL) {
5524d723e5aSJoerg Sonnenberger 		head = cl->parent_->children_;
5534d723e5aSJoerg Sonnenberger 		p = previous = head;
5544d723e5aSJoerg Sonnenberger 		if (head->next_ == NULL) {
5554d723e5aSJoerg Sonnenberger 			KKASSERT(head == cl);
5564d723e5aSJoerg Sonnenberger 			cl->parent_->children_ = NULL;
5574d723e5aSJoerg Sonnenberger 			cl->parent_->leaf_ = 1;
5584d723e5aSJoerg Sonnenberger 		} else while (p != NULL) {
5594d723e5aSJoerg Sonnenberger 			if (p == cl) {
5604d723e5aSJoerg Sonnenberger 				if (cl == head)
5614d723e5aSJoerg Sonnenberger 					cl->parent_->children_ = cl->next_;
5624d723e5aSJoerg Sonnenberger 				else
5634d723e5aSJoerg Sonnenberger 					previous->next_ = cl->next_;
5644d723e5aSJoerg Sonnenberger 				cl->next_ = NULL;
5654d723e5aSJoerg Sonnenberger 				p = NULL;
5664d723e5aSJoerg Sonnenberger 			} else {
5674d723e5aSJoerg Sonnenberger 				previous = p;
5684d723e5aSJoerg Sonnenberger 				p = p->next_;
5694d723e5aSJoerg Sonnenberger 			}
5704d723e5aSJoerg Sonnenberger 		}
5714d723e5aSJoerg Sonnenberger 	}
5724d723e5aSJoerg Sonnenberger 
5734d723e5aSJoerg Sonnenberger 	/*
5744d723e5aSJoerg Sonnenberger 	 * Delete class from class priority peer list.
5754d723e5aSJoerg Sonnenberger 	 */
5764d723e5aSJoerg Sonnenberger 	if ((p = ifd->active_[cl->pri_]) != NULL) {
5774d723e5aSJoerg Sonnenberger 		/*
5784d723e5aSJoerg Sonnenberger 		 * If there is more than one member of this priority
5794d723e5aSJoerg Sonnenberger 		 * level, then look for class(cl) in the priority level.
5804d723e5aSJoerg Sonnenberger 		 */
5814d723e5aSJoerg Sonnenberger 		if (p != p->peer_) {
5824d723e5aSJoerg Sonnenberger 			while (p->peer_ != cl)
5834d723e5aSJoerg Sonnenberger 				p = p->peer_;
5844d723e5aSJoerg Sonnenberger 			p->peer_ = cl->peer_;
5854d723e5aSJoerg Sonnenberger 
5864d723e5aSJoerg Sonnenberger 			if (ifd->active_[cl->pri_] == cl)
5874d723e5aSJoerg Sonnenberger 				ifd->active_[cl->pri_] = cl->peer_;
5884d723e5aSJoerg Sonnenberger 		} else {
5894d723e5aSJoerg Sonnenberger 			KKASSERT(p == cl);
5904d723e5aSJoerg Sonnenberger 			ifd->active_[cl->pri_] = NULL;
5914d723e5aSJoerg Sonnenberger 		}
5924d723e5aSJoerg Sonnenberger 	}
5934d723e5aSJoerg Sonnenberger 
5944d723e5aSJoerg Sonnenberger 	/*
5954d723e5aSJoerg Sonnenberger 	 * Recompute the WRR weights.
5964d723e5aSJoerg Sonnenberger 	 */
5974d723e5aSJoerg Sonnenberger 	if (ifd->wrr_) {
5984d723e5aSJoerg Sonnenberger 		ifd->alloc_[cl->pri_] -= cl->allotment_;
5994d723e5aSJoerg Sonnenberger 		ifd->num_[cl->pri_]--;
6004d723e5aSJoerg Sonnenberger 		rmc_wrr_set_weights(ifd);
6014d723e5aSJoerg Sonnenberger 	}
6024d723e5aSJoerg Sonnenberger 
6034d723e5aSJoerg Sonnenberger 	/*
6044d723e5aSJoerg Sonnenberger 	 * Re-compute the depth of the tree.
6054d723e5aSJoerg Sonnenberger 	 */
6064d723e5aSJoerg Sonnenberger #if 1 /* ALTQ */
6074d723e5aSJoerg Sonnenberger 	rmc_depth_recompute(cl->parent_);
6084d723e5aSJoerg Sonnenberger #else
6094d723e5aSJoerg Sonnenberger 	rmc_depth_recompute(ifd->root_);
6104d723e5aSJoerg Sonnenberger #endif
6114d723e5aSJoerg Sonnenberger 
6120b31d406SSascha Wildner 	crit_exit();
6134d723e5aSJoerg Sonnenberger 
6144d723e5aSJoerg Sonnenberger 	/*
6154d723e5aSJoerg Sonnenberger 	 * Free the class structure.
6164d723e5aSJoerg Sonnenberger 	 */
6174d723e5aSJoerg Sonnenberger 	if (cl->red_ != NULL) {
6184d723e5aSJoerg Sonnenberger #ifdef ALTQ_RIO
6194d723e5aSJoerg Sonnenberger 		if (q_is_rio(cl->q_))
6204d723e5aSJoerg Sonnenberger 			rio_destroy((rio_t *)cl->red_);
6214d723e5aSJoerg Sonnenberger #endif
6224d723e5aSJoerg Sonnenberger #ifdef ALTQ_RED
6234d723e5aSJoerg Sonnenberger 		if (q_is_red(cl->q_))
6244d723e5aSJoerg Sonnenberger 			red_destroy(cl->red_);
6254d723e5aSJoerg Sonnenberger #endif
6264d723e5aSJoerg Sonnenberger 	}
627efda3bd0SMatthew Dillon 	kfree(cl->q_, M_ALTQ);
628efda3bd0SMatthew Dillon 	kfree(cl, M_ALTQ);
6294d723e5aSJoerg Sonnenberger }
6304d723e5aSJoerg Sonnenberger 
6314d723e5aSJoerg Sonnenberger /*
6324d723e5aSJoerg Sonnenberger  * void
6334d723e5aSJoerg Sonnenberger  * rmc_init(...) - Initialize the resource management data structures
6344d723e5aSJoerg Sonnenberger  *	associated with the output portion of interface 'ifp'.  'ifd' is
6354d723e5aSJoerg Sonnenberger  *	where the structures will be built (for backwards compatibility, the
6364d723e5aSJoerg Sonnenberger  *	structures aren't kept in the ifnet struct).  'nsecPerByte'
6374d723e5aSJoerg Sonnenberger  *	gives the link speed (inverse of bandwidth) in nanoseconds/byte.
6384d723e5aSJoerg Sonnenberger  *	'restart' is the driver-specific routine that the generic 'delay
6394d723e5aSJoerg Sonnenberger  *	until under limit' action will call to restart output.  `maxq'
6404d723e5aSJoerg Sonnenberger  *	is the queue size of the 'link' & 'default' classes.  'maxqueued'
6414d723e5aSJoerg Sonnenberger  *	is the maximum number of packets that the resource management
6424d723e5aSJoerg Sonnenberger  *	code will allow to be queued 'downstream' (this is typically 1).
6434d723e5aSJoerg Sonnenberger  *
6444d723e5aSJoerg Sonnenberger  *	Returns:	NONE
6454d723e5aSJoerg Sonnenberger  */
6464d723e5aSJoerg Sonnenberger 
6474d723e5aSJoerg Sonnenberger void
6484d723e5aSJoerg Sonnenberger rmc_init(struct ifaltq *ifq, struct rm_ifdat *ifd, u_int nsecPerByte,
6494d723e5aSJoerg Sonnenberger          void (*restart)(struct ifaltq *), int maxq, int maxqueued, u_int maxidle,
6504d723e5aSJoerg Sonnenberger 	 int minidle, u_int offtime, int flags)
6514d723e5aSJoerg Sonnenberger {
6524d723e5aSJoerg Sonnenberger 	int i, mtu;
6534d723e5aSJoerg Sonnenberger 
6544d723e5aSJoerg Sonnenberger 	/*
6554d723e5aSJoerg Sonnenberger 	 * Initialize the CBQ tracing/debug facility.
6564d723e5aSJoerg Sonnenberger 	 */
6574d723e5aSJoerg Sonnenberger 	CBQTRACEINIT();
6584d723e5aSJoerg Sonnenberger 
6594d723e5aSJoerg Sonnenberger 	bzero(ifd, sizeof (*ifd));
6604d723e5aSJoerg Sonnenberger 	mtu = ifq->altq_ifp->if_mtu;
6614d723e5aSJoerg Sonnenberger 	ifd->ifq_ = ifq;
6624d723e5aSJoerg Sonnenberger 	ifd->restart = restart;
6634d723e5aSJoerg Sonnenberger 	ifd->maxqueued_ = maxqueued;
6644d723e5aSJoerg Sonnenberger 	ifd->ns_per_byte_ = nsecPerByte;
6654d723e5aSJoerg Sonnenberger 	ifd->maxpkt_ = mtu;
6664d723e5aSJoerg Sonnenberger 	ifd->wrr_ = (flags & RMCF_WRR) ? 1 : 0;
6674d723e5aSJoerg Sonnenberger 	ifd->efficient_ = (flags & RMCF_EFFICIENT) ? 1 : 0;
6684d723e5aSJoerg Sonnenberger #if 1
6694d723e5aSJoerg Sonnenberger 	ifd->maxiftime_ = mtu * nsecPerByte / 1000 * 16;
6704d723e5aSJoerg Sonnenberger 	if (mtu * nsecPerByte > 10 * 1000000)
6714d723e5aSJoerg Sonnenberger 		ifd->maxiftime_ /= 4;
6724d723e5aSJoerg Sonnenberger #endif
6734d723e5aSJoerg Sonnenberger 
6744d723e5aSJoerg Sonnenberger 	reset_cutoff(ifd);
6754d723e5aSJoerg Sonnenberger 	CBQTRACE(rmc_init, 'INIT', ifd->cutoff_);
6764d723e5aSJoerg Sonnenberger 
6774d723e5aSJoerg Sonnenberger 	/*
6784d723e5aSJoerg Sonnenberger 	 * Initialize the CBQ's WRR state.
6794d723e5aSJoerg Sonnenberger 	 */
6804d723e5aSJoerg Sonnenberger 	for (i = 0; i < RM_MAXPRIO; i++) {
6814d723e5aSJoerg Sonnenberger 		ifd->alloc_[i] = 0;
6824d723e5aSJoerg Sonnenberger 		ifd->M_[i] = 0;
6834d723e5aSJoerg Sonnenberger 		ifd->num_[i] = 0;
6844d723e5aSJoerg Sonnenberger 		ifd->na_[i] = 0;
6854d723e5aSJoerg Sonnenberger 		ifd->active_[i] = NULL;
6864d723e5aSJoerg Sonnenberger 	}
6874d723e5aSJoerg Sonnenberger 
6884d723e5aSJoerg Sonnenberger 	/*
6894d723e5aSJoerg Sonnenberger 	 * Initialize current packet state.
6904d723e5aSJoerg Sonnenberger 	 */
6914d723e5aSJoerg Sonnenberger 	ifd->qi_ = 0;
6924d723e5aSJoerg Sonnenberger 	ifd->qo_ = 0;
6934d723e5aSJoerg Sonnenberger 	for (i = 0; i < RM_MAXQUEUED; i++) {
6944d723e5aSJoerg Sonnenberger 		ifd->class_[i] = NULL;
6954d723e5aSJoerg Sonnenberger 		ifd->curlen_[i] = 0;
6964d723e5aSJoerg Sonnenberger 		ifd->borrowed_[i] = NULL;
6974d723e5aSJoerg Sonnenberger 	}
6984d723e5aSJoerg Sonnenberger 
6994d723e5aSJoerg Sonnenberger 	/*
7004d723e5aSJoerg Sonnenberger 	 * Create the root class of the link-sharing structure.
7014d723e5aSJoerg Sonnenberger 	 */
7024d723e5aSJoerg Sonnenberger 	ifd->root_ = rmc_newclass(0, ifd, nsecPerByte, rmc_root_overlimit,
7034d723e5aSJoerg Sonnenberger 				  maxq, 0, 0, maxidle, minidle, offtime, 0, 0);
7044d723e5aSJoerg Sonnenberger 	if (ifd->root_ == NULL) {
7054b1cf444SSascha Wildner 		kprintf("rmc_init: root class not allocated\n");
7064d723e5aSJoerg Sonnenberger 		return ;
7074d723e5aSJoerg Sonnenberger 	}
7084d723e5aSJoerg Sonnenberger 	ifd->root_->depth_ = 0;
7094d723e5aSJoerg Sonnenberger }
7104d723e5aSJoerg Sonnenberger 
7114d723e5aSJoerg Sonnenberger /*
7124d723e5aSJoerg Sonnenberger  * void
7134d723e5aSJoerg Sonnenberger  * rmc_queue_packet(struct rm_class *cl, struct mbuf *m) - Add packet given by
7144d723e5aSJoerg Sonnenberger  *	mbuf 'm' to queue for resource class 'cl'.  This routine is called
7154d723e5aSJoerg Sonnenberger  *	by a driver's if_output routine.  This routine must be called with
7164d723e5aSJoerg Sonnenberger  *	output packet completion interrupts locked out (to avoid racing with
7174d723e5aSJoerg Sonnenberger  *	rmc_dequeue_next).
7184d723e5aSJoerg Sonnenberger  *
7194d723e5aSJoerg Sonnenberger  *	Returns:	0 on successful queueing
7204d723e5aSJoerg Sonnenberger  *			-1 when packet drop occurs
7214d723e5aSJoerg Sonnenberger  */
7224d723e5aSJoerg Sonnenberger int
7234d723e5aSJoerg Sonnenberger rmc_queue_packet(struct rm_class *cl, struct mbuf *m)
7244d723e5aSJoerg Sonnenberger {
7254d723e5aSJoerg Sonnenberger 	struct timeval now;
7264d723e5aSJoerg Sonnenberger 	struct rm_ifdat *ifd = cl->ifdat_;
7274d723e5aSJoerg Sonnenberger 	int cpri = cl->pri_;
7284d723e5aSJoerg Sonnenberger 	int is_empty = qempty(cl->q_);
7294d723e5aSJoerg Sonnenberger 
7304d723e5aSJoerg Sonnenberger 	RM_GETTIME(now);
7314d723e5aSJoerg Sonnenberger 	if (ifd->cutoff_ > 0) {
7324d723e5aSJoerg Sonnenberger 		if (TV_LT(&cl->undertime_, &now)) {
7334d723e5aSJoerg Sonnenberger 			if (ifd->cutoff_ > cl->depth_)
7344d723e5aSJoerg Sonnenberger 				ifd->cutoff_ = cl->depth_;
7354d723e5aSJoerg Sonnenberger 			CBQTRACE(rmc_queue_packet, 'ffoc', cl->depth_);
7364d723e5aSJoerg Sonnenberger 		}
7374d723e5aSJoerg Sonnenberger #if 1 /* ALTQ */
7384d723e5aSJoerg Sonnenberger 		else {
7394d723e5aSJoerg Sonnenberger 			/*
7404d723e5aSJoerg Sonnenberger 			 * the class is overlimit. if the class has
7414d723e5aSJoerg Sonnenberger 			 * underlimit ancestors, set cutoff to the lowest
7424d723e5aSJoerg Sonnenberger 			 * depth among them.
7434d723e5aSJoerg Sonnenberger 			 */
7444d723e5aSJoerg Sonnenberger 			struct rm_class *borrow = cl->borrow_;
7454d723e5aSJoerg Sonnenberger 
7464d723e5aSJoerg Sonnenberger 			while (borrow != NULL &&
7474d723e5aSJoerg Sonnenberger 			       borrow->depth_ < ifd->cutoff_) {
7484d723e5aSJoerg Sonnenberger 				if (TV_LT(&borrow->undertime_, &now)) {
7494d723e5aSJoerg Sonnenberger 					ifd->cutoff_ = borrow->depth_;
7504d723e5aSJoerg Sonnenberger 					CBQTRACE(rmc_queue_packet, 'ffob', ifd->cutoff_);
7514d723e5aSJoerg Sonnenberger 					break;
7524d723e5aSJoerg Sonnenberger 				}
7534d723e5aSJoerg Sonnenberger 				borrow = borrow->borrow_;
7544d723e5aSJoerg Sonnenberger 			}
7554d723e5aSJoerg Sonnenberger 		}
7564d723e5aSJoerg Sonnenberger #else /* !ALTQ */
7574d723e5aSJoerg Sonnenberger 		else if ((ifd->cutoff_ > 1) && cl->borrow_) {
7584d723e5aSJoerg Sonnenberger 			if (TV_LT(&cl->borrow_->undertime_, &now)) {
7594d723e5aSJoerg Sonnenberger 				ifd->cutoff_ = cl->borrow_->depth_;
7604d723e5aSJoerg Sonnenberger 				CBQTRACE(rmc_queue_packet, 'ffob',
7614d723e5aSJoerg Sonnenberger 					 cl->borrow_->depth_);
7624d723e5aSJoerg Sonnenberger 			}
7634d723e5aSJoerg Sonnenberger 		}
7644d723e5aSJoerg Sonnenberger #endif /* !ALTQ */
7654d723e5aSJoerg Sonnenberger 	}
7664d723e5aSJoerg Sonnenberger 
7674d723e5aSJoerg Sonnenberger 	if (_rmc_addq(cl, m) < 0)
7684d723e5aSJoerg Sonnenberger 		/* failed */
7694d723e5aSJoerg Sonnenberger 		return (-1);
7704d723e5aSJoerg Sonnenberger 
7714d723e5aSJoerg Sonnenberger 	if (is_empty) {
7724d723e5aSJoerg Sonnenberger 		CBQTRACE(rmc_queue_packet, 'ytpe', cl->stats_.handle);
7734d723e5aSJoerg Sonnenberger 		ifd->na_[cpri]++;
7744d723e5aSJoerg Sonnenberger 	}
7754d723e5aSJoerg Sonnenberger 
7764d723e5aSJoerg Sonnenberger 	if (qlen(cl->q_) > qlimit(cl->q_)) {
7774d723e5aSJoerg Sonnenberger 		/* note: qlimit can be set to 0 or 1 */
7784d723e5aSJoerg Sonnenberger 		rmc_drop_action(cl);
7794d723e5aSJoerg Sonnenberger 		return (-1);
7804d723e5aSJoerg Sonnenberger 	}
7814d723e5aSJoerg Sonnenberger 	return (0);
7824d723e5aSJoerg Sonnenberger }
7834d723e5aSJoerg Sonnenberger 
7844d723e5aSJoerg Sonnenberger /*
7854d723e5aSJoerg Sonnenberger  * void
7864d723e5aSJoerg Sonnenberger  * rmc_tl_satisfied(struct rm_ifdat *ifd, struct timeval *now) - Check all
7874d723e5aSJoerg Sonnenberger  *	classes to see if there are satified.
7884d723e5aSJoerg Sonnenberger  */
7894d723e5aSJoerg Sonnenberger 
7904d723e5aSJoerg Sonnenberger static void
7914d723e5aSJoerg Sonnenberger rmc_tl_satisfied(struct rm_ifdat *ifd, struct timeval *now)
7924d723e5aSJoerg Sonnenberger {
7934d723e5aSJoerg Sonnenberger 	int i;
7944d723e5aSJoerg Sonnenberger 	rm_class_t *p, *bp;
7954d723e5aSJoerg Sonnenberger 
7964d723e5aSJoerg Sonnenberger 	for (i = RM_MAXPRIO - 1; i >= 0; i--) {
7974d723e5aSJoerg Sonnenberger 		if ((bp = ifd->active_[i]) != NULL) {
7984d723e5aSJoerg Sonnenberger 			p = bp;
7994d723e5aSJoerg Sonnenberger 			do {
8004d723e5aSJoerg Sonnenberger 				if (!rmc_satisfied(p, now)) {
8014d723e5aSJoerg Sonnenberger 					ifd->cutoff_ = p->depth_;
8024d723e5aSJoerg Sonnenberger 					return;
8034d723e5aSJoerg Sonnenberger 				}
8044d723e5aSJoerg Sonnenberger 				p = p->peer_;
8054d723e5aSJoerg Sonnenberger 			} while (p != bp);
8064d723e5aSJoerg Sonnenberger 		}
8074d723e5aSJoerg Sonnenberger 	}
8084d723e5aSJoerg Sonnenberger 
8094d723e5aSJoerg Sonnenberger 	reset_cutoff(ifd);
8104d723e5aSJoerg Sonnenberger }
8114d723e5aSJoerg Sonnenberger 
8124d723e5aSJoerg Sonnenberger /*
8134d723e5aSJoerg Sonnenberger  * rmc_satisfied - Return 1 of the class is satisfied.  O, otherwise.
8144d723e5aSJoerg Sonnenberger  */
8154d723e5aSJoerg Sonnenberger 
8164d723e5aSJoerg Sonnenberger static int
8174d723e5aSJoerg Sonnenberger rmc_satisfied(struct rm_class *cl, struct timeval *now)
8184d723e5aSJoerg Sonnenberger {
8194d723e5aSJoerg Sonnenberger 	rm_class_t *p;
8204d723e5aSJoerg Sonnenberger 
8214d723e5aSJoerg Sonnenberger 	if (cl == NULL)
8224d723e5aSJoerg Sonnenberger 		return (1);
8234d723e5aSJoerg Sonnenberger 	if (TV_LT(now, &cl->undertime_))
8244d723e5aSJoerg Sonnenberger 		return (1);
8254d723e5aSJoerg Sonnenberger 	if (cl->depth_ == 0) {
8264d723e5aSJoerg Sonnenberger 		if (!cl->sleeping_ && (qlen(cl->q_) > cl->qthresh_))
8274d723e5aSJoerg Sonnenberger 			return (0);
8284d723e5aSJoerg Sonnenberger 		else
8294d723e5aSJoerg Sonnenberger 			return (1);
8304d723e5aSJoerg Sonnenberger 	}
8314d723e5aSJoerg Sonnenberger 	if (cl->children_ != NULL) {
8324d723e5aSJoerg Sonnenberger 		p = cl->children_;
8334d723e5aSJoerg Sonnenberger 		while (p != NULL) {
8344d723e5aSJoerg Sonnenberger 			if (!rmc_satisfied(p, now))
8354d723e5aSJoerg Sonnenberger 				return (0);
8364d723e5aSJoerg Sonnenberger 			p = p->next_;
8374d723e5aSJoerg Sonnenberger 		}
8384d723e5aSJoerg Sonnenberger 	}
8394d723e5aSJoerg Sonnenberger 
8404d723e5aSJoerg Sonnenberger 	return (1);
8414d723e5aSJoerg Sonnenberger }
8424d723e5aSJoerg Sonnenberger 
8434d723e5aSJoerg Sonnenberger /*
8444d723e5aSJoerg Sonnenberger  * Return 1 if class 'cl' is under limit or can borrow from a parent,
8454d723e5aSJoerg Sonnenberger  * 0 if overlimit.  As a side-effect, this routine will invoke the
8464d723e5aSJoerg Sonnenberger  * class overlimit action if the class if overlimit.
8474d723e5aSJoerg Sonnenberger  */
8484d723e5aSJoerg Sonnenberger 
8494d723e5aSJoerg Sonnenberger static int
8504d723e5aSJoerg Sonnenberger rmc_under_limit(struct rm_class *cl, struct timeval *now)
8514d723e5aSJoerg Sonnenberger {
8524d723e5aSJoerg Sonnenberger 	rm_class_t *p = cl;
8534d723e5aSJoerg Sonnenberger 	rm_class_t *top;
8544d723e5aSJoerg Sonnenberger 	struct rm_ifdat *ifd = cl->ifdat_;
8554d723e5aSJoerg Sonnenberger 
8564d723e5aSJoerg Sonnenberger 	ifd->borrowed_[ifd->qi_] = NULL;
8574d723e5aSJoerg Sonnenberger 	/*
8584d723e5aSJoerg Sonnenberger 	 * If cl is the root class, then always return that it is
8594d723e5aSJoerg Sonnenberger 	 * underlimit.  Otherwise, check to see if the class is underlimit.
8604d723e5aSJoerg Sonnenberger 	 */
8614d723e5aSJoerg Sonnenberger 	if (cl->parent_ == NULL)
8624d723e5aSJoerg Sonnenberger 		return (1);
8634d723e5aSJoerg Sonnenberger 
8644d723e5aSJoerg Sonnenberger 	if (cl->sleeping_) {
8654d723e5aSJoerg Sonnenberger 		if (TV_LT(now, &cl->undertime_))
8664d723e5aSJoerg Sonnenberger 			return (0);
8674d723e5aSJoerg Sonnenberger 
8684d723e5aSJoerg Sonnenberger 		callout_stop(&cl->callout_);
8694d723e5aSJoerg Sonnenberger 		cl->sleeping_ = 0;
8704d723e5aSJoerg Sonnenberger 		cl->undertime_.tv_sec = 0;
8714d723e5aSJoerg Sonnenberger 		return (1);
8724d723e5aSJoerg Sonnenberger 	}
8734d723e5aSJoerg Sonnenberger 
8744d723e5aSJoerg Sonnenberger 	top = NULL;
8754d723e5aSJoerg Sonnenberger 	while (cl->undertime_.tv_sec && TV_LT(now, &cl->undertime_)) {
8764d723e5aSJoerg Sonnenberger 		if (((cl = cl->borrow_) == NULL) ||
8774d723e5aSJoerg Sonnenberger 		    (cl->depth_ > ifd->cutoff_)) {
8784d723e5aSJoerg Sonnenberger #ifdef ADJUST_CUTOFF
8794d723e5aSJoerg Sonnenberger 			if (cl != NULL)
8804d723e5aSJoerg Sonnenberger 				/* cutoff is taking effect, just
8814d723e5aSJoerg Sonnenberger 				   return false without calling
8824d723e5aSJoerg Sonnenberger 				   the delay action. */
8834d723e5aSJoerg Sonnenberger 				return (0);
8844d723e5aSJoerg Sonnenberger #endif
8854d723e5aSJoerg Sonnenberger #ifdef BORROW_OFFTIME
8864d723e5aSJoerg Sonnenberger 			/*
8874d723e5aSJoerg Sonnenberger 			 * check if the class can borrow offtime too.
8884d723e5aSJoerg Sonnenberger 			 * borrow offtime from the top of the borrow
8894d723e5aSJoerg Sonnenberger 			 * chain if the top class is not overloaded.
8904d723e5aSJoerg Sonnenberger 			 */
8914d723e5aSJoerg Sonnenberger 			if (cl != NULL) {
8924d723e5aSJoerg Sonnenberger 				/* cutoff is taking effect, use this class as top. */
8934d723e5aSJoerg Sonnenberger 				top = cl;
8944d723e5aSJoerg Sonnenberger 				CBQTRACE(rmc_under_limit, 'ffou', ifd->cutoff_);
8954d723e5aSJoerg Sonnenberger 			}
8964d723e5aSJoerg Sonnenberger 			if (top != NULL && top->avgidle_ == top->minidle_)
8974d723e5aSJoerg Sonnenberger 				top = NULL;
8984d723e5aSJoerg Sonnenberger 			p->overtime_ = *now;
8994d723e5aSJoerg Sonnenberger 			(p->overlimit)(p, top);
9004d723e5aSJoerg Sonnenberger #else
9014d723e5aSJoerg Sonnenberger 			p->overtime_ = *now;
9024d723e5aSJoerg Sonnenberger 			(p->overlimit)(p, NULL);
9034d723e5aSJoerg Sonnenberger #endif
9044d723e5aSJoerg Sonnenberger 			return (0);
9054d723e5aSJoerg Sonnenberger 		}
9064d723e5aSJoerg Sonnenberger 		top = cl;
9074d723e5aSJoerg Sonnenberger 	}
9084d723e5aSJoerg Sonnenberger 
9094d723e5aSJoerg Sonnenberger 	if (cl != p)
9104d723e5aSJoerg Sonnenberger 		ifd->borrowed_[ifd->qi_] = cl;
9114d723e5aSJoerg Sonnenberger 	return (1);
9124d723e5aSJoerg Sonnenberger }
9134d723e5aSJoerg Sonnenberger 
9144d723e5aSJoerg Sonnenberger /*
9154d723e5aSJoerg Sonnenberger  * _rmc_wrr_dequeue_next() - This is scheduler for WRR as opposed to
9164d723e5aSJoerg Sonnenberger  *	Packet-by-packet round robin.
9174d723e5aSJoerg Sonnenberger  *
9184d723e5aSJoerg Sonnenberger  * The heart of the weighted round-robin scheduler, which decides which
9194d723e5aSJoerg Sonnenberger  * class next gets to send a packet.  Highest priority first, then
9204d723e5aSJoerg Sonnenberger  * weighted round-robin within priorites.
9214d723e5aSJoerg Sonnenberger  *
9224d723e5aSJoerg Sonnenberger  * Each able-to-send class gets to send until its byte allocation is
9234d723e5aSJoerg Sonnenberger  * exhausted.  Thus, the active pointer is only changed after a class has
9244d723e5aSJoerg Sonnenberger  * exhausted its allocation.
9254d723e5aSJoerg Sonnenberger  *
9264d723e5aSJoerg Sonnenberger  * If the scheduler finds no class that is underlimit or able to borrow,
9274d723e5aSJoerg Sonnenberger  * then the first class found that had a nonzero queue and is allowed to
9284d723e5aSJoerg Sonnenberger  * borrow gets to send.
9294d723e5aSJoerg Sonnenberger  */
9304d723e5aSJoerg Sonnenberger 
9314d723e5aSJoerg Sonnenberger static struct mbuf *
9324d723e5aSJoerg Sonnenberger _rmc_wrr_dequeue_next(struct rm_ifdat *ifd, int op)
9334d723e5aSJoerg Sonnenberger {
9344d723e5aSJoerg Sonnenberger 	struct rm_class *cl = NULL, *first = NULL;
9354d723e5aSJoerg Sonnenberger 	u_int deficit;
9364d723e5aSJoerg Sonnenberger 	int cpri;
9374d723e5aSJoerg Sonnenberger 	struct mbuf *m;
9384d723e5aSJoerg Sonnenberger 	struct timeval now;
9394d723e5aSJoerg Sonnenberger 
9404d723e5aSJoerg Sonnenberger 	RM_GETTIME(now);
9414d723e5aSJoerg Sonnenberger 
9424d723e5aSJoerg Sonnenberger 	/*
9434d723e5aSJoerg Sonnenberger 	 * if the driver polls the top of the queue and then removes
9444d723e5aSJoerg Sonnenberger 	 * the polled packet, we must return the same packet.
9454d723e5aSJoerg Sonnenberger 	 */
9464d723e5aSJoerg Sonnenberger 	if (op == ALTDQ_REMOVE && ifd->pollcache_) {
9474d723e5aSJoerg Sonnenberger 		cl = ifd->pollcache_;
9484d723e5aSJoerg Sonnenberger 		cpri = cl->pri_;
9494d723e5aSJoerg Sonnenberger 		if (ifd->efficient_) {
9504d723e5aSJoerg Sonnenberger 			/* check if this class is overlimit */
9514d723e5aSJoerg Sonnenberger 			if (cl->undertime_.tv_sec != 0 &&
9524d723e5aSJoerg Sonnenberger 			    rmc_under_limit(cl, &now) == 0)
9534d723e5aSJoerg Sonnenberger 				first = cl;
9544d723e5aSJoerg Sonnenberger 		}
9554d723e5aSJoerg Sonnenberger 		ifd->pollcache_ = NULL;
9564d723e5aSJoerg Sonnenberger 		goto _wrr_out;
9574d723e5aSJoerg Sonnenberger 	}
9584d723e5aSJoerg Sonnenberger 	/* mode == ALTDQ_POLL || pollcache == NULL */
9594d723e5aSJoerg Sonnenberger 	ifd->pollcache_ = NULL;
9604d723e5aSJoerg Sonnenberger 	ifd->borrowed_[ifd->qi_] = NULL;
9614d723e5aSJoerg Sonnenberger #ifdef ADJUST_CUTOFF
9624d723e5aSJoerg Sonnenberger  _again:
9634d723e5aSJoerg Sonnenberger #endif
9644d723e5aSJoerg Sonnenberger 	for (cpri = RM_MAXPRIO - 1; cpri >= 0; cpri--) {
9654d723e5aSJoerg Sonnenberger 		if (ifd->na_[cpri] == 0)
9664d723e5aSJoerg Sonnenberger 			continue;
9674d723e5aSJoerg Sonnenberger 		deficit = 0;
9684d723e5aSJoerg Sonnenberger 		/*
9694d723e5aSJoerg Sonnenberger 		 * Loop through twice for a priority level, if some class
9704d723e5aSJoerg Sonnenberger 		 * was unable to send a packet the first round because
9714d723e5aSJoerg Sonnenberger 		 * of the weighted round-robin mechanism.
9724d723e5aSJoerg Sonnenberger 		 * During the second loop at this level, deficit==2.
9734d723e5aSJoerg Sonnenberger 		 * (This second loop is not needed if for every class,
9744d723e5aSJoerg Sonnenberger 		 * "M[cl->pri_])" times "cl->allotment" is greater than
9754d723e5aSJoerg Sonnenberger 		 * the byte size for the largest packet in the class.)
9764d723e5aSJoerg Sonnenberger 		 */
9774d723e5aSJoerg Sonnenberger  _wrr_loop:
9784d723e5aSJoerg Sonnenberger 		cl = ifd->active_[cpri];
9794d723e5aSJoerg Sonnenberger 		KKASSERT(cl != NULL);
9804d723e5aSJoerg Sonnenberger 		do {
9814d723e5aSJoerg Sonnenberger 			if ((deficit < 2) && (cl->bytes_alloc_ <= 0))
9824d723e5aSJoerg Sonnenberger 				cl->bytes_alloc_ += cl->w_allotment_;
9834d723e5aSJoerg Sonnenberger 			if (!qempty(cl->q_)) {
9844d723e5aSJoerg Sonnenberger 				if ((cl->undertime_.tv_sec == 0) ||
9854d723e5aSJoerg Sonnenberger 				    rmc_under_limit(cl, &now)) {
9864d723e5aSJoerg Sonnenberger 					if (cl->bytes_alloc_ > 0 || deficit > 1)
9874d723e5aSJoerg Sonnenberger 						goto _wrr_out;
9884d723e5aSJoerg Sonnenberger 
9894d723e5aSJoerg Sonnenberger 					/* underlimit but no alloc */
9904d723e5aSJoerg Sonnenberger 					deficit = 1;
9914d723e5aSJoerg Sonnenberger #if 1
9924d723e5aSJoerg Sonnenberger 					ifd->borrowed_[ifd->qi_] = NULL;
9934d723e5aSJoerg Sonnenberger #endif
9944d723e5aSJoerg Sonnenberger 				}
9954d723e5aSJoerg Sonnenberger 				else if (first == NULL && cl->borrow_ != NULL)
9964d723e5aSJoerg Sonnenberger 					first = cl; /* borrowing candidate */
9974d723e5aSJoerg Sonnenberger 			}
9984d723e5aSJoerg Sonnenberger 
9994d723e5aSJoerg Sonnenberger 			cl->bytes_alloc_ = 0;
10004d723e5aSJoerg Sonnenberger 			cl = cl->peer_;
10014d723e5aSJoerg Sonnenberger 		} while (cl != ifd->active_[cpri]);
10024d723e5aSJoerg Sonnenberger 
10034d723e5aSJoerg Sonnenberger 		if (deficit == 1) {
10044d723e5aSJoerg Sonnenberger 			/* first loop found an underlimit class with deficit */
10054d723e5aSJoerg Sonnenberger 			/* Loop on same priority level, with new deficit.  */
10064d723e5aSJoerg Sonnenberger 			deficit = 2;
10074d723e5aSJoerg Sonnenberger 			goto _wrr_loop;
10084d723e5aSJoerg Sonnenberger 		}
10094d723e5aSJoerg Sonnenberger 	}
10104d723e5aSJoerg Sonnenberger 
10114d723e5aSJoerg Sonnenberger #ifdef ADJUST_CUTOFF
10124d723e5aSJoerg Sonnenberger 	/*
10134d723e5aSJoerg Sonnenberger 	 * no underlimit class found.  if cutoff is taking effect,
10144d723e5aSJoerg Sonnenberger 	 * increase cutoff and try again.
10154d723e5aSJoerg Sonnenberger 	 */
10164d723e5aSJoerg Sonnenberger 	if (first != NULL && ifd->cutoff_ < ifd->root_->depth_) {
10174d723e5aSJoerg Sonnenberger 		ifd->cutoff_++;
10184d723e5aSJoerg Sonnenberger 		CBQTRACE(_rmc_wrr_dequeue_next, 'ojda', ifd->cutoff_);
10194d723e5aSJoerg Sonnenberger 		goto _again;
10204d723e5aSJoerg Sonnenberger 	}
10214d723e5aSJoerg Sonnenberger #endif /* ADJUST_CUTOFF */
10224d723e5aSJoerg Sonnenberger 	/*
10234d723e5aSJoerg Sonnenberger 	 * If LINK_EFFICIENCY is turned on, then the first overlimit
10244d723e5aSJoerg Sonnenberger 	 * class we encounter will send a packet if all the classes
10254d723e5aSJoerg Sonnenberger 	 * of the link-sharing structure are overlimit.
10264d723e5aSJoerg Sonnenberger 	 */
10274d723e5aSJoerg Sonnenberger 	reset_cutoff(ifd);
10284d723e5aSJoerg Sonnenberger 	CBQTRACE(_rmc_wrr_dequeue_next, 'otsr', ifd->cutoff_);
10294d723e5aSJoerg Sonnenberger 
10304d723e5aSJoerg Sonnenberger 	if (!ifd->efficient_ || first == NULL)
10314d723e5aSJoerg Sonnenberger 		return (NULL);
10324d723e5aSJoerg Sonnenberger 
10334d723e5aSJoerg Sonnenberger 	cl = first;
10344d723e5aSJoerg Sonnenberger 	cpri = cl->pri_;
10354d723e5aSJoerg Sonnenberger #if 0	/* too time-consuming for nothing */
10364d723e5aSJoerg Sonnenberger 	if (cl->sleeping_)
10374d723e5aSJoerg Sonnenberger 		callout_stop(&cl->callout_);
10384d723e5aSJoerg Sonnenberger 	cl->sleeping_ = 0;
10394d723e5aSJoerg Sonnenberger 	cl->undertime_.tv_sec = 0;
10404d723e5aSJoerg Sonnenberger #endif
10414d723e5aSJoerg Sonnenberger 	ifd->borrowed_[ifd->qi_] = cl->borrow_;
10424d723e5aSJoerg Sonnenberger 	ifd->cutoff_ = cl->borrow_->depth_;
10434d723e5aSJoerg Sonnenberger 
10444d723e5aSJoerg Sonnenberger 	/*
10454d723e5aSJoerg Sonnenberger 	 * Deque the packet and do the book keeping...
10464d723e5aSJoerg Sonnenberger 	 */
10474d723e5aSJoerg Sonnenberger  _wrr_out:
10484d723e5aSJoerg Sonnenberger 	if (op == ALTDQ_REMOVE) {
10494d723e5aSJoerg Sonnenberger 		m = _rmc_getq(cl);
10504d723e5aSJoerg Sonnenberger 		if (m == NULL)
10514d723e5aSJoerg Sonnenberger 			panic("_rmc_wrr_dequeue_next");
10524d723e5aSJoerg Sonnenberger 		if (qempty(cl->q_))
10534d723e5aSJoerg Sonnenberger 			ifd->na_[cpri]--;
10544d723e5aSJoerg Sonnenberger 
10554d723e5aSJoerg Sonnenberger 		/*
10564d723e5aSJoerg Sonnenberger 		 * Update class statistics and link data.
10574d723e5aSJoerg Sonnenberger 		 */
10584d723e5aSJoerg Sonnenberger 		if (cl->bytes_alloc_ > 0)
10594d723e5aSJoerg Sonnenberger 			cl->bytes_alloc_ -= m_pktlen(m);
10604d723e5aSJoerg Sonnenberger 
10614d723e5aSJoerg Sonnenberger 		if ((cl->bytes_alloc_ <= 0) || first == cl)
10624d723e5aSJoerg Sonnenberger 			ifd->active_[cl->pri_] = cl->peer_;
10634d723e5aSJoerg Sonnenberger 		else
10644d723e5aSJoerg Sonnenberger 			ifd->active_[cl->pri_] = cl;
10654d723e5aSJoerg Sonnenberger 
10664d723e5aSJoerg Sonnenberger 		ifd->class_[ifd->qi_] = cl;
10674d723e5aSJoerg Sonnenberger 		ifd->curlen_[ifd->qi_] = m_pktlen(m);
10684d723e5aSJoerg Sonnenberger 		ifd->now_[ifd->qi_] = now;
10694d723e5aSJoerg Sonnenberger 		ifd->qi_ = (ifd->qi_ + 1) % ifd->maxqueued_;
10704d723e5aSJoerg Sonnenberger 		ifd->queued_++;
10714d723e5aSJoerg Sonnenberger 	} else {
10724d723e5aSJoerg Sonnenberger 		/* mode == ALTDQ_PPOLL */
10734d723e5aSJoerg Sonnenberger 		m = _rmc_pollq(cl);
1074893c125dSSepherosa Ziehau #ifdef foo
1075893c125dSSepherosa Ziehau 		/*
1076893c125dSSepherosa Ziehau 		 * Don't use poll cache; the poll/dequeue
1077893c125dSSepherosa Ziehau 		 * model is no longer applicable to SMP
1078893c125dSSepherosa Ziehau 		 * system.  e.g.
1079893c125dSSepherosa Ziehau 		 *    CPU-A            CPU-B
1080893c125dSSepherosa Ziehau 		 *      :                :
1081893c125dSSepherosa Ziehau 		 *    poll               :
1082893c125dSSepherosa Ziehau 		 *      :              poll
1083893c125dSSepherosa Ziehau 		 *    dequeue (+)        :
1084893c125dSSepherosa Ziehau 		 *
1085893c125dSSepherosa Ziehau 		 * The dequeue at (+) will hit the poll
1086893c125dSSepherosa Ziehau 		 * cache set by CPU-B.
1087893c125dSSepherosa Ziehau 		 */
10884d723e5aSJoerg Sonnenberger 		ifd->pollcache_ = cl;
1089893c125dSSepherosa Ziehau #endif
10904d723e5aSJoerg Sonnenberger 	}
10914d723e5aSJoerg Sonnenberger 	return (m);
10924d723e5aSJoerg Sonnenberger }
10934d723e5aSJoerg Sonnenberger 
10944d723e5aSJoerg Sonnenberger /*
10954d723e5aSJoerg Sonnenberger  * Dequeue & return next packet from the highest priority class that
10964d723e5aSJoerg Sonnenberger  * has a packet to send & has enough allocation to send it.  This
10974d723e5aSJoerg Sonnenberger  * routine is called by a driver whenever it needs a new packet to
10984d723e5aSJoerg Sonnenberger  * output.
10994d723e5aSJoerg Sonnenberger  */
11004d723e5aSJoerg Sonnenberger static struct mbuf *
11014d723e5aSJoerg Sonnenberger _rmc_prr_dequeue_next(struct rm_ifdat *ifd, int op)
11024d723e5aSJoerg Sonnenberger {
11034d723e5aSJoerg Sonnenberger 	struct mbuf *m;
11044d723e5aSJoerg Sonnenberger 	int cpri;
11054d723e5aSJoerg Sonnenberger 	struct rm_class *cl, *first = NULL;
11064d723e5aSJoerg Sonnenberger 	struct timeval now;
11074d723e5aSJoerg Sonnenberger 
11084d723e5aSJoerg Sonnenberger 	RM_GETTIME(now);
11094d723e5aSJoerg Sonnenberger 
11104d723e5aSJoerg Sonnenberger 	/*
11114d723e5aSJoerg Sonnenberger 	 * if the driver polls the top of the queue and then removes
11124d723e5aSJoerg Sonnenberger 	 * the polled packet, we must return the same packet.
11134d723e5aSJoerg Sonnenberger 	 */
11144d723e5aSJoerg Sonnenberger 	if (op == ALTDQ_REMOVE && ifd->pollcache_) {
11154d723e5aSJoerg Sonnenberger 		cl = ifd->pollcache_;
11164d723e5aSJoerg Sonnenberger 		cpri = cl->pri_;
11174d723e5aSJoerg Sonnenberger 		ifd->pollcache_ = NULL;
11184d723e5aSJoerg Sonnenberger 		goto _prr_out;
1119*0c77d800SSascha Wildner 	}
11204d723e5aSJoerg Sonnenberger 	/* mode == ALTDQ_POLL || pollcache == NULL */
11214d723e5aSJoerg Sonnenberger 	ifd->pollcache_ = NULL;
11224d723e5aSJoerg Sonnenberger 	ifd->borrowed_[ifd->qi_] = NULL;
11234d723e5aSJoerg Sonnenberger #ifdef ADJUST_CUTOFF
11244d723e5aSJoerg Sonnenberger  _again:
11254d723e5aSJoerg Sonnenberger #endif
11264d723e5aSJoerg Sonnenberger 	for (cpri = RM_MAXPRIO - 1; cpri >= 0; cpri--) {
11274d723e5aSJoerg Sonnenberger 		if (ifd->na_[cpri] == 0)
11284d723e5aSJoerg Sonnenberger 			continue;
11294d723e5aSJoerg Sonnenberger 		cl = ifd->active_[cpri];
11304d723e5aSJoerg Sonnenberger 		KKASSERT(cl != NULL);
11314d723e5aSJoerg Sonnenberger 		do {
11324d723e5aSJoerg Sonnenberger 			if (!qempty(cl->q_)) {
11334d723e5aSJoerg Sonnenberger 				if ((cl->undertime_.tv_sec == 0) ||
11344d723e5aSJoerg Sonnenberger 				    rmc_under_limit(cl, &now))
11354d723e5aSJoerg Sonnenberger 					goto _prr_out;
11364d723e5aSJoerg Sonnenberger 				if (first == NULL && cl->borrow_ != NULL)
11374d723e5aSJoerg Sonnenberger 					first = cl;
11384d723e5aSJoerg Sonnenberger 			}
11394d723e5aSJoerg Sonnenberger 			cl = cl->peer_;
11404d723e5aSJoerg Sonnenberger 		} while (cl != ifd->active_[cpri]);
11414d723e5aSJoerg Sonnenberger 	}
11424d723e5aSJoerg Sonnenberger 
11434d723e5aSJoerg Sonnenberger #ifdef ADJUST_CUTOFF
11444d723e5aSJoerg Sonnenberger 	/*
11454d723e5aSJoerg Sonnenberger 	 * no underlimit class found.  if cutoff is taking effect, increase
11464d723e5aSJoerg Sonnenberger 	 * cutoff and try again.
11474d723e5aSJoerg Sonnenberger 	 */
11484d723e5aSJoerg Sonnenberger 	if (first != NULL && ifd->cutoff_ < ifd->root_->depth_) {
11494d723e5aSJoerg Sonnenberger 		ifd->cutoff_++;
11504d723e5aSJoerg Sonnenberger 		goto _again;
11514d723e5aSJoerg Sonnenberger 	}
11524d723e5aSJoerg Sonnenberger #endif /* ADJUST_CUTOFF */
11534d723e5aSJoerg Sonnenberger 	/*
11544d723e5aSJoerg Sonnenberger 	 * If LINK_EFFICIENCY is turned on, then the first overlimit
11554d723e5aSJoerg Sonnenberger 	 * class we encounter will send a packet if all the classes
11564d723e5aSJoerg Sonnenberger 	 * of the link-sharing structure are overlimit.
11574d723e5aSJoerg Sonnenberger 	 */
11584d723e5aSJoerg Sonnenberger 	reset_cutoff(ifd);
11594d723e5aSJoerg Sonnenberger 	if (!ifd->efficient_ || first == NULL)
11604d723e5aSJoerg Sonnenberger 		return (NULL);
11614d723e5aSJoerg Sonnenberger 
11624d723e5aSJoerg Sonnenberger 	cl = first;
11634d723e5aSJoerg Sonnenberger 	cpri = cl->pri_;
11644d723e5aSJoerg Sonnenberger #if 0	/* too time-consuming for nothing */
11654d723e5aSJoerg Sonnenberger 	if (cl->sleeping_)
11664d723e5aSJoerg Sonnenberger 		callout_stop(&cl->callout_);
11674d723e5aSJoerg Sonnenberger 	cl->sleeping_ = 0;
11684d723e5aSJoerg Sonnenberger 	cl->undertime_.tv_sec = 0;
11694d723e5aSJoerg Sonnenberger #endif
11704d723e5aSJoerg Sonnenberger 	ifd->borrowed_[ifd->qi_] = cl->borrow_;
11714d723e5aSJoerg Sonnenberger 	ifd->cutoff_ = cl->borrow_->depth_;
11724d723e5aSJoerg Sonnenberger 
11734d723e5aSJoerg Sonnenberger 	/*
11744d723e5aSJoerg Sonnenberger 	 * Deque the packet and do the book keeping...
11754d723e5aSJoerg Sonnenberger 	 */
11764d723e5aSJoerg Sonnenberger  _prr_out:
11774d723e5aSJoerg Sonnenberger 	if (op == ALTDQ_REMOVE) {
11784d723e5aSJoerg Sonnenberger 		m = _rmc_getq(cl);
11794d723e5aSJoerg Sonnenberger 		if (m == NULL)
11804d723e5aSJoerg Sonnenberger 			panic("_rmc_prr_dequeue_next");
11814d723e5aSJoerg Sonnenberger 		if (qempty(cl->q_))
11824d723e5aSJoerg Sonnenberger 			ifd->na_[cpri]--;
11834d723e5aSJoerg Sonnenberger 
11844d723e5aSJoerg Sonnenberger 		ifd->active_[cpri] = cl->peer_;
11854d723e5aSJoerg Sonnenberger 
11864d723e5aSJoerg Sonnenberger 		ifd->class_[ifd->qi_] = cl;
11874d723e5aSJoerg Sonnenberger 		ifd->curlen_[ifd->qi_] = m_pktlen(m);
11884d723e5aSJoerg Sonnenberger 		ifd->now_[ifd->qi_] = now;
11894d723e5aSJoerg Sonnenberger 		ifd->qi_ = (ifd->qi_ + 1) % ifd->maxqueued_;
11904d723e5aSJoerg Sonnenberger 		ifd->queued_++;
11914d723e5aSJoerg Sonnenberger 	} else {
11924d723e5aSJoerg Sonnenberger 		/* mode == ALTDQ_POLL */
11934d723e5aSJoerg Sonnenberger 		m = _rmc_pollq(cl);
1194893c125dSSepherosa Ziehau #ifdef foo
1195893c125dSSepherosa Ziehau 		/*
1196893c125dSSepherosa Ziehau 		 * Don't use poll cache; the poll/dequeue
1197893c125dSSepherosa Ziehau 		 * model is no longer applicable to SMP
1198893c125dSSepherosa Ziehau 		 * system.  e.g.
1199893c125dSSepherosa Ziehau 		 *    CPU-A            CPU-B
1200893c125dSSepherosa Ziehau 		 *      :                :
1201893c125dSSepherosa Ziehau 		 *    poll               :
1202893c125dSSepherosa Ziehau 		 *      :              poll
1203893c125dSSepherosa Ziehau 		 *    dequeue (+)        :
1204893c125dSSepherosa Ziehau 		 *
1205893c125dSSepherosa Ziehau 		 * The dequeue at (+) will hit the poll
1206893c125dSSepherosa Ziehau 		 * cache set by CPU-B.
1207893c125dSSepherosa Ziehau 		 */
12084d723e5aSJoerg Sonnenberger 		ifd->pollcache_ = cl;
1209893c125dSSepherosa Ziehau #endif
12104d723e5aSJoerg Sonnenberger 	}
12114d723e5aSJoerg Sonnenberger 	return (m);
12124d723e5aSJoerg Sonnenberger }
12134d723e5aSJoerg Sonnenberger 
12144d723e5aSJoerg Sonnenberger /*
12154d723e5aSJoerg Sonnenberger  * struct mbuf *
12164d723e5aSJoerg Sonnenberger  * rmc_dequeue_next(struct rm_ifdat *ifd, struct timeval *now) - this function
12174d723e5aSJoerg Sonnenberger  *	is invoked by the packet driver to get the next packet to be
12184d723e5aSJoerg Sonnenberger  *	dequeued and output on the link.  If WRR is enabled, then the
12194d723e5aSJoerg Sonnenberger  *	WRR dequeue next routine will determine the next packet to sent.
12204d723e5aSJoerg Sonnenberger  *	Otherwise, packet-by-packet round robin is invoked.
12214d723e5aSJoerg Sonnenberger  *
12224d723e5aSJoerg Sonnenberger  *	Returns:	NULL, if a packet is not available or if all
12234d723e5aSJoerg Sonnenberger  *			classes are overlimit.
12244d723e5aSJoerg Sonnenberger  *
12254d723e5aSJoerg Sonnenberger  *			Otherwise, Pointer to the next packet.
12264d723e5aSJoerg Sonnenberger  */
12274d723e5aSJoerg Sonnenberger 
12284d723e5aSJoerg Sonnenberger struct mbuf *
12294d723e5aSJoerg Sonnenberger rmc_dequeue_next(struct rm_ifdat *ifd, int mode)
12304d723e5aSJoerg Sonnenberger {
12314d723e5aSJoerg Sonnenberger 	if (ifd->queued_ >= ifd->maxqueued_)
12324d723e5aSJoerg Sonnenberger 		return (NULL);
12334d723e5aSJoerg Sonnenberger 	else if (ifd->wrr_)
12344d723e5aSJoerg Sonnenberger 		return (_rmc_wrr_dequeue_next(ifd, mode));
12354d723e5aSJoerg Sonnenberger 	else
12364d723e5aSJoerg Sonnenberger 		return (_rmc_prr_dequeue_next(ifd, mode));
12374d723e5aSJoerg Sonnenberger }
12384d723e5aSJoerg Sonnenberger 
12394d723e5aSJoerg Sonnenberger /*
12404d723e5aSJoerg Sonnenberger  * Update the utilization estimate for the packet that just completed.
12414d723e5aSJoerg Sonnenberger  * The packet's class & the parent(s) of that class all get their
12424d723e5aSJoerg Sonnenberger  * estimators updated.  This routine is called by the driver's output-
12434d723e5aSJoerg Sonnenberger  * packet-completion interrupt service routine.
12444d723e5aSJoerg Sonnenberger  */
12454d723e5aSJoerg Sonnenberger 
12464d723e5aSJoerg Sonnenberger /*
12474d723e5aSJoerg Sonnenberger  * a macro to approximate "divide by 1000" that gives 0.000999,
12484d723e5aSJoerg Sonnenberger  * if a value has enough effective digits.
12494d723e5aSJoerg Sonnenberger  * (on pentium, mul takes 9 cycles but div takes 46!)
12504d723e5aSJoerg Sonnenberger  */
12514d723e5aSJoerg Sonnenberger #define	NSEC_TO_USEC(t)	(((t) >> 10) + ((t) >> 16) + ((t) >> 17))
12524d723e5aSJoerg Sonnenberger void
12534d723e5aSJoerg Sonnenberger rmc_update_class_util(struct rm_ifdat *ifd)
12544d723e5aSJoerg Sonnenberger {
12554d723e5aSJoerg Sonnenberger 	int idle, avgidle, pktlen;
12564d723e5aSJoerg Sonnenberger 	int pkt_time, tidle;
12574d723e5aSJoerg Sonnenberger 	rm_class_t *cl, *borrowed;
12584d723e5aSJoerg Sonnenberger 	rm_class_t *borrows;
12594d723e5aSJoerg Sonnenberger 	struct timeval *nowp;
12604d723e5aSJoerg Sonnenberger 
12614d723e5aSJoerg Sonnenberger 	/*
12624d723e5aSJoerg Sonnenberger 	 * Get the most recent completed class.
12634d723e5aSJoerg Sonnenberger 	 */
12644d723e5aSJoerg Sonnenberger 	if ((cl = ifd->class_[ifd->qo_]) == NULL)
12654d723e5aSJoerg Sonnenberger 		return;
12664d723e5aSJoerg Sonnenberger 
12674d723e5aSJoerg Sonnenberger 	pktlen = ifd->curlen_[ifd->qo_];
12684d723e5aSJoerg Sonnenberger 	borrowed = ifd->borrowed_[ifd->qo_];
12694d723e5aSJoerg Sonnenberger 	borrows = borrowed;
12704d723e5aSJoerg Sonnenberger 
12714d723e5aSJoerg Sonnenberger 	PKTCNTR_ADD(&cl->stats_.xmit_cnt, pktlen);
12724d723e5aSJoerg Sonnenberger 
12734d723e5aSJoerg Sonnenberger 	/*
12744d723e5aSJoerg Sonnenberger 	 * Run estimator on class and its ancestors.
12754d723e5aSJoerg Sonnenberger 	 */
12764d723e5aSJoerg Sonnenberger 	/*
12774d723e5aSJoerg Sonnenberger 	 * rm_update_class_util is designed to be called when the
12784d723e5aSJoerg Sonnenberger 	 * transfer is completed from a xmit complete interrupt,
12794d723e5aSJoerg Sonnenberger 	 * but most drivers don't implement an upcall for that.
12804d723e5aSJoerg Sonnenberger 	 * so, just use estimated completion time.
12814d723e5aSJoerg Sonnenberger 	 * as a result, ifd->qi_ and ifd->qo_ are always synced.
12824d723e5aSJoerg Sonnenberger 	 */
12834d723e5aSJoerg Sonnenberger 	nowp = &ifd->now_[ifd->qo_];
12844d723e5aSJoerg Sonnenberger 	/* get pkt_time (for link) in usec */
12854d723e5aSJoerg Sonnenberger #if 1  /* use approximation */
12864d723e5aSJoerg Sonnenberger 	pkt_time = ifd->curlen_[ifd->qo_] * ifd->ns_per_byte_;
12874d723e5aSJoerg Sonnenberger 	pkt_time = NSEC_TO_USEC(pkt_time);
12884d723e5aSJoerg Sonnenberger #else
12894d723e5aSJoerg Sonnenberger 	pkt_time = ifd->curlen_[ifd->qo_] * ifd->ns_per_byte_ / 1000;
12904d723e5aSJoerg Sonnenberger #endif
12914d723e5aSJoerg Sonnenberger #if 1 /* ALTQ4PPP */
12924d723e5aSJoerg Sonnenberger 	if (TV_LT(nowp, &ifd->ifnow_)) {
12934d723e5aSJoerg Sonnenberger 		int iftime;
12944d723e5aSJoerg Sonnenberger 
12954d723e5aSJoerg Sonnenberger 		/*
12964d723e5aSJoerg Sonnenberger 		 * make sure the estimated completion time does not go
12974d723e5aSJoerg Sonnenberger 		 * too far.  it can happen when the link layer supports
12984d723e5aSJoerg Sonnenberger 		 * data compression or the interface speed is set to
12994d723e5aSJoerg Sonnenberger 		 * a much lower value.
13004d723e5aSJoerg Sonnenberger 		 */
13014d723e5aSJoerg Sonnenberger 		TV_DELTA(&ifd->ifnow_, nowp, iftime);
13024d723e5aSJoerg Sonnenberger 		if (iftime+pkt_time < ifd->maxiftime_) {
13034d723e5aSJoerg Sonnenberger 			TV_ADD_DELTA(&ifd->ifnow_, pkt_time, &ifd->ifnow_);
13044d723e5aSJoerg Sonnenberger 		} else {
13054d723e5aSJoerg Sonnenberger 			TV_ADD_DELTA(nowp, ifd->maxiftime_, &ifd->ifnow_);
13064d723e5aSJoerg Sonnenberger 		}
13074d723e5aSJoerg Sonnenberger 	} else {
13084d723e5aSJoerg Sonnenberger 		TV_ADD_DELTA(nowp, pkt_time, &ifd->ifnow_);
13094d723e5aSJoerg Sonnenberger 	}
13104d723e5aSJoerg Sonnenberger #else
13114d723e5aSJoerg Sonnenberger 	if (TV_LT(nowp, &ifd->ifnow_)) {
13124d723e5aSJoerg Sonnenberger 		TV_ADD_DELTA(&ifd->ifnow_, pkt_time, &ifd->ifnow_);
13134d723e5aSJoerg Sonnenberger 	} else {
13144d723e5aSJoerg Sonnenberger 		TV_ADD_DELTA(nowp, pkt_time, &ifd->ifnow_);
13154d723e5aSJoerg Sonnenberger 	}
13164d723e5aSJoerg Sonnenberger #endif
13174d723e5aSJoerg Sonnenberger 
13184d723e5aSJoerg Sonnenberger 	while (cl != NULL) {
13194d723e5aSJoerg Sonnenberger 		TV_DELTA(&ifd->ifnow_, &cl->last_, idle);
13204d723e5aSJoerg Sonnenberger 		if (idle >= 2000000)
13214d723e5aSJoerg Sonnenberger 			/*
13224d723e5aSJoerg Sonnenberger 			 * this class is idle enough, reset avgidle.
13234d723e5aSJoerg Sonnenberger 			 * (TV_DELTA returns 2000000 us when delta is large.)
13244d723e5aSJoerg Sonnenberger 			 */
13254d723e5aSJoerg Sonnenberger 			cl->avgidle_ = cl->maxidle_;
13264d723e5aSJoerg Sonnenberger 
13274d723e5aSJoerg Sonnenberger 		/* get pkt_time (for class) in usec */
13284d723e5aSJoerg Sonnenberger #if 1  /* use approximation */
13294d723e5aSJoerg Sonnenberger 		pkt_time = pktlen * cl->ns_per_byte_;
13304d723e5aSJoerg Sonnenberger 		pkt_time = NSEC_TO_USEC(pkt_time);
13314d723e5aSJoerg Sonnenberger #else
13324d723e5aSJoerg Sonnenberger 		pkt_time = pktlen * cl->ns_per_byte_ / 1000;
13334d723e5aSJoerg Sonnenberger #endif
13344d723e5aSJoerg Sonnenberger 		idle -= pkt_time;
13354d723e5aSJoerg Sonnenberger 
13364d723e5aSJoerg Sonnenberger 		avgidle = cl->avgidle_;
13374d723e5aSJoerg Sonnenberger 		avgidle += idle - (avgidle >> RM_FILTER_GAIN);
13384d723e5aSJoerg Sonnenberger 		cl->avgidle_ = avgidle;
13394d723e5aSJoerg Sonnenberger 
13404d723e5aSJoerg Sonnenberger 		/* Are we overlimit ? */
13414d723e5aSJoerg Sonnenberger 		if (avgidle <= 0) {
13424d723e5aSJoerg Sonnenberger 			CBQTRACE(rmc_update_class_util, 'milo', cl->stats_.handle);
13434d723e5aSJoerg Sonnenberger #if 1 /* ALTQ */
13444d723e5aSJoerg Sonnenberger 			/*
13454d723e5aSJoerg Sonnenberger 			 * need some lower bound for avgidle, otherwise
13464d723e5aSJoerg Sonnenberger 			 * a borrowing class gets unbounded penalty.
13474d723e5aSJoerg Sonnenberger 			 */
13484d723e5aSJoerg Sonnenberger 			if (avgidle < cl->minidle_)
13494d723e5aSJoerg Sonnenberger 				avgidle = cl->avgidle_ = cl->minidle_;
13504d723e5aSJoerg Sonnenberger #endif
13514d723e5aSJoerg Sonnenberger 			/* set next idle to make avgidle 0 */
13524d723e5aSJoerg Sonnenberger 			tidle = pkt_time +
13534d723e5aSJoerg Sonnenberger 				(((1 - RM_POWER) * avgidle) >> RM_FILTER_GAIN);
13544d723e5aSJoerg Sonnenberger 			TV_ADD_DELTA(nowp, tidle, &cl->undertime_);
13554d723e5aSJoerg Sonnenberger 			++cl->stats_.over;
13564d723e5aSJoerg Sonnenberger 		} else {
13574d723e5aSJoerg Sonnenberger 			cl->avgidle_ =
13584d723e5aSJoerg Sonnenberger 			    (avgidle > cl->maxidle_) ? cl->maxidle_ : avgidle;
13594d723e5aSJoerg Sonnenberger 			cl->undertime_.tv_sec = 0;
13604d723e5aSJoerg Sonnenberger 			if (cl->sleeping_) {
13614d723e5aSJoerg Sonnenberger 				callout_stop(&cl->callout_);
13624d723e5aSJoerg Sonnenberger 				cl->sleeping_ = 0;
13634d723e5aSJoerg Sonnenberger 			}
13644d723e5aSJoerg Sonnenberger 		}
13654d723e5aSJoerg Sonnenberger 
13664d723e5aSJoerg Sonnenberger 		if (borrows != NULL) {
13674d723e5aSJoerg Sonnenberger 			if (borrows != cl)
13684d723e5aSJoerg Sonnenberger 				++cl->stats_.borrows;
13694d723e5aSJoerg Sonnenberger 			else
13704d723e5aSJoerg Sonnenberger 				borrows = NULL;
13714d723e5aSJoerg Sonnenberger 		}
13724d723e5aSJoerg Sonnenberger 		cl->last_ = ifd->ifnow_;
13734d723e5aSJoerg Sonnenberger 		cl->last_pkttime_ = pkt_time;
13744d723e5aSJoerg Sonnenberger 
13754d723e5aSJoerg Sonnenberger #if 1
13764d723e5aSJoerg Sonnenberger 		if (cl->parent_ == NULL) {
13774d723e5aSJoerg Sonnenberger 			/* take stats of root class */
13784d723e5aSJoerg Sonnenberger 			PKTCNTR_ADD(&cl->stats_.xmit_cnt, pktlen);
13794d723e5aSJoerg Sonnenberger 		}
13804d723e5aSJoerg Sonnenberger #endif
13814d723e5aSJoerg Sonnenberger 
13824d723e5aSJoerg Sonnenberger 		cl = cl->parent_;
13834d723e5aSJoerg Sonnenberger 	}
13844d723e5aSJoerg Sonnenberger 
13854d723e5aSJoerg Sonnenberger 	/*
13864d723e5aSJoerg Sonnenberger 	 * Check to see if cutoff needs to set to a new level.
13874d723e5aSJoerg Sonnenberger 	 */
13884d723e5aSJoerg Sonnenberger 	cl = ifd->class_[ifd->qo_];
13894d723e5aSJoerg Sonnenberger 	if (borrowed && (ifd->cutoff_ >= borrowed->depth_)) {
13904d723e5aSJoerg Sonnenberger #if 1 /* ALTQ */
13914d723e5aSJoerg Sonnenberger 		if ((qlen(cl->q_) <= 0) || TV_LT(nowp, &borrowed->undertime_)) {
13924d723e5aSJoerg Sonnenberger 			rmc_tl_satisfied(ifd, nowp);
13934d723e5aSJoerg Sonnenberger 			CBQTRACE(rmc_update_class_util, 'broe', ifd->cutoff_);
13944d723e5aSJoerg Sonnenberger 		} else {
13954d723e5aSJoerg Sonnenberger 			ifd->cutoff_ = borrowed->depth_;
13964d723e5aSJoerg Sonnenberger 			CBQTRACE(rmc_update_class_util, 'ffob', borrowed->depth_);
13974d723e5aSJoerg Sonnenberger 		}
13984d723e5aSJoerg Sonnenberger #else /* !ALTQ */
13994d723e5aSJoerg Sonnenberger 		if ((qlen(cl->q_) <= 1) || TV_LT(&now, &borrowed->undertime_)) {
14004d723e5aSJoerg Sonnenberger 			reset_cutoff(ifd);
14014d723e5aSJoerg Sonnenberger #ifdef notdef
14024d723e5aSJoerg Sonnenberger 			rmc_tl_satisfied(ifd, &now);
14034d723e5aSJoerg Sonnenberger #endif
14044d723e5aSJoerg Sonnenberger 			CBQTRACE(rmc_update_class_util, 'broe', ifd->cutoff_);
14054d723e5aSJoerg Sonnenberger 		} else {
14064d723e5aSJoerg Sonnenberger 			ifd->cutoff_ = borrowed->depth_;
14074d723e5aSJoerg Sonnenberger 			CBQTRACE(rmc_update_class_util, 'ffob', borrowed->depth_);
14084d723e5aSJoerg Sonnenberger 		}
14094d723e5aSJoerg Sonnenberger #endif /* !ALTQ */
14104d723e5aSJoerg Sonnenberger 	}
14114d723e5aSJoerg Sonnenberger 
14124d723e5aSJoerg Sonnenberger 	/*
14134d723e5aSJoerg Sonnenberger 	 * Release class slot
14144d723e5aSJoerg Sonnenberger 	 */
14154d723e5aSJoerg Sonnenberger 	ifd->borrowed_[ifd->qo_] = NULL;
14164d723e5aSJoerg Sonnenberger 	ifd->class_[ifd->qo_] = NULL;
14174d723e5aSJoerg Sonnenberger 	ifd->qo_ = (ifd->qo_ + 1) % ifd->maxqueued_;
14184d723e5aSJoerg Sonnenberger 	ifd->queued_--;
14194d723e5aSJoerg Sonnenberger }
14204d723e5aSJoerg Sonnenberger 
14214d723e5aSJoerg Sonnenberger /*
14224d723e5aSJoerg Sonnenberger  * void
14234d723e5aSJoerg Sonnenberger  * rmc_drop_action(struct rm_class *cl) - Generic (not protocol-specific)
14244d723e5aSJoerg Sonnenberger  *	over-limit action routines.  These get invoked by rmc_under_limit()
14254d723e5aSJoerg Sonnenberger  *	if a class with packets to send if over its bandwidth limit & can't
14264d723e5aSJoerg Sonnenberger  *	borrow from a parent class.
14274d723e5aSJoerg Sonnenberger  *
14284d723e5aSJoerg Sonnenberger  *	Returns: NONE
14294d723e5aSJoerg Sonnenberger  */
14304d723e5aSJoerg Sonnenberger 
14314d723e5aSJoerg Sonnenberger static void
14324d723e5aSJoerg Sonnenberger rmc_drop_action(struct rm_class *cl)
14334d723e5aSJoerg Sonnenberger {
14344d723e5aSJoerg Sonnenberger 	struct rm_ifdat *ifd = cl->ifdat_;
14354d723e5aSJoerg Sonnenberger 
14364d723e5aSJoerg Sonnenberger 	KKASSERT(qlen(cl->q_) > 0);
14374d723e5aSJoerg Sonnenberger 	_rmc_dropq(cl);
14384d723e5aSJoerg Sonnenberger 	if (qempty(cl->q_))
14394d723e5aSJoerg Sonnenberger 		ifd->na_[cl->pri_]--;
14404d723e5aSJoerg Sonnenberger }
14414d723e5aSJoerg Sonnenberger 
14423bf25ce1SSascha Wildner void
14433bf25ce1SSascha Wildner rmc_dropall(struct rm_class *cl)
14444d723e5aSJoerg Sonnenberger {
14454d723e5aSJoerg Sonnenberger 	struct rm_ifdat *ifd = cl->ifdat_;
14464d723e5aSJoerg Sonnenberger 
14474d723e5aSJoerg Sonnenberger 	if (!qempty(cl->q_)) {
14484d723e5aSJoerg Sonnenberger 		_flushq(cl->q_);
14494d723e5aSJoerg Sonnenberger 
14504d723e5aSJoerg Sonnenberger 		ifd->na_[cl->pri_]--;
14514d723e5aSJoerg Sonnenberger 	}
14524d723e5aSJoerg Sonnenberger }
14534d723e5aSJoerg Sonnenberger 
14544d723e5aSJoerg Sonnenberger /*
14554d723e5aSJoerg Sonnenberger  * void
14564d723e5aSJoerg Sonnenberger  * rmc_delay_action(struct rm_class *cl) - This function is the generic CBQ
14574d723e5aSJoerg Sonnenberger  *	delay action routine.  It is invoked via rmc_under_limit when the
14584d723e5aSJoerg Sonnenberger  *	packet is discoverd to be overlimit.
14594d723e5aSJoerg Sonnenberger  *
14604d723e5aSJoerg Sonnenberger  *	If the delay action is result of borrow class being overlimit, then
14614d723e5aSJoerg Sonnenberger  *	delay for the offtime of the borrowing class that is overlimit.
14624d723e5aSJoerg Sonnenberger  *
14634d723e5aSJoerg Sonnenberger  *	Returns: NONE
14644d723e5aSJoerg Sonnenberger  */
14654d723e5aSJoerg Sonnenberger 
14664d723e5aSJoerg Sonnenberger void
14674d723e5aSJoerg Sonnenberger rmc_delay_action(struct rm_class *cl, struct rm_class *borrow)
14684d723e5aSJoerg Sonnenberger {
14694d723e5aSJoerg Sonnenberger 	int delay, t, extradelay;
14704d723e5aSJoerg Sonnenberger 
14714d723e5aSJoerg Sonnenberger 	cl->stats_.overactions++;
14724d723e5aSJoerg Sonnenberger 	TV_DELTA(&cl->undertime_, &cl->overtime_, delay);
14734d723e5aSJoerg Sonnenberger #ifndef BORROW_OFFTIME
14744d723e5aSJoerg Sonnenberger 	delay += cl->offtime_;
14754d723e5aSJoerg Sonnenberger #endif
14764d723e5aSJoerg Sonnenberger 
14774d723e5aSJoerg Sonnenberger 	if (!cl->sleeping_) {
14784d723e5aSJoerg Sonnenberger 		CBQTRACE(rmc_delay_action, 'yled', cl->stats_.handle);
14794d723e5aSJoerg Sonnenberger #ifdef BORROW_OFFTIME
14804d723e5aSJoerg Sonnenberger 		if (borrow != NULL)
14814d723e5aSJoerg Sonnenberger 			extradelay = borrow->offtime_;
14824d723e5aSJoerg Sonnenberger 		else
14834d723e5aSJoerg Sonnenberger #endif
14844d723e5aSJoerg Sonnenberger 			extradelay = cl->offtime_;
14854d723e5aSJoerg Sonnenberger 
14864d723e5aSJoerg Sonnenberger #ifdef ALTQ
14874d723e5aSJoerg Sonnenberger 		/*
14884d723e5aSJoerg Sonnenberger 		 * XXX recalculate suspend time:
14894d723e5aSJoerg Sonnenberger 		 * current undertime is (tidle + pkt_time) calculated
14904d723e5aSJoerg Sonnenberger 		 * from the last transmission.
14914d723e5aSJoerg Sonnenberger 		 *	tidle: time required to bring avgidle back to 0
14924d723e5aSJoerg Sonnenberger 		 *	pkt_time: target waiting time for this class
14934d723e5aSJoerg Sonnenberger 		 * we need to replace pkt_time by offtime
14944d723e5aSJoerg Sonnenberger 		 */
14954d723e5aSJoerg Sonnenberger 		extradelay -= cl->last_pkttime_;
14964d723e5aSJoerg Sonnenberger #endif
14974d723e5aSJoerg Sonnenberger 		if (extradelay > 0) {
14984d723e5aSJoerg Sonnenberger 			TV_ADD_DELTA(&cl->undertime_, extradelay, &cl->undertime_);
14994d723e5aSJoerg Sonnenberger 			delay += extradelay;
15004d723e5aSJoerg Sonnenberger 		}
15014d723e5aSJoerg Sonnenberger 
15024d723e5aSJoerg Sonnenberger 		cl->sleeping_ = 1;
15034d723e5aSJoerg Sonnenberger 		cl->stats_.delays++;
15044d723e5aSJoerg Sonnenberger 
15054d723e5aSJoerg Sonnenberger 		/*
15064d723e5aSJoerg Sonnenberger 		 * Since packets are phased randomly with respect to the
15074d723e5aSJoerg Sonnenberger 		 * clock, 1 tick (the next clock tick) can be an arbitrarily
15084d723e5aSJoerg Sonnenberger 		 * short time so we have to wait for at least two ticks.
15094d723e5aSJoerg Sonnenberger 		 * NOTE:  If there's no other traffic, we need the timer as
15104d723e5aSJoerg Sonnenberger 		 * a 'backstop' to restart this class.
15114d723e5aSJoerg Sonnenberger 		 */
1512a591f597SMatthew Dillon 		if (delay > ustick * 2)
1513a591f597SMatthew Dillon 			t = (delay + ustick - 1) / ustick;
15144d723e5aSJoerg Sonnenberger 		else
15154d723e5aSJoerg Sonnenberger 			t = 2;
15164d723e5aSJoerg Sonnenberger 		callout_reset(&cl->callout_, t, rmc_restart, cl);
15174d723e5aSJoerg Sonnenberger 	}
15184d723e5aSJoerg Sonnenberger }
15194d723e5aSJoerg Sonnenberger 
15204d723e5aSJoerg Sonnenberger /*
15214d723e5aSJoerg Sonnenberger  * void
15224d723e5aSJoerg Sonnenberger  * rmc_restart() - is just a helper routine for rmc_delay_action -- it is
15234d723e5aSJoerg Sonnenberger  *	called by the system timer code & is responsible checking if the
15244d723e5aSJoerg Sonnenberger  *	class is still sleeping (it might have been restarted as a side
15254d723e5aSJoerg Sonnenberger  *	effect of the queue scan on a packet arrival) and, if so, restarting
15264d723e5aSJoerg Sonnenberger  *	output for the class.  Inspecting the class state & restarting output
15274d723e5aSJoerg Sonnenberger  *	require locking the class structure.  In general the driver is
15284d723e5aSJoerg Sonnenberger  *	responsible for locking but this is the only routine that is not
15294d723e5aSJoerg Sonnenberger  *	called directly or indirectly from the interface driver so it has
15304d723e5aSJoerg Sonnenberger  *	know about system locking conventions.  Under bsd, locking is done
15314d723e5aSJoerg Sonnenberger  *	by raising IPL to splimp so that's what's implemented here.  On a
15324d723e5aSJoerg Sonnenberger  *	different system this would probably need to be changed.
15334d723e5aSJoerg Sonnenberger  *
153478195a76SMatthew Dillon  *	Since this function is called from an independant timeout, we
153578195a76SMatthew Dillon  *	have to set up the lock conditions expected for the ALTQ operation.
153678195a76SMatthew Dillon  *	Note that the restart will probably fall through to an if_start.
153778195a76SMatthew Dillon  *
15384d723e5aSJoerg Sonnenberger  *	Returns:	NONE
15394d723e5aSJoerg Sonnenberger  */
15404d723e5aSJoerg Sonnenberger 
15414d723e5aSJoerg Sonnenberger static void
15424d723e5aSJoerg Sonnenberger rmc_restart(void *arg)
15434d723e5aSJoerg Sonnenberger {
15444d723e5aSJoerg Sonnenberger 	struct rm_class *cl = arg;
15454d723e5aSJoerg Sonnenberger 	struct rm_ifdat *ifd = cl->ifdat_;
1546f0a26983SSepherosa Ziehau 	struct ifaltq_subque *ifsq = &ifd->ifq_->altq_subq[0];
15474d723e5aSJoerg Sonnenberger 
1548f0a26983SSepherosa Ziehau 	ALTQ_SQ_LOCK(ifsq);
15494d723e5aSJoerg Sonnenberger 	if (cl->sleeping_) {
15504d723e5aSJoerg Sonnenberger 		cl->sleeping_ = 0;
15514d723e5aSJoerg Sonnenberger 		cl->undertime_.tv_sec = 0;
15524d723e5aSJoerg Sonnenberger 
15534d723e5aSJoerg Sonnenberger 		if (ifd->queued_ < ifd->maxqueued_ && ifd->restart != NULL) {
15544d723e5aSJoerg Sonnenberger 			CBQTRACE(rmc_restart, 'trts', cl->stats_.handle);
15554d723e5aSJoerg Sonnenberger 			(ifd->restart)(ifd->ifq_);
15564d723e5aSJoerg Sonnenberger 		}
15574d723e5aSJoerg Sonnenberger 	}
1558f0a26983SSepherosa Ziehau 	ALTQ_SQ_UNLOCK(ifsq);
15594d723e5aSJoerg Sonnenberger }
15604d723e5aSJoerg Sonnenberger 
15614d723e5aSJoerg Sonnenberger /*
15624d723e5aSJoerg Sonnenberger  * void
15634d723e5aSJoerg Sonnenberger  * rmc_root_overlimit(struct rm_class *cl) - This the generic overlimit
15644d723e5aSJoerg Sonnenberger  *	handling routine for the root class of the link sharing structure.
15654d723e5aSJoerg Sonnenberger  *
15664d723e5aSJoerg Sonnenberger  *	Returns: NONE
15674d723e5aSJoerg Sonnenberger  */
15684d723e5aSJoerg Sonnenberger 
15694d723e5aSJoerg Sonnenberger static void
15704d723e5aSJoerg Sonnenberger rmc_root_overlimit(struct rm_class *cl, struct rm_class *borrow)
15714d723e5aSJoerg Sonnenberger {
15724d723e5aSJoerg Sonnenberger         panic("rmc_root_overlimit");
15734d723e5aSJoerg Sonnenberger }
15744d723e5aSJoerg Sonnenberger 
15754d723e5aSJoerg Sonnenberger /*
15764d723e5aSJoerg Sonnenberger  * Packet Queue handling routines.  Eventually, this is to localize the
15774d723e5aSJoerg Sonnenberger  *	effects on the code whether queues are red queues or droptail
15784d723e5aSJoerg Sonnenberger  *	queues.
15794d723e5aSJoerg Sonnenberger  */
15804d723e5aSJoerg Sonnenberger 
15814d723e5aSJoerg Sonnenberger static int
15824d723e5aSJoerg Sonnenberger _rmc_addq(rm_class_t *cl, struct mbuf *m)
15834d723e5aSJoerg Sonnenberger {
15844d723e5aSJoerg Sonnenberger #ifdef ALTQ_RIO
15854d723e5aSJoerg Sonnenberger 	if (q_is_rio(cl->q_))
15864d723e5aSJoerg Sonnenberger 		return rio_addq((rio_t *)cl->red_, cl->q_, m, cl->pktattr_);
15874d723e5aSJoerg Sonnenberger #endif
15884d723e5aSJoerg Sonnenberger #ifdef ALTQ_RED
15894d723e5aSJoerg Sonnenberger 	if (q_is_red(cl->q_))
15904d723e5aSJoerg Sonnenberger 		return red_addq(cl->red_, cl->q_, m, cl->pktattr_);
15914d723e5aSJoerg Sonnenberger #endif /* ALTQ_RED */
15924d723e5aSJoerg Sonnenberger 
15934d723e5aSJoerg Sonnenberger 	if (cl->flags_ & RMCF_CLEARDSCP)
15944d723e5aSJoerg Sonnenberger 		write_dsfield(m, cl->pktattr_, 0);
15954d723e5aSJoerg Sonnenberger 
15964d723e5aSJoerg Sonnenberger 	_addq(cl->q_, m);
15974d723e5aSJoerg Sonnenberger 	return (0);
15984d723e5aSJoerg Sonnenberger }
15994d723e5aSJoerg Sonnenberger 
16004d723e5aSJoerg Sonnenberger /* note: _rmc_dropq is not called for red */
16014d723e5aSJoerg Sonnenberger static void
16024d723e5aSJoerg Sonnenberger _rmc_dropq(rm_class_t *cl)
16034d723e5aSJoerg Sonnenberger {
16044d723e5aSJoerg Sonnenberger 	struct mbuf *m;
16054d723e5aSJoerg Sonnenberger 
16064d723e5aSJoerg Sonnenberger 	if ((m = _getq(cl->q_)) != NULL)
16074d723e5aSJoerg Sonnenberger 		m_freem(m);
16084d723e5aSJoerg Sonnenberger }
16094d723e5aSJoerg Sonnenberger 
16104d723e5aSJoerg Sonnenberger static struct mbuf *
16114d723e5aSJoerg Sonnenberger _rmc_getq(rm_class_t *cl)
16124d723e5aSJoerg Sonnenberger {
16134d723e5aSJoerg Sonnenberger #ifdef ALTQ_RIO
16144d723e5aSJoerg Sonnenberger 	if (q_is_rio(cl->q_))
16154d723e5aSJoerg Sonnenberger 		return rio_getq((rio_t *)cl->red_, cl->q_);
16164d723e5aSJoerg Sonnenberger #endif
16174d723e5aSJoerg Sonnenberger #ifdef ALTQ_RED
16184d723e5aSJoerg Sonnenberger 	if (q_is_red(cl->q_))
16194d723e5aSJoerg Sonnenberger 		return red_getq(cl->red_, cl->q_);
16204d723e5aSJoerg Sonnenberger #endif
16214d723e5aSJoerg Sonnenberger 	return _getq(cl->q_);
16224d723e5aSJoerg Sonnenberger }
16234d723e5aSJoerg Sonnenberger 
16244d723e5aSJoerg Sonnenberger static struct mbuf *
16254d723e5aSJoerg Sonnenberger _rmc_pollq(rm_class_t *cl)
16264d723e5aSJoerg Sonnenberger {
16274d723e5aSJoerg Sonnenberger 	return qhead(cl->q_);
16284d723e5aSJoerg Sonnenberger }
16294d723e5aSJoerg Sonnenberger 
16304d723e5aSJoerg Sonnenberger #ifdef CBQ_TRACE
16314d723e5aSJoerg Sonnenberger /*
16324d723e5aSJoerg Sonnenberger  * DDB hook to trace cbq events:
16334d723e5aSJoerg Sonnenberger  *  the last 1024 events are held in a circular buffer.
16344d723e5aSJoerg Sonnenberger  *  use "call cbqtrace_dump(N)" to display 20 events from Nth event.
16354d723e5aSJoerg Sonnenberger  */
16364d723e5aSJoerg Sonnenberger void		cbqtrace_dump(int);
16374d723e5aSJoerg Sonnenberger static char	*rmc_funcname(void *);
16384d723e5aSJoerg Sonnenberger 
16394d723e5aSJoerg Sonnenberger static struct rmc_funcs {
16404d723e5aSJoerg Sonnenberger 	void	*func;
16414d723e5aSJoerg Sonnenberger 	char	*name;
16424d723e5aSJoerg Sonnenberger } rmc_funcs[] = {
16434d723e5aSJoerg Sonnenberger 	rmc_init,		"rmc_init",
16444d723e5aSJoerg Sonnenberger 	rmc_queue_packet,	"rmc_queue_packet",
16454d723e5aSJoerg Sonnenberger 	rmc_under_limit,	"rmc_under_limit",
16464d723e5aSJoerg Sonnenberger 	rmc_update_class_util,	"rmc_update_class_util",
16474d723e5aSJoerg Sonnenberger 	rmc_delay_action,	"rmc_delay_action",
16484d723e5aSJoerg Sonnenberger 	rmc_restart,		"rmc_restart",
16494d723e5aSJoerg Sonnenberger 	_rmc_wrr_dequeue_next,	"_rmc_wrr_dequeue_next",
16504d723e5aSJoerg Sonnenberger 	NULL,			NULL
16514d723e5aSJoerg Sonnenberger };
16524d723e5aSJoerg Sonnenberger 
16533bf25ce1SSascha Wildner static chari *
16543bf25ce1SSascha Wildner rmc_funcname(void *func)
16554d723e5aSJoerg Sonnenberger {
16564d723e5aSJoerg Sonnenberger 	struct rmc_funcs *fp;
16574d723e5aSJoerg Sonnenberger 
16584d723e5aSJoerg Sonnenberger 	for (fp = rmc_funcs; fp->func != NULL; fp++) {
16594d723e5aSJoerg Sonnenberger 		if (fp->func == func)
16604d723e5aSJoerg Sonnenberger 			return (fp->name);
16614d723e5aSJoerg Sonnenberger 	}
16624d723e5aSJoerg Sonnenberger 
16634d723e5aSJoerg Sonnenberger 	return ("unknown");
16644d723e5aSJoerg Sonnenberger }
16654d723e5aSJoerg Sonnenberger 
16664d723e5aSJoerg Sonnenberger void
16674d723e5aSJoerg Sonnenberger cbqtrace_dump(int counter)
16684d723e5aSJoerg Sonnenberger {
16694d723e5aSJoerg Sonnenberger 	int i, *p;
16704d723e5aSJoerg Sonnenberger 	char *cp;
16714d723e5aSJoerg Sonnenberger 
16724d723e5aSJoerg Sonnenberger 	counter = counter % NCBQTRACE;
16734d723e5aSJoerg Sonnenberger 	p = (int *)&cbqtrace_buffer[counter];
16744d723e5aSJoerg Sonnenberger 
16754d723e5aSJoerg Sonnenberger 	for (i=0; i<20; i++) {
16764b1cf444SSascha Wildner 		kprintf("[0x%x] ", *p++);
16774b1cf444SSascha Wildner 		kprintf("%s: ", rmc_funcname((void *)*p++));
16784d723e5aSJoerg Sonnenberger 		cp = (char *)p++;
16794b1cf444SSascha Wildner 		kprintf("%c%c%c%c: ", cp[0], cp[1], cp[2], cp[3]);
16804b1cf444SSascha Wildner 		kprintf("%d\n",*p++);
16814d723e5aSJoerg Sonnenberger 
16824d723e5aSJoerg Sonnenberger 		if (p >= (int *)&cbqtrace_buffer[NCBQTRACE])
16834d723e5aSJoerg Sonnenberger 			p = (int *)cbqtrace_buffer;
16844d723e5aSJoerg Sonnenberger 	}
16854d723e5aSJoerg Sonnenberger }
16864d723e5aSJoerg Sonnenberger #endif /* CBQ_TRACE */
16874d723e5aSJoerg Sonnenberger #endif /* ALTQ_CBQ */
1688