• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/luci2-ui/luci2/src/rpcd/bwmon.c

  1 /*
  2  * rpcd - UBUS RPC server
  3  *
  4  *   Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
  5  *
  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.
  9  *
 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.
 17  */
 18 
 19 #include <limits.h>
 20 #include <stdio.h>
 21 #include <stdint.h>
 22 #include <stdbool.h>
 23 #include <stdlib.h>
 24 #include <dirent.h>
 25 #include <string.h>
 26 #include <sys/stat.h>
 27 #include <sys/types.h>
 28 #include <net/if.h>
 29 #include <libubus.h>
 30 #include <libubox/avl.h>
 31 #include <libubox/avl-cmp.h>
 32 
 33 #include <rpcd/plugin.h>
 34 
 35 #define RPC_BWMON_HISTORY                       120
 36 
 37 
 38 enum {
 39         RX_BYTES = 0,
 40         TX_BYTES = 1,
 41         RX_PACKETS = 2,
 42         TX_PACKETS = 3
 43 };
 44 
 45 const char *types[] = {
 46         "rx_bytes",
 47         "tx_bytes",
 48         "rx_packets",
 49         "tx_packets"
 50 };
 51 
 52 struct rpc_bwmon_device {
 53         struct avl_node avl;
 54         char ifname[IF_NAMESIZE];
 55         int pos;
 56         uint64_t prev[4];
 57         uint32_t values[4][RPC_BWMON_HISTORY];
 58 };
 59 
 60 static struct blob_buf buf;
 61 static struct avl_tree devices;
 62 
 63 
 64 enum {
 65         RPC_STATS_DEVICE,
 66         __RPC_STATS_MAX,
 67 };
 68 
 69 static const struct blobmsg_policy rpc_stats_policy[__RPC_STATS_MAX] = {
 70         [RPC_STATS_DEVICE] = { .name = "device", .type = BLOBMSG_TYPE_STRING },
 71 };
 72 
 73 
 74 static int
 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)
 78 {
 79         void *c;
 80         struct rpc_bwmon_device *dev;
 81 
 82         blob_buf_init(&buf, 0);
 83         c = blobmsg_open_array(&buf, "devices");
 84 
 85         avl_for_each_element(&devices, dev, avl)
 86                 blobmsg_add_string(&buf, NULL, dev->ifname);
 87 
 88         blobmsg_close_array(&buf, c);
 89 
 90         ubus_send_reply(ctx, req, buf.head);
 91         return 0;
 92 }
 93 
 94 
 95 static void
 96 rpc_bwmon_dump_stats(struct rpc_bwmon_device *dev)
 97 {
 98         void *c;
 99         int i, j;
100 
101         for (i = 0; i < 4; i++)
102         {
103                 c = blobmsg_open_array(&buf, types[i]);
104 
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]);
108 
109                 blobmsg_close_array(&buf, c);
110         }
111 }
112 
113 static int
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)
117 {
118         void *c, *d;
119         struct rpc_bwmon_device *dev;
120         struct blob_attr *tb[__RPC_STATS_MAX];
121 
122         blobmsg_parse(rpc_stats_policy, __RPC_STATS_MAX, tb,
123                       blob_data(msg), blob_len(msg));
124 
125         blob_buf_init(&buf, 0);
126 
127         if (tb[RPC_STATS_DEVICE])
128         {
129                 dev = avl_find_element(&devices,
130                                        blobmsg_get_string(tb[RPC_STATS_DEVICE]),
131                                        dev, avl);
132 
133                 if (!dev)
134                         return UBUS_STATUS_NOT_FOUND;
135 
136                 c = blobmsg_open_table(&buf, "statistics");
137                 rpc_bwmon_dump_stats(dev);
138                 blobmsg_close_table(&buf, c);
139 
140                 ubus_send_reply(ctx, req, buf.head);
141                 return 0;
142         }
143 
144         c = blobmsg_open_table(&buf, "statistics");
145 
146         avl_for_each_element(&devices, dev, avl)
147         {
148                 d = blobmsg_open_table(&buf, dev->ifname);
149                 rpc_bwmon_dump_stats(dev);
150                 blobmsg_close_table(&buf, d);
151         }
152 
153         blobmsg_close_table(&buf, c);
154 
155         ubus_send_reply(ctx, req, buf.head);
156         return 0;
157 }
158 
159 
160 static uint64_t
161 read_int(const char *ifname, const char *name)
162 {
163         FILE *file;
164         uint64_t val = 0;
165         char buf[32] = { }, path[PATH_MAX] = { };
166 
167         snprintf(path, sizeof(path) - 1, "/sys/class/net/%s/%s", ifname, name);
168 
169         if ((file = fopen(path, "r")) != NULL)
170         {
171                 if (fread(buf, 1, sizeof(buf) - 1, file) > 0)
172                         val = strtoull(buf, NULL, 0);
173 
174                 fclose(file);
175         }
176 
177         return val;
178 }
179 
180 static struct rpc_bwmon_device *
181 get_device(const char *ifname, bool create)
182 {
183         struct rpc_bwmon_device *dev;
184 
185         dev = avl_find_element(&devices, ifname, dev, avl);
186 
187         if (!dev && create)
188         {
189                 dev = calloc(1, sizeof(*dev));
190 
191                 if (!dev)
192                         return NULL;
193 
194                 dev->pos = -1;
195                 dev->avl.key = strcpy(dev->ifname, ifname);
196 
197                 avl_insert(&devices, &dev->avl);
198         }
199 
200         return dev;
201 }
202 
203 static void
204 put_value(struct rpc_bwmon_device *dev, int type, uint64_t value)
205 {
206         if (dev->pos >= 0)
207                 dev->values[type][dev->pos] = (uint32_t)(value - dev->prev[type]);
208 
209         dev->prev[type] = value;
210 }
211 
212 static void
213 rpc_bwmon_collect(struct uloop_timeout *t)
214 {
215         DIR *dir;
216         bool up;
217         struct dirent *e;
218         struct rpc_bwmon_device *dev;
219 
220         if ((dir = opendir("/sys/class/net")))
221         {
222                 while ((e = readdir(dir)) != NULL)
223                 {
224                         up = read_int(e->d_name, "flags") & 1;
225                         dev = get_device(e->d_name, up);
226 
227                         if (!dev)
228                                 continue;
229 
230                         put_value(dev, RX_BYTES,
231                                   read_int(e->d_name, "statistics/rx_bytes"));
232 
233                         put_value(dev, TX_BYTES,
234                                   read_int(e->d_name, "statistics/tx_bytes"));
235 
236                         put_value(dev, RX_PACKETS,
237                                   read_int(e->d_name, "statistics/rx_packets"));
238 
239                         put_value(dev, TX_PACKETS,
240                                   read_int(e->d_name, "statistics/tx_packets"));
241 
242                         dev->pos = (dev->pos + 1) % RPC_BWMON_HISTORY;
243                 }
244 
245                 closedir(dir);
246         }
247 
248         uloop_timeout_set(t, 1000);
249 }
250 
251 
252 static int
253 rpc_bwmon_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx)
254 {
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)
258         };
259 
260         static struct ubus_object_type bwmon_type =
261                 UBUS_OBJECT_TYPE("luci-rpc-bwmon", bwmon_methods);
262 
263         static struct ubus_object bwmon_obj = {
264                 .name = "luci2.network.bwmon",
265                 .type = &bwmon_type,
266                 .methods = bwmon_methods,
267                 .n_methods = ARRAY_SIZE(bwmon_methods),
268         };
269 
270         static struct uloop_timeout t = {
271                 .cb = rpc_bwmon_collect
272         };
273 
274         avl_init(&devices, avl_strcmp, false, NULL);
275 
276         uloop_timeout_set(&t, 1000);
277 
278         return ubus_add_object(ctx, &bwmon_obj);
279 }
280 
281 struct rpc_plugin rpc_plugin = {
282         .init = rpc_bwmon_api_init
283 };
284 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt