act_api.c 27.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * net/sched/act_api.c	Packet action 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.
 *
 * Author:	Jamal Hadi Salim
 *
 *
 */

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
18
#include <linux/slab.h>
L
Linus Torvalds 已提交
19 20 21
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/kmod.h>
22
#include <linux/err.h>
23
#include <linux/module.h>
24 25
#include <net/net_namespace.h>
#include <net/sock.h>
L
Linus Torvalds 已提交
26
#include <net/sch_generic.h>
27
#include <net/pkt_cls.h>
L
Linus Torvalds 已提交
28
#include <net/act_api.h>
29
#include <net/netlink.h>
L
Linus Torvalds 已提交
30

31 32 33 34 35 36
static int tcf_action_goto_chain_init(struct tc_action *a, struct tcf_proto *tp)
{
	u32 chain_index = a->tcfa_action & TC_ACT_EXT_VAL_MASK;

	if (!tp)
		return -EINVAL;
37
	a->goto_chain = tcf_chain_get(tp->chain->block, chain_index, true);
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
	if (!a->goto_chain)
		return -ENOMEM;
	return 0;
}

static void tcf_action_goto_chain_fini(struct tc_action *a)
{
	tcf_chain_put(a->goto_chain);
}

static void tcf_action_goto_chain_exec(const struct tc_action *a,
				       struct tcf_result *res)
{
	const struct tcf_chain *chain = a->goto_chain;

	res->goto_tp = rcu_dereference_bh(chain->filter_chain);
}

56 57
static void free_tcf(struct rcu_head *head)
{
58
	struct tc_action *p = container_of(head, struct tc_action, tcfa_rcu);
59 60 61

	free_percpu(p->cpu_bstats);
	free_percpu(p->cpu_qstats);
62 63 64 65 66

	if (p->act_cookie) {
		kfree(p->act_cookie->data);
		kfree(p->act_cookie);
	}
67 68
	if (p->goto_chain)
		tcf_action_goto_chain_fini(p);
69

70 71 72
	kfree(p);
}

73
static void tcf_idr_remove(struct tcf_idrinfo *idrinfo, struct tc_action *p)
74
{
75 76 77
	spin_lock_bh(&idrinfo->lock);
	idr_remove_ext(&idrinfo->action_idr, p->tcfa_index);
	spin_unlock_bh(&idrinfo->lock);
78
	gen_kill_estimator(&p->tcfa_rate_est);
79
	/*
80
	 * gen_estimator est_timer() might access p->tcfa_lock
81 82
	 * or bstats, wait a RCU grace period before freeing p
	 */
83
	call_rcu(&p->tcfa_rcu, free_tcf);
84 85
}

86
int __tcf_idr_release(struct tc_action *p, bool bind, bool strict)
87 88 89 90 91
{
	int ret = 0;

	if (p) {
		if (bind)
92 93
			p->tcfa_bindcnt--;
		else if (strict && p->tcfa_bindcnt > 0)
94
			return -EPERM;
95

96 97 98 99
		p->tcfa_refcnt--;
		if (p->tcfa_bindcnt <= 0 && p->tcfa_refcnt <= 0) {
			if (p->ops->cleanup)
				p->ops->cleanup(p, bind);
100
			tcf_idr_remove(p->idrinfo, p);
101
			ret = ACT_P_DELETED;
102 103
		}
	}
104

105 106
	return ret;
}
107
EXPORT_SYMBOL(__tcf_idr_release);
108

109
static int tcf_dump_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
110
			   struct netlink_callback *cb)
111
{
112
	int err = 0, index = -1, s_i = 0, n_i = 0;
113
	u32 act_flags = cb->args[2];
114
	unsigned long jiffy_since = cb->args[3];
115
	struct nlattr *nest;
116 117 118
	struct idr *idr = &idrinfo->action_idr;
	struct tc_action *p;
	unsigned long id = 1;
119

120
	spin_lock_bh(&idrinfo->lock);
121 122 123

	s_i = cb->args[0];

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
	idr_for_each_entry_ext(idr, p, id) {
		index++;
		if (index < s_i)
			continue;

		if (jiffy_since &&
		    time_after(jiffy_since,
			       (unsigned long)p->tcfa_tm.lastuse))
			continue;

		nest = nla_nest_start(skb, n_i);
		if (!nest)
			goto nla_put_failure;
		err = tcf_action_dump_1(skb, p, 0, 0);
		if (err < 0) {
			index--;
			nlmsg_trim(skb, nest);
			goto done;
142
		}
143 144 145 146 147
		nla_nest_end(skb, nest);
		n_i++;
		if (!(act_flags & TCA_FLAG_LARGE_DUMP_ON) &&
		    n_i >= TCA_ACT_MAX_PRIO)
			goto done;
148 149
	}
done:
150 151 152
	if (index >= 0)
		cb->args[0] = index + 1;

153
	spin_unlock_bh(&idrinfo->lock);
154 155 156 157
	if (n_i) {
		if (act_flags & TCA_FLAG_LARGE_DUMP_ON)
			cb->args[1] = n_i;
	}
158 159
	return n_i;

160
nla_put_failure:
161
	nla_nest_cancel(skb, nest);
162 163 164
	goto done;
}

165
static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
166
			  const struct tc_action_ops *ops)
167
{
168
	struct nlattr *nest;
169
	int n_i = 0;
170
	int ret = -EINVAL;
171 172 173
	struct idr *idr = &idrinfo->action_idr;
	struct tc_action *p;
	unsigned long id = 1;
174

175
	nest = nla_nest_start(skb, 0);
176 177
	if (nest == NULL)
		goto nla_put_failure;
178
	if (nla_put_string(skb, TCA_KIND, ops->kind))
179
		goto nla_put_failure;
180 181 182 183 184 185 186 187

	idr_for_each_entry_ext(idr, p, id) {
		ret = __tcf_idr_release(p, false, true);
		if (ret == ACT_P_DELETED) {
			module_put(p->ops->owner);
			n_i++;
		} else if (ret < 0) {
			goto nla_put_failure;
188 189
		}
	}
190 191
	if (nla_put_u32(skb, TCA_FCNT, n_i))
		goto nla_put_failure;
192
	nla_nest_end(skb, nest);
193 194

	return n_i;
195
nla_put_failure:
196
	nla_nest_cancel(skb, nest);
197
	return ret;
198 199
}

