cls_api.c 13.9 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * 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
 *
 */

#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/kmod.h>
25
#include <linux/err.h>
26
#include <linux/slab.h>
27 28
#include <net/net_namespace.h>
#include <net/sock.h>
29
#include <net/netlink.h>
L
Linus Torvalds 已提交
30 31 32 33 34
#include <net/pkt_sched.h>
#include <net/pkt_cls.h>

/* The list of all installed classifier types */

35
static struct tcf_proto_ops *tcf_proto_base __read_mostly;
L
Linus Torvalds 已提交
36 37 38 39 40 41

/* Protects list of registered TC modules. It is pure SMP lock. */
static DEFINE_RWLOCK(cls_mod_lock);

/* Find classifier type by string name */

42
static const struct tcf_proto_ops *tcf_proto_lookup_ops(struct nlattr *kind)
L
Linus Torvalds 已提交
43
{
44
	const struct tcf_proto_ops *t = NULL;
L
Linus Torvalds 已提交
45 46 47 48

	if (kind) {
		read_lock(&cls_mod_lock);
		for (t = tcf_proto_base; t; t = t->next) {
49
			if (nla_strcmp(kind, t->kind) == 0) {
L
Linus Torvalds 已提交
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 76 77 78
				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;
}
79
EXPORT_SYMBOL(register_tcf_proto_ops);
L
Linus Torvalds 已提交
80 81 82 83 84 85 86

int unregister_tcf_proto_ops(struct tcf_proto_ops *ops)
{
	struct tcf_proto_ops *t, **tp;
	int rc = -ENOENT;

	write_lock(&cls_mod_lock);
E
Eric Dumazet 已提交
87
	for (tp = &tcf_proto_base; (t = *tp) != NULL; tp = &t->next)
L
Linus Torvalds 已提交
88 89 90 91 92 93 94 95 96 97 98
		if (t == ops)
			break;

	if (!t)
		goto out;
	*tp = t->next;
	rc = 0;
out:
	write_unlock(&cls_mod_lock);
	return rc;
}
99
EXPORT_SYMBOL(unregister_tcf_proto_ops);
L
Linus Torvalds 已提交
100

101 102 103
static int tfilter_notify(struct net *net, struct sk_buff *oskb,
			  struct nlmsghdr *n, struct tcf_proto *tp,
			  unsigned long fh, int event);
L
Linus Torvalds 已提交
104 105 106 107


/* Select new prio value from the range, managed by kernel. */

108
static inline u32 tcf_auto_prio(struct tcf_proto *tp)
L
Linus Torvalds 已提交
109
{
110
	u32 first = TC_H_MAKE(0xC0000000U, 0U);
L
Linus Torvalds 已提交
111 112

	if (tp)
E
Eric Dumazet 已提交
113
		first = tp->prio - 1;
L
Linus Torvalds 已提交
114 115 116 117 118 119

	return first;
}

/* Add/change/delete/get a filter node */

120
static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n)
L
Linus Torvalds 已提交
121
{
122
	struct net *net = sock_net(skb->sk);
123
	struct nlattr *tca[TCA_MAX + 1];
124
	spinlock_t *root_lock;
L
Linus Torvalds 已提交
125 126 127 128 129 130 131 132 133
	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;
134
	const struct tcf_proto_ops *tp_ops;
135
	const struct Qdisc_class_ops *cops;
L
Linus Torvalds 已提交
136 137 138
	unsigned long cl;
	unsigned long fh;
	int err;
139
	int tp_created = 0;
L
Linus Torvalds 已提交
140

141 142
	if ((n->nlmsg_type != RTM_GETTFILTER) && !capable(CAP_NET_ADMIN))
		return -EPERM;
143

L
Linus Torvalds 已提交
144
replay:
145 146 147 148
	err = nlmsg_parse(n, sizeof(*t), tca, TCA_MAX, NULL);
	if (err < 0)
		return err;

149
	t = nlmsg_data(n);
L
Linus Torvalds 已提交
150 151 152 153 154 155 156 157
	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. */
E
Eric Dumazet 已提交
158 159
		if (n->nlmsg_type != RTM_NEWTFILTER ||
		    !(n->nlmsg_flags & NLM_F_CREATE))
L
Linus Torvalds 已提交
160
			return -ENOENT;
161
		prio = TC_H_MAKE(0x80000000U, 0U);
L
Linus Torvalds 已提交
162 163 164 165 166
	}

	/* Find head of filter chain. */

	/* Find link */
167
	dev = __dev_get_by_index(net, t->tcm_ifindex);
168
	if (dev == NULL)
L
Linus Torvalds 已提交
169 170 171 172
		return -ENODEV;

	/* Find qdisc */
	if (!parent) {
173
		q = dev->qdisc;
L
Linus Torvalds 已提交
174
		parent = q->handle;
175 176 177 178 179
	} else {
		q = qdisc_lookup(dev, TC_H_MAJ(t->tcm_parent));
		if (q == NULL)
			return -EINVAL;
	}
L
Linus Torvalds 已提交
180 181

	/* Is it classful? */
E
Eric Dumazet 已提交
182 183
	cops = q->ops->cl_ops;
	if (!cops)
L
Linus Torvalds 已提交
184 185
		return -EINVAL;

186 187 188
	if (cops->tcf_chain == NULL)
		return -EOPNOTSUPP;

L
Linus Torvalds 已提交
189 190 191 192 193 194 195 196 197 198 199 200 201 202
	/* 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 */
E
Eric Dumazet 已提交
203
	for (back = chain; (tp = *back) != NULL; back = &tp->next) {
L
Linus Torvalds 已提交
204 205
		if (tp->prio >= prio) {
			if (tp->prio == prio) {
E
Eric Dumazet 已提交
206 207
				if (!nprio ||
				    (tp->protocol != protocol && protocol))
L
Linus Torvalds 已提交
208 209 210 211 212 213 214
					goto errout;
			} else
				tp = NULL;
			break;
		}
	}

215
	root_lock = qdisc_root_sleeping_lock(q);
216

L
Linus Torvalds 已提交
217 218 219
	if (tp == NULL) {
		/* Proto-tcf does not exist, create new one */

220
		if (tca[TCA_KIND] == NULL || !protocol)
L
Linus Torvalds 已提交
221 222 223
			goto errout;

		err = -ENOENT;
E
Eric Dumazet 已提交
224 225
		if (n->nlmsg_type != RTM_NEWTFILTER ||
		    !(n->nlmsg_flags & NLM_F_CREATE))
L
Linus Torvalds 已提交
226 227 228 229 230 231
			goto errout;


		/* Create new proto tcf */

		err = -ENOBUFS;
232 233
		tp = kzalloc(sizeof(*tp), GFP_KERNEL);
		if (tp == NULL)
L
Linus Torvalds 已提交
234
			goto errout;
235
		err = -ENOENT;
236
		tp_ops = tcf_proto_lookup_ops(tca[TCA_KIND]);
L
Linus Torvalds 已提交
237
		if (tp_ops == NULL) {
238
#ifdef CONFIG_MODULES
239
			struct nlattr *kind = tca[TCA_KIND];
L
Linus Torvalds 已提交
240 241 242
			char name[IFNAMSIZ];

			if (kind != NULL &&
243
			    nla_strlcpy(name, kind, IFNAMSIZ) < IFNAMSIZ) {
L
Linus Torvalds 已提交
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
				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;
		}
		tp->ops = tp_ops;
		tp->protocol = protocol;
265
		tp->prio = nprio ? : TC_H_MAJ(tcf_auto_prio(*back));
L
Linus Torvalds 已提交
266 267 268
		tp->q = q;
		tp->classify = tp_ops->classify;
		tp->classid = parent;
269 270 271

		err = tp_ops->init(tp);
		if (err != 0) {
L
Linus Torvalds 已提交
272 273 274 275 276
			module_put(tp_ops->owner);
			kfree(tp);
			goto errout;
		}

277
		tp_created = 1;
L
Linus Torvalds 已提交
278

279
	} else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind))
L
Linus Torvalds 已提交
280 281 282 283 284 285
		goto errout;

	fh = tp->ops->get(tp, t->tcm_handle);

	if (fh == 0) {
		if (n->nlmsg_type == RTM_DELTFILTER && t->tcm_handle == 0) {
286
			spin_lock_bh(root_lock);
L
Linus Torvalds 已提交
287
			*back = tp->next;
288
			spin_unlock_bh(root_lock);
L
Linus Torvalds 已提交
289

290
			tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER);
L
Linus Torvalds 已提交
291 292 293 294 295 296
			tcf_destroy(tp);
			err = 0;
			goto errout;
		}

		err = -ENOENT;
297 298
		if (n->nlmsg_type != RTM_NEWTFILTER ||
		    !(n->nlmsg_flags & NLM_F_CREATE))
L
Linus Torvalds 已提交
299 300 301
			goto errout;
	} else {
		switch (n->nlmsg_type) {
302
		case RTM_NEWTFILTER:
L
Linus Torvalds 已提交
303
			err = -EEXIST;
304 305 306
			if (n->nlmsg_flags & NLM_F_EXCL) {
				if (tp_created)
					tcf_destroy(tp);
L
Linus Torvalds 已提交
307
				goto errout;
308
			}
L
Linus Torvalds 已提交
309 310 311 312
			break;
		case RTM_DELTFILTER:
			err = tp->ops->delete(tp, fh);
			if (err == 0)
313
				tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER);
L
Linus Torvalds 已提交
314 315
			goto errout;
		case RTM_GETTFILTER:
316
			err = tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER);
