OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [net/] [sched/] [act_police.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
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);

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.