act_api.c 23.6 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
void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo)
{
32 33 34 35 36 37 38 39 40 41
	spin_lock_bh(&hinfo->lock);
	hlist_del(&p->tcfc_head);
	spin_unlock_bh(&hinfo->lock);
	gen_kill_estimator(&p->tcfc_bstats,
			   &p->tcfc_rate_est);
	/*
	 * gen_estimator est_timer() might access p->tcfc_lock
	 * or bstats, wait a RCU grace period before freeing p
	 */
	kfree_rcu(p, tcfc_rcu);
42 43 44 45 46 47 48 49 50 51 52 53 54
}
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--;
55
		if (p->tcfc_bindcnt <= 0 && p->tcfc_refcnt <= 0) {
56 57 58 59 60 61 62 63 64 65 66
			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)
{
67
	struct hlist_head *head;
68
	struct tcf_common *p;
E
Eric Dumazet 已提交
69
	int err = 0, index = -1, i = 0, s_i = 0, n_i = 0;
70
	struct nlattr *nest;
71

72
	spin_lock_bh(&hinfo->lock);
73 74 75 76

	s_i = cb->args[0];

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

79
		hlist_for_each_entry_rcu(p, head, tcfc_head) {
80 81 82 83 84
			index++;
			if (index < s_i)
				continue;
			a->priv = p;
			a->order = n_i;
85 86 87 88

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

107
nla_put_failure:
108
	nla_nest_cancel(skb, nest);
109 110 111 112 113 114
	goto done;
}

static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a,
			  struct tcf_hashinfo *hinfo)
{
115 116 117
	struct hlist_head *head;
	struct hlist_node *n;
	struct tcf_common *p;
118
	struct nlattr *nest;
E
Eric Dumazet 已提交
119
	int i = 0, n_i = 0;
120

121 122 123
	nest = nla_nest_start(skb, a->order);
	if (nest == NULL)
		goto nla_put_failure;
124 125
	if (nla_put_string(skb, TCA_KIND, a->ops->kind))
		goto nla_put_failure;
126
	for (i = 0; i < (hinfo->hmask + 1); i++) {
127 128
		head = &hinfo->htab[tcf_hash(i, hinfo->hmask)];
		hlist_for_each_entry_safe(p, n, head, tcfc_head) {
129
			if (ACT_P_DELETED == tcf_hash_release(p, 0, hinfo))
E
Eric Dumazet 已提交
130
				module_put(a->ops->owner);
131 132 133
			n_i++;
		}
	}
134 135
	if (nla_put_u32(skb, TCA_FCNT, n_i))
		goto nla_put_failure;
136
	nla_nest_end(skb, nest);
137 138

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

struct tcf_common *tcf_hash_lookup(u32 index, struct tcf_hashinfo *hinfo)
{
162 163
	struct tcf_common *p = NULL;
	struct hlist_head *head;
164

165 166 167
	spin_lock_bh(&hinfo->lock);
	head = &hinfo->htab[tcf_hash(index, hinfo->hmask)];
	hlist_for_each_entry_rcu(p, head, tcfc_head)
168 169
		if (p->tcfc_index == index)
			break;
170
	spin_unlock_bh(&hinfo->lock);
171 172 173 174 175 176 177 178 179 180 181 182 183 184

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

185 186
	*idx_gen = val;
	return val;
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
}
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
	p->tcfc_refcnt = 1;
	if (bind)
		p->tcfc_bindcnt = 1;

	spin_lock_init(&p->tcfc_lock);
230
	INIT_HLIST_NODE(&p->tcfc_head);
231 232 233
	p->tcfc_index = index ? index : tcf_hash_new_index(idx_gen, hinfo);
	p->tcfc_tm.install = jiffies;
	p->tcfc_tm.lastuse = jiffies;
234 235 236 237 238 239 240 241 242
	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);
		}
	}

243 244 245 246 247 248 249 250 251
	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);

252 253 254
	spin_lock_bh(&hinfo->lock);
	hlist_add_head(&p->tcfc_head, &hinfo->htab[h]);
	spin_unlock_bh(&hinfo->lock);
255 256
}
EXPORT_SYMBOL(tcf_hash_insert);
L
Linus Torvalds 已提交
257

258
static LIST_HEAD(act_base);
L
Linus Torvalds 已提交
259 260 261 262
static DEFINE_RWLOCK(act_mod_lock);

int tcf_register_action(struct tc_action_ops *act)
{
263
	struct tc_action_ops *a;
L
Linus Torvalds 已提交
264

265 266 267 268
	/* Must supply act, dump, cleanup and init */
	if (!act->act || !act->dump || !act->cleanup || !act->init)
		return -EINVAL;

269
	/* Supply defaults */
270 271
	if (!act->lookup)
		act->lookup = tcf_hash_search;
272 273
	if (!act->walk)
		act->walk = tcf_generic_walker;
274

L
Linus Torvalds 已提交
275
	write_lock(&act_mod_lock);
276
	list_for_each_entry(a, &act_base, head) {
L
Linus Torvalds 已提交
277 278 279 280 281
		if (act->type == a->type || (strcmp(act->kind, a->kind) == 0)) {
			write_unlock(&act_mod_lock);
			return -EEXIST;
		}
	}
282
	list_add_tail(&act->head, &act_base);
L
Linus Torvalds 已提交
283 284 285
	write_unlock(&act_mod_lock);
	return 0;
}
286
EXPORT_SYMBOL(tcf_register_action);
L
Linus Torvalds 已提交
287 288 289

int tcf_unregister_action(struct tc_action_ops *act)
{
290
	struct tc_action_ops *a;
L
Linus Torvalds 已提交
291 292 293
	int err = -ENOENT;

	write_lock(&act_mod_lock);
294
	list_for_each_entry(a, &act_base, head)
L
Linus Torvalds 已提交
295 296 297
		if (a == act)
			break;
	if (a) {
298
		list_del(&act->head);
L
Linus Torvalds 已提交
299 300 301 302 303
		err = 0;
	}
	write_unlock(&act_mod_lock);
	return err;
}
304
EXPORT_SYMBOL(tcf_unregister_action);
L
Linus Torvalds 已提交
305 306 307 308 309 310 311 312

