]> git.proxmox.com Git - ovs.git/blob - tests/test-ovn.c
system-kmod-macros: Load TFTP module.
[ovs.git] / tests / test-ovn.c
1 /*
2 * Copyright (c) 2015, 2016, 2017 Nicira, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <config.h>
18 #include <errno.h>
19 #include <getopt.h>
20 #include <sys/wait.h>
21 #include "command-line.h"
22 #include "dp-packet.h"
23 #include "fatal-signal.h"
24 #include "flow.h"
25 #include "openvswitch/dynamic-string.h"
26 #include "openvswitch/match.h"
27 #include "openvswitch/ofp-actions.h"
28 #include "openvswitch/ofpbuf.h"
29 #include "openvswitch/vlog.h"
30 #include "ovn/actions.h"
31 #include "ovn/expr.h"
32 #include "ovn/lex.h"
33 #include "ovn/lib/logical-fields.h"
34 #include "ovn/lib/ovn-dhcp.h"
35 #include "ovs-thread.h"
36 #include "ovstest.h"
37 #include "openvswitch/shash.h"
38 #include "simap.h"
39 #include "util.h"
40
41 /* --relops: Bitmap of the relational operators to test, in exhaustive test. */
42 static unsigned int test_relops;
43
44 /* --nvars: Number of numeric variables to test, in exhaustive test. */
45 static int test_nvars = 2;
46
47 /* --svars: Number of string variables to test, in exhaustive test. */
48 static int test_svars = 2;
49
50 /* --bits: Number of bits per variable, in exhaustive test. */
51 static int test_bits = 3;
52
53 /* --operation: The operation to test, in exhaustive test. */
54 static enum { OP_CONVERT, OP_SIMPLIFY, OP_NORMALIZE, OP_FLOW } operation
55 = OP_FLOW;
56
57 /* --parallel: Number of parallel processes to use in test. */
58 static int test_parallel = 1;
59
60 /* -m, --more: Message verbosity */
61 static int verbosity;
62
63 static void
64 compare_token(const struct lex_token *a, const struct lex_token *b)
65 {
66 if (a->type != b->type) {
67 fprintf(stderr, "type differs: %d -> %d\n", a->type, b->type);
68 return;
69 }
70
71 if (!((a->s && b->s && !strcmp(a->s, b->s))
72 || (!a->s && !b->s))) {
73 fprintf(stderr, "string differs: %s -> %s\n",
74 a->s ? a->s : "(null)",
75 b->s ? b->s : "(null)");
76 return;
77 }
78
79 if (a->type == LEX_T_INTEGER || a->type == LEX_T_MASKED_INTEGER) {
80 if (memcmp(&a->value, &b->value, sizeof a->value)) {
81 fprintf(stderr, "value differs\n");
82 return;
83 }
84
85 if (a->type == LEX_T_MASKED_INTEGER
86 && memcmp(&a->mask, &b->mask, sizeof a->mask)) {
87 fprintf(stderr, "mask differs\n");
88 return;
89 }
90
91 if (a->format != b->format
92 && !(a->format == LEX_F_HEXADECIMAL
93 && b->format == LEX_F_DECIMAL
94 && a->value.integer == 0)) {
95 fprintf(stderr, "format differs: %d -> %d\n",
96 a->format, b->format);
97 }
98 }
99 }
100
101 static void
102 test_lex(struct ovs_cmdl_context *ctx OVS_UNUSED)
103 {
104 struct ds input;
105 struct ds output;
106
107 ds_init(&input);
108 ds_init(&output);
109 while (!ds_get_test_line(&input, stdin)) {
110 struct lexer lexer;
111
112 lexer_init(&lexer, ds_cstr(&input));
113 ds_clear(&output);
114 while (lexer_get(&lexer) != LEX_T_END) {
115 size_t len = output.length;
116 lex_token_format(&lexer.token, &output);
117
118 /* Check that the formatted version can really be parsed back
119 * losslessly. */
120 if (lexer.token.type != LEX_T_ERROR) {
121 const char *s = ds_cstr(&output) + len;
122 struct lexer l2;
123
124 lexer_init(&l2, s);
125 lexer_get(&l2);
126 compare_token(&lexer.token, &l2.token);
127 lexer_destroy(&l2);
128 }
129 ds_put_char(&output, ' ');
130 }
131 lexer_destroy(&lexer);
132
133 ds_chomp(&output, ' ');
134 puts(ds_cstr(&output));
135 }
136 ds_destroy(&input);
137 ds_destroy(&output);
138 }
139
140 static void
141 create_symtab(struct shash *symtab)
142 {
143 ovn_init_symtab(symtab);
144
145 /* For negative testing. */
146 expr_symtab_add_field(symtab, "bad_prereq", MFF_XREG0, "xyzzy", false);
147 expr_symtab_add_field(symtab, "self_recurse", MFF_XREG0,
148 "self_recurse != 0", false);
149 expr_symtab_add_field(symtab, "mutual_recurse_1", MFF_XREG0,
150 "mutual_recurse_2 != 0", false);
151 expr_symtab_add_field(symtab, "mutual_recurse_2", MFF_XREG0,
152 "mutual_recurse_1 != 0", false);
153 expr_symtab_add_string(symtab, "big_string", MFF_XREG0, NULL);
154 }
155
156 static void
157 create_dhcp_opts(struct hmap *dhcp_opts, struct hmap *dhcpv6_opts)
158 {
159 hmap_init(dhcp_opts);
160 dhcp_opt_add(dhcp_opts, "offerip", 0, "ipv4");
161 dhcp_opt_add(dhcp_opts, "netmask", 1, "ipv4");
162 dhcp_opt_add(dhcp_opts, "router", 3, "ipv4");
163 dhcp_opt_add(dhcp_opts, "dns_server", 6, "ipv4");
164 dhcp_opt_add(dhcp_opts, "log_server", 7, "ipv4");
165 dhcp_opt_add(dhcp_opts, "lpr_server", 9, "ipv4");
166 dhcp_opt_add(dhcp_opts, "domain", 15, "str");
167 dhcp_opt_add(dhcp_opts, "swap_server", 16, "ipv4");
168 dhcp_opt_add(dhcp_opts, "policy_filter", 21, "ipv4");
169 dhcp_opt_add(dhcp_opts, "router_solicitation", 32, "ipv4");
170 dhcp_opt_add(dhcp_opts, "nis_server", 41, "ipv4");
171 dhcp_opt_add(dhcp_opts, "ntp_server", 42, "ipv4");
172 dhcp_opt_add(dhcp_opts, "server_id", 54, "ipv4");
173 dhcp_opt_add(dhcp_opts, "tftp_server", 66, "ipv4");
174 dhcp_opt_add(dhcp_opts, "classless_static_route", 121, "static_routes");
175 dhcp_opt_add(dhcp_opts, "ip_forward_enable", 19, "bool");
176 dhcp_opt_add(dhcp_opts, "router_discovery", 31, "bool");
177 dhcp_opt_add(dhcp_opts, "ethernet_encap", 36, "bool");
178 dhcp_opt_add(dhcp_opts, "default_ttl", 23, "uint8");
179 dhcp_opt_add(dhcp_opts, "tcp_ttl", 37, "uint8");
180 dhcp_opt_add(dhcp_opts, "mtu", 26, "uint16");
181 dhcp_opt_add(dhcp_opts, "lease_time", 51, "uint32");
182
183 /* DHCPv6 options. */
184 hmap_init(dhcpv6_opts);
185 dhcp_opt_add(dhcpv6_opts, "server_id", 2, "mac");
186 dhcp_opt_add(dhcpv6_opts, "ia_addr", 5, "ipv6");
187 dhcp_opt_add(dhcpv6_opts, "dns_server", 23, "ipv6");
188 dhcp_opt_add(dhcpv6_opts, "domain_search", 24, "str");
189 }
190
191 static void
192 create_addr_sets(struct shash *addr_sets)
193 {
194 shash_init(addr_sets);
195
196 static const char *const addrs1[] = {
197 "10.0.0.1", "10.0.0.2", "10.0.0.3",
198 };
199 static const char *const addrs2[] = {
200 "::1", "::2", "::3",
201 };
202 static const char *const addrs3[] = {
203 "00:00:00:00:00:01", "00:00:00:00:00:02", "00:00:00:00:00:03",
204 };
205
206 expr_addr_sets_add(addr_sets, "set1", addrs1, 3);
207 expr_addr_sets_add(addr_sets, "set2", addrs2, 3);
208 expr_addr_sets_add(addr_sets, "set3", addrs3, 3);
209 }
210
211 static bool
212 lookup_port_cb(const void *ports_, const char *port_name, unsigned int *portp)
213 {
214 const struct simap *ports = ports_;
215 const struct simap_node *node = simap_find(ports, port_name);
216 if (!node) {
217 return false;
218 }
219 *portp = node->data;
220 return true;
221 }
222
223 static bool
224 is_chassis_resident_cb(const void *ports_, const char *port_name)
225 {
226 const struct simap *ports = ports_;
227 const struct simap_node *node = simap_find(ports, port_name);
228 if (node) {
229 return true;
230 }
231 return false;
232 }
233
234 static void
235 test_parse_expr__(int steps)
236 {
237 struct shash symtab;
238 struct shash addr_sets;
239 struct simap ports;
240 struct ds input;
241
242 create_symtab(&symtab);
243 create_addr_sets(&addr_sets);
244
245 simap_init(&ports);
246 simap_put(&ports, "eth0", 5);
247 simap_put(&ports, "eth1", 6);
248 simap_put(&ports, "LOCAL", ofp_to_u16(OFPP_LOCAL));
249
250 ds_init(&input);
251 while (!ds_get_test_line(&input, stdin)) {
252 struct expr *expr;
253 char *error;
254
255 expr = expr_parse_string(ds_cstr(&input), &symtab, &addr_sets, &error);
256 if (!error && steps > 0) {
257 expr = expr_annotate(expr, &symtab, &error);
258 }
259 if (!error) {
260 if (steps > 1) {
261 expr = expr_simplify(expr, is_chassis_resident_cb, &ports);
262 }
263 if (steps > 2) {
264 expr = expr_normalize(expr);
265 ovs_assert(expr_is_normalized(expr));
266 }
267 }
268 if (!error) {
269 if (steps > 3) {
270 struct hmap matches;
271
272 expr_to_matches(expr, lookup_port_cb, &ports, &matches);
273 expr_matches_print(&matches, stdout);
274 expr_matches_destroy(&matches);
275 } else {
276 struct ds output = DS_EMPTY_INITIALIZER;
277 expr_format(expr, &output);
278 puts(ds_cstr(&output));
279 ds_destroy(&output);
280 }
281 } else {
282 puts(error);
283 free(error);
284 }
285 expr_destroy(expr);
286 }
287 ds_destroy(&input);
288
289 simap_destroy(&ports);
290 expr_symtab_destroy(&symtab);
291 shash_destroy(&symtab);
292 expr_addr_sets_destroy(&addr_sets);
293 shash_destroy(&addr_sets);
294 }
295
296 static void
297 test_parse_expr(struct ovs_cmdl_context *ctx OVS_UNUSED)
298 {
299 test_parse_expr__(0);
300 }
301
302 static void
303 test_annotate_expr(struct ovs_cmdl_context *ctx OVS_UNUSED)
304 {
305 test_parse_expr__(1);
306 }
307
308 static void
309 test_simplify_expr(struct ovs_cmdl_context *ctx OVS_UNUSED)
310 {
311 test_parse_expr__(2);
312 }
313
314 static void
315 test_normalize_expr(struct ovs_cmdl_context *ctx OVS_UNUSED)
316 {
317 test_parse_expr__(3);
318 }
319
320 static void
321 test_expr_to_flows(struct ovs_cmdl_context *ctx OVS_UNUSED)
322 {
323 test_parse_expr__(4);
324 }
325 \f
326 /* Print the symbol table. */
327
328 static void
329 test_dump_symtab(struct ovs_cmdl_context *ctx OVS_UNUSED)
330 {
331 struct shash symtab;
332 create_symtab(&symtab);
333
334 const struct shash_node **nodes = shash_sort(&symtab);
335 for (size_t i = 0; i < shash_count(&symtab); i++) {
336 const struct expr_symbol *symbol = nodes[i]->data;
337 struct ds s = DS_EMPTY_INITIALIZER;
338 expr_symbol_format(symbol, &s);
339 puts(ds_cstr(&s));
340 ds_destroy(&s);
341 }
342
343 free(nodes);
344 expr_symtab_destroy(&symtab);
345 shash_destroy(&symtab);
346 }
347 \f
348 /* Evaluate an expression. */
349
350 static bool
351 lookup_atoi_cb(const void *aux OVS_UNUSED, const char *port_name,
352 unsigned int *portp)
353 {
354 *portp = atoi(port_name);
355 return true;
356 }
357
358 static void
359 test_evaluate_expr(struct ovs_cmdl_context *ctx)
360 {
361 struct shash symtab;
362 struct ds input;
363
364 ovn_init_symtab(&symtab);
365
366 struct flow uflow;
367 char *error = expr_parse_microflow(ctx->argv[1], &symtab, NULL,
368 lookup_atoi_cb, NULL, &uflow);
369 if (error) {
370 ovs_fatal(0, "%s", error);
371 }
372
373 ds_init(&input);
374 while (!ds_get_test_line(&input, stdin)) {
375 struct expr *expr;
376
377 expr = expr_parse_string(ds_cstr(&input), &symtab, NULL, &error);
378 if (!error) {
379 expr = expr_annotate(expr, &symtab, &error);
380 }
381 if (!error) {
382 printf("%d\n", expr_evaluate(expr, &uflow, lookup_atoi_cb, NULL));
383 } else {
384 puts(error);
385 free(error);
386 }
387 expr_destroy(expr);
388 }
389 ds_destroy(&input);
390
391 expr_symtab_destroy(&symtab);
392 shash_destroy(&symtab);
393 }
394 \f
395 /* Compositions.
396 *
397 * The "compositions" of a positive integer N are all of the ways that one can
398 * add up positive integers to sum to N. For example, the compositions of 3
399 * are 3, 2+1, 1+2, and 1+1+1.
400 *
401 * We use compositions to find all the ways to break up N terms of a Boolean
402 * expression into subexpressions. Suppose we want to generate all expressions
403 * with 3 terms. The compositions of 3 (ignoring 3 itself) provide the
404 * possibilities (x && x) || x, x || (x && x), and x || x || x. (Of course one
405 * can exchange && for || in each case.) One must recursively compose the
406 * sub-expressions whose values are 3 or greater; that is what the "tree shape"
407 * concept later covers.
408 *
409 * To iterate through all compositions of, e.g., 5:
410 *
411 * unsigned int state;
412 * int s[5];
413 * int n;
414 *
415 * for (n = first_composition(ARRAY_SIZE(s), &state, s); n > 0;
416 * n = next_composition(&state, s, n)) {
417 * // Do something with composition 's' with 'n' elements.
418 * }
419 *
420 * Algorithm from D. E. Knuth, _The Art of Computer Programming, Vol. 4A:
421 * Combinatorial Algorithms, Part 1_, section 7.2.1.1, answer to exercise
422 * 12(a).
423 */
424
425 /* Begins iteration through the compositions of 'n'. Initializes 's' to the
426 * number of elements in the first composition of 'n' and returns that number
427 * of elements. The first composition in fact is always 'n' itself, so the
428 * return value will be 1.
429 *
430 * Initializes '*state' to some internal state information. The caller must
431 * maintain this state (and 's') for use by next_composition().
432 *
433 * 's' must have room for at least 'n' elements. */
434 static int
435 first_composition(int n, unsigned int *state, int s[])
436 {
437 *state = 0;
438 s[0] = n;
439 return 1;
440 }
441
442 /* Advances 's', with 'sn' elements, to the next composition and returns the
443 * number of elements in this new composition, or 0 if no compositions are
444 * left. 'state' is the same internal state passed to first_composition(). */
445 static int
446 next_composition(unsigned int *state, int s[], int sn)
447 {
448 int j = sn - 1;
449 if (++*state & 1) {
450 if (s[j] > 1) {
451 s[j]--;
452 s[j + 1] = 1;
453 j++;
454 } else {
455 j--;
456 s[j]++;
457 }
458 } else {
459 if (s[j - 1] > 1) {
460 s[j - 1]--;
461 s[j + 1] = s[j];
462 s[j] = 1;
463 j++;
464 } else {
465 j--;
466 if (!j) {
467 return 0;
468 }
469 s[j] = s[j + 1];
470 s[j - 1]++;
471 }
472 }
473 return j + 1;
474 }
475
476 static void
477 test_composition(struct ovs_cmdl_context *ctx)
478 {
479 int n = atoi(ctx->argv[1]);
480 unsigned int state;
481 int s[50];
482
483 for (int sn = first_composition(n, &state, s); sn;
484 sn = next_composition(&state, s, sn)) {
485 for (int i = 0; i < sn; i++) {
486 printf("%d%c", s[i], i == sn - 1 ? '\n' : ' ');
487 }
488 }
489 }
490 \f
491 /* Tree shapes.
492 *
493 * This code generates all possible Boolean expressions with a specified number
494 * of terms N (equivalent to the number of external nodes in a tree).
495 *
496 * See test_tree_shape() for a simple example. */
497
498 /* An array of these structures describes the shape of a tree.
499 *
500 * A single element of struct tree_shape describes a single node in the tree.
501 * The node has 'sn' direct children. From left to right, for i in 0...sn-1,
502 * s[i] is 1 if the child is a leaf node, otherwise the child is a subtree and
503 * s[i] is the number of leaf nodes within that subtree. In the latter case,
504 * the subtree is described by another struct tree_shape within the enclosing
505 * array. The tree_shapes are ordered in the array in in-order.
506 */
507 struct tree_shape {
508 unsigned int state;
509 int s[50];
510 int sn;
511 };
512
513 static int
514 init_tree_shape__(struct tree_shape ts[], int n)
515 {
516 if (n <= 2) {
517 return 0;
518 }
519
520 int n_tses = 1;
521 /* Skip the first composition intentionally. */
522 ts->sn = first_composition(n, &ts->state, ts->s);
523 ts->sn = next_composition(&ts->state, ts->s, ts->sn);
524 for (int i = 0; i < ts->sn; i++) {
525 n_tses += init_tree_shape__(&ts[n_tses], ts->s[i]);
526 }
527 return n_tses;
528 }
529
530 /* Initializes 'ts[]' as the first in the set of all of possible shapes of
531 * trees with 'n' leaves. Returns the number of "struct tree_shape"s in the
532 * first tree shape. */
533 static int
534 init_tree_shape(struct tree_shape ts[], int n)
535 {
536 switch (n) {
537 case 1:
538 ts->sn = 1;
539 ts->s[0] = 1;
540 return 1;
541 case 2:
542 ts->sn = 2;
543 ts->s[0] = 1;
544 ts->s[1] = 1;
545 return 1;
546 default:
547 return init_tree_shape__(ts, n);
548 }
549 }
550
551 /* Advances 'ts', which currently has 'n_tses' elements, to the next possible
552 * tree shape with the number of leaves passed to init_tree_shape(). Returns
553 * the number of "struct tree_shape"s in the next shape, or 0 if all tree
554 * shapes have been visited. */
555 static int
556 next_tree_shape(struct tree_shape ts[], int n_tses)
557 {
558 if (n_tses == 1 && ts->sn == 2 && ts->s[0] == 1 && ts->s[1] == 1) {
559 return 0;
560 }
561 while (n_tses > 0) {
562 struct tree_shape *p = &ts[n_tses - 1];
563 p->sn = p->sn > 1 ? next_composition(&p->state, p->s, p->sn) : 0;
564 if (p->sn) {
565 for (int i = 0; i < p->sn; i++) {
566 n_tses += init_tree_shape__(&ts[n_tses], p->s[i]);
567 }
568 break;
569 }
570 n_tses--;
571 }
572 return n_tses;
573 }
574
575 static void
576 print_tree_shape(const struct tree_shape ts[], int n_tses)
577 {
578 for (int i = 0; i < n_tses; i++) {
579 if (i) {
580 printf(", ");
581 }
582 for (int j = 0; j < ts[i].sn; j++) {
583 int k = ts[i].s[j];
584 if (k > 9) {
585 printf("(%d)", k);
586 } else {
587 printf("%d", k);
588 }
589 }
590 }
591 }
592
593 static void
594 test_tree_shape(struct ovs_cmdl_context *ctx)
595 {
596 int n = atoi(ctx->argv[1]);
597 struct tree_shape ts[50];
598 int n_tses;
599
600 for (n_tses = init_tree_shape(ts, n); n_tses;
601 n_tses = next_tree_shape(ts, n_tses)) {
602 print_tree_shape(ts, n_tses);
603 putchar('\n');
604 }
605 }
606 \f
607 /* Iteration through all possible terminal expressions (e.g. EXPR_T_CMP and
608 * EXPR_T_BOOLEAN expressions).
609 *
610 * Given a tree shape, this allows the code to try all possible ways to plug in
611 * terms.
612 *
613 * Example use:
614 *
615 * struct expr terminal;
616 * const struct expr_symbol *vars = ...;
617 * int n_vars = ...;
618 * int n_bits = ...;
619 *
620 * init_terminal(&terminal, vars[0]);
621 * do {
622 * // Something with 'terminal'.
623 * } while (next_terminal(&terminal, vars, n_vars, n_bits));
624 */
625
626 /* Sets 'expr' to the first possible terminal expression. 'var' should be the
627 * first variable in the ones to be tested. */
628 static void
629 init_terminal(struct expr *expr, int phase,
630 const struct expr_symbol *nvars[], int n_nvars,
631 const struct expr_symbol *svars[], int n_svars)
632 {
633 if (phase < 1 && n_nvars) {
634 expr->type = EXPR_T_CMP;
635 expr->cmp.symbol = nvars[0];
636 expr->cmp.relop = rightmost_1bit_idx(test_relops);
637 memset(&expr->cmp.value, 0, sizeof expr->cmp.value);
638 memset(&expr->cmp.mask, 0, sizeof expr->cmp.mask);
639 expr->cmp.value.integer = htonll(0);
640 expr->cmp.mask.integer = htonll(0);
641 return;
642 }
643
644 if (phase < 2 && n_svars) {
645 expr->type = EXPR_T_CMP;
646 expr->cmp.symbol = svars[0];
647 expr->cmp.relop = EXPR_R_EQ;
648 expr->cmp.string = xstrdup("0");
649 return;
650 }
651
652 expr->type = EXPR_T_BOOLEAN;
653 expr->boolean = false;
654 }
655
656 /* Returns 'x' with the rightmost contiguous string of 1s changed to 0s,
657 * e.g. 01011100 => 01000000. See H. S. Warren, Jr., _Hacker's Delight_, 2nd
658 * ed., section 2-1. */
659 static unsigned int
660 turn_off_rightmost_1s(unsigned int x)
661 {
662 return ((x & -x) + x) & x;
663 }
664
665 static const struct expr_symbol *
666 next_var(const struct expr_symbol *symbol,
667 const struct expr_symbol *vars[], int n_vars)
668 {
669 for (int i = 0; i < n_vars; i++) {
670 if (symbol == vars[i]) {
671 return i + 1 >= n_vars ? NULL : vars[i + 1];
672 }
673 }
674 OVS_NOT_REACHED();
675 }
676
677 static enum expr_relop
678 next_relop(enum expr_relop relop)
679 {
680 unsigned int remaining_relops = test_relops & ~((1u << (relop + 1)) - 1);
681 return (remaining_relops
682 ? rightmost_1bit_idx(remaining_relops)
683 : rightmost_1bit_idx(test_relops));
684 }
685
686 /* Advances 'expr' to the next possible terminal expression within the 'n_vars'
687 * variables of 'n_bits' bits each in 'vars[]'. */
688 static bool
689 next_terminal(struct expr *expr,
690 const struct expr_symbol *nvars[], int n_nvars, int n_bits,
691 const struct expr_symbol *svars[], int n_svars)
692 {
693 if (expr->type == EXPR_T_BOOLEAN) {
694 if (expr->boolean) {
695 return false;
696 } else {
697 expr->boolean = true;
698 return true;
699 }
700 }
701
702 if (!expr->cmp.symbol->width) {
703 int next_value = atoi(expr->cmp.string) + 1;
704 free(expr->cmp.string);
705 if (next_value > 1) {
706 expr->cmp.symbol = next_var(expr->cmp.symbol, svars, n_svars);
707 if (!expr->cmp.symbol) {
708 init_terminal(expr, 2, nvars, n_nvars, svars, n_svars);
709 return true;
710 }
711 next_value = 0;
712 }
713 expr->cmp.string = xasprintf("%d", next_value);
714 return true;
715 }
716
717 unsigned int next;
718
719 next = (ntohll(expr->cmp.value.integer)
720 + (ntohll(expr->cmp.mask.integer) << n_bits));
721 for (;;) {
722 next++;
723 unsigned m = next >> n_bits;
724 unsigned v = next & ((1u << n_bits) - 1);
725 if (next >= (1u << (2 * n_bits))) {
726 enum expr_relop old_relop = expr->cmp.relop;
727 expr->cmp.relop = next_relop(old_relop);
728 if (expr->cmp.relop <= old_relop) {
729 expr->cmp.symbol = next_var(expr->cmp.symbol, nvars, n_nvars);
730 if (!expr->cmp.symbol) {
731 init_terminal(expr, 1, nvars, n_nvars, svars, n_svars);
732 return true;
733 }
734 }
735 next = UINT_MAX;
736 } else if (v & ~m) {
737 /* Skip: 1-bits in value correspond to 0-bits in mask. */
738 } else if ((!m || turn_off_rightmost_1s(m))
739 && (expr->cmp.relop != EXPR_R_EQ &&
740 expr->cmp.relop != EXPR_R_NE)) {
741 /* Skip: can't have discontiguous or all-0 mask for > >= < <=. */
742 } else {
743 expr->cmp.value.integer = htonll(v);
744 expr->cmp.mask.integer = htonll(m);
745 return true;
746 }
747 }
748 }
749 \f
750 static struct expr *
751 make_terminal(struct expr ***terminalp)
752 {
753 struct expr *e = expr_create_boolean(true);
754 **terminalp = e;
755 (*terminalp)++;
756 return e;
757 }
758
759 static struct expr *
760 build_simple_tree(enum expr_type type, int n, struct expr ***terminalp)
761 {
762 if (n == 2) {
763 struct expr *e = expr_create_andor(type);
764 for (int i = 0; i < 2; i++) {
765 struct expr *sub = make_terminal(terminalp);
766 ovs_list_push_back(&e->andor, &sub->node);
767 }
768 return e;
769 } else if (n == 1) {
770 return make_terminal(terminalp);
771 } else {
772 OVS_NOT_REACHED();
773 }
774 }
775
776 static struct expr *
777 build_tree_shape(enum expr_type type, const struct tree_shape **tsp,
778 struct expr ***terminalp)
779 {
780 const struct tree_shape *ts = *tsp;
781 (*tsp)++;
782
783 struct expr *e = expr_create_andor(type);
784 enum expr_type t = type == EXPR_T_AND ? EXPR_T_OR : EXPR_T_AND;
785 for (int i = 0; i < ts->sn; i++) {
786 struct expr *sub = (ts->s[i] > 2
787 ? build_tree_shape(t, tsp, terminalp)
788 : build_simple_tree(t, ts->s[i], terminalp));
789 ovs_list_push_back(&e->andor, &sub->node);
790 }
791 return e;
792 }
793
794 struct test_rule {
795 struct cls_rule cr;
796 };
797
798 static void
799 free_rule(struct test_rule *test_rule)
800 {
801 cls_rule_destroy(&test_rule->cr);
802 free(test_rule);
803 }
804
805 static bool
806 tree_shape_is_chassis_resident_cb(const void *c_aux OVS_UNUSED,
807 const char *port_name OVS_UNUSED)
808 {
809 return true;
810 }
811
812 static int
813 test_tree_shape_exhaustively(struct expr *expr, struct shash *symtab,
814 struct expr *terminals[], int n_terminals,
815 const struct expr_symbol *nvars[], int n_nvars,
816 int n_bits,
817 const struct expr_symbol *svars[], int n_svars)
818 {
819 int n_tested = 0;
820
821 const unsigned int var_mask = (1u << n_bits) - 1;
822 for (int i = 0; i < n_terminals; i++) {
823 init_terminal(terminals[i], 0, nvars, n_nvars, svars, n_svars);
824 }
825
826 struct ds s = DS_EMPTY_INITIALIZER;
827 struct flow f;
828 memset(&f, 0, sizeof f);
829 for (;;) {
830 for (int i = n_terminals - 1; ; i--) {
831 if (!i) {
832 ds_destroy(&s);
833 return n_tested;
834 }
835 if (next_terminal(terminals[i], nvars, n_nvars, n_bits,
836 svars, n_svars)) {
837 break;
838 }
839 init_terminal(terminals[i], 0, nvars, n_nvars, svars, n_svars);
840 }
841 ovs_assert(expr_honors_invariants(expr));
842
843 n_tested++;
844
845 struct expr *modified;
846 if (operation == OP_CONVERT) {
847 ds_clear(&s);
848 expr_format(expr, &s);
849
850 char *error;
851 modified = expr_parse_string(ds_cstr(&s), symtab, NULL, &error);
852 if (error) {
853 fprintf(stderr, "%s fails to parse (%s)\n",
854 ds_cstr(&s), error);
855 exit(EXIT_FAILURE);
856 }
857 } else if (operation >= OP_SIMPLIFY) {
858 modified = expr_simplify(expr_clone(expr),
859 tree_shape_is_chassis_resident_cb,
860 NULL);
861 ovs_assert(expr_honors_invariants(modified));
862
863 if (operation >= OP_NORMALIZE) {
864 modified = expr_normalize(modified);
865 ovs_assert(expr_is_normalized(modified));
866 }
867 }
868
869 struct hmap matches;
870 struct classifier cls;
871 if (operation >= OP_FLOW) {
872 struct expr_match *m;
873 struct test_rule *test_rule;
874
875 expr_to_matches(modified, lookup_atoi_cb, NULL, &matches);
876
877 classifier_init(&cls, NULL);
878 HMAP_FOR_EACH (m, hmap_node, &matches) {
879 test_rule = xmalloc(sizeof *test_rule);
880 cls_rule_init(&test_rule->cr, &m->match, 0);
881 classifier_insert(&cls, &test_rule->cr, OVS_VERSION_MIN,
882 m->conjunctions, m->n);
883 }
884 }
885 for (int subst = 0; subst < 1 << (n_bits * n_nvars + n_svars);
886 subst++) {
887 for (int i = 0; i < n_nvars; i++) {
888 f.regs[i] = (subst >> (i * n_bits)) & var_mask;
889 }
890 for (int i = 0; i < n_svars; i++) {
891 f.regs[n_nvars + i] = ((subst >> (n_nvars * n_bits + i))
892 & 1);
893 }
894
895 bool expected = expr_evaluate(expr, &f, lookup_atoi_cb, NULL);
896 bool actual = expr_evaluate(modified, &f, lookup_atoi_cb, NULL);
897 if (actual != expected) {
898 struct ds expr_s, modified_s;
899
900 ds_init(&expr_s);
901 expr_format(expr, &expr_s);
902
903 ds_init(&modified_s);
904 expr_format(modified, &modified_s);
905
906 fprintf(stderr,
907 "%s evaluates to %d, but %s evaluates to %d, for",
908 ds_cstr(&expr_s), expected,
909 ds_cstr(&modified_s), actual);
910 for (int i = 0; i < n_nvars; i++) {
911 if (i > 0) {
912 fputs(",", stderr);
913 }
914 fprintf(stderr, " n%d = 0x%x", i,
915 (subst >> (n_bits * i)) & var_mask);
916 }
917 for (int i = 0; i < n_svars; i++) {
918 fprintf(stderr, ", s%d = \"%d\"", i,
919 (subst >> (n_bits * n_nvars + i)) & 1);
920 }
921 putc('\n', stderr);
922 exit(EXIT_FAILURE);
923 }
924
925 if (operation >= OP_FLOW) {
926 bool found = classifier_lookup(&cls, OVS_VERSION_MIN,
927 &f, NULL) != NULL;
928 if (expected != found) {
929 struct ds expr_s, modified_s;
930
931 ds_init(&expr_s);
932 expr_format(expr, &expr_s);
933
934 ds_init(&modified_s);
935 expr_format(modified, &modified_s);
936
937 fprintf(stderr,
938 "%s and %s evaluate to %d, for",
939 ds_cstr(&expr_s), ds_cstr(&modified_s), expected);
940 for (int i = 0; i < n_nvars; i++) {
941 if (i > 0) {
942 fputs(",", stderr);
943 }
944 fprintf(stderr, " n%d = 0x%x", i,
945 (subst >> (n_bits * i)) & var_mask);
946 }
947 for (int i = 0; i < n_svars; i++) {
948 fprintf(stderr, ", s%d = \"%d\"", i,
949 (subst >> (n_bits * n_nvars + i)) & 1);
950 }
951 fputs(".\n", stderr);
952
953 fprintf(stderr, "Converted to classifier:\n");
954 expr_matches_print(&matches, stderr);
955 fprintf(stderr,
956 "However, %s flow was found in the classifier.\n",
957 found ? "a" : "no");
958 exit(EXIT_FAILURE);
959 }
960 }
961 }
962 if (operation >= OP_FLOW) {
963 struct test_rule *test_rule;
964
965 CLS_FOR_EACH (test_rule, cr, &cls) {
966 classifier_remove(&cls, &test_rule->cr);
967 ovsrcu_postpone(free_rule, test_rule);
968 }
969 classifier_destroy(&cls);
970 ovsrcu_quiesce();
971
972 expr_matches_destroy(&matches);
973 }
974 expr_destroy(modified);
975 }
976 }
977
978 #ifndef _WIN32
979 static void
980 wait_pid(pid_t *pids, int *n)
981 {
982 int status;
983 pid_t pid;
984
985 pid = waitpid(-1, &status, 0);
986 if (pid < 0) {
987 ovs_fatal(errno, "waitpid failed");
988 } else if (WIFEXITED(status)) {
989 if (WEXITSTATUS(status)) {
990 exit(WEXITSTATUS(status));
991 }
992 } else if (WIFSIGNALED(status)) {
993 raise(WTERMSIG(status));
994 exit(1);
995 } else {
996 OVS_NOT_REACHED();
997 }
998
999 for (int i = 0; i < *n; i++) {
1000 if (pids[i] == pid) {
1001 pids[i] = pids[--*n];
1002 return;
1003 }
1004 }
1005 ovs_fatal(0, "waitpid returned unknown child");
1006 }
1007 #endif
1008
1009 static void
1010 test_exhaustive(struct ovs_cmdl_context *ctx OVS_UNUSED)
1011 {
1012 int n_terminals = atoi(ctx->argv[1]);
1013 struct tree_shape ts[50];
1014 int n_tses;
1015
1016 struct shash symtab;
1017 const struct expr_symbol *nvars[4];
1018 const struct expr_symbol *svars[4];
1019
1020 ovs_assert(test_nvars <= ARRAY_SIZE(nvars));
1021 ovs_assert(test_svars <= ARRAY_SIZE(svars));
1022 ovs_assert(test_nvars + test_svars <= FLOW_N_REGS);
1023
1024 shash_init(&symtab);
1025 for (int i = 0; i < test_nvars; i++) {
1026 char *name = xasprintf("n%d", i);
1027 nvars[i] = expr_symtab_add_field(&symtab, name, MFF_REG0 + i, NULL,
1028 false);
1029 free(name);
1030 }
1031 for (int i = 0; i < test_svars; i++) {
1032 char *name = xasprintf("s%d", i);
1033 svars[i] = expr_symtab_add_string(&symtab, name,
1034 MFF_REG0 + test_nvars + i, NULL);
1035 free(name);
1036 }
1037
1038 #ifndef _WIN32
1039 pid_t *children = xmalloc(test_parallel * sizeof *children);
1040 int n_children = 0;
1041 #endif
1042
1043 int n_tested = 0;
1044 for (int i = 0; i < 2; i++) {
1045 enum expr_type base_type = i ? EXPR_T_OR : EXPR_T_AND;
1046
1047 for (n_tses = init_tree_shape(ts, n_terminals); n_tses;
1048 n_tses = next_tree_shape(ts, n_tses)) {
1049 const struct tree_shape *tsp = ts;
1050 struct expr *terminals[50];
1051 struct expr **terminalp = terminals;
1052 struct expr *expr = build_tree_shape(base_type, &tsp, &terminalp);
1053 ovs_assert(terminalp == &terminals[n_terminals]);
1054
1055 if (verbosity > 0) {
1056 print_tree_shape(ts, n_tses);
1057 printf(": ");
1058 struct ds s = DS_EMPTY_INITIALIZER;
1059 expr_format(expr, &s);
1060 puts(ds_cstr(&s));
1061 ds_destroy(&s);
1062 }
1063
1064 #ifndef _WIN32
1065 if (test_parallel > 1) {
1066 pid_t pid = xfork();
1067 if (!pid) {
1068 test_tree_shape_exhaustively(expr, &symtab,
1069 terminals, n_terminals,
1070 nvars, test_nvars, test_bits,
1071 svars, test_svars);
1072 expr_destroy(expr);
1073 exit(0);
1074 } else {
1075 if (n_children >= test_parallel) {
1076 wait_pid(children, &n_children);
1077 }
1078 children[n_children++] = pid;
1079 }
1080 } else
1081 #endif
1082 {
1083 n_tested += test_tree_shape_exhaustively(
1084 expr, &symtab, terminals, n_terminals,
1085 nvars, test_nvars, test_bits,
1086 svars, test_svars);
1087 }
1088 expr_destroy(expr);
1089 }
1090 }
1091 #ifndef _WIN32
1092 while (n_children > 0) {
1093 wait_pid(children, &n_children);
1094 }
1095 free(children);
1096 #endif
1097
1098 printf("Tested ");
1099 switch (operation) {
1100 case OP_CONVERT:
1101 printf("converting");
1102 break;
1103 case OP_SIMPLIFY:
1104 printf("simplifying");
1105 break;
1106 case OP_NORMALIZE:
1107 printf("normalizing");
1108 break;
1109 case OP_FLOW:
1110 printf("converting to flows");
1111 break;
1112 }
1113 if (n_tested) {
1114 printf(" %d expressions of %d terminals", n_tested, n_terminals);
1115 } else {
1116 printf(" all %d-terminal expressions", n_terminals);
1117 }
1118 if (test_nvars || test_svars) {
1119 printf(" with");
1120 if (test_nvars) {
1121 printf(" %d numeric vars (each %d bits) in terms of operators",
1122 test_nvars, test_bits);
1123 for (unsigned int relops = test_relops; relops;
1124 relops = zero_rightmost_1bit(relops)) {
1125 enum expr_relop r = rightmost_1bit_idx(relops);
1126 printf(" %s", expr_relop_to_string(r));
1127 }
1128 }
1129 if (test_nvars && test_svars) {
1130 printf (" and");
1131 }
1132 if (test_svars) {
1133 printf(" %d string vars", test_svars);
1134 }
1135 } else {
1136 printf(" in terms of Boolean constants only");
1137 }
1138 printf(".\n");
1139
1140 expr_symtab_destroy(&symtab);
1141 shash_destroy(&symtab);
1142 }
1143
1144 static void
1145 test_expr_to_packets(struct ovs_cmdl_context *ctx OVS_UNUSED)
1146 {
1147 struct shash symtab;
1148 struct ds input;
1149
1150 create_symtab(&symtab);
1151
1152 ds_init(&input);
1153 while (!ds_get_test_line(&input, stdin)) {
1154 struct flow uflow;
1155 char *error = expr_parse_microflow(ds_cstr(&input), &symtab, NULL,
1156 lookup_atoi_cb, NULL, &uflow);
1157 if (error) {
1158 puts(error);
1159 free(error);
1160 continue;
1161 }
1162
1163 uint64_t packet_stub[128 / 8];
1164 struct dp_packet packet;
1165 dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
1166 flow_compose(&packet, &uflow, 0);
1167
1168 struct ds output = DS_EMPTY_INITIALIZER;
1169 const uint8_t *buf = dp_packet_data(&packet);
1170 for (int i = 0; i < dp_packet_size(&packet); i++) {
1171 uint8_t val = buf[i];
1172 ds_put_format(&output, "%02"PRIx8, val);
1173 }
1174 puts(ds_cstr(&output));
1175 ds_destroy(&output);
1176
1177 dp_packet_uninit(&packet);
1178 }
1179 ds_destroy(&input);
1180
1181 expr_symtab_destroy(&symtab);
1182 shash_destroy(&symtab);
1183 }
1184 \f
1185 /* Actions. */
1186
1187 static void
1188 test_parse_actions(struct ovs_cmdl_context *ctx OVS_UNUSED)
1189 {
1190 struct shash symtab;
1191 struct hmap dhcp_opts;
1192 struct hmap dhcpv6_opts;
1193 struct simap ports;
1194 struct ds input;
1195 bool ok = true;
1196
1197 create_symtab(&symtab);
1198 create_dhcp_opts(&dhcp_opts, &dhcpv6_opts);
1199
1200 /* Initialize group ids. */
1201 struct group_table group_table;
1202 group_table.group_ids = bitmap_allocate(MAX_OVN_GROUPS);
1203 bitmap_set1(group_table.group_ids, 0); /* Group id 0 is invalid. */
1204 hmap_init(&group_table.desired_groups);
1205 hmap_init(&group_table.existing_groups);
1206
1207 simap_init(&ports);
1208 simap_put(&ports, "eth0", 5);
1209 simap_put(&ports, "eth1", 6);
1210 simap_put(&ports, "LOCAL", ofp_to_u16(OFPP_LOCAL));
1211
1212 ds_init(&input);
1213 while (!ds_get_test_line(&input, stdin)) {
1214 struct ofpbuf ovnacts;
1215 struct expr *prereqs;
1216 char *error;
1217
1218 puts(ds_cstr(&input));
1219
1220 ofpbuf_init(&ovnacts, 0);
1221
1222 const struct ovnact_parse_params pp = {
1223 .symtab = &symtab,
1224 .dhcp_opts = &dhcp_opts,
1225 .dhcpv6_opts = &dhcpv6_opts,
1226 .n_tables = 24,
1227 .cur_ltable = 10,
1228 };
1229 error = ovnacts_parse_string(ds_cstr(&input), &pp, &ovnacts, &prereqs);
1230 if (!error) {
1231 /* Convert the parsed representation back to a string and print it,
1232 * if it's different from the input. */
1233 struct ds ovnacts_s = DS_EMPTY_INITIALIZER;
1234 ovnacts_format(ovnacts.data, ovnacts.size, &ovnacts_s);
1235 if (strcmp(ds_cstr(&input), ds_cstr(&ovnacts_s))) {
1236 printf(" formats as %s\n", ds_cstr(&ovnacts_s));
1237 }
1238
1239 /* Encode the actions into OpenFlow and print. */
1240 const struct ovnact_encode_params ep = {
1241 .lookup_port = lookup_port_cb,
1242 .aux = &ports,
1243 .is_switch = true,
1244 .group_table = &group_table,
1245
1246 .pipeline = OVNACT_P_INGRESS,
1247 .ingress_ptable = 8,
1248 .egress_ptable = 40,
1249 .output_ptable = 64,
1250 .mac_bind_ptable = 65,
1251 };
1252 struct ofpbuf ofpacts;
1253 ofpbuf_init(&ofpacts, 0);
1254 ovnacts_encode(ovnacts.data, ovnacts.size, &ep, &ofpacts);
1255 struct ds ofpacts_s = DS_EMPTY_INITIALIZER;
1256 ofpacts_format(ofpacts.data, ofpacts.size, NULL, &ofpacts_s);
1257 printf(" encodes as %s\n", ds_cstr(&ofpacts_s));
1258 ds_destroy(&ofpacts_s);
1259 ofpbuf_uninit(&ofpacts);
1260
1261 /* Print prerequisites if any. */
1262 if (prereqs) {
1263 struct ds prereqs_s = DS_EMPTY_INITIALIZER;
1264 expr_format(prereqs, &prereqs_s);
1265 printf(" has prereqs %s\n", ds_cstr(&prereqs_s));
1266 ds_destroy(&prereqs_s);
1267 }
1268
1269 /* Now re-parse and re-format the string to verify that it's
1270 * round-trippable. */
1271 struct ofpbuf ovnacts2;
1272 struct expr *prereqs2;
1273 ofpbuf_init(&ovnacts2, 0);
1274 error = ovnacts_parse_string(ds_cstr(&ovnacts_s), &pp, &ovnacts2,
1275 &prereqs2);
1276 if (!error) {
1277 struct ds ovnacts2_s = DS_EMPTY_INITIALIZER;
1278 ovnacts_format(ovnacts2.data, ovnacts2.size, &ovnacts2_s);
1279 if (strcmp(ds_cstr(&ovnacts_s), ds_cstr(&ovnacts2_s))) {
1280 printf(" bad reformat: %s\n", ds_cstr(&ovnacts2_s));
1281 ok = false;
1282 }
1283 ds_destroy(&ovnacts2_s);
1284 } else {
1285 printf(" reparse error: %s\n", error);
1286 free(error);
1287 ok = false;
1288 }
1289 expr_destroy(prereqs2);
1290
1291 ovnacts_free(ovnacts2.data, ovnacts2.size);
1292 ofpbuf_uninit(&ovnacts2);
1293 ds_destroy(&ovnacts_s);
1294 } else {
1295 printf(" %s\n", error);
1296 free(error);
1297 }
1298
1299 expr_destroy(prereqs);
1300 ovnacts_free(ovnacts.data, ovnacts.size);
1301 ofpbuf_uninit(&ovnacts);
1302 }
1303 ds_destroy(&input);
1304
1305 simap_destroy(&ports);
1306 expr_symtab_destroy(&symtab);
1307 shash_destroy(&symtab);
1308 dhcp_opts_destroy(&dhcp_opts);
1309 dhcp_opts_destroy(&dhcpv6_opts);
1310
1311 exit(ok ? EXIT_SUCCESS : EXIT_FAILURE);
1312 }
1313 \f
1314 static unsigned int
1315 parse_relops(const char *s)
1316 {
1317 unsigned int relops = 0;
1318 struct lexer lexer;
1319
1320 lexer_init(&lexer, s);
1321 lexer_get(&lexer);
1322 do {
1323 enum expr_relop relop;
1324
1325 if (expr_relop_from_token(lexer.token.type, &relop)) {
1326 relops |= 1u << relop;
1327 lexer_get(&lexer);
1328 } else {
1329 ovs_fatal(0, "%s: relational operator expected at `%.*s'",
1330 s, (int) (lexer.input - lexer.start), lexer.start);
1331 }
1332 lexer_match(&lexer, LEX_T_COMMA);
1333 } while (lexer.token.type != LEX_T_END);
1334 lexer_destroy(&lexer);
1335
1336 return relops;
1337 }
1338
1339 static void
1340 usage(void)
1341 {
1342 printf("\
1343 %s: OVN test utility\n\
1344 usage: test-ovn %s [OPTIONS] COMMAND [ARG...]\n\
1345 \n\
1346 lex\n\
1347 Lexically analyzes OVN input from stdin and print them back on stdout.\n\
1348 \n\
1349 parse-expr\n\
1350 annotate-expr\n\
1351 simplify-expr\n\
1352 normalize-expr\n\
1353 expr-to-flows\n\
1354 Parses OVN expressions from stdin and prints them back on stdout after\n\
1355 differing degrees of analysis. Available fields are based on packet\n\
1356 headers.\n\
1357 \n\
1358 expr-to-packets\n\
1359 Parses OVN expressions from stdin and prints out matching packets in\n\
1360 hexadecimal on stdout.\n\
1361 \n\
1362 evaluate-expr MICROFLOW\n\
1363 Parses OVN expressions from stdin and evaluates them against the flow\n\
1364 specified in MICROFLOW, which must be an expression that constrains\n\
1365 the packet, e.g. \"ip4 && tcp.src == 80\" for a TCP packet with source\n\
1366 port 80, and prints the results on stdout, either 1 for true or 0 for\n\
1367 false. Use quoted integers, e.g. \"123\", for string fields.\n\
1368 \n\
1369 Example: for MICROFLOW of \"ip4 && tcp.src == 80\", \"eth.type == 0x800\"\n\
1370 evaluates to true, \"udp\" evaluates to false, and \"udp || tcp\"\n\
1371 evaluates to true.\n\
1372 \n\
1373 composition N\n\
1374 Prints all the compositions of N on stdout.\n\
1375 \n\
1376 tree-shape N\n\
1377 Prints all the tree shapes with N terminals on stdout.\n\
1378 \n\
1379 exhaustive N\n\
1380 Tests that all possible Boolean expressions with N terminals are properly\n\
1381 simplified, normalized, and converted to flows. Available options:\n\
1382 Overall options:\n\
1383 --operation=OPERATION Operation to test, one of: convert, simplify,\n\
1384 normalize, flow. Default: flow. 'normalize' includes 'simplify',\n\
1385 'flow' includes 'simplify' and 'normalize'.\n\
1386 --parallel=N Number of processes to use in parallel, default 1.\n\
1387 Numeric vars:\n\
1388 --nvars=N Number of numeric vars to test, in range 0...4, default 2.\n\
1389 --bits=N Number of bits per variable, in range 1...3, default 3.\n\
1390 --relops=OPERATORS Test only the specified Boolean operators.\n\
1391 OPERATORS may include == != < <= > >=, space or\n\
1392 comma separated. Default is all operators.\n\
1393 String vars:\n\
1394 --svars=N Number of string vars to test, in range 0...4, default 2.\n\
1395 \n\
1396 parse-actions\n\
1397 Parses OVN actions from stdin and prints the equivalent OpenFlow actions\n\
1398 on stdout.\n\
1399 ",
1400 program_name, program_name);
1401 exit(EXIT_SUCCESS);
1402 }
1403
1404 static void
1405 test_ovn_main(int argc, char *argv[])
1406 {
1407 enum {
1408 OPT_RELOPS = UCHAR_MAX + 1,
1409 OPT_NVARS,
1410 OPT_SVARS,
1411 OPT_BITS,
1412 OPT_OPERATION,
1413 OPT_PARALLEL
1414 };
1415 static const struct option long_options[] = {
1416 {"relops", required_argument, NULL, OPT_RELOPS},
1417 {"nvars", required_argument, NULL, OPT_NVARS},
1418 {"svars", required_argument, NULL, OPT_SVARS},
1419 {"bits", required_argument, NULL, OPT_BITS},
1420 {"operation", required_argument, NULL, OPT_OPERATION},
1421 {"parallel", required_argument, NULL, OPT_PARALLEL},
1422 {"more", no_argument, NULL, 'm'},
1423 {"help", no_argument, NULL, 'h'},
1424 {NULL, 0, NULL, 0},
1425 };
1426 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
1427
1428 set_program_name(argv[0]);
1429
1430 test_relops = parse_relops("== != < <= > >=");
1431 for (;;) {
1432 int option_index = 0;
1433 int c = getopt_long (argc, argv, short_options, long_options,
1434 &option_index);
1435
1436 if (c == -1) {
1437 break;
1438 }
1439 switch (c) {
1440 case OPT_RELOPS:
1441 test_relops = parse_relops(optarg);
1442 break;
1443
1444 case OPT_NVARS:
1445 test_nvars = atoi(optarg);
1446 if (test_nvars < 0 || test_nvars > 4) {
1447 ovs_fatal(0, "number of numeric variables must be "
1448 "between 0 and 4");
1449 }
1450 break;
1451
1452 case OPT_SVARS:
1453 test_svars = atoi(optarg);
1454 if (test_svars < 0 || test_svars > 4) {
1455 ovs_fatal(0, "number of string variables must be "
1456 "between 0 and 4");
1457 }
1458 break;
1459
1460 case OPT_BITS:
1461 test_bits = atoi(optarg);
1462 if (test_bits < 1 || test_bits > 3) {
1463 ovs_fatal(0, "number of bits must be between 1 and 3");
1464 }
1465 break;
1466
1467 case OPT_OPERATION:
1468 if (!strcmp(optarg, "convert")) {
1469 operation = OP_CONVERT;
1470 } else if (!strcmp(optarg, "simplify")) {
1471 operation = OP_SIMPLIFY;
1472 } else if (!strcmp(optarg, "normalize")) {
1473 operation = OP_NORMALIZE;
1474 } else if (!strcmp(optarg, "flow")) {
1475 operation = OP_FLOW;
1476 } else {
1477 ovs_fatal(0, "%s: unknown operation", optarg);
1478 }
1479 break;
1480
1481 case OPT_PARALLEL:
1482 test_parallel = atoi(optarg);
1483 break;
1484
1485 case 'm':
1486 verbosity++;
1487 break;
1488
1489 case 'h':
1490 usage();
1491 /* fall through */
1492
1493 case '?':
1494 exit(1);
1495
1496 default:
1497 abort();
1498 }
1499 }
1500 free(short_options);
1501
1502 static const struct ovs_cmdl_command commands[] = {
1503 /* Lexer. */
1504 {"lex", NULL, 0, 0, test_lex, OVS_RO},
1505
1506 /* Symbol table. */
1507 {"dump-symtab", NULL, 0, 0, test_dump_symtab, OVS_RO},
1508
1509 /* Expressions. */
1510 {"parse-expr", NULL, 0, 0, test_parse_expr, OVS_RO},
1511 {"annotate-expr", NULL, 0, 0, test_annotate_expr, OVS_RO},
1512 {"simplify-expr", NULL, 0, 0, test_simplify_expr, OVS_RO},
1513 {"normalize-expr", NULL, 0, 0, test_normalize_expr, OVS_RO},
1514 {"expr-to-flows", NULL, 0, 0, test_expr_to_flows, OVS_RO},
1515 {"evaluate-expr", NULL, 1, 1, test_evaluate_expr, OVS_RO},
1516 {"composition", NULL, 1, 1, test_composition, OVS_RO},
1517 {"tree-shape", NULL, 1, 1, test_tree_shape, OVS_RO},
1518 {"exhaustive", NULL, 1, 1, test_exhaustive, OVS_RO},
1519 {"expr-to-packets", NULL, 0, 0, test_expr_to_packets, OVS_RO},
1520
1521 /* Actions. */
1522 {"parse-actions", NULL, 0, 0, test_parse_actions, OVS_RO},
1523
1524 {NULL, NULL, 0, 0, NULL, OVS_RO},
1525 };
1526 struct ovs_cmdl_context ctx;
1527 ctx.argc = argc - optind;
1528 ctx.argv = argv + optind;
1529 ovs_cmdl_run_command(&ctx, commands);
1530 }
1531
1532 OVSTEST_REGISTER("test-ovn", test_ovn_main);