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
  21struct ingress_sched_data {
  22        struct tcf_block *block;
  23        struct tcf_block_ext_info block_info;
  24        struct mini_Qdisc_pair miniqp;
  25};
  26
  27static struct Qdisc *ingress_leaf(struct Qdisc *sch, unsigned long arg)
  28{
  29        return NULL;
  30}
  31
  32static unsigned long ingress_find(struct Qdisc *sch, u32 classid)
  33{
  34        return TC_H_MIN(classid) + 1;
  35}
  36
  37static unsigned long ingress_bind_filter(struct Qdisc *sch,
  38                                         unsigned long parent, u32 classid)
  39{
  40        return ingress_find(sch, classid);
  41}
  42
  43static void ingress_unbind_filter(struct Qdisc *sch, unsigned long cl)
  44{
  45}
  46
  47static void ingress_walk(struct Qdisc *sch, struct qdisc_walker *walker)
  48{
  49}
  50
  51static struct tcf_block *ingress_tcf_block(struct Qdisc *sch, unsigned long cl,
  52                                           struct netlink_ext_ack *extack)
  53{
  54        struct ingress_sched_data *q = qdisc_priv(sch);
  55
  56        return q->block;
  57}
  58
  59static void clsact_chain_head_change(struct tcf_proto *tp_head, void *priv)
  60{
  61        struct mini_Qdisc_pair *miniqp = priv;
  62
  63        mini_qdisc_pair_swap(miniqp, tp_head);
  64};
  65
  66static void ingress_ingress_block_set(struct Qdisc *sch, u32 block_index)
  67{
  68        struct ingress_sched_data *q = qdisc_priv(sch);
  69
  70        q->block_info.block_index = block_index;
  71}
  72
  73static u32 ingress_ingress_block_get(struct Qdisc *sch)
  74{
  75        struct ingress_sched_data *q = qdisc_priv(sch);
  76
  77        return q->block_info.block_index;
  78}
  79
  80static int ingress_init(struct Qdisc *sch, struct nlattr *opt,
  81                        struct netlink_ext_ack *extack)
  82{
  83        struct ingress_sched_data *q = qdisc_priv(sch);
  84        struct net_device *dev = qdisc_dev(sch);
  85        int err;
  86
  87        net_inc_ingress_queue();
  88
  89        mini_qdisc_pair_init(&q->miniqp, sch, &dev->miniq_ingress);
  90
  91        q->block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
  92        q->block_info.chain_head_change = clsact_chain_head_change;
  93        q->block_info.chain_head_change_priv = &q->miniqp;
  94
  95        err = tcf_block_get_ext(&q->block, sch, &q->block_info, extack);
  96        if (err)
  97                return err;
  98
  99        mini_qdisc_pair_block_init(&q->miniqp, q->block);
 100
 101        return 0;
 102}
 103
 104static void ingress_destroy(struct Qdisc *sch)
 105{
 106        struct ingress_sched_data *q = qdisc_priv(sch);
 107
 108        tcf_block_put_ext(q->block, sch, &q->block_info);
 109        net_dec_ingress_queue();
 110}
 111
 112static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb)
 113{
 114        struct nlattr *nest;
 115
 116        nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
 117        if (nest == NULL)
 118                goto nla_put_failure;
 119
 120        return nla_nest_end(skb, nest);
 121
 122nla_put_failure:
 123        nla_nest_cancel(skb, nest);
 124        return -1;
 125}
 126
 127static const struct Qdisc_class_ops ingress_class_ops = {
 128        .flags          =       QDISC_CLASS_OPS_DOIT_UNLOCKED,
 129        .leaf           =       ingress_leaf,
 130        .find           =       ingress_find,
 131        .walk           =       ingress_walk,
 132        .tcf_block      =       ingress_tcf_block,
 133        .bind_tcf       =       ingress_bind_filter,
 134        .unbind_tcf     =       ingress_unbind_filter,
 135};
 136
 137static struct Qdisc_ops ingress_qdisc_ops __read_mostly = {
 138        .cl_ops                 =       &ingress_class_ops,
 139        .id                     =       "ingress",
 140        .priv_size              =       sizeof(struct ingress_sched_data),
 141        .static_flags           =       TCQ_F_CPUSTATS,
 142        .init                   =       ingress_init,
 143        .destroy                =       ingress_destroy,
 144        .dump                   =       ingress_dump,
 145        .ingress_block_set      =       ingress_ingress_block_set,
 146        .ingress_block_get      =       ingress_ingress_block_get,
 147        .owner                  =       THIS_MODULE,
 148};
 149
 150struct clsact_sched_data {
 151        struct tcf_block *ingress_block;
 152        struct tcf_block *egress_block;
 153        struct tcf_block_ext_info ingress_block_info;
 154        struct tcf_block_ext_info egress_block_info;
 155        struct mini_Qdisc_pair miniqp_ingress;
 156        struct mini_Qdisc_pair miniqp_egress;
 157};
 158
 159static unsigned long clsact_find(struct Qdisc *sch, u32 classid)
 160{
 161        switch (TC_H_MIN(classid)) {
 162        case TC_H_MIN(TC_H_MIN_INGRESS):
 163        case TC_H_MIN(TC_H_MIN_EGRESS):
 164                return TC_H_MIN(classid);
 165        default:
 166                return 0;
 167        }
 168}
 169
 170static unsigned long clsact_bind_filter(struct Qdisc *sch,
 171                                        unsigned long parent, u32 classid)
 172{
 173        return clsact_find(sch, classid);
 174}
 175
 176static struct tcf_block *clsact_tcf_block(struct Qdisc *sch, unsigned long cl,
 177                                          struct netlink_ext_ack *extack)
 178{
 179        struct clsact_sched_data *q = qdisc_priv(sch);
 180
 181        switch (cl) {
 182        case TC_H_MIN(TC_H_MIN_INGRESS):
 183                return q->ingress_block;
 184        case TC_H_MIN(TC_H_MIN_EGRESS):
 185                return q->egress_block;
 186        default:
 187                return NULL;
 188        }
 189}
 190
 191static void clsact_ingress_block_set(struct Qdisc *sch, u32 block_index)
 192{
 193        struct clsact_sched_data *q = qdisc_priv(sch);
 194
 195        q->ingress_block_info.block_index = block_index;
 196}
 197
 198static void clsact_egress_block_set(struct Qdisc *sch, u32 block_index)
 199{
 200        struct clsact_sched_data *q = qdisc_priv(sch);
 201
 202        q->egress_block_info.block_index = block_index;
 203}
 204
 205static u32 clsact_ingress_block_get(struct Qdisc *sch)
 206{
 207        struct clsact_sched_data *q = qdisc_priv(sch);
 208
 209        return q->ingress_block_info.block_index;
 210}
 211
 212static u32 clsact_egress_block_get(struct Qdisc *sch)
 213{
 214        struct clsact_sched_data *q = qdisc_priv(sch);
 215
 216        return q->egress_block_info.block_index;
 217}
 218
 219static int clsact_init(struct Qdisc *sch, struct nlattr *opt,
 220                       struct netlink_ext_ack *extack)
 221{
 222        struct clsact_sched_data *q = qdisc_priv(sch);
 223        struct net_device *dev = qdisc_dev(sch);
 224        int err;
 225
 226        net_inc_ingress_queue();
 227        net_inc_egress_queue();
 228
 229        mini_qdisc_pair_init(&q->miniqp_ingress, sch, &dev->miniq_ingress);
 230
 231        q->ingress_block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
 232        q->ingress_block_info.chain_head_change = clsact_chain_head_change;
 233        q->ingress_block_info.chain_head_change_priv = &q->miniqp_ingress;
 234
 235        err = tcf_block_get_ext(&q->ingress_block, sch, &q->ingress_block_info,
 236                                extack);
 237        if (err)
 238                return err;
 239
 240        mini_qdisc_pair_block_init(&q->miniqp_ingress, q->ingress_block);
 241
 242        mini_qdisc_pair_init(&q->miniqp_egress, sch, &dev->miniq_egress);
 243
 244        q->egress_block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS;
 245        q->egress_block_info.chain_head_change = clsact_chain_head_change;
 246        q->egress_block_info.chain_head_change_priv = &q->miniqp_egress;
 247
 248        return tcf_block_get_ext(&q->egress_block, sch, &q->egress_block_info, extack);
 249}
 250
 251static void clsact_destroy(struct Qdisc *sch)
 252{
 253        struct clsact_sched_data *q = qdisc_priv(sch);
 254
 255        tcf_block_put_ext(q->egress_block, sch, &q->egress_block_info);
 256        tcf_block_put_ext(q->ingress_block, sch, &q->ingress_block_info);
 257
 258        net_dec_ingress_queue();
 259        net_dec_egress_queue();
 260}
 261
 262static const struct Qdisc_class_ops clsact_class_ops = {
 263        .flags          =       QDISC_CLASS_OPS_DOIT_UNLOCKED,
 264        .leaf           =       ingress_leaf,
 265        .find           =       clsact_find,
 266        .walk           =       ingress_walk,
 267        .tcf_block      =       clsact_tcf_block,
 268        .bind_tcf       =       clsact_bind_filter,
 269        .unbind_tcf     =       ingress_unbind_filter,
 270};
 271
 272static struct Qdisc_ops clsact_qdisc_ops __read_mostly = {
 273        .cl_ops                 =       &clsact_class_ops,
 274        .id                     =       "clsact",
 275        .priv_size              =       sizeof(struct clsact_sched_data),
 276        .static_flags           =       TCQ_F_CPUSTATS,
 277        .init                   =       clsact_init,
 278        .destroy                =       clsact_destroy,
 279        .dump                   =       ingress_dump,
 280        .ingress_block_set      =       clsact_ingress_block_set,
 281        .egress_block_set       =       clsact_egress_block_set,
 282        .ingress_block_get      =       clsact_ingress_block_get,
 283        .egress_block_get       =       clsact_egress_block_get,
 284        .owner                  =       THIS_MODULE,
 285};
 286
 287static int __init ingress_module_init(void)
 288{
 289        int ret;
 290
 291        ret = register_qdisc(&ingress_qdisc_ops);
 292        if (!ret) {
 293                ret = register_qdisc(&clsact_qdisc_ops);
 294                if (ret)
 295                        unregister_qdisc(&ingress_qdisc_ops);
 296        }
 297
 298        return ret;
 299}
 300
 301static void __exit ingress_module_exit(void)
 302{
 303        unregister_qdisc(&ingress_qdisc_ops);
 304        unregister_qdisc(&clsact_qdisc_ops);
 305}
 306
 307module_init(ingress_module_init);
 308module_exit(ingress_module_exit);
 309
 310MODULE_ALIAS("sch_clsact");
 311MODULE_LICENSE("GPL");
 312