]> arthur.barton.de Git - netdata.git/commitdiff
added qdiscs to tc plugin
authorStefan Forstenlechner <stefanforstenlechner@gmail.com>
Thu, 15 Dec 2016 15:36:13 +0000 (15:36 +0000)
committerStefan Forstenlechner <stefanforstenlechner@gmail.com>
Mon, 23 Jan 2017 22:45:30 +0000 (23:45 +0100)
plugins.d/tc-qos-helper.sh
src/plugin_tc.c

index e9253c8f256e45b25edf4c67d86cd5d06e2806cb..60342e9fe5378f94c087a4d9b988194a39ff44b3 100755 (executable)
@@ -110,7 +110,6 @@ show_tc_cls() {
         done </etc/iproute2/tc_cls
         return 0
     fi
-
     return 1
 }
 
@@ -145,6 +144,7 @@ show_tc() {
 
     # netdata can parse the output of tc
     ${tc} -s class show dev ${x}
+    ${tc} -s qdisc show dev ${x}
 
     # check FireQOS names for classes
     if [ ! -z "${fix_names}" ]
index f7bbdc707b0cb0f4abc23aef939241d3b9ad605c..83b46fdbc79d26e3da690aa3ab0f61cfae5d6a7c 100644 (file)
@@ -25,6 +25,7 @@ struct tc_class {
 
     char hasparent;
     char isleaf;
+    char isqdisc;
     unsigned long long bytes;
     unsigned long long packets;
     unsigned long long dropped;
@@ -68,7 +69,7 @@ struct tc_device {
     char enabled_dropped;
     char enabled_tokens;
     char enabled_ctokens;
-    char enabled_all_classes;
+    char enabled_all_classes_qdiscs;
 
     RRDSET *st_bytes;
     RRDSET *st_packets;
@@ -185,22 +186,22 @@ static inline void tc_device_classes_cleanup(struct tc_device *d) {
 }
 
 static inline void tc_device_commit(struct tc_device *d) {
-    static int enable_new_interfaces = -1, enable_bytes = -1, enable_packets = -1, enable_dropped = -1, enable_tokens = -1, enable_ctokens = -1, enabled_all_classes = -1;
+    static int enable_new_interfaces = -1, enable_bytes = -1, enable_packets = -1, enable_dropped = -1, enable_tokens = -1, enable_ctokens = -1, enabled_all_classes_qdiscs = -1;
 
     if(unlikely(enable_new_interfaces == -1)) {
-        enable_new_interfaces = config_get_boolean_ondemand("plugin:tc", "enable new interfaces detected at runtime", CONFIG_ONDEMAND_YES);
-        enable_bytes          = config_get_boolean_ondemand("plugin:tc", "enable traffic charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
-        enable_packets        = config_get_boolean_ondemand("plugin:tc", "enable packets charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
-        enable_dropped        = config_get_boolean_ondemand("plugin:tc", "enable dropped charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
-        enable_tokens         = config_get_boolean_ondemand("plugin:tc", "enable tokens charts for all interfaces", CONFIG_ONDEMAND_NO);
-        enable_ctokens        = config_get_boolean_ondemand("plugin:tc", "enable ctokens charts for all interfaces", CONFIG_ONDEMAND_NO);
-        enabled_all_classes   = config_get_boolean_ondemand("plugin:tc", "enable show all classes for all interfaces", CONFIG_ONDEMAND_NO);
+        enable_new_interfaces      = config_get_boolean_ondemand("plugin:tc", "enable new interfaces detected at runtime", CONFIG_ONDEMAND_YES);
+        enable_bytes               = config_get_boolean_ondemand("plugin:tc", "enable traffic charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+        enable_packets             = config_get_boolean_ondemand("plugin:tc", "enable packets charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+        enable_dropped             = config_get_boolean_ondemand("plugin:tc", "enable dropped charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+        enable_tokens              = config_get_boolean_ondemand("plugin:tc", "enable tokens charts for all interfaces", CONFIG_ONDEMAND_NO);
+        enable_ctokens             = config_get_boolean_ondemand("plugin:tc", "enable ctokens charts for all interfaces", CONFIG_ONDEMAND_NO);
+        enabled_all_classes_qdiscs = config_get_boolean_ondemand("plugin:tc", "enable show all classes and qdiscs for all interfaces", CONFIG_ONDEMAND_NO);
     }
 
     // we only need to add leaf classes
     struct tc_class *c, *x;
     unsigned long long bytes_sum = 0, packets_sum = 0, dropped_sum = 0, tokens_sum = 0, ctokens_sum = 0;
-    int active_classes = 0;
+    int active_qos = 0;
 
     // set all classes
     for(c = d->classes ; c ; c = c->next) {
@@ -216,11 +217,12 @@ static inline void tc_device_commit(struct tc_device *d) {
     // mark the classes as leafs and parents
     for(c = d->classes ; c ; c = c->next) {
         if(unlikely(!c->updated)) continue;
+        if(unlikely(c->isqdisc)) continue;
 
         for(x = d->classes ; x ; x = x->next) {
             if(unlikely(!x->updated)) continue;
-
             if(unlikely(c == x)) continue;
+            if(unlikely(x->isqdisc)) continue;
 
             if(x->parentid && (
                 (               c->hash      == x->parent_hash && strcmp(c->id,     x->parentid) == 0) ||
@@ -236,26 +238,29 @@ static inline void tc_device_commit(struct tc_device *d) {
     /*
     if(unlikely(debug_flags & D_TC_LOOP)) {
         for(c = d->classes ; c ; c = c->next) {
-            if((c->isleaf && c->hasparent) || d->enabled_all_classes) debug(D_TC_LOOP, "TC: Device '%s', class %s, OK", d->name, c->id);
+            if((c->isleaf && c->hasparent) || d->enabled_all_classes_qdiscs) debug(D_TC_LOOP, "TC: Device '%s', class %s, OK", d->name, c->id);
             else debug(D_TC_LOOP, "TC: Device '%s', class %s, IGNORE (isleaf: %d, hasparent: %d, parent: %s)", d->name?d->name:d->id, c->id, c->isleaf, c->hasparent, c->parentid?c->parentid:"(unset)");
         }
     }
     */
 
-    // we need at least a class
+    // we need the root qdisc
     for(c = d->classes ; c ; c = c->next) {
         // debug(D_TC_LOOP, "TC: Device '%s', class '%s', isLeaf=%d, HasParent=%d, Seen=%d", d->name?d->name:d->id, c->name?c->name:c->id, c->isleaf, c->hasparent, c->seen);
-        if(unlikely(c->updated && ((c->isleaf && c->hasparent) || d->enabled_all_classes))) {
-            active_classes++;
-            bytes_sum += c->bytes;
-            packets_sum += c->packets;
-            dropped_sum += c->dropped;
-            tokens_sum += c->tokens;
-            ctokens_sum += c->ctokens;
+        debug(D_TC_LOOP, "TC: Device '%s', class '%s', isleaf=%s, isqdisc=%s, hasparent=%s bytes=%d, packtes=%d, dropped=%d, tokens=%d, ctokens=%d", d->name?d->name:d->id, c->name?c->name:c->id, c->isleaf?"true":"false", c->isqdisc?"true":"false", c->hasparent?"true":"false", c->bytes, c->packets, c->dropped, c->tokens, c->ctokens);
+        if(unlikely(c->updated && c->isqdisc && !c->hasparent)) {
+            active_qos = 1;
+            bytes_sum = c->bytes;
+            packets_sum = c->packets;
+            dropped_sum = c->dropped;
+            tokens_sum = c->tokens;
+            ctokens_sum = c->ctokens;
+            debug(D_TC_LOOP, "TC: found root qdisc. active_qos=%d, bytes_sum=%llu", active_qos, bytes_sum);
+            break;
         }
     }
 
-    if(unlikely(!active_classes)) {
+    if(unlikely(!active_qos)) {
         debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. No leaf classes.", d->name?d->name:d->id);
         tc_device_classes_cleanup(d);
         return;
@@ -264,28 +269,28 @@ static inline void tc_device_commit(struct tc_device *d) {
     if(unlikely(d->enabled == (char)-1)) {
         char var_name[CONFIG_MAX_NAME + 1];
         snprintfz(var_name, CONFIG_MAX_NAME, "qos for %s", d->id);
-        d->enabled             = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_new_interfaces);
+        d->enabled                    = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_new_interfaces);
 
         snprintfz(var_name, CONFIG_MAX_NAME, "traffic chart for %s", d->id);
-        d->enabled_bytes       = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_bytes);
+        d->enabled_bytes              = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_bytes);
 
         snprintfz(var_name, CONFIG_MAX_NAME, "packets chart for %s", d->id);
-        d->enabled_packets     = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_packets);
+        d->enabled_packets            = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_packets);
 
         snprintfz(var_name, CONFIG_MAX_NAME, "dropped packets chart for %s", d->id);
-        d->enabled_dropped     = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_dropped);
+        d->enabled_dropped            = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_dropped);
 
         snprintfz(var_name, CONFIG_MAX_NAME, "tokens chart for %s", d->id);
-        d->enabled_tokens      = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_tokens);
+        d->enabled_tokens             = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_tokens);
 
         snprintfz(var_name, CONFIG_MAX_NAME, "ctokens chart for %s", d->id);
-        d->enabled_ctokens     = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_ctokens);
+        d->enabled_ctokens            = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_ctokens);
 
         snprintfz(var_name, CONFIG_MAX_NAME, "show all classes for %s", d->id);
-        d->enabled_all_classes = (char)config_get_boolean_ondemand("plugin:tc", var_name, enabled_all_classes);
+        d->enabled_all_classes_qdiscs = (char)config_get_boolean_ondemand("plugin:tc", var_name, enabled_all_classes_qdiscs);
     }
 
-    debug(D_TC_LOOP, "TC: evaluating TC device '%s'. enabled = %d/%d (bytes: %d/%d, packets: %d/%d, dropped: %d/%d, tokens: %d/%d, ctokens: %d/%d), classes = %d (bytes = %llu, packets = %llu, dropped = %llu, tokens = %llu, ctokens = %llu).",
+    debug(D_TC_LOOP, "TC: evaluating TC device '%s'. enabled = %d/%d (bytes: %d/%d, packets: %d/%d, dropped: %d/%d, tokens: %d/%d, ctokens: %d/%d, all_classes_qdiscs: %d/%d), classes: (bytes = %llu, packets = %llu, dropped = %llu, tokens = %llu, ctokens = %llu).",
         d->name?d->name:d->id,
         d->enabled, enable_new_interfaces,
         d->enabled_bytes, enable_bytes,
@@ -293,8 +298,7 @@ static inline void tc_device_commit(struct tc_device *d) {
         d->enabled_dropped, enable_dropped,
         d->enabled_tokens, enable_tokens,
         d->enabled_ctokens, enable_ctokens,
-        d->enabled_all_classes, enabled_all_classes,
-        active_classes,
+        d->enabled_all_classes_qdiscs, enabled_all_classes_qdiscs,
         bytes_sum,
         packets_sum,
         dropped_sum,
@@ -332,7 +336,7 @@ static inline void tc_device_commit(struct tc_device *d) {
             for(c = d->classes ; c ; c = c->next) {
                 if(unlikely(!c->updated)) continue;
 
-                if((c->isleaf && c->hasparent) || d->enabled_all_classes) {
+                if((c->isleaf && c->hasparent && !c->isqdisc) || d->enabled_all_classes_qdiscs) {
                     if(unlikely(!c->rd_bytes)) {
                         c->rd_bytes = rrddim_find(d->st_bytes, c->id);
                         if(unlikely(!c->rd_bytes)) {
@@ -386,7 +390,7 @@ static inline void tc_device_commit(struct tc_device *d) {
             for(c = d->classes ; c ; c = c->next) {
                 if(unlikely(!c->updated)) continue;
 
-                if((c->isleaf && c->hasparent) || d->enabled_all_classes) {
+                if((c->isleaf && c->hasparent && !c->isqdisc) || d->enabled_all_classes_qdiscs) {
                     if(unlikely(!c->rd_packets)) {
                         c->rd_packets = rrddim_find(d->st_packets, c->id);
                         if(unlikely(!c->rd_packets)) {
@@ -440,7 +444,7 @@ static inline void tc_device_commit(struct tc_device *d) {
             for(c = d->classes ; c ; c = c->next) {
                 if(unlikely(!c->updated)) continue;
 
-                if((c->isleaf && c->hasparent) || d->enabled_all_classes) {
+                if((c->isleaf && c->hasparent && !c->isqdisc) || d->enabled_all_classes_qdiscs) {
                     if(unlikely(!c->rd_dropped)) {
                         c->rd_dropped = rrddim_find(d->st_dropped, c->id);
                         if(unlikely(!c->rd_dropped)) {
@@ -494,7 +498,7 @@ static inline void tc_device_commit(struct tc_device *d) {
             for(c = d->classes ; c ; c = c->next) {
                 if(unlikely(!c->updated)) continue;
 
-                if((c->isleaf && c->hasparent) || d->enabled_all_classes) {
+                if((c->isleaf && c->hasparent && !c->isqdisc) || d->enabled_all_classes_qdiscs) {
                     if(unlikely(!c->rd_tokens)) {
                         c->rd_tokens = rrddim_find(d->st_tokens, c->id);
                         if(unlikely(!c->rd_tokens)) {
@@ -548,7 +552,7 @@ static inline void tc_device_commit(struct tc_device *d) {
             for(c = d->classes ; c ; c = c->next) {
                 if(unlikely(!c->updated)) continue;
 
-                if((c->isleaf && c->hasparent) || d->enabled_all_classes) {
+                if((c->isleaf && c->hasparent && !c->isqdisc) || d->enabled_all_classes_qdiscs) {
                     if(unlikely(!c->rd_ctokens)) {
                         c->rd_ctokens = rrddim_find(d->st_ctokens, c->id);
                         if(unlikely(!c->rd_ctokens)) {
@@ -645,7 +649,7 @@ static inline struct tc_device *tc_device_create(char *id)
     return(d);
 }
 
-static inline struct tc_class *tc_class_add(struct tc_device *n, char *id, char *parentid, char *leafid)
+static inline struct tc_class *tc_class_add(struct tc_device *n, char *id, char qdisc, char *parentid, char *leafid)
 {
     struct tc_class *c = tc_class_index_find(n, id, 0);
 
@@ -661,6 +665,7 @@ static inline struct tc_class *tc_class_add(struct tc_device *n, char *id, char
         c->id = strdupz(id);
         c->hash = simple_hash(c->id);
 
+        c->isqdisc = qdisc;
         if(parentid && *parentid) {
             c->parentid = strdupz(parentid);
             c->parent_hash = simple_hash(c->parentid);
@@ -773,6 +778,7 @@ void *tc_main(void *ptr) {
 
     uint32_t BEGIN_HASH = simple_hash("BEGIN");
     uint32_t END_HASH = simple_hash("END");
+    uint32_t QDISC_HASH = simple_hash("qdisc");
     uint32_t CLASS_HASH = simple_hash("class");
     uint32_t SENT_HASH = simple_hash("Sent");
     uint32_t LENDED_HASH = simple_hash("lended:");
@@ -821,7 +827,7 @@ void *tc_main(void *ptr) {
 
             first_hash = simple_hash(words[0]);
 
-            if(unlikely(device && first_hash == CLASS_HASH && strcmp(words[0], "class") == 0)) {
+            if(unlikely(device && ((first_hash == CLASS_HASH && strcmp(words[0], "class") == 0) ||  (first_hash == QDISC_HASH && strcmp(words[0], "qdisc") == 0)))) {
                 // debug(D_TC_LOOP, "CLASS line on class id='%s', parent='%s', parentid='%s', leaf='%s', leafid='%s'", words[2], words[3], words[4], words[5], words[6]);
 
                 // words[1] : class type
@@ -838,7 +844,11 @@ void *tc_main(void *ptr) {
                     char *parentid = words[4];  // the parent's id
                     char *leaf     = words[5];  // 'leaf'
                     char *leafid   = words[6];  // leafid
+                    char qdisc = 0;
 
+                    if(strcmp(words[0], "qdisc") == 0) {
+                        qdisc = 1;
+                    }
                     if(strcmp(parent, "root") == 0) {
                         parentid = NULL;
                         leafid = NULL;
@@ -853,7 +863,7 @@ void *tc_main(void *ptr) {
                         leafid = leafbuf;
                     }
 
-                    class = tc_class_add(device, id, parentid, leafid);
+                    class = tc_class_add(device, id, qdisc, parentid, leafid);
                 }
                 else {
                     // clear the last class