1 1.32 joe /* $NetBSD: altq_rmclass.c,v 1.32 2025/01/08 13:00:04 joe Exp $ */ 2 1.15 peter /* $KAME: altq_rmclass.c,v 1.19 2005/04/13 03:44:25 suz Exp $ */ 3 1.1 thorpej 4 1.1 thorpej /* 5 1.1 thorpej * Copyright (c) 1991-1997 Regents of the University of California. 6 1.1 thorpej * All rights reserved. 7 1.1 thorpej * 8 1.1 thorpej * Redistribution and use in source and binary forms, with or without 9 1.1 thorpej * modification, are permitted provided that the following conditions 10 1.1 thorpej * are met: 11 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 12 1.1 thorpej * notice, this list of conditions and the following disclaimer. 13 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 15 1.1 thorpej * documentation and/or other materials provided with the distribution. 16 1.1 thorpej * 3. All advertising materials mentioning features or use of this software 17 1.1 thorpej * must display the following acknowledgement: 18 1.1 thorpej * This product includes software developed by the Network Research 19 1.1 thorpej * Group at Lawrence Berkeley Laboratory. 20 1.1 thorpej * 4. Neither the name of the University nor of the Laboratory may be used 21 1.1 thorpej * to endorse or promote products derived from this software without 22 1.1 thorpej * specific prior written permission. 23 1.1 thorpej * 24 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 1.1 thorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 1.1 thorpej * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 1.1 thorpej * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 1.1 thorpej * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 1.1 thorpej * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 1.1 thorpej * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 1.1 thorpej * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 1.1 thorpej * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 1.1 thorpej * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 1.1 thorpej * SUCH DAMAGE. 35 1.1 thorpej * 36 1.1 thorpej * LBL code modified by speer (at) eng.sun.com, May 1977. 37 1.1 thorpej * For questions and/or comments, please send mail to cbq (at) ee.lbl.gov 38 1.1 thorpej */ 39 1.5 lukem 40 1.5 lukem #include <sys/cdefs.h> 41 1.32 joe __KERNEL_RCSID(0, "$NetBSD: altq_rmclass.c,v 1.32 2025/01/08 13:00:04 joe Exp $"); 42 1.1 thorpej 43 1.19 rpaulo /* #ident "@(#)rm_class.c 1.48 97/12/05 SMI" */ 44 1.1 thorpej 45 1.15 peter #ifdef _KERNEL_OPT 46 1.1 thorpej #include "opt_altq.h" 47 1.1 thorpej #include "opt_inet.h" 48 1.1 thorpej #endif 49 1.15 peter 50 1.1 thorpej #ifdef ALTQ_CBQ /* cbq is enabled by ALTQ_CBQ option in opt_altq.h */ 51 1.1 thorpej 52 1.1 thorpej #include <sys/param.h> 53 1.1 thorpej #include <sys/malloc.h> 54 1.1 thorpej #include <sys/mbuf.h> 55 1.1 thorpej #include <sys/socket.h> 56 1.1 thorpej #include <sys/systm.h> 57 1.1 thorpej #include <sys/errno.h> 58 1.1 thorpej #include <sys/time.h> 59 1.15 peter #ifdef ALTQ3_COMPAT 60 1.1 thorpej #include <sys/kernel.h> 61 1.15 peter #endif 62 1.22 tls #include <sys/cprng.h> 63 1.1 thorpej 64 1.1 thorpej #include <net/if.h> 65 1.28 ozaki #include <net/if_types.h> 66 1.15 peter #ifdef ALTQ3_COMPAT 67 1.1 thorpej #include <netinet/in.h> 68 1.1 thorpej #include <netinet/in_systm.h> 69 1.1 thorpej #include <netinet/ip.h> 70 1.15 peter #endif 71 1.1 thorpej 72 1.1 thorpej #include <altq/altq.h> 73 1.1 thorpej #include <altq/altq_rmclass.h> 74 1.1 thorpej #include <altq/altq_rmclass_debug.h> 75 1.1 thorpej #include <altq/altq_red.h> 76 1.1 thorpej #include <altq/altq_rio.h> 77 1.1 thorpej 78 1.1 thorpej /* 79 1.1 thorpej * Local Macros 80 1.1 thorpej */ 81 1.1 thorpej 82 1.1 thorpej #define reset_cutoff(ifd) { ifd->cutoff_ = RM_MAXDEPTH; } 83 1.1 thorpej 84 1.25 ozaki #define PSEC_TO_NSEC(t) ((t) / 1000) 85 1.25 ozaki 86 1.1 thorpej /* 87 1.1 thorpej * Local routines. 88 1.1 thorpej */ 89 1.1 thorpej 90 1.26 ozaki static int rmc_satisfied(struct rm_class *, struct timespec *); 91 1.15 peter static void rmc_wrr_set_weights(struct rm_ifdat *); 92 1.15 peter static void rmc_depth_compute(struct rm_class *); 93 1.15 peter static void rmc_depth_recompute(rm_class_t *); 94 1.15 peter 95 1.15 peter static mbuf_t *_rmc_wrr_dequeue_next(struct rm_ifdat *, int); 96 1.15 peter static mbuf_t *_rmc_prr_dequeue_next(struct rm_ifdat *, int); 97 1.15 peter 98 1.15 peter static int _rmc_addq(rm_class_t *, mbuf_t *); 99 1.15 peter static void _rmc_dropq(rm_class_t *); 100 1.15 peter static mbuf_t *_rmc_getq(rm_class_t *); 101 1.15 peter static mbuf_t *_rmc_pollq(rm_class_t *); 102 1.15 peter 103 1.26 ozaki static int rmc_under_limit(struct rm_class *, struct timespec *); 104 1.26 ozaki static void rmc_tl_satisfied(struct rm_ifdat *, struct timespec *); 105 1.15 peter static void rmc_drop_action(struct rm_class *); 106 1.15 peter static void rmc_restart(struct rm_class *); 107 1.15 peter static void rmc_root_overlimit(struct rm_class *, struct rm_class *); 108 1.1 thorpej 109 1.15 peter #define BORROW_OFFTIME 110 1.1 thorpej /* 111 1.1 thorpej * BORROW_OFFTIME (experimental): 112 1.1 thorpej * borrow the offtime of the class borrowing from. 113 1.1 thorpej * the reason is that when its own offtime is set, the class is unable 114 1.1 thorpej * to borrow much, especially when cutoff is taking effect. 115 1.1 thorpej * but when the borrowed class is overloaded (advidle is close to minidle), 116 1.1 thorpej * use the borrowing class's offtime to avoid overload. 117 1.1 thorpej */ 118 1.15 peter #define ADJUST_CUTOFF 119 1.1 thorpej /* 120 1.1 thorpej * ADJUST_CUTOFF (experimental): 121 1.1 thorpej * if no underlimit class is found due to cutoff, increase cutoff and 122 1.1 thorpej * retry the scheduling loop. 123 1.1 thorpej * also, don't invoke delay_actions while cutoff is taking effect, 124 1.1 thorpej * since a sleeping class won't have a chance to be scheduled in the 125 1.1 thorpej * next loop. 126 1.1 thorpej * 127 1.1 thorpej * now heuristics for setting the top-level variable (cutoff_) becomes: 128 1.1 thorpej * 1. if a packet arrives for a not-overlimit class, set cutoff 129 1.1 thorpej * to the depth of the class. 130 1.1 thorpej * 2. if cutoff is i, and a packet arrives for an overlimit class 131 1.1 thorpej * with an underlimit ancestor at a lower level than i (say j), 132 1.1 thorpej * then set cutoff to j. 133 1.1 thorpej * 3. at scheduling a packet, if there is no underlimit class 134 1.1 thorpej * due to the current cutoff level, increase cutoff by 1 and 135 1.1 thorpej * then try to schedule again. 136 1.1 thorpej */ 137 1.1 thorpej 138 1.1 thorpej /* 139 1.1 thorpej * rm_class_t * 140 1.1 thorpej * rmc_newclass(...) - Create a new resource management class at priority 141 1.1 thorpej * 'pri' on the interface given by 'ifd'. 142 1.1 thorpej * 143 1.1 thorpej * nsecPerByte is the data rate of the interface in nanoseconds/byte. 144 1.1 thorpej * E.g., 800 for a 10Mb/s ethernet. If the class gets less 145 1.1 thorpej * than 100% of the bandwidth, this number should be the 146 1.1 thorpej * 'effective' rate for the class. Let f be the 147 1.1 thorpej * bandwidth fraction allocated to this class, and let 148 1.1 thorpej * nsPerByte be the data rate of the output link in 149 1.1 thorpej * nanoseconds/byte. Then nsecPerByte is set to 150 1.1 thorpej * nsPerByte / f. E.g., 1600 (= 800 / .5) 151 1.1 thorpej * for a class that gets 50% of an ethernet's bandwidth. 152 1.1 thorpej * 153 1.1 thorpej * action the routine to call when the class is over limit. 154 1.1 thorpej * 155 1.1 thorpej * maxq max allowable queue size for class (in packets). 156 1.1 thorpej * 157 1.1 thorpej * parent parent class pointer. 158 1.1 thorpej * 159 1.1 thorpej * borrow class to borrow from (should be either 'parent' or null). 160 1.1 thorpej * 161 1.1 thorpej * maxidle max value allowed for class 'idle' time estimate (this 162 1.1 thorpej * parameter determines how large an initial burst of packets 163 1.1 thorpej * can be before overlimit action is invoked. 164 1.1 thorpej * 165 1.1 thorpej * offtime how long 'delay' action will delay when class goes over 166 1.1 thorpej * limit (this parameter determines the steady-state burst 167 1.1 thorpej * size when a class is running over its limit). 168 1.1 thorpej * 169 1.1 thorpej * Maxidle and offtime have to be computed from the following: If the 170 1.1 thorpej * average packet size is s, the bandwidth fraction allocated to this 171 1.1 thorpej * class is f, we want to allow b packet bursts, and the gain of the 172 1.1 thorpej * averaging filter is g (= 1 - 2^(-RM_FILTER_GAIN)), then: 173 1.1 thorpej * 174 1.1 thorpej * ptime = s * nsPerByte * (1 - f) / f 175 1.1 thorpej * maxidle = ptime * (1 - g^b) / g^b 176 1.1 thorpej * minidle = -ptime * (1 / (f - 1)) 177 1.1 thorpej * offtime = ptime * (1 + 1/(1 - g) * (1 - g^(b - 1)) / g^(b - 1) 178 1.1 thorpej * 179 1.1 thorpej * Operationally, it's convenient to specify maxidle & offtime in units 180 1.1 thorpej * independent of the link bandwidth so the maxidle & offtime passed to 181 1.1 thorpej * this routine are the above values multiplied by 8*f/(1000*nsPerByte). 182 1.1 thorpej * (The constant factor is a scale factor needed to make the parameters 183 1.1 thorpej * integers. This scaling also means that the 'unscaled' values of 184 1.1 thorpej * maxidle*nsecPerByte/8 and offtime*nsecPerByte/8 will be in microseconds, 185 1.1 thorpej * not nanoseconds.) Also note that the 'idle' filter computation keeps 186 1.1 thorpej * an estimate scaled upward by 2^RM_FILTER_GAIN so the passed value of 187 1.1 thorpej * maxidle also must be scaled upward by this value. Thus, the passed 188 1.1 thorpej * values for maxidle and offtime can be computed as follows: 189 1.1 thorpej * 190 1.1 thorpej * maxidle = maxidle * 2^RM_FILTER_GAIN * 8 / (1000 * nsecPerByte) 191 1.1 thorpej * offtime = offtime * 8 / (1000 * nsecPerByte) 192 1.1 thorpej * 193 1.9 perry * When USE_HRTIME is employed, then maxidle and offtime become: 194 1.9 perry * maxidle = maxilde * (8.0 / nsecPerByte); 195 1.1 thorpej * offtime = offtime * (8.0 / nsecPerByte); 196 1.1 thorpej */ 197 1.1 thorpej struct rm_class * 198 1.27 ozaki rmc_newclass(int pri, struct rm_ifdat *ifd, uint64_t psecPerByte, 199 1.15 peter void (*action)(rm_class_t *, rm_class_t *), int maxq, 200 1.15 peter struct rm_class *parent, struct rm_class *borrow, u_int maxidle, 201 1.15 peter int minidle, u_int offtime, int pktsize, int flags) 202 1.15 peter { 203 1.15 peter struct rm_class *cl; 204 1.15 peter struct rm_class *peer; 205 1.15 peter int s; 206 1.1 thorpej 207 1.1 thorpej if (pri >= RM_MAXPRIO) 208 1.32 joe return NULL; 209 1.1 thorpej #ifndef ALTQ_RED 210 1.1 thorpej if (flags & RMCF_RED) { 211 1.15 peter #ifdef ALTQ_DEBUG 212 1.1 thorpej printf("rmc_newclass: RED not configured for CBQ!\n"); 213 1.15 peter #endif 214 1.32 joe return NULL; 215 1.1 thorpej } 216 1.1 thorpej #endif 217 1.1 thorpej #ifndef ALTQ_RIO 218 1.1 thorpej if (flags & RMCF_RIO) { 219 1.15 peter #ifdef ALTQ_DEBUG 220 1.1 thorpej printf("rmc_newclass: RIO not configured for CBQ!\n"); 221 1.15 peter #endif 222 1.32 joe return NULL; 223 1.1 thorpej } 224 1.1 thorpej #endif 225 1.1 thorpej 226 1.13 christos cl = malloc(sizeof(struct rm_class), M_DEVBUF, M_WAITOK|M_ZERO); 227 1.1 thorpej if (cl == NULL) 228 1.32 joe return NULL; 229 1.1 thorpej CALLOUT_INIT(&cl->callout_); 230 1.15 peter 231 1.13 christos cl->q_ = malloc(sizeof(class_queue_t), M_DEVBUF, M_WAITOK|M_ZERO); 232 1.1 thorpej if (cl->q_ == NULL) { 233 1.13 christos free(cl, M_DEVBUF); 234 1.32 joe return NULL; 235 1.1 thorpej } 236 1.1 thorpej 237 1.1 thorpej /* 238 1.1 thorpej * Class initialization. 239 1.1 thorpej */ 240 1.1 thorpej cl->children_ = NULL; 241 1.1 thorpej cl->parent_ = parent; 242 1.1 thorpej cl->borrow_ = borrow; 243 1.1 thorpej cl->leaf_ = 1; 244 1.1 thorpej cl->ifdat_ = ifd; 245 1.1 thorpej cl->pri_ = pri; 246 1.25 ozaki cl->allotment_ = (u_int)(RM_PS_PER_SEC / psecPerByte); /* Bytes per sec */ 247 1.1 thorpej cl->depth_ = 0; 248 1.1 thorpej cl->qthresh_ = 0; 249 1.25 ozaki cl->ps_per_byte_ = psecPerByte; 250 1.1 thorpej 251 1.1 thorpej qlimit(cl->q_) = maxq; 252 1.1 thorpej qtype(cl->q_) = Q_DROPHEAD; 253 1.1 thorpej qlen(cl->q_) = 0; 254 1.1 thorpej cl->flags_ = flags; 255 1.1 thorpej 256 1.1 thorpej #if 1 /* minidle is also scaled in ALTQ */ 257 1.27 ozaki cl->minidle_ = ((int64_t)minidle * (int64_t)psecPerByte) / 8; 258 1.1 thorpej if (cl->minidle_ > 0) 259 1.1 thorpej cl->minidle_ = 0; 260 1.1 thorpej #else 261 1.1 thorpej cl->minidle_ = minidle; 262 1.1 thorpej #endif 263 1.27 ozaki cl->maxidle_ = ((int64_t)maxidle * (int64_t)psecPerByte) / 8; 264 1.1 thorpej if (cl->maxidle_ == 0) 265 1.1 thorpej cl->maxidle_ = 1; 266 1.1 thorpej #if 1 /* offtime is also scaled in ALTQ */ 267 1.1 thorpej cl->avgidle_ = cl->maxidle_; 268 1.27 ozaki cl->offtime_ = (((int64_t)offtime * (int64_t)psecPerByte) / 8) >> RM_FILTER_GAIN; 269 1.1 thorpej if (cl->offtime_ == 0) 270 1.1 thorpej cl->offtime_ = 1; 271 1.1 thorpej #else 272 1.1 thorpej cl->avgidle_ = 0; 273 1.1 thorpej cl->offtime_ = (offtime * nsecPerByte) / 8; 274 1.1 thorpej #endif 275 1.1 thorpej cl->overlimit = action; 276 1.1 thorpej 277 1.1 thorpej #ifdef ALTQ_RED 278 1.1 thorpej if (flags & (RMCF_RED|RMCF_RIO)) { 279 1.1 thorpej int red_flags, red_pkttime; 280 1.1 thorpej 281 1.1 thorpej red_flags = 0; 282 1.1 thorpej if (flags & RMCF_ECN) 283 1.1 thorpej red_flags |= REDF_ECN; 284 1.1 thorpej if (flags & RMCF_FLOWVALVE) 285 1.1 thorpej red_flags |= REDF_FLOWVALVE; 286 1.1 thorpej #ifdef ALTQ_RIO 287 1.1 thorpej if (flags & RMCF_CLEARDSCP) 288 1.1 thorpej red_flags |= RIOF_CLEARDSCP; 289 1.1 thorpej #endif 290 1.29 ozaki red_pkttime = PSEC_TO_NSEC(psecPerByte) * pktsize / 1000; 291 1.1 thorpej 292 1.1 thorpej if (flags & RMCF_RED) { 293 1.15 peter cl->red_ = red_alloc(0, 0, 294 1.15 peter qlimit(cl->q_) * 10/100, 295 1.15 peter qlimit(cl->q_) * 30/100, 296 1.15 peter red_flags, red_pkttime); 297 1.1 thorpej if (cl->red_ != NULL) 298 1.1 thorpej qtype(cl->q_) = Q_RED; 299 1.1 thorpej } 300 1.1 thorpej #ifdef ALTQ_RIO 301 1.1 thorpej else { 302 1.1 thorpej cl->red_ = (red_t *)rio_alloc(0, NULL, 303 1.1 thorpej red_flags, red_pkttime); 304 1.1 thorpej if (cl->red_ != NULL) 305 1.1 thorpej qtype(cl->q_) = Q_RIO; 306 1.1 thorpej } 307 1.1 thorpej #endif 308 1.1 thorpej } 309 1.1 thorpej #endif /* ALTQ_RED */ 310 1.1 thorpej 311 1.1 thorpej /* 312 1.1 thorpej * put the class into the class tree 313 1.1 thorpej */ 314 1.4 thorpej s = splnet(); 315 1.1 thorpej if ((peer = ifd->active_[pri]) != NULL) { 316 1.1 thorpej /* find the last class at this pri */ 317 1.1 thorpej cl->peer_ = peer; 318 1.1 thorpej while (peer->peer_ != ifd->active_[pri]) 319 1.1 thorpej peer = peer->peer_; 320 1.1 thorpej peer->peer_ = cl; 321 1.1 thorpej } else { 322 1.1 thorpej ifd->active_[pri] = cl; 323 1.1 thorpej cl->peer_ = cl; 324 1.1 thorpej } 325 1.1 thorpej 326 1.1 thorpej if (cl->parent_) { 327 1.1 thorpej cl->next_ = parent->children_; 328 1.1 thorpej parent->children_ = cl; 329 1.1 thorpej parent->leaf_ = 0; 330 1.1 thorpej } 331 1.1 thorpej 332 1.1 thorpej /* 333 1.15 peter * Compute the depth of this class and its ancestors in the class 334 1.1 thorpej * hierarchy. 335 1.1 thorpej */ 336 1.1 thorpej rmc_depth_compute(cl); 337 1.1 thorpej 338 1.1 thorpej /* 339 1.15 peter * If CBQ's WRR is enabled, then initialize the class WRR state. 340 1.1 thorpej */ 341 1.1 thorpej if (ifd->wrr_) { 342 1.1 thorpej ifd->num_[pri]++; 343 1.1 thorpej ifd->alloc_[pri] += cl->allotment_; 344 1.1 thorpej rmc_wrr_set_weights(ifd); 345 1.1 thorpej } 346 1.1 thorpej splx(s); 347 1.32 joe return cl; 348 1.1 thorpej } 349 1.1 thorpej 350 1.1 thorpej int 351 1.27 ozaki rmc_modclass(struct rm_class *cl, uint64_t psecPerByte, int maxq, u_int maxidle, 352 1.18 christos int minidle, u_int offtime, int pktsize) 353 1.1 thorpej { 354 1.1 thorpej struct rm_ifdat *ifd; 355 1.15 peter u_int old_allotment; 356 1.15 peter int s; 357 1.1 thorpej 358 1.1 thorpej ifd = cl->ifdat_; 359 1.1 thorpej old_allotment = cl->allotment_; 360 1.1 thorpej 361 1.4 thorpej s = splnet(); 362 1.25 ozaki cl->allotment_ = (u_int)(RM_PS_PER_SEC / psecPerByte); /* Bytes per sec */ 363 1.1 thorpej cl->qthresh_ = 0; 364 1.25 ozaki cl->ps_per_byte_ = psecPerByte; 365 1.1 thorpej 366 1.1 thorpej qlimit(cl->q_) = maxq; 367 1.1 thorpej 368 1.1 thorpej #if 1 /* minidle is also scaled in ALTQ */ 369 1.27 ozaki cl->minidle_ = ((int64_t)minidle * (int64_t)psecPerByte) / 8; 370 1.1 thorpej if (cl->minidle_ > 0) 371 1.1 thorpej cl->minidle_ = 0; 372 1.1 thorpej #else 373 1.1 thorpej cl->minidle_ = minidle; 374 1.1 thorpej #endif 375 1.27 ozaki cl->maxidle_ = ((int64_t)maxidle * (int64_t)psecPerByte) / 8; 376 1.1 thorpej if (cl->maxidle_ == 0) 377 1.1 thorpej cl->maxidle_ = 1; 378 1.1 thorpej #if 1 /* offtime is also scaled in ALTQ */ 379 1.1 thorpej cl->avgidle_ = cl->maxidle_; 380 1.27 ozaki cl->offtime_ = (((int64_t)offtime * (int64_t)psecPerByte) / 8) >> RM_FILTER_GAIN; 381 1.1 thorpej if (cl->offtime_ == 0) 382 1.1 thorpej cl->offtime_ = 1; 383 1.1 thorpej #else 384 1.1 thorpej cl->avgidle_ = 0; 385 1.1 thorpej cl->offtime_ = (offtime * nsecPerByte) / 8; 386 1.1 thorpej #endif 387 1.1 thorpej 388 1.1 thorpej /* 389 1.15 peter * If CBQ's WRR is enabled, then initialize the class WRR state. 390 1.1 thorpej */ 391 1.1 thorpej if (ifd->wrr_) { 392 1.1 thorpej ifd->alloc_[cl->pri_] += cl->allotment_ - old_allotment; 393 1.1 thorpej rmc_wrr_set_weights(ifd); 394 1.1 thorpej } 395 1.1 thorpej splx(s); 396 1.32 joe return 0; 397 1.1 thorpej } 398 1.1 thorpej 399 1.1 thorpej /* 400 1.1 thorpej * static void 401 1.1 thorpej * rmc_wrr_set_weights(struct rm_ifdat *ifdat) - This function computes 402 1.15 peter * the appropriate run robin weights for the CBQ weighted round robin 403 1.1 thorpej * algorithm. 404 1.1 thorpej * 405 1.1 thorpej * Returns: NONE 406 1.1 thorpej */ 407 1.1 thorpej 408 1.1 thorpej static void 409 1.15 peter rmc_wrr_set_weights(struct rm_ifdat *ifd) 410 1.1 thorpej { 411 1.1 thorpej int i; 412 1.1 thorpej struct rm_class *cl, *clh; 413 1.1 thorpej 414 1.1 thorpej for (i = 0; i < RM_MAXPRIO; i++) { 415 1.1 thorpej /* 416 1.1 thorpej * This is inverted from that of the simulator to 417 1.1 thorpej * maintain precision. 418 1.1 thorpej */ 419 1.1 thorpej if (ifd->num_[i] == 0) 420 1.1 thorpej ifd->M_[i] = 0; 421 1.1 thorpej else 422 1.1 thorpej ifd->M_[i] = ifd->alloc_[i] / 423 1.1 thorpej (ifd->num_[i] * ifd->maxpkt_); 424 1.1 thorpej /* 425 1.15 peter * Compute the weighted allotment for each class. 426 1.1 thorpej * This takes the expensive div instruction out 427 1.1 thorpej * of the main loop for the wrr scheduling path. 428 1.1 thorpej * These only get recomputed when a class comes or 429 1.1 thorpej * goes. 430 1.1 thorpej */ 431 1.1 thorpej if (ifd->active_[i] != NULL) { 432 1.1 thorpej clh = cl = ifd->active_[i]; 433 1.1 thorpej do { 434 1.1 thorpej /* safe-guard for slow link or alloc_ == 0 */ 435 1.1 thorpej if (ifd->M_[i] == 0) 436 1.1 thorpej cl->w_allotment_ = 0; 437 1.1 thorpej else 438 1.1 thorpej cl->w_allotment_ = cl->allotment_ / 439 1.1 thorpej ifd->M_[i]; 440 1.1 thorpej cl = cl->peer_; 441 1.1 thorpej } while ((cl != NULL) && (cl != clh)); 442 1.1 thorpej } 443 1.1 thorpej } 444 1.1 thorpej } 445 1.1 thorpej 446 1.1 thorpej int 447 1.15 peter rmc_get_weight(struct rm_ifdat *ifd, int pri) 448 1.1 thorpej { 449 1.1 thorpej if ((pri >= 0) && (pri < RM_MAXPRIO)) 450 1.1 thorpej return (ifd->M_[pri]); 451 1.1 thorpej else 452 1.32 joe return 0; 453 1.1 thorpej } 454 1.1 thorpej 455 1.1 thorpej /* 456 1.1 thorpej * static void 457 1.1 thorpej * rmc_depth_compute(struct rm_class *cl) - This function computes the 458 1.15 peter * appropriate depth of class 'cl' and its ancestors. 459 1.1 thorpej * 460 1.1 thorpej * Returns: NONE 461 1.1 thorpej */ 462 1.1 thorpej 463 1.1 thorpej static void 464 1.15 peter rmc_depth_compute(struct rm_class *cl) 465 1.1 thorpej { 466 1.15 peter rm_class_t *t = cl, *p; 467 1.1 thorpej 468 1.1 thorpej /* 469 1.1 thorpej * Recompute the depth for the branch of the tree. 470 1.1 thorpej */ 471 1.1 thorpej while (t != NULL) { 472 1.1 thorpej p = t->parent_; 473 1.1 thorpej if (p && (t->depth_ >= p->depth_)) { 474 1.1 thorpej p->depth_ = t->depth_ + 1; 475 1.1 thorpej t = p; 476 1.1 thorpej } else 477 1.1 thorpej t = NULL; 478 1.1 thorpej } 479 1.1 thorpej } 480 1.1 thorpej 481 1.1 thorpej /* 482 1.1 thorpej * static void 483 1.1 thorpej * rmc_depth_recompute(struct rm_class *cl) - This function re-computes 484 1.1 thorpej * the depth of the tree after a class has been deleted. 485 1.1 thorpej * 486 1.15 peter * Returns: NONE 487 1.1 thorpej */ 488 1.1 thorpej 489 1.1 thorpej static void 490 1.1 thorpej rmc_depth_recompute(rm_class_t *cl) 491 1.1 thorpej { 492 1.1 thorpej #if 1 /* ALTQ */ 493 1.1 thorpej rm_class_t *p, *t; 494 1.1 thorpej 495 1.1 thorpej p = cl; 496 1.1 thorpej while (p != NULL) { 497 1.1 thorpej if ((t = p->children_) == NULL) { 498 1.1 thorpej p->depth_ = 0; 499 1.1 thorpej } else { 500 1.1 thorpej int cdepth = 0; 501 1.1 thorpej 502 1.1 thorpej while (t != NULL) { 503 1.1 thorpej if (t->depth_ > cdepth) 504 1.1 thorpej cdepth = t->depth_; 505 1.1 thorpej t = t->next_; 506 1.1 thorpej } 507 1.1 thorpej 508 1.1 thorpej if (p->depth_ == cdepth + 1) 509 1.1 thorpej /* no change to this parent */ 510 1.1 thorpej return; 511 1.1 thorpej 512 1.1 thorpej p->depth_ = cdepth + 1; 513 1.1 thorpej } 514 1.9 perry 515 1.1 thorpej p = p->parent_; 516 1.1 thorpej } 517 1.1 thorpej #else 518 1.1 thorpej rm_class_t *t; 519 1.1 thorpej 520 1.1 thorpej if (cl->depth_ >= 1) { 521 1.1 thorpej if (cl->children_ == NULL) { 522 1.1 thorpej cl->depth_ = 0; 523 1.1 thorpej } else if ((t = cl->children_) != NULL) { 524 1.1 thorpej while (t != NULL) { 525 1.1 thorpej if (t->children_ != NULL) 526 1.1 thorpej rmc_depth_recompute(t); 527 1.1 thorpej t = t->next_; 528 1.1 thorpej } 529 1.1 thorpej } else 530 1.9 perry rmc_depth_compute(cl); 531 1.1 thorpej } 532 1.1 thorpej #endif 533 1.1 thorpej } 534 1.1 thorpej 535 1.1 thorpej /* 536 1.1 thorpej * void 537 1.1 thorpej * rmc_delete_class(struct rm_ifdat *ifdat, struct rm_class *cl) - This 538 1.12 wiz * function deletes a class from the link-sharing structure and frees 539 1.1 thorpej * all resources associated with the class. 540 1.1 thorpej * 541 1.1 thorpej * Returns: NONE 542 1.1 thorpej */ 543 1.1 thorpej 544 1.1 thorpej void 545 1.15 peter rmc_delete_class(struct rm_ifdat *ifd, struct rm_class *cl) 546 1.1 thorpej { 547 1.1 thorpej struct rm_class *p, *head, *previous; 548 1.15 peter int s; 549 1.1 thorpej 550 1.1 thorpej ASSERT(cl->children_ == NULL); 551 1.1 thorpej 552 1.1 thorpej if (cl->sleeping_) 553 1.1 thorpej CALLOUT_STOP(&cl->callout_); 554 1.9 perry 555 1.4 thorpej s = splnet(); 556 1.1 thorpej /* 557 1.1 thorpej * Free packets in the packet queue. 558 1.1 thorpej * XXX - this may not be a desired behavior. Packets should be 559 1.15 peter * re-queued. 560 1.1 thorpej */ 561 1.1 thorpej rmc_dropall(cl); 562 1.1 thorpej 563 1.1 thorpej /* 564 1.1 thorpej * If the class has a parent, then remove the class from the 565 1.1 thorpej * class from the parent's children chain. 566 1.1 thorpej */ 567 1.1 thorpej if (cl->parent_ != NULL) { 568 1.1 thorpej head = cl->parent_->children_; 569 1.1 thorpej p = previous = head; 570 1.1 thorpej if (head->next_ == NULL) { 571 1.1 thorpej ASSERT(head == cl); 572 1.1 thorpej cl->parent_->children_ = NULL; 573 1.1 thorpej cl->parent_->leaf_ = 1; 574 1.1 thorpej } else while (p != NULL) { 575 1.1 thorpej if (p == cl) { 576 1.1 thorpej if (cl == head) 577 1.1 thorpej cl->parent_->children_ = cl->next_; 578 1.1 thorpej else 579 1.1 thorpej previous->next_ = cl->next_; 580 1.1 thorpej cl->next_ = NULL; 581 1.1 thorpej p = NULL; 582 1.1 thorpej } else { 583 1.1 thorpej previous = p; 584 1.1 thorpej p = p->next_; 585 1.1 thorpej } 586 1.1 thorpej } 587 1.1 thorpej } 588 1.1 thorpej 589 1.1 thorpej /* 590 1.1 thorpej * Delete class from class priority peer list. 591 1.1 thorpej */ 592 1.1 thorpej if ((p = ifd->active_[cl->pri_]) != NULL) { 593 1.1 thorpej /* 594 1.1 thorpej * If there is more than one member of this priority 595 1.1 thorpej * level, then look for class(cl) in the priority level. 596 1.1 thorpej */ 597 1.1 thorpej if (p != p->peer_) { 598 1.1 thorpej while (p->peer_ != cl) 599 1.1 thorpej p = p->peer_; 600 1.1 thorpej p->peer_ = cl->peer_; 601 1.1 thorpej 602 1.1 thorpej if (ifd->active_[cl->pri_] == cl) 603 1.1 thorpej ifd->active_[cl->pri_] = cl->peer_; 604 1.1 thorpej } else { 605 1.1 thorpej ASSERT(p == cl); 606 1.1 thorpej ifd->active_[cl->pri_] = NULL; 607 1.1 thorpej } 608 1.1 thorpej } 609 1.1 thorpej 610 1.1 thorpej /* 611 1.1 thorpej * Recompute the WRR weights. 612 1.1 thorpej */ 613 1.1 thorpej if (ifd->wrr_) { 614 1.1 thorpej ifd->alloc_[cl->pri_] -= cl->allotment_; 615 1.1 thorpej ifd->num_[cl->pri_]--; 616 1.1 thorpej rmc_wrr_set_weights(ifd); 617 1.1 thorpej } 618 1.1 thorpej 619 1.1 thorpej /* 620 1.1 thorpej * Re-compute the depth of the tree. 621 1.1 thorpej */ 622 1.1 thorpej #if 1 /* ALTQ */ 623 1.1 thorpej rmc_depth_recompute(cl->parent_); 624 1.1 thorpej #else 625 1.1 thorpej rmc_depth_recompute(ifd->root_); 626 1.1 thorpej #endif 627 1.1 thorpej 628 1.1 thorpej splx(s); 629 1.1 thorpej 630 1.1 thorpej /* 631 1.1 thorpej * Free the class structure. 632 1.1 thorpej */ 633 1.1 thorpej if (cl->red_ != NULL) { 634 1.1 thorpej #ifdef ALTQ_RIO 635 1.1 thorpej if (q_is_rio(cl->q_)) 636 1.1 thorpej rio_destroy((rio_t *)cl->red_); 637 1.1 thorpej #endif 638 1.1 thorpej #ifdef ALTQ_RED 639 1.1 thorpej if (q_is_red(cl->q_)) 640 1.1 thorpej red_destroy(cl->red_); 641 1.1 thorpej #endif 642 1.1 thorpej } 643 1.13 christos free(cl->q_, M_DEVBUF); 644 1.13 christos free(cl, M_DEVBUF); 645 1.1 thorpej } 646 1.1 thorpej 647 1.1 thorpej 648 1.1 thorpej /* 649 1.17 peter * int 650 1.1 thorpej * rmc_init(...) - Initialize the resource management data structures 651 1.1 thorpej * associated with the output portion of interface 'ifp'. 'ifd' is 652 1.1 thorpej * where the structures will be built (for backwards compatibility, the 653 1.1 thorpej * structures aren't kept in the ifnet struct). 'nsecPerByte' 654 1.1 thorpej * gives the link speed (inverse of bandwidth) in nanoseconds/byte. 655 1.1 thorpej * 'restart' is the driver-specific routine that the generic 'delay 656 1.1 thorpej * until under limit' action will call to restart output. `maxq' 657 1.1 thorpej * is the queue size of the 'link' & 'default' classes. 'maxqueued' 658 1.1 thorpej * is the maximum number of packets that the resource management 659 1.1 thorpej * code will allow to be queued 'downstream' (this is typically 1). 660 1.1 thorpej * 661 1.17 peter * Returns: 0 on success 662 1.1 thorpej */ 663 1.1 thorpej 664 1.17 peter int 665 1.27 ozaki rmc_init(struct ifaltq *ifq, struct rm_ifdat *ifd, uint64_t psecPerByte, 666 1.15 peter void (*restart)(struct ifaltq *), int maxq, int maxqueued, u_int maxidle, 667 1.15 peter int minidle, u_int offtime, int flags) 668 1.1 thorpej { 669 1.17 peter int i, mtu; 670 1.1 thorpej 671 1.1 thorpej /* 672 1.15 peter * Initialize the CBQ tracing/debug facility. 673 1.1 thorpej */ 674 1.9 perry CBQTRACEINIT(); 675 1.1 thorpej 676 1.17 peter mtu = ifq->altq_ifp->if_mtu; 677 1.17 peter if (mtu < 1) { 678 1.17 peter printf("altq: %s: invalid MTU (interface not initialized?)\n", 679 1.17 peter ifq->altq_ifp->if_xname); 680 1.32 joe return EINVAL; 681 1.17 peter } 682 1.17 peter 683 1.15 peter (void)memset((char *)ifd, 0, sizeof (*ifd)); 684 1.1 thorpej ifd->ifq_ = ifq; 685 1.1 thorpej ifd->restart = restart; 686 1.1 thorpej ifd->maxqueued_ = maxqueued; 687 1.25 ozaki ifd->ps_per_byte_ = psecPerByte; 688 1.1 thorpej ifd->maxpkt_ = mtu; 689 1.1 thorpej ifd->wrr_ = (flags & RMCF_WRR) ? 1 : 0; 690 1.1 thorpej ifd->efficient_ = (flags & RMCF_EFFICIENT) ? 1 : 0; 691 1.1 thorpej #if 1 692 1.25 ozaki ifd->maxiftime_ = mtu * psecPerByte / 1000 / 1000 * 16; 693 1.27 ozaki if ((int64_t)mtu * psecPerByte > (int64_t)10 * 1000000000) 694 1.1 thorpej ifd->maxiftime_ /= 4; 695 1.1 thorpej #endif 696 1.1 thorpej 697 1.1 thorpej reset_cutoff(ifd); 698 1.15 peter CBQTRACE(rmc_init, 'INIT', ifd->cutoff_); 699 1.1 thorpej 700 1.1 thorpej /* 701 1.1 thorpej * Initialize the CBQ's WRR state. 702 1.1 thorpej */ 703 1.1 thorpej for (i = 0; i < RM_MAXPRIO; i++) { 704 1.1 thorpej ifd->alloc_[i] = 0; 705 1.1 thorpej ifd->M_[i] = 0; 706 1.1 thorpej ifd->num_[i] = 0; 707 1.1 thorpej ifd->na_[i] = 0; 708 1.1 thorpej ifd->active_[i] = NULL; 709 1.1 thorpej } 710 1.1 thorpej 711 1.1 thorpej /* 712 1.1 thorpej * Initialize current packet state. 713 1.1 thorpej */ 714 1.1 thorpej ifd->qi_ = 0; 715 1.1 thorpej ifd->qo_ = 0; 716 1.1 thorpej for (i = 0; i < RM_MAXQUEUED; i++) { 717 1.1 thorpej ifd->class_[i] = NULL; 718 1.1 thorpej ifd->curlen_[i] = 0; 719 1.1 thorpej ifd->borrowed_[i] = NULL; 720 1.1 thorpej } 721 1.1 thorpej 722 1.1 thorpej /* 723 1.1 thorpej * Create the root class of the link-sharing structure. 724 1.1 thorpej */ 725 1.1 thorpej if ((ifd->root_ = rmc_newclass(0, ifd, 726 1.25 ozaki psecPerByte, 727 1.1 thorpej rmc_root_overlimit, maxq, 0, 0, 728 1.1 thorpej maxidle, minidle, offtime, 729 1.1 thorpej 0, 0)) == NULL) { 730 1.1 thorpej printf("rmc_init: root class not allocated\n"); 731 1.32 joe return ENOMEM; 732 1.1 thorpej } 733 1.1 thorpej ifd->root_->depth_ = 0; 734 1.17 peter 735 1.32 joe return 0; 736 1.1 thorpej } 737 1.1 thorpej 738 1.1 thorpej /* 739 1.1 thorpej * void 740 1.1 thorpej * rmc_queue_packet(struct rm_class *cl, mbuf_t *m) - Add packet given by 741 1.1 thorpej * mbuf 'm' to queue for resource class 'cl'. This routine is called 742 1.1 thorpej * by a driver's if_output routine. This routine must be called with 743 1.1 thorpej * output packet completion interrupts locked out (to avoid racing with 744 1.1 thorpej * rmc_dequeue_next). 745 1.1 thorpej * 746 1.1 thorpej * Returns: 0 on successful queueing 747 1.1 thorpej * -1 when packet drop occurs 748 1.1 thorpej */ 749 1.1 thorpej int 750 1.15 peter rmc_queue_packet(struct rm_class *cl, mbuf_t *m) 751 1.1 thorpej { 752 1.26 ozaki struct timespec now; 753 1.1 thorpej struct rm_ifdat *ifd = cl->ifdat_; 754 1.15 peter int cpri = cl->pri_; 755 1.15 peter int is_empty = qempty(cl->q_); 756 1.1 thorpej 757 1.1 thorpej RM_GETTIME(now); 758 1.1 thorpej if (ifd->cutoff_ > 0) { 759 1.26 ozaki if (TS_LT(&cl->undertime_, &now)) { 760 1.1 thorpej if (ifd->cutoff_ > cl->depth_) 761 1.1 thorpej ifd->cutoff_ = cl->depth_; 762 1.15 peter CBQTRACE(rmc_queue_packet, 'ffoc', cl->depth_); 763 1.1 thorpej } 764 1.1 thorpej #if 1 /* ALTQ */ 765 1.1 thorpej else { 766 1.1 thorpej /* 767 1.1 thorpej * the class is overlimit. if the class has 768 1.1 thorpej * underlimit ancestors, set cutoff to the lowest 769 1.9 perry * depth among them. 770 1.1 thorpej */ 771 1.1 thorpej struct rm_class *borrow = cl->borrow_; 772 1.1 thorpej 773 1.1 thorpej while (borrow != NULL && 774 1.1 thorpej borrow->depth_ < ifd->cutoff_) { 775 1.26 ozaki if (TS_LT(&borrow->undertime_, &now)) { 776 1.1 thorpej ifd->cutoff_ = borrow->depth_; 777 1.15 peter CBQTRACE(rmc_queue_packet, 'ffob', ifd->cutoff_); 778 1.1 thorpej break; 779 1.1 thorpej } 780 1.1 thorpej borrow = borrow->borrow_; 781 1.1 thorpej } 782 1.9 perry } 783 1.1 thorpej #else /* !ALTQ */ 784 1.1 thorpej else if ((ifd->cutoff_ > 1) && cl->borrow_) { 785 1.26 ozaki if (TS_LT(&cl->borrow_->undertime_, &now)) { 786 1.1 thorpej ifd->cutoff_ = cl->borrow_->depth_; 787 1.15 peter CBQTRACE(rmc_queue_packet, 'ffob', 788 1.1 thorpej cl->borrow_->depth_); 789 1.1 thorpej } 790 1.9 perry } 791 1.1 thorpej #endif /* !ALTQ */ 792 1.1 thorpej } 793 1.1 thorpej 794 1.1 thorpej if (_rmc_addq(cl, m) < 0) 795 1.1 thorpej /* failed */ 796 1.32 joe return -1; 797 1.1 thorpej 798 1.1 thorpej if (is_empty) { 799 1.15 peter CBQTRACE(rmc_queue_packet, 'ytpe', cl->stats_.handle); 800 1.1 thorpej ifd->na_[cpri]++; 801 1.1 thorpej } 802 1.1 thorpej 803 1.1 thorpej if (qlen(cl->q_) > qlimit(cl->q_)) { 804 1.1 thorpej /* note: qlimit can be set to 0 or 1 */ 805 1.1 thorpej rmc_drop_action(cl); 806 1.32 joe return -1; 807 1.1 thorpej } 808 1.32 joe return 0; 809 1.1 thorpej } 810 1.1 thorpej 811 1.1 thorpej /* 812 1.1 thorpej * void 813 1.26 ozaki * rmc_tl_satisfied(struct rm_ifdat *ifd, struct timespec *now) - Check all 814 1.1 thorpej * classes to see if there are satified. 815 1.1 thorpej */ 816 1.1 thorpej 817 1.1 thorpej static void 818 1.26 ozaki rmc_tl_satisfied(struct rm_ifdat *ifd, struct timespec *now) 819 1.1 thorpej { 820 1.15 peter int i; 821 1.1 thorpej rm_class_t *p, *bp; 822 1.1 thorpej 823 1.1 thorpej for (i = RM_MAXPRIO - 1; i >= 0; i--) { 824 1.1 thorpej if ((bp = ifd->active_[i]) != NULL) { 825 1.1 thorpej p = bp; 826 1.1 thorpej do { 827 1.1 thorpej if (!rmc_satisfied(p, now)) { 828 1.1 thorpej ifd->cutoff_ = p->depth_; 829 1.1 thorpej return; 830 1.9 perry } 831 1.1 thorpej p = p->peer_; 832 1.1 thorpej } while (p != bp); 833 1.1 thorpej } 834 1.1 thorpej } 835 1.1 thorpej 836 1.1 thorpej reset_cutoff(ifd); 837 1.1 thorpej } 838 1.1 thorpej 839 1.1 thorpej /* 840 1.1 thorpej * rmc_satisfied - Return 1 of the class is satisfied. O, otherwise. 841 1.1 thorpej */ 842 1.1 thorpej 843 1.1 thorpej static int 844 1.26 ozaki rmc_satisfied(struct rm_class *cl, struct timespec *now) 845 1.1 thorpej { 846 1.15 peter rm_class_t *p; 847 1.1 thorpej 848 1.1 thorpej if (cl == NULL) 849 1.32 joe return 1; 850 1.26 ozaki if (TS_LT(now, &cl->undertime_)) 851 1.32 joe return 1; 852 1.1 thorpej if (cl->depth_ == 0) { 853 1.1 thorpej if (!cl->sleeping_ && (qlen(cl->q_) > cl->qthresh_)) 854 1.32 joe return 0; 855 1.9 perry else 856 1.32 joe return 1; 857 1.1 thorpej } 858 1.1 thorpej if (cl->children_ != NULL) { 859 1.1 thorpej p = cl->children_; 860 1.1 thorpej while (p != NULL) { 861 1.1 thorpej if (!rmc_satisfied(p, now)) 862 1.32 joe return 0; 863 1.1 thorpej p = p->next_; 864 1.1 thorpej } 865 1.1 thorpej } 866 1.1 thorpej 867 1.32 joe return 1; 868 1.1 thorpej } 869 1.1 thorpej 870 1.1 thorpej /* 871 1.1 thorpej * Return 1 if class 'cl' is under limit or can borrow from a parent, 872 1.1 thorpej * 0 if overlimit. As a side-effect, this routine will invoke the 873 1.1 thorpej * class overlimit action if the class if overlimit. 874 1.1 thorpej */ 875 1.1 thorpej 876 1.1 thorpej static int 877 1.26 ozaki rmc_under_limit(struct rm_class *cl, struct timespec *now) 878 1.1 thorpej { 879 1.1 thorpej rm_class_t *p = cl; 880 1.1 thorpej rm_class_t *top; 881 1.1 thorpej struct rm_ifdat *ifd = cl->ifdat_; 882 1.31 ozaki int sleeping = cl->sleeping_; 883 1.1 thorpej 884 1.1 thorpej ifd->borrowed_[ifd->qi_] = NULL; 885 1.1 thorpej /* 886 1.1 thorpej * If cl is the root class, then always return that it is 887 1.1 thorpej * underlimit. Otherwise, check to see if the class is underlimit. 888 1.1 thorpej */ 889 1.1 thorpej if (cl->parent_ == NULL) 890 1.32 joe return 1; 891 1.1 thorpej 892 1.31 ozaki if (!TS_LT(now, &cl->undertime_)) { 893 1.31 ozaki /* Fast path: the given class is allowed to send packets */ 894 1.31 ozaki if (sleeping) { 895 1.31 ozaki CALLOUT_STOP(&cl->callout_); 896 1.31 ozaki cl->sleeping_ = 0; 897 1.31 ozaki cl->undertime_.tv_sec = 0; 898 1.31 ozaki } 899 1.32 joe return 1; 900 1.1 thorpej } 901 1.1 thorpej 902 1.1 thorpej top = NULL; 903 1.31 ozaki do { 904 1.1 thorpej if (((cl = cl->borrow_) == NULL) || 905 1.1 thorpej (cl->depth_ > ifd->cutoff_)) { 906 1.31 ozaki /* No need to call the delay action */ 907 1.31 ozaki if (sleeping) 908 1.32 joe return 0; 909 1.1 thorpej #ifdef ADJUST_CUTOFF 910 1.1 thorpej if (cl != NULL) 911 1.1 thorpej /* cutoff is taking effect, just 912 1.1 thorpej return false without calling 913 1.1 thorpej the delay action. */ 914 1.32 joe return 0; 915 1.1 thorpej #endif 916 1.1 thorpej #ifdef BORROW_OFFTIME 917 1.1 thorpej /* 918 1.1 thorpej * check if the class can borrow offtime too. 919 1.1 thorpej * borrow offtime from the top of the borrow 920 1.1 thorpej * chain if the top class is not overloaded. 921 1.1 thorpej */ 922 1.1 thorpej if (cl != NULL) { 923 1.1 thorpej /* cutoff is taking effect, use this class as top. */ 924 1.9 perry top = cl; 925 1.15 peter CBQTRACE(rmc_under_limit, 'ffou', ifd->cutoff_); 926 1.1 thorpej } 927 1.1 thorpej if (top != NULL && top->avgidle_ == top->minidle_) 928 1.1 thorpej top = NULL; 929 1.1 thorpej p->overtime_ = *now; 930 1.1 thorpej (p->overlimit)(p, top); 931 1.1 thorpej #else 932 1.1 thorpej p->overtime_ = *now; 933 1.1 thorpej (p->overlimit)(p, NULL); 934 1.1 thorpej #endif 935 1.32 joe return 0; 936 1.1 thorpej } 937 1.1 thorpej top = cl; 938 1.31 ozaki } while (cl->undertime_.tv_sec && TS_LT(now, &cl->undertime_)); 939 1.1 thorpej 940 1.1 thorpej if (cl != p) 941 1.1 thorpej ifd->borrowed_[ifd->qi_] = cl; 942 1.32 joe return 1; 943 1.1 thorpej } 944 1.1 thorpej 945 1.1 thorpej /* 946 1.1 thorpej * _rmc_wrr_dequeue_next() - This is scheduler for WRR as opposed to 947 1.1 thorpej * Packet-by-packet round robin. 948 1.1 thorpej * 949 1.15 peter * The heart of the weighted round-robin scheduler, which decides which 950 1.1 thorpej * class next gets to send a packet. Highest priority first, then 951 1.1 thorpej * weighted round-robin within priorites. 952 1.1 thorpej * 953 1.1 thorpej * Each able-to-send class gets to send until its byte allocation is 954 1.1 thorpej * exhausted. Thus, the active pointer is only changed after a class has 955 1.1 thorpej * exhausted its allocation. 956 1.1 thorpej * 957 1.1 thorpej * If the scheduler finds no class that is underlimit or able to borrow, 958 1.1 thorpej * then the first class found that had a nonzero queue and is allowed to 959 1.1 thorpej * borrow gets to send. 960 1.1 thorpej */ 961 1.1 thorpej 962 1.1 thorpej static mbuf_t * 963 1.15 peter _rmc_wrr_dequeue_next(struct rm_ifdat *ifd, int op) 964 1.1 thorpej { 965 1.1 thorpej struct rm_class *cl = NULL, *first = NULL; 966 1.15 peter u_int deficit; 967 1.15 peter int cpri; 968 1.1 thorpej mbuf_t *m; 969 1.26 ozaki struct timespec now; 970 1.1 thorpej 971 1.1 thorpej RM_GETTIME(now); 972 1.1 thorpej 973 1.1 thorpej /* 974 1.1 thorpej * if the driver polls the top of the queue and then removes 975 1.1 thorpej * the polled packet, we must return the same packet. 976 1.1 thorpej */ 977 1.1 thorpej if (op == ALTDQ_REMOVE && ifd->pollcache_) { 978 1.1 thorpej cl = ifd->pollcache_; 979 1.1 thorpej cpri = cl->pri_; 980 1.1 thorpej if (ifd->efficient_) { 981 1.1 thorpej /* check if this class is overlimit */ 982 1.1 thorpej if (cl->undertime_.tv_sec != 0 && 983 1.1 thorpej rmc_under_limit(cl, &now) == 0) 984 1.1 thorpej first = cl; 985 1.1 thorpej } 986 1.1 thorpej ifd->pollcache_ = NULL; 987 1.1 thorpej goto _wrr_out; 988 1.1 thorpej } 989 1.1 thorpej else { 990 1.1 thorpej /* mode == ALTDQ_POLL || pollcache == NULL */ 991 1.1 thorpej ifd->pollcache_ = NULL; 992 1.1 thorpej ifd->borrowed_[ifd->qi_] = NULL; 993 1.1 thorpej } 994 1.1 thorpej #ifdef ADJUST_CUTOFF 995 1.1 thorpej _again: 996 1.1 thorpej #endif 997 1.1 thorpej for (cpri = RM_MAXPRIO - 1; cpri >= 0; cpri--) { 998 1.1 thorpej if (ifd->na_[cpri] == 0) 999 1.1 thorpej continue; 1000 1.1 thorpej deficit = 0; 1001 1.1 thorpej /* 1002 1.1 thorpej * Loop through twice for a priority level, if some class 1003 1.1 thorpej * was unable to send a packet the first round because 1004 1.1 thorpej * of the weighted round-robin mechanism. 1005 1.1 thorpej * During the second loop at this level, deficit==2. 1006 1.1 thorpej * (This second loop is not needed if for every class, 1007 1.1 thorpej * "M[cl->pri_])" times "cl->allotment" is greater than 1008 1.1 thorpej * the byte size for the largest packet in the class.) 1009 1.1 thorpej */ 1010 1.1 thorpej _wrr_loop: 1011 1.1 thorpej cl = ifd->active_[cpri]; 1012 1.1 thorpej ASSERT(cl != NULL); 1013 1.1 thorpej do { 1014 1.1 thorpej if ((deficit < 2) && (cl->bytes_alloc_ <= 0)) 1015 1.1 thorpej cl->bytes_alloc_ += cl->w_allotment_; 1016 1.1 thorpej if (!qempty(cl->q_)) { 1017 1.1 thorpej if ((cl->undertime_.tv_sec == 0) || 1018 1.1 thorpej rmc_under_limit(cl, &now)) { 1019 1.1 thorpej if (cl->bytes_alloc_ > 0 || deficit > 1) 1020 1.1 thorpej goto _wrr_out; 1021 1.1 thorpej 1022 1.1 thorpej /* underlimit but no alloc */ 1023 1.1 thorpej deficit = 1; 1024 1.1 thorpej #if 1 1025 1.1 thorpej ifd->borrowed_[ifd->qi_] = NULL; 1026 1.1 thorpej #endif 1027 1.1 thorpej } 1028 1.1 thorpej else if (first == NULL && cl->borrow_ != NULL) 1029 1.1 thorpej first = cl; /* borrowing candidate */ 1030 1.1 thorpej } 1031 1.1 thorpej 1032 1.1 thorpej cl->bytes_alloc_ = 0; 1033 1.1 thorpej cl = cl->peer_; 1034 1.1 thorpej } while (cl != ifd->active_[cpri]); 1035 1.9 perry 1036 1.1 thorpej if (deficit == 1) { 1037 1.1 thorpej /* first loop found an underlimit class with deficit */ 1038 1.1 thorpej /* Loop on same priority level, with new deficit. */ 1039 1.1 thorpej deficit = 2; 1040 1.1 thorpej goto _wrr_loop; 1041 1.9 perry } 1042 1.1 thorpej } 1043 1.1 thorpej 1044 1.1 thorpej #ifdef ADJUST_CUTOFF 1045 1.1 thorpej /* 1046 1.1 thorpej * no underlimit class found. if cutoff is taking effect, 1047 1.1 thorpej * increase cutoff and try again. 1048 1.1 thorpej */ 1049 1.1 thorpej if (first != NULL && ifd->cutoff_ < ifd->root_->depth_) { 1050 1.1 thorpej ifd->cutoff_++; 1051 1.15 peter CBQTRACE(_rmc_wrr_dequeue_next, 'ojda', ifd->cutoff_); 1052 1.1 thorpej goto _again; 1053 1.1 thorpej } 1054 1.1 thorpej #endif /* ADJUST_CUTOFF */ 1055 1.1 thorpej /* 1056 1.1 thorpej * If LINK_EFFICIENCY is turned on, then the first overlimit 1057 1.1 thorpej * class we encounter will send a packet if all the classes 1058 1.1 thorpej * of the link-sharing structure are overlimit. 1059 1.1 thorpej */ 1060 1.1 thorpej reset_cutoff(ifd); 1061 1.15 peter CBQTRACE(_rmc_wrr_dequeue_next, 'otsr', ifd->cutoff_); 1062 1.1 thorpej 1063 1.1 thorpej if (!ifd->efficient_ || first == NULL) 1064 1.32 joe return NULL; 1065 1.1 thorpej 1066 1.1 thorpej cl = first; 1067 1.1 thorpej cpri = cl->pri_; 1068 1.1 thorpej #if 0 /* too time-consuming for nothing */ 1069 1.1 thorpej if (cl->sleeping_) 1070 1.1 thorpej CALLOUT_STOP(&cl->callout_); 1071 1.1 thorpej cl->sleeping_ = 0; 1072 1.1 thorpej cl->undertime_.tv_sec = 0; 1073 1.1 thorpej #endif 1074 1.1 thorpej ifd->borrowed_[ifd->qi_] = cl->borrow_; 1075 1.1 thorpej ifd->cutoff_ = cl->borrow_->depth_; 1076 1.1 thorpej 1077 1.1 thorpej /* 1078 1.1 thorpej * Deque the packet and do the book keeping... 1079 1.1 thorpej */ 1080 1.1 thorpej _wrr_out: 1081 1.1 thorpej if (op == ALTDQ_REMOVE) { 1082 1.1 thorpej m = _rmc_getq(cl); 1083 1.1 thorpej if (m == NULL) 1084 1.1 thorpej panic("_rmc_wrr_dequeue_next"); 1085 1.1 thorpej if (qempty(cl->q_)) 1086 1.1 thorpej ifd->na_[cpri]--; 1087 1.1 thorpej 1088 1.1 thorpej /* 1089 1.1 thorpej * Update class statistics and link data. 1090 1.1 thorpej */ 1091 1.1 thorpej if (cl->bytes_alloc_ > 0) 1092 1.1 thorpej cl->bytes_alloc_ -= m_pktlen(m); 1093 1.1 thorpej 1094 1.1 thorpej if ((cl->bytes_alloc_ <= 0) || first == cl) 1095 1.1 thorpej ifd->active_[cl->pri_] = cl->peer_; 1096 1.1 thorpej else 1097 1.1 thorpej ifd->active_[cl->pri_] = cl; 1098 1.1 thorpej 1099 1.1 thorpej ifd->class_[ifd->qi_] = cl; 1100 1.1 thorpej ifd->curlen_[ifd->qi_] = m_pktlen(m); 1101 1.1 thorpej ifd->now_[ifd->qi_] = now; 1102 1.1 thorpej ifd->qi_ = (ifd->qi_ + 1) % ifd->maxqueued_; 1103 1.1 thorpej ifd->queued_++; 1104 1.1 thorpej } else { 1105 1.1 thorpej /* mode == ALTDQ_PPOLL */ 1106 1.1 thorpej m = _rmc_pollq(cl); 1107 1.1 thorpej ifd->pollcache_ = cl; 1108 1.1 thorpej } 1109 1.32 joe return m; 1110 1.1 thorpej } 1111 1.1 thorpej 1112 1.1 thorpej /* 1113 1.1 thorpej * Dequeue & return next packet from the highest priority class that 1114 1.1 thorpej * has a packet to send & has enough allocation to send it. This 1115 1.1 thorpej * routine is called by a driver whenever it needs a new packet to 1116 1.1 thorpej * output. 1117 1.1 thorpej */ 1118 1.1 thorpej static mbuf_t * 1119 1.15 peter _rmc_prr_dequeue_next(struct rm_ifdat *ifd, int op) 1120 1.1 thorpej { 1121 1.1 thorpej mbuf_t *m; 1122 1.15 peter int cpri; 1123 1.1 thorpej struct rm_class *cl, *first = NULL; 1124 1.26 ozaki struct timespec now; 1125 1.1 thorpej 1126 1.1 thorpej RM_GETTIME(now); 1127 1.1 thorpej 1128 1.1 thorpej /* 1129 1.1 thorpej * if the driver polls the top of the queue and then removes 1130 1.1 thorpej * the polled packet, we must return the same packet. 1131 1.1 thorpej */ 1132 1.1 thorpej if (op == ALTDQ_REMOVE && ifd->pollcache_) { 1133 1.1 thorpej cl = ifd->pollcache_; 1134 1.1 thorpej cpri = cl->pri_; 1135 1.1 thorpej ifd->pollcache_ = NULL; 1136 1.1 thorpej goto _prr_out; 1137 1.1 thorpej } else { 1138 1.1 thorpej /* mode == ALTDQ_POLL || pollcache == NULL */ 1139 1.1 thorpej ifd->pollcache_ = NULL; 1140 1.1 thorpej ifd->borrowed_[ifd->qi_] = NULL; 1141 1.1 thorpej } 1142 1.1 thorpej #ifdef ADJUST_CUTOFF 1143 1.1 thorpej _again: 1144 1.1 thorpej #endif 1145 1.1 thorpej for (cpri = RM_MAXPRIO - 1; cpri >= 0; cpri--) { 1146 1.1 thorpej if (ifd->na_[cpri] == 0) 1147 1.1 thorpej continue; 1148 1.1 thorpej cl = ifd->active_[cpri]; 1149 1.1 thorpej ASSERT(cl != NULL); 1150 1.1 thorpej do { 1151 1.1 thorpej if (!qempty(cl->q_)) { 1152 1.1 thorpej if ((cl->undertime_.tv_sec == 0) || 1153 1.1 thorpej rmc_under_limit(cl, &now)) 1154 1.1 thorpej goto _prr_out; 1155 1.1 thorpej if (first == NULL && cl->borrow_ != NULL) 1156 1.1 thorpej first = cl; 1157 1.1 thorpej } 1158 1.1 thorpej cl = cl->peer_; 1159 1.1 thorpej } while (cl != ifd->active_[cpri]); 1160 1.1 thorpej } 1161 1.1 thorpej 1162 1.1 thorpej #ifdef ADJUST_CUTOFF 1163 1.1 thorpej /* 1164 1.1 thorpej * no underlimit class found. if cutoff is taking effect, increase 1165 1.1 thorpej * cutoff and try again. 1166 1.1 thorpej */ 1167 1.1 thorpej if (first != NULL && ifd->cutoff_ < ifd->root_->depth_) { 1168 1.1 thorpej ifd->cutoff_++; 1169 1.1 thorpej goto _again; 1170 1.1 thorpej } 1171 1.1 thorpej #endif /* ADJUST_CUTOFF */ 1172 1.1 thorpej /* 1173 1.1 thorpej * If LINK_EFFICIENCY is turned on, then the first overlimit 1174 1.1 thorpej * class we encounter will send a packet if all the classes 1175 1.1 thorpej * of the link-sharing structure are overlimit. 1176 1.1 thorpej */ 1177 1.1 thorpej reset_cutoff(ifd); 1178 1.1 thorpej if (!ifd->efficient_ || first == NULL) 1179 1.32 joe return NULL; 1180 1.1 thorpej 1181 1.1 thorpej cl = first; 1182 1.1 thorpej cpri = cl->pri_; 1183 1.1 thorpej #if 0 /* too time-consuming for nothing */ 1184 1.1 thorpej if (cl->sleeping_) 1185 1.1 thorpej CALLOUT_STOP(&cl->callout_); 1186 1.1 thorpej cl->sleeping_ = 0; 1187 1.1 thorpej cl->undertime_.tv_sec = 0; 1188 1.1 thorpej #endif 1189 1.1 thorpej ifd->borrowed_[ifd->qi_] = cl->borrow_; 1190 1.1 thorpej ifd->cutoff_ = cl->borrow_->depth_; 1191 1.1 thorpej 1192 1.1 thorpej /* 1193 1.1 thorpej * Deque the packet and do the book keeping... 1194 1.1 thorpej */ 1195 1.1 thorpej _prr_out: 1196 1.1 thorpej if (op == ALTDQ_REMOVE) { 1197 1.1 thorpej m = _rmc_getq(cl); 1198 1.1 thorpej if (m == NULL) 1199 1.1 thorpej panic("_rmc_prr_dequeue_next"); 1200 1.1 thorpej if (qempty(cl->q_)) 1201 1.1 thorpej ifd->na_[cpri]--; 1202 1.1 thorpej 1203 1.1 thorpej ifd->active_[cpri] = cl->peer_; 1204 1.1 thorpej 1205 1.1 thorpej ifd->class_[ifd->qi_] = cl; 1206 1.1 thorpej ifd->curlen_[ifd->qi_] = m_pktlen(m); 1207 1.1 thorpej ifd->now_[ifd->qi_] = now; 1208 1.1 thorpej ifd->qi_ = (ifd->qi_ + 1) % ifd->maxqueued_; 1209 1.1 thorpej ifd->queued_++; 1210 1.1 thorpej } else { 1211 1.1 thorpej /* mode == ALTDQ_POLL */ 1212 1.1 thorpej m = _rmc_pollq(cl); 1213 1.1 thorpej ifd->pollcache_ = cl; 1214 1.1 thorpej } 1215 1.32 joe return m; 1216 1.1 thorpej } 1217 1.1 thorpej 1218 1.1 thorpej /* 1219 1.1 thorpej * mbuf_t * 1220 1.26 ozaki * rmc_dequeue_next(struct rm_ifdat *ifd, struct timespec *now) - this function 1221 1.1 thorpej * is invoked by the packet driver to get the next packet to be 1222 1.1 thorpej * dequeued and output on the link. If WRR is enabled, then the 1223 1.1 thorpej * WRR dequeue next routine will determine the next packet to sent. 1224 1.1 thorpej * Otherwise, packet-by-packet round robin is invoked. 1225 1.1 thorpej * 1226 1.1 thorpej * Returns: NULL, if a packet is not available or if all 1227 1.1 thorpej * classes are overlimit. 1228 1.1 thorpej * 1229 1.1 thorpej * Otherwise, Pointer to the next packet. 1230 1.1 thorpej */ 1231 1.1 thorpej 1232 1.1 thorpej mbuf_t * 1233 1.15 peter rmc_dequeue_next(struct rm_ifdat *ifd, int mode) 1234 1.1 thorpej { 1235 1.1 thorpej if (ifd->queued_ >= ifd->maxqueued_) 1236 1.32 joe return NULL; 1237 1.1 thorpej else if (ifd->wrr_) 1238 1.1 thorpej return (_rmc_wrr_dequeue_next(ifd, mode)); 1239 1.1 thorpej else 1240 1.1 thorpej return (_rmc_prr_dequeue_next(ifd, mode)); 1241 1.1 thorpej } 1242 1.1 thorpej 1243 1.1 thorpej /* 1244 1.1 thorpej * Update the utilization estimate for the packet that just completed. 1245 1.1 thorpej * The packet's class & the parent(s) of that class all get their 1246 1.1 thorpej * estimators updated. This routine is called by the driver's output- 1247 1.1 thorpej * packet-completion interrupt service routine. 1248 1.1 thorpej */ 1249 1.1 thorpej 1250 1.1 thorpej /* 1251 1.1 thorpej * a macro to approximate "divide by 1000" that gives 0.000999, 1252 1.1 thorpej * if a value has enough effective digits. 1253 1.1 thorpej * (on pentium, mul takes 9 cycles but div takes 46!) 1254 1.1 thorpej */ 1255 1.1 thorpej #define NSEC_TO_USEC(t) (((t) >> 10) + ((t) >> 16) + ((t) >> 17)) 1256 1.25 ozaki /* Don't worry. Recent compilers don't use div. */ 1257 1.25 ozaki #define PSEC_TO_USEC(t) ((t) / 1000 / 1000) 1258 1.1 thorpej void 1259 1.15 peter rmc_update_class_util(struct rm_ifdat *ifd) 1260 1.1 thorpej { 1261 1.27 ozaki int64_t idle, avgidle, pktlen; 1262 1.27 ozaki int64_t pkt_time; 1263 1.27 ozaki int64_t tidle; 1264 1.23 ozaki rm_class_t *cl, *cl0, *borrowed; 1265 1.1 thorpej rm_class_t *borrows; 1266 1.26 ozaki struct timespec *nowp; 1267 1.1 thorpej 1268 1.1 thorpej /* 1269 1.1 thorpej * Get the most recent completed class. 1270 1.1 thorpej */ 1271 1.1 thorpej if ((cl = ifd->class_[ifd->qo_]) == NULL) 1272 1.1 thorpej return; 1273 1.1 thorpej 1274 1.23 ozaki cl0 = cl; 1275 1.27 ozaki pktlen = (int64_t)ifd->curlen_[ifd->qo_]; 1276 1.1 thorpej borrowed = ifd->borrowed_[ifd->qo_]; 1277 1.1 thorpej borrows = borrowed; 1278 1.1 thorpej 1279 1.1 thorpej PKTCNTR_ADD(&cl->stats_.xmit_cnt, pktlen); 1280 1.1 thorpej 1281 1.1 thorpej /* 1282 1.15 peter * Run estimator on class and its ancestors. 1283 1.1 thorpej */ 1284 1.1 thorpej /* 1285 1.1 thorpej * rm_update_class_util is designed to be called when the 1286 1.1 thorpej * transfer is completed from a xmit complete interrupt, 1287 1.1 thorpej * but most drivers don't implement an upcall for that. 1288 1.1 thorpej * so, just use estimated completion time. 1289 1.1 thorpej * as a result, ifd->qi_ and ifd->qo_ are always synced. 1290 1.1 thorpej */ 1291 1.1 thorpej nowp = &ifd->now_[ifd->qo_]; 1292 1.1 thorpej /* get pkt_time (for link) in usec */ 1293 1.1 thorpej #if 1 /* use approximation */ 1294 1.27 ozaki pkt_time = (int64_t)ifd->curlen_[ifd->qo_] * (int64_t)ifd->ps_per_byte_; 1295 1.26 ozaki pkt_time = PSEC_TO_NSEC(pkt_time); 1296 1.1 thorpej #else 1297 1.1 thorpej pkt_time = ifd->curlen_[ifd->qo_] * ifd->ns_per_byte_ / 1000; 1298 1.1 thorpej #endif 1299 1.28 ozaki if (ifd->ifq_->altq_ifp->if_type == IFT_PPP) { 1300 1.28 ozaki if (TS_LT(nowp, &ifd->ifnow_)) { 1301 1.28 ozaki int iftime; 1302 1.1 thorpej 1303 1.28 ozaki /* 1304 1.28 ozaki * make sure the estimated completion time does not go 1305 1.28 ozaki * too far. it can happen when the link layer supports 1306 1.28 ozaki * data compression or the interface speed is set to 1307 1.28 ozaki * a much lower value. 1308 1.28 ozaki */ 1309 1.28 ozaki TS_DELTA(&ifd->ifnow_, nowp, iftime); 1310 1.28 ozaki if (iftime+pkt_time < ifd->maxiftime_) { 1311 1.28 ozaki TS_ADD_DELTA(&ifd->ifnow_, pkt_time, &ifd->ifnow_); 1312 1.28 ozaki } else { 1313 1.28 ozaki TS_ADD_DELTA(nowp, ifd->maxiftime_, &ifd->ifnow_); 1314 1.28 ozaki } 1315 1.28 ozaki } else { 1316 1.28 ozaki TS_ADD_DELTA(nowp, pkt_time, &ifd->ifnow_); 1317 1.28 ozaki } 1318 1.28 ozaki } else { 1319 1.28 ozaki if (TS_LT(nowp, &ifd->ifnow_)) { 1320 1.26 ozaki TS_ADD_DELTA(&ifd->ifnow_, pkt_time, &ifd->ifnow_); 1321 1.1 thorpej } else { 1322 1.28 ozaki TS_ADD_DELTA(nowp, pkt_time, &ifd->ifnow_); 1323 1.1 thorpej } 1324 1.1 thorpej } 1325 1.1 thorpej 1326 1.1 thorpej while (cl != NULL) { 1327 1.26 ozaki TS_DELTA(&ifd->ifnow_, &cl->last_, idle); 1328 1.26 ozaki if (idle >= 2000000000) 1329 1.1 thorpej /* 1330 1.1 thorpej * this class is idle enough, reset avgidle. 1331 1.26 ozaki * (TS_DELTA returns 2000000000 ns when delta is large.) 1332 1.1 thorpej */ 1333 1.1 thorpej cl->avgidle_ = cl->maxidle_; 1334 1.1 thorpej 1335 1.1 thorpej /* get pkt_time (for class) in usec */ 1336 1.1 thorpej #if 1 /* use approximation */ 1337 1.27 ozaki pkt_time = pktlen * (int64_t)cl->ps_per_byte_; 1338 1.26 ozaki pkt_time = PSEC_TO_NSEC(pkt_time); 1339 1.1 thorpej #else 1340 1.1 thorpej pkt_time = pktlen * cl->ns_per_byte_ / 1000; 1341 1.1 thorpej #endif 1342 1.1 thorpej idle -= pkt_time; 1343 1.1 thorpej 1344 1.1 thorpej avgidle = cl->avgidle_; 1345 1.1 thorpej avgidle += idle - (avgidle >> RM_FILTER_GAIN); 1346 1.1 thorpej cl->avgidle_ = avgidle; 1347 1.9 perry 1348 1.1 thorpej /* Are we overlimit ? */ 1349 1.1 thorpej if (avgidle <= 0) { 1350 1.15 peter CBQTRACE(rmc_update_class_util, 'milo', cl->stats_.handle); 1351 1.1 thorpej #if 1 /* ALTQ */ 1352 1.1 thorpej /* 1353 1.1 thorpej * need some lower bound for avgidle, otherwise 1354 1.1 thorpej * a borrowing class gets unbounded penalty. 1355 1.1 thorpej */ 1356 1.1 thorpej if (avgidle < cl->minidle_) 1357 1.1 thorpej avgidle = cl->avgidle_ = cl->minidle_; 1358 1.1 thorpej #endif 1359 1.1 thorpej /* set next idle to make avgidle 0 */ 1360 1.1 thorpej tidle = pkt_time + 1361 1.1 thorpej (((1 - RM_POWER) * avgidle) >> RM_FILTER_GAIN); 1362 1.26 ozaki TS_ADD_DELTA(nowp, tidle, &cl->undertime_); 1363 1.1 thorpej ++cl->stats_.over; 1364 1.1 thorpej } else { 1365 1.1 thorpej cl->avgidle_ = 1366 1.1 thorpej (avgidle > cl->maxidle_) ? cl->maxidle_ : avgidle; 1367 1.1 thorpej cl->undertime_.tv_sec = 0; 1368 1.1 thorpej if (cl->sleeping_) { 1369 1.1 thorpej CALLOUT_STOP(&cl->callout_); 1370 1.1 thorpej cl->sleeping_ = 0; 1371 1.1 thorpej } 1372 1.1 thorpej } 1373 1.1 thorpej 1374 1.1 thorpej if (borrows != NULL) { 1375 1.1 thorpej if (borrows != cl) 1376 1.1 thorpej ++cl->stats_.borrows; 1377 1.1 thorpej else 1378 1.1 thorpej borrows = NULL; 1379 1.1 thorpej } 1380 1.1 thorpej cl->last_ = ifd->ifnow_; 1381 1.1 thorpej cl->last_pkttime_ = pkt_time; 1382 1.1 thorpej 1383 1.1 thorpej #if 1 1384 1.23 ozaki if (cl->parent_ == NULL && cl != cl0) { 1385 1.1 thorpej /* take stats of root class */ 1386 1.1 thorpej PKTCNTR_ADD(&cl->stats_.xmit_cnt, pktlen); 1387 1.1 thorpej } 1388 1.1 thorpej #endif 1389 1.1 thorpej 1390 1.1 thorpej cl = cl->parent_; 1391 1.9 perry } 1392 1.1 thorpej 1393 1.1 thorpej /* 1394 1.1 thorpej * Check to see if cutoff needs to set to a new level. 1395 1.1 thorpej */ 1396 1.1 thorpej cl = ifd->class_[ifd->qo_]; 1397 1.1 thorpej if (borrowed && (ifd->cutoff_ >= borrowed->depth_)) { 1398 1.1 thorpej #if 1 /* ALTQ */ 1399 1.26 ozaki if ((qlen(cl->q_) <= 0) || TS_LT(nowp, &borrowed->undertime_)) { 1400 1.1 thorpej rmc_tl_satisfied(ifd, nowp); 1401 1.15 peter CBQTRACE(rmc_update_class_util, 'broe', ifd->cutoff_); 1402 1.9 perry } else { 1403 1.1 thorpej ifd->cutoff_ = borrowed->depth_; 1404 1.15 peter CBQTRACE(rmc_update_class_util, 'ffob', borrowed->depth_); 1405 1.1 thorpej } 1406 1.1 thorpej #else /* !ALTQ */ 1407 1.26 ozaki if ((qlen(cl->q_) <= 1) || TS_LT(&now, &borrowed->undertime_)) { 1408 1.1 thorpej reset_cutoff(ifd); 1409 1.1 thorpej #ifdef notdef 1410 1.1 thorpej rmc_tl_satisfied(ifd, &now); 1411 1.1 thorpej #endif 1412 1.15 peter CBQTRACE(rmc_update_class_util, 'broe', ifd->cutoff_); 1413 1.9 perry } else { 1414 1.1 thorpej ifd->cutoff_ = borrowed->depth_; 1415 1.15 peter CBQTRACE(rmc_update_class_util, 'ffob', borrowed->depth_); 1416 1.1 thorpej } 1417 1.1 thorpej #endif /* !ALTQ */ 1418 1.1 thorpej } 1419 1.1 thorpej 1420 1.1 thorpej /* 1421 1.1 thorpej * Release class slot 1422 1.1 thorpej */ 1423 1.1 thorpej ifd->borrowed_[ifd->qo_] = NULL; 1424 1.1 thorpej ifd->class_[ifd->qo_] = NULL; 1425 1.1 thorpej ifd->qo_ = (ifd->qo_ + 1) % ifd->maxqueued_; 1426 1.1 thorpej ifd->queued_--; 1427 1.1 thorpej } 1428 1.1 thorpej 1429 1.1 thorpej /* 1430 1.1 thorpej * void 1431 1.1 thorpej * rmc_drop_action(struct rm_class *cl) - Generic (not protocol-specific) 1432 1.1 thorpej * over-limit action routines. These get invoked by rmc_under_limit() 1433 1.1 thorpej * if a class with packets to send if over its bandwidth limit & can't 1434 1.1 thorpej * borrow from a parent class. 1435 1.1 thorpej * 1436 1.1 thorpej * Returns: NONE 1437 1.1 thorpej */ 1438 1.1 thorpej 1439 1.1 thorpej static void 1440 1.15 peter rmc_drop_action(struct rm_class *cl) 1441 1.1 thorpej { 1442 1.1 thorpej struct rm_ifdat *ifd = cl->ifdat_; 1443 1.1 thorpej 1444 1.1 thorpej ASSERT(qlen(cl->q_) > 0); 1445 1.1 thorpej _rmc_dropq(cl); 1446 1.1 thorpej if (qempty(cl->q_)) 1447 1.1 thorpej ifd->na_[cl->pri_]--; 1448 1.1 thorpej } 1449 1.1 thorpej 1450 1.15 peter void 1451 1.15 peter rmc_dropall(struct rm_class *cl) 1452 1.1 thorpej { 1453 1.15 peter struct rm_ifdat *ifd = cl->ifdat_; 1454 1.9 perry 1455 1.1 thorpej if (!qempty(cl->q_)) { 1456 1.1 thorpej _flushq(cl->q_); 1457 1.9 perry 1458 1.1 thorpej ifd->na_[cl->pri_]--; 1459 1.1 thorpej } 1460 1.1 thorpej } 1461 1.1 thorpej 1462 1.1 thorpej #if (__FreeBSD_version > 300000) 1463 1.21 christos static int tvhzto(struct timeval *); 1464 1.1 thorpej 1465 1.1 thorpej static int 1466 1.21 christos tvhzto(struct timeval *tv) 1467 1.1 thorpej { 1468 1.1 thorpej struct timeval t2; 1469 1.1 thorpej 1470 1.1 thorpej getmicrotime(&t2); 1471 1.1 thorpej t2.tv_sec = tv->tv_sec - t2.tv_sec; 1472 1.1 thorpej t2.tv_usec = tv->tv_usec - t2.tv_usec; 1473 1.32 joe return tvtohz(&t2); 1474 1.1 thorpej } 1475 1.1 thorpej #endif /* __FreeBSD_version > 300000 */ 1476 1.1 thorpej 1477 1.1 thorpej /* 1478 1.1 thorpej * void 1479 1.1 thorpej * rmc_delay_action(struct rm_class *cl) - This function is the generic CBQ 1480 1.1 thorpej * delay action routine. It is invoked via rmc_under_limit when the 1481 1.30 andvar * packet is discovered to be overlimit. 1482 1.1 thorpej * 1483 1.1 thorpej * If the delay action is result of borrow class being overlimit, then 1484 1.1 thorpej * delay for the offtime of the borrowing class that is overlimit. 1485 1.1 thorpej * 1486 1.1 thorpej * Returns: NONE 1487 1.1 thorpej */ 1488 1.1 thorpej 1489 1.1 thorpej void 1490 1.15 peter rmc_delay_action(struct rm_class *cl, struct rm_class *borrow) 1491 1.1 thorpej { 1492 1.26 ozaki int t; 1493 1.27 ozaki int64_t ndelay, extradelay; 1494 1.1 thorpej 1495 1.1 thorpej cl->stats_.overactions++; 1496 1.24 ozaki if (borrow != NULL) 1497 1.26 ozaki TS_DELTA(&borrow->undertime_, &cl->overtime_, ndelay); 1498 1.24 ozaki else 1499 1.26 ozaki TS_DELTA(&cl->undertime_, &cl->overtime_, ndelay); 1500 1.1 thorpej #ifndef BORROW_OFFTIME 1501 1.16 mrg ndelay += cl->offtime_; 1502 1.1 thorpej #endif 1503 1.1 thorpej 1504 1.1 thorpej if (!cl->sleeping_) { 1505 1.15 peter CBQTRACE(rmc_delay_action, 'yled', cl->stats_.handle); 1506 1.1 thorpej #ifdef BORROW_OFFTIME 1507 1.1 thorpej if (borrow != NULL) 1508 1.1 thorpej extradelay = borrow->offtime_; 1509 1.1 thorpej else 1510 1.1 thorpej #endif 1511 1.1 thorpej extradelay = cl->offtime_; 1512 1.1 thorpej 1513 1.1 thorpej #ifdef ALTQ 1514 1.1 thorpej /* 1515 1.1 thorpej * XXX recalculate suspend time: 1516 1.1 thorpej * current undertime is (tidle + pkt_time) calculated 1517 1.1 thorpej * from the last transmission. 1518 1.1 thorpej * tidle: time required to bring avgidle back to 0 1519 1.1 thorpej * pkt_time: target waiting time for this class 1520 1.1 thorpej * we need to replace pkt_time by offtime 1521 1.1 thorpej */ 1522 1.1 thorpej extradelay -= cl->last_pkttime_; 1523 1.1 thorpej #endif 1524 1.1 thorpej if (extradelay > 0) { 1525 1.26 ozaki TS_ADD_DELTA(&cl->undertime_, extradelay, &cl->undertime_); 1526 1.16 mrg ndelay += extradelay; 1527 1.1 thorpej } 1528 1.1 thorpej 1529 1.1 thorpej cl->sleeping_ = 1; 1530 1.1 thorpej cl->stats_.delays++; 1531 1.1 thorpej 1532 1.1 thorpej /* 1533 1.1 thorpej * Since packets are phased randomly with respect to the 1534 1.1 thorpej * clock, 1 tick (the next clock tick) can be an arbitrarily 1535 1.1 thorpej * short time so we have to wait for at least two ticks. 1536 1.1 thorpej * NOTE: If there's no other traffic, we need the timer as 1537 1.1 thorpej * a 'backstop' to restart this class. 1538 1.9 perry */ 1539 1.26 ozaki if (NSEC_TO_USEC(ndelay) > tick * 2) { 1540 1.1 thorpej #ifdef __FreeBSD__ 1541 1.1 thorpej /* FreeBSD rounds up the tick */ 1542 1.21 christos t = tvhzto(&cl->undertime_); 1543 1.1 thorpej #else 1544 1.1 thorpej /* other BSDs round down the tick */ 1545 1.26 ozaki t = tshzto(&cl->undertime_) + 1; 1546 1.1 thorpej #endif 1547 1.1 thorpej } else 1548 1.1 thorpej t = 2; 1549 1.1 thorpej CALLOUT_RESET(&cl->callout_, t, 1550 1.20 christos (timeout_t *)rmc_restart, (void *)cl); 1551 1.1 thorpej } 1552 1.1 thorpej } 1553 1.1 thorpej 1554 1.1 thorpej /* 1555 1.1 thorpej * void 1556 1.1 thorpej * rmc_restart() - is just a helper routine for rmc_delay_action -- it is 1557 1.1 thorpej * called by the system timer code & is responsible checking if the 1558 1.1 thorpej * class is still sleeping (it might have been restarted as a side 1559 1.1 thorpej * effect of the queue scan on a packet arrival) and, if so, restarting 1560 1.1 thorpej * output for the class. Inspecting the class state & restarting output 1561 1.1 thorpej * require locking the class structure. In general the driver is 1562 1.1 thorpej * responsible for locking but this is the only routine that is not 1563 1.1 thorpej * called directly or indirectly from the interface driver so it has 1564 1.1 thorpej * know about system locking conventions. Under bsd, locking is done 1565 1.4 thorpej * by raising IPL to splnet so that's what's implemented here. On a 1566 1.1 thorpej * different system this would probably need to be changed. 1567 1.1 thorpej * 1568 1.1 thorpej * Returns: NONE 1569 1.1 thorpej */ 1570 1.1 thorpej 1571 1.1 thorpej static void 1572 1.15 peter rmc_restart(struct rm_class *cl) 1573 1.1 thorpej { 1574 1.15 peter struct rm_ifdat *ifd = cl->ifdat_; 1575 1.15 peter int s; 1576 1.1 thorpej 1577 1.4 thorpej s = splnet(); 1578 1.1 thorpej if (cl->sleeping_) { 1579 1.1 thorpej cl->sleeping_ = 0; 1580 1.1 thorpej cl->undertime_.tv_sec = 0; 1581 1.1 thorpej 1582 1.1 thorpej if (ifd->queued_ < ifd->maxqueued_ && ifd->restart != NULL) { 1583 1.15 peter CBQTRACE(rmc_restart, 'trts', cl->stats_.handle); 1584 1.1 thorpej (ifd->restart)(ifd->ifq_); 1585 1.1 thorpej } 1586 1.1 thorpej } 1587 1.1 thorpej splx(s); 1588 1.1 thorpej } 1589 1.1 thorpej 1590 1.1 thorpej /* 1591 1.1 thorpej * void 1592 1.1 thorpej * rmc_root_overlimit(struct rm_class *cl) - This the generic overlimit 1593 1.1 thorpej * handling routine for the root class of the link sharing structure. 1594 1.1 thorpej * 1595 1.1 thorpej * Returns: NONE 1596 1.1 thorpej */ 1597 1.1 thorpej 1598 1.1 thorpej static void 1599 1.18 christos rmc_root_overlimit(struct rm_class *cl, 1600 1.18 christos struct rm_class *borrow) 1601 1.1 thorpej { 1602 1.15 peter panic("rmc_root_overlimit"); 1603 1.1 thorpej } 1604 1.1 thorpej 1605 1.1 thorpej /* 1606 1.1 thorpej * Packet Queue handling routines. Eventually, this is to localize the 1607 1.1 thorpej * effects on the code whether queues are red queues or droptail 1608 1.1 thorpej * queues. 1609 1.1 thorpej */ 1610 1.1 thorpej 1611 1.1 thorpej static int 1612 1.15 peter _rmc_addq(rm_class_t *cl, mbuf_t *m) 1613 1.1 thorpej { 1614 1.1 thorpej #ifdef ALTQ_RIO 1615 1.9 perry if (q_is_rio(cl->q_)) 1616 1.1 thorpej return rio_addq((rio_t *)cl->red_, cl->q_, m, cl->pktattr_); 1617 1.1 thorpej #endif 1618 1.1 thorpej #ifdef ALTQ_RED 1619 1.9 perry if (q_is_red(cl->q_)) 1620 1.1 thorpej return red_addq(cl->red_, cl->q_, m, cl->pktattr_); 1621 1.1 thorpej #endif /* ALTQ_RED */ 1622 1.1 thorpej 1623 1.1 thorpej if (cl->flags_ & RMCF_CLEARDSCP) 1624 1.1 thorpej write_dsfield(m, cl->pktattr_, 0); 1625 1.1 thorpej 1626 1.1 thorpej _addq(cl->q_, m); 1627 1.32 joe return 0; 1628 1.1 thorpej } 1629 1.1 thorpej 1630 1.1 thorpej /* note: _rmc_dropq is not called for red */ 1631 1.1 thorpej static void 1632 1.15 peter _rmc_dropq(rm_class_t *cl) 1633 1.1 thorpej { 1634 1.15 peter mbuf_t *m; 1635 1.1 thorpej 1636 1.1 thorpej if ((m = _getq(cl->q_)) != NULL) 1637 1.1 thorpej m_freem(m); 1638 1.1 thorpej } 1639 1.1 thorpej 1640 1.1 thorpej static mbuf_t * 1641 1.15 peter _rmc_getq(rm_class_t *cl) 1642 1.1 thorpej { 1643 1.1 thorpej #ifdef ALTQ_RIO 1644 1.1 thorpej if (q_is_rio(cl->q_)) 1645 1.1 thorpej return rio_getq((rio_t *)cl->red_, cl->q_); 1646 1.1 thorpej #endif 1647 1.1 thorpej #ifdef ALTQ_RED 1648 1.1 thorpej if (q_is_red(cl->q_)) 1649 1.1 thorpej return red_getq(cl->red_, cl->q_); 1650 1.1 thorpej #endif 1651 1.1 thorpej return _getq(cl->q_); 1652 1.1 thorpej } 1653 1.1 thorpej 1654 1.1 thorpej static mbuf_t * 1655 1.15 peter _rmc_pollq(rm_class_t *cl) 1656 1.1 thorpej { 1657 1.1 thorpej return qhead(cl->q_); 1658 1.1 thorpej } 1659 1.1 thorpej 1660 1.1 thorpej #ifdef CBQ_TRACE 1661 1.1 thorpej 1662 1.15 peter struct cbqtrace cbqtrace_buffer[NCBQTRACE+1]; 1663 1.15 peter struct cbqtrace *cbqtrace_ptr = NULL; 1664 1.15 peter int cbqtrace_count; 1665 1.15 peter 1666 1.1 thorpej /* 1667 1.1 thorpej * DDB hook to trace cbq events: 1668 1.1 thorpej * the last 1024 events are held in a circular buffer. 1669 1.1 thorpej * use "call cbqtrace_dump(N)" to display 20 events from Nth event. 1670 1.1 thorpej */ 1671 1.1 thorpej void cbqtrace_dump(int); 1672 1.1 thorpej static char *rmc_funcname(void *); 1673 1.1 thorpej 1674 1.1 thorpej static struct rmc_funcs { 1675 1.15 peter void *func; 1676 1.15 peter char *name; 1677 1.15 peter } rmc_funcs[] = 1678 1.15 peter { 1679 1.15 peter rmc_init, "rmc_init", 1680 1.15 peter rmc_queue_packet, "rmc_queue_packet", 1681 1.15 peter rmc_under_limit, "rmc_under_limit", 1682 1.15 peter rmc_update_class_util, "rmc_update_class_util", 1683 1.15 peter rmc_delay_action, "rmc_delay_action", 1684 1.15 peter rmc_restart, "rmc_restart", 1685 1.15 peter _rmc_wrr_dequeue_next, "_rmc_wrr_dequeue_next", 1686 1.15 peter NULL, NULL 1687 1.1 thorpej }; 1688 1.1 thorpej 1689 1.15 peter static char * 1690 1.15 peter rmc_funcname(void *func) 1691 1.1 thorpej { 1692 1.1 thorpej struct rmc_funcs *fp; 1693 1.1 thorpej 1694 1.1 thorpej for (fp = rmc_funcs; fp->func != NULL; fp++) 1695 1.1 thorpej if (fp->func == func) 1696 1.1 thorpej return (fp->name); 1697 1.1 thorpej return ("unknown"); 1698 1.1 thorpej } 1699 1.1 thorpej 1700 1.15 peter void 1701 1.15 peter cbqtrace_dump(int counter) 1702 1.1 thorpej { 1703 1.15 peter int i, *p; 1704 1.15 peter char *cp; 1705 1.1 thorpej 1706 1.1 thorpej counter = counter % NCBQTRACE; 1707 1.1 thorpej p = (int *)&cbqtrace_buffer[counter]; 1708 1.9 perry 1709 1.1 thorpej for (i=0; i<20; i++) { 1710 1.1 thorpej printf("[0x%x] ", *p++); 1711 1.1 thorpej printf("%s: ", rmc_funcname((void *)*p++)); 1712 1.1 thorpej cp = (char *)p++; 1713 1.1 thorpej printf("%c%c%c%c: ", cp[0], cp[1], cp[2], cp[3]); 1714 1.1 thorpej printf("%d\n",*p++); 1715 1.1 thorpej 1716 1.1 thorpej if (p >= (int *)&cbqtrace_buffer[NCBQTRACE]) 1717 1.1 thorpej p = (int *)cbqtrace_buffer; 1718 1.1 thorpej } 1719 1.1 thorpej } 1720 1.1 thorpej #endif /* CBQ_TRACE */ 1721 1.1 thorpej #endif /* ALTQ_CBQ */ 1722 1.1 thorpej 1723 1.1 thorpej #if defined(ALTQ_CBQ) || defined(ALTQ_RED) || defined(ALTQ_RIO) || defined(ALTQ_HFSC) || defined(ALTQ_PRIQ) 1724 1.1 thorpej #if !defined(__GNUC__) || defined(ALTQ_DEBUG) 1725 1.1 thorpej 1726 1.9 perry void 1727 1.15 peter _addq(class_queue_t *q, mbuf_t *m) 1728 1.1 thorpej { 1729 1.15 peter mbuf_t *m0; 1730 1.9 perry 1731 1.1 thorpej if ((m0 = qtail(q)) != NULL) 1732 1.1 thorpej m->m_nextpkt = m0->m_nextpkt; 1733 1.1 thorpej else 1734 1.1 thorpej m0 = m; 1735 1.1 thorpej m0->m_nextpkt = m; 1736 1.1 thorpej qtail(q) = m; 1737 1.1 thorpej qlen(q)++; 1738 1.1 thorpej } 1739 1.1 thorpej 1740 1.1 thorpej mbuf_t * 1741 1.15 peter _getq(class_queue_t *q) 1742 1.1 thorpej { 1743 1.15 peter mbuf_t *m, *m0; 1744 1.9 perry 1745 1.1 thorpej if ((m = qtail(q)) == NULL) 1746 1.32 joe return NULL; 1747 1.1 thorpej if ((m0 = m->m_nextpkt) != m) 1748 1.1 thorpej m->m_nextpkt = m0->m_nextpkt; 1749 1.1 thorpej else { 1750 1.1 thorpej ASSERT(qlen(q) == 1); 1751 1.1 thorpej qtail(q) = NULL; 1752 1.1 thorpej } 1753 1.1 thorpej qlen(q)--; 1754 1.3 thorpej m0->m_nextpkt = NULL; 1755 1.32 joe return m0; 1756 1.1 thorpej } 1757 1.1 thorpej 1758 1.1 thorpej /* drop a packet at the tail of the queue */ 1759 1.1 thorpej mbuf_t * 1760 1.15 peter _getq_tail(class_queue_t *q) 1761 1.1 thorpej { 1762 1.15 peter mbuf_t *m, *m0, *prev; 1763 1.1 thorpej 1764 1.1 thorpej if ((m = m0 = qtail(q)) == NULL) 1765 1.1 thorpej return NULL; 1766 1.1 thorpej do { 1767 1.1 thorpej prev = m0; 1768 1.1 thorpej m0 = m0->m_nextpkt; 1769 1.1 thorpej } while (m0 != m); 1770 1.1 thorpej prev->m_nextpkt = m->m_nextpkt; 1771 1.1 thorpej if (prev == m) { 1772 1.1 thorpej ASSERT(qlen(q) == 1); 1773 1.1 thorpej qtail(q) = NULL; 1774 1.1 thorpej } else 1775 1.1 thorpej qtail(q) = prev; 1776 1.1 thorpej qlen(q)--; 1777 1.3 thorpej m->m_nextpkt = NULL; 1778 1.32 joe return m; 1779 1.1 thorpej } 1780 1.1 thorpej 1781 1.1 thorpej /* randomly select a packet in the queue */ 1782 1.1 thorpej mbuf_t * 1783 1.15 peter _getq_random(class_queue_t *q) 1784 1.1 thorpej { 1785 1.15 peter struct mbuf *m; 1786 1.15 peter int i, n; 1787 1.1 thorpej 1788 1.1 thorpej if ((m = qtail(q)) == NULL) 1789 1.1 thorpej return NULL; 1790 1.1 thorpej if (m->m_nextpkt == m) { 1791 1.1 thorpej ASSERT(qlen(q) == 1); 1792 1.1 thorpej qtail(q) = NULL; 1793 1.1 thorpej } else { 1794 1.1 thorpej struct mbuf *prev = NULL; 1795 1.9 perry 1796 1.22 tls n = cprng_fast32() % qlen(q) + 1; 1797 1.1 thorpej for (i = 0; i < n; i++) { 1798 1.1 thorpej prev = m; 1799 1.1 thorpej m = m->m_nextpkt; 1800 1.1 thorpej } 1801 1.1 thorpej prev->m_nextpkt = m->m_nextpkt; 1802 1.1 thorpej if (m == qtail(q)) 1803 1.1 thorpej qtail(q) = prev; 1804 1.1 thorpej } 1805 1.1 thorpej qlen(q)--; 1806 1.3 thorpej m->m_nextpkt = NULL; 1807 1.32 joe return m; 1808 1.1 thorpej } 1809 1.1 thorpej 1810 1.1 thorpej void 1811 1.15 peter _removeq(class_queue_t *q, mbuf_t *m) 1812 1.1 thorpej { 1813 1.15 peter mbuf_t *m0, *prev; 1814 1.9 perry 1815 1.1 thorpej m0 = qtail(q); 1816 1.1 thorpej do { 1817 1.1 thorpej prev = m0; 1818 1.1 thorpej m0 = m0->m_nextpkt; 1819 1.1 thorpej } while (m0 != m); 1820 1.1 thorpej prev->m_nextpkt = m->m_nextpkt; 1821 1.9 perry if (prev == m) 1822 1.1 thorpej qtail(q) = NULL; 1823 1.1 thorpej else if (qtail(q) == m) 1824 1.1 thorpej qtail(q) = prev; 1825 1.1 thorpej qlen(q)--; 1826 1.1 thorpej } 1827 1.1 thorpej 1828 1.1 thorpej void 1829 1.15 peter _flushq(class_queue_t *q) 1830 1.1 thorpej { 1831 1.1 thorpej mbuf_t *m; 1832 1.1 thorpej 1833 1.1 thorpej while ((m = _getq(q)) != NULL) 1834 1.1 thorpej m_freem(m); 1835 1.1 thorpej ASSERT(qlen(q) == 0); 1836 1.1 thorpej } 1837 1.1 thorpej 1838 1.1 thorpej #endif /* !__GNUC__ || ALTQ_DEBUG */ 1839 1.1 thorpej #endif /* ALTQ_CBQ || ALTQ_RED || ALTQ_RIO || ALTQ_HFSC || ALTQ_PRIQ */ 1840