cls_api.c 28.8 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
/*
 * 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>
22
#include <linux/err.h>
L
Linus Torvalds 已提交
23 24 25
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/kmod.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
#include <net/pkt_sched.h>
#include <net/pkt_cls.h>

/* The list of all installed classifier types */
34
static LIST_HEAD(tcf_proto_base);
L
Linus Torvalds 已提交
35 36 37 38 39 40

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

/* Find classifier type by string name */

41
static const struct tcf_proto_ops *tcf_proto_lookup_ops(const char *kind)
L
Linus Torvalds 已提交
42
{
43
	const struct tcf_proto_ops *t, *res = NULL;
L
Linus Torvalds 已提交
44 45 46

	if (kind) {
		read_lock(&cls_mod_lock);
47
		list_for_each_entry(t, &tcf_proto_base, head) {
48
			if (strcmp(kind, t->kind) == 0) {
49 50
				if (try_module_get(t->owner))
					res = t;
L
Linus Torvalds 已提交
51 52 53 54 55
				break;
			}
		}
		read_unlock(&cls_mod_lock);
	}
56
	return res;
L
Linus Torvalds 已提交
57 58 59 60 61 62
}

/* Register(unregister) new classifier type */

int register_tcf_proto_ops(struct tcf_proto_ops *ops)
{
63
	struct tcf_proto_ops *t;
L
Linus Torvalds 已提交
64 65 66
	int rc = -EEXIST;

	write_lock(&cls_mod_lock);
67
	list_for_each_entry(t, &tcf_proto_base, head)
L
Linus Torvalds 已提交
68 69 70
		if (!strcmp(ops->kind, t->kind))
			goto out;

71
	list_add_tail(&ops->head, &tcf_proto_base);
L
Linus Torvalds 已提交
72 73 74 75 76
	rc = 0;
out:
	write_unlock(&cls_mod_lock);
	return rc;
}
77
EXPORT_SYMBOL(register_tcf_proto_ops);
L
Linus Torvalds 已提交
78

79 80
static struct workqueue_struct *tc_filter_wq;

L
Linus Torvalds 已提交
81 82
int unregister_tcf_proto_ops(struct tcf_proto_ops *ops)
{
83
	struct tcf_proto_ops *t;
L
Linus Torvalds 已提交
84 85
	int rc = -ENOENT;

86 87 88 89
	/* Wait for outstanding call_rcu()s, if any, from a
	 * tcf_proto_ops's destroy() handler.
	 */
	rcu_barrier();
90
	flush_workqueue(tc_filter_wq);
91

L
Linus Torvalds 已提交
92
	write_lock(&cls_mod_lock);
93 94 95 96
	list_for_each_entry(t, &tcf_proto_base, head) {
		if (t == ops) {
			list_del(&t->head);
			rc = 0;
L
Linus Torvalds 已提交
97
			break;
98 99
		}
	}
L
Linus Torvalds 已提交
100 101 102
	write_unlock(&cls_mod_lock);
	return rc;
}
103
EXPORT_SYMBOL(unregister_tcf_proto_ops);
L
Linus Torvalds 已提交
104

105 106 107 108 109 110
bool tcf_queue_work(struct work_struct *work)
{
	return queue_work(tc_filter_wq, work);
}
EXPORT_SYMBOL(tcf_queue_work);

L
Linus Torvalds 已提交
111 112
/* Select new prio value from the range, managed by kernel. */

113
static inline u32 tcf_auto_prio(struct tcf_proto *tp)
L
Linus Torvalds 已提交
114
{
115
	u32 first = TC_H_MAKE(0xC0000000U, 0U);
L
Linus Torvalds 已提交
116 117

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

120
	return TC_H_MAJ(first);
L
Linus Torvalds 已提交
121 122
}

123
static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
124
					  u32 prio, u32 parent, struct Qdisc *q,
125
					  struct tcf_chain *chain)
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
{
	struct tcf_proto *tp;
	int err;

	tp = kzalloc(sizeof(*tp), GFP_KERNEL);
	if (!tp)
		return ERR_PTR(-ENOBUFS);

	err = -ENOENT;
	tp->ops = tcf_proto_lookup_ops(kind);
	if (!tp->ops) {
#ifdef CONFIG_MODULES
		rtnl_unlock();
		request_module("cls_%s", kind);
		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) {
			module_put(tp->ops->owner);
			err = -EAGAIN;
		} else {
			err = -ENOENT;
		}
		goto errout;
#endif
	}
	tp->classify = tp->ops->classify;
	tp->protocol = protocol;
	tp->prio = prio;
	tp->classid = parent;
	tp->q = q;
161
	tp->chain = chain;
162 163 164 165 166 167 168 169 170 171 172 173 174

	err = tp->ops->init(tp);
	if (err) {
		module_put(tp->ops->owner);
		goto errout;
	}
	return tp;

errout:
	kfree(tp);
	return ERR_PTR(err);
}

175
static void tcf_proto_destroy(struct tcf_proto *tp)
176
{
177 178 179
	tp->ops->destroy(tp);
	module_put(tp->ops->owner);
	kfree_rcu(tp, rcu);
180 181
}

182 183
static struct tcf_chain *tcf_chain_create(struct tcf_block *block,
					  u32 chain_index)
184
{
185 186 187 188 189 190 191 192
	struct tcf_chain *chain;

	chain = kzalloc(sizeof(*chain), GFP_KERNEL);
	if (!chain)
		return NULL;
	list_add_tail(&chain->list, &block->chain_list);
	chain->block = block;
	chain->index = chain_index;
193
	chain->refcnt = 1;
194
	return chain;
195 196
}

197 198 199 200 201 202 203 204
static void tcf_chain_head_change(struct tcf_chain *chain,
				  struct tcf_proto *tp_head)
{
	if (chain->chain_head_change)
		chain->chain_head_change(tp_head,
					 chain->chain_head_change_priv);
}

