1#ifndef __NET_SCHED_CODEL_IMPL_H
2#define __NET_SCHED_CODEL_IMPL_H
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
52static void codel_params_init(struct codel_params *params)
53{
54 params->interval = MS2TIME(100);
55 params->target = MS2TIME(5);
56 params->ce_threshold = CODEL_DISABLED_THRESHOLD;
57 params->ecn = false;
58}
59
60static void codel_vars_init(struct codel_vars *vars)
61{
62 memset(vars, 0, sizeof(*vars));
63}
64
65static void codel_stats_init(struct codel_stats *stats)
66{
67 stats->maxpacket = 0;
68}
69
70
71
72
73
74
75
76static void codel_Newton_step(struct codel_vars *vars)
77{
78 u32 invsqrt = ((u32)vars->rec_inv_sqrt) << REC_INV_SQRT_SHIFT;
79 u32 invsqrt2 = ((u64)invsqrt * invsqrt) >> 32;
80 u64 val = (3LL << 32) - ((u64)vars->count * invsqrt2);
81
82 val >>= 2;
83 val = (val * invsqrt) >> (32 - 2 + 1);
84
85 vars->rec_inv_sqrt = val >> REC_INV_SQRT_SHIFT;
86}
87
88
89
90
91
92
93static codel_time_t codel_control_law(codel_time_t t,
94 codel_time_t interval,
95 u32 rec_inv_sqrt)
96{
97 return t + reciprocal_scale(interval, rec_inv_sqrt << REC_INV_SQRT_SHIFT);
98}
99
100static bool codel_should_drop(const struct sk_buff *skb,
101 void *ctx,
102 struct codel_vars *vars,
103 struct codel_params *params,
104 struct codel_stats *stats,
105 codel_skb_len_t skb_len_func,
106 codel_skb_time_t skb_time_func,
107 u32 *backlog,
108 codel_time_t now)
109{
110 bool ok_to_drop;
111 u32 skb_len;
112
113 if (!skb) {
114 vars->first_above_time = 0;
115 return false;
116 }
117
118 skb_len = skb_len_func(skb);
119 vars->ldelay = now - skb_time_func(skb);
120
121 if (unlikely(skb_len > stats->maxpacket))
122 stats->maxpacket = skb_len;
123
124 if (codel_time_before(vars->ldelay, params->target) ||
125 *backlog <= params->mtu) {
126
127 vars->first_above_time = 0;
128 return false;
129 }
130 ok_to_drop = false;
131 if (vars->first_above_time == 0) {
132
133
134
135 vars->first_above_time = now + params->interval;
136 } else if (codel_time_after(now, vars->first_above_time)) {
137 ok_to_drop = true;
138 }
139 return ok_to_drop;
140}
141
142static struct sk_buff *codel_dequeue(void *ctx,
143 u32 *backlog,
144 struct codel_params *params,
145 struct codel_vars *vars,
146 struct codel_stats *stats,
147 codel_skb_len_t skb_len_func,
148 codel_skb_time_t skb_time_func,
149 codel_skb_drop_t drop_func,
150 codel_skb_dequeue_t dequeue_func)
151{
152 struct sk_buff *skb = dequeue_func(vars, ctx);
153 codel_time_t now;
154 bool drop;
155
156 if (!skb) {
157 vars->dropping = false;
158 return skb;
159 }
160 now = codel_get_time();
161 drop = codel_should_drop(skb, ctx, vars, params, stats,
162 skb_len_func, skb_time_func, backlog, now);
163 if (vars->dropping) {
164 if (!drop) {
165
166 vars->dropping = false;
167 } else if (codel_time_after_eq(now, vars->drop_next)) {
168
169
170
171
172
173
174
175
176 while (vars->dropping &&
177 codel_time_after_eq(now, vars->drop_next)) {
178 vars->count++;
179
180
181 codel_Newton_step(vars);
182 if (params->ecn && INET_ECN_set_ce(skb)) {
183 stats->ecn_mark++;
184 vars->drop_next =
185 codel_control_law(vars->drop_next,
186 params->interval,
187 vars->rec_inv_sqrt);
188 goto end;
189 }
190 stats->drop_len += skb_len_func(skb);
191 drop_func(skb, ctx);
192 stats->drop_count++;
193 skb = dequeue_func(vars, ctx);
194 if (!codel_should_drop(skb, ctx,
195 vars, params, stats,
196 skb_len_func,
197 skb_time_func,
198 backlog, now)) {
199
200 vars->dropping = false;
201 } else {
202
203 vars->drop_next =
204 codel_control_law(vars->drop_next,
205 params->interval,
206 vars->rec_inv_sqrt);
207 }
208 }
209 }
210 } else if (drop) {
211 u32 delta;
212
213 if (params->ecn && INET_ECN_set_ce(skb)) {
214 stats->ecn_mark++;
215 } else {
216 stats->drop_len += skb_len_func(skb);
217 drop_func(skb, ctx);
218 stats->drop_count++;
219
220 skb = dequeue_func(vars, ctx);
221 drop = codel_should_drop(skb, ctx, vars, params,
222 stats, skb_len_func,
223 skb_time_func, backlog, now);
224 }
225 vars->dropping = true;
226
227
228
229
230 delta = vars->count - vars->lastcount;
231 if (delta > 1 &&
232 codel_time_before(now - vars->drop_next,
233 16 * params->interval)) {
234 vars->count = delta;
235
236
237
238
239 codel_Newton_step(vars);
240 } else {
241 vars->count = 1;
242 vars->rec_inv_sqrt = ~0U >> REC_INV_SQRT_SHIFT;
243 }
244 vars->lastcount = vars->count;
245 vars->drop_next = codel_control_law(now, params->interval,
246 vars->rec_inv_sqrt);
247 }
248end:
249 if (skb && codel_time_after(vars->ldelay, params->ce_threshold) &&
250 INET_ECN_set_ce(skb))
251 stats->ce_mark++;
252 return skb;
253}
254
255#endif
256