odp-util: Format and scan multiple MPLS labels.
[cascardo/ovs.git] / tests / test-bundle.c
index 8a89292..4f6eb0c 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011 Nicira Networks.
+/* Copyright (c) 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  */
 
 #include <config.h>
-
+#undef NDEBUG
 #include "bundle.h"
-
 #include <math.h>
 #include <stdlib.h>
-
 #include "flow.h"
+#include "ofp-actions.h"
 #include "ofpbuf.h"
-#include "random.h"
-
+#include "ovstest.h"
 #include "util.h"
 
 #define N_FLOWS  50000
 #define MAX_SLAVES 8 /* Maximum supported by this test framework. */
 
 struct slave {
-    uint16_t slave_id;
+    ofp_port_t slave_id;
 
     bool enabled;
     size_t flow_count;
@@ -42,7 +40,7 @@ struct slave_group {
 };
 
 static struct slave *
-slave_lookup(struct slave_group *sg, uint16_t slave_id)
+slave_lookup(struct slave_group *sg, ofp_port_t slave_id)
 {
     size_t i;
 
@@ -56,7 +54,7 @@ slave_lookup(struct slave_group *sg, uint16_t slave_id)
 }
 
 static bool
-slave_enabled_cb(uint16_t slave_id, void *aux)
+slave_enabled_cb(ofp_port_t slave_id, void *aux)
 {
     struct slave *slave;
 
@@ -64,22 +62,29 @@ slave_enabled_cb(uint16_t slave_id, void *aux)
     return slave ? slave->enabled : false;
 }
 
-static struct nx_action_bundle *
+static struct ofpact_bundle *
 parse_bundle_actions(char *actions)
 {
-    struct nx_action_bundle *nab;
-    struct ofpbuf b;
+    struct ofpact_bundle *bundle;
+    struct ofpbuf ofpacts;
+    struct ofpact *action;
+    char *error;
+
+    ofpbuf_init(&ofpacts, 0);
+    error = bundle_parse_load(actions, &ofpacts);
+    if (error) {
+        ovs_fatal(0, "%s", error);
+    }
 
-    ofpbuf_init(&b, 0);
-    bundle_parse(&b, actions);
-    nab = ofpbuf_steal_data(&b);
-    ofpbuf_uninit(&b);
+    action = ofpacts.data;
+    bundle = ofpact_get_BUNDLE(xmemdup(action, action->len));
+    ofpbuf_uninit(&ofpacts);
 
-    if (ntohs(nab->n_slaves) > MAX_SLAVES) {
+    if (bundle->n_slaves > MAX_SLAVES) {
         ovs_fatal(0, "At most %u slaves are supported", MAX_SLAVES);
     }
 
-    return nab;
+    return bundle;
 }
 
 static const char *
@@ -97,28 +102,28 @@ mask_str(uint8_t mask, size_t n_bits)
     return str;
 }
 
-int
-main(int argc, char *argv[])
+static void
+test_bundle_main(int argc, char *argv[])
 {
     bool ok = true;
-    struct nx_action_bundle *nab;
+    struct ofpact_bundle *bundle;
     struct flow *flows;
     size_t i, n_permute, old_n_enabled;
     struct slave_group sg;
+    int old_active;
 
     set_program_name(argv[0]);
-    random_init();
 
     if (argc != 2) {
         ovs_fatal(0, "usage: %s bundle_action", program_name);
     }
 
-    nab = parse_bundle_actions(argv[1]);
+    bundle = parse_bundle_actions(argv[1]);
 
     /* Generate 'slaves' array. */
     sg.n_slaves = 0;
-    for (i = 0; i < ntohs(nab->n_slaves); i++) {
-        uint16_t slave_id = bundle_get_slave(nab, i);
+    for (i = 0; i < bundle->n_slaves; i++) {
+        ofp_port_t slave_id = bundle->slaves[i];
 
         if (slave_lookup(&sg, slave_id)) {
             ovs_fatal(0, "Redundant slaves are not supported. ");
@@ -131,8 +136,8 @@ main(int argc, char *argv[])
     /* Generate flows. */
     flows = xmalloc(N_FLOWS * sizeof *flows);
     for (i = 0; i < N_FLOWS; i++) {
-        random_bytes(&flows[i], sizeof flows[i]);
-        flows[i].regs[0] = OFPP_NONE;
+        flow_random_hash_fields(&flows[i]);
+        flows[i].regs[0] = ofp_to_u16(OFPP_NONE);
     }
 
     /* Cycles through each possible liveness permutation for the given
@@ -140,12 +145,14 @@ main(int argc, char *argv[])
      * skip it by starting at i = 1. We do one extra iteration to cover
      * transitioning from the final state back to the initial state. */
     old_n_enabled = 0;
+    old_active = -1;
     n_permute = 1 << sg.n_slaves;
     for (i = 1; i <= n_permute + 1; i++) {
         struct slave *slave;
         size_t j, n_enabled, changed;
         double disruption, perfect;
         uint8_t mask;
+        int active;
 
         mask = i % n_permute;
 
@@ -167,32 +174,47 @@ main(int argc, char *argv[])
             }
         }
 
+        active = -1;
+        for (j = 0; j < sg.n_slaves; j++) {
+            if (sg.slaves[j].enabled) {
+                active = j;
+                break;
+            }
+        }
+
         changed = 0;
         for (j = 0; j < N_FLOWS; j++) {
             struct flow *flow = &flows[j];
-            uint16_t old_slave_id;
+            ofp_port_t old_slave_id, ofp_port;
+            struct flow_wildcards wc;
 
-            old_slave_id = flow->regs[0];
-            flow->regs[0] = bundle_execute(nab, flow, slave_enabled_cb, &sg);
+            old_slave_id = u16_to_ofp(flow->regs[0]);
+            ofp_port = bundle_execute(bundle, flow, &wc, slave_enabled_cb,
+                                      &sg);
+            flow->regs[0] = ofp_to_u16(ofp_port);
 
-            if (flow->regs[0] != OFPP_NONE) {
-                slave_lookup(&sg, flow->regs[0])->flow_count++;
+            if (ofp_port != OFPP_NONE) {
+                slave_lookup(&sg, ofp_port)->flow_count++;
             }
 
-            if (old_slave_id != flow->regs[0]) {
+            if (old_slave_id != ofp_port) {
                 changed++;
             }
         }
 
-        if (old_n_enabled || n_enabled) {
-            perfect = 1.0 / MAX(old_n_enabled, n_enabled);
+        if (bundle->algorithm == NX_BD_ALG_ACTIVE_BACKUP) {
+            perfect = active == old_active ? 0.0 : 1.0;
         } else {
-            /* This will happen when 'sg.n_slaves' is 0. */
-            perfect = 0;
+            if (old_n_enabled || n_enabled) {
+                perfect = 1.0 / MAX(old_n_enabled, n_enabled);
+            } else {
+                /* This will happen when 'sg.n_slaves' is 0. */
+                perfect = 0;
+            }
         }
 
         disruption = changed / (double)N_FLOWS;
-        printf("%s: disruption=%.2f (perfect=%.2f) ",
+        printf("%s: disruption=%.2f (perfect=%.2f)",
                mask_str(mask, sg.n_slaves), disruption, perfect);
 
         for (j = 0 ; j < sg.n_slaves; j++) {
@@ -200,10 +222,16 @@ main(int argc, char *argv[])
             double flow_percent;
 
             flow_percent = slave->flow_count / (double)N_FLOWS;
-            printf("%.2f ", flow_percent);
+            printf( " %.2f", flow_percent);
 
             if (slave->enabled) {
-                double perfect_fp = 1.0 / n_enabled;
+                double perfect_fp;
+
+                if (bundle->algorithm == NX_BD_ALG_ACTIVE_BACKUP) {
+                    perfect_fp = j == active ? 1.0 : 0.0;
+                } else {
+                    perfect_fp = 1.0 / n_enabled;
+                }
 
                 if (fabs(flow_percent - perfect_fp) >= .01) {
                     fprintf(stderr, "%s: slave %d: flow_percentage=%.5f for"
@@ -228,10 +256,13 @@ main(int argc, char *argv[])
             ok = false;
         }
 
+        old_active = active;
         old_n_enabled = n_enabled;
     }
 
-    free(nab);
+    free(bundle);
     free(flows);
-    return ok ? 0 : 1;
+    exit(ok ? 0 : 1);
 }
+
+OVSTEST_REGISTER("test-bundle", test_bundle_main);