/* 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);
313
		list_for_each_entry(a, &act_base, head) {
L
Linus Torvalds 已提交
314 315 316 317 318 319 320 321 322 323 324 325 326
			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;
}

327 328
/* lookup by nlattr */
static struct tc_action_ops *tc_lookup_action(struct nlattr *kind)
L
Linus Torvalds 已提交
329 330 331 332 333
{
	struct tc_action_ops *a = NULL;

	if (kind) {
		read_lock(&act_mod_lock);
334
		list_for_each_entry(a, &act_base, head) {
335
			if (nla_strcmp(kind, a->kind) == 0) {
L
Linus Torvalds 已提交
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 364 365 366 367 368 369 370
				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

371
int tcf_action_exec(struct sk_buff *skb, const struct list_head *actions,
372
		    struct tcf_result *res)
L
Linus Torvalds 已提交
373
{
374
	const struct tc_action *a;
L
Linus Torvalds 已提交
375 376 377 378 379 380 381
	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;
	}
382
	list_for_each_entry(a, actions, list) {
L
Linus Torvalds 已提交
383
repeat:
384
		if (a->ops) {
385
			ret = a->ops->act(skb, a, res);
L
Linus Torvalds 已提交
386 387 388 389 390 391 392
			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 已提交
393 394
			if (ret != TC_ACT_PIPE)
				goto exec_done;
L
Linus Torvalds 已提交
395 396 397 398 399
		}
	}
exec_done:
	return ret;
}
400
EXPORT_SYMBOL(tcf_action_exec);
L
Linus Torvalds 已提交
401

402
void tcf_action_destroy(struct list_head *actions, int bind)
L
Linus Torvalds 已提交
403
{
404
	struct tc_action *a, *tmp;
L
Linus Torvalds 已提交
405

406
	list_for_each_entry_safe(a, tmp, actions, list) {
407
		if (a->ops) {
L
Linus Torvalds 已提交
408 409
			if (a->ops->cleanup(a, bind) == ACT_P_DELETED)
				module_put(a->ops->owner);
410
			list_del(&a->list);
L
Linus Torvalds 已提交
411
			kfree(a);
412 413 414
		} else {
			/*FIXME: Remove later - catch insertion bugs*/
			WARN(1, "tcf_action_destroy: BUG? destroying NULL ops\n");
415
			list_del(&a->list);
L
Linus Torvalds 已提交
416 417 418 419 420 421 422 423 424 425
			kfree(a);
		}
	}
}

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

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

438
	if (a->ops == NULL)
L
Linus Torvalds 已提交
439 440
		return err;

441 442
	if (nla_put_string(skb, TCA_KIND, a->ops->kind))
		goto nla_put_failure;
L
Linus Torvalds 已提交
443
	if (tcf_action_copy_stats(skb, a, 0))
444
		goto nla_put_failure;
445 446 447
	nest = nla_nest_start(skb, TCA_OPTIONS);
	if (nest == NULL)
		goto nla_put_failure;
E
Eric Dumazet 已提交
448 449
	err = tcf_action_dump_old(skb, a, bind, ref);
	if (err > 0) {
450
		nla_nest_end(skb, nest);
L
Linus Torvalds 已提交
451 452 453
		return err;
	}

454
nla_put_failure:
455
	nlmsg_trim(skb, b);
L
Linus Torvalds 已提交
456 457
	return -1;
}
458
EXPORT_SYMBOL(tcf_action_dump_1);
L
Linus Torvalds 已提交
459 460

int
461
tcf_action_dump(struct sk_buff *skb, struct list_head *actions, int bind, int ref)
L
Linus Torvalds 已提交
462 463 464
{
	struct tc_action *a;
	int err = -EINVAL;
465
	struct nlattr *nest;
L
Linus Torvalds 已提交
466

467
	list_for_each_entry(a, actions, list) {
468 469 470
		nest = nla_nest_start(skb, a->order);
		if (nest == NULL)
			goto nla_put_failure;
L
Linus Torvalds 已提交
471 472
		err = tcf_action_dump_1(skb, a, bind, ref);
		if (err < 0)
473
			goto errout;
474
		nla_nest_end(skb, nest);
L
Linus Torvalds 已提交
475 476 477 478
	}

	return 0;

479
nla_put_failure:
480 481
	err = -EINVAL;
errout:
482
	nla_nest_cancel(skb, nest);
483
	return err;
L
Linus Torvalds 已提交
484 485
}

486 487 488
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 已提交
489 490 491 492
{
	struct tc_action *a;
	struct tc_action_ops *a_o;
	char act_name[IFNAMSIZ];
E
Eric Dumazet 已提交
493
	struct nlattr *tb[TCA_ACT_MAX + 1];
494
	struct nlattr *kind;
495
	int err;
L
Linus Torvalds 已提交
496 497

	if (name == NULL) {
498 499
		err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL);
		if (err < 0)
L
Linus Torvalds 已提交
500
			goto err_out;
501
		err = -EINVAL;
502
		kind = tb[TCA_ACT_KIND];
L
Linus Torvalds 已提交
503 504
		if (kind == NULL)
			goto err_out;
505
		if (nla_strlcpy(act_name, kind, IFNAMSIZ) >= IFNAMSIZ)
L
Linus Torvalds 已提交
506 507
			goto err_out;
	} else {
508
		err = -EINVAL;
L
Linus Torvalds 已提交
509 510 511 512 513 514
		if (strlcpy(act_name, name, IFNAMSIZ) >= IFNAMSIZ)
			goto err_out;
	}

	a_o = tc_lookup_action_n(act_name);
	if (a_o == NULL) {
515
#ifdef CONFIG_MODULES
L
Linus Torvalds 已提交
516
		rtnl_unlock();
517
		request_module("act_%s", act_name);
L
Linus Torvalds 已提交
518 519 520 521 522 523 524 525 526 527 528
		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) {
529
			err = -EAGAIN;
L
Linus Torvalds 已提交
530 531 532
			goto err_mod;
		}
#endif
533
		err = -ENOENT;
L
Linus Torvalds 已提交
534 535 536
		goto err_out;
	}

537
	err = -ENOMEM;
538
	a = kzalloc(sizeof(*a), GFP_KERNEL);
L
Linus Torvalds 已提交
539 540 541
	if (a == NULL)
		goto err_mod;

542
	INIT_LIST_HEAD(&a->list);
L
Linus Torvalds 已提交
543 544
	/* backward compatibility for policer */
	if (name == NULL)
545
		err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, a, ovr, bind);
L
Linus Torvalds 已提交
546
	else
547
		err = a_o->init(net, nla, est, a, ovr, bind);
548
	if (err < 0)
L
Linus Torvalds 已提交
549 550 551
		goto err_free;

	/* module count goes up only when brand new policy is created
E
Eric Dumazet 已提交
552 553 554
	 * if it exists and is only bound to in a_o->init() then
	 * ACT_P_CREATED is not returned (a zero is).
	 */
555
	if (err != ACT_P_CREATED)
L
Linus Torvalds 已提交
556 557 558 559 560 561 562 563 564 565
		module_put(a_o->owner);
	a->ops = a_o;

	return a;

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

569
int tcf_action_init(struct net *net, struct nlattr *nla,
570
				  struct nlattr *est, char *name, int ovr,
571
				  int bind, struct list_head *actions)
L
Linus Torvalds 已提交
572
{
E
Eric Dumazet 已提交
573
	struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
574
	struct tc_action *act;
575
	int err;
L
Linus Torvalds 已提交
576 577
	int i;

578 579
	err = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL);
	if (err < 0)
580
		return err;
L
Linus Torvalds 已提交
581

582
	for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
583
		act = tcf_action_init_1(net, tb[i], est, name, ovr, bind);
584 585
		if (IS_ERR(act)) {
			err = PTR_ERR(act);
L
Linus Torvalds 已提交
586
			goto err;
587
		}
588
		act->order = i;
589
		list_add_tail(&act->list, actions);
L
Linus Torvalds 已提交
590
	}
591
	return 0;
L
Linus Torvalds 已提交
592 593

err:
594 595
	tcf_action_destroy(actions, bind);
	return err;
L
Linus Torvalds 已提交
596 597 598 599 600 601 602 603
}

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

L
Linus Torvalds 已提交
605 606 607 608
	if (h == NULL)
		goto errout;

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

	if (err < 0)
		goto errout;

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

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

	return 0;

errout:
	return -1;
}

static int
640
tca_get_fill(struct sk_buff *skb, struct list_head *actions, u32 portid, u32 seq,
641
	     u16 flags, int event, int bind, int ref)
L
Linus Torvalds 已提交
642 643 644
{
	struct tcamsg *t;
	struct nlmsghdr *nlh;
645
	unsigned char *b = skb_tail_pointer(skb);
646
	struct nlattr *nest;
L
Linus Torvalds 已提交
647

648
	nlh = nlmsg_put(skb, portid, seq, event, sizeof(*t), flags);
649 650 651
	if (!nlh)
		goto out_nlmsg_trim;
	t = nlmsg_data(nlh);
L
Linus Torvalds 已提交
652
	t->tca_family = AF_UNSPEC;
653 654
	t->tca__pad1 = 0;
	t->tca__pad2 = 0;
655

656 657
	nest = nla_nest_start(skb, TCA_ACT_TAB);
	if (nest == NULL)
658
		goto out_nlmsg_trim;
L
Linus Torvalds 已提交
659

660
	if (tcf_action_dump(skb, actions, bind, ref) < 0)
661
		goto out_nlmsg_trim;
L
Linus Torvalds 已提交
662

663
	nla_nest_end(skb, nest);
664

665
	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
L
Linus Torvalds 已提交
666 667
	return skb->len;

668
out_nlmsg_trim:
669
	nlmsg_trim(skb, b);
L
Linus Torvalds 已提交
670 671 672 673
	return -1;
}

static int
674
act_get_notify(struct net *net, u32 portid, struct nlmsghdr *n,
675
	       struct list_head *actions, int event)
L
Linus Torvalds 已提交
676 677 678 679 680 681
{
	struct sk_buff *skb;

	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
	if (!skb)
		return -ENOBUFS;
682
	if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, event, 0, 0) <= 0) {
L
Linus Torvalds 已提交
683 684 685
		kfree_skb(skb);
		return -EINVAL;
	}
686

687
	return rtnl_unicast(skb, net, portid);
L
Linus Torvalds 已提交
688 689 690
}

static struct tc_action *
691
tcf_action_get_1(struct nlattr *nla, struct nlmsghdr *n, u32 portid)
L
Linus Torvalds 已提交
692
{
E
Eric Dumazet 已提交
693
	struct nlattr *tb[TCA_ACT_MAX + 1];
L
Linus Torvalds 已提交
694 695
	struct tc_action *a;
	int index;
696
	int err;
L
Linus Torvalds 已提交
697

698 699
	err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL);
	if (err < 0)
700
		goto err_out;
L
Linus Torvalds 已提交
701

702
	err = -EINVAL;
703 704
	if (tb[TCA_ACT_INDEX] == NULL ||
	    nla_len(tb[TCA_ACT_INDEX]) < sizeof(index))
