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 601 602 603 604 605
	if (h == NULL)
		goto errout;

	/* compat_mode being true specifies a call that is supposed
	 * to add additional backward compatiblity statistic TLVs.
	 */
	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 621 622
	if (gnet_stats_copy_basic(&d, &h->tcf_bstats) < 0 ||
	    gnet_stats_copy_rate_est(&d, &h->tcf_rate_est) < 0 ||
	    gnet_stats_copy_queue(&d, &h->tcf_qstats) < 0)
L
Linus Torvalds 已提交
623 624 625 626 627 628 629 630 631 632 633 634 635
		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,
636
	     u16 flags, int event, int bind, int ref)
L
Linus Torvalds 已提交
637 638 639
{
	struct tcamsg *t;
	struct nlmsghdr *nlh;
640
	unsigned char *b = skb_tail_pointer(skb);
641
	struct nlattr *nest;
L
Linus Torvalds 已提交
642

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

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

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

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

657
	nla_nest_end(skb, nest);
658

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

662
nla_put_failure:
L
Linus Torvalds 已提交
663
nlmsg_failure:
664
	nlmsg_trim(skb, b);
L
Linus Torvalds 已提交
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
	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;
	}
680

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

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

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

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

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

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

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

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

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;

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

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

	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);
773
		return err;
L
Linus Torvalds 已提交
774 775
	}

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

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

782
	err = -EINVAL;
783
	kind = tb[TCA_ACT_KIND];
L
Linus Torvalds 已提交
784 785 786 787 788 789 790
	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;
791 792
	t->tca__pad1 = 0;
	t->tca__pad2 = 0;
L
Linus Torvalds 已提交
793

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

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

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

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

	return err;

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

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

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

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

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

		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,
871
				 0, 1) <= 0) {
L
Linus Torvalds 已提交
872 873 874 875 876 877 878
			kfree_skb(skb);
			ret = -EINVAL;
			goto err;
		}

		/* now do the delete */
		tcf_action_destroy(head, 0);
879
		ret = rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC,
880
				     n->nlmsg_flags&NLM_F_ECHO);
L
Linus Torvalds 已提交
881 882 883 884 885 886 887 888 889 890
		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,
891
			  u16 flags)
L
Linus Torvalds 已提交
892 893 894 895
{
	struct tcamsg *t;
	struct nlmsghdr *nlh;
	struct sk_buff *skb;
896
	struct nlattr *nest;
L
Linus Torvalds 已提交
897 898 899 900 901 902 903
	unsigned char *b;
	int err = 0;

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

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

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

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

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

919
	nla_nest_end(skb, nest);
920

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

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

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

935

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

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

	/* 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)
{
966
	struct net *net = sock_net(skb->sk);
967
	struct nlattr *tca[TCA_ACT_MAX + 1];
L
Linus Torvalds 已提交
968 969 970
	u32 pid = skb ? NETLINK_CB(skb).pid : 0;
	int ret = 0, ovr = 0;

971 972 973
	if (net != &init_net)
		return -EINVAL;

974 975 976 977 978
	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 已提交
979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995
		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:
996
		ret = tcf_action_add(tca[TCA_ACT_TAB], n, pid, ovr);
L
Linus Torvalds 已提交
997 998 999 1000
		if (ret == -EAGAIN)
			goto replay;
		break;
	case RTM_DELACTION:
1001
		ret = tca_action_gd(tca[TCA_ACT_TAB], n, pid, RTM_DELACTION);
L
Linus Torvalds 已提交
1002 1003
		break;
	case RTM_GETACTION:
1004
		ret = tca_action_gd(tca[TCA_ACT_TAB], n, pid, RTM_GETACTION);
L
Linus Torvalds 已提交
1005 1006 1007 1008 1009 1010 1011 1012
		break;
	default:
		BUG();
	}

	return ret;
}

1013
static struct nlattr *
1014
find_dump_kind(const struct nlmsghdr *n)
L
Linus Torvalds 已提交
1015
{
1016 1017 1018 1019
	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 已提交
1020

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

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

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

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

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

1054 1055 1056
	if (net != &init_net)
		return 0;

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

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

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

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

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

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

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

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

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

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

static int __init tc_action_init(void)
{
1111 1112 1113
	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 已提交
1114 1115 1116 1117 1118

	return 0;
}

subsys_initcall(tc_action_init);