root/net/psample/psample.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. psample_group_nl_fill
  2. psample_nl_cmd_get_group_dumpit
  3. psample_group_notify
  4. psample_group_create
  5. psample_group_destroy
  6. psample_group_lookup
  7. psample_group_get
  8. psample_group_take
  9. psample_group_put
  10. psample_sample_packet
  11. psample_module_init
  12. psample_module_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * net/psample/psample.c - Netlink channel for packet sampling
   4  * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com>
   5  */
   6 
   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>
  12 #include <net/sock.h>
  13 #include <net/netlink.h>
  14 #include <net/genetlink.h>
  15 #include <net/psample.h>
  16 #include <linux/spinlock.h>
  17 
  18 #define PSAMPLE_MAX_PACKET_SIZE 0xffff
  19 
  20 static LIST_HEAD(psample_groups_list);
  21 static DEFINE_SPINLOCK(psample_groups_lock);
  22 
  23 /* multicast groups */
  24 enum psample_nl_multicast_groups {
  25         PSAMPLE_NL_MCGRP_CONFIG,
  26         PSAMPLE_NL_MCGRP_SAMPLE,
  27 };
  28 
  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 },
  32 };
  33 
  34 static struct genl_family psample_nl_family __ro_after_init;
  35 
  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,
  39                                  int flags)
  40 {
  41         void *hdr;
  42         int ret;
  43 
  44         hdr = genlmsg_put(msg, portid, seq, &psample_nl_family, flags, cmd);
  45         if (!hdr)
  46                 return -EMSGSIZE;
  47 
  48         ret = nla_put_u32(msg, PSAMPLE_ATTR_SAMPLE_GROUP, group->group_num);
  49         if (ret < 0)
  50                 goto error;
  51 
  52         ret = nla_put_u32(msg, PSAMPLE_ATTR_GROUP_REFCOUNT, group->refcount);
  53         if (ret < 0)
  54                 goto error;
  55 
  56         ret = nla_put_u32(msg, PSAMPLE_ATTR_GROUP_SEQ, group->seq);
  57         if (ret < 0)
  58                 goto error;
  59 
  60         genlmsg_end(msg, hdr);
  61         return 0;
  62 
  63 error:
  64         genlmsg_cancel(msg, hdr);
  65         return -EMSGSIZE;
  66 }
  67 
  68 static int psample_nl_cmd_get_group_dumpit(struct sk_buff *msg,
  69                                            struct netlink_callback *cb)
  70 {
  71         struct psample_group *group;
  72         int start = cb->args[0];
  73         int idx = 0;
  74         int err;
  75 
  76         spin_lock_bh(&psample_groups_lock);
  77         list_for_each_entry(group, &psample_groups_list, list) {
  78                 if (!net_eq(group->net, sock_net(msg->sk)))
  79                         continue;
  80                 if (idx < start) {
  81                         idx++;
  82                         continue;
  83                 }
  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);
  87                 if (err)
  88                         break;
  89                 idx++;
  90         }
  91 
  92         spin_unlock_bh(&psample_groups_lock);
  93         cb->args[0] = idx;
  94         return msg->len;
  95 }
  96 
  97 static const struct genl_ops psample_nl_ops[] = {
  98         {
  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 */
 103         }
 104 };
 105 
 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,
 110         .netnsok        = true,
 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),
 116 };
 117 
 118 static void psample_group_notify(struct psample_group *group,
 119                                  enum psample_command cmd)
 120 {
 121         struct sk_buff *msg;
 122         int err;
 123 
 124         msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
 125         if (!msg)
 126                 return;
 127 
 128         err = psample_group_nl_fill(msg, group, cmd, 0, 0, NLM_F_MULTI);
 129         if (!err)
 130                 genlmsg_multicast_netns(&psample_nl_family, group->net, msg, 0,
 131                                         PSAMPLE_NL_MCGRP_CONFIG, GFP_ATOMIC);
 132         else
 133                 nlmsg_free(msg);
 134 }
 135 
 136 static struct psample_group *psample_group_create(struct net *net,
 137                                                   u32 group_num)
 138 {
 139         struct psample_group *group;
 140 
 141         group = kzalloc(sizeof(*group), GFP_ATOMIC);
 142         if (!group)
 143                 return NULL;
 144 
 145         group->net = net;
 146         group->group_num = group_num;
 147         list_add_tail(&group->list, &psample_groups_list);
 148 
 149         psample_group_notify(group, PSAMPLE_CMD_NEW_GROUP);
 150         return group;
 151 }
 152 
 153 static void psample_group_destroy(struct psample_group *group)
 154 {
 155         psample_group_notify(group, PSAMPLE_CMD_DEL_GROUP);
 156         list_del(&group->list);
 157         kfree_rcu(group, rcu);
 158 }
 159 
 160 static struct psample_group *
 161 psample_group_lookup(struct net *net, u32 group_num)
 162 {
 163         struct psample_group *group;
 164 
 165         list_for_each_entry(group, &psample_groups_list, list)
 166                 if ((group->group_num == group_num) && (group->net == net))
 167                         return group;
 168         return NULL;
 169 }
 170 
 171 struct psample_group *psample_group_get(struct net *net, u32 group_num)
 172 {
 173         struct psample_group *group;
 174 
 175         spin_lock_bh(&psample_groups_lock);
 176 
 177         group = psample_group_lookup(net, group_num);
 178         if (!group) {
 179                 group = psample_group_create(net, group_num);
 180                 if (!group)
 181                         goto out;
 182         }
 183         group->refcount++;
 184 
 185 out:
 186         spin_unlock_bh(&psample_groups_lock);
 187         return group;
 188 }
 189 EXPORT_SYMBOL_GPL(psample_group_get);
 190 
 191 void psample_group_take(struct psample_group *group)
 192 {
 193         spin_lock_bh(&psample_groups_lock);
 194         group->refcount++;
 195         spin_unlock_bh(&psample_groups_lock);
 196 }
 197 EXPORT_SYMBOL_GPL(psample_group_take);
 198 
 199 void psample_group_put(struct psample_group *group)
 200 {
 201         spin_lock_bh(&psample_groups_lock);
 202 
 203         if (--group->refcount == 0)
 204                 psample_group_destroy(group);
 205 
 206         spin_unlock_bh(&psample_groups_lock);
 207 }
 208 EXPORT_SYMBOL_GPL(psample_group_put);
 209 
 210 void psample_sample_packet(struct psample_group *group, struct sk_buff *skb,
 211                            u32 trunc_size, int in_ifindex, int out_ifindex,
 212                            u32 sample_rate)
 213 {
 214         struct sk_buff *nl_skb;
 215         int data_len;
 216         int meta_len;
 217         void *data;
 218         int ret;
 219 
 220         meta_len = (in_ifindex ? nla_total_size(sizeof(u16)) : 0) +
 221                    (out_ifindex ? nla_total_size(sizeof(u16)) : 0) +
 222                    nla_total_size(sizeof(u32)) +        /* sample_rate */
 223                    nla_total_size(sizeof(u32)) +        /* orig_size */
 224                    nla_total_size(sizeof(u32)) +        /* group_num */
 225                    nla_total_size(sizeof(u32));         /* seq */
 226 
 227         data_len = min(skb->len, trunc_size);
 228         if (meta_len + nla_total_size(data_len) > PSAMPLE_MAX_PACKET_SIZE)
 229                 data_len = PSAMPLE_MAX_PACKET_SIZE - meta_len - NLA_HDRLEN
 230                             - NLA_ALIGNTO;
 231 
 232         nl_skb = genlmsg_new(meta_len + nla_total_size(data_len), GFP_ATOMIC);
 233         if (unlikely(!nl_skb))
 234                 return;
 235 
 236         data = genlmsg_put(nl_skb, 0, 0, &psample_nl_family, 0,
 237                            PSAMPLE_CMD_SAMPLE);
 238         if (unlikely(!data))
 239                 goto error;
 240 
 241         if (in_ifindex) {
 242                 ret = nla_put_u16(nl_skb, PSAMPLE_ATTR_IIFINDEX, in_ifindex);
 243                 if (unlikely(ret < 0))
 244                         goto error;
 245         }
 246 
 247         if (out_ifindex) {
 248                 ret = nla_put_u16(nl_skb, PSAMPLE_ATTR_OIFINDEX, out_ifindex);
 249                 if (unlikely(ret < 0))
 250                         goto error;
 251         }
 252 
 253         ret = nla_put_u32(nl_skb, PSAMPLE_ATTR_SAMPLE_RATE, sample_rate);
 254         if (unlikely(ret < 0))
 255                 goto error;
 256 
 257         ret = nla_put_u32(nl_skb, PSAMPLE_ATTR_ORIGSIZE, skb->len);
 258         if (unlikely(ret < 0))
 259                 goto error;
 260 
 261         ret = nla_put_u32(nl_skb, PSAMPLE_ATTR_SAMPLE_GROUP, group->group_num);
 262         if (unlikely(ret < 0))
 263                 goto error;
 264 
 265         ret = nla_put_u32(nl_skb, PSAMPLE_ATTR_GROUP_SEQ, group->seq++);
 266         if (unlikely(ret < 0))
 267                 goto error;
 268 
 269         if (data_len) {
 270                 int nla_len = nla_total_size(data_len);
 271                 struct nlattr *nla;
 272 
 273                 nla = skb_put(nl_skb, nla_len);
 274                 nla->nla_type = PSAMPLE_ATTR_DATA;
 275                 nla->nla_len = nla_attr_size(data_len);
 276 
 277                 if (skb_copy_bits(skb, 0, nla_data(nla), data_len))
 278                         goto error;
 279         }
 280 
 281         genlmsg_end(nl_skb, data);
 282         genlmsg_multicast_netns(&psample_nl_family, group->net, nl_skb, 0,
 283                                 PSAMPLE_NL_MCGRP_SAMPLE, GFP_ATOMIC);
 284 
 285         return;
 286 error:
 287         pr_err_ratelimited("Could not create psample log message\n");
 288         nlmsg_free(nl_skb);
 289 }
 290 EXPORT_SYMBOL_GPL(psample_sample_packet);
 291 
 292 static int __init psample_module_init(void)
 293 {
 294         return genl_register_family(&psample_nl_family);
 295 }
 296 
 297 static void __exit psample_module_exit(void)
 298 {
 299         genl_unregister_family(&psample_nl_family);
 300 }
 301 
 302 module_init(psample_module_init);
 303 module_exit(psample_module_exit);
 304 
 305 MODULE_AUTHOR("Yotam Gigi <yotam.gi@gmail.com>");
 306 MODULE_DESCRIPTION("netlink channel for packet sampling");
 307 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */