act_api.c 23.8 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 27
#include <net/sch_generic.h>
#include <net/act_api.h>
28
#include <net/netlink.h>
L
Linus Torvalds 已提交
29

30 31 32 33 34 35 36 37 38 39 40 41
void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo)
{
	unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask);
	struct tcf_common **p1p;

	for (p1p = &hinfo->htab[h]; *p1p; p1p = &(*p1p)->tcfc_next) {
		if (*p1p == p) {
			write_lock_bh(hinfo->lock);
			*p1p = p->tcfc_next;
			write_unlock_bh(hinfo->lock);
			gen_kill_estimator(&p->tcfc_bstats,
					   &p->tcfc_rate_est);
42 43 44 45
			/*
			 * gen_estimator est_timer() might access p->tcfc_lock
			 * or bstats, wait a RCU grace period before freeing p
			 */
46
			kfree_rcu(p, tcfc_rcu);
47 48 49
			return;
		}
	}
50
	WARN_ON(1);
51 52 53 54 55 56 57 58 59 60 61 62 63
}
EXPORT_SYMBOL(tcf_hash_destroy);

int tcf_hash_release(struct tcf_common *p, int bind,
		     struct tcf_hashinfo *hinfo)
{
	int ret = 0;

	if (p) {
		if (bind)
			p->tcfc_bindcnt--;

		p->tcfc_refcnt--;
64
		if (p->tcfc_bindcnt <= 0 && p->tcfc_refcnt <= 0) {
65 66 67 68 69 70 71 72 73 74 75 76
			tcf_hash_destroy(p, hinfo);
			ret = 1;
		}
	}
	return ret;
}
EXPORT_SYMBOL(tcf_hash_release);

static int tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb,
			   struct tc_action *a, struct tcf_hashinfo *hinfo)
{
	struct tcf_common *p;
E
Eric Dumazet 已提交
77
	int err = 0, index = -1, i = 0, s_i = 0, n_i = 0;
78
	struct nlattr *nest;
79

80
	read_lock_bh(hinfo->lock);
81 82 83 84 85 86 87 88 89 90 91 92

	s_i = cb->args[0];

	for (i = 0; i < (hinfo->hmask + 1); i++) {
		p = hinfo->htab[tcf_hash(i, hinfo->hmask)];

		for (; p; p = p->tcfc_next) {
			index++;
			if (index < s_i)
				continue;
			a->priv = p;
			a->order = n_i;
93 94 95 96

			nest = nla_nest_start(skb, a->order);
			if (nest == NULL)
				goto nla_put_failure;
97 98 99
			err = tcf_action_dump_1(skb, a, 0, 0);
			if (err < 0) {
				index--;
100
				nlmsg_trim(skb, nest);
101 102
				goto done;
			}
103
			nla_nest_end(skb, nest);
104 105 106 107 108 109
			n_i++;
			if (n_i >= TCA_ACT_MAX_PRIO)
				goto done;
		}
	}
done:
110
	read_unlock_bh(hinfo->lock);
111 112 113 114
	if (n_i)
		cb->args[0] += n_i;
	return n_i;

115
nla_put_failure:
116
	nla_nest_cancel(skb, nest);
117 118 119 120 121 122 123
	goto done;
}

static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a,
			  struct tcf_hashinfo *hinfo)
{
	struct tcf_common *p, *s_p;
124
	struct nlattr *nest;
E
Eric Dumazet 已提交
125
	int i = 0, n_i = 0;
126

127 128 129
	nest = nla_nest_start(skb, a->order);
	if (nest == NULL)
		goto nla_put_failure;
130 131
	if (nla_put_string(skb, TCA_KIND, a->ops->kind))
		goto nla_put_failure;
132 133 134 135 136 137
	for (i = 0; i < (hinfo->hmask + 1); i++) {
		p = hinfo->htab[tcf_hash(i, hinfo->hmask)];

		while (p != NULL) {
			s_p = p->tcfc_next;
			if (ACT_P_DELETED == tcf_hash_release(p, 0, hinfo))
E
Eric Dumazet 已提交
138
				module_put(a->ops->owner);
139 140 141 142
			n_i++;
			p = s_p;
		}
	}
143 144
	if (nla_put_u32(skb, TCA_FCNT, n_i))
		goto nla_put_failure;
145
	nla_nest_end(skb, nest);
146 147

	return n_i;
148
nla_put_failure:
149
	nla_nest_cancel(skb, nest);
150 151 152 153 154 155 156 157 158 159 160 161 162
	return -EINVAL;
}

int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb,
		       int type, struct tc_action *a)
{
	struct tcf_hashinfo *hinfo = a->ops->hinfo;

	if (type == RTM_DELACTION) {
		return tcf_del_walker(skb, a, hinfo);
	} else if (type == RTM_GETACTION) {
		return tcf_dump_walker(skb, cb, a, hinfo);
	} else {
163
		WARN(1, "tcf_generic_walker: unknown action %d\n", type);
164 165 166 167 168 169 170 171 172
		return -EINVAL;
	}
}
EXPORT_SYMBOL(tcf_generic_walker);

