Blame view
net/sched/act_api.c
23.8 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 12 |
/* * net/sched/act_api.c Packet action API. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Author: Jamal Hadi Salim * * */ |
1da177e4c Linux-2.6.12-rc2 |
13 14 |
#include <linux/types.h> #include <linux/kernel.h> |
1da177e4c Linux-2.6.12-rc2 |
15 |
#include <linux/string.h> |
1da177e4c Linux-2.6.12-rc2 |
16 |
#include <linux/errno.h> |
5a0e3ad6a include cleanup: ... |
17 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
18 |
#include <linux/skbuff.h> |
1da177e4c Linux-2.6.12-rc2 |
19 20 |
#include <linux/init.h> #include <linux/kmod.h> |
ab27cfb85 [NET_SCHED]: act_... |
21 |
#include <linux/err.h> |
3a9a231d9 net: Fix files ex... |
22 |
#include <linux/module.h> |
b854272b3 [NET]: Modify all... |
23 24 |
#include <net/net_namespace.h> #include <net/sock.h> |
1da177e4c Linux-2.6.12-rc2 |
25 26 |
#include <net/sch_generic.h> #include <net/act_api.h> |
dc5fc579b [NETLINK]: Use nl... |
27 |
#include <net/netlink.h> |
1da177e4c Linux-2.6.12-rc2 |
28 |
|
519c818e8 net: sched: add p... |
29 30 |
static void free_tcf(struct rcu_head *head) { |
ec0595cc4 net_sched: get ri... |
31 |
struct tc_action *p = container_of(head, struct tc_action, tcfa_rcu); |
519c818e8 net: sched: add p... |
32 33 34 35 36 |
free_percpu(p->cpu_bstats); free_percpu(p->cpu_qstats); kfree(p); } |
ec0595cc4 net_sched: get ri... |
37 |
static void tcf_hash_destroy(struct tcf_hashinfo *hinfo, struct tc_action *p) |
e9ce1cd3c [PKT_SCHED]: Kill... |
38 |
{ |
89819dc01 net_sched: conver... |
39 |
spin_lock_bh(&hinfo->lock); |
ec0595cc4 net_sched: get ri... |
40 |
hlist_del(&p->tcfa_head); |
89819dc01 net_sched: conver... |
41 |
spin_unlock_bh(&hinfo->lock); |
ec0595cc4 net_sched: get ri... |
42 43 |
gen_kill_estimator(&p->tcfa_bstats, &p->tcfa_rate_est); |
89819dc01 net_sched: conver... |
44 |
/* |
ec0595cc4 net_sched: get ri... |
45 |
* gen_estimator est_timer() might access p->tcfa_lock |
89819dc01 net_sched: conver... |
46 47 |
* or bstats, wait a RCU grace period before freeing p */ |
ec0595cc4 net_sched: get ri... |
48 |
call_rcu(&p->tcfa_rcu, free_tcf); |
e9ce1cd3c [PKT_SCHED]: Kill... |
49 |
} |
e9ce1cd3c [PKT_SCHED]: Kill... |
50 |
|
ec0595cc4 net_sched: get ri... |
51 |
int __tcf_hash_release(struct tc_action *p, bool bind, bool strict) |
e9ce1cd3c [PKT_SCHED]: Kill... |
52 53 54 55 56 |
{ int ret = 0; if (p) { if (bind) |
ec0595cc4 net_sched: get ri... |
57 58 |
p->tcfa_bindcnt--; else if (strict && p->tcfa_bindcnt > 0) |
55334a5db net_sched: act: r... |
59 |
return -EPERM; |
e9ce1cd3c [PKT_SCHED]: Kill... |
60 |
|
ec0595cc4 net_sched: get ri... |
61 62 63 64 |
p->tcfa_refcnt--; if (p->tcfa_bindcnt <= 0 && p->tcfa_refcnt <= 0) { if (p->ops->cleanup) p->ops->cleanup(p, bind); |
ec0595cc4 net_sched: get ri... |
65 |
tcf_hash_destroy(p->hinfo, p); |
1d4150c02 net_sched: prepar... |
66 |
ret = ACT_P_DELETED; |
e9ce1cd3c [PKT_SCHED]: Kill... |
67 68 |
} } |
28e6b67f0 net: sched: fix r... |
69 |
|
e9ce1cd3c [PKT_SCHED]: Kill... |
70 71 |
return ret; } |
28e6b67f0 net: sched: fix r... |
72 |
EXPORT_SYMBOL(__tcf_hash_release); |
e9ce1cd3c [PKT_SCHED]: Kill... |
73 |
|
ddf97ccdd net_sched: add ne... |
74 |
static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb, |
a85a970af net_sched: move t... |
75 |
struct netlink_callback *cb) |
e9ce1cd3c [PKT_SCHED]: Kill... |
76 |
{ |
cc7ec456f net_sched: cleanups |
77 |
int err = 0, index = -1, i = 0, s_i = 0, n_i = 0; |
4b3550ef5 [NET_SCHED]: Use ... |
78 |
struct nlattr *nest; |
e9ce1cd3c [PKT_SCHED]: Kill... |
79 |
|
89819dc01 net_sched: conver... |
80 |
spin_lock_bh(&hinfo->lock); |
e9ce1cd3c [PKT_SCHED]: Kill... |
81 82 83 84 |
s_i = cb->args[0]; for (i = 0; i < (hinfo->hmask + 1); i++) { |
a85a970af net_sched: move t... |
85 |
struct hlist_head *head; |
ec0595cc4 net_sched: get ri... |
86 |
struct tc_action *p; |
a85a970af net_sched: move t... |
87 |
|
89819dc01 net_sched: conver... |
88 |
head = &hinfo->htab[tcf_hash(i, hinfo->hmask)]; |
e9ce1cd3c [PKT_SCHED]: Kill... |
89 |
|
ec0595cc4 net_sched: get ri... |
90 |
hlist_for_each_entry_rcu(p, head, tcfa_head) { |
e9ce1cd3c [PKT_SCHED]: Kill... |
91 92 93 |
index++; if (index < s_i) continue; |
4b3550ef5 [NET_SCHED]: Use ... |
94 |
|
a85a970af net_sched: move t... |
95 |
nest = nla_nest_start(skb, n_i); |
4b3550ef5 [NET_SCHED]: Use ... |
96 97 |
if (nest == NULL) goto nla_put_failure; |
ec0595cc4 net_sched: get ri... |
98 |
err = tcf_action_dump_1(skb, p, 0, 0); |
e9ce1cd3c [PKT_SCHED]: Kill... |
99 100 |
if (err < 0) { index--; |
4b3550ef5 [NET_SCHED]: Use ... |
101 |
nlmsg_trim(skb, nest); |
e9ce1cd3c [PKT_SCHED]: Kill... |
102 103 |
goto done; } |
4b3550ef5 [NET_SCHED]: Use ... |
104 |
nla_nest_end(skb, nest); |
e9ce1cd3c [PKT_SCHED]: Kill... |
105 106 107 108 109 110 |
n_i++; if (n_i >= TCA_ACT_MAX_PRIO) goto done; } } done: |
89819dc01 net_sched: conver... |
111 |
spin_unlock_bh(&hinfo->lock); |
e9ce1cd3c [PKT_SCHED]: Kill... |
112 113 114 |
if (n_i) cb->args[0] += n_i; return n_i; |
7ba699c60 [NET_SCHED]: Conv... |
115 |
nla_put_failure: |
4b3550ef5 [NET_SCHED]: Use ... |
116 |
nla_nest_cancel(skb, nest); |
e9ce1cd3c [PKT_SCHED]: Kill... |
117 118 |
goto done; } |
ddf97ccdd net_sched: add ne... |
119 |
static int tcf_del_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb, |
a85a970af net_sched: move t... |
120 |
const struct tc_action_ops *ops) |
e9ce1cd3c [PKT_SCHED]: Kill... |
121 |
{ |
4b3550ef5 [NET_SCHED]: Use ... |
122 |
struct nlattr *nest; |
cc7ec456f net_sched: cleanups |
123 |
int i = 0, n_i = 0; |
55334a5db net_sched: act: r... |
124 |
int ret = -EINVAL; |
e9ce1cd3c [PKT_SCHED]: Kill... |
125 |
|
a85a970af net_sched: move t... |
126 |
nest = nla_nest_start(skb, 0); |
4b3550ef5 [NET_SCHED]: Use ... |
127 128 |
if (nest == NULL) goto nla_put_failure; |
a85a970af net_sched: move t... |
129 |
if (nla_put_string(skb, TCA_KIND, ops->kind)) |
1b34ec43c pkt_sched: Stop u... |
130 |
goto nla_put_failure; |
e9ce1cd3c [PKT_SCHED]: Kill... |
131 |
for (i = 0; i < (hinfo->hmask + 1); i++) { |
a85a970af net_sched: move t... |
132 133 |
struct hlist_head *head; struct hlist_node *n; |
ec0595cc4 net_sched: get ri... |
134 |
struct tc_action *p; |
a85a970af net_sched: move t... |
135 |
|
89819dc01 net_sched: conver... |
136 |
head = &hinfo->htab[tcf_hash(i, hinfo->hmask)]; |
ec0595cc4 net_sched: get ri... |
137 138 |
hlist_for_each_entry_safe(p, n, head, tcfa_head) { ret = __tcf_hash_release(p, false, true); |
55334a5db net_sched: act: r... |
139 |
if (ret == ACT_P_DELETED) { |
ec0595cc4 net_sched: get ri... |
140 |
module_put(p->ops->owner); |
805c1f4ae net_sched: act: a... |
141 |
n_i++; |
55334a5db net_sched: act: r... |
142 143 |
} else if (ret < 0) goto nla_put_failure; |
e9ce1cd3c [PKT_SCHED]: Kill... |
144 145 |
} } |
1b34ec43c pkt_sched: Stop u... |
146 147 |
if (nla_put_u32(skb, TCA_FCNT, n_i)) goto nla_put_failure; |
4b3550ef5 [NET_SCHED]: Use ... |
148 |
nla_nest_end(skb, nest); |
e9ce1cd3c [PKT_SCHED]: Kill... |
149 150 |
return n_i; |
7ba699c60 [NET_SCHED]: Conv... |
151 |
nla_put_failure: |
4b3550ef5 [NET_SCHED]: Use ... |
152 |
nla_nest_cancel(skb, nest); |
55334a5db net_sched: act: r... |
153 |
return ret; |
e9ce1cd3c [PKT_SCHED]: Kill... |
154 |
} |
ddf97ccdd net_sched: add ne... |
155 156 |
int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb, struct netlink_callback *cb, int type, |
a85a970af net_sched: move t... |
157 |
const struct tc_action_ops *ops) |
e9ce1cd3c [PKT_SCHED]: Kill... |
158 |
{ |
ddf97ccdd net_sched: add ne... |
159 |
struct tcf_hashinfo *hinfo = tn->hinfo; |
e9ce1cd3c [PKT_SCHED]: Kill... |
160 |
if (type == RTM_DELACTION) { |
a85a970af net_sched: move t... |
161 |
return tcf_del_walker(hinfo, skb, ops); |
e9ce1cd3c [PKT_SCHED]: Kill... |
162 |
} else if (type == RTM_GETACTION) { |
a85a970af net_sched: move t... |
163 |
return tcf_dump_walker(hinfo, skb, cb); |
e9ce1cd3c [PKT_SCHED]: Kill... |
164 |
} else { |
6ff9c3644 net sched: printk... |
165 166 |
WARN(1, "tcf_generic_walker: unknown action %d ", type); |
e9ce1cd3c [PKT_SCHED]: Kill... |
167 168 169 |
return -EINVAL; } } |
ddf97ccdd net_sched: add ne... |
170 |
EXPORT_SYMBOL(tcf_generic_walker); |
e9ce1cd3c [PKT_SCHED]: Kill... |
171 |
|
ec0595cc4 net_sched: get ri... |
172 |
static struct tc_action *tcf_hash_lookup(u32 index, struct tcf_hashinfo *hinfo) |
e9ce1cd3c [PKT_SCHED]: Kill... |
173 |
{ |
ec0595cc4 net_sched: get ri... |
174 |
struct tc_action *p = NULL; |
89819dc01 net_sched: conver... |
175 |
struct hlist_head *head; |
e9ce1cd3c [PKT_SCHED]: Kill... |
176 |
|
89819dc01 net_sched: conver... |
177 178 |
spin_lock_bh(&hinfo->lock); head = &hinfo->htab[tcf_hash(index, hinfo->hmask)]; |
ec0595cc4 net_sched: get ri... |
179 180 |
hlist_for_each_entry_rcu(p, head, tcfa_head) if (p->tcfa_index == index) |
e9ce1cd3c [PKT_SCHED]: Kill... |
181 |
break; |
89819dc01 net_sched: conver... |
182 |
spin_unlock_bh(&hinfo->lock); |
e9ce1cd3c [PKT_SCHED]: Kill... |
183 184 185 |
return p; } |
e9ce1cd3c [PKT_SCHED]: Kill... |
186 |
|
ddf97ccdd net_sched: add ne... |
187 |
u32 tcf_hash_new_index(struct tc_action_net *tn) |
e9ce1cd3c [PKT_SCHED]: Kill... |
188 |
{ |
ddf97ccdd net_sched: add ne... |
189 |
struct tcf_hashinfo *hinfo = tn->hinfo; |
ddafd34f4 net_sched: act: m... |
190 |
u32 val = hinfo->index; |
e9ce1cd3c [PKT_SCHED]: Kill... |
191 192 193 194 195 |
do { if (++val == 0) val = 1; } while (tcf_hash_lookup(val, hinfo)); |
ddafd34f4 net_sched: act: m... |
196 |
hinfo->index = val; |
17569faed net_sched: remove... |
197 |
return val; |
e9ce1cd3c [PKT_SCHED]: Kill... |
198 199 |
} EXPORT_SYMBOL(tcf_hash_new_index); |
a85a970af net_sched: move t... |
200 |
int tcf_hash_search(struct tc_action_net *tn, struct tc_action **a, u32 index) |
e9ce1cd3c [PKT_SCHED]: Kill... |
201 |
{ |
ddf97ccdd net_sched: add ne... |
202 |
struct tcf_hashinfo *hinfo = tn->hinfo; |
ec0595cc4 net_sched: get ri... |
203 |
struct tc_action *p = tcf_hash_lookup(index, hinfo); |
e9ce1cd3c [PKT_SCHED]: Kill... |
204 205 |
if (p) { |
ec0595cc4 net_sched: get ri... |
206 |
*a = p; |
e9ce1cd3c [PKT_SCHED]: Kill... |
207 208 209 210 |
return 1; } return 0; } |
6e6a50c25 net_sched: act: e... |
211 |
EXPORT_SYMBOL(tcf_hash_search); |
e9ce1cd3c [PKT_SCHED]: Kill... |
212 |
|
a85a970af net_sched: move t... |
213 |
bool tcf_hash_check(struct tc_action_net *tn, u32 index, struct tc_action **a, |
b2313077e net_sched: make t... |
214 |
int bind) |
e9ce1cd3c [PKT_SCHED]: Kill... |
215 |
{ |
ddf97ccdd net_sched: add ne... |
216 |
struct tcf_hashinfo *hinfo = tn->hinfo; |
ec0595cc4 net_sched: get ri... |
217 |
struct tc_action *p = NULL; |
e9ce1cd3c [PKT_SCHED]: Kill... |
218 |
if (index && (p = tcf_hash_lookup(index, hinfo)) != NULL) { |
76aab2c1e pkt_sched: Fix ac... |
219 |
if (bind) |
ec0595cc4 net_sched: get ri... |
220 221 222 |
p->tcfa_bindcnt++; p->tcfa_refcnt++; *a = p; |
b2313077e net_sched: make t... |
223 |
return true; |
e9ce1cd3c [PKT_SCHED]: Kill... |
224 |
} |
b2313077e net_sched: make t... |
225 |
return false; |
e9ce1cd3c [PKT_SCHED]: Kill... |
226 227 |
} EXPORT_SYMBOL(tcf_hash_check); |
86062033f net_sched: act: h... |
228 229 |
void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est) { |
86062033f net_sched: act: h... |
230 |
if (est) |
ec0595cc4 net_sched: get ri... |
231 232 233 |
gen_kill_estimator(&a->tcfa_bstats, &a->tcfa_rate_est); call_rcu(&a->tcfa_rcu, free_tcf); |
86062033f net_sched: act: h... |
234 235 |
} EXPORT_SYMBOL(tcf_hash_cleanup); |
ddf97ccdd net_sched: add ne... |
236 |
int tcf_hash_create(struct tc_action_net *tn, u32 index, struct nlattr *est, |
a85a970af net_sched: move t... |
237 238 |
struct tc_action **a, const struct tc_action_ops *ops, int bind, bool cpustats) |
e9ce1cd3c [PKT_SCHED]: Kill... |
239 |
{ |
ec0595cc4 net_sched: get ri... |
240 |
struct tc_action *p = kzalloc(ops->size, GFP_KERNEL); |
ddf97ccdd net_sched: add ne... |
241 |
struct tcf_hashinfo *hinfo = tn->hinfo; |
519c818e8 net: sched: add p... |
242 |
int err = -ENOMEM; |
e9ce1cd3c [PKT_SCHED]: Kill... |
243 244 |
if (unlikely(!p)) |
86062033f net_sched: act: h... |
245 |
return -ENOMEM; |
ec0595cc4 net_sched: get ri... |
246 |
p->tcfa_refcnt = 1; |
e9ce1cd3c [PKT_SCHED]: Kill... |
247 |
if (bind) |
ec0595cc4 net_sched: get ri... |
248 |
p->tcfa_bindcnt = 1; |
e9ce1cd3c [PKT_SCHED]: Kill... |
249 |
|
519c818e8 net: sched: add p... |
250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
if (cpustats) { p->cpu_bstats = netdev_alloc_pcpu_stats(struct gnet_stats_basic_cpu); if (!p->cpu_bstats) { err1: kfree(p); return err; } p->cpu_qstats = alloc_percpu(struct gnet_stats_queue); if (!p->cpu_qstats) { err2: free_percpu(p->cpu_bstats); goto err1; } } |
ec0595cc4 net_sched: get ri... |
264 265 266 267 268 269 |
spin_lock_init(&p->tcfa_lock); INIT_HLIST_NODE(&p->tcfa_head); p->tcfa_index = index ? index : tcf_hash_new_index(tn); p->tcfa_tm.install = jiffies; p->tcfa_tm.lastuse = jiffies; p->tcfa_tm.firstuse = 0; |
0e991ec6a tc: propogate err... |
270 |
if (est) { |
ec0595cc4 net_sched: get ri... |
271 272 273 |
err = gen_new_estimator(&p->tcfa_bstats, p->cpu_bstats, &p->tcfa_rate_est, &p->tcfa_lock, NULL, est); |
0e991ec6a tc: propogate err... |
274 |
if (err) { |
519c818e8 net: sched: add p... |
275 276 |
free_percpu(p->cpu_qstats); goto err2; |
0e991ec6a tc: propogate err... |
277 278 |
} } |
ec0595cc4 net_sched: get ri... |
279 280 281 282 |
p->hinfo = hinfo; p->ops = ops; INIT_LIST_HEAD(&p->list); *a = p; |
86062033f net_sched: act: h... |
283 |
return 0; |
e9ce1cd3c [PKT_SCHED]: Kill... |
284 285 |
} EXPORT_SYMBOL(tcf_hash_create); |
ddf97ccdd net_sched: add ne... |
286 |
void tcf_hash_insert(struct tc_action_net *tn, struct tc_action *a) |
e9ce1cd3c [PKT_SCHED]: Kill... |
287 |
{ |
ddf97ccdd net_sched: add ne... |
288 |
struct tcf_hashinfo *hinfo = tn->hinfo; |
ec0595cc4 net_sched: get ri... |
289 |
unsigned int h = tcf_hash(a->tcfa_index, hinfo->hmask); |
e9ce1cd3c [PKT_SCHED]: Kill... |
290 |
|
89819dc01 net_sched: conver... |
291 |
spin_lock_bh(&hinfo->lock); |
ec0595cc4 net_sched: get ri... |
292 |
hlist_add_head(&a->tcfa_head, &hinfo->htab[h]); |
89819dc01 net_sched: conver... |
293 |
spin_unlock_bh(&hinfo->lock); |
e9ce1cd3c [PKT_SCHED]: Kill... |
294 295 |
} EXPORT_SYMBOL(tcf_hash_insert); |
1da177e4c Linux-2.6.12-rc2 |
296 |
|
ddf97ccdd net_sched: add ne... |
297 298 |
void tcf_hashinfo_destroy(const struct tc_action_ops *ops, struct tcf_hashinfo *hinfo) |
1d4150c02 net_sched: prepar... |
299 |
{ |
1d4150c02 net_sched: prepar... |
300 301 302 |
int i; for (i = 0; i < hinfo->hmask + 1; i++) { |
ec0595cc4 net_sched: get ri... |
303 |
struct tc_action *p; |
1d4150c02 net_sched: prepar... |
304 |
struct hlist_node *n; |
ec0595cc4 net_sched: get ri... |
305 |
hlist_for_each_entry_safe(p, n, &hinfo->htab[i], tcfa_head) { |
1d4150c02 net_sched: prepar... |
306 |
int ret; |
ec0595cc4 net_sched: get ri... |
307 |
ret = __tcf_hash_release(p, false, true); |
1d4150c02 net_sched: prepar... |
308 309 310 311 312 313 314 315 |
if (ret == ACT_P_DELETED) module_put(ops->owner); else if (ret < 0) return; } } kfree(hinfo->htab); } |
ddf97ccdd net_sched: add ne... |
316 |
EXPORT_SYMBOL(tcf_hashinfo_destroy); |
1d4150c02 net_sched: prepar... |
317 |
|
1f747c26c net_sched: conver... |
318 |
static LIST_HEAD(act_base); |
1da177e4c Linux-2.6.12-rc2 |
319 |
static DEFINE_RWLOCK(act_mod_lock); |
ddf97ccdd net_sched: add ne... |
320 321 |
int tcf_register_action(struct tc_action_ops *act, struct pernet_operations *ops) |
1da177e4c Linux-2.6.12-rc2 |
322 |
{ |
1f747c26c net_sched: conver... |
323 |
struct tc_action_ops *a; |
ddf97ccdd net_sched: add ne... |
324 |
int ret; |
1da177e4c Linux-2.6.12-rc2 |
325 |
|
ddf97ccdd net_sched: add ne... |
326 |
if (!act->act || !act->dump || !act->init || !act->walk || !act->lookup) |
76c82d7a3 net_sched: Fail i... |
327 |
return -EINVAL; |
ab102b80c net_sched: reorde... |
328 329 330 331 332 333 334 |
/* We have to register pernet ops before making the action ops visible, * otherwise tcf_action_init_1() could get a partially initialized * netns. */ ret = register_pernet_subsys(ops); if (ret) return ret; |
1da177e4c Linux-2.6.12-rc2 |
335 |
write_lock(&act_mod_lock); |
1f747c26c net_sched: conver... |
336 |
list_for_each_entry(a, &act_base, head) { |
1da177e4c Linux-2.6.12-rc2 |
337 338 |
if (act->type == a->type || (strcmp(act->kind, a->kind) == 0)) { write_unlock(&act_mod_lock); |
ab102b80c net_sched: reorde... |
339 |
unregister_pernet_subsys(ops); |
1da177e4c Linux-2.6.12-rc2 |
340 341 342 |
return -EEXIST; } } |
1f747c26c net_sched: conver... |
343 |
list_add_tail(&act->head, &act_base); |
1da177e4c Linux-2.6.12-rc2 |
344 |
write_unlock(&act_mod_lock); |
ddf97ccdd net_sched: add ne... |
345 |
|
1da177e4c Linux-2.6.12-rc2 |
346 347 |
return 0; } |
62e3ba1b5 [NET_SCHED]: Move... |
348 |
EXPORT_SYMBOL(tcf_register_action); |
1da177e4c Linux-2.6.12-rc2 |
349 |
|
ddf97ccdd net_sched: add ne... |
350 351 |
int tcf_unregister_action(struct tc_action_ops *act, struct pernet_operations *ops) |
1da177e4c Linux-2.6.12-rc2 |
352 |
{ |
1f747c26c net_sched: conver... |
353 |
struct tc_action_ops *a; |
1da177e4c Linux-2.6.12-rc2 |
354 355 356 |
int err = -ENOENT; write_lock(&act_mod_lock); |
a792866ad net_sched: fix re... |
357 358 359 360 |
list_for_each_entry(a, &act_base, head) { if (a == act) { list_del(&act->head); err = 0; |
1da177e4c Linux-2.6.12-rc2 |
361 |
break; |
a792866ad net_sched: fix re... |
362 |
} |
1da177e4c Linux-2.6.12-rc2 |
363 364 |
} write_unlock(&act_mod_lock); |
ab102b80c net_sched: reorde... |
365 366 |
if (!err) unregister_pernet_subsys(ops); |
1da177e4c Linux-2.6.12-rc2 |
367 368 |
return err; } |
62e3ba1b5 [NET_SCHED]: Move... |
369 |
EXPORT_SYMBOL(tcf_unregister_action); |
1da177e4c Linux-2.6.12-rc2 |
370 371 372 373 |
/* lookup by name */ static struct tc_action_ops *tc_lookup_action_n(char *kind) { |
a792866ad net_sched: fix re... |
374 |
struct tc_action_ops *a, *res = NULL; |
1da177e4c Linux-2.6.12-rc2 |
375 376 377 |
if (kind) { read_lock(&act_mod_lock); |
1f747c26c net_sched: conver... |
378 |
list_for_each_entry(a, &act_base, head) { |
1da177e4c Linux-2.6.12-rc2 |
379 |
if (strcmp(kind, a->kind) == 0) { |
a792866ad net_sched: fix re... |
380 381 |
if (try_module_get(a->owner)) res = a; |
1da177e4c Linux-2.6.12-rc2 |
382 383 384 385 386 |
break; } } read_unlock(&act_mod_lock); } |
a792866ad net_sched: fix re... |
387 |
return res; |
1da177e4c Linux-2.6.12-rc2 |
388 |
} |
7ba699c60 [NET_SCHED]: Conv... |
389 390 |
/* lookup by nlattr */ static struct tc_action_ops *tc_lookup_action(struct nlattr *kind) |
1da177e4c Linux-2.6.12-rc2 |
391 |
{ |
a792866ad net_sched: fix re... |
392 |
struct tc_action_ops *a, *res = NULL; |
1da177e4c Linux-2.6.12-rc2 |
393 394 395 |
if (kind) { read_lock(&act_mod_lock); |
1f747c26c net_sched: conver... |
396 |
list_for_each_entry(a, &act_base, head) { |
7ba699c60 [NET_SCHED]: Conv... |
397 |
if (nla_strcmp(kind, a->kind) == 0) { |
a792866ad net_sched: fix re... |
398 399 |
if (try_module_get(a->owner)) res = a; |
1da177e4c Linux-2.6.12-rc2 |
400 401 402 403 404 |
break; } } read_unlock(&act_mod_lock); } |
a792866ad net_sched: fix re... |
405 |
return res; |
1da177e4c Linux-2.6.12-rc2 |
406 |
} |
1da177e4c Linux-2.6.12-rc2 |
407 |
|
22dc13c83 net_sched: conver... |
408 409 |
int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions, int nr_actions, struct tcf_result *res) |
1da177e4c Linux-2.6.12-rc2 |
410 |
{ |
22dc13c83 net_sched: conver... |
411 |
int ret = -1, i; |
1da177e4c Linux-2.6.12-rc2 |
412 413 414 |
if (skb->tc_verd & TC_NCLS) { skb->tc_verd = CLR_TC_NCLS(skb->tc_verd); |
1da177e4c Linux-2.6.12-rc2 |
415 416 417 |
ret = TC_ACT_OK; goto exec_done; } |
22dc13c83 net_sched: conver... |
418 419 |
for (i = 0; i < nr_actions; i++) { const struct tc_action *a = actions[i]; |
1da177e4c Linux-2.6.12-rc2 |
420 |
repeat: |
63acd6807 net_sched: Remove... |
421 |
ret = a->ops->act(skb, a, res); |
63acd6807 net_sched: Remove... |
422 423 424 425 |
if (ret == TC_ACT_REPEAT) goto repeat; /* we need a ttl - JHS */ if (ret != TC_ACT_PIPE) goto exec_done; |
1da177e4c Linux-2.6.12-rc2 |
426 427 |
} exec_done: |
1da177e4c Linux-2.6.12-rc2 |
428 429 |
return ret; } |
62e3ba1b5 [NET_SCHED]: Move... |
430 |
EXPORT_SYMBOL(tcf_action_exec); |
1da177e4c Linux-2.6.12-rc2 |
431 |
|
55334a5db net_sched: act: r... |
432 |
int tcf_action_destroy(struct list_head *actions, int bind) |
1da177e4c Linux-2.6.12-rc2 |
433 |
{ |
33be62715 net_sched: act: u... |
434 |
struct tc_action *a, *tmp; |
55334a5db net_sched: act: r... |
435 |
int ret = 0; |
1da177e4c Linux-2.6.12-rc2 |
436 |
|
33be62715 net_sched: act: u... |
437 |
list_for_each_entry_safe(a, tmp, actions, list) { |
28e6b67f0 net: sched: fix r... |
438 |
ret = __tcf_hash_release(a, bind, true); |
55334a5db net_sched: act: r... |
439 |
if (ret == ACT_P_DELETED) |
63acd6807 net_sched: Remove... |
440 |
module_put(a->ops->owner); |
55334a5db net_sched: act: r... |
441 442 |
else if (ret < 0) return ret; |
1da177e4c Linux-2.6.12-rc2 |
443 |
} |
55334a5db net_sched: act: r... |
444 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
445 446 447 448 449 |
} int tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int bind, int ref) { |
1da177e4c Linux-2.6.12-rc2 |
450 451 452 453 454 455 456 |
return a->ops->dump(skb, a, bind, ref); } int tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int bind, int ref) { int err = -EINVAL; |
27a884dc3 [SK_BUFF]: Conver... |
457 |
unsigned char *b = skb_tail_pointer(skb); |
4b3550ef5 [NET_SCHED]: Use ... |
458 |
struct nlattr *nest; |
1da177e4c Linux-2.6.12-rc2 |
459 |
|
1b34ec43c pkt_sched: Stop u... |
460 461 |
if (nla_put_string(skb, TCA_KIND, a->ops->kind)) goto nla_put_failure; |
1da177e4c Linux-2.6.12-rc2 |
462 |
if (tcf_action_copy_stats(skb, a, 0)) |
7ba699c60 [NET_SCHED]: Conv... |
463 |
goto nla_put_failure; |
4b3550ef5 [NET_SCHED]: Use ... |
464 465 466 |
nest = nla_nest_start(skb, TCA_OPTIONS); if (nest == NULL) goto nla_put_failure; |
cc7ec456f net_sched: cleanups |
467 468 |
err = tcf_action_dump_old(skb, a, bind, ref); if (err > 0) { |
4b3550ef5 [NET_SCHED]: Use ... |
469 |
nla_nest_end(skb, nest); |
1da177e4c Linux-2.6.12-rc2 |
470 471 |
return err; } |
7ba699c60 [NET_SCHED]: Conv... |
472 |
nla_put_failure: |
dc5fc579b [NETLINK]: Use nl... |
473 |
nlmsg_trim(skb, b); |
1da177e4c Linux-2.6.12-rc2 |
474 475 |
return -1; } |
62e3ba1b5 [NET_SCHED]: Move... |
476 |
EXPORT_SYMBOL(tcf_action_dump_1); |
1da177e4c Linux-2.6.12-rc2 |
477 |
|
0b0f43fe2 net sched: indent... |
478 479 |
int tcf_action_dump(struct sk_buff *skb, struct list_head *actions, int bind, int ref) |
1da177e4c Linux-2.6.12-rc2 |
480 481 482 |
{ struct tc_action *a; int err = -EINVAL; |
4b3550ef5 [NET_SCHED]: Use ... |
483 |
struct nlattr *nest; |
1da177e4c Linux-2.6.12-rc2 |
484 |
|
33be62715 net_sched: act: u... |
485 |
list_for_each_entry(a, actions, list) { |
4b3550ef5 [NET_SCHED]: Use ... |
486 487 488 |
nest = nla_nest_start(skb, a->order); if (nest == NULL) goto nla_put_failure; |
1da177e4c Linux-2.6.12-rc2 |
489 490 |
err = tcf_action_dump_1(skb, a, bind, ref); if (err < 0) |
4fe683f50 [PKT_SCHED]: Fix ... |
491 |
goto errout; |
4b3550ef5 [NET_SCHED]: Use ... |
492 |
nla_nest_end(skb, nest); |
1da177e4c Linux-2.6.12-rc2 |
493 494 495 |
} return 0; |
7ba699c60 [NET_SCHED]: Conv... |
496 |
nla_put_failure: |
4fe683f50 [PKT_SCHED]: Fix ... |
497 498 |
err = -EINVAL; errout: |
4b3550ef5 [NET_SCHED]: Use ... |
499 |
nla_nest_cancel(skb, nest); |
4fe683f50 [PKT_SCHED]: Fix ... |
500 |
return err; |
1da177e4c Linux-2.6.12-rc2 |
501 |
} |
c1b52739e pkt_sched: namesp... |
502 503 504 |
struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla, struct nlattr *est, char *name, int ovr, int bind) |
1da177e4c Linux-2.6.12-rc2 |
505 506 507 508 |
{ struct tc_action *a; struct tc_action_ops *a_o; char act_name[IFNAMSIZ]; |
cc7ec456f net_sched: cleanups |
509 |
struct nlattr *tb[TCA_ACT_MAX + 1]; |
7ba699c60 [NET_SCHED]: Conv... |
510 |
struct nlattr *kind; |
ab27cfb85 [NET_SCHED]: act_... |
511 |
int err; |
1da177e4c Linux-2.6.12-rc2 |
512 |
|
1da177e4c Linux-2.6.12-rc2 |
513 |
if (name == NULL) { |
cee63723b [NET_SCHED]: Prop... |
514 515 |
err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL); if (err < 0) |
1da177e4c Linux-2.6.12-rc2 |
516 |
goto err_out; |
cee63723b [NET_SCHED]: Prop... |
517 |
err = -EINVAL; |
7ba699c60 [NET_SCHED]: Conv... |
518 |
kind = tb[TCA_ACT_KIND]; |
1da177e4c Linux-2.6.12-rc2 |
519 520 |
if (kind == NULL) goto err_out; |
7ba699c60 [NET_SCHED]: Conv... |
521 |
if (nla_strlcpy(act_name, kind, IFNAMSIZ) >= IFNAMSIZ) |
1da177e4c Linux-2.6.12-rc2 |
522 523 |
goto err_out; } else { |
cee63723b [NET_SCHED]: Prop... |
524 |
err = -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
525 526 527 528 529 530 |
if (strlcpy(act_name, name, IFNAMSIZ) >= IFNAMSIZ) goto err_out; } a_o = tc_lookup_action_n(act_name); if (a_o == NULL) { |
95a5afca4 net: Remove CONFI... |
531 |
#ifdef CONFIG_MODULES |
1da177e4c Linux-2.6.12-rc2 |
532 |
rtnl_unlock(); |
4bba39259 [PKT_SCHED]: Pref... |
533 |
request_module("act_%s", act_name); |
1da177e4c Linux-2.6.12-rc2 |
534 535 536 537 538 539 540 541 542 543 544 |
rtnl_lock(); a_o = tc_lookup_action_n(act_name); /* We dropped the RTNL semaphore in order to * perform the module load. So, even if we * succeeded in loading the module we have to * tell the caller to replay the request. We * indicate this using -EAGAIN. */ if (a_o != NULL) { |
ab27cfb85 [NET_SCHED]: act_... |
545 |
err = -EAGAIN; |
1da177e4c Linux-2.6.12-rc2 |
546 547 548 |
goto err_mod; } #endif |
ab27cfb85 [NET_SCHED]: act_... |
549 |
err = -ENOENT; |
1da177e4c Linux-2.6.12-rc2 |
550 551 |
goto err_out; } |
1da177e4c Linux-2.6.12-rc2 |
552 553 |
/* backward compatibility for policer */ if (name == NULL) |
a85a970af net_sched: move t... |
554 |
err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, &a, ovr, bind); |
1da177e4c Linux-2.6.12-rc2 |
555 |
else |
a85a970af net_sched: move t... |
556 |
err = a_o->init(net, nla, est, &a, ovr, bind); |
ab27cfb85 [NET_SCHED]: act_... |
557 |
if (err < 0) |
a85a970af net_sched: move t... |
558 |
goto err_mod; |
1da177e4c Linux-2.6.12-rc2 |
559 560 |
/* module count goes up only when brand new policy is created |
cc7ec456f net_sched: cleanups |
561 562 563 |
* if it exists and is only bound to in a_o->init() then * ACT_P_CREATED is not returned (a zero is). */ |
ab27cfb85 [NET_SCHED]: act_... |
564 |
if (err != ACT_P_CREATED) |
1da177e4c Linux-2.6.12-rc2 |
565 |
module_put(a_o->owner); |
1da177e4c Linux-2.6.12-rc2 |
566 |
|
1da177e4c Linux-2.6.12-rc2 |
567 |
return a; |
1da177e4c Linux-2.6.12-rc2 |
568 569 570 |
err_mod: module_put(a_o->owner); err_out: |
ab27cfb85 [NET_SCHED]: act_... |
571 |
return ERR_PTR(err); |
1da177e4c Linux-2.6.12-rc2 |
572 |
} |
aecc5cefc net sched actions... |
573 574 575 576 577 578 579 580 581 582 |
static void cleanup_a(struct list_head *actions, int ovr) { struct tc_action *a; if (!ovr) return; list_for_each_entry(a, actions, list) a->tcfa_refcnt--; } |
5a7a5555a net sched: stylis... |
583 584 |
int tcf_action_init(struct net *net, struct nlattr *nla, struct nlattr *est, char *name, int ovr, int bind, struct list_head *actions) |
1da177e4c Linux-2.6.12-rc2 |
585 |
{ |
cc7ec456f net_sched: cleanups |
586 |
struct nlattr *tb[TCA_ACT_MAX_PRIO + 1]; |
33be62715 net_sched: act: u... |
587 |
struct tc_action *act; |
cee63723b [NET_SCHED]: Prop... |
588 |
int err; |
1da177e4c Linux-2.6.12-rc2 |
589 |
int i; |
cee63723b [NET_SCHED]: Prop... |
590 591 |
err = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL); if (err < 0) |
33be62715 net_sched: act: u... |
592 |
return err; |
1da177e4c Linux-2.6.12-rc2 |
593 |
|
7ba699c60 [NET_SCHED]: Conv... |
594 |
for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) { |
c1b52739e pkt_sched: namesp... |
595 |
act = tcf_action_init_1(net, tb[i], est, name, ovr, bind); |
33be62715 net_sched: act: u... |
596 597 |
if (IS_ERR(act)) { err = PTR_ERR(act); |
1da177e4c Linux-2.6.12-rc2 |
598 |
goto err; |
33be62715 net_sched: act: u... |
599 |
} |
7ba699c60 [NET_SCHED]: Conv... |
600 |
act->order = i; |
aecc5cefc net sched actions... |
601 602 |
if (ovr) act->tcfa_refcnt++; |
33be62715 net_sched: act: u... |
603 |
list_add_tail(&act->list, actions); |
1da177e4c Linux-2.6.12-rc2 |
604 |
} |
aecc5cefc net sched actions... |
605 606 607 608 609 |
/* Remove the temp refcnt which was necessary to protect against * destroying an existing action which was being replaced */ cleanup_a(actions, ovr); |
33be62715 net_sched: act: u... |
610 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
611 612 |
err: |
33be62715 net_sched: act: u... |
613 614 |
tcf_action_destroy(actions, bind); return err; |
1da177e4c Linux-2.6.12-rc2 |
615 |
} |
ec0595cc4 net_sched: get ri... |
616 |
int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *p, |
1da177e4c Linux-2.6.12-rc2 |
617 618 619 620 |
int compat_mode) { int err = 0; struct gnet_dump d; |
10297b993 [NET] SCHED: Fix ... |
621 |
|
7eb8896df net_sched: act: r... |
622 |
if (p == NULL) |
1da177e4c Linux-2.6.12-rc2 |
623 624 625 |
goto errout; /* compat_mode being true specifies a call that is supposed |
06fe9fb41 tree-wide: fix a ... |
626 |
* to add additional backward compatibility statistic TLVs. |
1da177e4c Linux-2.6.12-rc2 |
627 628 |
*/ if (compat_mode) { |
ec0595cc4 net_sched: get ri... |
629 |
if (p->type == TCA_OLD_COMPAT) |
1da177e4c Linux-2.6.12-rc2 |
630 |
err = gnet_stats_start_copy_compat(skb, 0, |
9854518ea sched: align nlat... |
631 632 |
TCA_STATS, TCA_XSTATS, |
ec0595cc4 net_sched: get ri... |
633 |
&p->tcfa_lock, &d, |
9854518ea sched: align nlat... |
634 |
TCA_PAD); |
1da177e4c Linux-2.6.12-rc2 |
635 636 637 638 |
else return 0; } else err = gnet_stats_start_copy(skb, TCA_ACT_STATS, |
ec0595cc4 net_sched: get ri... |
639 |
&p->tcfa_lock, &d, TCA_ACT_PAD); |
1da177e4c Linux-2.6.12-rc2 |
640 641 642 |
if (err < 0) goto errout; |
ec0595cc4 net_sched: get ri... |
643 644 645 |
if (gnet_stats_copy_basic(NULL, &d, p->cpu_bstats, &p->tcfa_bstats) < 0 || gnet_stats_copy_rate_est(&d, &p->tcfa_bstats, &p->tcfa_rate_est) < 0 || |
519c818e8 net: sched: add p... |
646 |
gnet_stats_copy_queue(&d, p->cpu_qstats, |
ec0595cc4 net_sched: get ri... |
647 648 |
&p->tcfa_qstats, p->tcfa_qstats.qlen) < 0) |
1da177e4c Linux-2.6.12-rc2 |
649 650 651 652 653 654 655 656 657 658 |
goto errout; if (gnet_stats_finish_copy(&d) < 0) goto errout; return 0; errout: return -1; } |
0b0f43fe2 net sched: indent... |
659 660 661 |
static int tca_get_fill(struct sk_buff *skb, struct list_head *actions, u32 portid, u32 seq, u16 flags, int event, int bind, int ref) |
1da177e4c Linux-2.6.12-rc2 |
662 663 664 |
{ struct tcamsg *t; struct nlmsghdr *nlh; |
27a884dc3 [SK_BUFF]: Conver... |
665 |
unsigned char *b = skb_tail_pointer(skb); |
4b3550ef5 [NET_SCHED]: Use ... |
666 |
struct nlattr *nest; |
1da177e4c Linux-2.6.12-rc2 |
667 |
|
15e473046 netlink: Rename p... |
668 |
nlh = nlmsg_put(skb, portid, seq, event, sizeof(*t), flags); |
8b00a53c6 pkt_sched: act_ap... |
669 670 671 |
if (!nlh) goto out_nlmsg_trim; t = nlmsg_data(nlh); |
1da177e4c Linux-2.6.12-rc2 |
672 |
t->tca_family = AF_UNSPEC; |
9ef1d4c7c [NETLINK]: Missin... |
673 674 |
t->tca__pad1 = 0; t->tca__pad2 = 0; |
10297b993 [NET] SCHED: Fix ... |
675 |
|
4b3550ef5 [NET_SCHED]: Use ... |
676 677 |
nest = nla_nest_start(skb, TCA_ACT_TAB); if (nest == NULL) |
8b00a53c6 pkt_sched: act_ap... |
678 |
goto out_nlmsg_trim; |
1da177e4c Linux-2.6.12-rc2 |
679 |
|
33be62715 net_sched: act: u... |
680 |
if (tcf_action_dump(skb, actions, bind, ref) < 0) |
8b00a53c6 pkt_sched: act_ap... |
681 |
goto out_nlmsg_trim; |
1da177e4c Linux-2.6.12-rc2 |
682 |
|
4b3550ef5 [NET_SCHED]: Use ... |
683 |
nla_nest_end(skb, nest); |
10297b993 [NET] SCHED: Fix ... |
684 |
|
27a884dc3 [SK_BUFF]: Conver... |
685 |
nlh->nlmsg_len = skb_tail_pointer(skb) - b; |
1da177e4c Linux-2.6.12-rc2 |
686 |
return skb->len; |
8b00a53c6 pkt_sched: act_ap... |
687 |
out_nlmsg_trim: |
dc5fc579b [NETLINK]: Use nl... |
688 |
nlmsg_trim(skb, b); |
1da177e4c Linux-2.6.12-rc2 |
689 690 691 692 |
return -1; } static int |
15e473046 netlink: Rename p... |
693 |
act_get_notify(struct net *net, u32 portid, struct nlmsghdr *n, |
33be62715 net_sched: act: u... |
694 |
struct list_head *actions, int event) |
1da177e4c Linux-2.6.12-rc2 |
695 696 |
{ struct sk_buff *skb; |
1da177e4c Linux-2.6.12-rc2 |
697 698 699 700 |
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb) return -ENOBUFS; |
0b0f43fe2 net sched: indent... |
701 702 |
if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, event, 0, 0) <= 0) { |
1da177e4c Linux-2.6.12-rc2 |
703 704 705 |
kfree_skb(skb); return -EINVAL; } |
2942e9005 [RTNETLINK]: Use ... |
706 |
|
15e473046 netlink: Rename p... |
707 |
return rtnl_unicast(skb, net, portid); |
1da177e4c Linux-2.6.12-rc2 |
708 |
} |
ddf97ccdd net_sched: add ne... |
709 710 |
static struct tc_action *tcf_action_get_1(struct net *net, struct nlattr *nla, struct nlmsghdr *n, u32 portid) |
1da177e4c Linux-2.6.12-rc2 |
711 |
{ |
cc7ec456f net_sched: cleanups |
712 |
struct nlattr *tb[TCA_ACT_MAX + 1]; |
a85a970af net_sched: move t... |
713 |
const struct tc_action_ops *ops; |
1da177e4c Linux-2.6.12-rc2 |
714 715 |
struct tc_action *a; int index; |
ab27cfb85 [NET_SCHED]: act_... |
716 |
int err; |
1da177e4c Linux-2.6.12-rc2 |
717 |
|
cee63723b [NET_SCHED]: Prop... |
718 719 |
err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL); if (err < 0) |
ab27cfb85 [NET_SCHED]: act_... |
720 |
goto err_out; |
1da177e4c Linux-2.6.12-rc2 |
721 |
|
cee63723b [NET_SCHED]: Prop... |
722 |
err = -EINVAL; |
7ba699c60 [NET_SCHED]: Conv... |
723 724 |
if (tb[TCA_ACT_INDEX] == NULL || nla_len(tb[TCA_ACT_INDEX]) < sizeof(index)) |
ab27cfb85 [NET_SCHED]: act_... |
725 |
goto err_out; |
1587bac49 [NET_SCHED]: Use ... |
726 |
index = nla_get_u32(tb[TCA_ACT_INDEX]); |
1da177e4c Linux-2.6.12-rc2 |
727 |
|
ab27cfb85 [NET_SCHED]: act_... |
728 |
err = -EINVAL; |
a85a970af net_sched: move t... |
729 730 731 |
ops = tc_lookup_action(tb[TCA_ACT_KIND]); if (!ops) /* could happen in batch of actions */ goto err_out; |
ab27cfb85 [NET_SCHED]: act_... |
732 |
err = -ENOENT; |
a85a970af net_sched: move t... |
733 |
if (ops->lookup(net, &a, index) == 0) |
1da177e4c Linux-2.6.12-rc2 |
734 |
goto err_mod; |
a85a970af net_sched: move t... |
735 |
module_put(ops->owner); |
1da177e4c Linux-2.6.12-rc2 |
736 |
return a; |
ab27cfb85 [NET_SCHED]: act_... |
737 |
|
1da177e4c Linux-2.6.12-rc2 |
738 |
err_mod: |
a85a970af net_sched: move t... |
739 |
module_put(ops->owner); |
ab27cfb85 [NET_SCHED]: act_... |
740 741 |
err_out: return ERR_PTR(err); |
1da177e4c Linux-2.6.12-rc2 |
742 |
} |
7316ae88c net_sched: make t... |
743 |
static int tca_action_flush(struct net *net, struct nlattr *nla, |
15e473046 netlink: Rename p... |
744 |
struct nlmsghdr *n, u32 portid) |
1da177e4c Linux-2.6.12-rc2 |
745 746 747 748 749 750 |
{ struct sk_buff *skb; unsigned char *b; struct nlmsghdr *nlh; struct tcamsg *t; struct netlink_callback dcb; |
4b3550ef5 [NET_SCHED]: Use ... |
751 |
struct nlattr *nest; |
cc7ec456f net_sched: cleanups |
752 |
struct nlattr *tb[TCA_ACT_MAX + 1]; |
a85a970af net_sched: move t... |
753 |
const struct tc_action_ops *ops; |
7ba699c60 [NET_SCHED]: Conv... |
754 |
struct nlattr *kind; |
36723873b net-sched: fix Ac... |
755 |
int err = -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
756 |
|
1da177e4c Linux-2.6.12-rc2 |
757 758 |
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb) { |
6ff9c3644 net sched: printk... |
759 760 |
pr_debug("tca_action_flush: failed skb alloc "); |
36723873b net-sched: fix Ac... |
761 |
return err; |
1da177e4c Linux-2.6.12-rc2 |
762 |
} |
27a884dc3 [SK_BUFF]: Conver... |
763 |
b = skb_tail_pointer(skb); |
1da177e4c Linux-2.6.12-rc2 |
764 |
|
cee63723b [NET_SCHED]: Prop... |
765 766 |
err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL); if (err < 0) |
1da177e4c Linux-2.6.12-rc2 |
767 |
goto err_out; |
cee63723b [NET_SCHED]: Prop... |
768 |
err = -EINVAL; |
7ba699c60 [NET_SCHED]: Conv... |
769 |
kind = tb[TCA_ACT_KIND]; |
a85a970af net_sched: move t... |
770 771 |
ops = tc_lookup_action(kind); if (!ops) /*some idjot trying to flush unknown action */ |
1da177e4c Linux-2.6.12-rc2 |
772 |
goto err_out; |
0b0f43fe2 net sched: indent... |
773 774 |
nlh = nlmsg_put(skb, portid, n->nlmsg_seq, RTM_DELACTION, sizeof(*t), 0); |
8b00a53c6 pkt_sched: act_ap... |
775 776 777 |
if (!nlh) goto out_module_put; t = nlmsg_data(nlh); |
1da177e4c Linux-2.6.12-rc2 |
778 |
t->tca_family = AF_UNSPEC; |
9ef1d4c7c [NETLINK]: Missin... |
779 780 |
t->tca__pad1 = 0; t->tca__pad2 = 0; |
1da177e4c Linux-2.6.12-rc2 |
781 |
|
4b3550ef5 [NET_SCHED]: Use ... |
782 783 |
nest = nla_nest_start(skb, TCA_ACT_TAB); if (nest == NULL) |
8b00a53c6 pkt_sched: act_ap... |
784 |
goto out_module_put; |
1da177e4c Linux-2.6.12-rc2 |
785 |
|
a85a970af net_sched: move t... |
786 |
err = ops->walk(net, skb, &dcb, RTM_DELACTION, ops); |
1da177e4c Linux-2.6.12-rc2 |
787 |
if (err < 0) |
8b00a53c6 pkt_sched: act_ap... |
788 |
goto out_module_put; |
f97017cde net-sched: Fix ac... |
789 790 |
if (err == 0) goto noflush_out; |
1da177e4c Linux-2.6.12-rc2 |
791 |
|
4b3550ef5 [NET_SCHED]: Use ... |
792 |
nla_nest_end(skb, nest); |
1da177e4c Linux-2.6.12-rc2 |
793 |
|
27a884dc3 [SK_BUFF]: Conver... |
794 |
nlh->nlmsg_len = skb_tail_pointer(skb) - b; |
1da177e4c Linux-2.6.12-rc2 |
795 |
nlh->nlmsg_flags |= NLM_F_ROOT; |
a85a970af net_sched: move t... |
796 |
module_put(ops->owner); |
15e473046 netlink: Rename p... |
797 |
err = rtnetlink_send(skb, net, portid, RTNLGRP_TC, |
cc7ec456f net_sched: cleanups |
798 |
n->nlmsg_flags & NLM_F_ECHO); |
1da177e4c Linux-2.6.12-rc2 |
799 800 801 802 |
if (err > 0) return 0; return err; |
8b00a53c6 pkt_sched: act_ap... |
803 |
out_module_put: |
a85a970af net_sched: move t... |
804 |
module_put(ops->owner); |
1da177e4c Linux-2.6.12-rc2 |
805 |
err_out: |
f97017cde net-sched: Fix ac... |
806 |
noflush_out: |
1da177e4c Linux-2.6.12-rc2 |
807 |
kfree_skb(skb); |
1da177e4c Linux-2.6.12-rc2 |
808 809 810 811 |
return err; } static int |
a56e19538 net_sched: act: c... |
812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 |
tcf_del_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions, u32 portid) { int ret; struct sk_buff *skb; skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb) return -ENOBUFS; if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, RTM_DELACTION, 0, 1) <= 0) { kfree_skb(skb); return -EINVAL; } /* now do the delete */ |
55334a5db net_sched: act: r... |
829 830 831 832 833 |
ret = tcf_action_destroy(actions, 0); if (ret < 0) { kfree_skb(skb); return ret; } |
a56e19538 net_sched: act: c... |
834 835 836 837 838 839 840 841 842 |
ret = rtnetlink_send(skb, net, portid, RTNLGRP_TC, n->nlmsg_flags & NLM_F_ECHO); if (ret > 0) return 0; return ret; } static int |
7316ae88c net_sched: make t... |
843 |
tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n, |
15e473046 netlink: Rename p... |
844 |
u32 portid, int event) |
1da177e4c Linux-2.6.12-rc2 |
845 |
{ |
cee63723b [NET_SCHED]: Prop... |
846 |
int i, ret; |
cc7ec456f net_sched: cleanups |
847 |
struct nlattr *tb[TCA_ACT_MAX_PRIO + 1]; |
33be62715 net_sched: act: u... |
848 849 |
struct tc_action *act; LIST_HEAD(actions); |
1da177e4c Linux-2.6.12-rc2 |
850 |
|
cee63723b [NET_SCHED]: Prop... |
851 852 853 |
ret = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL); if (ret < 0) return ret; |
1da177e4c Linux-2.6.12-rc2 |
854 |
|
cc7ec456f net_sched: cleanups |
855 |
if (event == RTM_DELACTION && n->nlmsg_flags & NLM_F_ROOT) { |
f97017cde net-sched: Fix ac... |
856 |
if (tb[1] != NULL) |
15e473046 netlink: Rename p... |
857 |
return tca_action_flush(net, tb[1], n, portid); |
f97017cde net-sched: Fix ac... |
858 859 |
else return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
860 |
} |
7ba699c60 [NET_SCHED]: Conv... |
861 |
for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) { |
ddf97ccdd net_sched: add ne... |
862 |
act = tcf_action_get_1(net, tb[i], n, portid); |
ab27cfb85 [NET_SCHED]: act_... |
863 864 |
if (IS_ERR(act)) { ret = PTR_ERR(act); |
1da177e4c Linux-2.6.12-rc2 |
865 |
goto err; |
ab27cfb85 [NET_SCHED]: act_... |
866 |
} |
7ba699c60 [NET_SCHED]: Conv... |
867 |
act->order = i; |
33be62715 net_sched: act: u... |
868 |
list_add_tail(&act->list, &actions); |
1da177e4c Linux-2.6.12-rc2 |
869 870 871 |
} if (event == RTM_GETACTION) |
33be62715 net_sched: act: u... |
872 |
ret = act_get_notify(net, portid, n, &actions, event); |
1da177e4c Linux-2.6.12-rc2 |
873 |
else { /* delete */ |
a56e19538 net_sched: act: c... |
874 875 |
ret = tcf_del_notify(net, n, &actions, portid); if (ret) |
1da177e4c Linux-2.6.12-rc2 |
876 |
goto err; |
1da177e4c Linux-2.6.12-rc2 |
877 878 879 |
return ret; } err: |
b260a714a net sched actions... |
880 881 |
if (event != RTM_GETACTION) tcf_action_destroy(&actions, 0); |
1da177e4c Linux-2.6.12-rc2 |
882 883 |
return ret; } |
a56e19538 net_sched: act: c... |
884 885 886 |
static int tcf_add_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions, u32 portid) |
1da177e4c Linux-2.6.12-rc2 |
887 |
{ |
1da177e4c Linux-2.6.12-rc2 |
888 |
struct sk_buff *skb; |
1da177e4c Linux-2.6.12-rc2 |
889 890 891 892 893 |
int err = 0; skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb) return -ENOBUFS; |
a56e19538 net_sched: act: c... |
894 895 896 897 898 |
if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, n->nlmsg_flags, RTM_NEWACTION, 0, 0) <= 0) { kfree_skb(skb); return -EINVAL; } |
10297b993 [NET] SCHED: Fix ... |
899 |
|
a56e19538 net_sched: act: c... |
900 901 |
err = rtnetlink_send(skb, net, portid, RTNLGRP_TC, n->nlmsg_flags & NLM_F_ECHO); |
1da177e4c Linux-2.6.12-rc2 |
902 903 904 |
if (err > 0) err = 0; return err; |
1da177e4c Linux-2.6.12-rc2 |
905 |
} |
5a7a5555a net sched: stylis... |
906 907 |
static int tcf_action_add(struct net *net, struct nlattr *nla, struct nlmsghdr *n, u32 portid, int ovr) |
1da177e4c Linux-2.6.12-rc2 |
908 909 |
{ int ret = 0; |
33be62715 net_sched: act: u... |
910 |
LIST_HEAD(actions); |
1da177e4c Linux-2.6.12-rc2 |
911 |
|
33be62715 net_sched: act: u... |
912 913 |
ret = tcf_action_init(net, nla, NULL, NULL, ovr, 0, &actions); if (ret) |
f07fed82a net_sched: remove... |
914 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
915 |
|
f07fed82a net_sched: remove... |
916 |
return tcf_add_notify(net, n, &actions, portid); |
1da177e4c Linux-2.6.12-rc2 |
917 |
} |
661d2967b rtnetlink: Remove... |
918 |
static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n) |
1da177e4c Linux-2.6.12-rc2 |
919 |
{ |
3b1e0a655 [NET] NETNS: Omit... |
920 |
struct net *net = sock_net(skb->sk); |
7ba699c60 [NET_SCHED]: Conv... |
921 |
struct nlattr *tca[TCA_ACT_MAX + 1]; |
15e473046 netlink: Rename p... |
922 |
u32 portid = skb ? NETLINK_CB(skb).portid : 0; |
1da177e4c Linux-2.6.12-rc2 |
923 |
int ret = 0, ovr = 0; |
0b0f43fe2 net sched: indent... |
924 925 |
if ((n->nlmsg_type != RTM_GETACTION) && !netlink_capable(skb, CAP_NET_ADMIN)) |
dfc47ef86 net: Push capable... |
926 |
return -EPERM; |
7ba699c60 [NET_SCHED]: Conv... |
927 928 929 930 931 |
ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ACT_MAX, NULL); if (ret < 0) return ret; if (tca[TCA_ACT_TAB] == NULL) { |
6ff9c3644 net sched: printk... |
932 933 |
pr_notice("tc_ctl_action: received NO action attribs "); |
1da177e4c Linux-2.6.12-rc2 |
934 935 |
return -EINVAL; } |
cc7ec456f net_sched: cleanups |
936 |
/* n->nlmsg_flags & NLM_F_CREATE */ |
1da177e4c Linux-2.6.12-rc2 |
937 938 939 |
switch (n->nlmsg_type) { case RTM_NEWACTION: /* we are going to assume all other flags |
25985edce Fix common misspe... |
940 |
* imply create only if it doesn't exist |
1da177e4c Linux-2.6.12-rc2 |
941 942 943 944 |
* Note that CREATE | EXCL implies that * but since we want avoid ambiguity (eg when flags * is zero) then just set this */ |
cc7ec456f net_sched: cleanups |
945 |
if (n->nlmsg_flags & NLM_F_REPLACE) |
1da177e4c Linux-2.6.12-rc2 |
946 947 |
ovr = 1; replay: |
15e473046 netlink: Rename p... |
948 |
ret = tcf_action_add(net, tca[TCA_ACT_TAB], n, portid, ovr); |
1da177e4c Linux-2.6.12-rc2 |
949 950 951 952 |
if (ret == -EAGAIN) goto replay; break; case RTM_DELACTION: |
7316ae88c net_sched: make t... |
953 |
ret = tca_action_gd(net, tca[TCA_ACT_TAB], n, |
15e473046 netlink: Rename p... |
954 |
portid, RTM_DELACTION); |
1da177e4c Linux-2.6.12-rc2 |
955 956 |
break; case RTM_GETACTION: |
7316ae88c net_sched: make t... |
957 |
ret = tca_action_gd(net, tca[TCA_ACT_TAB], n, |
15e473046 netlink: Rename p... |
958 |
portid, RTM_GETACTION); |
1da177e4c Linux-2.6.12-rc2 |
959 960 961 962 963 964 965 |
break; default: BUG(); } return ret; } |
5a7a5555a net sched: stylis... |
966 |
static struct nlattr *find_dump_kind(const struct nlmsghdr *n) |
1da177e4c Linux-2.6.12-rc2 |
967 |
{ |
cc7ec456f net_sched: cleanups |
968 |
struct nlattr *tb1, *tb2[TCA_ACT_MAX + 1]; |
7ba699c60 [NET_SCHED]: Conv... |
969 970 971 |
struct nlattr *tb[TCA_ACT_MAX_PRIO + 1]; struct nlattr *nla[TCAA_MAX + 1]; struct nlattr *kind; |
1da177e4c Linux-2.6.12-rc2 |
972 |
|
c96c9471d [NET_SCHED]: act_... |
973 |
if (nlmsg_parse(n, sizeof(struct tcamsg), nla, TCAA_MAX, NULL) < 0) |
1da177e4c Linux-2.6.12-rc2 |
974 |
return NULL; |
7ba699c60 [NET_SCHED]: Conv... |
975 |
tb1 = nla[TCA_ACT_TAB]; |
1da177e4c Linux-2.6.12-rc2 |
976 977 |
if (tb1 == NULL) return NULL; |
7ba699c60 [NET_SCHED]: Conv... |
978 979 |
if (nla_parse(tb, TCA_ACT_MAX_PRIO, nla_data(tb1), NLMSG_ALIGN(nla_len(tb1)), NULL) < 0) |
1da177e4c Linux-2.6.12-rc2 |
980 |
return NULL; |
1da177e4c Linux-2.6.12-rc2 |
981 |
|
6d834e04e [NET_SCHED]: act_... |
982 983 |
if (tb[1] == NULL) return NULL; |
4700e9ce6 net_sched actions... |
984 |
if (nla_parse_nested(tb2, TCA_ACT_MAX, tb[1], NULL) < 0) |
1da177e4c Linux-2.6.12-rc2 |
985 |
return NULL; |
7ba699c60 [NET_SCHED]: Conv... |
986 |
kind = tb2[TCA_ACT_KIND]; |
1da177e4c Linux-2.6.12-rc2 |
987 |
|
26dab8930 [PKT_SCHED]: Fix ... |
988 |
return kind; |
1da177e4c Linux-2.6.12-rc2 |
989 |
} |
5a7a5555a net sched: stylis... |
990 |
static int tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) |
1da177e4c Linux-2.6.12-rc2 |
991 |
{ |
ddf97ccdd net_sched: add ne... |
992 |
struct net *net = sock_net(skb->sk); |
1da177e4c Linux-2.6.12-rc2 |
993 |
struct nlmsghdr *nlh; |
27a884dc3 [SK_BUFF]: Conver... |
994 |
unsigned char *b = skb_tail_pointer(skb); |
4b3550ef5 [NET_SCHED]: Use ... |
995 |
struct nlattr *nest; |
1da177e4c Linux-2.6.12-rc2 |
996 |
struct tc_action_ops *a_o; |
1da177e4c Linux-2.6.12-rc2 |
997 |
int ret = 0; |
8b00a53c6 pkt_sched: act_ap... |
998 |
struct tcamsg *t = (struct tcamsg *) nlmsg_data(cb->nlh); |
7ba699c60 [NET_SCHED]: Conv... |
999 |
struct nlattr *kind = find_dump_kind(cb->nlh); |
1da177e4c Linux-2.6.12-rc2 |
1000 1001 |
if (kind == NULL) { |
6ff9c3644 net sched: printk... |
1002 1003 |
pr_info("tc_dump_action: action bad kind "); |
1da177e4c Linux-2.6.12-rc2 |
1004 1005 |
return 0; } |
26dab8930 [PKT_SCHED]: Fix ... |
1006 |
a_o = tc_lookup_action(kind); |
cc7ec456f net_sched: cleanups |
1007 |
if (a_o == NULL) |
1da177e4c Linux-2.6.12-rc2 |
1008 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
1009 |
|
15e473046 netlink: Rename p... |
1010 |
nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, |
8b00a53c6 pkt_sched: act_ap... |
1011 1012 1013 1014 |
cb->nlh->nlmsg_type, sizeof(*t), 0); if (!nlh) goto out_module_put; t = nlmsg_data(nlh); |
1da177e4c Linux-2.6.12-rc2 |
1015 |
t->tca_family = AF_UNSPEC; |
9ef1d4c7c [NETLINK]: Missin... |
1016 1017 |
t->tca__pad1 = 0; t->tca__pad2 = 0; |
1da177e4c Linux-2.6.12-rc2 |
1018 |
|
4b3550ef5 [NET_SCHED]: Use ... |
1019 1020 |
nest = nla_nest_start(skb, TCA_ACT_TAB); if (nest == NULL) |
8b00a53c6 pkt_sched: act_ap... |
1021 |
goto out_module_put; |
1da177e4c Linux-2.6.12-rc2 |
1022 |
|
a85a970af net_sched: move t... |
1023 |
ret = a_o->walk(net, skb, cb, RTM_GETACTION, a_o); |
1da177e4c Linux-2.6.12-rc2 |
1024 |
if (ret < 0) |
8b00a53c6 pkt_sched: act_ap... |
1025 |
goto out_module_put; |
1da177e4c Linux-2.6.12-rc2 |
1026 1027 |
if (ret > 0) { |
4b3550ef5 [NET_SCHED]: Use ... |
1028 |
nla_nest_end(skb, nest); |
1da177e4c Linux-2.6.12-rc2 |
1029 1030 |
ret = skb->len; } else |
ebecaa666 net sched actions... |
1031 |
nlmsg_trim(skb, b); |
1da177e4c Linux-2.6.12-rc2 |
1032 |
|
27a884dc3 [SK_BUFF]: Conver... |
1033 |
nlh->nlmsg_len = skb_tail_pointer(skb) - b; |
15e473046 netlink: Rename p... |
1034 |
if (NETLINK_CB(cb->skb).portid && ret) |
1da177e4c Linux-2.6.12-rc2 |
1035 1036 1037 |
nlh->nlmsg_flags |= NLM_F_MULTI; module_put(a_o->owner); return skb->len; |
8b00a53c6 pkt_sched: act_ap... |
1038 |
out_module_put: |
1da177e4c Linux-2.6.12-rc2 |
1039 |
module_put(a_o->owner); |
dc5fc579b [NETLINK]: Use nl... |
1040 |
nlmsg_trim(skb, b); |
1da177e4c Linux-2.6.12-rc2 |
1041 1042 1043 1044 1045 |
return skb->len; } static int __init tc_action_init(void) { |
c7ac8679b rtnetlink: Comput... |
1046 1047 1048 1049 |
rtnl_register(PF_UNSPEC, RTM_NEWACTION, tc_ctl_action, NULL, NULL); rtnl_register(PF_UNSPEC, RTM_DELACTION, tc_ctl_action, NULL, NULL); rtnl_register(PF_UNSPEC, RTM_GETACTION, tc_ctl_action, tc_dump_action, NULL); |
1da177e4c Linux-2.6.12-rc2 |
1050 |
|
1da177e4c Linux-2.6.12-rc2 |
1051 1052 1053 1054 |
return 0; } subsys_initcall(tc_action_init); |