Reincarnated GRD. Changed mesh decay to go to 1/N rather than 0.
[distributedratelimiting.git] / drl / ulogd_DRL.c
index 5d7ca7e..ef2a17b 100644 (file)
@@ -766,8 +766,37 @@ static int validate_configs(parsed_configs configs, drl_instance_t *instance) {
     return 0;
 }
 
     return 0;
 }
 
+static int fill_set_leaf_pointer(drl_instance_t *instance, identity_t *ident) {
+    int count = 0;
+    identity_t *current_ident;
+    leaf_t *current_leaf;
+    leaf_t **leaves = malloc(instance->leaf_count * sizeof(leaf_t *));
+    if (leaves == NULL) {
+        return 1;
+    }
+
+    map_reset_iterate(instance->leaf_map);
+    while ((current_leaf = (leaf_t *) map_next(instance->leaf_map))) {
+        current_ident = current_leaf->parent;
+        while (current_ident != NULL && current_ident != instance->last_machine) {
+            if (current_ident == ident) {
+                /* Found the ident we were looking for - add the leaf. */
+                leaves[count] = current_leaf;
+                count += 1;
+                break;
+            }
+            current_ident = current_ident->parent;
+        }
+    }
+
+    ident->leaves = leaves;
+    ident->leaf_count = count;
+
+    return 0;
+}
+
 static int init_identities(parsed_configs configs, drl_instance_t *instance) {
 static int init_identities(parsed_configs configs, drl_instance_t *instance) {
-    int i;
+    int i, j;
     ident_config *config = configs.machines;
     leaf_t *leaf = NULL;
 
     ident_config *config = configs.machines;
     leaf_t *leaf = NULL;
 
@@ -817,6 +846,18 @@ static int init_identities(parsed_configs configs, drl_instance_t *instance) {
 
         TAILQ_INSERT_TAIL(instance->cal + (instance->cal_slot & SCHEDMASK),
                           instance->machines[i], calendar);
 
         TAILQ_INSERT_TAIL(instance->cal + (instance->cal_slot & SCHEDMASK),
                           instance->machines[i], calendar);
+
+        /* Setup the array of pointers to leaves.  This is easy for machines
+         * because a machine node applies to every leaf. */
+        instance->machines[i]->leaves =
+            malloc(instance->leaf_count * sizeof(leaf_t *));
+        if (instance->machines[i]->leaves == NULL) {
+            return ENOMEM;
+        }
+        instance->machines[i]->leaf_count = instance->leaf_count;
+        for (j = 0; j < instance->leaf_count; ++j) {
+            instance->machines[i]->leaves[j] = &instance->leaves[j];
+        }
     }
 
     /* Connect the set subtree to the machines. Any set or leaf without a
     }
 
     /* Connect the set subtree to the machines. Any set or leaf without a
@@ -838,6 +879,13 @@ static int init_identities(parsed_configs configs, drl_instance_t *instance) {
 
         TAILQ_INSERT_TAIL(instance->cal + (instance->cal_slot & SCHEDMASK),
                           instance->sets[i], calendar);
 
         TAILQ_INSERT_TAIL(instance->cal + (instance->cal_slot & SCHEDMASK),
                           instance->sets[i], calendar);
+
+        /* Setup the array of pointers to leaves.  This is harder for sets,
+         * but this doesn't need to be super-efficient because it happens
+         * rarely and it isn't on the critical path for reconfig(). */
+        if (fill_set_leaf_pointer(instance, instance->sets[i])) {
+            return ENOMEM;
+        }
     }
 
     /* Success. */
     }
 
     /* Success. */
@@ -1039,6 +1087,94 @@ static int create_htb_hierarchy(drl_instance_t *instance) {
     }
     printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd);
 
     }
     printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd);
 
