1 /* 2 * net/sched/cls_api.c Packet classifier 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 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 10 * 11 * Changes: 12 * 13 * Eduardo J. Blanco <ejbs@netlabs.com.uy> :990222: kmod support 14 * 15 */ 16 17 #include <linux/module.h> 18 #include <linux/types.h> 19 #include <linux/kernel.h> 20 #include <linux/string.h> 21 #include <linux/errno.h> 22 #include <linux/err.h> 23 #include <linux/skbuff.h> 24 #include <linux/init.h> 25 #include <linux/kmod.h> 26 #include <linux/err.h> 27 #include <linux/slab.h> 28 #include <net/net_namespace.h> 29 #include <net/sock.h> 30 #include <net/netlink.h> 31 #include <net/pkt_sched.h> 32 #include <net/pkt_cls.h> 33 34 /* The list of all installed classifier types */ 35 static LIST_HEAD(tcf_proto_base); 36 37 /* Protects list of registered TC modules. It is pure SMP lock. */ 38 static DEFINE_RWLOCK(cls_mod_lock); 39 40 /* Find classifier type by string name */ 41 42 static const struct tcf_proto_ops *tcf_proto_lookup_ops(const char *kind) 43 { 44 const struct tcf_proto_ops *t, *res = NULL; 45 46 if (kind) { 47 read_lock(&cls_mod_lock); 48 list_for_each_entry(t, &tcf_proto_base, head) { 49 if (strcmp(kind, t->kind) == 0) { 50 if (try_module_get(t->owner)) 51 res = t; 52 break; 53 } 54 } 55 read_unlock(&cls_mod_lock); 56 } 57 return res; 58 } 59 60 /* Register(unregister) new classifier type */ 61 62 int register_tcf_proto_ops(struct tcf_proto_ops *ops) 63 { 64 struct tcf_proto_ops *t; 65 int rc = -EEXIST; 66 67 write_lock(&cls_mod_lock); 68 list_for_each_entry(t, &tcf_proto_base, head) 69 if (!strcmp(ops->kind, t->kind)) 70 goto out; 71 72 list_add_tail(&ops->head, &tcf_proto_base); 73 rc = 0; 74 out: 75 write_unlock(&cls_mod_lock); 76 return rc; 77 } 78 EXPORT_SYMBOL(register_tcf_proto_ops); 79 80 int unregister_tcf_proto_ops(struct tcf_proto_ops *ops) 81 { 82 struct tcf_proto_ops *t; 83 int rc = -ENOENT; 84 85 /* Wait for outstanding call_rcu()s, if any, from a 86 * tcf_proto_ops's destroy() handler. 87 */ 88 rcu_barrier(); 89 90 write_lock(&cls_mod_lock); 91 list_for_each_entry(t, &tcf_proto_base, head) { 92 if (t == ops) { 93 list_del(&t->head); 94 rc = 0; 95 break; 96 } 97 } 98 write_unlock(&cls_mod_lock); 99 return rc; 100 } 101 EXPORT_SYMBOL(unregister_tcf_proto_ops); 102 103 static int tfilter_notify(struct net *net, struct sk_buff *oskb, 104 struct nlmsghdr *n, struct tcf_proto *tp, 105 unsigned long fh, int event, bool unicast); 106 107 static void tfilter_notify_chain(struct net *net, struct sk_buff *oskb, 108 struct nlmsghdr *n, 109 struct tcf_proto __rcu **chain, int event) 110 { 111 struct tcf_proto __rcu **it_chain; 112 struct tcf_proto *tp; 113 114 for (it_chain = chain; (tp = rtnl_dereference(*it_chain)) != NULL; 115 it_chain = &tp->next) 116 tfilter_notify(net, oskb, n, tp, 0, event, false); 117 } 118 119 /* Select new prio value from the range, managed by kernel. */ 120 121 static inline u32 tcf_auto_prio(struct tcf_proto *tp) 122 { 123 u32 first = TC_H_MAKE(0xC0000000U, 0U); 124 125 if (tp) 126 first = tp->prio - 1; 127 128 return first; 129 } 130 131 static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol, 132 u32 prio, u32 parent, struct Qdisc *q) 133 { 134 struct tcf_proto *tp; 135 int err; 136 137 tp = kzalloc(sizeof(*tp), GFP_KERNEL); 138 if (!tp) 139 return ERR_PTR(-ENOBUFS); 140 141 err = -ENOENT; 142 tp->ops = tcf_proto_lookup_ops(kind); 143 if (!tp->ops) { 144 #ifdef CONFIG_MODULES 145 rtnl_unlock(); 146 request_module("cls_%s", kind); 147 rtnl_lock(); 148 tp->ops = tcf_proto_lookup_ops(kind); 149 /* We dropped the RTNL semaphore in order to perform 150 * the module load. So, even if we succeeded in loading 151 * the module we have to replay the request. We indicate 152 * this using -EAGAIN. 153 */ 154 if (tp->ops) { 155 module_put(tp->ops->owner); 156 err = -EAGAIN; 157 } else { 158 err = -ENOENT; 159 } 160 goto errout; 161 #endif 162 } 163 tp->classify = tp->ops->classify; 164 tp->protocol = protocol; 165 tp->prio = prio; 166 tp->classid = parent; 167 tp->q = q; 168 169 err = tp->ops->init(tp); 170 if (err) { 171 module_put(tp->ops->owner); 172 goto errout; 173 } 174 return tp; 175 176 errout: 177 kfree(tp); 178 return ERR_PTR(err); 179 } 180 181 static bool tcf_proto_destroy(struct tcf_proto *tp, bool force) 182 { 183 if (tp->ops->destroy(tp, force)) { 184 module_put(tp->ops->owner); 185 kfree_rcu(tp, rcu); 186 return true; 187 } 188 return false; 189 } 190 191 void tcf_destroy_chain(struct tcf_proto __rcu **fl) 192 { 193 struct tcf_proto *tp; 194 195 while ((tp = rtnl_dereference(*fl)) != NULL) { 196 RCU_INIT_POINTER(*fl, tp->next); 197 tcf_proto_destroy(tp, true); 198 } 199 } 200 EXPORT_SYMBOL(tcf_destroy_chain); 201 202 /* Add/change/delete/get a filter node */ 203 204 static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n) 205 { 206 struct net *net = sock_net(skb->sk); 207 struct nlattr *tca[TCA_MAX + 1]; 208 struct tcmsg *t; 209 u32 protocol; 210 u32 prio; 211 u32 nprio; 212 u32 parent; 213 struct net_device *dev; 214 struct Qdisc *q; 215 struct tcf_proto __rcu **back; 216 struct tcf_proto __rcu **chain; 217 struct tcf_proto *next; 218 struct tcf_proto *tp; 219 const struct Qdisc_class_ops *cops; 220 unsigned long cl; 221 unsigned long fh; 222 int err; 223 int tp_created; 224 225 if ((n->nlmsg_type != RTM_GETTFILTER) && 226 !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) 227 return -EPERM; 228 229 replay: 230 tp_created = 0; 231 232 err = nlmsg_parse(n, sizeof(*t), tca, TCA_MAX, NULL); 233 if (err < 0) 234 return err; 235 236 t = nlmsg_data(n); 237 protocol = TC_H_MIN(t->tcm_info); 238 prio = TC_H_MAJ(t->tcm_info); 239 nprio = prio; 240 parent = t->tcm_parent; 241 cl = 0; 242 243 if (prio == 0) { 244 switch (n->nlmsg_type) { 245 case RTM_DELTFILTER: 246 if (protocol || t->tcm_handle || tca[TCA_KIND]) 247 return -ENOENT; 248 break; 249 case RTM_NEWTFILTER: 250 /* If no priority is provided by the user, 251 * we allocate one. 252 */ 253 if (n->nlmsg_flags & NLM_F_CREATE) { 254 prio = TC_H_MAKE(0x80000000U, 0U); 255 break; 256 } 257 /* fall-through */ 258 default: 259 return -ENOENT; 260 } 261 } 262 263 /* Find head of filter chain. */ 264 265 /* Find link */ 266 dev = __dev_get_by_index(net, t->tcm_ifindex); 267 if (dev == NULL) 268 return -ENODEV; 269 270 /* Find qdisc */ 271 if (!parent) { 272 q = dev->qdisc; 273 parent = q->handle; 274 } else { 275 q = qdisc_lookup(dev, TC_H_MAJ(t->tcm_parent)); 276 if (q == NULL) 277 return -EINVAL; 278 } 279 280 /* Is it classful? */ 281 cops = q->ops->cl_ops; 282 if (!cops) 283 return -EINVAL; 284 285 if (cops->tcf_chain == NULL) 286 return -EOPNOTSUPP; 287 288 /* Do we search for filter, attached to class? */ 289 if (TC_H_MIN(parent)) { 290 cl = cops->get(q, parent); 291 if (cl == 0) 292 return -ENOENT; 293 } 294 295 /* And the last stroke */ 296 chain = cops->tcf_chain(q, cl); 297 if (chain == NULL) { 298 err = -EINVAL; 299 goto errout; 300 } 301 if (n->nlmsg_type == RTM_DELTFILTER && prio == 0) { 302 tfilter_notify_chain(net, skb, n, chain, RTM_DELTFILTER); 303 tcf_destroy_chain(chain); 304 err = 0; 305 goto errout; 306 } 307 308 /* Check the chain for existence of proto-tcf with this priority */ 309 for (back = chain; 310 (tp = rtnl_dereference(*back)) != NULL; 311 back = &tp->next) { 312 if (tp->prio >= prio) { 313 if (tp->prio == prio) { 314 if (!nprio || 315 (tp->protocol != protocol && protocol)) { 316 err = -EINVAL; 317 goto errout; 318 } 319 } else { 320 tp = NULL; 321 } 322 break; 323 } 324 } 325 326 if (tp == NULL) { 327 /* Proto-tcf does not exist, create new one */ 328 329 if (tca[TCA_KIND] == NULL || !protocol) { 330 err = -EINVAL; 331 goto errout; 332 } 333 334 if (n->nlmsg_type != RTM_NEWTFILTER || 335 !(n->nlmsg_flags & NLM_F_CREATE)) { 336 err = -ENOENT; 337 goto errout; 338 } 339 340 if (!nprio) 341 nprio = TC_H_MAJ(tcf_auto_prio(rtnl_dereference(*back))); 342 343 tp = tcf_proto_create(nla_data(tca[TCA_KIND]), 344 protocol, nprio, parent, q); 345 if (IS_ERR(tp)) { 346 err = PTR_ERR(tp); 347 goto errout; 348 } 349 tp_created = 1; 350 } else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) { 351 err = -EINVAL; 352 goto errout; 353 } 354 355 fh = tp->ops->get(tp, t->tcm_handle); 356 357 if (fh == 0) { 358 if (n->nlmsg_type == RTM_DELTFILTER && t->tcm_handle == 0) { 359 next = rtnl_dereference(tp->next); 360 RCU_INIT_POINTER(*back, next); 361 tfilter_notify(net, skb, n, tp, fh, 362 RTM_DELTFILTER, false); 363 tcf_proto_destroy(tp, true); 364 err = 0; 365 goto errout; 366 } 367 368 if (n->nlmsg_type != RTM_NEWTFILTER || 369 !(n->nlmsg_flags & NLM_F_CREATE)) { 370 err = -ENOENT; 371 goto errout; 372 } 373 } else { 374 switch (n->nlmsg_type) { 375 case RTM_NEWTFILTER: 376 if (n->nlmsg_flags & NLM_F_EXCL) { 377 if (tp_created) 378 tcf_proto_destroy(tp, true); 379 err = -EEXIST; 380 goto errout; 381 } 382 break; 383 case RTM_DELTFILTER: 384 err = tp->ops->delete(tp, fh); 385 if (err) 386 goto errout; 387 next = rtnl_dereference(tp->next); 388 tfilter_notify(net, skb, n, tp, t->tcm_handle, 389 RTM_DELTFILTER, false); 390 if (tcf_proto_destroy(tp, false)) 391 RCU_INIT_POINTER(*back, next); 392 goto errout; 393 case RTM_GETTFILTER: 394 err = tfilter_notify(net, skb, n, tp, fh, 395 RTM_NEWTFILTER, true); 396 goto errout; 397 default: 398 err = -EINVAL; 399 goto errout; 400 } 401 } 402 403 err = tp->ops->change(net, skb, tp, cl, t->tcm_handle, tca, &fh, 404 n->nlmsg_flags & NLM_F_CREATE ? TCA_ACT_NOREPLACE : TCA_ACT_REPLACE); 405 if (err == 0) { 406 if (tp_created) { 407 RCU_INIT_POINTER(tp->next, rtnl_dereference(*back)); 408 rcu_assign_pointer(*back, tp); 409 } 410 tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER, false); 411 } else { 412 if (tp_created) 413 tcf_proto_destroy(tp, true); 414 } 415 416 errout: 417 if (cl) 418 cops->put(q, cl); 419 if (err == -EAGAIN) 420 /* Replay the request. */ 421 goto replay; 422 return err; 423 } 424 425 static int tcf_fill_node(struct net *net, struct sk_buff *skb, 426 struct tcf_proto *tp, unsigned long fh, u32 portid, 427 u32 seq, u16 flags, int event) 428 { 429 struct tcmsg *tcm; 430 struct nlmsghdr *nlh; 431 unsigned char *b = skb_tail_pointer(skb); 432 433 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags); 434 if (!nlh) 435 goto out_nlmsg_trim; 436 tcm = nlmsg_data(nlh); 437 tcm->tcm_family = AF_UNSPEC; 438 tcm->tcm__pad1 = 0; 439 tcm->tcm__pad2 = 0; 440 tcm->tcm_ifindex = qdisc_dev(tp->q)->ifindex; 441 tcm->tcm_parent = tp->classid; 442 tcm->tcm_info = TC_H_MAKE(tp->prio, tp->protocol); 443 if (nla_put_string(skb, TCA_KIND, tp->ops->kind)) 444 goto nla_put_failure; 445 tcm->tcm_handle = fh; 446 if (RTM_DELTFILTER != event) { 447 tcm->tcm_handle = 0; 448 if (tp->ops->dump && tp->ops->dump(net, tp, fh, skb, tcm) < 0) 449 goto nla_put_failure; 450 } 451 nlh->nlmsg_len = skb_tail_pointer(skb) - b; 452 return skb->len; 453 454 out_nlmsg_trim: 455 nla_put_failure: 456 nlmsg_trim(skb, b); 457 return -1; 458 } 459 460 static int tfilter_notify(struct net *net, struct sk_buff *oskb, 461 struct nlmsghdr *n, struct tcf_proto *tp, 462 unsigned long fh, int event, bool unicast) 463 { 464 struct sk_buff *skb; 465 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0; 466 467 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 468 if (!skb) 469 return -ENOBUFS; 470 471 if (tcf_fill_node(net, skb, tp, fh, portid, n->nlmsg_seq, 472 n->nlmsg_flags, event) <= 0) { 473 kfree_skb(skb); 474 return -EINVAL; 475 } 476 477 if (unicast) 478 return netlink_unicast(net->rtnl, skb, portid, MSG_DONTWAIT); 479 480 return rtnetlink_send(skb, net, portid, RTNLGRP_TC, 481 n->nlmsg_flags & NLM_F_ECHO); 482 } 483 484 struct tcf_dump_args { 485 struct tcf_walker w; 486 struct sk_buff *skb; 487 struct netlink_callback *cb; 488 }; 489 490 static int tcf_node_dump(struct tcf_proto *tp, unsigned long n, 491 struct tcf_walker *arg) 492 { 493 struct tcf_dump_args *a = (void *)arg; 494 struct net *net = sock_net(a->skb->sk); 495 496 return tcf_fill_node(net, a->skb, tp, n, NETLINK_CB(a->cb->skb).portid, 497 a->cb->nlh->nlmsg_seq, NLM_F_MULTI, 498 RTM_NEWTFILTER); 499 } 500 501 /* called with RTNL */ 502 static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) 503 { 504 struct net *net = sock_net(skb->sk); 505 int t; 506 int s_t; 507 struct net_device *dev; 508 struct Qdisc *q; 509 struct tcf_proto *tp, __rcu **chain; 510 struct tcmsg *tcm = nlmsg_data(cb->nlh); 511 unsigned long cl = 0; 512 const struct Qdisc_class_ops *cops; 513 struct tcf_dump_args arg; 514 515 if (nlmsg_len(cb->nlh) < sizeof(*tcm)) 516 return skb->len; 517 dev = __dev_get_by_index(net, tcm->tcm_ifindex); 518 if (!dev) 519 return skb->len; 520 521 if (!tcm->tcm_parent) 522 q = dev->qdisc; 523 else 524 q = qdisc_lookup(dev, TC_H_MAJ(tcm->tcm_parent)); 525 if (!q) 526 goto out; 527 cops = q->ops->cl_ops; 528 if (!cops) 529 goto errout; 530 if (cops->tcf_chain == NULL) 531 goto errout; 532 if (TC_H_MIN(tcm->tcm_parent)) { 533 cl = cops->get(q, tcm->tcm_parent); 534 if (cl == 0) 535 goto errout; 536 } 537 chain = cops->tcf_chain(q, cl); 538 if (chain == NULL) 539 goto errout; 540 541 s_t = cb->args[0]; 542 543 for (tp = rtnl_dereference(*chain), t = 0; 544 tp; tp = rtnl_dereference(tp->next), t++) { 545 if (t < s_t) 546 continue; 547 if (TC_H_MAJ(tcm->tcm_info) && 548 TC_H_MAJ(tcm->tcm_info) != tp->prio) 549 continue; 550 if (TC_H_MIN(tcm->tcm_info) && 551 TC_H_MIN(tcm->tcm_info) != tp->protocol) 552 continue; 553 if (t > s_t) 554 memset(&cb->args[1], 0, 555 sizeof(cb->args)-sizeof(cb->args[0])); 556 if (cb->args[1] == 0) { 557 if (tcf_fill_node(net, skb, tp, 0, 558 NETLINK_CB(cb->skb).portid, 559 cb->nlh->nlmsg_seq, NLM_F_MULTI, 560 RTM_NEWTFILTER) <= 0) 561 break; 562 563 cb->args[1] = 1; 564 } 565 if (tp->ops->walk == NULL) 566 continue; 567 arg.w.fn = tcf_node_dump; 568 arg.skb = skb; 569 arg.cb = cb; 570 arg.w.stop = 0; 571 arg.w.skip = cb->args[1] - 1; 572 arg.w.count = 0; 573 tp->ops->walk(tp, &arg.w); 574 cb->args[1] = arg.w.count + 1; 575 if (arg.w.stop) 576 break; 577 } 578 579 cb->args[0] = t; 580 581 errout: 582 if (cl) 583 cops->put(q, cl); 584 out: 585 return skb->len; 586 } 587 588 void tcf_exts_destroy(struct tcf_exts *exts) 589 { 590 #ifdef CONFIG_NET_CLS_ACT 591 LIST_HEAD(actions); 592 593 tcf_exts_to_list(exts, &actions); 594 tcf_action_destroy(&actions, TCA_ACT_UNBIND); 595 kfree(exts->actions); 596 exts->nr_actions = 0; 597 #endif 598 } 599 EXPORT_SYMBOL(tcf_exts_destroy); 600 601 int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb, 602 struct nlattr *rate_tlv, struct tcf_exts *exts, bool ovr) 603 { 604 #ifdef CONFIG_NET_CLS_ACT 605 { 606 struct tc_action *act; 607 608 if (exts->police && tb[exts->police]) { 609 act = tcf_action_init_1(net, tb[exts->police], rate_tlv, 610 "police", ovr, TCA_ACT_BIND); 611 if (IS_ERR(act)) 612 return PTR_ERR(act); 613 614 act->type = exts->type = TCA_OLD_COMPAT; 615 exts->actions[0] = act; 616 exts->nr_actions = 1; 617 } else if (exts->action && tb[exts->action]) { 618 LIST_HEAD(actions); 619 int err, i = 0; 620 621 err = tcf_action_init(net, tb[exts->action], rate_tlv, 622 NULL, ovr, TCA_ACT_BIND, 623 &actions); 624 if (err) 625 return err; 626 list_for_each_entry(act, &actions, list) 627 exts->actions[i++] = act; 628 exts->nr_actions = i; 629 } 630 } 631 #else 632 if ((exts->action && tb[exts->action]) || 633 (exts->police && tb[exts->police])) 634 return -EOPNOTSUPP; 635 #endif 636 637 return 0; 638 } 639 EXPORT_SYMBOL(tcf_exts_validate); 640 641 void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst, 642 struct tcf_exts *src) 643 { 644 #ifdef CONFIG_NET_CLS_ACT 645 struct tcf_exts old = *dst; 646 647 tcf_tree_lock(tp); 648 dst->nr_actions = src->nr_actions; 649 dst->actions = src->actions; 650 dst->type = src->type; 651 tcf_tree_unlock(tp); 652 653 tcf_exts_destroy(&old); 654 #endif 655 } 656 EXPORT_SYMBOL(tcf_exts_change); 657 658 #ifdef CONFIG_NET_CLS_ACT 659 static struct tc_action *tcf_exts_first_act(struct tcf_exts *exts) 660 { 661 if (exts->nr_actions == 0) 662 return NULL; 663 else 664 return exts->actions[0]; 665 } 666 #endif 667 668 int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts) 669 { 670 #ifdef CONFIG_NET_CLS_ACT 671 struct nlattr *nest; 672 673 if (exts->action && exts->nr_actions) { 674 /* 675 * again for backward compatible mode - we want 676 * to work with both old and new modes of entering 677 * tc data even if iproute2 was newer - jhs 678 */ 679 if (exts->type != TCA_OLD_COMPAT) { 680 LIST_HEAD(actions); 681 682 nest = nla_nest_start(skb, exts->action); 683 if (nest == NULL) 684 goto nla_put_failure; 685 686 tcf_exts_to_list(exts, &actions); 687 if (tcf_action_dump(skb, &actions, 0, 0) < 0) 688 goto nla_put_failure; 689 nla_nest_end(skb, nest); 690 } else if (exts->police) { 691 struct tc_action *act = tcf_exts_first_act(exts); 692 nest = nla_nest_start(skb, exts->police); 693 if (nest == NULL || !act) 694 goto nla_put_failure; 695 if (tcf_action_dump_old(skb, act, 0, 0) < 0) 696 goto nla_put_failure; 697 nla_nest_end(skb, nest); 698 } 699 } 700 return 0; 701 702 nla_put_failure: 703 nla_nest_cancel(skb, nest); 704 return -1; 705 #else 706 return 0; 707 #endif 708 } 709 EXPORT_SYMBOL(tcf_exts_dump); 710 711 712 int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts) 713 { 714 #ifdef CONFIG_NET_CLS_ACT 715 struct tc_action *a = tcf_exts_first_act(exts); 716 if (a != NULL && tcf_action_copy_stats(skb, a, 1) < 0) 717 return -1; 718 #endif 719 return 0; 720 } 721 EXPORT_SYMBOL(tcf_exts_dump_stats); 722 723 int tcf_exts_get_dev(struct net_device *dev, struct tcf_exts *exts, 724 struct net_device **hw_dev) 725 { 726 #ifdef CONFIG_NET_CLS_ACT 727 const struct tc_action *a; 728 LIST_HEAD(actions); 729 730 if (tc_no_actions(exts)) 731 return -EINVAL; 732 733 tcf_exts_to_list(exts, &actions); 734 list_for_each_entry(a, &actions, list) { 735 if (a->ops->get_dev) { 736 a->ops->get_dev(a, dev_net(dev), hw_dev); 737 break; 738 } 739 } 740 if (*hw_dev) 741 return 0; 742 #endif 743 return -EOPNOTSUPP; 744 } 745 EXPORT_SYMBOL(tcf_exts_get_dev); 746 747 static int __init tc_filter_init(void) 748 { 749 rtnl_register(PF_UNSPEC, RTM_NEWTFILTER, tc_ctl_tfilter, NULL, NULL); 750 rtnl_register(PF_UNSPEC, RTM_DELTFILTER, tc_ctl_tfilter, NULL, NULL); 751 rtnl_register(PF_UNSPEC, RTM_GETTFILTER, tc_ctl_tfilter, 752 tc_dump_tfilter, NULL); 753 754 return 0; 755 } 756 757 subsys_initcall(tc_filter_init); 758