/* 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; }