+#ifdef DELAY40MS
+    /* Only for artificial delay testing. */
+    sprintf(cmd, "/sbin/tc qdisc del dev eth0 parent 1:1000 handle 1000 pfifo");
+    execute_cmd(cmd);
+
+    sprintf(cmd, "/sbin/tc qdisc replace dev eth0 parent 1:1000 handle 1000 netem loss 0 delay 40ms");
+    execute_cmd(cmd);
+    sprintf(cmd, "/sbin/tc qdisc del dev eth0 parent 1:11f9 handle 11f9 pfifo");
+    execute_cmd(cmd);
+
+    sprintf(cmd, "/sbin/tc qdisc replace dev eth0 parent 1:11f9 handle 11f9 netem loss 0 delay 40ms");
+    execute_cmd(cmd);
+    sprintf(cmd, "/sbin/tc qdisc del dev eth0 parent 1:11fa handle 11fa pfifo");
+    execute_cmd(cmd);
+
+    sprintf(cmd, "/sbin/tc qdisc replace dev eth0 parent 1:11fa handle 11fa netem loss 0 delay 40ms");
+    execute_cmd(cmd);
+    /* End delay testing */
+#endif
+
+    return 0;
+}
+
+static int setup_tc_grd(drl_instance_t *instance) {
+    int i;
+    char cmd[300];
+
+    for (i = 0; i < instance->leaf_count; ++i) {
+        /* Delete the old pfifo qdisc that might have been there before. */
+        sprintf(cmd, "/sbin/tc qdisc del dev eth0 parent 1:1%x handle 1%x pfifo",
+                instance->leaves[i].xid, instance->leaves[i].xid);
+
+        if (execute_cmd(cmd)) {
+            //FIXME: remove this print and do a log.
+            printf("GRD: pfifo qdisc wasn't there!\n");
+        }
+
+        /* Add the netem qdisc. */
+#ifdef DELAY40MS
+        sprintf(cmd, "/sbin/tc qdisc replace dev eth0 parent 1:1%x handle 1%x netem loss 0 delay 40ms",
+                instance->leaves[i].xid, instance->leaves[i].xid);
+#else
+        sprintf(cmd, "/sbin/tc qdisc replace dev eth0 parent 1:1%x handle 1%x netem loss 0 delay 0ms",
+                instance->leaves[i].xid, instance->leaves[i].xid);
+#endif
+
+        if (execute_cmd(cmd)) {
+            return 1;
+        }
+    }
+
+    /* Do the same for 1000 and 1fff. */
+    sprintf(cmd, "/sbin/tc qdisc del dev eth0 parent 1:1000 handle 1000 pfifo");
+
+    if (execute_cmd(cmd)) {
+        //FIXME: remove this print and do a log.
+        printf("GRD: pfifo qdisc wasn't there!\n");
+    }
+
+    /* Add the netem qdisc. */
+#ifdef DELAY40MS
+    sprintf(cmd, "/sbin/tc qdisc replace dev eth0 parent 1:1000 handle 1000 netem loss 0 delay 40ms");
+#else
+    sprintf(cmd, "/sbin/tc qdisc replace dev eth0 parent 1:1000 handle 1000 netem loss 0 delay 0ms");
+#endif
+
+    if (execute_cmd(cmd)) {
+        return 1;
+    }
+
+    sprintf(cmd, "/sbin/tc qdisc del dev eth0 parent 1:1fff handle 1fff pfifo");
+
+    if (execute_cmd(cmd)) {
+        //FIXME: remove this print and do a log.
+        printf("GRD: pfifo qdisc wasn't there!\n");
+    }
+
+    /* Add the netem qdisc. */
+#ifdef DELAY40MS
+    sprintf(cmd, "/sbin/tc qdisc replace dev eth0 parent 1:1fff handle 1fff netem loss 0 delay 40ms");
+#else
+    sprintf(cmd, "/sbin/tc qdisc replace dev eth0 parent 1:1fff handle 1fff netem loss 0 delay 0ms");
+#endif
+
+    if (execute_cmd(cmd)) {
+        return 1;
+    }
+
     return 0;
 }
 
     return 0;
 }
 
