act_api.c 23.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * 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>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/kmod.h>
21
#include <linux/err.h>
22 23
#include <net/net_namespace.h>
#include <net/sock.h>
L
Linus Torvalds 已提交
24 25
#include <net/sch_generic.h>
#include <net/act_api.h>
26
#include <net/netlink.h>
L
Linus Torvalds 已提交
27

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
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);
			kfree(p);
			return;
		}
	}
44
	WARN_ON(1);
45 46 47 48 49 50 51 52 53 54 55 56 57
}
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--;
58
		if (p->tcfc_bindcnt <= 0 && p->tcfc_refcnt <= 0) {
59 60 61 62 63 64 65 66 67 68 69 70 71
			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;
	int err = 0, index = -1,i = 0, s_i = 0, n_i = 0;
72
	struct nlattr *nest;
73

74
	read_lock_bh(hinfo->lock);
75 76 77 78 79 80 81 82 83 84 85 86

	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;
87 88 89 90

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

109
nla_put_failure:
110
	nla_nest_cancel(skb, nest);
111 112 113 114 115 116 117
	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;
118
	struct nlattr *nest;
119 120
	int i= 0, n_i = 0;

121 122 123
	nest = nla_nest_start(skb, a->order);
	if (nest == NULL)
		goto nla_put_failure;
124
	NLA_PUT_STRING(skb, TCA_KIND, a->ops->kind);
125 126 127 128 129 130 131 132 133 134 135
	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))
				 module_put(a->ops->owner);
			n_i++;
			p = s_p;
		}
	}
136
	NLA_PUT_U32(skb, TCA_FCNT, n_i);
137
	nla_nest_end(skb, nest);
138 139

	return n_i;
140
nla_put_failure:
141
	nla_nest_cancel(skb, nest);
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
	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 {
		printk("tcf_generic_walker: unknown action %d\n", type);
		return -EINVAL;
	}
}
EXPORT_SYMBOL(tcf_generic_walker);

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

165
	read_lock_bh(hinfo->lock);
166 167 168 169 170
	for (p = hinfo->htab[tcf_hash(index, hinfo->hmask)]; p;
	     p = p->tcfc_next) {
		if (p->tcfc_index == index)
			break;
	}
171
	read_unlock_bh(hinfo->lock);
172 173 174 175 176 177 178 179 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

	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) {
208
		if (bind)
209
			p->tcfc_bindcnt++;
210
		p->tcfc_refcnt++;
211 212 213 214 215 216
		a->priv = p;
	}
	return p;
}
EXPORT_SYMBOL(tcf_hash_check);

217 218 219
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)
220 221 222 223
{
	struct tcf_common *p = kzalloc(size, GFP_KERNEL);

	if (unlikely(!p))
224
		return ERR_PTR(-ENOMEM);
225 226 227 228 229 230 231 232
	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;
233 234 235 236 237 238 239 240 241
	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);
		}
	}

242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
	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 已提交
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276

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;

	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;
}
277
EXPORT_SYMBOL(tcf_register_action);
L
Linus Torvalds 已提交
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295

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;
}
296
EXPORT_SYMBOL(tcf_unregister_action);
L
Linus Torvalds 已提交
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318

/* 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;
}

319 320
/* lookup by nlattr */
static struct tc_action_ops *tc_lookup_action(struct nlattr *kind)
L
Linus Torvalds 已提交
321 322 323 324 325 326
{
	struct tc_action_ops *a = NULL;

	if (kind) {
		read_lock(&act_mod_lock);
		for (a = act_base; a; a = a->next) {
327
			if (nla_strcmp(kind, a->kind) == 0) {
L
Linus Torvalds 已提交
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
				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

int tcf_action_exec(struct sk_buff *skb, struct tc_action *act,
364
		    struct tcf_result *res)
L
Linus Torvalds 已提交
365 366 367 368 369 370 371 372 373 374 375 376
{
	struct tc_action *a;
	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:
		if (a->ops && a->ops->act) {
377
			ret = a->ops->act(skb, a, res);
L
Linus Torvalds 已提交
378 379 380 381 382 383 384
			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 已提交
385 386
			if (ret != TC_ACT_PIPE)
				goto exec_done;
L
Linus Torvalds 已提交
387 388 389 390 391 392
		}
		act = a->next;
	}
exec_done:
	return ret;
}
393
EXPORT_SYMBOL(tcf_action_exec);
L
Linus Torvalds 已提交
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426

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

	for (a = act; a; a = act) {
		if (a->ops && a->ops->cleanup) {
			if (a->ops->cleanup(a, bind) == ACT_P_DELETED)
				module_put(a->ops->owner);
			act = act->next;
			kfree(a);
		} else { /*FIXME: Remove later - catch insertion bugs*/
			printk("tcf_action_destroy: BUG? destroying NULL ops\n");
			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;

	if (a->ops == NULL || a->ops->dump == NULL)
		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;
427
	unsigned char *b = skb_tail_pointer(skb);
428
	struct nlattr *nest;
L
Linus Torvalds 已提交
429 430 431 432

	if (a->ops == NULL || a->ops->dump == NULL)
		return err;

433
	NLA_PUT_STRING(skb, TCA_KIND, a->ops->kind);
L
Linus Torvalds 已提交
434
	if (tcf_action_copy_stats(skb, a, 0))
435
		goto nla_put_failure;
436 437 438
	nest = nla_nest_start(skb, TCA_OPTIONS);
	if (nest == NULL)
		goto nla_put_failure;
L
Linus Torvalds 已提交
439
	if ((err = tcf_action_dump_old(skb, a, bind, ref)) > 0) {
440
		nla_nest_end(skb, nest);
L
Linus Torvalds 已提交
441 442 443
		return err;
	}

444
nla_put_failure:
445
	nlmsg_trim(skb, b);
L
Linus Torvalds 已提交
446 447
	return -1;
}
448
EXPORT_SYMBOL(tcf_action_dump_1);
L
Linus Torvalds 已提交
449 450 451 452 453 454

int
tcf_action_dump(struct sk_buff *skb, struct tc_action *act, int bind, int ref)
{
	struct tc_action *a;
	int err = -EINVAL;
455
	struct nlattr *nest;
L
Linus Torvalds 已提交
456 457 458

	while ((a = act) != NULL) {
		act = a->next;
459 460 461
		nest = nla_nest_start(skb, a->order);
		if (nest == NULL)
			goto nla_put_failure;
L
Linus Torvalds 已提交
462 463
		err = tcf_action_dump_1(skb, a, bind, ref);
		if (err < 0)
464
			goto errout;
465
		nla_nest_end(skb, nest);
L
Linus Torvalds 已提交
466 467 468 469
	}

	return 0;

470
nla_put_failure:
471 472
	err = -EINVAL;
errout:
473
	nla_nest_cancel(skb, nest);
474
	return err;
L
Linus Torvalds 已提交
475 476
}

477
struct tc_action *tcf_action_init_1(struct nlattr *nla, struct nlattr *est,
478
				    char *name, int ovr, int bind)
L
Linus Torvalds 已提交
479 480 481 482
{
	struct tc_action *a;
	struct tc_action_ops *a_o;
	char act_name[IFNAMSIZ];
483 484
	struct nlattr *tb[TCA_ACT_MAX+1];
	struct nlattr *kind;
485
	int err;
L
Linus Torvalds 已提交
486 487

	if (name == NULL) {
488 489
		err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL);
		if (err < 0)
L
Linus Torvalds 已提交
490
			goto err_out;
491
		err = -EINVAL;
492
		kind = tb[TCA_ACT_KIND];
L
Linus Torvalds 已提交
493 494
		if (kind == NULL)
			goto err_out;
495
		if (nla_strlcpy(act_name, kind, IFNAMSIZ) >= IFNAMSIZ)
L
Linus Torvalds 已提交
496 497
			goto err_out;
	} else {
498
		err = -EINVAL;
L
Linus Torvalds 已提交
499 500 501 502 503 504
		if (strlcpy(act_name, name, IFNAMSIZ) >= IFNAMSIZ)
			goto err_out;
	}

	a_o = tc_lookup_action_n(act_name);
	if (a_o == NULL) {
505
#ifdef CONFIG_MODULES
L
Linus Torvalds 已提交
506
		rtnl_unlock();
507
		request_module("act_%s", act_name);
L
Linus Torvalds 已提交
508 509 510 511 512 513 514 515 516 517 518
		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) {
519
			err = -EAGAIN;
L
Linus Torvalds 已提交
520 521 522
			goto err_mod;
		}
#endif
523
		err = -ENOENT;
L
Linus Torvalds 已提交
524 525 526
		goto err_out;
	}

527
	err = -ENOMEM;
528
	a = kzalloc(sizeof(*a), GFP_KERNEL);
L
Linus Torvalds 已提交
529 530 531 532 533
	if (a == NULL)
		goto err_mod;

	/* backward compatibility for policer */
	if (name == NULL)
534
		err = a_o->init(tb[TCA_ACT_OPTIONS], est, a, ovr, bind);
L
Linus Torvalds 已提交
535
	else
536 537
		err = a_o->init(nla, est, a, ovr, bind);
	if (err < 0)
L
Linus Torvalds 已提交
538 539 540 541 542 543
		goto err_free;

	/* module count goes up only when brand new policy is created
	   if it exists and is only bound to in a_o->init() then
	   ACT_P_CREATED is not returned (a zero is).
	*/
544
	if (err != ACT_P_CREATED)
L
Linus Torvalds 已提交
545 546 547 548 549 550 551 552 553 554
		module_put(a_o->owner);
	a->ops = a_o;

	return a;

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

558
struct tc_action *tcf_action_init(struct nlattr *nla, struct nlattr *est,
559
				  char *name, int ovr, int bind)
L
Linus Torvalds 已提交
560
{
561
	struct nlattr *tb[TCA_ACT_MAX_PRIO+1];
L
Linus Torvalds 已提交
562
	struct tc_action *head = NULL, *act, *act_prev = NULL;
563
	int err;
L
Linus Torvalds 已提交
564 565
	int i;

566 567 568
	err = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL);
	if (err < 0)
		return ERR_PTR(err);
L
Linus Torvalds 已提交
569

570
	for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
571 572
		act = tcf_action_init_1(tb[i], est, name, ovr, bind);
		if (IS_ERR(act))
L
Linus Torvalds 已提交
573
			goto err;
574
		act->order = i;
L
Linus Torvalds 已提交
575 576 577 578 579 580 581 582 583 584 585 586

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

err:
	if (head != NULL)
		tcf_action_destroy(head, bind);
587
	return act;
L
Linus Torvalds 已提交
588 589 590 591 592 593 594 595
}

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;
596

L
Linus Torvalds 已提交
597 598 599 600
	if (h == NULL)
		goto errout;

	/* compat_mode being true specifies a call that is supposed
601
	 * to add additional backward compatibility statistic TLVs.
L
Linus Torvalds 已提交
602 603 604 605
	 */
	if (compat_mode) {
		if (a->type == TCA_OLD_COMPAT)
			err = gnet_stats_start_copy_compat(skb, 0,
606
				TCA_STATS, TCA_XSTATS, &h->tcf_lock, &d);
L
Linus Torvalds 已提交
607 608 609 610
		else
			return 0;
	} else
		err = gnet_stats_start_copy(skb, TCA_ACT_STATS,
611
					    &h->tcf_lock, &d);
L
Linus Torvalds 已提交
612 613 614 615 616 617 618 619

	if (err < 0)
		goto errout;

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

620
	if (gnet_stats_copy_basic(&d, &h->tcf_bstats) < 0 ||
621 622
	    gnet_stats_copy_rate_est(&d, &h->tcf_bstats,
				     &h->tcf_rate_est) < 0 ||
623
	    gnet_stats_copy_queue(&d, &h->tcf_qstats) < 0)
L
Linus Torvalds 已提交
624 625 626 627 628 629 630 631 632 633 634 635 636
		goto errout;

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

	return 0;

errout:
	return -1;
}

static int
tca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 pid, u32 seq,
637
	     u16 flags, int event, int bind, int ref)
L
Linus Torvalds 已提交
638 639 640
{
	struct tcamsg *t;
	struct nlmsghdr *nlh;
641
	unsigned char *b = skb_tail_pointer(skb);
642
	struct nlattr *nest;
L
Linus Torvalds 已提交
643

J
Jamal Hadi Salim 已提交
644 645
	nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*t), flags);

L
Linus Torvalds 已提交
646 647
	t = NLMSG_DATA(nlh);
	t->tca_family = AF_UNSPEC;
648 649
	t->tca__pad1 = 0;
	t->tca__pad2 = 0;
650

651 652 653
	nest = nla_nest_start(skb, TCA_ACT_TAB);
	if (nest == NULL)
		goto nla_put_failure;
L
Linus Torvalds 已提交
654 655

	if (tcf_action_dump(skb, a, bind, ref) < 0)
656
		goto nla_put_failure;
L
Linus Torvalds 已提交
657

658
	nla_nest_end(skb, nest);
659

660
	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
L
Linus Torvalds 已提交
661 662
	return skb->len;

663
nla_put_failure:
L
Linus Torvalds 已提交
664
nlmsg_failure:
665
	nlmsg_trim(skb, b);
L
Linus Torvalds 已提交
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
	return -1;
}

static int
act_get_notify(u32 pid, struct nlmsghdr *n, struct tc_action *a, int event)
{
	struct sk_buff *skb;

	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
	if (!skb)
		return -ENOBUFS;
	if (tca_get_fill(skb, a, pid, n->nlmsg_seq, 0, event, 0, 0) <= 0) {
		kfree_skb(skb);
		return -EINVAL;
	}
681

682
	return rtnl_unicast(skb, &init_net, pid);
L
Linus Torvalds 已提交
683 684 685
}

static struct tc_action *
686
tcf_action_get_1(struct nlattr *nla, struct nlmsghdr *n, u32 pid)
L
Linus Torvalds 已提交
687
{
688
	struct nlattr *tb[TCA_ACT_MAX+1];
L
Linus Torvalds 已提交
689 690
	struct tc_action *a;
	int index;
691
	int err;
L
Linus Torvalds 已提交
692

693 694
	err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL);
	if (err < 0)
695
		goto err_out;
L
Linus Torvalds 已提交
696

697
	err = -EINVAL;
698 699
	if (tb[TCA_ACT_INDEX] == NULL ||
	    nla_len(tb[TCA_ACT_INDEX]) < sizeof(index))
700
		goto err_out;
701
	index = nla_get_u32(tb[TCA_ACT_INDEX]);
L
Linus Torvalds 已提交
702

703
	err = -ENOMEM;
704
	a = kzalloc(sizeof(struct tc_action), GFP_KERNEL);
L
Linus Torvalds 已提交
705
	if (a == NULL)
706
		goto err_out;
L
Linus Torvalds 已提交
707

708
	err = -EINVAL;
709
	a->ops = tc_lookup_action(tb[TCA_ACT_KIND]);
L
Linus Torvalds 已提交
710 711 712 713
	if (a->ops == NULL)
		goto err_free;
	if (a->ops->lookup == NULL)
		goto err_mod;
714
	err = -ENOENT;
L
Linus Torvalds 已提交
715 716 717 718 719
	if (a->ops->lookup(a, index) == 0)
		goto err_mod;

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

L
Linus Torvalds 已提交
721 722 723 724
err_mod:
	module_put(a->ops->owner);
err_free:
	kfree(a);
725 726
err_out:
	return ERR_PTR(err);
L
Linus Torvalds 已提交
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
}

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;

743
	act = kzalloc(sizeof(*act), GFP_KERNEL);
L
Linus Torvalds 已提交
744 745 746 747 748 749 750 751
	if (act == NULL) {
		printk("create_a: failed to alloc!\n");
		return NULL;
	}
	act->order = i;
	return act;
}

752
static int tca_action_flush(struct nlattr *nla, struct nlmsghdr *n, u32 pid)
L
Linus Torvalds 已提交
753 754 755 756 757 758
{
	struct sk_buff *skb;
	unsigned char *b;
	struct nlmsghdr *nlh;
	struct tcamsg *t;
	struct netlink_callback dcb;
759
	struct nlattr *nest;
760 761
	struct nlattr *tb[TCA_ACT_MAX+1];
	struct nlattr *kind;
L
Linus Torvalds 已提交
762
	struct tc_action *a = create_a(0);
763
	int err = -ENOMEM;
L
Linus Torvalds 已提交
764 765 766 767 768 769 770 771 772 773

	if (a == NULL) {
		printk("tca_action_flush: couldnt create tc_action\n");
		return err;
	}

	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
	if (!skb) {
		printk("tca_action_flush: failed skb alloc\n");
		kfree(a);
774
		return err;
L
Linus Torvalds 已提交
775 776
	}

777
	b = skb_tail_pointer(skb);
L
Linus Torvalds 已提交
778

779 780
	err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL);
	if (err < 0)
L
Linus Torvalds 已提交
781 782
		goto err_out;

783
	err = -EINVAL;
784
	kind = tb[TCA_ACT_KIND];
L
Linus Torvalds 已提交
785 786 787 788 789 790 791
	a->ops = tc_lookup_action(kind);
	if (a->ops == NULL)
		goto err_out;

	nlh = NLMSG_PUT(skb, pid, n->nlmsg_seq, RTM_DELACTION, sizeof(*t));
	t = NLMSG_DATA(nlh);
	t->tca_family = AF_UNSPEC;
792 793
	t->tca__pad1 = 0;
	t->tca__pad2 = 0;
L
Linus Torvalds 已提交
794

795 796 797
	nest = nla_nest_start(skb, TCA_ACT_TAB);
	if (nest == NULL)
		goto nla_put_failure;
L
Linus Torvalds 已提交
798 799 800

	err = a->ops->walk(skb, &dcb, RTM_DELACTION, a);
	if (err < 0)
801
		goto nla_put_failure;
802 803
	if (err == 0)
		goto noflush_out;
L
Linus Torvalds 已提交
804

805
	nla_nest_end(skb, nest);
L
Linus Torvalds 已提交
806

807
	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
L
Linus Torvalds 已提交
808 809 810
	nlh->nlmsg_flags |= NLM_F_ROOT;
	module_put(a->ops->owner);
	kfree(a);
811
	err = rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
L
Linus Torvalds 已提交
812 813 814 815 816
	if (err > 0)
		return 0;

	return err;

817
nla_put_failure:
L
Linus Torvalds 已提交
818
nlmsg_failure:
819
	module_put(a->ops->owner);
L
Linus Torvalds 已提交
820
err_out:
821
noflush_out:
L
Linus Torvalds 已提交
822 823 824 825 826 827
	kfree_skb(skb);
	kfree(a);
	return err;
}

static int
828
tca_action_gd(struct nlattr *nla, struct nlmsghdr *n, u32 pid, int event)
L
Linus Torvalds 已提交
829
{
830
	int i, ret;
831
	struct nlattr *tb[TCA_ACT_MAX_PRIO+1];
L
Linus Torvalds 已提交
832 833
	struct tc_action *head = NULL, *act, *act_prev = NULL;

834 835 836
	ret = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL);
	if (ret < 0)
		return ret;
L
Linus Torvalds 已提交
837 838

	if (event == RTM_DELACTION && n->nlmsg_flags&NLM_F_ROOT) {
839 840 841 842
		if (tb[1] != NULL)
			return tca_action_flush(tb[1], n, pid);
		else
			return -EINVAL;
L
Linus Torvalds 已提交
843 844
	}

845
	for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
846 847 848
		act = tcf_action_get_1(tb[i], n, pid);
		if (IS_ERR(act)) {
			ret = PTR_ERR(act);
L
Linus Torvalds 已提交
849
			goto err;
850
		}
851
		act->order = i;
L
Linus Torvalds 已提交
852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871

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

	if (event == RTM_GETACTION)
		ret = act_get_notify(pid, n, head, event);
	else { /* delete */
		struct sk_buff *skb;

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

		if (tca_get_fill(skb, head, pid, n->nlmsg_seq, 0, event,
872
				 0, 1) <= 0) {
L
Linus Torvalds 已提交
873 874 875 876 877 878 879
			kfree_skb(skb);
			ret = -EINVAL;
			goto err;
		}

		/* now do the delete */
		tcf_action_destroy(head, 0);
880
		ret = rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC,
881
				     n->nlmsg_flags&NLM_F_ECHO);
L
Linus Torvalds 已提交
882 883 884 885 886 887 888 889 890 891
		if (ret > 0)
			return 0;
		return ret;
	}
err:
	cleanup_a(head);
	return ret;
}

static int tcf_add_notify(struct tc_action *a, u32 pid, u32 seq, int event,
892
			  u16 flags)
L
Linus Torvalds 已提交
893 894 895 896
{
	struct tcamsg *t;
	struct nlmsghdr *nlh;
	struct sk_buff *skb;
897
	struct nlattr *nest;
L
Linus Torvalds 已提交
898 899 900 901 902 903 904
	unsigned char *b;
	int err = 0;

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

905
	b = skb_tail_pointer(skb);
L
Linus Torvalds 已提交
906

J
Jamal Hadi Salim 已提交
907
	nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*t), flags);
L
Linus Torvalds 已提交
908 909
	t = NLMSG_DATA(nlh);
	t->tca_family = AF_UNSPEC;
910 911 912
	t->tca__pad1 = 0;
	t->tca__pad2 = 0;

