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