blob: a0baf56f5826b90667fbe6e17841b6f98ad96eaf [file] [log] [blame]
Daniel Borkmanne4fc4082013-06-21 19:38:08 +02001#include <linux/module.h>
2#include <linux/kernel.h>
3#include <linux/netdevice.h>
4#include <linux/netlink.h>
5#include <net/net_namespace.h>
6#include <linux/if_arp.h>
7
8struct pcpu_lstats {
9 u64 packets;
10 u64 bytes;
11 struct u64_stats_sync syncp;
12};
13
14static netdev_tx_t nlmon_xmit(struct sk_buff *skb, struct net_device *dev)
15{
16 int len = skb->len;
17 struct pcpu_lstats *stats = this_cpu_ptr(dev->lstats);
18
19 u64_stats_update_begin(&stats->syncp);
20 stats->bytes += len;
21 stats->packets++;
22 u64_stats_update_end(&stats->syncp);
23
24 dev_kfree_skb(skb);
25
26 return NETDEV_TX_OK;
27}
28
29static int nlmon_is_valid_mtu(int new_mtu)
30{
Daniel Borkmann3b233fe2013-06-27 13:44:26 +020031 /* Note that in netlink we do not really have an upper limit. On
32 * default, we use NLMSG_GOODSIZE. Here at least we should make
33 * sure that it's at least the header size.
34 */
35 return new_mtu >= (int) sizeof(struct nlmsghdr);
Daniel Borkmanne4fc4082013-06-21 19:38:08 +020036}
37
38static int nlmon_change_mtu(struct net_device *dev, int new_mtu)
39{
40 if (!nlmon_is_valid_mtu(new_mtu))
41 return -EINVAL;
42
43 dev->mtu = new_mtu;
44 return 0;
45}
46
47static int nlmon_dev_init(struct net_device *dev)
48{
49 dev->lstats = alloc_percpu(struct pcpu_lstats);
50
51 return dev->lstats == NULL ? -ENOMEM : 0;
52}
53
54static void nlmon_dev_uninit(struct net_device *dev)
55{
56 free_percpu(dev->lstats);
57}
58
59static struct netlink_tap nlmon_tap;
60
61static int nlmon_open(struct net_device *dev)
62{
63 return netlink_add_tap(&nlmon_tap);
64}
65
66static int nlmon_close(struct net_device *dev)
67{
68 return netlink_remove_tap(&nlmon_tap);
69}
70
71static struct rtnl_link_stats64 *
72nlmon_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
73{
74 int i;
75 u64 bytes = 0, packets = 0;
76
77 for_each_possible_cpu(i) {
78 const struct pcpu_lstats *nl_stats;
79 u64 tbytes, tpackets;
80 unsigned int start;
81
82 nl_stats = per_cpu_ptr(dev->lstats, i);
83
84 do {
85 start = u64_stats_fetch_begin_bh(&nl_stats->syncp);
86 tbytes = nl_stats->bytes;
87 tpackets = nl_stats->packets;
88 } while (u64_stats_fetch_retry_bh(&nl_stats->syncp, start));
89
90 packets += tpackets;
91 bytes += tbytes;
92 }
93
94 stats->rx_packets = packets;
95 stats->tx_packets = 0;
96
97 stats->rx_bytes = bytes;
98 stats->tx_bytes = 0;
99
100 return stats;
101}
102
103static u32 always_on(struct net_device *dev)
104{
105 return 1;
106}
107
108static const struct ethtool_ops nlmon_ethtool_ops = {
109 .get_link = always_on,
110};
111
112static const struct net_device_ops nlmon_ops = {
113 .ndo_init = nlmon_dev_init,
114 .ndo_uninit = nlmon_dev_uninit,
115 .ndo_open = nlmon_open,
116 .ndo_stop = nlmon_close,
117 .ndo_start_xmit = nlmon_xmit,
118 .ndo_get_stats64 = nlmon_get_stats64,
119 .ndo_change_mtu = nlmon_change_mtu,
120};
121
122static struct netlink_tap nlmon_tap __read_mostly = {
123 .module = THIS_MODULE,
124};
125
126static void nlmon_setup(struct net_device *dev)
127{
128 dev->type = ARPHRD_NETLINK;
129 dev->tx_queue_len = 0;
130
131 dev->netdev_ops = &nlmon_ops;
132 dev->ethtool_ops = &nlmon_ethtool_ops;
133 dev->destructor = free_netdev;
134
135 dev->features = NETIF_F_FRAGLIST | NETIF_F_HIGHDMA;
136 dev->flags = IFF_NOARP;
137
138 /* That's rather a softlimit here, which, of course,
139 * can be altered. Not a real MTU, but what is to be
140 * expected in most cases.
141 */
142 dev->mtu = NLMSG_GOODSIZE;
143}
144
145static __init int nlmon_register(void)
146{
147 int err;
148 struct net_device *nldev;
149
150 nldev = nlmon_tap.dev = alloc_netdev(0, "netlink", nlmon_setup);
151 if (unlikely(nldev == NULL))
152 return -ENOMEM;
153
154 err = register_netdev(nldev);
155 if (unlikely(err))
156 free_netdev(nldev);
157
158 return err;
159}
160
161static __exit void nlmon_unregister(void)
162{
163 struct net_device *nldev = nlmon_tap.dev;
164
165 unregister_netdev(nldev);
166}
167
168module_init(nlmon_register);
169module_exit(nlmon_unregister);
170
171MODULE_LICENSE("GPL v2");
172MODULE_AUTHOR("Daniel Borkmann <dborkman@redhat.com>");
173MODULE_AUTHOR("Mathieu Geli <geli@enseirb.fr>");
174MODULE_DESCRIPTION("Netlink monitoring device");