J
Jiri Pirko 已提交
205
static void tcf_chain_flush(struct tcf_chain *chain)
206
{
207
	struct tcf_proto *tp = rtnl_dereference(chain->filter_chain);
208

209
	tcf_chain_head_change(chain, NULL);
210
	while (tp) {
211
		RCU_INIT_POINTER(chain->filter_chain, tp->next);
212
		tcf_proto_destroy(tp);
213 214
		tp = rtnl_dereference(chain->filter_chain);
		tcf_chain_put(chain);
215
	}
J
Jiri Pirko 已提交
216 217 218 219
}

static void tcf_chain_destroy(struct tcf_chain *chain)
{
220 221
	struct tcf_block *block = chain->block;

222 223
	list_del(&chain->list);
	kfree(chain);
224 225
	if (list_empty(&block->chain_list))
		kfree(block);
226
}
227

228 229 230
static void tcf_chain_hold(struct tcf_chain *chain)
{
	++chain->refcnt;
231 232
}

233 234
struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index,
				bool create)
235 236 237 238
{
	struct tcf_chain *chain;

	list_for_each_entry(chain, &block->chain_list, list) {
239 240 241 242
		if (chain->index == chain_index) {
			tcf_chain_hold(chain);
			return chain;
		}
243
	}
244

245
	return create ? tcf_chain_create(block, chain_index) : NULL;
246 247 248 249 250
}
EXPORT_SYMBOL(tcf_chain_get);

void tcf_chain_put(struct tcf_chain *chain)
{
251
	if (--chain->refcnt == 0)
252 253 254 255
		tcf_chain_destroy(chain);
}
EXPORT_SYMBOL(tcf_chain_put);

256 257 258 259 260 261 262
static void tcf_block_offload_cmd(struct tcf_block *block, struct Qdisc *q,
				  struct tcf_block_ext_info *ei,
				  enum tc_block_command command)
{
	struct net_device *dev = q->dev_queue->dev;
	struct tc_block_offload bo = {};

263
	if (!dev->netdev_ops->ndo_setup_tc)
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
		return;
	bo.command = command;
	bo.binder_type = ei->binder_type;
	bo.block = block;
	dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_BLOCK, &bo);
}

static void tcf_block_offload_bind(struct tcf_block *block, struct Qdisc *q,
				   struct tcf_block_ext_info *ei)
{
	tcf_block_offload_cmd(block, q, ei, TC_BLOCK_BIND);
}

static void tcf_block_offload_unbind(struct tcf_block *block, struct Qdisc *q,
				     struct tcf_block_ext_info *ei)
{
	tcf_block_offload_cmd(block, q, ei, TC_BLOCK_UNBIND);
}

283
int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
284
		      struct tcf_block_ext_info *ei)
285 286
{
	struct tcf_block *block = kzalloc(sizeof(*block), GFP_KERNEL);
287
	struct tcf_chain *chain;
288
	int err;
289 290 291

	if (!block)
		return -ENOMEM;
292
	INIT_LIST_HEAD(&block->chain_list);
293 294
	INIT_LIST_HEAD(&block->cb_list);

295 296 297
	/* Create chain 0 by default, it has to be always present. */
	chain = tcf_chain_create(block, 0);
	if (!chain) {
298 299 300
		err = -ENOMEM;
		goto err_chain_create;
	}
301 302 303
	WARN_ON(!ei->chain_head_change);
	chain->chain_head_change = ei->chain_head_change;
	chain->chain_head_change_priv = ei->chain_head_change_priv;
304
	block->net = qdisc_net(q);
305
	block->q = q;
306
	tcf_block_offload_bind(block, q, ei);
307 308
	*p_block = block;
	return 0;
309 310 311 312

err_chain_create:
	kfree(block);
	return err;
313
}
314 315
EXPORT_SYMBOL(tcf_block_get_ext);

316 317 318 319 320 321 322
static void tcf_chain_head_change_dflt(struct tcf_proto *tp_head, void *priv)
{
	struct tcf_proto __rcu **p_filter_chain = priv;

	rcu_assign_pointer(*p_filter_chain, tp_head);
}

323 324 325
int tcf_block_get(struct tcf_block **p_block,
		  struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q)
{
326 327 328 329
	struct tcf_block_ext_info ei = {
		.chain_head_change = tcf_chain_head_change_dflt,
		.chain_head_change_priv = p_filter_chain,
	};
330

331 332
	WARN_ON(!p_filter_chain);
	return tcf_block_get_ext(p_block, q, &ei);
333
}
334 335
EXPORT_SYMBOL(tcf_block_get);

336
/* XXX: Standalone actions are not allowed to jump to any chain, and bound
337
 * actions should be all removed after flushing.
338
 */
339
void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
340
		       struct tcf_block_ext_info *ei)
341
{
342
	struct tcf_chain *chain, *tmp;
343

344
	/* Hold a refcnt for all chains, so that they don't disappear
345 346
	 * while we are iterating.
	 */
347 348
	if (!block)
		return;
349
	list_for_each_entry(chain, &block->chain_list, list)
350
		tcf_chain_hold(chain);
351 352

	list_for_each_entry(chain, &block->chain_list, list)
353
		tcf_chain_flush(chain);
354

355 356
	tcf_block_offload_unbind(block, q, ei);

357
	/* At this point, all the chains should have refcnt >= 1. */
358 359
	list_for_each_entry_safe(chain, tmp, &block->chain_list, list)
		tcf_chain_put(chain);
360 361 362 363

	/* Finally, put chain 0 and allow block to be freed. */
	chain = list_first_entry(&block->chain_list, struct tcf_chain, list);
	tcf_chain_put(chain);
364
}
365 366 367 368 369 370
EXPORT_SYMBOL(tcf_block_put_ext);

