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