Blame view
net/sched/cls_api.c
14 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* * net/sched/cls_api.c Packet classifier 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. * * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * * Changes: * * Eduardo J. Blanco <ejbs@netlabs.com.uy> :990222: kmod support * */ |
1da177e4c Linux-2.6.12-rc2 |
16 17 18 |
#include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> |
1da177e4c Linux-2.6.12-rc2 |
19 |
#include <linux/string.h> |
1da177e4c Linux-2.6.12-rc2 |
20 |
#include <linux/errno.h> |
1da177e4c Linux-2.6.12-rc2 |
21 |
#include <linux/skbuff.h> |
1da177e4c Linux-2.6.12-rc2 |
22 23 |
#include <linux/init.h> #include <linux/kmod.h> |
ab27cfb85 [NET_SCHED]: act_... |
24 |
#include <linux/err.h> |
5a0e3ad6a include cleanup: ... |
25 |
#include <linux/slab.h> |
b854272b3 [NET]: Modify all... |
26 27 |
#include <net/net_namespace.h> #include <net/sock.h> |
dc5fc579b [NETLINK]: Use nl... |
28 |
#include <net/netlink.h> |
1da177e4c Linux-2.6.12-rc2 |
29 30 |
#include <net/pkt_sched.h> #include <net/pkt_cls.h> |
1da177e4c Linux-2.6.12-rc2 |
31 |
/* The list of all installed classifier types */ |
362728746 net_sched: conver... |
32 |
static LIST_HEAD(tcf_proto_base); |
1da177e4c Linux-2.6.12-rc2 |
33 34 35 36 37 |
/* Protects list of registered TC modules. It is pure SMP lock. */ static DEFINE_RWLOCK(cls_mod_lock); /* Find classifier type by string name */ |
dc7f9f6e8 net: sched: const... |
38 |
static const struct tcf_proto_ops *tcf_proto_lookup_ops(struct nlattr *kind) |
1da177e4c Linux-2.6.12-rc2 |
39 |
{ |
dcd760813 net_sched: fix a ... |
40 |
const struct tcf_proto_ops *t, *res = NULL; |
1da177e4c Linux-2.6.12-rc2 |
41 42 43 |
if (kind) { read_lock(&cls_mod_lock); |
362728746 net_sched: conver... |
44 |
list_for_each_entry(t, &tcf_proto_base, head) { |
add93b610 [NET_SCHED]: Conv... |
45 |
if (nla_strcmp(kind, t->kind) == 0) { |
dcd760813 net_sched: fix a ... |
46 47 |
if (try_module_get(t->owner)) res = t; |
1da177e4c Linux-2.6.12-rc2 |
48 49 50 51 52 |
break; } } read_unlock(&cls_mod_lock); } |
dcd760813 net_sched: fix a ... |
53 |
return res; |
1da177e4c Linux-2.6.12-rc2 |
54 55 56 57 58 59 |
} /* Register(unregister) new classifier type */ int register_tcf_proto_ops(struct tcf_proto_ops *ops) { |
362728746 net_sched: conver... |
60 |
struct tcf_proto_ops *t; |
1da177e4c Linux-2.6.12-rc2 |
61 62 63 |
int rc = -EEXIST; write_lock(&cls_mod_lock); |
362728746 net_sched: conver... |
64 |
list_for_each_entry(t, &tcf_proto_base, head) |
1da177e4c Linux-2.6.12-rc2 |
65 66 |
if (!strcmp(ops->kind, t->kind)) goto out; |
362728746 net_sched: conver... |
67 |
list_add_tail(&ops->head, &tcf_proto_base); |
1da177e4c Linux-2.6.12-rc2 |
68 69 70 71 72 |
rc = 0; out: write_unlock(&cls_mod_lock); return rc; } |
aa767bfea [PKT_SCHED] net c... |
73 |
EXPORT_SYMBOL(register_tcf_proto_ops); |
1da177e4c Linux-2.6.12-rc2 |
74 75 76 |
int unregister_tcf_proto_ops(struct tcf_proto_ops *ops) { |
362728746 net_sched: conver... |
77 |
struct tcf_proto_ops *t; |
1da177e4c Linux-2.6.12-rc2 |
78 79 80 |
int rc = -ENOENT; write_lock(&cls_mod_lock); |
dcd760813 net_sched: fix a ... |
81 82 83 84 |
list_for_each_entry(t, &tcf_proto_base, head) { if (t == ops) { list_del(&t->head); rc = 0; |
1da177e4c Linux-2.6.12-rc2 |
85 |
break; |
dcd760813 net_sched: fix a ... |
86 87 |
} } |
1da177e4c Linux-2.6.12-rc2 |
88 89 90 |
write_unlock(&cls_mod_lock); return rc; } |
aa767bfea [PKT_SCHED] net c... |
91 |
EXPORT_SYMBOL(unregister_tcf_proto_ops); |
1da177e4c Linux-2.6.12-rc2 |
92 |
|
7316ae88c net_sched: make t... |
93 94 95 |
static int tfilter_notify(struct net *net, struct sk_buff *oskb, struct nlmsghdr *n, struct tcf_proto *tp, unsigned long fh, int event); |
1da177e4c Linux-2.6.12-rc2 |
96 97 98 |
/* Select new prio value from the range, managed by kernel. */ |
aa767bfea [PKT_SCHED] net c... |
99 |
static inline u32 tcf_auto_prio(struct tcf_proto *tp) |
1da177e4c Linux-2.6.12-rc2 |
100 |
{ |
aa767bfea [PKT_SCHED] net c... |
101 |
u32 first = TC_H_MAKE(0xC0000000U, 0U); |
1da177e4c Linux-2.6.12-rc2 |
102 103 |
if (tp) |
cc7ec456f net_sched: cleanups |
104 |
first = tp->prio - 1; |
1da177e4c Linux-2.6.12-rc2 |
105 106 107 108 109 |
return first; } /* Add/change/delete/get a filter node */ |
661d2967b rtnetlink: Remove... |
110 |
static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n) |
1da177e4c Linux-2.6.12-rc2 |
111 |
{ |
3b1e0a655 [NET] NETNS: Omit... |
112 |
struct net *net = sock_net(skb->sk); |
add93b610 [NET_SCHED]: Conv... |
113 |
struct nlattr *tca[TCA_MAX + 1]; |
55dbc640c pkt_sched: Remove... |
114 |
spinlock_t *root_lock; |
1da177e4c Linux-2.6.12-rc2 |
115 116 117 118 119 120 121 122 123 |
struct tcmsg *t; u32 protocol; u32 prio; u32 nprio; u32 parent; struct net_device *dev; struct Qdisc *q; struct tcf_proto **back, **chain; struct tcf_proto *tp; |
dc7f9f6e8 net: sched: const... |
124 |
const struct tcf_proto_ops *tp_ops; |
20fea08b5 [NET]: Move Qdisc... |
125 |
const struct Qdisc_class_ops *cops; |
1da177e4c Linux-2.6.12-rc2 |
126 127 128 |
unsigned long cl; unsigned long fh; int err; |
12186be7d net_cls: fix unco... |
129 |
int tp_created = 0; |
1da177e4c Linux-2.6.12-rc2 |
130 |
|
dfc47ef86 net: Push capable... |
131 132 |
if ((n->nlmsg_type != RTM_GETTFILTER) && !capable(CAP_NET_ADMIN)) return -EPERM; |
de179c8c1 netlink: have len... |
133 |
|
1da177e4c Linux-2.6.12-rc2 |
134 |
replay: |
de179c8c1 netlink: have len... |
135 136 137 |
err = nlmsg_parse(n, sizeof(*t), tca, TCA_MAX, NULL); if (err < 0) return err; |
942b81653 pkt_sched: cls_ap... |
138 |
t = nlmsg_data(n); |
1da177e4c Linux-2.6.12-rc2 |
139 140 141 142 143 144 145 146 |
protocol = TC_H_MIN(t->tcm_info); prio = TC_H_MAJ(t->tcm_info); nprio = prio; parent = t->tcm_parent; cl = 0; if (prio == 0) { /* If no priority is given, user wants we allocated it. */ |
cc7ec456f net_sched: cleanups |
147 148 |
if (n->nlmsg_type != RTM_NEWTFILTER || !(n->nlmsg_flags & NLM_F_CREATE)) |
1da177e4c Linux-2.6.12-rc2 |
149 |
return -ENOENT; |
aa767bfea [PKT_SCHED] net c... |
150 |
prio = TC_H_MAKE(0x80000000U, 0U); |
1da177e4c Linux-2.6.12-rc2 |
151 152 153 154 155 |
} /* Find head of filter chain. */ /* Find link */ |
7316ae88c net_sched: make t... |
156 |
dev = __dev_get_by_index(net, t->tcm_ifindex); |
aa767bfea [PKT_SCHED] net c... |
157 |
if (dev == NULL) |
1da177e4c Linux-2.6.12-rc2 |
158 159 160 161 |
return -ENODEV; /* Find qdisc */ if (!parent) { |
af356afa0 net_sched: reintr... |
162 |
q = dev->qdisc; |
1da177e4c Linux-2.6.12-rc2 |
163 |
parent = q->handle; |
aa767bfea [PKT_SCHED] net c... |
164 165 166 167 168 |
} else { q = qdisc_lookup(dev, TC_H_MAJ(t->tcm_parent)); if (q == NULL) return -EINVAL; } |
1da177e4c Linux-2.6.12-rc2 |
169 170 |
/* Is it classful? */ |
cc7ec456f net_sched: cleanups |
171 172 |
cops = q->ops->cl_ops; if (!cops) |
1da177e4c Linux-2.6.12-rc2 |
173 |
return -EINVAL; |
71ebe5e91 net_sched: make c... |
174 175 |
if (cops->tcf_chain == NULL) return -EOPNOTSUPP; |
1da177e4c Linux-2.6.12-rc2 |
176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
/* Do we search for filter, attached to class? */ if (TC_H_MIN(parent)) { cl = cops->get(q, parent); if (cl == 0) return -ENOENT; } /* And the last stroke */ chain = cops->tcf_chain(q, cl); err = -EINVAL; if (chain == NULL) goto errout; /* Check the chain for existence of proto-tcf with this priority */ |
cc7ec456f net_sched: cleanups |
190 |
for (back = chain; (tp = *back) != NULL; back = &tp->next) { |
1da177e4c Linux-2.6.12-rc2 |
191 192 |
if (tp->prio >= prio) { if (tp->prio == prio) { |
cc7ec456f net_sched: cleanups |
193 194 |
if (!nprio || (tp->protocol != protocol && protocol)) |
1da177e4c Linux-2.6.12-rc2 |
195 196 197 198 199 200 |
goto errout; } else tp = NULL; break; } } |
102396ae6 pkt_sched: Fix lo... |
201 |
root_lock = qdisc_root_sleeping_lock(q); |
55dbc640c pkt_sched: Remove... |
202 |
|
1da177e4c Linux-2.6.12-rc2 |
203 204 |
if (tp == NULL) { /* Proto-tcf does not exist, create new one */ |
add93b610 [NET_SCHED]: Conv... |
205 |
if (tca[TCA_KIND] == NULL || !protocol) |
1da177e4c Linux-2.6.12-rc2 |
206 207 208 |
goto errout; err = -ENOENT; |
cc7ec456f net_sched: cleanups |
209 210 |
if (n->nlmsg_type != RTM_NEWTFILTER || !(n->nlmsg_flags & NLM_F_CREATE)) |
1da177e4c Linux-2.6.12-rc2 |
211 212 213 214 215 216 |
goto errout; /* Create new proto tcf */ err = -ENOBUFS; |
aa767bfea [PKT_SCHED] net c... |
217 218 |
tp = kzalloc(sizeof(*tp), GFP_KERNEL); if (tp == NULL) |
1da177e4c Linux-2.6.12-rc2 |
219 |
goto errout; |
f2df82494 net_sched: cls_ap... |
220 |
err = -ENOENT; |
add93b610 [NET_SCHED]: Conv... |
221 |
tp_ops = tcf_proto_lookup_ops(tca[TCA_KIND]); |
1da177e4c Linux-2.6.12-rc2 |
222 |
if (tp_ops == NULL) { |
95a5afca4 net: Remove CONFI... |
223 |
#ifdef CONFIG_MODULES |
add93b610 [NET_SCHED]: Conv... |
224 |
struct nlattr *kind = tca[TCA_KIND]; |
1da177e4c Linux-2.6.12-rc2 |
225 226 227 |
char name[IFNAMSIZ]; if (kind != NULL && |
add93b610 [NET_SCHED]: Conv... |
228 |
nla_strlcpy(name, kind, IFNAMSIZ) < IFNAMSIZ) { |
1da177e4c Linux-2.6.12-rc2 |
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
rtnl_unlock(); request_module("cls_%s", name); rtnl_lock(); tp_ops = tcf_proto_lookup_ops(kind); /* We dropped the RTNL semaphore in order to * perform the module load. So, even if we * succeeded in loading the module we have to * replay the request. We indicate this using * -EAGAIN. */ if (tp_ops != NULL) { module_put(tp_ops->owner); err = -EAGAIN; } } #endif kfree(tp); goto errout; } |
1da177e4c Linux-2.6.12-rc2 |
248 249 |
tp->ops = tp_ops; tp->protocol = protocol; |
d0ab8ff81 net: Only store h... |
250 |
tp->prio = nprio ? : TC_H_MAJ(tcf_auto_prio(*back)); |
1da177e4c Linux-2.6.12-rc2 |
251 252 253 |
tp->q = q; tp->classify = tp_ops->classify; tp->classid = parent; |
aa767bfea [PKT_SCHED] net c... |
254 255 256 |
err = tp_ops->init(tp); if (err != 0) { |
1da177e4c Linux-2.6.12-rc2 |
257 258 259 260 |
module_put(tp_ops->owner); kfree(tp); goto errout; } |
12186be7d net_cls: fix unco... |
261 |
tp_created = 1; |
1da177e4c Linux-2.6.12-rc2 |
262 |
|
add93b610 [NET_SCHED]: Conv... |
263 |
} else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) |
1da177e4c Linux-2.6.12-rc2 |
264 265 266 267 268 269 |
goto errout; fh = tp->ops->get(tp, t->tcm_handle); if (fh == 0) { if (n->nlmsg_type == RTM_DELTFILTER && t->tcm_handle == 0) { |
55dbc640c pkt_sched: Remove... |
270 |
spin_lock_bh(root_lock); |
1da177e4c Linux-2.6.12-rc2 |
271 |
*back = tp->next; |
323c04883 pkt_sched: Fix un... |
272 |
spin_unlock_bh(root_lock); |
1da177e4c Linux-2.6.12-rc2 |
273 |
|
7316ae88c net_sched: make t... |
274 |
tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER); |
1da177e4c Linux-2.6.12-rc2 |
275 276 277 278 279 280 |
tcf_destroy(tp); err = 0; goto errout; } err = -ENOENT; |
aa767bfea [PKT_SCHED] net c... |
281 282 |
if (n->nlmsg_type != RTM_NEWTFILTER || !(n->nlmsg_flags & NLM_F_CREATE)) |
1da177e4c Linux-2.6.12-rc2 |
283 284 285 |
goto errout; } else { switch (n->nlmsg_type) { |
10297b993 [NET] SCHED: Fix ... |
286 |
case RTM_NEWTFILTER: |
1da177e4c Linux-2.6.12-rc2 |
287 |
err = -EEXIST; |
12186be7d net_cls: fix unco... |
288 289 290 |
if (n->nlmsg_flags & NLM_F_EXCL) { if (tp_created) tcf_destroy(tp); |
1da177e4c Linux-2.6.12-rc2 |
291 |
goto errout; |
12186be7d net_cls: fix unco... |
292 |
} |
1da177e4c Linux-2.6.12-rc2 |
293 294 295 296 |
break; case RTM_DELTFILTER: err = tp->ops->delete(tp, fh); if (err == 0) |
7316ae88c net_sched: make t... |
297 |
tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER); |
1da177e4c Linux-2.6.12-rc2 |
298 299 |
goto errout; case RTM_GETTFILTER: |
7316ae88c net_sched: make t... |
300 |
err = tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER); |
1da177e4c Linux-2.6.12-rc2 |
301 302 303 304 305 306 |
goto errout; default: err = -EINVAL; goto errout; } } |
c1b52739e pkt_sched: namesp... |
307 |
err = tp->ops->change(net, skb, tp, cl, t->tcm_handle, tca, &fh); |
12186be7d net_cls: fix unco... |
308 309 310 311 312 313 314 |
if (err == 0) { if (tp_created) { spin_lock_bh(root_lock); tp->next = *back; *back = tp; spin_unlock_bh(root_lock); } |
7316ae88c net_sched: make t... |
315 |
tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER); |
12186be7d net_cls: fix unco... |
316 317 318 319 |
} else { if (tp_created) tcf_destroy(tp); } |
1da177e4c Linux-2.6.12-rc2 |
320 321 322 323 324 325 326 327 328 |
errout: if (cl) cops->put(q, cl); if (err == -EAGAIN) /* Replay the request. */ goto replay; return err; } |
832d1d5bf net_sched: add st... |
329 |
static int tcf_fill_node(struct net *net, struct sk_buff *skb, struct tcf_proto *tp, |
15e473046 netlink: Rename p... |
330 |
unsigned long fh, u32 portid, u32 seq, u16 flags, int event) |
1da177e4c Linux-2.6.12-rc2 |
331 332 333 |
{ struct tcmsg *tcm; struct nlmsghdr *nlh; |
27a884dc3 [SK_BUFF]: Conver... |
334 |
unsigned char *b = skb_tail_pointer(skb); |
1da177e4c Linux-2.6.12-rc2 |
335 |
|
15e473046 netlink: Rename p... |
336 |
nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags); |
942b81653 pkt_sched: cls_ap... |
337 338 339 |
if (!nlh) goto out_nlmsg_trim; tcm = nlmsg_data(nlh); |
1da177e4c Linux-2.6.12-rc2 |
340 |
tcm->tcm_family = AF_UNSPEC; |
9ef1d4c7c [NETLINK]: Missin... |
341 |
tcm->tcm__pad1 = 0; |
ad61df918 netlink: fix typo... |
342 |
tcm->tcm__pad2 = 0; |
5ce2d488f pkt_sched: Remove... |
343 |
tcm->tcm_ifindex = qdisc_dev(tp->q)->ifindex; |
1da177e4c Linux-2.6.12-rc2 |
344 345 |
tcm->tcm_parent = tp->classid; tcm->tcm_info = TC_H_MAKE(tp->prio, tp->protocol); |
1b34ec43c pkt_sched: Stop u... |
346 347 |
if (nla_put_string(skb, TCA_KIND, tp->ops->kind)) goto nla_put_failure; |
1da177e4c Linux-2.6.12-rc2 |
348 349 350 |
tcm->tcm_handle = fh; if (RTM_DELTFILTER != event) { tcm->tcm_handle = 0; |
832d1d5bf net_sched: add st... |
351 |
if (tp->ops->dump && tp->ops->dump(net, tp, fh, skb, tcm) < 0) |
add93b610 [NET_SCHED]: Conv... |
352 |
goto nla_put_failure; |
1da177e4c Linux-2.6.12-rc2 |
353 |
} |
27a884dc3 [SK_BUFF]: Conver... |
354 |
nlh->nlmsg_len = skb_tail_pointer(skb) - b; |
1da177e4c Linux-2.6.12-rc2 |
355 |
return skb->len; |
942b81653 pkt_sched: cls_ap... |
356 |
out_nlmsg_trim: |
add93b610 [NET_SCHED]: Conv... |
357 |
nla_put_failure: |
dc5fc579b [NETLINK]: Use nl... |
358 |
nlmsg_trim(skb, b); |
1da177e4c Linux-2.6.12-rc2 |
359 360 |
return -1; } |
7316ae88c net_sched: make t... |
361 362 363 |
static int tfilter_notify(struct net *net, struct sk_buff *oskb, struct nlmsghdr *n, struct tcf_proto *tp, unsigned long fh, int event) |
1da177e4c Linux-2.6.12-rc2 |
364 365 |
{ struct sk_buff *skb; |
15e473046 netlink: Rename p... |
366 |
u32 portid = oskb ? NETLINK_CB(oskb).portid : 0; |
1da177e4c Linux-2.6.12-rc2 |
367 368 369 370 |
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb) return -ENOBUFS; |
832d1d5bf net_sched: add st... |
371 |
if (tcf_fill_node(net, skb, tp, fh, portid, n->nlmsg_seq, 0, event) <= 0) { |
1da177e4c Linux-2.6.12-rc2 |
372 373 374 |
kfree_skb(skb); return -EINVAL; } |
15e473046 netlink: Rename p... |
375 |
return rtnetlink_send(skb, net, portid, RTNLGRP_TC, |
aa767bfea [PKT_SCHED] net c... |
376 |
n->nlmsg_flags & NLM_F_ECHO); |
1da177e4c Linux-2.6.12-rc2 |
377 |
} |
aa767bfea [PKT_SCHED] net c... |
378 |
struct tcf_dump_args { |
1da177e4c Linux-2.6.12-rc2 |
379 380 381 382 |
struct tcf_walker w; struct sk_buff *skb; struct netlink_callback *cb; }; |
aa767bfea [PKT_SCHED] net c... |
383 384 |
static int tcf_node_dump(struct tcf_proto *tp, unsigned long n, struct tcf_walker *arg) |
1da177e4c Linux-2.6.12-rc2 |
385 |
{ |
aa767bfea [PKT_SCHED] net c... |
386 |
struct tcf_dump_args *a = (void *)arg; |
832d1d5bf net_sched: add st... |
387 |
struct net *net = sock_net(a->skb->sk); |
1da177e4c Linux-2.6.12-rc2 |
388 |
|
832d1d5bf net_sched: add st... |
389 |
return tcf_fill_node(net, a->skb, tp, n, NETLINK_CB(a->cb->skb).portid, |
1da177e4c Linux-2.6.12-rc2 |
390 391 |
a->cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTFILTER); } |
bd27a8750 net_cls: Use __de... |
392 |
/* called with RTNL */ |
1da177e4c Linux-2.6.12-rc2 |
393 394 |
static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) { |
3b1e0a655 [NET] NETNS: Omit... |
395 |
struct net *net = sock_net(skb->sk); |
1da177e4c Linux-2.6.12-rc2 |
396 397 398 399 400 |
int t; int s_t; struct net_device *dev; struct Qdisc *q; struct tcf_proto *tp, **chain; |
942b81653 pkt_sched: cls_ap... |
401 |
struct tcmsg *tcm = nlmsg_data(cb->nlh); |
1da177e4c Linux-2.6.12-rc2 |
402 |
unsigned long cl = 0; |
20fea08b5 [NET]: Move Qdisc... |
403 |
const struct Qdisc_class_ops *cops; |
1da177e4c Linux-2.6.12-rc2 |
404 |
struct tcf_dump_args arg; |
573ce260b net-next: replace... |
405 |
if (nlmsg_len(cb->nlh) < sizeof(*tcm)) |
1da177e4c Linux-2.6.12-rc2 |
406 |
return skb->len; |
cc7ec456f net_sched: cleanups |
407 408 |
dev = __dev_get_by_index(net, tcm->tcm_ifindex); if (!dev) |
1da177e4c Linux-2.6.12-rc2 |
409 |
return skb->len; |
1da177e4c Linux-2.6.12-rc2 |
410 |
if (!tcm->tcm_parent) |
af356afa0 net_sched: reintr... |
411 |
q = dev->qdisc; |
1da177e4c Linux-2.6.12-rc2 |
412 413 414 415 |
else q = qdisc_lookup(dev, TC_H_MAJ(tcm->tcm_parent)); if (!q) goto out; |
cc7ec456f net_sched: cleanups |
416 417 |
cops = q->ops->cl_ops; if (!cops) |
1da177e4c Linux-2.6.12-rc2 |
418 |
goto errout; |
71ebe5e91 net_sched: make c... |
419 420 |
if (cops->tcf_chain == NULL) goto errout; |
1da177e4c Linux-2.6.12-rc2 |
421 422 423 424 425 426 427 428 429 430 |
if (TC_H_MIN(tcm->tcm_parent)) { cl = cops->get(q, tcm->tcm_parent); if (cl == 0) goto errout; } chain = cops->tcf_chain(q, cl); if (chain == NULL) goto errout; s_t = cb->args[0]; |
cc7ec456f net_sched: cleanups |
431 432 433 |
for (tp = *chain, t = 0; tp; tp = tp->next, t++) { if (t < s_t) continue; |
1da177e4c Linux-2.6.12-rc2 |
434 435 436 437 438 439 440 441 442 |
if (TC_H_MAJ(tcm->tcm_info) && TC_H_MAJ(tcm->tcm_info) != tp->prio) continue; if (TC_H_MIN(tcm->tcm_info) && TC_H_MIN(tcm->tcm_info) != tp->protocol) continue; if (t > s_t) memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0])); if (cb->args[1] == 0) { |
832d1d5bf net_sched: add st... |
443 |
if (tcf_fill_node(net, skb, tp, 0, NETLINK_CB(cb->skb).portid, |
aa767bfea [PKT_SCHED] net c... |
444 445 |
cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTFILTER) <= 0) |
1da177e4c Linux-2.6.12-rc2 |
446 |
break; |
aa767bfea [PKT_SCHED] net c... |
447 |
|
1da177e4c Linux-2.6.12-rc2 |
448 449 450 451 452 453 454 455 |
cb->args[1] = 1; } if (tp->ops->walk == NULL) continue; arg.w.fn = tcf_node_dump; arg.skb = skb; arg.cb = cb; arg.w.stop = 0; |
cc7ec456f net_sched: cleanups |
456 |
arg.w.skip = cb->args[1] - 1; |
1da177e4c Linux-2.6.12-rc2 |
457 458 |
arg.w.count = 0; tp->ops->walk(tp, &arg.w); |
cc7ec456f net_sched: cleanups |
459 |
cb->args[1] = arg.w.count + 1; |
1da177e4c Linux-2.6.12-rc2 |
460 461 462 463 464 465 466 467 468 469 |
if (arg.w.stop) break; } cb->args[0] = t; errout: if (cl) cops->put(q, cl); out: |
1da177e4c Linux-2.6.12-rc2 |
470 471 |
return skb->len; } |
aa767bfea [PKT_SCHED] net c... |
472 |
void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts) |
1da177e4c Linux-2.6.12-rc2 |
473 474 |
{ #ifdef CONFIG_NET_CLS_ACT |
33be62715 net_sched: act: u... |
475 476 |
tcf_action_destroy(&exts->actions, TCA_ACT_UNBIND); INIT_LIST_HEAD(&exts->actions); |
1da177e4c Linux-2.6.12-rc2 |
477 478 |
#endif } |
aa767bfea [PKT_SCHED] net c... |
479 |
EXPORT_SYMBOL(tcf_exts_destroy); |
1da177e4c Linux-2.6.12-rc2 |
480 |
|
c1b52739e pkt_sched: namesp... |
481 |
int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb, |
5da57f422 net_sched: cls: r... |
482 |
struct nlattr *rate_tlv, struct tcf_exts *exts) |
1da177e4c Linux-2.6.12-rc2 |
483 |
{ |
1da177e4c Linux-2.6.12-rc2 |
484 485 |
#ifdef CONFIG_NET_CLS_ACT { |
1da177e4c Linux-2.6.12-rc2 |
486 |
struct tc_action *act; |
33be62715 net_sched: act: u... |
487 |
INIT_LIST_HEAD(&exts->actions); |
5da57f422 net_sched: cls: r... |
488 489 |
if (exts->police && tb[exts->police]) { act = tcf_action_init_1(net, tb[exts->police], rate_tlv, |
aa767bfea [PKT_SCHED] net c... |
490 |
"police", TCA_ACT_NOREPLACE, |
ab27cfb85 [NET_SCHED]: act_... |
491 492 493 |
TCA_ACT_BIND); if (IS_ERR(act)) return PTR_ERR(act); |
1da177e4c Linux-2.6.12-rc2 |
494 |
|
33be62715 net_sched: act: u... |
495 496 |
act->type = exts->type = TCA_OLD_COMPAT; list_add(&act->list, &exts->actions); |
5da57f422 net_sched: cls: r... |
497 |
} else if (exts->action && tb[exts->action]) { |
33be62715 net_sched: act: u... |
498 |
int err; |
5da57f422 net_sched: cls: r... |
499 |
err = tcf_action_init(net, tb[exts->action], rate_tlv, |
c1b52739e pkt_sched: namesp... |
500 |
NULL, TCA_ACT_NOREPLACE, |
33be62715 net_sched: act: u... |
501 502 503 |
TCA_ACT_BIND, &exts->actions); if (err) return err; |
1da177e4c Linux-2.6.12-rc2 |
504 505 |
} } |
1da177e4c Linux-2.6.12-rc2 |
506 |
#else |
5da57f422 net_sched: cls: r... |
507 508 |
if ((exts->action && tb[exts->action]) || (exts->police && tb[exts->police])) |
1da177e4c Linux-2.6.12-rc2 |
509 510 511 512 513 |
return -EOPNOTSUPP; #endif return 0; } |
aa767bfea [PKT_SCHED] net c... |
514 |
EXPORT_SYMBOL(tcf_exts_validate); |
1da177e4c Linux-2.6.12-rc2 |
515 |
|
aa767bfea [PKT_SCHED] net c... |
516 517 |
void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst, struct tcf_exts *src) |
1da177e4c Linux-2.6.12-rc2 |
518 519 |
{ #ifdef CONFIG_NET_CLS_ACT |
33be62715 net_sched: act: u... |
520 521 |
if (!list_empty(&src->actions)) { LIST_HEAD(tmp); |
1da177e4c Linux-2.6.12-rc2 |
522 |
tcf_tree_lock(tp); |
33be62715 net_sched: act: u... |
523 524 |
list_splice_init(&dst->actions, &tmp); list_splice(&src->actions, &dst->actions); |
1da177e4c Linux-2.6.12-rc2 |
525 |
tcf_tree_unlock(tp); |
33be62715 net_sched: act: u... |
526 |
tcf_action_destroy(&tmp, TCA_ACT_UNBIND); |
1da177e4c Linux-2.6.12-rc2 |
527 |
} |
1da177e4c Linux-2.6.12-rc2 |
528 529 |
#endif } |
aa767bfea [PKT_SCHED] net c... |
530 |
EXPORT_SYMBOL(tcf_exts_change); |
1da177e4c Linux-2.6.12-rc2 |
531 |
|
33be62715 net_sched: act: u... |
532 533 |
#define tcf_exts_first_act(ext) \ list_first_entry(&(exts)->actions, struct tc_action, list) |
5da57f422 net_sched: cls: r... |
534 |
int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts) |
1da177e4c Linux-2.6.12-rc2 |
535 536 |
{ #ifdef CONFIG_NET_CLS_ACT |
5da57f422 net_sched: cls: r... |
537 |
if (exts->action && !list_empty(&exts->actions)) { |
1da177e4c Linux-2.6.12-rc2 |
538 539 540 541 542 |
/* * again for backward compatible mode - we want * to work with both old and new modes of entering * tc data even if iproute2 was newer - jhs */ |
4b3550ef5 [NET_SCHED]: Use ... |
543 |
struct nlattr *nest; |
33be62715 net_sched: act: u... |
544 |
if (exts->type != TCA_OLD_COMPAT) { |
5da57f422 net_sched: cls: r... |
545 |
nest = nla_nest_start(skb, exts->action); |
4b3550ef5 [NET_SCHED]: Use ... |
546 547 |
if (nest == NULL) goto nla_put_failure; |
33be62715 net_sched: act: u... |
548 |
if (tcf_action_dump(skb, &exts->actions, 0, 0) < 0) |
add93b610 [NET_SCHED]: Conv... |
549 |
goto nla_put_failure; |
4b3550ef5 [NET_SCHED]: Use ... |
550 |
nla_nest_end(skb, nest); |
5da57f422 net_sched: cls: r... |
551 |
} else if (exts->police) { |
33be62715 net_sched: act: u... |
552 |
struct tc_action *act = tcf_exts_first_act(exts); |
5da57f422 net_sched: cls: r... |
553 |
nest = nla_nest_start(skb, exts->police); |
63acd6807 net_sched: Remove... |
554 |
if (nest == NULL || !act) |
4b3550ef5 [NET_SCHED]: Use ... |
555 |
goto nla_put_failure; |
33be62715 net_sched: act: u... |
556 |
if (tcf_action_dump_old(skb, act, 0, 0) < 0) |
add93b610 [NET_SCHED]: Conv... |
557 |
goto nla_put_failure; |
4b3550ef5 [NET_SCHED]: Use ... |
558 |
nla_nest_end(skb, nest); |
1da177e4c Linux-2.6.12-rc2 |
559 560 |
} } |
1da177e4c Linux-2.6.12-rc2 |
561 562 |
#endif return 0; |
add93b610 [NET_SCHED]: Conv... |
563 |
nla_put_failure: __attribute__ ((unused)) |
1da177e4c Linux-2.6.12-rc2 |
564 565 |
return -1; } |
aa767bfea [PKT_SCHED] net c... |
566 |
EXPORT_SYMBOL(tcf_exts_dump); |
1da177e4c Linux-2.6.12-rc2 |
567 |
|
aa767bfea [PKT_SCHED] net c... |
568 |
|
5da57f422 net_sched: cls: r... |
569 |
int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts) |
1da177e4c Linux-2.6.12-rc2 |
570 571 |
{ #ifdef CONFIG_NET_CLS_ACT |
33be62715 net_sched: act: u... |
572 573 574 |
struct tc_action *a = tcf_exts_first_act(exts); if (tcf_action_copy_stats(skb, a, 1) < 0) return -1; |
1da177e4c Linux-2.6.12-rc2 |
575 576 |
#endif return 0; |
1da177e4c Linux-2.6.12-rc2 |
577 |
} |
aa767bfea [PKT_SCHED] net c... |
578 |
EXPORT_SYMBOL(tcf_exts_dump_stats); |
1da177e4c Linux-2.6.12-rc2 |
579 580 581 |
static int __init tc_filter_init(void) { |
c7ac8679b rtnetlink: Comput... |
582 583 |
rtnl_register(PF_UNSPEC, RTM_NEWTFILTER, tc_ctl_tfilter, NULL, NULL); rtnl_register(PF_UNSPEC, RTM_DELTFILTER, tc_ctl_tfilter, NULL, NULL); |
82623c0d7 [PKT_SCHED] cls: ... |
584 |
rtnl_register(PF_UNSPEC, RTM_GETTFILTER, tc_ctl_tfilter, |
c7ac8679b rtnetlink: Comput... |
585 |
tc_dump_tfilter, NULL); |
1da177e4c Linux-2.6.12-rc2 |
586 |
|
1da177e4c Linux-2.6.12-rc2 |
587 588 589 590 |
return 0; } subsys_initcall(tc_filter_init); |