void tcf_block_put(struct tcf_block *block)
{
	struct tcf_block_ext_info ei = {0, };

371
	tcf_block_put_ext(block, block->q, &ei);
372
}
373

374
EXPORT_SYMBOL(tcf_block_put);
375

376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
struct tcf_block_cb {
	struct list_head list;
	tc_setup_cb_t *cb;
	void *cb_ident;
	void *cb_priv;
	unsigned int refcnt;
};

void *tcf_block_cb_priv(struct tcf_block_cb *block_cb)
{
	return block_cb->cb_priv;
}
EXPORT_SYMBOL(tcf_block_cb_priv);

struct tcf_block_cb *tcf_block_cb_lookup(struct tcf_block *block,
					 tc_setup_cb_t *cb, void *cb_ident)
{	struct tcf_block_cb *block_cb;

	list_for_each_entry(block_cb, &block->cb_list, list)
		if (block_cb->cb == cb && block_cb->cb_ident == cb_ident)
			return block_cb;
	return NULL;
}
EXPORT_SYMBOL(tcf_block_cb_lookup);

void tcf_block_cb_incref(struct tcf_block_cb *block_cb)
{
	block_cb->refcnt++;
}
EXPORT_SYMBOL(tcf_block_cb_incref);

unsigned int tcf_block_cb_decref(struct tcf_block_cb *block_cb)
{
	return --block_cb->refcnt;
}
EXPORT_SYMBOL(tcf_block_cb_decref);

struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block,
					     tc_setup_cb_t *cb, void *cb_ident,
					     void *cb_priv)
{
	struct tcf_block_cb *block_cb;

	block_cb = kzalloc(sizeof(*block_cb), GFP_KERNEL);
	if (!block_cb)
		return NULL;
	block_cb->cb = cb;
	block_cb->cb_ident = cb_ident;
	block_cb->cb_priv = cb_priv;
	list_add(&block_cb->list, &block->cb_list);
	return block_cb;
}
EXPORT_SYMBOL(__tcf_block_cb_register);

int tcf_block_cb_register(struct tcf_block *block,
			  tc_setup_cb_t *cb, void *cb_ident,
			  void *cb_priv)
{
	struct tcf_block_cb *block_cb;

	block_cb = __tcf_block_cb_register(block, cb, cb_ident, cb_priv);
	return block_cb ? 0 : -ENOMEM;
}
EXPORT_SYMBOL(tcf_block_cb_register);

void __tcf_block_cb_unregister(struct tcf_block_cb *block_cb)
{
	list_del(&block_cb->list);
	kfree(block_cb);
}
EXPORT_SYMBOL(__tcf_block_cb_unregister);

void tcf_block_cb_unregister(struct tcf_block *block,
			     tc_setup_cb_t *cb, void *cb_ident)
{
	struct tcf_block_cb *block_cb;

	block_cb = tcf_block_cb_lookup(block, cb, cb_ident);
	if (!block_cb)
		return;
	__tcf_block_cb_unregister(block_cb);
}
EXPORT_SYMBOL(tcf_block_cb_unregister);

static int tcf_block_cb_call(struct tcf_block *block, enum tc_setup_type type,
			     void *type_data, bool err_stop)
{
	struct tcf_block_cb *block_cb;
	int ok_count = 0;
	int err;

	list_for_each_entry(block_cb, &block->cb_list, list) {
		err = block_cb->cb(type, type_data, block_cb->cb_priv);
		if (err) {
			if (err_stop)
				return err;
		} else {
			ok_count++;
		}
	}
	return ok_count;
}

479 480 481 482 483 484 485 486 487 488
/* Main classifier routine: scans classifier chain attached
 * to this qdisc, (optionally) tests for protocol and asks
 * specific classifiers.
 */
int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
		 struct tcf_result *res, bool compat_mode)
{
	__be16 protocol = tc_skb_protocol(skb);
#ifdef CONFIG_NET_CLS_ACT
	const int max_reclassify_loop = 4;
489 490
	const struct tcf_proto *orig_tp = tp;
	const struct tcf_proto *first_tp;
491 492 493 494 495 496 497 498 499 500 501 502 503
	int limit = 0;

reclassify:
#endif
	for (; tp; tp = rcu_dereference_bh(tp->next)) {
		int err;

		if (tp->protocol != protocol &&
		    tp->protocol != htons(ETH_P_ALL))
			continue;

		err = tp->classify(skb, tp, res);
#ifdef CONFIG_NET_CLS_ACT
504
		if (unlikely(err == TC_ACT_RECLASSIFY && !compat_mode)) {
505
			first_tp = orig_tp;
506
			goto reset;
507
		} else if (unlikely(TC_ACT_EXT_CMP(err, TC_ACT_GOTO_CHAIN))) {
508
			first_tp = res->goto_tp;
509 510
			goto reset;
		}
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525
#endif
		if (err >= 0)
			return err;
	}

	return TC_ACT_UNSPEC; /* signal: continue lookup */
#ifdef CONFIG_NET_CLS_ACT
reset:
	if (unlikely(limit++ >= max_reclassify_loop)) {
		net_notice_ratelimited("%s: reclassify loop, rule prio %u, protocol %02x\n",
				       tp->q->ops->id, tp->prio & 0xffff,
				       ntohs(tp->protocol));
		return TC_ACT_SHOT;
	}

526
	tp = first_tp;
527 528 529 530 531 532
	protocol = tc_skb_protocol(skb);
	goto reclassify;
#endif
}
EXPORT_SYMBOL(tcf_classify);

533 534 535 536 537 538 539 540 541 542 543 544 545 546
struct tcf_chain_info {
	struct tcf_proto __rcu **pprev;
	struct tcf_proto __rcu *next;
};

