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