This source file includes following definitions.
- rio_alloc
- rio_destroy
- rio_getstats
- dscp2index
- rio_addq
- rio_getq
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 #include <sys/param.h>
63 #include <sys/malloc.h>
64 #include <sys/mbuf.h>
65 #include <sys/socket.h>
66 #include <sys/systm.h>
67 #include <sys/errno.h>
68
69 #include <net/if.h>
70 #include <net/if_types.h>
71
72 #include <netinet/in.h>
73 #include <netinet/in_systm.h>
74 #include <netinet/ip.h>
75 #ifdef INET6
76 #include <netinet/ip6.h>
77 #endif
78
79 #include <net/pfvar.h>
80 #include <altq/altq.h>
81 #include <altq/altq_cdnr.h>
82 #include <altq/altq_red.h>
83 #include <altq/altq_rio.h>
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116 #define W_WEIGHT 512
117
118
119
120 #define W_WEIGHT_1 128
121
122
123
124 #define W_WEIGHT_2 64
125
126
127
128 #define FP_SHIFT 12
129
130
131 #define INV_P_MAX 10
132 #define TH_MIN 5
133 #define TH_MAX 15
134
135 #define RIO_LIMIT 60
136 #define RIO_STATS
137
138 #define TV_DELTA(a, b, delta) { \
139 int xxs; \
140 \
141 delta = (a)->tv_usec - (b)->tv_usec; \
142 if ((xxs = (a)->tv_sec - (b)->tv_sec) != 0) { \
143 if (xxs < 0) { \
144 delta = 60000000; \
145 } else if (xxs > 4) { \
146 if (xxs > 60) \
147 delta = 60000000; \
148 else \
149 delta += xxs * 1000000; \
150 } else while (xxs > 0) { \
151 delta += 1000000; \
152 xxs--; \
153 } \
154 } \
155 }
156
157
158 static struct redparams default_rio_params[RIO_NDROPPREC] = {
159
160 { TH_MAX * 2 + TH_MIN, TH_MAX * 3, INV_P_MAX },
161 { TH_MAX + TH_MIN, TH_MAX * 2, INV_P_MAX },
162 { TH_MIN, TH_MAX, INV_P_MAX }
163 };
164
165
166 static int dscp2index(u_int8_t);
167
168 rio_t *
169 rio_alloc(int weight, struct redparams *params, int flags, int pkttime)
170 {
171 rio_t *rp;
172 int w, i;
173 int npkts_per_sec;
174
175 MALLOC(rp, rio_t *, sizeof(rio_t), M_DEVBUF, M_WAITOK);
176 if (rp == NULL)
177 return (NULL);
178 bzero(rp, sizeof(rio_t));
179
180 rp->rio_flags = flags;
181 if (pkttime == 0)
182
183 rp->rio_pkttime = 800;
184 else
185 rp->rio_pkttime = pkttime;
186
187 if (weight != 0)
188 rp->rio_weight = weight;
189 else {
190
191 rp->rio_weight = W_WEIGHT;
192
193
194 npkts_per_sec = 1000000 / rp->rio_pkttime;
195 if (npkts_per_sec < 50) {
196
197 rp->rio_weight = W_WEIGHT_2;
198 } else if (npkts_per_sec < 300) {
199
200 rp->rio_weight = W_WEIGHT_1;
201 }
202 }
203
204
205 w = rp->rio_weight;
206 for (i = 0; w > 1; i++)
207 w = w >> 1;
208 rp->rio_wshift = i;
209 w = 1 << rp->rio_wshift;
210 if (w != rp->rio_weight) {
211 printf("invalid weight value %d for red! use %d\n",
212 rp->rio_weight, w);
213 rp->rio_weight = w;
214 }
215
216
217 rp->rio_wtab = wtab_alloc(rp->rio_weight);
218
219 for (i = 0; i < RIO_NDROPPREC; i++) {
220 struct dropprec_state *prec = &rp->rio_precstate[i];
221
222 prec->avg = 0;
223 prec->idle = 1;
224
225 if (params == NULL || params[i].inv_pmax == 0)
226 prec->inv_pmax = default_rio_params[i].inv_pmax;
227 else
228 prec->inv_pmax = params[i].inv_pmax;
229 if (params == NULL || params[i].th_min == 0)
230 prec->th_min = default_rio_params[i].th_min;
231 else
232 prec->th_min = params[i].th_min;
233 if (params == NULL || params[i].th_max == 0)
234 prec->th_max = default_rio_params[i].th_max;
235 else
236 prec->th_max = params[i].th_max;
237
238
239
240
241
242 prec->th_min_s = prec->th_min << (rp->rio_wshift + FP_SHIFT);
243 prec->th_max_s = prec->th_max << (rp->rio_wshift + FP_SHIFT);
244
245
246
247
248
249 prec->probd = (2 * (prec->th_max - prec->th_min)
250 * prec->inv_pmax) << FP_SHIFT;
251
252 microtime(&prec->last);
253 }
254
255 return (rp);
256 }
257
258 void
259 rio_destroy(rio_t *rp)
260 {
261 wtab_destroy(rp->rio_wtab);
262 FREE(rp, M_DEVBUF);
263 }
264
265 void
266 rio_getstats(rio_t *rp, struct redstats *sp)
267 {
268 int i;
269
270 for (i = 0; i < RIO_NDROPPREC; i++) {
271 bcopy(&rp->q_stats[i], sp, sizeof(struct redstats));
272 sp->q_avg = rp->rio_precstate[i].avg >> rp->rio_wshift;
273 sp++;
274 }
275 }
276
277 #if (RIO_NDROPPREC == 3)
278
279
280
281
282 static int
283 dscp2index(u_int8_t dscp)
284 {
285 int dpindex = dscp & AF_DROPPRECMASK;
286
287 if (dpindex == 0)
288 return (0);
289 return ((dpindex >> 3) - 1);
290 }
291 #endif
292
293 #if 1
294
295
296
297
298
299 #define RIOM_SET_PRECINDEX(m, idx) \
300 do { (m)->m_pkthdr.rcvif = (struct ifnet *)((long)(idx)); } while (0)
301 #define RIOM_GET_PRECINDEX(m) \
302 ({ long idx; idx = (long)((m)->m_pkthdr.rcvif); \
303 (m)->m_pkthdr.rcvif = NULL; idx; })
304 #endif
305
306 int
307 rio_addq(rio_t *rp, class_queue_t *q, struct mbuf *m,
308 struct altq_pktattr *pktattr)
309 {
310 int avg, droptype;
311 u_int8_t dsfield, odsfield;
312 int dpindex, i, n, t;
313 struct timeval now;
314 struct dropprec_state *prec;
315
316 dsfield = odsfield = read_dsfield(m, pktattr);
317 dpindex = dscp2index(dsfield);
318
319
320
321
322
323 now.tv_sec = 0;
324 for (i = dpindex; i < RIO_NDROPPREC; i++) {
325 prec = &rp->rio_precstate[i];
326 avg = prec->avg;
327 if (prec->idle) {
328 prec->idle = 0;
329 if (now.tv_sec == 0)
330 microtime(&now);
331 t = (now.tv_sec - prec->last.tv_sec);
332 if (t > 60)
333 avg = 0;
334 else {
335 t = t * 1000000 +
336 (now.tv_usec - prec->last.tv_usec);
337 n = t / rp->rio_pkttime;
338
339 if (n > 0)
340 avg = (avg >> FP_SHIFT) *
341 pow_w(rp->rio_wtab, n);
342 }
343 }
344
345
346 avg += (prec->qlen << FP_SHIFT) - (avg >> rp->rio_wshift);
347 prec->avg = avg;
348
349
350
351
352 prec->count++;
353 }
354
355 prec = &rp->rio_precstate[dpindex];
356 avg = prec->avg;
357
358
359 droptype = DTYPE_NODROP;
360 if (avg >= prec->th_min_s && prec->qlen > 1) {
361 if (avg >= prec->th_max_s) {
362
363 droptype = DTYPE_FORCED;
364 } else if (prec->old == 0) {
365
366 prec->count = 1;
367 prec->old = 1;
368 } else if (drop_early((avg - prec->th_min_s) >> rp->rio_wshift,
369 prec->probd, prec->count)) {
370
371 droptype = DTYPE_EARLY;
372 }
373 } else {
374
375 prec->old = 0;
376 }
377
378
379
380
381 if (droptype == DTYPE_NODROP && qlen(q) >= qlimit(q))
382 droptype = DTYPE_FORCED;
383
384 if (droptype != DTYPE_NODROP) {
385
386 for (i = dpindex; i < RIO_NDROPPREC; i++)
387 rp->rio_precstate[i].count = 0;
388 #ifdef RIO_STATS
389 if (droptype == DTYPE_EARLY)
390 rp->q_stats[dpindex].drop_unforced++;
391 else
392 rp->q_stats[dpindex].drop_forced++;
393 PKTCNTR_ADD(&rp->q_stats[dpindex].drop_cnt, m_pktlen(m));
394 #endif
395 m_freem(m);
396 return (-1);
397 }
398
399 for (i = dpindex; i < RIO_NDROPPREC; i++)
400 rp->rio_precstate[i].qlen++;
401
402
403 RIOM_SET_PRECINDEX(m, dpindex);
404
405 if (rp->rio_flags & RIOF_CLEARDSCP)
406 dsfield &= ~DSCP_MASK;
407
408 if (dsfield != odsfield)
409 write_dsfield(m, pktattr, dsfield);
410
411 _addq(q, m);
412
413 #ifdef RIO_STATS
414 PKTCNTR_ADD(&rp->q_stats[dpindex].xmit_cnt, m_pktlen(m));
415 #endif
416 return (0);
417 }
418
419 struct mbuf *
420 rio_getq(rio_t *rp, class_queue_t *q)
421 {
422 struct mbuf *m;
423 int dpindex, i;
424
425 if ((m = _getq(q)) == NULL)
426 return NULL;
427
428 dpindex = RIOM_GET_PRECINDEX(m);
429 for (i = dpindex; i < RIO_NDROPPREC; i++) {
430 if (--rp->rio_precstate[i].qlen == 0) {
431 if (rp->rio_precstate[i].idle == 0) {
432 rp->rio_precstate[i].idle = 1;
433 microtime(&rp->rio_precstate[i].last);
434 }
435 }
436 }
437 return (m);
438 }