void bundle_to_nxast(const struct ofpact_bundle *bundle, struct ofpbuf *openflow) { int slaves_len = ROUND_UP(2 * bundle->n_slaves, OFP_ACTION_ALIGN); struct nx_action_bundle *nab; ovs_be16 *slaves; size_t i; nab = (bundle->dst.field ? ofputil_put_NXAST_BUNDLE_LOAD(openflow) : ofputil_put_NXAST_BUNDLE(openflow)); nab->len = htons(ntohs(nab->len) + slaves_len); nab->algorithm = htons(bundle->algorithm); nab->fields = htons(bundle->fields); nab->basis = htons(bundle->basis); nab->slave_type = htonl(NXM_OF_IN_PORT); nab->n_slaves = htons(bundle->n_slaves); if (bundle->dst.field) { nab->ofs_nbits = nxm_encode_ofs_nbits(bundle->dst.ofs, bundle->dst.n_bits); nab->dst = htonl(bundle->dst.field->nxm_header); } slaves = ofpbuf_put_zeros(openflow, slaves_len); for (i = 0; i < bundle->n_slaves; i++) { slaves[i] = htons(ofp_to_u16(bundle->slaves[i])); } }
/* Constructs and returns an OFPT_QUEUE_GET_CONFIG request for the specified * 'port' and 'queue', suitable for OpenFlow version 'version'. * * 'queue' is honored only for OpenFlow 1.4 and later; older versions always * request all queues. */ struct ofpbuf * ofputil_encode_queue_get_config_request(enum ofp_version version, ofp_port_t port, uint32_t queue) { struct ofpbuf *request; if (version == OFP10_VERSION) { struct ofp10_queue_get_config_request *qgcr10; request = ofpraw_alloc(OFPRAW_OFPT10_QUEUE_GET_CONFIG_REQUEST, version, 0); qgcr10 = ofpbuf_put_zeros(request, sizeof *qgcr10); qgcr10->port = htons(ofp_to_u16(port)); } else if (version < OFP14_VERSION) { struct ofp11_queue_get_config_request *qgcr11; request = ofpraw_alloc(OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST, version, 0); qgcr11 = ofpbuf_put_zeros(request, sizeof *qgcr11); qgcr11->port = ofputil_port_to_ofp11(port); } else { struct ofp14_queue_desc_request *qdr14; request = ofpraw_alloc(OFPRAW_OFPST14_QUEUE_DESC_REQUEST, version, 0); qdr14 = ofpbuf_put_zeros(request, sizeof *qdr14); qdr14->port = ofputil_port_to_ofp11(port); qdr14->queue = htonl(queue); } return request; }
/* qsort comparison function. */ static int compare_queues(const void *a_, const void *b_) { const struct ofputil_queue_config *a = a_; const struct ofputil_queue_config *b = b_; uint16_t ap = ofp_to_u16(a->port); uint16_t bp = ofp_to_u16(b->port); if (ap != bp) { return ap < bp ? -1 : 1; } uint32_t aq = a->queue; uint32_t bq = b->queue; return aq < bq ? -1 : aq > bq; }
static void ofputil_queue_stats_to_ofp10(const struct ofputil_queue_stats *oqs, struct ofp10_queue_stats *qs10) { qs10->port_no = htons(ofp_to_u16(oqs->port_no)); memset(qs10->pad, 0, sizeof qs10->pad); qs10->queue_id = htonl(oqs->queue_id); put_32aligned_be64(&qs10->tx_bytes, htonll(oqs->tx_bytes)); put_32aligned_be64(&qs10->tx_packets, htonll(oqs->tx_packets)); put_32aligned_be64(&qs10->tx_errors, htonll(oqs->tx_errors)); }
/* Parses OFPT_QUEUE_GET_CONFIG request 'oh', storing the port specified by the * request into '*port'. Returns 0 if successful, otherwise an OpenFlow error * code. */ enum ofperr ofputil_decode_queue_get_config_request(const struct ofp_header *oh, ofp_port_t *port, uint32_t *queue) { const struct ofp10_queue_get_config_request *qgcr10; const struct ofp11_queue_get_config_request *qgcr11; const struct ofp14_queue_desc_request *qdr14; struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); enum ofpraw raw = ofpraw_pull_assert(&b); switch ((int) raw) { case OFPRAW_OFPT10_QUEUE_GET_CONFIG_REQUEST: qgcr10 = b.data; *port = u16_to_ofp(ntohs(qgcr10->port)); *queue = OFPQ_ALL; break; case OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST: qgcr11 = b.data; *queue = OFPQ_ALL; enum ofperr error = ofputil_port_from_ofp11(qgcr11->port, port); if (error || *port == OFPP_ANY) { return error; } break; case OFPRAW_OFPST14_QUEUE_DESC_REQUEST: qdr14 = b.data; *queue = ntohl(qdr14->queue); return ofputil_port_from_ofp11(qdr14->port, port); default: OVS_NOT_REACHED(); } return (ofp_to_u16(*port) < ofp_to_u16(OFPP_MAX) ? 0 : OFPERR_OFPQOFC_BAD_PORT); }
/* Constructs and returns the beginning of a reply to * OFPT_QUEUE_GET_CONFIG_REQUEST or OFPMP_QUEUE_DESC request 'oh'. The caller * may append information about individual queues with * ofputil_append_queue_get_config_reply(). */ void ofputil_start_queue_get_config_reply(const struct ofp_header *request, struct ovs_list *replies) { struct ofpbuf *reply; ofp_port_t port; uint32_t queue; ovs_assert(!ofputil_decode_queue_get_config_request(request, &port, &queue)); enum ofpraw raw = ofpraw_decode_assert(request); switch ((int) raw) { case OFPRAW_OFPT10_QUEUE_GET_CONFIG_REQUEST: reply = ofpraw_alloc_reply(OFPRAW_OFPT10_QUEUE_GET_CONFIG_REPLY, request, 0); struct ofp10_queue_get_config_reply *qgcr10 = ofpbuf_put_zeros(reply, sizeof *qgcr10); qgcr10->port = htons(ofp_to_u16(port)); break; case OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST: reply = ofpraw_alloc_reply(OFPRAW_OFPT11_QUEUE_GET_CONFIG_REPLY, request, 0); struct ofp11_queue_get_config_reply *qgcr11 = ofpbuf_put_zeros(reply, sizeof *qgcr11); qgcr11->port = ofputil_port_to_ofp11(port); break; case OFPRAW_OFPST14_QUEUE_DESC_REQUEST: reply = ofpraw_alloc_stats_reply(request, 0); break; default: OVS_NOT_REACHED(); } ovs_list_init(replies); ovs_list_push_back(replies, &reply->list_node); }
/* Encode a queue stats request for 'oqsr', the encoded message * will be for OpenFlow version 'ofp_version'. Returns message * as a struct ofpbuf. Returns encoded message on success, NULL on error. */ struct ofpbuf * ofputil_encode_queue_stats_request( enum ofp_version ofp_version, const struct ofputil_queue_stats_request *oqsr) { struct ofpbuf *request; switch (ofp_version) { case OFP11_VERSION: case OFP12_VERSION: case OFP13_VERSION: case OFP14_VERSION: case OFP15_VERSION: case OFP16_VERSION: { struct ofp11_queue_stats_request *req; request = ofpraw_alloc(OFPRAW_OFPST11_QUEUE_REQUEST, ofp_version, 0); req = ofpbuf_put_zeros(request, sizeof *req); req->port_no = ofputil_port_to_ofp11(oqsr->port_no); req->queue_id = htonl(oqsr->queue_id); break; } case OFP10_VERSION: { struct ofp10_queue_stats_request *req; request = ofpraw_alloc(OFPRAW_OFPST10_QUEUE_REQUEST, ofp_version, 0); req = ofpbuf_put_zeros(request, sizeof *req); /* OpenFlow 1.0 needs OFPP_ALL instead of OFPP_ANY */ req->port_no = htons(ofp_to_u16(oqsr->port_no == OFPP_ANY ? OFPP_ALL : oqsr->port_no)); req->queue_id = htonl(oqsr->queue_id); break; } default: OVS_NOT_REACHED(); } return request; }
/* Composes 'fm' so that executing it will implement 'learn' given that the * packet being processed has 'flow' as its flow. * * Uses 'ofpacts' to store the flow mod's actions. The caller must initialize * 'ofpacts' and retains ownership of it. 'fm->ofpacts' will point into the * 'ofpacts' buffer. * * The caller has to actually execute 'fm'. */ void learn_execute(const struct ofpact_learn *learn, const struct flow *flow, struct ofputil_flow_mod *fm, struct ofpbuf *ofpacts) { const struct ofpact_learn_spec *spec; match_init_catchall(&fm->match); fm->priority = learn->priority; fm->cookie = htonll(0); fm->cookie_mask = htonll(0); fm->new_cookie = learn->cookie; fm->modify_cookie = fm->new_cookie != OVS_BE64_MAX; fm->table_id = learn->table_id; fm->command = OFPFC_MODIFY_STRICT; fm->idle_timeout = learn->idle_timeout; fm->hard_timeout = learn->hard_timeout; fm->importance = 0; fm->buffer_id = UINT32_MAX; fm->out_port = OFPP_NONE; fm->flags = 0; if (learn->flags & NX_LEARN_F_SEND_FLOW_REM) { fm->flags |= OFPUTIL_FF_SEND_FLOW_REM; } fm->ofpacts = NULL; fm->ofpacts_len = 0; fm->delete_reason = OFPRR_DELETE; if (learn->fin_idle_timeout || learn->fin_hard_timeout) { struct ofpact_fin_timeout *oft; oft = ofpact_put_FIN_TIMEOUT(ofpacts); oft->fin_idle_timeout = learn->fin_idle_timeout; oft->fin_hard_timeout = learn->fin_hard_timeout; } for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) { struct ofpact_set_field *sf; union mf_subvalue value; if (spec->src_type == NX_LEARN_SRC_FIELD) { mf_read_subfield(&spec->src, flow, &value); } else { value = spec->src_imm; } switch (spec->dst_type) { case NX_LEARN_DST_MATCH: mf_write_subfield(&spec->dst, &value, &fm->match); break; case NX_LEARN_DST_LOAD: sf = ofpact_put_reg_load(ofpacts); sf->field = spec->dst.field; bitwise_copy(&value, sizeof value, 0, &sf->value, spec->dst.field->n_bytes, spec->dst.ofs, spec->n_bits); bitwise_one(&sf->mask, spec->dst.field->n_bytes, spec->dst.ofs, spec->n_bits); break; case NX_LEARN_DST_OUTPUT: if (spec->n_bits <= 16 || is_all_zeros(value.u8, sizeof value - 2)) { ovs_be16 *last_be16 = &value.be16[ARRAY_SIZE(value.be16) - 1]; ofp_port_t port = u16_to_ofp(ntohs(*last_be16)); if (ofp_to_u16(port) < ofp_to_u16(OFPP_MAX) || port == OFPP_IN_PORT || port == OFPP_FLOOD || port == OFPP_LOCAL || port == OFPP_ALL) { ofpact_put_OUTPUT(ofpacts)->port = port; } } break; } } ofpact_pad(ofpacts); fm->ofpacts = ofpbuf_data(ofpacts); fm->ofpacts_len = ofpbuf_size(ofpacts); }
/* Composes 'fm' so that executing it will implement 'learn' given that the * packet being processed has 'flow' as its flow. * * Uses 'ofpacts' to store the flow mod's actions. The caller must initialize * 'ofpacts' and retains ownership of it. 'fm->ofpacts' will point into the * 'ofpacts' buffer. * * The caller has to actually execute 'fm'. */ void learn_execute(const struct ofpact_learn *learn, const struct flow *flow, struct ofputil_flow_mod *fm, struct ofpbuf *ofpacts) { const struct ofpact_learn_spec *spec; match_init_catchall(&fm->match); fm->priority = learn->priority; fm->cookie = htonll(0); fm->cookie_mask = htonll(0); fm->new_cookie = htonll(learn->cookie); fm->table_id = learn->table_id; fm->command = OFPFC_MODIFY_STRICT; fm->idle_timeout = learn->idle_timeout; fm->hard_timeout = learn->hard_timeout; fm->buffer_id = UINT32_MAX; fm->out_port = OFPP_NONE; fm->flags = learn->flags; fm->ofpacts = NULL; fm->ofpacts_len = 0; if (learn->fin_idle_timeout || learn->fin_hard_timeout) { struct ofpact_fin_timeout *oft; oft = ofpact_put_FIN_TIMEOUT(ofpacts); oft->fin_idle_timeout = learn->fin_idle_timeout; oft->fin_hard_timeout = learn->fin_hard_timeout; } for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) { union mf_subvalue value; int chunk, ofs; if (spec->src_type == NX_LEARN_SRC_FIELD) { mf_read_subfield(&spec->src, flow, &value); } else { value = spec->src_imm; } switch (spec->dst_type) { case NX_LEARN_DST_MATCH: mf_write_subfield(&spec->dst, &value, &fm->match); break; case NX_LEARN_DST_LOAD: for (ofs = 0; ofs < spec->n_bits; ofs += chunk) { struct ofpact_reg_load *load; chunk = MIN(spec->n_bits - ofs, 64); load = ofpact_put_REG_LOAD(ofpacts); load->dst.field = spec->dst.field; load->dst.ofs = spec->dst.ofs + ofs; load->dst.n_bits = chunk; bitwise_copy(&value, sizeof value, ofs, &load->subvalue, sizeof load->subvalue, 0, chunk); } break; case NX_LEARN_DST_OUTPUT: if (spec->n_bits <= 16 || is_all_zeros(value.u8, sizeof value - 2)) { ofp_port_t port = u16_to_ofp(ntohs(value.be16[7])); if (ofp_to_u16(port) < ofp_to_u16(OFPP_MAX) || port == OFPP_IN_PORT || port == OFPP_FLOOD || port == OFPP_LOCAL || port == OFPP_ALL) { ofpact_put_OUTPUT(ofpacts)->port = port; } } break; } } ofpact_pad(ofpacts); fm->ofpacts = ofpacts->data; fm->ofpacts_len = ofpacts->size; }
/* Composes 'fm' so that executing it will implement 'learn' given that the * packet being processed has 'flow' as its flow. * * Uses 'ofpacts' to store the flow mod's actions. The caller must initialize * 'ofpacts' and retains ownership of it. 'fm->ofpacts' will point into the * 'ofpacts' buffer. * * The caller has to actually execute 'fm'. */ void learn_execute(const struct ofpact_learn *learn, const struct flow *flow, struct ofputil_flow_mod *fm, struct ofpbuf *ofpacts) { const struct ofpact_learn_spec *spec; match_init_catchall(&fm->match); fm->priority = learn->priority; fm->cookie = htonll(0); fm->cookie_mask = htonll(0); fm->new_cookie = learn->cookie; fm->modify_cookie = fm->new_cookie != OVS_BE64_MAX; fm->table_id = learn->table_id; fm->command = OFPFC_MODIFY_STRICT; fm->idle_timeout = learn->idle_timeout; fm->hard_timeout = learn->hard_timeout; fm->importance = 0; fm->buffer_id = UINT32_MAX; fm->out_port = OFPP_NONE; fm->ofpacts_tlv_bitmap = 0; fm->flags = 0; if (learn->flags & NX_LEARN_F_SEND_FLOW_REM) { fm->flags |= OFPUTIL_FF_SEND_FLOW_REM; } fm->ofpacts = NULL; fm->ofpacts_len = 0; if (learn->fin_idle_timeout || learn->fin_hard_timeout) { struct ofpact_fin_timeout *oft; oft = ofpact_put_FIN_TIMEOUT(ofpacts); oft->fin_idle_timeout = learn->fin_idle_timeout; oft->fin_hard_timeout = learn->fin_hard_timeout; } OFPACT_LEARN_SPEC_FOR_EACH (spec, learn) { struct ofpact_set_field *sf; union mf_subvalue value; if (spec->src_type == NX_LEARN_SRC_FIELD) { mf_read_subfield(&spec->src, flow, &value); } else { mf_subvalue_from_value(&spec->dst, &value, ofpact_learn_spec_imm(spec)); } switch (spec->dst_type) { case NX_LEARN_DST_MATCH: mf_write_subfield(&spec->dst, &value, &fm->match); match_add_ethernet_prereq(&fm->match, spec->dst.field); mf_vl_mff_set_tlv_bitmap( spec->dst.field, &fm->match.flow.tunnel.metadata.present.map); break; case NX_LEARN_DST_LOAD: sf = ofpact_put_reg_load(ofpacts, spec->dst.field, NULL, NULL); bitwise_copy(&value, sizeof value, 0, sf->value, spec->dst.field->n_bytes, spec->dst.ofs, spec->n_bits); bitwise_one(ofpact_set_field_mask(sf), spec->dst.field->n_bytes, spec->dst.ofs, spec->n_bits); mf_vl_mff_set_tlv_bitmap(spec->dst.field, &fm->ofpacts_tlv_bitmap); break; case NX_LEARN_DST_OUTPUT: if (spec->n_bits <= 16 || is_all_zeros(value.u8, sizeof value - 2)) { ofp_port_t port = u16_to_ofp(ntohll(value.integer)); if (ofp_to_u16(port) < ofp_to_u16(OFPP_MAX) || port == OFPP_IN_PORT || port == OFPP_FLOOD || port == OFPP_LOCAL || port == OFPP_ALL) { ofpact_put_OUTPUT(ofpacts)->port = port; } } break; } } fm->ofpacts = ofpacts->data; fm->ofpacts_len = ofpacts->size; }
static void test_parse_actions(const char *input) { struct shash symtab; struct hmap dhcp_opts; struct hmap dhcpv6_opts; struct hmap nd_ra_opts; struct simap ports; create_symtab(&symtab); create_gen_opts(&dhcp_opts, &dhcpv6_opts, &nd_ra_opts); /* Initialize group ids. */ struct ovn_extend_table group_table; ovn_extend_table_init(&group_table); /* Initialize meter ids for QoS. */ struct ovn_extend_table meter_table; ovn_extend_table_init(&meter_table); simap_init(&ports); simap_put(&ports, "eth0", 5); simap_put(&ports, "eth1", 6); simap_put(&ports, "LOCAL", ofp_to_u16(OFPP_LOCAL)); struct ofpbuf ovnacts; struct expr *prereqs; char *error; puts(input); ofpbuf_init(&ovnacts, 0); const struct ovnact_parse_params pp = { .symtab = &symtab, .dhcp_opts = &dhcp_opts, .dhcpv6_opts = &dhcpv6_opts, .nd_ra_opts = &nd_ra_opts, .n_tables = 24, .cur_ltable = 10, }; error = ovnacts_parse_string(input, &pp, &ovnacts, &prereqs); if (!error) { /* Convert the parsed representation back to a string and print it, * if it's different from the input. */ struct ds ovnacts_s = DS_EMPTY_INITIALIZER; ovnacts_format(ovnacts.data, ovnacts.size, &ovnacts_s); if (strcmp(input, ds_cstr(&ovnacts_s))) { printf(" formats as %s\n", ds_cstr(&ovnacts_s)); } /* Encode the actions into OpenFlow and print. */ const struct ovnact_encode_params ep = { .lookup_port = lookup_port_cb, .aux = &ports, .is_switch = true, .group_table = &group_table, .meter_table = &meter_table, .pipeline = OVNACT_P_INGRESS, .ingress_ptable = 8, .egress_ptable = 40, .output_ptable = 64, .mac_bind_ptable = 65, }; struct ofpbuf ofpacts; ofpbuf_init(&ofpacts, 0); ovnacts_encode(ovnacts.data, ovnacts.size, &ep, &ofpacts); struct ds ofpacts_s = DS_EMPTY_INITIALIZER; struct ofpact_format_params fp = { .s = &ofpacts_s }; ofpacts_format(ofpacts.data, ofpacts.size, &fp); printf(" encodes as %s\n", ds_cstr(&ofpacts_s)); ds_destroy(&ofpacts_s); ofpbuf_uninit(&ofpacts); /* Print prerequisites if any. */ if (prereqs) { struct ds prereqs_s = DS_EMPTY_INITIALIZER; expr_format(prereqs, &prereqs_s); printf(" has prereqs %s\n", ds_cstr(&prereqs_s)); ds_destroy(&prereqs_s); } /* Now re-parse and re-format the string to verify that it's * round-trippable. */ struct ofpbuf ovnacts2; struct expr *prereqs2; ofpbuf_init(&ovnacts2, 0); error = ovnacts_parse_string(ds_cstr(&ovnacts_s), &pp, &ovnacts2, &prereqs2); if (!error) { struct ds ovnacts2_s = DS_EMPTY_INITIALIZER; ovnacts_format(ovnacts2.data, ovnacts2.size, &ovnacts2_s); if (strcmp(ds_cstr(&ovnacts_s), ds_cstr(&ovnacts2_s))) { printf(" bad reformat: %s\n", ds_cstr(&ovnacts2_s)); } ds_destroy(&ovnacts2_s); } else { printf(" reparse error: %s\n", error); free(error); } expr_destroy(prereqs2); ovnacts_free(ovnacts2.data, ovnacts2.size); ofpbuf_uninit(&ovnacts2); ds_destroy(&ovnacts_s); } else { printf(" %s\n", error); free(error); } expr_destroy(prereqs); ovnacts_free(ovnacts.data, ovnacts.size); ofpbuf_uninit(&ovnacts); simap_destroy(&ports); expr_symtab_destroy(&symtab); shash_destroy(&symtab); dhcp_opts_destroy(&dhcp_opts); dhcp_opts_destroy(&dhcpv6_opts); nd_ra_opts_destroy(&nd_ra_opts); ovn_extend_table_destroy(&group_table); ovn_extend_table_destroy(&meter_table); } static void test_parse_expr(const char *input) { struct shash symtab; struct shash addr_sets; struct shash port_groups; struct simap ports; struct expr *expr; char *error; create_symtab(&symtab); create_addr_sets(&addr_sets); create_port_groups(&port_groups); simap_init(&ports); simap_put(&ports, "eth0", 5); simap_put(&ports, "eth1", 6); simap_put(&ports, "LOCAL", ofp_to_u16(OFPP_LOCAL)); simap_put(&ports, "lsp1", 0x11); simap_put(&ports, "lsp2", 0x12); simap_put(&ports, "lsp3", 0x13); expr = expr_parse_string(input, &symtab, &addr_sets, &port_groups, &error); if (!error) { expr = expr_annotate(expr, &symtab, &error); } if (!error) { expr = expr_simplify(expr, is_chassis_resident_cb, &ports); expr = expr_normalize(expr); ovs_assert(expr_is_normalized(expr)); } if (!error) { struct hmap matches; expr_to_matches(expr, lookup_port_cb, &ports, &matches); expr_matches_print(&matches, stdout); expr_matches_destroy(&matches); } else { puts(error); free(error); } expr_destroy(expr); simap_destroy(&ports); expr_symtab_destroy(&symtab); shash_destroy(&symtab); expr_const_sets_destroy(&addr_sets); shash_destroy(&addr_sets); expr_const_sets_destroy(&port_groups); shash_destroy(&port_groups); } static bool lookup_atoi_cb(const void *aux OVS_UNUSED, const char *port_name, unsigned int *portp) { *portp = atoi(port_name); return true; } static void test_expr_to_packets(const char *input) { struct shash symtab; create_symtab(&symtab); struct flow uflow; char *error = expr_parse_microflow(input, &symtab, NULL, NULL, lookup_atoi_cb, NULL, &uflow); if (error) { puts(error); free(error); expr_symtab_destroy(&symtab); shash_destroy(&symtab); return; } uint64_t packet_stub[128 / 8]; struct dp_packet packet; dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub); flow_compose(&packet, &uflow, NULL, 64); struct ds output = DS_EMPTY_INITIALIZER; const uint8_t *buf = dp_packet_data(&packet); for (int i = 0; i < dp_packet_size(&packet); i++) { uint8_t val = buf[i]; ds_put_format(&output, "%02"PRIx8, val); } puts(ds_cstr(&output)); ds_destroy(&output); dp_packet_uninit(&packet); expr_symtab_destroy(&symtab); shash_destroy(&symtab); } int LLVMFuzzerTestOneInput(const uint8_t *input_, size_t size) { /* Bail out if we cannot construct at least a 1 char string. */ const char *input = (const char *) input_; if (size < 2 || input[size - 1] != '\0' || strchr(input, '\n') || strlen(input) != size - 1) { return 0; } /* Disable logging to avoid write to disk. */ static bool isInit = false; if (!isInit) { vlog_set_verbosity("off"); isInit = true; } /* Parse, annotate, simplify, normalize expr and convert to flows. */ test_parse_expr(input); /* Parse actions. */ test_parse_actions(input); /* Test OVN lexer. */ test_lex(input); /* Expr to packets. */ test_expr_to_packets(input); return 0; }