linux/net/sched/cls_api.c
<<
>>
Prefs
   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 */
  35static LIST_HEAD(tcf_proto_base);
  36
  37/* Protects list of registered TC modules. It is pure SMP lock. */
  38static DEFINE_RWLOCK(cls_mod_lock);
  39
  40/* Find classifier type by string name */
  41
  42static 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
  62int 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;
  74out:
  75        write_unlock(&cls_mod_lock);
  76        return rc;
  77}
  78EXPORT_SYMBOL(register_tcf_proto_ops);
  79
  80int 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}
 101EXPORT_SYMBOL(unregister_tcf_proto_ops);
 102
 103static 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
 107static 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
 121static 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
 131static 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
 176errout:
 177        kfree(tp);
 178        return ERR_PTR(err);
 179}
 180
 181static 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
 191void 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}
 200EXPORT_SYMBOL(tcf_destroy_chain);
 201
 202/* Add/change/delete/get a filter node */
 203
 204static 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
 229replay:
 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
 416errout:
 417        if (cl)
 418                cops->put(q, cl);
 419        if (err == -EAGAIN)
 420                /* Replay the request. */
 421                goto replay;
 422        return err;
 423}
 424
 425static 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
 454out_nlmsg_trim:
 455nla_put_failure:
 456        nlmsg_trim(skb, b);
 457        return -1;
 458}
 459
 460static 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
 484struct tcf_dump_args {
 485        struct tcf_walker w;
 486        struct sk_buff *skb;
 487        struct netlink_callback *cb;
 488};
 489
 490static 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 */
 502static 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
 581errout:
 582        if (cl)
 583                cops->put(q, cl);
 584out:
 585        return skb->len;
 586}
 587
 588void 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}
 599EXPORT_SYMBOL(tcf_exts_destroy);
 600
 601int 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}
 639EXPORT_SYMBOL(tcf_exts_validate);
 640
 641void 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}
 656EXPORT_SYMBOL(tcf_exts_change);
 657
 658#ifdef CONFIG_NET_CLS_ACT
 659static 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
 668int 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
 702nla_put_failure:
 703        nla_nest_cancel(skb, nest);
 704        return -1;
 705#else
 706        return 0;
 707#endif
 708}
 709EXPORT_SYMBOL(tcf_exts_dump);
 710
 711
 712int 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}
 721EXPORT_SYMBOL(tcf_exts_dump_stats);
 722
 723int 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}
 745EXPORT_SYMBOL(tcf_exts_get_dev);
 746
 747static 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
 757subsys_initcall(tc_filter_init);
 758