2 * net/psample/psample.c - Netlink channel for packet sampling
3 * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com>
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.
10 #include <linux/types.h>
11 #include <linux/kernel.h>
12 #include <linux/skbuff.h>
13 #include <linux/module.h>
14 #include <net/net_namespace.h>
16 #include <net/netlink.h>
17 #include <net/genetlink.h>
18 #include <net/psample.h>
19 #include <linux/spinlock.h>
21 #define PSAMPLE_MAX_PACKET_SIZE 0xffff
23 static LIST_HEAD(psample_groups_list
);
24 static DEFINE_SPINLOCK(psample_groups_lock
);
26 /* multicast groups */
27 enum psample_nl_multicast_groups
{
28 PSAMPLE_NL_MCGRP_CONFIG
,
29 PSAMPLE_NL_MCGRP_SAMPLE
,
32 static const struct genl_multicast_group psample_nl_mcgrps
[] = {
33 [PSAMPLE_NL_MCGRP_CONFIG
] = { .name
= PSAMPLE_NL_MCGRP_CONFIG_NAME
},
34 [PSAMPLE_NL_MCGRP_SAMPLE
] = { .name
= PSAMPLE_NL_MCGRP_SAMPLE_NAME
},
37 static struct genl_family psample_nl_family __ro_after_init
;
39 static int psample_group_nl_fill(struct sk_buff
*msg
,
40 struct psample_group
*group
,
41 enum psample_command cmd
, u32 portid
, u32 seq
,
47 hdr
= genlmsg_put(msg
, portid
, seq
, &psample_nl_family
, flags
, cmd
);
51 ret
= nla_put_u32(msg
, PSAMPLE_ATTR_SAMPLE_GROUP
, group
->group_num
);
55 ret
= nla_put_u32(msg
, PSAMPLE_ATTR_GROUP_REFCOUNT
, group
->refcount
);
59 ret
= nla_put_u32(msg
, PSAMPLE_ATTR_GROUP_SEQ
, group
->seq
);
63 genlmsg_end(msg
, hdr
);
67 genlmsg_cancel(msg
, hdr
);
71 static int psample_nl_cmd_get_group_dumpit(struct sk_buff
*msg
,
72 struct netlink_callback
*cb
)
74 struct psample_group
*group
;
75 int start
= cb
->args
[0];
79 spin_lock(&psample_groups_lock
);
80 list_for_each_entry(group
, &psample_groups_list
, list
) {
81 if (!net_eq(group
->net
, sock_net(msg
->sk
)))
87 err
= psample_group_nl_fill(msg
, group
, PSAMPLE_CMD_NEW_GROUP
,
88 NETLINK_CB(cb
->skb
).portid
,
89 cb
->nlh
->nlmsg_seq
, NLM_F_MULTI
);
95 spin_unlock(&psample_groups_lock
);
100 static const struct genl_ops psample_nl_ops
[] = {
102 .cmd
= PSAMPLE_CMD_GET_GROUP
,
103 .dumpit
= psample_nl_cmd_get_group_dumpit
,
104 /* can be retrieved by unprivileged users */
108 static struct genl_family psample_nl_family __ro_after_init
= {
109 .name
= PSAMPLE_GENL_NAME
,
110 .version
= PSAMPLE_GENL_VERSION
,
111 .maxattr
= PSAMPLE_ATTR_MAX
,
113 .module
= THIS_MODULE
,
114 .mcgrps
= psample_nl_mcgrps
,
115 .ops
= psample_nl_ops
,
116 .n_ops
= ARRAY_SIZE(psample_nl_ops
),
117 .n_mcgrps
= ARRAY_SIZE(psample_nl_mcgrps
),
120 static void psample_group_notify(struct psample_group
*group
,
121 enum psample_command cmd
)
126 msg
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_ATOMIC
);
130 err
= psample_group_nl_fill(msg
, group
, cmd
, 0, 0, NLM_F_MULTI
);
132 genlmsg_multicast_netns(&psample_nl_family
, group
->net
, msg
, 0,
133 PSAMPLE_NL_MCGRP_CONFIG
, GFP_ATOMIC
);
138 static struct psample_group
*psample_group_create(struct net
*net
,
141 struct psample_group
*group
;
143 group
= kzalloc(sizeof(*group
), GFP_ATOMIC
);
148 group
->group_num
= group_num
;
149 list_add_tail(&group
->list
, &psample_groups_list
);
151 psample_group_notify(group
, PSAMPLE_CMD_NEW_GROUP
);
155 static void psample_group_destroy(struct psample_group
*group
)
157 psample_group_notify(group
, PSAMPLE_CMD_DEL_GROUP
);
158 list_del(&group
->list
);
162 static struct psample_group
*
163 psample_group_lookup(struct net
*net
, u32 group_num
)
165 struct psample_group
*group
;
167 list_for_each_entry(group
, &psample_groups_list
, list
)
168 if ((group
->group_num
== group_num
) && (group
->net
== net
))
173 struct psample_group
*psample_group_get(struct net
*net
, u32 group_num
)
175 struct psample_group
*group
;
177 spin_lock(&psample_groups_lock
);
179 group
= psample_group_lookup(net
, group_num
);
181 group
= psample_group_create(net
, group_num
);
188 spin_unlock(&psample_groups_lock
);
191 EXPORT_SYMBOL_GPL(psample_group_get
);
193 void psample_group_put(struct psample_group
*group
)
195 spin_lock(&psample_groups_lock
);
197 if (--group
->refcount
== 0)
198 psample_group_destroy(group
);
200 spin_unlock(&psample_groups_lock
);
202 EXPORT_SYMBOL_GPL(psample_group_put
);
204 void psample_sample_packet(struct psample_group
*group
, struct sk_buff
*skb
,
205 u32 trunc_size
, int in_ifindex
, int out_ifindex
,
208 struct sk_buff
*nl_skb
;
214 meta_len
= (in_ifindex
? nla_total_size(sizeof(u16
)) : 0) +
215 (out_ifindex
? nla_total_size(sizeof(u16
)) : 0) +
216 nla_total_size(sizeof(u32
)) + /* sample_rate */
217 nla_total_size(sizeof(u32
)) + /* orig_size */
218 nla_total_size(sizeof(u32
)) + /* group_num */
219 nla_total_size(sizeof(u32
)); /* seq */
221 data_len
= min(skb
->len
, trunc_size
);
222 if (meta_len
+ nla_total_size(data_len
) > PSAMPLE_MAX_PACKET_SIZE
)
223 data_len
= PSAMPLE_MAX_PACKET_SIZE
- meta_len
- NLA_HDRLEN
226 nl_skb
= genlmsg_new(meta_len
+ data_len
, GFP_ATOMIC
);
227 if (unlikely(!nl_skb
))
230 data
= genlmsg_put(nl_skb
, 0, 0, &psample_nl_family
, 0,
236 ret
= nla_put_u16(nl_skb
, PSAMPLE_ATTR_IIFINDEX
, in_ifindex
);
237 if (unlikely(ret
< 0))
242 ret
= nla_put_u16(nl_skb
, PSAMPLE_ATTR_OIFINDEX
, out_ifindex
);
243 if (unlikely(ret
< 0))
247 ret
= nla_put_u32(nl_skb
, PSAMPLE_ATTR_SAMPLE_RATE
, sample_rate
);
248 if (unlikely(ret
< 0))
251 ret
= nla_put_u32(nl_skb
, PSAMPLE_ATTR_ORIGSIZE
, skb
->len
);
252 if (unlikely(ret
< 0))
255 ret
= nla_put_u32(nl_skb
, PSAMPLE_ATTR_SAMPLE_GROUP
, group
->group_num
);
256 if (unlikely(ret
< 0))
259 ret
= nla_put_u32(nl_skb
, PSAMPLE_ATTR_GROUP_SEQ
, group
->seq
++);
260 if (unlikely(ret
< 0))
264 int nla_len
= nla_total_size(data_len
);
267 nla
= skb_put(nl_skb
, nla_len
);
268 nla
->nla_type
= PSAMPLE_ATTR_DATA
;
269 nla
->nla_len
= nla_attr_size(data_len
);
271 if (skb_copy_bits(skb
, 0, nla_data(nla
), data_len
))
275 genlmsg_end(nl_skb
, data
);
276 genlmsg_multicast_netns(&psample_nl_family
, group
->net
, nl_skb
, 0,
277 PSAMPLE_NL_MCGRP_SAMPLE
, GFP_ATOMIC
);
281 pr_err_ratelimited("Could not create psample log message\n");
284 EXPORT_SYMBOL_GPL(psample_sample_packet
);
286 static int __init
psample_module_init(void)
288 return genl_register_family(&psample_nl_family
);
291 static void __exit
psample_module_exit(void)
293 genl_unregister_family(&psample_nl_family
);
296 module_init(psample_module_init
);
297 module_exit(psample_module_exit
);
299 MODULE_AUTHOR("Yotam Gigi <yotam.gi@gmail.com>");
300 MODULE_DESCRIPTION("netlink channel for packet sampling");
301 MODULE_LICENSE("GPL v2");