struct tcf_common *tcf_hash_lookup(u32 index, struct tcf_hashinfo *hinfo)
{
	struct tcf_common *p;

173
	read_lock_bh(hinfo->lock);
174 175 176 177 178
	for (p = hinfo->htab[tcf_hash(index, hinfo->hmask)]; p;
	     p = p->tcfc_next) {
		if (p->tcfc_index == index)
			break;
	}
179
	read_unlock_bh(hinfo->lock);
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215

	return p;
}
EXPORT_SYMBOL(tcf_hash_lookup);

u32 tcf_hash_new_index(u32 *idx_gen, struct tcf_hashinfo *hinfo)
{
	u32 val = *idx_gen;

	do {
		if (++val == 0)
			val = 1;
	} while (tcf_hash_lookup(val, hinfo));

	return (*idx_gen = val);
}
EXPORT_SYMBOL(tcf_hash_new_index);

int tcf_hash_search(struct tc_action *a, u32 index)
{
	struct tcf_hashinfo *hinfo = a->ops->hinfo;
	struct tcf_common *p = tcf_hash_lookup(index, hinfo);

	if (p) {
		a->priv = p;
		return 1;
	}
	return 0;
}
EXPORT_SYMBOL(tcf_hash_search);

struct tcf_common *tcf_hash_check(u32 index, struct tc_action *a, int bind,
				  struct tcf_hashinfo *hinfo)
{
	struct tcf_common *p = NULL;
	if (index && (p = tcf_hash_lookup(index, hinfo)) != NULL) {
216
		if (bind)
217
			p->tcfc_bindcnt++;
218
		p->tcfc_refcnt++;
219 220 221 222 223 224
		a->priv = p;
	}
	return p;
}
EXPORT_SYMBOL(tcf_hash_check);

225 226 227
struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est,
				   struct tc_action *a, int size, int bind,
				   u32 *idx_gen, struct tcf_hashinfo *hinfo)
228 229 230 231
{
	struct tcf_common *p = kzalloc(size, GFP_KERNEL);

	if (unlikely(!p))
232
		return ERR_PTR(-ENOMEM);
233 234 235 236 237 238 239 240
	p->tcfc_refcnt = 1;
	if (bind)
		p->tcfc_bindcnt = 1;

	spin_lock_init(&p->tcfc_lock);
	p->tcfc_index = index ? index : tcf_hash_new_index(idx_gen, hinfo);
	p->tcfc_tm.install = jiffies;
	p->tcfc_tm.lastuse = jiffies;
241 242 243 244 245 246 247 248 249
	if (est) {
		int err = gen_new_estimator(&p->tcfc_bstats, &p->tcfc_rate_est,
					    &p->tcfc_lock, est);
		if (err) {
			kfree(p);
			return ERR_PTR(err);
		}
	}

250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
	a->priv = (void *) p;
	return p;
}
EXPORT_SYMBOL(tcf_hash_create);

void tcf_hash_insert(struct tcf_common *p, struct tcf_hashinfo *hinfo)
{
	unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask);

	write_lock_bh(hinfo->lock);
	p->tcfc_next = hinfo->htab[h];
	hinfo->htab[h] = p;
	write_unlock_bh(hinfo->lock);
}
EXPORT_SYMBOL(tcf_hash_insert);
L
Linus Torvalds 已提交
265 266 267 268 269 270 271 272

static struct tc_action_ops *act_base = NULL;
static DEFINE_RWLOCK(act_mod_lock);

int tcf_register_action(struct tc_action_ops *act)
{
	struct tc_action_ops *a, **ap;

273 274 275 276
	/* Must supply act, dump, cleanup and init */
	if (!act->act || !act->dump || !act->cleanup || !act->init)
		return -EINVAL;

277
	/* Supply defaults */
278 279
	if (!act->lookup)
		act->lookup = tcf_hash_search;
280 281
	if (!act->walk)
		act->walk = tcf_generic_walker;
282

L
Linus Torvalds 已提交
283 284 285 286 287 288 289 290 291 292 293 294
	write_lock(&act_mod_lock);
	for (ap = &act_base; (a = *ap) != NULL; ap = &a->next) {
		if (act->type == a->type || (strcmp(act->kind, a->kind) == 0)) {
			write_unlock(&act_mod_lock);
			return -EEXIST;
		}
	}
	act->next = NULL;
	*ap = act;
	write_unlock(&act_mod_lock);
	return 0;
}
295
EXPORT_SYMBOL(tcf_register_action);
L
Linus Torvalds 已提交
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313

int tcf_unregister_action(struct tc_action_ops *act)
{
	struct tc_action_ops *a, **ap;
	int err = -ENOENT;

	write_lock(&act_mod_lock);
	for (ap = &act_base; (a = *ap) != NULL; ap = &a->next)
		if (a == act)
			break;
	if (a) {
		*ap = a->next;
		a->next = NULL;
		err = 0;
	}
	write_unlock(&act_mod_lock);
	return err;
}
314
EXPORT_SYMBOL(tcf_unregister_action);
L
Linus Torvalds 已提交
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336

/* lookup by name */
static struct tc_action_ops *tc_lookup_action_n(char *kind)
{
	struct tc_action_ops *a = NULL;

