1 /* drivers/misc/iface_stat.c
3 * Copyright (C) 2011 Google, Inc.
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
16 #include <linux/err.h>
17 #include <linux/init.h>
18 #include <linux/kernel.h>
20 #include <linux/list.h>
21 #include <linux/proc_fs.h>
22 #include <linux/slab.h>
23 #include <linux/stat.h>
24 #include <linux/netdevice.h>
25 #include <linux/inetdevice.h>
26 #include <linux/rtnetlink.h>
27 #include <linux/iface_stat.h>
29 static LIST_HEAD(iface_list);
30 static struct proc_dir_entry *iface_stat_procdir;
33 struct list_head if_link;
35 unsigned long tx_bytes;
36 unsigned long rx_bytes;
37 unsigned long tx_packets;
38 unsigned long rx_packets;
42 static int read_proc_entry(char *page, char **start, off_t off,
43 int count, int *eof, void *data)
48 unsigned long *iface_entry = (unsigned long *) data;
52 value = (unsigned long) (*iface_entry);
53 p += sprintf(p, "%lu\n", value);
54 len = (p - page) - off;
55 *eof = (len <= count) ? 1 : 0;
60 static int read_proc_bool_entry(char *page, char **start, off_t off,
61 int count, int *eof, void *data)
66 unsigned long *iface_entry = (unsigned long *) data;
70 value = (bool) (*iface_entry);
71 p += sprintf(p, "%u\n", value ? 1 : 0);
72 len = (p - page) - off;
73 *eof = (len <= count) ? 1 : 0;
78 /* Find the entry for tracking the specified interface. */
79 static struct iface_stat *get_iface_stat(const char *ifname)
81 struct iface_stat *iface_entry;
85 list_for_each_entry(iface_entry, &iface_list, if_link) {
86 if (!strcmp(iface_entry->iface_name, ifname))
93 * Create a new entry for tracking the specified interface.
94 * Do nothing if the entry already exists.
95 * Called when an interface is configured with a valid IP address.
97 void create_iface_stat(const struct in_device *in_dev)
99 struct iface_stat *new_iface;
100 struct proc_dir_entry *proc_entry;
101 const struct net_device *dev;
103 struct iface_stat *entry;
105 struct in_ifaddr *ifa = NULL;
107 ASSERT_RTNL(); /* No need for separate locking */
111 pr_err("iface_stat: This should never happen.\n");
116 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next)
117 if (!strcmp(dev->name, ifa->ifa_label))
121 ipaddr = ifa->ifa_local;
123 pr_err("iface_stat: Interface not found.\n");
127 entry = get_iface_stat(dev->name);
129 pr_debug("iface_stat: Already monitoring device %s\n", ifname);
130 if (ipv4_is_loopback(ipaddr)) {
131 entry->active = false;
132 pr_debug("iface_stat: Disabling monitor for "
133 "loopback device %s\n", ifname);
135 entry->active = true;
136 pr_debug("iface_stat: Re-enabling monitor for "
137 "device %s with ip %pI4\n",
141 } else if (ipv4_is_loopback(ipaddr)) {
142 pr_debug("iface_stat: Ignoring monitor for "
143 "loopback device %s with ip %pI4\n",
148 /* Create a new entry for tracking the specified interface. */
149 new_iface = kmalloc(sizeof(struct iface_stat), GFP_KERNEL);
150 if (new_iface == NULL)
153 new_iface->iface_name = kmalloc((strlen(ifname)+1)*sizeof(char),
155 if (new_iface->iface_name == NULL) {
160 strcpy(new_iface->iface_name, ifname);
161 /* Counters start at 0, so we can track 4GB of network traffic. */
162 new_iface->tx_bytes = 0;
163 new_iface->rx_bytes = 0;
164 new_iface->rx_packets = 0;
165 new_iface->tx_packets = 0;
166 new_iface->active = true;
168 /* Append the newly created iface stat struct to the list. */
169 list_add_tail(&new_iface->if_link, &iface_list);
170 proc_entry = proc_mkdir(ifname, iface_stat_procdir);
172 /* Keep reference to iface_stat so we know where to read stats from. */
173 create_proc_read_entry("tx_bytes", S_IRUGO, proc_entry,
174 read_proc_entry, &new_iface->tx_bytes);
176 create_proc_read_entry("rx_bytes", S_IRUGO, proc_entry,
177 read_proc_entry, &new_iface->rx_bytes);
179 create_proc_read_entry("tx_packets", S_IRUGO, proc_entry,
180 read_proc_entry, &new_iface->tx_packets);
182 create_proc_read_entry("rx_packets", S_IRUGO, proc_entry,
183 read_proc_entry, &new_iface->rx_packets);
185 create_proc_read_entry("active", S_IRUGO, proc_entry,
186 read_proc_bool_entry, &new_iface->active);
188 pr_debug("iface_stat: Now monitoring device %s with ip %pI4\n",
193 * Update stats for the specified interface. Do nothing if the entry
194 * does not exist (when a device was never configured with an IP address).
195 * Called when an device is being unregistered.
197 void iface_stat_update(struct net_device *dev)
199 const struct net_device_stats *stats = dev_get_stats(dev);
200 struct iface_stat *entry;
204 entry = get_iface_stat(dev->name);
206 pr_debug("iface_stat: dev %s monitor not found\n", dev->name);
210 if (entry->active) { /* FIXME: Support for more than 4GB */
211 entry->tx_bytes += stats->tx_bytes;
212 entry->tx_packets += stats->tx_packets;
213 entry->rx_bytes += stats->rx_bytes;
214 entry->rx_packets += stats->rx_packets;
215 entry->active = false;
216 pr_debug("iface_stat: Updating stats for "
217 "dev %s which went down\n", dev->name);
219 pr_debug("iface_stat: Didn't update stats for "
220 "dev %s which went down\n", dev->name);
223 static int __init iface_stat_init(void)
225 iface_stat_procdir = proc_mkdir("iface_stat", NULL);
226 if (!iface_stat_procdir) {
227 pr_err("iface_stat: failed to create proc entry\n");
234 device_initcall(iface_stat_init);