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

Subversion Repositories test_project

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * net/sched/pedit.c    Generic packet editor
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:     Jamal Hadi Salim (2002-4)
10
 */
11
 
12
#include <linux/types.h>
13
#include <linux/kernel.h>
14
#include <linux/string.h>
15
#include <linux/errno.h>
16
#include <linux/skbuff.h>
17
#include <linux/rtnetlink.h>
18
#include <linux/module.h>
19
#include <linux/init.h>
20
#include <net/netlink.h>
21
#include <net/pkt_sched.h>
22
#include <linux/tc_act/tc_pedit.h>
23
#include <net/tc_act/tc_pedit.h>
24
 
25
#define PEDIT_TAB_MASK  15
26
static struct tcf_common *tcf_pedit_ht[PEDIT_TAB_MASK + 1];
27
static u32 pedit_idx_gen;
28
static DEFINE_RWLOCK(pedit_lock);
29
 
30
static struct tcf_hashinfo pedit_hash_info = {
31
        .htab   =       tcf_pedit_ht,
32
        .hmask  =       PEDIT_TAB_MASK,
33
        .lock   =       &pedit_lock,
34
};
35
 
36
static int tcf_pedit_init(struct rtattr *rta, struct rtattr *est,
37
                          struct tc_action *a, int ovr, int bind)
38
{
39
        struct rtattr *tb[TCA_PEDIT_MAX];
40
        struct tc_pedit *parm;
41
        int ret = 0;
42
        struct tcf_pedit *p;
43
        struct tcf_common *pc;
44
        struct tc_pedit_key *keys = NULL;
45
        int ksize;
46
 
47
        if (rta == NULL || rtattr_parse_nested(tb, TCA_PEDIT_MAX, rta) < 0)
48
                return -EINVAL;
49
 
50
        if (tb[TCA_PEDIT_PARMS - 1] == NULL ||
51
            RTA_PAYLOAD(tb[TCA_PEDIT_PARMS-1]) < sizeof(*parm))
52
                return -EINVAL;
53
        parm = RTA_DATA(tb[TCA_PEDIT_PARMS-1]);
54
        ksize = parm->nkeys * sizeof(struct tc_pedit_key);
55
        if (RTA_PAYLOAD(tb[TCA_PEDIT_PARMS-1]) < sizeof(*parm) + ksize)
56
                return -EINVAL;
57
 
58
        pc = tcf_hash_check(parm->index, a, bind, &pedit_hash_info);
59
        if (!pc) {
60
                if (!parm->nkeys)
61
                        return -EINVAL;
62
                pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind,
63
                                     &pedit_idx_gen, &pedit_hash_info);
64
                if (unlikely(!pc))
65
                        return -ENOMEM;
66
                p = to_pedit(pc);
67
                keys = kmalloc(ksize, GFP_KERNEL);
68
                if (keys == NULL) {
69
                        kfree(pc);
70
                        return -ENOMEM;
71
                }
72
                ret = ACT_P_CREATED;
73
        } else {
74
                p = to_pedit(pc);
75
                if (!ovr) {
76
                        tcf_hash_release(pc, bind, &pedit_hash_info);
77
                        return -EEXIST;
78
                }
79
                if (p->tcfp_nkeys && p->tcfp_nkeys != parm->nkeys) {
80
                        keys = kmalloc(ksize, GFP_KERNEL);
81
                        if (keys == NULL)
82
                                return -ENOMEM;
83
                }
84
        }
85
 
86
        spin_lock_bh(&p->tcf_lock);
87
        p->tcfp_flags = parm->flags;
88
        p->tcf_action = parm->action;
89
        if (keys) {
90
                kfree(p->tcfp_keys);
91
                p->tcfp_keys = keys;
92
                p->tcfp_nkeys = parm->nkeys;
93
        }
94
        memcpy(p->tcfp_keys, parm->keys, ksize);
95
        spin_unlock_bh(&p->tcf_lock);
96
        if (ret == ACT_P_CREATED)
97
                tcf_hash_insert(pc, &pedit_hash_info);
98
        return ret;
99
}
100
 
101
static int tcf_pedit_cleanup(struct tc_action *a, int bind)
102
{
103
        struct tcf_pedit *p = a->priv;
104
 
105
        if (p) {
106
                struct tc_pedit_key *keys = p->tcfp_keys;
107
                if (tcf_hash_release(&p->common, bind, &pedit_hash_info)) {
108
                        kfree(keys);
109
                        return 1;
110
                }
111
        }
112
        return 0;
113
}
114
 
115
static int tcf_pedit(struct sk_buff *skb, struct tc_action *a,
116
                     struct tcf_result *res)
117
{
118
        struct tcf_pedit *p = a->priv;
119
        int i, munged = 0;
120
        u8 *pptr;
121
 
122
        if (!(skb->tc_verd & TC_OK2MUNGE)) {
123
                /* should we set skb->cloned? */
124
                if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
125
                        return p->tcf_action;
126
                }
127
        }