	if (kind) {
		read_lock(&act_mod_lock);
		for (a = act_base; a; a = a->next) {
			if (strcmp(kind, a->kind) == 0) {
				if (!try_module_get(a->owner)) {
					read_unlock(&act_mod_lock);
					return NULL;
				}
				break;
			}
		}
		read_unlock(&act_mod_lock);
	}
	return a;
}

337 338
/* lookup by nlattr */
static struct tc_action_ops *tc_lookup_action(struct nlattr *kind)
L
Linus Torvalds 已提交
339 340 341 342 343 344
{
	struct tc_action_ops *a = NULL;

	if (kind) {
		read_lock(&act_mod_lock);
		for (a = act_base; a; a = a->next) {
345
			if (nla_strcmp(kind, a->kind) == 0) {
L
Linus Torvalds 已提交
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
				if (!try_module_get(a->owner)) {
					read_unlock(&act_mod_lock);
					return NULL;
				}
				break;
			}
		}
		read_unlock(&act_mod_lock);
	}
	return a;
}

#if 0
/* lookup by id */
static struct tc_action_ops *tc_lookup_action_id(u32 type)
{
	struct tc_action_ops *a = NULL;

	if (type) {
		read_lock(&act_mod_lock);
		for (a = act_base; a; a = a->next) {
			if (a->type == type) {
				if (!try_module_get(a->owner)) {
					read_unlock(&act_mod_lock);
					return NULL;
				}
				break;
			}
		}
		read_unlock(&act_mod_lock);
	}
	return a;
}
#endif

381
int tcf_action_exec(struct sk_buff *skb, const struct tc_action *act,
382
		    struct tcf_result *res)
L
Linus Torvalds 已提交
383
{
384
	const struct tc_action *a;
L
Linus Torvalds 已提交
385 386 387 388 389 390 391 392 393
	int ret = -1;

	if (skb->tc_verd & TC_NCLS) {
		skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
		ret = TC_ACT_OK;
		goto exec_done;
	}
	while ((a = act) != NULL) {
repeat:
394
		if (a->ops) {
395
			ret = a->ops->act(skb, a, res);
L
Linus Torvalds 已提交
396 397 398 399 400 401 402
			if (TC_MUNGED & skb->tc_verd) {
				/* copied already, allow trampling */
				skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd);
				skb->tc_verd = CLR_TC_MUNGED(skb->tc_verd);
			}
			if (ret == TC_ACT_REPEAT)
				goto repeat;	/* we need a ttl - JHS */
J
J Hadi Salim 已提交
403 404
			if (ret != TC_ACT_PIPE)
				goto exec_done;
L
Linus Torvalds 已提交
405 406 407 408 409 410
		}
		act = a->next;
	}
exec_done:
	return ret;
}
411
EXPORT_SYMBOL(tcf_action_exec);
L
Linus Torvalds 已提交
412 413 414 415 416 417

void tcf_action_destroy(struct tc_action *act, int bind)
{
	struct tc_action *a;

	for (a = act; a; a = act) {
418
		if (a->ops) {
L
Linus Torvalds 已提交
419 420 421 422
			if (a->ops->cleanup(a, bind) == ACT_P_DELETED)
				module_put(a->ops->owner);
			act = act->next;
			kfree(a);
423 424 425
		} else {
			/*FIXME: Remove later - catch insertion bugs*/
			WARN(1, "tcf_action_destroy: BUG? destroying NULL ops\n");
L
Linus Torvalds 已提交
426 427 428 429 430 431 432 433 434 435 436
			act = act->next;
			kfree(a);
		}
	}
}

int
tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
{
	int err = -EINVAL;

437
	if (a->ops == NULL)
L
Linus Torvalds 已提交
438 439 440 441 442 443 444 445
		return err;
	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;
446
	unsigned char *b = skb_tail_pointer(skb);
447
	struct nlattr *nest;
L
Linus Torvalds 已提交
448

449
	if (a->ops == NULL)
L
Linus Torvalds 已提交
450 451
		return err;

452 453
	if (nla_put_string(skb, TCA_KIND, a->ops->kind))
		goto nla_put_failure;
L
Linus Torvalds 已提交
454
	if (tcf_action_copy_stats(skb, a, 0))
455
		goto nla_put_failure;
456 457 458
	nest = nla_nest_start(skb, TCA_OPTIONS);
	if (nest == NULL)
		goto nla_put_failure;
E
Eric Dumazet 已提交
459 460
	err = tcf_action_dump_old(skb, a, bind, ref);
	if (err > 0) {
461
		nla_nest_end(skb, nest);
L
Linus Torvalds 已提交
462 463 464
		return err;
	}

465
nla_put_failure:
466
	nlmsg_trim(skb, b);
L
Linus Torvalds 已提交
467 468
	return -1;
}
469
EXPORT_SYMBOL(tcf_action_dump_1);
L
Linus Torvalds 已提交
470 471 472 473 474 475

