1 /* See the DRL-LICENSE file for this file's software license. */
6 #include <libxml/xmlmemory.h>
7 #include <libxml/parser.h>
8 #include <netinet/in.h>
12 #include <sys/socket.h>
14 #include "raterouter.h"
15 #include "ratetypes.h"
20 void free_ident(ident_config *ident) {
22 while (ident->peers) {
23 ident_peer *tofree = ident->peers;
24 ident->peers = ident->peers->next;
29 while (ident->members) {
30 ident_member *tofree = ident->members;
31 ident->members = ident->members->next;
39 void free_ident_list(ident_config *list) {
49 static int xid_filter(const struct dirent *d) {
50 if (atoi(d->d_name) > 0)
56 int get_eligible_leaves(drl_instance_t *instance) {
57 struct dirent **names;
59 leaf_t *leaves = NULL;
60 map_handle leaf_map = allocate_map();
62 if (leaf_map == NULL) {
66 count = scandir("/proc/virtual", &names, xid_filter, alphasort);
72 leaves = malloc(count * sizeof(leaf_t));
74 /* Couldn't allocate leaves array. Need to free names memory. */
82 memset(leaves, 0, count * sizeof(leaf_t));
84 for (i = 0; i < count; ++i) {
85 leaves[i].xid = atoi(names[i]->d_name);
86 leaves[i].parent = NULL;
87 leaves[i].drop_prob = 0.0;
92 map_insert(leaf_map, &leaves[i].xid, sizeof(leaves[i].xid), &leaves[i]);
97 instance->leaf_map = leaf_map;
98 instance->leaves = leaves;
99 instance->leaf_count = count;
104 int parse_leaves(drl_instance_t *instance, char *leafstring) {
107 char *comma = leafstring;
108 leaf_t *leaves = NULL;
111 while ((comma = strchr(comma, ',')) != NULL) {
116 leaf_map = allocate_map();
117 if (leaf_map == NULL) {
121 leaves = malloc(count * sizeof(leaf_t));
122 if (leaves == NULL) {
125 memset(leaves, 0, count * sizeof(leaf_t));
128 for (i = 0; i < count; ++i) {
129 leaves[i].xid = (uint32_t) strtol(comma, NULL, 16);
130 leaves[i].parent = NULL;
131 leaves[i].drop_prob = 0.0;
134 printlog(LOG_DEBUG, "Read leaf - hex: %x, dec: %d\n", leaves[i].xid, leaves[i].xid);
136 comma = strchr(comma, ',');
140 instance->leaf_map = leaf_map;
141 instance->leaves = leaves;
142 instance->leaf_count = count;
147 static int parse_common(xmlDocPtr doc, xmlNodePtr ident, ident_config *common) {
153 xmlChar *failure_behavior;
156 xmlChar *mainloop_intervals;
157 xmlChar *communication_intervals;
158 xmlChar *independent;
161 xmlNodePtr fields = ident->children;
162 ident_peer *current = NULL;
164 /* The struct has been memsetted to 0, this is just to be safe. */
165 #ifdef BUILD_ZOOKEEPER
166 common->zk_host = NULL;
168 common->peers = NULL;
169 common->members = NULL;
172 /* Make sure no required fields are missing. */
173 id = xmlGetProp(ident, (const xmlChar *) "id");
175 printlog(LOG_CRITICAL, "Ident missing globally unique identifier.\n");
178 common->id = atoi((const char *) id);
182 limit = xmlGetProp(ident, (const xmlChar *) "limit");
184 printlog(LOG_CRITICAL, "Ident missing global rate limit.\n");
187 common->limit = atoi((const char *) limit);
191 commfabric = xmlGetProp(ident, (const xmlChar *) "commfabric");
192 if (commfabric == NULL) {
193 printlog(LOG_CRITICAL, "Ident missing comm fabric specifier.\n");
196 if (!xmlStrcmp(commfabric, (const xmlChar *) "MESH")) {
197 common->commfabric = COMM_MESH;
198 } else if (!xmlStrcmp(commfabric, (const xmlChar *) "GOSSIP")) {
199 common->commfabric = COMM_GOSSIP;
201 printlog(LOG_CRITICAL, "Unknown/invalid comm fabric.\n");
208 /* Only care about branching factor and failure detector if we're using gossip. */
209 if (common->commfabric == COMM_GOSSIP) {
210 branch = xmlGetProp(ident, (const xmlChar *) "branch");
211 if (branch == NULL) {
212 printlog(LOG_CRITICAL, "Ident missing gossip branch.\n");
215 common->branch = atoi((const char *) branch);
219 membership = xmlGetProp(ident, (const xmlChar *) "membership");
220 if (membership == NULL) {
221 printlog(LOG_CRITICAL, "Ident missing membership protocol selection.\n");
224 if (!xmlStrcmp(membership, (const xmlChar *) "SWIM")) {
225 common->membership = SWIM;
226 } else if (!xmlStrcmp(membership, (const xmlChar *) "ZOOKEEPER")) {
227 #ifdef BUILD_ZOOKEEPER
228 common->membership = ZOOKEEPER;
230 printlog(LOG_CRITICAL, "Zookeeper requested, but support not compiled into DRL at configure time.\n");
235 printlog(LOG_CRITICAL, "Unknown/invalid gossip group membership protocol.\n");
242 failure_behavior = xmlGetProp(ident, (const xmlChar *) "failure_behavior");
243 if (failure_behavior == NULL) {
244 printlog(LOG_CRITICAL, "Ident missing failure handling behavior.\n");
247 if (!xmlStrcmp(failure_behavior, (const xmlChar *) "PANIC")) {
248 common->failure_behavior = PANIC;
249 } else if (!xmlStrcmp(failure_behavior, (const xmlChar *) "QUORUM")) {
250 common->failure_behavior = QUORUM;
252 printlog(LOG_CRITICAL, "Unknown/invalid gossip failure behavior policy.\n");
253 xmlFree(failure_behavior);
256 xmlFree(failure_behavior);
260 accounting = xmlGetProp(ident, (const xmlChar *) "accounting");
261 if (accounting == NULL) {
262 printlog(LOG_CRITICAL, "Ident missing accounting.\n");
265 if (!xmlStrcmp(accounting, (const xmlChar *) "STANDARD")) {
266 common->accounting = ACT_STANDARD;
267 } else if (!xmlStrcmp(accounting, (const xmlChar *) "SAMPLEHOLD")) {
268 common->accounting = ACT_SAMPLEHOLD;
269 } else if (!xmlStrcmp(accounting, (const xmlChar *) "SIMPLE")) {
270 common->accounting = ACT_SIMPLE;
271 } else if (!xmlStrcmp(accounting, (const xmlChar *) "MULTIPLEINTERVAL")) {
272 common->accounting = ACT_MULTIPLE;
274 printlog(LOG_CRITICAL, "Unknown/invalid accounting table.\n");
281 ewma = xmlGetProp(ident, (const xmlChar *) "ewma");
283 printlog(LOG_CRITICAL, "Ident missing ewma weight.\n");
286 common->fixed_ewma_weight = atof((const char *) ewma);
290 mainloop_intervals = xmlGetProp(ident, (const xmlChar *) "loop_intervals");
291 if (mainloop_intervals == NULL) {
292 printlog(LOG_WARN, "Ident id: %d missing loop_intervals, assuming 1.\n", common->id);
293 common->mainloop_intervals = 1;
295 common->mainloop_intervals = atoi((const char *) mainloop_intervals);
296 xmlFree(mainloop_intervals);
299 communication_intervals = xmlGetProp(ident, (const xmlChar *) "comm_intervals");
300 if (communication_intervals == NULL) {
301 printlog(LOG_WARN, "Ident id: %d missing comm_intervals, assuming 1.\n", common->id);
302 common->communication_intervals = 1;
304 common->communication_intervals = atoi((const char *) communication_intervals);
305 xmlFree(communication_intervals);
308 independent = xmlGetProp(ident, (const xmlChar *) "independent");
309 if (independent == NULL) {
310 common->independent = 0;
312 common->independent = atoi((const char *) independent);
313 xmlFree(independent);
316 htb_node = xmlGetProp(ident, (const xmlChar *) "htb_node");
317 htb_parent = xmlGetProp(ident, (const xmlChar *) "htb_parent");
318 if (htb_node == NULL) {
319 common->htb_node = -1;
321 sscanf((const char *)htb_node, "%x", &common->htb_node);
324 if (htb_parent == NULL) {
325 common->htb_parent = -1;
327 sscanf((const char *)htb_parent, "%x", &common->htb_parent);
331 while (fields != NULL) {
332 if((!xmlStrcmp(fields->name, (const xmlChar *) "peer"))) {
333 xmlChar *ip = xmlNodeListGetString(doc, fields->children, 1);
334 if (current == NULL) {
336 common->peers = malloc(sizeof(ident_peer));
337 if (common->peers == NULL) {
340 common->peers->ip = inet_addr((const char *) ip);
341 common->peers->next = NULL;
342 common->peer_count += 1;
343 current = common->peers;
345 /* Add it to the list. */
346 current->next = malloc(sizeof(ident_peer));
347 if (current->next == NULL) {
350 current = current->next;
351 current->ip = inet_addr((const char *) ip);
352 common->peer_count += 1;
353 current->next = NULL;
356 } else if ((!xmlStrcmp(fields->name, (const xmlChar *) "zkhost"))) {
357 xmlChar *host = xmlNodeListGetString(doc, fields->children, 1);
359 #ifdef BUILD_ZOOKEEPER
360 common->zk_host = strdup((const char *) host);
361 if (common->zk_host == NULL) {
367 fields = fields->next;
370 if (common->peers == NULL) {
371 printlog(LOG_CRITICAL, "Must have at least one peer.\n");
375 #ifdef BUILD_ZOOKEEPER
376 if (common->membership == ZOOKEEPER && common->zk_host == NULL) {
377 printlog(LOG_CRITICAL, "Group membership protocol ZOOKEEPER requires a zkhost field.\n");
385 static ident_config *parse_machine(xmlDocPtr doc, xmlNodePtr ident, parsed_configs *configs) {
386 ident_config *common = malloc(sizeof(ident_config));
388 if (common == NULL) {
392 memset(common, 0, sizeof(ident_config));
393 if (parse_common(doc, ident, common)) {
398 /* No further information needed for machine-level identities. */
399 common->type = IDENT_MACHINE;
400 common->members = NULL;
403 if (configs->last_machine == NULL) {
404 configs->machines = common;
405 configs->last_machine = common;
407 configs->last_machine->next = common;
408 configs->last_machine = common;
411 configs->machine_count += 1;
416 static ident_config *parse_set(xmlDocPtr doc, xmlNodePtr ident, parsed_configs *configs) {
417 xmlNodePtr fields = ident->children;
418 ident_config *common = malloc(sizeof(ident_config));
419 ident_member *current = NULL;
421 if (common == NULL) {
425 memset(common, 0, sizeof(ident_config));
426 if (parse_common(doc, ident, common)) {
431 while (fields != NULL) {
432 ident_member *member = NULL;
434 if (!xmlStrcmp(fields->name, (const xmlChar *) "xid")) {
435 xmlChar *xid = xmlNodeListGetString(doc, fields->children, 1);
437 if (atoi((const char *) xid) >= 0) {
438 member = malloc(sizeof(ident_member));
439 if (member == NULL) {
444 member->type = MEMBER_XID;
445 sscanf((const char *) xid, "%x", &member->value);
454 } else if (!xmlStrcmp(fields->name, (const xmlChar *) "guid")) {
455 xmlChar *guid = xmlNodeListGetString(doc, fields->children, 1);
457 if (atoi((const char *) guid) >= 0) {
458 member = malloc(sizeof(ident_member));
459 if (member == NULL) {
464 member->type = MEMBER_GUID;
465 member->value = atoi((const char *) guid);
477 if (common->members == NULL) {
478 common->members = member;
481 current->next = member;
486 fields = fields->next;
489 /* A sliver set must have at least one member (xid or guid) or else it is
491 if (common->members == NULL) {
496 common->type = IDENT_SET;
499 if (configs->last_set == NULL) {
500 configs->sets = common;
501 configs->last_set = common;
503 configs->last_set->next = common;
504 configs->last_set = common;
507 configs->set_count += 1;
512 int parse_drl_config(const char *configfile, parsed_configs *configs) {
514 xmlNodePtr drl, ident;
516 configs->machines = NULL;
517 configs->sets = NULL;
518 configs->last_machine = NULL;
519 configs->last_set = NULL;
520 configs->machine_count = 0;
521 configs->set_count = 0;
523 if(!(doc = xmlParseFile(configfile))){
524 printlog(LOG_CRITICAL, "Config file (%s) not parsed successfully.\n", configfile);
529 if(!(drl = xmlDocGetRootElement(doc))){
530 printlog(LOG_CRITICAL, "Config file (%s) has no root element.\n", configfile);
534 if(xmlStrcmp(drl->name, (const xmlChar *) "drl")){
535 printlog(LOG_CRITICAL, "Config file (%s) of the wrong type, root node != drl\n", configfile);
540 ident = drl->children;
541 while(ident != NULL) {
542 ident_config *new = NULL;
544 if((!xmlStrcmp(ident->name, (const xmlChar *) "machine"))) {
545 new = parse_machine(doc, ident, configs);
546 } else if ((!xmlStrcmp(ident->name, (const xmlChar *) "set"))) {
547 new = parse_set(doc, ident, configs);
548 } else if ((!xmlStrcmp(ident->name, (const xmlChar *) "text"))) {
549 /* libxml seems to wrap everything inside two 'text's. */
555 /* FIXME: Make this more descriptive. :) */
556 printlog(LOG_CRITICAL, "Error occurred while parsing...\n");
558 free_ident_list(configs->machines);
559 free_ident_list(configs->sets);
561 configs->machines = NULL;
562 configs->sets = NULL;
563 configs->last_machine = NULL;
564 configs->last_set = NULL;
575 /* Return the list of parsed identities. */