0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/slab.h>
0010 #include <linux/types.h>
0011 #include <linux/kernel.h>
0012 #include <linux/string.h>
0013 #include <linux/errno.h>
0014 #include <linux/rtnetlink.h>
0015 #include <linux/skbuff.h>
0016 #include <linux/idr.h>
0017 #include <linux/percpu.h>
0018 #include <net/netlink.h>
0019 #include <net/act_api.h>
0020 #include <net/pkt_cls.h>
0021
0022 struct basic_head {
0023 struct list_head flist;
0024 struct idr handle_idr;
0025 struct rcu_head rcu;
0026 };
0027
0028 struct basic_filter {
0029 u32 handle;
0030 struct tcf_exts exts;
0031 struct tcf_ematch_tree ematches;
0032 struct tcf_result res;
0033 struct tcf_proto *tp;
0034 struct list_head link;
0035 struct tc_basic_pcnt __percpu *pf;
0036 struct rcu_work rwork;
0037 };
0038
0039 static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp,
0040 struct tcf_result *res)
0041 {
0042 int r;
0043 struct basic_head *head = rcu_dereference_bh(tp->root);
0044 struct basic_filter *f;
0045
0046 list_for_each_entry_rcu(f, &head->flist, link) {
0047 __this_cpu_inc(f->pf->rcnt);
0048 if (!tcf_em_tree_match(skb, &f->ematches, NULL))
0049 continue;
0050 __this_cpu_inc(f->pf->rhit);
0051 *res = f->res;
0052 r = tcf_exts_exec(skb, &f->exts, res);
0053 if (r < 0)
0054 continue;
0055 return r;
0056 }
0057 return -1;
0058 }
0059
0060 static void *basic_get(struct tcf_proto *tp, u32 handle)
0061 {
0062 struct basic_head *head = rtnl_dereference(tp->root);
0063 struct basic_filter *f;
0064
0065 list_for_each_entry(f, &head->flist, link) {
0066 if (f->handle == handle) {
0067 return f;
0068 }
0069 }
0070
0071 return NULL;
0072 }
0073
0074 static int basic_init(struct tcf_proto *tp)
0075 {
0076 struct basic_head *head;
0077
0078 head = kzalloc(sizeof(*head), GFP_KERNEL);
0079 if (head == NULL)
0080 return -ENOBUFS;
0081 INIT_LIST_HEAD(&head->flist);
0082 idr_init(&head->handle_idr);
0083 rcu_assign_pointer(tp->root, head);
0084 return 0;
0085 }
0086
0087 static void __basic_delete_filter(struct basic_filter *f)
0088 {
0089 tcf_exts_destroy(&f->exts);
0090 tcf_em_tree_destroy(&f->ematches);
0091 tcf_exts_put_net(&f->exts);
0092 free_percpu(f->pf);
0093 kfree(f);
0094 }
0095
0096 static void basic_delete_filter_work(struct work_struct *work)
0097 {
0098 struct basic_filter *f = container_of(to_rcu_work(work),
0099 struct basic_filter,
0100 rwork);
0101 rtnl_lock();
0102 __basic_delete_filter(f);
0103 rtnl_unlock();
0104 }
0105
0106 static void basic_destroy(struct tcf_proto *tp, bool rtnl_held,
0107 struct netlink_ext_ack *extack)
0108 {
0109 struct basic_head *head = rtnl_dereference(tp->root);
0110 struct basic_filter *f, *n;
0111
0112 list_for_each_entry_safe(f, n, &head->flist, link) {
0113 list_del_rcu(&f->link);
0114 tcf_unbind_filter(tp, &f->res);
0115 idr_remove(&head->handle_idr, f->handle);
0116 if (tcf_exts_get_net(&f->exts))
0117 tcf_queue_work(&f->rwork, basic_delete_filter_work);
0118 else
0119 __basic_delete_filter(f);
0120 }
0121 idr_destroy(&head->handle_idr);
0122 kfree_rcu(head, rcu);
0123 }
0124
0125 static int basic_delete(struct tcf_proto *tp, void *arg, bool *last,
0126 bool rtnl_held, struct netlink_ext_ack *extack)
0127 {
0128 struct basic_head *head = rtnl_dereference(tp->root);
0129 struct basic_filter *f = arg;
0130
0131 list_del_rcu(&f->link);
0132 tcf_unbind_filter(tp, &f->res);
0133 idr_remove(&head->handle_idr, f->handle);
0134 tcf_exts_get_net(&f->exts);
0135 tcf_queue_work(&f->rwork, basic_delete_filter_work);
0136 *last = list_empty(&head->flist);
0137 return 0;
0138 }
0139
0140 static const struct nla_policy basic_policy[TCA_BASIC_MAX + 1] = {
0141 [TCA_BASIC_CLASSID] = { .type = NLA_U32 },
0142 [TCA_BASIC_EMATCHES] = { .type = NLA_NESTED },
0143 };
0144
0145 static int basic_set_parms(struct net *net, struct tcf_proto *tp,
0146 struct basic_filter *f, unsigned long base,
0147 struct nlattr **tb,
0148 struct nlattr *est, u32 flags,
0149 struct netlink_ext_ack *extack)
0150 {
0151 int err;
0152
0153 err = tcf_exts_validate(net, tp, tb, est, &f->exts, flags, extack);
0154 if (err < 0)
0155 return err;
0156
0157 err = tcf_em_tree_validate(tp, tb[TCA_BASIC_EMATCHES], &f->ematches);
0158 if (err < 0)
0159 return err;
0160
0161 if (tb[TCA_BASIC_CLASSID]) {
0162 f->res.classid = nla_get_u32(tb[TCA_BASIC_CLASSID]);
0163 tcf_bind_filter(tp, &f->res, base);
0164 }
0165
0166 f->tp = tp;
0167 return 0;
0168 }
0169
0170 static int basic_change(struct net *net, struct sk_buff *in_skb,
0171 struct tcf_proto *tp, unsigned long base, u32 handle,
0172 struct nlattr **tca, void **arg,
0173 u32 flags, struct netlink_ext_ack *extack)
0174 {
0175 int err;
0176 struct basic_head *head = rtnl_dereference(tp->root);
0177 struct nlattr *tb[TCA_BASIC_MAX + 1];
0178 struct basic_filter *fold = (struct basic_filter *) *arg;
0179 struct basic_filter *fnew;
0180
0181 if (tca[TCA_OPTIONS] == NULL)
0182 return -EINVAL;
0183
0184 err = nla_parse_nested_deprecated(tb, TCA_BASIC_MAX, tca[TCA_OPTIONS],
0185 basic_policy, NULL);
0186 if (err < 0)
0187 return err;
0188
0189 if (fold != NULL) {
0190 if (handle && fold->handle != handle)
0191 return -EINVAL;
0192 }
0193
0194 fnew = kzalloc(sizeof(*fnew), GFP_KERNEL);
0195 if (!fnew)
0196 return -ENOBUFS;
0197
0198 err = tcf_exts_init(&fnew->exts, net, TCA_BASIC_ACT, TCA_BASIC_POLICE);
0199 if (err < 0)
0200 goto errout;
0201
0202 if (!handle) {
0203 handle = 1;
0204 err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
0205 INT_MAX, GFP_KERNEL);
0206 } else if (!fold) {
0207 err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
0208 handle, GFP_KERNEL);
0209 }
0210 if (err)
0211 goto errout;
0212 fnew->handle = handle;
0213 fnew->pf = alloc_percpu(struct tc_basic_pcnt);
0214 if (!fnew->pf) {
0215 err = -ENOMEM;
0216 goto errout;
0217 }
0218
0219 err = basic_set_parms(net, tp, fnew, base, tb, tca[TCA_RATE], flags,
0220 extack);
0221 if (err < 0) {
0222 if (!fold)
0223 idr_remove(&head->handle_idr, fnew->handle);
0224 goto errout;
0225 }
0226
0227 *arg = fnew;
0228
0229 if (fold) {
0230 idr_replace(&head->handle_idr, fnew, fnew->handle);
0231 list_replace_rcu(&fold->link, &fnew->link);
0232 tcf_unbind_filter(tp, &fold->res);
0233 tcf_exts_get_net(&fold->exts);
0234 tcf_queue_work(&fold->rwork, basic_delete_filter_work);
0235 } else {
0236 list_add_rcu(&fnew->link, &head->flist);
0237 }
0238
0239 return 0;
0240 errout:
0241 free_percpu(fnew->pf);
0242 tcf_exts_destroy(&fnew->exts);
0243 kfree(fnew);
0244 return err;
0245 }
0246
0247 static void basic_walk(struct tcf_proto *tp, struct tcf_walker *arg,
0248 bool rtnl_held)
0249 {
0250 struct basic_head *head = rtnl_dereference(tp->root);
0251 struct basic_filter *f;
0252
0253 list_for_each_entry(f, &head->flist, link) {
0254 if (arg->count < arg->skip)
0255 goto skip;
0256
0257 if (arg->fn(tp, f, arg) < 0) {
0258 arg->stop = 1;
0259 break;
0260 }
0261 skip:
0262 arg->count++;
0263 }
0264 }
0265
0266 static void basic_bind_class(void *fh, u32 classid, unsigned long cl, void *q,
0267 unsigned long base)
0268 {
0269 struct basic_filter *f = fh;
0270
0271 if (f && f->res.classid == classid) {
0272 if (cl)
0273 __tcf_bind_filter(q, &f->res, base);
0274 else
0275 __tcf_unbind_filter(q, &f->res);
0276 }
0277 }
0278
0279 static int basic_dump(struct net *net, struct tcf_proto *tp, void *fh,
0280 struct sk_buff *skb, struct tcmsg *t, bool rtnl_held)
0281 {
0282 struct tc_basic_pcnt gpf = {};
0283 struct basic_filter *f = fh;
0284 struct nlattr *nest;
0285 int cpu;
0286
0287 if (f == NULL)
0288 return skb->len;
0289
0290 t->tcm_handle = f->handle;
0291
0292 nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
0293 if (nest == NULL)
0294 goto nla_put_failure;
0295
0296 if (f->res.classid &&
0297 nla_put_u32(skb, TCA_BASIC_CLASSID, f->res.classid))
0298 goto nla_put_failure;
0299
0300 for_each_possible_cpu(cpu) {
0301 struct tc_basic_pcnt *pf = per_cpu_ptr(f->pf, cpu);
0302
0303 gpf.rcnt += pf->rcnt;
0304 gpf.rhit += pf->rhit;
0305 }
0306
0307 if (nla_put_64bit(skb, TCA_BASIC_PCNT,
0308 sizeof(struct tc_basic_pcnt),
0309 &gpf, TCA_BASIC_PAD))
0310 goto nla_put_failure;
0311
0312 if (tcf_exts_dump(skb, &f->exts) < 0 ||
0313 tcf_em_tree_dump(skb, &f->ematches, TCA_BASIC_EMATCHES) < 0)
0314 goto nla_put_failure;
0315
0316 nla_nest_end(skb, nest);
0317
0318 if (tcf_exts_dump_stats(skb, &f->exts) < 0)
0319 goto nla_put_failure;
0320
0321 return skb->len;
0322
0323 nla_put_failure:
0324 nla_nest_cancel(skb, nest);
0325 return -1;
0326 }
0327
0328 static struct tcf_proto_ops cls_basic_ops __read_mostly = {
0329 .kind = "basic",
0330 .classify = basic_classify,
0331 .init = basic_init,
0332 .destroy = basic_destroy,
0333 .get = basic_get,
0334 .change = basic_change,
0335 .delete = basic_delete,
0336 .walk = basic_walk,
0337 .dump = basic_dump,
0338 .bind_class = basic_bind_class,
0339 .owner = THIS_MODULE,
0340 };
0341
0342 static int __init init_basic(void)
0343 {
0344 return register_tcf_proto_ops(&cls_basic_ops);
0345 }
0346
0347 static void __exit exit_basic(void)
0348 {
0349 unregister_tcf_proto_ops(&cls_basic_ops);
0350 }
0351
0352 module_init(init_basic)
0353 module_exit(exit_basic)
0354 MODULE_LICENSE("GPL");