int
tcf_action_dump(struct sk_buff *skb, struct tc_action *act, int bind, int ref)
{
	struct tc_action *a;
	int err = -EINVAL;
476
	struct nlattr *nest;
L
Linus Torvalds 已提交
477 478 479

	while ((a = act) != NULL) {
		act = a->next;
480 481 482
		nest = nla_nest_start(skb, a->order);
		if (nest == NULL)
			goto nla_put_failure;
L
Linus Torvalds 已提交
483 484
		err = tcf_action_dump_1(skb, a, bind, ref);
		if (err < 0)
485
			goto errout;
486
		nla_nest_end(skb, nest);
L
Linus Torvalds 已提交
487 488 489 490
	}

	return 0;

491
nla_put_failure:
492 493
	err = -EINVAL;
errout:
494
	nla_nest_cancel(skb, nest);
495
	return err;
L
Linus Torvalds 已提交
496 497
}

498 499 500
struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
				    struct nlattr *est, char *name, int ovr,
				    int bind)
L
Linus Torvalds 已提交
501 502 503 504
{
	struct tc_action *a;
	struct tc_action_ops *a_o;
	char act_name[IFNAMSIZ];
E
Eric Dumazet 已提交
505
	struct nlattr *tb[TCA_ACT_MAX + 1];
506
	struct nlattr *kind;
507
	int err;
L
Linus Torvalds 已提交
508 509

	if (name == NULL) {
510 511
		err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL);
		if (err < 0)
L
Linus Torvalds 已提交
512
			goto err_out;
513
		err = -EINVAL;
514
		kind = tb[TCA_ACT_KIND];
L
Linus Torvalds 已提交
515 516
		if (kind == NULL)
			goto err_out;
517
		if (nla_strlcpy(act_name, kind, IFNAMSIZ) >= IFNAMSIZ)
L
Linus Torvalds 已提交
518 519
			goto err_out;
	} else {
520
		err = -EINVAL;
L
Linus Torvalds 已提交
521 522 523 524 525 526
		if (strlcpy(act_name, name, IFNAMSIZ) >= IFNAMSIZ)
			goto err_out;
	}

	a_o = tc_lookup_action_n(act_name);
	if (a_o == NULL) {
527
#ifdef CONFIG_MODULES
L
Linus Torvalds 已提交
528
		rtnl_unlock();
529
		request_module("act_%s", act_name);
L
Linus Torvalds 已提交
530 531 532 533 534 535 536 537 538 539 540
		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) {
541
			err = -EAGAIN;
L
Linus Torvalds 已提交
542 543 544
			goto err_mod;
		}
#endif
545
		err = -ENOENT;
L
Linus Torvalds 已提交
546 547 548
		goto err_out;
	}

549
	err = -ENOMEM;
550
	a = kzalloc(sizeof(*a), GFP_KERNEL);
L
Linus Torvalds 已提交
551 552 553 554 555
	if (a == NULL)
		goto err_mod;

	/* backward compatibility for policer */
	if (name == NULL)
556
		err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, a, ovr, bind);
L
Linus Torvalds 已提交
557
	else
558
		err = a_o->init(net, nla, est, a, ovr, bind);
559
	if (err < 0)
L
Linus Torvalds 已提交
560 561 562
		goto err_free;

	/* module count goes up only when brand new policy is created
E
Eric Dumazet 已提交
563 564 565
	 * if it exists and is only bound to in a_o->init() then
	 * ACT_P_CREATED is not returned (a zero is).
	 */
566
	if (err != ACT_P_CREATED)
L
Linus Torvalds 已提交
567 568 569 570 571 572 573 574 575 576
		module_put(a_o->owner);
	a->ops = a_o;

	return a;

err_free:
	kfree(a);
err_mod:
	module_put(a_o->owner);
err_out:
577
	return ERR_PTR(err);
L
Linus Torvalds 已提交
578 579
}

580 581 582
struct tc_action *tcf_action_init(struct net *net, struct nlattr *nla,
				  struct nlattr *est, char *name, int ovr,
				  int bind)
L
Linus Torvalds 已提交
583
{
E
Eric Dumazet 已提交
584
	struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
L
Linus Torvalds 已提交
585
	struct tc_action *head = NULL, *act, *act_prev = NULL;
586
	int err;
L
Linus Torvalds 已提交
587 588
	int i;

589 590 591
	err = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL);
	if (err < 0)
		return ERR_PTR(err);
L
Linus Torvalds 已提交
592

593
	for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
594
		act = tcf_action_init_1(net, tb[i], est, name, ovr, bind);
595
		if (IS_ERR(act))
L
Linus Torvalds 已提交
596
			goto err;
597
		act->order = i;
L
Linus Torvalds 已提交
598 599 600 601 602 603 604 605 606 607 608 609

		if (head == NULL)
			head = act;
		else
			act_prev->next = act;
		act_prev = act;
	}
	return head;

err:
	if (head != NULL)
		tcf_action_destroy(head, bind);
610
	return act;
L
Linus Torvalds 已提交
611 612 613 614 615 616 617 618
}

int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,
			  int compat_mode)
{
	int err = 0;
	struct gnet_dump d;
	struct tcf_act_hdr *h = a->priv;
619

L
Linus Torvalds 已提交
620 621 622 623
	if (h == NULL)
		goto errout;

	/* compat_mode being true specifies a call that is supposed
624
	 * to add additional backward compatibility statistic TLVs.
L
Linus Torvalds 已提交
625 626 627 628
	 */
	if (compat_mode) {
		if (a->type == TCA_OLD_COMPAT)
			err = gnet_stats_start_copy_compat(skb, 0,
629
				TCA_STATS, TCA_XSTATS, &h->tcf_lock, &d);
L
Linus Torvalds 已提交
630 631 632 633
		else
			return 0;
	} else
		err = gnet_stats_start_copy(skb, TCA_ACT_STATS,
634
					    &h->tcf_lock, &d);
L
Linus Torvalds 已提交
635 636 637 638 639 640 641 642

	if (err < 0)
		goto errout;

	if (a->ops != NULL && a->ops->get_stats != NULL)
		if (a->ops->get_stats(skb, a) < 0)
			goto errout;

643
	if (gnet_stats_copy_basic(&d, &h->tcf_bstats) < 0 ||
644 645
	    gnet_stats_copy_rate_est(&d, &h->tcf_bstats,
				     &h->tcf_rate_est) < 0 ||
646
	    gnet_stats_copy_queue(&d, &h->tcf_qstats) < 0)
L
Linus Torvalds 已提交
647 648 649 650 651 652 653 654 655 656 657 658
		goto errout;

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

	return 0;

errout:
	return -1;
}

static int
659
tca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 portid, u32 seq,
660
	     u16 flags, int event, int bind, int ref)
L
Linus Torvalds 已提交
661 662 663
{
	struct tcamsg *t;
	struct nlmsghdr *nlh;
664
	unsigned char *b = skb_tail_pointer(skb);
665
	struct nlattr *nest;
L
Linus Torvalds 已提交
666

667
	nlh = nlmsg_put(skb, portid, seq, event, sizeof(*t), flags);
668 669 670
	if (!nlh)
		goto out_nlmsg_trim;
	t = nlmsg_data(nlh);
L
Linus Torvalds 已提交
671
	t->tca_family = AF_UNSPEC;
672 673
	t->tca__pad1 = 0;
	t->tca__pad2 = 0;
674

675 676
	nest = nla_nest_start(skb, TCA_ACT_TAB);
	if (nest == NULL)
677
		goto out_nlmsg_trim;
L
Linus Torvalds 已提交
678 679

	if (tcf_action_dump(skb, a, bind, ref) < 0)
680
		goto out_nlmsg_trim;
L
Linus Torvalds 已提交
681

682
	nla_nest_end(skb, nest);
683

684
	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
L
Linus Torvalds 已提交
685 686
	return skb->len;

687
out_nlmsg_trim:
688
	nlmsg_trim(skb, b);
L
Linus Torvalds 已提交
689 690 691 692
	return -1;
}

static int
693
act_get_notify(struct net *net, u32 portid, struct nlmsghdr *n,
694
	       struct tc_action *a, int event)
L
Linus Torvalds 已提交
695 696 697 698 699 700
{
	struct sk_buff *skb;

	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
	if (!skb)
		return -ENOBUFS;
701
	if (tca_get_fill(skb, a, portid, n->nlmsg_seq, 0, event, 0, 0) <= 0) {
L
Linus Torvalds 已提交
702 703 704
		kfree_skb(skb);
		return -EINVAL;
	}
705

706
	return rtnl_unicast(skb, net, portid);
L
Linus Torvalds 已提交
707 708 709
}

static struct tc_action *
710
tcf_action_get_1(struct nlattr *nla, struct nlmsghdr *n, u32 portid)
L
Linus Torvalds 已提交
711
{
E
Eric Dumazet 已提交
712
	struct nlattr *tb[TCA_ACT_MAX + 1];
L
Linus Torvalds 已提交
713 714
	struct tc_action *a;
	int index;
715
	int err;
L
Linus Torvalds 已提交
716

717 718
	err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL);
	if (err < 0)
719
		goto err_out;
L
Linus Torvalds 已提交
720

721
	err = -EINVAL;
722 723
	if (tb[TCA_ACT_INDEX] == NULL ||
	    nla_len(tb[TCA_ACT_INDEX]) < sizeof(index))
724
		goto err_out;
725
	index = nla_get_u32(tb[TCA_ACT_INDEX]);
L
Linus Torvalds 已提交
726

727
	err = -ENOMEM;
728
	a = kzalloc(sizeof(struct tc_action), GFP_KERNEL);
L
Linus Torvalds 已提交
729
	if (a == NULL)
730
		goto err_out;
L
Linus Torvalds 已提交
731

732
	err = -EINVAL;
733
	a->ops = tc_lookup_action(tb[TCA_ACT_KIND]);
L
Linus Torvalds 已提交
734 735
	if (a->ops == NULL)
		goto err_free;
736
	err = -ENOENT;
L
Linus Torvalds 已提交
737 738 739 740 741
	if (a->ops->lookup(a, index) == 0)
		goto err_mod;

	module_put(a->ops->owner);
	return a;
742

L
Linus Torvalds 已提交
743 744 745 746
err_mod:
	module_put(a->ops->owner);
err_free:
	kfree(a);
747 748
err_out:
	return ERR_PTR(err);
L
Linus Torvalds 已提交
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764
}

