act_api.c 27.5 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
	/* user doesn't specify an index */
	if (!index) {
299
		idr_preload(GFP_KERNEL);
300 301
		spin_lock_bh(&idrinfo->lock);
		err = idr_alloc_ext(idr, NULL, &idr_index, 1, 0,
302
				    GFP_ATOMIC);
303
		spin_unlock_bh(&idrinfo->lock);
304
		idr_preload_end();
305 306 307 308 309 310 311
		if (err) {
err3:
			free_percpu(p->cpu_qstats);
			goto err2;
		}
		p->tcfa_index = idr_index;
	} else {
312
		idr_preload(GFP_KERNEL);
313 314
		spin_lock_bh(&idrinfo->lock);
		err = idr_alloc_ext(idr, NULL, NULL, index, index + 1,
315
				    GFP_ATOMIC);
316
		spin_unlock_bh(&idrinfo->lock);
317
		idr_preload_end();
318 319 320 321 322
		if (err)
			goto err3;
		p->tcfa_index = index;
	}

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

335
	p->idrinfo = idrinfo;
336 337 338
	p->ops = ops;
	INIT_LIST_HEAD(&p->list);
	*a = p;
339
	return 0;
340
}
341
EXPORT_SYMBOL(tcf_idr_create);
342

343
void tcf_idr_insert(struct tc_action_net *tn, struct tc_action *a)
344
{
345
	struct tcf_idrinfo *idrinfo = tn->idrinfo;
346

347 348 349
	spin_lock_bh(&idrinfo->lock);
	idr_replace_ext(&idrinfo->action_idr, a, a->tcfa_index);
	spin_unlock_bh(&idrinfo->lock);
350
}
351
EXPORT_SYMBOL(tcf_idr_insert);
L
Linus Torvalds 已提交
352

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

361 362 363 364 365 366
	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;
367
	}
368
	idr_destroy(&idrinfo->action_idr);
369
}
370
EXPORT_SYMBOL(tcf_idrinfo_destroy);
371

372
static LIST_HEAD(act_base);
L
Linus Torvalds 已提交
373 374
static DEFINE_RWLOCK(act_mod_lock);

375 376
int tcf_register_action(struct tc_action_ops *act,
			struct pernet_operations *ops)
L
Linus Torvalds 已提交
377
{
378
	struct tc_action_ops *a;
379
	int ret;
L
Linus Torvalds 已提交
380

381
	if (!act->act || !act->dump || !act->init || !act->walk || !act->lookup)
382 383
		return -EINVAL;

384 385 386 387 388 389 390 391
	/* 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 已提交
392
	write_lock(&act_mod_lock);
393
	list_for_each_entry(a, &act_base, head) {
L
Linus Torvalds 已提交
394 395
		if (act->type == a->type || (strcmp(act->kind, a->kind) == 0)) {
			write_unlock(&act_mod_lock);
396
			unregister_pernet_subsys(ops);
L
Linus Torvalds 已提交
397 398 399
			return -EEXIST;
		}
	}
400
	list_add_tail(&act->head, &act_base);
L
Linus Torvalds 已提交
401
	write_unlock(&act_mod_lock);
402

L
Linus Torvalds 已提交
403 404
	return 0;
}
405
EXPORT_SYMBOL(tcf_register_action);
L
Linus Torvalds 已提交
406

407 408
int tcf_unregister_action(struct tc_action_ops *act,
			  struct pernet_operations *ops)
L
Linus Torvalds 已提交
409
{
410
	struct tc_action_ops *a;
L
Linus Torvalds 已提交
411 412 413
	int err = -ENOENT;

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

/* lookup by name */
static struct tc_action_ops *tc_lookup_action_n(char *kind)
{
431
	struct tc_action_ops *a, *res = NULL;
L
Linus Torvalds 已提交
432 433 434

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

447 448
/* lookup by nlattr */
static struct tc_action_ops *tc_lookup_action(struct nlattr *kind)
L
Linus Torvalds 已提交
449
{
450
	struct tc_action_ops *a, *res = NULL;
L
Linus Torvalds 已提交
451 452 453

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

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

476 477 478
	if (skb_skip_tc_classify(skb))
		return TC_ACT_OK;

479
restart_act_graph:
480 481 482
	for (i = 0; i < nr_actions; i++) {
		const struct tc_action *a = actions[i];

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

492
		if (TC_ACT_EXT_CMP(ret, TC_ACT_JUMP)) {
493 494 495 496 497 498 499 500 501 502 503
			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;
			}
504 505
		} else if (TC_ACT_EXT_CMP(ret, TC_ACT_GOTO_CHAIN)) {
			tcf_action_goto_chain_exec(a, res);
506 507
		}

508
		if (ret != TC_ACT_PIPE)
509
			break;
L
Linus Torvalds 已提交
510
	}
511

L
Linus Torvalds 已提交
512 513
	return ret;
}
514
EXPORT_SYMBOL(tcf_action_exec);
L
Linus Torvalds 已提交
515

516
int tcf_action_destroy(struct list_head *actions, int bind)
L
Linus Torvalds 已提交
517
{
518
	struct tc_action *a, *tmp;
519
	int ret = 0;
L
Linus Torvalds 已提交
520

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

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;
541
	unsigned char *b = skb_tail_pointer(skb);
542
	struct nlattr *nest;
L
Linus Torvalds 已提交
543

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

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

563
nla_put_failure:
564
	nlmsg_trim(skb, b);
L
Linus Torvalds 已提交
565 566
	return -1;
}
567
EXPORT_SYMBOL(tcf_action_dump_1);
L
Linus Torvalds 已提交
568

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

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

	return 0;

588
nla_put_failure:
589 590
	err = -EINVAL;
errout:
591
	nla_nest_cancel(skb, nest);
592
	return err;
L
Linus Torvalds 已提交
593 594
}

