Blame view

net/sched/act_police.c 11 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
  /*
0c6965dd3   Jiri Pirko   sched: fix act fi...
3
   * net/sched/act_police.c	Input police filter
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
   * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
   * 		J Hadi Salim (action changes)
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
  #include <linux/string.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
  #include <linux/errno.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
  #include <linux/skbuff.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
  #include <linux/rtnetlink.h>
  #include <linux/init.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
16
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
  #include <net/act_api.h>
dc5fc579b   Arnaldo Carvalho de Melo   [NETLINK]: Use nl...
18
  #include <net/netlink.h>
d6124d6ba   Davide Caratti   net/sched: act_po...
19
  #include <net/pkt_cls.h>
fa762da94   Pieter Jansen van Vuuren   net/sched: move p...
20
  #include <net/tc_act/tc_police.h>
1e9b3d533   Patrick McHardy   [NET_SCHED]: poli...
21

e9ce1cd3c   David S. Miller   [PKT_SCHED]: Kill...
22
  /* Each policer is serialized by its individual spinlock */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23

c7d03a00b   Alexey Dobriyan   netns: make struc...
24
  static unsigned int police_net_id;
a85a970af   WANG Cong   net_sched: move t...
25
  static struct tc_action_ops act_police_ops;
ddf97ccdd   WANG Cong   net_sched: add ne...
26

