xref: /openbmc/linux/net/sched/act_police.c (revision 4bba3925924148c24fb0c7636a04ad69a6a56b84)
1*4bba3925SPatrick McHardy /*
2*4bba3925SPatrick McHardy  * net/sched/police.c	Input police filter.
3*4bba3925SPatrick McHardy  *
4*4bba3925SPatrick McHardy  *		This program is free software; you can redistribute it and/or
5*4bba3925SPatrick McHardy  *		modify it under the terms of the GNU General Public License
6*4bba3925SPatrick McHardy  *		as published by the Free Software Foundation; either version
7*4bba3925SPatrick McHardy  *		2 of the License, or (at your option) any later version.
8*4bba3925SPatrick McHardy  *
9*4bba3925SPatrick McHardy  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10*4bba3925SPatrick McHardy  * 		J Hadi Salim (action changes)
11*4bba3925SPatrick McHardy  */
12*4bba3925SPatrick McHardy 
13*4bba3925SPatrick McHardy #include <asm/uaccess.h>
14*4bba3925SPatrick McHardy #include <asm/system.h>
15*4bba3925SPatrick McHardy #include <linux/bitops.h>
16*4bba3925SPatrick McHardy #include <linux/config.h>
17*4bba3925SPatrick McHardy #include <linux/module.h>
18*4bba3925SPatrick McHardy #include <linux/types.h>
19*4bba3925SPatrick McHardy #include <linux/kernel.h>
20*4bba3925SPatrick McHardy #include <linux/sched.h>
21*4bba3925SPatrick McHardy #include <linux/string.h>
22*4bba3925SPatrick McHardy #include <linux/mm.h>
23*4bba3925SPatrick McHardy #include <linux/socket.h>
24*4bba3925SPatrick McHardy #include <linux/sockios.h>
25*4bba3925SPatrick McHardy #include <linux/in.h>
26*4bba3925SPatrick McHardy #include <linux/errno.h>
27*4bba3925SPatrick McHardy #include <linux/interrupt.h>
28*4bba3925SPatrick McHardy #include <linux/netdevice.h>
29*4bba3925SPatrick McHardy #include <linux/skbuff.h>
30*4bba3925SPatrick McHardy #include <linux/module.h>
31*4bba3925SPatrick McHardy #include <linux/rtnetlink.h>
32*4bba3925SPatrick McHardy #include <linux/init.h>
33*4bba3925SPatrick McHardy #include <net/sock.h>
34*4bba3925SPatrick McHardy #include <net/act_api.h>
35*4bba3925SPatrick McHardy 
36*4bba3925SPatrick McHardy #define L2T(p,L)   ((p)->R_tab->data[(L)>>(p)->R_tab->rate.cell_log])
37*4bba3925SPatrick McHardy #define L2T_P(p,L) ((p)->P_tab->data[(L)>>(p)->P_tab->rate.cell_log])
38*4bba3925SPatrick McHardy #define PRIV(a) ((struct tcf_police *) (a)->priv)
39*4bba3925SPatrick McHardy 
40*4bba3925SPatrick McHardy /* use generic hash table */
41*4bba3925SPatrick McHardy #define MY_TAB_SIZE     16
42*4bba3925SPatrick McHardy #define MY_TAB_MASK     15
43*4bba3925SPatrick McHardy static u32 idx_gen;
44*4bba3925SPatrick McHardy static struct tcf_police *tcf_police_ht[MY_TAB_SIZE];
45*4bba3925SPatrick McHardy /* Policer hash table lock */
46*4bba3925SPatrick McHardy static DEFINE_RWLOCK(police_lock);
47*4bba3925SPatrick McHardy 
48*4bba3925SPatrick McHardy /* Each policer is serialized by its individual spinlock */
49*4bba3925SPatrick McHardy 
50*4bba3925SPatrick McHardy static __inline__ unsigned tcf_police_hash(u32 index)
51*4bba3925SPatrick McHardy {
52*4bba3925SPatrick McHardy 	return index&0xF;
53*4bba3925SPatrick McHardy }
54*4bba3925SPatrick McHardy 
55*4bba3925SPatrick McHardy static __inline__ struct tcf_police * tcf_police_lookup(u32 index)
56*4bba3925SPatrick McHardy {
57*4bba3925SPatrick McHardy 	struct tcf_police *p;
58*4bba3925SPatrick McHardy 
59*4bba3925SPatrick McHardy 	read_lock(&police_lock);
60*4bba3925SPatrick McHardy 	for (p = tcf_police_ht[tcf_police_hash(index)]; p; p = p->next) {
61*4bba3925SPatrick McHardy 		if (p->index == index)
62*4bba3925SPatrick McHardy 			break;
63*4bba3925SPatrick McHardy 	}
64*4bba3925SPatrick McHardy 	read_unlock(&police_lock);
65*4bba3925SPatrick McHardy 	return p;
66*4bba3925SPatrick McHardy }
67*4bba3925SPatrick McHardy 
68*4bba3925SPatrick McHardy #ifdef CONFIG_NET_CLS_ACT
69*4bba3925SPatrick McHardy static int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb,
70*4bba3925SPatrick McHardy                               int type, struct tc_action *a)
71*4bba3925SPatrick McHardy {
72*4bba3925SPatrick McHardy 	struct tcf_police *p;
73*4bba3925SPatrick McHardy 	int err = 0, index = -1, i = 0, s_i = 0, n_i = 0;
74*4bba3925SPatrick McHardy 	struct rtattr *r;
75*4bba3925SPatrick McHardy 
76*4bba3925SPatrick McHardy 	read_lock(&police_lock);
77*4bba3925SPatrick McHardy 
78*4bba3925SPatrick McHardy 	s_i = cb->args[0];
79*4bba3925SPatrick McHardy 
80*4bba3925SPatrick McHardy 	for (i = 0; i < MY_TAB_SIZE; i++) {
81*4bba3925SPatrick McHardy 		p = tcf_police_ht[tcf_police_hash(i)];
82*4bba3925SPatrick McHardy 
83*4bba3925SPatrick McHardy 		for (; p; p = p->next) {
84*4bba3925SPatrick McHardy 			index++;
85*4bba3925SPatrick McHardy 			if (index < s_i)
86*4bba3925SPatrick McHardy 				continue;
87*4bba3925SPatrick McHardy 			a->priv = p;
88*4bba3925SPatrick McHardy 			a->order = index;
89*4bba3925SPatrick McHardy 			r = (struct rtattr*) skb->tail;
90*4bba3925SPatrick McHardy 			RTA_PUT(skb, a->order, 0, NULL);
91*4bba3925SPatrick McHardy 			if (type == RTM_DELACTION)
92*4bba3925SPatrick McHardy 				err = tcf_action_dump_1(skb, a, 0, 1);
93*4bba3925SPatrick McHardy 			else
94*4bba3925SPatrick McHardy 				err = tcf_action_dump_1(skb, a, 0, 0);
95*4bba3925SPatrick McHardy 			if (err < 0) {
96*4bba3925SPatrick McHardy 				index--;
97*4bba3925SPatrick McHardy 				skb_trim(skb, (u8*)r - skb->data);
98*4bba3925SPatrick McHardy 				goto done;
99*4bba3925SPatrick McHardy 			}
100*4bba3925SPatrick McHardy 			r->rta_len = skb->tail - (u8*)r;
101*4bba3925SPatrick McHardy 			n_i++;
102*4bba3925SPatrick McHardy 		}
103*4bba3925SPatrick McHardy 	}
104*4bba3925SPatrick McHardy done:
105*4bba3925SPatrick McHardy 	read_unlock(&police_lock);
106*4bba3925SPatrick McHardy 	if (n_i)
107*4bba3925SPatrick McHardy 		cb->args[0] += n_i;
108*4bba3925SPatrick McHardy 	return n_i;
109*4bba3925SPatrick McHardy 
110*4bba3925SPatrick McHardy rtattr_failure:
111*4bba3925SPatrick McHardy 	skb_trim(skb, (u8*)r - skb->data);
112*4bba3925SPatrick McHardy 	goto done;
113*4bba3925SPatrick McHardy }
114*4bba3925SPatrick McHardy 
115*4bba3925SPatrick McHardy static inline int
116*4bba3925SPatrick McHardy tcf_hash_search(struct tc_action *a, u32 index)
117*4bba3925SPatrick McHardy {
118*4bba3925SPatrick McHardy 	struct tcf_police *p = tcf_police_lookup(index);
119*4bba3925SPatrick McHardy 
120*4bba3925SPatrick McHardy 	if (p != NULL) {
121*4bba3925SPatrick McHardy 		a->priv = p;
122*4bba3925SPatrick McHardy 		return 1;
123*4bba3925SPatrick McHardy 	} else {
124*4bba3925SPatrick McHardy 		return 0;
125*4bba3925SPatrick McHardy 	}
126*4bba3925SPatrick McHardy }
127*4bba3925SPatrick McHardy #endif
128*4bba3925SPatrick McHardy 
129*4bba3925SPatrick McHardy static inline u32 tcf_police_new_index(void)
130*4bba3925SPatrick McHardy {
131*4bba3925SPatrick McHardy 	do {
132*4bba3925SPatrick McHardy 		if (++idx_gen == 0)
133*4bba3925SPatrick McHardy 			idx_gen = 1;
134*4bba3925SPatrick McHardy 	} while (tcf_police_lookup(idx_gen));
135*4bba3925SPatrick McHardy 
136*4bba3925SPatrick McHardy 	return idx_gen;
137*4bba3925SPatrick McHardy }
138*4bba3925SPatrick McHardy 
139*4bba3925SPatrick McHardy void tcf_police_destroy(struct tcf_police *p)
140*4bba3925SPatrick McHardy {
141*4bba3925SPatrick McHardy 	unsigned h = tcf_police_hash(p->index);
142*4bba3925SPatrick McHardy 	struct tcf_police **p1p;
143*4bba3925SPatrick McHardy 
144*4bba3925SPatrick McHardy 	for (p1p = &tcf_police_ht[h]; *p1p; p1p = &(*p1p)->next) {
145*4bba3925SPatrick McHardy 		if (*p1p == p) {
146*4bba3925SPatrick McHardy 			write_lock_bh(&police_lock);
147*4bba3925SPatrick McHardy 			*p1p = p->next;
148*4bba3925SPatrick McHardy 			write_unlock_bh(&police_lock);
149*4bba3925SPatrick McHardy #ifdef CONFIG_NET_ESTIMATOR
150*4bba3925SPatrick McHardy 			gen_kill_estimator(&p->bstats, &p->rate_est);
151*4bba3925SPatrick McHardy #endif
152*4bba3925SPatrick McHardy 			if (p->R_tab)
153*4bba3925SPatrick McHardy 				qdisc_put_rtab(p->R_tab);
154*4bba3925SPatrick McHardy 			if (p->P_tab)
155*4bba3925SPatrick McHardy 				qdisc_put_rtab(p->P_tab);
156*4bba3925SPatrick McHardy 			kfree(p);
157*4bba3925SPatrick McHardy 			return;
158*4bba3925SPatrick McHardy 		}
159*4bba3925SPatrick McHardy 	}
160*4bba3925SPatrick McHardy 	BUG_TRAP(0);
161*4bba3925SPatrick McHardy }
162*4bba3925SPatrick McHardy 
163*4bba3925SPatrick McHardy #ifdef CONFIG_NET_CLS_ACT
164*4bba3925SPatrick McHardy static int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,
165*4bba3925SPatrick McHardy                                  struct tc_action *a, int ovr, int bind)
166*4bba3925SPatrick McHardy {
167*4bba3925SPatrick McHardy 	unsigned h;
168*4bba3925SPatrick McHardy 	int ret = 0, err;
169*4bba3925SPatrick McHardy 	struct rtattr *tb[TCA_POLICE_MAX];
170*4bba3925SPatrick McHardy 	struct tc_police *parm;
171*4bba3925SPatrick McHardy 	struct tcf_police *p;
172*4bba3925SPatrick McHardy 	struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL;
173*4bba3925SPatrick McHardy 
174*4bba3925SPatrick McHardy 	if (rta == NULL || rtattr_parse_nested(tb, TCA_POLICE_MAX, rta) < 0)
175*4bba3925SPatrick McHardy 		return -EINVAL;
176*4bba3925SPatrick McHardy 
177*4bba3925SPatrick McHardy 	if (tb[TCA_POLICE_TBF-1] == NULL ||
178*4bba3925SPatrick McHardy 	    RTA_PAYLOAD(tb[TCA_POLICE_TBF-1]) != sizeof(*parm))
179*4bba3925SPatrick McHardy 		return -EINVAL;
180*4bba3925SPatrick McHardy 	parm = RTA_DATA(tb[TCA_POLICE_TBF-1]);
181*4bba3925SPatrick McHardy 
182*4bba3925SPatrick McHardy 	if (tb[TCA_POLICE_RESULT-1] != NULL &&
183*4bba3925SPatrick McHardy 	    RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32))
184*4bba3925SPatrick McHardy 		return -EINVAL;
185*4bba3925SPatrick McHardy 	if (tb[TCA_POLICE_RESULT-1] != NULL &&
186*4bba3925SPatrick McHardy 	    RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32))
187*4bba3925SPatrick McHardy 		return -EINVAL;
188*4bba3925SPatrick McHardy 
189*4bba3925SPatrick McHardy 	if (parm->index && (p = tcf_police_lookup(parm->index)) != NULL) {
190*4bba3925SPatrick McHardy 		a->priv = p;
191*4bba3925SPatrick McHardy 		if (bind) {
192*4bba3925SPatrick McHardy 			p->bindcnt += 1;
193*4bba3925SPatrick McHardy 			p->refcnt += 1;
194*4bba3925SPatrick McHardy 		}
195*4bba3925SPatrick McHardy 		if (ovr)
196*4bba3925SPatrick McHardy 			goto override;
197*4bba3925SPatrick McHardy 		return ret;
198*4bba3925SPatrick McHardy 	}
199*4bba3925SPatrick McHardy 
200*4bba3925SPatrick McHardy 	p = kmalloc(sizeof(*p), GFP_KERNEL);
201*4bba3925SPatrick McHardy 	if (p == NULL)
202*4bba3925SPatrick McHardy 		return -ENOMEM;
203*4bba3925SPatrick McHardy 	memset(p, 0, sizeof(*p));
204*4bba3925SPatrick McHardy 
205*4bba3925SPatrick McHardy 	ret = ACT_P_CREATED;
206*4bba3925SPatrick McHardy 	p->refcnt = 1;
207*4bba3925SPatrick McHardy 	spin_lock_init(&p->lock);
208*4bba3925SPatrick McHardy 	p->stats_lock = &p->lock;
209*4bba3925SPatrick McHardy 	if (bind)
210*4bba3925SPatrick McHardy 		p->bindcnt = 1;
211*4bba3925SPatrick McHardy override:
212*4bba3925SPatrick McHardy 	if (parm->rate.rate) {
213*4bba3925SPatrick McHardy 		err = -ENOMEM;
214*4bba3925SPatrick McHardy 		R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1]);
215*4bba3925SPatrick McHardy 		if (R_tab == NULL)
216*4bba3925SPatrick McHardy 			goto failure;
217*4bba3925SPatrick McHardy 		if (parm->peakrate.rate) {
218*4bba3925SPatrick McHardy 			P_tab = qdisc_get_rtab(&parm->peakrate,
219*4bba3925SPatrick McHardy 					       tb[TCA_POLICE_PEAKRATE-1]);
220*4bba3925SPatrick McHardy 			if (p->P_tab == NULL) {
221*4bba3925SPatrick McHardy 				qdisc_put_rtab(R_tab);
222*4bba3925SPatrick McHardy 				goto failure;
223*4bba3925SPatrick McHardy 			}
224*4bba3925SPatrick McHardy 		}
225*4bba3925SPatrick McHardy 	}
226*4bba3925SPatrick McHardy 	/* No failure allowed after this point */
227*4bba3925SPatrick McHardy 	spin_lock_bh(&p->lock);
228*4bba3925SPatrick McHardy 	if (R_tab != NULL) {
229*4bba3925SPatrick McHardy 		qdisc_put_rtab(p->R_tab);
230*4bba3925SPatrick McHardy 		p->R_tab = R_tab;
231*4bba3925SPatrick McHardy 	}
232*4bba3925SPatrick McHardy 	if (P_tab != NULL) {
233*4bba3925SPatrick McHardy 		qdisc_put_rtab(p->P_tab);
234*4bba3925SPatrick McHardy 		p->P_tab = P_tab;
235*4bba3925SPatrick McHardy 	}
236*4bba3925SPatrick McHardy 
237*4bba3925SPatrick McHardy 	if (tb[TCA_POLICE_RESULT-1])
238*4bba3925SPatrick McHardy 		p->result = *(u32*)RTA_DATA(tb[TCA_POLICE_RESULT-1]);
239*4bba3925SPatrick McHardy 	p->toks = p->burst = parm->burst;
240*4bba3925SPatrick McHardy 	p->mtu = parm->mtu;
241*4bba3925SPatrick McHardy 	if (p->mtu == 0) {
242*4bba3925SPatrick McHardy 		p->mtu = ~0;
243*4bba3925SPatrick McHardy 		if (p->R_tab)
244*4bba3925SPatrick McHardy 			p->mtu = 255<<p->R_tab->rate.cell_log;
245*4bba3925SPatrick McHardy 	}
246*4bba3925SPatrick McHardy 	if (p->P_tab)
247*4bba3925SPatrick McHardy 		p->ptoks = L2T_P(p, p->mtu);
248*4bba3925SPatrick McHardy 	p->action = parm->action;
249*4bba3925SPatrick McHardy 
250*4bba3925SPatrick McHardy #ifdef CONFIG_NET_ESTIMATOR
251*4bba3925SPatrick McHardy 	if (tb[TCA_POLICE_AVRATE-1])
252*4bba3925SPatrick McHardy 		p->ewma_rate = *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]);
253*4bba3925SPatrick McHardy 	if (est)
254*4bba3925SPatrick McHardy 		gen_replace_estimator(&p->bstats, &p->rate_est, p->stats_lock, est);
255*4bba3925SPatrick McHardy #endif
256*4bba3925SPatrick McHardy 
257*4bba3925SPatrick McHardy 	spin_unlock_bh(&p->lock);
258*4bba3925SPatrick McHardy 	if (ret != ACT_P_CREATED)
259*4bba3925SPatrick McHardy 		return ret;
260*4bba3925SPatrick McHardy 
261*4bba3925SPatrick McHardy 	PSCHED_GET_TIME(p->t_c);
262*4bba3925SPatrick McHardy 	p->index = parm->index ? : tcf_police_new_index();
263*4bba3925SPatrick McHardy 	h = tcf_police_hash(p->index);
264*4bba3925SPatrick McHardy 	write_lock_bh(&police_lock);
265*4bba3925SPatrick McHardy 	p->next = tcf_police_ht[h];
266*4bba3925SPatrick McHardy 	tcf_police_ht[h] = p;
267*4bba3925SPatrick McHardy 	write_unlock_bh(&police_lock);
268*4bba3925SPatrick McHardy 
269*4bba3925SPatrick McHardy 	a->priv = p;
270*4bba3925SPatrick McHardy 	return ret;
271*4bba3925SPatrick McHardy 
272*4bba3925SPatrick McHardy failure:
273*4bba3925SPatrick McHardy 	if (ret == ACT_P_CREATED)
274*4bba3925SPatrick McHardy 		kfree(p);
275*4bba3925SPatrick McHardy 	return err;
276*4bba3925SPatrick McHardy }
277*4bba3925SPatrick McHardy 
278*4bba3925SPatrick McHardy static int tcf_act_police_cleanup(struct tc_action *a, int bind)
279*4bba3925SPatrick McHardy {
280*4bba3925SPatrick McHardy 	struct tcf_police *p = PRIV(a);
281*4bba3925SPatrick McHardy 
282*4bba3925SPatrick McHardy 	if (p != NULL)
283*4bba3925SPatrick McHardy 		return tcf_police_release(p, bind);
284*4bba3925SPatrick McHardy 	return 0;
285*4bba3925SPatrick McHardy }
286*4bba3925SPatrick McHardy 
287*4bba3925SPatrick McHardy static int tcf_act_police(struct sk_buff *skb, struct tc_action *a,
288*4bba3925SPatrick McHardy                           struct tcf_result *res)
289*4bba3925SPatrick McHardy {
290*4bba3925SPatrick McHardy 	psched_time_t now;
291*4bba3925SPatrick McHardy 	struct tcf_police *p = PRIV(a);
292*4bba3925SPatrick McHardy 	long toks;
293*4bba3925SPatrick McHardy 	long ptoks = 0;
294*4bba3925SPatrick McHardy 
295*4bba3925SPatrick McHardy 	spin_lock(&p->lock);
296*4bba3925SPatrick McHardy 
297*4bba3925SPatrick McHardy 	p->bstats.bytes += skb->len;
298*4bba3925SPatrick McHardy 	p->bstats.packets++;
299*4bba3925SPatrick McHardy 
300*4bba3925SPatrick McHardy #ifdef CONFIG_NET_ESTIMATOR
301*4bba3925SPatrick McHardy 	if (p->ewma_rate && p->rate_est.bps >= p->ewma_rate) {
302*4bba3925SPatrick McHardy 		p->qstats.overlimits++;
303*4bba3925SPatrick McHardy 		spin_unlock(&p->lock);
304*4bba3925SPatrick McHardy 		return p->action;
305*4bba3925SPatrick McHardy 	}
306*4bba3925SPatrick McHardy #endif
307*4bba3925SPatrick McHardy 
308*4bba3925SPatrick McHardy 	if (skb->len <= p->mtu) {
309*4bba3925SPatrick McHardy 		if (p->R_tab == NULL) {
310*4bba3925SPatrick McHardy 			spin_unlock(&p->lock);
311*4bba3925SPatrick McHardy 			return p->result;
312*4bba3925SPatrick McHardy 		}
313*4bba3925SPatrick McHardy 
314*4bba3925SPatrick McHardy 		PSCHED_GET_TIME(now);
315*4bba3925SPatrick McHardy 
316*4bba3925SPatrick McHardy 		toks = PSCHED_TDIFF_SAFE(now, p->t_c, p->burst);
317*4bba3925SPatrick McHardy 
318*4bba3925SPatrick McHardy 		if (p->P_tab) {
319*4bba3925SPatrick McHardy 			ptoks = toks + p->ptoks;
320*4bba3925SPatrick McHardy 			if (ptoks > (long)L2T_P(p, p->mtu))
321*4bba3925SPatrick McHardy 				ptoks = (long)L2T_P(p, p->mtu);
322*4bba3925SPatrick McHardy 			ptoks -= L2T_P(p, skb->len);
323*4bba3925SPatrick McHardy 		}
324*4bba3925SPatrick McHardy 		toks += p->toks;
325*4bba3925SPatrick McHardy 		if (toks > (long)p->burst)
326*4bba3925SPatrick McHardy 			toks = p->burst;
327*4bba3925SPatrick McHardy 		toks -= L2T(p, skb->len);
328*4bba3925SPatrick McHardy 
329*4bba3925SPatrick McHardy 		if ((toks|ptoks) >= 0) {
330*4bba3925SPatrick McHardy 			p->t_c = now;
331*4bba3925SPatrick McHardy 			p->toks = toks;
332*4bba3925SPatrick McHardy 			p->ptoks = ptoks;
333*4bba3925SPatrick McHardy 			spin_unlock(&p->lock);
334*4bba3925SPatrick McHardy 			return p->result;
335*4bba3925SPatrick McHardy 		}
336*4bba3925SPatrick McHardy 	}
337*4bba3925SPatrick McHardy 
338*4bba3925SPatrick McHardy 	p->qstats.overlimits++;
339*4bba3925SPatrick McHardy 	spin_unlock(&p->lock);
340*4bba3925SPatrick McHardy 	return p->action;
341*4bba3925SPatrick McHardy }
342*4bba3925SPatrick McHardy 
343*4bba3925SPatrick McHardy static int
344*4bba3925SPatrick McHardy tcf_act_police_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
345*4bba3925SPatrick McHardy {
346*4bba3925SPatrick McHardy 	unsigned char	 *b = skb->tail;
347*4bba3925SPatrick McHardy 	struct tc_police opt;
348*4bba3925SPatrick McHardy 	struct tcf_police *p = PRIV(a);
349*4bba3925SPatrick McHardy 
350*4bba3925SPatrick McHardy 	opt.index = p->index;
351*4bba3925SPatrick McHardy 	opt.action = p->action;
352*4bba3925SPatrick McHardy 	opt.mtu = p->mtu;
353*4bba3925SPatrick McHardy 	opt.burst = p->burst;
354*4bba3925SPatrick McHardy 	opt.refcnt = p->refcnt - ref;
355*4bba3925SPatrick McHardy 	opt.bindcnt = p->bindcnt - bind;
356*4bba3925SPatrick McHardy 	if (p->R_tab)
357*4bba3925SPatrick McHardy 		opt.rate = p->R_tab->rate;
358*4bba3925SPatrick McHardy 	else
359*4bba3925SPatrick McHardy 		memset(&opt.rate, 0, sizeof(opt.rate));
360*4bba3925SPatrick McHardy 	if (p->P_tab)
361*4bba3925SPatrick McHardy 		opt.peakrate = p->P_tab->rate;
362*4bba3925SPatrick McHardy 	else
363*4bba3925SPatrick McHardy 		memset(&opt.peakrate, 0, sizeof(opt.peakrate));
364*4bba3925SPatrick McHardy 	RTA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt);
365*4bba3925SPatrick McHardy 	if (p->result)
366*4bba3925SPatrick McHardy 		RTA_PUT(skb, TCA_POLICE_RESULT, sizeof(int), &p->result);
367*4bba3925SPatrick McHardy #ifdef CONFIG_NET_ESTIMATOR
368*4bba3925SPatrick McHardy 	if (p->ewma_rate)
369*4bba3925SPatrick McHardy 		RTA_PUT(skb, TCA_POLICE_AVRATE, 4, &p->ewma_rate);
370*4bba3925SPatrick McHardy #endif
371*4bba3925SPatrick McHardy 	return skb->len;
372*4bba3925SPatrick McHardy 
373*4bba3925SPatrick McHardy rtattr_failure:
374*4bba3925SPatrick McHardy 	skb_trim(skb, b - skb->data);
375*4bba3925SPatrick McHardy 	return -1;
376*4bba3925SPatrick McHardy }
377*4bba3925SPatrick McHardy 
378*4bba3925SPatrick McHardy MODULE_AUTHOR("Alexey Kuznetsov");
379*4bba3925SPatrick McHardy MODULE_DESCRIPTION("Policing actions");
380*4bba3925SPatrick McHardy MODULE_LICENSE("GPL");
381*4bba3925SPatrick McHardy 
382*4bba3925SPatrick McHardy static struct tc_action_ops act_police_ops = {
383*4bba3925SPatrick McHardy 	.kind		=	"police",
384*4bba3925SPatrick McHardy 	.type		=	TCA_ID_POLICE,
385*4bba3925SPatrick McHardy 	.capab		=	TCA_CAP_NONE,
386*4bba3925SPatrick McHardy 	.owner		=	THIS_MODULE,
387*4bba3925SPatrick McHardy 	.act		=	tcf_act_police,
388*4bba3925SPatrick McHardy 	.dump		=	tcf_act_police_dump,
389*4bba3925SPatrick McHardy 	.cleanup	=	tcf_act_police_cleanup,
390*4bba3925SPatrick McHardy 	.lookup		=	tcf_hash_search,
391*4bba3925SPatrick McHardy 	.init		=	tcf_act_police_locate,
392*4bba3925SPatrick McHardy 	.walk		=	tcf_generic_walker
393*4bba3925SPatrick McHardy };
394*4bba3925SPatrick McHardy 
395*4bba3925SPatrick McHardy static int __init
396*4bba3925SPatrick McHardy police_init_module(void)
397*4bba3925SPatrick McHardy {
398*4bba3925SPatrick McHardy 	return tcf_register_action(&act_police_ops);
399*4bba3925SPatrick McHardy }
400*4bba3925SPatrick McHardy 
401*4bba3925SPatrick McHardy static void __exit
402*4bba3925SPatrick McHardy police_cleanup_module(void)
403*4bba3925SPatrick McHardy {
404*4bba3925SPatrick McHardy 	tcf_unregister_action(&act_police_ops);
405*4bba3925SPatrick McHardy }
406*4bba3925SPatrick McHardy 
407*4bba3925SPatrick McHardy module_init(police_init_module);
408*4bba3925SPatrick McHardy module_exit(police_cleanup_module);
409*4bba3925SPatrick McHardy 
410*4bba3925SPatrick McHardy #else /* CONFIG_NET_CLS_ACT */
411*4bba3925SPatrick McHardy 
412*4bba3925SPatrick McHardy struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est)
413*4bba3925SPatrick McHardy {
414*4bba3925SPatrick McHardy 	unsigned h;
415*4bba3925SPatrick McHardy 	struct tcf_police *p;
416*4bba3925SPatrick McHardy 	struct rtattr *tb[TCA_POLICE_MAX];
417*4bba3925SPatrick McHardy 	struct tc_police *parm;
418*4bba3925SPatrick McHardy 
419*4bba3925SPatrick McHardy 	if (rtattr_parse_nested(tb, TCA_POLICE_MAX, rta) < 0)
420*4bba3925SPatrick McHardy 		return NULL;
421*4bba3925SPatrick McHardy 
422*4bba3925SPatrick McHardy 	if (tb[TCA_POLICE_TBF-1] == NULL ||
423*4bba3925SPatrick McHardy 	    RTA_PAYLOAD(tb[TCA_POLICE_TBF-1]) != sizeof(*parm))
424*4bba3925SPatrick McHardy 		return NULL;
425*4bba3925SPatrick McHardy 
426*4bba3925SPatrick McHardy 	parm = RTA_DATA(tb[TCA_POLICE_TBF-1]);
427*4bba3925SPatrick McHardy 
428*4bba3925SPatrick McHardy 	if (parm->index && (p = tcf_police_lookup(parm->index)) != NULL) {
429*4bba3925SPatrick McHardy 		p->refcnt++;
430*4bba3925SPatrick McHardy 		return p;
431*4bba3925SPatrick McHardy 	}
432*4bba3925SPatrick McHardy 
433*4bba3925SPatrick McHardy 	p = kmalloc(sizeof(*p), GFP_KERNEL);
434*4bba3925SPatrick McHardy 	if (p == NULL)
435*4bba3925SPatrick McHardy 		return NULL;
436*4bba3925SPatrick McHardy 
437*4bba3925SPatrick McHardy 	memset(p, 0, sizeof(*p));
438*4bba3925SPatrick McHardy 	p->refcnt = 1;
439*4bba3925SPatrick McHardy 	spin_lock_init(&p->lock);
440*4bba3925SPatrick McHardy 	p->stats_lock = &p->lock;
441*4bba3925SPatrick McHardy 	if (parm->rate.rate) {
442*4bba3925SPatrick McHardy 		p->R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1]);
443*4bba3925SPatrick McHardy 		if (p->R_tab == NULL)
444*4bba3925SPatrick McHardy 			goto failure;
445*4bba3925SPatrick McHardy 		if (parm->peakrate.rate) {
446*4bba3925SPatrick McHardy 			p->P_tab = qdisc_get_rtab(&parm->peakrate,
447*4bba3925SPatrick McHardy 			                          tb[TCA_POLICE_PEAKRATE-1]);
448*4bba3925SPatrick McHardy 			if (p->P_tab == NULL)
449*4bba3925SPatrick McHardy 				goto failure;
450*4bba3925SPatrick McHardy 		}
451*4bba3925SPatrick McHardy 	}
452*4bba3925SPatrick McHardy 	if (tb[TCA_POLICE_RESULT-1]) {
453*4bba3925SPatrick McHardy 		if (RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32))
454*4bba3925SPatrick McHardy 			goto failure;
455*4bba3925SPatrick McHardy 		p->result = *(u32*)RTA_DATA(tb[TCA_POLICE_RESULT-1]);
456*4bba3925SPatrick McHardy 	}
457*4bba3925SPatrick McHardy #ifdef CONFIG_NET_ESTIMATOR
458*4bba3925SPatrick McHardy 	if (tb[TCA_POLICE_AVRATE-1]) {
459*4bba3925SPatrick McHardy 		if (RTA_PAYLOAD(tb[TCA_POLICE_AVRATE-1]) != sizeof(u32))
460*4bba3925SPatrick McHardy 			goto failure;
461*4bba3925SPatrick McHardy 		p->ewma_rate = *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]);
462*4bba3925SPatrick McHardy 	}
463*4bba3925SPatrick McHardy #endif
464*4bba3925SPatrick McHardy 	p->toks = p->burst = parm->burst;
465*4bba3925SPatrick McHardy 	p->mtu = parm->mtu;
466*4bba3925SPatrick McHardy 	if (p->mtu == 0) {
467*4bba3925SPatrick McHardy 		p->mtu = ~0;
468*4bba3925SPatrick McHardy 		if (p->R_tab)
469*4bba3925SPatrick McHardy 			p->mtu = 255<<p->R_tab->rate.cell_log;
470*4bba3925SPatrick McHardy 	}
471*4bba3925SPatrick McHardy 	if (p->P_tab)
472*4bba3925SPatrick McHardy 		p->ptoks = L2T_P(p, p->mtu);
473*4bba3925SPatrick McHardy 	PSCHED_GET_TIME(p->t_c);
474*4bba3925SPatrick McHardy 	p->index = parm->index ? : tcf_police_new_index();
475*4bba3925SPatrick McHardy 	p->action = parm->action;
476*4bba3925SPatrick McHardy #ifdef CONFIG_NET_ESTIMATOR
477*4bba3925SPatrick McHardy 	if (est)
478*4bba3925SPatrick McHardy 		gen_new_estimator(&p->bstats, &p->rate_est, p->stats_lock, est);
479*4bba3925SPatrick McHardy #endif
480*4bba3925SPatrick McHardy 	h = tcf_police_hash(p->index);
481*4bba3925SPatrick McHardy 	write_lock_bh(&police_lock);
482*4bba3925SPatrick McHardy 	p->next = tcf_police_ht[h];
483*4bba3925SPatrick McHardy 	tcf_police_ht[h] = p;
484*4bba3925SPatrick McHardy 	write_unlock_bh(&police_lock);
485*4bba3925SPatrick McHardy 	return p;
486*4bba3925SPatrick McHardy 
487*4bba3925SPatrick McHardy failure:
488*4bba3925SPatrick McHardy 	if (p->R_tab)
489*4bba3925SPatrick McHardy 		qdisc_put_rtab(p->R_tab);
490*4bba3925SPatrick McHardy 	kfree(p);
491*4bba3925SPatrick McHardy 	return NULL;
492*4bba3925SPatrick McHardy }
493*4bba3925SPatrick McHardy 
494*4bba3925SPatrick McHardy int tcf_police(struct sk_buff *skb, struct tcf_police *p)
495*4bba3925SPatrick McHardy {
496*4bba3925SPatrick McHardy 	psched_time_t now;
497*4bba3925SPatrick McHardy 	long toks;
498*4bba3925SPatrick McHardy 	long ptoks = 0;
499*4bba3925SPatrick McHardy 
500*4bba3925SPatrick McHardy 	spin_lock(&p->lock);
501*4bba3925SPatrick McHardy 
502*4bba3925SPatrick McHardy 	p->bstats.bytes += skb->len;
503*4bba3925SPatrick McHardy 	p->bstats.packets++;
504*4bba3925SPatrick McHardy 
505*4bba3925SPatrick McHardy #ifdef CONFIG_NET_ESTIMATOR
506*4bba3925SPatrick McHardy 	if (p->ewma_rate && p->rate_est.bps >= p->ewma_rate) {
507*4bba3925SPatrick McHardy 		p->qstats.overlimits++;
508*4bba3925SPatrick McHardy 		spin_unlock(&p->lock);
509*4bba3925SPatrick McHardy 		return p->action;
510*4bba3925SPatrick McHardy 	}
511*4bba3925SPatrick McHardy #endif
512*4bba3925SPatrick McHardy 
513*4bba3925SPatrick McHardy 	if (skb->len <= p->mtu) {
514*4bba3925SPatrick McHardy 		if (p->R_tab == NULL) {
515*4bba3925SPatrick McHardy 			spin_unlock(&p->lock);
516*4bba3925SPatrick McHardy 			return p->result;
517*4bba3925SPatrick McHardy 		}
518*4bba3925SPatrick McHardy 
519*4bba3925SPatrick McHardy 		PSCHED_GET_TIME(now);
520*4bba3925SPatrick McHardy 
521*4bba3925SPatrick McHardy 		toks = PSCHED_TDIFF_SAFE(now, p->t_c, p->burst);
522*4bba3925SPatrick McHardy 
523*4bba3925SPatrick McHardy 		if (p->P_tab) {
524*4bba3925SPatrick McHardy 			ptoks = toks + p->ptoks;
525*4bba3925SPatrick McHardy 			if (ptoks > (long)L2T_P(p, p->mtu))
526*4bba3925SPatrick McHardy 				ptoks = (long)L2T_P(p, p->mtu);
527*4bba3925SPatrick McHardy 			ptoks -= L2T_P(p, skb->len);
528*4bba3925SPatrick McHardy 		}
529*4bba3925SPatrick McHardy 		toks += p->toks;
530*4bba3925SPatrick McHardy 		if (toks > (long)p->burst)
531*4bba3925SPatrick McHardy 			toks = p->burst;
532*4bba3925SPatrick McHardy 		toks -= L2T(p, skb->len);
533*4bba3925SPatrick McHardy 
534*4bba3925SPatrick McHardy 		if ((toks|ptoks) >= 0) {
535*4bba3925SPatrick McHardy 			p->t_c = now;
536*4bba3925SPatrick McHardy 			p->toks = toks;
537*4bba3925SPatrick McHardy 			p->ptoks = ptoks;
538*4bba3925SPatrick McHardy 			spin_unlock(&p->lock);
539*4bba3925SPatrick McHardy 			return p->result;
540*4bba3925SPatrick McHardy 		}
541*4bba3925SPatrick McHardy 	}
542*4bba3925SPatrick McHardy 
543*4bba3925SPatrick McHardy 	p->qstats.overlimits++;
544*4bba3925SPatrick McHardy 	spin_unlock(&p->lock);
545*4bba3925SPatrick McHardy 	return p->action;
546*4bba3925SPatrick McHardy }
547*4bba3925SPatrick McHardy EXPORT_SYMBOL(tcf_police);
548*4bba3925SPatrick McHardy 
549*4bba3925SPatrick McHardy int tcf_police_dump(struct sk_buff *skb, struct tcf_police *p)
550*4bba3925SPatrick McHardy {
551*4bba3925SPatrick McHardy 	unsigned char	 *b = skb->tail;
552*4bba3925SPatrick McHardy 	struct tc_police opt;
553*4bba3925SPatrick McHardy 
554*4bba3925SPatrick McHardy 	opt.index = p->index;
555*4bba3925SPatrick McHardy 	opt.action = p->action;
556*4bba3925SPatrick McHardy 	opt.mtu = p->mtu;
557*4bba3925SPatrick McHardy 	opt.burst = p->burst;
558*4bba3925SPatrick McHardy 	if (p->R_tab)
559*4bba3925SPatrick McHardy 		opt.rate = p->R_tab->rate;
560*4bba3925SPatrick McHardy 	else
561*4bba3925SPatrick McHardy 		memset(&opt.rate, 0, sizeof(opt.rate));
562*4bba3925SPatrick McHardy 	if (p->P_tab)
563*4bba3925SPatrick McHardy 		opt.peakrate = p->P_tab->rate;
564*4bba3925SPatrick McHardy 	else
565*4bba3925SPatrick McHardy 		memset(&opt.peakrate, 0, sizeof(opt.peakrate));
566*4bba3925SPatrick McHardy 	RTA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt);
567*4bba3925SPatrick McHardy 	if (p->result)
568*4bba3925SPatrick McHardy 		RTA_PUT(skb, TCA_POLICE_RESULT, sizeof(int), &p->result);
569*4bba3925SPatrick McHardy #ifdef CONFIG_NET_ESTIMATOR
570*4bba3925SPatrick McHardy 	if (p->ewma_rate)
571*4bba3925SPatrick McHardy 		RTA_PUT(skb, TCA_POLICE_AVRATE, 4, &p->ewma_rate);
572*4bba3925SPatrick McHardy #endif
573*4bba3925SPatrick McHardy 	return skb->len;
574*4bba3925SPatrick McHardy 
575*4bba3925SPatrick McHardy rtattr_failure:
576*4bba3925SPatrick McHardy 	skb_trim(skb, b - skb->data);
577*4bba3925SPatrick McHardy 	return -1;
578*4bba3925SPatrick McHardy }
579*4bba3925SPatrick McHardy 
580*4bba3925SPatrick McHardy int tcf_police_dump_stats(struct sk_buff *skb, struct tcf_police *p)
581*4bba3925SPatrick McHardy {
582*4bba3925SPatrick McHardy 	struct gnet_dump d;
583*4bba3925SPatrick McHardy 
584*4bba3925SPatrick McHardy 	if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS,
585*4bba3925SPatrick McHardy 			TCA_XSTATS, p->stats_lock, &d) < 0)
586*4bba3925SPatrick McHardy 		goto errout;
587*4bba3925SPatrick McHardy 
588*4bba3925SPatrick McHardy 	if (gnet_stats_copy_basic(&d, &p->bstats) < 0 ||
589*4bba3925SPatrick McHardy #ifdef CONFIG_NET_ESTIMATOR
590*4bba3925SPatrick McHardy 	    gnet_stats_copy_rate_est(&d, &p->rate_est) < 0 ||
591*4bba3925SPatrick McHardy #endif
592*4bba3925SPatrick McHardy 	    gnet_stats_copy_queue(&d, &p->qstats) < 0)
593*4bba3925SPatrick McHardy 		goto errout;
594*4bba3925SPatrick McHardy 
595*4bba3925SPatrick McHardy 	if (gnet_stats_finish_copy(&d) < 0)
596*4bba3925SPatrick McHardy 		goto errout;
597*4bba3925SPatrick McHardy 
598*4bba3925SPatrick McHardy 	return 0;
599*4bba3925SPatrick McHardy 
600*4bba3925SPatrick McHardy errout:
601*4bba3925SPatrick McHardy 	return -1;
602*4bba3925SPatrick McHardy }
603*4bba3925SPatrick McHardy 
604*4bba3925SPatrick McHardy #endif /* CONFIG_NET_CLS_ACT */
605