913 914 915
	nest = nla_nest_start(skb, TCA_ACT_TAB);
	if (nest == NULL)
		goto nla_put_failure;
L
Linus Torvalds 已提交
916 917

	if (tcf_action_dump(skb, a, 0, 0) < 0)
918
		goto nla_put_failure;
L
Linus Torvalds 已提交
919

920
	nla_nest_end(skb, nest);
921

922
	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
923
	NETLINK_CB(skb).dst_group = RTNLGRP_TC;
924

925
	err = rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, flags&NLM_F_ECHO);
L
Linus Torvalds 已提交
926 927 928 929
	if (err > 0)
		err = 0;
	return err;

930
nla_put_failure:
L
Linus Torvalds 已提交
931
nlmsg_failure:
932
	kfree_skb(skb);
L
Linus Torvalds 已提交
933 934 935
	return -1;
}

936

L
Linus Torvalds 已提交
937
static int
938
tcf_action_add(struct nlattr *nla, struct nlmsghdr *n, u32 pid, int ovr)
L
Linus Torvalds 已提交
939 940 941 942 943 944
{
	int ret = 0;
	struct tc_action *act;
	struct tc_action *a;
	u32 seq = n->nlmsg_seq;

945
	act = tcf_action_init(nla, NULL, NULL, ovr, 0);
L
Linus Torvalds 已提交
946 947
	if (act == NULL)
		goto done;
948 949 950 951
	if (IS_ERR(act)) {
		ret = PTR_ERR(act);
		goto done;
	}
L
Linus Torvalds 已提交
952 953 954 955 956 957 958 959 960 961 962 963 964 965 966

	/* dump then free all the actions after update; inserted policy
	 * stays intact
	 * */
	ret = tcf_add_notify(act, pid, seq, RTM_NEWACTION, n->nlmsg_flags);
	for (a = act; a; a = act) {
		act = a->next;
		kfree(a);
	}
done:
	return ret;
}

static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
{
967
	struct net *net = sock_net(skb->sk);
968
	struct nlattr *tca[TCA_ACT_MAX + 1];
L
Linus Torvalds 已提交
969 970 971
	u32 pid = skb ? NETLINK_CB(skb).pid : 0;
	int ret = 0, ovr = 0;

O
Octavian Purdila 已提交
972
	if (!net_eq(net, &init_net))
973 974
		return -EINVAL;

975 976 977 978 979
	ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ACT_MAX, NULL);
	if (ret < 0)
		return ret;

	if (tca[TCA_ACT_TAB] == NULL) {
L
Linus Torvalds 已提交
980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996
		printk("tc_ctl_action: received NO action attribs\n");
		return -EINVAL;
	}

	/* n->nlmsg_flags&NLM_F_CREATE
	 * */
	switch (n->nlmsg_type) {
	case RTM_NEWACTION:
		/* we are going to assume all other flags
		 * imply create only if it doesnt exist
		 * Note that CREATE | EXCL implies that
		 * but since we want avoid ambiguity (eg when flags
		 * is zero) then just set this
		 */
		if (n->nlmsg_flags&NLM_F_REPLACE)
			ovr = 1;
replay:
997
		ret = tcf_action_add(tca[TCA_ACT_TAB], n, pid, ovr);
L
Linus Torvalds 已提交
998 999 1000 1001
		if (ret == -EAGAIN)
			goto replay;
		break;
	case RTM_DELACTION:
1002
		ret = tca_action_gd(tca[TCA_ACT_TAB], n, pid, RTM_DELACTION);
L
Linus Torvalds 已提交
1003 1004
		break;
	case RTM_GETACTION:
1005
		ret = tca_action_gd(tca[TCA_ACT_TAB], n, pid, RTM_GETACTION);
L
Linus Torvalds 已提交
1006 1007 1008 1009 1010 1011 1012 1013
		break;
	default:
		BUG();
	}

	return ret;
}

