xref: /openbmc/linux/include/net/fq_impl.h (revision 8c418b5b15747eda05d086e80fa0a767982fbf37)
1557fc4a0SMichal Kazior /*
2557fc4a0SMichal Kazior  * Copyright (c) 2016 Qualcomm Atheros, Inc
3557fc4a0SMichal Kazior  *
4557fc4a0SMichal Kazior  * GPL v2
5557fc4a0SMichal Kazior  *
6557fc4a0SMichal Kazior  * Based on net/sched/sch_fq_codel.c
7557fc4a0SMichal Kazior  */
8557fc4a0SMichal Kazior #ifndef __NET_SCHED_FQ_IMPL_H
9557fc4a0SMichal Kazior #define __NET_SCHED_FQ_IMPL_H
10557fc4a0SMichal Kazior 
11557fc4a0SMichal Kazior #include <net/fq.h>
12557fc4a0SMichal Kazior 
13557fc4a0SMichal Kazior /* functions that are embedded into includer */
14557fc4a0SMichal Kazior 
15*8c418b5bSJohannes Berg static void fq_adjust_removal(struct fq *fq,
16*8c418b5bSJohannes Berg 			      struct fq_flow *flow,
17*8c418b5bSJohannes Berg 			      struct sk_buff *skb)
18557fc4a0SMichal Kazior {
19557fc4a0SMichal Kazior 	struct fq_tin *tin = flow->tin;
20557fc4a0SMichal Kazior 
21557fc4a0SMichal Kazior 	tin->backlog_bytes -= skb->len;
22557fc4a0SMichal Kazior 	tin->backlog_packets--;
23557fc4a0SMichal Kazior 	flow->backlog -= skb->len;
24557fc4a0SMichal Kazior 	fq->backlog--;
25097b065bSToke Høiland-Jørgensen 	fq->memory_usage -= skb->truesize;
26*8c418b5bSJohannes Berg }
27*8c418b5bSJohannes Berg 
28*8c418b5bSJohannes Berg static void fq_rejigger_backlog(struct fq *fq, struct fq_flow *flow)
29*8c418b5bSJohannes Berg {
30*8c418b5bSJohannes Berg 	struct fq_flow *i;
31557fc4a0SMichal Kazior 
32557fc4a0SMichal Kazior 	if (flow->backlog == 0) {
33557fc4a0SMichal Kazior 		list_del_init(&flow->backlogchain);
34557fc4a0SMichal Kazior 	} else {
35557fc4a0SMichal Kazior 		i = flow;
36557fc4a0SMichal Kazior 
37557fc4a0SMichal Kazior 		list_for_each_entry_continue(i, &fq->backlogs, backlogchain)
38557fc4a0SMichal Kazior 			if (i->backlog < flow->backlog)
39557fc4a0SMichal Kazior 				break;
40557fc4a0SMichal Kazior 
41557fc4a0SMichal Kazior 		list_move_tail(&flow->backlogchain,
42557fc4a0SMichal Kazior 			       &i->backlogchain);
43557fc4a0SMichal Kazior 	}
44*8c418b5bSJohannes Berg }
45*8c418b5bSJohannes Berg 
46*8c418b5bSJohannes Berg static struct sk_buff *fq_flow_dequeue(struct fq *fq,
47*8c418b5bSJohannes Berg 				       struct fq_flow *flow)
48*8c418b5bSJohannes Berg {
49*8c418b5bSJohannes Berg 	struct sk_buff *skb;
50*8c418b5bSJohannes Berg 
51*8c418b5bSJohannes Berg 	lockdep_assert_held(&fq->lock);
52*8c418b5bSJohannes Berg 
53*8c418b5bSJohannes Berg 	skb = __skb_dequeue(&flow->queue);
54*8c418b5bSJohannes Berg 	if (!skb)
55*8c418b5bSJohannes Berg 		return NULL;
56*8c418b5bSJohannes Berg 
57*8c418b5bSJohannes Berg 	fq_adjust_removal(fq, flow, skb);
58*8c418b5bSJohannes Berg 	fq_rejigger_backlog(fq, flow);
59557fc4a0SMichal Kazior 
60557fc4a0SMichal Kazior 	return skb;
61557fc4a0SMichal Kazior }
62557fc4a0SMichal Kazior 
63557fc4a0SMichal Kazior static struct sk_buff *fq_tin_dequeue(struct fq *fq,
64557fc4a0SMichal Kazior 				      struct fq_tin *tin,
65557fc4a0SMichal Kazior 				      fq_tin_dequeue_t dequeue_func)
66557fc4a0SMichal Kazior {
67557fc4a0SMichal Kazior 	struct fq_flow *flow;
68557fc4a0SMichal Kazior 	struct list_head *head;
69557fc4a0SMichal Kazior 	struct sk_buff *skb;
70557fc4a0SMichal Kazior 
71557fc4a0SMichal Kazior 	lockdep_assert_held(&fq->lock);
72557fc4a0SMichal Kazior 
73557fc4a0SMichal Kazior begin:
74557fc4a0SMichal Kazior 	head = &tin->new_flows;
75557fc4a0SMichal Kazior 	if (list_empty(head)) {
76557fc4a0SMichal Kazior 		head = &tin->old_flows;
77557fc4a0SMichal Kazior 		if (list_empty(head))
78557fc4a0SMichal Kazior 			return NULL;
79557fc4a0SMichal Kazior 	}
80557fc4a0SMichal Kazior 
81557fc4a0SMichal Kazior 	flow = list_first_entry(head, struct fq_flow, flowchain);
82557fc4a0SMichal Kazior 
83557fc4a0SMichal Kazior 	if (flow->deficit <= 0) {
84557fc4a0SMichal Kazior 		flow->deficit += fq->quantum;
85557fc4a0SMichal Kazior 		list_move_tail(&flow->flowchain,
86557fc4a0SMichal Kazior 			       &tin->old_flows);
87557fc4a0SMichal Kazior 		goto begin;
88557fc4a0SMichal Kazior 	}
89557fc4a0SMichal Kazior 
90557fc4a0SMichal Kazior 	skb = dequeue_func(fq, tin, flow);
91557fc4a0SMichal Kazior 	if (!skb) {
92557fc4a0SMichal Kazior 		/* force a pass through old_flows to prevent starvation */
93557fc4a0SMichal Kazior 		if ((head == &tin->new_flows) &&
94557fc4a0SMichal Kazior 		    !list_empty(&tin->old_flows)) {
95557fc4a0SMichal Kazior 			list_move_tail(&flow->flowchain, &tin->old_flows);
96557fc4a0SMichal Kazior 		} else {
97557fc4a0SMichal Kazior 			list_del_init(&flow->flowchain);
98557fc4a0SMichal Kazior 			flow->tin = NULL;
99557fc4a0SMichal Kazior 		}
100557fc4a0SMichal Kazior 		goto begin;
101557fc4a0SMichal Kazior 	}
102557fc4a0SMichal Kazior 
103557fc4a0SMichal Kazior 	flow->deficit -= skb->len;
104557fc4a0SMichal Kazior 	tin->tx_bytes += skb->len;
105557fc4a0SMichal Kazior 	tin->tx_packets++;
106557fc4a0SMichal Kazior 
107557fc4a0SMichal Kazior 	return skb;
108557fc4a0SMichal Kazior }
109557fc4a0SMichal Kazior 
110557fc4a0SMichal Kazior static struct fq_flow *fq_flow_classify(struct fq *fq,
111557fc4a0SMichal Kazior 					struct fq_tin *tin,
112557fc4a0SMichal Kazior 					struct sk_buff *skb,
113557fc4a0SMichal Kazior 					fq_flow_get_default_t get_default_func)
114557fc4a0SMichal Kazior {
115557fc4a0SMichal Kazior 	struct fq_flow *flow;
116557fc4a0SMichal Kazior 	u32 hash;
117557fc4a0SMichal Kazior 	u32 idx;
118557fc4a0SMichal Kazior 
119557fc4a0SMichal Kazior 	lockdep_assert_held(&fq->lock);
120557fc4a0SMichal Kazior 
121557fc4a0SMichal Kazior 	hash = skb_get_hash_perturb(skb, fq->perturbation);
122557fc4a0SMichal Kazior 	idx = reciprocal_scale(hash, fq->flows_cnt);
123557fc4a0SMichal Kazior 	flow = &fq->flows[idx];
124557fc4a0SMichal Kazior 
125557fc4a0SMichal Kazior 	if (flow->tin && flow->tin != tin) {
126557fc4a0SMichal Kazior 		flow = get_default_func(fq, tin, idx, skb);
127557fc4a0SMichal Kazior 		tin->collisions++;
128557fc4a0SMichal Kazior 		fq->collisions++;
129557fc4a0SMichal Kazior 	}
130557fc4a0SMichal Kazior 
131557fc4a0SMichal Kazior 	if (!flow->tin)
132557fc4a0SMichal Kazior 		tin->flows++;
133557fc4a0SMichal Kazior 
134557fc4a0SMichal Kazior 	return flow;
135557fc4a0SMichal Kazior }
136557fc4a0SMichal Kazior 
137b43e7199SMichal Kazior static void fq_recalc_backlog(struct fq *fq,
138557fc4a0SMichal Kazior 			      struct fq_tin *tin,
139b43e7199SMichal Kazior 			      struct fq_flow *flow)
140557fc4a0SMichal Kazior {
141557fc4a0SMichal Kazior 	struct fq_flow *i;
142557fc4a0SMichal Kazior 
143557fc4a0SMichal Kazior 	if (list_empty(&flow->backlogchain))
144557fc4a0SMichal Kazior 		list_add_tail(&flow->backlogchain, &fq->backlogs);
145557fc4a0SMichal Kazior 
146557fc4a0SMichal Kazior 	i = flow;
147557fc4a0SMichal Kazior 	list_for_each_entry_continue_reverse(i, &fq->backlogs,
148557fc4a0SMichal Kazior 					     backlogchain)
149557fc4a0SMichal Kazior 		if (i->backlog > flow->backlog)
150557fc4a0SMichal Kazior 			break;
151557fc4a0SMichal Kazior 
152557fc4a0SMichal Kazior 	list_move(&flow->backlogchain, &i->backlogchain);
153b43e7199SMichal Kazior }
154b43e7199SMichal Kazior 
155b43e7199SMichal Kazior static void fq_tin_enqueue(struct fq *fq,
156b43e7199SMichal Kazior 			   struct fq_tin *tin,
157b43e7199SMichal Kazior 			   struct sk_buff *skb,
158b43e7199SMichal Kazior 			   fq_skb_free_t free_func,
159b43e7199SMichal Kazior 			   fq_flow_get_default_t get_default_func)
160b43e7199SMichal Kazior {
161b43e7199SMichal Kazior 	struct fq_flow *flow;
162b43e7199SMichal Kazior 
163b43e7199SMichal Kazior 	lockdep_assert_held(&fq->lock);
164b43e7199SMichal Kazior 
165b43e7199SMichal Kazior 	flow = fq_flow_classify(fq, tin, skb, get_default_func);
166b43e7199SMichal Kazior 
167b43e7199SMichal Kazior 	flow->tin = tin;
168b43e7199SMichal Kazior 	flow->backlog += skb->len;
169b43e7199SMichal Kazior 	tin->backlog_bytes += skb->len;
170b43e7199SMichal Kazior 	tin->backlog_packets++;
171097b065bSToke Høiland-Jørgensen 	fq->memory_usage += skb->truesize;
172b43e7199SMichal Kazior 	fq->backlog++;
173b43e7199SMichal Kazior 
174b43e7199SMichal Kazior 	fq_recalc_backlog(fq, tin, flow);
175557fc4a0SMichal Kazior 
176557fc4a0SMichal Kazior 	if (list_empty(&flow->flowchain)) {
177557fc4a0SMichal Kazior 		flow->deficit = fq->quantum;
178557fc4a0SMichal Kazior 		list_add_tail(&flow->flowchain,
179557fc4a0SMichal Kazior 			      &tin->new_flows);
180557fc4a0SMichal Kazior 	}
181557fc4a0SMichal Kazior 
182557fc4a0SMichal Kazior 	__skb_queue_tail(&flow->queue, skb);
183557fc4a0SMichal Kazior 
184097b065bSToke Høiland-Jørgensen 	if (fq->backlog > fq->limit || fq->memory_usage > fq->memory_limit) {
185557fc4a0SMichal Kazior 		flow = list_first_entry_or_null(&fq->backlogs,
186557fc4a0SMichal Kazior 						struct fq_flow,
187557fc4a0SMichal Kazior 						backlogchain);
188557fc4a0SMichal Kazior 		if (!flow)
189557fc4a0SMichal Kazior 			return;
190557fc4a0SMichal Kazior 
191557fc4a0SMichal Kazior 		skb = fq_flow_dequeue(fq, flow);
192557fc4a0SMichal Kazior 		if (!skb)
193557fc4a0SMichal Kazior 			return;
194557fc4a0SMichal Kazior 
195557fc4a0SMichal Kazior 		free_func(fq, flow->tin, flow, skb);
196557fc4a0SMichal Kazior 
197557fc4a0SMichal Kazior 		flow->tin->overlimit++;
198557fc4a0SMichal Kazior 		fq->overlimit++;
199097b065bSToke Høiland-Jørgensen 		if (fq->memory_usage > fq->memory_limit)
200097b065bSToke Høiland-Jørgensen 			fq->overmemory++;
201557fc4a0SMichal Kazior 	}
202557fc4a0SMichal Kazior }
203557fc4a0SMichal Kazior 
204*8c418b5bSJohannes Berg static void fq_flow_filter(struct fq *fq,
205*8c418b5bSJohannes Berg 			   struct fq_flow *flow,
206*8c418b5bSJohannes Berg 			   fq_skb_filter_t filter_func,
207*8c418b5bSJohannes Berg 			   void *filter_data,
208*8c418b5bSJohannes Berg 			   fq_skb_free_t free_func)
209*8c418b5bSJohannes Berg {
210*8c418b5bSJohannes Berg 	struct fq_tin *tin = flow->tin;
211*8c418b5bSJohannes Berg 	struct sk_buff *skb, *tmp;
212*8c418b5bSJohannes Berg 
213*8c418b5bSJohannes Berg 	lockdep_assert_held(&fq->lock);
214*8c418b5bSJohannes Berg 
215*8c418b5bSJohannes Berg 	skb_queue_walk_safe(&flow->queue, skb, tmp) {
216*8c418b5bSJohannes Berg 		if (!filter_func(fq, tin, flow, skb, filter_data))
217*8c418b5bSJohannes Berg 			continue;
218*8c418b5bSJohannes Berg 
219*8c418b5bSJohannes Berg 		__skb_unlink(skb, &flow->queue);
220*8c418b5bSJohannes Berg 		fq_adjust_removal(fq, flow, skb);
221*8c418b5bSJohannes Berg 		free_func(fq, tin, flow, skb);
222*8c418b5bSJohannes Berg 	}
223*8c418b5bSJohannes Berg 
224*8c418b5bSJohannes Berg 	fq_rejigger_backlog(fq, flow);
225*8c418b5bSJohannes Berg }
226*8c418b5bSJohannes Berg 
227*8c418b5bSJohannes Berg static void fq_tin_filter(struct fq *fq,
228*8c418b5bSJohannes Berg 			  struct fq_tin *tin,
229*8c418b5bSJohannes Berg 			  fq_skb_filter_t filter_func,
230*8c418b5bSJohannes Berg 			  void *filter_data,
231*8c418b5bSJohannes Berg 			  fq_skb_free_t free_func)
232*8c418b5bSJohannes Berg {
233*8c418b5bSJohannes Berg 	struct fq_flow *flow;
234*8c418b5bSJohannes Berg 
235*8c418b5bSJohannes Berg 	lockdep_assert_held(&fq->lock);
236*8c418b5bSJohannes Berg 
237*8c418b5bSJohannes Berg 	list_for_each_entry(flow, &tin->new_flows, flowchain)
238*8c418b5bSJohannes Berg 		fq_flow_filter(fq, flow, filter_func, filter_data, free_func);
239*8c418b5bSJohannes Berg 	list_for_each_entry(flow, &tin->old_flows, flowchain)
240*8c418b5bSJohannes Berg 		fq_flow_filter(fq, flow, filter_func, filter_data, free_func);
241*8c418b5bSJohannes Berg }
242*8c418b5bSJohannes Berg 
243557fc4a0SMichal Kazior static void fq_flow_reset(struct fq *fq,
244557fc4a0SMichal Kazior 			  struct fq_flow *flow,
245557fc4a0SMichal Kazior 			  fq_skb_free_t free_func)
246557fc4a0SMichal Kazior {
247557fc4a0SMichal Kazior 	struct sk_buff *skb;
248557fc4a0SMichal Kazior 
249557fc4a0SMichal Kazior 	while ((skb = fq_flow_dequeue(fq, flow)))
250557fc4a0SMichal Kazior 		free_func(fq, flow->tin, flow, skb);
251557fc4a0SMichal Kazior 
252557fc4a0SMichal Kazior 	if (!list_empty(&flow->flowchain))
253557fc4a0SMichal Kazior 		list_del_init(&flow->flowchain);
254557fc4a0SMichal Kazior 
255557fc4a0SMichal Kazior 	if (!list_empty(&flow->backlogchain))
256557fc4a0SMichal Kazior 		list_del_init(&flow->backlogchain);
257557fc4a0SMichal Kazior 
258557fc4a0SMichal Kazior 	flow->tin = NULL;
259557fc4a0SMichal Kazior 
260557fc4a0SMichal Kazior 	WARN_ON_ONCE(flow->backlog);
261557fc4a0SMichal Kazior }
262557fc4a0SMichal Kazior 
263557fc4a0SMichal Kazior static void fq_tin_reset(struct fq *fq,
264557fc4a0SMichal Kazior 			 struct fq_tin *tin,
265557fc4a0SMichal Kazior 			 fq_skb_free_t free_func)
266557fc4a0SMichal Kazior {
267557fc4a0SMichal Kazior 	struct list_head *head;
268557fc4a0SMichal Kazior 	struct fq_flow *flow;
269557fc4a0SMichal Kazior 
270557fc4a0SMichal Kazior 	for (;;) {
271557fc4a0SMichal Kazior 		head = &tin->new_flows;
272557fc4a0SMichal Kazior 		if (list_empty(head)) {
273557fc4a0SMichal Kazior 			head = &tin->old_flows;
274557fc4a0SMichal Kazior 			if (list_empty(head))
275557fc4a0SMichal Kazior 				break;
276557fc4a0SMichal Kazior 		}
277557fc4a0SMichal Kazior 
278557fc4a0SMichal Kazior 		flow = list_first_entry(head, struct fq_flow, flowchain);
279557fc4a0SMichal Kazior 		fq_flow_reset(fq, flow, free_func);
280557fc4a0SMichal Kazior 	}
281557fc4a0SMichal Kazior 
282557fc4a0SMichal Kazior 	WARN_ON_ONCE(tin->backlog_bytes);
283557fc4a0SMichal Kazior 	WARN_ON_ONCE(tin->backlog_packets);
284557fc4a0SMichal Kazior }
285557fc4a0SMichal Kazior 
286557fc4a0SMichal Kazior static void fq_flow_init(struct fq_flow *flow)
287557fc4a0SMichal Kazior {
288557fc4a0SMichal Kazior 	INIT_LIST_HEAD(&flow->flowchain);
289557fc4a0SMichal Kazior 	INIT_LIST_HEAD(&flow->backlogchain);
290557fc4a0SMichal Kazior 	__skb_queue_head_init(&flow->queue);
291557fc4a0SMichal Kazior }
292557fc4a0SMichal Kazior 
293557fc4a0SMichal Kazior static void fq_tin_init(struct fq_tin *tin)
294557fc4a0SMichal Kazior {
295557fc4a0SMichal Kazior 	INIT_LIST_HEAD(&tin->new_flows);
296557fc4a0SMichal Kazior 	INIT_LIST_HEAD(&tin->old_flows);
297557fc4a0SMichal Kazior }
298557fc4a0SMichal Kazior 
299557fc4a0SMichal Kazior static int fq_init(struct fq *fq, int flows_cnt)
300557fc4a0SMichal Kazior {
301557fc4a0SMichal Kazior 	int i;
302557fc4a0SMichal Kazior 
303557fc4a0SMichal Kazior 	memset(fq, 0, sizeof(fq[0]));
304557fc4a0SMichal Kazior 	INIT_LIST_HEAD(&fq->backlogs);
305557fc4a0SMichal Kazior 	spin_lock_init(&fq->lock);
306557fc4a0SMichal Kazior 	fq->flows_cnt = max_t(u32, flows_cnt, 1);
307557fc4a0SMichal Kazior 	fq->perturbation = prandom_u32();
308557fc4a0SMichal Kazior 	fq->quantum = 300;
309557fc4a0SMichal Kazior 	fq->limit = 8192;
310097b065bSToke Høiland-Jørgensen 	fq->memory_limit = 16 << 20; /* 16 MBytes */
311557fc4a0SMichal Kazior 
312557fc4a0SMichal Kazior 	fq->flows = kcalloc(fq->flows_cnt, sizeof(fq->flows[0]), GFP_KERNEL);
313557fc4a0SMichal Kazior 	if (!fq->flows)
314557fc4a0SMichal Kazior 		return -ENOMEM;
315557fc4a0SMichal Kazior 
316557fc4a0SMichal Kazior 	for (i = 0; i < fq->flows_cnt; i++)
317557fc4a0SMichal Kazior 		fq_flow_init(&fq->flows[i]);
318557fc4a0SMichal Kazior 
319557fc4a0SMichal Kazior 	return 0;
320557fc4a0SMichal Kazior }
321557fc4a0SMichal Kazior 
322557fc4a0SMichal Kazior static void fq_reset(struct fq *fq,
323557fc4a0SMichal Kazior 		     fq_skb_free_t free_func)
324557fc4a0SMichal Kazior {
325557fc4a0SMichal Kazior 	int i;
326557fc4a0SMichal Kazior 
327557fc4a0SMichal Kazior 	for (i = 0; i < fq->flows_cnt; i++)
328557fc4a0SMichal Kazior 		fq_flow_reset(fq, &fq->flows[i], free_func);
329557fc4a0SMichal Kazior 
330557fc4a0SMichal Kazior 	kfree(fq->flows);
331557fc4a0SMichal Kazior 	fq->flows = NULL;
332557fc4a0SMichal Kazior }
333557fc4a0SMichal Kazior 
334557fc4a0SMichal Kazior #endif
335