595
static struct tc_cookie *nla_memdup_cookie(struct nlattr **tb)
596
{
597 598 599 600 601 602 603 604
	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;
605
	}
606
	c->len = nla_len(tb[TCA_ACT_COOKIE]);
607

608
	return c;
609 610
}

611 612 613
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 已提交
614 615 616
{
	struct tc_action *a;
	struct tc_action_ops *a_o;
617
	struct tc_cookie *cookie = NULL;
L
Linus Torvalds 已提交
618
	char act_name[IFNAMSIZ];
E
Eric Dumazet 已提交
619
	struct nlattr *tb[TCA_ACT_MAX + 1];
620
	struct nlattr *kind;
621
	int err;
L
Linus Torvalds 已提交
622 623

	if (name == NULL) {
624
		err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL, NULL);
625
		if (err < 0)
L
Linus Torvalds 已提交
626
			goto err_out;
627
		err = -EINVAL;
628
		kind = tb[TCA_ACT_KIND];
L
Linus Torvalds 已提交
629 630
		if (kind == NULL)
			goto err_out;
631
		if (nla_strlcpy(act_name, kind, IFNAMSIZ) >= IFNAMSIZ)
L
Linus Torvalds 已提交
632
			goto err_out;
633 634 635 636 637 638 639 640 641 642 643 644
		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 已提交
645
	} else {
646
		err = -EINVAL;
L
Linus Torvalds 已提交
647 648 649 650 651 652
		if (strlcpy(act_name, name, IFNAMSIZ) >= IFNAMSIZ)
			goto err_out;
	}

	a_o = tc_lookup_action_n(act_name);
	if (a_o == NULL) {
653
#ifdef CONFIG_MODULES
L
Linus Torvalds 已提交
654
		rtnl_unlock();
655
		request_module("act_%s", act_name);
L
Linus Torvalds 已提交
656 657 658 659 660 661 662 663 664 665 666
		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) {
667
			err = -EAGAIN;
L
Linus Torvalds 已提交
668 669 670
			goto err_mod;
		}
#endif
671
		err = -ENOENT;
L
Linus Torvalds 已提交
672 673 674 675 676
		goto err_out;
	}

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

683 684 685 686
	if (name == NULL && tb[TCA_ACT_COOKIE]) {
		if (a->act_cookie) {
			kfree(a->act_cookie->data);
			kfree(a->act_cookie);
687
		}
688
		a->act_cookie = cookie;
689 690
	}

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

698 699 700 701 702 703 704 705 706 707 708
	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 已提交
709 710 711 712 713
	return a;

err_mod:
	module_put(a_o->owner);
err_out:
714 715 716 717
	if (cookie) {
		kfree(cookie->data);
		kfree(cookie);
	}
718
	return ERR_PTR(err);
L
Linus Torvalds 已提交
719 720
}

721 722 723 724 725 726 727 728 729 730 731
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--;
}

732 733 734
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 已提交
735
{
E
Eric Dumazet 已提交
736
	struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
737
	struct tc_action *act;
738
	int err;
L
Linus Torvalds 已提交
739 740
	int i;

741
	err = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL, NULL);
