@cryptotaxi247 / netdata-1 / commits / 8a51160d1

full traffic control support for graphing tc classes. it gets names from fireqos.

Costa Tsaousis (ktsaou) committed Mar 25, 2014 at 03:10 UTC 8a51160d10d74804c0abf97a9c5e8a825a83f4fa
4 files changed +283 -121
netdata.c
+247 -114
@@ -284,6 +284,7 @@ int create_listen_socket(int port)
284 #define RRD_STATS_NAME_MAX 1024
285
286 struct rrd_dimension {
287 + char id[RRD_STATS_NAME_MAX + 1];
288 char name[RRD_STATS_NAME_MAX + 1];
289 size_t bytes;
290 size_t entries;
@@ -350,7 +351,7 @@ RRD_STATS *rrd_stats_create(const char *name, unsigned long entries)
351 return(st);
352 }
353
353 -RRD_DIMENSION *rrd_stats_dimension_add(RRD_STATS *st, const char *name, size_t bytes, size_t multiplier, size_t divisor)
354 +RRD_DIMENSION *rrd_stats_dimension_add(RRD_STATS *st, const char *id, const char *name, size_t bytes, long multiplier, long divisor)
355 {
356 RRD_DIMENSION *rd = NULL;
357
@@ -370,6 +371,7 @@ RRD_DIMENSION *rrd_stats_dimension_add(RRD_STATS *st, const char *name, size_t b
371 return NULL;
372 }
373
374 + strncpy(rd->id, id, RRD_STATS_NAME_MAX);
375 strncpy(rd->name, name, RRD_STATS_NAME_MAX);
376 rd->name[RRD_STATS_NAME_MAX] = '\0';
377
@@ -393,12 +395,12 @@ RRD_STATS *rrd_stats_find(const char *name)
395 return(st);
396 }
397
396 -RRD_DIMENSION *rrd_stats_dimension_find(RRD_STATS *st, const char *dimension)
398 +RRD_DIMENSION *rrd_stats_dimension_find(RRD_STATS *st, const char *id)
399 {
400 RRD_DIMENSION *rd = st->dimensions;
401
402 for ( ; rd ; rd = rd->next ) {
401 - if(strcmp(rd->name, dimension) == 0) break;
403 + if(strcmp(rd->id, id) == 0) break;
404 }
405
406 return(rd);
@@ -425,30 +427,30 @@ void rrd_stats_done(RRD_STATS *st)
427 pthread_mutex_unlock(&st->mutex);
428 }
429
428 -void rrd_stats_dimension_set(RRD_STATS *st, const char *dimension, void *data)
430 +void rrd_stats_dimension_set(RRD_STATS *st, const char *id, void *data)
431 {
430 - RRD_DIMENSION *rd = rrd_stats_dimension_find(st, dimension);
432 + RRD_DIMENSION *rd = rrd_stats_dimension_find(st, id);
433 if(!rd) {
432 - error("Cannot find dimension '%s' on stats '%s'.", dimension, st->name);
434 + error("Cannot find dimension with id '%s' on stats '%s'.", id, st->name);
435 return;
436 }
437
436 - if(rd->bytes == sizeof(unsigned long long)) {
438 + if(rd->bytes == sizeof(long long)) {
439 long long *dimension = rd->values, *value = data;
440
441 dimension[st->last_entry] = (*value);
442 }
441 - else if(rd->bytes == sizeof(unsigned long)) {
443 + else if(rd->bytes == sizeof(long)) {
444 long *dimension = rd->values, *value = data;
445
446 dimension[st->last_entry] = (*value);
447 }
446 - else if(rd->bytes == sizeof(unsigned int)) {
448 + else if(rd->bytes == sizeof(int)) {
449 int *dimension = rd->values, *value = data;
450
451 dimension[st->last_entry] = (*value);
452 }
451 - else if(rd->bytes == sizeof(unsigned char)) {
453 + else if(rd->bytes == sizeof(char)) {
454 char *dimension = rd->values, *value = data;
455
456 dimension[st->last_entry] = (*value);
@@ -549,7 +551,7 @@ size_t rrd_stats_json(RRD_STATS *st, char *b, size_t length, size_t entries_to_s
551 struct tm *tm = localtime(&st->times[t].tv_sec);
552 if(!tm) { error("localtime() failed."); continue; }
553
552 - sprintf(dtm, "\"Date(%d, %d, %d, %d, %d, %d)\"", tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); // datetime
554 + sprintf(dtm, "\"Date(%d, %d, %d, %d, %d, %d, %d)\"", tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(st->times[t].tv_usec / 1000)); // datetime
555 // strftime(dtm, 200, "\"Date(%Y, %m, %d, %H, %M, %S)\"", tm); // datetime
556 // strftime(dtm, 200, "[%H, %M, %S, 0]", tm); // timeofday
557 i += sprintf(&b[i], "%s {\"c\":[{\"v\":%s},", printed?"]},\n":"", dtm);
@@ -558,27 +560,30 @@ size_t rrd_stats_json(RRD_STATS *st, char *b, size_t length, size_t entries_to_s
560 }
561
562 for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
561 - if(rd->bytes == sizeof(unsigned long long)) {
563 + if(rd->bytes == sizeof(long long)) {
564 long long *dimension = rd->values;
563 - value = (dimension[t] - dimension[lt]) * 1000000 * rd->multiplier / usec / rd->divisor;
565 + value = dimension[t] - dimension[lt];
566 }
565 - else if(rd->bytes == sizeof(unsigned long)) {
567 + else if(rd->bytes == sizeof(long)) {
568 long *dimension = rd->values;
567 - value = (dimension[t] - dimension[lt]) * 1000000 * rd->multiplier / usec / rd->divisor;
569 + value = dimension[t] - dimension[lt];
570 }
569 - else if(rd->bytes == sizeof(unsigned int)) {
571 + else if(rd->bytes == sizeof(int)) {
572 int *dimension = rd->values;
571 - value = (dimension[t] - dimension[lt]) * 1000000 * rd->multiplier / usec / rd->divisor;
573 + value = dimension[t] - dimension[lt];
574 }
573 - else if(rd->bytes == sizeof(unsigned char)) {
575 + else if(rd->bytes == sizeof(char)) {
576 char *dimension = rd->values;
575 - value = (dimension[t] - dimension[lt]) * 1000000 * rd->multiplier / usec / rd->divisor;
577 + value = dimension[t] - dimension[lt];
578 }
579 else fatal("Cannot produce JSON for size %d bytes dimension.", rd->bytes);
580
581 + value = value * 1000000L / usec;
582 + value = value * rd->multiplier / rd->divisor;
583 +
584 switch(group_method) {
585 case GROUP_MAX:
581 - if(value > group_values[c]) group_values[c] = value;
586 + if(abs(value) > abs(group_values[c])) group_values[c] = value;
587 break;
588
589 default:
@@ -1386,10 +1391,10 @@ int do_proc_net_dev() {
1391 continue;
1392 }
1393
1389 - if(!rrd_stats_dimension_add(st, "sent", sizeof(unsigned long long), 8, 1024))
1394 + if(!rrd_stats_dimension_add(st, "sent", "sent", sizeof(unsigned long long), -8, 1024))
1395 error("Cannot add RRD_STATS dimension %s.", "sent");
1396
1392 - if(!rrd_stats_dimension_add(st, "received", sizeof(unsigned long long), 8, 1024))
1397 + if(!rrd_stats_dimension_add(st, "received", "received", sizeof(unsigned long long), 8, 1024))
1398 error("Cannot add RRD_STATS dimension %s.", "received");
1399
1400 }
@@ -1405,6 +1410,9 @@ int do_proc_net_dev() {
1410 return 0;
1411 }
1412
1413 +// ----------------------------------------------------------------------------
1414 +// /proc/diskstats processor
1415 +
1416 int do_proc_diskstats() {
1417 char buffer[MAX_PROC_DISKSTATS_LINE+1] = "";
1418 char name[MAX_PROC_DISKSTATS_DISK_NAME + 1] = "disk.";
@@ -1484,10 +1492,10 @@ int do_proc_diskstats() {
1492 continue;
1493 }
1494
1487 - if(!rrd_stats_dimension_add(st, "writes", sizeof(unsigned long long), sector_size, 1024))
1495 + if(!rrd_stats_dimension_add(st, "writes", "writes", sizeof(unsigned long long), sector_size * -1, 1024))
1496 error("Cannot add RRD_STATS dimension %s.", "writes");
1497
1490 - if(!rrd_stats_dimension_add(st, "reads", sizeof(unsigned long long), sector_size, 1024))
1498 + if(!rrd_stats_dimension_add(st, "reads", "reads", sizeof(unsigned long long), sector_size, 1024))
1499 error("Cannot add RRD_STATS dimension %s.", "reads");
1500
1501 }
@@ -1503,6 +1511,9 @@ int do_proc_diskstats() {
1511 return 0;
1512 }
1513
1514 +// ----------------------------------------------------------------------------
1515 +// /proc processor
1516 +
1517 void *proc_main(void *ptr)
1518 {
1519 struct timeval last, now, tmp;
@@ -1545,125 +1556,240 @@ void *proc_main(void *ptr)
1556 return NULL;
1557 }
1558
1559 +// ----------------------------------------------------------------------------
1560 +// /sbin/tc processor
1561 +// this requires the script tc-all.sh
1562 +
1563 #define PIPE_READ 0
1564 #define PIPE_WRITE 1
1550 -#define TC_SHOW_MAX 65536
1565 +#define TC_LINE_MAX 1024
1566
1552 -void *tc_main(void *ptr)
1553 -{
1554 - return NULL;
1555 -
1556 - char buffer[TC_SHOW_MAX+1] = "";
1557 - struct timeval last, now, tmp;
1558 - int pipefd[2];
1559 - long i, len;
1567 +struct tc_class {
1568 + char id[RRD_STATS_NAME_MAX + 1];
1569 + char name[RRD_STATS_NAME_MAX + 1];
1570
1561 - gettimeofday(&last, NULL);
1562 - last.tv_sec -= update_every;
1571 + char parentid[RRD_STATS_NAME_MAX + 1];
1572
1564 - for(;1;) {
1565 - unsigned long long usec, susec;
1566 - gettimeofday(&now, NULL);
1573 + int hasparent;
1574 + int isleaf;
1575 + unsigned long long bytes;
1576
1568 - // calculate the time it took for a full loop
1569 - usec = usecdiff(&now, &last);
1570 - debug(D_TC_LOOP, "TC: Last loop took %llu usec.", usec);
1577 + struct tc_class *next;
1578 +};
1579
1580 +struct tc_device {
1581 + char name[RRD_STATS_NAME_MAX + 1];
1582
1583 + struct tc_class *classes;
1584 +};
1585
1574 - // BEGIN -- the job to be done
1586 +void tc_device_commit(struct tc_device *d)
1587 +{
1588 + // we only need to add leaf classes
1589 + struct tc_class *c, *x;
1590 + for ( c = d->classes ; c ; c = c->next) {
1591 + c->isleaf = 1;
1592 +
1593 + for ( x = d->classes ; x ; x = x->next) {
1594 + if(strcmp(c->id, x->parentid) == 0) {
1595 + c->isleaf = 0;
1596 + x->hasparent = 1;
1597 + }
1598 + }
1599 + }
1600 +
1601 + // debugging:
1602 + // for ( c = d->classes ; c ; c = c->next) {
1603 + // if(c->isleaf && c->hasparent) debug(D_TC_LOOP, "Device %s, class %s, OK", d->name, c->id);
1604 + // else debug(D_TC_LOOP, "Device %s, class %s, IGNORE (isleaf: %d, hasparent: %d, parent: %s)", d->name, c->id, c->isleaf, c->hasparent, c->parentid);
1605 + // }
1606 +
1607 + for ( c = d->classes ; c ; c = c->next) {
1608 + if(c->isleaf && c->hasparent) break;
1609 + }
1610 + if(!c) {
1611 + debug(D_TC_LOOP, "Ignoring TC device '%s'. No leaf classes.", d->name);
1612 + return;
1613 + }
1614
1576 - /* --- BEGIN OF OLD VERSION ---
1577 - // this works!
1578 - // it is simpler...
1579 - // but it is 2-3 times slower than the current implementation!
1580 - // I guess the difference is that popen first runs /bin/sh.
1615 + debug(D_TC_LOOP, "Committing TC device '%s'", d->name);
1616
1582 - FILE *fp = popen("/sbin/tc -s -d qdisc show", "r");
1617 + RRD_STATS *st = rrd_stats_find(d->name);
1618 + if(!st) {
1619 + st = rrd_stats_create(d->name, save_history);
1620 + if(!st) {
1621 + error("Cannot create RRD_STATS for interface %s.", d->name);
1622 + return;
1623 + }
1624
1584 - char *p;
1585 - while((p = fgets(buffer, TC_SHOW_MAX, fp))) {
1586 - buffer[TC_SHOW_MAX] = '\0';
1587 - debug(D_TC_LOOP, "TC: read '%s'", p);
1625 + for ( c = d->classes ; c ; c = c->next) {
1626 + if(c->isleaf && c->hasparent) {
1627 + if(!rrd_stats_dimension_add(st, c->id, c->name, sizeof(unsigned long long), 8, 1024))
1628 + error("Cannot add RRD_STATS dimension %s.", c->name);
1629 + }
1630 }
1589 - pclose(fp);
1631 + }
1632 + else rrd_stats_next(st);
1633
1591 - --- END OF OLD VERSION --- */
1634 + for ( c = d->classes ; c ; c = c->next) {
1635 + if(c->isleaf && c->hasparent)
1636 + rrd_stats_dimension_set(st, c->id, &c->bytes);
1637 + }
1638 + rrd_stats_done(st);
1639 +}
1640
1593 - if(pipe(pipefd) != 0) {
1594 - error("TC: Cannot create pipe for tc. TC will be disabled.");
1595 - return NULL;
1641 +void tc_device_set_class_name(struct tc_device *d, char *id, char *name)
1642 +{
1643 + struct tc_class *c;
1644 + for ( c = d->classes ; c ; c = c->next) {
1645 + if(strcmp(c->id, id) == 0) {
1646 + strncpy(c->name, name, RRD_STATS_NAME_MAX);
1647 + break;
1648 }
1649 + }
1650 +}
1651
1598 - pid_t pid = fork();
1599 - if(pid == -1) {
1600 - error("TC: cannot fork child. TC will be disabled.");
1601 - return NULL;
1602 - }
1603 - else if(pid == 0) {
1604 - // the child
1652 +struct tc_device *tc_device_create(char *name)
1653 +{
1654 + struct tc_device *d;
1655
1606 - // close the read fd of the pipe
1607 - close(pipefd[PIPE_READ]);
1656 + d = calloc(sizeof(struct tc_device), 1);
1657 + if(!d) return NULL;
1658
1609 - // attach the pipe to stdout and stderr
1610 - if(dup2(pipefd[PIPE_WRITE], STDOUT_FILENO) == -1) {
1611 - error("TC: cannot attach pipe write to stdout.");
1612 - exit(1);
1613 - }
1614 - if(dup2(pipefd[PIPE_WRITE], STDERR_FILENO) == -1) {
1615 - error("TC: cannot attach pipe write to stderr.");
1616 - exit(1);
1617 - }
1659 + strcpy(d->name, "tc.");
1660 + strncpy(&d->name[3], name, RRD_STATS_NAME_MAX - 3);
1661
1619 - // execute tc to get the output
1620 - execl("/sbin/tc", "-s", "-d", "qdisc", "show", NULL);
1621 - exit(0);
1622 - }
1623 - // the parent
1624 -
1625 - // close the write fd of the pipe
1626 - close(pipefd[PIPE_WRITE]);
1627 -
1628 - // read data from the pipe
1629 - i = 1;
1630 - len = 0;
1631 - while(i > 0 && len < TC_SHOW_MAX) {
1632 - debug(D_TC_LOOP, "TC: Reading from pipe...");
1633 - i = read(pipefd[PIPE_READ], &buffer[len], TC_SHOW_MAX - len);
1634 - if(i > 0) len += i;
1635 - // debug(D_TC_LOOP, "TC READ: '%s'", buffer);
1636 - }
1637 - buffer[len] = '\0';
1638 - debug(D_TC_LOOP, "TC: Completed reading %d bytes.", len);
1639 - close(pipefd[PIPE_READ]);
1662 + return(d);
1663 +}
1664
1641 - // END -- the job is done
1665 +struct tc_class *tc_class_add(struct tc_device *n, char *id, char *parentid)
1666 +{
1667 + struct tc_class *c;
1668
1669 + c = calloc(sizeof(struct tc_class), 1);
1670 + if(!c) return NULL;
1671
1672 + c->next = n->classes;
1673 + n->classes = c;
1674
1645 - // find the time to sleep in order to wait exactly update_every seconds
1646 - gettimeofday(&tmp, NULL);
1647 - usec = usecdiff(&tmp, &now);
1648 - debug(D_TC_LOOP, "TC: This loop took %llu usec.", usec);
1649 -
1650 - if(usec < (update_every * 1000000)) susec = (update_every * 1000000) - usec;
1651 - else susec = 0;
1652 -
1653 - // make sure we will wait at least 100ms
1654 - if(susec < 100000) susec = 100000;
1655 -
1656 - debug(D_TC_LOOP, "TC: Sleeping for %llu usec.", susec);
1657 - usleep(susec);
1658 -
1659 - // copy now to last
1660 - last.tv_sec = now.tv_sec;
1661 - last.tv_usec = now.tv_usec;
1675 + strncpy(c->id, id, RRD_STATS_NAME_MAX);
1676 + strcpy(c->name, c->id);
1677 + if(parentid) strncpy(c->parentid, parentid, RRD_STATS_NAME_MAX);
1678 +
1679 + return(c);
1680 +}
1681 +
1682 +void tc_class_free(struct tc_class *c)
1683 +{
1684 + if(c->next) tc_class_free(c->next);
1685 + free(c);
1686 +}
1687 +
1688 +void tc_device_free(struct tc_device *n)
1689 +{
1690 + if(n->classes) tc_class_free(n->classes);
1691 + free(n);
1692 +}
1693 +
1694 +pid_t tc_child_pid = 0;
1695 +void *tc_main(void *ptr)
1696 +{
1697 + char buffer[TC_LINE_MAX+1] = "";
1698 +
1699 + for(;1;) {
1700 + FILE *fp;
1701 + struct tc_device *device = NULL;
1702 + struct tc_class *class = NULL;
1703 +
1704 + sprintf(buffer, "./tc-all.sh %d", update_every);
1705 + fp = popen(buffer, "r");
1706 +
1707 + while(fgets(buffer, TC_LINE_MAX, fp) != NULL) {
1708 + buffer[TC_LINE_MAX] = '\0';
1709 + char *b = buffer, *p;
1710 + // debug(D_TC_LOOP, "TC: read '%s'", buffer);
1711 +
1712 + p = strsep(&b, " \n");
1713 + while (p && (*p == ' ' || *p == '\0')) p = strsep(&b, " \n");
1714 + if(!p) continue;
1715 +
1716 + if(strcmp(p, "END") == 0) {
1717 + if(device) {
1718 + tc_device_commit(device);
1719 + tc_device_free(device);
1720 + device = NULL;
1721 + class = NULL;
1722 + }
1723 + }
1724 + else if(strcmp(p, "BEGIN") == 0) {
1725 + if(device) tc_device_free(device);
1726 +
1727 + p = strsep(&b, " \n");
1728 + if(p && *p) device = tc_device_create(p);
1729 + }
1730 + else if(device && (strcmp(p, "class") == 0)) {
1731 + p = strsep(&b, " \n"); // the class: htb, fq_codel, etc
1732 + char *id = strsep(&b, " \n"); // the class major:minor
1733 + char *parent = strsep(&b, " \n"); // 'parent' or 'root'
1734 + char *parentid = strsep(&b, " \n"); // the parent's id
1735 +
1736 + if(id && *id
1737 + && parent && *parent
1738 + && parentid && *parentid
1739 + && (
1740 + (strcmp(parent, "parent") == 0 && parentid && *parentid)
1741 + || strcmp(parent, "root") == 0
1742 + )) {
1743 + if(strcmp(parent, "root") == 0) parentid = NULL;
1744 +
1745 + class = tc_class_add(device, id, parentid);
1746 + }
1747 + }
1748 + else if(device && class && (strcmp(p, "Sent") == 0)) {
1749 + p = strsep(&b, " \n");
1750 + if(p && *p) class->bytes = atoll(p);
1751 + }
1752 + else if(device && (strcmp(p, "SETCLASSNAME") == 0)) {
1753 + char *name = strsep(&b, " |\n");
1754 + char *id = strsep(&b, " |\n");
1755 + tc_device_set_class_name(device, id, name);
1756 + }
1757 + else if((strcmp(p, "MYPID") == 0)) {
1758 + char *id = strsep(&b, " \n");
1759 + tc_child_pid = atol(id);
1760 + debug(D_TC_LOOP, "Child PID is %d.", tc_child_pid);
1761 + }
1762 + }
1763 + pclose(fp);
1764 +
1765 + sleep(1);
1766 }
1767
1768 return NULL;
1769 }
1770
1771 +void bye(void)
1772 +{
1773 + if(tc_child_pid) kill(tc_child_pid, SIGTERM);
1774 + tc_child_pid = 0;
1775 +}
1776 +
1777 +void sig_handler(int signo)
1778 +{
1779 + error("Signal %d received.", signo);
1780 +
1781 + switch(signo) {
1782 + case SIGTERM:
1783 + case SIGQUIT:
1784 + case SIGINT:
1785 + case SIGHUP:
1786 + error("Cleanup.");
1787 + if(tc_child_pid) kill(tc_child_pid, SIGTERM);
1788 + tc_child_pid = 0;
1789 + exit(1);
1790 + break;
1791 + }
1792 +}
1793
1794 int main(int argc, char **argv)
1795 {
@@ -1732,6 +1858,13 @@ int main(int argc, char **argv)
1858 silent = 1;
1859 }
1860
1861 + // make sure we cleanup correctly
1862 + atexit(bye);
1863 + if(signal(SIGINT, sig_handler) == SIG_ERR) error("Can't catch SIGINT.");
1864 + if(signal(SIGTERM, sig_handler) == SIG_ERR) error("Can't catch SIGTERM.");
1865 + if(signal(SIGQUIT, sig_handler) == SIG_ERR) error("Can't catch SIGQUIT.");
1866 + if(signal(SIGHUP, sig_handler) == SIG_ERR) error("Can't catch SIGHUP.");
1867 +
1868 pthread_t p_proc, p_tc;
1869 int r_proc, r_tc;
1870
netdata.js
+10 -1
@@ -40,10 +40,19 @@
40 if(height >= 200) hAxisTitle = "Time of Day";
41 if(width >= 400) vAxisTitle = charts[index].vtitle;
42
43 + var title = charts[index].title;
44 +
45 + var isStacked = false;
46 + if(charts[index].name.substring(0, 3) == "tc.") {
47 + isStacked = true;
48 + title += " [stacked]";
49 + }
50 +
51 var options = {
52 width: width,
53 height: height,
46 - title: charts[index].title,
54 + title: title,
55 + isStacked: isStacked,
56 hAxis: {title: hAxisTitle},
57 vAxis: {title: vAxisTitle, minValue: 10},
58 // animation: {duration: 1000, easing: 'inAndOut'},
netdata.start
+11 -3
@@ -75,10 +75,15 @@ else
75 echo >&2 "Directory $base/data already exists. Not touching it, however it should be a link '${data}'."
76 fi
77
78 +cp "${base}/netdata.js" "${data}/"
79 +cp "${base}/tc-all.sh" "${data}/"
80 +chmod 700 "${data}/tc-all.sh"
81 +
82 echo "Finding proper parameters for dashboard..."
83
84 echo "Stopping a (possibly) running netdata..."
85 killall netdata 2>/dev/null
86 +killall tc-all.sh 2>/dev/null
87
88 echo "Compiling netdata"
89 gcc -Wall -O3 -o netdata netdata.c -lpthread || exit 1
@@ -89,7 +94,7 @@ cd data
94 $p/netdata -d -u $NETDATA_CONFIG_INTERNAL_UPDATE_EVERY -l $NETDATA_HISTORY_LINES || exit 1
95 cd "$p"
96
92 -sleep 1
97 +sleep 2
98
99 # count all graphs
100 all=`wget http://127.0.0.1:19999/list -O - 2>/dev/null`
@@ -148,8 +153,6 @@ then
153 fi
154 echo "Final screen size is $w x $h..."
155
151 -cp "${base}/netdata.js" "${data}/"
152 -
156 echo "Generating ${data}/index.html"
157 host="`hostname`"
158 cat >${data}/index.html <<EOF
@@ -199,6 +202,11 @@ do
202 vtitle="I/O in kilobytes/s"
203 ;;
204
205 + tc.*)
206 + title="Class utilization for "
207 + vtitle="bandwidth in kilobits/s"
208 + ;;
209 +
210 esac
211
212 eval "NETDATA_TITLE_${y}=\${NETDATA_TITLE_${y}:-${x}}"
tc-all.sh
+15 -3
@@ -7,14 +7,26 @@ if [ "$x" -eq 0 ]
7 x=1
8 fi
9
10 +echo "MYPID $$"
11 +
12 while [ 1 ]
13 do
14 /sbin/tc qdisc show | cut -d ' ' -f 5 | sort -u | while read x
15 do
14 - echo
15 - echo "DEVICE $x"
16 - echo
16 + echo "BEGIN $x"
17 /sbin/tc -s class show dev $x
18 + if [ -f /var/run/fireqos/ifaces/$x ]
19 + then
20 + name=`cat /var/run/fireqos/ifaces/$x`
21 + # echo "SETDEVICENAME $name"
22 + interface_classes=
23 + source /var/run/fireqos/$name.conf
24 + for x in $interface_classes
25 + do
26 + echo "SETCLASSNAME $x"
27 + done
28 + fi
29 + echo "END $x"
30 done
31
32 sleep $x