static struct tcf_proto *tcf_chain_tp_prev(struct tcf_chain_info *chain_info)
{
	return rtnl_dereference(*chain_info->pprev);
}

static void tcf_chain_tp_insert(struct tcf_chain *chain,
				struct tcf_chain_info *chain_info,
				struct tcf_proto *tp)
{
547 548
	if (*chain_info->pprev == chain->filter_chain)
		tcf_chain_head_change(chain, tp);
549 550
	RCU_INIT_POINTER(tp->next, tcf_chain_tp_prev(chain_info));
	rcu_assign_pointer(*chain_info->pprev, tp);
551
	tcf_chain_hold(chain);
552 553 554 555 556 557 558 559
}

static void tcf_chain_tp_remove(struct tcf_chain *chain,
				struct tcf_chain_info *chain_info,
				struct tcf_proto *tp)
{
	struct tcf_proto *next = rtnl_dereference(chain_info->next);

560 561
	if (tp == chain->filter_chain)
		tcf_chain_head_change(chain, next);
562
	RCU_INIT_POINTER(*chain_info->pprev, next);
563
	tcf_chain_put(chain);
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
}

static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain,
					   struct tcf_chain_info *chain_info,
					   u32 protocol, u32 prio,
					   bool prio_allocate)
{
	struct tcf_proto **pprev;
	struct tcf_proto *tp;

	/* Check the chain for existence of proto-tcf with this priority */
	for (pprev = &chain->filter_chain;
	     (tp = rtnl_dereference(*pprev)); pprev = &tp->next) {
		if (tp->prio >= prio) {
			if (tp->prio == prio) {
				if (prio_allocate ||
				    (tp->protocol != protocol && protocol))
					return ERR_PTR(-EINVAL);
			} else {
				tp = NULL;
			}
			break;
		}
	}
	chain_info->pprev = pprev;
	chain_info->next = tp ? tp->next : NULL;
	return tp;
}

593
static int tcf_fill_node(struct net *net, struct sk_buff *skb,
594 595
			 struct tcf_proto *tp, struct Qdisc *q, u32 parent,
			 void *fh, u32 portid, u32 seq, u16 flags, int event)
596 597 598 599 600 601 602 603 604 605 606 607
{
	struct tcmsg *tcm;
	struct nlmsghdr  *nlh;
	unsigned char *b = skb_tail_pointer(skb);

	nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags);
	if (!nlh)
		goto out_nlmsg_trim;
	tcm = nlmsg_data(nlh);
	tcm->tcm_family = AF_UNSPEC;
	tcm->tcm__pad1 = 0;
	tcm->tcm__pad2 = 0;
608 609
	tcm->tcm_ifindex = qdisc_dev(q)->ifindex;
	tcm->tcm_parent = parent;
610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
	tcm->tcm_info = TC_H_MAKE(tp->prio, tp->protocol);
	if (nla_put_string(skb, TCA_KIND, tp->ops->kind))
		goto nla_put_failure;
	if (nla_put_u32(skb, TCA_CHAIN, tp->chain->index))
		goto nla_put_failure;
	if (!fh) {
		tcm->tcm_handle = 0;
	} else {
		if (tp->ops->dump && tp->ops->dump(net, tp, fh, skb, tcm) < 0)
			goto nla_put_failure;
	}
	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
	return skb->len;

out_nlmsg_trim:
nla_put_failure:
	nlmsg_trim(skb, b);
	return -1;
}

static int tfilter_notify(struct net *net, struct sk_buff *oskb,
			  struct nlmsghdr *n, struct tcf_proto *tp,
632
			  struct Qdisc *q, u32 parent,
633 634 635 636 637 638 639 640 641
			  void *fh, int event, bool unicast)
{
	struct sk_buff *skb;
	u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;

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

642
	if (tcf_fill_node(net, skb, tp, q, parent, fh, portid, n->nlmsg_seq,
643 644 645 646 647 648 649 650 651 652 653 654 655 656
			  n->nlmsg_flags, event) <= 0) {
		kfree_skb(skb);
		return -EINVAL;
	}

	if (unicast)
		return netlink_unicast(net->rtnl, skb, portid, MSG_DONTWAIT);

	return rtnetlink_send(skb, net, portid, RTNLGRP_TC,
			      n->nlmsg_flags & NLM_F_ECHO);
}

static int tfilter_del_notify(struct net *net, struct sk_buff *oskb,
			      struct nlmsghdr *n, struct tcf_proto *tp,
657
			      struct Qdisc *q, u32 parent,
658 659 660 661 662 663 664 665 666 667
			      void *fh, bool unicast, bool *last)
{
	struct sk_buff *skb;
	u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
	int err;

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

668
	if (tcf_fill_node(net, skb, tp, q, parent, fh, portid, n->nlmsg_seq,
669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
			  n->nlmsg_flags, RTM_DELTFILTER) <= 0) {
		kfree_skb(skb);
		return -EINVAL;
	}

	err = tp->ops->delete(tp, fh, last);
	if (err) {
		kfree_skb(skb);
		return err;
	}

	if (unicast)
		return netlink_unicast(net->rtnl, skb, portid, MSG_DONTWAIT);

	return rtnetlink_send(skb, net, portid, RTNLGRP_TC,
			      n->nlmsg_flags & NLM_F_ECHO);
}

static void tfilter_notify_chain(struct net *net, struct sk_buff *oskb,
688
				 struct Qdisc *q, u32 parent,
689 690 691 692 693 694 695
				 struct nlmsghdr *n,
				 struct tcf_chain *chain, int event)
{
	struct tcf_proto *tp;

	for (tp = rtnl_dereference(chain->filter_chain);
	     tp; tp = rtnl_dereference(tp->next))
696
		tfilter_notify(net, oskb, n, tp, q, parent, 0, event, false);
697 698
}

L
Linus Torvalds 已提交
699 700
/* Add/change/delete/get a filter node */

