]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - net/sched/cls_matchall.c
net: sched: gred: pass the right attribute to gred_change_table_def()
[mirror_ubuntu-bionic-kernel.git] / net / sched / cls_matchall.c
CommitLineData
bf3994d2
JP
1/*
2 * net/sched/cls_matchll.c Match-all classifier
3 *
4 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/kernel.h>
13#include <linux/init.h>
14#include <linux/module.h>
15
16#include <net/sch_generic.h>
17#include <net/pkt_cls.h>
18
fd62d9f5 19struct cls_mall_head {
bf3994d2
JP
20 struct tcf_exts exts;
21 struct tcf_result res;
22 u32 handle;
b87f7936 23 u32 flags;
7afe8e4f 24 struct rcu_work rwork;
bf3994d2
JP
25};
26
27static int mall_classify(struct sk_buff *skb, const struct tcf_proto *tp,
28 struct tcf_result *res)
29{
30 struct cls_mall_head *head = rcu_dereference_bh(tp->root);
bf3994d2 31
fd62d9f5 32 if (tc_skip_sw(head->flags))
b87f7936
YG
33 return -1;
34
3ff4cbec 35 *res = head->res;
fd62d9f5 36 return tcf_exts_exec(skb, &head->exts, res);
bf3994d2
JP
37}
38
39static int mall_init(struct tcf_proto *tp)
40{
bf3994d2
JP
41 return 0;
42}
43
57767e78
CW
44static void __mall_destroy(struct cls_mall_head *head)
45{
46 tcf_exts_destroy(&head->exts);
47 tcf_exts_put_net(&head->exts);
48 kfree(head);
49}
50
df2735ee
CW
51static void mall_destroy_work(struct work_struct *work)
52{
7afe8e4f
CW
53 struct cls_mall_head *head = container_of(to_rcu_work(work),
54 struct cls_mall_head,
55 rwork);
df2735ee 56 rtnl_lock();
57767e78 57 __mall_destroy(head);
df2735ee
CW
58 rtnl_unlock();
59}
60
2447a96f
JP
61static void mall_destroy_hw_filter(struct tcf_proto *tp,
62 struct cls_mall_head *head,
63 unsigned long cookie)
b87f7936 64{
de4784ca 65 struct tc_cls_matchall_offload cls_mall = {};
2447a96f 66 struct tcf_block *block = tp->chain->block;
b87f7936 67
de4784ca 68 tc_cls_common_offload_init(&cls_mall.common, tp);
2447a96f 69 cls_mall.command = TC_CLSMATCHALL_DESTROY;
de4784ca 70 cls_mall.cookie = cookie;
b87f7936 71
2447a96f 72 tc_setup_cb_call(block, NULL, TC_SETUP_CLSMATCHALL, &cls_mall, false);
b87f7936
YG
73}
74
2447a96f
JP
75static int mall_replace_hw_filter(struct tcf_proto *tp,
76 struct cls_mall_head *head,
77 unsigned long cookie)
b87f7936 78{
de4784ca 79 struct tc_cls_matchall_offload cls_mall = {};
2447a96f
JP
80 struct tcf_block *block = tp->chain->block;
81 bool skip_sw = tc_skip_sw(head->flags);
82 int err;
b87f7936 83
de4784ca 84 tc_cls_common_offload_init(&cls_mall.common, tp);
2447a96f
JP
85 cls_mall.command = TC_CLSMATCHALL_REPLACE;
86 cls_mall.exts = &head->exts;
de4784ca 87 cls_mall.cookie = cookie;
b87f7936 88
2447a96f
JP
89 err = tc_setup_cb_call(block, NULL, TC_SETUP_CLSMATCHALL,
90 &cls_mall, skip_sw);
91 if (err < 0) {
92 mall_destroy_hw_filter(tp, head, cookie);
93 return err;
94 } else if (err > 0) {
95 head->flags |= TCA_CLS_FLAGS_IN_HW;
96 }
97
98 if (skip_sw && !(head->flags & TCA_CLS_FLAGS_IN_HW))
99 return -EINVAL;
100
101 return 0;
b87f7936
YG
102}
103
763dbf63 104static void mall_destroy(struct tcf_proto *tp)
bf3994d2
JP
105{
106 struct cls_mall_head *head = rtnl_dereference(tp->root);
107
fd62d9f5 108 if (!head)
763dbf63 109 return;
bf3994d2 110
adc8d0d1
HL
111 tcf_unbind_filter(tp, &head->res);
112
2447a96f 113 if (!tc_skip_hw(head->flags))
fd62d9f5 114 mall_destroy_hw_filter(tp, head, (unsigned long) head);
b87f7936 115
57767e78 116 if (tcf_exts_get_net(&head->exts))
7afe8e4f 117 tcf_queue_work(&head->rwork, mall_destroy_work);
57767e78
CW
118 else
119 __mall_destroy(head);
bf3994d2
JP
120}
121
8113c095 122static void *mall_get(struct tcf_proto *tp, u32 handle)
bf3994d2 123{
8113c095 124 return NULL;
bf3994d2
JP
125}
126
127static const struct nla_policy mall_policy[TCA_MATCHALL_MAX + 1] = {
128 [TCA_MATCHALL_UNSPEC] = { .type = NLA_UNSPEC },
129 [TCA_MATCHALL_CLASSID] = { .type = NLA_U32 },
130};
131
132static int mall_set_parms(struct net *net, struct tcf_proto *tp,
fd62d9f5 133 struct cls_mall_head *head,
bf3994d2
JP
134 unsigned long base, struct nlattr **tb,
135 struct nlattr *est, bool ovr)
136{
bf3994d2
JP
137 int err;
138
a74cb369 139 err = tcf_exts_validate(net, tp, tb, est, &head->exts, ovr);
bf3994d2 140 if (err < 0)
a74cb369 141 return err;
bf3994d2
JP
142
143 if (tb[TCA_MATCHALL_CLASSID]) {
fd62d9f5
YG
144 head->res.classid = nla_get_u32(tb[TCA_MATCHALL_CLASSID]);
145 tcf_bind_filter(tp, &head->res, base);
bf3994d2 146 }
bf3994d2
JP
147 return 0;
148}
149
150static int mall_change(struct net *net, struct sk_buff *in_skb,
151 struct tcf_proto *tp, unsigned long base,
152 u32 handle, struct nlattr **tca,
8113c095 153 void **arg, bool ovr)
bf3994d2
JP
154{
155 struct cls_mall_head *head = rtnl_dereference(tp->root);
bf3994d2 156 struct nlattr *tb[TCA_MATCHALL_MAX + 1];
fd62d9f5 157 struct cls_mall_head *new;
b87f7936 158 u32 flags = 0;
bf3994d2
JP
159 int err;
160
161 if (!tca[TCA_OPTIONS])
162 return -EINVAL;
163
fd62d9f5
YG
164 if (head)
165 return -EEXIST;
bf3994d2 166
fceb6435
JB
167 err = nla_parse_nested(tb, TCA_MATCHALL_MAX, tca[TCA_OPTIONS],
168 mall_policy, NULL);
bf3994d2
JP
169 if (err < 0)
170 return err;
171
b87f7936
YG
172 if (tb[TCA_MATCHALL_FLAGS]) {
173 flags = nla_get_u32(tb[TCA_MATCHALL_FLAGS]);
174 if (!tc_flags_valid(flags))
175 return -EINVAL;
176 }
177
fd62d9f5
YG
178 new = kzalloc(sizeof(*new), GFP_KERNEL);
179 if (!new)
bf3994d2
JP
180 return -ENOBUFS;
181
fb6ad63b 182 err = tcf_exts_init(&new->exts, net, TCA_MATCHALL_ACT, 0);
ec2507d2
YG
183 if (err)
184 goto err_exts_init;
bf3994d2
JP
185
186 if (!handle)
187 handle = 1;
fd62d9f5
YG
188 new->handle = handle;
189 new->flags = flags;
bf3994d2 190
fd62d9f5 191 err = mall_set_parms(net, tp, new, base, tb, tca[TCA_RATE], ovr);
bf3994d2 192 if (err)
ec2507d2 193 goto err_set_parms;
bf3994d2 194
2447a96f 195 if (!tc_skip_hw(new->flags)) {
fd62d9f5 196 err = mall_replace_hw_filter(tp, new, (unsigned long) new);
2447a96f
JP
197 if (err)
198 goto err_replace_hw_filter;
b87f7936 199 }
c7d2b2f5
OG
200
201 if (!tc_in_hw(new->flags))
202 new->flags |= TCA_CLS_FLAGS_NOT_IN_HW;
b87f7936 203
8113c095 204 *arg = head;
fd62d9f5 205 rcu_assign_pointer(tp->root, new);
bf3994d2
JP
206 return 0;
207
ec2507d2
YG
208err_replace_hw_filter:
209err_set_parms:
e2160156 210 tcf_exts_destroy(&new->exts);
ec2507d2 211err_exts_init:
fd62d9f5 212 kfree(new);
bf3994d2
JP
213 return err;
214}
215
8113c095 216static int mall_delete(struct tcf_proto *tp, void *arg, bool *last)
bf3994d2 217{
fd62d9f5 218 return -EOPNOTSUPP;
bf3994d2
JP
219}
220
221static void mall_walk(struct tcf_proto *tp, struct tcf_walker *arg)
222{
223 struct cls_mall_head *head = rtnl_dereference(tp->root);
bf3994d2
JP
224
225 if (arg->count < arg->skip)
226 goto skip;
8113c095 227 if (arg->fn(tp, head, arg) < 0)
bf3994d2
JP
228 arg->stop = 1;
229skip:
230 arg->count++;
231}
232
8113c095 233static int mall_dump(struct net *net, struct tcf_proto *tp, void *fh,
bf3994d2
JP
234 struct sk_buff *skb, struct tcmsg *t)
235{
8113c095 236 struct cls_mall_head *head = fh;
bf3994d2
JP
237 struct nlattr *nest;
238
fd62d9f5 239 if (!head)
bf3994d2
JP
240 return skb->len;
241
fd62d9f5 242 t->tcm_handle = head->handle;
bf3994d2
JP
243
244 nest = nla_nest_start(skb, TCA_OPTIONS);
245 if (!nest)
246 goto nla_put_failure;
247
fd62d9f5
YG
248 if (head->res.classid &&
249 nla_put_u32(skb, TCA_MATCHALL_CLASSID, head->res.classid))
bf3994d2
JP
250 goto nla_put_failure;
251
7a335ada
OG
252 if (head->flags && nla_put_u32(skb, TCA_MATCHALL_FLAGS, head->flags))
253 goto nla_put_failure;
254
fd62d9f5 255 if (tcf_exts_dump(skb, &head->exts))
bf3994d2
JP
256 goto nla_put_failure;
257
258 nla_nest_end(skb, nest);
259
fd62d9f5 260 if (tcf_exts_dump_stats(skb, &head->exts) < 0)
bf3994d2
JP
261 goto nla_put_failure;
262
263 return skb->len;
264
265nla_put_failure:
266 nla_nest_cancel(skb, nest);
267 return -1;
268}
269
07d79fc7
CW
270static void mall_bind_class(void *fh, u32 classid, unsigned long cl)
271{
272 struct cls_mall_head *head = fh;
273
274 if (head && head->res.classid == classid)
275 head->res.class = cl;
276}
277
bf3994d2
JP
278static struct tcf_proto_ops cls_mall_ops __read_mostly = {
279 .kind = "matchall",
280 .classify = mall_classify,
281 .init = mall_init,
282 .destroy = mall_destroy,
283 .get = mall_get,
284 .change = mall_change,
285 .delete = mall_delete,
286 .walk = mall_walk,
287 .dump = mall_dump,
07d79fc7 288 .bind_class = mall_bind_class,
bf3994d2
JP
289 .owner = THIS_MODULE,
290};
291
292static int __init cls_mall_init(void)
293{
294 return register_tcf_proto_ops(&cls_mall_ops);
295}
296
297static void __exit cls_mall_exit(void)
298{
299 unregister_tcf_proto_ops(&cls_mall_ops);
300}
301
302module_init(cls_mall_init);
303module_exit(cls_mall_exit);
304
305MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
306MODULE_DESCRIPTION("Match-all classifier");
307MODULE_LICENSE("GPL v2");