200 201
int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
		       struct netlink_callback *cb, int type,
202
		       const struct tc_action_ops *ops)
203
{
204
	struct tcf_idrinfo *idrinfo = tn->idrinfo;
205

206
	if (type == RTM_DELACTION) {
207
		return tcf_del_walker(idrinfo, skb, ops);
208
	} else if (type == RTM_GETACTION) {
209
		return tcf_dump_walker(idrinfo, skb, cb);
210
	} else {
211
		WARN(1, "tcf_generic_walker: unknown action %d\n", type);
212 213 214
		return -EINVAL;
	}
}
215
EXPORT_SYMBOL(tcf_generic_walker);
216

217
static struct tc_action *tcf_idr_lookup(u32 index, struct tcf_idrinfo *idrinfo)
218
{
219
	struct tc_action *p = NULL;
220

221 222 223
	spin_lock_bh(&idrinfo->lock);
	p = idr_find_ext(&idrinfo->action_idr, index);
	spin_unlock_bh(&idrinfo->lock);
224 225 226 227

	return p;
}

228
int tcf_idr_search(struct tc_action_net *tn, struct tc_action **a, u32 index)
229
{
230 231
	struct tcf_idrinfo *idrinfo = tn->idrinfo;
	struct tc_action *p = tcf_idr_lookup(index, idrinfo);
232 233

	if (p) {
234
		*a = p;
235 236 237 238
		return 1;
	}
	return 0;
}
239
EXPORT_SYMBOL(tcf_idr_search);
240

241 242
bool tcf_idr_check(struct tc_action_net *tn, u32 index, struct tc_action **a,
		   int bind)
243
{
244 245
	struct tcf_idrinfo *idrinfo = tn->idrinfo;
	struct tc_action *p = tcf_idr_lookup(index, idrinfo);
246

247
	if (index && p) {
248
		if (bind)
249 250 251
			p->tcfa_bindcnt++;
		p->tcfa_refcnt++;
		*a = p;
252
		return true;
253
	}
254
	return false;
255
}
256
EXPORT_SYMBOL(tcf_idr_check);
257

258
void tcf_idr_cleanup(struct tc_action *a, struct nlattr *est)
259 260
{
	if (est)
261
		gen_kill_estimator(&a->tcfa_rate_est);
262
	call_rcu(&a->tcfa_rcu, free_tcf);
263
}
264
EXPORT_SYMBOL(tcf_idr_cleanup);
265

266 267 268
int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
		   struct tc_action **a, const struct tc_action_ops *ops,
		   int bind, bool cpustats)
269
{
270
	struct tc_action *p = kzalloc(ops->size, GFP_KERNEL);
271 272
	struct tcf_idrinfo *idrinfo = tn->idrinfo;
	struct idr *idr = &idrinfo->action_idr;
273
	int err = -ENOMEM;
274
	unsigned long idr_index;
275 276

	if (unlikely(!p))
277
		return -ENOMEM;
278
	p->tcfa_refcnt = 1;
279
	if (bind)
280
		p->tcfa_bindcnt = 1;
281

282 283 284 285 286 287 288 289 290 291 292 293 294 295
	if (cpustats) {
		p->cpu_bstats = netdev_alloc_pcpu_stats(struct gnet_stats_basic_cpu);
		if (!p->cpu_bstats) {
err1:
			kfree(p);
			return err;
		}
		p->cpu_qstats = alloc_percpu(struct gnet_stats_queue);
		if (!p->cpu_qstats) {
err2:
			free_percpu(p->cpu_bstats);
			goto err1;
		}
	}
296
	spin_lock_init(&p->tcfa_lock);
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
	/* user doesn't specify an index */
	if (!index) {
		spin_lock_bh(&idrinfo->lock);
		err = idr_alloc_ext(idr, NULL, &idr_index, 1, 0,
				    GFP_KERNEL);
		spin_unlock_bh(&idrinfo->lock);
		if (err) {
err3:
			free_percpu(p->cpu_qstats);
			goto err2;
		}
		p->tcfa_index = idr_index;
	} else {
		spin_lock_bh(&idrinfo->lock);
		err = idr_alloc_ext(idr, NULL, NULL, index, index + 1,
				    GFP_KERNEL);
		spin_unlock_bh(&idrinfo->lock);
		if (err)
			goto err3;
		p->tcfa_index = index;
	}

319 320 321
	p->tcfa_tm.install = jiffies;
	p->tcfa_tm.lastuse = jiffies;
	p->tcfa_tm.firstuse = 0;
322
	if (est) {
323 324 325
		err = gen_new_estimator(&p->tcfa_bstats, p->cpu_bstats,
					&p->tcfa_rate_est,
					&p->tcfa_lock, NULL, est);
326
		if (err) {
327
			goto err3;
328 329 330
		}
	}

331
	p->idrinfo = idrinfo;
332 333 334
	p->ops = ops;
	INIT_LIST_HEAD(&p->list);
	*a = p;
335
	return 0;
336
}
337
EXPORT_SYMBOL(tcf_idr_create);
338

339
void tcf_idr_insert(struct tc_action_net *tn, struct tc_action *a)
340
{
341
	struct tcf_idrinfo *idrinfo = tn->idrinfo;
342

343 344 345
	spin_lock_bh(&idrinfo->lock);
	idr_replace_ext(&idrinfo->action_idr, a, a->tcfa_index);
	spin_unlock_bh(&idrinfo->lock);
346
}
347
EXPORT_SYMBOL(tcf_idr_insert);
L
Linus Torvalds 已提交
348

349 350
void tcf_idrinfo_destroy(const struct tc_action_ops *ops,
			 struct tcf_idrinfo *idrinfo)
351
{
352 353 354 355
	struct idr *idr = &idrinfo->action_idr;
	struct tc_action *p;
	int ret;
	unsigned long id = 1;
356

357 358 359 360 361 362
	idr_for_each_entry_ext(idr, p, id) {
		ret = __tcf_idr_release(p, false, true);
		if (ret == ACT_P_DELETED)
			module_put(ops->owner);
		else if (ret < 0)
			return;
363
	}
364
	idr_destroy(&idrinfo->action_idr);
365
}
366
EXPORT_SYMBOL(tcf_idrinfo_destroy);
367