701 702
static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
			  struct netlink_ext_ack *extack)
L
Linus Torvalds 已提交
703
{
704
	struct net *net = sock_net(skb->sk);
705
	struct nlattr *tca[TCA_MAX + 1];
L
Linus Torvalds 已提交
706 707 708
	struct tcmsg *t;
	u32 protocol;
	u32 prio;
709
	bool prio_allocate;
L
Linus Torvalds 已提交
710
	u32 parent;
711
	u32 chain_index;
L
Linus Torvalds 已提交
712 713
	struct net_device *dev;
	struct Qdisc  *q;
714
	struct tcf_chain_info chain_info;
715
	struct tcf_chain *chain = NULL;
716
	struct tcf_block *block;
L
Linus Torvalds 已提交
717
	struct tcf_proto *tp;
718
	const struct Qdisc_class_ops *cops;
L
Linus Torvalds 已提交
719
	unsigned long cl;
720
	void *fh;
L
Linus Torvalds 已提交
721
	int err;
722
	int tp_created;
L
Linus Torvalds 已提交
723

724
	if ((n->nlmsg_type != RTM_GETTFILTER) &&
725
	    !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
726
		return -EPERM;
727

L
Linus Torvalds 已提交
728
replay:
729 730
	tp_created = 0;

731
	err = nlmsg_parse(n, sizeof(*t), tca, TCA_MAX, NULL, extack);
732 733 734
	if (err < 0)
		return err;

735
	t = nlmsg_data(n);
L
Linus Torvalds 已提交
736 737
	protocol = TC_H_MIN(t->tcm_info);
	prio = TC_H_MAJ(t->tcm_info);
738
	prio_allocate = false;
L
Linus Torvalds 已提交
739 740 741 742
	parent = t->tcm_parent;
	cl = 0;

	if (prio == 0) {
743 744
		switch (n->nlmsg_type) {
		case RTM_DELTFILTER:
745
			if (protocol || t->tcm_handle || tca[TCA_KIND])
746 747 748 749 750 751 752 753
				return -ENOENT;
			break;
		case RTM_NEWTFILTER:
			/* If no priority is provided by the user,
			 * we allocate one.
			 */
			if (n->nlmsg_flags & NLM_F_CREATE) {
				prio = TC_H_MAKE(0x80000000U, 0U);
754
				prio_allocate = true;
755 756 757 758
				break;
			}
			/* fall-through */
		default:
L
Linus Torvalds 已提交
759
			return -ENOENT;
760
		}
L
Linus Torvalds 已提交
761 762 763 764 765
	}

	/* Find head of filter chain. */

	/* Find link */
766
	dev = __dev_get_by_index(net, t->tcm_ifindex);
767
	if (dev == NULL)
L
Linus Torvalds 已提交
768 769 770 771
		return -ENODEV;

	/* Find qdisc */
	if (!parent) {
772
		q = dev->qdisc;
L
Linus Torvalds 已提交
773
		parent = q->handle;
774 775 776 777 778
	} else {
		q = qdisc_lookup(dev, TC_H_MAJ(t->tcm_parent));
		if (q == NULL)
			return -EINVAL;
	}
L
Linus Torvalds 已提交
779 780

	/* Is it classful? */
E
Eric Dumazet 已提交
781 782
	cops = q->ops->cl_ops;
	if (!cops)
L
Linus Torvalds 已提交
783 784
		return -EINVAL;

785
	if (!cops->tcf_block)
786 787
		return -EOPNOTSUPP;

L
Linus Torvalds 已提交
788 789
	/* Do we search for filter, attached to class? */
	if (TC_H_MIN(parent)) {
790
		cl = cops->find(q, parent);
L
Linus Torvalds 已提交
791 792 793 794 795
		if (cl == 0)
			return -ENOENT;
	}

	/* And the last stroke */
796
	block = cops->tcf_block(q, cl, extack);
797
	if (!block) {
798
		err = -EINVAL;
L
Linus Torvalds 已提交
799
		goto errout;
800
	}
801 802 803 804 805 806

	chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0;
	if (chain_index > TC_ACT_EXT_VAL_MASK) {
		err = -EINVAL;
		goto errout;
	}
807 808
	chain = tcf_chain_get(block, chain_index,
			      n->nlmsg_type == RTM_NEWTFILTER);
809
	if (!chain) {
810
		err = n->nlmsg_type == RTM_NEWTFILTER ? -ENOMEM : -EINVAL;
811 812
		goto errout;
	}
813

814
	if (n->nlmsg_type == RTM_DELTFILTER && prio == 0) {
815 816
		tfilter_notify_chain(net, skb, q, parent, n,
				     chain, RTM_DELTFILTER);
J
Jiri Pirko 已提交
817
		tcf_chain_flush(chain);
818 819 820
		err = 0;
		goto errout;
	}
L
Linus Torvalds 已提交
821

822 823 824 825 826
	tp = tcf_chain_tp_find(chain, &chain_info, protocol,
			       prio, prio_allocate);
	if (IS_ERR(tp)) {
		err = PTR_ERR(tp);
		goto errout;
L
Linus Torvalds 已提交
827 828 829 830 831
	}

	if (tp == NULL) {
		/* Proto-tcf does not exist, create new one */

832 833
		if (tca[TCA_KIND] == NULL || !protocol) {
			err = -EINVAL;
L
Linus Torvalds 已提交
834
			goto errout;
835
		}
L
Linus Torvalds 已提交
836

E
Eric Dumazet 已提交
837
		if (n->nlmsg_type != RTM_NEWTFILTER ||
838 839
		    !(n->nlmsg_flags & NLM_F_CREATE)) {
			err = -ENOENT;
L
Linus Torvalds 已提交
840
			goto errout;
841
		}
L
Linus Torvalds 已提交
842

843
		if (prio_allocate)
844
			prio = tcf_auto_prio(tcf_chain_tp_prev(&chain_info));
L
Linus Torvalds 已提交
845

846
		tp = tcf_proto_create(nla_data(tca[TCA_KIND]),
847
				      protocol, prio, parent, q, chain);
848 849
		if (IS_ERR(tp)) {
			err = PTR_ERR(tp);
L
Linus Torvalds 已提交
850 851
			goto errout;
		}
852
		tp_created = 1;
853 854
	} else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) {
		err = -EINVAL;
L
Linus Torvalds 已提交
855
		goto errout;
856
	}
L
Linus Torvalds 已提交
857 858 859

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

860
	if (!fh) {
L
Linus Torvalds 已提交
861
		if (n->nlmsg_type == RTM_DELTFILTER && t->tcm_handle == 0) {
862
			tcf_chain_tp_remove(chain, &chain_info, tp);
863
			tfilter_notify(net, skb, n, tp, q, parent, fh,
864
				       RTM_DELTFILTER, false);
865
			tcf_proto_destroy(tp);
L
Linus Torvalds 已提交
866 867 868 869
			err = 0;
			goto errout;
		}

870
		if (n->nlmsg_type != RTM_NEWTFILTER ||
871 872
		    !(n->nlmsg_flags & NLM_F_CREATE)) {
			err = -ENOENT;
L
Linus Torvalds 已提交
873
			goto errout;
874
		}
L
Linus Torvalds 已提交
875
	} else {
876 877
		bool last;

L
Linus Torvalds 已提交
878
		switch (n->nlmsg_type) {
879
		case RTM_NEWTFILTER:
880 881
			if (n->nlmsg_flags & NLM_F_EXCL) {
				if (tp_created)
882
					tcf_proto_destroy(tp);
883
				err = -EEXIST;
L
Linus Torvalds 已提交
884
				goto errout;
885
			}
L
Linus Torvalds 已提交
886 887
			break;
		case RTM_DELTFILTER:
888 889
			err = tfilter_del_notify(net, skb, n, tp, q, parent,
						 fh, false, &last);
890 891
			if (err)
				goto errout;
892
			if (last) {
893
				tcf_chain_tp_remove(chain, &chain_info, tp);
894 895
				tcf_proto_destroy(tp);
			}
896
			goto errout;
L
Linus Torvalds 已提交
897
		case RTM_GETTFILTER:
898
			err = tfilter_notify(net, skb, n, tp, q, parent, fh,
899
					     RTM_NEWTFILTER, true);
L
Linus Torvalds 已提交
900 901 902 903 904 905 906
			goto errout;
		default:
			err = -EINVAL;
			goto errout;
		}
	}

907 908
	err = tp->ops->change(net, skb, tp, cl, t->tcm_handle, tca, &fh,
			      n->nlmsg_flags & NLM_F_CREATE ? TCA_ACT_NOREPLACE : TCA_ACT_REPLACE);
909
	if (err == 0) {
910 911
		if (tp_created)
			tcf_chain_tp_insert(chain, &chain_info, tp);
912 913
		tfilter_notify(net, skb, n, tp, q, parent, fh,
			       RTM_NEWTFILTER, false);
914 915
	} else {
		if (tp_created)
916
			tcf_proto_destroy(tp);
917
	}
L
Linus Torvalds 已提交
918 919

errout:
920 921
	if (chain)
		tcf_chain_put(chain);
L
Linus Torvalds 已提交
922 923 924 925 926 927
	if (err == -EAGAIN)
		/* Replay the request. */
		goto replay;
	return err;
}

