X-Git-Url: https://arthur.barton.de/gitweb/?a=blobdiff_plain;f=src%2Fplugin_tc.c;h=7dcfedb33e56d6db1e0a60bc55b8b39fdef44360;hb=61bf5dc9fbaa494684246728e2fb48a0ab25fc95;hp=95a4d3dcadb29ec43cd5dc8080204ceefcf6dbd7;hpb=2b183c2ab992540571df2d2d01c8b14edf038a42;p=netdata.git diff --git a/src/plugin_tc.c b/src/plugin_tc.c index 95a4d3dc..7dcfedb3 100644 --- a/src/plugin_tc.c +++ b/src/plugin_tc.c @@ -190,13 +190,13 @@ 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_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_qdiscs = config_get_boolean_ondemand("plugin:tc", "enable show all classes and qdiscs for all interfaces", CONFIG_ONDEMAND_NO); + enable_new_interfaces = config_get_boolean_ondemand("plugin:tc", "enable new interfaces detected at runtime", CONFIG_BOOLEAN_YES); + enable_bytes = config_get_boolean_ondemand("plugin:tc", "enable traffic charts for all interfaces", CONFIG_BOOLEAN_AUTO); + enable_packets = config_get_boolean_ondemand("plugin:tc", "enable packets charts for all interfaces", CONFIG_BOOLEAN_AUTO); + enable_dropped = config_get_boolean_ondemand("plugin:tc", "enable dropped charts for all interfaces", CONFIG_BOOLEAN_AUTO); + enable_tokens = config_get_boolean_ondemand("plugin:tc", "enable tokens charts for all interfaces", CONFIG_BOOLEAN_NO); + enable_ctokens = config_get_boolean_ondemand("plugin:tc", "enable ctokens charts for all interfaces", CONFIG_BOOLEAN_NO); + enabled_all_classes_qdiscs = config_get_boolean_ondemand("plugin:tc", "enable show all classes and qdiscs for all interfaces", CONFIG_BOOLEAN_NO); } if(unlikely(d->enabled == (char)-1)) { @@ -230,17 +230,20 @@ static inline void tc_device_commit(struct tc_device *d) { int active_nodes = 0, updated_classes = 0, updated_qdiscs = 0; // prepare all classes + // we set reasonable defaults for the rest of the code below + for(c = d->classes ; c ; c = c->next) { - c->render = 0; + c->render = 0; // do not render this class - c->isleaf = 1; - c->hasparent = 0; + c->isleaf = 1; // this is a leaf class + c->hasparent = 0; // without a parent if(unlikely(!c->updated)) - c->unupdated++; + c->unupdated++; // increase its unupdated counter else { - c->unupdated = 0; + c->unupdated = 0; // reset its unupdated counter + // count how many of each kind if(c->isqdisc) updated_qdiscs++; else @@ -256,6 +259,8 @@ static inline void tc_device_commit(struct tc_device *d) { if(unlikely(updated_classes && updated_qdiscs)) { error("TC: device '%s' has active both classes (%d) and qdiscs (%d). Will render only qdiscs.", d->id, updated_classes, updated_qdiscs); + + // set all classes to !updated for(c = d->classes ; c ; c = c->next) if(unlikely(!c->isqdisc && c->updated)) c->updated = 0; @@ -264,39 +269,49 @@ 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; - - //debug(D_TC_LOOP, "TC: In device '%s', %s '%s' has leafid: '%s' and parentid '%s'.", - // d->id, - // c->isqdisc?"qdisc":"class", - // c->id, - // c->leafid?c->leafid:"NULL", - // c->parentid?c->parentid:"NULL"); - - // find if c is leaf or not - for(x = d->classes; x; x = x->next) { - if(unlikely(!x->updated || c == x || !x->parentid)) continue; - - if( (c->hash == x->parent_hash && strcmp(c->id, x->parentid) == 0) || - (c->leafid && c->leaf_hash == x->parent_hash && strcmp(c->leafid, x->parentid) == 0)) { - // debug(D_TC_LOOP, "TC: In device '%s', %s '%s' (leafid: '%s') has as leaf %s '%s' (parentid: '%s').", d->name?d->name:d->id, c->isqdisc?"qdisc":"class", c->name?c->name:c->id, c->leafid?c->leafid:c->id, x->isqdisc?"qdisc":"class", x->name?x->name:x->id, x->parentid?x->parentid:x->id); - c->isleaf = 0; - x->hasparent = 1; + // + // TC is hierarchical: + // - classes can have other classes in them + // - the same is true for qdiscs (i.e. qdiscs have classes, that have other qdiscs) + // + // we need to present a chart with leaf nodes only, so that the sum + // of all dimensions of the chart, will be the total utilization + // of the interface. + // + // here we try to find the ones we need to report + // by default all nodes are marked with: isleaf = 1 (see above) + // + // so, here we remove the isleaf flag from nodes in the middle + // and we add the hasparent flag to leaf nodes we found their parent + if(likely(!d->enabled_all_classes_qdiscs)) { + for(c = d->classes; c; c = c->next) { + if(unlikely(!c->updated)) continue; + + //debug(D_TC_LOOP, "TC: In device '%s', %s '%s' has leafid: '%s' and parentid '%s'.", + // d->id, + // c->isqdisc?"qdisc":"class", + // c->id, + // c->leafid?c->leafid:"NULL", + // c->parentid?c->parentid:"NULL"); + + // find if c is leaf or not + for(x = d->classes; x; x = x->next) { + if(unlikely(!x->updated || c == x || !x->parentid)) continue; + + // classes have both parentid and leafid + // qdiscs have only parentid + // the following works for both (it is an OR) + + if((c->hash == x->parent_hash && strcmp(c->id, x->parentid) == 0) || + (c->leafid && c->leaf_hash == x->parent_hash && strcmp(c->leafid, x->parentid) == 0)) { + // debug(D_TC_LOOP, "TC: In device '%s', %s '%s' (leafid: '%s') has as leaf %s '%s' (parentid: '%s').", d->name?d->name:d->id, c->isqdisc?"qdisc":"class", c->name?c->name:c->id, c->leafid?c->leafid:c->id, x->isqdisc?"qdisc":"class", x->name?x->name:x->id, x->parentid?x->parentid:x->id); + c->isleaf = 0; + x->hasparent = 1; + } } } } - // debugging only - /* - if(unlikely(debug_flags & D_TC_LOOP)) { - for(c = d->classes ; c ; c = c->next) { - if((c->isleaf && c->hasparent) || d->enabled_all_classes_qdiscs) debug(D_TC_LOOP, "TC: final nodes dump for '%s': class %s, OK", d->name, c->id); - else debug(D_TC_LOOP, "TC: final nodes dump for '%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)"); - } - } - */ - for(c = d->classes ; c ; c = c->next) { if(unlikely(!c->updated)) continue; @@ -319,6 +334,17 @@ static inline void tc_device_commit(struct tc_device *d) { //} } +#ifdef NETDATA_INTERNAL_CHECKS + // dump all the list to see what we know + + if(unlikely(debug_flags & D_TC_LOOP)) { + for(c = d->classes ; c ; c = c->next) { + if(c->render) debug(D_TC_LOOP, "TC: final nodes dump for '%s': class %s, OK", d->name, c->id); + else debug(D_TC_LOOP, "TC: final nodes dump for '%s': class %s, IGNORE (updated: %d, isleaf: %d, hasparent: %d, parent: %s)", d->name?d->name:d->id, c->id, c->updated, c->isleaf, c->hasparent, c->parentid?c->parentid:"(unset)"); + } + } +#endif + if(unlikely(!active_nodes)) { debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. No useful classes/qdiscs.", d->name?d->name:d->id); tc_device_classes_cleanup(d); @@ -344,11 +370,15 @@ static inline void tc_device_commit(struct tc_device *d) { // -------------------------------------------------------------------- // bytes - if(d->enabled_bytes == CONFIG_ONDEMAND_YES || (d->enabled_bytes == CONFIG_ONDEMAND_ONDEMAND && bytes_sum)) { - d->enabled_bytes = CONFIG_ONDEMAND_YES; + if(d->enabled_bytes == CONFIG_BOOLEAN_YES || (d->enabled_bytes == CONFIG_BOOLEAN_AUTO && bytes_sum)) { + d->enabled_bytes = CONFIG_BOOLEAN_YES; if(unlikely(!d->st_bytes)) - d->st_bytes = rrdset_create(RRD_TYPE_TC, d->id, d->name?d->name:d->id, d->family?d->family:d->id, RRD_TYPE_TC ".qos", "Class Usage", "kilobits/s", 7000, rrd_update_every, d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE : RRDSET_TYPE_STACKED); + d->st_bytes = rrdset_create_localhost(RRD_TYPE_TC, d->id, d->name ? d->name : d->id + , d->family ? d->family : d->id, RRD_TYPE_TC ".qos", "Class Usage" + , "kilobits/s", 7000, localhost->rrd_update_every + , d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE + : RRDSET_TYPE_STACKED); else { rrdset_next(d->st_bytes); @@ -362,7 +392,7 @@ static inline void tc_device_commit(struct tc_device *d) { if(unlikely(!c->render)) continue; if(unlikely(!c->rd_bytes)) - c->rd_bytes = rrddim_add(d->st_bytes, c->id, c->name?c->name:c->id, 8, 1024, RRDDIM_INCREMENTAL); + c->rd_bytes = rrddim_add(d->st_bytes, c->id, c->name?c->name:c->id, 8, 1024, RRD_ALGORITHM_INCREMENTAL); else if(unlikely(c->name_updated)) rrddim_set_name(d->st_bytes, c->rd_bytes, c->name); @@ -374,8 +404,8 @@ static inline void tc_device_commit(struct tc_device *d) { // -------------------------------------------------------------------- // packets - if(d->enabled_packets == CONFIG_ONDEMAND_YES || (d->enabled_packets == CONFIG_ONDEMAND_ONDEMAND && packets_sum)) { - d->enabled_packets = CONFIG_ONDEMAND_YES; + if(d->enabled_packets == CONFIG_BOOLEAN_YES || (d->enabled_packets == CONFIG_BOOLEAN_AUTO && packets_sum)) { + d->enabled_packets = CONFIG_BOOLEAN_YES; if(unlikely(!d->st_packets)) { char id[RRD_ID_LENGTH_MAX + 1]; @@ -383,7 +413,10 @@ static inline void tc_device_commit(struct tc_device *d) { snprintfz(id, RRD_ID_LENGTH_MAX, "%s_packets", d->id); snprintfz(name, RRD_ID_LENGTH_MAX, "%s_packets", d->name?d->name:d->id); - d->st_packets = rrdset_create(RRD_TYPE_TC, id, name, d->family?d->family:d->id, RRD_TYPE_TC ".qos_packets", "Class Packets", "packets/s", 7010, rrd_update_every, d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE : RRDSET_TYPE_STACKED); + d->st_packets = rrdset_create_localhost(RRD_TYPE_TC, id, name, d->family ? d->family : d->id + , RRD_TYPE_TC ".qos_packets", "Class Packets", "packets/s", 7010 + , localhost->rrd_update_every, d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE + : RRDSET_TYPE_STACKED); } else { rrdset_next(d->st_packets); @@ -402,7 +435,7 @@ static inline void tc_device_commit(struct tc_device *d) { if(unlikely(!c->render)) continue; if(unlikely(!c->rd_packets)) - c->rd_packets = rrddim_add(d->st_packets, c->id, c->name?c->name:c->id, 1, 1, RRDDIM_INCREMENTAL); + c->rd_packets = rrddim_add(d->st_packets, c->id, c->name?c->name:c->id, 1, 1, RRD_ALGORITHM_INCREMENTAL); else if(unlikely(c->name_updated)) rrddim_set_name(d->st_packets, c->rd_packets, c->name); @@ -414,8 +447,8 @@ static inline void tc_device_commit(struct tc_device *d) { // -------------------------------------------------------------------- // dropped - if(d->enabled_dropped == CONFIG_ONDEMAND_YES || (d->enabled_dropped == CONFIG_ONDEMAND_ONDEMAND && dropped_sum)) { - d->enabled_dropped = CONFIG_ONDEMAND_YES; + if(d->enabled_dropped == CONFIG_BOOLEAN_YES || (d->enabled_dropped == CONFIG_BOOLEAN_AUTO && dropped_sum)) { + d->enabled_dropped = CONFIG_BOOLEAN_YES; if(unlikely(!d->st_dropped)) { char id[RRD_ID_LENGTH_MAX + 1]; @@ -423,7 +456,11 @@ static inline void tc_device_commit(struct tc_device *d) { snprintfz(id, RRD_ID_LENGTH_MAX, "%s_dropped", d->id); snprintfz(name, RRD_ID_LENGTH_MAX, "%s_dropped", d->name?d->name:d->id); - d->st_dropped = rrdset_create(RRD_TYPE_TC, id, name, d->family?d->family:d->id, RRD_TYPE_TC ".qos_dropped", "Class Dropped Packets", "packets/s", 7020, rrd_update_every, d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE : RRDSET_TYPE_STACKED); + d->st_dropped = rrdset_create_localhost(RRD_TYPE_TC, id, name, d->family ? d->family : d->id + , RRD_TYPE_TC ".qos_dropped", "Class Dropped Packets", "packets/s" + , 7020, localhost->rrd_update_every + , d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE + : RRDSET_TYPE_STACKED); } else { rrdset_next(d->st_dropped); @@ -442,7 +479,7 @@ static inline void tc_device_commit(struct tc_device *d) { if(unlikely(!c->render)) continue; if(unlikely(!c->rd_dropped)) - c->rd_dropped = rrddim_add(d->st_dropped, c->id, c->name?c->name:c->id, 1, 1, RRDDIM_INCREMENTAL); + c->rd_dropped = rrddim_add(d->st_dropped, c->id, c->name?c->name:c->id, 1, 1, RRD_ALGORITHM_INCREMENTAL); else if(unlikely(c->name_updated)) rrddim_set_name(d->st_dropped, c->rd_dropped, c->name); @@ -454,8 +491,8 @@ static inline void tc_device_commit(struct tc_device *d) { // -------------------------------------------------------------------- // tokens - if(d->enabled_tokens == CONFIG_ONDEMAND_YES || (d->enabled_tokens == CONFIG_ONDEMAND_ONDEMAND && tokens_sum)) { - d->enabled_tokens = CONFIG_ONDEMAND_YES; + if(d->enabled_tokens == CONFIG_BOOLEAN_YES || (d->enabled_tokens == CONFIG_BOOLEAN_AUTO && tokens_sum)) { + d->enabled_tokens = CONFIG_BOOLEAN_YES; if(unlikely(!d->st_tokens)) { char id[RRD_ID_LENGTH_MAX + 1]; @@ -463,7 +500,9 @@ static inline void tc_device_commit(struct tc_device *d) { snprintfz(id, RRD_ID_LENGTH_MAX, "%s_tokens", d->id); snprintfz(name, RRD_ID_LENGTH_MAX, "%s_tokens", d->name?d->name:d->id); - d->st_tokens = rrdset_create(RRD_TYPE_TC, id, name, d->family?d->family:d->id, RRD_TYPE_TC ".qos_tokens", "Class Tokens", "tokens", 7030, rrd_update_every, RRDSET_TYPE_LINE); + d->st_tokens = rrdset_create_localhost(RRD_TYPE_TC, id, name, d->family ? d->family : d->id + , RRD_TYPE_TC ".qos_tokens", "Class Tokens", "tokens", 7030 + , localhost->rrd_update_every, RRDSET_TYPE_LINE); } else { rrdset_next(d->st_tokens); @@ -482,7 +521,7 @@ static inline void tc_device_commit(struct tc_device *d) { if(unlikely(!c->render)) continue; if(unlikely(!c->rd_tokens)) { - c->rd_tokens = rrddim_add(d->st_tokens, c->id, c->name?c->name:c->id, 1, 1, RRDDIM_ABSOLUTE); + c->rd_tokens = rrddim_add(d->st_tokens, c->id, c->name?c->name:c->id, 1, 1, RRD_ALGORITHM_ABSOLUTE); } else if(unlikely(c->name_updated)) rrddim_set_name(d->st_tokens, c->rd_tokens, c->name); @@ -495,8 +534,8 @@ static inline void tc_device_commit(struct tc_device *d) { // -------------------------------------------------------------------- // ctokens - if(d->enabled_ctokens == CONFIG_ONDEMAND_YES || (d->enabled_ctokens == CONFIG_ONDEMAND_ONDEMAND && ctokens_sum)) { - d->enabled_ctokens = CONFIG_ONDEMAND_YES; + if(d->enabled_ctokens == CONFIG_BOOLEAN_YES || (d->enabled_ctokens == CONFIG_BOOLEAN_AUTO && ctokens_sum)) { + d->enabled_ctokens = CONFIG_BOOLEAN_YES; if(unlikely(!d->st_ctokens)) { char id[RRD_ID_LENGTH_MAX + 1]; @@ -504,7 +543,9 @@ static inline void tc_device_commit(struct tc_device *d) { snprintfz(id, RRD_ID_LENGTH_MAX, "%s_ctokens", d->id); snprintfz(name, RRD_ID_LENGTH_MAX, "%s_ctokens", d->name?d->name:d->id); - d->st_ctokens = rrdset_create(RRD_TYPE_TC, id, name, d->family?d->family:d->id, RRD_TYPE_TC ".qos_ctokens", "Class cTokens", "ctokens", 7040, rrd_update_every, RRDSET_TYPE_LINE); + d->st_ctokens = rrdset_create_localhost(RRD_TYPE_TC, id, name, d->family ? d->family : d->id + , RRD_TYPE_TC ".qos_ctokens", "Class cTokens", "ctokens", 7040 + , localhost->rrd_update_every, RRDSET_TYPE_LINE); } else { debug(D_TC_LOOP, "TC: Updating _ctokens chart for device '%s'", d->name?d->name:d->id); @@ -524,7 +565,7 @@ static inline void tc_device_commit(struct tc_device *d) { if(unlikely(!c->render)) continue; if(unlikely(!c->rd_ctokens)) - c->rd_ctokens = rrddim_add(d->st_ctokens, c->id, c->name?c->name:c->id, 1, 1, RRDDIM_ABSOLUTE); + c->rd_ctokens = rrddim_add(d->st_ctokens, c->id, c->name?c->name:c->id, 1, 1, RRD_ALGORITHM_ABSOLUTE); else if(unlikely(c->name_updated)) rrddim_set_name(d->st_ctokens, c->rd_ctokens, c->name); @@ -756,7 +797,7 @@ void *tc_main(void *ptr) { #endif uint32_t first_hash; - snprintfz(buffer, TC_LINE_MAX, "%s/tc-qos-helper.sh", config_get("plugins", "plugins directory", PLUGINS_DIR)); + snprintfz(buffer, TC_LINE_MAX, "%s/tc-qos-helper.sh", netdata_configured_plugins_dir); char *tc_script = config_get("plugin:tc", "script to run to get tc values", buffer); for(;1;) { @@ -766,7 +807,7 @@ void *tc_main(void *ptr) { struct tc_device *device = NULL; struct tc_class *class = NULL; - snprintfz(buffer, TC_LINE_MAX, "exec %s %d", tc_script, rrd_update_every); + snprintfz(buffer, TC_LINE_MAX, "exec %s %d", tc_script, localhost->rrd_update_every); debug(D_TC_LOOP, "executing '%s'", buffer); fp = mypopen(buffer, (pid_t *)&tc_child_pid); @@ -826,6 +867,9 @@ void *tc_main(void *ptr) { if(parent_is_parent && parentid) { // eliminate the minor number from parentid + // why: parentid is the id of the parent class + // but major: is also the id of the parent qdisc + char *s = parentid; while(*s && *s != ':') s++; if(*s == ':') s[1] = '\0'; @@ -945,11 +989,13 @@ void *tc_main(void *ptr) { // debug(D_TC_LOOP, "WORKTIME line '%s' '%s'", words[1], words[2]); getrusage(RUSAGE_THREAD, &thread); - if(unlikely(!stcpu)) stcpu = rrdset_find("netdata.plugin_tc_cpu"); + if(unlikely(!stcpu)) stcpu = rrdset_find_localhost("netdata.plugin_tc_cpu"); if(unlikely(!stcpu)) { - stcpu = rrdset_create("netdata", "plugin_tc_cpu", NULL, "tc.helper", NULL, "NetData TC CPU usage", "milliseconds/s", 135000, rrd_update_every, RRDSET_TYPE_STACKED); - rrddim_add(stcpu, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL); - rrddim_add(stcpu, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL); + stcpu = rrdset_create_localhost("netdata", "plugin_tc_cpu", NULL, "tc.helper", NULL + , "NetData TC CPU usage", "milliseconds/s", 135000, localhost->rrd_update_every + , RRDSET_TYPE_STACKED); + rrddim_add(stcpu, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); + rrddim_add(stcpu, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(stcpu); @@ -957,10 +1003,12 @@ void *tc_main(void *ptr) { rrddim_set(stcpu, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec); rrdset_done(stcpu); - if(unlikely(!sttime)) stcpu = rrdset_find("netdata.plugin_tc_time"); + if(unlikely(!sttime)) sttime = rrdset_find_localhost("netdata.plugin_tc_time"); if(unlikely(!sttime)) { - sttime = rrdset_create("netdata", "plugin_tc_time", NULL, "tc.helper", NULL, "NetData TC script execution", "milliseconds/run", 135001, rrd_update_every, RRDSET_TYPE_AREA); - rrddim_add(sttime, "run_time", "run time", 1, 1, RRDDIM_ABSOLUTE); + sttime = rrdset_create_localhost("netdata", "plugin_tc_time", NULL, "tc.helper", NULL + , "NetData TC script execution", "milliseconds/run", 135001 + , localhost->rrd_update_every, RRDSET_TYPE_AREA); + rrddim_add(sttime, "run_time", "run time", 1, 1, RRD_ALGORITHM_ABSOLUTE); } else rrdset_next(sttime); @@ -1008,7 +1056,7 @@ void *tc_main(void *ptr) { goto cleanup; } - sleep((unsigned int) rrd_update_every); + sleep((unsigned int) localhost->rrd_update_every); } cleanup: