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