368
static LIST_HEAD(act_base);
L
Linus Torvalds 已提交
369 370
static DEFINE_RWLOCK(act_mod_lock);

371 372
int tcf_register_action(struct tc_action_ops *act,
			struct pernet_operations *ops)
L
Linus Torvalds 已提交
373
{
374
	struct tc_action_ops *a;
375
	int ret;
L
Linus Torvalds 已提交
376

377
	if (!act->act || !act->dump || !act->init || !act->walk || !act->lookup)
378 379
		return -EINVAL;

380 381 382 383 384 385 386 387
	/* We have to register pernet ops before making the action ops visible,
	 * otherwise tcf_action_init_1() could get a partially initialized
	 * netns.
	 */
	ret = register_pernet_subsys(ops);
	if (ret)
		return ret;

L
Linus Torvalds 已提交
388
	write_lock(&act_mod_lock);
389
	list_for_each_entry(a, &act_base, head) {
L
Linus Torvalds 已提交
390 391
		if (act->type == a->type || (strcmp(act->kind, a->kind) == 0)) {
			write_unlock(&act_mod_lock);
392
			unregister_pernet_subsys(ops);
L
Linus Torvalds 已提交
393 394 395
			return -EEXIST;
		}
	}
396
	list_add_tail(&act->head, &act_base);
L
Linus Torvalds 已提交
397
	write_unlock(&act_mod_lock);
398

L
Linus Torvalds 已提交
399 400
	return 0;
}
401
EXPORT_SYMBOL(tcf_register_action);
L
Linus Torvalds 已提交
402

403 404
int tcf_unregister_action(struct tc_action_ops *act,
			  struct pernet_operations *ops)
L
Linus Torvalds 已提交
405
{
406
	struct tc_action_ops *a;
L
Linus Torvalds 已提交
407 408 409
	int err = -ENOENT;

	write_lock(&act_mod_lock);
410 411 412 413
	list_for_each_entry(a, &act_base, head) {
		if (a == act) {
			list_del(&act->head);
			err = 0;
L
Linus Torvalds 已提交
414
			break;
415
		}
L
Linus Torvalds 已提交
416 417
	}
	write_unlock(&act_mod_lock);
418 419
	if (!err)
		unregister_pernet_subsys(ops);
L
Linus Torvalds 已提交
420 421
	return err;
}
422
EXPORT_SYMBOL(tcf_unregister_action);
L
Linus Torvalds 已提交
423 424 425 426

/* lookup by name */
static struct tc_action_ops *tc_lookup_action_n(char *kind)
{
427
	struct tc_action_ops *a, *res = NULL;
L
Linus Torvalds 已提交
428 429 430

	if (kind) {
		read_lock(&act_mod_lock);
431
		list_for_each_entry(a, &act_base, head) {
L
Linus Torvalds 已提交
432
			if (strcmp(kind, a->kind) == 0) {
433 434
				if (try_module_get(a->owner))
					res = a;
L
Linus Torvalds 已提交
435 436 437 438 439
				break;
			}
		}
		read_unlock(&act_mod_lock);
	}
440
	return res;
L
Linus Torvalds 已提交
441 442
}

443 444
/* lookup by nlattr */
static struct tc_action_ops *tc_lookup_action(struct nlattr *kind)
L
Linus Torvalds 已提交
445
{
446
	struct tc_action_ops *a, *res = NULL;
L
Linus Torvalds 已提交
447 448 449

	if (kind) {
		read_lock(&act_mod_lock);
450
		list_for_each_entry(a, &act_base, head) {
451
			if (nla_strcmp(kind, a->kind) == 0) {
452 453
				if (try_module_get(a->owner))
					res = a;
L
Linus Torvalds 已提交
454 455 456 457 458
				break;
			}
		}
		read_unlock(&act_mod_lock);
	}
459
	return res;
L
Linus Torvalds 已提交
460 461
}

462 463
/*TCA_ACT_MAX_PRIO is 32, there count upto 32 */
#define TCA_ACT_MAX_PRIO_MASK 0x1FF
464 465
int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,
		    int nr_actions, struct tcf_result *res)
L
Linus Torvalds 已提交
466
{
467 468
	u32 jmp_prgcnt = 0;
	u32 jmp_ttl = TCA_ACT_MAX_PRIO; /*matches actions per filter */
469 470
	int i;
	int ret = TC_ACT_OK;
L
Linus Torvalds 已提交
471

472 473 474
	if (skb_skip_tc_classify(skb))
		return TC_ACT_OK;

475
restart_act_graph:
476 477 478
	for (i = 0; i < nr_actions; i++) {
		const struct tc_action *a = actions[i];

479 480 481 482
		if (jmp_prgcnt > 0) {
			jmp_prgcnt -= 1;
			continue;
		}
L
Linus Torvalds 已提交
483
repeat:
484 485 486
		ret = a->ops->act(skb, a, res);
		if (ret == TC_ACT_REPEAT)
			goto repeat;	/* we need a ttl - JHS */
487

488
		if (TC_ACT_EXT_CMP(ret, TC_ACT_JUMP)) {
489 490 491 492 493 494 495 496 497 498 499
			jmp_prgcnt = ret & TCA_ACT_MAX_PRIO_MASK;
			if (!jmp_prgcnt || (jmp_prgcnt > nr_actions)) {
				/* faulty opcode, stop pipeline */
				return TC_ACT_OK;
			} else {
				jmp_ttl -= 1;
				if (jmp_ttl > 0)
					goto restart_act_graph;
				else /* faulty graph, stop pipeline */
					return TC_ACT_OK;
			}
500 501
		} else if (TC_ACT_EXT_CMP(ret, TC_ACT_GOTO_CHAIN)) {
			tcf_action_goto_chain_exec(a, res);
502 503
		}

504
		if (ret != TC_ACT_PIPE)
505
			break;
L
Linus Torvalds 已提交
506
	}
507

L
Linus Torvalds 已提交
508 509
	return ret;
}
510
EXPORT_SYMBOL(tcf_action_exec);
L
Linus Torvalds 已提交
511