static void cleanup_a(struct tc_action *act)
{
	struct tc_action *a;

	for (a = act; a; a = act) {
		act = a->next;
		kfree(a);
	}
}

static struct tc_action *create_a(int i)
{
	struct tc_action *act;

765
	act = kzalloc(sizeof(*act), GFP_KERNEL);
L
Linus Torvalds 已提交
766
	if (act == NULL) {
767
		pr_debug("create_a: failed to alloc!\n");
L
Linus Torvalds 已提交
768 769 770 771 772 773
		return NULL;
	}
	act->order = i;
	return act;
}

774
static int tca_action_flush(struct net *net, struct nlattr *nla,
775
			    struct nlmsghdr *n, u32 portid)
L
Linus Torvalds 已提交
776 777 778 779 780 781
{
	struct sk_buff *skb;
	unsigned char *b;
	struct nlmsghdr *nlh;
	struct tcamsg *t;
	struct netlink_callback dcb;
782
	struct nlattr *nest;
E
Eric Dumazet 已提交
783
	struct nlattr *tb[TCA_ACT_MAX + 1];
784
	struct nlattr *kind;
L
Linus Torvalds 已提交
785
	struct tc_action *a = create_a(0);
786
	int err = -ENOMEM;
L
Linus Torvalds 已提交
787 788

	if (a == NULL) {
789
		pr_debug("tca_action_flush: couldnt create tc_action\n");
L
Linus Torvalds 已提交
790 791 792 793 794
		return err;
	}

	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
	if (!skb) {
795
		pr_debug("tca_action_flush: failed skb alloc\n");
L
Linus Torvalds 已提交
796
		kfree(a);
797
		return err;
L
Linus Torvalds 已提交
798 799
	}

800
	b = skb_tail_pointer(skb);
L
Linus Torvalds 已提交
801

802 803
	err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL);
	if (err < 0)
L
Linus Torvalds 已提交
804 805
		goto err_out;

806
	err = -EINVAL;
807
	kind = tb[TCA_ACT_KIND];
L
Linus Torvalds 已提交
808 809 810 811
	a->ops = tc_lookup_action(kind);
	if (a->ops == NULL)
		goto err_out;

812
	nlh = nlmsg_put(skb, portid, n->nlmsg_seq, RTM_DELACTION, sizeof(*t), 0);
813 814 815
	if (!nlh)
		goto out_module_put;
	t = nlmsg_data(nlh);
L
Linus Torvalds 已提交
816
	t->tca_family = AF_UNSPEC;
817 818
	t->tca__pad1 = 0;
	t->tca__pad2 = 0;
L
Linus Torvalds 已提交
819

820 821
	nest = nla_nest_start(skb, TCA_ACT_TAB);
	if (nest == NULL)
822
		goto out_module_put;
L
Linus Torvalds 已提交
823 824 825

	err = a->ops->walk(skb, &dcb, RTM_DELACTION, a);
	if (err < 0)
826
		goto out_module_put;
827 828
	if (err == 0)
		goto noflush_out;
L
Linus Torvalds 已提交
829

830
	nla_nest_end(skb, nest);
L
Linus Torvalds 已提交
831

832
	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
L
Linus Torvalds 已提交
833 834 835
	nlh->nlmsg_flags |= NLM_F_ROOT;
	module_put(a->ops->owner);
	kfree(a);
836
	err = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
E
Eric Dumazet 已提交
837
			     n->nlmsg_flags & NLM_F_ECHO);
L
Linus Torvalds 已提交
838 839 840 841 842
	if (err > 0)
		return 0;

	return err;

843
out_module_put:
844
	module_put(a->ops->owner);
L
Linus Torvalds 已提交
845
err_out:
846
noflush_out:
L
Linus Torvalds 已提交
847 848 849 850 851 852
	kfree_skb(skb);
	kfree(a);
	return err;
}

static int
853
tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
854
	      u32 portid, int event)
L
Linus Torvalds 已提交
855
{
856
	int i, ret;
E
Eric Dumazet 已提交
857
	struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
L
Linus Torvalds 已提交
858 859
	struct tc_action *head = NULL, *act, *act_prev = NULL;

860 861 862
	ret = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL);
	if (ret < 0)
		return ret;
L
Linus Torvalds 已提交
863

E
Eric Dumazet 已提交
864
	if (event == RTM_DELACTION && n->nlmsg_flags & NLM_F_ROOT) {
865
		if (tb[1] != NULL)
866
			return tca_action_flush(net, tb[1], n, portid);
867 868
		else
			return -EINVAL;
L
Linus Torvalds 已提交
869 870
	}

871
	for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
872
		act = tcf_action_get_1(tb[i], n, portid);
873 874
		if (IS_ERR(act)) {
			ret = PTR_ERR(act);
L
Linus Torvalds 已提交
875
			goto err;
876
		}
877
		act->order = i;
L
Linus Torvalds 已提交
878 879 880 881 882 883 884 885 886

		if (head == NULL)
			head = act;
		else
			act_prev->next = act;
		act_prev = act;
	}

	if (event == RTM_GETACTION)
887
		ret = act_get_notify(net, portid, n, head, event);
