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