512
int tcf_action_destroy(struct list_head *actions, int bind)
L
Linus Torvalds 已提交
513
{
514
	struct tc_action *a, *tmp;
515
	int ret = 0;
L
Linus Torvalds 已提交
516

517
	list_for_each_entry_safe(a, tmp, actions, list) {
518
		ret = __tcf_idr_release(a, bind, true);
519
		if (ret == ACT_P_DELETED)
520
			module_put(a->ops->owner);
521 522
		else if (ret < 0)
			return ret;
L
Linus Torvalds 已提交
523
	}
524
	return ret;
L
Linus Torvalds 已提交
525 526 527 528 529 530 531 532 533 534 535 536
}

int
tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
{
	return a->ops->dump(skb, a, bind, ref);
}

int
tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
{
	int err = -EINVAL;
537
	unsigned char *b = skb_tail_pointer(skb);
538
	struct nlattr *nest;
L
Linus Torvalds 已提交
539

540 541
	if (nla_put_string(skb, TCA_KIND, a->ops->kind))
		goto nla_put_failure;
L
Linus Torvalds 已提交
542
	if (tcf_action_copy_stats(skb, a, 0))
543
		goto nla_put_failure;
544 545 546 547 548 549
	if (a->act_cookie) {
		if (nla_put(skb, TCA_ACT_COOKIE, a->act_cookie->len,
			    a->act_cookie->data))
			goto nla_put_failure;
	}

550 551 552
	nest = nla_nest_start(skb, TCA_OPTIONS);
	if (nest == NULL)
		goto nla_put_failure;
E
Eric Dumazet 已提交
553 554
	err = tcf_action_dump_old(skb, a, bind, ref);
	if (err > 0) {
555
		nla_nest_end(skb, nest);
L
Linus Torvalds 已提交
556 557 558
		return err;
	}

559
nla_put_failure:
560
	nlmsg_trim(skb, b);
L
Linus Torvalds 已提交
561 562
	return -1;
}
563
EXPORT_SYMBOL(tcf_action_dump_1);
L
Linus Torvalds 已提交
564

565 566
int tcf_action_dump(struct sk_buff *skb, struct list_head *actions,
		    int bind, int ref)
L
Linus Torvalds 已提交
567 568 569
{
	struct tc_action *a;
	int err = -EINVAL;
570
	struct nlattr *nest;
L
Linus Torvalds 已提交
571

572
	list_for_each_entry(a, actions, list) {
573 574 575
		nest = nla_nest_start(skb, a->order);
		if (nest == NULL)
			goto nla_put_failure;
L
Linus Torvalds 已提交
576 577
		err = tcf_action_dump_1(skb, a, bind, ref);
		if (err < 0)
578
			goto errout;
579
		nla_nest_end(skb, nest);
L
Linus Torvalds 已提交
580 581 582 583
	}

	return 0;

584
nla_put_failure:
585 586
	err = -EINVAL;
errout:
587
	nla_nest_cancel(skb, nest);
588
	return err;
L
Linus Torvalds 已提交
589 590
}

591
static struct tc_cookie *nla_memdup_cookie(struct nlattr **tb)
592
{
593 594 595 596 597 598 599 600
	struct tc_cookie *c = kzalloc(sizeof(*c), GFP_KERNEL);
	if (!c)
		return NULL;

	c->data = nla_memdup(tb[TCA_ACT_COOKIE], GFP_KERNEL);
	if (!c->data) {
		kfree(c);
		return NULL;
601
	}
602
	c->len = nla_len(tb[TCA_ACT_COOKIE]);
603

604
	return c;
605 606
}

607 608 609
struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
				    struct nlattr *nla, struct nlattr *est,
				    char *name, int ovr, int bind)
L
Linus Torvalds 已提交
610 611 612
{
	struct tc_action *a;
	struct tc_action_ops *a_o;
613
	struct tc_cookie *cookie = NULL;
L
Linus Torvalds 已提交
614
	char act_name[IFNAMSIZ];
E
Eric Dumazet 已提交
615
	struct nlattr *tb[TCA_ACT_MAX + 1];
616
	struct nlattr *kind;
617
	int err;
L
Linus Torvalds 已提交
618 619

	if (name == NULL) {
620
		err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL, NULL);
621
		if (err < 0)
L
Linus Torvalds 已提交
622
			goto err_out;
623
		err = -EINVAL;
624
		kind = tb[TCA_ACT_KIND];
L
Linus Torvalds 已提交
625 626
		if (kind == NULL)
			goto err_out;
627
		if (nla_strlcpy(act_name, kind, IFNAMSIZ) >= IFNAMSIZ)
L
Linus Torvalds 已提交
628
			goto err_out;
629 630 631 632 633 634 635 636 637 638 639 640
		if (tb[TCA_ACT_COOKIE]) {
			int cklen = nla_len(tb[TCA_ACT_COOKIE]);

			if (cklen > TC_COOKIE_MAX_SIZE)
				goto err_out;

			cookie = nla_memdup_cookie(tb);
			if (!cookie) {
				err = -ENOMEM;
				goto err_out;
			}
		}
L
Linus Torvalds 已提交
641
	} else {
642
		err = -EINVAL;
L
Linus Torvalds 已提交
643 644 645 646 647 648
		if (strlcpy(act_name, name, IFNAMSIZ) >= IFNAMSIZ)
			goto err_out;
	}

	a_o = tc_lookup_action_n(act_name);
	if (a_o == NULL) {
649
#ifdef CONFIG_MODULES
L
Linus Torvalds 已提交
650
		rtnl_unlock();
651
		request_module("act_%s", act_name);
L
Linus Torvalds 已提交
652 653 654 655 656 657 658 659 660 661 662
		rtnl_lock();

		a_o = tc_lookup_action_n(act_name);

		/* We dropped the RTNL semaphore in order to
		 * perform the module load.  So, even if we
		 * succeeded in loading the module we have to
		 * tell the caller to replay the request.  We
		 * indicate this using -EAGAIN.
		 */
		if (a_o != NULL) {
663
			err = -EAGAIN;
L
Linus Torvalds 已提交
664 665 666
			goto err_mod;
		}
#endif
667
		err = -ENOENT;
L
Linus Torvalds 已提交
668 669 670 671 672
		goto err_out;
	}

	/* backward compatibility for policer */
	if (name == NULL)
673
		err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, &a, ovr, bind);
L
Linus Torvalds 已提交
674
	else
675
		err = a_o->init(net, nla, est, &a, ovr, bind);
676
	if (err < 0)
677
		goto err_mod;
L
Linus Torvalds 已提交
678

679 680 681 682
	if (name == NULL && tb[TCA_ACT_COOKIE]) {
		if (a->act_cookie) {
			kfree(a->act_cookie->data);
			kfree(a->act_cookie);
683
		}
684
		a->act_cookie = cookie;
685 686
	}

L
Linus Torvalds 已提交
687
	/* module count goes up only when brand new policy is created
E
Eric Dumazet 已提交
688 689 690
	 * if it exists and is only bound to in a_o->init() then
	 * ACT_P_CREATED is not returned (a zero is).
	 */
691
	if (err != ACT_P_CREATED)
L
Linus Torvalds 已提交
692 693
		module_put(a_o->owner);

694 695 696 697 698 699 700 701 702 703 704
	if (TC_ACT_EXT_CMP(a->tcfa_action, TC_ACT_GOTO_CHAIN)) {
		err = tcf_action_goto_chain_init(a, tp);
		if (err) {
			LIST_HEAD(actions);

			list_add_tail(&a->list, &actions);
			tcf_action_destroy(&actions, bind);
			return ERR_PTR(err);
		}
	}

L
Linus Torvalds 已提交
705 706 707 708 709
	return a;

err_mod:
	module_put(a_o->owner);
err_out:
710 711 712 713
	if (cookie) {
		kfree(cookie->data);
		kfree(cookie);
	}
714
	return ERR_PTR(err);
L
Linus Torvalds 已提交
715 716
}

717 718 719 720 721 722 723 724 725 726 727
static void cleanup_a(struct list_head *actions, int ovr)
{
	struct tc_action *a;

	if (!ovr)
		return;

	list_for_each_entry(a, actions, list)
		a->tcfa_refcnt--;
}

728 729 730
int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
		    struct nlattr *est, char *name, int ovr, int bind,
		    struct list_head *actions)
L
Linus Torvalds 已提交
731
{
E
Eric Dumazet 已提交
732
	struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
733
	struct tc_action *act;
734
	int err;
L
Linus Torvalds 已提交
735 736
	int i;

737
	err = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL, NULL);
738
	if (err < 0)
739
		return err;
L
Linus Torvalds 已提交
740

741
	for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
742
		act = tcf_action_init_1(net, tp, tb[i], est, name, ovr, bind);
743 744
		if (IS_ERR(act)) {
			err = PTR_ERR(act);
L
Linus Torvalds 已提交
745
			goto err;
746
		}
747
		act->order = i;
748 749
		if (ovr)
			act->tcfa_refcnt++;
750
		list_add_tail(&act->list, actions);
L
Linus Torvalds 已提交
751
	}
752 753 754 755 756

	/* Remove the temp refcnt which was necessary to protect against
	 * destroying an existing action which was being replaced
	 */
	cleanup_a(actions, ovr);
757
	return 0;
L
Linus Torvalds 已提交
758 759

err:
760 761
	tcf_action_destroy(actions, bind);
	return err;
L
Linus Torvalds 已提交
762 763
}

764
int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *p,
L
Linus Torvalds 已提交
765 766 767 768
			  int compat_mode)
{
	int err = 0;
	struct gnet_dump d;
769

770
	if (p == NULL)
L
Linus Torvalds 已提交
771 772 773
		goto errout;

	/* compat_mode being true specifies a call that is supposed
774
	 * to add additional backward compatibility statistic TLVs.
L
Linus Torvalds 已提交
775 776
	 */
	if (compat_mode) {
777
		if (p->type == TCA_OLD_COMPAT)
L
Linus Torvalds 已提交
778
			err = gnet_stats_start_copy_compat(skb, 0,
779 780
							   TCA_STATS,
							   TCA_XSTATS,
781
							   &p->tcfa_lock, &d,
782
							   TCA_PAD);
L
Linus Torvalds 已提交
783 784 785 786
		else
			return 0;
	} else
		err = gnet_stats_start_copy(skb, TCA_ACT_STATS,
787
					    &p->tcfa_lock, &d, TCA_ACT_PAD);
L
Linus Torvalds 已提交
788 789 790 791

	if (err < 0)
		goto errout;

792
	if (gnet_stats_copy_basic(NULL, &d, p->cpu_bstats, &p->tcfa_bstats) < 0 ||
793
	    gnet_stats_copy_rate_est(&d, &p->tcfa_rate_est) < 0 ||
794
	    gnet_stats_copy_queue(&d, p->cpu_qstats,
795 796
				  &p->tcfa_qstats,
				  p->tcfa_qstats.qlen) < 0)
L
Linus Torvalds 已提交
797 798 799 800 801 802 803 804 805 806 807
		goto errout;

	if (gnet_stats_finish_copy(&d) < 0)
		goto errout;

	return 0;

errout:
	return -1;
}

808 809 810
static int tca_get_fill(struct sk_buff *skb, struct list_head *actions,
			u32 portid, u32 seq, u16 flags, int event, int bind,
			int ref)
L
Linus Torvalds 已提交
811 812 813
{
	struct tcamsg *t;
	struct nlmsghdr *nlh;
814
	unsigned char *b = skb_tail_pointer(skb);
815
	struct nlattr *nest;
L
Linus Torvalds 已提交
816

817
	nlh = nlmsg_put(skb, portid, seq, event, sizeof(*t), flags);
818 819 820
	if (!nlh)
		goto out_nlmsg_trim;
	t = nlmsg_data(nlh);
L
Linus Torvalds 已提交
821
	t->tca_family = AF_UNSPEC;
822 823
	t->tca__pad1 = 0;
	t->tca__pad2 = 0;
824

825 826
	nest = nla_nest_start(skb, TCA_ACT_TAB);
	if (nest == NULL)
827
		goto out_nlmsg_trim;
L
Linus Torvalds 已提交
828

829
	if (tcf_action_dump(skb, actions, bind, ref) < 0)
830
		goto out_nlmsg_trim;
L
Linus Torvalds 已提交
831

832
	nla_nest_end(skb, nest);
833

834
	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
L
Linus Torvalds 已提交
835 836
	return skb->len;

837
out_nlmsg_trim:
838
	nlmsg_trim(skb, b);
L
Linus Torvalds 已提交
839 840 841 842
	return -1;
}