928
struct tcf_dump_args {
L
Linus Torvalds 已提交
929 930 931
	struct tcf_walker w;
	struct sk_buff *skb;
	struct netlink_callback *cb;
932 933
	struct Qdisc *q;
	u32 parent;
L
Linus Torvalds 已提交
934 935
};

936
static int tcf_node_dump(struct tcf_proto *tp, void *n, struct tcf_walker *arg)
L
Linus Torvalds 已提交
937
{
938
	struct tcf_dump_args *a = (void *)arg;
939
	struct net *net = sock_net(a->skb->sk);
L
Linus Torvalds 已提交
940

941 942
	return tcf_fill_node(net, a->skb, tp, a->q, a->parent,
			     n, NETLINK_CB(a->cb->skb).portid,
J
Jamal Hadi Salim 已提交
943 944
			     a->cb->nlh->nlmsg_seq, NLM_F_MULTI,
			     RTM_NEWTFILTER);
L
Linus Torvalds 已提交
945 946
}

947 948
static bool tcf_chain_dump(struct tcf_chain *chain, struct Qdisc *q, u32 parent,
			   struct sk_buff *skb, struct netlink_callback *cb,
949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969
			   long index_start, long *p_index)
{
	struct net *net = sock_net(skb->sk);
	struct tcmsg *tcm = nlmsg_data(cb->nlh);
	struct tcf_dump_args arg;
	struct tcf_proto *tp;

	for (tp = rtnl_dereference(chain->filter_chain);
	     tp; tp = rtnl_dereference(tp->next), (*p_index)++) {
		if (*p_index < index_start)
			continue;
		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 (*p_index > index_start)
			memset(&cb->args[1], 0,
			       sizeof(cb->args) - sizeof(cb->args[0]));
		if (cb->args[1] == 0) {
970
			if (tcf_fill_node(net, skb, tp, q, parent, 0,
971 972 973
					  NETLINK_CB(cb->skb).portid,
					  cb->nlh->nlmsg_seq, NLM_F_MULTI,
					  RTM_NEWTFILTER) <= 0)
974
				return false;
975 976 977 978 979 980 981 982

			cb->args[1] = 1;
		}
		if (!tp->ops->walk)
			continue;
		arg.w.fn = tcf_node_dump;
		arg.skb = skb;
		arg.cb = cb;
983 984
		arg.q = q;
		arg.parent = parent;
985 986 987 988 989 990
		arg.w.stop = 0;
		arg.w.skip = cb->args[1] - 1;
		arg.w.count = 0;
		tp->ops->walk(tp, &arg.w);
		cb->args[1] = arg.w.count + 1;
		if (arg.w.stop)
991
			return false;
992
	}
993
	return true;
994 995
}