L
Linus Torvalds 已提交
888 889 890 891 892 893 894 895 896
	else { /* delete */
		struct sk_buff *skb;

		skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
		if (!skb) {
			ret = -ENOBUFS;
			goto err;
		}

897
		if (tca_get_fill(skb, head, portid, n->nlmsg_seq, 0, event,
898
				 0, 1) <= 0) {
L
Linus Torvalds 已提交
899 900 901 902 903 904 905
			kfree_skb(skb);
			ret = -EINVAL;
			goto err;
		}

		/* now do the delete */
		tcf_action_destroy(head, 0);
906
		ret = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
E
Eric Dumazet 已提交
907
				     n->nlmsg_flags & NLM_F_ECHO);
L
Linus Torvalds 已提交
908 909 910 911 912 913 914 915 916
		if (ret > 0)
			return 0;
		return ret;
	}
err:
	cleanup_a(head);
	return ret;
}

917
static int tcf_add_notify(struct net *net, struct tc_action *a,
918
			  u32 portid, u32 seq, int event, u16 flags)
L
Linus Torvalds 已提交
919 920 921 922
{
	struct tcamsg *t;
	struct nlmsghdr *nlh;
	struct sk_buff *skb;
923
	struct nlattr *nest;
L
Linus Torvalds 已提交
924 925 926 927 928 929 930
	unsigned char *b;
	int err = 0;

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

931
	b = skb_tail_pointer(skb);
L
Linus Torvalds 已提交
932

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

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

	if (tcf_action_dump(skb, a, 0, 0) < 0)
946
		goto out_kfree_skb;
L
Linus Torvalds 已提交
947

948
	nla_nest_end(skb, nest);
949

950
	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
951
	NETLINK_CB(skb).dst_group = RTNLGRP_TC;
952

953
	err = rtnetlink_send(skb, net, portid, RTNLGRP_TC, flags & NLM_F_ECHO);
L
Linus Torvalds 已提交
954 955 956 957
	if (err > 0)
		err = 0;
	return err;

958
out_kfree_skb:
959
	kfree_skb(skb);
L
Linus Torvalds 已提交
960 961 962
	return -1;
}

963

L
Linus Torvalds 已提交
964
static int
965
tcf_action_add(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
966
	       u32 portid, int ovr)
L
Linus Torvalds 已提交
967 968 969 970 971 972
{
	int ret = 0;
	struct tc_action *act;
	struct tc_action *a;
	u32 seq = n->nlmsg_seq;

973
	act = tcf_action_init(net, nla, NULL, NULL, ovr, 0);
L
Linus Torvalds 已提交
974 975
	if (act == NULL)
		goto done;
976 977 978 979
	if (IS_ERR(act)) {
		ret = PTR_ERR(act);
		goto done;
	}
L
Linus Torvalds 已提交
980 981 982

	/* dump then free all the actions after update; inserted policy
	 * stays intact
E
Eric Dumazet 已提交
983
	 */
984
	ret = tcf_add_notify(net, act, portid, seq, RTM_NEWACTION, n->nlmsg_flags);
L
Linus Torvalds 已提交
985 986 987 988 989 990 991 992
	for (a = act; a; a = act) {
		act = a->next;
		kfree(a);
	}
done:
	return ret;
}

993
static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n)
L
Linus Torvalds 已提交
994
{
995
	struct net *net = sock_net(skb->sk);
996
	struct nlattr *tca[TCA_ACT_MAX + 1];
997
	u32 portid = skb ? NETLINK_CB(skb).portid : 0;
L
Linus Torvalds 已提交
998 999
	int ret = 0, ovr = 0;

1000 1001 1002
	if ((n->nlmsg_type != RTM_GETACTION) && !capable(CAP_NET_ADMIN))
		return -EPERM;

1003 1004 1005 1006 1007
	ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ACT_MAX, NULL);
	if (ret < 0)
		return ret;

	if (tca[TCA_ACT_TAB] == NULL) {
1008
		pr_notice("tc_ctl_action: received NO action attribs\n");
L
Linus Torvalds 已提交
1009 1010 1011
		return -EINVAL;
	}

E
Eric Dumazet 已提交
1012
	/* n->nlmsg_flags & NLM_F_CREATE */
L
Linus Torvalds 已提交
1013 1014 1015
	switch (n->nlmsg_type) {
	case RTM_NEWACTION:
		/* we are going to assume all other flags
L
Lucas De Marchi 已提交
1016
		 * imply create only if it doesn't exist
L
Linus Torvalds 已提交
1017 1018 1019 1020
		 * Note that CREATE | EXCL implies that
		 * but since we want avoid ambiguity (eg when flags
		 * is zero) then just set this
		 */
E
Eric Dumazet 已提交
1021
		if (n->nlmsg_flags & NLM_F_REPLACE)
L
Linus Torvalds 已提交
1022 1023
			ovr = 1;
replay:
1024
		ret = tcf_action_add(net, tca[TCA_ACT_TAB], n, portid, ovr);
L
Linus Torvalds 已提交
1025 1026 1027 1028
		if (ret == -EAGAIN)
			goto replay;
		break;
	case RTM_DELACTION:
1029
		ret = tca_action_gd(net, tca[TCA_ACT_TAB], n,
1030
				    portid, RTM_DELACTION);
L
Linus Torvalds 已提交
1031 1032
		break;
	case RTM_GETACTION:
1033
		ret = tca_action_gd(net, tca[TCA_ACT_TAB], n,
1034
				    portid, RTM_GETACTION);
L
Linus Torvalds 已提交
1035 1036 1037 1038 1039 1040 1041 1042
		break;
	default:
		BUG();
	}

	return ret;
}

