Blame view
net/sched/act_simple.c
6.43 KB
2874c5fd2
|
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
db7530797
|
2 |
/* |
0c6965dd3
|
3 |
* net/sched/act_simple.c Simple example of an action |
db7530797
|
4 |
* |
fa1b1cff3
|
5 |
* Authors: Jamal Hadi Salim (2005-8) |
db7530797
|
6 |
*/ |
cbdbf00aa
|
7 |
#include <linux/module.h> |
5a0e3ad6a
|
8 |
#include <linux/slab.h> |
cbdbf00aa
|
9 |
#include <linux/init.h> |
db7530797
|
10 |
#include <linux/kernel.h> |
db7530797
|
11 12 |
#include <linux/skbuff.h> #include <linux/rtnetlink.h> |
dc5fc579b
|
13 |
#include <net/netlink.h> |
db7530797
|
14 |
#include <net/pkt_sched.h> |
4b006b0c1
|
15 |
#include <net/pkt_cls.h> |
db7530797
|
16 |
|
db7530797
|
17 18 |
#include <linux/tc_act/tc_defact.h> #include <net/tc_act/tc_defact.h> |
c7d03a00b
|
19 |
static unsigned int simp_net_id; |
a85a970af
|
20 |
static struct tc_action_ops act_simp_ops; |
ddf97ccdd
|
21 |
|
fa1b1cff3
|
22 |
#define SIMP_MAX_DATA 32 |
798de374e
|
23 24 |
static int tcf_simp_act(struct sk_buff *skb, const struct tc_action *a, struct tcf_result *res) |
db7530797
|
25 |
{ |
a85a970af
|
26 |
struct tcf_defact *d = to_defact(a); |
db7530797
|
27 |
|
e9ce1cd3c
|
28 |
spin_lock(&d->tcf_lock); |
9c4a4e488
|
29 |
tcf_lastuse_update(&d->tcf_tm); |
bfe0d0298
|
30 |
bstats_update(&d->tcf_bstats, skb); |
db7530797
|
31 |
|
10297b993
|
32 33 34 |
/* print policy string followed by _ then packet count * Example if this was the 3rd packet and the string was "hello" * then it would look like "hello_3" (without quotes) |
cc7ec456f
|
35 |
*/ |
d0083d98f
|
36 37 |
pr_info("simple: %s_%llu ", |
e9ce1cd3c
|
38 39 40 41 |
(char *)d->tcfd_defdata, d->tcf_bstats.packets); spin_unlock(&d->tcf_lock); return d->tcf_action; } |
9a63b255d
|
42 |
static void tcf_simp_release(struct tc_action *a) |
e9ce1cd3c
|
43 |
{ |
86062033f
|
44 |
struct tcf_defact *d = to_defact(a); |
a5b5c958f
|
45 |
kfree(d->tcfd_defdata); |
e9ce1cd3c
|
46 |
} |
8d499533e
|
47 |
static int alloc_defdata(struct tcf_defact *d, const struct nlattr *defdata) |
e9ce1cd3c
|
48 |
{ |
0eff683f7
|
49 |
d->tcfd_defdata = kzalloc(SIMP_MAX_DATA, GFP_KERNEL); |
e9ce1cd3c
|
50 51 |
if (unlikely(!d->tcfd_defdata)) return -ENOMEM; |
8d499533e
|
52 |
nla_strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); |
e9ce1cd3c
|
53 54 |
return 0; } |
4b006b0c1
|
55 56 57 |
static int reset_policy(struct tc_action *a, const struct nlattr *defdata, struct tc_defact *p, struct tcf_proto *tp, struct netlink_ext_ack *extack) |
e9ce1cd3c
|
58 |
{ |
4b006b0c1
|
59 60 61 62 63 64 65 66 |
struct tcf_chain *goto_ch = NULL; struct tcf_defact *d; int err; err = tcf_action_check_ctrlact(p->action, tp, &goto_ch, extack); if (err < 0) return err; d = to_defact(a); |
9d1045ad6
|
67 |
spin_lock_bh(&d->tcf_lock); |
4b006b0c1
|
68 |
goto_ch = tcf_action_set_ctrlact(a, p->action, goto_ch); |
9d1045ad6
|
69 |
memset(d->tcfd_defdata, 0, SIMP_MAX_DATA); |
8d499533e
|
70 |
nla_strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); |
9d1045ad6
|
71 |
spin_unlock_bh(&d->tcf_lock); |
4b006b0c1
|
72 73 74 |
if (goto_ch) tcf_chain_put_by_act(goto_ch); return 0; |
e9ce1cd3c
|
75 |
} |
53b2bf3f8
|
76 77 |
static const struct nla_policy simple_policy[TCA_DEF_MAX + 1] = { [TCA_DEF_PARMS] = { .len = sizeof(struct tc_defact) }, |
fa1b1cff3
|
78 |
[TCA_DEF_DATA] = { .type = NLA_STRING, .len = SIMP_MAX_DATA }, |
53b2bf3f8
|
79 |
}; |
c1b52739e
|
80 |
static int tcf_simp_init(struct net *net, struct nlattr *nla, |
a85a970af
|
81 |
struct nlattr *est, struct tc_action **a, |
789871bb2
|
82 |
int ovr, int bind, bool rtnl_held, |
abbb0d336
|
83 84 |
struct tcf_proto *tp, u32 flags, struct netlink_ext_ack *extack) |
e9ce1cd3c
|
85 |
{ |
ddf97ccdd
|
86 |
struct tc_action_net *tn = net_generic(net, simp_net_id); |
7ba699c60
|
87 |
struct nlattr *tb[TCA_DEF_MAX + 1]; |
4b006b0c1
|
88 |
struct tcf_chain *goto_ch = NULL; |
e9ce1cd3c
|
89 90 |
struct tc_defact *parm; struct tcf_defact *d; |
b2313077e
|
91 92 |
bool exists = false; int ret = 0, err; |
7be8ef2cd
|
93 |
u32 index; |
e9ce1cd3c
|
94 |
|
cee63723b
|
95 |
if (nla == NULL) |
e9ce1cd3c
|
96 |
return -EINVAL; |
8cb081746
|
97 98 |
err = nla_parse_nested_deprecated(tb, TCA_DEF_MAX, nla, simple_policy, NULL); |
cee63723b
|
99 100 |
if (err < 0) return err; |
53b2bf3f8
|
101 |
if (tb[TCA_DEF_PARMS] == NULL) |
e9ce1cd3c
|
102 |
return -EINVAL; |
fa1b1cff3
|
103 |
parm = nla_data(tb[TCA_DEF_PARMS]); |
7be8ef2cd
|
104 105 |
index = parm->index; err = tcf_idr_check_alloc(tn, &index, a, bind); |
0190c1d45
|
106 107 108 |
if (err < 0) return err; exists = err; |
0e5538ab2
|
109 110 111 112 113 |
if (exists && bind) return 0; if (tb[TCA_DEF_DATA] == NULL) { if (exists) |
65a206c01
|
114 |
tcf_idr_release(*a, bind); |
0190c1d45
|
115 |
else |
7be8ef2cd
|
116 |
tcf_idr_cleanup(tn, index); |
0e5538ab2
|
117 118 |
return -EINVAL; } |
0e5538ab2
|
119 |
if (!exists) { |
7be8ef2cd
|
120 |
ret = tcf_idr_create(tn, index, est, a, |
e38226786
|
121 |
&act_simp_ops, bind, false, 0); |
0190c1d45
|
122 |
if (ret) { |
7be8ef2cd
|
123 |
tcf_idr_cleanup(tn, index); |
86062033f
|
124 |
return ret; |
0190c1d45
|
125 |
} |
e9ce1cd3c
|
126 |
|
a85a970af
|
127 |
d = to_defact(*a); |
4b006b0c1
|
128 129 130 131 132 133 134 135 136 137 |
err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); if (err < 0) goto release_idr; err = alloc_defdata(d, tb[TCA_DEF_DATA]); if (err < 0) goto put_chain; tcf_action_set_ctrlact(*a, parm->action, goto_ch); |
e9ce1cd3c
|
138 139 |
ret = ACT_P_CREATED; } else { |
4e8ddd7f1
|
140 |
if (!ovr) { |
4b006b0c1
|
141 142 |
err = -EEXIST; goto release_idr; |
4e8ddd7f1
|
143 |
} |
1a29321ed
|
144 |
|
4b006b0c1
|
145 146 147 |
err = reset_policy(*a, tb[TCA_DEF_DATA], parm, tp, extack); if (err) goto release_idr; |
e9ce1cd3c
|
148 |
} |
e9ce1cd3c
|
149 |
if (ret == ACT_P_CREATED) |
65a206c01
|
150 |
tcf_idr_insert(tn, *a); |
e9ce1cd3c
|
151 |
return ret; |
4b006b0c1
|
152 153 154 155 156 157 |
put_chain: if (goto_ch) tcf_chain_put_by_act(goto_ch); release_idr: tcf_idr_release(*a, bind); return err; |
e9ce1cd3c
|
158 |
} |
cc7ec456f
|
159 160 |
static int tcf_simp_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) |
e9ce1cd3c
|
161 |
{ |
27a884dc3
|
162 |
unsigned char *b = skb_tail_pointer(skb); |
a85a970af
|
163 |
struct tcf_defact *d = to_defact(a); |
1c40be12f
|
164 165 |
struct tc_defact opt = { .index = d->tcf_index, |
036bb4432
|
166 167 |
.refcnt = refcount_read(&d->tcf_refcnt) - ref, .bindcnt = atomic_read(&d->tcf_bindcnt) - bind, |
1c40be12f
|
168 |
}; |
e9ce1cd3c
|
169 |
struct tcf_t t; |
5e48180ed
|
170 171 |
spin_lock_bh(&d->tcf_lock); opt.action = d->tcf_action; |
1b34ec43c
|
172 173 174 |
if (nla_put(skb, TCA_DEF_PARMS, sizeof(opt), &opt) || nla_put_string(skb, TCA_DEF_DATA, d->tcfd_defdata)) goto nla_put_failure; |
48d8ee169
|
175 176 |
tcf_tm_dump(&t, &d->tcf_tm); |
9854518ea
|
177 |
if (nla_put_64bit(skb, TCA_DEF_TM, sizeof(t), &t, TCA_DEF_PAD)) |
1b34ec43c
|
178 |
goto nla_put_failure; |
5e48180ed
|
179 |
spin_unlock_bh(&d->tcf_lock); |
e9ce1cd3c
|
180 |
return skb->len; |
7ba699c60
|
181 |
nla_put_failure: |
5e48180ed
|
182 |
spin_unlock_bh(&d->tcf_lock); |
dc5fc579b
|
183 |
nlmsg_trim(skb, b); |
e9ce1cd3c
|
184 |
return -1; |
db7530797
|
185 |
} |
ddf97ccdd
|
186 187 |
static int tcf_simp_walker(struct net *net, struct sk_buff *skb, struct netlink_callback *cb, int type, |
417801055
|
188 189 |
const struct tc_action_ops *ops, struct netlink_ext_ack *extack) |
ddf97ccdd
|
190 191 |
{ struct tc_action_net *tn = net_generic(net, simp_net_id); |
b36201455
|
192 |
return tcf_generic_walker(tn, skb, cb, type, ops, extack); |
ddf97ccdd
|
193 |
} |
f061b48c1
|
194 |
static int tcf_simp_search(struct net *net, struct tc_action **a, u32 index) |
ddf97ccdd
|
195 196 |
{ struct tc_action_net *tn = net_generic(net, simp_net_id); |
65a206c01
|
197 |
return tcf_idr_search(tn, a, index); |
ddf97ccdd
|
198 |
} |
db7530797
|
199 |
static struct tc_action_ops act_simp_ops = { |
e9ce1cd3c
|
200 |
.kind = "simple", |
eddd2cf19
|
201 |
.id = TCA_ID_SIMP, |
e9ce1cd3c
|
202 |
.owner = THIS_MODULE, |
798de374e
|
203 |
.act = tcf_simp_act, |
e9ce1cd3c
|
204 |
.dump = tcf_simp_dump, |
86062033f
|
205 |
.cleanup = tcf_simp_release, |
e9ce1cd3c
|
206 |
.init = tcf_simp_init, |
ddf97ccdd
|
207 208 |
.walk = tcf_simp_walker, .lookup = tcf_simp_search, |
a85a970af
|
209 |
.size = sizeof(struct tcf_defact), |
ddf97ccdd
|
210 211 212 213 214 |
}; static __net_init int simp_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, simp_net_id); |
981471bd3
|
215 |
return tc_action_net_init(net, tn, &act_simp_ops); |
ddf97ccdd
|
216 |
} |
039af9c66
|
217 |
static void __net_exit simp_exit_net(struct list_head *net_list) |
ddf97ccdd
|
218 |
{ |
039af9c66
|
219 |
tc_action_net_exit(net_list, simp_net_id); |
ddf97ccdd
|
220 221 222 223 |
} static struct pernet_operations simp_net_ops = { .init = simp_init_net, |
039af9c66
|
224 |
.exit_batch = simp_exit_net, |
ddf97ccdd
|
225 226 |
.id = &simp_net_id, .size = sizeof(struct tc_action_net), |
db7530797
|
227 228 229 230 231 232 233 234 |
}; MODULE_AUTHOR("Jamal Hadi Salim(2005)"); MODULE_DESCRIPTION("Simple example action"); MODULE_LICENSE("GPL"); static int __init simp_init_module(void) { |
ddf97ccdd
|
235 |
int ret = tcf_register_action(&act_simp_ops, &simp_net_ops); |
db7530797
|
236 |
if (!ret) |
6ff9c3644
|
237 238 |
pr_info("Simple TC action Loaded "); |
db7530797
|
239 240 241 242 243 |
return ret; } static void __exit simp_cleanup_module(void) { |
ddf97ccdd
|
244 |
tcf_unregister_action(&act_simp_ops, &simp_net_ops); |
db7530797
|
245 246 247 248 |
} module_init(simp_init_module); module_exit(simp_cleanup_module); |