E
Eric Dumazet 已提交
996
/* called with RTNL */
L
Linus Torvalds 已提交
997 998
static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
{
999
	struct net *net = sock_net(skb->sk);
1000
	struct nlattr *tca[TCA_MAX + 1];
L
Linus Torvalds 已提交
1001 1002
	struct net_device *dev;
	struct Qdisc *q;
1003
	struct tcf_block *block;
1004
	struct tcf_chain *chain;
1005
	struct tcmsg *tcm = nlmsg_data(cb->nlh);
L
Linus Torvalds 已提交
1006
	unsigned long cl = 0;
1007
	const struct Qdisc_class_ops *cops;
1008 1009
	long index_start;
	long index;
1010
	u32 parent;
1011
	int err;
L
Linus Torvalds 已提交
1012

1013
	if (nlmsg_len(cb->nlh) < sizeof(*tcm))
L
Linus Torvalds 已提交
1014
		return skb->len;
1015 1016 1017 1018 1019

	err = nlmsg_parse(cb->nlh, sizeof(*tcm), tca, TCA_MAX, NULL, NULL);
	if (err)
		return err;

E
Eric Dumazet 已提交
1020 1021
	dev = __dev_get_by_index(net, tcm->tcm_ifindex);
	if (!dev)
L
Linus Torvalds 已提交
1022 1023
		return skb->len;

1024 1025
	parent = tcm->tcm_parent;
	if (!parent) {
1026
		q = dev->qdisc;
1027 1028
		parent = q->handle;
	} else {
L
Linus Torvalds 已提交
1029
		q = qdisc_lookup(dev, TC_H_MAJ(tcm->tcm_parent));
1030
	}
L
Linus Torvalds 已提交
1031 1032
	if (!q)
		goto out;
E
Eric Dumazet 已提交
1033 1034
	cops = q->ops->cl_ops;
	if (!cops)
1035
		goto out;
1036
	if (!cops->tcf_block)
1037
		goto out;
L
Linus Torvalds 已提交
1038
	if (TC_H_MIN(tcm->tcm_parent)) {
1039
		cl = cops->find(q, tcm->tcm_parent);
L
Linus Torvalds 已提交
1040
		if (cl == 0)
1041
			goto out;
L
Linus Torvalds 已提交
1042
	}
1043
	block = cops->tcf_block(q, cl, NULL);
1044
	if (!block)
1045
		goto out;
L
Linus Torvalds 已提交
1046

1047 1048
	index_start = cb->args[0];
	index = 0;
1049 1050 1051 1052 1053

	list_for_each_entry(chain, &block->chain_list, list) {
		if (tca[TCA_CHAIN] &&
		    nla_get_u32(tca[TCA_CHAIN]) != chain->index)
			continue;
1054 1055
		if (!tcf_chain_dump(chain, q, parent, skb, cb,
				    index_start, &index))
1056 1057 1058
			break;
	}

1059
	cb->args[0] = index;
L
Linus Torvalds 已提交
1060 1061 1062 1063 1064

out:
	return skb->len;
}

1065
void tcf_exts_destroy(struct tcf_exts *exts)
L
Linus Torvalds 已提交
1066 1067
{
#ifdef CONFIG_NET_CLS_ACT
1068 1069
	LIST_HEAD(actions);

1070
	ASSERT_RTNL();
1071 1072 1073 1074
	tcf_exts_to_list(exts, &actions);
	tcf_action_destroy(&actions, TCA_ACT_UNBIND);
	kfree(exts->actions);
	exts->nr_actions = 0;
L
Linus Torvalds 已提交
1075 1076
#endif
}
1077
EXPORT_SYMBOL(tcf_exts_destroy);
L
Linus Torvalds 已提交
1078

1079
int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
J
Jamal Hadi Salim 已提交
1080
		      struct nlattr *rate_tlv, struct tcf_exts *exts, bool ovr)
L
Linus Torvalds 已提交
1081 1082 1083 1084 1085
{
#ifdef CONFIG_NET_CLS_ACT
	{
		struct tc_action *act;

1086
		if (exts->police && tb[exts->police]) {
1087 1088 1089
			act = tcf_action_init_1(net, tp, tb[exts->police],
						rate_tlv, "police", ovr,
						TCA_ACT_BIND);
1090 1091
			if (IS_ERR(act))
				return PTR_ERR(act);
L
Linus Torvalds 已提交
1092

1093
			act->type = exts->type = TCA_OLD_COMPAT;
1094 1095
			exts->actions[0] = act;
			exts->nr_actions = 1;
1096
		} else if (exts->action && tb[exts->action]) {
1097 1098 1099
			LIST_HEAD(actions);
			int err, i = 0;

1100 1101
			err = tcf_action_init(net, tp, tb[exts->action],
					      rate_tlv, NULL, ovr, TCA_ACT_BIND,
J
Jamal Hadi Salim 已提交
1102
					      &actions);
1103 1104
			if (err)
				return err;
1105 1106 1107
			list_for_each_entry(act, &actions, list)
				exts->actions[i++] = act;
			exts->nr_actions = i;
L
Linus Torvalds 已提交
1108
		}
1109
		exts->net = net;
L
Linus Torvalds 已提交
1110 1111
	}
#else
1112 1113
	if ((exts->action && tb[exts->action]) ||
	    (exts->police && tb[exts->police]))
L
Linus Torvalds 已提交
1114 1115 1116 1117 1118
		return -EOPNOTSUPP;
#endif

	return 0;
}
1119
EXPORT_SYMBOL(tcf_exts_validate);
L
Linus Torvalds 已提交
1120

