2 * rpcd - UBUS RPC server
4 * Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
27 #include <sys/types.h>
30 #include <libubox/avl.h>
31 #include <libubox/avl-cmp.h>
33 #include <rpcd/plugin.h>
35 #define RPC_BWMON_HISTORY 120
45 const char *types[] = {
52 struct rpc_bwmon_device {
54 char ifname[IF_NAMESIZE];
57 uint32_t values[4][RPC_BWMON_HISTORY];
60 static struct blob_buf buf;
61 static struct avl_tree devices;
69 static const struct blobmsg_policy rpc_stats_policy[__RPC_STATS_MAX] = {
70 [RPC_STATS_DEVICE] = { .name = "device", .type = BLOBMSG_TYPE_STRING },
75 rpc_bwmon_devices(struct ubus_context *ctx, struct ubus_object *obj,
76 struct ubus_request_data *req, const char *method,
77 struct blob_attr *msg)
80 struct rpc_bwmon_device *dev;
82 blob_buf_init(&buf, 0);
83 c = blobmsg_open_array(&buf, "devices");
85 avl_for_each_element(&devices, dev, avl)
86 blobmsg_add_string(&buf, NULL, dev->ifname);
88 blobmsg_close_array(&buf, c);
90 ubus_send_reply(ctx, req, buf.head);
96 rpc_bwmon_dump_stats(struct rpc_bwmon_device *dev)
101 for (i = 0; i < 4; i++)
103 c = blobmsg_open_array(&buf, types[i]);
105 for (j = 0; j < RPC_BWMON_HISTORY; j++)
106 blobmsg_add_u32(&buf, NULL,
107 dev->values[i][(dev->pos + j) % RPC_BWMON_HISTORY]);
109 blobmsg_close_array(&buf, c);
114 rpc_bwmon_stats(struct ubus_context *ctx, struct ubus_object *obj,
115 struct ubus_request_data *req, const char *method,
116 struct blob_attr *msg)
119 struct rpc_bwmon_device *dev;
120 struct blob_attr *tb[__RPC_STATS_MAX];
122 blobmsg_parse(rpc_stats_policy, __RPC_STATS_MAX, tb,
123 blob_data(msg), blob_len(msg));
125 blob_buf_init(&buf, 0);
127 if (tb[RPC_STATS_DEVICE])
129 dev = avl_find_element(&devices,
130 blobmsg_get_string(tb[RPC_STATS_DEVICE]),
134 return UBUS_STATUS_NOT_FOUND;
136 c = blobmsg_open_table(&buf, "statistics");
137 rpc_bwmon_dump_stats(dev);
138 blobmsg_close_table(&buf, c);
140 ubus_send_reply(ctx, req, buf.head);
144 c = blobmsg_open_table(&buf, "statistics");
146 avl_for_each_element(&devices, dev, avl)
148 d = blobmsg_open_table(&buf, dev->ifname);
149 rpc_bwmon_dump_stats(dev);
150 blobmsg_close_table(&buf, d);
153 blobmsg_close_table(&buf, c);
155 ubus_send_reply(ctx, req, buf.head);
161 read_int(const char *ifname, const char *name)
165 char buf[32] = { }, path[PATH_MAX] = { };
167 snprintf(path, sizeof(path) - 1, "/sys/class/net/%s/%s", ifname, name);
169 if ((file = fopen(path, "r")) != NULL)
171 if (fread(buf, 1, sizeof(buf) - 1, file) > 0)
172 val = strtoull(buf, NULL, 0);
180 static struct rpc_bwmon_device *
181 get_device(const char *ifname, bool create)
183 struct rpc_bwmon_device *dev;
185 dev = avl_find_element(&devices, ifname, dev, avl);
189 dev = calloc(1, sizeof(*dev));
195 dev->avl.key = strcpy(dev->ifname, ifname);
197 avl_insert(&devices, &dev->avl);
204 put_value(struct rpc_bwmon_device *dev, int type, uint64_t value)
207 dev->values[type][dev->pos] = (uint32_t)(value - dev->prev[type]);
209 dev->prev[type] = value;
213 rpc_bwmon_collect(struct uloop_timeout *t)
218 struct rpc_bwmon_device *dev;
220 if ((dir = opendir("/sys/class/net")))
222 while ((e = readdir(dir)) != NULL)
224 up = read_int(e->d_name, "flags") & 1;
225 dev = get_device(e->d_name, up);
230 put_value(dev, RX_BYTES,
231 read_int(e->d_name, "statistics/rx_bytes"));
233 put_value(dev, TX_BYTES,
234 read_int(e->d_name, "statistics/tx_bytes"));
236 put_value(dev, RX_PACKETS,
237 read_int(e->d_name, "statistics/rx_packets"));
239 put_value(dev, TX_PACKETS,
240 read_int(e->d_name, "statistics/tx_packets"));
242 dev->pos = (dev->pos + 1) % RPC_BWMON_HISTORY;
248 uloop_timeout_set(t, 1000);
253 rpc_bwmon_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx)
255 static const struct ubus_method bwmon_methods[] = {
256 UBUS_METHOD_NOARG("devices", rpc_bwmon_devices),
257 UBUS_METHOD("statistics", rpc_bwmon_stats, rpc_stats_policy)
260 static struct ubus_object_type bwmon_type =
261 UBUS_OBJECT_TYPE("luci-rpc-bwmon", bwmon_methods);
263 static struct ubus_object bwmon_obj = {
264 .name = "luci2.network.bwmon",
266 .methods = bwmon_methods,
267 .n_methods = ARRAY_SIZE(bwmon_methods),
270 static struct uloop_timeout t = {
271 .cb = rpc_bwmon_collect
274 avl_init(&devices, avl_strcmp, false, NULL);
276 uloop_timeout_set(&t, 1000);
278 return ubus_add_object(ctx, &bwmon_obj);
281 const struct rpc_plugin rpc_plugin = {
282 .init = rpc_bwmon_api_init