static int
843
tcf_get_notify(struct net *net, u32 portid, struct nlmsghdr *n,
844
	       struct list_head *actions, int event)
L
Linus Torvalds 已提交
845 846 847 848 849 850
{
	struct sk_buff *skb;

	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
	if (!skb)
		return -ENOBUFS;
851 852
	if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, event,
			 0, 0) <= 0) {
L
Linus Torvalds 已提交
853 854 855
		kfree_skb(skb);
		return -EINVAL;
	}
856

857
	return rtnl_unicast(skb, net, portid);
L
Linus Torvalds 已提交
858 859
}

860 861
static struct tc_action *tcf_action_get_1(struct net *net, struct nlattr *nla,
					  struct nlmsghdr *n, u32 portid)
L
Linus Torvalds 已提交
862
{
E
Eric Dumazet 已提交
863
	struct nlattr *tb[TCA_ACT_MAX + 1];
864
	const struct tc_action_ops *ops;
L
Linus Torvalds 已提交
865 866
	struct tc_action *a;
	int index;
867
	int err;
L
Linus Torvalds 已提交
868

869
	err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL, NULL);
870
	if (err < 0)
871
		goto err_out;
L
Linus Torvalds 已提交
872

873
	err = -EINVAL;
874 875
	if (tb[TCA_ACT_INDEX] == NULL ||
	    nla_len(tb[TCA_ACT_INDEX]) < sizeof(index))
876
		goto err_out;
877
	index = nla_get_u32(tb[TCA_ACT_INDEX]);
L
Linus Torvalds 已提交
878

879
	err = -EINVAL;
880 881 882
	ops = tc_lookup_action(tb[TCA_ACT_KIND]);
	if (!ops) /* could happen in batch of actions */
		goto err_out;
883
	err = -ENOENT;
884
	if (ops->lookup(net, &a, index) == 0)
L
Linus Torvalds 已提交
885 886
		goto err_mod;

887
	module_put(ops->owner);
L
Linus Torvalds 已提交
888
	return a;
889

L
Linus Torvalds 已提交
890
err_mod:
891
	module_put(ops->owner);
892 893
err_out:
	return ERR_PTR(err);
L
Linus Torvalds 已提交
894 895
}

896
static int tca_action_flush(struct net *net, struct nlattr *nla,
897
			    struct nlmsghdr *n, u32 portid)
L
Linus Torvalds 已提交
898 899 900 901 902 903
{
	struct sk_buff *skb;
	unsigned char *b;
	struct nlmsghdr *nlh;
	struct tcamsg *t;
	struct netlink_callback dcb;
904
	struct nlattr *nest;
E
Eric Dumazet 已提交
905
	struct nlattr *tb[TCA_ACT_MAX + 1];
906
	const struct tc_action_ops *ops;
907
	struct nlattr *kind;
908
	int err = -ENOMEM;
L
Linus Torvalds 已提交
909 910 911

	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
	if (!skb) {
912
		pr_debug("tca_action_flush: failed skb alloc\n");
913
		return err;
L
Linus Torvalds 已提交
914 915
	}

916
	b = skb_tail_pointer(skb);
L
Linus Torvalds 已提交
917

918
	err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL, NULL);
919
	if (err < 0)
L
Linus Torvalds 已提交
920 921
		goto err_out;

922
	err = -EINVAL;
923
	kind = tb[TCA_ACT_KIND];
924 925
	ops = tc_lookup_action(kind);
	if (!ops) /*some idjot trying to flush unknown action */
L
Linus Torvalds 已提交
926 927
		goto err_out;

928 929
	nlh = nlmsg_put(skb, portid, n->nlmsg_seq, RTM_DELACTION,
			sizeof(*t), 0);
930 931 932
	if (!nlh)
		goto out_module_put;
	t = nlmsg_data(nlh);
L
Linus Torvalds 已提交
933
	t->tca_family = AF_UNSPEC;
934 935
	t->tca__pad1 = 0;
	t->tca__pad2 = 0;
L
Linus Torvalds 已提交
936

937 938
	nest = nla_nest_start(skb, TCA_ACT_TAB);
	if (nest == NULL)
939
		goto out_module_put;
L
Linus Torvalds 已提交
940

941
	err = ops->walk(net, skb, &dcb, RTM_DELACTION, ops);
942
	if (err <= 0)
943
		goto out_module_put;
L
Linus Torvalds 已提交
944

945
	nla_nest_end(skb, nest);
L
Linus Torvalds 已提交
946

947
	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
L
Linus Torvalds 已提交
948
	nlh->nlmsg_flags |= NLM_F_ROOT;
949
	module_put(ops->owner);
950
	err = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
E
Eric Dumazet 已提交
951
			     n->nlmsg_flags & NLM_F_ECHO);
L
Linus Torvalds 已提交
952 953 954 955 956
	if (err > 0)
		return 0;

	return err;

957
out_module_put:
958
	module_put(ops->owner);
L
Linus Torvalds 已提交
959 960 961 962 963
err_out:
	kfree_skb(skb);
	return err;
}

964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981
static int
tcf_del_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions,
	       u32 portid)
{
	int ret;
	struct sk_buff *skb;

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

	if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, RTM_DELACTION,
			 0, 1) <= 0) {
		kfree_skb(skb);
		return -EINVAL;
	}

	/* now do the delete */
982 983 984 985 986
	ret = tcf_action_destroy(actions, 0);
	if (ret < 0) {
		kfree_skb(skb);
		return ret;
	}
987 988 989 990 991 992 993 994

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