1121
void tcf_exts_change(struct tcf_exts *dst, struct tcf_exts *src)
L
Linus Torvalds 已提交
1122 1123
{
#ifdef CONFIG_NET_CLS_ACT
1124 1125
	struct tcf_exts old = *dst;

1126
	*dst = *src;
1127
	tcf_exts_destroy(&old);
L
Linus Torvalds 已提交
1128 1129
#endif
}
1130
EXPORT_SYMBOL(tcf_exts_change);
L
Linus Torvalds 已提交
1131

1132 1133 1134 1135 1136 1137 1138 1139 1140
#ifdef CONFIG_NET_CLS_ACT
static struct tc_action *tcf_exts_first_act(struct tcf_exts *exts)
{
	if (exts->nr_actions == 0)
		return NULL;
	else
		return exts->actions[0];
}
#endif
1141

1142
int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts)
L
Linus Torvalds 已提交
1143 1144
{
#ifdef CONFIG_NET_CLS_ACT
1145 1146
	struct nlattr *nest;

1147
	if (exts->action && tcf_exts_has_actions(exts)) {
L
Linus Torvalds 已提交
1148 1149 1150 1151 1152
		/*
		 * 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
		 */
1153
		if (exts->type != TCA_OLD_COMPAT) {
1154 1155
			LIST_HEAD(actions);

1156
			nest = nla_nest_start(skb, exts->action);
1157 1158
			if (nest == NULL)
				goto nla_put_failure;
1159 1160 1161

			tcf_exts_to_list(exts, &actions);
			if (tcf_action_dump(skb, &actions, 0, 0) < 0)
1162
				goto nla_put_failure;
1163
			nla_nest_end(skb, nest);
1164
		} else if (exts->police) {
1165
			struct tc_action *act = tcf_exts_first_act(exts);
1166
			nest = nla_nest_start(skb, exts->police);
1167
			if (nest == NULL || !act)
1168
				goto nla_put_failure;
1169
			if (tcf_action_dump_old(skb, act, 0, 0) < 0)
1170
				goto nla_put_failure;
1171
			nla_nest_end(skb, nest);
L
Linus Torvalds 已提交
1172 1173 1174
		}
	}
	return 0;
1175 1176 1177

nla_put_failure:
	nla_nest_cancel(skb, nest);
L
Linus Torvalds 已提交
1178
	return -1;
1179 1180 1181
#else
	return 0;
#endif
L
Linus Torvalds 已提交
1182
}
1183
EXPORT_SYMBOL(tcf_exts_dump);
L
Linus Torvalds 已提交
1184

1185

1186
int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts)
L
Linus Torvalds 已提交
1187 1188
{
#ifdef CONFIG_NET_CLS_ACT
1189
	struct tc_action *a = tcf_exts_first_act(exts);
1190
	if (a != NULL && tcf_action_copy_stats(skb, a, 1) < 0)
1191
		return -1;
L
Linus Torvalds 已提交
1192 1193 1194
#endif
	return 0;
}
1195
EXPORT_SYMBOL(tcf_exts_dump_stats);
L
Linus Torvalds 已提交
1196

1197 1198 1199
static int tc_exts_setup_cb_egdev_call(struct tcf_exts *exts,
				       enum tc_setup_type type,
				       void *type_data, bool err_stop)
1200 1201 1202 1203 1204
{
	int ok_count = 0;
#ifdef CONFIG_NET_CLS_ACT
	const struct tc_action *a;
	struct net_device *dev;
1205
	int i, ret;
1206 1207 1208 1209

	if (!tcf_exts_has_actions(exts))
		return 0;

1210 1211
	for (i = 0; i < exts->nr_actions; i++) {
		a = exts->actions[i];
1212 1213 1214
		if (!a->ops->get_dev)
			continue;
		dev = a->ops->get_dev(a);
1215
		if (!dev)
1216 1217 1218 1219 1220 1221 1222 1223 1224
			continue;
		ret = tc_setup_cb_egdev_call(dev, type, type_data, err_stop);
		if (ret < 0)
			return ret;
		ok_count += ret;
	}
#endif
	return ok_count;
}
1225

1226 1227
int tc_setup_cb_call(struct tcf_block *block, struct tcf_exts *exts,
		     enum tc_setup_type type, void *type_data, bool err_stop)
1228
{
1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
	int ok_count;
	int ret;

	ret = tcf_block_cb_call(block, type, type_data, err_stop);
	if (ret < 0)
		return ret;
	ok_count = ret;

	if (!exts)
		return ok_count;
	ret = tc_exts_setup_cb_egdev_call(exts, type, type_data, err_stop);
	if (ret < 0)
		return ret;
	ok_count += ret;

	return ok_count;
1245 1246
}
EXPORT_SYMBOL(tc_setup_cb_call);
1247

L
Linus Torvalds 已提交
1248 1249
static int __init tc_filter_init(void)
{
1250 1251 1252 1253
	tc_filter_wq = alloc_ordered_workqueue("tc_filter_workqueue", 0);
	if (!tc_filter_wq)
		return -ENOMEM;

1254 1255
	rtnl_register(PF_UNSPEC, RTM_NEWTFILTER, tc_ctl_tfilter, NULL, 0);
	rtnl_register(PF_UNSPEC, RTM_DELTFILTER, tc_ctl_tfilter, NULL, 0);
1256
	rtnl_register(PF_UNSPEC, RTM_GETTFILTER, tc_ctl_tfilter,
1257
		      tc_dump_tfilter, 0);
L
Linus Torvalds 已提交
1258 1259 1260 1261 1262

	return 0;
}

subsys_initcall(tc_filter_init);