Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0-only */
2 : : /*
3 : : * Copyright (c) 2016 Qualcomm Atheros, Inc
4 : : *
5 : : * Based on net/sched/sch_fq_codel.c
6 : : */
7 : : #ifndef __NET_SCHED_FQ_IMPL_H
8 : : #define __NET_SCHED_FQ_IMPL_H
9 : :
10 : : #include <net/fq.h>
11 : :
12 : : /* functions that are embedded into includer */
13 : :
14 : 0 : static void fq_adjust_removal(struct fq *fq,
15 : : struct fq_flow *flow,
16 : : struct sk_buff *skb)
17 : : {
18 : 0 : struct fq_tin *tin = flow->tin;
19 : :
20 : 0 : tin->backlog_bytes -= skb->len;
21 : 0 : tin->backlog_packets--;
22 : 0 : flow->backlog -= skb->len;
23 : 0 : fq->backlog--;
24 : 0 : fq->memory_usage -= skb->truesize;
25 : : }
26 : :
27 : 0 : static void fq_rejigger_backlog(struct fq *fq, struct fq_flow *flow)
28 : : {
29 : 0 : struct fq_flow *i;
30 : :
31 [ # # ]: 0 : if (flow->backlog == 0) {
32 : 0 : list_del_init(&flow->backlogchain);
33 : : } else {
34 : 0 : i = flow;
35 : :
36 [ # # ]: 0 : list_for_each_entry_continue(i, &fq->backlogs, backlogchain)
37 [ # # ]: 0 : if (i->backlog < flow->backlog)
38 : : break;
39 : :
40 : 0 : list_move_tail(&flow->backlogchain,
41 : : &i->backlogchain);
42 : : }
43 : 0 : }
44 : :
45 : 0 : static struct sk_buff *fq_flow_dequeue(struct fq *fq,
46 : : struct fq_flow *flow)
47 : : {
48 : 0 : struct sk_buff *skb;
49 : :
50 : 0 : lockdep_assert_held(&fq->lock);
51 : :
52 [ # # ]: 0 : skb = __skb_dequeue(&flow->queue);
53 [ # # ]: 0 : if (!skb)
54 : 0 : return NULL;
55 : :
56 : 0 : fq_adjust_removal(fq, flow, skb);
57 : 0 : fq_rejigger_backlog(fq, flow);
58 : :
59 : 0 : return skb;
60 : : }
61 : :
62 : 0 : static struct sk_buff *fq_tin_dequeue(struct fq *fq,
63 : : struct fq_tin *tin,
64 : : fq_tin_dequeue_t dequeue_func)
65 : : {
66 : 0 : struct fq_flow *flow;
67 : 0 : struct list_head *head;
68 : 0 : struct sk_buff *skb;
69 : :
70 : 0 : lockdep_assert_held(&fq->lock);
71 : :
72 : : begin:
73 : 0 : head = &tin->new_flows;
74 [ # # ]: 0 : if (list_empty(head)) {
75 : 0 : head = &tin->old_flows;
76 [ # # ]: 0 : if (list_empty(head))
77 : : return NULL;
78 : : }
79 : :
80 : 0 : flow = list_first_entry(head, struct fq_flow, flowchain);
81 : :
82 [ # # ]: 0 : if (flow->deficit <= 0) {
83 : 0 : flow->deficit += fq->quantum;
84 : 0 : list_move_tail(&flow->flowchain,
85 : : &tin->old_flows);
86 : 0 : goto begin;
87 : : }
88 : :
89 : 0 : skb = dequeue_func(fq, tin, flow);
90 [ # # ]: 0 : if (!skb) {
91 : : /* force a pass through old_flows to prevent starvation */
92 [ # # # # ]: 0 : if ((head == &tin->new_flows) &&
93 [ # # ]: 0 : !list_empty(&tin->old_flows)) {
94 : 0 : list_move_tail(&flow->flowchain, &tin->old_flows);
95 : : } else {
96 : 0 : list_del_init(&flow->flowchain);
97 : 0 : flow->tin = NULL;
98 : : }
99 : 0 : goto begin;
100 : : }
101 : :
102 : 0 : flow->deficit -= skb->len;
103 : 0 : tin->tx_bytes += skb->len;
104 : 0 : tin->tx_packets++;
105 : :
106 : 0 : return skb;
107 : : }
108 : :
109 : 0 : static u32 fq_flow_idx(struct fq *fq, struct sk_buff *skb)
110 : : {
111 : 0 : u32 hash = skb_get_hash_perturb(skb, &fq->perturbation);
112 : :
113 : 0 : return reciprocal_scale(hash, fq->flows_cnt);
114 : : }
115 : :
116 : 0 : static struct fq_flow *fq_flow_classify(struct fq *fq,
117 : : struct fq_tin *tin, u32 idx,
118 : : struct sk_buff *skb,
119 : : fq_flow_get_default_t get_default_func)
120 : : {
121 : 0 : struct fq_flow *flow;
122 : :
123 : 0 : lockdep_assert_held(&fq->lock);
124 : :
125 : 0 : flow = &fq->flows[idx];
126 [ # # # # ]: 0 : if (flow->tin && flow->tin != tin) {
127 : 0 : flow = get_default_func(fq, tin, idx, skb);
128 : 0 : tin->collisions++;
129 : 0 : fq->collisions++;
130 : : }
131 : :
132 [ # # ]: 0 : if (!flow->tin)
133 : 0 : tin->flows++;
134 : :
135 : 0 : return flow;
136 : : }
137 : :
138 : : static void fq_recalc_backlog(struct fq *fq,
139 : : struct fq_tin *tin,
140 : : struct fq_flow *flow)
141 : : {
142 : : struct fq_flow *i;
143 : :
144 : : if (list_empty(&flow->backlogchain))
145 : : list_add_tail(&flow->backlogchain, &fq->backlogs);
146 : :
147 : : i = flow;
148 : : list_for_each_entry_continue_reverse(i, &fq->backlogs,
149 : : backlogchain)
150 : : if (i->backlog > flow->backlog)
151 : : break;
152 : :
153 : : list_move(&flow->backlogchain, &i->backlogchain);
154 : : }
155 : :
156 : 0 : static void fq_tin_enqueue(struct fq *fq,
157 : : struct fq_tin *tin, u32 idx,
158 : : struct sk_buff *skb,
159 : : fq_skb_free_t free_func,
160 : : fq_flow_get_default_t get_default_func)
161 : : {
162 : 0 : struct fq_flow *flow;
163 : 0 : bool oom;
164 : :
165 : 0 : lockdep_assert_held(&fq->lock);
166 : :
167 : 0 : flow = fq_flow_classify(fq, tin, idx, skb, get_default_func);
168 : :
169 : 0 : flow->tin = tin;
170 : 0 : flow->backlog += skb->len;
171 : 0 : tin->backlog_bytes += skb->len;
172 : 0 : tin->backlog_packets++;
173 : 0 : fq->memory_usage += skb->truesize;
174 : 0 : fq->backlog++;
175 : :
176 : 0 : fq_recalc_backlog(fq, tin, flow);
177 : :
178 [ # # ]: 0 : if (list_empty(&flow->flowchain)) {
179 : 0 : flow->deficit = fq->quantum;
180 : 0 : list_add_tail(&flow->flowchain,
181 : : &tin->new_flows);
182 : : }
183 : :
184 : 0 : __skb_queue_tail(&flow->queue, skb);
185 : 0 : oom = (fq->memory_usage > fq->memory_limit);
186 [ # # # # ]: 0 : while (fq->backlog > fq->limit || oom) {
187 [ # # ]: 0 : flow = list_first_entry_or_null(&fq->backlogs,
188 : : struct fq_flow,
189 : : backlogchain);
190 [ # # ]: 0 : if (!flow)
191 : : return;
192 : :
193 : 0 : skb = fq_flow_dequeue(fq, flow);
194 [ # # ]: 0 : if (!skb)
195 : : return;
196 : :
197 : 0 : free_func(fq, flow->tin, flow, skb);
198 : :
199 : 0 : flow->tin->overlimit++;
200 : 0 : fq->overlimit++;
201 [ # # ]: 0 : if (oom) {
202 : 0 : fq->overmemory++;
203 : 0 : oom = (fq->memory_usage > fq->memory_limit);
204 : : }
205 : : }
206 : : }
207 : :
208 : 0 : static void fq_flow_filter(struct fq *fq,
209 : : struct fq_flow *flow,
210 : : fq_skb_filter_t filter_func,
211 : : void *filter_data,
212 : : fq_skb_free_t free_func)
213 : : {
214 : 0 : struct fq_tin *tin = flow->tin;
215 : 0 : struct sk_buff *skb, *tmp;
216 : :
217 : 0 : lockdep_assert_held(&fq->lock);
218 : :
219 [ # # ]: 0 : skb_queue_walk_safe(&flow->queue, skb, tmp) {
220 [ # # ]: 0 : if (!filter_func(fq, tin, flow, skb, filter_data))
221 : 0 : continue;
222 : :
223 : 0 : __skb_unlink(skb, &flow->queue);
224 : 0 : fq_adjust_removal(fq, flow, skb);
225 : 0 : free_func(fq, tin, flow, skb);
226 : : }
227 : :
228 : 0 : fq_rejigger_backlog(fq, flow);
229 : 0 : }
230 : :
231 : 0 : static void fq_tin_filter(struct fq *fq,
232 : : struct fq_tin *tin,
233 : : fq_skb_filter_t filter_func,
234 : : void *filter_data,
235 : : fq_skb_free_t free_func)
236 : : {
237 : 0 : struct fq_flow *flow;
238 : :
239 : 0 : lockdep_assert_held(&fq->lock);
240 : :
241 [ # # ]: 0 : list_for_each_entry(flow, &tin->new_flows, flowchain)
242 : 0 : fq_flow_filter(fq, flow, filter_func, filter_data, free_func);
243 [ # # ]: 0 : list_for_each_entry(flow, &tin->old_flows, flowchain)
244 : 0 : fq_flow_filter(fq, flow, filter_func, filter_data, free_func);
245 : 0 : }
246 : :
247 : 0 : static void fq_flow_reset(struct fq *fq,
248 : : struct fq_flow *flow,
249 : : fq_skb_free_t free_func)
250 : : {
251 : 0 : struct sk_buff *skb;
252 : :
253 [ # # ]: 0 : while ((skb = fq_flow_dequeue(fq, flow)))
254 : 0 : free_func(fq, flow->tin, flow, skb);
255 : :
256 [ # # ]: 0 : if (!list_empty(&flow->flowchain))
257 : 0 : list_del_init(&flow->flowchain);
258 : :
259 [ # # ]: 0 : if (!list_empty(&flow->backlogchain))
260 : 0 : list_del_init(&flow->backlogchain);
261 : :
262 : 0 : flow->tin = NULL;
263 : :
264 [ # # ]: 0 : WARN_ON_ONCE(flow->backlog);
265 : 0 : }
266 : :
267 : 0 : static void fq_tin_reset(struct fq *fq,
268 : : struct fq_tin *tin,
269 : : fq_skb_free_t free_func)
270 : : {
271 : 0 : struct list_head *head;
272 : 0 : struct fq_flow *flow;
273 : :
274 : 0 : for (;;) {
275 : 0 : head = &tin->new_flows;
276 [ # # ]: 0 : if (list_empty(head)) {
277 : 0 : head = &tin->old_flows;
278 [ # # ]: 0 : if (list_empty(head))
279 : : break;
280 : : }
281 : :
282 : 0 : flow = list_first_entry(head, struct fq_flow, flowchain);
283 : 0 : fq_flow_reset(fq, flow, free_func);
284 : : }
285 : :
286 [ # # ]: 0 : WARN_ON_ONCE(tin->backlog_bytes);
287 [ # # ]: 0 : WARN_ON_ONCE(tin->backlog_packets);
288 : 0 : }
289 : :
290 : 24582 : static void fq_flow_init(struct fq_flow *flow)
291 : : {
292 : 24582 : INIT_LIST_HEAD(&flow->flowchain);
293 : 24582 : INIT_LIST_HEAD(&flow->backlogchain);
294 [ + - ]: 24582 : __skb_queue_head_init(&flow->queue);
295 : : }
296 : :
297 : 6 : static void fq_tin_init(struct fq_tin *tin)
298 : : {
299 [ + - ]: 6 : INIT_LIST_HEAD(&tin->new_flows);
300 [ + - ]: 6 : INIT_LIST_HEAD(&tin->old_flows);
301 : : }
302 : :
303 : 6 : static int fq_init(struct fq *fq, int flows_cnt)
304 : : {
305 : 6 : int i;
306 : :
307 : 6 : memset(fq, 0, sizeof(fq[0]));
308 : 6 : INIT_LIST_HEAD(&fq->backlogs);
309 : 6 : spin_lock_init(&fq->lock);
310 : 6 : fq->flows_cnt = max_t(u32, flows_cnt, 1);
311 : 6 : get_random_bytes(&fq->perturbation, sizeof(fq->perturbation));
312 : 6 : fq->quantum = 300;
313 : 6 : fq->limit = 8192;
314 : 6 : fq->memory_limit = 16 << 20; /* 16 MBytes */
315 : :
316 : 6 : fq->flows = kvcalloc(fq->flows_cnt, sizeof(fq->flows[0]), GFP_KERNEL);
317 [ + - ]: 6 : if (!fq->flows)
318 : : return -ENOMEM;
319 : :
320 [ + + ]: 24582 : for (i = 0; i < fq->flows_cnt; i++)
321 : 24576 : fq_flow_init(&fq->flows[i]);
322 : :
323 : : return 0;
324 : : }
325 : :
326 : 0 : static void fq_reset(struct fq *fq,
327 : : fq_skb_free_t free_func)
328 : : {
329 : 0 : int i;
330 : :
331 [ # # ]: 0 : for (i = 0; i < fq->flows_cnt; i++)
332 : 0 : fq_flow_reset(fq, &fq->flows[i], free_func);
333 : :
334 : 0 : kvfree(fq->flows);
335 : 0 : fq->flows = NULL;
336 : 0 : }
337 : :
338 : : #endif
|