1#ifndef __NET_SCHED_RED_H
2#define __NET_SCHED_RED_H
3
4#include <linux/types.h>
5#include <net/pkt_sched.h>
6#include <net/inet_ecn.h>
7#include <net/dsfield.h>
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90#define RED_STAB_SIZE 256
91#define RED_STAB_MASK (RED_STAB_SIZE - 1)
92
93struct red_stats {
94 u32 prob_drop;
95 u32 prob_mark;
96 u32 forced_drop;
97 u32 forced_mark;
98 u32 pdrop;
99 u32 other;
100};
101
102struct red_parms {
103
104 u32 qth_min;
105 u32 qth_max;
106 u32 Scell_max;
107 u32 Rmask;
108 u8 Scell_log;
109 u8 Wlog;
110 u8 Plog;
111 u8 Stab[RED_STAB_SIZE];
112
113
114 int qcount;
115
116 u32 qR;
117
118 unsigned long qavg;
119 ktime_t qidlestart;
120};
121
122static inline u32 red_rmask(u8 Plog)
123{
124 return Plog < 32 ? ((1 << Plog) - 1) : ~0UL;
125}
126
127static inline void red_set_parms(struct red_parms *p,
128 u32 qth_min, u32 qth_max, u8 Wlog, u8 Plog,
129 u8 Scell_log, u8 *stab)
130{
131
132
133
134
135 p->qavg = 0;
136
137 p->qcount = -1;
138 p->qth_min = qth_min << Wlog;
139 p->qth_max = qth_max << Wlog;
140 p->Wlog = Wlog;
141 p->Plog = Plog;
142 p->Rmask = red_rmask(Plog);
143 p->Scell_log = Scell_log;
144 p->Scell_max = (255 << Scell_log);
145
146 memcpy(p->Stab, stab, sizeof(p->Stab));
147}
148
149static inline int red_is_idling(struct red_parms *p)
150{
151 return p->qidlestart.tv64 != 0;
152}
153
154static inline void red_start_of_idle_period(struct red_parms *p)
155{
156 p->qidlestart = ktime_get();
157}
158
159static inline void red_end_of_idle_period(struct red_parms *p)
160{
161 p->qidlestart.tv64 = 0;
162}
163
164static inline void red_restart(struct red_parms *p)
165{
166 red_end_of_idle_period(p);
167 p->qavg = 0;
168 p->qcount = -1;
169}
170
171static inline unsigned long red_calc_qavg_from_idle_time(struct red_parms *p)
172{
173 s64 delta = ktime_us_delta(ktime_get(), p->qidlestart);
174 long us_idle = min_t(s64, delta, p->Scell_max);
175 int shift;
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197 shift = p->Stab[(us_idle >> p->Scell_log) & RED_STAB_MASK];
198
199 if (shift)
200 return p->qavg >> shift;
201 else {
202
203
204
205
206
207
208
209 us_idle = (p->qavg * (u64)us_idle) >> p->Scell_log;
210
211 if (us_idle < (p->qavg >> 1))
212 return p->qavg - us_idle;
213 else
214 return p->qavg >> 1;
215 }
216}
217
218static inline unsigned long red_calc_qavg_no_idle_time(struct red_parms *p,
219 unsigned int backlog)
220{
221
222
223
224
225
226
227
228
229
230 return p->qavg + (backlog - (p->qavg >> p->Wlog));
231}
232
233static inline unsigned long red_calc_qavg(struct red_parms *p,
234 unsigned int backlog)
235{
236 if (!red_is_idling(p))
237 return red_calc_qavg_no_idle_time(p, backlog);
238 else
239 return red_calc_qavg_from_idle_time(p);
240}
241
242static inline u32 red_random(struct red_parms *p)
243{
244 return net_random() & p->Rmask;
245}
246
247static inline int red_mark_probability(struct red_parms *p, unsigned long qavg)
248{
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265 return !(((qavg - p->qth_min) >> p->Wlog) * p->qcount < p->qR);
266}
267
268enum {
269 RED_BELOW_MIN_THRESH,
270 RED_BETWEEN_TRESH,
271 RED_ABOVE_MAX_TRESH,
272};
273
274static inline int red_cmp_thresh(struct red_parms *p, unsigned long qavg)
275{
276 if (qavg < p->qth_min)
277 return RED_BELOW_MIN_THRESH;
278 else if (qavg >= p->qth_max)
279 return RED_ABOVE_MAX_TRESH;
280 else
281 return RED_BETWEEN_TRESH;
282}
283
284enum {
285 RED_DONT_MARK,
286 RED_PROB_MARK,
287 RED_HARD_MARK,
288};
289
290static inline int red_action(struct red_parms *p, unsigned long qavg)
291{
292 switch (red_cmp_thresh(p, qavg)) {
293 case RED_BELOW_MIN_THRESH:
294 p->qcount = -1;
295 return RED_DONT_MARK;
296
297 case RED_BETWEEN_TRESH:
298 if (++p->qcount) {
299 if (red_mark_probability(p, qavg)) {
300 p->qcount = 0;
301 p->qR = red_random(p);
302 return RED_PROB_MARK;
303 }
304 } else
305 p->qR = red_random(p);
306
307 return RED_DONT_MARK;
308
309 case RED_ABOVE_MAX_TRESH:
310 p->qcount = -1;
311 return RED_HARD_MARK;
312 }
313
314 BUG();
315 return RED_DONT_MARK;
316}
317
318#endif
319