static struct expr_node * parse_zero(struct locus *loc, char **str, int *ownp) { eat_spaces(str); if (**str == '(') { ++*str; int own; struct expr_node *arg = parse_argnum(loc, str, &own, 0); if (arg == NULL) return NULL; if (parse_char(loc, str, ')') < 0) { fail: expr_destroy(arg); free(arg); return NULL; } struct expr_node *ret = build_zero_w_arg(arg, own); if (ret == NULL) goto fail; *ownp = 1; return ret; } else { *ownp = 0; return expr_node_zero(); } }
/* Parses OVN actions, in the format described for the "actions" column in the * Logical_Flow table in ovn-sb(5), and appends the parsed versions of the * actions to 'ofpacts' as "struct ofpact"s. * * 'symtab' provides a table of "struct expr_symbol"s to support (as one would * provide to expr_parse()). * * 'ports' must be a map from strings (presumably names of ports) to integers * (as one would provide to expr_to_matches()). Strings used in the actions * that are not in 'ports' are translated to zero. * * 'ct_zones' provides a map from a port name to its connection tracking zone. * * OVN maps each logical flow table (ltable), one-to-one, onto a physical * OpenFlow flow table (ptable). A number of parameters describe this mapping * and data related to flow tables: * * - 'first_ptable' and 'n_tables' define the range of OpenFlow tables to * which the logical "next" action should be able to jump. Logical table * 0 maps to OpenFlow table 'first_ptable', logical table 1 to * 'first_ptable + 1', and so on. If 'n_tables' is 0 then "next" is * disallowed entirely. * * - 'cur_ltable' is an offset from 'first_ptable' (e.g. 0 <= cur_ltable < * n_ptables) of the logical flow that contains the actions. If * cur_ltable + 1 < n_tables, then this defines the default table that * "next" will jump to. * * 'next_table_id' should be the OpenFlow table to which the "next" action will * resubmit, or 0 to disable "next". * * - 'output_ptable' should be the OpenFlow table to which the logical * "output" action will resubmit * * Some actions add extra requirements (prerequisites) to the flow's match. If * so, this function sets '*prereqsp' to the actions' prerequisites; otherwise, * it sets '*prereqsp' to NULL. The caller owns '*prereqsp' and must * eventually free it. * * Returns NULL on success, otherwise a malloc()'d error message that the * caller must free. On failure, 'ofpacts' has the same contents and * '*prereqsp' is set to NULL, but some tokens may have been consumed from * 'lexer'. */ char * OVS_WARN_UNUSED_RESULT actions_parse(struct lexer *lexer, const struct shash *symtab, const struct simap *ports, const struct simap *ct_zones, uint8_t first_ptable, uint8_t n_tables, uint8_t cur_ltable, uint8_t output_ptable, struct ofpbuf *ofpacts, struct expr **prereqsp) { size_t ofpacts_start = ofpacts->size; struct action_context ctx; ctx.lexer = lexer; ctx.symtab = symtab; ctx.ports = ports; ctx.ct_zones = ct_zones; ctx.first_ptable = first_ptable; ctx.n_tables = n_tables; ctx.cur_ltable = cur_ltable; ctx.output_ptable = output_ptable; ctx.error = NULL; ctx.ofpacts = ofpacts; ctx.prereqs = NULL; parse_actions(&ctx); if (!ctx.error) { *prereqsp = ctx.prereqs; return NULL; } else { ofpacts->size = ofpacts_start; expr_destroy(ctx.prereqs); *prereqsp = NULL; return ctx.error; } }
/* Parses OVN actions, in the format described for the "actions" column in the * Logical_Flow table in ovn-sb(5), and appends the parsed versions of the * actions to 'ofpacts' as "struct ofpact"s. * * 'ap' provides most of the parameters for translation. * * Some actions add extra requirements (prerequisites) to the flow's match. If * so, this function sets '*prereqsp' to the actions' prerequisites; otherwise, * it sets '*prereqsp' to NULL. The caller owns '*prereqsp' and must * eventually free it. * * Returns NULL on success, otherwise a malloc()'d error message that the * caller must free. On failure, 'ofpacts' has the same contents and * '*prereqsp' is set to NULL, but some tokens may have been consumed from * 'lexer'. */ char * OVS_WARN_UNUSED_RESULT actions_parse(struct lexer *lexer, const struct action_params *ap, struct ofpbuf *ofpacts, struct expr **prereqsp) { size_t ofpacts_start = ofpacts->size; struct action_context ctx = { .ap = ap, .lexer = lexer, .error = NULL, .ofpacts = ofpacts, .prereqs = NULL, }; parse_actions(&ctx); if (!ctx.error) { *prereqsp = ctx.prereqs; return NULL; } else { ofpacts->size = ofpacts_start; expr_destroy(ctx.prereqs); *prereqsp = NULL; return ctx.error; } }
int main(int argc, char **argv) { if (argc < 2) exit_error(E_INTERNAL); FILE *fp = fopen(argv[1], "r"); if (fp == NULL) exit_error(E_INTERNAL); //gcInit(); lex_init(fp); global_init(); expr_init(); parse(); fclose(fp); expr_destroy(); interpret(); //gcDestroy(); return 0; }
void mn_delete(cml_node *mn) { strdelete(mn->name); strdelete(mn->banner); listclear(mn->rules_using); if (mn->visibility_expr != 0) expr_destroy(mn->visibility_expr); if (mn->saveability_expr != 0) expr_destroy(mn->saveability_expr); /* only remove the list structure, all nodes are deleted seperately */ listclear(mn->children); if (mn->expr != 0) expr_destroy(mn->expr); atom_dtor(&mn->value); listclear(mn->transactions_guarded); listclear(mn->bindings); range_delete(mn->range); listdelete(mn->enumdefs, cml_enumdef, cml_enumdef_delete); listclear(mn->dependants); listclear(mn->dependees); strdelete(mn->help_text); g_free(mn); }
static void cmd_destroy(cmd_t * cmd_p) { if (!cmd_p) return; if (!queue_isempty(&cmd_p->qn)) (void) queue_remove(&cmd_p->qn); if (!cmd_p->isnamed) expr_destroy(cmd_p->expr.expr_p); free(cmd_p); } /* end cmd_destroy */
static void set_destroy(set_t * set_p) { if (!set_p) return; /* remove ourselves from any list */ if (!queue_isempty(&set_p->qn)) (void) queue_remove(&set_p->qn); if (set_p->setname_p) free(set_p->setname_p); /* destroy the exprlist */ expr_destroy(set_p->exprlist_p); free(set_p); } /* end set_destroy */
static int parse_string(struct protolib *plib, struct locus *loc, char **str, struct arg_type_info **retp, int *ownp) { struct arg_type_info *info = NULL; struct expr_node *length; int own_length; if (isdigit(CTYPE_CONV(**str))) { /* string0 is string[retval], length is zero(retval) * stringN is string[argN], length is zero(argN) */ long l; if (parse_int(loc, str, &l) < 0 || check_int(loc, l) < 0) return -1; struct expr_node *length_arg = malloc(sizeof(*length_arg)); if (length_arg == NULL) return -1; if (l == 0) expr_init_named(length_arg, "retval", 0); else expr_init_argno(length_arg, l - 1); length = build_zero_w_arg(length_arg, 1); if (length == NULL) { expr_destroy(length_arg); free(length_arg); return -1; } own_length = 1; } else { eat_spaces(str); if (**str == '[') { (*str)++; eat_spaces(str); length = parse_argnum(loc, str, &own_length, 1); if (length == NULL) return -1; eat_spaces(str); parse_char(loc, str, ']'); } else if (**str == '(') { /* Usage of "string" as lens. */ ++*str; eat_spaces(str); info = parse_type(plib, loc, str, NULL, 0, ownp, NULL); if (info == NULL) return -1; length = NULL; own_length = 0; eat_spaces(str); parse_char(loc, str, ')'); } else { /* It was just a simple string after all. */ length = expr_node_zero(); own_length = 0; } } /* String is a pointer to array of chars. */ if (info == NULL) { struct arg_type_info *info1 = malloc(sizeof(*info1)); struct arg_type_info *info2 = malloc(sizeof(*info2)); if (info1 == NULL || info2 == NULL) { free(info1); free(info2); fail: if (own_length) { assert(length != NULL); expr_destroy(length); free(length); } return -1; } type_init_array(info2, type_get_simple(ARGTYPE_CHAR), 0, length, own_length); type_init_pointer(info1, info2, 1); info = info1; *ownp = 1; } /* We'll need to set the lens, so unshare. */ if (unshare_type_info(loc, &info, ownp) < 0) /* If unshare_type_info failed, it must have been as a * result of cloning attempt because *OWNP was 0. * Thus we don't need to destroy INFO. */ goto fail; info->lens = &string_lens; info->own_lens = 0; *retp = info; return 0; }
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; }