summaryrefslogtreecommitdiff
path: root/tests/test-multipath.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test-multipath.c')
-rw-r--r--tests/test-multipath.c131
1 files changed, 131 insertions, 0 deletions
diff --git a/tests/test-multipath.c b/tests/test-multipath.c
new file mode 100644
index 000000000..03a666f40
--- /dev/null
+++ b/tests/test-multipath.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2010 Nicira Networks.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include "multipath.h"
+
+#include <assert.h>
+#include <getopt.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "flow.h"
+#include "random.h"
+#include "util.h"
+
+int
+main(int argc, char *argv[])
+{
+ enum { MP_MAX_LINKS = 63 };
+ struct nx_action_multipath mp;
+ bool ok = true;
+ int n;
+
+ set_program_name(argv[0]);
+ random_init();
+
+ if (argc != 2) {
+ ovs_fatal(0, "usage: %s multipath_action", program_name);
+ }
+
+ multipath_parse(&mp, argv[1]);
+ for (n = 1; n <= MP_MAX_LINKS; n++) {
+ enum { N_FLOWS = 65536 };
+ double disruption, perfect, distribution;
+ int histogram[MP_MAX_LINKS];
+ double sum_dev2, stddev;
+ int changed;
+ int i;
+
+ changed = 0;
+ memset(histogram, 0, sizeof histogram);
+ for (i = 0; i < N_FLOWS; i++) {
+ int old_link, new_link;
+ struct flow flow;
+
+ random_bytes(&flow, sizeof flow);
+
+ mp.max_link = htons(n - 1);
+ multipath_execute(&mp, &flow);
+ old_link = flow.regs[0];
+
+ mp.max_link = htons(n);
+ multipath_execute(&mp, &flow);
+ new_link = flow.regs[0];
+
+ assert(old_link >= 0 && old_link < n);
+ assert(new_link >= 0 && new_link < n + 1);
+
+ histogram[old_link]++;
+ changed += old_link != new_link;
+ }
+
+ sum_dev2 = 0.0;
+ for (i = 0; i < n; i++) {
+ double mean = (double) N_FLOWS / n;
+ double deviation = histogram[i] - mean;
+
+ sum_dev2 += deviation * deviation;
+ }
+ stddev = sqrt(sum_dev2 / n);
+
+ disruption = (double) changed / N_FLOWS;
+ perfect = 1.0 / (n + 1);
+ distribution = stddev / ((double) N_FLOWS / n);
+ printf("%2d -> %2d: disruption=%.2f (perfect=%.2f); "
+ "stddev/expected=%.4f\n",
+ n, n + 1, disruption, perfect, distribution);
+
+ switch (ntohs(mp.algorithm)) {
+ case NX_MP_ALG_MODULO_N:
+ if (disruption < (n < 2 ? .25 : .5)) {
+ fprintf(stderr, "%d -> %d: disruption=%.2f < .5\n",
+ n, n + 1, disruption);
+ ok = false;
+ }
+ break;
+
+ case NX_MP_ALG_HASH_THRESHOLD:
+ if (disruption < .48 || disruption > .52) {
+ fprintf(stderr, "%d -> %d: disruption=%.2f not approximately "
+ ".5\n", n, n + 1, disruption);
+ ok = false;
+ }
+ break;
+
+ case NX_MP_ALG_ITER_HASH:
+ if (!(n & (n - 1))) {
+ break;
+ }
+ /* Fall through. */
+ case NX_MP_ALG_HRW:
+ if (fabs(disruption - perfect) >= .01) {
+ fprintf(stderr, "%d -> %d: disruption=%.5f differs from "
+ "perfect=%.5f by more than .01\n",
+ n, n + 1, disruption, perfect);
+ ok = false;
+ }
+ break;
+
+ default:
+ NOT_REACHED();
+ }
+ }
+
+ return ok ? 0 : 1;
+}