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