705
		goto err_out;
706
	index = nla_get_u32(tb[TCA_ACT_INDEX]);
L
Linus Torvalds 已提交
707

708
	err = -ENOMEM;
709
	a = kzalloc(sizeof(struct tc_action), GFP_KERNEL);
L
Linus Torvalds 已提交
710
	if (a == NULL)
711
		goto err_out;
L
Linus Torvalds 已提交
712

713
	INIT_LIST_HEAD(&a->list);
714
	err = -EINVAL;
715
	a->ops = tc_lookup_action(tb[TCA_ACT_KIND]);
L
Linus Torvalds 已提交
716 717
	if (a->ops == NULL)
		goto err_free;
718
	err = -ENOENT;
L
Linus Torvalds 已提交
719 720 721 722 723
	if (a->ops->lookup(a, index) == 0)
		goto err_mod;

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

L
Linus Torvalds 已提交
725 726 727 728
err_mod:
	module_put(a->ops->owner);
err_free:
	kfree(a);
729 730
err_out:
	return ERR_PTR(err);
L
Linus Torvalds 已提交
731 732
}

733
static void cleanup_a(struct list_head *actions)
L
Linus Torvalds 已提交
734
{
735
	struct tc_action *a, *tmp;
L
Linus Torvalds 已提交
736

737 738
	list_for_each_entry_safe(a, tmp, actions, list) {
		list_del(&a->list);
L
Linus Torvalds 已提交
739 740 741 742 743 744 745 746
		kfree(a);
	}
}

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

747
	act = kzalloc(sizeof(*act), GFP_KERNEL);
L
Linus Torvalds 已提交
748
	if (act == NULL) {
749
		pr_debug("create_a: failed to alloc!\n");
L
Linus Torvalds 已提交
750 751 752
		return NULL;
	}
	act->order = i;
753
	INIT_LIST_HEAD(&act->list);
L
Linus Torvalds 已提交
754 755 756
	return act;
}

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

	if (a == NULL) {
772
		pr_debug("tca_action_flush: couldnt create tc_action\n");
L
Linus Torvalds 已提交
773 774 775 776 777
		return err;
	}

	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
	if (!skb) {
778
		pr_debug("tca_action_flush: failed skb alloc\n");
L
Linus Torvalds 已提交
779
		kfree(a);
780
		return err;
L
Linus Torvalds 已提交
781 782
	}

783
	b = skb_tail_pointer(skb);
L
Linus Torvalds 已提交
784

785 786
	err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL);
	if (err < 0)
L
Linus Torvalds 已提交
787 788
		goto err_out;

789
	err = -EINVAL;
790
	kind = tb[TCA_ACT_KIND];
L
Linus Torvalds 已提交
791 792 793 794
	a->ops = tc_lookup_action(kind);
	if (a->ops == NULL)
		goto err_out;

795
	nlh = nlmsg_put(skb, portid, n->nlmsg_seq, RTM_DELACTION, sizeof(*t), 0);
796 797 798
	if (!nlh)
		goto out_module_put;
	t = nlmsg_data(nlh);
L
Linus Torvalds 已提交
799
	t->tca_family = AF_UNSPEC;
800 801
	t->tca__pad1 = 0;
	t->tca__pad2 = 0;
L
Linus Torvalds 已提交
802

803 804
	nest = nla_nest_start(skb, TCA_ACT_TAB);
	if (nest == NULL)
805
		goto out_module_put;
L
Linus Torvalds 已提交
806 807 808

	err = a->ops->walk(skb, &dcb, RTM_DELACTION, a);
	if (err < 0)
809
		goto out_module_put;
810 811
	if (err == 0)
		goto noflush_out;
L
Linus Torvalds 已提交
812

813
	nla_nest_end(skb, nest);
L
Linus Torvalds 已提交
814

815
	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
L
Linus Torvalds 已提交
816 817 818
	nlh->nlmsg_flags |= NLM_F_ROOT;
	module_put(a->ops->owner);
	kfree(a);
819
	err = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
E
Eric Dumazet 已提交
820
			     n->nlmsg_flags & NLM_F_ECHO);
L
Linus Torvalds 已提交
821 822 823 824 825
	if (err > 0)
		return 0;

	return err;

826
out_module_put:
827
	module_put(a->ops->owner);
L
Linus Torvalds 已提交
828
err_out:
829
noflush_out:
L
Linus Torvalds 已提交
830 831 832 833 834 835
	kfree_skb(skb);
	kfree(a);
	return err;
}

static int
836
tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
837
	      u32 portid, int event)
L
Linus Torvalds 已提交
838
{
839
	int i, ret;
E
Eric Dumazet 已提交
840
	struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
841 842
	struct tc_action *act;
	LIST_HEAD(actions);
L
Linus Torvalds 已提交
843

844 845 846
	ret = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL);
	if (ret < 0)
		return ret;
L
Linus Torvalds 已提交
847

E
Eric Dumazet 已提交
848
	if (event == RTM_DELACTION && n->nlmsg_flags & NLM_F_ROOT) {
849
		if (tb[1] != NULL)
850
			return tca_action_flush(net, tb[1], n, portid);
851 852
		else
			return -EINVAL;
L
Linus Torvalds 已提交
853 854
	}

855
	for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
856
		act = tcf_action_get_1(tb[i], n, portid);
857 858
		if (IS_ERR(act)) {
			ret = PTR_ERR(act);
L
Linus Torvalds 已提交
859
			goto err;
860
		}
861
		act->order = i;
862
		list_add_tail(&act->list, &actions);
L
Linus Torvalds 已提交
863 864 865
	}

	if (event == RTM_GETACTION)
866
		ret = act_get_notify(net, portid, n, &actions, event);
L
Linus Torvalds 已提交
867 868 869 870 871 872 873 874 875
	else { /* delete */
		struct sk_buff *skb;

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

876
		if (tca_get_fill(skb, &actions, portid, n->nlmsg_seq, 0, event,
877
				 0, 1) <= 0) {
L
Linus Torvalds 已提交
878 879 880 881 882 883
			kfree_skb(skb);
			ret = -EINVAL;
			goto err;
		}

		/* now do the delete */
884
		tcf_action_destroy(&actions, 0);
885
		ret = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
E
Eric Dumazet 已提交
886
				     n->nlmsg_flags & NLM_F_ECHO);
L
Linus Torvalds 已提交
887 888 889 890 891
		if (ret > 0)
			return 0;
		return ret;
	}
err:
892
	cleanup_a(&actions);
L
Linus Torvalds 已提交
893 894 895
	return ret;
}

896
static int tcf_add_notify(struct net *net, struct list_head *actions,
897
			  u32 portid, u32 seq, int event, u16 flags)
L
Linus Torvalds 已提交
898 899 900 901
{
	struct tcamsg *t;
	struct nlmsghdr *nlh;
	struct sk_buff *skb;
902
	struct nlattr *nest;
L
Linus Torvalds 已提交
903 904 905 906 907 908 909
	unsigned char *b;
	int err = 0;

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

910
	b = skb_tail_pointer(skb);
L
Linus Torvalds 已提交
911

912
	nlh = nlmsg_put(skb, portid, seq, event, sizeof(*t), flags);
913 914 915
	if (!nlh)
		goto out_kfree_skb;
	t = nlmsg_data(nlh);
L
Linus Torvalds 已提交
916
	t->tca_family = AF_UNSPEC;
917 918 919
	t->tca__pad1 = 0;
	t->tca__pad2 = 0;

920 921
	nest = nla_nest_start(skb, TCA_ACT_TAB);
	if (nest == NULL)
922
		goto out_kfree_skb;
L
Linus Torvalds 已提交
923

924
	if (tcf_action_dump(skb, actions, 0, 0) < 0)
925
		goto out_kfree_skb;
L
Linus Torvalds 已提交
926

927
	nla_nest_end(skb, nest);
928

929
	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
930
	NETLINK_CB(skb).dst_group = RTNLGRP_TC;
931

932
	err = rtnetlink_send(skb, net, portid, RTNLGRP_TC, flags & NLM_F_ECHO);
L
Linus Torvalds 已提交
933 934 935 936
	if (err > 0)
		err = 0;
	return err;

937
out_kfree_skb:
938
	kfree_skb(skb);
L
Linus Torvalds 已提交
939 940 941
	return -1;
}

942

L
Linus Torvalds 已提交
943
static int
944
tcf_action_add(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
945
	       u32 portid, int ovr)
