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 <net/netlink.h> 21 #include <net/act_api.h> 22 #include <net/pkt_cls.h> 23 24 struct basic_head { 25 u32 hgenerator; 26 struct list_head flist; 27 struct rcu_head rcu; 28 }; 29 30 struct basic_filter { 31 u32 handle; 32 struct tcf_exts exts; 33 struct tcf_ematch_tree ematches; 34 struct tcf_result res; 35 struct tcf_proto *tp; 36 struct list_head link; 37 struct rcu_head rcu; 38 }; 39 40 static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp, 41 struct tcf_result *res) 42 { 43 int r; 44 struct basic_head *head = rcu_dereference_bh(tp->root); 45 struct basic_filter *f; 46 47 list_for_each_entry_rcu(f, &head->flist, link) { 48 if (!tcf_em_tree_match(skb, &f->ematches, NULL)) 49 continue; 50 *res = f->res; 51 r = tcf_exts_exec(skb, &f->exts, res); 52 if (r < 0) 53 continue; 54 return r; 55 } 56 return -1; 57 } 58 59 static void *basic_get(struct tcf_proto *tp, u32 handle) 60 { 61 struct basic_head *head = rtnl_dereference(tp->root); 62 struct basic_filter *f; 63 64 list_for_each_entry(f, &head->flist, link) { 65 if (f->handle == handle) { 66 return f; 67 } 68 } 69 70 return NULL; 71 } 72 73 static int basic_init(struct tcf_proto *tp) 74 { 75 struct basic_head *head; 76 77 head = kzalloc(sizeof(*head), GFP_KERNEL); 78 if (head == NULL) 79 return -ENOBUFS; 80 INIT_LIST_HEAD(&head->flist); 81 rcu_assign_pointer(tp->root, head); 82 return 0; 83 } 84 85 static void basic_delete_filter(struct rcu_head *head) 86 { 87 struct basic_filter *f = container_of(head, struct basic_filter, rcu); 88 89 tcf_exts_destroy(&f->exts); 90 tcf_em_tree_destroy(&f->ematches); 91 kfree(f); 92 } 93 94 static void basic_destroy(struct tcf_proto *tp) 95 { 96 struct basic_head *head = rtnl_dereference(tp->root); 97 struct basic_filter *f, *n; 98 99 list_for_each_entry_safe(f, n, &head->flist, link) { 100 list_del_rcu(&f->link); 101 tcf_unbind_filter(tp, &f->res); 102 call_rcu(&f->rcu, basic_delete_filter); 103 } 104 kfree_rcu(head, rcu); 105 } 106 107 static int basic_delete(struct tcf_proto *tp, void *arg, bool *last) 108 { 109 struct basic_head *head = rtnl_dereference(tp->root); 110 struct basic_filter *f = arg; 111 112 list_del_rcu(&f->link); 113 tcf_unbind_filter(tp, &f->res); 114 call_rcu(&f->rcu, basic_delete_filter); 115 *last = list_empty(&head->flist); 116 return 0; 117 } 118 119 static const struct nla_policy basic_policy[TCA_BASIC_MAX + 1] = { 120 [TCA_BASIC_CLASSID] = { .type = NLA_U32 }, 121 [TCA_BASIC_EMATCHES] = { .type = NLA_NESTED }, 122 }; 123 124 static int basic_set_parms(struct net *net, struct tcf_proto *tp, 125 struct basic_filter *f, unsigned long base, 126 struct nlattr **tb, 127 struct nlattr *est, bool ovr) 128 { 129 int err; 130 131 err = tcf_exts_validate(net, tp, tb, est, &f->exts, ovr); 132 if (err < 0) 133 return err; 134 135 err = tcf_em_tree_validate(tp, tb[TCA_BASIC_EMATCHES], &f->ematches); 136 if (err < 0) 137 return err; 138 139 if (tb[TCA_BASIC_CLASSID]) { 140 f->res.classid = nla_get_u32(tb[TCA_BASIC_CLASSID]); 141 tcf_bind_filter(tp, &f->res, base); 142 } 143 144 f->tp = tp; 145 return 0; 146 } 147 148 static int basic_change(struct net *net, struct sk_buff *in_skb, 149 struct tcf_proto *tp, unsigned long base, u32 handle, 150 struct nlattr **tca, void **arg, bool ovr) 151 { 152 int err; 153 struct basic_head *head = rtnl_dereference(tp->root); 154 struct nlattr *tb[TCA_BASIC_MAX + 1]; 155 struct basic_filter *fold = (struct basic_filter *) *arg; 156 struct basic_filter *fnew; 157 158 if (tca[TCA_OPTIONS] == NULL) 159 return -EINVAL; 160 161 err = nla_parse_nested(tb, TCA_BASIC_MAX, tca[TCA_OPTIONS], 162 basic_policy, NULL); 163 if (err < 0) 164 return err; 165 166 if (fold != NULL) { 167 if (handle && fold->handle != handle) 168 return -EINVAL; 169 } 170 171 fnew = kzalloc(sizeof(*fnew), GFP_KERNEL); 172 if (!fnew) 173 return -ENOBUFS; 174 175 err = tcf_exts_init(&fnew->exts, TCA_BASIC_ACT, TCA_BASIC_POLICE); 176 if (err < 0) 177 goto errout; 178 179 err = -EINVAL; 180 if (handle) { 181 fnew->handle = handle; 182 } else if (fold) { 183 fnew->handle = fold->handle; 184 } else { 185 unsigned int i = 0x80000000; 186 do { 187 if (++head->hgenerator == 0x7FFFFFFF) 188 head->hgenerator = 1; 189 } while (--i > 0 && basic_get(tp, head->hgenerator)); 190 191 if (i <= 0) { 192 pr_err("Insufficient number of handles\n"); 193 goto errout; 194 } 195 196 fnew->handle = head->hgenerator; 197 } 198 199 err = basic_set_parms(net, tp, fnew, base, tb, tca[TCA_RATE], ovr); 200 if (err < 0) 201 goto errout; 202 203 *arg = fnew; 204 205 if (fold) { 206 list_replace_rcu(&fold->link, &fnew->link); 207 tcf_unbind_filter(tp, &fold->res); 208 call_rcu(&fold->rcu, basic_delete_filter); 209 } else { 210 list_add_rcu(&fnew->link, &head->flist); 211 } 212 213 return 0; 214 errout: 215 tcf_exts_destroy(&fnew->exts); 216 kfree(fnew); 217 return err; 218 } 219 220 static void basic_walk(struct tcf_proto *tp, struct tcf_walker *arg) 221 { 222 struct basic_head *head = rtnl_dereference(tp->root); 223 struct basic_filter *f; 224 225 list_for_each_entry(f, &head->flist, link) { 226 if (arg->count < arg->skip) 227 goto skip; 228 229 if (arg->fn(tp, f, arg) < 0) { 230 arg->stop = 1; 231 break; 232 } 233 skip: 234 arg->count++; 235 } 236 } 237 238 static void basic_bind_class(void *fh, u32 classid, unsigned long cl) 239 { 240 struct basic_filter *f = fh; 241 242 if (f && f->res.classid == classid) 243 f->res.class = cl; 244 } 245 246 static int basic_dump(struct net *net, struct tcf_proto *tp, void *fh, 247 struct sk_buff *skb, struct tcmsg *t) 248 { 249 struct basic_filter *f = fh; 250 struct nlattr *nest; 251 252 if (f == NULL) 253 return skb->len; 254 255 t->tcm_handle = f->handle; 256 257 nest = nla_nest_start(skb, TCA_OPTIONS); 258 if (nest == NULL) 259 goto nla_put_failure; 260 261 if (f->res.classid && 262 nla_put_u32(skb, TCA_BASIC_CLASSID, f->res.classid)) 263 goto nla_put_failure; 264 265 if (tcf_exts_dump(skb, &f->exts) < 0 || 266 tcf_em_tree_dump(skb, &f->ematches, TCA_BASIC_EMATCHES) < 0) 267 goto nla_put_failure; 268 269 nla_nest_end(skb, nest); 270 271 if (tcf_exts_dump_stats(skb, &f->exts) < 0) 272 goto nla_put_failure; 273 274 return skb->len; 275 276 nla_put_failure: 277 nla_nest_cancel(skb, nest); 278 return -1; 279 } 280 281 static struct tcf_proto_ops cls_basic_ops __read_mostly = { 282 .kind = "basic", 283 .classify = basic_classify, 284 .init = basic_init, 285 .destroy = basic_destroy, 286 .get = basic_get, 287 .change = basic_change, 288 .delete = basic_delete, 289 .walk = basic_walk, 290 .dump = basic_dump, 291 .bind_class = basic_bind_class, 292 .owner = THIS_MODULE, 293 }; 294 295 static int __init init_basic(void) 296 { 297 return register_tcf_proto_ops(&cls_basic_ops); 298 } 299 300 static void __exit exit_basic(void) 301 { 302 unregister_tcf_proto_ops(&cls_basic_ops); 303 } 304 305 module_init(init_basic) 306 module_exit(exit_basic) 307 MODULE_LICENSE("GPL"); 308 309