1 /* 2 * net/sched/cls_basic.c Basic Packet Classifier. 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: Thomas Graf <tgraf@suug.ch> 10 */ 11 12 #include <linux/module.h> 13 #include <linux/slab.h> 14 #include <linux/types.h> 15 #include <linux/kernel.h> 16 #include <linux/string.h> 17 #include <linux/errno.h> 18 #include <linux/rtnetlink.h> 19 #include <linux/skbuff.h> 20 #include <linux/idr.h> 21 #include <linux/percpu.h> 22 #include <net/netlink.h> 23 #include <net/act_api.h> 24 #include <net/pkt_cls.h> 25 26 struct basic_head { 27 struct list_head flist; 28 struct idr handle_idr; 29 struct rcu_head rcu; 30 }; 31 32 struct basic_filter { 33 u32 handle; 34 struct tcf_exts exts; 35 struct tcf_ematch_tree ematches; 36 struct tcf_result res; 37 struct tcf_proto *tp; 38 struct list_head link; 39 struct tc_basic_pcnt __percpu *pf; 40 struct rcu_work rwork; 41 }; 42 43 static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp, 44 struct tcf_result *res) 45 { 46 int r; 47 struct basic_head *head = rcu_dereference_bh(tp->root); 48 struct basic_filter *f; 49 50 list_for_each_entry_rcu(f, &head->flist, link) { 51 __this_cpu_inc(f->pf->rcnt); 52 if (!tcf_em_tree_match(skb, &f->ematches, NULL)) 53 continue; 54 __this_cpu_inc(f->pf->rhit); 55 *res = f->res; 56 r = tcf_exts_exec(skb, &f->exts, res); 57 if (r < 0) 58 continue; 59 return r; 60 } 61 return -1; 62 } 63 64 static void *basic_get(struct tcf_proto *tp, u32 handle) 65 { 66 struct basic_head *head = rtnl_dereference(tp->root); 67 struct basic_filter *f; 68 69 list_for_each_entry(f, &head->flist, link) { 70 if (f->handle == handle) { 71 return f; 72 } 73 } 74 75 return NULL; 76 } 77 78 static int basic_init(struct tcf_proto *tp) 79 { 80 struct basic_head *head; 81 82 head = kzalloc(sizeof(*head), GFP_KERNEL); 83 if (head == NULL) 84 return -ENOBUFS; 85 INIT_LIST_HEAD(&head->flist); 86 idr_init(&head->handle_idr); 87 rcu_assign_pointer(tp->root, head); 88 return 0; 89 } 90 91 static void __basic_delete_filter(struct basic_filter *f) 92 { 93 tcf_exts_destroy(&f->exts); 94 tcf_em_tree_destroy(&f->ematches); 95 tcf_exts_put_net(&f->exts); 96 free_percpu(f->pf); 97 kfree(f); 98 } 99 100 static void basic_delete_filter_work(struct work_struct *work) 101 { 102 struct basic_filter *f = container_of(to_rcu_work(work), 103 struct basic_filter, 104 rwork); 105 rtnl_lock(); 106 __basic_delete_filter(f); 107 rtnl_unlock(); 108 } 109 110 static void basic_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack) 111 { 112 struct basic_head *head = rtnl_dereference(tp->root); 113 struct basic_filter *f, *n; 114 115 list_for_each_entry_safe(f, n, &head->flist, link) { 116 list_del_rcu(&f->link); 117 tcf_unbind_filter(tp, &f->res); 118 idr_remove(&head->handle_idr, f->handle); 119 if (tcf_exts_get_net(&f->exts)) 120 tcf_queue_work(&f->rwork, basic_delete_filter_work); 121 else 122 __basic_delete_filter(f); 123 } 124 idr_destroy(&head->handle_idr); 125 kfree_rcu(head, rcu); 126 } 127 128 static int basic_delete(struct tcf_proto *tp, void *arg, bool *last, 129 struct netlink_ext_ack *extack) 130 { 131 struct basic_head *head = rtnl_dereference(tp->root); 132 struct basic_filter *f = arg; 133 134 list_del_rcu(&f->link); 135 tcf_unbind_filter(tp, &f->res); 136 idr_remove(&head->handle_idr, f->handle); 137 tcf_exts_get_net(&f->exts); 138 tcf_queue_work(&f->rwork, basic_delete_filter_work); 139 *last = list_empty(&head->flist); 140 return 0; 141 } 142 143 static const struct nla_policy basic_policy[TCA_BASIC_MAX + 1] = { 144 [TCA_BASIC_CLASSID] = { .type = NLA_U32 }, 145 [TCA_BASIC_EMATCHES] = { .type = NLA_NESTED }, 146 }; 147 148 static int basic_set_parms(struct net *net, struct tcf_proto *tp, 149 struct basic_filter *f, unsigned long base, 150 struct nlattr **tb, 151 struct nlattr *est, bool ovr, 152 struct netlink_ext_ack *extack) 153 { 154 int err; 155 156 err = tcf_exts_validate(net, tp, tb, est, &f->exts, ovr, extack); 157 if (err < 0) 158 return err; 159 160 err = tcf_em_tree_validate(tp, tb[TCA_BASIC_EMATCHES], &f->ematches); 161 if (err < 0) 162 return err; 163 164 if (tb[TCA_BASIC_CLASSID]) { 165 f->res.classid = nla_get_u32(tb[TCA_BASIC_CLASSID]); 166 tcf_bind_filter(tp, &f->res, base); 167 } 168 169 f->tp = tp; 170 return 0; 171 } 172 173 static int basic_change(struct net *net, struct sk_buff *in_skb, 174 struct tcf_proto *tp, unsigned long base, u32 handle, 175 struct nlattr **tca, void **arg, bool ovr, 176 struct netlink_ext_ack *extack) 177 { 178 int err; 179 struct basic_head *head = rtnl_dereference(tp->root); 180 struct nlattr *tb[TCA_BASIC_MAX + 1]; 181 struct basic_filter *fold = (struct basic_filter *) *arg; 182 struct basic_filter *fnew; 183 184 if (tca[TCA_OPTIONS] == NULL) 185 return -EINVAL; 186 187 err = nla_parse_nested(tb, TCA_BASIC_MAX, tca[TCA_OPTIONS], 188 basic_policy, NULL); 189 if (err < 0) 190 return err; 191 192 if (fold != NULL) { 193 if (handle && fold->handle != handle) 194 return -EINVAL; 195 } 196 197 fnew = kzalloc(sizeof(*fnew), GFP_KERNEL); 198 if (!fnew) 199 return -ENOBUFS; 200 201 err = tcf_exts_init(&fnew->exts, TCA_BASIC_ACT, TCA_BASIC_POLICE); 202 if (err < 0) 203 goto errout; 204 205 if (!handle) { 206 handle = 1; 207 err = idr_alloc_u32(&head->handle_idr, fnew, &handle, 208 INT_MAX, GFP_KERNEL); 209 } else if (!fold) { 210 err = idr_alloc_u32(&head->handle_idr, fnew, &handle, 211 handle, GFP_KERNEL); 212 } 213 if (err) 214 goto errout; 215 fnew->handle = handle; 216 fnew->pf = alloc_percpu(struct tc_basic_pcnt); 217 if (!fnew->pf) { 218 err = -ENOMEM; 219 goto errout; 220 } 221 222 err = basic_set_parms(net, tp, fnew, base, tb, tca[TCA_RATE], ovr, 223 extack); 224 if (err < 0) { 225 if (!fold) 226 idr_remove(&head->handle_idr, fnew->handle); 227 goto errout; 228 } 229 230 *arg = fnew; 231 232 if (fold) { 233 idr_replace(&head->handle_idr, fnew, fnew->handle); 234 list_replace_rcu(&fold->link, &fnew->link); 235 tcf_unbind_filter(tp, &fold->res); 236 tcf_exts_get_net(&fold->exts); 237 tcf_queue_work(&fold->rwork, basic_delete_filter_work); 238 } else { 239 list_add_rcu(&fnew->link, &head->flist); 240 } 241 242 return 0; 243 errout: 244 free_percpu(fnew->pf); 245 tcf_exts_destroy(&fnew->exts); 246 kfree(fnew); 247 return err; 248 } 249 250 static void basic_walk(struct tcf_proto *tp, struct tcf_walker *arg) 251 { 252 struct basic_head *head = rtnl_dereference(tp->root); 253 struct basic_filter *f; 254 255 list_for_each_entry(f, &head->flist, link) { 256 if (arg->count < arg->skip) 257 goto skip; 258 259 if (arg->fn(tp, f, arg) < 0) { 260 arg->stop = 1; 261 break; 262 } 263 skip: 264 arg->count++; 265 } 266 } 267 268 static void basic_bind_class(void *fh, u32 classid, unsigned long cl) 269 { 270 struct basic_filter *f = fh; 271 272 if (f && f->res.classid == classid) 273 f->res.class = cl; 274 } 275 276 static int basic_dump(struct net *net, struct tcf_proto *tp, void *fh, 277 struct sk_buff *skb, struct tcmsg *t) 278 { 279 struct tc_basic_pcnt gpf = {}; 280 struct basic_filter *f = fh; 281 struct nlattr *nest; 282 int cpu; 283 284 if (f == NULL) 285 return skb->len; 286 287 t->tcm_handle = f->handle; 288 289 nest = nla_nest_start(skb, TCA_OPTIONS); 290 if (nest == NULL) 291 goto nla_put_failure; 292 293 if (f->res.classid && 294 nla_put_u32(skb, TCA_BASIC_CLASSID, f->res.classid)) 295 goto nla_put_failure; 296 297 for_each_possible_cpu(cpu) { 298 struct tc_basic_pcnt *pf = per_cpu_ptr(f->pf, cpu); 299 300 gpf.rcnt += pf->rcnt; 301 gpf.rhit += pf->rhit; 302 } 303 304 if (nla_put_64bit(skb, TCA_BASIC_PCNT, 305 sizeof(struct tc_basic_pcnt), 306 &gpf, TCA_BASIC_PAD)) 307 goto nla_put_failure; 308 309 if (tcf_exts_dump(skb, &f->exts) < 0 || 310 tcf_em_tree_dump(skb, &f->ematches, TCA_BASIC_EMATCHES) < 0) 311 goto nla_put_failure; 312 313 nla_nest_end(skb, nest); 314 315 if (tcf_exts_dump_stats(skb, &f->exts) < 0) 316 goto nla_put_failure; 317 318 return skb->len; 319 320 nla_put_failure: 321 nla_nest_cancel(skb, nest); 322 return -1; 323 } 324 325 static struct tcf_proto_ops cls_basic_ops __read_mostly = { 326 .kind = "basic", 327 .classify = basic_classify, 328 .init = basic_init, 329 .destroy = basic_destroy, 330 .get = basic_get, 331 .change = basic_change, 332 .delete = basic_delete, 333 .walk = basic_walk, 334 .dump = basic_dump, 335 .bind_class = basic_bind_class, 336 .owner = THIS_MODULE, 337 }; 338 339 static int __init init_basic(void) 340 { 341 return register_tcf_proto_ops(&cls_basic_ops); 342 } 343 344 static void __exit exit_basic(void) 345 { 346 unregister_tcf_proto_ops(&cls_basic_ops); 347 } 348 349 module_init(init_basic) 350 module_exit(exit_basic) 351 MODULE_LICENSE("GPL"); 352