1043
static struct nlattr *
1044
find_dump_kind(const struct nlmsghdr *n)
L
Linus Torvalds 已提交
1045
{
E
Eric Dumazet 已提交
1046
	struct nlattr *tb1, *tb2[TCA_ACT_MAX + 1];
1047 1048 1049
	struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
	struct nlattr *nla[TCAA_MAX + 1];
	struct nlattr *kind;
L
Linus Torvalds 已提交
1050

1051
	if (nlmsg_parse(n, sizeof(struct tcamsg), nla, TCAA_MAX, NULL) < 0)
L
Linus Torvalds 已提交
1052
		return NULL;
1053
	tb1 = nla[TCA_ACT_TAB];
L
Linus Torvalds 已提交
1054 1055 1056
	if (tb1 == NULL)
		return NULL;

1057 1058
	if (nla_parse(tb, TCA_ACT_MAX_PRIO, nla_data(tb1),
		      NLMSG_ALIGN(nla_len(tb1)), NULL) < 0)
L
Linus Torvalds 已提交
1059 1060
		return NULL;

1061 1062 1063 1064
	if (tb[1] == NULL)
		return NULL;
	if (nla_parse(tb2, TCA_ACT_MAX, nla_data(tb[1]),
		      nla_len(tb[1]), NULL) < 0)
L
Linus Torvalds 已提交
1065
		return NULL;
1066
	kind = tb2[TCA_ACT_KIND];
L
Linus Torvalds 已提交
1067

1068
	return kind;
L
Linus Torvalds 已提交
1069 1070 1071 1072 1073 1074
}

static int
tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
{
	struct nlmsghdr *nlh;
1075
	unsigned char *b = skb_tail_pointer(skb);
1076
	struct nlattr *nest;
L
Linus Torvalds 已提交
1077 1078 1079
	struct tc_action_ops *a_o;
	struct tc_action a;
	int ret = 0;
1080
	struct tcamsg *t = (struct tcamsg *) nlmsg_data(cb->nlh);
1081
	struct nlattr *kind = find_dump_kind(cb->nlh);
L
Linus Torvalds 已提交
1082 1083

	if (kind == NULL) {
1084
		pr_info("tc_dump_action: action bad kind\n");
L
Linus Torvalds 已提交
1085 1086 1087
		return 0;
	}

1088
	a_o = tc_lookup_action(kind);
E
Eric Dumazet 已提交
1089
	if (a_o == NULL)
L
Linus Torvalds 已提交
1090 1091 1092 1093 1094
		return 0;

	memset(&a, 0, sizeof(struct tc_action));
	a.ops = a_o;

1095
	nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
1096 1097 1098 1099
			cb->nlh->nlmsg_type, sizeof(*t), 0);
	if (!nlh)
		goto out_module_put;
	t = nlmsg_data(nlh);
L
Linus Torvalds 已提交
1100
	t->tca_family = AF_UNSPEC;
1101 1102
	t->tca__pad1 = 0;
	t->tca__pad2 = 0;
L
Linus Torvalds 已提交
1103

1104 1105
	nest = nla_nest_start(skb, TCA_ACT_TAB);
	if (nest == NULL)
1106
		goto out_module_put;
L
Linus Torvalds 已提交
1107 1108 1109

	ret = a_o->walk(skb, cb, RTM_GETACTION, &a);
	if (ret < 0)
1110
		goto out_module_put;
L
Linus Torvalds 已提交
1111 1112

	if (ret > 0) {
1113
		nla_nest_end(skb, nest);
L
Linus Torvalds 已提交
1114 1115
		ret = skb->len;
	} else
1116
		nla_nest_cancel(skb, nest);
L
Linus Torvalds 已提交
1117

1118
	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
1119
	if (NETLINK_CB(cb->skb).portid && ret)
L
Linus Torvalds 已提交
1120 1121 1122 1123
		nlh->nlmsg_flags |= NLM_F_MULTI;
	module_put(a_o->owner);
	return skb->len;

1124
out_module_put:
L
Linus Torvalds 已提交
1125
	module_put(a_o->owner);
1126
	nlmsg_trim(skb, b);
L
Linus Torvalds 已提交
1127 1128 1129 1130 1131
	return skb->len;
}

static int __init tc_action_init(void)
{
1132 1133 1134 1135
	rtnl_register(PF_UNSPEC, RTM_NEWACTION, tc_ctl_action, NULL, NULL);
	rtnl_register(PF_UNSPEC, RTM_DELACTION, tc_ctl_action, NULL, NULL);
	rtnl_register(PF_UNSPEC, RTM_GETACTION, tc_ctl_action, tc_dump_action,
		      NULL);
L
Linus Torvalds 已提交
1136 1137 1138 1139 1140

	return 0;
}

subsys_initcall(tc_action_init);