#include "common.h"
#define RRD_TYPE_TC "tc"
#define RRD_TYPE_TC_LEN strlen(RRD_TYPE_TC)
// ----------------------------------------------------------------------------
// /sbin/tc processor
// this requires the script plugins.d/tc-qos-helper.sh
#define TC_LINE_MAX 1024
struct tc_class {
avl avl;
char *id;
uint32_t hash;
char *name;
char *leafid;
uint32_t leaf_hash;
char *parentid;
uint32_t parent_hash;
char hasparent;
char isleaf;
unsigned long long bytes;
unsigned long long packets;
unsigned long long dropped;
unsigned long long overlimits;
unsigned long long requeues;
unsigned long long lended;
unsigned long long borrowed;
unsigned long long giants;
unsigned long long tokens;
unsigned long long ctokens;
RRDDIM *rd_bytes;
RRDDIM *rd_packets;
RRDDIM *rd_dropped;
char name_updated;
char updated; // updated bytes
int seen; // seen in the tc list (even without bytes)
struct tc_class *next;
struct tc_class *prev;
};
struct tc_device {
avl avl;
char *id;
uint32_t hash;
char *name;
char *family;
char name_updated;
char family_updated;
char enabled;
char enabled_bytes;
char enabled_packets;
char enabled_dropped;
RRDSET *st_bytes;
RRDSET *st_packets;
RRDSET *st_dropped;
avl_tree classes_index;
struct tc_class *classes;
struct tc_device *next;
struct tc_device *prev;
};
struct tc_device *tc_device_root = NULL;
// ----------------------------------------------------------------------------
// tc_device index
static int tc_device_compare(void* a, void* b) {
if(((struct tc_device *)a)->hash < ((struct tc_device *)b)->hash) return -1;
else if(((struct tc_device *)a)->hash > ((struct tc_device *)b)->hash) return 1;
else return strcmp(((struct tc_device *)a)->id, ((struct tc_device *)b)->id);
}
avl_tree tc_device_root_index = {
NULL,
tc_device_compare
};
#define tc_device_index_add(st) avl_insert(&tc_device_root_index, (avl *)(st))
#define tc_device_index_del(st) avl_remove(&tc_device_root_index, (avl *)(st))
static inline struct tc_device *tc_device_index_find(const char *id, uint32_t hash) {
struct tc_device tmp;
tmp.id = (char *)id;
tmp.hash = (hash)?hash:simple_hash(tmp.id);
return (struct tc_device *)avl_search(&(tc_device_root_index), (avl *)&tmp);
}
// ----------------------------------------------------------------------------
// tc_class index
static int tc_class_compare(void* a, void* b) {
if(((struct tc_class *)a)->hash < ((struct tc_class *)b)->hash) return -1;
else if(((struct tc_class *)a)->hash > ((struct tc_class *)b)->hash) return 1;
else return strcmp(((struct tc_class *)a)->id, ((struct tc_class *)b)->id);
}
#define tc_class_index_add(st, rd) avl_insert(&((st)->classes_index), (avl *)(rd))
#define tc_class_index_del(st, rd) avl_remove(&((st)->classes_index), (avl *)(rd))
static inline struct tc_class *tc_class_index_find(struct tc_device *st, const char *id, uint32_t hash) {
struct tc_class tmp;
tmp.id = (char *)id;
tmp.hash = (hash)?hash:simple_hash(tmp.id);
return (struct tc_class *)avl_search(&(st->classes_index), (avl *) &tmp);
}
// ----------------------------------------------------------------------------
static inline void tc_class_free(struct tc_device *n, struct tc_class *c) {
debug(D_TC_LOOP, "Removing from device '%s' class '%s', parentid '%s', leafid '%s', seen=%d", n->id, c->id, c->parentid?c->parentid:"", c->leafid?c->leafid:"", c->seen);
if(c->next) c->next->prev =