ef2a17ba4ed1053ff689255ddf6b6f652f474044
[distributedratelimiting.git] / drl / ulogd_DRL.c
1 /* See the DRL-LICENSE file for this file's software license. */
2
3 /*
4  * ulogd output target for DRL: GRD and FPS
5  *
6  * Ken Yocum <kyocum@cs.ucsd.edu>
7  *
8  * Original shell of this code from ulogd_NETFLOW
9  * Like that code, we keep track of per-slice data rates 
10  * out of this slice.  Thus we are rate limiting particular slices
11  * across multiple boxes, ensuring that their outbound rate does not
12  * exceed some fixed limit.  
13  *
14  * Fabric:  static mesh
15  *
16  * Enforcer: linux drop percentage.
17  *    
18  * This file reads packets from the netlink socket.  It updates all
19  * the hashmaps which track how much data has arrived per flow.
20  * It starts two threads for this limiter.
21  * One thread handles periodic estimation.
22  * The other thread handles communication with other limiters. 
23  *
24  * 
25  * Code map
26  *
27  * ulogd_DRL: attach to netlink socket, accept packets.  replaces ratelimit.cc
28  * util.c: generic hashing functions, flow comparisons, sundry items. 
29  * gossip.c: Recv gossip, send gossip.
30  * peer_comm.c: Thread to listen for updates from other limiters. 
31  * estimate.c: Thread to calculate the local limits. 
32  * 
33  * 
34  * Ken Yocum <kyocum@cs.ucsd.edu>
35  * 2007 
36  * 
37  * Some code appropriated from ulogd_NETFLOW:
38  *
39  * Mark Huang <mlhuang@cs.princeton.edu>
40  * Copyright (C) 2004-2005 The Trustees of Princeton University
41  *
42  * Based on admindump.pl by Mic Bowman and Paul Brett
43  * Copyright (c) 2002 Intel Corporation
44  *
45  */
46
47 /* Enable GNU glibc extensions */
48 #define _GNU_SOURCE
49
50 #include <stdio.h>
51 #include <stdlib.h>
52
53 /* va_start() and friends */
54 #include <stdarg.h>
55
56 /* ispunct() */
57 #include <ctype.h>
58
59 /* strstr() and friends */
60 #include <string.h>
61
62 /* dirname() and basename() */
63 #include <libgen.h>
64
65 /* fork() and wait() */
66 #include <sys/types.h>
67 #include <unistd.h>
68 #include <sys/wait.h>
69
70 /* errno and assert() */
71 #include <errno.h>
72 #include <assert.h>
73
74 /* getopt_long() */
75 #include <getopt.h>
76
77 /* time() and friends */
78 #include <time.h>
79 #include <sys/time.h>
80
81 /* inet_aton() */
82 #include <sys/socket.h>
83 #include <netinet/in.h>
84 #include <arpa/inet.h>
85
86 /* ICMP definitions */
87 #include <netinet/ip.h>
88 #include <netinet/ip_icmp.h>
89
90 /* stat() */
91 #include <sys/stat.h>
92
93 /* pthread_create() */
94 #include <pthread.h>
95
96 /* flock() */
97 #include <sys/file.h>
98
99 /* Signal definitions - so that we can catch SIGHUP and update config. */
100 #include <signal.h>
101
102 #include <ulogd/ulogd.h>
103 #include <ulogd/conffile.h>
104
105 /* Perhaps useful for files within vservers? */
106 #if !defined(STANDALONE) && HAVE_LIBPROPER
107 #include <proper/prop.h>
108 #endif
109
110 /*
111  * Jenkins hash support
112  * lives in raterouter.h
113  */
114
115 /* DRL specifics */
116 #include "raterouter.h"
117 #include "util.h"
118 #include "calendar.h"
119 #include "ratetypes.h" /* needs util and pthread.h */
120 #include "logging.h"
121
122 /*
123  * /etc/ulogd.conf configuration options
124  * Add the config options for DRL. 
125  */
126
127 static config_entry_t drl_configfile = {
128     .next = NULL,
129     .key = "drl_configfile",
130     .type = CONFIG_TYPE_STRING,
131     .options = CONFIG_OPT_MANDATORY,
132     .u = { .string = "drl.xml" },
133 };
134
135 /** The administrative bandwidth limit (mbps) for the local node.  The node
136  * will not set a limit higher than this, even when distributed capacity is
137  * available.  Set to 0 for no limit. */
138 static config_entry_t nodelimit = {
139     .next = &drl_configfile,
140     .key = "nodelimit",
141     .type = CONFIG_TYPE_INT,
142     .options = CONFIG_OPT_MANDATORY,
143     .u = { .value = 0 },
144 };
145
146 /** Determines the verbosity of logging. */
147 static config_entry_t drl_loglevel = {
148     .next = &nodelimit,
149     .key = "drl_loglevel",
150     .type = CONFIG_TYPE_INT,
151     .options = CONFIG_OPT_MANDATORY,
152     .u = { .value = LOG_WARN },
153 };
154
155 /** The path of the logfile. */
156 static config_entry_t drl_logfile = {
157     .next = &drl_loglevel,
158     .key = "drl_logfile",
159     .type = CONFIG_TYPE_STRING,
160     .options = CONFIG_OPT_MANDATORY,
161     .u = { .string = "drl_logfile.log" },
162 };
163
164 /** The choice of DRL protocol. */
165 static config_entry_t policy = {
166     .next = &drl_logfile,
167     .key = "policy",
168     .type = CONFIG_TYPE_STRING,
169     .options = CONFIG_OPT_MANDATORY,
170     .u = { .string = "GRD" },
171 };
172
173 /** The estimate interval, in milliseconds. */
174 static config_entry_t estintms = {
175     .next = &policy,
176     .key = "estintms",
177     .type = CONFIG_TYPE_INT,
178     .options = CONFIG_OPT_MANDATORY,
179     .u = { .value = 100 },
180 };
181
182 #define config_entries (&estintms)
183
184 /*
185  * Debug functionality
186  */
187
188 #ifdef DMALLOC
189 #include <dmalloc.h>
190 #endif
191
192 #define NIPQUAD(addr) \
193     ((unsigned char *)&addr)[0], \
194     ((unsigned char *)&addr)[1], \
195     ((unsigned char *)&addr)[2], \
196     ((unsigned char *)&addr)[3]
197
198 #define IPQUAD(addr) \
199     ((unsigned char *)&addr)[3], \
200     ((unsigned char *)&addr)[2], \
201     ((unsigned char *)&addr)[1], \
202     ((unsigned char *)&addr)[0]
203
204
205
206 /* Salt for the hash functions */
207 static int salt;
208
209 /*
210  * Hash slice name lookups on context ID.
211  */
212
213 /* Special context IDs */
214 #define UNKNOWN_XID -1
215 #define ROOT_XID 0
216
217 enum {
218     CONNECTION_REFUSED_XID = 65536, /* MAX_S_CONTEXT + 1 */
219     ICMP_ECHOREPLY_XID,
220     ICMP_UNREACH_XID,
221 };
222
223
224 /* globals */
225 pthread_t estimate_thread;
226 pthread_t signal_thread;
227 pthread_t comm_thread;
228 uint32_t local_ip = 0;
229 limiter_t limiter;
230 extern FILE *logfile;
231 extern uint8_t system_loglevel;
232
233 /* functions */
234
235 static inline uint32_t
236 hash_flow(uint8_t protocol, uint32_t src_ip, uint16_t src_port, uint32_t dst_ip, uint16_t dst_port)
237 {
238     unsigned char mybytes[FLOWKEYSIZE];
239     mybytes[0] = protocol;
240     *(uint32_t*)(&(mybytes[1])) = src_ip;
241     *(uint32_t*)(&(mybytes[5])) = dst_ip;
242     *(uint32_t*)(&(mybytes[9])) = (src_port << 16) | dst_port;
243     return jhash(mybytes,FLOWKEYSIZE,salt) & (FLOW_HASH_SIZE - 1);
244 }
245
246 uint32_t sampled_hasher(const key_flow *key) {
247     return hash_flow(key->protocol, key->source_ip, key->source_port, key->dest_ip, key->dest_port);
248 }
249
250 uint32_t standard_hasher(const key_flow *key) {
251     return hash_flow(key->protocol, key->source_ip, key->source_port, key->dest_ip, key->dest_port);
252 }
253
254 struct intr_id {
255     char* name;
256     ulog_iret_t *res;
257 };
258
259 /* Interesting keys */
260 enum {
261     OOB_TIME_SEC = 0,
262     OOB_MARK,
263     IP_SADDR,
264     IP_DADDR,
265     IP_TOTLEN,
266     IP_PROTOCOL,
267     TCP_SPORT,
268     TCP_DPORT,
269     TCP_ACK,
270     TCP_FIN,
271     TCP_SYN,
272     TCP_RST,
273     UDP_SPORT,
274     UDP_DPORT,
275     ICMP_TYPE,
276     ICMP_CODE,
277     GRE_FLAG_KEY,
278     GRE_VERSION,
279     GRE_KEY,
280     PPTP_CALLID,
281 };
282
283 #define INTR_IDS (sizeof(intr_ids)/sizeof(intr_ids[0]))
284 static struct intr_id intr_ids[] = {
285     [OOB_TIME_SEC] = { "oob.time.sec", 0 },
286     [OOB_MARK] = { "oob.mark", 0 },
287     [IP_SADDR] = { "ip.saddr", 0 },
288     [IP_DADDR] = { "ip.daddr", 0 },
289     [IP_TOTLEN] = { "ip.totlen", 0 },
290     [IP_PROTOCOL] = { "ip.protocol", 0 },
291     [TCP_SPORT] = { "tcp.sport", 0 },
292     [TCP_DPORT] { "tcp.dport", 0 },
293     [TCP_ACK] = { "tcp.ack", 0 },
294     [TCP_FIN] = { "tcp.fin", 0 },
295     [TCP_SYN] = { "tcp.syn", 0 },
296     [TCP_RST] = { "tcp.rst", 0 },
297     [UDP_SPORT] = { "udp.sport", 0 },
298     [UDP_DPORT] = { "udp.dport", 0 },
299     [ICMP_TYPE] = { "icmp.type", 0 },
300     [ICMP_CODE] = { "icmp.code", 0 },
301     [GRE_FLAG_KEY] = { "gre.flag.key", 0 },
302     [GRE_VERSION] = { "gre.version", 0 },
303     [GRE_KEY] = { "gre.key", 0 },
304     [PPTP_CALLID] = { "pptp.callid", 0 },
305 };
306
307 #define GET_VALUE(x) intr_ids[x].res->value
308
309 #define DATE(t) ((t) / (24*60*60) * (24*60*60))
310
311 static int _output_drl(ulog_iret_t *res)
312 {
313     int xid;
314     uint32_t src_ip, dst_ip;
315     uint16_t src_port, dst_port;
316     uint8_t protocol;
317
318     key_flow key;
319     identity_t *ident;
320     leaf_t *leaf;
321
322     protocol = GET_VALUE(IP_PROTOCOL).ui8;
323     src_ip = GET_VALUE(IP_SADDR).ui32;
324     dst_ip = GET_VALUE(IP_DADDR).ui32;
325     xid = GET_VALUE(OOB_MARK).ui32;
326
327     switch (protocol) {
328             
329         case IPPROTO_TCP:
330             src_port = GET_VALUE(TCP_SPORT).ui16;
331             dst_port = GET_VALUE(TCP_DPORT).ui16;
332             break;
333
334         case IPPROTO_UDP:
335             /* netflow had an issue with many udp flows and set
336              * src_port=0 to handle it.  We don't. 
337              */
338             src_port = GET_VALUE(UDP_SPORT).ui16;
339
340             /*
341              * traceroutes create a large number of flows in the db
342              * this is a quick hack to catch the most common form
343              * of traceroute (basically we're mapping any UDP packet
344              * in the 33435-33524 range to the "trace" port, 33524 is
345              * 3 packets * nhops (30).
346              */
347             dst_port = GET_VALUE(UDP_DPORT).ui16;
348             if (dst_port >= 33435 && dst_port <= 33524)
349                 dst_port = 33435;
350             break;
351
352         case IPPROTO_ICMP:
353             src_port = GET_VALUE(ICMP_TYPE).ui8;
354             dst_port = GET_VALUE(ICMP_CODE).ui8;
355
356             /*
357              * We special case some of the ICMP traffic that the kernel
358              * always generates. Since this is attributed to root, it 
359              * creates significant "noise" in the output. We want to be
360              * able to quickly see that root is generating traffic.
361              */
362             if (xid == ROOT_XID) {
363                 if (src_port == ICMP_ECHOREPLY)
364                     xid = ICMP_ECHOREPLY_XID;
365                 else if (src_port == ICMP_UNREACH)
366                     xid = ICMP_UNREACH_XID;
367             }
368             break;
369
370         case IPPROTO_GRE:
371             if (GET_VALUE(GRE_FLAG_KEY).b) {
372                 if (GET_VALUE(GRE_VERSION).ui8 == 1) {
373                     /* Get PPTP call ID */
374                     src_port = GET_VALUE(PPTP_CALLID).ui16;
375                 } else {
376                     /* XXX Truncate GRE keys to 16 bits */
377                     src_port = (uint16_t) GET_VALUE(GRE_KEY).ui32;
378                 }
379             } else {
380                 /* No key available */
381                 src_port = 0;
382             }
383             dst_port = 0;
384             break;
385
386         default:
387             /* This is the default key for packets from unsupported protocols */
388             src_port = 0;
389             dst_port = 0;
390             break;
391     }
392
393     key.protocol = protocol;
394     key.source_ip = src_ip;
395     key.dest_ip = dst_ip;
396     key.source_port = src_port;
397     key.dest_port = dst_port;
398     key.packet_size = GET_VALUE(IP_TOTLEN).ui16;
399     key.packet_time = (time_t) GET_VALUE(OOB_TIME_SEC).ui32;
400
401     pthread_rwlock_rdlock(&limiter.limiter_lock); /* CLUNK! */
402
403     leaf = (leaf_t *) map_search(limiter.stable_instance.leaf_map, &xid, sizeof(xid));
404
405     /* Even if the packet doesn't match any specific xid, it should still
406      * count in the machine-type tables.  This catches root (xid == 0) and
407      * unclassified (xid = fff) packets, which don't have map entries. */
408     if (leaf == NULL) {
409         ident = limiter.stable_instance.last_machine;
410     } else {
411         ident = leaf->parent;
412     }
413
414     while (ident) {
415         pthread_mutex_lock(&ident->table_mutex);
416
417         /* Update the identity's table. */
418         ident->table_sample_function(ident->table, &key);
419
420         pthread_mutex_unlock(&ident->table_mutex);
421
422         ident = ident->parent;
423     }
424
425     pthread_rwlock_unlock(&limiter.limiter_lock); /* CLINK! */
426
427     return 0;
428 }
429
430 /* get all key id's for the keys we are intrested in */
431 static int get_ids(void)
432 {
433     int i;
434     struct intr_id *cur_id;
435
436     for (i = 0; i < INTR_IDS; i++) {
437         cur_id = &intr_ids[i];
438         cur_id->res = keyh_getres(keyh_getid(cur_id->name));
439         if (!cur_id->res) {
440             ulogd_log(ULOGD_ERROR, 
441                     "Cannot resolve keyhash id for %s\n", 
442                     cur_id->name);
443             return 1;
444         }
445     }
446     return 0;
447 }
448
449 static void free_identity(identity_t *ident) {
450     if (ident) {
451         free_comm(&ident->comm);
452
453         if (ident->table) {
454             ident->table_destroy_function(ident->table);
455         }
456
457         pthread_mutex_destroy(&ident->table_mutex);
458
459         free(ident);
460     }
461 }
462
463 static void free_identity_map(map_handle map) {
464     identity_t *tofree = NULL;
465
466     map_reset_iterate(map);
467     while ((tofree = (identity_t *) map_next(map))) {
468         free_identity(tofree);
469     }
470
471     free_map(map, 0);
472 }
473
474 static void free_instance(drl_instance_t *instance) {
475     if (instance->leaves)
476         free(instance->leaves);
477     if (instance->leaf_map)
478         free_map(instance->leaf_map, 0);
479     if (instance->ident_map)
480         free_identity_map(instance->ident_map);
481     if (instance->machines)
482         free(instance->machines);
483     if (instance->sets)
484         free(instance->sets);
485     if (instance->cal) {
486         free(instance->cal);
487     }
488
489     memset(instance, 0, sizeof(drl_instance_t));
490 }
491
492 static void free_failed_config(parsed_configs configs, drl_instance_t *instance) {
493     /* Free configs. */
494     if (configs.machines)
495         free_ident_list(configs.machines);
496     if (configs.sets)
497         free_ident_list(configs.sets);
498
499     /* Free instance. */
500     if (instance)
501         free_instance(instance);
502 }
503
504 static identity_t *new_identity(ident_config *config) {
505     identity_t *ident = malloc(sizeof(identity_t));
506     remote_node_t *comm_nodes = malloc(sizeof(remote_node_t)*config->peer_count);
507     ident_peer *peer = config->peers;
508     int peer_slot = 0;
509
510     if (ident == NULL) {
511         return NULL;
512     }
513
514     if (comm_nodes == NULL) {
515         free(ident);
516         return NULL;
517     }
518
519     memset(ident, 0, sizeof(identity_t));
520     memset(comm_nodes, 0, config->peer_count * sizeof(remote_node_t));
521
522     ident->id = config->id;
523     ident->limit = (uint32_t) (((double) config->limit * 1000000.0) / 8.0);
524     ident->fixed_ewma_weight = config->fixed_ewma_weight;
525     ident->intervals = config->intervals;
526     ident->ewma_weight = pow(ident->fixed_ewma_weight, 
527                              (limiter.estintms/1000.0) * config->intervals);
528     ident->parent = NULL;
529
530     pthread_mutex_init(&ident->table_mutex, NULL);
531     switch (config->accounting) {
532         case ACT_STANDARD:
533             ident->table =
534                 standard_table_create(standard_hasher, &ident->common);
535
536             /* Ugly function pointer casting.  Makes things sufficiently
537              * generic, though. */
538             ident->table_sample_function =
539                 (int (*)(void *, const key_flow *)) standard_table_sample;
540             ident->table_cleanup_function =
541                 (int (*)(void *)) standard_table_cleanup;
542             ident->table_update_function =
543                 (void (*)(void *, struct timeval, double)) standard_table_update_flows;
544             ident->table_destroy_function =
545                 (void (*)(void *)) standard_table_destroy;
546             break;
547
548         case ACT_SAMPLEHOLD:
549             ident->table = sampled_table_create(sampled_hasher,
550                     ident->limit * IDENT_CLEAN_INTERVAL,
551                     1, 20, &ident->common);
552
553             ident->table_sample_function =
554                 (int (*)(void *, const key_flow *)) sampled_table_sample;
555             ident->table_cleanup_function =
556                 (int (*)(void *)) sampled_table_cleanup;
557             ident->table_update_function =
558                 (void (*)(void *, struct timeval, double)) sampled_table_update_flows;
559             ident->table_destroy_function =
560                 (void (*)(void *)) sampled_table_destroy;
561             break;
562
563         case ACT_SIMPLE:
564             ident->table = simple_table_create(&ident->common);
565
566             ident->table_sample_function =
567                 (int (*)(void *, const key_flow *)) simple_table_sample;
568             ident->table_cleanup_function =
569                 (int (*)(void *)) simple_table_cleanup;
570             ident->table_update_function =
571                 (void (*)(void *, struct timeval, double)) simple_table_update_flows;
572             ident->table_destroy_function =
573                 (void (*)(void *)) simple_table_destroy;
574             break;
575     }
576
577     /* Make sure the table was allocated. */
578     if (ident->table == NULL) {
579         free(ident);
580         return NULL;
581     }
582
583     while (peer) {
584         comm_nodes[peer_slot].addr = peer->ip;
585         comm_nodes[peer_slot].port = htons(LIMITER_LISTEN_PORT);
586         peer = peer->next;
587         peer_slot += 1;
588     }
589
590     if (new_comm(&ident->comm, config, comm_nodes)) {
591         printlog(LOG_CRITICAL, "Failed to create communication structure.\n");
592         return NULL;
593     }
594
595     ident->comm.remote_nodes = comm_nodes;
596
597     return ident;
598 }
599
600 /* Determines the validity of the parameters of one ident_config.
601  *
602  * 0 valid
603  * 1 invalid
604  */
605 static int validate_config(ident_config *config) {
606     /* Limit must be a positive integer. */
607     if (config->limit < 1) {
608         return 1;
609     }
610
611     /* Commfabric must be a valid choice (COMM_MESH or COMM_GOSSIP). */
612     if (config->commfabric != COMM_MESH &&
613             config->commfabric != COMM_GOSSIP) {
614         return 1;
615     }
616
617     /* If commfabric is COMM_GOSSIP, this must be a positive integer. */
618     if (config->commfabric == COMM_GOSSIP && config->branch < 1) {
619         return 1;
620     }
621
622     /* Accounting must be a valid choice (ACT_STANDARD, ACT_SAMPLEHOLD,
623      * ACT_SIMPLE). */
624     if (config->accounting != ACT_STANDARD &&
625             config->accounting != ACT_SAMPLEHOLD &&
626             config->accounting != ACT_SIMPLE) {
627         return 1;
628     }
629
630     /* Ewma weight must be greater than or equal to zero. */
631     if (config->fixed_ewma_weight < 0) {
632         return 1;
633     }
634
635     /* Note: Parsing stage requires that each ident has at least one peer. */
636     return 0;
637 }
638
639 /* 0 success
640  * non-zero failure
641  */
642 static int validate_configs(parsed_configs configs, drl_instance_t *instance) {
643
644     ident_config *mlist = configs.machines;
645     ident_config *slist = configs.sets;
646     ident_config *tmp = NULL;
647     int i = 0;
648
649     while (mlist) {
650         /* ID must be non-zero and unique. */
651         /* This is ugly and hackish, but this function will be called rarely.
652          * I'm tired of trying to be clever. */
653         if (mlist->id < 0) {
654             printlog(LOG_CRITICAL, "Negative ident id: %d (%x) ?\n", mlist->id, mlist->id);
655             return EINVAL;
656         }
657         tmp = mlist->next;
658         while (tmp) {
659             if (mlist->id == tmp->id) {
660                 printlog(LOG_CRITICAL, "Duplicate ident id: %d (%x)\n", mlist->id, mlist->id);
661                 return EINVAL;
662             }
663             tmp = tmp->next;
664         }
665         tmp = configs.sets;
666         while (tmp) {
667             if (mlist->id == tmp->id) {
668                 printlog(LOG_CRITICAL, "Duplicate ident id: %d (%x)\n", mlist->id, mlist->id);
669                 return EINVAL;
670             }
671             tmp = tmp->next;
672         }
673
674         if (validate_config(mlist)) {
675             printlog(LOG_CRITICAL, "Invalid ident parameters for id: %d (%x)\n", mlist->id, mlist->id);
676             return EINVAL;
677         }
678
679         mlist = mlist->next;
680     }
681
682     instance->sets = malloc(configs.set_count * sizeof(identity_t *));
683     if (instance->sets == NULL) {
684         return ENOMEM;
685     }
686
687     memset(instance->sets, 0, configs.set_count * sizeof(identity_t *));
688     instance->set_count = configs.set_count;
689
690     /* For sets, make sure that the hierarchy is valid. */
691     while (slist) {
692         ident_member *members = slist->members;
693
694         /* ID must be non-zero and unique. */
695         if (slist->id < 0) {
696             printlog(LOG_CRITICAL, "Negative ident id: %d (%x) ?\n", slist->id, slist->id);
697             return EINVAL;
698         }
699         tmp = slist->next;
700         while (tmp) {
701             if (slist->id == tmp->id) {
702                 printlog(LOG_CRITICAL, "Duplicate ident id: %d (%x)\n", slist->id, slist->id);
703                 return EINVAL;
704             }
705             tmp = tmp->next;
706         }
707
708         if (validate_config(slist)) {
709             printlog(LOG_CRITICAL, "Invalid ident parameters for id: %d (%x)\n", slist->id, slist->id);
710             return EINVAL;
711         }
712
713         /* Allocate an identity_t for this set-type identity. */
714         instance->sets[i] = new_identity(slist);
715
716         if (instance->sets[i] == NULL) {
717             return ENOMEM;
718         }
719
720         /* Loop through children and look up each in leaf or ident map
721          * depending on the type of child.  Set the child's parent pointer
722          * to the identity we just created above, unless it is already set,
723          * in which case we have an error. */
724         while (members) {
725             identity_t *child_ident = NULL;
726             leaf_t *child_leaf = NULL;
727
728             switch (members->type) {
729                 case MEMBER_XID:
730                     child_leaf = map_search(instance->leaf_map, &members->value,
731                                             sizeof(members->value));
732                     if (child_leaf == NULL) {
733                         return EINVAL;
734                     }
735                     if (child_leaf->parent != NULL) {
736                         /* Error - This leaf already has a parent. */
737                         return EINVAL;
738                     }
739                     child_leaf->parent = instance->sets[i];
740                     break;
741                 case MEMBER_GUID:
742                     child_ident = map_search(instance->ident_map, &members->value,
743                                              sizeof(members->value));
744                     if (child_ident == NULL) {
745                         return EINVAL;
746                     }
747                     if (child_ident->parent != NULL) {
748                         /* Error - This identity already has a parent. */
749                         return EINVAL;
750                     }
751                     child_ident->parent = instance->sets[i];
752                     break;
753                 default:
754                     /* Error - shouldn't be possible. */
755                     break;
756             }
757             members = members->next;
758         }
759
760         map_insert(instance->ident_map, &instance->sets[i]->id,
761                    sizeof(instance->sets[i]->id), instance->sets[i]);
762
763         slist = slist->next;
764         i++;
765     }
766     return 0;
767 }
768
769 static int fill_set_leaf_pointer(drl_instance_t *instance, identity_t *ident) {
770     int count = 0;
771     identity_t *current_ident;
772     leaf_t *current_leaf;
773     leaf_t **leaves = malloc(instance->leaf_count * sizeof(leaf_t *));
774     if (leaves == NULL) {
775         return 1;
776     }
777
778     map_reset_iterate(instance->leaf_map);
779     while ((current_leaf = (leaf_t *) map_next(instance->leaf_map))) {
780         current_ident = current_leaf->parent;
781         while (current_ident != NULL && current_ident != instance->last_machine) {
782             if (current_ident == ident) {
783                 /* Found the ident we were looking for - add the leaf. */
784                 leaves[count] = current_leaf;
785                 count += 1;
786                 break;
787             }
788             current_ident = current_ident->parent;
789         }
790     }
791
792     ident->leaves = leaves;
793     ident->leaf_count = count;
794
795     return 0;
796 }
797
798 static int init_identities(parsed_configs configs, drl_instance_t *instance) {
799     int i, j;
800     ident_config *config = configs.machines;
801     leaf_t *leaf = NULL;
802
803     instance->cal = malloc(sizeof(struct ident_calendar) * SCHEDLEN);
804
805     if (instance->cal == NULL) {
806         return ENOMEM;
807     }
808
809     for (i = 0; i < SCHEDLEN; ++i) {
810         TAILQ_INIT(instance->cal + i);
811     }
812     instance->cal_slot = 0;
813
814     instance->machines = malloc(configs.machine_count * sizeof(drl_instance_t *));
815
816     if (instance->machines == NULL) {
817         return ENOMEM;
818     }
819
820     memset(instance->machines, 0, configs.machine_count * sizeof(drl_instance_t *));
821     instance->machine_count = configs.machine_count;
822
823     /* Allocate and add the machine identities. */
824     for (i = 0; i < configs.machine_count; ++i) {
825         instance->machines[i] = new_identity(config);
826
827         if (instance->machines[i] == NULL) {
828             return ENOMEM;
829         }
830
831         /* The first has no parent - it is the root.  All others have the
832          * previous ident as their parent. */
833         if (i == 0) {
834             instance->machines[i]->parent = NULL;
835         } else {
836             instance->machines[i]->parent = instance->machines[i - 1];
837         }
838
839         instance->last_machine = instance->machines[i];
840
841         /* Add the ident to the guid->ident map. */
842         map_insert(instance->ident_map, &instance->machines[i]->id,
843                    sizeof(instance->machines[i]->id), instance->machines[i]);
844
845         config = config->next;
846
847         TAILQ_INSERT_TAIL(instance->cal + (instance->cal_slot & SCHEDMASK),
848                           instance->machines[i], calendar);
849
850         /* Setup the array of pointers to leaves.  This is easy for machines
851          * because a machine node applies to every leaf. */
852         instance->machines[i]->leaves =
853             malloc(instance->leaf_count * sizeof(leaf_t *));
854         if (instance->machines[i]->leaves == NULL) {
855             return ENOMEM;
856         }
857         instance->machines[i]->leaf_count = instance->leaf_count;
858         for (j = 0; j < instance->leaf_count; ++j) {
859             instance->machines[i]->leaves[j] = &instance->leaves[j];
860         }
861     }
862
863     /* Connect the set subtree to the machines. Any set or leaf without a
864      * parent will take the last machine as its parent. */
865
866     /* Leaves... */
867     map_reset_iterate(instance->leaf_map);
868     while ((leaf = (leaf_t *) map_next(instance->leaf_map))) {
869         if (leaf->parent == NULL) {
870             leaf->parent = instance->last_machine;
871         }
872     }
873
874     /* Sets... */
875     for (i = 0; i < instance->set_count; ++i) {
876         if (instance->sets[i]->parent == NULL) {
877             instance->sets[i]->parent = instance->last_machine;
878         }
879
880         TAILQ_INSERT_TAIL(instance->cal + (instance->cal_slot & SCHEDMASK),
881                           instance->sets[i], calendar);
882
883         /* Setup the array of pointers to leaves.  This is harder for sets,
884          * but this doesn't need to be super-efficient because it happens
885          * rarely and it isn't on the critical path for reconfig(). */
886         if (fill_set_leaf_pointer(instance, instance->sets[i])) {
887             return ENOMEM;
888         }
889     }
890
891     /* Success. */
892     return 0;
893 }
894
895 static void print_instance(drl_instance_t *instance) {
896     leaf_t *leaf = NULL;
897     identity_t *ident = NULL;
898
899     map_reset_iterate(instance->leaf_map);
900     while ((leaf = (leaf_t *) map_next(instance->leaf_map))) {
901         printf("%x:", leaf->xid);
902         ident = leaf->parent;
903         while (ident) {
904             printf("%d:",ident->id);
905             ident = ident->parent;
906         }
907         printf("Leaf's parent pointer is %p\n", leaf->parent);
908     }
909
910     printf("instance->last_machine is %p\n", instance->last_machine);
911 }
912
913 static int assign_htb_hierarchy(drl_instance_t *instance) {
914     int i, j;
915     int next_node = 0x11;
916
917     /* Chain machine nodes under 1:10. */
918     for (i = 0; i < instance->machine_count; ++i) {
919         if (instance->machines[i]->parent == NULL) {
920             /* Top node. */
921             instance->machines[i]->htb_parent = 0x10;
922         } else {
923             /* Pointerific! */
924             instance->machines[i]->htb_parent =
925                         instance->machines[i]->parent->htb_node;
926         }
927
928         instance->machines[i]->htb_node = next_node;
929         next_node += 1;
930     }
931
932     next_node += 0x10;
933
934     /* Add set nodes under machine nodes. Iterate backwards to ensure parent is
935      * already there. */
936     for (j = (instance->set_count - 1); j >= 0; --j) {
937         if (instance->sets[j]->parent == NULL) {
938             instance->sets[j]->htb_parent = 0x10;
939         } else {
940             instance->sets[j]->htb_parent = instance->sets[j]->parent->htb_node;
941         }
942         instance->sets[j]->htb_node = next_node;
943
944         next_node += 1;
945     }
946
947     return 0;
948 }
949
950 /* Added this so that I could comment one line and kill off all of the
951  * command execution. */
952 static int execute_cmd(const char *cmd) {
953     return system(cmd);
954 }
955
956 static int create_htb_hierarchy(drl_instance_t *instance) {
957     char cmd[300];
958     int i, j, k;
959
960     /* Nuke the hierarchy. */
961     sprintf(cmd, "tc qdisc del dev eth0 root handle 1: htb");
962     execute_cmd(cmd);
963     printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd);
964
965     /* Re-initialize the basics. */
966     sprintf(cmd, "tc qdisc add dev eth0 root handle 1: htb default 1fff");
967     if (execute_cmd(cmd)) {
968         return 1;
969     }
970     printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd);
971     sprintf(cmd, "tc class add dev eth0 parent 1: classid 1:1 htb rate 1000mbit ceil 1000mbit");
972     if (execute_cmd(cmd)) {
973         return 1;
974     }
975     printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd);
976
977     /* Add back 1:10. (Nodelimit : Megabits/sec -> bits/second)*/
978     if (limiter.nodelimit) {
979         sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:1 classid 1:10 htb rate 8bit ceil %lubit",
980                 (unsigned long) limiter.nodelimit * 1024 * 1024);
981     } else {
982         sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:1 classid 1:10 htb rate 8bit ceil 1000mbit");
983     }
984
985     if (execute_cmd(cmd)) {
986         return 1;
987     }
988     printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd);
989
990     /* Add back 1:20. */
991     sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:1 classid 1:20 htb rate 8bit ceil 1000mbit");
992
993     if (execute_cmd(cmd)) {
994         return 1;
995     }
996     printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd);
997
998
999     /* Add machines. */
1000     for (i = 0; i < instance->machine_count; ++i) {
1001         sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:%x classid 1:%x htb rate 8bit ceil %lubit",
1002                 instance->machines[i]->htb_parent,
1003                 instance->machines[i]->htb_node,
1004                 (unsigned long) instance->machines[i]->limit * 1024 * 1024);
1005
1006         if (execute_cmd(cmd)) {
1007             return 1;
1008         }
1009         printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd);
1010     }
1011
1012     /* Add sets. */
1013     for (j = (instance->set_count - 1); j >= 0; --j) {
1014         sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:%x classid 1:%x htb rate 8bit ceil %lubit",
1015                 instance->sets[j]->htb_parent,
1016                 instance->sets[j]->htb_node,
1017                 (unsigned long) instance->sets[j]->limit * 1024 * 1024);
1018
1019         if (execute_cmd(cmd)) {
1020             return 1;
1021         }
1022         printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd);
1023     }
1024
1025     /* Add leaves. FIXME: Set static sliver limit as ceil here! */
1026     for (k = 0; k < instance->leaf_count; ++k) {
1027         if (instance->leaves[k].parent == NULL) {
1028             sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:10 classid 1:1%x htb rate 8bit ceil %lubit",
1029                 instance->leaves[k].xid,
1030                 (unsigned long) 100 * 1024 * 1024);
1031         } else {
1032             sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:%x classid 1:1%x htb rate 8bit ceil %lubit",
1033                     instance->leaves[k].parent->htb_node,
1034                     instance->leaves[k].xid,
1035                     (unsigned long) 100 * 1024 * 1024);
1036         }
1037
1038         if (execute_cmd(cmd)) {
1039             return 1;
1040         }
1041         printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd);
1042         
1043         sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:20 classid 1:2%x htb rate 8bit ceil 1000mbit",
1044                 instance->leaves[k].xid);
1045
1046         if (execute_cmd(cmd)) {
1047             return 1;
1048         }
1049         printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd);
1050     }
1051
1052     /* Add 1:1000 and 1:2000 */
1053     if (instance->last_machine == NULL) {
1054         sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:10 classid 1:1000 htb rate 8bit ceil 1000mbit");
1055     } else {
1056         sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:%x classid 1:1000 htb rate 8bit ceil 1000mbit",
1057                 instance->last_machine->htb_node);
1058     }
1059
1060     if (execute_cmd(cmd)) {
1061         return 1;
1062     }
1063     printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd);
1064     sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:20 classid 1:2000 htb rate 8bit ceil 1000mbit");
1065
1066     if (execute_cmd(cmd)) {
1067         return 1;
1068     }
1069     printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd);
1070
1071     /* Add 1:1fff and 1:2fff */
1072     if (instance->last_machine == NULL) {
1073         sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:10 classid 1:1fff htb rate 8bit ceil 1000mbit");
1074     } else {
1075         sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:%x classid 1:1fff htb rate 8bit ceil 1000mbit",
1076                 instance->last_machine->htb_node);
1077     }
1078
1079     if (execute_cmd(cmd)) {
1080         return 1;
1081     }
1082     printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd);
1083     sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:20 classid 1:2fff htb rate 8bit ceil 1000mbit");
1084
1085     if (execute_cmd(cmd)) {
1086         return 1;
1087     }
1088     printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd);
1089
1090 #ifdef DELAY40MS
1091     /* Only for artificial delay testing. */
1092     sprintf(cmd, "/sbin/tc qdisc del dev eth0 parent 1:1000 handle 1000 pfifo");
1093     execute_cmd(cmd);
1094
1095     sprintf(cmd, "/sbin/tc qdisc replace dev eth0 parent 1:1000 handle 1000 netem loss 0 delay 40ms");
1096     execute_cmd(cmd);
1097     sprintf(cmd, "/sbin/tc qdisc del dev eth0 parent 1:11f9 handle 11f9 pfifo");
1098     execute_cmd(cmd);
1099
1100     sprintf(cmd, "/sbin/tc qdisc replace dev eth0 parent 1:11f9 handle 11f9 netem loss 0 delay 40ms");
1101     execute_cmd(cmd);
1102     sprintf(cmd, "/sbin/tc qdisc del dev eth0 parent 1:11fa handle 11fa pfifo");
1103     execute_cmd(cmd);
1104
1105     sprintf(cmd, "/sbin/tc qdisc replace dev eth0 parent 1:11fa handle 11fa netem loss 0 delay 40ms");
1106     execute_cmd(cmd);
1107     /* End delay testing */
1108 #endif
1109
1110     return 0;
1111 }
1112
1113 static int setup_tc_grd(drl_instance_t *instance) {
1114     int i;
1115     char cmd[300];
1116
1117     for (i = 0; i < instance->leaf_count; ++i) {
1118         /* Delete the old pfifo qdisc that might have been there before. */
1119         sprintf(cmd, "/sbin/tc qdisc del dev eth0 parent 1:1%x handle 1%x pfifo",
1120                 instance->leaves[i].xid, instance->leaves[i].xid);
1121
1122         if (execute_cmd(cmd)) {
1123             //FIXME: remove this print and do a log.
1124             printf("GRD: pfifo qdisc wasn't there!\n");
1125         }
1126
1127         /* Add the netem qdisc. */
1128 #ifdef DELAY40MS
1129         sprintf(cmd, "/sbin/tc qdisc replace dev eth0 parent 1:1%x handle 1%x netem loss 0 delay 40ms",
1130                 instance->leaves[i].xid, instance->leaves[i].xid);
1131 #else
1132         sprintf(cmd, "/sbin/tc qdisc replace dev eth0 parent 1:1%x handle 1%x netem loss 0 delay 0ms",
1133                 instance->leaves[i].xid, instance->leaves[i].xid);
1134 #endif
1135
1136         if (execute_cmd(cmd)) {
1137             return 1;
1138         }
1139     }
1140
1141     /* Do the same for 1000 and 1fff. */
1142     sprintf(cmd, "/sbin/tc qdisc del dev eth0 parent 1:1000 handle 1000 pfifo");
1143
1144     if (execute_cmd(cmd)) {
1145         //FIXME: remove this print and do a log.
1146         printf("GRD: pfifo qdisc wasn't there!\n");
1147     }
1148
1149     /* Add the netem qdisc. */
1150 #ifdef DELAY40MS
1151     sprintf(cmd, "/sbin/tc qdisc replace dev eth0 parent 1:1000 handle 1000 netem loss 0 delay 40ms");
1152 #else
1153     sprintf(cmd, "/sbin/tc qdisc replace dev eth0 parent 1:1000 handle 1000 netem loss 0 delay 0ms");
1154 #endif
1155
1156     if (execute_cmd(cmd)) {
1157         return 1;
1158     }
1159
1160     sprintf(cmd, "/sbin/tc qdisc del dev eth0 parent 1:1fff handle 1fff pfifo");
1161
1162     if (execute_cmd(cmd)) {
1163         //FIXME: remove this print and do a log.
1164         printf("GRD: pfifo qdisc wasn't there!\n");
1165     }
1166
1167     /* Add the netem qdisc. */
1168 #ifdef DELAY40MS
1169     sprintf(cmd, "/sbin/tc qdisc replace dev eth0 parent 1:1fff handle 1fff netem loss 0 delay 40ms");
1170 #else
1171     sprintf(cmd, "/sbin/tc qdisc replace dev eth0 parent 1:1fff handle 1fff netem loss 0 delay 0ms");
1172 #endif
1173
1174     if (execute_cmd(cmd)) {
1175         return 1;
1176     }
1177
1178     return 0;
1179 }
1180
1181 /* init_drl 
1182  * 
1183  * Initialize this limiter with options 
1184  * Open UDP socket for peer communication
1185  */
1186 static int init_drl(void) {
1187     parsed_configs configs;
1188     struct sockaddr_in server_address;
1189     
1190     memset(&limiter, 0, sizeof(limiter_t));
1191
1192     /* Setup logging. */
1193     system_loglevel = (uint8_t) drl_loglevel.u.value;
1194     logfile = fopen(drl_logfile.u.string, "w");
1195
1196     if (logfile == NULL) {
1197         printf("Couldn't open logfile - ");
1198         perror("fopen()");
1199         exit(EXIT_FAILURE);
1200     }
1201
1202     printlog(LOG_CRITICAL, "ulogd_DRL initializing . . .\n");
1203
1204     limiter.nodelimit = (uint32_t) (((double) nodelimit.u.value * 1000000.0) / 8.0);
1205
1206     init_hashing();  /* for all hash maps */
1207
1208     pthread_rwlock_init(&limiter.limiter_lock,NULL);
1209
1210     /* determine our local IP by iterating through interfaces */
1211     if ((limiter.ip = get_local_ip())==0) {
1212         printlog(LOG_CRITICAL,
1213                  "ulogd_DRL unable to aquire local IP address, not registering.\n");
1214         return (false);
1215     }
1216     limiter.localaddr = inet_addr(limiter.ip);
1217     limiter.port = htons(LIMITER_LISTEN_PORT);
1218     limiter.udp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
1219     if (limiter.udp_socket < 0) {
1220         printlog(LOG_CRITICAL, "Failed to create UDP socket().\n");
1221         return false;
1222     }
1223
1224     memset(&server_address, 0, sizeof(server_address));
1225     server_address.sin_family = AF_INET;
1226     server_address.sin_addr.s_addr = limiter.localaddr;
1227     server_address.sin_port = limiter.port;
1228
1229     if (bind(limiter.udp_socket, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) {
1230         printlog(LOG_CRITICAL, "Failed to bind UDP socket.\n");
1231         return false;
1232     }
1233
1234     printlog(LOG_WARN, "     POLICY: %s\n",policy.u.string);
1235     if (strcasecmp(policy.u.string,"GRD") == 0) {
1236         limiter.policy = POLICY_GRD;
1237     } else if (strcasecmp(policy.u.string,"FPS") == 0) {
1238         limiter.policy = POLICY_FPS;
1239     } else {
1240         printlog(LOG_CRITICAL,
1241                  "Unknown DRL policy %s, aborting.\n",policy.u.string);
1242         return (false);
1243     }
1244
1245     limiter.estintms = estintms.u.value;
1246     if (limiter.estintms > 1000) {
1247         printlog(LOG_CRITICAL,
1248                  "DRL: sorry estimate intervals must be less than 1 second.");
1249         printlog(LOG_CRITICAL,
1250                  "  Simple source mods will allow larger intervals.  Using 1 second.\n");
1251         limiter.estintms = 1000;
1252     }
1253     printlog(LOG_WARN, "     Est interval: %dms\n",limiter.estintms);
1254     
1255     /* Acquire the big limiter lock for writing.  Prevents pretty much
1256      * anything else from happening while the hierarchy is being changed. */
1257     pthread_rwlock_wrlock(&limiter.limiter_lock);
1258
1259     limiter.stable_instance.ident_map = allocate_map();
1260     if (limiter.stable_instance.ident_map == NULL) {
1261         printlog(LOG_CRITICAL, "Failed to allocate memory for identity map.\n");
1262         return false;
1263     }
1264
1265     if (get_eligible_leaves(&limiter.stable_instance)) {
1266         printlog(LOG_CRITICAL, "Failed to read eligigle leaves.\n");
1267         return false;
1268     }
1269
1270     if (parse_drl_config(drl_configfile.u.string, &configs)) {
1271         /* Parse error occured. Return non-zero to notify init_drl(). */
1272         return false;
1273     }
1274
1275     /* Validate identity hierarchy! */
1276     if (validate_configs(configs, &limiter.stable_instance)) {
1277         /* Clean up everything. */
1278         free_failed_config(configs, &limiter.stable_instance);
1279         return false;
1280     }
1281
1282     if (init_identities(configs, &limiter.stable_instance)) {
1283         free_failed_config(configs, &limiter.stable_instance);
1284         return false;
1285     }
1286
1287     /* At this point, we should be done with configs. */
1288     free_ident_list(configs.machines);
1289     free_ident_list(configs.sets);
1290
1291     /* Debugging - FIXME: remove this? */
1292     print_instance(&limiter.stable_instance);
1293
1294     switch (limiter.policy) {
1295         case POLICY_FPS:
1296             if (assign_htb_hierarchy(&limiter.stable_instance)) {
1297                 free_instance(&limiter.stable_instance);
1298                 return false;
1299             }
1300
1301             if (create_htb_hierarchy(&limiter.stable_instance)) {
1302                 free_instance(&limiter.stable_instance);
1303                 return false;
1304             }
1305         break;
1306
1307         case POLICY_GRD:
1308             if (setup_tc_grd(&limiter.stable_instance)) {
1309                 free_instance(&limiter.stable_instance);
1310                 return false;
1311             }
1312         break;
1313
1314         default:
1315         return false;
1316     }
1317
1318     pthread_rwlock_unlock(&limiter.limiter_lock);
1319
1320     if (pthread_create(&limiter.udp_recv_thread, NULL, limiter_receive_thread, NULL)) {
1321         printlog(LOG_CRITICAL, "Unable to start UDP receive thread.\n");
1322         return false;
1323     }
1324
1325     printlog(LOG_WARN, "ulogd_DRL init finished.\n");
1326
1327     return true;
1328 }
1329
1330 static void reconfig() {
1331     parsed_configs configs;
1332
1333     printlog(LOG_DEBUG, "--Starting reconfig()--\n");
1334     flushlog();
1335
1336     memset(&configs, 0, sizeof(parsed_configs));
1337     memset(&limiter.new_instance, 0, sizeof(drl_instance_t));
1338
1339     limiter.new_instance.ident_map = allocate_map();
1340     if (limiter.new_instance.ident_map == NULL) {
1341         printlog(LOG_CRITICAL, "Failed to allocate ident_map during reconfig().\n");
1342         return;
1343     }
1344
1345     if (get_eligible_leaves(&limiter.new_instance)) {
1346         free_failed_config(configs, &limiter.new_instance);
1347         printlog(LOG_CRITICAL, "Failed to read leaves during reconfig().\n");
1348         return;
1349     }
1350
1351     if (parse_drl_config(drl_configfile.u.string, &configs)) {
1352         free_failed_config(configs, &limiter.new_instance);
1353         printlog(LOG_CRITICAL, "Failed to parse config during reconfig().\n");
1354         return;
1355     }
1356
1357     if (validate_configs(configs, &limiter.new_instance)) {
1358         free_failed_config(configs, &limiter.new_instance);
1359         printlog(LOG_CRITICAL, "Validation failed during reconfig().\n");
1360         pthread_rwlock_unlock(&limiter.limiter_lock);
1361         return;
1362     }
1363
1364     if (init_identities(configs, &limiter.new_instance)) {
1365         free_failed_config(configs, &limiter.new_instance);
1366         printlog(LOG_CRITICAL, "Initialization failed during reconfig().\n");
1367         pthread_rwlock_unlock(&limiter.limiter_lock);
1368         return;
1369     }
1370
1371     free_ident_list(configs.machines);
1372     free_ident_list(configs.sets);
1373
1374     /* Debugging - FIXME: remove this? */
1375     print_instance(&limiter.new_instance);
1376     
1377     /* Lock */
1378     pthread_rwlock_wrlock(&limiter.limiter_lock);
1379
1380     switch (limiter.policy) {
1381         case POLICY_FPS:
1382             if (assign_htb_hierarchy(&limiter.new_instance)) {
1383                 free_instance(&limiter.new_instance);
1384                 printlog(LOG_CRITICAL, "Failed to assign HTB hierarchy during reconfig().\n");
1385                 pthread_rwlock_unlock(&limiter.limiter_lock);
1386                 return;
1387             }
1388
1389             if (create_htb_hierarchy(&limiter.new_instance)) {
1390                 free_instance(&limiter.new_instance);
1391                 printlog(LOG_CRITICAL, "Failed to create HTB hierarchy during reconfig().\n");
1392
1393                 /* Re-create old instance. */
1394                 if (create_htb_hierarchy(&limiter.stable_instance)) {
1395                     /* Error reinstating the old one - big problem. */
1396                     printlog(LOG_CRITICAL, "Failed to reinstate HTB hierarchy during reconfig().\n");
1397                     printlog(LOG_CRITICAL, "Giving up...\n");
1398                     flushlog();
1399                     exit(EXIT_FAILURE);
1400                 }
1401
1402                 pthread_rwlock_unlock(&limiter.limiter_lock);
1403                 return;
1404             }
1405         break;
1406
1407         case POLICY_GRD:
1408             if (setup_tc_grd(&limiter.new_instance)) {
1409                 free_instance(&limiter.new_instance);
1410                 printlog(LOG_CRITICAL, "GRD tc calls failed during reconfig().\n");
1411
1412                 /* Try to re-create old instance. */
1413                 if (setup_tc_grd(&limiter.stable_instance)) {
1414                     printlog(LOG_CRITICAL, "Failed to reinstate old GRD qdiscs during reconfig().\n");
1415                     printlog(LOG_CRITICAL, "Giving up...\n");
1416                     flushlog();
1417                     exit(EXIT_FAILURE);
1418                 }
1419             }
1420         break;
1421
1422         default:
1423             /* Should be impossible. */
1424             printf("Pigs are flying?\n");
1425             exit(EXIT_FAILURE);
1426     }
1427
1428     /* Switch over new to stable instance. */
1429     free_instance(&limiter.stable_instance);
1430     memcpy(&limiter.stable_instance, &limiter.new_instance, sizeof(drl_instance_t));
1431
1432     /* Success! - Unlock */
1433     pthread_rwlock_unlock(&limiter.limiter_lock);
1434 }
1435
1436 static ulog_output_t drl_op = {
1437     .name = "drl",
1438     .output = &_output_drl,
1439     .signal = NULL, /* This appears to be broken. Using my own handler. */
1440     .init = NULL,
1441     .fini = NULL,
1442 };
1443
1444 /* Tests the amount of time it takes to call reconfig(). */
1445 static void time_reconfig(int iterations) {
1446     struct timeval start, end;
1447     int i;
1448
1449     gettimeofday(&start, NULL);
1450     for (i = 0; i < iterations; ++i) {
1451         reconfig();
1452     }
1453     gettimeofday(&end, NULL);
1454
1455     printf("%d reconfigs() took %d seconds and %d microseconds.\n",
1456            iterations, end.tv_sec - start.tv_sec, end.tv_usec - start.tv_usec);
1457     exit(0);
1458
1459     // Seems to take about 85ms / iteration
1460 }
1461
1462 static void *signal_thread_func(void *args) {
1463     int sig;
1464     int err;
1465     sigset_t sigs;
1466
1467     sigemptyset(&sigs);
1468     sigaddset(&sigs, SIGHUP);
1469     pthread_sigmask(SIG_BLOCK, &sigs, NULL);
1470
1471     while (1) {
1472         sigemptyset(&sigs);
1473         sigaddset(&sigs, SIGHUP);
1474
1475         err = sigwait(&sigs, &sig);
1476
1477         if (err) {
1478             printlog(LOG_CRITICAL, "sigwait() returned an error.\n");
1479             flushlog();
1480         }
1481
1482         switch (sig) {
1483             case SIGHUP:
1484                 printlog(LOG_WARN, "Caught SIGHUP - re-reading XML file.\n");
1485                 reconfig();
1486                 //time_reconfig(1000); //instrumentation
1487                 flushlog();
1488                 break;
1489             default:
1490                 /* Should be impossible... */
1491                 break;
1492         }
1493     }
1494
1495 }
1496
1497 /* register output plugin with ulogd */
1498 static void _drl_reg_op(void)
1499 {
1500     ulog_output_t *op = &drl_op;
1501     sigset_t signal_mask;
1502
1503     sigemptyset(&signal_mask);
1504     sigaddset(&signal_mask, SIGHUP);
1505     pthread_sigmask(SIG_BLOCK, &signal_mask, NULL);
1506
1507     if (pthread_create(&signal_thread, NULL, &signal_thread_func, NULL) != 0) {
1508         printlog(LOG_CRITICAL, "Failed to create signal handling thread.\n");
1509         fprintf(stderr, "An error has occured starting ulogd_DRL.  Refer to your logfile (%s) for additional information.\n", drl_logfile.u.string);
1510         flushlog();
1511         exit(EXIT_FAILURE);
1512     }
1513
1514     if (!init_drl()) {
1515         printlog(LOG_CRITICAL, "Init failed. :(\n");
1516         fprintf(stderr, "An error has occured starting ulogd_DRL.  Refer to your logfile (%s) for additional information.\n", drl_logfile.u.string);
1517         flushlog();
1518         exit(EXIT_FAILURE);
1519     }
1520
1521     register_output(op);
1522
1523     /* start up the thread that will periodically estimate the
1524      * local rate and set the local limits
1525      * see estimate.c
1526      */
1527     if (pthread_create(&estimate_thread, NULL, (void*(*)(void*)) &handle_estimation, &limiter)!=0) {
1528         ulogd_log(ULOGD_ERROR, "couldn't start estimate thread for 0x%x %s\n",limiter.localaddr,
1529                 limiter.ip);
1530         fprintf(stderr, "An error has occured starting ulogd_DRL.  Refer to your logfile (%s) for additional information.\n", drl_logfile.u.string);
1531         exit(EXIT_FAILURE);
1532     }
1533 }
1534
1535 void _init(void)
1536 {
1537     /* have the opts parsed */
1538     config_parse_file("DRL", config_entries);
1539
1540     if (get_ids()) {
1541         ulogd_log(ULOGD_ERROR, "can't resolve all keyhash id's\n");
1542         exit(2);
1543     }
1544
1545     /* Seed the hash function */
1546     salt = getpid() ^ time(NULL);
1547
1548     _drl_reg_op();
1549 }