L
Linus Torvalds 已提交
317 318 319 320 321 322 323
			goto errout;
		default:
			err = -EINVAL;
			goto errout;
		}
	}

324
	err = tp->ops->change(net, skb, tp, cl, t->tcm_handle, tca, &fh);
325 326 327 328 329 330 331
	if (err == 0) {
		if (tp_created) {
			spin_lock_bh(root_lock);
			tp->next = *back;
			*back = tp;
			spin_unlock_bh(root_lock);
		}
332
		tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER);
333 334 335 336
	} else {
		if (tp_created)
			tcf_destroy(tp);
	}
L
Linus Torvalds 已提交
337 338 339 340 341 342 343 344 345 346

errout:
	if (cl)
		cops->put(q, cl);
	if (err == -EAGAIN)
		/* Replay the request. */
		goto replay;
	return err;
}

347
static int tcf_fill_node(struct sk_buff *skb, struct tcf_proto *tp,
348
			 unsigned long fh, u32 portid, u32 seq, u16 flags, int event)
L
Linus Torvalds 已提交
349 350 351
{
	struct tcmsg *tcm;
	struct nlmsghdr  *nlh;
352
	unsigned char *b = skb_tail_pointer(skb);
L
Linus Torvalds 已提交
353

354
	nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags);
