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, bool rtnl_held, 111 struct netlink_ext_ack *extack) 112 { 113 struct basic_head *head = rtnl_dereference(tp->root); 114 struct basic_filter *f, *n; 115 116 list_for_each_entry_safe(f, n, &head->flist, link) { 117 list_del_rcu(&f->link); 118 tcf_unbind_filter(tp, &f->res); 119 idr_remove(&head->handle_idr, f->handle); 120 if (tcf_exts_get_net(&f->exts)) 121 tcf_queue_work(&f->rwork, basic_delete_filter_work); 122 else 123 __basic_delete_filter(f); 124 } 125 idr_destroy(&head->handle_idr); 126 kfree_rcu(head, rcu); 127 } 128 129 static int basic_delete(struct tcf_proto *tp, void *arg, bool *last, 130 bool rtnl_held, struct netlink_ext_ack *extack) 131 { 132 struct basic_head *head = rtnl_dereference(tp->root); 133 struct basic_filter *f = arg; 134 135 list_del_rcu(&f->link); 136 tcf_unbind_filter(tp, &f->res); 137 idr_remove(&head->handle_idr, f->handle); 138 tcf_exts_get_net(&f->exts); 139 tcf_queue_work(&f->rwork, basic_delete_filter_work); 140 *last = list_empty(&head->flist); 141 return 0; 142 } 143 144 static const struct nla_policy basic_policy[TCA_BASIC_MAX + 1] = { 145 [TCA_BASIC_CLASSID] = { .type = NLA_U32 }, 146 [TCA_BASIC_EMATCHES] = { .type = NLA_NESTED }, 147 }; 148 149 static int basic_set_parms(struct net *net, struct tcf_proto *tp, 150 struct basic_filter *f, unsigned long base, 151 struct nlattr **tb, 152 struct nlattr *est, bool ovr, 153 struct netlink_ext_ack *extack) 154 { 155 int err; 156 157 err = tcf_exts_validate(net, tp, tb, est, &f->exts, ovr, true, extack); 158 if (err < 0) 159 return err; 160 161 err = tcf_em_tree_validate(tp, tb[TCA_BASIC_EMATCHES], &f->ematches); 162 if (err < 0) 163 return err; 164 165 if (tb[TCA_BASIC_CLASSID]) { 166 f->res.classid = nla_get_u32(tb[TCA_BASIC_CLASSID]); 167 tcf_bind_filter(tp, &f->res, base); 168 } 169 170 f->tp = tp; 171 return 0; 172 } 173 174 static int basic_change(struct net *net, struct sk_buff *in_skb, 175 struct tcf_proto *tp, unsigned long base, u32 handle, 176 struct nlattr **tca, void **arg, bool ovr, 177 bool rtnl_held, struct netlink_ext_ack *extack) 178 { 179 int err; 180 struct basic_head *head = rtnl_dereference(tp->root); 181 struct nlattr *tb[TCA_BASIC_MAX + 1]; 182 struct basic_filter *fold = (struct basic_filter *) *arg; 183 struct basic_filter *fnew; 184 185 if (tca[TCA_OPTIONS] == NULL) 186 return -EINVAL; 187 188 err = nla_parse_nested(tb, TCA_BASIC_MAX, tca[TCA_OPTIONS], 189 basic_policy, NULL); 190 if (err < 0) 191 return err; 192 193 if (fold != NULL) { 194 if (handle && fold->handle != handle) 195 return -EINVAL; 196 } 197 198 fnew = kzalloc(sizeof(*fnew), GFP_KERNEL); 199 if (!fnew) 200 return -ENOBUFS; 201 202 err = tcf_exts_init(&fnew->exts, net, TCA_BASIC_ACT, TCA_BASIC_POLICE); 203 if (err < 0) 204 goto errout; 205 206 if (!handle) { 207 handle = 1; 208 err = idr_alloc_u32(&head->handle_idr, fnew, &handle, 209 INT_MAX, GFP_KERNEL); 210 } else if (!fold) { 211 err = idr_alloc_u32(&head->handle_idr, fnew, &handle, 212 handle, GFP_KERNEL); 213 } 214 if (err) 215 goto errout; 216 fnew->handle = handle; 217 fnew->pf = alloc_percpu(struct tc_basic_pcnt); 218 if (!fnew->pf) { 219 err = -ENOMEM; 220 goto errout; 221 } 222 223 err = basic_set_parms(net, tp, fnew, base, tb, tca[TCA_RATE], ovr, 224 extack); 225 if (err < 0) { 226 if (!fold) 227 idr_remove(&head->handle_idr, fnew->handle); 228 goto errout; 229 } 230 231 *arg = fnew; 232 233 if (fold) { 234 idr_replace(&head->handle_idr, fnew, fnew->handle); 235 list_replace_rcu(&fold->link, &fnew->link); 236 tcf_unbind_filter(tp, &fold->res); 237 tcf_exts_get_net(&fold->exts); 238 tcf_queue_work(&fold->rwork, basic_delete_filter_work); 239 } else { 240 list_add_rcu(&fnew->link, &head->flist); 241 } 242 243 return 0; 244 errout: 245 free_percpu(fnew->pf); 246 tcf_exts_destroy(&fnew->exts); 247 kfree(fnew); 248 return err; 249 } 250 251 static void basic_walk(struct tcf_proto *tp, struct tcf_walker *arg, 252 bool rtnl_held) 253 { 254 struct basic_head *head = rtnl_dereference(tp->root); 255 struct basic_filter *f; 256 257 list_for_each_entry(f, &head->flist, link) { 258 if (arg->count < arg->skip) 259 goto skip; 260 261 if (arg->fn(tp, f, arg) < 0) { 262 arg->stop = 1; 263 break; 264 } 265 skip: 266 arg->count++; 267 } 268 } 269 270 static void basic_bind_class(void *fh, u32 classid, unsigned long cl) 271 { 272 struct basic_filter *f = fh; 273 274 if (f && f->res.classid == classid) 275 f->res.class = cl; 276 } 277 278 static int basic_dump(struct net *net, struct tcf_proto *tp, void *fh, 279 struct sk_buff *skb, struct tcmsg *t, bool rtnl_held) 280 { 281 struct tc_basic_pcnt gpf = {}; 282 struct basic_filter *f = fh; 283 struct nlattr *nest; 284 int cpu; 285 286 if (f == NULL) 287 return skb->len; 288 289 t->tcm_handle = f->handle; 290 291 nest = nla_nest_start(skb, TCA_OPTIONS); 292 if (nest == NULL) 293 goto nla_put_failure; 294 295 if (f->res.classid && 296 nla_put_u32(skb, TCA_BASIC_CLASSID, f->res.classid)) 297 goto nla_put_failure; 298 299 for_each_possible_cpu(cpu) { 300 struct tc_basic_pcnt *pf = per_cpu_ptr(f->pf, cpu); 301 302 gpf.rcnt += pf->rcnt; 303 gpf.rhit += pf->rhit; 304 } 305 306 if (nla_put_64bit(skb, TCA_BASIC_PCNT, 307 sizeof(struct tc_basic_pcnt), 308 &gpf, TCA_BASIC_PAD)) 309 goto nla_put_failure; 310 311 if (tcf_exts_dump(skb, &f->exts) < 0 || 312 tcf_em_tree_dump(skb, &f->ematches, TCA_BASIC_EMATCHES) < 0) 313 goto nla_put_failure; 314 315 nla_nest_end(skb, nest); 316 317 if (tcf_exts_dump_stats(skb, &f->exts) < 0) 318 goto nla_put_failure; 319 320 return skb->len; 321 322 nla_put_failure: 323 nla_nest_cancel(skb, nest); 324 return -1; 325 } 326 327 static struct tcf_proto_ops cls_basic_ops __read_mostly = { 328 .kind = "basic", 329 .classify = basic_classify, 330 .init = basic_init, 331 .destroy = basic_destroy, 332 .get = basic_get, 333 .change = basic_change, 334 .delete = basic_delete, 335 .walk = basic_walk, 336 .dump = basic_dump, 337 .bind_class = basic_bind_class, 338 .owner = THIS_MODULE, 339 }; 340 341 static int __init init_basic(void) 342 { 343 return register_tcf_proto_ops(&cls_basic_ops); 344 } 345 346 static void __exit exit_basic(void) 347 { 348 unregister_tcf_proto_ops(&cls_basic_ops); 349 } 350 351 module_init(init_basic) 352 module_exit(exit_basic) 353 MODULE_LICENSE("GPL"); 354