X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drl%2Fconfig.c;fp=drl%2Fconfig.c;h=1c56ce89275a34375d05310e332e152516cfa12e;hb=0be9704d6b24d09ebd55beedec52758cb88c570b;hp=0000000000000000000000000000000000000000;hpb=6747e89080a8265aa73320bd9f40a0fa6e1c161e;p=distributedratelimiting.git diff --git a/drl/config.c b/drl/config.c new file mode 100644 index 0000000..1c56ce8 --- /dev/null +++ b/drl/config.c @@ -0,0 +1,427 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "raterouter.h" +#include "ratetypes.h" +#include "config.h" +#include "util.h" +#include "logging.h" + +void free_ident(ident_config *ident) { + /* Free peers. */ + while (ident->peers) { + ident_peer *tofree = ident->peers; + ident->peers = ident->peers->next; + free(tofree); + } + + /* Free members. */ + while (ident->members) { + ident_member *tofree = ident->members; + ident->members = ident->members->next; + free(tofree); + } + + /* Free ident. */ + free(ident); +} + +void free_ident_list(ident_config *list) { + ident_config *tofree; + + while (list) { + tofree = list; + list = list->next; + free_ident(tofree); + } +} + +static int xid_filter(const struct dirent *d) { + if (atoi(d->d_name) > 0) + return 1; + else + return 0; +} + +int get_eligible_leaves(drl_instance_t *instance) { + struct dirent **names; + int count, i; + leaf_t *leaves = NULL; + map_handle leaf_map = allocate_map(); + + if (leaf_map == NULL) { + return ENOMEM; + } + + count = scandir("/proc/virtual", &names, xid_filter, alphasort); + + if (count < 1) { + return 1; + } + + leaves = malloc(count * sizeof(leaf_t)); + if (leaves == NULL) { + /* Couldn't allocate leaves array. Need to free names memory. */ + while (count--) { + free(names[count]); + } + free(names); + + return ENOMEM; + } + + for (i = 0; i < count; ++i) { + leaves[i].xid = atoi(names[i]->d_name); + leaves[i].parent = NULL; + + free(names[i]); + + map_insert(leaf_map, &leaves[i].xid, sizeof(leaves[i].xid), &leaves[i]); + } + + free(names); + + instance->leaf_map = leaf_map; + instance->leaves = leaves; + instance->leaf_count = count; + + return 0; +} + +static int parse_common(xmlDocPtr doc, xmlNodePtr ident, ident_config *common) { + xmlChar *id; + xmlChar *limit; + xmlChar *commfabric; + xmlChar *branch; + xmlChar *accounting; + xmlChar *ewma; + xmlChar *intervals; + xmlNodePtr fields = ident->children; + ident_peer *current = NULL; + + /* Make sure no required fields are missing. */ + id = xmlGetProp(ident, (const xmlChar *) "id"); + if (id == NULL) { + printlog(LOG_CRITICAL, "Ident missing globally unique identifier.\n"); + return EINVAL; + } else { + common->id = atoi((const char *) id); + xmlFree(id); + } + + limit = xmlGetProp(ident, (const xmlChar *) "limit"); + if (limit == NULL) { + printlog(LOG_CRITICAL, "Ident missing global rate limit.\n"); + return EINVAL; + } else { + common->limit = atoi((const char *) limit); + xmlFree(limit); + } + + commfabric = xmlGetProp(ident, (const xmlChar *) "commfabric"); + if (commfabric == NULL) { + printlog(LOG_CRITICAL, "Ident missing comm fabric specifier.\n"); + return EINVAL; + } else { + if (!xmlStrcmp(commfabric, (const xmlChar *) "MESH")) { + common->commfabric = COMM_MESH; + } else if (!xmlStrcmp(commfabric, (const xmlChar *) "GOSSIP")) { + common->commfabric = COMM_GOSSIP; + } else { + printlog(LOG_CRITICAL, "Unknown/invalid comm fabric.\n"); + xmlFree(commfabric); + return EINVAL; + } + xmlFree(commfabric); + } + + /* Only care about branching factor if we're using gossip. */ + if (common->commfabric == COMM_GOSSIP) { + branch = xmlGetProp(ident, (const xmlChar *) "branch"); + if (branch == NULL) { + printlog(LOG_CRITICAL, "Ident missing gossip branch.\n"); + return EINVAL; + } else { + common->branch = atoi((const char *) branch); + xmlFree(branch); + } + } + + accounting = xmlGetProp(ident, (const xmlChar *) "accounting"); + if (accounting == NULL) { + printlog(LOG_CRITICAL, "Ident missing accounting.\n"); + return EINVAL; + } else { + if (!xmlStrcmp(accounting, (const xmlChar *) "STANDARD")) { + common->accounting = ACT_STANDARD; + } else if (!xmlStrcmp(accounting, (const xmlChar *) "SAMPLEHOLD")) { + common->accounting = ACT_SAMPLEHOLD; + } else if (!xmlStrcmp(accounting, (const xmlChar *) "SIMPLE")) { + common->accounting = ACT_SIMPLE; + } else { + printlog(LOG_CRITICAL, "Unknown/invalid accounting table.\n"); + xmlFree(accounting); + return EINVAL; + } + xmlFree(accounting); + } + + ewma = xmlGetProp(ident, (const xmlChar *) "ewma"); + if (ewma == NULL) { + printlog(LOG_CRITICAL, "Ident missing ewma weight.\n"); + return EINVAL; + } else { + common->fixed_ewma_weight = atof((const char *) ewma); + xmlFree(ewma); + } + + intervals = xmlGetProp(ident, (const xmlChar *) "intervals"); + if (intervals == NULL) { + printlog(LOG_CRITICAL, "Ident missing interval count.\n"); + return EINVAL; + } else { + common->intervals = atoi((const char *) intervals); + xmlFree(intervals); + } + + while (fields != NULL) { + if((!xmlStrcmp(fields->name, (const xmlChar *) "peer"))) { + xmlChar *ip = xmlNodeListGetString(doc, fields->children, 1); + if (current == NULL) { + /* No peers yet. */ + common->peers = malloc(sizeof(ident_peer)); + if (common->peers == NULL) { + return ENOMEM; + } + common->peers->ip = inet_addr((const char *) ip); + common->peers->next = NULL; + common->peer_count += 1; + current = common->peers; + } else { + /* Add it to the list. */ + current->next = malloc(sizeof(ident_peer)); + if (current->next == NULL) { + return ENOMEM; + } + current = current->next; + current->ip = inet_addr((const char *) ip); + common->peer_count += 1; + current->next = NULL; + } + xmlFree(ip); + } + fields = fields->next; + } + + if (common->peers == NULL) { + printlog(LOG_CRITICAL, "Must have at least one peer.\n"); + return EINVAL; + } + + /* No errors. */ + return 0; +} + +static ident_config *parse_machine(xmlDocPtr doc, xmlNodePtr ident, parsed_configs *configs) { + ident_config *common = malloc(sizeof(ident_config)); + + if (common == NULL) { + return NULL; + } + + memset(common, 0, sizeof(ident_config)); + if (parse_common(doc, ident, common)) { + free_ident(common); + return NULL; + } + + /* No further information needed for machine-level identities. */ + common->type = IDENT_MACHINE; + common->members = NULL; + common->next = NULL; + + if (configs->last_machine == NULL) { + configs->machines = common; + configs->last_machine = common; + } else { + configs->last_machine->next = common; + configs->last_machine = common; + } + + configs->machine_count += 1; + + return common; +} + +static ident_config *parse_set(xmlDocPtr doc, xmlNodePtr ident, parsed_configs *configs) { + xmlNodePtr fields = ident->children; + ident_config *common = malloc(sizeof(ident_config)); + ident_member *current = NULL; + + if (common == NULL) { + return NULL; + } + + memset(common, 0, sizeof(ident_config)); + if (parse_common(doc, ident, common)) { + free_ident(common); + return NULL; + } + + while (fields != NULL) { + ident_member *member = NULL; + + if (!xmlStrcmp(fields->name, (const xmlChar *) "xid")) { + xmlChar *xid = xmlNodeListGetString(doc, fields->children, 1); + + if (atoi((const char *) xid) >= 0) { + member = malloc(sizeof(ident_member)); + if (member == NULL) { + free_ident(common); + xmlFree(xid); + return NULL; + } + member->type = MEMBER_XID; + sscanf((const char *) xid, "%x", &member->value); + member->next = NULL; + } else { + free_ident(common); + xmlFree(xid); + return NULL; + } + + xmlFree(xid); + } else if (!xmlStrcmp(fields->name, (const xmlChar *) "guid")) { + xmlChar *guid = xmlNodeListGetString(doc, fields->children, 1); + + if (atoi((const char *) guid) >= 0) { + member = malloc(sizeof(ident_member)); + if (member == NULL) { + free_ident(common); + xmlFree(guid); + return NULL; + } + member->type = MEMBER_GUID; + member->value = atoi((const char *) guid); + member->next = NULL; + } else { + free_ident(common); + xmlFree(guid); + return NULL; + } + + xmlFree(guid); + } + + if (member) { + if (common->members == NULL) { + common->members = member; + current = member; + } else { + current->next = member; + current = member; + } + } + + fields = fields->next; + } + + /* A sliver set must have at least one member (xid or guid) or else it is + * meaningless. */ + if (common->members == NULL) { + free_ident(common); + return NULL; + } + + common->type = IDENT_SET; + common->next = NULL; + + if (configs->last_set == NULL) { + configs->sets = common; + configs->last_set = common; + } else { + configs->last_set->next = common; + configs->last_set = common; + } + + configs->set_count += 1; + + return common; +} + +int parse_drl_config(const char *configfile, parsed_configs *configs) { + xmlDocPtr doc; + xmlNodePtr drl, ident; + + configs->machines = NULL; + configs->sets = NULL; + configs->last_machine = NULL; + configs->last_set = NULL; + configs->machine_count = 0; + configs->set_count = 0; + + if(!(doc = xmlParseFile(configfile))){ + printlog(LOG_CRITICAL, "Config file (%s) not parsed successfully.\n", configfile); + xmlFreeDoc(doc); + return EIO; + } + + if(!(drl = xmlDocGetRootElement(doc))){ + printlog(LOG_CRITICAL, "Config file (%s) has no root element.\n", configfile); + xmlFreeDoc(doc); + return EIO; + } + if(xmlStrcmp(drl->name, (const xmlChar *) "drl")){ + printlog(LOG_CRITICAL, "Config file (%s) of the wrong type, root node != drl\n", configfile); + xmlFreeDoc(doc); + return EIO; + } + + ident = drl->children; + while(ident != NULL) { + ident_config *new = NULL; + + if((!xmlStrcmp(ident->name, (const xmlChar *) "machine"))) { + new = parse_machine(doc, ident, configs); + } else if ((!xmlStrcmp(ident->name, (const xmlChar *) "set"))) { + new = parse_set(doc, ident, configs); + } else if ((!xmlStrcmp(ident->name, (const xmlChar *) "text"))) { + /* libxml seems to wrap everything inside two 'text's. */ + ident = ident->next; + continue; + } + + if (new == NULL) { + /* FIXME: Make this more descriptive. :) */ + printlog(LOG_CRITICAL, "Error occurred while parsing...\n"); + + free_ident_list(configs->machines); + free_ident_list(configs->sets); + + configs->machines = NULL; + configs->sets = NULL; + configs->last_machine = NULL; + configs->last_set = NULL; + + xmlFreeDoc(doc); + return 1; + } + + ident = ident->next; + } + + xmlFreeDoc(doc); + + /* Return the list of parsed identities. */ + return 0; +}