Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* net/sched/sch_ingress.c - Ingress and clsact qdisc
0003  *
0004  * Authors:     Jamal Hadi Salim 1999
0005  */
0006 
0007 #include <linux/module.h>
0008 #include <linux/types.h>
0009 #include <linux/list.h>
0010 #include <linux/skbuff.h>
0011 #include <linux/rtnetlink.h>
0012 
0013 #include <net/netlink.h>
0014 #include <net/pkt_sched.h>
0015 #include <net/pkt_cls.h>
0016 
0017 struct ingress_sched_data {
0018     struct tcf_block *block;
0019     struct tcf_block_ext_info block_info;
0020     struct mini_Qdisc_pair miniqp;
0021 };
0022 
0023 static struct Qdisc *ingress_leaf(struct Qdisc *sch, unsigned long arg)
0024 {
0025     return NULL;
0026 }
0027 
0028 static unsigned long ingress_find(struct Qdisc *sch, u32 classid)
0029 {
0030     return TC_H_MIN(classid) + 1;
0031 }
0032 
0033 static unsigned long ingress_bind_filter(struct Qdisc *sch,
0034                      unsigned long parent, u32 classid)
0035 {
0036     return ingress_find(sch, classid);
0037 }
0038 
0039 static void ingress_unbind_filter(struct Qdisc *sch, unsigned long cl)
0040 {
0041 }
0042 
0043 static void ingress_walk(struct Qdisc *sch, struct qdisc_walker *walker)
0044 {
0045 }
0046 
0047 static struct tcf_block *ingress_tcf_block(struct Qdisc *sch, unsigned long cl,
0048                        struct netlink_ext_ack *extack)
0049 {
0050     struct ingress_sched_data *q = qdisc_priv(sch);
0051 
0052     return q->block;
0053 }
0054 
0055 static void clsact_chain_head_change(struct tcf_proto *tp_head, void *priv)
0056 {
0057     struct mini_Qdisc_pair *miniqp = priv;
0058 
0059     mini_qdisc_pair_swap(miniqp, tp_head);
0060 };
0061 
0062 static void ingress_ingress_block_set(struct Qdisc *sch, u32 block_index)
0063 {
0064     struct ingress_sched_data *q = qdisc_priv(sch);
0065 
0066     q->block_info.block_index = block_index;
0067 }
0068 
0069 static u32 ingress_ingress_block_get(struct Qdisc *sch)
0070 {
0071     struct ingress_sched_data *q = qdisc_priv(sch);
0072 
0073     return q->block_info.block_index;
0074 }
0075 
0076 static int ingress_init(struct Qdisc *sch, struct nlattr *opt,
0077             struct netlink_ext_ack *extack)
0078 {
0079     struct ingress_sched_data *q = qdisc_priv(sch);
0080     struct net_device *dev = qdisc_dev(sch);
0081     int err;
0082 
0083     net_inc_ingress_queue();
0084 
0085     mini_qdisc_pair_init(&q->miniqp, sch, &dev->miniq_ingress);
0086 
0087     q->block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
0088     q->block_info.chain_head_change = clsact_chain_head_change;
0089     q->block_info.chain_head_change_priv = &q->miniqp;
0090 
0091     err = tcf_block_get_ext(&q->block, sch, &q->block_info, extack);
0092     if (err)
0093         return err;
0094 
0095     mini_qdisc_pair_block_init(&q->miniqp, q->block);
0096 
0097     return 0;
0098 }
0099 
0100 static void ingress_destroy(struct Qdisc *sch)
0101 {
0102     struct ingress_sched_data *q = qdisc_priv(sch);
0103 
0104     tcf_block_put_ext(q->block, sch, &q->block_info);
0105     net_dec_ingress_queue();
0106 }
0107 
0108 static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb)
0109 {
0110     struct nlattr *nest;
0111 
0112     nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
0113     if (nest == NULL)
0114         goto nla_put_failure;
0115 
0116     return nla_nest_end(skb, nest);
0117 
0118 nla_put_failure:
0119     nla_nest_cancel(skb, nest);
0120     return -1;
0121 }
0122 
0123 static const struct Qdisc_class_ops ingress_class_ops = {
0124     .flags      =   QDISC_CLASS_OPS_DOIT_UNLOCKED,
0125     .leaf       =   ingress_leaf,
0126     .find       =   ingress_find,
0127     .walk       =   ingress_walk,
0128     .tcf_block  =   ingress_tcf_block,
0129     .bind_tcf   =   ingress_bind_filter,
0130     .unbind_tcf =   ingress_unbind_filter,
0131 };
0132 
0133 static struct Qdisc_ops ingress_qdisc_ops __read_mostly = {
0134     .cl_ops         =   &ingress_class_ops,
0135     .id         =   "ingress",
0136     .priv_size      =   sizeof(struct ingress_sched_data),
0137     .static_flags       =   TCQ_F_CPUSTATS,
0138     .init           =   ingress_init,
0139     .destroy        =   ingress_destroy,
0140     .dump           =   ingress_dump,
0141     .ingress_block_set  =   ingress_ingress_block_set,
0142     .ingress_block_get  =   ingress_ingress_block_get,
0143     .owner          =   THIS_MODULE,
0144 };
0145 
0146 struct clsact_sched_data {
0147     struct tcf_block *ingress_block;
0148     struct tcf_block *egress_block;
0149     struct tcf_block_ext_info ingress_block_info;
0150     struct tcf_block_ext_info egress_block_info;
0151     struct mini_Qdisc_pair miniqp_ingress;
0152     struct mini_Qdisc_pair miniqp_egress;
0153 };
0154 
0155 static unsigned long clsact_find(struct Qdisc *sch, u32 classid)
0156 {
0157     switch (TC_H_MIN(classid)) {
0158     case TC_H_MIN(TC_H_MIN_INGRESS):
0159     case TC_H_MIN(TC_H_MIN_EGRESS):
0160         return TC_H_MIN(classid);
0161     default:
0162         return 0;
0163     }
0164 }
0165 
0166 static unsigned long clsact_bind_filter(struct Qdisc *sch,
0167                     unsigned long parent, u32 classid)
0168 {
0169     return clsact_find(sch, classid);
0170 }
0171 
0172 static struct tcf_block *clsact_tcf_block(struct Qdisc *sch, unsigned long cl,
0173                       struct netlink_ext_ack *extack)
0174 {
0175     struct clsact_sched_data *q = qdisc_priv(sch);
0176 
0177     switch (cl) {
0178     case TC_H_MIN(TC_H_MIN_INGRESS):
0179         return q->ingress_block;
0180     case TC_H_MIN(TC_H_MIN_EGRESS):
0181         return q->egress_block;
0182     default:
0183         return NULL;
0184     }
0185 }
0186 
0187 static void clsact_ingress_block_set(struct Qdisc *sch, u32 block_index)
0188 {
0189     struct clsact_sched_data *q = qdisc_priv(sch);
0190 
0191     q->ingress_block_info.block_index = block_index;
0192 }
0193 
0194 static void clsact_egress_block_set(struct Qdisc *sch, u32 block_index)
0195 {
0196     struct clsact_sched_data *q = qdisc_priv(sch);
0197 
0198     q->egress_block_info.block_index = block_index;
0199 }
0200 
0201 static u32 clsact_ingress_block_get(struct Qdisc *sch)
0202 {
0203     struct clsact_sched_data *q = qdisc_priv(sch);
0204 
0205     return q->ingress_block_info.block_index;
0206 }
0207 
0208 static u32 clsact_egress_block_get(struct Qdisc *sch)
0209 {
0210     struct clsact_sched_data *q = qdisc_priv(sch);
0211 
0212     return q->egress_block_info.block_index;
0213 }
0214 
0215 static int clsact_init(struct Qdisc *sch, struct nlattr *opt,
0216                struct netlink_ext_ack *extack)
0217 {
0218     struct clsact_sched_data *q = qdisc_priv(sch);
0219     struct net_device *dev = qdisc_dev(sch);
0220     int err;
0221 
0222     net_inc_ingress_queue();
0223     net_inc_egress_queue();
0224 
0225     mini_qdisc_pair_init(&q->miniqp_ingress, sch, &dev->miniq_ingress);
0226 
0227     q->ingress_block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
0228     q->ingress_block_info.chain_head_change = clsact_chain_head_change;
0229     q->ingress_block_info.chain_head_change_priv = &q->miniqp_ingress;
0230 
0231     err = tcf_block_get_ext(&q->ingress_block, sch, &q->ingress_block_info,
0232                 extack);
0233     if (err)
0234         return err;
0235 
0236     mini_qdisc_pair_block_init(&q->miniqp_ingress, q->ingress_block);
0237 
0238     mini_qdisc_pair_init(&q->miniqp_egress, sch, &dev->miniq_egress);
0239 
0240     q->egress_block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS;
0241     q->egress_block_info.chain_head_change = clsact_chain_head_change;
0242     q->egress_block_info.chain_head_change_priv = &q->miniqp_egress;
0243 
0244     return tcf_block_get_ext(&q->egress_block, sch, &q->egress_block_info, extack);
0245 }
0246 
0247 static void clsact_destroy(struct Qdisc *sch)
0248 {
0249     struct clsact_sched_data *q = qdisc_priv(sch);
0250 
0251     tcf_block_put_ext(q->egress_block, sch, &q->egress_block_info);
0252     tcf_block_put_ext(q->ingress_block, sch, &q->ingress_block_info);
0253 
0254     net_dec_ingress_queue();
0255     net_dec_egress_queue();
0256 }
0257 
0258 static const struct Qdisc_class_ops clsact_class_ops = {
0259     .flags      =   QDISC_CLASS_OPS_DOIT_UNLOCKED,
0260     .leaf       =   ingress_leaf,
0261     .find       =   clsact_find,
0262     .walk       =   ingress_walk,
0263     .tcf_block  =   clsact_tcf_block,
0264     .bind_tcf   =   clsact_bind_filter,
0265     .unbind_tcf =   ingress_unbind_filter,
0266 };
0267 
0268 static struct Qdisc_ops clsact_qdisc_ops __read_mostly = {
0269     .cl_ops         =   &clsact_class_ops,
0270     .id         =   "clsact",
0271     .priv_size      =   sizeof(struct clsact_sched_data),
0272     .static_flags       =   TCQ_F_CPUSTATS,
0273     .init           =   clsact_init,
0274     .destroy        =   clsact_destroy,
0275     .dump           =   ingress_dump,
0276     .ingress_block_set  =   clsact_ingress_block_set,
0277     .egress_block_set   =   clsact_egress_block_set,
0278     .ingress_block_get  =   clsact_ingress_block_get,
0279     .egress_block_get   =   clsact_egress_block_get,
0280     .owner          =   THIS_MODULE,
0281 };
0282 
0283 static int __init ingress_module_init(void)
0284 {
0285     int ret;
0286 
0287     ret = register_qdisc(&ingress_qdisc_ops);
0288     if (!ret) {
0289         ret = register_qdisc(&clsact_qdisc_ops);
0290         if (ret)
0291             unregister_qdisc(&ingress_qdisc_ops);
0292     }
0293 
0294     return ret;
0295 }
0296 
0297 static void __exit ingress_module_exit(void)
0298 {
0299     unregister_qdisc(&ingress_qdisc_ops);
0300     unregister_qdisc(&clsact_qdisc_ops);
0301 }
0302 
0303 module_init(ingress_module_init);
0304 module_exit(ingress_module_exit);
0305 
0306 MODULE_ALIAS("sch_clsact");
0307 MODULE_LICENSE("GPL");