1014
static struct nlattr *
1015
find_dump_kind(const struct nlmsghdr *n)
L
Linus Torvalds 已提交
1016
{
1017 1018 1019 1020
	struct nlattr *tb1, *tb2[TCA_ACT_MAX+1];
	struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
	struct nlattr *nla[TCAA_MAX + 1];
	struct nlattr *kind;
L
Linus Torvalds 已提交
1021

1022
	if (nlmsg_parse(n, sizeof(struct tcamsg), nla, TCAA_MAX, NULL) < 0)
L
Linus Torvalds 已提交
1023
		return NULL;
1024
	tb1 = nla[TCA_ACT_TAB];
L
Linus Torvalds 已提交
1025 1026 1027
	if (tb1 == NULL)
		return NULL;

1028 1029
	if (nla_parse(tb, TCA_ACT_MAX_PRIO, nla_data(tb1),
		      NLMSG_ALIGN(nla_len(tb1)), NULL) < 0)
L
Linus Torvalds 已提交
1030 1031
		return NULL;

1032 1033 1034 1035
	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 已提交
1036
		return NULL;
1037
	kind = tb2[TCA_ACT_KIND];
L
Linus Torvalds 已提交
1038

1039
	return kind;
L
Linus Torvalds 已提交
1040 1041 1042 1043 1044
}

static int
tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
{
1045
	struct net *net = sock_net(skb->sk);
L
Linus Torvalds 已提交
1046
	struct nlmsghdr *nlh;
1047
	unsigned char *b = skb_tail_pointer(skb);
1048
	struct nlattr *nest;
L
Linus Torvalds 已提交
1049 1050 1051 1052
	struct tc_action_ops *a_o;
	struct tc_action a;
	int ret = 0;
	struct tcamsg *t = (struct tcamsg *) NLMSG_DATA(cb->nlh);
1053
	struct nlattr *kind = find_dump_kind(cb->nlh);
L
Linus Torvalds 已提交
1054

O
Octavian Purdila 已提交
1055
	if (!net_eq(net, &init_net))
1056 1057
		return 0;

L
Linus Torvalds 已提交
1058 1059 1060 1061 1062
	if (kind == NULL) {
		printk("tc_dump_action: action bad kind\n");
		return 0;
	}

1063
	a_o = tc_lookup_action(kind);
L
Linus Torvalds 已提交
1064 1065 1066 1067 1068 1069 1070 1071
	if (a_o == NULL) {
		return 0;
	}

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

	if (a_o->walk == NULL) {
1072
		printk("tc_dump_action: %s !capable of dumping table\n", a_o->kind);
1073
		goto nla_put_failure;
L
Linus Torvalds 已提交
1074 1075 1076
	}

	nlh = NLMSG_PUT(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
1077
			cb->nlh->nlmsg_type, sizeof(*t));
L
Linus Torvalds 已提交
1078 1079
	t = NLMSG_DATA(nlh);
	t->tca_family = AF_UNSPEC;
1080 1081
	t->tca__pad1 = 0;
	t->tca__pad2 = 0;
L
Linus Torvalds 已提交
1082

1083 1084 1085
	nest = nla_nest_start(skb, TCA_ACT_TAB);
	if (nest == NULL)
		goto nla_put_failure;
L
Linus Torvalds 已提交
1086 1087 1088

	ret = a_o->walk(skb, cb, RTM_GETACTION, &a);
	if (ret < 0)
1089
		goto nla_put_failure;
L
Linus Torvalds 已提交
1090 1091

	if (ret > 0) {
1092
		nla_nest_end(skb, nest);
L
Linus Torvalds 已提交
1093 1094
		ret = skb->len;
	} else
1095
		nla_nest_cancel(skb, nest);
L
Linus Torvalds 已提交
1096

1097
	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
L
Linus Torvalds 已提交
1098 1099 1100 1101 1102
	if (NETLINK_CB(cb->skb).pid && ret)
		nlh->nlmsg_flags |= NLM_F_MULTI;
	module_put(a_o->owner);
	return skb->len;

1103
nla_put_failure:
L
Linus Torvalds 已提交
1104 1105
nlmsg_failure:
	module_put(a_o->owner);
1106
	nlmsg_trim(skb, b);
L
Linus Torvalds 已提交
1107 1108 1109 1110 1111
	return skb->len;
}

static int __init tc_action_init(void)
{
1112 1113 1114
	rtnl_register(PF_UNSPEC, RTM_NEWACTION, tc_ctl_action, NULL);
	rtnl_register(PF_UNSPEC, RTM_DELACTION, tc_ctl_action, NULL);
	rtnl_register(PF_UNSPEC, RTM_GETACTION, tc_ctl_action, tc_dump_action);
L
Linus Torvalds 已提交
1115 1116 1117 1118 1119

	return 0;
}

subsys_initcall(tc_action_init);