128
 
129
        pptr = skb_network_header(skb);
130
 
131
        spin_lock(&p->tcf_lock);
132
 
133
        p->tcf_tm.lastuse = jiffies;
134
 
135
        if (p->tcfp_nkeys > 0) {
136
                struct tc_pedit_key *tkey = p->tcfp_keys;
137
 
138
                for (i = p->tcfp_nkeys; i > 0; i--, tkey++) {
139
                        u32 *ptr;
140
                        int offset = tkey->off;
141
 
142
                        if (tkey->offmask) {
143
                                if (skb->len > tkey->at) {
144
                                         char *j = pptr + tkey->at;
145
                                         offset += ((*j & tkey->offmask) >>
146
                                                   tkey->shift);
147
                                } else {
148
                                        goto bad;
149
                                }
150
                        }
151
 
152
                        if (offset % 4) {
153
                                printk("offset must be on 32 bit boundaries\n");
154
                                goto bad;
155
                        }
156
                        if (offset > 0 && offset > skb->len) {
157
                                printk("offset %d cant exceed pkt length %d\n",
158
                                       offset, skb->len);
159
                                goto bad;
160
                        }
161
 
162
                        ptr = (u32 *)(pptr+offset);
163
                        /* just do it, baby */
164
                        *ptr = ((*ptr & tkey->mask) ^ tkey->val);
165
                        munged++;
166
                }
167
 
168
                if (munged)
169
                        skb->tc_verd = SET_TC_MUNGED(skb->tc_verd);
170
                goto done;
171
        } else {
172
                printk("pedit BUG: index %d\n", p->tcf_index);
173
        }
174
 
175
bad:
176
        p->tcf_qstats.overlimits++;
177
done:
178
        p->tcf_bstats.bytes += skb->len;
179
        p->tcf_bstats.packets++;
180
        spin_unlock(&p->tcf_lock);
181
        return p->tcf_action;
182
}
183
 
184
static int tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a,
185
                          int bind, int ref)
186
{
187
        unsigned char *b = skb_tail_pointer(skb);
188
        struct tcf_pedit *p = a->priv;
189
        struct tc_pedit *opt;
190
        struct tcf_t t;
191
        int s;
192
 
193
        s = sizeof(*opt) + p->tcfp_nkeys * sizeof(struct tc_pedit_key);
194
 
195
        /* netlink spinlocks held above us - must use ATOMIC */
196
        opt = kzalloc(s, GFP_ATOMIC);
197
        if (unlikely(!opt))
198
                return -ENOBUFS;
199
 
200
        memcpy(opt->keys, p->tcfp_keys,
201
               p->tcfp_nkeys * sizeof(struct tc_pedit_key));
202
        opt->index = p->tcf_index;
203
        opt->nkeys = p->tcfp_nkeys;
204
        opt->flags = p->tcfp_flags;
205
        opt->action = p->tcf_action;
206
        opt->refcnt = p->tcf_refcnt - ref;
207
        opt->bindcnt = p->tcf_bindcnt - bind;
208
 
209
        RTA_PUT(skb, TCA_PEDIT_PARMS, s, opt);
210
        t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install);
211
        t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse);
212
        t.expires = jiffies_to_clock_t(p->tcf_tm.expires);
213
        RTA_PUT(skb, TCA_PEDIT_TM, sizeof(t), &t);
214
        kfree(opt);
215
        return skb->len;
216
 
217
rtattr_failure:
218
        nlmsg_trim(skb, b);
219
        kfree(opt);
220
        return -1;
221
}
222
 
223
static struct tc_action_ops act_pedit_ops = {
224
        .kind           =       "pedit",
225
        .hinfo          =       &pedit_hash_info,
226
        .type           =       TCA_ACT_PEDIT,
227
        .capab          =       TCA_CAP_NONE,
228
        .owner          =       THIS_MODULE,
229
        .act            =       tcf_pedit,
230
        .dump           =       tcf_pedit_dump,
231
        .cleanup        =       tcf_pedit_cleanup,
232
        .lookup         =       tcf_hash_search,
233
        .init           =       tcf_pedit_init,
234
        .walk           =       tcf_generic_walker
235
};
236
 
237
MODULE_AUTHOR("Jamal Hadi Salim(2002-4)");
238
MODULE_DESCRIPTION("Generic Packet Editor actions");
239
MODULE_LICENSE("GPL");
240
 
241
static int __init pedit_init_module(void)
242
{
243
        return tcf_register_action(&act_pedit_ops);
244
}
245
 
246
static void __exit pedit_cleanup_module(void)
247
{
248
        tcf_unregister_action(&act_pedit_ops);
249
}
250
 
251
module_init(pedit_init_module);
252
module_exit(pedit_cleanup_module);
253
 

powered by: WebSVN 2.1.0

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