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