linux/net/sched/sch_ingress.c
<<
>>
Prefs
   1/* net/sched/sch_ingress.c - Ingress and clsact qdisc
   2 *
   3 *              This program is free software; you can redistribute it and/or
   4 *              modify it under the terms of the GNU General Public License
   5 *              as published by the Free Software Foundation; either version
   6 *              2 of the License, or (at your option) any later version.
   7 *
   8 * Authors:     Jamal Hadi Salim 1999
   9 */
  10
  11#include <linux/module.h>
  12#include <linux/types.h>
  13#include <linux/list.h>
  14#include <linux/skbuff.h>
  15#include <linux/rtnetlink.h>
  16
  17#include <net/netlink.h>
  18#include <net/pkt_sched.h>
  19#include <net/pkt_cls.h>
  20
  21static struct Qdisc *ingress_leaf(struct Qdisc *sch, unsigned long arg)
  22{
  23        return NULL;
  24}
  25
  26static unsigned long ingress_get(struct Qdisc *sch, u32 classid)
  27{
  28        return TC_H_MIN(classid) + 1;
  29}
  30
  31static bool ingress_cl_offload(u32 classid)
  32{
  33        return true;
  34}
  35
  36static unsigned long ingress_bind_filter(struct Qdisc *sch,
  37                                         unsigned long parent, u32 classid)
  38{
  39        return ingress_get(sch, classid);
  40}
  41
  42static void ingress_put(struct Qdisc *sch, unsigned long cl)
  43{
  44}
  45
  46static void ingress_walk(struct Qdisc *sch, struct qdisc_walker *walker)
  47{
  48}
  49
  50static struct tcf_proto __rcu **ingress_find_tcf(struct Qdisc *sch,
  51                                                 unsigned long cl)
  52{
  53        struct net_device *dev = qdisc_dev(sch);
  54
  55        return &dev->ingress_cl_list;
  56}
  57
  58static int ingress_init(struct Qdisc *sch, struct nlattr *opt)
  59{
  60        net_inc_ingress_queue();
  61        sch->flags |= TCQ_F_CPUSTATS;
  62
  63        return 0;
  64}
  65
  66static void ingress_destroy(struct Qdisc *sch)
  67{
  68        struct net_device *dev = qdisc_dev(sch);
  69
  70        tcf_destroy_chain(&dev->ingress_cl_list);
  71        net_dec_ingress_queue();
  72}
  73
  74static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb)
  75{
  76        struct nlattr *nest;
  77
  78        nest = nla_nest_start(skb, TCA_OPTIONS);
  79        if (nest == NULL)
  80                goto nla_put_failure;
  81
  82        return nla_nest_end(skb, nest);
  83
  84nla_put_failure:
  85        nla_nest_cancel(skb, nest);
  86        return -1;
  87}
  88
  89static const struct Qdisc_class_ops ingress_class_ops = {
  90        .leaf           =       ingress_leaf,
  91        .get            =       ingress_get,
  92        .put            =       ingress_put,
  93        .walk           =       ingress_walk,
  94        .tcf_chain      =       ingress_find_tcf,
  95        .tcf_cl_offload =       ingress_cl_offload,
  96        .bind_tcf       =       ingress_bind_filter,
  97        .unbind_tcf     =       ingress_put,
  98};
  99
 100static struct Qdisc_ops ingress_qdisc_ops __read_mostly = {
 101        .cl_ops         =       &ingress_class_ops,
 102        .id             =       "ingress",
 103        .init           =       ingress_init,
 104        .destroy        =       ingress_destroy,
 105        .dump           =       ingress_dump,
 106        .owner          =       THIS_MODULE,
 107};
 108
 109static unsigned long clsact_get(struct Qdisc *sch, u32 classid)
 110{
 111        switch (TC_H_MIN(classid)) {
 112        case TC_H_MIN(TC_H_MIN_INGRESS):
 113        case TC_H_MIN(TC_H_MIN_EGRESS):
 114                return TC_H_MIN(classid);
 115        default:
 116                return 0;
 117        }
 118}
 119
 120static bool clsact_cl_offload(u32 classid)
 121{
 122        return TC_H_MIN(classid) == TC_H_MIN(TC_H_MIN_INGRESS);
 123}
 124
 125static unsigned long clsact_bind_filter(struct Qdisc *sch,
 126                                        unsigned long parent, u32 classid)
 127{
 128        return clsact_get(sch, classid);
 129}
 130
 131static struct tcf_proto __rcu **clsact_find_tcf(struct Qdisc *sch,
 132                                                unsigned long cl)
 133{
 134        struct net_device *dev = qdisc_dev(sch);
 135
 136        switch (cl) {
 137        case TC_H_MIN(TC_H_MIN_INGRESS):
 138                return &dev->ingress_cl_list;
 139        case TC_H_MIN(TC_H_MIN_EGRESS):
 140                return &dev->egress_cl_list;
 141        default:
 142                return NULL;
 143        }
 144}
 145
 146static int clsact_init(struct Qdisc *sch, struct nlattr *opt)
 147{
 148        net_inc_ingress_queue();
 149        net_inc_egress_queue();
 150
 151        sch->flags |= TCQ_F_CPUSTATS;
 152
 153        return 0;
 154}
 155
 156static void clsact_destroy(struct Qdisc *sch)
 157{
 158        struct net_device *dev = qdisc_dev(sch);
 159
 160        tcf_destroy_chain(&dev->ingress_cl_list);
 161        tcf_destroy_chain(&dev->egress_cl_list);
 162
 163        net_dec_ingress_queue();
 164        net_dec_egress_queue();
 165}
 166
 167static const struct Qdisc_class_ops clsact_class_ops = {
 168        .leaf           =       ingress_leaf,
 169        .get            =       clsact_get,
 170        .put            =       ingress_put,
 171        .walk           =       ingress_walk,
 172        .tcf_chain      =       clsact_find_tcf,
 173        .tcf_cl_offload =       clsact_cl_offload,
 174        .bind_tcf       =       clsact_bind_filter,
 175        .unbind_tcf     =       ingress_put,
 176};
 177
 178static struct Qdisc_ops clsact_qdisc_ops __read_mostly = {
 179        .cl_ops         =       &clsact_class_ops,
 180        .id             =       "clsact",
 181        .init           =       clsact_init,
 182        .destroy        =       clsact_destroy,
 183        .dump           =       ingress_dump,
 184        .owner          =       THIS_MODULE,
 185};
 186
 187static int __init ingress_module_init(void)
 188{
 189        int ret;
 190
 191        ret = register_qdisc(&ingress_qdisc_ops);
 192        if (!ret) {
 193                ret = register_qdisc(&clsact_qdisc_ops);
 194                if (ret)
 195                        unregister_qdisc(&ingress_qdisc_ops);
 196        }
 197
 198        return ret;
 199}
 200
 201static void __exit ingress_module_exit(void)
 202{
 203        unregister_qdisc(&ingress_qdisc_ops);
 204        unregister_qdisc(&clsact_qdisc_ops);
 205}
 206
 207module_init(ingress_module_init);
 208module_exit(ingress_module_exit);
 209
 210MODULE_ALIAS("sch_clsact");
 211MODULE_LICENSE("GPL");
 212