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. */
83 for (i = 0; i < count; ++i) {
84 leaves[i].xid = atoi(names[i]->d_name);
85 leaves[i].parent = NULL;
89 map_insert(leaf_map, &leaves[i].xid, sizeof(leaves[i].xid), &leaves[i]);
94 instance->leaf_map = leaf_map;
95 instance->leaves = leaves;
96 instance->leaf_count = count;
101 static int parse_common(xmlDocPtr doc, xmlNodePtr ident, ident_config *common) {
108 xmlChar *mainloop_intervals;
109 xmlChar *communication_intervals;
110 xmlNodePtr fields = ident->children;
111 ident_peer *current = NULL;
113 /* Make sure no required fields are missing. */
114 id = xmlGetProp(ident, (const xmlChar *) "id");
116 printlog(LOG_CRITICAL, "Ident missing globally unique identifier.\n");
119 common->id = atoi((const char *) id);
123 limit = xmlGetProp(ident, (const xmlChar *) "limit");
125 printlog(LOG_CRITICAL, "Ident missing global rate limit.\n");
128 common->limit = atoi((const char *) limit);
132 commfabric = xmlGetProp(ident, (const xmlChar *) "commfabric");
133 if (commfabric == NULL) {
134 printlog(LOG_CRITICAL, "Ident missing comm fabric specifier.\n");
137 if (!xmlStrcmp(commfabric, (const xmlChar *) "MESH")) {
138 common->commfabric = COMM_MESH;
139 } else if (!xmlStrcmp(commfabric, (const xmlChar *) "GOSSIP")) {
140 common->commfabric = COMM_GOSSIP;
142 printlog(LOG_CRITICAL, "Unknown/invalid comm fabric.\n");
149 /* Only care about branching factor if we're using gossip. */
150 if (common->commfabric == COMM_GOSSIP) {
151 branch = xmlGetProp(ident, (const xmlChar *) "branch");
152 if (branch == NULL) {
153 printlog(LOG_CRITICAL, "Ident missing gossip branch.\n");
156 common->branch = atoi((const char *) branch);
161 accounting = xmlGetProp(ident, (const xmlChar *) "accounting");
162 if (accounting == NULL) {
163 printlog(LOG_CRITICAL, "Ident missing accounting.\n");
166 if (!xmlStrcmp(accounting, (const xmlChar *) "STANDARD")) {
167 common->accounting = ACT_STANDARD;
168 } else if (!xmlStrcmp(accounting, (const xmlChar *) "SAMPLEHOLD")) {
169 common->accounting = ACT_SAMPLEHOLD;
170 } else if (!xmlStrcmp(accounting, (const xmlChar *) "SIMPLE")) {
171 common->accounting = ACT_SIMPLE;
172 } else if (!xmlStrcmp(accounting, (const xmlChar *) "MULTIPLEINTERVAL")) {
173 common->accounting = ACT_MULTIPLE;
175 printlog(LOG_CRITICAL, "Unknown/invalid accounting table.\n");
182 ewma = xmlGetProp(ident, (const xmlChar *) "ewma");
184 printlog(LOG_CRITICAL, "Ident missing ewma weight.\n");
187 common->fixed_ewma_weight = atof((const char *) ewma);
191 mainloop_intervals = xmlGetProp(ident, (const xmlChar *) "loop_intervals");
192 if (mainloop_intervals == NULL) {
193 printlog(LOG_WARN, "Ident id: %d missing loop_intervals, assuming 1.\n", common->id);
194 common->mainloop_intervals = 1;
196 common->mainloop_intervals = atoi((const char *) mainloop_intervals);
197 xmlFree(mainloop_intervals);
200 communication_intervals = xmlGetProp(ident, (const xmlChar *) "comm_intervals");
201 if (communication_intervals == NULL) {
202 printlog(LOG_WARN, "Ident id: %d missing comm_intervals, assuming 1.\n", common->id);
203 common->communication_intervals = 1;
205 common->communication_intervals = atoi((const char *) communication_intervals);
206 xmlFree(communication_intervals);
209 while (fields != NULL) {
210 if((!xmlStrcmp(fields->name, (const xmlChar *) "peer"))) {
211 xmlChar *ip = xmlNodeListGetString(doc, fields->children, 1);
212 if (current == NULL) {
214 common->peers = malloc(sizeof(ident_peer));
215 if (common->peers == NULL) {
218 common->peers->ip = inet_addr((const char *) ip);
219 common->peers->next = NULL;
220 common->peer_count += 1;
221 current = common->peers;
223 /* Add it to the list. */
224 current->next = malloc(sizeof(ident_peer));
225 if (current->next == NULL) {
228 current = current->next;
229 current->ip = inet_addr((const char *) ip);
230 common->peer_count += 1;
231 current->next = NULL;
235 fields = fields->next;
238 if (common->peers == NULL) {
239 printlog(LOG_CRITICAL, "Must have at least one peer.\n");
247 static ident_config *parse_machine(xmlDocPtr doc, xmlNodePtr ident, parsed_configs *configs) {
248 ident_config *common = malloc(sizeof(ident_config));
250 if (common == NULL) {
254 memset(common, 0, sizeof(ident_config));
255 if (parse_common(doc, ident, common)) {
260 /* No further information needed for machine-level identities. */
261 common->type = IDENT_MACHINE;
262 common->members = NULL;
265 if (configs->last_machine == NULL) {
266 configs->machines = common;
267 configs->last_machine = common;
269 configs->last_machine->next = common;
270 configs->last_machine = common;
273 configs->machine_count += 1;
278 static ident_config *parse_set(xmlDocPtr doc, xmlNodePtr ident, parsed_configs *configs) {
279 xmlNodePtr fields = ident->children;
280 ident_config *common = malloc(sizeof(ident_config));
281 ident_member *current = NULL;
283 if (common == NULL) {
287 memset(common, 0, sizeof(ident_config));
288 if (parse_common(doc, ident, common)) {
293 while (fields != NULL) {
294 ident_member *member = NULL;
296 if (!xmlStrcmp(fields->name, (const xmlChar *) "xid")) {
297 xmlChar *xid = xmlNodeListGetString(doc, fields->children, 1);
299 if (atoi((const char *) xid) >= 0) {
300 member = malloc(sizeof(ident_member));
301 if (member == NULL) {
306 member->type = MEMBER_XID;
307 sscanf((const char *) xid, "%x", &member->value);
316 } else if (!xmlStrcmp(fields->name, (const xmlChar *) "guid")) {
317 xmlChar *guid = xmlNodeListGetString(doc, fields->children, 1);
319 if (atoi((const char *) guid) >= 0) {
320 member = malloc(sizeof(ident_member));
321 if (member == NULL) {
326 member->type = MEMBER_GUID;
327 member->value = atoi((const char *) guid);
339 if (common->members == NULL) {
340 common->members = member;
343 current->next = member;
348 fields = fields->next;
351 /* A sliver set must have at least one member (xid or guid) or else it is
353 if (common->members == NULL) {
358 common->type = IDENT_SET;
361 if (configs->last_set == NULL) {
362 configs->sets = common;
363 configs->last_set = common;
365 configs->last_set->next = common;
366 configs->last_set = common;
369 configs->set_count += 1;
374 int parse_drl_config(const char *configfile, parsed_configs *configs) {
376 xmlNodePtr drl, ident;
378 configs->machines = NULL;
379 configs->sets = NULL;
380 configs->last_machine = NULL;
381 configs->last_set = NULL;
382 configs->machine_count = 0;
383 configs->set_count = 0;
385 if(!(doc = xmlParseFile(configfile))){
386 printlog(LOG_CRITICAL, "Config file (%s) not parsed successfully.\n", configfile);
391 if(!(drl = xmlDocGetRootElement(doc))){
392 printlog(LOG_CRITICAL, "Config file (%s) has no root element.\n", configfile);
396 if(xmlStrcmp(drl->name, (const xmlChar *) "drl")){
397 printlog(LOG_CRITICAL, "Config file (%s) of the wrong type, root node != drl\n", configfile);
402 ident = drl->children;
403 while(ident != NULL) {
404 ident_config *new = NULL;
406 if((!xmlStrcmp(ident->name, (const xmlChar *) "machine"))) {
407 new = parse_machine(doc, ident, configs);
408 } else if ((!xmlStrcmp(ident->name, (const xmlChar *) "set"))) {
409 new = parse_set(doc, ident, configs);
410 } else if ((!xmlStrcmp(ident->name, (const xmlChar *) "text"))) {
411 /* libxml seems to wrap everything inside two 'text's. */
417 /* FIXME: Make this more descriptive. :) */
418 printlog(LOG_CRITICAL, "Error occurred while parsing...\n");
420 free_ident_list(configs->machines);
421 free_ident_list(configs->sets);
423 configs->machines = NULL;
424 configs->sets = NULL;
425 configs->last_machine = NULL;
426 configs->last_set = NULL;
437 /* Return the list of parsed identities. */