355 356 357
	if (!nlh)
		goto out_nlmsg_trim;
	tcm = nlmsg_data(nlh);
L
Linus Torvalds 已提交
358
	tcm->tcm_family = AF_UNSPEC;
359
	tcm->tcm__pad1 = 0;
J
Jiri Pirko 已提交
360
	tcm->tcm__pad2 = 0;
361
	tcm->tcm_ifindex = qdisc_dev(tp->q)->ifindex;
L
Linus Torvalds 已提交
362 363
	tcm->tcm_parent = tp->classid;
	tcm->tcm_info = TC_H_MAKE(tp->prio, tp->protocol);
364 365
	if (nla_put_string(skb, TCA_KIND, tp->ops->kind))
		goto nla_put_failure;
L
Linus Torvalds 已提交
366 367 368 369
	tcm->tcm_handle = fh;
	if (RTM_DELTFILTER != event) {
		tcm->tcm_handle = 0;
		if (tp->ops->dump && tp->ops->dump(tp, fh, skb, tcm) < 0)
370
			goto nla_put_failure;
L
Linus Torvalds 已提交
371
	}
372
	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
L
Linus Torvalds 已提交
373 374
	return skb->len;

375
out_nlmsg_trim:
376
nla_put_failure:
377
	nlmsg_trim(skb, b);
L
Linus Torvalds 已提交
378 379 380
	return -1;
}

381 382 383
static int tfilter_notify(struct net *net, struct sk_buff *oskb,
			  struct nlmsghdr *n, struct tcf_proto *tp,
			  unsigned long fh, int event)
L
Linus Torvalds 已提交
384 385
{
	struct sk_buff *skb;
386
	u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
L
Linus Torvalds 已提交
387 388 389 390 391

	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
	if (!skb)
		return -ENOBUFS;

392
	if (tcf_fill_node(skb, tp, fh, portid, n->nlmsg_seq, 0, event) <= 0) {
L
Linus Torvalds 已提交
393 394 395 396
		kfree_skb(skb);
		return -EINVAL;
	}

397
	return rtnetlink_send(skb, net, portid, RTNLGRP_TC,
398
			      n->nlmsg_flags & NLM_F_ECHO);
L
Linus Torvalds 已提交
399 400
}

