xref: /openbmc/linux/drivers/net/nlmon.c (revision 3b233fe0)
1 #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 
8 struct pcpu_lstats {
9 	u64 packets;
10 	u64 bytes;
11 	struct u64_stats_sync syncp;
12 };
13 
14 static 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 
29 static int nlmon_is_valid_mtu(int new_mtu)
30 {
31 	/* 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);
36 }
37 
38 static 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 
47 static 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 
54 static void nlmon_dev_uninit(struct net_device *dev)
55 {
56 	free_percpu(dev->lstats);
57 }
58 
59 static struct netlink_tap nlmon_tap;
60 
61 static int nlmon_open(struct net_device *dev)
62 {
63 	return netlink_add_tap(&nlmon_tap);
64 }
65 
66 static int nlmon_close(struct net_device *dev)
67 {
68 	return netlink_remove_tap(&nlmon_tap);
69 }
70 
71 static struct rtnl_link_stats64 *
72 nlmon_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 
103 static u32 always_on(struct net_device *dev)
104 {
105 	return 1;
106 }
107 
108 static const struct ethtool_ops nlmon_ethtool_ops = {
109 	.get_link = always_on,
110 };
111 
112 static 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 
122 static struct netlink_tap nlmon_tap __read_mostly = {
123 	.module = THIS_MODULE,
124 };
125 
126 static 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 
145 static __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 
161 static __exit void nlmon_unregister(void)
162 {
163 	struct net_device *nldev = nlmon_tap.dev;
164 
165 	unregister_netdev(nldev);
166 }
167 
168 module_init(nlmon_register);
169 module_exit(nlmon_unregister);
170 
171 MODULE_LICENSE("GPL v2");
172 MODULE_AUTHOR("Daniel Borkmann <dborkman@redhat.com>");
173 MODULE_AUTHOR("Mathieu Geli <geli@enseirb.fr>");
174 MODULE_DESCRIPTION("Netlink monitoring device");
175