Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.19-rc1 1097 lines 24 kB view raw
1/* 2 * net/sched/act_api.c Packet action API. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Author: Jamal Hadi Salim 10 * 11 * 12 */ 13 14#include <asm/uaccess.h> 15#include <asm/system.h> 16#include <linux/bitops.h> 17#include <linux/types.h> 18#include <linux/kernel.h> 19#include <linux/sched.h> 20#include <linux/string.h> 21#include <linux/mm.h> 22#include <linux/socket.h> 23#include <linux/sockios.h> 24#include <linux/in.h> 25#include <linux/errno.h> 26#include <linux/interrupt.h> 27#include <linux/netdevice.h> 28#include <linux/skbuff.h> 29#include <linux/rtnetlink.h> 30#include <linux/init.h> 31#include <linux/kmod.h> 32#include <net/sock.h> 33#include <net/sch_generic.h> 34#include <net/act_api.h> 35 36void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo) 37{ 38 unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask); 39 struct tcf_common **p1p; 40 41 for (p1p = &hinfo->htab[h]; *p1p; p1p = &(*p1p)->tcfc_next) { 42 if (*p1p == p) { 43 write_lock_bh(hinfo->lock); 44 *p1p = p->tcfc_next; 45 write_unlock_bh(hinfo->lock); 46#ifdef CONFIG_NET_ESTIMATOR 47 gen_kill_estimator(&p->tcfc_bstats, 48 &p->tcfc_rate_est); 49#endif 50 kfree(p); 51 return; 52 } 53 } 54 BUG_TRAP(0); 55} 56EXPORT_SYMBOL(tcf_hash_destroy); 57 58int tcf_hash_release(struct tcf_common *p, int bind, 59 struct tcf_hashinfo *hinfo) 60{ 61 int ret = 0; 62 63 if (p) { 64 if (bind) 65 p->tcfc_bindcnt--; 66 67 p->tcfc_refcnt--; 68 if (p->tcfc_bindcnt <= 0 && p->tcfc_refcnt <= 0) { 69 tcf_hash_destroy(p, hinfo); 70 ret = 1; 71 } 72 } 73 return ret; 74} 75EXPORT_SYMBOL(tcf_hash_release); 76 77static int tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb, 78 struct tc_action *a, struct tcf_hashinfo *hinfo) 79{ 80 struct tcf_common *p; 81 int err = 0, index = -1,i = 0, s_i = 0, n_i = 0; 82 struct rtattr *r ; 83 84 read_lock(hinfo->lock); 85 86 s_i = cb->args[0]; 87 88 for (i = 0; i < (hinfo->hmask + 1); i++) { 89 p = hinfo->htab[tcf_hash(i, hinfo->hmask)]; 90 91 for (; p; p = p->tcfc_next) { 92 index++; 93 if (index < s_i) 94 continue; 95 a->priv = p; 96 a->order = n_i; 97 r = (struct rtattr*) skb->tail; 98 RTA_PUT(skb, a->order, 0, NULL); 99 err = tcf_action_dump_1(skb, a, 0, 0); 100 if (err < 0) { 101 index--; 102 skb_trim(skb, (u8*)r - skb->data); 103 goto done; 104 } 105 r->rta_len = skb->tail - (u8*)r; 106 n_i++; 107 if (n_i >= TCA_ACT_MAX_PRIO) 108 goto done; 109 } 110 } 111done: 112 read_unlock(hinfo->lock); 113 if (n_i) 114 cb->args[0] += n_i; 115 return n_i; 116 117rtattr_failure: 118 skb_trim(skb, (u8*)r - skb->data); 119 goto done; 120} 121 122static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a, 123 struct tcf_hashinfo *hinfo) 124{ 125 struct tcf_common *p, *s_p; 126 struct rtattr *r ; 127 int i= 0, n_i = 0; 128 129 r = (struct rtattr*) skb->tail; 130 RTA_PUT(skb, a->order, 0, NULL); 131 RTA_PUT(skb, TCA_KIND, IFNAMSIZ, a->ops->kind); 132 for (i = 0; i < (hinfo->hmask + 1); i++) { 133 p = hinfo->htab[tcf_hash(i, hinfo->hmask)]; 134 135 while (p != NULL) { 136 s_p = p->tcfc_next; 137 if (ACT_P_DELETED == tcf_hash_release(p, 0, hinfo)) 138 module_put(a->ops->owner); 139 n_i++; 140 p = s_p; 141 } 142 } 143 RTA_PUT(skb, TCA_FCNT, 4, &n_i); 144 r->rta_len = skb->tail - (u8*)r; 145 146 return n_i; 147rtattr_failure: 148 skb_trim(skb, (u8*)r - skb->data); 149 return -EINVAL; 150} 151 152int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb, 153 int type, struct tc_action *a) 154{ 155 struct tcf_hashinfo *hinfo = a->ops->hinfo; 156 157 if (type == RTM_DELACTION) { 158 return tcf_del_walker(skb, a, hinfo); 159 } else if (type == RTM_GETACTION) { 160 return tcf_dump_walker(skb, cb, a, hinfo); 161 } else { 162 printk("tcf_generic_walker: unknown action %d\n", type); 163 return -EINVAL; 164 } 165} 166EXPORT_SYMBOL(tcf_generic_walker); 167 168struct tcf_common *tcf_hash_lookup(u32 index, struct tcf_hashinfo *hinfo) 169{ 170 struct tcf_common *p; 171 172 read_lock(hinfo->lock); 173 for (p = hinfo->htab[tcf_hash(index, hinfo->hmask)]; p; 174 p = p->tcfc_next) { 175 if (p->tcfc_index == index) 176 break; 177 } 178 read_unlock(hinfo->lock); 179 180 return p; 181} 182EXPORT_SYMBOL(tcf_hash_lookup); 183 184u32 tcf_hash_new_index(u32 *idx_gen, struct tcf_hashinfo *hinfo) 185{ 186 u32 val = *idx_gen; 187 188 do { 189 if (++val == 0) 190 val = 1; 191 } while (tcf_hash_lookup(val, hinfo)); 192 193 return (*idx_gen = val); 194} 195EXPORT_SYMBOL(tcf_hash_new_index); 196 197int tcf_hash_search(struct tc_action *a, u32 index) 198{ 199 struct tcf_hashinfo *hinfo = a->ops->hinfo; 200 struct tcf_common *p = tcf_hash_lookup(index, hinfo); 201 202 if (p) { 203 a->priv = p; 204 return 1; 205 } 206 return 0; 207} 208EXPORT_SYMBOL(tcf_hash_search); 209 210struct tcf_common *tcf_hash_check(u32 index, struct tc_action *a, int bind, 211 struct tcf_hashinfo *hinfo) 212{ 213 struct tcf_common *p = NULL; 214 if (index && (p = tcf_hash_lookup(index, hinfo)) != NULL) { 215 if (bind) { 216 p->tcfc_bindcnt++; 217 p->tcfc_refcnt++; 218 } 219 a->priv = p; 220 } 221 return p; 222} 223EXPORT_SYMBOL(tcf_hash_check); 224 225struct tcf_common *tcf_hash_create(u32 index, struct rtattr *est, struct tc_action *a, int size, int bind, u32 *idx_gen, struct tcf_hashinfo *hinfo) 226{ 227 struct tcf_common *p = kzalloc(size, GFP_KERNEL); 228 229 if (unlikely(!p)) 230 return p; 231 p->tcfc_refcnt = 1; 232 if (bind) 233 p->tcfc_bindcnt = 1; 234 235 spin_lock_init(&p->tcfc_lock); 236 p->tcfc_stats_lock = &p->tcfc_lock; 237 p->tcfc_index = index ? index : tcf_hash_new_index(idx_gen, hinfo); 238 p->tcfc_tm.install = jiffies; 239 p->tcfc_tm.lastuse = jiffies; 240#ifdef CONFIG_NET_ESTIMATOR 241 if (est) 242 gen_new_estimator(&p->tcfc_bstats, &p->tcfc_rate_est, 243 p->tcfc_stats_lock, est); 244#endif 245 a->priv = (void *) p; 246 return p; 247} 248EXPORT_SYMBOL(tcf_hash_create); 249 250void tcf_hash_insert(struct tcf_common *p, struct tcf_hashinfo *hinfo) 251{ 252 unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask); 253 254 write_lock_bh(hinfo->lock); 255 p->tcfc_next = hinfo->htab[h]; 256 hinfo->htab[h] = p; 257 write_unlock_bh(hinfo->lock); 258} 259EXPORT_SYMBOL(tcf_hash_insert); 260 261static struct tc_action_ops *act_base = NULL; 262static DEFINE_RWLOCK(act_mod_lock); 263 264int tcf_register_action(struct tc_action_ops *act) 265{ 266 struct tc_action_ops *a, **ap; 267 268 write_lock(&act_mod_lock); 269 for (ap = &act_base; (a = *ap) != NULL; ap = &a->next) { 270 if (act->type == a->type || (strcmp(act->kind, a->kind) == 0)) { 271 write_unlock(&act_mod_lock); 272 return -EEXIST; 273 } 274 } 275 act->next = NULL; 276 *ap = act; 277 write_unlock(&act_mod_lock); 278 return 0; 279} 280 281int tcf_unregister_action(struct tc_action_ops *act) 282{ 283 struct tc_action_ops *a, **ap; 284 int err = -ENOENT; 285 286 write_lock(&act_mod_lock); 287 for (ap = &act_base; (a = *ap) != NULL; ap = &a->next) 288 if (a == act) 289 break; 290 if (a) { 291 *ap = a->next; 292 a->next = NULL; 293 err = 0; 294 } 295 write_unlock(&act_mod_lock); 296 return err; 297} 298 299/* lookup by name */ 300static struct tc_action_ops *tc_lookup_action_n(char *kind) 301{ 302 struct tc_action_ops *a = NULL; 303 304 if (kind) { 305 read_lock(&act_mod_lock); 306 for (a = act_base; a; a = a->next) { 307 if (strcmp(kind, a->kind) == 0) { 308 if (!try_module_get(a->owner)) { 309 read_unlock(&act_mod_lock); 310 return NULL; 311 } 312 break; 313 } 314 } 315 read_unlock(&act_mod_lock); 316 } 317 return a; 318} 319 320/* lookup by rtattr */ 321static struct tc_action_ops *tc_lookup_action(struct rtattr *kind) 322{ 323 struct tc_action_ops *a = NULL; 324 325 if (kind) { 326 read_lock(&act_mod_lock); 327 for (a = act_base; a; a = a->next) { 328 if (rtattr_strcmp(kind, a->kind) == 0) { 329 if (!try_module_get(a->owner)) { 330 read_unlock(&act_mod_lock); 331 return NULL; 332 } 333 break; 334 } 335 } 336 read_unlock(&act_mod_lock); 337 } 338 return a; 339} 340 341#if 0 342/* lookup by id */ 343static struct tc_action_ops *tc_lookup_action_id(u32 type) 344{ 345 struct tc_action_ops *a = NULL; 346 347 if (type) { 348 read_lock(&act_mod_lock); 349 for (a = act_base; a; a = a->next) { 350 if (a->type == type) { 351 if (!try_module_get(a->owner)) { 352 read_unlock(&act_mod_lock); 353 return NULL; 354 } 355 break; 356 } 357 } 358 read_unlock(&act_mod_lock); 359 } 360 return a; 361} 362#endif 363 364int tcf_action_exec(struct sk_buff *skb, struct tc_action *act, 365 struct tcf_result *res) 366{ 367 struct tc_action *a; 368 int ret = -1; 369 370 if (skb->tc_verd & TC_NCLS) { 371 skb->tc_verd = CLR_TC_NCLS(skb->tc_verd); 372 ret = TC_ACT_OK; 373 goto exec_done; 374 } 375 while ((a = act) != NULL) { 376repeat: 377 if (a->ops && a->ops->act) { 378 ret = a->ops->act(skb, a, res); 379 if (TC_MUNGED & skb->tc_verd) { 380 /* copied already, allow trampling */ 381 skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd); 382 skb->tc_verd = CLR_TC_MUNGED(skb->tc_verd); 383 } 384 if (ret == TC_ACT_REPEAT) 385 goto repeat; /* we need a ttl - JHS */ 386 if (ret != TC_ACT_PIPE) 387 goto exec_done; 388 } 389 act = a->next; 390 } 391exec_done: 392 return ret; 393} 394 395void tcf_action_destroy(struct tc_action *act, int bind) 396{ 397 struct tc_action *a; 398 399 for (a = act; a; a = act) { 400 if (a->ops && a->ops->cleanup) { 401 if (a->ops->cleanup(a, bind) == ACT_P_DELETED) 402 module_put(a->ops->owner); 403 act = act->next; 404 kfree(a); 405 } else { /*FIXME: Remove later - catch insertion bugs*/ 406 printk("tcf_action_destroy: BUG? destroying NULL ops\n"); 407 act = act->next; 408 kfree(a); 409 } 410 } 411} 412 413int 414tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int bind, int ref) 415{ 416 int err = -EINVAL; 417 418 if (a->ops == NULL || a->ops->dump == NULL) 419 return err; 420 return a->ops->dump(skb, a, bind, ref); 421} 422 423int 424tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int bind, int ref) 425{ 426 int err = -EINVAL; 427 unsigned char *b = skb->tail; 428 struct rtattr *r; 429 430 if (a->ops == NULL || a->ops->dump == NULL) 431 return err; 432 433 RTA_PUT(skb, TCA_KIND, IFNAMSIZ, a->ops->kind); 434 if (tcf_action_copy_stats(skb, a, 0)) 435 goto rtattr_failure; 436 r = (struct rtattr*) skb->tail; 437 RTA_PUT(skb, TCA_OPTIONS, 0, NULL); 438 if ((err = tcf_action_dump_old(skb, a, bind, ref)) > 0) { 439 r->rta_len = skb->tail - (u8*)r; 440 return err; 441 } 442 443rtattr_failure: 444 skb_trim(skb, b - skb->data); 445 return -1; 446} 447 448int 449tcf_action_dump(struct sk_buff *skb, struct tc_action *act, int bind, int ref) 450{ 451 struct tc_action *a; 452 int err = -EINVAL; 453 unsigned char *b = skb->tail; 454 struct rtattr *r ; 455 456 while ((a = act) != NULL) { 457 r = (struct rtattr*) skb->tail; 458 act = a->next; 459 RTA_PUT(skb, a->order, 0, NULL); 460 err = tcf_action_dump_1(skb, a, bind, ref); 461 if (err < 0) 462 goto errout; 463 r->rta_len = skb->tail - (u8*)r; 464 } 465 466 return 0; 467 468rtattr_failure: 469 err = -EINVAL; 470errout: 471 skb_trim(skb, b - skb->data); 472 return err; 473} 474 475struct tc_action *tcf_action_init_1(struct rtattr *rta, struct rtattr *est, 476 char *name, int ovr, int bind, int *err) 477{ 478 struct tc_action *a; 479 struct tc_action_ops *a_o; 480 char act_name[IFNAMSIZ]; 481 struct rtattr *tb[TCA_ACT_MAX+1]; 482 struct rtattr *kind; 483 484 *err = -EINVAL; 485 486 if (name == NULL) { 487 if (rtattr_parse_nested(tb, TCA_ACT_MAX, rta) < 0) 488 goto err_out; 489 kind = tb[TCA_ACT_KIND-1]; 490 if (kind == NULL) 491 goto err_out; 492 if (rtattr_strlcpy(act_name, kind, IFNAMSIZ) >= IFNAMSIZ) 493 goto err_out; 494 } else { 495 if (strlcpy(act_name, name, IFNAMSIZ) >= IFNAMSIZ) 496 goto err_out; 497 } 498 499 a_o = tc_lookup_action_n(act_name); 500 if (a_o == NULL) { 501#ifdef CONFIG_KMOD 502 rtnl_unlock(); 503 request_module("act_%s", act_name); 504 rtnl_lock(); 505 506 a_o = tc_lookup_action_n(act_name); 507 508 /* We dropped the RTNL semaphore in order to 509 * perform the module load. So, even if we 510 * succeeded in loading the module we have to 511 * tell the caller to replay the request. We 512 * indicate this using -EAGAIN. 513 */ 514 if (a_o != NULL) { 515 *err = -EAGAIN; 516 goto err_mod; 517 } 518#endif 519 *err = -ENOENT; 520 goto err_out; 521 } 522 523 *err = -ENOMEM; 524 a = kzalloc(sizeof(*a), GFP_KERNEL); 525 if (a == NULL) 526 goto err_mod; 527 528 /* backward compatibility for policer */ 529 if (name == NULL) 530 *err = a_o->init(tb[TCA_ACT_OPTIONS-1], est, a, ovr, bind); 531 else 532 *err = a_o->init(rta, est, a, ovr, bind); 533 if (*err < 0) 534 goto err_free; 535 536 /* module count goes up only when brand new policy is created 537 if it exists and is only bound to in a_o->init() then 538 ACT_P_CREATED is not returned (a zero is). 539 */ 540 if (*err != ACT_P_CREATED) 541 module_put(a_o->owner); 542 a->ops = a_o; 543 544 *err = 0; 545 return a; 546 547err_free: 548 kfree(a); 549err_mod: 550 module_put(a_o->owner); 551err_out: 552 return NULL; 553} 554 555struct tc_action *tcf_action_init(struct rtattr *rta, struct rtattr *est, 556 char *name, int ovr, int bind, int *err) 557{ 558 struct rtattr *tb[TCA_ACT_MAX_PRIO+1]; 559 struct tc_action *head = NULL, *act, *act_prev = NULL; 560 int i; 561 562 if (rtattr_parse_nested(tb, TCA_ACT_MAX_PRIO, rta) < 0) { 563 *err = -EINVAL; 564 return head; 565 } 566 567 for (i=0; i < TCA_ACT_MAX_PRIO && tb[i]; i++) { 568 act = tcf_action_init_1(tb[i], est, name, ovr, bind, err); 569 if (act == NULL) 570 goto err; 571 act->order = i+1; 572 573 if (head == NULL) 574 head = act; 575 else 576 act_prev->next = act; 577 act_prev = act; 578 } 579 return head; 580 581err: 582 if (head != NULL) 583 tcf_action_destroy(head, bind); 584 return NULL; 585} 586 587int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a, 588 int compat_mode) 589{ 590 int err = 0; 591 struct gnet_dump d; 592 struct tcf_act_hdr *h = a->priv; 593 594 if (h == NULL) 595 goto errout; 596 597 /* compat_mode being true specifies a call that is supposed 598 * to add additional backward compatiblity statistic TLVs. 599 */ 600 if (compat_mode) { 601 if (a->type == TCA_OLD_COMPAT) 602 err = gnet_stats_start_copy_compat(skb, 0, 603 TCA_STATS, TCA_XSTATS, h->tcf_stats_lock, &d); 604 else 605 return 0; 606 } else 607 err = gnet_stats_start_copy(skb, TCA_ACT_STATS, 608 h->tcf_stats_lock, &d); 609 610 if (err < 0) 611 goto errout; 612 613 if (a->ops != NULL && a->ops->get_stats != NULL) 614 if (a->ops->get_stats(skb, a) < 0) 615 goto errout; 616 617 if (gnet_stats_copy_basic(&d, &h->tcf_bstats) < 0 || 618#ifdef CONFIG_NET_ESTIMATOR 619 gnet_stats_copy_rate_est(&d, &h->tcf_rate_est) < 0 || 620#endif 621 gnet_stats_copy_queue(&d, &h->tcf_qstats) < 0) 622 goto errout; 623 624 if (gnet_stats_finish_copy(&d) < 0) 625 goto errout; 626 627 return 0; 628 629errout: 630 return -1; 631} 632 633static int 634tca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 pid, u32 seq, 635 u16 flags, int event, int bind, int ref) 636{ 637 struct tcamsg *t; 638 struct nlmsghdr *nlh; 639 unsigned char *b = skb->tail; 640 struct rtattr *x; 641 642 nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*t), flags); 643 644 t = NLMSG_DATA(nlh); 645 t->tca_family = AF_UNSPEC; 646 t->tca__pad1 = 0; 647 t->tca__pad2 = 0; 648 649 x = (struct rtattr*) skb->tail; 650 RTA_PUT(skb, TCA_ACT_TAB, 0, NULL); 651 652 if (tcf_action_dump(skb, a, bind, ref) < 0) 653 goto rtattr_failure; 654 655 x->rta_len = skb->tail - (u8*)x; 656 657 nlh->nlmsg_len = skb->tail - b; 658 return skb->len; 659 660rtattr_failure: 661nlmsg_failure: 662 skb_trim(skb, b - skb->data); 663 return -1; 664} 665 666static int 667act_get_notify(u32 pid, struct nlmsghdr *n, struct tc_action *a, int event) 668{ 669 struct sk_buff *skb; 670 671 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 672 if (!skb) 673 return -ENOBUFS; 674 if (tca_get_fill(skb, a, pid, n->nlmsg_seq, 0, event, 0, 0) <= 0) { 675 kfree_skb(skb); 676 return -EINVAL; 677 } 678 679 return rtnl_unicast(skb, pid); 680} 681 682static struct tc_action * 683tcf_action_get_1(struct rtattr *rta, struct nlmsghdr *n, u32 pid, int *err) 684{ 685 struct rtattr *tb[TCA_ACT_MAX+1]; 686 struct tc_action *a; 687 int index; 688 689 *err = -EINVAL; 690 if (rtattr_parse_nested(tb, TCA_ACT_MAX, rta) < 0) 691 return NULL; 692 693 if (tb[TCA_ACT_INDEX - 1] == NULL || 694 RTA_PAYLOAD(tb[TCA_ACT_INDEX - 1]) < sizeof(index)) 695 return NULL; 696 index = *(int *)RTA_DATA(tb[TCA_ACT_INDEX - 1]); 697 698 *err = -ENOMEM; 699 a = kzalloc(sizeof(struct tc_action), GFP_KERNEL); 700 if (a == NULL) 701 return NULL; 702 703 *err = -EINVAL; 704 a->ops = tc_lookup_action(tb[TCA_ACT_KIND - 1]); 705 if (a->ops == NULL) 706 goto err_free; 707 if (a->ops->lookup == NULL) 708 goto err_mod; 709 *err = -ENOENT; 710 if (a->ops->lookup(a, index) == 0) 711 goto err_mod; 712 713 module_put(a->ops->owner); 714 *err = 0; 715 return a; 716err_mod: 717 module_put(a->ops->owner); 718err_free: 719 kfree(a); 720 return NULL; 721} 722 723static void cleanup_a(struct tc_action *act) 724{ 725 struct tc_action *a; 726 727 for (a = act; a; a = act) { 728 act = a->next; 729 kfree(a); 730 } 731} 732 733static struct tc_action *create_a(int i) 734{ 735 struct tc_action *act; 736 737 act = kzalloc(sizeof(*act), GFP_KERNEL); 738 if (act == NULL) { 739 printk("create_a: failed to alloc!\n"); 740 return NULL; 741 } 742 act->order = i; 743 return act; 744} 745 746static int tca_action_flush(struct rtattr *rta, struct nlmsghdr *n, u32 pid) 747{ 748 struct sk_buff *skb; 749 unsigned char *b; 750 struct nlmsghdr *nlh; 751 struct tcamsg *t; 752 struct netlink_callback dcb; 753 struct rtattr *x; 754 struct rtattr *tb[TCA_ACT_MAX+1]; 755 struct rtattr *kind; 756 struct tc_action *a = create_a(0); 757 int err = -EINVAL; 758 759 if (a == NULL) { 760 printk("tca_action_flush: couldnt create tc_action\n"); 761 return err; 762 } 763 764 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 765 if (!skb) { 766 printk("tca_action_flush: failed skb alloc\n"); 767 kfree(a); 768 return -ENOBUFS; 769 } 770 771 b = (unsigned char *)skb->tail; 772 773 if (rtattr_parse_nested(tb, TCA_ACT_MAX, rta) < 0) 774 goto err_out; 775 776 kind = tb[TCA_ACT_KIND-1]; 777 a->ops = tc_lookup_action(kind); 778 if (a->ops == NULL) 779 goto err_out; 780 781 nlh = NLMSG_PUT(skb, pid, n->nlmsg_seq, RTM_DELACTION, sizeof(*t)); 782 t = NLMSG_DATA(nlh); 783 t->tca_family = AF_UNSPEC; 784 t->tca__pad1 = 0; 785 t->tca__pad2 = 0; 786 787 x = (struct rtattr *) skb->tail; 788 RTA_PUT(skb, TCA_ACT_TAB, 0, NULL); 789 790 err = a->ops->walk(skb, &dcb, RTM_DELACTION, a); 791 if (err < 0) 792 goto rtattr_failure; 793 794 x->rta_len = skb->tail - (u8 *) x; 795 796 nlh->nlmsg_len = skb->tail - b; 797 nlh->nlmsg_flags |= NLM_F_ROOT; 798 module_put(a->ops->owner); 799 kfree(a); 800 err = rtnetlink_send(skb, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); 801 if (err > 0) 802 return 0; 803 804 return err; 805 806rtattr_failure: 807nlmsg_failure: 808 module_put(a->ops->owner); 809err_out: 810 kfree_skb(skb); 811 kfree(a); 812 return err; 813} 814 815static int 816tca_action_gd(struct rtattr *rta, struct nlmsghdr *n, u32 pid, int event) 817{ 818 int i, ret = 0; 819 struct rtattr *tb[TCA_ACT_MAX_PRIO+1]; 820 struct tc_action *head = NULL, *act, *act_prev = NULL; 821 822 if (rtattr_parse_nested(tb, TCA_ACT_MAX_PRIO, rta) < 0) 823 return -EINVAL; 824 825 if (event == RTM_DELACTION && n->nlmsg_flags&NLM_F_ROOT) { 826 if (tb[0] != NULL && tb[1] == NULL) 827 return tca_action_flush(tb[0], n, pid); 828 } 829 830 for (i=0; i < TCA_ACT_MAX_PRIO && tb[i]; i++) { 831 act = tcf_action_get_1(tb[i], n, pid, &ret); 832 if (act == NULL) 833 goto err; 834 act->order = i+1; 835 836 if (head == NULL) 837 head = act; 838 else 839 act_prev->next = act; 840 act_prev = act; 841 } 842 843 if (event == RTM_GETACTION) 844 ret = act_get_notify(pid, n, head, event); 845 else { /* delete */ 846 struct sk_buff *skb; 847 848 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 849 if (!skb) { 850 ret = -ENOBUFS; 851 goto err; 852 } 853 854 if (tca_get_fill(skb, head, pid, n->nlmsg_seq, 0, event, 855 0, 1) <= 0) { 856 kfree_skb(skb); 857 ret = -EINVAL; 858 goto err; 859 } 860 861 /* now do the delete */ 862 tcf_action_destroy(head, 0); 863 ret = rtnetlink_send(skb, pid, RTNLGRP_TC, 864 n->nlmsg_flags&NLM_F_ECHO); 865 if (ret > 0) 866 return 0; 867 return ret; 868 } 869err: 870 cleanup_a(head); 871 return ret; 872} 873 874static int tcf_add_notify(struct tc_action *a, u32 pid, u32 seq, int event, 875 u16 flags) 876{ 877 struct tcamsg *t; 878 struct nlmsghdr *nlh; 879 struct sk_buff *skb; 880 struct rtattr *x; 881 unsigned char *b; 882 int err = 0; 883 884 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 885 if (!skb) 886 return -ENOBUFS; 887 888 b = (unsigned char *)skb->tail; 889 890 nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*t), flags); 891 t = NLMSG_DATA(nlh); 892 t->tca_family = AF_UNSPEC; 893 t->tca__pad1 = 0; 894 t->tca__pad2 = 0; 895 896 x = (struct rtattr*) skb->tail; 897 RTA_PUT(skb, TCA_ACT_TAB, 0, NULL); 898 899 if (tcf_action_dump(skb, a, 0, 0) < 0) 900 goto rtattr_failure; 901 902 x->rta_len = skb->tail - (u8*)x; 903 904 nlh->nlmsg_len = skb->tail - b; 905 NETLINK_CB(skb).dst_group = RTNLGRP_TC; 906 907 err = rtnetlink_send(skb, pid, RTNLGRP_TC, flags&NLM_F_ECHO); 908 if (err > 0) 909 err = 0; 910 return err; 911 912rtattr_failure: 913nlmsg_failure: 914 kfree_skb(skb); 915 return -1; 916} 917 918 919static int 920tcf_action_add(struct rtattr *rta, struct nlmsghdr *n, u32 pid, int ovr) 921{ 922 int ret = 0; 923 struct tc_action *act; 924 struct tc_action *a; 925 u32 seq = n->nlmsg_seq; 926 927 act = tcf_action_init(rta, NULL, NULL, ovr, 0, &ret); 928 if (act == NULL) 929 goto done; 930 931 /* dump then free all the actions after update; inserted policy 932 * stays intact 933 * */ 934 ret = tcf_add_notify(act, pid, seq, RTM_NEWACTION, n->nlmsg_flags); 935 for (a = act; a; a = act) { 936 act = a->next; 937 kfree(a); 938 } 939done: 940 return ret; 941} 942 943static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg) 944{ 945 struct rtattr **tca = arg; 946 u32 pid = skb ? NETLINK_CB(skb).pid : 0; 947 int ret = 0, ovr = 0; 948 949 if (tca[TCA_ACT_TAB-1] == NULL) { 950 printk("tc_ctl_action: received NO action attribs\n"); 951 return -EINVAL; 952 } 953 954 /* n->nlmsg_flags&NLM_F_CREATE 955 * */ 956 switch (n->nlmsg_type) { 957 case RTM_NEWACTION: 958 /* we are going to assume all other flags 959 * imply create only if it doesnt exist 960 * Note that CREATE | EXCL implies that 961 * but since we want avoid ambiguity (eg when flags 962 * is zero) then just set this 963 */ 964 if (n->nlmsg_flags&NLM_F_REPLACE) 965 ovr = 1; 966replay: 967 ret = tcf_action_add(tca[TCA_ACT_TAB-1], n, pid, ovr); 968 if (ret == -EAGAIN) 969 goto replay; 970 break; 971 case RTM_DELACTION: 972 ret = tca_action_gd(tca[TCA_ACT_TAB-1], n, pid, RTM_DELACTION); 973 break; 974 case RTM_GETACTION: 975 ret = tca_action_gd(tca[TCA_ACT_TAB-1], n, pid, RTM_GETACTION); 976 break; 977 default: 978 BUG(); 979 } 980 981 return ret; 982} 983 984static struct rtattr * 985find_dump_kind(struct nlmsghdr *n) 986{ 987 struct rtattr *tb1, *tb2[TCA_ACT_MAX+1]; 988 struct rtattr *tb[TCA_ACT_MAX_PRIO + 1]; 989 struct rtattr *rta[TCAA_MAX + 1]; 990 struct rtattr *kind; 991 int min_len = NLMSG_LENGTH(sizeof(struct tcamsg)); 992 int attrlen = n->nlmsg_len - NLMSG_ALIGN(min_len); 993 struct rtattr *attr = (void *) n + NLMSG_ALIGN(min_len); 994 995 if (rtattr_parse(rta, TCAA_MAX, attr, attrlen) < 0) 996 return NULL; 997 tb1 = rta[TCA_ACT_TAB - 1]; 998 if (tb1 == NULL) 999 return NULL; 1000 1001 if (rtattr_parse(tb, TCA_ACT_MAX_PRIO, RTA_DATA(tb1), 1002 NLMSG_ALIGN(RTA_PAYLOAD(tb1))) < 0) 1003 return NULL; 1004 if (tb[0] == NULL) 1005 return NULL; 1006 1007 if (rtattr_parse(tb2, TCA_ACT_MAX, RTA_DATA(tb[0]), 1008 RTA_PAYLOAD(tb[0])) < 0) 1009 return NULL; 1010 kind = tb2[TCA_ACT_KIND-1]; 1011 1012 return kind; 1013} 1014 1015static int 1016tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) 1017{ 1018 struct nlmsghdr *nlh; 1019 unsigned char *b = skb->tail; 1020 struct rtattr *x; 1021 struct tc_action_ops *a_o; 1022 struct tc_action a; 1023 int ret = 0; 1024 struct tcamsg *t = (struct tcamsg *) NLMSG_DATA(cb->nlh); 1025 struct rtattr *kind = find_dump_kind(cb->nlh); 1026 1027 if (kind == NULL) { 1028 printk("tc_dump_action: action bad kind\n"); 1029 return 0; 1030 } 1031 1032 a_o = tc_lookup_action(kind); 1033 if (a_o == NULL) { 1034 return 0; 1035 } 1036 1037 memset(&a, 0, sizeof(struct tc_action)); 1038 a.ops = a_o; 1039 1040 if (a_o->walk == NULL) { 1041 printk("tc_dump_action: %s !capable of dumping table\n", a_o->kind); 1042 goto rtattr_failure; 1043 } 1044 1045 nlh = NLMSG_PUT(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, 1046 cb->nlh->nlmsg_type, sizeof(*t)); 1047 t = NLMSG_DATA(nlh); 1048 t->tca_family = AF_UNSPEC; 1049 t->tca__pad1 = 0; 1050 t->tca__pad2 = 0; 1051 1052 x = (struct rtattr *) skb->tail; 1053 RTA_PUT(skb, TCA_ACT_TAB, 0, NULL); 1054 1055 ret = a_o->walk(skb, cb, RTM_GETACTION, &a); 1056 if (ret < 0) 1057 goto rtattr_failure; 1058 1059 if (ret > 0) { 1060 x->rta_len = skb->tail - (u8 *) x; 1061 ret = skb->len; 1062 } else 1063 skb_trim(skb, (u8*)x - skb->data); 1064 1065 nlh->nlmsg_len = skb->tail - b; 1066 if (NETLINK_CB(cb->skb).pid && ret) 1067 nlh->nlmsg_flags |= NLM_F_MULTI; 1068 module_put(a_o->owner); 1069 return skb->len; 1070 1071rtattr_failure: 1072nlmsg_failure: 1073 module_put(a_o->owner); 1074 skb_trim(skb, b - skb->data); 1075 return skb->len; 1076} 1077 1078static int __init tc_action_init(void) 1079{ 1080 struct rtnetlink_link *link_p = rtnetlink_links[PF_UNSPEC]; 1081 1082 if (link_p) { 1083 link_p[RTM_NEWACTION-RTM_BASE].doit = tc_ctl_action; 1084 link_p[RTM_DELACTION-RTM_BASE].doit = tc_ctl_action; 1085 link_p[RTM_GETACTION-RTM_BASE].doit = tc_ctl_action; 1086 link_p[RTM_GETACTION-RTM_BASE].dumpit = tc_dump_action; 1087 } 1088 1089 return 0; 1090} 1091 1092subsys_initcall(tc_action_init); 1093 1094EXPORT_SYMBOL(tcf_register_action); 1095EXPORT_SYMBOL(tcf_unregister_action); 1096EXPORT_SYMBOL(tcf_action_exec); 1097EXPORT_SYMBOL(tcf_action_dump_1);