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/netlink.h>
26
#include <linux/err.h>
27
#include <linux/slab.h>
28 29
#include <net/net_namespace.h>
#include <net/sock.h>
30
#include <net/netlink.h>
L
Linus Torvalds 已提交
31 32 33 34 35
#include <net/pkt_sched.h>
#include <net/pkt_cls.h>

/* The list of all installed classifier types */

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

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

/* Find classifier type by string name */

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

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

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 已提交
88
	for (tp = &tcf_proto_base; (t = *tp) != NULL; tp = &t->next)
L
Linus Torvalds 已提交
89 90 91 92 93 94 95 96 97 98 99
		if (t == ops)
			break;

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

102 103 104
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 已提交
105 106 107 108


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

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

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

	return first;
}

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

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

142 143
	if ((n->nlmsg_type != RTM_GETTFILTER) && !capable(CAP_NET_ADMIN))
		return -EPERM;
L
Linus Torvalds 已提交
144
replay:
145
	t = nlmsg_data(n);
L
Linus Torvalds 已提交
146 147 148 149 150 151 152 153
	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 已提交
154 155
		if (n->nlmsg_type != RTM_NEWTFILTER ||
		    !(n->nlmsg_flags & NLM_F_CREATE))
L
Linus Torvalds 已提交
156
			return -ENOENT;
157
		prio = TC_H_MAKE(0x80000000U, 0U);
L
Linus Torvalds 已提交
158 159 160 161 162
	}

	/* Find head of filter chain. */

	/* Find link */
163
	dev = __dev_get_by_index(net, t->tcm_ifindex);
164
	if (dev == NULL)
L
Linus Torvalds 已提交
165 166
		return -ENODEV;

167 168 169 170
	err = nlmsg_parse(n, sizeof(*t), tca, TCA_MAX, NULL);
	if (err < 0)
		return err;

L
Linus Torvalds 已提交
171 172
	/* 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 430 431
	struct tcf_dump_args arg;

	if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm)))
		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 503 504 505 506 507 508
{
#ifdef CONFIG_NET_CLS_ACT
	if (exts->action) {
		tcf_action_destroy(exts->action, TCA_ACT_UNBIND);
		exts->action = NULL;
	}
#endif
}
509
EXPORT_SYMBOL(tcf_exts_destroy);
L
Linus Torvalds 已提交
510

511
int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
512
		  struct nlattr *rate_tlv, struct tcf_exts *exts,
513
		  const struct tcf_ext_map *map)
L
Linus Torvalds 已提交
514 515
{
	memset(exts, 0, sizeof(*exts));
516

L
Linus Torvalds 已提交
517 518 519 520
#ifdef CONFIG_NET_CLS_ACT
	{
		struct tc_action *act;

521
		if (map->police && tb[map->police]) {
522
			act = tcf_action_init_1(net, tb[map->police], rate_tlv,
523
						"police", TCA_ACT_NOREPLACE,
524 525 526
						TCA_ACT_BIND);
			if (IS_ERR(act))
				return PTR_ERR(act);
L
Linus Torvalds 已提交
527 528 529

			act->type = TCA_OLD_COMPAT;
			exts->action = act;
530
		} else if (map->action && tb[map->action]) {
531 532 533
			act = tcf_action_init(net, tb[map->action], rate_tlv,
					      NULL, TCA_ACT_NOREPLACE,
					      TCA_ACT_BIND);
534 535
			if (IS_ERR(act))
				return PTR_ERR(act);
L
Linus Torvalds 已提交
536 537 538 539 540

			exts->action = act;
		}
	}
#else
541 542
	if ((map->action && tb[map->action]) ||
	    (map->police && tb[map->police]))
L
Linus Torvalds 已提交
543 544 545 546 547
		return -EOPNOTSUPP;
#endif

	return 0;
}
548
EXPORT_SYMBOL(tcf_exts_validate);
L
Linus Torvalds 已提交
549

550 551
void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst,
		     struct tcf_exts *src)
L
Linus Torvalds 已提交
552 553 554 555 556
{
#ifdef CONFIG_NET_CLS_ACT
	if (src->action) {
		struct tc_action *act;
		tcf_tree_lock(tp);
557 558
		act = dst->action;
		dst->action = src->action;
L
Linus Torvalds 已提交
559 560 561 562 563 564
		tcf_tree_unlock(tp);
		if (act)
			tcf_action_destroy(act, TCA_ACT_UNBIND);
	}
#endif
}
565
EXPORT_SYMBOL(tcf_exts_change);
L
Linus Torvalds 已提交
566

567
int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts,
568
		  const struct tcf_ext_map *map)
L
Linus Torvalds 已提交
569 570 571 572 573 574 575 576
{
#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
		 */
577
		struct nlattr *nest;
L
Linus Torvalds 已提交
578 579

		if (exts->action->type != TCA_OLD_COMPAT) {
580 581 582
			nest = nla_nest_start(skb, map->action);
			if (nest == NULL)
				goto nla_put_failure;
L
Linus Torvalds 已提交
583
			if (tcf_action_dump(skb, exts->action, 0, 0) < 0)
584
				goto nla_put_failure;
585
			nla_nest_end(skb, nest);
L
Linus Torvalds 已提交
586
		} else if (map->police) {
587 588 589
			nest = nla_nest_start(skb, map->police);
			if (nest == NULL)
				goto nla_put_failure;
L
Linus Torvalds 已提交
590
			if (tcf_action_dump_old(skb, exts->action, 0, 0) < 0)
591
				goto nla_put_failure;
592
			nla_nest_end(skb, nest);
L
Linus Torvalds 已提交
593 594 595 596
		}
	}
#endif
	return 0;
597
nla_put_failure: __attribute__ ((unused))
L
Linus Torvalds 已提交
598 599
	return -1;
}
600
EXPORT_SYMBOL(tcf_exts_dump);
L
Linus Torvalds 已提交
601

602 603

int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts,
604
			const struct tcf_ext_map *map)
L
Linus Torvalds 已提交
605 606 607 608
{
#ifdef CONFIG_NET_CLS_ACT
	if (exts->action)
		if (tcf_action_copy_stats(skb, exts->action, 1) < 0)
609
			goto nla_put_failure;
L
Linus Torvalds 已提交
610 611
#endif
	return 0;
612
nla_put_failure: __attribute__ ((unused))
L
Linus Torvalds 已提交
613 614
	return -1;
}
615
EXPORT_SYMBOL(tcf_exts_dump_stats);
L
Linus Torvalds 已提交
616 617 618

static int __init tc_filter_init(void)
{
619 620
	rtnl_register(PF_UNSPEC, RTM_NEWTFILTER, tc_ctl_tfilter, NULL, NULL);
	rtnl_register(PF_UNSPEC, RTM_DELTFILTER, tc_ctl_tfilter, NULL, NULL);
621
	rtnl_register(PF_UNSPEC, RTM_GETTFILTER, tc_ctl_tfilter,
622
		      tc_dump_tfilter, NULL);
L
Linus Torvalds 已提交
623 624 625 626 627

	return 0;
}

subsys_initcall(tc_filter_init);