401
struct tcf_dump_args {
L
Linus Torvalds 已提交
402 403 404 405 406
	struct tcf_walker w;
	struct sk_buff *skb;
	struct netlink_callback *cb;
};

407 408
static int tcf_node_dump(struct tcf_proto *tp, unsigned long n,
			 struct tcf_walker *arg)
L
Linus Torvalds 已提交
409
{
410
	struct tcf_dump_args *a = (void *)arg;
L
Linus Torvalds 已提交
411

412
	return tcf_fill_node(a->skb, tp, n, NETLINK_CB(a->cb->skb).portid,
L
Linus Torvalds 已提交
413 414 415
			     a->cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTFILTER);
}

E
Eric Dumazet 已提交
416
/* called with RTNL */
L
Linus Torvalds 已提交
417 418
static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
{
419
	struct net *net = sock_net(skb->sk);
L
Linus Torvalds 已提交
420 421 422 423 424
	int t;
	int s_t;
	struct net_device *dev;
	struct Qdisc *q;
	struct tcf_proto *tp, **chain;
425
	struct tcmsg *tcm = nlmsg_data(cb->nlh);
L
Linus Torvalds 已提交
426
	unsigned long cl = 0;
427
	const struct Qdisc_class_ops *cops;
L
Linus Torvalds 已提交
428 429
	struct tcf_dump_args arg;

430
	if (nlmsg_len(cb->nlh) < sizeof(*tcm))
L
Linus Torvalds 已提交
431
		return skb->len;
E
Eric Dumazet 已提交
432 433
	dev = __dev_get_by_index(net, tcm->tcm_ifindex);
	if (!dev)
L
Linus Torvalds 已提交
434 435 436
		return skb->len;

	if (!tcm->tcm_parent)
437
		q = dev->qdisc;
L
Linus Torvalds 已提交
438 439 440 441
	else
		q = qdisc_lookup(dev, TC_H_MAJ(tcm->tcm_parent));
	if (!q)
		goto out;
E
Eric Dumazet 已提交
442 443
	cops = q->ops->cl_ops;
	if (!cops)
L
Linus Torvalds 已提交
444
		goto errout;
445 446
	if (cops->tcf_chain == NULL)
		goto errout;
L
Linus Torvalds 已提交
447 448 449 450 451 452 453 454 455 456 457
	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];

E
Eric Dumazet 已提交
458 459 460
	for (tp = *chain, t = 0; tp; tp = tp->next, t++) {
		if (t < s_t)
			continue;
L
Linus Torvalds 已提交
461 462 463 464 465 466 467 468 469
		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) {
470
			if (tcf_fill_node(skb, tp, 0, NETLINK_CB(cb->skb).portid,
471 472
					  cb->nlh->nlmsg_seq, NLM_F_MULTI,
					  RTM_NEWTFILTER) <= 0)
L
Linus Torvalds 已提交
473
				break;
474

L
Linus Torvalds 已提交
475 476 477 478 479 480 481 482
			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;
E
Eric Dumazet 已提交
483
		arg.w.skip = cb->args[1] - 1;
L
Linus Torvalds 已提交
484 485
		arg.w.count = 0;
		tp->ops->walk(tp, &arg.w);
E
Eric Dumazet 已提交
486
		cb->args[1] = arg.w.count + 1;
L
Linus Torvalds 已提交
487 488 489 490 491 492 493 494 495 496 497 498 499
		if (arg.w.stop)
			break;
	}

	cb->args[0] = t;

errout:
	if (cl)
		cops->put(q, cl);
out:
	return skb->len;
}

500
void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts)
L
Linus Torvalds 已提交
501 502
{
#ifdef CONFIG_NET_CLS_ACT
503 504
	tcf_action_destroy(&exts->actions, TCA_ACT_UNBIND);
	INIT_LIST_HEAD(&exts->actions);
L
Linus Torvalds 已提交
505 506
#endif
}
507
EXPORT_SYMBOL(tcf_exts_destroy);
L
Linus Torvalds 已提交
508

509
int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
510
		  struct nlattr *rate_tlv, struct tcf_exts *exts)
