Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/sched/act_police.c
15109 views
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, <[email protected]>
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 <linux/slab.h>
22
#include <net/act_api.h>
23
#include <net/netlink.h>
24
25
#define L2T(p, L) qdisc_l2t((p)->tcfp_R_tab, L)
26
#define L2T_P(p, L) qdisc_l2t((p)->tcfp_P_tab, L)
27
28
#define POL_TAB_MASK 15
29
static struct tcf_common *tcf_police_ht[POL_TAB_MASK + 1];
30
static u32 police_idx_gen;
31
static DEFINE_RWLOCK(police_lock);
32
33
static struct tcf_hashinfo police_hash_info = {
34
.htab = tcf_police_ht,
35
.hmask = POL_TAB_MASK,
36
.lock = &police_lock,
37
};
38
39
/* old policer structure from before tc actions */
40
struct tc_police_compat {
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 nlattr *nest;
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
nest = nla_nest_start(skb, a->order);
73
if (nest == NULL)
74
goto nla_put_failure;
75
if (type == RTM_DELACTION)
76
err = tcf_action_dump_1(skb, a, 0, 1);
77
else
78
err = tcf_action_dump_1(skb, a, 0, 0);
79
if (err < 0) {
80
index--;
81
nla_nest_cancel(skb, nest);
82
goto done;
83
}
84
nla_nest_end(skb, nest);
85
n_i++;
86
}
87
}
88
done:
89
read_unlock_bh(&police_lock);
90
if (n_i)
91
cb->args[0] += n_i;
92
return n_i;
93
94
nla_put_failure:
95
nla_nest_cancel(skb, nest);
96
goto done;
97
}
98
99
static void tcf_police_destroy(struct tcf_police *p)
100
{
101
unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK);
102
struct tcf_common **p1p;
103
104
for (p1p = &tcf_police_ht[h]; *p1p; p1p = &(*p1p)->tcfc_next) {
105
if (*p1p == &p->common) {
106
write_lock_bh(&police_lock);
107
*p1p = p->tcf_next;
108
write_unlock_bh(&police_lock);
109
gen_kill_estimator(&p->tcf_bstats,
110
&p->tcf_rate_est);
111
if (p->tcfp_R_tab)
112
qdisc_put_rtab(p->tcfp_R_tab);
113
if (p->tcfp_P_tab)
114
qdisc_put_rtab(p->tcfp_P_tab);
115
/*
116
* gen_estimator est_timer() might access p->tcf_lock
117
* or bstats, wait a RCU grace period before freeing p
118
*/
119
kfree_rcu(p, tcf_rcu);
120
return;
121
}
122
}
123
WARN_ON(1);
124
}
125
126
static const struct nla_policy police_policy[TCA_POLICE_MAX + 1] = {
127
[TCA_POLICE_RATE] = { .len = TC_RTAB_SIZE },
128
[TCA_POLICE_PEAKRATE] = { .len = TC_RTAB_SIZE },
129
[TCA_POLICE_AVRATE] = { .type = NLA_U32 },
130
[TCA_POLICE_RESULT] = { .type = NLA_U32 },
131
};
132
133
static int tcf_act_police_locate(struct nlattr *nla, struct nlattr *est,
134
struct tc_action *a, int ovr, int bind)
135
{
136
unsigned int h;
137
int ret = 0, err;
138
struct nlattr *tb[TCA_POLICE_MAX + 1];
139
struct tc_police *parm;
140
struct tcf_police *police;
141
struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL;
142
int size;
143
144
if (nla == NULL)
145
return -EINVAL;
146
147
err = nla_parse_nested(tb, TCA_POLICE_MAX, nla, police_policy);
148
if (err < 0)
149
return err;
150
151
if (tb[TCA_POLICE_TBF] == NULL)
152
return -EINVAL;
153
size = nla_len(tb[TCA_POLICE_TBF]);
154
if (size != sizeof(*parm) && size != sizeof(struct tc_police_compat))
155
return -EINVAL;
156
parm = nla_data(tb[TCA_POLICE_TBF]);
157
158
if (parm->index) {
159
struct tcf_common *pc;
160
161
pc = tcf_hash_lookup(parm->index, &police_hash_info);
162
if (pc != NULL) {
163
a->priv = pc;
164
police = to_police(pc);
165
if (bind) {
166
police->tcf_bindcnt += 1;
167
police->tcf_refcnt += 1;
168
}
169
if (ovr)
170
goto override;
171
return ret;
172
}
173
}
174
175
police = kzalloc(sizeof(*police), GFP_KERNEL);
176
if (police == NULL)
177
return -ENOMEM;
178
ret = ACT_P_CREATED;
179
police->tcf_refcnt = 1;
180
spin_lock_init(&police->tcf_lock);
181
if (bind)
182
police->tcf_bindcnt = 1;
183
override:
184
if (parm->rate.rate) {
185
err = -ENOMEM;
186
R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE]);
187
if (R_tab == NULL)
188
goto failure;
189
190
if (parm->peakrate.rate) {
191
P_tab = qdisc_get_rtab(&parm->peakrate,
192
tb[TCA_POLICE_PEAKRATE]);
193
if (P_tab == NULL)
194
goto failure;
195
}
196
}
197
198
spin_lock_bh(&police->tcf_lock);
199
if (est) {
200
err = gen_replace_estimator(&police->tcf_bstats,
201
&police->tcf_rate_est,
202
&police->tcf_lock, est);
203
if (err)
204
goto failure_unlock;
205
} else if (tb[TCA_POLICE_AVRATE] &&
206
(ret == ACT_P_CREATED ||
207
!gen_estimator_active(&police->tcf_bstats,
208
&police->tcf_rate_est))) {
209
err = -EINVAL;
210
goto failure_unlock;
211
}
212
213
/* No failure allowed after this point */
214
if (R_tab != NULL) {
215
qdisc_put_rtab(police->tcfp_R_tab);
216
police->tcfp_R_tab = R_tab;
217
}
218
if (P_tab != NULL) {
219
qdisc_put_rtab(police->tcfp_P_tab);
220
police->tcfp_P_tab = P_tab;
221
}
222
223
if (tb[TCA_POLICE_RESULT])
224
police->tcfp_result = nla_get_u32(tb[TCA_POLICE_RESULT]);
225
police->tcfp_toks = police->tcfp_burst = parm->burst;
226
police->tcfp_mtu = parm->mtu;
227
if (police->tcfp_mtu == 0) {
228
police->tcfp_mtu = ~0;
229
if (police->tcfp_R_tab)
230
police->tcfp_mtu = 255<<police->tcfp_R_tab->rate.cell_log;
231
}
232
if (police->tcfp_P_tab)
233
police->tcfp_ptoks = L2T_P(police, police->tcfp_mtu);
234
police->tcf_action = parm->action;
235
236
if (tb[TCA_POLICE_AVRATE])
237
police->tcfp_ewma_rate = nla_get_u32(tb[TCA_POLICE_AVRATE]);
238
239
spin_unlock_bh(&police->tcf_lock);
240
if (ret != ACT_P_CREATED)
241
return ret;
242
243
police->tcfp_t_c = psched_get_time();
244
police->tcf_index = parm->index ? parm->index :
245
tcf_hash_new_index(&police_idx_gen, &police_hash_info);
246
h = tcf_hash(police->tcf_index, POL_TAB_MASK);
247
write_lock_bh(&police_lock);
248
police->tcf_next = tcf_police_ht[h];
249
tcf_police_ht[h] = &police->common;
250
write_unlock_bh(&police_lock);
251
252
a->priv = police;
253
return ret;
254
255
failure_unlock:
256
spin_unlock_bh(&police->tcf_lock);
257
failure:
258
if (P_tab)
259
qdisc_put_rtab(P_tab);
260
if (R_tab)
261
qdisc_put_rtab(R_tab);
262
if (ret == ACT_P_CREATED)
263
kfree(police);
264
return err;
265
}
266
267
static int tcf_act_police_cleanup(struct tc_action *a, int bind)
268
{
269
struct tcf_police *p = a->priv;
270
int ret = 0;
271
272
if (p != NULL) {
273
if (bind)
274
p->tcf_bindcnt--;
275
276
p->tcf_refcnt--;
277
if (p->tcf_refcnt <= 0 && !p->tcf_bindcnt) {
278
tcf_police_destroy(p);
279
ret = 1;
280
}
281
}
282
return ret;
283
}
284
285
static int tcf_act_police(struct sk_buff *skb, struct tc_action *a,
286
struct tcf_result *res)
287
{
288
struct tcf_police *police = a->priv;
289
psched_time_t now;
290
long toks;
291
long ptoks = 0;
292
293
spin_lock(&police->tcf_lock);
294
295
bstats_update(&police->tcf_bstats, skb);
296
297
if (police->tcfp_ewma_rate &&
298
police->tcf_rate_est.bps >= police->tcfp_ewma_rate) {
299
police->tcf_qstats.overlimits++;
300
if (police->tcf_action == TC_ACT_SHOT)
301
police->tcf_qstats.drops++;
302
spin_unlock(&police->tcf_lock);
303
return police->tcf_action;
304
}
305
306
if (qdisc_pkt_len(skb) <= police->tcfp_mtu) {
307
if (police->tcfp_R_tab == NULL) {
308
spin_unlock(&police->tcf_lock);
309
return police->tcfp_result;
310
}
311
312
now = psched_get_time();
313
toks = psched_tdiff_bounded(now, police->tcfp_t_c,
314
police->tcfp_burst);
315
if (police->tcfp_P_tab) {
316
ptoks = toks + police->tcfp_ptoks;
317
if (ptoks > (long)L2T_P(police, police->tcfp_mtu))
318
ptoks = (long)L2T_P(police, police->tcfp_mtu);
319
ptoks -= L2T_P(police, qdisc_pkt_len(skb));
320
}
321
toks += police->tcfp_toks;
322
if (toks > (long)police->tcfp_burst)
323
toks = police->tcfp_burst;
324
toks -= L2T(police, qdisc_pkt_len(skb));
325
if ((toks|ptoks) >= 0) {
326
police->tcfp_t_c = now;
327
police->tcfp_toks = toks;
328
police->tcfp_ptoks = ptoks;
329
spin_unlock(&police->tcf_lock);
330
return police->tcfp_result;
331
}
332
}
333
334
police->tcf_qstats.overlimits++;
335
if (police->tcf_action == TC_ACT_SHOT)
336
police->tcf_qstats.drops++;
337
spin_unlock(&police->tcf_lock);
338
return police->tcf_action;
339
}
340
341
static int
342
tcf_act_police_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
343
{
344
unsigned char *b = skb_tail_pointer(skb);
345
struct tcf_police *police = a->priv;
346
struct tc_police opt = {
347
.index = police->tcf_index,
348
.action = police->tcf_action,
349
.mtu = police->tcfp_mtu,
350
.burst = police->tcfp_burst,
351
.refcnt = police->tcf_refcnt - ref,
352
.bindcnt = police->tcf_bindcnt - bind,
353
};
354
355
if (police->tcfp_R_tab)
356
opt.rate = police->tcfp_R_tab->rate;
357
if (police->tcfp_P_tab)
358
opt.peakrate = police->tcfp_P_tab->rate;
359
NLA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt);
360
if (police->tcfp_result)
361
NLA_PUT_U32(skb, TCA_POLICE_RESULT, police->tcfp_result);
362
if (police->tcfp_ewma_rate)
363
NLA_PUT_U32(skb, TCA_POLICE_AVRATE, police->tcfp_ewma_rate);
364
return skb->len;
365
366
nla_put_failure:
367
nlmsg_trim(skb, b);
368
return -1;
369
}
370
371
MODULE_AUTHOR("Alexey Kuznetsov");
372
MODULE_DESCRIPTION("Policing actions");
373
MODULE_LICENSE("GPL");
374
375
static struct tc_action_ops act_police_ops = {
376
.kind = "police",
377
.hinfo = &police_hash_info,
378
.type = TCA_ID_POLICE,
379
.capab = TCA_CAP_NONE,
380
.owner = THIS_MODULE,
381
.act = tcf_act_police,
382
.dump = tcf_act_police_dump,
383
.cleanup = tcf_act_police_cleanup,
384
.lookup = tcf_hash_search,
385
.init = tcf_act_police_locate,
386
.walk = tcf_act_police_walker
387
};
388
389
static int __init
390
police_init_module(void)
391
{
392
return tcf_register_action(&act_police_ops);
393
}
394
395
static void __exit
396
police_cleanup_module(void)
397
{
398
tcf_unregister_action(&act_police_ops);
399
}
400
401
module_init(police_init_module);
402
module_exit(police_cleanup_module);
403
404