L
Linus Torvalds 已提交
995
static int
996
tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
997
	      u32 portid, int event)
L
Linus Torvalds 已提交
998
{
999
	int i, ret;
E
Eric Dumazet 已提交
1000
	struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
1001 1002
	struct tc_action *act;
	LIST_HEAD(actions);
L
Linus Torvalds 已提交
1003

1004
	ret = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL, NULL);
1005 1006
	if (ret < 0)
		return ret;
L
Linus Torvalds 已提交
1007

E
Eric Dumazet 已提交
1008
	if (event == RTM_DELACTION && n->nlmsg_flags & NLM_F_ROOT) {
1009
		if (tb[1] != NULL)
1010
			return tca_action_flush(net, tb[1], n, portid);
1011 1012
		else
			return -EINVAL;
L
Linus Torvalds 已提交
1013 1014
	}

1015
	for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
1016
		act = tcf_action_get_1(net, tb[i], n, portid);
1017 1018
		if (IS_ERR(act)) {
			ret = PTR_ERR(act);
L
Linus Torvalds 已提交
1019
			goto err;
1020
		}
1021
		act->order = i;
1022
		list_add_tail(&act->list, &actions);
L
Linus Torvalds 已提交
1023 1024 1025
	}

	if (event == RTM_GETACTION)
1026
		ret = tcf_get_notify(net, portid, n, &actions, event);
L
Linus Torvalds 已提交
1027
	else { /* delete */
1028 1029
		ret = tcf_del_notify(net, n, &actions, portid);
		if (ret)
L
Linus Torvalds 已提交
1030 1031 1032 1033
			goto err;
		return ret;
	}
err:
1034 1035
	if (event != RTM_GETACTION)
		tcf_action_destroy(&actions, 0);
L
Linus Torvalds 已提交
1036 1037 1038
	return ret;
}

1039 1040 1041
static int
tcf_add_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions,
	       u32 portid)
L
Linus Torvalds 已提交
1042 1043 1044 1045 1046 1047 1048 1049
{
	struct sk_buff *skb;
	int err = 0;

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

1050 1051 1052 1053 1054
	if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, n->nlmsg_flags,
			 RTM_NEWACTION, 0, 0) <= 0) {
		kfree_skb(skb);
		return -EINVAL;
	}
1055

1056 1057
	err = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
			     n->nlmsg_flags & NLM_F_ECHO);
L
Linus Torvalds 已提交
1058 1059 1060 1061 1062
	if (err > 0)
		err = 0;
	return err;
}

J
Jamal Hadi Salim 已提交
1063 1064
static int tcf_action_add(struct net *net, struct nlattr *nla,
			  struct nlmsghdr *n, u32 portid, int ovr)
L
Linus Torvalds 已提交
1065 1066
{
	int ret = 0;
1067
	LIST_HEAD(actions);
L
Linus Torvalds 已提交
1068

1069
	ret = tcf_action_init(net, NULL, nla, NULL, NULL, ovr, 0, &actions);
1070
	if (ret)
1071
		return ret;
L
Linus Torvalds 已提交
1072

1073
	return tcf_add_notify(net, n, &actions, portid);
L
Linus Torvalds 已提交
1074 1075
}

1076 1077 1078 1079
static u32 tcaa_root_flags_allowed = TCA_FLAG_LARGE_DUMP_ON;
static const struct nla_policy tcaa_policy[TCA_ROOT_MAX + 1] = {
	[TCA_ROOT_FLAGS] = { .type = NLA_BITFIELD32,
			     .validation_data = &tcaa_root_flags_allowed },
1080
	[TCA_ROOT_TIME_DELTA]      = { .type = NLA_U32 },
1081 1082
};

1083 1084
static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n,
			 struct netlink_ext_ack *extack)
L
Linus Torvalds 已提交
1085
{
1086
	struct net *net = sock_net(skb->sk);
1087
	struct nlattr *tca[TCA_ROOT_MAX + 1];
1088
	u32 portid = skb ? NETLINK_CB(skb).portid : 0;
L
Linus Torvalds 已提交
1089 1090
	int ret = 0, ovr = 0;

1091 1092
	if ((n->nlmsg_type != RTM_GETACTION) &&
	    !netlink_capable(skb, CAP_NET_ADMIN))
1093 1094
		return -EPERM;

1095
	ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ROOT_MAX, NULL,
1096
			  extack);
1097 1098 1099 1100
	if (ret < 0)
		return ret;

	if (tca[TCA_ACT_TAB] == NULL) {
1101
		pr_notice("tc_ctl_action: received NO action attribs\n");
L
Linus Torvalds 已提交
1102 1103 1104
		return -EINVAL;
	}

E
Eric Dumazet 已提交
1105
	/* n->nlmsg_flags & NLM_F_CREATE */
L
Linus Torvalds 已提交
1106 1107 1108
	switch (n->nlmsg_type) {
	case RTM_NEWACTION:
		/* we are going to assume all other flags
L
Lucas De Marchi 已提交
1109
		 * imply create only if it doesn't exist
L
Linus Torvalds 已提交
1110 1111 1112 1113
		 * Note that CREATE | EXCL implies that
		 * but since we want avoid ambiguity (eg when flags
		 * is zero) then just set this
		 */
E
Eric Dumazet 已提交
1114
		if (n->nlmsg_flags & NLM_F_REPLACE)
L
Linus Torvalds 已提交
1115 1116
			ovr = 1;
replay:
1117
		ret = tcf_action_add(net, tca[TCA_ACT_TAB], n, portid, ovr);
L
Linus Torvalds 已提交
1118 1119 1120 1121
		if (ret == -EAGAIN)
			goto replay;
		break;
	case RTM_DELACTION:
1122
		ret = tca_action_gd(net, tca[TCA_ACT_TAB], n,
1123
				    portid, RTM_DELACTION);
L
Linus Torvalds 已提交
1124 1125
		break;
	case RTM_GETACTION:
1126
		ret = tca_action_gd(net, tca[TCA_ACT_TAB], n,
1127
				    portid, RTM_GETACTION);
L
Linus Torvalds 已提交
1128 1129 1130 1131 1132 1133 1134 1135
		break;
	default:
		BUG();
	}

	return ret;
}