L
Linus Torvalds 已提交
511 512 513 514 515
{
#ifdef CONFIG_NET_CLS_ACT
	{
		struct tc_action *act;

516
		INIT_LIST_HEAD(&exts->actions);
517 518
		if (exts->police && tb[exts->police]) {
			act = tcf_action_init_1(net, tb[exts->police], rate_tlv,
519
						"police", TCA_ACT_NOREPLACE,
520 521 522
						TCA_ACT_BIND);
			if (IS_ERR(act))
				return PTR_ERR(act);
L
Linus Torvalds 已提交
523

524 525
			act->type = exts->type = TCA_OLD_COMPAT;
			list_add(&act->list, &exts->actions);
526
		} else if (exts->action && tb[exts->action]) {
527
			int err;
528
			err = tcf_action_init(net, tb[exts->action], rate_tlv,
529
					      NULL, TCA_ACT_NOREPLACE,
530 531 532
					      TCA_ACT_BIND, &exts->actions);
			if (err)
				return err;
L
Linus Torvalds 已提交
533 534 535
		}
	}
#else
536 537
	if ((exts->action && tb[exts->action]) ||
	    (exts->police && tb[exts->police]))
L
Linus Torvalds 已提交
538 539 540 541 542
		return -EOPNOTSUPP;
#endif

	return 0;
}
543
EXPORT_SYMBOL(tcf_exts_validate);
L
Linus Torvalds 已提交
544

545 546
void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst,
		     struct tcf_exts *src)
L
Linus Torvalds 已提交
547 548
{
#ifdef CONFIG_NET_CLS_ACT
549 550
	if (!list_empty(&src->actions)) {
		LIST_HEAD(tmp);
L
Linus Torvalds 已提交
551
		tcf_tree_lock(tp);
552 553
		list_splice_init(&dst->actions, &tmp);
		list_splice(&src->actions, &dst->actions);
L
Linus Torvalds 已提交
554
		tcf_tree_unlock(tp);
555
		tcf_action_destroy(&tmp, TCA_ACT_UNBIND);
L
Linus Torvalds 已提交
556 557 558
	}
#endif
}
559
EXPORT_SYMBOL(tcf_exts_change);
L
Linus Torvalds 已提交
560

561 562 563
#define tcf_exts_first_act(ext) \
		list_first_entry(&(exts)->actions, struct tc_action, list)

564
int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts)
L
Linus Torvalds 已提交
565 566
{
#ifdef CONFIG_NET_CLS_ACT
567
	if (exts->action && !list_empty(&exts->actions)) {
L
Linus Torvalds 已提交
568 569 570 571 572
		/*
		 * 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
		 */
573
		struct nlattr *nest;
574
		if (exts->type != TCA_OLD_COMPAT) {
575
			nest = nla_nest_start(skb, exts->action);
576 577
			if (nest == NULL)
				goto nla_put_failure;
578
			if (tcf_action_dump(skb, &exts->actions, 0, 0) < 0)
579
				goto nla_put_failure;
580
			nla_nest_end(skb, nest);
581
		} else if (exts->police) {
582
			struct tc_action *act = tcf_exts_first_act(exts);
583
			nest = nla_nest_start(skb, exts->police);
584 585
			if (nest == NULL)
				goto nla_put_failure;
586
			if (tcf_action_dump_old(skb, act, 0, 0) < 0)
587
				goto nla_put_failure;
588
			nla_nest_end(skb, nest);
L
Linus Torvalds 已提交
589 590 591 592
		}
	}
#endif
	return 0;
593
nla_put_failure: __attribute__ ((unused))
L
Linus Torvalds 已提交
594 595
	return -1;
}
596
EXPORT_SYMBOL(tcf_exts_dump);
L
Linus Torvalds 已提交
597

598

599
int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts)
L
Linus Torvalds 已提交
600 601
{
#ifdef CONFIG_NET_CLS_ACT
602 603 604
	struct tc_action *a = tcf_exts_first_act(exts);
	if (tcf_action_copy_stats(skb, a, 1) < 0)
		return -1;
L
Linus Torvalds 已提交
605 606 607
#endif
	return 0;
}
608
EXPORT_SYMBOL(tcf_exts_dump_stats);
L
Linus Torvalds 已提交
609 610 611

static int __init tc_filter_init(void)
{
612 613
	rtnl_register(PF_UNSPEC, RTM_NEWTFILTER, tc_ctl_tfilter, NULL, NULL);
	rtnl_register(PF_UNSPEC, RTM_DELTFILTER, tc_ctl_tfilter, NULL, NULL);
614
	rtnl_register(PF_UNSPEC, RTM_GETTFILTER, tc_ctl_tfilter,
615
		      tc_dump_tfilter, NULL);
L
Linus Torvalds 已提交
616 617 618 619 620

	return 0;
}

subsys_initcall(tc_filter_init);