1 // SPDX-License-Identifier: GPL-2.0-only
3 * net/psample/psample.c - Netlink channel for packet sampling
4 * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com>
7 #include <linux/types.h>
8 #include <linux/kernel.h>
9 #include <linux/skbuff.h>
10 #include <linux/module.h>
11 #include <net/net_namespace.h>
13 #include <net/netlink.h>
14 #include <net/genetlink.h>
15 #include <net/psample.h>
16 #include <linux/spinlock.h>
18 #define PSAMPLE_MAX_PACKET_SIZE 0xffff
20 static LIST_HEAD(psample_groups_list
);
21 static DEFINE_SPINLOCK(psample_groups_lock
);
23 /* multicast groups */
24 enum psample_nl_multicast_groups
{
25 PSAMPLE_NL_MCGRP_CONFIG
,
26 PSAMPLE_NL_MCGRP_SAMPLE
,
29 static const struct genl_multicast_group psample_nl_mcgrps
[] = {
30 [PSAMPLE_NL_MCGRP_CONFIG
] = { .name
= PSAMPLE_NL_MCGRP_CONFIG_NAME
},
31 [PSAMPLE_NL_MCGRP_SAMPLE
] = { .name
= PSAMPLE_NL_MCGRP_SAMPLE_NAME
},
34 static struct genl_family psample_nl_family __ro_after_init
;
36 static int psample_group_nl_fill(struct sk_buff
*msg
,
37 struct psample_group
*group
,
38 enum psample_command cmd
, u32 portid
, u32 seq
,
44 hdr
= genlmsg_put(msg
, portid
, seq
, &psample_nl_family
, flags
, cmd
);
48 ret
= nla_put_u32(msg
, PSAMPLE_ATTR_SAMPLE_GROUP
, group
->group_num
);
52 ret
= nla_put_u32(msg
, PSAMPLE_ATTR_GROUP_REFCOUNT
, group
->refcount
);
56 ret
= nla_put_u32(msg
, PSAMPLE_ATTR_GROUP_SEQ
, group
->seq
);
60 genlmsg_end(msg
, hdr
);
64 genlmsg_cancel(msg
, hdr
);
68 static int psample_nl_cmd_get_group_dumpit(struct sk_buff
*msg
,
69 struct netlink_callback
*cb
)
71 struct psample_group
*group
;
72 int start
= cb
->args
[0];
76 spin_lock(&psample_groups_lock
);
77 list_for_each_entry(group
, &psample_groups_list
, list
) {
78 if (!net_eq(group
->net
, sock_net(msg
->sk
)))
84 err
= psample_group_nl_fill(msg
, group
, PSAMPLE_CMD_NEW_GROUP
,
85 NETLINK_CB(cb
->skb
).portid
,
86 cb
->nlh
->nlmsg_seq
, NLM_F_MULTI
);
92 spin_unlock(&psample_groups_lock
);
97 static const struct genl_ops psample_nl_ops
[] = {
99 .cmd
= PSAMPLE_CMD_GET_GROUP
,
100 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
101 .dumpit
= psample_nl_cmd_get_group_dumpit
,
102 /* can be retrieved by unprivileged users */
106 static struct genl_family psample_nl_family __ro_after_init
= {
107 .name
= PSAMPLE_GENL_NAME
,
108 .version
= PSAMPLE_GENL_VERSION
,
109 .maxattr
= PSAMPLE_ATTR_MAX
,
111 .module
= THIS_MODULE
,
112 .mcgrps
= psample_nl_mcgrps
,
113 .ops
= psample_nl_ops
,
114 .n_ops
= ARRAY_SIZE(psample_nl_ops
),
115 .n_mcgrps
= ARRAY_SIZE(psample_nl_mcgrps
),
118 static void psample_group_notify(struct psample_group
*group
,
119 enum psample_command cmd
)
124 msg
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_ATOMIC
);
128 err
= psample_group_nl_fill(msg
, group
, cmd
, 0, 0, NLM_F_MULTI
);
130 genlmsg_multicast_netns(&psample_nl_family
, group
->net
, msg
, 0,
131 PSAMPLE_NL_MCGRP_CONFIG
, GFP_ATOMIC
);
136 static struct psample_group
*psample_group_create(struct net
*net
,
139 struct psample_group
*group
;
141 group
= kzalloc(sizeof(*group
), GFP_ATOMIC
);
146 group
->group_num
= group_num
;
147 list_add_tail(&group
->list
, &psample_groups_list
);
149 psample_group_notify(group
, PSAMPLE_CMD_NEW_GROUP
);
153 static void psample_group_destroy(struct psample_group
*group
)
155 psample_group_notify(group
, PSAMPLE_CMD_DEL_GROUP
);
156 list_del(&group
->list
);
157 kfree_rcu(group
, rcu
);
160 static struct psample_group
*
161 psample_group_lookup(struct net
*net
, u32 group_num
)
163 struct psample_group
*group
;
165 list_for_each_entry(group
, &psample_groups_list
, list
)
166 if ((group
->group_num
== group_num
) && (group
->net
== net
))
171 struct psample_group
*psample_group_get(struct net
*net
, u32 group_num
)
173 struct psample_group
*group
;
175 spin_lock(&psample_groups_lock
);
177 group
= psample_group_lookup(net
, group_num
);
179 group
= psample_group_create(net
, group_num
);
186 spin_unlock(&psample_groups_lock
);
189 EXPORT_SYMBOL_GPL(psample_group_get
);
191 void psample_group_put(struct psample_group
*group
)
193 spin_lock(&psample_groups_lock
);
195 if (--group
->refcount
== 0)
196 psample_group_destroy(group
);
198 spin_unlock(&psample_groups_lock
);
200 EXPORT_SYMBOL_GPL(psample_group_put
);
202 void psample_sample_packet(struct psample_group
*group
, struct sk_buff
*skb
,
203 u32 trunc_size
, int in_ifindex
, int out_ifindex
,
206 struct sk_buff
*nl_skb
;
212 meta_len
= (in_ifindex
? nla_total_size(sizeof(u16
)) : 0) +
213 (out_ifindex
? nla_total_size(sizeof(u16
)) : 0) +
214 nla_total_size(sizeof(u32
)) + /* sample_rate */
215 nla_total_size(sizeof(u32
)) + /* orig_size */
216 nla_total_size(sizeof(u32
)) + /* group_num */
217 nla_total_size(sizeof(u32
)); /* seq */
219 data_len
= min(skb
->len
, trunc_size
);
220 if (meta_len
+ nla_total_size(data_len
) > PSAMPLE_MAX_PACKET_SIZE
)
221 data_len
= PSAMPLE_MAX_PACKET_SIZE
- meta_len
- NLA_HDRLEN
224 nl_skb
= genlmsg_new(meta_len
+ data_len
, GFP_ATOMIC
);
225 if (unlikely(!nl_skb
))
228 data
= genlmsg_put(nl_skb
, 0, 0, &psample_nl_family
, 0,
234 ret
= nla_put_u16(nl_skb
, PSAMPLE_ATTR_IIFINDEX
, in_ifindex
);
235 if (unlikely(ret
< 0))
240 ret
= nla_put_u16(nl_skb
, PSAMPLE_ATTR_OIFINDEX
, out_ifindex
);
241 if (unlikely(ret
< 0))
245 ret
= nla_put_u32(nl_skb
, PSAMPLE_ATTR_SAMPLE_RATE
, sample_rate
);
246 if (unlikely(ret
< 0))
249 ret
= nla_put_u32(nl_skb
, PSAMPLE_ATTR_ORIGSIZE
, skb
->len
);
250 if (unlikely(ret
< 0))
253 ret
= nla_put_u32(nl_skb
, PSAMPLE_ATTR_SAMPLE_GROUP
, group
->group_num
);
254 if (unlikely(ret
< 0))
257 ret
= nla_put_u32(nl_skb
, PSAMPLE_ATTR_GROUP_SEQ
, group
->seq
++);
258 if (unlikely(ret
< 0))
262 int nla_len
= nla_total_size(data_len
);
265 nla
= skb_put(nl_skb
, nla_len
);
266 nla
->nla_type
= PSAMPLE_ATTR_DATA
;
267 nla
->nla_len
= nla_attr_size(data_len
);
269 if (skb_copy_bits(skb
, 0, nla_data(nla
), data_len
))
273 genlmsg_end(nl_skb
, data
);
274 genlmsg_multicast_netns(&psample_nl_family
, group
->net
, nl_skb
, 0,
275 PSAMPLE_NL_MCGRP_SAMPLE
, GFP_ATOMIC
);
279 pr_err_ratelimited("Could not create psample log message\n");
282 EXPORT_SYMBOL_GPL(psample_sample_packet
);
284 static int __init
psample_module_init(void)
286 return genl_register_family(&psample_nl_family
);
289 static void __exit
psample_module_exit(void)
291 genl_unregister_family(&psample_nl_family
);
294 module_init(psample_module_init
);
295 module_exit(psample_module_exit
);
297 MODULE_AUTHOR("Yotam Gigi <yotam.gi@gmail.com>");
298 MODULE_DESCRIPTION("netlink channel for packet sampling");
299 MODULE_LICENSE("GPL v2");