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