@@ -1097,9 +1233,9 @@ static int init_drl(void) {
 
     printlog(LOG_WARN, "     POLICY: %s\n",policy.u.string);
     if (strcasecmp(policy.u.string,"GRD") == 0) {
 
     printlog(LOG_WARN, "     POLICY: %s\n",policy.u.string);
     if (strcasecmp(policy.u.string,"GRD") == 0) {
-        limiter.policynum = POLICY_GRD;
+        limiter.policy = POLICY_GRD;
     } else if (strcasecmp(policy.u.string,"FPS") == 0) {
     } else if (strcasecmp(policy.u.string,"FPS") == 0) {
-        limiter.policynum = POLICY_FPS;
+        limiter.policy = POLICY_FPS;
     } else {
         printlog(LOG_CRITICAL,
                  "Unknown DRL policy %s, aborting.\n",policy.u.string);
     } else {
         printlog(LOG_CRITICAL,
                  "Unknown DRL policy %s, aborting.\n",policy.u.string);
@@ -1155,13 +1291,27 @@ static int init_drl(void) {
     /* Debugging - FIXME: remove this? */
     print_instance(&limiter.stable_instance);
 
     /* Debugging - FIXME: remove this? */
     print_instance(&limiter.stable_instance);
 
-    if (assign_htb_hierarchy(&limiter.stable_instance)) {
-        free_instance(&limiter.stable_instance);
-        return false;
-    }
+    switch (limiter.policy) {
+        case POLICY_FPS:
+            if (assign_htb_hierarchy(&limiter.stable_instance)) {
+                free_instance(&limiter.stable_instance);
+                return false;
+            }
+
+            if (create_htb_hierarchy(&limiter.stable_instance)) {
+                free_instance(&limiter.stable_instance);
+                return false;
+            }
+        break;
 
 
-    if (create_htb_hierarchy(&limiter.stable_instance)) {
-        free_instance(&limiter.stable_instance);
+        case POLICY_GRD:
+            if (setup_tc_grd(&limiter.stable_instance)) {
+                free_instance(&limiter.stable_instance);
+                return false;
+            }
+        break;
+
+        default:
         return false;
     }
 
         return false;
     }
 
@@ -1204,9 +1354,6 @@ static void reconfig() {
         return;
     }
 
         return;
     }
 
-    /* Lock */
-    pthread_rwlock_wrlock(&limiter.limiter_lock);
-
     if (validate_configs(configs, &limiter.new_instance)) {
         free_failed_config(configs, &limiter.new_instance);
         printlog(LOG_CRITICAL, "Validation failed during reconfig().\n");
     if (validate_configs(configs, &limiter.new_instance)) {
         free_failed_config(configs, &limiter.new_instance);
         printlog(LOG_CRITICAL, "Validation failed during reconfig().\n");
@@ -1226,28 +1373,56 @@ static void reconfig() {
 
     /* Debugging - FIXME: remove this? */
     print_instance(&limiter.new_instance);
 
     /* Debugging - FIXME: remove this? */
     print_instance(&limiter.new_instance);
+    
+    /* Lock */
+    pthread_rwlock_wrlock(&limiter.limiter_lock);
 
 
-    if (assign_htb_hierarchy(&limiter.new_instance)) {
-        free_instance(&limiter.new_instance);
-        printlog(LOG_CRITICAL, "Failed to assign HTB hierarchy during reconfig().\n");
-        pthread_rwlock_unlock(&limiter.limiter_lock);
-        return;
-    }
+    switch (limiter.policy) {
+        case POLICY_FPS:
+            if (assign_htb_hierarchy(&limiter.new_instance)) {
+                free_instance(&limiter.new_instance);
+                printlog(LOG_CRITICAL, "Failed to assign HTB hierarchy during reconfig().\n");
+                pthread_rwlock_unlock(&limiter.limiter_lock);
+                return;
+            }
 
 
-    if (create_htb_hierarchy(&limiter.new_instance)) {
-        free_instance(&limiter.new_instance);
-        printlog(LOG_CRITICAL, "Failed to create HTB hierarchy during reconfig().\n");
+            if (create_htb_hierarchy(&limiter.new_instance)) {
+                free_instance(&limiter.new_instance);
+                printlog(LOG_CRITICAL, "Failed to create HTB hierarchy during reconfig().\n");
+
+                /* Re-create old instance. */
+                if (create_htb_hierarchy(&limiter.stable_instance)) {
+                    /* Error reinstating the old one - big problem. */
+                    printlog(LOG_CRITICAL, "Failed to reinstate HTB hierarchy during reconfig().\n");
+                    printlog(LOG_CRITICAL, "Giving up...\n");
+                    flushlog();
+                    exit(EXIT_FAILURE);
+                }
 
 
-        /* Re-create old instance. */
-        if (create_htb_hierarchy(&limiter.stable_instance)) {
-            /* Error reinstating the old one - big problem. */
-            printlog(LOG_CRITICAL, "Failed to reinstate HTB hierarchy during reconfig().\n");
-            flushlog();
-            exit(EXIT_FAILURE);
-        }
+                pthread_rwlock_unlock(&limiter.limiter_lock);
+                return;
+            }
+        break;
+
+        case POLICY_GRD:
+            if (setup_tc_grd(&limiter.new_instance)) {
+                free_instance(&limiter.new_instance);
+                printlog(LOG_CRITICAL, "GRD tc calls failed during reconfig().\n");
+
+                /* Try to re-create old instance. */
+                if (setup_tc_grd(&limiter.stable_instance)) {
+                    printlog(LOG_CRITICAL, "Failed to reinstate old GRD qdiscs during reconfig().\n");
+                    printlog(LOG_CRITICAL, "Giving up...\n");
+                    flushlog();
+                    exit(EXIT_FAILURE);
+                }
+            }
+        break;
 
 
-        pthread_rwlock_unlock(&limiter.limiter_lock);
-        return;
+        default:
+            /* Should be impossible. */
+            printf("Pigs are flying?\n");
+            exit(EXIT_FAILURE);
     }
 
     /* Switch over new to stable instance. */
     }
 
     /* Switch over new to stable instance. */