2 * Copyright (c) 2015 Nicira, Inc.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "command-line.h"
22 #include "dynamic-string.h"
23 #include "fatal-signal.h"
25 #include "ovn/lib/expr.h"
26 #include "ovn/lib/lex.h"
27 #include "ovs-thread.h"
31 #include "openvswitch/vlog.h"
33 /* --relops: Bitmap of the relational operators to test, in exhaustive test. */
34 static unsigned int test_relops;
36 /* --vars: Number of variables to test, in exhaustive test. */
37 static int test_vars = 2;
39 /* --bits: Number of bits per variable, in exhaustive test. */
40 static int test_bits = 3;
42 /* --operation: The operation to test, in exhaustive test. */
43 static enum { OP_CONVERT, OP_SIMPLIFY, OP_NORMALIZE, OP_FLOW } operation
46 /* --parallel: Number of parallel processes to use in test. */
47 static int test_parallel = 1;
49 /* -m, --more: Message verbosity */
53 compare_token(const struct lex_token *a, const struct lex_token *b)
55 if (a->type != b->type) {
56 fprintf(stderr, "type differs: %d -> %d\n", a->type, b->type);
60 if (!((a->s && b->s && !strcmp(a->s, b->s))
61 || (!a->s && !b->s))) {
62 fprintf(stderr, "string differs: %s -> %s\n",
63 a->s ? a->s : "(null)",
64 b->s ? b->s : "(null)");
68 if (a->type == LEX_T_INTEGER || a->type == LEX_T_MASKED_INTEGER) {
69 if (memcmp(&a->value, &b->value, sizeof a->value)) {
70 fprintf(stderr, "value differs\n");
74 if (a->type == LEX_T_MASKED_INTEGER
75 && memcmp(&a->mask, &b->mask, sizeof a->mask)) {
76 fprintf(stderr, "mask differs\n");
80 if (a->format != b->format
81 && !(a->format == LEX_F_HEXADECIMAL
82 && b->format == LEX_F_DECIMAL
83 && a->value.integer == 0)) {
84 fprintf(stderr, "format differs: %d -> %d\n",
85 a->format, b->format);
91 test_lex(struct ovs_cmdl_context *ctx OVS_UNUSED)
98 while (!ds_get_line(&input, stdin)) {
101 lexer_init(&lexer, ds_cstr(&input));
103 while (lexer_get(&lexer) != LEX_T_END) {
104 size_t len = output.length;
105 lex_token_format(&lexer.token, &output);
107 /* Check that the formatted version can really be parsed back
109 if (lexer.token.type != LEX_T_ERROR) {
110 const char *s = ds_cstr(&output) + len;
115 compare_token(&lexer.token, &l2.token);
118 ds_put_char(&output, ' ');
120 lexer_destroy(&lexer);
122 ds_chomp(&output, ' ');
123 puts(ds_cstr(&output));
130 create_symtab(struct shash *symtab)
134 expr_symtab_add_string(symtab, "inport", NULL);
135 expr_symtab_add_string(symtab, "outport", NULL);
137 expr_symtab_add_field(symtab, "xreg0", MFF_XREG0, NULL, false);
138 expr_symtab_add_field(symtab, "xreg1", MFF_XREG1, NULL, false);
139 expr_symtab_add_field(symtab, "xreg2", MFF_XREG2, NULL, false);
140 expr_symtab_add_field(symtab, "xreg3", MFF_XREG3, NULL, false);
142 expr_symtab_add_subfield(symtab, "reg0", NULL, "xreg0[32..63]");
143 expr_symtab_add_subfield(symtab, "reg1", NULL, "xreg0[0..31]");
144 expr_symtab_add_subfield(symtab, "reg2", NULL, "xreg1[32..63]");
145 expr_symtab_add_subfield(symtab, "reg3", NULL, "xreg1[0..31]");
146 expr_symtab_add_subfield(symtab, "reg4", NULL, "xreg2[32..63]");
147 expr_symtab_add_subfield(symtab, "reg5", NULL, "xreg2[0..31]");
148 expr_symtab_add_subfield(symtab, "reg6", NULL, "xreg3[32..63]");
149 expr_symtab_add_subfield(symtab, "reg7", NULL, "xreg3[0..31]");
151 expr_symtab_add_field(symtab, "eth.src", MFF_ETH_SRC, NULL, false);
152 expr_symtab_add_field(symtab, "eth.dst", MFF_ETH_DST, NULL, false);
153 expr_symtab_add_field(symtab, "eth.type", MFF_ETH_TYPE, NULL, true);
155 expr_symtab_add_field(symtab, "vlan.tci", MFF_VLAN_TCI, NULL, false);
156 expr_symtab_add_predicate(symtab, "vlan.present", "vlan.tci[12]");
157 expr_symtab_add_subfield(symtab, "vlan.pcp", "vlan.present",
159 expr_symtab_add_subfield(symtab, "vlan.vid", "vlan.present",
162 expr_symtab_add_predicate(symtab, "ip4", "eth.type == 0x800");
163 expr_symtab_add_predicate(symtab, "ip6", "eth.type == 0x86dd");
164 expr_symtab_add_predicate(symtab, "ip", "ip4 || ip6");
165 expr_symtab_add_field(symtab, "ip.proto", MFF_IP_PROTO, "ip", true);
166 expr_symtab_add_field(symtab, "ip.dscp", MFF_IP_DSCP, "ip", false);
167 expr_symtab_add_field(symtab, "ip.ecn", MFF_IP_ECN, "ip", false);
168 expr_symtab_add_field(symtab, "ip.ttl", MFF_IP_TTL, "ip", false);
170 expr_symtab_add_field(symtab, "ip4.src", MFF_IPV4_SRC, "ip4", false);
171 expr_symtab_add_field(symtab, "ip4.dst", MFF_IPV4_DST, "ip4", false);
173 expr_symtab_add_predicate(symtab, "icmp4", "ip4 && ip.proto == 1");
174 expr_symtab_add_field(symtab, "icmp4.type", MFF_ICMPV4_TYPE, "icmp4",
176 expr_symtab_add_field(symtab, "icmp4.code", MFF_ICMPV4_CODE, "icmp4",
179 expr_symtab_add_field(symtab, "ip6.src", MFF_IPV6_SRC, "ip6", false);
180 expr_symtab_add_field(symtab, "ip6.dst", MFF_IPV6_DST, "ip6", false);
181 expr_symtab_add_field(symtab, "ip6.label", MFF_IPV6_LABEL, "ip6", false);
183 expr_symtab_add_predicate(symtab, "icmp6", "ip6 && ip.proto == 58");
184 expr_symtab_add_field(symtab, "icmp6.type", MFF_ICMPV6_TYPE, "icmp6",
186 expr_symtab_add_field(symtab, "icmp6.code", MFF_ICMPV6_CODE, "icmp6",
189 expr_symtab_add_predicate(symtab, "icmp", "icmp4 || icmp6");
191 expr_symtab_add_field(symtab, "ip.frag", MFF_IP_FRAG, "ip", false);
192 expr_symtab_add_predicate(symtab, "ip.is_frag", "ip.frag[0]");
193 expr_symtab_add_predicate(symtab, "ip.later_frag", "ip.frag[1]");
194 expr_symtab_add_predicate(symtab, "ip.first_frag", "ip.is_frag && !ip.later_frag");
196 expr_symtab_add_predicate(symtab, "arp", "eth.type == 0x806");
197 expr_symtab_add_field(symtab, "arp.op", MFF_ARP_OP, "arp", false);
198 expr_symtab_add_field(symtab, "arp.spa", MFF_ARP_SPA, "arp", false);
199 expr_symtab_add_field(symtab, "arp.sha", MFF_ARP_SHA, "arp", false);
200 expr_symtab_add_field(symtab, "arp.tpa", MFF_ARP_TPA, "arp", false);
201 expr_symtab_add_field(symtab, "arp.tha", MFF_ARP_THA, "arp", false);
203 expr_symtab_add_predicate(symtab, "nd", "icmp6.type == {135, 136} && icmp6.code == 0");
204 expr_symtab_add_field(symtab, "nd.target", MFF_ND_TARGET, "nd", false);
205 expr_symtab_add_field(symtab, "nd.sll", MFF_ND_SLL,
206 "nd && icmp6.type == 135", false);
207 expr_symtab_add_field(symtab, "nd.tll", MFF_ND_TLL,
208 "nd && icmp6.type == 136", false);
210 expr_symtab_add_predicate(symtab, "tcp", "ip.proto == 6");
211 expr_symtab_add_field(symtab, "tcp.src", MFF_TCP_SRC, "tcp", false);
212 expr_symtab_add_field(symtab, "tcp.dst", MFF_TCP_DST, "tcp", false);
213 expr_symtab_add_field(symtab, "tcp.flags", MFF_TCP_FLAGS, "tcp", false);
215 expr_symtab_add_predicate(symtab, "udp", "ip.proto == 17");
216 expr_symtab_add_field(symtab, "udp.src", MFF_UDP_SRC, "udp", false);
217 expr_symtab_add_field(symtab, "udp.dst", MFF_UDP_DST, "udp", false);
219 expr_symtab_add_predicate(symtab, "sctp", "ip.proto == 132");
220 expr_symtab_add_field(symtab, "sctp.src", MFF_SCTP_SRC, "sctp", false);
221 expr_symtab_add_field(symtab, "sctp.dst", MFF_SCTP_DST, "sctp", false);
223 /* For negative testing. */
224 expr_symtab_add_field(symtab, "bad_prereq", MFF_XREG0, "xyzzy", false);
225 expr_symtab_add_field(symtab, "self_recurse", MFF_XREG0,
226 "self_recurse != 0", false);
227 expr_symtab_add_field(symtab, "mutual_recurse_1", MFF_XREG0,
228 "mutual_recurse_2 != 0", false);
229 expr_symtab_add_field(symtab, "mutual_recurse_2", MFF_XREG0,
230 "mutual_recurse_1 != 0", false);
234 test_parse_expr__(int steps)
239 create_symtab(&symtab);
241 while (!ds_get_test_line(&input, stdin)) {
245 expr = expr_parse_string(ds_cstr(&input), &symtab, &error);
246 if (!error && steps > 0) {
247 expr = expr_annotate(expr, &symtab, &error);
251 expr = expr_simplify(expr);
254 expr = expr_normalize(expr);
255 ovs_assert(expr_is_normalized(expr));
259 struct ds output = DS_EMPTY_INITIALIZER;
260 expr_format(expr, &output);
261 puts(ds_cstr(&output));
271 expr_symtab_destroy(&symtab);
272 shash_destroy(&symtab);
276 test_parse_expr(struct ovs_cmdl_context *ctx OVS_UNUSED)
278 test_parse_expr__(0);
282 test_annotate_expr(struct ovs_cmdl_context *ctx OVS_UNUSED)
284 test_parse_expr__(1);
288 test_simplify_expr(struct ovs_cmdl_context *ctx OVS_UNUSED)
290 test_parse_expr__(2);
294 test_normalize_expr(struct ovs_cmdl_context *ctx OVS_UNUSED)
296 test_parse_expr__(3);
299 /* Evaluate an expression. */
301 static bool evaluate_expr(const struct expr *, unsigned int subst, int n_bits);
304 evaluate_andor_expr(const struct expr *expr, unsigned int subst, int n_bits,
307 const struct expr *sub;
309 LIST_FOR_EACH (sub, node, &expr->andor) {
310 if (evaluate_expr(sub, subst, n_bits) == short_circuit) {
311 return short_circuit;
314 return !short_circuit;
318 evaluate_cmp_expr(const struct expr *expr, unsigned int subst, int n_bits)
320 int var_idx = expr->cmp.symbol->name[0] - 'a';
321 unsigned var_mask = (1u << n_bits) - 1;
322 unsigned int arg1 = (subst >> (var_idx * n_bits)) & var_mask;
323 unsigned int arg2 = ntohll(expr->cmp.value.integer);
324 unsigned int mask = ntohll(expr->cmp.mask.integer);
326 ovs_assert(!(mask & ~var_mask));
327 ovs_assert(!(arg2 & ~var_mask));
328 ovs_assert(!(arg2 & ~mask));
331 switch (expr->cmp.relop) {
355 /* Evaluates 'expr' and returns its Boolean result. 'subst' provides the value
356 * for the variables, which must be 'n_bits' bits each and be named "a", "b",
357 * "c", etc. The value of variable "a" is the least-significant 'n_bits' bits
358 * of 'subst', the value of "b" is the next 'n_bits' bits, and so on. */
360 evaluate_expr(const struct expr *expr, unsigned int subst, int n_bits)
362 switch (expr->type) {
364 return evaluate_cmp_expr(expr, subst, n_bits);
367 return evaluate_andor_expr(expr, subst, n_bits, false);
370 return evaluate_andor_expr(expr, subst, n_bits, true);
373 return expr->boolean;
381 test_evaluate_expr(struct ovs_cmdl_context *ctx)
383 int a = atoi(ctx->argv[1]);
384 int b = atoi(ctx->argv[2]);
385 int c = atoi(ctx->argv[3]);
386 unsigned int subst = a | (b << 3) || (c << 6);
391 expr_symtab_add_field(&symtab, "xreg0", MFF_XREG0, NULL, false);
392 expr_symtab_add_field(&symtab, "xreg1", MFF_XREG1, NULL, false);
393 expr_symtab_add_field(&symtab, "xreg2", MFF_XREG1, NULL, false);
394 expr_symtab_add_subfield(&symtab, "a", NULL, "xreg0[0..2]");
395 expr_symtab_add_subfield(&symtab, "b", NULL, "xreg1[0..2]");
396 expr_symtab_add_subfield(&symtab, "c", NULL, "xreg2[0..2]");
399 while (!ds_get_test_line(&input, stdin)) {
403 expr = expr_parse_string(ds_cstr(&input), &symtab, &error);
405 expr = expr_annotate(expr, &symtab, &error);
408 printf("%d\n", evaluate_expr(expr, subst, 3));
417 expr_symtab_destroy(&symtab);
418 shash_destroy(&symtab);
423 * The "compositions" of a positive integer N are all of the ways that one can
424 * add up positive integers to sum to N. For example, the compositions of 3
425 * are 3, 2+1, 1+2, and 1+1+1.
427 * We use compositions to find all the ways to break up N terms of a Boolean
428 * expression into subexpressions. Suppose we want to generate all expressions
429 * with 3 terms. The compositions of 3 (ignoring 3 itself) provide the
430 * possibilities (x && x) || x, x || (x && x), and x || x || x. (Of course one
431 * can exchange && for || in each case.) One must recursively compose the
432 * sub-expressions whose values are 3 or greater; that is what the "tree shape"
433 * concept later covers.
435 * To iterate through all compositions of, e.g., 5:
437 * unsigned int state;
441 * for (n = first_composition(ARRAY_SIZE(s), &state, s); n > 0;
442 * n = next_composition(&state, s, n)) {
443 * // Do something with composition 's' with 'n' elements.
446 * Algorithm from D. E. Knuth, _The Art of Computer Programming, Vol. 4A:
447 * Combinatorial Algorithms, Part 1_, section 7.2.1.1, answer to exercise
451 /* Begins iteration through the compositions of 'n'. Initializes 's' to the
452 * number of elements in the first composition of 'n' and returns that number
453 * of elements. The first composition in fact is always 'n' itself, so the
454 * return value will be 1.
456 * Initializes '*state' to some internal state information. The caller must
457 * maintain this state (and 's') for use by next_composition().
459 * 's' must have room for at least 'n' elements. */
461 first_composition(int n, unsigned int *state, int s[])
468 /* Advances 's', with 'sn' elements, to the next composition and returns the
469 * number of elements in this new composition, or 0 if no compositions are
470 * left. 'state' is the same internal state passed to first_composition(). */
472 next_composition(unsigned int *state, int s[], int sn)
503 test_composition(struct ovs_cmdl_context *ctx)
505 int n = atoi(ctx->argv[1]);
509 for (int sn = first_composition(n, &state, s); sn;
510 sn = next_composition(&state, s, sn)) {
511 for (int i = 0; i < sn; i++) {
512 printf("%d%c", s[i], i == sn - 1 ? '\n' : ' ');
519 * This code generates all possible Boolean expressions with a specified number
520 * of terms N (equivalent to the number of external nodes in a tree).
522 * See test_tree_shape() for a simple example. */
524 /* An array of these structures describes the shape of a tree.
526 * A single element of struct tree_shape describes a single node in the tree.
527 * The node has 'sn' direct children. From left to right, for i in 0...sn-1,
528 * s[i] is 1 if the child is a leaf node, otherwise the child is a subtree and
529 * s[i] is the number of leaf nodes within that subtree. In the latter case,
530 * the subtree is described by another struct tree_shape within the enclosing
531 * array. The tree_shapes are ordered in the array in in-order.
540 init_tree_shape__(struct tree_shape ts[], int n)
547 /* Skip the first composition intentionally. */
548 ts->sn = first_composition(n, &ts->state, ts->s);
549 ts->sn = next_composition(&ts->state, ts->s, ts->sn);
550 for (int i = 0; i < ts->sn; i++) {
551 n_tses += init_tree_shape__(&ts[n_tses], ts->s[i]);
556 /* Initializes 'ts[]' as the first in the set of all of possible shapes of
557 * trees with 'n' leaves. Returns the number of "struct tree_shape"s in the
558 * first tree shape. */
560 init_tree_shape(struct tree_shape ts[], int n)
573 return init_tree_shape__(ts, n);
577 /* Advances 'ts', which currently has 'n_tses' elements, to the next possible
578 * tree shape with the number of leaves passed to init_tree_shape(). Returns
579 * the number of "struct tree_shape"s in the next shape, or 0 if all tree
580 * shapes have been visited. */
582 next_tree_shape(struct tree_shape ts[], int n_tses)
584 if (n_tses == 1 && ts->sn == 2 && ts->s[0] == 1 && ts->s[1] == 1) {
588 struct tree_shape *p = &ts[n_tses - 1];
589 p->sn = p->sn > 1 ? next_composition(&p->state, p->s, p->sn) : 0;
591 for (int i = 0; i < p->sn; i++) {
592 n_tses += init_tree_shape__(&ts[n_tses], p->s[i]);
602 print_tree_shape(const struct tree_shape ts[], int n_tses)
604 for (int i = 0; i < n_tses; i++) {
608 for (int j = 0; j < ts[i].sn; j++) {
620 test_tree_shape(struct ovs_cmdl_context *ctx)
622 int n = atoi(ctx->argv[1]);
623 struct tree_shape ts[50];
626 for (n_tses = init_tree_shape(ts, n); n_tses;
627 n_tses = next_tree_shape(ts, n_tses)) {
628 print_tree_shape(ts, n_tses);
633 /* Iteration through all possible terminal expressions (e.g. EXPR_T_CMP and
634 * EXPR_T_BOOLEAN expressions).
636 * Given a tree shape, this allows the code to try all possible ways to plug in
641 * struct expr terminal;
642 * const struct expr_symbol *vars = ...;
646 * init_terminal(&terminal, vars[0]);
648 * // Something with 'terminal'.
649 * } while (next_terminal(&terminal, vars, n_vars, n_bits));
652 /* Sets 'expr' to the first possible terminal expression. 'var' should be the
653 * first variable in the ones to be tested. */
655 init_terminal(struct expr *expr, const struct expr_symbol *var)
657 expr->type = EXPR_T_CMP;
658 expr->cmp.symbol = var;
659 expr->cmp.relop = rightmost_1bit_idx(test_relops);
660 memset(&expr->cmp.value, 0, sizeof expr->cmp.value);
661 memset(&expr->cmp.mask, 0, sizeof expr->cmp.mask);
662 expr->cmp.value.integer = htonll(0);
663 expr->cmp.mask.integer = htonll(1);
666 /* Returns 'x' with the rightmost contiguous string of 1s changed to 0s,
667 * e.g. 01011100 => 01000000. See H. S. Warren, Jr., _Hacker's Delight_, 2nd
668 * ed., section 2-1. */
670 turn_off_rightmost_1s(unsigned int x)
672 return ((x & -x) + x) & x;
675 static const struct expr_symbol *
676 next_var(const struct expr_symbol *symbol,
677 const struct expr_symbol *vars[], int n_vars)
679 for (int i = 0; i < n_vars; i++) {
680 if (symbol == vars[i]) {
681 return i + 1 >= n_vars ? NULL : vars[i + 1];
687 static enum expr_relop
688 next_relop(enum expr_relop relop)
690 unsigned int remaining_relops = test_relops & ~((1u << (relop + 1)) - 1);
691 return (remaining_relops
692 ? rightmost_1bit_idx(remaining_relops)
693 : rightmost_1bit_idx(test_relops));
696 /* Advances 'expr' to the next possible terminal expression within the 'n_vars'
697 * variables of 'n_bits' bits each in 'vars[]'. */
699 next_terminal(struct expr *expr, const struct expr_symbol *vars[], int n_vars,
702 if (expr->type == EXPR_T_BOOLEAN) {
706 expr->boolean = true;
713 next = (ntohll(expr->cmp.value.integer)
714 + (ntohll(expr->cmp.mask.integer) << n_bits));
717 unsigned m = next >> n_bits;
718 unsigned v = next & ((1u << n_bits) - 1);
719 if (next >= (1u << (2 * n_bits))) {
720 enum expr_relop old_relop = expr->cmp.relop;
721 expr->cmp.relop = next_relop(old_relop);
722 if (expr->cmp.relop <= old_relop) {
723 expr->cmp.symbol = next_var(expr->cmp.symbol,vars, n_vars);
724 if (!expr->cmp.symbol) {
725 expr->type = EXPR_T_BOOLEAN;
726 expr->boolean = false;
732 /* Skip: empty mask is pathological. */
734 /* Skip: 1-bits in value correspond to 0-bits in mask. */
735 } else if (turn_off_rightmost_1s(m)
736 && (expr->cmp.relop != EXPR_R_EQ &&
737 expr->cmp.relop != EXPR_R_NE)) {
738 /* Skip: can't have discontiguous mask for > >= < <=. */
740 expr->cmp.value.integer = htonll(v);
741 expr->cmp.mask.integer = htonll(m);
748 make_terminal(struct expr ***terminalp)
750 struct expr *e = expr_create_boolean(true);
757 build_simple_tree(enum expr_type type, int n, struct expr ***terminalp)
760 struct expr *e = expr_create_andor(type);
761 for (int i = 0; i < 2; i++) {
762 struct expr *sub = make_terminal(terminalp);
763 list_push_back(&e->andor, &sub->node);
767 return make_terminal(terminalp);
774 build_tree_shape(enum expr_type type, const struct tree_shape **tsp,
775 struct expr ***terminalp)
777 const struct tree_shape *ts = *tsp;
780 struct expr *e = expr_create_andor(type);
781 enum expr_type t = type == EXPR_T_AND ? EXPR_T_OR : EXPR_T_AND;
782 for (int i = 0; i < ts->sn; i++) {
783 struct expr *sub = (ts->s[i] > 2
784 ? build_tree_shape(t, tsp, terminalp)
785 : build_simple_tree(t, ts->s[i], terminalp));
786 list_push_back(&e->andor, &sub->node);
796 free_rule(struct test_rule *test_rule)
798 cls_rule_destroy(&test_rule->cr);
803 test_tree_shape_exhaustively(struct expr *expr, struct shash *symtab,
804 struct expr *terminals[], int n_terminals,
805 const struct expr_symbol *vars[], int n_vars,
810 const unsigned int var_mask = (1u << n_bits) - 1;
811 for (int i = 0; i < n_terminals; i++) {
812 init_terminal(terminals[i], vars[0]);
815 struct ds s = DS_EMPTY_INITIALIZER;
817 memset(&f, 0, sizeof f);
819 for (int i = n_terminals - 1; ; i--) {
824 if (next_terminal(terminals[i], vars, n_vars, n_bits)) {
827 init_terminal(terminals[i], vars[0]);
829 ovs_assert(expr_honors_invariants(expr));
833 struct expr *modified;
834 if (operation == OP_CONVERT) {
836 expr_format(expr, &s);
839 modified = expr_parse_string(ds_cstr(&s), symtab, &error);
841 fprintf(stderr, "%s fails to parse (%s)\n",
845 } else if (operation >= OP_SIMPLIFY) {
846 modified = expr_simplify(expr_clone(expr));
847 ovs_assert(expr_honors_invariants(modified));
849 if (operation >= OP_NORMALIZE) {
850 modified = expr_normalize(modified);
851 ovs_assert(expr_is_normalized(modified));
856 struct classifier cls;
857 if (operation >= OP_FLOW) {
858 struct expr_match *m;
859 struct test_rule *test_rule;
862 n_conjs = expr_to_matches(modified, &matches);
864 classifier_init(&cls, NULL);
865 HMAP_FOR_EACH (m, hmap_node, &matches) {
866 test_rule = xmalloc(sizeof *test_rule);
867 cls_rule_init(&test_rule->cr, &m->match, 0);
868 classifier_insert(&cls, &test_rule->cr, m->conjunctions, m->n);
870 for (uint32_t conj_id = 1; conj_id <= n_conjs; conj_id++) {
872 match_init_catchall(&match);
873 match_set_conj_id(&match, conj_id);
875 test_rule = xmalloc(sizeof *test_rule);
876 cls_rule_init(&test_rule->cr, &match, 0);
877 classifier_insert(&cls, &test_rule->cr, NULL, 0);
880 for (int subst = 0; subst < 1 << (n_bits * n_vars); subst++) {
881 bool expected = evaluate_expr(expr, subst, n_bits);
882 bool actual = evaluate_expr(modified, subst, n_bits);
883 if (actual != expected) {
884 struct ds expr_s, modified_s;
887 expr_format(expr, &expr_s);
889 ds_init(&modified_s);
890 expr_format(modified, &modified_s);
893 "%s evaluates to %d, but %s evaluates to %d, for",
894 ds_cstr(&expr_s), expected,
895 ds_cstr(&modified_s), actual);
896 for (int i = 0; i < n_vars; i++) {
900 fprintf(stderr, " %c = 0x%x", 'a' + i,
901 (subst >> (n_bits * i)) & var_mask);
907 if (operation >= OP_FLOW) {
908 for (int i = 0; i < n_vars; i++) {
909 f.regs[i] = (subst >> (i * n_bits)) & var_mask;
911 bool found = classifier_lookup(&cls, &f, NULL) != NULL;
912 if (expected != found) {
913 struct ds expr_s, modified_s;
916 expr_format(expr, &expr_s);
918 ds_init(&modified_s);
919 expr_format(modified, &modified_s);
922 "%s and %s evaluate to %d, for",
923 ds_cstr(&expr_s), ds_cstr(&modified_s), expected);
924 for (int i = 0; i < n_vars; i++) {
928 fprintf(stderr, " %c = 0x%x", 'a' + i,
929 (subst >> (n_bits * i)) & var_mask);
931 fputs(".\n", stderr);
933 fprintf(stderr, "Converted to classifier:\n");
935 struct expr_match *m;
936 HMAP_FOR_EACH (m, hmap_node, &matches) {
937 char *s = match_to_string(&m->match,
938 OFP_DEFAULT_PRIORITY);
941 for (int i = 0; i < m->n; i++) {
942 const struct cls_conjunction *c
943 = &m->conjunctions[i];
945 "%c conjunction(%"PRIu32", %d/%d)",
947 c->id, c->clause, c->n_clauses);
954 "However, %s flow was found in the classifier.\n",
960 if (operation >= OP_FLOW) {
961 struct expr_match *m, *n;
962 struct test_rule *test_rule;
964 CLS_FOR_EACH (test_rule, cr, &cls) {
965 classifier_remove(&cls, &test_rule->cr);
966 ovsrcu_postpone(free_rule, test_rule);
968 classifier_destroy(&cls);
971 HMAP_FOR_EACH_SAFE (m, n, hmap_node, &matches) {
972 hmap_remove(&matches, &m->hmap_node);
973 free(m->conjunctions);
976 hmap_destroy(&matches);
978 expr_destroy(modified);
984 wait_pid(pid_t *pids, int *n)
989 pid = waitpid(WAIT_ANY, &status, 0);
991 ovs_fatal(errno, "waitpid failed");
992 } else if (WIFEXITED(status)) {
993 if (WEXITSTATUS(status)) {
994 exit(WEXITSTATUS(status));
996 } else if (WIFSIGNALED(status)) {
997 raise(WTERMSIG(status));
1003 for (int i = 0; i < *n; i++) {
1004 if (pids[i] == pid) {
1005 pids[i] = pids[--*n];
1009 ovs_fatal(0, "waitpid returned unknown child");
1014 test_exhaustive(struct ovs_cmdl_context *ctx OVS_UNUSED)
1016 int n_terminals = atoi(ctx->argv[1]);
1017 struct tree_shape ts[50];
1020 struct shash symtab;
1021 const struct expr_symbol *vars[4];
1023 ovs_assert(test_vars <= ARRAY_SIZE(vars));
1025 shash_init(&symtab);
1026 for (int i = 0; i < test_vars; i++) {
1027 char name[2] = { 'a' + i, '\0' };
1029 vars[i] = expr_symtab_add_field(&symtab, name, MFF_REG0 + i, NULL,
1034 pid_t *children = xmalloc(test_parallel * sizeof *children);
1039 for (int i = 0; i < 2; i++) {
1040 enum expr_type base_type = i ? EXPR_T_OR : EXPR_T_AND;
1042 for (n_tses = init_tree_shape(ts, n_terminals); n_tses;
1043 n_tses = next_tree_shape(ts, n_tses)) {
1044 const struct tree_shape *tsp = ts;
1045 struct expr *terminals[50];
1046 struct expr **terminalp = terminals;
1047 struct expr *expr = build_tree_shape(base_type, &tsp, &terminalp);
1048 ovs_assert(terminalp == &terminals[n_terminals]);
1050 if (verbosity > 0) {
1051 print_tree_shape(ts, n_tses);
1053 struct ds s = DS_EMPTY_INITIALIZER;
1054 expr_format(expr, &s);
1060 if (test_parallel > 1) {
1061 pid_t pid = xfork();
1063 test_tree_shape_exhaustively(expr, &symtab,
1064 terminals, n_terminals,
1065 vars, test_vars, test_bits);
1069 if (n_children >= test_parallel) {
1070 wait_pid(children, &n_children);
1072 children[n_children++] = pid;
1077 n_tested += test_tree_shape_exhaustively(
1078 expr, &symtab, terminals, n_terminals,
1079 vars, test_vars, test_bits);
1085 while (n_children > 0) {
1086 wait_pid(children, &n_children);
1092 switch (operation) {
1094 printf("converting");
1097 printf("simplifying");
1100 printf("normalizing");
1103 printf("converting to flows");
1107 printf(" %d expressions of %d terminals", n_tested, n_terminals);
1109 printf(" all %d-terminal expressions", n_terminals);
1111 printf(" with %d vars each of %d bits in terms of operators",
1112 test_vars, test_bits);
1113 for (unsigned int relops = test_relops; relops;
1114 relops = zero_rightmost_1bit(relops)) {
1115 enum expr_relop r = rightmost_1bit_idx(relops);
1116 printf(" %s", expr_relop_to_string(r));
1120 expr_symtab_destroy(&symtab);
1121 shash_destroy(&symtab);
1125 parse_relops(const char *s)
1127 unsigned int relops = 0;
1130 lexer_init(&lexer, s);
1133 enum expr_relop relop;
1135 if (expr_relop_from_token(lexer.token.type, &relop)) {
1136 relops |= 1u << relop;
1139 ovs_fatal(0, "%s: relational operator expected at `%.*s'",
1140 s, (int) (lexer.input - lexer.start), lexer.start);
1142 lexer_match(&lexer, LEX_T_COMMA);
1143 } while (lexer.token.type != LEX_T_END);
1144 lexer_destroy(&lexer);
1153 %s: OVN test utility\n\
1154 usage: test-ovn %s [OPTIONS] COMMAND [ARG...]\n\
1157 Lexically analyzes OVN input from stdin and print them back on stdout.\n\
1163 Parses OVN expressions from stdin and print them back on stdout after\n\
1164 differing degrees of analysis. Available fields are based on packet\n\
1167 evaluate-expr A B C\n\
1168 Parses OVN expressions from stdin, evaluate them with assigned values,\n\
1169 and print the results on stdout. Available fields are 'a', 'b', and 'c'\n\
1170 of 3 bits each. A, B, and C should be in the range 0 to 7.\n\
1173 Prints all the compositions of N on stdout.\n\
1176 Prints all the tree shapes with N terminals on stdout.\n\
1179 Tests that all possible Boolean expressions with N terminals are properly\n\
1180 simplified, normalized, and converted to flows. Available options:\n\
1181 --relops=OPERATORS Test only the specified Boolean operators.\n\
1182 OPERATORS may include == != < <= > >=, space or\n\
1183 comma separated. Default is all operators.\n\
1184 --vars=N Number of variables to test, in range 1...4, default 2.\n\
1185 --bits=N Number of bits per variable, in range 1...3, default 3.\n\
1186 --operation=OPERATION Operation to test, one of: convert, simplify,\n\
1187 normalize, flow. Default: flow. 'normalize' includes 'simplify',\n\
1188 'flow' includes 'simplify' and 'normaize'.\n\
1189 --parallel=N Number of processes to use in parallel, default 1.\n\
1191 program_name, program_name);
1196 test_ovn_main(int argc, char *argv[])
1198 set_program_name(argv[0]);
1200 test_relops = parse_relops("== != < <= > >=");
1203 OPT_RELOPS = UCHAR_MAX + 1,
1210 static const struct option options[] = {
1211 {"relops", required_argument, NULL, OPT_RELOPS},
1212 {"vars", required_argument, NULL, OPT_VARS},
1213 {"bits", required_argument, NULL, OPT_BITS},
1214 {"operation", required_argument, NULL, OPT_OPERATION},
1215 {"parallel", required_argument, NULL, OPT_PARALLEL},
1216 {"more", no_argument, NULL, 'm'},
1217 {"help", no_argument, NULL, 'h'},
1220 int option_index = 0;
1221 int c = getopt_long (argc, argv, "", options, &option_index);
1228 test_relops = parse_relops(optarg);
1232 test_vars = atoi(optarg);
1233 if (test_vars < 1 || test_vars > 4) {
1234 ovs_fatal(0, "number of variables must be between 1 and 4");
1239 test_bits = atoi(optarg);
1240 if (test_bits < 1 || test_bits > 3) {
1241 ovs_fatal(0, "number of bits must be between 1 and 3");
1246 if (!strcmp(optarg, "convert")) {
1247 operation = OP_CONVERT;
1248 } else if (!strcmp(optarg, "simplify")) {
1249 operation = OP_SIMPLIFY;
1250 } else if (!strcmp(optarg, "normalize")) {
1251 operation = OP_NORMALIZE;
1252 } else if (!strcmp(optarg, "flow")) {
1253 operation = OP_FLOW;
1255 ovs_fatal(0, "%s: unknown operation", optarg);
1260 test_parallel = atoi(optarg);
1278 static const struct ovs_cmdl_command commands[] = {
1279 {"lex", NULL, 0, 0, test_lex},
1280 {"parse-expr", NULL, 0, 0, test_parse_expr},
1281 {"annotate-expr", NULL, 0, 0, test_annotate_expr},
1282 {"simplify-expr", NULL, 0, 0, test_simplify_expr},
1283 {"normalize-expr", NULL, 0, 0, test_normalize_expr},
1284 {"evaluate-expr", NULL, 1, 1, test_evaluate_expr},
1285 {"composition", NULL, 1, 1, test_composition},
1286 {"tree-shape", NULL, 1, 1, test_tree_shape},
1287 {"exhaustive", NULL, 1, 1, test_exhaustive},
1288 {NULL, NULL, 0, 0, NULL},
1290 struct ovs_cmdl_context ctx;
1291 ctx.argc = argc - optind;
1292 ctx.argv = argv + optind;
1293 ovs_cmdl_run_command(&ctx, commands);
1296 OVSTEST_REGISTER("test-ovn", test_ovn_main);