2ac063474   Jamal Hadi Salim   net: sched: act_p...
27
  static int tcf_police_walker(struct net *net, struct sk_buff *skb,
ddf97ccdd   WANG Cong   net_sched: add ne...
28
  				 struct netlink_callback *cb, int type,
417801055   Alexander Aring   net: sched: act: ...
29
30
  				 const struct tc_action_ops *ops,
  				 struct netlink_ext_ack *extack)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
  {
ddf97ccdd   WANG Cong   net_sched: add ne...
32
  	struct tc_action_net *tn = net_generic(net, police_net_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33

b36201455   Alexander Aring   net: sched: act: ...
34
  	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36

53b2bf3f8   Patrick McHardy   [NET_SCHED]: Use ...
37
38
39
40
41
  static const struct nla_policy police_policy[TCA_POLICE_MAX + 1] = {
  	[TCA_POLICE_RATE]	= { .len = TC_RTAB_SIZE },
  	[TCA_POLICE_PEAKRATE]	= { .len = TC_RTAB_SIZE },
  	[TCA_POLICE_AVRATE]	= { .type = NLA_U32 },
  	[TCA_POLICE_RESULT]	= { .type = NLA_U32 },
d1967e495   David Dai   net_sched: act_po...
42
43
  	[TCA_POLICE_RATE64]     = { .type = NLA_U64 },
  	[TCA_POLICE_PEAKRATE64] = { .type = NLA_U64 },
53b2bf3f8   Patrick McHardy   [NET_SCHED]: Use ...
44
  };
2ac063474   Jamal Hadi Salim   net: sched: act_p...
45
  static int tcf_police_init(struct net *net, struct nlattr *nla,
a85a970af   WANG Cong   net_sched: move t...
46
  			       struct nlattr *est, struct tc_action **a,
789871bb2   Vlad Buslov   net: sched: imple...
47
  			       int ovr, int bind, bool rtnl_held,
85d0966fa   Davide Caratti   net/sched: prepar...
48
  			       struct tcf_proto *tp,
589dad6d7   Alexander Aring   net: sched: act: ...
49
  			       struct netlink_ext_ack *extack)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  {
fd6d43386   Davide Caratti   net/sched: act_po...
51
  	int ret = 0, tcfp_result = TC_ACT_OK, err, size;
7ba699c60   Patrick McHardy   [NET_SCHED]: Conv...
52
  	struct nlattr *tb[TCA_POLICE_MAX + 1];
d6124d6ba   Davide Caratti   net/sched: act_po...
53
  	struct tcf_chain *goto_ch = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
  	struct tc_police *parm;
e9ce1cd3c   David S. Miller   [PKT_SCHED]: Kill...
55
  	struct tcf_police *police;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
  	struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL;
ddf97ccdd   WANG Cong   net_sched: add ne...
57
  	struct tc_action_net *tn = net_generic(net, police_net_id);
2d550dbad   Davide Caratti   net/sched: act_po...
58
  	struct tcf_police_params *new;
0852e4552   WANG Cong   net_sched: unify ...
59
  	bool exists = false;
7be8ef2cd   Dmytro Linkin   net: sched: use t...
60
  	u32 index;
d1967e495   David Dai   net_sched: act_po...
61
  	u64 rate64, prate64;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62

cee63723b   Patrick McHardy   [NET_SCHED]: Prop...
63
  	if (nla == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  		return -EINVAL;
8cb081746   Johannes Berg   netlink: make val...
65
66
  	err = nla_parse_nested_deprecated(tb, TCA_POLICE_MAX, nla,
  					  police_policy, NULL);
cee63723b   Patrick McHardy   [NET_SCHED]: Prop...
67
68
  	if (err < 0)
  		return err;
7ba699c60   Patrick McHardy   [NET_SCHED]: Conv...
69
  	if (tb[TCA_POLICE_TBF] == NULL)
1e9b3d533   Patrick McHardy   [NET_SCHED]: poli...
70
  		return -EINVAL;
7ba699c60   Patrick McHardy   [NET_SCHED]: Conv...
71
  	size = nla_len(tb[TCA_POLICE_TBF]);
1e9b3d533   Patrick McHardy   [NET_SCHED]: poli...
72
  	if (size != sizeof(*parm) && size != sizeof(struct tc_police_compat))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
  		return -EINVAL;
0852e4552   WANG Cong   net_sched: unify ...
74

7ba699c60   Patrick McHardy   [NET_SCHED]: Conv...
75
  	parm = nla_data(tb[TCA_POLICE_TBF]);
7be8ef2cd   Dmytro Linkin   net: sched: use t...
76
77
  	index = parm->index;
  	err = tcf_idr_check_alloc(tn, &index, a, bind);
0190c1d45   Vlad Buslov   net: sched: atomi...
78
79
80
  	if (err < 0)
  		return err;
  	exists = err;
0852e4552   WANG Cong   net_sched: unify ...
81
82
  	if (exists && bind)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83

0852e4552   WANG Cong   net_sched: unify ...
84
  	if (!exists) {
7be8ef2cd   Dmytro Linkin   net: sched: use t...
85
  		ret = tcf_idr_create(tn, index, NULL, a,
93be42f91   Davide Caratti   net/sched: act_po...
86
  				     &act_police_ops, bind, true);
0190c1d45   Vlad Buslov   net: sched: atomi...
87
  		if (ret) {
7be8ef2cd   Dmytro Linkin   net: sched: use t...
88
  			tcf_idr_cleanup(tn, index);
a03e6fe56   WANG Cong   act_police: fix a...
89
  			return ret;
0190c1d45   Vlad Buslov   net: sched: atomi...
90
  		}
a03e6fe56   WANG Cong   act_police: fix a...
91
  		ret = ACT_P_CREATED;
484afd1bd   Davide Caratti   net/sched: act_po...
92
  		spin_lock_init(&(to_police(*a)->tcfp_lock));
4e8ddd7f1   Vlad Buslov   net: sched: don't...
93
  	} else if (!ovr) {
65a206c01   Chris Mi   net/sched: Change...
94
  		tcf_idr_release(*a, bind);
4e8ddd7f1   Vlad Buslov   net: sched: don't...
95
  		return -EEXIST;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
  	}
d6124d6ba   Davide Caratti   net/sched: act_po...
97
98
99
  	err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
  	if (err < 0)
  		goto release_idr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100

a85a970af   WANG Cong   net_sched: move t...
101
  	police = to_police(*a);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
  	if (parm->rate.rate) {
  		err = -ENOMEM;
e9bc3fa28   Alexander Aring   net: sch: api: ad...
104
  		R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE], NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
  		if (R_tab == NULL)
  			goto failure;
c1b56878f   Stephen Hemminger   tc: policing requ...
107

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
  		if (parm->peakrate.rate) {
  			P_tab = qdisc_get_rtab(&parm->peakrate,
e9bc3fa28   Alexander Aring   net: sch: api: ad...
110
  					       tb[TCA_POLICE_PEAKRATE], NULL);
71bcb09a5   Stephen Hemminger   tc: check for err...
111
  			if (P_tab == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  				goto failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
  		}
  	}
71bcb09a5   Stephen Hemminger   tc: check for err...
115

71bcb09a5   Stephen Hemminger   tc: check for err...
116
  	if (est) {
93be42f91   Davide Caratti   net/sched: act_po...
117
118
  		err = gen_replace_estimator(&police->tcf_bstats,
  					    police->common.cpu_bstats,
71bcb09a5   Stephen Hemminger   tc: check for err...
119
  					    &police->tcf_rate_est,
edb09eb17   Eric Dumazet   net: sched: do no...
120
121
  					    &police->tcf_lock,
  					    NULL, est);
71bcb09a5   Stephen Hemminger   tc: check for err...
122
  		if (err)
74030603d   WANG Cong   net_sched: move t...
123
  			goto failure;
a883bf564   Jarek Poplawski   pkt_sched: act_po...
124
125
  	} else if (tb[TCA_POLICE_AVRATE] &&
  		   (ret == ACT_P_CREATED ||
1c0d32fde   Eric Dumazet   net_sched: gen_es...
126
  		    !gen_estimator_active(&police->tcf_rate_est))) {
a883bf564   Jarek Poplawski   pkt_sched: act_po...
127
  		err = -EINVAL;
74030603d   WANG Cong   net_sched: move t...
128
  		goto failure;
71bcb09a5   Stephen Hemminger   tc: check for err...
129
  	}
fd6d43386   Davide Caratti   net/sched: act_po...
130
131
132
133
134
135
136
137
138
  	if (tb[TCA_POLICE_RESULT]) {
  		tcfp_result = nla_get_u32(tb[TCA_POLICE_RESULT]);
  		if (TC_ACT_EXT_CMP(tcfp_result, TC_ACT_GOTO_CHAIN)) {
  			NL_SET_ERR_MSG(extack,
  				       "goto chain not allowed on fallback");
  			err = -EINVAL;
  			goto failure;
  		}
  	}
2d550dbad   Davide Caratti   net/sched: act_po...
139
140
141
142
143
  	new = kzalloc(sizeof(*new), GFP_KERNEL);
  	if (unlikely(!new)) {
  		err = -ENOMEM;
  		goto failure;
  	}
71bcb09a5   Stephen Hemminger   tc: check for err...
144
  	/* No failure allowed after this point */
fd6d43386   Davide Caratti   net/sched: act_po...
145
  	new->tcfp_result = tcfp_result;
2d550dbad   Davide Caratti   net/sched: act_po...
146
147
148
  	new->tcfp_mtu = parm->mtu;
  	if (!new->tcfp_mtu) {
  		new->tcfp_mtu = ~0;
c6d14ff11   Jiri Pirko   act_police: impro...
149
  		if (R_tab)
2d550dbad   Davide Caratti   net/sched: act_po...
150
  			new->tcfp_mtu = 255 << R_tab->rate.cell_log;
c6d14ff11   Jiri Pirko   act_police: impro...
151
152
  	}
  	if (R_tab) {
2d550dbad   Davide Caratti   net/sched: act_po...
153
  		new->rate_present = true;
d1967e495   David Dai   net_sched: act_po...
154
155
156
  		rate64 = tb[TCA_POLICE_RATE64] ?
  			 nla_get_u64(tb[TCA_POLICE_RATE64]) : 0;
  		psched_ratecfg_precompute(&new->rate, &R_tab->rate, rate64);
c6d14ff11   Jiri Pirko   act_police: impro...
157
158
  		qdisc_put_rtab(R_tab);
  	} else {
2d550dbad   Davide Caratti   net/sched: act_po...
159
  		new->rate_present = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
  	}
c6d14ff11   Jiri Pirko   act_police: impro...
161
  	if (P_tab) {
2d550dbad   Davide Caratti   net/sched: act_po...
162
  		new->peak_present = true;
d1967e495   David Dai   net_sched: act_po...
163
164
165
  		prate64 = tb[TCA_POLICE_PEAKRATE64] ?
  			  nla_get_u64(tb[TCA_POLICE_PEAKRATE64]) : 0;
  		psched_ratecfg_precompute(&new->peak, &P_tab->rate, prate64);
c6d14ff11   Jiri Pirko   act_police: impro...
166
167
  		qdisc_put_rtab(P_tab);
  	} else {
2d550dbad   Davide Caratti   net/sched: act_po...
168
  		new->peak_present = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
  	}
2d550dbad   Davide Caratti   net/sched: act_po...
170
  	new->tcfp_burst = PSCHED_TICKS2NS(parm->burst);
f2cbd4852   Davide Caratti   net/sched: act_po...
171
  	if (new->peak_present)
2d550dbad   Davide Caratti   net/sched: act_po...
172
173
  		new->tcfp_mtu_ptoks = (s64)psched_l2t_ns(&new->peak,
  							 new->tcfp_mtu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174

7ba699c60   Patrick McHardy   [NET_SCHED]: Conv...
175
  	if (tb[TCA_POLICE_AVRATE])
2d550dbad   Davide Caratti   net/sched: act_po...
176
  		new->tcfp_ewma_rate = nla_get_u32(tb[TCA_POLICE_AVRATE]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177

2d550dbad   Davide Caratti   net/sched: act_po...
178
  	spin_lock_bh(&police->tcf_lock);
f2cbd4852   Davide Caratti   net/sched: act_po...
179
180
181
182
183
184
  	spin_lock_bh(&police->tcfp_lock);
  	police->tcfp_t_c = ktime_get_ns();
  	police->tcfp_toks = new->tcfp_burst;
  	if (new->peak_present)
  		police->tcfp_ptoks = new->tcfp_mtu_ptoks;
  	spin_unlock_bh(&police->tcfp_lock);
d6124d6ba   Davide Caratti   net/sched: act_po...
185
  	goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
2d550dbad   Davide Caratti   net/sched: act_po...
186
187
188
  	rcu_swap_protected(police->params,
  			   new,
  			   lockdep_is_held(&police->tcf_lock));
e9ce1cd3c   David S. Miller   [PKT_SCHED]: Kill...
189
  	spin_unlock_bh(&police->tcf_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190

d6124d6ba   Davide Caratti   net/sched: act_po...
191
192
  	if (goto_ch)
  		tcf_chain_put_by_act(goto_ch);
2d550dbad   Davide Caratti   net/sched: act_po...
193
194
  	if (new)
  		kfree_rcu(new, rcu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195

2d550dbad   Davide Caratti   net/sched: act_po...
196
197
  	if (ret == ACT_P_CREATED)
  		tcf_idr_insert(tn, *a);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
  	return ret;
  
  failure:
3b69a4c9b   Yang Yingliang   act_police: remov...
201
202
  	qdisc_put_rtab(P_tab);
  	qdisc_put_rtab(R_tab);
d6124d6ba   Davide Caratti   net/sched: act_po...
203
204
205
  	if (goto_ch)
  		tcf_chain_put_by_act(goto_ch);
  release_idr:
4e8ddd7f1   Vlad Buslov   net: sched: don't...
206
  	tcf_idr_release(*a, bind);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
  	return err;
  }
2ac063474   Jamal Hadi Salim   net: sched: act_p...
209
  static int tcf_police_act(struct sk_buff *skb, const struct tc_action *a,
10297b993   YOSHIFUJI Hideaki   [NET] SCHED: Fix ...
210
  			  struct tcf_result *res)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
  {
a85a970af   WANG Cong   net_sched: move t...
212
  	struct tcf_police *police = to_police(a);
2d550dbad   Davide Caratti   net/sched: act_po...
213
  	struct tcf_police_params *p;
93be42f91   Davide Caratti   net/sched: act_po...
214
215
  	s64 now, toks, ptoks = 0;
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216

3d3ed1815   Jamal Hadi Salim   net sched actions...
217
  	tcf_lastuse_update(&police->tcf_tm);
93be42f91   Davide Caratti   net/sched: act_po...
218
  	bstats_cpu_update(this_cpu_ptr(police->common.cpu_bstats), skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219

2d550dbad   Davide Caratti   net/sched: act_po...
220
221
222
223
  	ret = READ_ONCE(police->tcf_action);
  	p = rcu_dereference_bh(police->params);
  
  	if (p->tcfp_ewma_rate) {
1c0d32fde   Eric Dumazet   net_sched: gen_es...
224
225
226
  		struct gnet_stats_rate_est64 sample;
  
  		if (!gen_estimator_read(&police->tcf_rate_est, &sample) ||
2d550dbad   Davide Caratti   net/sched: act_po...
227
  		    sample.bps >= p->tcfp_ewma_rate)
93be42f91   Davide Caratti   net/sched: act_po...
228
  			goto inc_overlimits;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230

2d550dbad   Davide Caratti   net/sched: act_po...
231
232
233
234
  	if (qdisc_pkt_len(skb) <= p->tcfp_mtu) {
  		if (!p->rate_present) {
  			ret = p->tcfp_result;
  			goto end;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
  		}
d2de875c6   Eric Dumazet   net: use ktime_ge...
236
  		now = ktime_get_ns();
f2cbd4852   Davide Caratti   net/sched: act_po...
237
238
  		spin_lock_bh(&police->tcfp_lock);
  		toks = min_t(s64, now - police->tcfp_t_c, p->tcfp_burst);
2d550dbad   Davide Caratti   net/sched: act_po...
239
  		if (p->peak_present) {
f2cbd4852   Davide Caratti   net/sched: act_po...
240
  			ptoks = toks + police->tcfp_ptoks;
2d550dbad   Davide Caratti   net/sched: act_po...
241
242
243
244
  			if (ptoks > p->tcfp_mtu_ptoks)
  				ptoks = p->tcfp_mtu_ptoks;
  			ptoks -= (s64)psched_l2t_ns(&p->peak,
  						    qdisc_pkt_len(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
  		}
f2cbd4852   Davide Caratti   net/sched: act_po...
246
  		toks += police->tcfp_toks;
2d550dbad   Davide Caratti   net/sched: act_po...
247
248
249
  		if (toks > p->tcfp_burst)
  			toks = p->tcfp_burst;
  		toks -= (s64)psched_l2t_ns(&p->rate, qdisc_pkt_len(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
  		if ((toks|ptoks) >= 0) {
f2cbd4852   Davide Caratti   net/sched: act_po...
251
252
253
254
  			police->tcfp_t_c = now;
  			police->tcfp_toks = toks;
  			police->tcfp_ptoks = ptoks;
  			spin_unlock_bh(&police->tcfp_lock);
2d550dbad   Davide Caratti   net/sched: act_po...
255
  			ret = p->tcfp_result;
93be42f91   Davide Caratti   net/sched: act_po...
256
  			goto inc_drops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
  		}
f2cbd4852   Davide Caratti   net/sched: act_po...
258
  		spin_unlock_bh(&police->tcfp_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
  	}
93be42f91   Davide Caratti   net/sched: act_po...
260
261
262
263
264
265
  
  inc_overlimits:
  	qstats_overlimit_inc(this_cpu_ptr(police->common.cpu_qstats));
  inc_drops:
  	if (ret == TC_ACT_SHOT)
  		qstats_drop_inc(this_cpu_ptr(police->common.cpu_qstats));
2d550dbad   Davide Caratti   net/sched: act_po...
266
  end:
93be42f91   Davide Caratti   net/sched: act_po...
267
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
  }
2d550dbad   Davide Caratti   net/sched: act_po...
269
270
271
272
273
274
275
276
277
  static void tcf_police_cleanup(struct tc_action *a)
  {
  	struct tcf_police *police = to_police(a);
  	struct tcf_police_params *p;
  
  	p = rcu_dereference_protected(police->params, 1);
  	if (p)
  		kfree_rcu(p, rcu);
  }
12f02b6b1   Pieter Jansen van Vuuren   net/sched: allow ...
278
279
280
281
282
283
284
285
286
287
288
289
290
  static void tcf_police_stats_update(struct tc_action *a,
  				    u64 bytes, u32 packets,
  				    u64 lastuse, bool hw)
  {
  	struct tcf_police *police = to_police(a);
  	struct tcf_t *tm = &police->tcf_tm;
  
  	_bstats_cpu_update(this_cpu_ptr(a->cpu_bstats), bytes, packets);
  	if (hw)
  		_bstats_cpu_update(this_cpu_ptr(a->cpu_bstats_hw),
  				   bytes, packets);
  	tm->lastuse = max_t(u64, tm->lastuse, lastuse);
  }
2ac063474   Jamal Hadi Salim   net: sched: act_p...
291
  static int tcf_police_dump(struct sk_buff *skb, struct tc_action *a,
5a7a5555a   Jamal Hadi Salim   net sched: stylis...
292
  			       int bind, int ref)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
  {
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
294
  	unsigned char *b = skb_tail_pointer(skb);
a85a970af   WANG Cong   net_sched: move t...
295
  	struct tcf_police *police = to_police(a);
2d550dbad   Davide Caratti   net/sched: act_po...
296
  	struct tcf_police_params *p;
0f04cfd09   Jeff Mahoney   net sched: fix ke...
297
298
  	struct tc_police opt = {
  		.index = police->tcf_index,
036bb4432   Vlad Buslov   net: sched: chang...
299
300
  		.refcnt = refcount_read(&police->tcf_refcnt) - ref,
  		.bindcnt = atomic_read(&police->tcf_bindcnt) - bind,
0f04cfd09   Jeff Mahoney   net sched: fix ke...
301
  	};
3d3ed1815   Jamal Hadi Salim   net sched actions...
302
  	struct tcf_t t;
0f04cfd09   Jeff Mahoney   net sched: fix ke...
303

e329bc427   Vlad Buslov   net: sched: act_p...
304
305
  	spin_lock_bh(&police->tcf_lock);
  	opt.action = police->tcf_action;
2d550dbad   Davide Caratti   net/sched: act_po...
306
307
308
309
  	p = rcu_dereference_protected(police->params,
  				      lockdep_is_held(&police->tcf_lock));
  	opt.mtu = p->tcfp_mtu;
  	opt.burst = PSCHED_NS2TICKS(p->tcfp_burst);
d1967e495   David Dai   net_sched: act_po...
310
  	if (p->rate_present) {
2d550dbad   Davide Caratti   net/sched: act_po...
311
  		psched_ratecfg_getrate(&opt.rate, &p->rate);
d1967e495   David Dai   net_sched: act_po...
312
313
314
315
316
317
318
  		if ((police->params->rate.rate_bytes_ps >= (1ULL << 32)) &&
  		    nla_put_u64_64bit(skb, TCA_POLICE_RATE64,
  				      police->params->rate.rate_bytes_ps,
  				      TCA_POLICE_PAD))
  			goto nla_put_failure;
  	}
  	if (p->peak_present) {
2d550dbad   Davide Caratti   net/sched: act_po...
319
  		psched_ratecfg_getrate(&opt.peakrate, &p->peak);
d1967e495   David Dai   net_sched: act_po...
320
321
322
323
324
325
  		if ((police->params->peak.rate_bytes_ps >= (1ULL << 32)) &&
  		    nla_put_u64_64bit(skb, TCA_POLICE_PEAKRATE64,
  				      police->params->peak.rate_bytes_ps,
  				      TCA_POLICE_PAD))
  			goto nla_put_failure;
  	}
1b34ec43c   David S. Miller   pkt_sched: Stop u...
326
327
  	if (nla_put(skb, TCA_POLICE_TBF, sizeof(opt), &opt))
  		goto nla_put_failure;
2d550dbad   Davide Caratti   net/sched: act_po...
328
329
  	if (p->tcfp_result &&
  	    nla_put_u32(skb, TCA_POLICE_RESULT, p->tcfp_result))
1b34ec43c   David S. Miller   pkt_sched: Stop u...
330
  		goto nla_put_failure;
2d550dbad   Davide Caratti   net/sched: act_po...
331
332
  	if (p->tcfp_ewma_rate &&
  	    nla_put_u32(skb, TCA_POLICE_AVRATE, p->tcfp_ewma_rate))
1b34ec43c   David S. Miller   pkt_sched: Stop u...
333
  		goto nla_put_failure;
3d3ed1815   Jamal Hadi Salim   net sched actions...
334
335
336
  
  	t.install = jiffies_to_clock_t(jiffies - police->tcf_tm.install);
  	t.lastuse = jiffies_to_clock_t(jiffies - police->tcf_tm.lastuse);
53eb440f4   Jamal Hadi Salim   net sched actions...
337
  	t.firstuse = jiffies_to_clock_t(jiffies - police->tcf_tm.firstuse);
3d3ed1815   Jamal Hadi Salim   net sched actions...
338
339
340
  	t.expires = jiffies_to_clock_t(police->tcf_tm.expires);
  	if (nla_put_64bit(skb, TCA_POLICE_TM, sizeof(t), &t, TCA_POLICE_PAD))
  		goto nla_put_failure;
e329bc427   Vlad Buslov   net: sched: act_p...
341
  	spin_unlock_bh(&police->tcf_lock);
3d3ed1815   Jamal Hadi Salim   net sched actions...
342

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
  	return skb->len;
7ba699c60   Patrick McHardy   [NET_SCHED]: Conv...
344
  nla_put_failure:
e329bc427   Vlad Buslov   net: sched: act_p...
345
  	spin_unlock_bh(&police->tcf_lock);
dc5fc579b   Arnaldo Carvalho de Melo   [NETLINK]: Use nl...
346
  	nlmsg_trim(skb, b);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
348
  	return -1;
  }
f061b48c1   Cong Wang   Revert "net: sche...
349
  static int tcf_police_search(struct net *net, struct tc_action **a, u32 index)
ddf97ccdd   WANG Cong   net_sched: add ne...
350
351
  {
  	struct tc_action_net *tn = net_generic(net, police_net_id);
65a206c01   Chris Mi   net/sched: Change...
352
  	return tcf_idr_search(tn, a, index);
ddf97ccdd   WANG Cong   net_sched: add ne...
353
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
355
356
357
358
359
  MODULE_AUTHOR("Alexey Kuznetsov");
  MODULE_DESCRIPTION("Policing actions");
  MODULE_LICENSE("GPL");
  
  static struct tc_action_ops act_police_ops = {
  	.kind		=	"police",
eddd2cf19   Eli Cohen   net: Change TCA_A...
360
  	.id		=	TCA_ID_POLICE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
  	.owner		=	THIS_MODULE,
12f02b6b1   Pieter Jansen van Vuuren   net/sched: allow ...
362
  	.stats_update	=	tcf_police_stats_update,
2ac063474   Jamal Hadi Salim   net: sched: act_p...
363
364
365
366
  	.act		=	tcf_police_act,
  	.dump		=	tcf_police_dump,
  	.init		=	tcf_police_init,
  	.walk		=	tcf_police_walker,
ddf97ccdd   WANG Cong   net_sched: add ne...
367
  	.lookup		=	tcf_police_search,
2d550dbad   Davide Caratti   net/sched: act_po...
368
  	.cleanup	=	tcf_police_cleanup,
a85a970af   WANG Cong   net_sched: move t...
369
  	.size		=	sizeof(struct tcf_police),
ddf97ccdd   WANG Cong   net_sched: add ne...
370
371
372
373
374
  };
  
  static __net_init int police_init_net(struct net *net)
  {
  	struct tc_action_net *tn = net_generic(net, police_net_id);
981471bd3   Cong Wang   net_sched: fix a ...
375
  	return tc_action_net_init(net, tn, &act_police_ops);
ddf97ccdd   WANG Cong   net_sched: add ne...
376
  }
039af9c66   Cong Wang   net_sched: switch...
377
  static void __net_exit police_exit_net(struct list_head *net_list)
ddf97ccdd   WANG Cong   net_sched: add ne...
378
  {
039af9c66   Cong Wang   net_sched: switch...
379
  	tc_action_net_exit(net_list, police_net_id);
ddf97ccdd   WANG Cong   net_sched: add ne...
380
381
382
383
  }
  
  static struct pernet_operations police_net_ops = {
  	.init = police_init_net,
039af9c66   Cong Wang   net_sched: switch...
384
  	.exit_batch = police_exit_net,
ddf97ccdd   WANG Cong   net_sched: add ne...
385
386
  	.id   = &police_net_id,
  	.size = sizeof(struct tc_action_net),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
  };
5a7a5555a   Jamal Hadi Salim   net sched: stylis...
388
  static int __init police_init_module(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
  {
ddf97ccdd   WANG Cong   net_sched: add ne...
390
  	return tcf_register_action(&act_police_ops, &police_net_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
  }
5a7a5555a   Jamal Hadi Salim   net sched: stylis...
392
  static void __exit police_cleanup_module(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
  {
ddf97ccdd   WANG Cong   net_sched: add ne...
394
  	tcf_unregister_action(&act_police_ops, &police_net_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
397
398
  }
  
  module_init(police_init_module);
  module_exit(police_cleanup_module);