GNU Linux-libre 4.14.290-gnu1
[releases.git] / net / sched / act_sample.c
1 /*
2  * net/sched/act_sample.c - Packet sampling tc action
3  * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  */
9
10 #include <linux/types.h>
11 #include <linux/kernel.h>
12 #include <linux/string.h>
13 #include <linux/errno.h>
14 #include <linux/skbuff.h>
15 #include <linux/rtnetlink.h>
16 #include <linux/module.h>
17 #include <linux/init.h>
18 #include <linux/gfp.h>
19 #include <net/net_namespace.h>
20 #include <net/netlink.h>
21 #include <net/pkt_sched.h>
22 #include <linux/tc_act/tc_sample.h>
23 #include <net/tc_act/tc_sample.h>
24 #include <net/psample.h>
25
26 #include <linux/if_arp.h>
27
28 static unsigned int sample_net_id;
29 static struct tc_action_ops act_sample_ops;
30
31 static const struct nla_policy sample_policy[TCA_SAMPLE_MAX + 1] = {
32         [TCA_SAMPLE_PARMS]              = { .len = sizeof(struct tc_sample) },
33         [TCA_SAMPLE_RATE]               = { .type = NLA_U32 },
34         [TCA_SAMPLE_TRUNC_SIZE]         = { .type = NLA_U32 },
35         [TCA_SAMPLE_PSAMPLE_GROUP]      = { .type = NLA_U32 },
36 };
37
38 static int tcf_sample_init(struct net *net, struct nlattr *nla,
39                            struct nlattr *est, struct tc_action **a, int ovr,
40                            int bind)
41 {
42         struct tc_action_net *tn = net_generic(net, sample_net_id);
43         struct nlattr *tb[TCA_SAMPLE_MAX + 1];
44         struct psample_group *psample_group;
45         struct tc_sample *parm;
46         struct tcf_sample *s;
47         bool exists = false;
48         u32 rate;
49         int ret;
50
51         if (!nla)
52                 return -EINVAL;
53         ret = nla_parse_nested(tb, TCA_SAMPLE_MAX, nla, sample_policy, NULL);
54         if (ret < 0)
55                 return ret;
56         if (!tb[TCA_SAMPLE_PARMS] || !tb[TCA_SAMPLE_RATE] ||
57             !tb[TCA_SAMPLE_PSAMPLE_GROUP])
58                 return -EINVAL;
59
60         parm = nla_data(tb[TCA_SAMPLE_PARMS]);
61
62         exists = tcf_idr_check(tn, parm->index, a, bind);
63         if (exists && bind)
64                 return 0;
65
66         if (!exists) {
67                 ret = tcf_idr_create(tn, parm->index, est, a,
68                                      &act_sample_ops, bind, true);
69                 if (ret)
70                         return ret;
71                 ret = ACT_P_CREATED;
72         } else {
73                 tcf_idr_release(*a, bind);
74                 if (!ovr)
75                         return -EEXIST;
76         }
77
78         rate = nla_get_u32(tb[TCA_SAMPLE_RATE]);
79         if (!rate) {
80                 tcf_idr_release(*a, bind);
81                 return -EINVAL;
82         }
83
84         s = to_sample(*a);
85         s->tcf_action = parm->action;
86         s->rate = nla_get_u32(tb[TCA_SAMPLE_RATE]);
87         s->rate = rate;
88         s->psample_group_num = nla_get_u32(tb[TCA_SAMPLE_PSAMPLE_GROUP]);
89         psample_group = psample_group_get(net, s->psample_group_num);
90         if (!psample_group) {
91                 if (ret == ACT_P_CREATED)
92                         tcf_idr_release(*a, bind);
93                 return -ENOMEM;
94         }
95         rcu_swap_protected(s->psample_group, psample_group,
96                            lockdep_is_held(&s->tcf_lock));
97
98         if (tb[TCA_SAMPLE_TRUNC_SIZE]) {
99                 s->truncate = true;
100                 s->trunc_size = nla_get_u32(tb[TCA_SAMPLE_TRUNC_SIZE]);
101         }
102
103         if (psample_group)
104                 psample_group_put(psample_group);
105         if (ret == ACT_P_CREATED)
106                 tcf_idr_insert(tn, *a);
107         return ret;
108 }
109
110 static void tcf_sample_cleanup_rcu(struct rcu_head *rcu)
111 {
112         struct tcf_sample *s = container_of(rcu, struct tcf_sample, rcu);
113         struct psample_group *psample_group;
114
115         psample_group = rcu_dereference_protected(s->psample_group, 1);
116         RCU_INIT_POINTER(s->psample_group, NULL);
117         if (psample_group)
118                 psample_group_put(psample_group);
119 }
120
121 static void tcf_sample_cleanup(struct tc_action *a, int bind)
122 {
123         struct tcf_sample *s = to_sample(a);
124
125         call_rcu(&s->rcu, tcf_sample_cleanup_rcu);
126 }
127
128 static bool tcf_sample_dev_ok_push(struct net_device *dev)
129 {
130         switch (dev->type) {
131         case ARPHRD_TUNNEL:
132         case ARPHRD_TUNNEL6:
133         case ARPHRD_SIT:
134         case ARPHRD_IPGRE:
135         case ARPHRD_IP6GRE:
136         case ARPHRD_VOID:
137         case ARPHRD_NONE:
138                 return false;
139         default:
140                 return true;
141         }
142 }
143
144 static int tcf_sample_act(struct sk_buff *skb, const struct tc_action *a,
145                           struct tcf_result *res)
146 {
147         struct tcf_sample *s = to_sample(a);
148         struct psample_group *psample_group;
149         int retval;
150         int size;
151         int iif;
152         int oif;
153
154         tcf_lastuse_update(&s->tcf_tm);
155         bstats_cpu_update(this_cpu_ptr(s->common.cpu_bstats), skb);
156         retval = READ_ONCE(s->tcf_action);
157
158         rcu_read_lock();
159         psample_group = rcu_dereference(s->psample_group);
160
161         /* randomly sample packets according to rate */
162         if (psample_group && (prandom_u32() % s->rate == 0)) {
163                 if (!skb_at_tc_ingress(skb)) {
164                         iif = skb->skb_iif;
165                         oif = skb->dev->ifindex;
166                 } else {
167                         iif = skb->dev->ifindex;
168                         oif = 0;
169                 }
170
171                 /* on ingress, the mac header gets popped, so push it back */
172                 if (skb_at_tc_ingress(skb) && tcf_sample_dev_ok_push(skb->dev))
173                         skb_push(skb, skb->mac_len);
174
175                 size = s->truncate ? s->trunc_size : skb->len;
176                 psample_sample_packet(psample_group, skb, size, iif, oif,
177                                       s->rate);
178
179                 if (skb_at_tc_ingress(skb) && tcf_sample_dev_ok_push(skb->dev))
180                         skb_pull(skb, skb->mac_len);
181         }
182
183         rcu_read_unlock();
184         return retval;
185 }
186
187 static int tcf_sample_dump(struct sk_buff *skb, struct tc_action *a,
188                            int bind, int ref)
189 {
190         unsigned char *b = skb_tail_pointer(skb);
191         struct tcf_sample *s = to_sample(a);
192         struct tc_sample opt = {
193                 .index      = s->tcf_index,
194                 .action     = s->tcf_action,
195                 .refcnt     = s->tcf_refcnt - ref,
196                 .bindcnt    = s->tcf_bindcnt - bind,
197         };
198         struct tcf_t t;
199
200         if (nla_put(skb, TCA_SAMPLE_PARMS, sizeof(opt), &opt))
201                 goto nla_put_failure;
202
203         tcf_tm_dump(&t, &s->tcf_tm);
204         if (nla_put_64bit(skb, TCA_SAMPLE_TM, sizeof(t), &t, TCA_SAMPLE_PAD))
205                 goto nla_put_failure;
206
207         if (nla_put_u32(skb, TCA_SAMPLE_RATE, s->rate))
208                 goto nla_put_failure;
209
210         if (s->truncate)
211                 if (nla_put_u32(skb, TCA_SAMPLE_TRUNC_SIZE, s->trunc_size))
212                         goto nla_put_failure;
213
214         if (nla_put_u32(skb, TCA_SAMPLE_PSAMPLE_GROUP, s->psample_group_num))
215                 goto nla_put_failure;
216         return skb->len;
217
218 nla_put_failure:
219         nlmsg_trim(skb, b);
220         return -1;
221 }
222
223 static int tcf_sample_walker(struct net *net, struct sk_buff *skb,
224                              struct netlink_callback *cb, int type,
225                              const struct tc_action_ops *ops)
226 {
227         struct tc_action_net *tn = net_generic(net, sample_net_id);
228
229         return tcf_generic_walker(tn, skb, cb, type, ops);
230 }
231
232 static int tcf_sample_search(struct net *net, struct tc_action **a, u32 index)
233 {
234         struct tc_action_net *tn = net_generic(net, sample_net_id);
235
236         return tcf_idr_search(tn, a, index);
237 }
238
239 static struct tc_action_ops act_sample_ops = {
240         .kind     = "sample",
241         .type     = TCA_ACT_SAMPLE,
242         .owner    = THIS_MODULE,
243         .act      = tcf_sample_act,
244         .dump     = tcf_sample_dump,
245         .init     = tcf_sample_init,
246         .cleanup  = tcf_sample_cleanup,
247         .walk     = tcf_sample_walker,
248         .lookup   = tcf_sample_search,
249         .size     = sizeof(struct tcf_sample),
250 };
251
252 static __net_init int sample_init_net(struct net *net)
253 {
254         struct tc_action_net *tn = net_generic(net, sample_net_id);
255
256         return tc_action_net_init(net, tn, &act_sample_ops);
257 }
258
259 static void __net_exit sample_exit_net(struct net *net)
260 {
261         struct tc_action_net *tn = net_generic(net, sample_net_id);
262
263         tc_action_net_exit(tn);
264 }
265
266 static struct pernet_operations sample_net_ops = {
267         .init = sample_init_net,
268         .exit = sample_exit_net,
269         .id   = &sample_net_id,
270         .size = sizeof(struct tc_action_net),
271 };
272
273 static int __init sample_init_module(void)
274 {
275         return tcf_register_action(&act_sample_ops, &sample_net_ops);
276 }
277
278 static void __exit sample_cleanup_module(void)
279 {
280         rcu_barrier();
281         tcf_unregister_action(&act_sample_ops, &sample_net_ops);
282 }
283
284 module_init(sample_init_module);
285 module_exit(sample_cleanup_module);
286
287 MODULE_AUTHOR("Yotam Gigi <yotam.gi@gmail.com>");
288 MODULE_DESCRIPTION("Packet sampling action");
289 MODULE_LICENSE("GPL v2");