L
Linus Torvalds 已提交
946 947
{
	int ret = 0;
948
	LIST_HEAD(actions);
L
Linus Torvalds 已提交
949 950
	u32 seq = n->nlmsg_seq;

951 952
	ret = tcf_action_init(net, nla, NULL, NULL, ovr, 0, &actions);
	if (ret)
953
		goto done;
L
Linus Torvalds 已提交
954 955 956

	/* dump then free all the actions after update; inserted policy
	 * stays intact
E
Eric Dumazet 已提交
957
	 */
958 959
	ret = tcf_add_notify(net, &actions, portid, seq, RTM_NEWACTION, n->nlmsg_flags);
	cleanup_a(&actions);
L
Linus Torvalds 已提交
960 961 962 963
done:
	return ret;
}

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

971 972 973
	if ((n->nlmsg_type != RTM_GETACTION) && !capable(CAP_NET_ADMIN))
		return -EPERM;

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) {
979
		pr_notice("tc_ctl_action: received NO action attribs\n");
L
Linus Torvalds 已提交
980 981 982
		return -EINVAL;
	}

E
Eric Dumazet 已提交
983
	/* n->nlmsg_flags & NLM_F_CREATE */
L
Linus Torvalds 已提交
984 985 986
	switch (n->nlmsg_type) {
	case RTM_NEWACTION:
		/* we are going to assume all other flags
L
Lucas De Marchi 已提交
987
		 * imply create only if it doesn't exist
L
Linus Torvalds 已提交
988 989 990 991
		 * Note that CREATE | EXCL implies that
		 * but since we want avoid ambiguity (eg when flags
		 * is zero) then just set this
		 */
E
Eric Dumazet 已提交
992
		if (n->nlmsg_flags & NLM_F_REPLACE)
L
Linus Torvalds 已提交
993 994
			ovr = 1;
replay:
995
		ret = tcf_action_add(net, tca[TCA_ACT_TAB], n, portid, ovr);
L
Linus Torvalds 已提交
996 997 998 999
		if (ret == -EAGAIN)
			goto replay;
		break;
	case RTM_DELACTION:
1000
		ret = tca_action_gd(net, tca[TCA_ACT_TAB], n,
1001
				    portid, RTM_DELACTION);
L
Linus Torvalds 已提交
1002 1003
		break;
	case RTM_GETACTION:
1004
		ret = tca_action_gd(net, tca[TCA_ACT_TAB], n,
1005
				    portid, 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
{
E
Eric Dumazet 已提交
1017
	struct nlattr *tb1, *tb2[TCA_ACT_MAX + 1];
1018 1019 1020
	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 1045
}

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

	if (kind == NULL) {
1055
		pr_info("tc_dump_action: action bad kind\n");
L
Linus Torvalds 已提交
1056 1057 1058
		return 0;
	}

1059
	a_o = tc_lookup_action(kind);
E
Eric Dumazet 已提交
1060
	if (a_o == NULL)
L
Linus Torvalds 已提交
1061 1062 1063 1064 1065
		return 0;

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

1066
	nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
1067 1068 1069 1070
			cb->nlh->nlmsg_type, sizeof(*t), 0);
	if (!nlh)
		goto out_module_put;
	t = nlmsg_data(nlh);
L
Linus Torvalds 已提交
1071
	t->tca_family = AF_UNSPEC;
1072 1073
	t->tca__pad1 = 0;
	t->tca__pad2 = 0;
L
Linus Torvalds 已提交
1074

1075 1076
	nest = nla_nest_start(skb, TCA_ACT_TAB);
	if (nest == NULL)
1077
		goto out_module_put;
L
Linus Torvalds 已提交
1078 1079 1080

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

	if (ret > 0) {
1084
		nla_nest_end(skb, nest);
L
Linus Torvalds 已提交
1085 1086
		ret = skb->len;
	} else
1087
		nla_nest_cancel(skb, nest);
L
Linus Torvalds 已提交
1088

1089
	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
1090
	if (NETLINK_CB(cb->skb).portid && ret)
L
Linus Torvalds 已提交
1091 1092 1093 1094
		nlh->nlmsg_flags |= NLM_F_MULTI;
	module_put(a_o->owner);
	return skb->len;

1095
out_module_put:
L
Linus Torvalds 已提交
1096
	module_put(a_o->owner);
1097
	nlmsg_trim(skb, b);
L
Linus Torvalds 已提交
1098 1099 1100 1101 1102
	return skb->len;
}

static int __init tc_action_init(void)
{
1103 1104 1105 1106
	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 已提交
1107 1108 1109 1110 1111

	return 0;
}

subsys_initcall(tc_action_init);