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