xref: /openbmc/linux/net/sched/act_police.c (revision 96de0e252cedffad61b3cb5e05662c591898e69a)
1 /*
2  * net/sched/police.c	Input police filter.
3  *
4  *		This program is free software; you can redistribute it and/or
5  *		modify it under the terms of the GNU General Public License
6  *		as published by the Free Software Foundation; either version
7  *		2 of the License, or (at your option) any later version.
8  *
9  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10  * 		J Hadi Salim (action changes)
11  */
12 
13 #include <linux/module.h>
14 #include <linux/types.h>
15 #include <linux/kernel.h>
16 #include <linux/string.h>
17 #include <linux/errno.h>
18 #include <linux/skbuff.h>
19 #include <linux/rtnetlink.h>
20 #include <linux/init.h>
21 #include <net/act_api.h>
22 #include <net/netlink.h>
23 
24 #define L2T(p,L)   qdisc_l2t((p)->tcfp_R_tab, L)
25 #define L2T_P(p,L) qdisc_l2t((p)->tcfp_P_tab, L)
26 
27 #define POL_TAB_MASK     15
28 static struct tcf_common *tcf_police_ht[POL_TAB_MASK + 1];
29 static u32 police_idx_gen;
30 static DEFINE_RWLOCK(police_lock);
31 
32 static struct tcf_hashinfo police_hash_info = {
33 	.htab	=	tcf_police_ht,
34 	.hmask	=	POL_TAB_MASK,
35 	.lock	=	&police_lock,
36 };
37 
38 /* old policer structure from before tc actions */
39 struct tc_police_compat
40 {
41 	u32			index;
42 	int			action;
43 	u32			limit;
44 	u32			burst;
45 	u32			mtu;
46 	struct tc_ratespec	rate;
47 	struct tc_ratespec	peakrate;
48 };
49 
50 /* Each policer is serialized by its individual spinlock */
51 
52 static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *cb,
53 			      int type, struct tc_action *a)
54 {
55 	struct tcf_common *p;
56 	int err = 0, index = -1, i = 0, s_i = 0, n_i = 0;
57 	struct rtattr *r;
58 
59 	read_lock_bh(&police_lock);
60 
61 	s_i = cb->args[0];
62 
63 	for (i = 0; i < (POL_TAB_MASK + 1); i++) {
64 		p = tcf_police_ht[tcf_hash(i, POL_TAB_MASK)];
65 
66 		for (; p; p = p->tcfc_next) {
67 			index++;
68 			if (index < s_i)
69 				continue;
70 			a->priv = p;
71 			a->order = index;
72 			r = (struct rtattr *)skb_tail_pointer(skb);
73 			RTA_PUT(skb, a->order, 0, NULL);
74 			if (type == RTM_DELACTION)
75 				err = tcf_action_dump_1(skb, a, 0, 1);
76 			else
77 				err = tcf_action_dump_1(skb, a, 0, 0);
78 			if (err < 0) {
79 				index--;
80 				nlmsg_trim(skb, r);
81 				goto done;
82 			}
83 			r->rta_len = skb_tail_pointer(skb) - (u8 *)r;
84 			n_i++;
85 		}
86 	}
87 done:
88 	read_unlock_bh(&police_lock);
89 	if (n_i)
90 		cb->args[0] += n_i;
91 	return n_i;
92 
93 rtattr_failure:
94 	nlmsg_trim(skb, r);
95 	goto done;
96 }
97 
98 static void tcf_police_destroy(struct tcf_police *p)
99 {
100 	unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK);
101 	struct tcf_common **p1p;
102 
103 	for (p1p = &tcf_police_ht[h]; *p1p; p1p = &(*p1p)->tcfc_next) {
104 		if (*p1p == &p->common) {
105 			write_lock_bh(&police_lock);
106 			*p1p = p->tcf_next;
107 			write_unlock_bh(&police_lock);
108 			gen_kill_estimator(&p->tcf_bstats,
109 					   &p->tcf_rate_est);
110 			if (p->tcfp_R_tab)
111 				qdisc_put_rtab(p->tcfp_R_tab);
112 			if (p->tcfp_P_tab)
113 				qdisc_put_rtab(p->tcfp_P_tab);
114 			kfree(p);
115 			return;
116 		}
117 	}
118 	BUG_TRAP(0);
119 }
120 
121 static int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,
122 				 struct tc_action *a, int ovr, int bind)
123 {
124 	unsigned h;
125 	int ret = 0, err;
126 	struct rtattr *tb[TCA_POLICE_MAX];
127 	struct tc_police *parm;
128 	struct tcf_police *police;
129 	struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL;
130 	int size;
131 
132 	if (rta == NULL || rtattr_parse_nested(tb, TCA_POLICE_MAX, rta) < 0)
133 		return -EINVAL;
134 
135 	if (tb[TCA_POLICE_TBF-1] == NULL)
136 		return -EINVAL;
137 	size = RTA_PAYLOAD(tb[TCA_POLICE_TBF-1]);
138 	if (size != sizeof(*parm) && size != sizeof(struct tc_police_compat))
139 		return -EINVAL;
140 	parm = RTA_DATA(tb[TCA_POLICE_TBF-1]);
141 
142 	if (tb[TCA_POLICE_RESULT-1] != NULL &&
143 	    RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32))
144 		return -EINVAL;
145 	if (tb[TCA_POLICE_RESULT-1] != NULL &&
146 	    RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32))
147 		return -EINVAL;
148 
149 	if (parm->index) {
150 		struct tcf_common *pc;
151 
152 		pc = tcf_hash_lookup(parm->index, &police_hash_info);
153 		if (pc != NULL) {
154 			a->priv = pc;
155 			police = to_police(pc);
156 			if (bind) {
157 				police->tcf_bindcnt += 1;
158 				police->tcf_refcnt += 1;
159 			}
160 			if (ovr)
161 				goto override;
162 			return ret;
163 		}
164 	}
165 
166 	police = kzalloc(sizeof(*police), GFP_KERNEL);
167 	if (police == NULL)
168 		return -ENOMEM;
169 	ret = ACT_P_CREATED;
170 	police->tcf_refcnt = 1;
171 	spin_lock_init(&police->tcf_lock);
172 	if (bind)
173 		police->tcf_bindcnt = 1;
174 override:
175 	if (parm->rate.rate) {
176 		err = -ENOMEM;
177 		R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1]);
178 		if (R_tab == NULL)
179 			goto failure;
180 		if (parm->peakrate.rate) {
181 			P_tab = qdisc_get_rtab(&parm->peakrate,
182 					       tb[TCA_POLICE_PEAKRATE-1]);
183 			if (P_tab == NULL) {
184 				qdisc_put_rtab(R_tab);
185 				goto failure;
186 			}
187 		}
188 	}
189 	/* No failure allowed after this point */
190 	spin_lock_bh(&police->tcf_lock);
191 	if (R_tab != NULL) {
192 		qdisc_put_rtab(police->tcfp_R_tab);
193 		police->tcfp_R_tab = R_tab;
194 	}
195 	if (P_tab != NULL) {
196 		qdisc_put_rtab(police->tcfp_P_tab);
197 		police->tcfp_P_tab = P_tab;
198 	}
199 
200 	if (tb[TCA_POLICE_RESULT-1])
201 		police->tcfp_result = *(u32*)RTA_DATA(tb[TCA_POLICE_RESULT-1]);
202 	police->tcfp_toks = police->tcfp_burst = parm->burst;
203 	police->tcfp_mtu = parm->mtu;
204 	if (police->tcfp_mtu == 0) {
205 		police->tcfp_mtu = ~0;
206 		if (police->tcfp_R_tab)
207 			police->tcfp_mtu = 255<<police->tcfp_R_tab->rate.cell_log;
208 	}
209 	if (police->tcfp_P_tab)
210 		police->tcfp_ptoks = L2T_P(police, police->tcfp_mtu);
211 	police->tcf_action = parm->action;
212 
213 	if (tb[TCA_POLICE_AVRATE-1])
214 		police->tcfp_ewma_rate =
215 			*(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]);
216 	if (est)
217 		gen_replace_estimator(&police->tcf_bstats,
218 				      &police->tcf_rate_est,
219 				      &police->tcf_lock, est);
220 
221 	spin_unlock_bh(&police->tcf_lock);
222 	if (ret != ACT_P_CREATED)
223 		return ret;
224 
225 	police->tcfp_t_c = psched_get_time();
226 	police->tcf_index = parm->index ? parm->index :
227 		tcf_hash_new_index(&police_idx_gen, &police_hash_info);
228 	h = tcf_hash(police->tcf_index, POL_TAB_MASK);
229 	write_lock_bh(&police_lock);
230 	police->tcf_next = tcf_police_ht[h];
231 	tcf_police_ht[h] = &police->common;
232 	write_unlock_bh(&police_lock);
233 
234 	a->priv = police;
235 	return ret;
236 
237 failure:
238 	if (ret == ACT_P_CREATED)
239 		kfree(police);
240 	return err;
241 }
242 
243 static int tcf_act_police_cleanup(struct tc_action *a, int bind)
244 {
245 	struct tcf_police *p = a->priv;
246 	int ret = 0;
247 
248 	if (p != NULL) {
249 		if (bind)
250 			p->tcf_bindcnt--;
251 
252 		p->tcf_refcnt--;
253 		if (p->tcf_refcnt <= 0 && !p->tcf_bindcnt) {
254 			tcf_police_destroy(p);
255 			ret = 1;
256 		}
257 	}
258 	return ret;
259 }
260 
261 static int tcf_act_police(struct sk_buff *skb, struct tc_action *a,
262 			  struct tcf_result *res)
263 {
264 	struct tcf_police *police = a->priv;
265 	psched_time_t now;
266 	long toks;
267 	long ptoks = 0;
268 
269 	spin_lock(&police->tcf_lock);
270 
271 	police->tcf_bstats.bytes += skb->len;
272 	police->tcf_bstats.packets++;
273 
274 	if (police->tcfp_ewma_rate &&
275 	    police->tcf_rate_est.bps >= police->tcfp_ewma_rate) {
276 		police->tcf_qstats.overlimits++;
277 		spin_unlock(&police->tcf_lock);
278 		return police->tcf_action;
279 	}
280 
281 	if (skb->len <= police->tcfp_mtu) {
282 		if (police->tcfp_R_tab == NULL) {
283 			spin_unlock(&police->tcf_lock);
284 			return police->tcfp_result;
285 		}
286 
287 		now = psched_get_time();
288 		toks = psched_tdiff_bounded(now, police->tcfp_t_c,
289 					    police->tcfp_burst);
290 		if (police->tcfp_P_tab) {
291 			ptoks = toks + police->tcfp_ptoks;
292 			if (ptoks > (long)L2T_P(police, police->tcfp_mtu))
293 				ptoks = (long)L2T_P(police, police->tcfp_mtu);
294 			ptoks -= L2T_P(police, skb->len);
295 		}
296 		toks += police->tcfp_toks;
297 		if (toks > (long)police->tcfp_burst)
298 			toks = police->tcfp_burst;
299 		toks -= L2T(police, skb->len);
300 		if ((toks|ptoks) >= 0) {
301 			police->tcfp_t_c = now;
302 			police->tcfp_toks = toks;
303 			police->tcfp_ptoks = ptoks;
304 			spin_unlock(&police->tcf_lock);
305 			return police->tcfp_result;
306 		}
307 	}
308 
309 	police->tcf_qstats.overlimits++;
310 	spin_unlock(&police->tcf_lock);
311 	return police->tcf_action;
312 }
313 
314 static int
315 tcf_act_police_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
316 {
317 	unsigned char *b = skb_tail_pointer(skb);
318 	struct tcf_police *police = a->priv;
319 	struct tc_police opt;
320 
321 	opt.index = police->tcf_index;
322 	opt.action = police->tcf_action;
323 	opt.mtu = police->tcfp_mtu;
324 	opt.burst = police->tcfp_burst;
325 	opt.refcnt = police->tcf_refcnt - ref;
326 	opt.bindcnt = police->tcf_bindcnt - bind;
327 	if (police->tcfp_R_tab)
328 		opt.rate = police->tcfp_R_tab->rate;
329 	else
330 		memset(&opt.rate, 0, sizeof(opt.rate));
331 	if (police->tcfp_P_tab)
332 		opt.peakrate = police->tcfp_P_tab->rate;
333 	else
334 		memset(&opt.peakrate, 0, sizeof(opt.peakrate));
335 	RTA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt);
336 	if (police->tcfp_result)
337 		RTA_PUT(skb, TCA_POLICE_RESULT, sizeof(int),
338 			&police->tcfp_result);
339 	if (police->tcfp_ewma_rate)
340 		RTA_PUT(skb, TCA_POLICE_AVRATE, 4, &police->tcfp_ewma_rate);
341 	return skb->len;
342 
343 rtattr_failure:
344 	nlmsg_trim(skb, b);
345 	return -1;
346 }
347 
348 MODULE_AUTHOR("Alexey Kuznetsov");
349 MODULE_DESCRIPTION("Policing actions");
350 MODULE_LICENSE("GPL");
351 
352 static struct tc_action_ops act_police_ops = {
353 	.kind		=	"police",
354 	.hinfo		=	&police_hash_info,
355 	.type		=	TCA_ID_POLICE,
356 	.capab		=	TCA_CAP_NONE,
357 	.owner		=	THIS_MODULE,
358 	.act		=	tcf_act_police,
359 	.dump		=	tcf_act_police_dump,
360 	.cleanup	=	tcf_act_police_cleanup,
361 	.lookup		=	tcf_hash_search,
362 	.init		=	tcf_act_police_locate,
363 	.walk		=	tcf_act_police_walker
364 };
365 
366 static int __init
367 police_init_module(void)
368 {
369 	return tcf_register_action(&act_police_ops);
370 }
371 
372 static void __exit
373 police_cleanup_module(void)
374 {
375 	tcf_unregister_action(&act_police_ops);
376 }
377 
378 module_init(police_init_module);
379 module_exit(police_cleanup_module);
380