1da8ae05dSGleb Smirnoff /*-
2772e66a6SGleb Smirnoff * Copyright (c) 1991-1997 Regents of the University of California.
3772e66a6SGleb Smirnoff * All rights reserved.
4772e66a6SGleb Smirnoff *
5772e66a6SGleb Smirnoff * Redistribution and use in source and binary forms, with or without
6772e66a6SGleb Smirnoff * modification, are permitted provided that the following conditions
7772e66a6SGleb Smirnoff * are met:
8772e66a6SGleb Smirnoff * 1. Redistributions of source code must retain the above copyright
9772e66a6SGleb Smirnoff * notice, this list of conditions and the following disclaimer.
10772e66a6SGleb Smirnoff * 2. Redistributions in binary form must reproduce the above copyright
11772e66a6SGleb Smirnoff * notice, this list of conditions and the following disclaimer in the
12772e66a6SGleb Smirnoff * documentation and/or other materials provided with the distribution.
13772e66a6SGleb Smirnoff * 3. All advertising materials mentioning features or use of this software
14772e66a6SGleb Smirnoff * must display the following acknowledgement:
15772e66a6SGleb Smirnoff * This product includes software developed by the Network Research
16772e66a6SGleb Smirnoff * Group at Lawrence Berkeley Laboratory.
17772e66a6SGleb Smirnoff * 4. Neither the name of the University nor of the Laboratory may be used
18772e66a6SGleb Smirnoff * to endorse or promote products derived from this software without
19772e66a6SGleb Smirnoff * specific prior written permission.
20772e66a6SGleb Smirnoff *
21772e66a6SGleb Smirnoff * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22772e66a6SGleb Smirnoff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23772e66a6SGleb Smirnoff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24772e66a6SGleb Smirnoff * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25772e66a6SGleb Smirnoff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26772e66a6SGleb Smirnoff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27772e66a6SGleb Smirnoff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28772e66a6SGleb Smirnoff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29772e66a6SGleb Smirnoff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30772e66a6SGleb Smirnoff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31772e66a6SGleb Smirnoff * SUCH DAMAGE.
32772e66a6SGleb Smirnoff *
33772e66a6SGleb Smirnoff * LBL code modified by speer@eng.sun.com, May 1977.
34772e66a6SGleb Smirnoff * For questions and/or comments, please send mail to cbq@ee.lbl.gov
35da8ae05dSGleb Smirnoff * $KAME: altq_rmclass.c,v 1.19 2005/04/13 03:44:25 suz Exp $
36772e66a6SGleb Smirnoff */
37772e66a6SGleb Smirnoff #include "opt_altq.h"
38772e66a6SGleb Smirnoff #include "opt_inet.h"
39772e66a6SGleb Smirnoff #include "opt_inet6.h"
40772e66a6SGleb Smirnoff #ifdef ALTQ_CBQ /* cbq is enabled by ALTQ_CBQ option in opt_altq.h */
41772e66a6SGleb Smirnoff
42772e66a6SGleb Smirnoff #include <sys/param.h>
43772e66a6SGleb Smirnoff #include <sys/malloc.h>
44772e66a6SGleb Smirnoff #include <sys/mbuf.h>
45772e66a6SGleb Smirnoff #include <sys/socket.h>
46772e66a6SGleb Smirnoff #include <sys/systm.h>
47772e66a6SGleb Smirnoff #include <sys/errno.h>
48772e66a6SGleb Smirnoff #include <sys/time.h>
49772e66a6SGleb Smirnoff
50772e66a6SGleb Smirnoff #include <net/if.h>
51772e66a6SGleb Smirnoff #include <net/if_var.h>
522c2b37adSJustin Hibbits #include <net/if_private.h>
53772e66a6SGleb Smirnoff
54772e66a6SGleb Smirnoff #include <net/altq/if_altq.h>
55772e66a6SGleb Smirnoff #include <net/altq/altq.h>
560a70aaf8SLuiz Otavio O Souza #include <net/altq/altq_codel.h>
57772e66a6SGleb Smirnoff #include <net/altq/altq_rmclass.h>
58772e66a6SGleb Smirnoff #include <net/altq/altq_rmclass_debug.h>
59772e66a6SGleb Smirnoff #include <net/altq/altq_red.h>
60772e66a6SGleb Smirnoff #include <net/altq/altq_rio.h>
61772e66a6SGleb Smirnoff
62772e66a6SGleb Smirnoff /*
63772e66a6SGleb Smirnoff * Local Macros
64772e66a6SGleb Smirnoff */
65772e66a6SGleb Smirnoff #define reset_cutoff(ifd) { ifd->cutoff_ = RM_MAXDEPTH; }
66772e66a6SGleb Smirnoff
67772e66a6SGleb Smirnoff /*
68772e66a6SGleb Smirnoff * Local routines.
69772e66a6SGleb Smirnoff */
70772e66a6SGleb Smirnoff
71772e66a6SGleb Smirnoff static int rmc_satisfied(struct rm_class *, struct timeval *);
72772e66a6SGleb Smirnoff static void rmc_wrr_set_weights(struct rm_ifdat *);
73772e66a6SGleb Smirnoff static void rmc_depth_compute(struct rm_class *);
74772e66a6SGleb Smirnoff static void rmc_depth_recompute(rm_class_t *);
75772e66a6SGleb Smirnoff
76772e66a6SGleb Smirnoff static mbuf_t *_rmc_wrr_dequeue_next(struct rm_ifdat *, int);
77772e66a6SGleb Smirnoff static mbuf_t *_rmc_prr_dequeue_next(struct rm_ifdat *, int);
78772e66a6SGleb Smirnoff
79772e66a6SGleb Smirnoff static int _rmc_addq(rm_class_t *, mbuf_t *);
80772e66a6SGleb Smirnoff static void _rmc_dropq(rm_class_t *);
81772e66a6SGleb Smirnoff static mbuf_t *_rmc_getq(rm_class_t *);
82772e66a6SGleb Smirnoff static mbuf_t *_rmc_pollq(rm_class_t *);
83772e66a6SGleb Smirnoff
84772e66a6SGleb Smirnoff static int rmc_under_limit(struct rm_class *, struct timeval *);
85772e66a6SGleb Smirnoff static void rmc_tl_satisfied(struct rm_ifdat *, struct timeval *);
86772e66a6SGleb Smirnoff static void rmc_drop_action(struct rm_class *);
8765d2f9c1SJohn Baldwin static void rmc_restart(void *);
88772e66a6SGleb Smirnoff static void rmc_root_overlimit(struct rm_class *, struct rm_class *);
89772e66a6SGleb Smirnoff
90772e66a6SGleb Smirnoff #define BORROW_OFFTIME
91772e66a6SGleb Smirnoff /*
92772e66a6SGleb Smirnoff * BORROW_OFFTIME (experimental):
93772e66a6SGleb Smirnoff * borrow the offtime of the class borrowing from.
94772e66a6SGleb Smirnoff * the reason is that when its own offtime is set, the class is unable
95772e66a6SGleb Smirnoff * to borrow much, especially when cutoff is taking effect.
96772e66a6SGleb Smirnoff * but when the borrowed class is overloaded (advidle is close to minidle),
97772e66a6SGleb Smirnoff * use the borrowing class's offtime to avoid overload.
98772e66a6SGleb Smirnoff */
99772e66a6SGleb Smirnoff #define ADJUST_CUTOFF
100772e66a6SGleb Smirnoff /*
101772e66a6SGleb Smirnoff * ADJUST_CUTOFF (experimental):
102772e66a6SGleb Smirnoff * if no underlimit class is found due to cutoff, increase cutoff and
103772e66a6SGleb Smirnoff * retry the scheduling loop.
104772e66a6SGleb Smirnoff * also, don't invoke delay_actions while cutoff is taking effect,
105772e66a6SGleb Smirnoff * since a sleeping class won't have a chance to be scheduled in the
106772e66a6SGleb Smirnoff * next loop.
107772e66a6SGleb Smirnoff *
108772e66a6SGleb Smirnoff * now heuristics for setting the top-level variable (cutoff_) becomes:
109772e66a6SGleb Smirnoff * 1. if a packet arrives for a not-overlimit class, set cutoff
110772e66a6SGleb Smirnoff * to the depth of the class.
111772e66a6SGleb Smirnoff * 2. if cutoff is i, and a packet arrives for an overlimit class
112772e66a6SGleb Smirnoff * with an underlimit ancestor at a lower level than i (say j),
113772e66a6SGleb Smirnoff * then set cutoff to j.
114772e66a6SGleb Smirnoff * 3. at scheduling a packet, if there is no underlimit class
115772e66a6SGleb Smirnoff * due to the current cutoff level, increase cutoff by 1 and
116772e66a6SGleb Smirnoff * then try to schedule again.
117772e66a6SGleb Smirnoff */
118772e66a6SGleb Smirnoff
119772e66a6SGleb Smirnoff /*
120772e66a6SGleb Smirnoff * rm_class_t *
121772e66a6SGleb Smirnoff * rmc_newclass(...) - Create a new resource management class at priority
122772e66a6SGleb Smirnoff * 'pri' on the interface given by 'ifd'.
123772e66a6SGleb Smirnoff *
124772e66a6SGleb Smirnoff * nsecPerByte is the data rate of the interface in nanoseconds/byte.
125772e66a6SGleb Smirnoff * E.g., 800 for a 10Mb/s ethernet. If the class gets less
126772e66a6SGleb Smirnoff * than 100% of the bandwidth, this number should be the
127772e66a6SGleb Smirnoff * 'effective' rate for the class. Let f be the
128772e66a6SGleb Smirnoff * bandwidth fraction allocated to this class, and let
129772e66a6SGleb Smirnoff * nsPerByte be the data rate of the output link in
130772e66a6SGleb Smirnoff * nanoseconds/byte. Then nsecPerByte is set to
131772e66a6SGleb Smirnoff * nsPerByte / f. E.g., 1600 (= 800 / .5)
132772e66a6SGleb Smirnoff * for a class that gets 50% of an ethernet's bandwidth.
133772e66a6SGleb Smirnoff *
134772e66a6SGleb Smirnoff * action the routine to call when the class is over limit.
135772e66a6SGleb Smirnoff *
136772e66a6SGleb Smirnoff * maxq max allowable queue size for class (in packets).
137772e66a6SGleb Smirnoff *
138772e66a6SGleb Smirnoff * parent parent class pointer.
139772e66a6SGleb Smirnoff *
140772e66a6SGleb Smirnoff * borrow class to borrow from (should be either 'parent' or null).
141772e66a6SGleb Smirnoff *
142772e66a6SGleb Smirnoff * maxidle max value allowed for class 'idle' time estimate (this
143772e66a6SGleb Smirnoff * parameter determines how large an initial burst of packets
144772e66a6SGleb Smirnoff * can be before overlimit action is invoked.
145772e66a6SGleb Smirnoff *
146772e66a6SGleb Smirnoff * offtime how long 'delay' action will delay when class goes over
147772e66a6SGleb Smirnoff * limit (this parameter determines the steady-state burst
148772e66a6SGleb Smirnoff * size when a class is running over its limit).
149772e66a6SGleb Smirnoff *
150772e66a6SGleb Smirnoff * Maxidle and offtime have to be computed from the following: If the
151772e66a6SGleb Smirnoff * average packet size is s, the bandwidth fraction allocated to this
152772e66a6SGleb Smirnoff * class is f, we want to allow b packet bursts, and the gain of the
153772e66a6SGleb Smirnoff * averaging filter is g (= 1 - 2^(-RM_FILTER_GAIN)), then:
154772e66a6SGleb Smirnoff *
155772e66a6SGleb Smirnoff * ptime = s * nsPerByte * (1 - f) / f
156772e66a6SGleb Smirnoff * maxidle = ptime * (1 - g^b) / g^b
157772e66a6SGleb Smirnoff * minidle = -ptime * (1 / (f - 1))
158772e66a6SGleb Smirnoff * offtime = ptime * (1 + 1/(1 - g) * (1 - g^(b - 1)) / g^(b - 1)
159772e66a6SGleb Smirnoff *
160772e66a6SGleb Smirnoff * Operationally, it's convenient to specify maxidle & offtime in units
161772e66a6SGleb Smirnoff * independent of the link bandwidth so the maxidle & offtime passed to
162772e66a6SGleb Smirnoff * this routine are the above values multiplied by 8*f/(1000*nsPerByte).
163772e66a6SGleb Smirnoff * (The constant factor is a scale factor needed to make the parameters
164772e66a6SGleb Smirnoff * integers. This scaling also means that the 'unscaled' values of
165772e66a6SGleb Smirnoff * maxidle*nsecPerByte/8 and offtime*nsecPerByte/8 will be in microseconds,
166772e66a6SGleb Smirnoff * not nanoseconds.) Also note that the 'idle' filter computation keeps
167772e66a6SGleb Smirnoff * an estimate scaled upward by 2^RM_FILTER_GAIN so the passed value of
168772e66a6SGleb Smirnoff * maxidle also must be scaled upward by this value. Thus, the passed
169772e66a6SGleb Smirnoff * values for maxidle and offtime can be computed as follows:
170772e66a6SGleb Smirnoff *
171772e66a6SGleb Smirnoff * maxidle = maxidle * 2^RM_FILTER_GAIN * 8 / (1000 * nsecPerByte)
172772e66a6SGleb Smirnoff * offtime = offtime * 8 / (1000 * nsecPerByte)
173772e66a6SGleb Smirnoff *
174772e66a6SGleb Smirnoff * When USE_HRTIME is employed, then maxidle and offtime become:
175772e66a6SGleb Smirnoff * maxidle = maxilde * (8.0 / nsecPerByte);
176772e66a6SGleb Smirnoff * offtime = offtime * (8.0 / nsecPerByte);
177772e66a6SGleb Smirnoff */
178772e66a6SGleb Smirnoff struct rm_class *
rmc_newclass(int pri,struct rm_ifdat * ifd,u_int nsecPerByte,void (* action)(rm_class_t *,rm_class_t *),int maxq,struct rm_class * parent,struct rm_class * borrow,u_int maxidle,int minidle,u_int offtime,int pktsize,int flags)179772e66a6SGleb Smirnoff rmc_newclass(int pri, struct rm_ifdat *ifd, u_int nsecPerByte,
180772e66a6SGleb Smirnoff void (*action)(rm_class_t *, rm_class_t *), int maxq,
181772e66a6SGleb Smirnoff struct rm_class *parent, struct rm_class *borrow, u_int maxidle,
182772e66a6SGleb Smirnoff int minidle, u_int offtime, int pktsize, int flags)
183772e66a6SGleb Smirnoff {
184772e66a6SGleb Smirnoff struct rm_class *cl;
185772e66a6SGleb Smirnoff struct rm_class *peer;
186772e66a6SGleb Smirnoff int s;
187772e66a6SGleb Smirnoff
188772e66a6SGleb Smirnoff if (pri >= RM_MAXPRIO)
189772e66a6SGleb Smirnoff return (NULL);
190772e66a6SGleb Smirnoff #ifndef ALTQ_RED
191772e66a6SGleb Smirnoff if (flags & RMCF_RED) {
192772e66a6SGleb Smirnoff #ifdef ALTQ_DEBUG
193772e66a6SGleb Smirnoff printf("rmc_newclass: RED not configured for CBQ!\n");
194772e66a6SGleb Smirnoff #endif
195772e66a6SGleb Smirnoff return (NULL);
196772e66a6SGleb Smirnoff }
197772e66a6SGleb Smirnoff #endif
198772e66a6SGleb Smirnoff #ifndef ALTQ_RIO
199772e66a6SGleb Smirnoff if (flags & RMCF_RIO) {
200772e66a6SGleb Smirnoff #ifdef ALTQ_DEBUG
201772e66a6SGleb Smirnoff printf("rmc_newclass: RIO not configured for CBQ!\n");
202772e66a6SGleb Smirnoff #endif
203772e66a6SGleb Smirnoff return (NULL);
204772e66a6SGleb Smirnoff }
205772e66a6SGleb Smirnoff #endif
2060a70aaf8SLuiz Otavio O Souza #ifndef ALTQ_CODEL
2070a70aaf8SLuiz Otavio O Souza if (flags & RMCF_CODEL) {
2080a70aaf8SLuiz Otavio O Souza #ifdef ALTQ_DEBUG
2090a70aaf8SLuiz Otavio O Souza printf("rmc_newclass: CODEL not configured for CBQ!\n");
2100a70aaf8SLuiz Otavio O Souza #endif
2110a70aaf8SLuiz Otavio O Souza return (NULL);
2120a70aaf8SLuiz Otavio O Souza }
2130a70aaf8SLuiz Otavio O Souza #endif
214772e66a6SGleb Smirnoff
215772e66a6SGleb Smirnoff cl = malloc(sizeof(struct rm_class), M_DEVBUF, M_NOWAIT | M_ZERO);
216772e66a6SGleb Smirnoff if (cl == NULL)
217772e66a6SGleb Smirnoff return (NULL);
218772e66a6SGleb Smirnoff CALLOUT_INIT(&cl->callout_);
219772e66a6SGleb Smirnoff cl->q_ = malloc(sizeof(class_queue_t), M_DEVBUF, M_NOWAIT | M_ZERO);
220772e66a6SGleb Smirnoff if (cl->q_ == NULL) {
221772e66a6SGleb Smirnoff free(cl, M_DEVBUF);
222772e66a6SGleb Smirnoff return (NULL);
223772e66a6SGleb Smirnoff }
224772e66a6SGleb Smirnoff
225772e66a6SGleb Smirnoff /*
226772e66a6SGleb Smirnoff * Class initialization.
227772e66a6SGleb Smirnoff */
228772e66a6SGleb Smirnoff cl->children_ = NULL;
229772e66a6SGleb Smirnoff cl->parent_ = parent;
230772e66a6SGleb Smirnoff cl->borrow_ = borrow;
231772e66a6SGleb Smirnoff cl->leaf_ = 1;
232772e66a6SGleb Smirnoff cl->ifdat_ = ifd;
233772e66a6SGleb Smirnoff cl->pri_ = pri;
234772e66a6SGleb Smirnoff cl->allotment_ = RM_NS_PER_SEC / nsecPerByte; /* Bytes per sec */
235772e66a6SGleb Smirnoff cl->depth_ = 0;
236772e66a6SGleb Smirnoff cl->qthresh_ = 0;
237772e66a6SGleb Smirnoff cl->ns_per_byte_ = nsecPerByte;
238772e66a6SGleb Smirnoff
239772e66a6SGleb Smirnoff qlimit(cl->q_) = maxq;
240772e66a6SGleb Smirnoff qtype(cl->q_) = Q_DROPHEAD;
241772e66a6SGleb Smirnoff qlen(cl->q_) = 0;
242772e66a6SGleb Smirnoff cl->flags_ = flags;
243772e66a6SGleb Smirnoff
244772e66a6SGleb Smirnoff #if 1 /* minidle is also scaled in ALTQ */
245772e66a6SGleb Smirnoff cl->minidle_ = (minidle * (int)nsecPerByte) / 8;
246772e66a6SGleb Smirnoff if (cl->minidle_ > 0)
247772e66a6SGleb Smirnoff cl->minidle_ = 0;
248772e66a6SGleb Smirnoff #else
249772e66a6SGleb Smirnoff cl->minidle_ = minidle;
250772e66a6SGleb Smirnoff #endif
251772e66a6SGleb Smirnoff cl->maxidle_ = (maxidle * nsecPerByte) / 8;
252772e66a6SGleb Smirnoff if (cl->maxidle_ == 0)
253772e66a6SGleb Smirnoff cl->maxidle_ = 1;
254772e66a6SGleb Smirnoff #if 1 /* offtime is also scaled in ALTQ */
255772e66a6SGleb Smirnoff cl->avgidle_ = cl->maxidle_;
256772e66a6SGleb Smirnoff cl->offtime_ = ((offtime * nsecPerByte) / 8) >> RM_FILTER_GAIN;
257772e66a6SGleb Smirnoff if (cl->offtime_ == 0)
258772e66a6SGleb Smirnoff cl->offtime_ = 1;
259772e66a6SGleb Smirnoff #else
260772e66a6SGleb Smirnoff cl->avgidle_ = 0;
261772e66a6SGleb Smirnoff cl->offtime_ = (offtime * nsecPerByte) / 8;
262772e66a6SGleb Smirnoff #endif
263772e66a6SGleb Smirnoff cl->overlimit = action;
264772e66a6SGleb Smirnoff
265772e66a6SGleb Smirnoff #ifdef ALTQ_RED
266772e66a6SGleb Smirnoff if (flags & (RMCF_RED|RMCF_RIO)) {
267772e66a6SGleb Smirnoff int red_flags, red_pkttime;
268772e66a6SGleb Smirnoff
269772e66a6SGleb Smirnoff red_flags = 0;
270772e66a6SGleb Smirnoff if (flags & RMCF_ECN)
271772e66a6SGleb Smirnoff red_flags |= REDF_ECN;
272772e66a6SGleb Smirnoff if (flags & RMCF_FLOWVALVE)
273772e66a6SGleb Smirnoff red_flags |= REDF_FLOWVALVE;
274772e66a6SGleb Smirnoff #ifdef ALTQ_RIO
275772e66a6SGleb Smirnoff if (flags & RMCF_CLEARDSCP)
276772e66a6SGleb Smirnoff red_flags |= RIOF_CLEARDSCP;
277772e66a6SGleb Smirnoff #endif
278772e66a6SGleb Smirnoff red_pkttime = nsecPerByte * pktsize / 1000;
279772e66a6SGleb Smirnoff
280772e66a6SGleb Smirnoff if (flags & RMCF_RED) {
281772e66a6SGleb Smirnoff cl->red_ = red_alloc(0, 0,
282772e66a6SGleb Smirnoff qlimit(cl->q_) * 10/100,
283772e66a6SGleb Smirnoff qlimit(cl->q_) * 30/100,
284772e66a6SGleb Smirnoff red_flags, red_pkttime);
285772e66a6SGleb Smirnoff if (cl->red_ != NULL)
286772e66a6SGleb Smirnoff qtype(cl->q_) = Q_RED;
287772e66a6SGleb Smirnoff }
288772e66a6SGleb Smirnoff #ifdef ALTQ_RIO
289772e66a6SGleb Smirnoff else {
290772e66a6SGleb Smirnoff cl->red_ = (red_t *)rio_alloc(0, NULL,
291772e66a6SGleb Smirnoff red_flags, red_pkttime);
292772e66a6SGleb Smirnoff if (cl->red_ != NULL)
293772e66a6SGleb Smirnoff qtype(cl->q_) = Q_RIO;
294772e66a6SGleb Smirnoff }
295772e66a6SGleb Smirnoff #endif
296772e66a6SGleb Smirnoff }
297772e66a6SGleb Smirnoff #endif /* ALTQ_RED */
2980a70aaf8SLuiz Otavio O Souza #ifdef ALTQ_CODEL
2990a70aaf8SLuiz Otavio O Souza if (flags & RMCF_CODEL) {
3000a70aaf8SLuiz Otavio O Souza cl->codel_ = codel_alloc(5, 100, 0);
3010a70aaf8SLuiz Otavio O Souza if (cl->codel_ != NULL)
3020a70aaf8SLuiz Otavio O Souza qtype(cl->q_) = Q_CODEL;
3030a70aaf8SLuiz Otavio O Souza }
3040a70aaf8SLuiz Otavio O Souza #endif
305772e66a6SGleb Smirnoff
306772e66a6SGleb Smirnoff /*
307772e66a6SGleb Smirnoff * put the class into the class tree
308772e66a6SGleb Smirnoff */
309772e66a6SGleb Smirnoff s = splnet();
310772e66a6SGleb Smirnoff IFQ_LOCK(ifd->ifq_);
311772e66a6SGleb Smirnoff if ((peer = ifd->active_[pri]) != NULL) {
312772e66a6SGleb Smirnoff /* find the last class at this pri */
313772e66a6SGleb Smirnoff cl->peer_ = peer;
314772e66a6SGleb Smirnoff while (peer->peer_ != ifd->active_[pri])
315772e66a6SGleb Smirnoff peer = peer->peer_;
316772e66a6SGleb Smirnoff peer->peer_ = cl;
317772e66a6SGleb Smirnoff } else {
318772e66a6SGleb Smirnoff ifd->active_[pri] = cl;
319772e66a6SGleb Smirnoff cl->peer_ = cl;
320772e66a6SGleb Smirnoff }
321772e66a6SGleb Smirnoff
322772e66a6SGleb Smirnoff if (cl->parent_) {
323772e66a6SGleb Smirnoff cl->next_ = parent->children_;
324772e66a6SGleb Smirnoff parent->children_ = cl;
325772e66a6SGleb Smirnoff parent->leaf_ = 0;
326772e66a6SGleb Smirnoff }
327772e66a6SGleb Smirnoff
328772e66a6SGleb Smirnoff /*
329772e66a6SGleb Smirnoff * Compute the depth of this class and its ancestors in the class
330772e66a6SGleb Smirnoff * hierarchy.
331772e66a6SGleb Smirnoff */
332772e66a6SGleb Smirnoff rmc_depth_compute(cl);
333772e66a6SGleb Smirnoff
334772e66a6SGleb Smirnoff /*
335772e66a6SGleb Smirnoff * If CBQ's WRR is enabled, then initialize the class WRR state.
336772e66a6SGleb Smirnoff */
337772e66a6SGleb Smirnoff if (ifd->wrr_) {
338772e66a6SGleb Smirnoff ifd->num_[pri]++;
339772e66a6SGleb Smirnoff ifd->alloc_[pri] += cl->allotment_;
340772e66a6SGleb Smirnoff rmc_wrr_set_weights(ifd);
341772e66a6SGleb Smirnoff }
342772e66a6SGleb Smirnoff IFQ_UNLOCK(ifd->ifq_);
343772e66a6SGleb Smirnoff splx(s);
344772e66a6SGleb Smirnoff return (cl);
345772e66a6SGleb Smirnoff }
346772e66a6SGleb Smirnoff
347772e66a6SGleb Smirnoff int
rmc_modclass(struct rm_class * cl,u_int nsecPerByte,int maxq,u_int maxidle,int minidle,u_int offtime,int pktsize)348772e66a6SGleb Smirnoff rmc_modclass(struct rm_class *cl, u_int nsecPerByte, int maxq, u_int maxidle,
349772e66a6SGleb Smirnoff int minidle, u_int offtime, int pktsize)
350772e66a6SGleb Smirnoff {
351772e66a6SGleb Smirnoff struct rm_ifdat *ifd;
352772e66a6SGleb Smirnoff u_int old_allotment;
353772e66a6SGleb Smirnoff int s;
354772e66a6SGleb Smirnoff
355772e66a6SGleb Smirnoff ifd = cl->ifdat_;
356772e66a6SGleb Smirnoff old_allotment = cl->allotment_;
357772e66a6SGleb Smirnoff
358772e66a6SGleb Smirnoff s = splnet();
359772e66a6SGleb Smirnoff IFQ_LOCK(ifd->ifq_);
360772e66a6SGleb Smirnoff cl->allotment_ = RM_NS_PER_SEC / nsecPerByte; /* Bytes per sec */
361772e66a6SGleb Smirnoff cl->qthresh_ = 0;
362772e66a6SGleb Smirnoff cl->ns_per_byte_ = nsecPerByte;
363772e66a6SGleb Smirnoff
364772e66a6SGleb Smirnoff qlimit(cl->q_) = maxq;
365772e66a6SGleb Smirnoff
366772e66a6SGleb Smirnoff #if 1 /* minidle is also scaled in ALTQ */
367772e66a6SGleb Smirnoff cl->minidle_ = (minidle * nsecPerByte) / 8;
368772e66a6SGleb Smirnoff if (cl->minidle_ > 0)
369772e66a6SGleb Smirnoff cl->minidle_ = 0;
370772e66a6SGleb Smirnoff #else
371772e66a6SGleb Smirnoff cl->minidle_ = minidle;
372772e66a6SGleb Smirnoff #endif
373772e66a6SGleb Smirnoff cl->maxidle_ = (maxidle * nsecPerByte) / 8;
374772e66a6SGleb Smirnoff if (cl->maxidle_ == 0)
375772e66a6SGleb Smirnoff cl->maxidle_ = 1;
376772e66a6SGleb Smirnoff #if 1 /* offtime is also scaled in ALTQ */
377772e66a6SGleb Smirnoff cl->avgidle_ = cl->maxidle_;
378772e66a6SGleb Smirnoff cl->offtime_ = ((offtime * nsecPerByte) / 8) >> RM_FILTER_GAIN;
379772e66a6SGleb Smirnoff if (cl->offtime_ == 0)
380772e66a6SGleb Smirnoff cl->offtime_ = 1;
381772e66a6SGleb Smirnoff #else
382772e66a6SGleb Smirnoff cl->avgidle_ = 0;
383772e66a6SGleb Smirnoff cl->offtime_ = (offtime * nsecPerByte) / 8;
384772e66a6SGleb Smirnoff #endif
385772e66a6SGleb Smirnoff
386772e66a6SGleb Smirnoff /*
387772e66a6SGleb Smirnoff * If CBQ's WRR is enabled, then initialize the class WRR state.
388772e66a6SGleb Smirnoff */
389772e66a6SGleb Smirnoff if (ifd->wrr_) {
390772e66a6SGleb Smirnoff ifd->alloc_[cl->pri_] += cl->allotment_ - old_allotment;
391772e66a6SGleb Smirnoff rmc_wrr_set_weights(ifd);
392772e66a6SGleb Smirnoff }
393772e66a6SGleb Smirnoff IFQ_UNLOCK(ifd->ifq_);
394772e66a6SGleb Smirnoff splx(s);
395772e66a6SGleb Smirnoff return (0);
396772e66a6SGleb Smirnoff }
397772e66a6SGleb Smirnoff
398772e66a6SGleb Smirnoff /*
399772e66a6SGleb Smirnoff * static void
400772e66a6SGleb Smirnoff * rmc_wrr_set_weights(struct rm_ifdat *ifdat) - This function computes
401772e66a6SGleb Smirnoff * the appropriate run robin weights for the CBQ weighted round robin
402772e66a6SGleb Smirnoff * algorithm.
403772e66a6SGleb Smirnoff *
404772e66a6SGleb Smirnoff * Returns: NONE
405772e66a6SGleb Smirnoff */
406772e66a6SGleb Smirnoff
407772e66a6SGleb Smirnoff static void
rmc_wrr_set_weights(struct rm_ifdat * ifd)408772e66a6SGleb Smirnoff rmc_wrr_set_weights(struct rm_ifdat *ifd)
409772e66a6SGleb Smirnoff {
410772e66a6SGleb Smirnoff int i;
411772e66a6SGleb Smirnoff struct rm_class *cl, *clh;
412772e66a6SGleb Smirnoff
413772e66a6SGleb Smirnoff for (i = 0; i < RM_MAXPRIO; i++) {
414772e66a6SGleb Smirnoff /*
415772e66a6SGleb Smirnoff * This is inverted from that of the simulator to
416772e66a6SGleb Smirnoff * maintain precision.
417772e66a6SGleb Smirnoff */
418772e66a6SGleb Smirnoff if (ifd->num_[i] == 0)
419772e66a6SGleb Smirnoff ifd->M_[i] = 0;
420772e66a6SGleb Smirnoff else
421772e66a6SGleb Smirnoff ifd->M_[i] = ifd->alloc_[i] /
422772e66a6SGleb Smirnoff (ifd->num_[i] * ifd->maxpkt_);
423772e66a6SGleb Smirnoff /*
424772e66a6SGleb Smirnoff * Compute the weighted allotment for each class.
425772e66a6SGleb Smirnoff * This takes the expensive div instruction out
426772e66a6SGleb Smirnoff * of the main loop for the wrr scheduling path.
427772e66a6SGleb Smirnoff * These only get recomputed when a class comes or
428772e66a6SGleb Smirnoff * goes.
429772e66a6SGleb Smirnoff */
430772e66a6SGleb Smirnoff if (ifd->active_[i] != NULL) {
431772e66a6SGleb Smirnoff clh = cl = ifd->active_[i];
432772e66a6SGleb Smirnoff do {
433772e66a6SGleb Smirnoff /* safe-guard for slow link or alloc_ == 0 */
434772e66a6SGleb Smirnoff if (ifd->M_[i] == 0)
435772e66a6SGleb Smirnoff cl->w_allotment_ = 0;
436772e66a6SGleb Smirnoff else
437772e66a6SGleb Smirnoff cl->w_allotment_ = cl->allotment_ /
438772e66a6SGleb Smirnoff ifd->M_[i];
439772e66a6SGleb Smirnoff cl = cl->peer_;
440772e66a6SGleb Smirnoff } while ((cl != NULL) && (cl != clh));
441772e66a6SGleb Smirnoff }
442772e66a6SGleb Smirnoff }
443772e66a6SGleb Smirnoff }
444772e66a6SGleb Smirnoff
445772e66a6SGleb Smirnoff int
rmc_get_weight(struct rm_ifdat * ifd,int pri)446772e66a6SGleb Smirnoff rmc_get_weight(struct rm_ifdat *ifd, int pri)
447772e66a6SGleb Smirnoff {
448772e66a6SGleb Smirnoff if ((pri >= 0) && (pri < RM_MAXPRIO))
449772e66a6SGleb Smirnoff return (ifd->M_[pri]);
450772e66a6SGleb Smirnoff else
451772e66a6SGleb Smirnoff return (0);
452772e66a6SGleb Smirnoff }
453772e66a6SGleb Smirnoff
454772e66a6SGleb Smirnoff /*
455772e66a6SGleb Smirnoff * static void
456772e66a6SGleb Smirnoff * rmc_depth_compute(struct rm_class *cl) - This function computes the
457772e66a6SGleb Smirnoff * appropriate depth of class 'cl' and its ancestors.
458772e66a6SGleb Smirnoff *
459772e66a6SGleb Smirnoff * Returns: NONE
460772e66a6SGleb Smirnoff */
461772e66a6SGleb Smirnoff
462772e66a6SGleb Smirnoff static void
rmc_depth_compute(struct rm_class * cl)463772e66a6SGleb Smirnoff rmc_depth_compute(struct rm_class *cl)
464772e66a6SGleb Smirnoff {
465772e66a6SGleb Smirnoff rm_class_t *t = cl, *p;
466772e66a6SGleb Smirnoff
467772e66a6SGleb Smirnoff /*
468772e66a6SGleb Smirnoff * Recompute the depth for the branch of the tree.
469772e66a6SGleb Smirnoff */
470772e66a6SGleb Smirnoff while (t != NULL) {
471772e66a6SGleb Smirnoff p = t->parent_;
472772e66a6SGleb Smirnoff if (p && (t->depth_ >= p->depth_)) {
473772e66a6SGleb Smirnoff p->depth_ = t->depth_ + 1;
474772e66a6SGleb Smirnoff t = p;
475772e66a6SGleb Smirnoff } else
476772e66a6SGleb Smirnoff t = NULL;
477772e66a6SGleb Smirnoff }
478772e66a6SGleb Smirnoff }
479772e66a6SGleb Smirnoff
480772e66a6SGleb Smirnoff /*
481772e66a6SGleb Smirnoff * static void
482772e66a6SGleb Smirnoff * rmc_depth_recompute(struct rm_class *cl) - This function re-computes
483772e66a6SGleb Smirnoff * the depth of the tree after a class has been deleted.
484772e66a6SGleb Smirnoff *
485772e66a6SGleb Smirnoff * Returns: NONE
486772e66a6SGleb Smirnoff */
487772e66a6SGleb Smirnoff
488772e66a6SGleb Smirnoff static void
rmc_depth_recompute(rm_class_t * cl)489772e66a6SGleb Smirnoff rmc_depth_recompute(rm_class_t *cl)
490772e66a6SGleb Smirnoff {
491772e66a6SGleb Smirnoff #if 1 /* ALTQ */
492772e66a6SGleb Smirnoff rm_class_t *p, *t;
493772e66a6SGleb Smirnoff
494772e66a6SGleb Smirnoff p = cl;
495772e66a6SGleb Smirnoff while (p != NULL) {
496772e66a6SGleb Smirnoff if ((t = p->children_) == NULL) {
497772e66a6SGleb Smirnoff p->depth_ = 0;
498772e66a6SGleb Smirnoff } else {
499772e66a6SGleb Smirnoff int cdepth = 0;
500772e66a6SGleb Smirnoff
501772e66a6SGleb Smirnoff while (t != NULL) {
502772e66a6SGleb Smirnoff if (t->depth_ > cdepth)
503772e66a6SGleb Smirnoff cdepth = t->depth_;
504772e66a6SGleb Smirnoff t = t->next_;
505772e66a6SGleb Smirnoff }
506772e66a6SGleb Smirnoff
507772e66a6SGleb Smirnoff if (p->depth_ == cdepth + 1)
508772e66a6SGleb Smirnoff /* no change to this parent */
509772e66a6SGleb Smirnoff return;
510772e66a6SGleb Smirnoff
511772e66a6SGleb Smirnoff p->depth_ = cdepth + 1;
512772e66a6SGleb Smirnoff }
513772e66a6SGleb Smirnoff
514772e66a6SGleb Smirnoff p = p->parent_;
515772e66a6SGleb Smirnoff }
516772e66a6SGleb Smirnoff #else
517772e66a6SGleb Smirnoff rm_class_t *t;
518772e66a6SGleb Smirnoff
519772e66a6SGleb Smirnoff if (cl->depth_ >= 1) {
520772e66a6SGleb Smirnoff if (cl->children_ == NULL) {
521772e66a6SGleb Smirnoff cl->depth_ = 0;
522772e66a6SGleb Smirnoff } else if ((t = cl->children_) != NULL) {
523772e66a6SGleb Smirnoff while (t != NULL) {
524772e66a6SGleb Smirnoff if (t->children_ != NULL)
525772e66a6SGleb Smirnoff rmc_depth_recompute(t);
526772e66a6SGleb Smirnoff t = t->next_;
527772e66a6SGleb Smirnoff }
528772e66a6SGleb Smirnoff } else
529772e66a6SGleb Smirnoff rmc_depth_compute(cl);
530772e66a6SGleb Smirnoff }
531772e66a6SGleb Smirnoff #endif
532772e66a6SGleb Smirnoff }
533772e66a6SGleb Smirnoff
534772e66a6SGleb Smirnoff /*
535772e66a6SGleb Smirnoff * void
536772e66a6SGleb Smirnoff * rmc_delete_class(struct rm_ifdat *ifdat, struct rm_class *cl) - This
537772e66a6SGleb Smirnoff * function deletes a class from the link-sharing structure and frees
538772e66a6SGleb Smirnoff * all resources associated with the class.
539772e66a6SGleb Smirnoff *
540772e66a6SGleb Smirnoff * Returns: NONE
541772e66a6SGleb Smirnoff */
542772e66a6SGleb Smirnoff
543772e66a6SGleb Smirnoff void
rmc_delete_class(struct rm_ifdat * ifd,struct rm_class * cl)544772e66a6SGleb Smirnoff rmc_delete_class(struct rm_ifdat *ifd, struct rm_class *cl)
545772e66a6SGleb Smirnoff {
546772e66a6SGleb Smirnoff struct rm_class *p, *head, *previous;
547772e66a6SGleb Smirnoff int s;
548772e66a6SGleb Smirnoff
549772e66a6SGleb Smirnoff ASSERT(cl->children_ == NULL);
550772e66a6SGleb Smirnoff
551772e66a6SGleb Smirnoff if (cl->sleeping_)
552772e66a6SGleb Smirnoff CALLOUT_STOP(&cl->callout_);
553772e66a6SGleb Smirnoff
554772e66a6SGleb Smirnoff s = splnet();
555772e66a6SGleb Smirnoff IFQ_LOCK(ifd->ifq_);
556772e66a6SGleb Smirnoff /*
557772e66a6SGleb Smirnoff * Free packets in the packet queue.
558772e66a6SGleb Smirnoff * XXX - this may not be a desired behavior. Packets should be
559772e66a6SGleb Smirnoff * re-queued.
560772e66a6SGleb Smirnoff */
561772e66a6SGleb Smirnoff rmc_dropall(cl);
562772e66a6SGleb Smirnoff
563772e66a6SGleb Smirnoff /*
564772e66a6SGleb Smirnoff * If the class has a parent, then remove the class from the
565772e66a6SGleb Smirnoff * class from the parent's children chain.
566772e66a6SGleb Smirnoff */
567772e66a6SGleb Smirnoff if (cl->parent_ != NULL) {
568772e66a6SGleb Smirnoff head = cl->parent_->children_;
569772e66a6SGleb Smirnoff p = previous = head;
570772e66a6SGleb Smirnoff if (head->next_ == NULL) {
571772e66a6SGleb Smirnoff ASSERT(head == cl);
572772e66a6SGleb Smirnoff cl->parent_->children_ = NULL;
573772e66a6SGleb Smirnoff cl->parent_->leaf_ = 1;
574772e66a6SGleb Smirnoff } else while (p != NULL) {
575772e66a6SGleb Smirnoff if (p == cl) {
576772e66a6SGleb Smirnoff if (cl == head)
577772e66a6SGleb Smirnoff cl->parent_->children_ = cl->next_;
578772e66a6SGleb Smirnoff else
579772e66a6SGleb Smirnoff previous->next_ = cl->next_;
580772e66a6SGleb Smirnoff cl->next_ = NULL;
581772e66a6SGleb Smirnoff p = NULL;
582772e66a6SGleb Smirnoff } else {
583772e66a6SGleb Smirnoff previous = p;
584772e66a6SGleb Smirnoff p = p->next_;
585772e66a6SGleb Smirnoff }
586772e66a6SGleb Smirnoff }
587772e66a6SGleb Smirnoff }
588772e66a6SGleb Smirnoff
589772e66a6SGleb Smirnoff /*
590772e66a6SGleb Smirnoff * Delete class from class priority peer list.
591772e66a6SGleb Smirnoff */
592772e66a6SGleb Smirnoff if ((p = ifd->active_[cl->pri_]) != NULL) {
593772e66a6SGleb Smirnoff /*
594772e66a6SGleb Smirnoff * If there is more than one member of this priority
595772e66a6SGleb Smirnoff * level, then look for class(cl) in the priority level.
596772e66a6SGleb Smirnoff */
597772e66a6SGleb Smirnoff if (p != p->peer_) {
598772e66a6SGleb Smirnoff while (p->peer_ != cl)
599772e66a6SGleb Smirnoff p = p->peer_;
600772e66a6SGleb Smirnoff p->peer_ = cl->peer_;
601772e66a6SGleb Smirnoff
602772e66a6SGleb Smirnoff if (ifd->active_[cl->pri_] == cl)
603772e66a6SGleb Smirnoff ifd->active_[cl->pri_] = cl->peer_;
604772e66a6SGleb Smirnoff } else {
605772e66a6SGleb Smirnoff ASSERT(p == cl);
606772e66a6SGleb Smirnoff ifd->active_[cl->pri_] = NULL;
607772e66a6SGleb Smirnoff }
608772e66a6SGleb Smirnoff }
609772e66a6SGleb Smirnoff
610772e66a6SGleb Smirnoff /*
611772e66a6SGleb Smirnoff * Recompute the WRR weights.
612772e66a6SGleb Smirnoff */
613772e66a6SGleb Smirnoff if (ifd->wrr_) {
614772e66a6SGleb Smirnoff ifd->alloc_[cl->pri_] -= cl->allotment_;
615772e66a6SGleb Smirnoff ifd->num_[cl->pri_]--;
616772e66a6SGleb Smirnoff rmc_wrr_set_weights(ifd);
617772e66a6SGleb Smirnoff }
618772e66a6SGleb Smirnoff
619772e66a6SGleb Smirnoff /*
620772e66a6SGleb Smirnoff * Re-compute the depth of the tree.
621772e66a6SGleb Smirnoff */
622772e66a6SGleb Smirnoff #if 1 /* ALTQ */
623772e66a6SGleb Smirnoff rmc_depth_recompute(cl->parent_);
624772e66a6SGleb Smirnoff #else
625772e66a6SGleb Smirnoff rmc_depth_recompute(ifd->root_);
626772e66a6SGleb Smirnoff #endif
627772e66a6SGleb Smirnoff
628772e66a6SGleb Smirnoff IFQ_UNLOCK(ifd->ifq_);
629772e66a6SGleb Smirnoff splx(s);
630772e66a6SGleb Smirnoff
631772e66a6SGleb Smirnoff /*
632772e66a6SGleb Smirnoff * Free the class structure.
633772e66a6SGleb Smirnoff */
634772e66a6SGleb Smirnoff if (cl->red_ != NULL) {
635772e66a6SGleb Smirnoff #ifdef ALTQ_RIO
636772e66a6SGleb Smirnoff if (q_is_rio(cl->q_))
637772e66a6SGleb Smirnoff rio_destroy((rio_t *)cl->red_);
638772e66a6SGleb Smirnoff #endif
639772e66a6SGleb Smirnoff #ifdef ALTQ_RED
640772e66a6SGleb Smirnoff if (q_is_red(cl->q_))
641772e66a6SGleb Smirnoff red_destroy(cl->red_);
642772e66a6SGleb Smirnoff #endif
6430a70aaf8SLuiz Otavio O Souza #ifdef ALTQ_CODEL
6440a70aaf8SLuiz Otavio O Souza if (q_is_codel(cl->q_))
6450a70aaf8SLuiz Otavio O Souza codel_destroy(cl->codel_);
6460a70aaf8SLuiz Otavio O Souza #endif
647772e66a6SGleb Smirnoff }
648772e66a6SGleb Smirnoff free(cl->q_, M_DEVBUF);
649772e66a6SGleb Smirnoff free(cl, M_DEVBUF);
650772e66a6SGleb Smirnoff }
651772e66a6SGleb Smirnoff
652772e66a6SGleb Smirnoff /*
653772e66a6SGleb Smirnoff * void
654772e66a6SGleb Smirnoff * rmc_init(...) - Initialize the resource management data structures
655772e66a6SGleb Smirnoff * associated with the output portion of interface 'ifp'. 'ifd' is
656772e66a6SGleb Smirnoff * where the structures will be built (for backwards compatibility, the
657772e66a6SGleb Smirnoff * structures aren't kept in the ifnet struct). 'nsecPerByte'
658772e66a6SGleb Smirnoff * gives the link speed (inverse of bandwidth) in nanoseconds/byte.
659772e66a6SGleb Smirnoff * 'restart' is the driver-specific routine that the generic 'delay
660772e66a6SGleb Smirnoff * until under limit' action will call to restart output. `maxq'
661772e66a6SGleb Smirnoff * is the queue size of the 'link' & 'default' classes. 'maxqueued'
662772e66a6SGleb Smirnoff * is the maximum number of packets that the resource management
663772e66a6SGleb Smirnoff * code will allow to be queued 'downstream' (this is typically 1).
664772e66a6SGleb Smirnoff *
665772e66a6SGleb Smirnoff * Returns: NONE
666772e66a6SGleb Smirnoff */
667772e66a6SGleb Smirnoff
668772e66a6SGleb Smirnoff void
rmc_init(struct ifaltq * ifq,struct rm_ifdat * ifd,u_int nsecPerByte,void (* restart)(struct ifaltq *),int maxq,int maxqueued,u_int maxidle,int minidle,u_int offtime,int flags)669772e66a6SGleb Smirnoff rmc_init(struct ifaltq *ifq, struct rm_ifdat *ifd, u_int nsecPerByte,
670772e66a6SGleb Smirnoff void (*restart)(struct ifaltq *), int maxq, int maxqueued, u_int maxidle,
671772e66a6SGleb Smirnoff int minidle, u_int offtime, int flags)
672772e66a6SGleb Smirnoff {
673772e66a6SGleb Smirnoff int i, mtu;
674772e66a6SGleb Smirnoff
675772e66a6SGleb Smirnoff /*
676772e66a6SGleb Smirnoff * Initialize the CBQ tracing/debug facility.
677772e66a6SGleb Smirnoff */
678772e66a6SGleb Smirnoff CBQTRACEINIT();
679772e66a6SGleb Smirnoff
680772e66a6SGleb Smirnoff bzero((char *)ifd, sizeof (*ifd));
681772e66a6SGleb Smirnoff mtu = ifq->altq_ifp->if_mtu;
682772e66a6SGleb Smirnoff ifd->ifq_ = ifq;
683772e66a6SGleb Smirnoff ifd->restart = restart;
684772e66a6SGleb Smirnoff ifd->maxqueued_ = maxqueued;
685772e66a6SGleb Smirnoff ifd->ns_per_byte_ = nsecPerByte;
686772e66a6SGleb Smirnoff ifd->maxpkt_ = mtu;
687772e66a6SGleb Smirnoff ifd->wrr_ = (flags & RMCF_WRR) ? 1 : 0;
688772e66a6SGleb Smirnoff ifd->efficient_ = (flags & RMCF_EFFICIENT) ? 1 : 0;
689772e66a6SGleb Smirnoff #if 1
690772e66a6SGleb Smirnoff ifd->maxiftime_ = mtu * nsecPerByte / 1000 * 16;
691772e66a6SGleb Smirnoff if (mtu * nsecPerByte > 10 * 1000000)
692772e66a6SGleb Smirnoff ifd->maxiftime_ /= 4;
693772e66a6SGleb Smirnoff #endif
694772e66a6SGleb Smirnoff
695772e66a6SGleb Smirnoff reset_cutoff(ifd);
696772e66a6SGleb Smirnoff CBQTRACE(rmc_init, 'INIT', ifd->cutoff_);
697772e66a6SGleb Smirnoff
698772e66a6SGleb Smirnoff /*
699772e66a6SGleb Smirnoff * Initialize the CBQ's WRR state.
700772e66a6SGleb Smirnoff */
701772e66a6SGleb Smirnoff for (i = 0; i < RM_MAXPRIO; i++) {
702772e66a6SGleb Smirnoff ifd->alloc_[i] = 0;
703772e66a6SGleb Smirnoff ifd->M_[i] = 0;
704772e66a6SGleb Smirnoff ifd->num_[i] = 0;
705772e66a6SGleb Smirnoff ifd->na_[i] = 0;
706772e66a6SGleb Smirnoff ifd->active_[i] = NULL;
707772e66a6SGleb Smirnoff }
708772e66a6SGleb Smirnoff
709772e66a6SGleb Smirnoff /*
710772e66a6SGleb Smirnoff * Initialize current packet state.
711772e66a6SGleb Smirnoff */
712772e66a6SGleb Smirnoff ifd->qi_ = 0;
713772e66a6SGleb Smirnoff ifd->qo_ = 0;
714772e66a6SGleb Smirnoff for (i = 0; i < RM_MAXQUEUED; i++) {
715772e66a6SGleb Smirnoff ifd->class_[i] = NULL;
716772e66a6SGleb Smirnoff ifd->curlen_[i] = 0;
717772e66a6SGleb Smirnoff ifd->borrowed_[i] = NULL;
718772e66a6SGleb Smirnoff }
719772e66a6SGleb Smirnoff
720772e66a6SGleb Smirnoff /*
721772e66a6SGleb Smirnoff * Create the root class of the link-sharing structure.
722772e66a6SGleb Smirnoff */
723772e66a6SGleb Smirnoff if ((ifd->root_ = rmc_newclass(0, ifd,
724772e66a6SGleb Smirnoff nsecPerByte,
725772e66a6SGleb Smirnoff rmc_root_overlimit, maxq, 0, 0,
726772e66a6SGleb Smirnoff maxidle, minidle, offtime,
727772e66a6SGleb Smirnoff 0, 0)) == NULL) {
728772e66a6SGleb Smirnoff printf("rmc_init: root class not allocated\n");
729772e66a6SGleb Smirnoff return ;
730772e66a6SGleb Smirnoff }
731772e66a6SGleb Smirnoff ifd->root_->depth_ = 0;
732772e66a6SGleb Smirnoff }
733772e66a6SGleb Smirnoff
734772e66a6SGleb Smirnoff /*
735772e66a6SGleb Smirnoff * void
736772e66a6SGleb Smirnoff * rmc_queue_packet(struct rm_class *cl, mbuf_t *m) - Add packet given by
737772e66a6SGleb Smirnoff * mbuf 'm' to queue for resource class 'cl'. This routine is called
738772e66a6SGleb Smirnoff * by a driver's if_output routine. This routine must be called with
739772e66a6SGleb Smirnoff * output packet completion interrupts locked out (to avoid racing with
740772e66a6SGleb Smirnoff * rmc_dequeue_next).
741772e66a6SGleb Smirnoff *
742772e66a6SGleb Smirnoff * Returns: 0 on successful queueing
743772e66a6SGleb Smirnoff * -1 when packet drop occurs
744772e66a6SGleb Smirnoff */
745772e66a6SGleb Smirnoff int
rmc_queue_packet(struct rm_class * cl,mbuf_t * m)746772e66a6SGleb Smirnoff rmc_queue_packet(struct rm_class *cl, mbuf_t *m)
747772e66a6SGleb Smirnoff {
748772e66a6SGleb Smirnoff struct timeval now;
749772e66a6SGleb Smirnoff struct rm_ifdat *ifd = cl->ifdat_;
750772e66a6SGleb Smirnoff int cpri = cl->pri_;
751772e66a6SGleb Smirnoff int is_empty = qempty(cl->q_);
752772e66a6SGleb Smirnoff
753772e66a6SGleb Smirnoff RM_GETTIME(now);
754772e66a6SGleb Smirnoff if (ifd->cutoff_ > 0) {
755772e66a6SGleb Smirnoff if (TV_LT(&cl->undertime_, &now)) {
756772e66a6SGleb Smirnoff if (ifd->cutoff_ > cl->depth_)
757772e66a6SGleb Smirnoff ifd->cutoff_ = cl->depth_;
758772e66a6SGleb Smirnoff CBQTRACE(rmc_queue_packet, 'ffoc', cl->depth_);
759772e66a6SGleb Smirnoff }
760772e66a6SGleb Smirnoff #if 1 /* ALTQ */
761772e66a6SGleb Smirnoff else {
762772e66a6SGleb Smirnoff /*
763772e66a6SGleb Smirnoff * the class is overlimit. if the class has
764772e66a6SGleb Smirnoff * underlimit ancestors, set cutoff to the lowest
765772e66a6SGleb Smirnoff * depth among them.
766772e66a6SGleb Smirnoff */
767772e66a6SGleb Smirnoff struct rm_class *borrow = cl->borrow_;
768772e66a6SGleb Smirnoff
769772e66a6SGleb Smirnoff while (borrow != NULL &&
770772e66a6SGleb Smirnoff borrow->depth_ < ifd->cutoff_) {
771772e66a6SGleb Smirnoff if (TV_LT(&borrow->undertime_, &now)) {
772772e66a6SGleb Smirnoff ifd->cutoff_ = borrow->depth_;
773772e66a6SGleb Smirnoff CBQTRACE(rmc_queue_packet, 'ffob', ifd->cutoff_);
774772e66a6SGleb Smirnoff break;
775772e66a6SGleb Smirnoff }
776772e66a6SGleb Smirnoff borrow = borrow->borrow_;
777772e66a6SGleb Smirnoff }
778772e66a6SGleb Smirnoff }
779772e66a6SGleb Smirnoff #else /* !ALTQ */
780772e66a6SGleb Smirnoff else if ((ifd->cutoff_ > 1) && cl->borrow_) {
781772e66a6SGleb Smirnoff if (TV_LT(&cl->borrow_->undertime_, &now)) {
782772e66a6SGleb Smirnoff ifd->cutoff_ = cl->borrow_->depth_;
783772e66a6SGleb Smirnoff CBQTRACE(rmc_queue_packet, 'ffob',
784772e66a6SGleb Smirnoff cl->borrow_->depth_);
785772e66a6SGleb Smirnoff }
786772e66a6SGleb Smirnoff }
787772e66a6SGleb Smirnoff #endif /* !ALTQ */
788772e66a6SGleb Smirnoff }
789772e66a6SGleb Smirnoff
790772e66a6SGleb Smirnoff if (_rmc_addq(cl, m) < 0)
791772e66a6SGleb Smirnoff /* failed */
792772e66a6SGleb Smirnoff return (-1);
793772e66a6SGleb Smirnoff
794772e66a6SGleb Smirnoff if (is_empty) {
795772e66a6SGleb Smirnoff CBQTRACE(rmc_queue_packet, 'ytpe', cl->stats_.handle);
796772e66a6SGleb Smirnoff ifd->na_[cpri]++;
797772e66a6SGleb Smirnoff }
798772e66a6SGleb Smirnoff
799772e66a6SGleb Smirnoff if (qlen(cl->q_) > qlimit(cl->q_)) {
800772e66a6SGleb Smirnoff /* note: qlimit can be set to 0 or 1 */
801772e66a6SGleb Smirnoff rmc_drop_action(cl);
802772e66a6SGleb Smirnoff return (-1);
803772e66a6SGleb Smirnoff }
804772e66a6SGleb Smirnoff return (0);
805772e66a6SGleb Smirnoff }
806772e66a6SGleb Smirnoff
807772e66a6SGleb Smirnoff /*
808772e66a6SGleb Smirnoff * void
809772e66a6SGleb Smirnoff * rmc_tl_satisfied(struct rm_ifdat *ifd, struct timeval *now) - Check all
810772e66a6SGleb Smirnoff * classes to see if there are satified.
811772e66a6SGleb Smirnoff */
812772e66a6SGleb Smirnoff
813772e66a6SGleb Smirnoff static void
rmc_tl_satisfied(struct rm_ifdat * ifd,struct timeval * now)814772e66a6SGleb Smirnoff rmc_tl_satisfied(struct rm_ifdat *ifd, struct timeval *now)
815772e66a6SGleb Smirnoff {
816772e66a6SGleb Smirnoff int i;
817772e66a6SGleb Smirnoff rm_class_t *p, *bp;
818772e66a6SGleb Smirnoff
819772e66a6SGleb Smirnoff for (i = RM_MAXPRIO - 1; i >= 0; i--) {
820772e66a6SGleb Smirnoff if ((bp = ifd->active_[i]) != NULL) {
821772e66a6SGleb Smirnoff p = bp;
822772e66a6SGleb Smirnoff do {
823772e66a6SGleb Smirnoff if (!rmc_satisfied(p, now)) {
824772e66a6SGleb Smirnoff ifd->cutoff_ = p->depth_;
825772e66a6SGleb Smirnoff return;
826772e66a6SGleb Smirnoff }
827772e66a6SGleb Smirnoff p = p->peer_;
828772e66a6SGleb Smirnoff } while (p != bp);
829772e66a6SGleb Smirnoff }
830772e66a6SGleb Smirnoff }
831772e66a6SGleb Smirnoff
832772e66a6SGleb Smirnoff reset_cutoff(ifd);
833772e66a6SGleb Smirnoff }
834772e66a6SGleb Smirnoff
835772e66a6SGleb Smirnoff /*
836772e66a6SGleb Smirnoff * rmc_satisfied - Return 1 of the class is satisfied. O, otherwise.
837772e66a6SGleb Smirnoff */
838772e66a6SGleb Smirnoff
839772e66a6SGleb Smirnoff static int
rmc_satisfied(struct rm_class * cl,struct timeval * now)840772e66a6SGleb Smirnoff rmc_satisfied(struct rm_class *cl, struct timeval *now)
841772e66a6SGleb Smirnoff {
842772e66a6SGleb Smirnoff rm_class_t *p;
843772e66a6SGleb Smirnoff
844772e66a6SGleb Smirnoff if (cl == NULL)
845772e66a6SGleb Smirnoff return (1);
846772e66a6SGleb Smirnoff if (TV_LT(now, &cl->undertime_))
847772e66a6SGleb Smirnoff return (1);
848772e66a6SGleb Smirnoff if (cl->depth_ == 0) {
849772e66a6SGleb Smirnoff if (!cl->sleeping_ && (qlen(cl->q_) > cl->qthresh_))
850772e66a6SGleb Smirnoff return (0);
851772e66a6SGleb Smirnoff else
852772e66a6SGleb Smirnoff return (1);
853772e66a6SGleb Smirnoff }
854772e66a6SGleb Smirnoff if (cl->children_ != NULL) {
855772e66a6SGleb Smirnoff p = cl->children_;
856772e66a6SGleb Smirnoff while (p != NULL) {
857772e66a6SGleb Smirnoff if (!rmc_satisfied(p, now))
858772e66a6SGleb Smirnoff return (0);
859772e66a6SGleb Smirnoff p = p->next_;
860772e66a6SGleb Smirnoff }
861772e66a6SGleb Smirnoff }
862772e66a6SGleb Smirnoff
863772e66a6SGleb Smirnoff return (1);
864772e66a6SGleb Smirnoff }
865772e66a6SGleb Smirnoff
866772e66a6SGleb Smirnoff /*
867772e66a6SGleb Smirnoff * Return 1 if class 'cl' is under limit or can borrow from a parent,
868772e66a6SGleb Smirnoff * 0 if overlimit. As a side-effect, this routine will invoke the
869772e66a6SGleb Smirnoff * class overlimit action if the class if overlimit.
870772e66a6SGleb Smirnoff */
871772e66a6SGleb Smirnoff
872772e66a6SGleb Smirnoff static int
rmc_under_limit(struct rm_class * cl,struct timeval * now)873772e66a6SGleb Smirnoff rmc_under_limit(struct rm_class *cl, struct timeval *now)
874772e66a6SGleb Smirnoff {
875772e66a6SGleb Smirnoff rm_class_t *p = cl;
876772e66a6SGleb Smirnoff rm_class_t *top;
877772e66a6SGleb Smirnoff struct rm_ifdat *ifd = cl->ifdat_;
878772e66a6SGleb Smirnoff
879772e66a6SGleb Smirnoff ifd->borrowed_[ifd->qi_] = NULL;
880772e66a6SGleb Smirnoff /*
881772e66a6SGleb Smirnoff * If cl is the root class, then always return that it is
882772e66a6SGleb Smirnoff * underlimit. Otherwise, check to see if the class is underlimit.
883772e66a6SGleb Smirnoff */
884772e66a6SGleb Smirnoff if (cl->parent_ == NULL)
885772e66a6SGleb Smirnoff return (1);
886772e66a6SGleb Smirnoff
887772e66a6SGleb Smirnoff if (cl->sleeping_) {
888772e66a6SGleb Smirnoff if (TV_LT(now, &cl->undertime_))
889772e66a6SGleb Smirnoff return (0);
890772e66a6SGleb Smirnoff
891772e66a6SGleb Smirnoff CALLOUT_STOP(&cl->callout_);
892772e66a6SGleb Smirnoff cl->sleeping_ = 0;
893772e66a6SGleb Smirnoff cl->undertime_.tv_sec = 0;
894772e66a6SGleb Smirnoff return (1);
895772e66a6SGleb Smirnoff }
896772e66a6SGleb Smirnoff
897772e66a6SGleb Smirnoff top = NULL;
898772e66a6SGleb Smirnoff while (cl->undertime_.tv_sec && TV_LT(now, &cl->undertime_)) {
899772e66a6SGleb Smirnoff if (((cl = cl->borrow_) == NULL) ||
900772e66a6SGleb Smirnoff (cl->depth_ > ifd->cutoff_)) {
901772e66a6SGleb Smirnoff #ifdef ADJUST_CUTOFF
902772e66a6SGleb Smirnoff if (cl != NULL)
903772e66a6SGleb Smirnoff /* cutoff is taking effect, just
904772e66a6SGleb Smirnoff return false without calling
905772e66a6SGleb Smirnoff the delay action. */
906772e66a6SGleb Smirnoff return (0);
907772e66a6SGleb Smirnoff #endif
908772e66a6SGleb Smirnoff #ifdef BORROW_OFFTIME
909772e66a6SGleb Smirnoff /*
910772e66a6SGleb Smirnoff * check if the class can borrow offtime too.
911772e66a6SGleb Smirnoff * borrow offtime from the top of the borrow
912772e66a6SGleb Smirnoff * chain if the top class is not overloaded.
913772e66a6SGleb Smirnoff */
914772e66a6SGleb Smirnoff if (cl != NULL) {
915772e66a6SGleb Smirnoff /* cutoff is taking effect, use this class as top. */
916772e66a6SGleb Smirnoff top = cl;
917772e66a6SGleb Smirnoff CBQTRACE(rmc_under_limit, 'ffou', ifd->cutoff_);
918772e66a6SGleb Smirnoff }
919772e66a6SGleb Smirnoff if (top != NULL && top->avgidle_ == top->minidle_)
920772e66a6SGleb Smirnoff top = NULL;
921772e66a6SGleb Smirnoff p->overtime_ = *now;
922772e66a6SGleb Smirnoff (p->overlimit)(p, top);
923772e66a6SGleb Smirnoff #else
924772e66a6SGleb Smirnoff p->overtime_ = *now;
925772e66a6SGleb Smirnoff (p->overlimit)(p, NULL);
926772e66a6SGleb Smirnoff #endif
927772e66a6SGleb Smirnoff return (0);
928772e66a6SGleb Smirnoff }
929772e66a6SGleb Smirnoff top = cl;
930772e66a6SGleb Smirnoff }
931772e66a6SGleb Smirnoff
932772e66a6SGleb Smirnoff if (cl != p)
933772e66a6SGleb Smirnoff ifd->borrowed_[ifd->qi_] = cl;
934772e66a6SGleb Smirnoff return (1);
935772e66a6SGleb Smirnoff }
936772e66a6SGleb Smirnoff
937772e66a6SGleb Smirnoff /*
938772e66a6SGleb Smirnoff * _rmc_wrr_dequeue_next() - This is scheduler for WRR as opposed to
939772e66a6SGleb Smirnoff * Packet-by-packet round robin.
940772e66a6SGleb Smirnoff *
941772e66a6SGleb Smirnoff * The heart of the weighted round-robin scheduler, which decides which
942772e66a6SGleb Smirnoff * class next gets to send a packet. Highest priority first, then
943772e66a6SGleb Smirnoff * weighted round-robin within priorites.
944772e66a6SGleb Smirnoff *
945772e66a6SGleb Smirnoff * Each able-to-send class gets to send until its byte allocation is
946772e66a6SGleb Smirnoff * exhausted. Thus, the active pointer is only changed after a class has
947772e66a6SGleb Smirnoff * exhausted its allocation.
948772e66a6SGleb Smirnoff *
949772e66a6SGleb Smirnoff * If the scheduler finds no class that is underlimit or able to borrow,
950772e66a6SGleb Smirnoff * then the first class found that had a nonzero queue and is allowed to
951772e66a6SGleb Smirnoff * borrow gets to send.
952772e66a6SGleb Smirnoff */
953772e66a6SGleb Smirnoff
954772e66a6SGleb Smirnoff static mbuf_t *
_rmc_wrr_dequeue_next(struct rm_ifdat * ifd,int op)955772e66a6SGleb Smirnoff _rmc_wrr_dequeue_next(struct rm_ifdat *ifd, int op)
956772e66a6SGleb Smirnoff {
957772e66a6SGleb Smirnoff struct rm_class *cl = NULL, *first = NULL;
958772e66a6SGleb Smirnoff u_int deficit;
959772e66a6SGleb Smirnoff int cpri;
960772e66a6SGleb Smirnoff mbuf_t *m;
961772e66a6SGleb Smirnoff struct timeval now;
962772e66a6SGleb Smirnoff
963772e66a6SGleb Smirnoff RM_GETTIME(now);
964772e66a6SGleb Smirnoff
965772e66a6SGleb Smirnoff /*
966772e66a6SGleb Smirnoff * if the driver polls the top of the queue and then removes
967772e66a6SGleb Smirnoff * the polled packet, we must return the same packet.
968772e66a6SGleb Smirnoff */
969772e66a6SGleb Smirnoff if (op == ALTDQ_REMOVE && ifd->pollcache_) {
970772e66a6SGleb Smirnoff cl = ifd->pollcache_;
971772e66a6SGleb Smirnoff cpri = cl->pri_;
972772e66a6SGleb Smirnoff if (ifd->efficient_) {
973772e66a6SGleb Smirnoff /* check if this class is overlimit */
974772e66a6SGleb Smirnoff if (cl->undertime_.tv_sec != 0 &&
975772e66a6SGleb Smirnoff rmc_under_limit(cl, &now) == 0)
976772e66a6SGleb Smirnoff first = cl;
977772e66a6SGleb Smirnoff }
978772e66a6SGleb Smirnoff ifd->pollcache_ = NULL;
979772e66a6SGleb Smirnoff goto _wrr_out;
980772e66a6SGleb Smirnoff }
981772e66a6SGleb Smirnoff else {
982772e66a6SGleb Smirnoff /* mode == ALTDQ_POLL || pollcache == NULL */
983772e66a6SGleb Smirnoff ifd->pollcache_ = NULL;
984772e66a6SGleb Smirnoff ifd->borrowed_[ifd->qi_] = NULL;
985772e66a6SGleb Smirnoff }
986772e66a6SGleb Smirnoff #ifdef ADJUST_CUTOFF
987772e66a6SGleb Smirnoff _again:
988772e66a6SGleb Smirnoff #endif
989772e66a6SGleb Smirnoff for (cpri = RM_MAXPRIO - 1; cpri >= 0; cpri--) {
990772e66a6SGleb Smirnoff if (ifd->na_[cpri] == 0)
991772e66a6SGleb Smirnoff continue;
992772e66a6SGleb Smirnoff deficit = 0;
993772e66a6SGleb Smirnoff /*
994772e66a6SGleb Smirnoff * Loop through twice for a priority level, if some class
995772e66a6SGleb Smirnoff * was unable to send a packet the first round because
996772e66a6SGleb Smirnoff * of the weighted round-robin mechanism.
997772e66a6SGleb Smirnoff * During the second loop at this level, deficit==2.
998772e66a6SGleb Smirnoff * (This second loop is not needed if for every class,
999772e66a6SGleb Smirnoff * "M[cl->pri_])" times "cl->allotment" is greater than
1000772e66a6SGleb Smirnoff * the byte size for the largest packet in the class.)
1001772e66a6SGleb Smirnoff */
1002772e66a6SGleb Smirnoff _wrr_loop:
1003772e66a6SGleb Smirnoff cl = ifd->active_[cpri];
1004772e66a6SGleb Smirnoff ASSERT(cl != NULL);
1005772e66a6SGleb Smirnoff do {
1006772e66a6SGleb Smirnoff if ((deficit < 2) && (cl->bytes_alloc_ <= 0))
1007772e66a6SGleb Smirnoff cl->bytes_alloc_ += cl->w_allotment_;
1008772e66a6SGleb Smirnoff if (!qempty(cl->q_)) {
1009772e66a6SGleb Smirnoff if ((cl->undertime_.tv_sec == 0) ||
1010772e66a6SGleb Smirnoff rmc_under_limit(cl, &now)) {
1011772e66a6SGleb Smirnoff if (cl->bytes_alloc_ > 0 || deficit > 1)
1012772e66a6SGleb Smirnoff goto _wrr_out;
1013772e66a6SGleb Smirnoff
1014772e66a6SGleb Smirnoff /* underlimit but no alloc */
1015772e66a6SGleb Smirnoff deficit = 1;
1016772e66a6SGleb Smirnoff #if 1
1017772e66a6SGleb Smirnoff ifd->borrowed_[ifd->qi_] = NULL;
1018772e66a6SGleb Smirnoff #endif
1019772e66a6SGleb Smirnoff }
1020772e66a6SGleb Smirnoff else if (first == NULL && cl->borrow_ != NULL)
1021772e66a6SGleb Smirnoff first = cl; /* borrowing candidate */
1022772e66a6SGleb Smirnoff }
1023772e66a6SGleb Smirnoff
1024772e66a6SGleb Smirnoff cl->bytes_alloc_ = 0;
1025772e66a6SGleb Smirnoff cl = cl->peer_;
1026772e66a6SGleb Smirnoff } while (cl != ifd->active_[cpri]);
1027772e66a6SGleb Smirnoff
1028772e66a6SGleb Smirnoff if (deficit == 1) {
1029772e66a6SGleb Smirnoff /* first loop found an underlimit class with deficit */
1030772e66a6SGleb Smirnoff /* Loop on same priority level, with new deficit. */
1031772e66a6SGleb Smirnoff deficit = 2;
1032772e66a6SGleb Smirnoff goto _wrr_loop;
1033772e66a6SGleb Smirnoff }
1034772e66a6SGleb Smirnoff }
1035772e66a6SGleb Smirnoff
1036772e66a6SGleb Smirnoff #ifdef ADJUST_CUTOFF
1037772e66a6SGleb Smirnoff /*
1038772e66a6SGleb Smirnoff * no underlimit class found. if cutoff is taking effect,
1039772e66a6SGleb Smirnoff * increase cutoff and try again.
1040772e66a6SGleb Smirnoff */
1041772e66a6SGleb Smirnoff if (first != NULL && ifd->cutoff_ < ifd->root_->depth_) {
1042772e66a6SGleb Smirnoff ifd->cutoff_++;
1043772e66a6SGleb Smirnoff CBQTRACE(_rmc_wrr_dequeue_next, 'ojda', ifd->cutoff_);
1044772e66a6SGleb Smirnoff goto _again;
1045772e66a6SGleb Smirnoff }
1046772e66a6SGleb Smirnoff #endif /* ADJUST_CUTOFF */
1047772e66a6SGleb Smirnoff /*
1048772e66a6SGleb Smirnoff * If LINK_EFFICIENCY is turned on, then the first overlimit
1049772e66a6SGleb Smirnoff * class we encounter will send a packet if all the classes
1050772e66a6SGleb Smirnoff * of the link-sharing structure are overlimit.
1051772e66a6SGleb Smirnoff */
1052772e66a6SGleb Smirnoff reset_cutoff(ifd);
1053772e66a6SGleb Smirnoff CBQTRACE(_rmc_wrr_dequeue_next, 'otsr', ifd->cutoff_);
1054772e66a6SGleb Smirnoff
1055772e66a6SGleb Smirnoff if (!ifd->efficient_ || first == NULL)
1056772e66a6SGleb Smirnoff return (NULL);
1057772e66a6SGleb Smirnoff
1058772e66a6SGleb Smirnoff cl = first;
1059772e66a6SGleb Smirnoff cpri = cl->pri_;
1060772e66a6SGleb Smirnoff #if 0 /* too time-consuming for nothing */
1061772e66a6SGleb Smirnoff if (cl->sleeping_)
1062772e66a6SGleb Smirnoff CALLOUT_STOP(&cl->callout_);
1063772e66a6SGleb Smirnoff cl->sleeping_ = 0;
1064772e66a6SGleb Smirnoff cl->undertime_.tv_sec = 0;
1065772e66a6SGleb Smirnoff #endif
1066772e66a6SGleb Smirnoff ifd->borrowed_[ifd->qi_] = cl->borrow_;
1067772e66a6SGleb Smirnoff ifd->cutoff_ = cl->borrow_->depth_;
1068772e66a6SGleb Smirnoff
1069772e66a6SGleb Smirnoff /*
1070772e66a6SGleb Smirnoff * Deque the packet and do the book keeping...
1071772e66a6SGleb Smirnoff */
1072772e66a6SGleb Smirnoff _wrr_out:
1073772e66a6SGleb Smirnoff if (op == ALTDQ_REMOVE) {
1074772e66a6SGleb Smirnoff m = _rmc_getq(cl);
1075772e66a6SGleb Smirnoff if (m == NULL)
1076772e66a6SGleb Smirnoff panic("_rmc_wrr_dequeue_next");
1077772e66a6SGleb Smirnoff if (qempty(cl->q_))
1078772e66a6SGleb Smirnoff ifd->na_[cpri]--;
1079772e66a6SGleb Smirnoff
1080772e66a6SGleb Smirnoff /*
1081772e66a6SGleb Smirnoff * Update class statistics and link data.
1082772e66a6SGleb Smirnoff */
1083772e66a6SGleb Smirnoff if (cl->bytes_alloc_ > 0)
1084772e66a6SGleb Smirnoff cl->bytes_alloc_ -= m_pktlen(m);
1085772e66a6SGleb Smirnoff
1086772e66a6SGleb Smirnoff if ((cl->bytes_alloc_ <= 0) || first == cl)
1087772e66a6SGleb Smirnoff ifd->active_[cl->pri_] = cl->peer_;
1088772e66a6SGleb Smirnoff else
1089772e66a6SGleb Smirnoff ifd->active_[cl->pri_] = cl;
1090772e66a6SGleb Smirnoff
1091772e66a6SGleb Smirnoff ifd->class_[ifd->qi_] = cl;
1092772e66a6SGleb Smirnoff ifd->curlen_[ifd->qi_] = m_pktlen(m);
1093772e66a6SGleb Smirnoff ifd->now_[ifd->qi_] = now;
1094772e66a6SGleb Smirnoff ifd->qi_ = (ifd->qi_ + 1) % ifd->maxqueued_;
1095772e66a6SGleb Smirnoff ifd->queued_++;
1096772e66a6SGleb Smirnoff } else {
1097772e66a6SGleb Smirnoff /* mode == ALTDQ_PPOLL */
1098772e66a6SGleb Smirnoff m = _rmc_pollq(cl);
1099772e66a6SGleb Smirnoff ifd->pollcache_ = cl;
1100772e66a6SGleb Smirnoff }
1101772e66a6SGleb Smirnoff return (m);
1102772e66a6SGleb Smirnoff }
1103772e66a6SGleb Smirnoff
1104772e66a6SGleb Smirnoff /*
1105772e66a6SGleb Smirnoff * Dequeue & return next packet from the highest priority class that
1106772e66a6SGleb Smirnoff * has a packet to send & has enough allocation to send it. This
1107772e66a6SGleb Smirnoff * routine is called by a driver whenever it needs a new packet to
1108772e66a6SGleb Smirnoff * output.
1109772e66a6SGleb Smirnoff */
1110772e66a6SGleb Smirnoff static mbuf_t *
_rmc_prr_dequeue_next(struct rm_ifdat * ifd,int op)1111772e66a6SGleb Smirnoff _rmc_prr_dequeue_next(struct rm_ifdat *ifd, int op)
1112772e66a6SGleb Smirnoff {
1113772e66a6SGleb Smirnoff mbuf_t *m;
1114772e66a6SGleb Smirnoff int cpri;
1115772e66a6SGleb Smirnoff struct rm_class *cl, *first = NULL;
1116772e66a6SGleb Smirnoff struct timeval now;
1117772e66a6SGleb Smirnoff
1118772e66a6SGleb Smirnoff RM_GETTIME(now);
1119772e66a6SGleb Smirnoff
1120772e66a6SGleb Smirnoff /*
1121772e66a6SGleb Smirnoff * if the driver polls the top of the queue and then removes
1122772e66a6SGleb Smirnoff * the polled packet, we must return the same packet.
1123772e66a6SGleb Smirnoff */
1124772e66a6SGleb Smirnoff if (op == ALTDQ_REMOVE && ifd->pollcache_) {
1125772e66a6SGleb Smirnoff cl = ifd->pollcache_;
1126772e66a6SGleb Smirnoff cpri = cl->pri_;
1127772e66a6SGleb Smirnoff ifd->pollcache_ = NULL;
1128772e66a6SGleb Smirnoff goto _prr_out;
1129772e66a6SGleb Smirnoff } else {
1130772e66a6SGleb Smirnoff /* mode == ALTDQ_POLL || pollcache == NULL */
1131772e66a6SGleb Smirnoff ifd->pollcache_ = NULL;
1132772e66a6SGleb Smirnoff ifd->borrowed_[ifd->qi_] = NULL;
1133772e66a6SGleb Smirnoff }
1134772e66a6SGleb Smirnoff #ifdef ADJUST_CUTOFF
1135772e66a6SGleb Smirnoff _again:
1136772e66a6SGleb Smirnoff #endif
1137772e66a6SGleb Smirnoff for (cpri = RM_MAXPRIO - 1; cpri >= 0; cpri--) {
1138772e66a6SGleb Smirnoff if (ifd->na_[cpri] == 0)
1139772e66a6SGleb Smirnoff continue;
1140772e66a6SGleb Smirnoff cl = ifd->active_[cpri];
1141772e66a6SGleb Smirnoff ASSERT(cl != NULL);
1142772e66a6SGleb Smirnoff do {
1143772e66a6SGleb Smirnoff if (!qempty(cl->q_)) {
1144772e66a6SGleb Smirnoff if ((cl->undertime_.tv_sec == 0) ||
1145772e66a6SGleb Smirnoff rmc_under_limit(cl, &now))
1146772e66a6SGleb Smirnoff goto _prr_out;
1147772e66a6SGleb Smirnoff if (first == NULL && cl->borrow_ != NULL)
1148772e66a6SGleb Smirnoff first = cl;
1149772e66a6SGleb Smirnoff }
1150772e66a6SGleb Smirnoff cl = cl->peer_;
1151772e66a6SGleb Smirnoff } while (cl != ifd->active_[cpri]);
1152772e66a6SGleb Smirnoff }
1153772e66a6SGleb Smirnoff
1154772e66a6SGleb Smirnoff #ifdef ADJUST_CUTOFF
1155772e66a6SGleb Smirnoff /*
1156772e66a6SGleb Smirnoff * no underlimit class found. if cutoff is taking effect, increase
1157772e66a6SGleb Smirnoff * cutoff and try again.
1158772e66a6SGleb Smirnoff */
1159772e66a6SGleb Smirnoff if (first != NULL && ifd->cutoff_ < ifd->root_->depth_) {
1160772e66a6SGleb Smirnoff ifd->cutoff_++;
1161772e66a6SGleb Smirnoff goto _again;
1162772e66a6SGleb Smirnoff }
1163772e66a6SGleb Smirnoff #endif /* ADJUST_CUTOFF */
1164772e66a6SGleb Smirnoff /*
1165772e66a6SGleb Smirnoff * If LINK_EFFICIENCY is turned on, then the first overlimit
1166772e66a6SGleb Smirnoff * class we encounter will send a packet if all the classes
1167772e66a6SGleb Smirnoff * of the link-sharing structure are overlimit.
1168772e66a6SGleb Smirnoff */
1169772e66a6SGleb Smirnoff reset_cutoff(ifd);
1170772e66a6SGleb Smirnoff if (!ifd->efficient_ || first == NULL)
1171772e66a6SGleb Smirnoff return (NULL);
1172772e66a6SGleb Smirnoff
1173772e66a6SGleb Smirnoff cl = first;
1174772e66a6SGleb Smirnoff cpri = cl->pri_;
1175772e66a6SGleb Smirnoff #if 0 /* too time-consuming for nothing */
1176772e66a6SGleb Smirnoff if (cl->sleeping_)
1177772e66a6SGleb Smirnoff CALLOUT_STOP(&cl->callout_);
1178772e66a6SGleb Smirnoff cl->sleeping_ = 0;
1179772e66a6SGleb Smirnoff cl->undertime_.tv_sec = 0;
1180772e66a6SGleb Smirnoff #endif
1181772e66a6SGleb Smirnoff ifd->borrowed_[ifd->qi_] = cl->borrow_;
1182772e66a6SGleb Smirnoff ifd->cutoff_ = cl->borrow_->depth_;
1183772e66a6SGleb Smirnoff
1184772e66a6SGleb Smirnoff /*
1185772e66a6SGleb Smirnoff * Deque the packet and do the book keeping...
1186772e66a6SGleb Smirnoff */
1187772e66a6SGleb Smirnoff _prr_out:
1188772e66a6SGleb Smirnoff if (op == ALTDQ_REMOVE) {
1189772e66a6SGleb Smirnoff m = _rmc_getq(cl);
1190772e66a6SGleb Smirnoff if (m == NULL)
1191772e66a6SGleb Smirnoff panic("_rmc_prr_dequeue_next");
1192772e66a6SGleb Smirnoff if (qempty(cl->q_))
1193772e66a6SGleb Smirnoff ifd->na_[cpri]--;
1194772e66a6SGleb Smirnoff
1195772e66a6SGleb Smirnoff ifd->active_[cpri] = cl->peer_;
1196772e66a6SGleb Smirnoff
1197772e66a6SGleb Smirnoff ifd->class_[ifd->qi_] = cl;
1198772e66a6SGleb Smirnoff ifd->curlen_[ifd->qi_] = m_pktlen(m);
1199772e66a6SGleb Smirnoff ifd->now_[ifd->qi_] = now;
1200772e66a6SGleb Smirnoff ifd->qi_ = (ifd->qi_ + 1) % ifd->maxqueued_;
1201772e66a6SGleb Smirnoff ifd->queued_++;
1202772e66a6SGleb Smirnoff } else {
1203772e66a6SGleb Smirnoff /* mode == ALTDQ_POLL */
1204772e66a6SGleb Smirnoff m = _rmc_pollq(cl);
1205772e66a6SGleb Smirnoff ifd->pollcache_ = cl;
1206772e66a6SGleb Smirnoff }
1207772e66a6SGleb Smirnoff return (m);
1208772e66a6SGleb Smirnoff }
1209772e66a6SGleb Smirnoff
1210772e66a6SGleb Smirnoff /*
1211772e66a6SGleb Smirnoff * mbuf_t *
1212772e66a6SGleb Smirnoff * rmc_dequeue_next(struct rm_ifdat *ifd, struct timeval *now) - this function
1213772e66a6SGleb Smirnoff * is invoked by the packet driver to get the next packet to be
1214772e66a6SGleb Smirnoff * dequeued and output on the link. If WRR is enabled, then the
1215772e66a6SGleb Smirnoff * WRR dequeue next routine will determine the next packet to sent.
1216772e66a6SGleb Smirnoff * Otherwise, packet-by-packet round robin is invoked.
1217772e66a6SGleb Smirnoff *
1218772e66a6SGleb Smirnoff * Returns: NULL, if a packet is not available or if all
1219772e66a6SGleb Smirnoff * classes are overlimit.
1220772e66a6SGleb Smirnoff *
1221772e66a6SGleb Smirnoff * Otherwise, Pointer to the next packet.
1222772e66a6SGleb Smirnoff */
1223772e66a6SGleb Smirnoff
1224772e66a6SGleb Smirnoff mbuf_t *
rmc_dequeue_next(struct rm_ifdat * ifd,int mode)1225772e66a6SGleb Smirnoff rmc_dequeue_next(struct rm_ifdat *ifd, int mode)
1226772e66a6SGleb Smirnoff {
1227772e66a6SGleb Smirnoff if (ifd->queued_ >= ifd->maxqueued_)
1228772e66a6SGleb Smirnoff return (NULL);
1229772e66a6SGleb Smirnoff else if (ifd->wrr_)
1230772e66a6SGleb Smirnoff return (_rmc_wrr_dequeue_next(ifd, mode));
1231772e66a6SGleb Smirnoff else
1232772e66a6SGleb Smirnoff return (_rmc_prr_dequeue_next(ifd, mode));
1233772e66a6SGleb Smirnoff }
1234772e66a6SGleb Smirnoff
1235772e66a6SGleb Smirnoff /*
1236772e66a6SGleb Smirnoff * Update the utilization estimate for the packet that just completed.
1237772e66a6SGleb Smirnoff * The packet's class & the parent(s) of that class all get their
1238772e66a6SGleb Smirnoff * estimators updated. This routine is called by the driver's output-
1239772e66a6SGleb Smirnoff * packet-completion interrupt service routine.
1240772e66a6SGleb Smirnoff */
1241772e66a6SGleb Smirnoff
1242772e66a6SGleb Smirnoff /*
1243772e66a6SGleb Smirnoff * a macro to approximate "divide by 1000" that gives 0.000999,
1244772e66a6SGleb Smirnoff * if a value has enough effective digits.
1245772e66a6SGleb Smirnoff * (on pentium, mul takes 9 cycles but div takes 46!)
1246772e66a6SGleb Smirnoff */
1247772e66a6SGleb Smirnoff #define NSEC_TO_USEC(t) (((t) >> 10) + ((t) >> 16) + ((t) >> 17))
1248772e66a6SGleb Smirnoff void
rmc_update_class_util(struct rm_ifdat * ifd)1249772e66a6SGleb Smirnoff rmc_update_class_util(struct rm_ifdat *ifd)
1250772e66a6SGleb Smirnoff {
1251772e66a6SGleb Smirnoff int idle, avgidle, pktlen;
1252772e66a6SGleb Smirnoff int pkt_time, tidle;
1253772e66a6SGleb Smirnoff rm_class_t *cl, *borrowed;
1254772e66a6SGleb Smirnoff rm_class_t *borrows;
1255772e66a6SGleb Smirnoff struct timeval *nowp;
1256772e66a6SGleb Smirnoff
1257772e66a6SGleb Smirnoff /*
1258772e66a6SGleb Smirnoff * Get the most recent completed class.
1259772e66a6SGleb Smirnoff */
1260772e66a6SGleb Smirnoff if ((cl = ifd->class_[ifd->qo_]) == NULL)
1261772e66a6SGleb Smirnoff return;
1262772e66a6SGleb Smirnoff
1263772e66a6SGleb Smirnoff pktlen = ifd->curlen_[ifd->qo_];
1264772e66a6SGleb Smirnoff borrowed = ifd->borrowed_[ifd->qo_];
1265772e66a6SGleb Smirnoff borrows = borrowed;
1266772e66a6SGleb Smirnoff
1267772e66a6SGleb Smirnoff PKTCNTR_ADD(&cl->stats_.xmit_cnt, pktlen);
1268772e66a6SGleb Smirnoff
1269772e66a6SGleb Smirnoff /*
1270772e66a6SGleb Smirnoff * Run estimator on class and its ancestors.
1271772e66a6SGleb Smirnoff */
1272772e66a6SGleb Smirnoff /*
1273772e66a6SGleb Smirnoff * rm_update_class_util is designed to be called when the
1274772e66a6SGleb Smirnoff * transfer is completed from a xmit complete interrupt,
1275772e66a6SGleb Smirnoff * but most drivers don't implement an upcall for that.
1276772e66a6SGleb Smirnoff * so, just use estimated completion time.
1277772e66a6SGleb Smirnoff * as a result, ifd->qi_ and ifd->qo_ are always synced.
1278772e66a6SGleb Smirnoff */
1279772e66a6SGleb Smirnoff nowp = &ifd->now_[ifd->qo_];
1280772e66a6SGleb Smirnoff /* get pkt_time (for link) in usec */
1281772e66a6SGleb Smirnoff #if 1 /* use approximation */
1282772e66a6SGleb Smirnoff pkt_time = ifd->curlen_[ifd->qo_] * ifd->ns_per_byte_;
1283772e66a6SGleb Smirnoff pkt_time = NSEC_TO_USEC(pkt_time);
1284772e66a6SGleb Smirnoff #else
1285772e66a6SGleb Smirnoff pkt_time = ifd->curlen_[ifd->qo_] * ifd->ns_per_byte_ / 1000;
1286772e66a6SGleb Smirnoff #endif
1287772e66a6SGleb Smirnoff #if 1 /* ALTQ4PPP */
1288772e66a6SGleb Smirnoff if (TV_LT(nowp, &ifd->ifnow_)) {
1289772e66a6SGleb Smirnoff int iftime;
1290772e66a6SGleb Smirnoff
1291772e66a6SGleb Smirnoff /*
1292772e66a6SGleb Smirnoff * make sure the estimated completion time does not go
1293772e66a6SGleb Smirnoff * too far. it can happen when the link layer supports
1294772e66a6SGleb Smirnoff * data compression or the interface speed is set to
1295772e66a6SGleb Smirnoff * a much lower value.
1296772e66a6SGleb Smirnoff */
1297772e66a6SGleb Smirnoff TV_DELTA(&ifd->ifnow_, nowp, iftime);
1298772e66a6SGleb Smirnoff if (iftime+pkt_time < ifd->maxiftime_) {
1299772e66a6SGleb Smirnoff TV_ADD_DELTA(&ifd->ifnow_, pkt_time, &ifd->ifnow_);
1300772e66a6SGleb Smirnoff } else {
1301772e66a6SGleb Smirnoff TV_ADD_DELTA(nowp, ifd->maxiftime_, &ifd->ifnow_);
1302772e66a6SGleb Smirnoff }
1303772e66a6SGleb Smirnoff } else {
1304772e66a6SGleb Smirnoff TV_ADD_DELTA(nowp, pkt_time, &ifd->ifnow_);
1305772e66a6SGleb Smirnoff }
1306772e66a6SGleb Smirnoff #else
1307772e66a6SGleb Smirnoff if (TV_LT(nowp, &ifd->ifnow_)) {
1308772e66a6SGleb Smirnoff TV_ADD_DELTA(&ifd->ifnow_, pkt_time, &ifd->ifnow_);
1309772e66a6SGleb Smirnoff } else {
1310772e66a6SGleb Smirnoff TV_ADD_DELTA(nowp, pkt_time, &ifd->ifnow_);
1311772e66a6SGleb Smirnoff }
1312772e66a6SGleb Smirnoff #endif
1313772e66a6SGleb Smirnoff
1314772e66a6SGleb Smirnoff while (cl != NULL) {
1315772e66a6SGleb Smirnoff TV_DELTA(&ifd->ifnow_, &cl->last_, idle);
1316772e66a6SGleb Smirnoff if (idle >= 2000000)
1317772e66a6SGleb Smirnoff /*
1318772e66a6SGleb Smirnoff * this class is idle enough, reset avgidle.
1319772e66a6SGleb Smirnoff * (TV_DELTA returns 2000000 us when delta is large.)
1320772e66a6SGleb Smirnoff */
1321772e66a6SGleb Smirnoff cl->avgidle_ = cl->maxidle_;
1322772e66a6SGleb Smirnoff
1323772e66a6SGleb Smirnoff /* get pkt_time (for class) in usec */
1324772e66a6SGleb Smirnoff #if 1 /* use approximation */
1325772e66a6SGleb Smirnoff pkt_time = pktlen * cl->ns_per_byte_;
1326772e66a6SGleb Smirnoff pkt_time = NSEC_TO_USEC(pkt_time);
1327772e66a6SGleb Smirnoff #else
1328772e66a6SGleb Smirnoff pkt_time = pktlen * cl->ns_per_byte_ / 1000;
1329772e66a6SGleb Smirnoff #endif
1330772e66a6SGleb Smirnoff idle -= pkt_time;
1331772e66a6SGleb Smirnoff
1332772e66a6SGleb Smirnoff avgidle = cl->avgidle_;
1333772e66a6SGleb Smirnoff avgidle += idle - (avgidle >> RM_FILTER_GAIN);
1334772e66a6SGleb Smirnoff cl->avgidle_ = avgidle;
1335772e66a6SGleb Smirnoff
1336772e66a6SGleb Smirnoff /* Are we overlimit ? */
1337772e66a6SGleb Smirnoff if (avgidle <= 0) {
1338772e66a6SGleb Smirnoff CBQTRACE(rmc_update_class_util, 'milo', cl->stats_.handle);
1339772e66a6SGleb Smirnoff #if 1 /* ALTQ */
1340772e66a6SGleb Smirnoff /*
1341772e66a6SGleb Smirnoff * need some lower bound for avgidle, otherwise
1342772e66a6SGleb Smirnoff * a borrowing class gets unbounded penalty.
1343772e66a6SGleb Smirnoff */
1344772e66a6SGleb Smirnoff if (avgidle < cl->minidle_)
1345772e66a6SGleb Smirnoff avgidle = cl->avgidle_ = cl->minidle_;
1346772e66a6SGleb Smirnoff #endif
1347772e66a6SGleb Smirnoff /* set next idle to make avgidle 0 */
1348772e66a6SGleb Smirnoff tidle = pkt_time +
1349772e66a6SGleb Smirnoff (((1 - RM_POWER) * avgidle) >> RM_FILTER_GAIN);
1350772e66a6SGleb Smirnoff TV_ADD_DELTA(nowp, tidle, &cl->undertime_);
1351772e66a6SGleb Smirnoff ++cl->stats_.over;
1352772e66a6SGleb Smirnoff } else {
1353772e66a6SGleb Smirnoff cl->avgidle_ =
1354772e66a6SGleb Smirnoff (avgidle > cl->maxidle_) ? cl->maxidle_ : avgidle;
1355772e66a6SGleb Smirnoff cl->undertime_.tv_sec = 0;
1356772e66a6SGleb Smirnoff if (cl->sleeping_) {
1357772e66a6SGleb Smirnoff CALLOUT_STOP(&cl->callout_);
1358772e66a6SGleb Smirnoff cl->sleeping_ = 0;
1359772e66a6SGleb Smirnoff }
1360772e66a6SGleb Smirnoff }
1361772e66a6SGleb Smirnoff
1362772e66a6SGleb Smirnoff if (borrows != NULL) {
1363772e66a6SGleb Smirnoff if (borrows != cl)
1364772e66a6SGleb Smirnoff ++cl->stats_.borrows;
1365772e66a6SGleb Smirnoff else
1366772e66a6SGleb Smirnoff borrows = NULL;
1367772e66a6SGleb Smirnoff }
1368772e66a6SGleb Smirnoff cl->last_ = ifd->ifnow_;
1369772e66a6SGleb Smirnoff cl->last_pkttime_ = pkt_time;
1370772e66a6SGleb Smirnoff
1371772e66a6SGleb Smirnoff #if 1
1372772e66a6SGleb Smirnoff if (cl->parent_ == NULL) {
1373772e66a6SGleb Smirnoff /* take stats of root class */
1374772e66a6SGleb Smirnoff PKTCNTR_ADD(&cl->stats_.xmit_cnt, pktlen);
1375772e66a6SGleb Smirnoff }
1376772e66a6SGleb Smirnoff #endif
1377772e66a6SGleb Smirnoff
1378772e66a6SGleb Smirnoff cl = cl->parent_;
1379772e66a6SGleb Smirnoff }
1380772e66a6SGleb Smirnoff
1381772e66a6SGleb Smirnoff /*
1382772e66a6SGleb Smirnoff * Check to see if cutoff needs to set to a new level.
1383772e66a6SGleb Smirnoff */
1384772e66a6SGleb Smirnoff cl = ifd->class_[ifd->qo_];
1385772e66a6SGleb Smirnoff if (borrowed && (ifd->cutoff_ >= borrowed->depth_)) {
1386772e66a6SGleb Smirnoff #if 1 /* ALTQ */
1387772e66a6SGleb Smirnoff if ((qlen(cl->q_) <= 0) || TV_LT(nowp, &borrowed->undertime_)) {
1388772e66a6SGleb Smirnoff rmc_tl_satisfied(ifd, nowp);
1389772e66a6SGleb Smirnoff CBQTRACE(rmc_update_class_util, 'broe', ifd->cutoff_);
1390772e66a6SGleb Smirnoff } else {
1391772e66a6SGleb Smirnoff ifd->cutoff_ = borrowed->depth_;
1392772e66a6SGleb Smirnoff CBQTRACE(rmc_update_class_util, 'ffob', borrowed->depth_);
1393772e66a6SGleb Smirnoff }
1394772e66a6SGleb Smirnoff #else /* !ALTQ */
1395772e66a6SGleb Smirnoff if ((qlen(cl->q_) <= 1) || TV_LT(&now, &borrowed->undertime_)) {
1396772e66a6SGleb Smirnoff reset_cutoff(ifd);
1397772e66a6SGleb Smirnoff #ifdef notdef
1398772e66a6SGleb Smirnoff rmc_tl_satisfied(ifd, &now);
1399772e66a6SGleb Smirnoff #endif
1400772e66a6SGleb Smirnoff CBQTRACE(rmc_update_class_util, 'broe', ifd->cutoff_);
1401772e66a6SGleb Smirnoff } else {
1402772e66a6SGleb Smirnoff ifd->cutoff_ = borrowed->depth_;
1403772e66a6SGleb Smirnoff CBQTRACE(rmc_update_class_util, 'ffob', borrowed->depth_);
1404772e66a6SGleb Smirnoff }
1405772e66a6SGleb Smirnoff #endif /* !ALTQ */
1406772e66a6SGleb Smirnoff }
1407772e66a6SGleb Smirnoff
1408772e66a6SGleb Smirnoff /*
1409772e66a6SGleb Smirnoff * Release class slot
1410772e66a6SGleb Smirnoff */
1411772e66a6SGleb Smirnoff ifd->borrowed_[ifd->qo_] = NULL;
1412772e66a6SGleb Smirnoff ifd->class_[ifd->qo_] = NULL;
1413772e66a6SGleb Smirnoff ifd->qo_ = (ifd->qo_ + 1) % ifd->maxqueued_;
1414772e66a6SGleb Smirnoff ifd->queued_--;
1415772e66a6SGleb Smirnoff }
1416772e66a6SGleb Smirnoff
1417772e66a6SGleb Smirnoff /*
1418772e66a6SGleb Smirnoff * void
1419772e66a6SGleb Smirnoff * rmc_drop_action(struct rm_class *cl) - Generic (not protocol-specific)
1420772e66a6SGleb Smirnoff * over-limit action routines. These get invoked by rmc_under_limit()
1421772e66a6SGleb Smirnoff * if a class with packets to send if over its bandwidth limit & can't
1422772e66a6SGleb Smirnoff * borrow from a parent class.
1423772e66a6SGleb Smirnoff *
1424772e66a6SGleb Smirnoff * Returns: NONE
1425772e66a6SGleb Smirnoff */
1426772e66a6SGleb Smirnoff
1427772e66a6SGleb Smirnoff static void
rmc_drop_action(struct rm_class * cl)1428772e66a6SGleb Smirnoff rmc_drop_action(struct rm_class *cl)
1429772e66a6SGleb Smirnoff {
1430772e66a6SGleb Smirnoff struct rm_ifdat *ifd = cl->ifdat_;
1431772e66a6SGleb Smirnoff
1432772e66a6SGleb Smirnoff ASSERT(qlen(cl->q_) > 0);
1433772e66a6SGleb Smirnoff _rmc_dropq(cl);
1434772e66a6SGleb Smirnoff if (qempty(cl->q_))
1435772e66a6SGleb Smirnoff ifd->na_[cl->pri_]--;
1436772e66a6SGleb Smirnoff }
1437772e66a6SGleb Smirnoff
rmc_dropall(struct rm_class * cl)1438772e66a6SGleb Smirnoff void rmc_dropall(struct rm_class *cl)
1439772e66a6SGleb Smirnoff {
1440772e66a6SGleb Smirnoff struct rm_ifdat *ifd = cl->ifdat_;
1441772e66a6SGleb Smirnoff
1442772e66a6SGleb Smirnoff if (!qempty(cl->q_)) {
1443772e66a6SGleb Smirnoff _flushq(cl->q_);
1444772e66a6SGleb Smirnoff
1445772e66a6SGleb Smirnoff ifd->na_[cl->pri_]--;
1446772e66a6SGleb Smirnoff }
1447772e66a6SGleb Smirnoff }
1448772e66a6SGleb Smirnoff
1449772e66a6SGleb Smirnoff static int
hzto(struct timeval * tv)1450*ef2235ecSElliott Mitchell hzto(struct timeval *tv)
1451772e66a6SGleb Smirnoff {
1452772e66a6SGleb Smirnoff struct timeval t2;
1453772e66a6SGleb Smirnoff
1454772e66a6SGleb Smirnoff getmicrotime(&t2);
1455772e66a6SGleb Smirnoff t2.tv_sec = tv->tv_sec - t2.tv_sec;
1456772e66a6SGleb Smirnoff t2.tv_usec = tv->tv_usec - t2.tv_usec;
1457772e66a6SGleb Smirnoff return (tvtohz(&t2));
1458772e66a6SGleb Smirnoff }
1459772e66a6SGleb Smirnoff
1460772e66a6SGleb Smirnoff /*
1461772e66a6SGleb Smirnoff * void
1462772e66a6SGleb Smirnoff * rmc_delay_action(struct rm_class *cl) - This function is the generic CBQ
1463772e66a6SGleb Smirnoff * delay action routine. It is invoked via rmc_under_limit when the
1464772e66a6SGleb Smirnoff * packet is discoverd to be overlimit.
1465772e66a6SGleb Smirnoff *
1466772e66a6SGleb Smirnoff * If the delay action is result of borrow class being overlimit, then
1467772e66a6SGleb Smirnoff * delay for the offtime of the borrowing class that is overlimit.
1468772e66a6SGleb Smirnoff *
1469772e66a6SGleb Smirnoff * Returns: NONE
1470772e66a6SGleb Smirnoff */
1471772e66a6SGleb Smirnoff
1472772e66a6SGleb Smirnoff void
rmc_delay_action(struct rm_class * cl,struct rm_class * borrow)1473772e66a6SGleb Smirnoff rmc_delay_action(struct rm_class *cl, struct rm_class *borrow)
1474772e66a6SGleb Smirnoff {
1475772e66a6SGleb Smirnoff int delay, t, extradelay;
1476772e66a6SGleb Smirnoff
1477772e66a6SGleb Smirnoff cl->stats_.overactions++;
1478772e66a6SGleb Smirnoff TV_DELTA(&cl->undertime_, &cl->overtime_, delay);
1479772e66a6SGleb Smirnoff #ifndef BORROW_OFFTIME
1480772e66a6SGleb Smirnoff delay += cl->offtime_;
1481772e66a6SGleb Smirnoff #endif
1482772e66a6SGleb Smirnoff
1483772e66a6SGleb Smirnoff if (!cl->sleeping_) {
1484772e66a6SGleb Smirnoff CBQTRACE(rmc_delay_action, 'yled', cl->stats_.handle);
1485772e66a6SGleb Smirnoff #ifdef BORROW_OFFTIME
1486772e66a6SGleb Smirnoff if (borrow != NULL)
1487772e66a6SGleb Smirnoff extradelay = borrow->offtime_;
1488772e66a6SGleb Smirnoff else
1489772e66a6SGleb Smirnoff #endif
1490772e66a6SGleb Smirnoff extradelay = cl->offtime_;
1491772e66a6SGleb Smirnoff
1492772e66a6SGleb Smirnoff #ifdef ALTQ
1493772e66a6SGleb Smirnoff /*
1494772e66a6SGleb Smirnoff * XXX recalculate suspend time:
1495772e66a6SGleb Smirnoff * current undertime is (tidle + pkt_time) calculated
1496772e66a6SGleb Smirnoff * from the last transmission.
1497772e66a6SGleb Smirnoff * tidle: time required to bring avgidle back to 0
1498772e66a6SGleb Smirnoff * pkt_time: target waiting time for this class
1499772e66a6SGleb Smirnoff * we need to replace pkt_time by offtime
1500772e66a6SGleb Smirnoff */
1501772e66a6SGleb Smirnoff extradelay -= cl->last_pkttime_;
1502772e66a6SGleb Smirnoff #endif
1503772e66a6SGleb Smirnoff if (extradelay > 0) {
1504772e66a6SGleb Smirnoff TV_ADD_DELTA(&cl->undertime_, extradelay, &cl->undertime_);
1505772e66a6SGleb Smirnoff delay += extradelay;
1506772e66a6SGleb Smirnoff }
1507772e66a6SGleb Smirnoff
1508772e66a6SGleb Smirnoff cl->sleeping_ = 1;
1509772e66a6SGleb Smirnoff cl->stats_.delays++;
1510772e66a6SGleb Smirnoff
1511772e66a6SGleb Smirnoff /*
1512772e66a6SGleb Smirnoff * Since packets are phased randomly with respect to the
1513772e66a6SGleb Smirnoff * clock, 1 tick (the next clock tick) can be an arbitrarily
1514772e66a6SGleb Smirnoff * short time so we have to wait for at least two ticks.
1515772e66a6SGleb Smirnoff * NOTE: If there's no other traffic, we need the timer as
1516772e66a6SGleb Smirnoff * a 'backstop' to restart this class.
1517772e66a6SGleb Smirnoff */
1518772e66a6SGleb Smirnoff if (delay > tick * 2) {
1519772e66a6SGleb Smirnoff /* FreeBSD rounds up the tick */
1520772e66a6SGleb Smirnoff t = hzto(&cl->undertime_);
1521772e66a6SGleb Smirnoff } else
1522772e66a6SGleb Smirnoff t = 2;
152365d2f9c1SJohn Baldwin CALLOUT_RESET(&cl->callout_, t, rmc_restart, cl);
1524772e66a6SGleb Smirnoff }
1525772e66a6SGleb Smirnoff }
1526772e66a6SGleb Smirnoff
1527772e66a6SGleb Smirnoff /*
1528772e66a6SGleb Smirnoff * void
1529772e66a6SGleb Smirnoff * rmc_restart() - is just a helper routine for rmc_delay_action -- it is
1530772e66a6SGleb Smirnoff * called by the system timer code & is responsible checking if the
1531772e66a6SGleb Smirnoff * class is still sleeping (it might have been restarted as a side
1532772e66a6SGleb Smirnoff * effect of the queue scan on a packet arrival) and, if so, restarting
1533772e66a6SGleb Smirnoff * output for the class. Inspecting the class state & restarting output
1534772e66a6SGleb Smirnoff * require locking the class structure. In general the driver is
1535772e66a6SGleb Smirnoff * responsible for locking but this is the only routine that is not
1536772e66a6SGleb Smirnoff * called directly or indirectly from the interface driver so it has
1537772e66a6SGleb Smirnoff * know about system locking conventions. Under bsd, locking is done
1538772e66a6SGleb Smirnoff * by raising IPL to splimp so that's what's implemented here. On a
1539772e66a6SGleb Smirnoff * different system this would probably need to be changed.
1540772e66a6SGleb Smirnoff *
1541772e66a6SGleb Smirnoff * Returns: NONE
1542772e66a6SGleb Smirnoff */
1543772e66a6SGleb Smirnoff
1544772e66a6SGleb Smirnoff static void
rmc_restart(void * arg)154565d2f9c1SJohn Baldwin rmc_restart(void *arg)
1546772e66a6SGleb Smirnoff {
154765d2f9c1SJohn Baldwin struct rm_class *cl = arg;
1548772e66a6SGleb Smirnoff struct rm_ifdat *ifd = cl->ifdat_;
1549159258afSKristof Provost struct epoch_tracker et;
1550772e66a6SGleb Smirnoff int s;
1551772e66a6SGleb Smirnoff
1552772e66a6SGleb Smirnoff s = splnet();
1553159258afSKristof Provost NET_EPOCH_ENTER(et);
1554772e66a6SGleb Smirnoff IFQ_LOCK(ifd->ifq_);
1555159258afSKristof Provost CURVNET_SET(ifd->ifq_->altq_ifp->if_vnet);
1556772e66a6SGleb Smirnoff if (cl->sleeping_) {
1557772e66a6SGleb Smirnoff cl->sleeping_ = 0;
1558772e66a6SGleb Smirnoff cl->undertime_.tv_sec = 0;
1559772e66a6SGleb Smirnoff
1560772e66a6SGleb Smirnoff if (ifd->queued_ < ifd->maxqueued_ && ifd->restart != NULL) {
1561772e66a6SGleb Smirnoff CBQTRACE(rmc_restart, 'trts', cl->stats_.handle);
1562772e66a6SGleb Smirnoff (ifd->restart)(ifd->ifq_);
1563772e66a6SGleb Smirnoff }
1564772e66a6SGleb Smirnoff }
1565159258afSKristof Provost CURVNET_RESTORE();
1566772e66a6SGleb Smirnoff IFQ_UNLOCK(ifd->ifq_);
1567159258afSKristof Provost NET_EPOCH_EXIT(et);
1568772e66a6SGleb Smirnoff splx(s);
1569772e66a6SGleb Smirnoff }
1570772e66a6SGleb Smirnoff
1571772e66a6SGleb Smirnoff /*
1572772e66a6SGleb Smirnoff * void
1573772e66a6SGleb Smirnoff * rmc_root_overlimit(struct rm_class *cl) - This the generic overlimit
1574772e66a6SGleb Smirnoff * handling routine for the root class of the link sharing structure.
1575772e66a6SGleb Smirnoff *
1576772e66a6SGleb Smirnoff * Returns: NONE
1577772e66a6SGleb Smirnoff */
1578772e66a6SGleb Smirnoff
1579772e66a6SGleb Smirnoff static void
rmc_root_overlimit(struct rm_class * cl,struct rm_class * borrow)1580772e66a6SGleb Smirnoff rmc_root_overlimit(struct rm_class *cl, struct rm_class *borrow)
1581772e66a6SGleb Smirnoff {
1582772e66a6SGleb Smirnoff panic("rmc_root_overlimit");
1583772e66a6SGleb Smirnoff }
1584772e66a6SGleb Smirnoff
1585772e66a6SGleb Smirnoff /*
1586772e66a6SGleb Smirnoff * Packet Queue handling routines. Eventually, this is to localize the
1587772e66a6SGleb Smirnoff * effects on the code whether queues are red queues or droptail
1588772e66a6SGleb Smirnoff * queues.
1589772e66a6SGleb Smirnoff */
1590772e66a6SGleb Smirnoff
1591772e66a6SGleb Smirnoff static int
_rmc_addq(rm_class_t * cl,mbuf_t * m)1592772e66a6SGleb Smirnoff _rmc_addq(rm_class_t *cl, mbuf_t *m)
1593772e66a6SGleb Smirnoff {
1594772e66a6SGleb Smirnoff #ifdef ALTQ_RIO
1595772e66a6SGleb Smirnoff if (q_is_rio(cl->q_))
1596772e66a6SGleb Smirnoff return rio_addq((rio_t *)cl->red_, cl->q_, m, cl->pktattr_);
1597772e66a6SGleb Smirnoff #endif
1598772e66a6SGleb Smirnoff #ifdef ALTQ_RED
1599772e66a6SGleb Smirnoff if (q_is_red(cl->q_))
1600772e66a6SGleb Smirnoff return red_addq(cl->red_, cl->q_, m, cl->pktattr_);
1601772e66a6SGleb Smirnoff #endif /* ALTQ_RED */
16020a70aaf8SLuiz Otavio O Souza #ifdef ALTQ_CODEL
16030a70aaf8SLuiz Otavio O Souza if (q_is_codel(cl->q_))
16040a70aaf8SLuiz Otavio O Souza return codel_addq(cl->codel_, cl->q_, m);
16050a70aaf8SLuiz Otavio O Souza #endif
1606772e66a6SGleb Smirnoff
1607772e66a6SGleb Smirnoff if (cl->flags_ & RMCF_CLEARDSCP)
1608772e66a6SGleb Smirnoff write_dsfield(m, cl->pktattr_, 0);
1609772e66a6SGleb Smirnoff
1610772e66a6SGleb Smirnoff _addq(cl->q_, m);
1611772e66a6SGleb Smirnoff return (0);
1612772e66a6SGleb Smirnoff }
1613772e66a6SGleb Smirnoff
1614772e66a6SGleb Smirnoff /* note: _rmc_dropq is not called for red */
1615772e66a6SGleb Smirnoff static void
_rmc_dropq(rm_class_t * cl)1616772e66a6SGleb Smirnoff _rmc_dropq(rm_class_t *cl)
1617772e66a6SGleb Smirnoff {
1618772e66a6SGleb Smirnoff mbuf_t *m;
1619772e66a6SGleb Smirnoff
1620772e66a6SGleb Smirnoff if ((m = _getq(cl->q_)) != NULL)
1621772e66a6SGleb Smirnoff m_freem(m);
1622772e66a6SGleb Smirnoff }
1623772e66a6SGleb Smirnoff
1624772e66a6SGleb Smirnoff static mbuf_t *
_rmc_getq(rm_class_t * cl)1625772e66a6SGleb Smirnoff _rmc_getq(rm_class_t *cl)
1626772e66a6SGleb Smirnoff {
1627772e66a6SGleb Smirnoff #ifdef ALTQ_RIO
1628772e66a6SGleb Smirnoff if (q_is_rio(cl->q_))
1629772e66a6SGleb Smirnoff return rio_getq((rio_t *)cl->red_, cl->q_);
1630772e66a6SGleb Smirnoff #endif
1631772e66a6SGleb Smirnoff #ifdef ALTQ_RED
1632772e66a6SGleb Smirnoff if (q_is_red(cl->q_))
1633772e66a6SGleb Smirnoff return red_getq(cl->red_, cl->q_);
1634772e66a6SGleb Smirnoff #endif
16350a70aaf8SLuiz Otavio O Souza #ifdef ALTQ_CODEL
16360a70aaf8SLuiz Otavio O Souza if (q_is_codel(cl->q_))
16370a70aaf8SLuiz Otavio O Souza return codel_getq(cl->codel_, cl->q_);
16380a70aaf8SLuiz Otavio O Souza #endif
1639772e66a6SGleb Smirnoff return _getq(cl->q_);
1640772e66a6SGleb Smirnoff }
1641772e66a6SGleb Smirnoff
1642772e66a6SGleb Smirnoff static mbuf_t *
_rmc_pollq(rm_class_t * cl)1643772e66a6SGleb Smirnoff _rmc_pollq(rm_class_t *cl)
1644772e66a6SGleb Smirnoff {
1645772e66a6SGleb Smirnoff return qhead(cl->q_);
1646772e66a6SGleb Smirnoff }
1647772e66a6SGleb Smirnoff
1648772e66a6SGleb Smirnoff #ifdef CBQ_TRACE
1649772e66a6SGleb Smirnoff
1650772e66a6SGleb Smirnoff struct cbqtrace cbqtrace_buffer[NCBQTRACE+1];
1651772e66a6SGleb Smirnoff struct cbqtrace *cbqtrace_ptr = NULL;
1652772e66a6SGleb Smirnoff int cbqtrace_count;
1653772e66a6SGleb Smirnoff
1654772e66a6SGleb Smirnoff /*
1655772e66a6SGleb Smirnoff * DDB hook to trace cbq events:
1656772e66a6SGleb Smirnoff * the last 1024 events are held in a circular buffer.
1657772e66a6SGleb Smirnoff * use "call cbqtrace_dump(N)" to display 20 events from Nth event.
1658772e66a6SGleb Smirnoff */
1659772e66a6SGleb Smirnoff void cbqtrace_dump(int);
1660772e66a6SGleb Smirnoff static char *rmc_funcname(void *);
1661772e66a6SGleb Smirnoff
1662772e66a6SGleb Smirnoff static struct rmc_funcs {
1663772e66a6SGleb Smirnoff void *func;
1664772e66a6SGleb Smirnoff char *name;
1665772e66a6SGleb Smirnoff } rmc_funcs[] =
1666772e66a6SGleb Smirnoff {
1667772e66a6SGleb Smirnoff rmc_init, "rmc_init",
1668772e66a6SGleb Smirnoff rmc_queue_packet, "rmc_queue_packet",
1669772e66a6SGleb Smirnoff rmc_under_limit, "rmc_under_limit",
1670772e66a6SGleb Smirnoff rmc_update_class_util, "rmc_update_class_util",
1671772e66a6SGleb Smirnoff rmc_delay_action, "rmc_delay_action",
1672772e66a6SGleb Smirnoff rmc_restart, "rmc_restart",
1673772e66a6SGleb Smirnoff _rmc_wrr_dequeue_next, "_rmc_wrr_dequeue_next",
1674772e66a6SGleb Smirnoff NULL, NULL
1675772e66a6SGleb Smirnoff };
1676772e66a6SGleb Smirnoff
rmc_funcname(void * func)1677772e66a6SGleb Smirnoff static char *rmc_funcname(void *func)
1678772e66a6SGleb Smirnoff {
1679772e66a6SGleb Smirnoff struct rmc_funcs *fp;
1680772e66a6SGleb Smirnoff
1681772e66a6SGleb Smirnoff for (fp = rmc_funcs; fp->func != NULL; fp++)
1682772e66a6SGleb Smirnoff if (fp->func == func)
1683772e66a6SGleb Smirnoff return (fp->name);
1684772e66a6SGleb Smirnoff return ("unknown");
1685772e66a6SGleb Smirnoff }
1686772e66a6SGleb Smirnoff
cbqtrace_dump(int counter)1687772e66a6SGleb Smirnoff void cbqtrace_dump(int counter)
1688772e66a6SGleb Smirnoff {
1689772e66a6SGleb Smirnoff int i, *p;
1690772e66a6SGleb Smirnoff char *cp;
1691772e66a6SGleb Smirnoff
1692772e66a6SGleb Smirnoff counter = counter % NCBQTRACE;
1693772e66a6SGleb Smirnoff p = (int *)&cbqtrace_buffer[counter];
1694772e66a6SGleb Smirnoff
1695772e66a6SGleb Smirnoff for (i=0; i<20; i++) {
1696772e66a6SGleb Smirnoff printf("[0x%x] ", *p++);
1697772e66a6SGleb Smirnoff printf("%s: ", rmc_funcname((void *)*p++));
1698772e66a6SGleb Smirnoff cp = (char *)p++;
1699772e66a6SGleb Smirnoff printf("%c%c%c%c: ", cp[0], cp[1], cp[2], cp[3]);
1700772e66a6SGleb Smirnoff printf("%d\n",*p++);
1701772e66a6SGleb Smirnoff
1702772e66a6SGleb Smirnoff if (p >= (int *)&cbqtrace_buffer[NCBQTRACE])
1703772e66a6SGleb Smirnoff p = (int *)cbqtrace_buffer;
1704772e66a6SGleb Smirnoff }
1705772e66a6SGleb Smirnoff }
1706772e66a6SGleb Smirnoff #endif /* CBQ_TRACE */
1707772e66a6SGleb Smirnoff #endif /* ALTQ_CBQ */
1708772e66a6SGleb Smirnoff
17090a70aaf8SLuiz Otavio O Souza #if defined(ALTQ_CBQ) || defined(ALTQ_RED) || defined(ALTQ_RIO) || \
17100a70aaf8SLuiz Otavio O Souza defined(ALTQ_HFSC) || defined(ALTQ_PRIQ) || defined(ALTQ_CODEL)
1711772e66a6SGleb Smirnoff #if !defined(__GNUC__) || defined(ALTQ_DEBUG)
1712772e66a6SGleb Smirnoff
1713772e66a6SGleb Smirnoff void
_addq(class_queue_t * q,mbuf_t * m)1714772e66a6SGleb Smirnoff _addq(class_queue_t *q, mbuf_t *m)
1715772e66a6SGleb Smirnoff {
1716772e66a6SGleb Smirnoff mbuf_t *m0;
1717772e66a6SGleb Smirnoff
1718772e66a6SGleb Smirnoff if ((m0 = qtail(q)) != NULL)
1719772e66a6SGleb Smirnoff m->m_nextpkt = m0->m_nextpkt;
1720772e66a6SGleb Smirnoff else
1721772e66a6SGleb Smirnoff m0 = m;
1722772e66a6SGleb Smirnoff m0->m_nextpkt = m;
1723772e66a6SGleb Smirnoff qtail(q) = m;
1724772e66a6SGleb Smirnoff qlen(q)++;
1725772e66a6SGleb Smirnoff }
1726772e66a6SGleb Smirnoff
1727772e66a6SGleb Smirnoff mbuf_t *
_getq(class_queue_t * q)1728772e66a6SGleb Smirnoff _getq(class_queue_t *q)
1729772e66a6SGleb Smirnoff {
1730772e66a6SGleb Smirnoff mbuf_t *m, *m0;
1731772e66a6SGleb Smirnoff
1732772e66a6SGleb Smirnoff if ((m = qtail(q)) == NULL)
1733772e66a6SGleb Smirnoff return (NULL);
1734772e66a6SGleb Smirnoff if ((m0 = m->m_nextpkt) != m)
1735772e66a6SGleb Smirnoff m->m_nextpkt = m0->m_nextpkt;
1736772e66a6SGleb Smirnoff else {
1737772e66a6SGleb Smirnoff ASSERT(qlen(q) == 1);
1738772e66a6SGleb Smirnoff qtail(q) = NULL;
1739772e66a6SGleb Smirnoff }
1740772e66a6SGleb Smirnoff qlen(q)--;
1741772e66a6SGleb Smirnoff m0->m_nextpkt = NULL;
1742772e66a6SGleb Smirnoff return (m0);
1743772e66a6SGleb Smirnoff }
1744772e66a6SGleb Smirnoff
1745772e66a6SGleb Smirnoff /* drop a packet at the tail of the queue */
1746772e66a6SGleb Smirnoff mbuf_t *
_getq_tail(class_queue_t * q)1747772e66a6SGleb Smirnoff _getq_tail(class_queue_t *q)
1748772e66a6SGleb Smirnoff {
1749772e66a6SGleb Smirnoff mbuf_t *m, *m0, *prev;
1750772e66a6SGleb Smirnoff
1751772e66a6SGleb Smirnoff if ((m = m0 = qtail(q)) == NULL)
1752772e66a6SGleb Smirnoff return NULL;
1753772e66a6SGleb Smirnoff do {
1754772e66a6SGleb Smirnoff prev = m0;
1755772e66a6SGleb Smirnoff m0 = m0->m_nextpkt;
1756772e66a6SGleb Smirnoff } while (m0 != m);
1757772e66a6SGleb Smirnoff prev->m_nextpkt = m->m_nextpkt;
1758772e66a6SGleb Smirnoff if (prev == m) {
1759772e66a6SGleb Smirnoff ASSERT(qlen(q) == 1);
1760772e66a6SGleb Smirnoff qtail(q) = NULL;
1761772e66a6SGleb Smirnoff } else
1762772e66a6SGleb Smirnoff qtail(q) = prev;
1763772e66a6SGleb Smirnoff qlen(q)--;
1764772e66a6SGleb Smirnoff m->m_nextpkt = NULL;
1765772e66a6SGleb Smirnoff return (m);
1766772e66a6SGleb Smirnoff }
1767772e66a6SGleb Smirnoff
1768772e66a6SGleb Smirnoff /* randomly select a packet in the queue */
1769772e66a6SGleb Smirnoff mbuf_t *
_getq_random(class_queue_t * q)1770772e66a6SGleb Smirnoff _getq_random(class_queue_t *q)
1771772e66a6SGleb Smirnoff {
1772772e66a6SGleb Smirnoff struct mbuf *m;
1773772e66a6SGleb Smirnoff int i, n;
1774772e66a6SGleb Smirnoff
1775772e66a6SGleb Smirnoff if ((m = qtail(q)) == NULL)
1776772e66a6SGleb Smirnoff return NULL;
1777772e66a6SGleb Smirnoff if (m->m_nextpkt == m) {
1778772e66a6SGleb Smirnoff ASSERT(qlen(q) == 1);
1779772e66a6SGleb Smirnoff qtail(q) = NULL;
1780772e66a6SGleb Smirnoff } else {
1781772e66a6SGleb Smirnoff struct mbuf *prev = NULL;
1782772e66a6SGleb Smirnoff
1783772e66a6SGleb Smirnoff n = arc4random() % qlen(q) + 1;
1784772e66a6SGleb Smirnoff for (i = 0; i < n; i++) {
1785772e66a6SGleb Smirnoff prev = m;
1786772e66a6SGleb Smirnoff m = m->m_nextpkt;
1787772e66a6SGleb Smirnoff }
1788772e66a6SGleb Smirnoff prev->m_nextpkt = m->m_nextpkt;
1789772e66a6SGleb Smirnoff if (m == qtail(q))
1790772e66a6SGleb Smirnoff qtail(q) = prev;
1791772e66a6SGleb Smirnoff }
1792772e66a6SGleb Smirnoff qlen(q)--;
1793772e66a6SGleb Smirnoff m->m_nextpkt = NULL;
1794772e66a6SGleb Smirnoff return (m);
1795772e66a6SGleb Smirnoff }
1796772e66a6SGleb Smirnoff
1797772e66a6SGleb Smirnoff void
_removeq(class_queue_t * q,mbuf_t * m)1798772e66a6SGleb Smirnoff _removeq(class_queue_t *q, mbuf_t *m)
1799772e66a6SGleb Smirnoff {
1800772e66a6SGleb Smirnoff mbuf_t *m0, *prev;
1801772e66a6SGleb Smirnoff
1802772e66a6SGleb Smirnoff m0 = qtail(q);
1803772e66a6SGleb Smirnoff do {
1804772e66a6SGleb Smirnoff prev = m0;
1805772e66a6SGleb Smirnoff m0 = m0->m_nextpkt;
1806772e66a6SGleb Smirnoff } while (m0 != m);
1807772e66a6SGleb Smirnoff prev->m_nextpkt = m->m_nextpkt;
1808772e66a6SGleb Smirnoff if (prev == m)
1809772e66a6SGleb Smirnoff qtail(q) = NULL;
1810772e66a6SGleb Smirnoff else if (qtail(q) == m)
1811772e66a6SGleb Smirnoff qtail(q) = prev;
1812772e66a6SGleb Smirnoff qlen(q)--;
1813772e66a6SGleb Smirnoff }
1814772e66a6SGleb Smirnoff
1815772e66a6SGleb Smirnoff void
_flushq(class_queue_t * q)1816772e66a6SGleb Smirnoff _flushq(class_queue_t *q)
1817772e66a6SGleb Smirnoff {
1818772e66a6SGleb Smirnoff mbuf_t *m;
1819772e66a6SGleb Smirnoff
1820772e66a6SGleb Smirnoff while ((m = _getq(q)) != NULL)
1821772e66a6SGleb Smirnoff m_freem(m);
1822772e66a6SGleb Smirnoff ASSERT(qlen(q) == 0);
1823772e66a6SGleb Smirnoff }
1824772e66a6SGleb Smirnoff
1825772e66a6SGleb Smirnoff #endif /* !__GNUC__ || ALTQ_DEBUG */
1826772e66a6SGleb Smirnoff #endif /* ALTQ_CBQ || ALTQ_RED || ALTQ_RIO || ALTQ_HFSC || ALTQ_PRIQ */
1827