1136
static struct nlattr *find_dump_kind(struct nlattr **nla)
L
Linus Torvalds 已提交
1137
{
E
Eric Dumazet 已提交
1138
	struct nlattr *tb1, *tb2[TCA_ACT_MAX + 1];
1139 1140
	struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
	struct nlattr *kind;
L
Linus Torvalds 已提交
1141

1142
	tb1 = nla[TCA_ACT_TAB];
L
Linus Torvalds 已提交
1143 1144 1145
	if (tb1 == NULL)
		return NULL;

1146
	if (nla_parse(tb, TCA_ACT_MAX_PRIO, nla_data(tb1),
1147
		      NLMSG_ALIGN(nla_len(tb1)), NULL, NULL) < 0)
L
Linus Torvalds 已提交
1148 1149
		return NULL;

1150 1151
	if (tb[1] == NULL)
		return NULL;
1152
	if (nla_parse_nested(tb2, TCA_ACT_MAX, tb[1], NULL, NULL) < 0)
L
Linus Torvalds 已提交
1153
		return NULL;
1154
	kind = tb2[TCA_ACT_KIND];
L
Linus Torvalds 已提交
1155

1156
	return kind;
L
Linus Torvalds 已提交
1157 1158
}

J
Jamal Hadi Salim 已提交
1159
static int tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
L
Linus Torvalds 已提交
1160
{
1161
	struct net *net = sock_net(skb->sk);
L
Linus Torvalds 已提交
1162
	struct nlmsghdr *nlh;
1163
	unsigned char *b = skb_tail_pointer(skb);
1164
	struct nlattr *nest;
L
Linus Torvalds 已提交
1165 1166
	struct tc_action_ops *a_o;
	int ret = 0;
1167
	struct tcamsg *t = (struct tcamsg *) nlmsg_data(cb->nlh);
1168 1169
	struct nlattr *tb[TCA_ROOT_MAX + 1];
	struct nlattr *count_attr = NULL;
1170
	unsigned long jiffy_since = 0;
1171 1172
	struct nlattr *kind = NULL;
	struct nla_bitfield32 bf;
1173
	u32 msecs_since = 0;
1174 1175 1176 1177 1178 1179
	u32 act_count = 0;

	ret = nlmsg_parse(cb->nlh, sizeof(struct tcamsg), tb, TCA_ROOT_MAX,
			  tcaa_policy, NULL);
	if (ret < 0)
		return ret;
L
Linus Torvalds 已提交
1180

1181
	kind = find_dump_kind(tb);
L
Linus Torvalds 已提交
1182
	if (kind == NULL) {
1183
		pr_info("tc_dump_action: action bad kind\n");
L
Linus Torvalds 已提交
1184 1185 1186
		return 0;
	}

1187
	a_o = tc_lookup_action(kind);
E
Eric Dumazet 已提交
1188
	if (a_o == NULL)
L
Linus Torvalds 已提交
1189 1190
		return 0;

1191 1192 1193 1194 1195 1196
	cb->args[2] = 0;
	if (tb[TCA_ROOT_FLAGS]) {
		bf = nla_get_bitfield32(tb[TCA_ROOT_FLAGS]);
		cb->args[2] = bf.value;
	}

1197 1198 1199 1200
	if (tb[TCA_ROOT_TIME_DELTA]) {
		msecs_since = nla_get_u32(tb[TCA_ROOT_TIME_DELTA]);
	}

1201
	nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
1202 1203 1204
			cb->nlh->nlmsg_type, sizeof(*t), 0);
	if (!nlh)
		goto out_module_put;
1205

1206 1207 1208
	if (msecs_since)
		jiffy_since = jiffies - msecs_to_jiffies(msecs_since);

1209
	t = nlmsg_data(nlh);
L
Linus Torvalds 已提交
1210
	t->tca_family = AF_UNSPEC;
1211 1212
	t->tca__pad1 = 0;
	t->tca__pad2 = 0;
1213
	cb->args[3] = jiffy_since;
1214 1215 1216
	count_attr = nla_reserve(skb, TCA_ROOT_COUNT, sizeof(u32));
	if (!count_attr)
		goto out_module_put;
L
Linus Torvalds 已提交
1217

1218 1219
	nest = nla_nest_start(skb, TCA_ACT_TAB);
	if (nest == NULL)
1220
		goto out_module_put;
L
Linus Torvalds 已提交
1221

1222
	ret = a_o->walk(net, skb, cb, RTM_GETACTION, a_o);
L
Linus Torvalds 已提交
1223
	if (ret < 0)
1224
		goto out_module_put;
L
Linus Torvalds 已提交
1225 1226

	if (ret > 0) {
1227
		nla_nest_end(skb, nest);
L
Linus Torvalds 已提交
1228
		ret = skb->len;
1229 1230 1231
		act_count = cb->args[1];
		memcpy(nla_data(count_attr), &act_count, sizeof(u32));
		cb->args[1] = 0;
L
Linus Torvalds 已提交
1232
	} else
1233
		nlmsg_trim(skb, b);
L
Linus Torvalds 已提交
1234

1235
	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
1236
	if (NETLINK_CB(cb->skb).portid && ret)
L
Linus Torvalds 已提交
1237 1238 1239 1240
		nlh->nlmsg_flags |= NLM_F_MULTI;
	module_put(a_o->owner);
	return skb->len;

1241
out_module_put:
L
Linus Torvalds 已提交
1242
	module_put(a_o->owner);
1243
	nlmsg_trim(skb, b);
L
Linus Torvalds 已提交
1244 1245 1246 1247 1248
	return skb->len;
}

static int __init tc_action_init(void)
{
1249 1250
	rtnl_register(PF_UNSPEC, RTM_NEWACTION, tc_ctl_action, NULL, 0);
	rtnl_register(PF_UNSPEC, RTM_DELACTION, tc_ctl_action, NULL, 0);
1251
	rtnl_register(PF_UNSPEC, RTM_GETACTION, tc_ctl_action, tc_dump_action,
1252
		      0);
L
Linus Torvalds 已提交
1253 1254 1255 1256 1257

	return 0;
}

subsys_initcall(tc_action_init);