2 * luci-bwc - Very simple bandwidth collector cache for LuCI realtime graphs
4 * Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
31 #include <arpa/inet.h>
37 #define DB_PATH "/var/lib/luci-bwc"
38 #define DB_IF_FILE DB_PATH "/if/%s"
39 #define DB_LD_FILE DB_PATH "/load"
41 #define IF_SCAN_PATTERN \
42 " %[^ :]:%" SCNu64 " %" SCNu64 \
43 " %*d %*d %*d %*d %*d %*d" \
44 " %" SCNu64 " %" SCNu64
46 #define LD_SCAN_PATTERN \
50 struct traffic_entry {
66 static uint64_t htonll(uint64_t value)
70 if (*(char *)&num == 1)
71 return htonl((uint32_t)(value & 0xFFFFFFFF)) |
72 htonl((uint32_t)(value >> 32));
80 static int init_directory(char *path)
84 for (p = &path[1]; *p; p++)
90 if (mkdir(path, 0700) && (errno != EEXIST))
100 static int update_file(const char *path, void *entry, int esize)
106 if ((file = open(path, O_RDWR)) >= 0)
108 map = mmap(NULL, esize * STEP_COUNT, PROT_READ | PROT_WRITE,
109 MAP_SHARED | MAP_LOCKED, file, 0);
111 if ((map != NULL) && (map != MAP_FAILED))
113 memmove(map, map + esize, esize * (STEP_COUNT-1));
114 memcpy(map + esize * (STEP_COUNT-1), entry, esize);
116 munmap(map, esize * STEP_COUNT);
128 static int init_ifstat(const char *ifname)
132 struct traffic_entry e = { 0 };
134 snprintf(path, sizeof(path), DB_IF_FILE, ifname);
136 if (init_directory(path))
139 if ((file = open(path, O_WRONLY | O_CREAT, 0600)) >= 0)
141 for (i = 0; i < STEP_COUNT; i++)
143 if (write(file, &e, sizeof(struct traffic_entry)) < 0)
155 static int update_ifstat(
156 const char *ifname, uint64_t rxb, uint64_t rxp, uint64_t txb, uint64_t txp
161 struct traffic_entry e;
163 snprintf(path, sizeof(path), DB_IF_FILE, ifname);
167 if (init_ifstat(ifname))
169 fprintf(stderr, "Failed to init %s: %s\n",
170 path, strerror(errno));
176 e.time = htonll(time(NULL));
182 return update_file(path, &e, sizeof(struct traffic_entry));
185 static int init_ldstat(void)
189 struct load_entry e = { 0 };
191 snprintf(path, sizeof(path), DB_LD_FILE);
193 if (init_directory(path))
196 if ((file = open(path, O_WRONLY | O_CREAT, 0600)) >= 0)
198 for (i = 0; i < STEP_COUNT; i++)
200 if (write(file, &e, sizeof(struct load_entry)) < 0)
212 static int update_ldstat(uint16_t load1, uint16_t load5, uint16_t load15)
219 snprintf(path, sizeof(path), DB_LD_FILE);
225 fprintf(stderr, "Failed to init %s: %s\n",
226 path, strerror(errno));
232 e.time = htonll(time(NULL));
233 e.load1 = htons(load1);
234 e.load5 = htons(load5);
235 e.load15 = htons(load15);
237 return update_file(path, &e, sizeof(struct load_entry));
240 static int run_daemon(int nofork)
243 uint64_t rxb, txb, rxp, txp;
244 float lf1, lf5, lf15;
278 if ((info = fopen("/proc/net/dev", "r")) != NULL)
280 while (fgets(line, sizeof(line), info))
282 if (strchr(line, '|'))
285 if (sscanf(line, IF_SCAN_PATTERN, ifname, &rxb, &rxp, &txb, &txp))
287 if (strncmp(ifname, "lo", sizeof(ifname)))
288 update_ifstat(ifname, rxb, rxp, txb, txp);
295 if ((info = fopen("/proc/loadavg", "r")) != NULL)
297 if (fscanf(info, LD_SCAN_PATTERN, &lf1, &lf5, &lf15))
299 update_ldstat((uint16_t)(lf1 * 100),
300 (uint16_t)(lf5 * 100),
301 (uint16_t)(lf15 * 100));
311 static int run_dump_ifname(const char *ifname)
316 int entrysize = sizeof(struct traffic_entry);
317 int mapsize = STEP_COUNT * entrysize;
322 struct traffic_entry *e;
324 snprintf(path, sizeof(path), DB_IF_FILE, ifname);
326 if ((file = open(path, O_RDONLY)) >= 0)
328 map = mmap(NULL, mapsize, PROT_READ, MAP_SHARED | MAP_LOCKED, file, 0);
330 if ((map != NULL) && (map != MAP_FAILED))
332 for (i = 0; i < mapsize; i += entrysize)
334 e = (struct traffic_entry *) &map[i];
339 printf("[ %" PRIu64 ", %" PRIu64 ", %" PRIu64
340 ", %" PRIu64 ", %" PRIu64 " ]%s\n",
342 ntohll(e->rxb), ntohll(e->rxp),
343 ntohll(e->txb), ntohll(e->txp),
344 ((i + entrysize) < mapsize) ? "," : "");
347 munmap(map, mapsize);
355 fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
361 static int run_dump_load(void)
366 int entrysize = sizeof(struct load_entry);
367 int mapsize = STEP_COUNT * entrysize;
372 struct load_entry *e;
374 snprintf(path, sizeof(path), DB_LD_FILE);
376 if ((file = open(path, O_RDONLY)) >= 0)
378 map = mmap(NULL, mapsize, PROT_READ, MAP_SHARED | MAP_LOCKED, file, 0);
380 if ((map != NULL) && (map != MAP_FAILED))
382 for (i = 0; i < mapsize; i += entrysize)
384 e = (struct load_entry *) &map[i];
389 printf("[ %" PRIu64 ", %u, %u, %u ]%s\n",
391 ntohs(e->load1), ntohs(e->load5), ntohs(e->load15),
392 ((i + entrysize) < mapsize) ? "," : "");
395 munmap(map, mapsize);
403 fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
410 int main(int argc, char *argv[])
419 while ((opt = getopt(argc, argv, "dfi:l")) > -1)
446 return run_daemon(nofork);
448 else if (iprint && ifname)
449 return run_dump_ifname(ifname);
452 return run_dump_load();
460 argv[0], argv[0], argv[0]