742
	if (err < 0)
743
		return err;
L
Linus Torvalds 已提交
744

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

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

err:
764 765
	tcf_action_destroy(actions, bind);
	return err;
L
Linus Torvalds 已提交
766 767
}

768
int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *p,
L
Linus Torvalds 已提交
769 770 771 772
			  int compat_mode)
{
	int err = 0;
	struct gnet_dump d;
773

774
	if (p == NULL)
L
Linus Torvalds 已提交
775 776 777
		goto errout;

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

	if (err < 0)
		goto errout;

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

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

	return 0;

errout:
	return -1;
}

812 813 814
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 已提交
815 816 817
{
	struct tcamsg *t;
	struct nlmsghdr *nlh;
818
	unsigned char *b = skb_tail_pointer(skb);
819
	struct nlattr *nest;
L
Linus Torvalds 已提交
820

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

829 830
	nest = nla_nest_start(skb, TCA_ACT_TAB);
	if (nest == NULL)
831
		goto out_nlmsg_trim;
L
Linus Torvalds 已提交
832

833
	if (tcf_action_dump(skb, actions, bind, ref) < 0)
834
		goto out_nlmsg_trim;
L
Linus Torvalds 已提交
835

836
	nla_nest_end(skb, nest);
837

838
	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
L
Linus Torvalds 已提交
839 840
	return skb->len;

841
out_nlmsg_trim:
842
	nlmsg_trim(skb, b);
L
Linus Torvalds 已提交
843 844 845 846
	return -1;
}

static int
847
tcf_get_notify(struct net *net, u32 portid, struct nlmsghdr *n,
848
	       struct list_head *actions, int event)
L
Linus Torvalds 已提交
849 850 851 852 853 854
{
	struct sk_buff *skb;

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

861
	return rtnl_unicast(skb, net, portid);
L
Linus Torvalds 已提交
862 863
}

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

873
	err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL, NULL);
874
	if (err < 0)
875
		goto err_out;
L
Linus Torvalds 已提交
876

877
	err = -EINVAL;
878 879
	if (tb[TCA_ACT_INDEX] == NULL ||
	    nla_len(tb[TCA_ACT_INDEX]) < sizeof(index))
880
		goto err_out;
881
	index = nla_get_u32(tb[TCA_ACT_INDEX]);
L
Linus Torvalds 已提交
882

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

891
	module_put(ops->owner);
L
Linus Torvalds 已提交
892
	return a;
893

L
Linus Torvalds 已提交
894
err_mod:
895
	module_put(ops->owner);
896 897
err_out:
	return ERR_PTR(err);
L
Linus Torvalds 已提交
898 899
}

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

	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
	if (!skb) {
916
		pr_debug("tca_action_flush: failed skb alloc\n");
917
		return err;
L
Linus Torvalds 已提交
918 919
	}

920
	b = skb_tail_pointer(skb);
L
Linus Torvalds 已提交
921

922
	err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL, NULL);
923
	if (err < 0)
L
Linus Torvalds 已提交
924 925
		goto err_out;

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

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

941 942
	nest = nla_nest_start(skb, TCA_ACT_TAB);
	if (nest == NULL)
943
		goto out_module_put;
L
Linus Torvalds 已提交
944

945
	err = ops->walk(net, skb, &dcb, RTM_DELACTION, ops);
946
	if (err <= 0)
947
		goto out_module_put;
L
Linus Torvalds 已提交
948

949
	nla_nest_end(skb, nest);
L
Linus Torvalds 已提交
950

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

	return err;

961
out_module_put:
962
	module_put(ops->owner);
L
Linus Torvalds 已提交
963 964 965 966 967
err_out:
	kfree_skb(skb);
	return err;
}

968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985
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 */
986 987 988 989 990
	ret = tcf_action_destroy(actions, 0);
	if (ret < 0) {
		kfree_skb(skb);
		return ret;
	}
991 992 993 994 995 996 997 998

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

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

1008
	ret = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL, NULL);
1009 1010
	if (ret < 0)
		return ret;
L
Linus Torvalds 已提交
1011

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

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

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

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

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

1054 1055 1056 1057 1058
	if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, n->nlmsg_flags,
			 RTM_NEWACTION, 0, 0) <= 0) {
		kfree_skb(skb);
		return -EINVAL;
	}
1059

1060 1061
	err = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
			     n->nlmsg_flags & NLM_F_ECHO);
L
Linus Torvalds 已提交
1062 1063 1064 1065 1066
	if (err > 0)
		err = 0;
	return err;
}

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

1073
	ret = tcf_action_init(net, NULL, nla, NULL, NULL, ovr, 0, &actions);
1074
	if (ret)
1075
		return ret;
L
Linus Torvalds 已提交
1076

1077
	return tcf_add_notify(net, n, &actions, portid);
L
Linus Torvalds 已提交
1078 1079
}

1080 1081 1082 1083
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 },
1084
	[TCA_ROOT_TIME_DELTA]      = { .type = NLA_U32 },
1085 1086
};

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

1095 1096
	if ((n->nlmsg_type != RTM_GETACTION) &&
	    !netlink_capable(skb, CAP_NET_ADMIN))
1097 1098
		return -EPERM;

1099
	ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ROOT_MAX, NULL,
1100
			  extack);
1101 1102 1103 1104
	if (ret < 0)
		return ret;

	if (tca[TCA_ACT_TAB] == NULL) {
1105
		pr_notice("tc_ctl_action: received NO action attribs\n");
L
Linus Torvalds 已提交
1106 1107 1108
		return -EINVAL;
	}

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

	return ret;
}

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

1146
	tb1 = nla[TCA_ACT_TAB];
L
Linus Torvalds 已提交
1147 1148 1149
	if (tb1 == NULL)
		return NULL;

1150
	if (nla_parse(tb, TCA_ACT_MAX_PRIO, nla_data(tb1),
1151
		      NLMSG_ALIGN(nla_len(tb1)), NULL, NULL) < 0)
L
Linus Torvalds 已提交
1152 1153
		return NULL;

1154 1155
	if (tb[1] == NULL)
		return NULL;
1156
	if (nla_parse_nested(tb2, TCA_ACT_MAX, tb[1], NULL, NULL) < 0)
L
Linus Torvalds 已提交
1157
		return NULL;
1158
	kind = tb2[TCA_ACT_KIND];
L
Linus Torvalds 已提交
1159

1160
	return kind;
L
Linus Torvalds 已提交
1161 1162
}

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

1185
	kind = find_dump_kind(tb);
L
Linus Torvalds 已提交
1186
	if (kind == NULL) {
1187
		pr_info("tc_dump_action: action bad kind\n");
L
Linus Torvalds 已提交
1188 1189 1190
		return 0;
	}

1191
	a_o = tc_lookup_action(kind);
E
Eric Dumazet 已提交
1192
	if (a_o == NULL)
L
Linus Torvalds 已提交
1193 1194
		return 0;

1195 1196 1197 1198 1199 1200
	cb->args[2] = 0;
	if (tb[TCA_ROOT_FLAGS]) {
		bf = nla_get_bitfield32(tb[TCA_ROOT_FLAGS]);
		cb->args[2] = bf.value;
	}

1201 1202 1203 1204
	if (tb[TCA_ROOT_TIME_DELTA]) {
		msecs_since = nla_get_u32(tb[TCA_ROOT_TIME_DELTA]);
	}

1205
	nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
1206 1207 1208
			cb->nlh->nlmsg_type, sizeof(*t), 0);
	if (!nlh)
		goto out_module_put;
1209

1210 1211 1212
	if (msecs_since)
		jiffy_since = jiffies - msecs_to_jiffies(msecs_since);

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

1222 1223
	nest = nla_nest_start(skb, TCA_ACT_TAB);
	if (nest == NULL)
1224
		goto out_module_put;
L
Linus Torvalds 已提交
1225

1226
	ret = a_o->walk(net, skb, cb, RTM_GETACTION, a_o);
L
Linus Torvalds 已提交
1227
	if (ret < 0)
1228
		goto out_module_put;
L
Linus Torvalds 已提交
1229 1230

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

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

1245
out_module_put:
L
Linus Torvalds 已提交
1246
	module_put(a_o->owner);
1247
	nlmsg_trim(skb, b);
L
Linus Torvalds 已提交
1248 1249 1250 1251 1252
	return skb->len;
}

static int __init tc_action_init(void)
{
1253 1254
	rtnl_register(PF_UNSPEC, RTM_NEWACTION, tc_ctl_action, NULL, 0);
	rtnl_register(PF_UNSPEC, RTM_DELACTION, tc_ctl_action, NULL, 0);
1255
	rtnl_register(PF_UNSPEC, RTM_GETACTION, tc_ctl_action, tc_dump_action,
1256
		      0);
L
Linus Torvalds 已提交
1257 1258 1259 1260 1261

	return 0;
}

subsys_initcall(tc_action_init);