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