static void parse_named_action(enum ofputil_action_code code, char *arg, struct ofpbuf *ofpacts) { struct ofpact_tunnel *tunnel; uint16_t vid; uint16_t ethertype; ovs_be32 ip; uint8_t pcp; uint8_t tos; switch (code) { case OFPUTIL_ACTION_INVALID: NOT_REACHED(); case OFPUTIL_OFPAT10_OUTPUT: case OFPUTIL_OFPAT11_OUTPUT: parse_output(arg, ofpacts); break; case OFPUTIL_OFPAT10_SET_VLAN_VID: case OFPUTIL_OFPAT11_SET_VLAN_VID: vid = str_to_u32(arg); if (vid & ~VLAN_VID_MASK) { ovs_fatal(0, "%s: not a valid VLAN VID", arg); } ofpact_put_SET_VLAN_VID(ofpacts)->vlan_vid = vid; break; case OFPUTIL_OFPAT10_SET_VLAN_PCP: case OFPUTIL_OFPAT11_SET_VLAN_PCP: pcp = str_to_u32(arg); if (pcp & ~7) { ovs_fatal(0, "%s: not a valid VLAN PCP", arg); } ofpact_put_SET_VLAN_PCP(ofpacts)->vlan_pcp = pcp; break; case OFPUTIL_OFPAT12_SET_FIELD: set_field_parse(arg, ofpacts); break; case OFPUTIL_OFPAT10_STRIP_VLAN: case OFPUTIL_OFPAT11_POP_VLAN: ofpact_put_STRIP_VLAN(ofpacts); break; case OFPUTIL_OFPAT11_PUSH_VLAN: ethertype = str_to_u16(arg, "ethertype"); if (ethertype != ETH_TYPE_VLAN_8021Q) { /* XXX ETH_TYPE_VLAN_8021AD case isn't supported */ ovs_fatal(0, "%s: not a valid VLAN ethertype", arg); } ofpact_put_PUSH_VLAN(ofpacts); break; case OFPUTIL_OFPAT11_SET_QUEUE: ofpact_put_SET_QUEUE(ofpacts)->queue_id = str_to_u32(arg); break; case OFPUTIL_OFPAT10_SET_DL_SRC: case OFPUTIL_OFPAT11_SET_DL_SRC: str_to_mac(arg, ofpact_put_SET_ETH_SRC(ofpacts)->mac); break; case OFPUTIL_OFPAT10_SET_DL_DST: case OFPUTIL_OFPAT11_SET_DL_DST: str_to_mac(arg, ofpact_put_SET_ETH_DST(ofpacts)->mac); break; case OFPUTIL_OFPAT10_SET_NW_SRC: case OFPUTIL_OFPAT11_SET_NW_SRC: str_to_ip(arg, &ip); ofpact_put_SET_IPV4_SRC(ofpacts)->ipv4 = ip; break; case OFPUTIL_OFPAT10_SET_NW_DST: case OFPUTIL_OFPAT11_SET_NW_DST: str_to_ip(arg, &ip); ofpact_put_SET_IPV4_DST(ofpacts)->ipv4 = ip; break; case OFPUTIL_OFPAT10_SET_NW_TOS: case OFPUTIL_OFPAT11_SET_NW_TOS: tos = str_to_u32(arg); if (tos & ~IP_DSCP_MASK) { ovs_fatal(0, "%s: not a valid TOS", arg); } ofpact_put_SET_IPV4_DSCP(ofpacts)->dscp = tos; break; case OFPUTIL_OFPAT11_DEC_NW_TTL: NOT_REACHED(); case OFPUTIL_OFPAT10_SET_TP_SRC: case OFPUTIL_OFPAT11_SET_TP_SRC: ofpact_put_SET_L4_SRC_PORT(ofpacts)->port = str_to_u32(arg); break; case OFPUTIL_OFPAT10_SET_TP_DST: case OFPUTIL_OFPAT11_SET_TP_DST: ofpact_put_SET_L4_DST_PORT(ofpacts)->port = str_to_u32(arg); break; case OFPUTIL_OFPAT10_ENQUEUE: parse_enqueue(arg, ofpacts); break; case OFPUTIL_NXAST_RESUBMIT: parse_resubmit(arg, ofpacts); break; case OFPUTIL_NXAST_SET_TUNNEL: case OFPUTIL_NXAST_SET_TUNNEL64: tunnel = ofpact_put_SET_TUNNEL(ofpacts); tunnel->ofpact.compat = code; tunnel->tun_id = str_to_u64(arg); break; case OFPUTIL_NXAST_WRITE_METADATA: parse_metadata(ofpacts, arg); break; case OFPUTIL_NXAST_SET_QUEUE: ofpact_put_SET_QUEUE(ofpacts)->queue_id = str_to_u32(arg); break; case OFPUTIL_NXAST_POP_QUEUE: ofpact_put_POP_QUEUE(ofpacts); break; case OFPUTIL_NXAST_REG_MOVE: nxm_parse_reg_move(ofpact_put_REG_MOVE(ofpacts), arg); break; case OFPUTIL_NXAST_REG_LOAD: nxm_parse_reg_load(ofpact_put_REG_LOAD(ofpacts), arg); break; case OFPUTIL_NXAST_NOTE: parse_note(arg, ofpacts); break; case OFPUTIL_NXAST_MULTIPATH: multipath_parse(ofpact_put_MULTIPATH(ofpacts), arg); break; case OFPUTIL_NXAST_BUNDLE: bundle_parse(arg, ofpacts); break; case OFPUTIL_NXAST_BUNDLE_LOAD: bundle_parse_load(arg, ofpacts); break; case OFPUTIL_NXAST_RESUBMIT_TABLE: case OFPUTIL_NXAST_OUTPUT_REG: case OFPUTIL_NXAST_DEC_TTL_CNT_IDS: NOT_REACHED(); case OFPUTIL_NXAST_LEARN: learn_parse(arg, ofpacts); break; case OFPUTIL_NXAST_EXIT: ofpact_put_EXIT(ofpacts); break; case OFPUTIL_NXAST_DEC_TTL: parse_dec_ttl(ofpacts, arg); break; case OFPUTIL_NXAST_SET_MPLS_TTL: case OFPUTIL_OFPAT11_SET_MPLS_TTL: parse_set_mpls_ttl(ofpacts, arg); break; case OFPUTIL_OFPAT11_DEC_MPLS_TTL: case OFPUTIL_NXAST_DEC_MPLS_TTL: ofpact_put_DEC_MPLS_TTL(ofpacts); break; case OFPUTIL_NXAST_FIN_TIMEOUT: parse_fin_timeout(ofpacts, arg); break; case OFPUTIL_NXAST_CONTROLLER: parse_controller(ofpacts, arg); break; case OFPUTIL_OFPAT11_PUSH_MPLS: case OFPUTIL_NXAST_PUSH_MPLS: ofpact_put_PUSH_MPLS(ofpacts)->ethertype = htons(str_to_u16(arg, "push_mpls")); break; case OFPUTIL_OFPAT11_POP_MPLS: case OFPUTIL_NXAST_POP_MPLS: ofpact_put_POP_MPLS(ofpacts)->ethertype = htons(str_to_u16(arg, "pop_mpls")); break; case OFPUTIL_NXAST_STACK_PUSH: nxm_parse_stack_action(ofpact_put_STACK_PUSH(ofpacts), arg); break; case OFPUTIL_NXAST_STACK_POP: nxm_parse_stack_action(ofpact_put_STACK_POP(ofpacts), arg); break; case OFPUTIL_NXAST_SAMPLE: parse_sample(ofpacts, arg); break; } }
/* Returns NULL if successful, otherwise a malloc()'d string describing the * error. The caller is responsible for freeing the returned string. */ static char * OVS_WARN_UNUSED_RESULT learn_parse_spec(const char *orig, char *name, char *value, struct ofpact_learn_spec *spec) { if (mf_from_name(name)) { const struct mf_field *dst = mf_from_name(name); union mf_value imm; char *error; error = mf_parse_value(dst, value, &imm); if (error) { return error; } spec->n_bits = dst->n_bits; spec->src_type = NX_LEARN_SRC_IMMEDIATE; memset(&spec->src_imm, 0, sizeof spec->src_imm); memcpy(&spec->src_imm.u8[sizeof spec->src_imm - dst->n_bytes], &imm, dst->n_bytes); spec->dst_type = NX_LEARN_DST_MATCH; spec->dst.field = dst; spec->dst.ofs = 0; spec->dst.n_bits = dst->n_bits; } else if (strchr(name, '[')) { /* Parse destination and check prerequisites. */ char *error; error = mf_parse_subfield(&spec->dst, name); if (error) { return error; } if (!mf_nxm_header(spec->dst.field->id)) { return xasprintf("%s: experimenter OXM field '%s' not supported", orig, name); } /* Parse source and check prerequisites. */ if (value[0] != '\0') { error = mf_parse_subfield(&spec->src, value); if (error) { return error; } if (spec->src.n_bits != spec->dst.n_bits) { return xasprintf("%s: bit widths of %s (%u) and %s (%u) " "differ", orig, name, spec->src.n_bits, value, spec->dst.n_bits); } } else { spec->src = spec->dst; } spec->n_bits = spec->src.n_bits; spec->src_type = NX_LEARN_SRC_FIELD; spec->dst_type = NX_LEARN_DST_MATCH; } else if (!strcmp(name, "load")) { if (value[strcspn(value, "[-")] == '-') { char *error = learn_parse_load_immediate(value, spec); if (error) { return error; } } else { struct ofpact_reg_move move; char *error; error = nxm_parse_reg_move(&move, value); if (error) { return error; } spec->n_bits = move.src.n_bits; spec->src_type = NX_LEARN_SRC_FIELD; spec->src = move.src; spec->dst_type = NX_LEARN_DST_LOAD; spec->dst = move.dst; } } else if (!strcmp(name, "output")) { char *error = mf_parse_subfield(&spec->src, value); if (error) { return error; } spec->n_bits = spec->src.n_bits; spec->src_type = NX_LEARN_SRC_FIELD; spec->dst_type = NX_LEARN_DST_OUTPUT; } else { return xasprintf("%s: unknown keyword %s", orig, name); } return NULL; }
static void learn_parse_spec(const char *orig, char *name, char *value, struct ofpact_learn_spec *spec) { if (mf_from_name(name)) { const struct mf_field *dst = mf_from_name(name); union mf_value imm; char *error; error = mf_parse_value(dst, value, &imm); if (error) { ovs_fatal(0, "%s", error); } spec->n_bits = dst->n_bits; spec->src_type = NX_LEARN_SRC_IMMEDIATE; memset(&spec->src_imm, 0, sizeof spec->src_imm); memcpy(&spec->src_imm.u8[sizeof spec->src_imm - dst->n_bytes], &imm, dst->n_bytes); spec->dst_type = NX_LEARN_DST_MATCH; spec->dst.field = dst; spec->dst.ofs = 0; spec->dst.n_bits = dst->n_bits; } else if (strchr(name, '[')) { /* Parse destination and check prerequisites. */ if (mf_parse_subfield(&spec->dst, name)[0] != '\0') { ovs_fatal(0, "%s: syntax error after NXM field name `%s'", orig, name); } /* Parse source and check prerequisites. */ if (value[0] != '\0') { if (mf_parse_subfield(&spec->src, value)[0] != '\0') { ovs_fatal(0, "%s: syntax error after NXM field name `%s'", orig, value); } if (spec->src.n_bits != spec->dst.n_bits) { ovs_fatal(0, "%s: bit widths of %s (%u) and %s (%u) differ", orig, name, spec->src.n_bits, value, spec->dst.n_bits); } } else { spec->src = spec->dst; } spec->n_bits = spec->src.n_bits; spec->src_type = NX_LEARN_SRC_FIELD; spec->dst_type = NX_LEARN_DST_MATCH; } else if (!strcmp(name, "load")) { if (value[strcspn(value, "[-")] == '-') { learn_parse_load_immediate(value, spec); } else { struct ofpact_reg_move move; nxm_parse_reg_move(&move, value); spec->n_bits = move.src.n_bits; spec->src_type = NX_LEARN_SRC_FIELD; spec->src = move.src; spec->dst_type = NX_LEARN_DST_LOAD; spec->dst = move.dst; } } else if (!strcmp(name, "output")) { if (mf_parse_subfield(&spec->src, value)[0] != '\0') { ovs_fatal(0, "%s: syntax error after NXM field name `%s'", orig, name); } spec->n_bits = spec->src.n_bits; spec->src_type = NX_LEARN_SRC_FIELD; spec->dst_type = NX_LEARN_DST_OUTPUT; } else { ovs_fatal(0, "%s: unknown keyword %s", orig, name); } }
/* Returns NULL if successful, otherwise a malloc()'d string describing the * error. The caller is responsible for freeing the returned string. */ static char * OVS_WARN_UNUSED_RESULT learn_parse_spec(const char *orig, char *name, char *value, const struct ofputil_port_map *port_map, struct ofpact_learn_spec *spec, struct ofpbuf *ofpacts, struct match *match) { /* Parse destination and check prerequisites. */ struct mf_subfield dst; char *error = mf_parse_subfield(&dst, name); bool parse_error = error != NULL; free(error); if (!parse_error) { if (!mf_nxm_header(dst.field->id)) { return xasprintf("%s: experimenter OXM field '%s' not supported", orig, name); } spec->dst = dst; spec->n_bits = dst.n_bits; spec->dst_type = NX_LEARN_DST_MATCH; /* Parse source and check prerequisites. */ if (value[0] != '\0') { struct mf_subfield src; error = mf_parse_subfield(&src, value); if (error) { union mf_value imm; char *imm_error = NULL; /* Try an immediate value. */ if (dst.ofs == 0 && dst.n_bits == dst.field->n_bits) { /* Full field value. */ imm_error = mf_parse_value(dst.field, value, port_map, &imm); } else { char *tail; /* Partial field value. */ if (parse_int_string(value, (uint8_t *)&imm, dst.field->n_bytes, &tail) || *tail != 0) { imm_error = xasprintf("%s: cannot parse integer value", orig); } if (!imm_error && !bitwise_is_all_zeros(&imm, dst.field->n_bytes, dst.n_bits, dst.field->n_bytes * 8 - dst.n_bits)) { struct ds ds; ds_init(&ds); mf_format(dst.field, &imm, NULL, NULL, &ds); imm_error = xasprintf("%s: value %s does not fit into %d bits", orig, ds_cstr(&ds), dst.n_bits); ds_destroy(&ds); } } if (imm_error) { char *err = xasprintf("%s: %s value %s cannot be parsed as a subfield (%s) or an immediate value (%s)", orig, name, value, error, imm_error); free(error); free(imm_error); return err; } spec->src_type = NX_LEARN_SRC_IMMEDIATE; /* Update 'match' to allow for satisfying destination * prerequisites. */ mf_write_subfield_value(&dst, &imm, match); /* Push value last, as this may reallocate 'spec'! */ unsigned int imm_bytes = DIV_ROUND_UP(dst.n_bits, 8); uint8_t *src_imm = ofpbuf_put_zeros(ofpacts, OFPACT_ALIGN(imm_bytes)); memcpy(src_imm, &imm, imm_bytes); free(error); return NULL; } spec->src = src; if (spec->src.n_bits != spec->dst.n_bits) { return xasprintf("%s: bit widths of %s (%u) and %s (%u) " "differ", orig, name, spec->src.n_bits, value, spec->dst.n_bits); } } else { spec->src = spec->dst; } spec->src_type = NX_LEARN_SRC_FIELD; } else if (!strcmp(name, "load")) { union mf_subvalue imm; char *tail; char *dst_value = strstr(value, "->"); if (dst_value == value) { return xasprintf("%s: missing source before `->' in `%s'", name, value); } if (!dst_value) { return xasprintf("%s: missing `->' in `%s'", name, value); } if (!parse_int_string(value, imm.u8, sizeof imm.u8, (char **) &tail) && tail != value) { if (tail != dst_value) { return xasprintf("%s: garbage before `->' in `%s'", name, value); } error = learn_parse_load_immediate(&imm, dst_value + 2, value, spec, ofpacts); if (error) { return error; } } else { struct ofpact_reg_move move; error = nxm_parse_reg_move(&move, value); if (error) { return error; } spec->n_bits = move.src.n_bits; spec->src_type = NX_LEARN_SRC_FIELD; spec->src = move.src; spec->dst_type = NX_LEARN_DST_LOAD; spec->dst = move.dst; } } else if (!strcmp(name, "output")) { error = mf_parse_subfield(&spec->src, value); if (error) { return error; } spec->n_bits = spec->src.n_bits; spec->src_type = NX_LEARN_SRC_FIELD; spec->dst_type = NX_LEARN_DST_OUTPUT; } else { return xasprintf("%s: unknown keyword %s", orig, name); } return NULL; }
/* Returns NULL if successful, otherwise a malloc()'d string describing the * error. The caller is responsible for freeing the returned string. */ static char * OVS_WARN_UNUSED_RESULT learn_parse_spec(const char *orig, char *name, char *value, struct ofpact_learn_spec *spec, struct ofpbuf *ofpacts, struct match *match) { if (mf_from_name(name)) { const struct mf_field *dst = mf_from_name(name); union mf_value imm; char *error; error = mf_parse_value(dst, value, &imm); if (error) { return error; } spec->n_bits = dst->n_bits; spec->src_type = NX_LEARN_SRC_IMMEDIATE; spec->dst_type = NX_LEARN_DST_MATCH; spec->dst.field = dst; spec->dst.ofs = 0; spec->dst.n_bits = dst->n_bits; /* Update 'match' to allow for satisfying destination * prerequisites. */ mf_set_value(dst, &imm, match, NULL); /* Push value last, as this may reallocate 'spec'! */ uint8_t *src_imm = ofpbuf_put_zeros(ofpacts, OFPACT_ALIGN(dst->n_bytes)); memcpy(src_imm, &imm, dst->n_bytes); } else if (strchr(name, '[')) { /* Parse destination and check prerequisites. */ char *error; error = mf_parse_subfield(&spec->dst, name); if (error) { return error; } if (!mf_nxm_header(spec->dst.field->id)) { return xasprintf("%s: experimenter OXM field '%s' not supported", orig, name); } /* Parse source and check prerequisites. */ if (value[0] != '\0') { error = mf_parse_subfield(&spec->src, value); if (error) { return error; } if (spec->src.n_bits != spec->dst.n_bits) { return xasprintf("%s: bit widths of %s (%u) and %s (%u) " "differ", orig, name, spec->src.n_bits, value, spec->dst.n_bits); } } else { spec->src = spec->dst; } spec->n_bits = spec->src.n_bits; spec->src_type = NX_LEARN_SRC_FIELD; spec->dst_type = NX_LEARN_DST_MATCH; } else if (!strcmp(name, "load")) { if (value[strcspn(value, "[-")] == '-') { char *error = learn_parse_load_immediate(value, spec, ofpacts); if (error) { return error; } } else { struct ofpact_reg_move move; char *error; error = nxm_parse_reg_move(&move, value); if (error) { return error; } spec->n_bits = move.src.n_bits; spec->src_type = NX_LEARN_SRC_FIELD; spec->src = move.src; spec->dst_type = NX_LEARN_DST_LOAD; spec->dst = move.dst; } } else if (!strcmp(name, "output")) { char *error = mf_parse_subfield(&spec->src, value); if (error) { return error; } spec->n_bits = spec->src.n_bits; spec->src_type = NX_LEARN_SRC_FIELD; spec->dst_type = NX_LEARN_DST_OUTPUT; } else { return xasprintf("%s: unknown keyword %s", orig, name); } return NULL; }
static void parse_named_action(enum ofputil_action_code code, const struct flow *flow, struct ofpbuf *b, char *arg) { struct ofp_action_dl_addr *oada; struct ofp_action_vlan_pcp *oavp; struct ofp_action_vlan_vid *oavv; struct ofp_action_nw_addr *oana; struct ofp_action_tp_port *oata; switch (code) { case OFPUTIL_OFPAT_OUTPUT: parse_output(b, arg); break; case OFPUTIL_OFPAT_SET_VLAN_VID: oavv = ofputil_put_OFPAT_SET_VLAN_VID(b); oavv->vlan_vid = htons(str_to_u32(arg)); break; case OFPUTIL_OFPAT_SET_VLAN_PCP: oavp = ofputil_put_OFPAT_SET_VLAN_PCP(b); oavp->vlan_pcp = str_to_u32(arg); break; case OFPUTIL_OFPAT_STRIP_VLAN: ofputil_put_OFPAT_STRIP_VLAN(b); break; case OFPUTIL_OFPAT_SET_DL_SRC: case OFPUTIL_OFPAT_SET_DL_DST: oada = ofputil_put_action(code, b); str_to_mac(arg, oada->dl_addr); break; case OFPUTIL_OFPAT_SET_NW_SRC: case OFPUTIL_OFPAT_SET_NW_DST: oana = ofputil_put_action(code, b); str_to_ip(arg, &oana->nw_addr); break; case OFPUTIL_OFPAT_SET_NW_TOS: ofputil_put_OFPAT_SET_NW_TOS(b)->nw_tos = str_to_u32(arg); break; case OFPUTIL_OFPAT_SET_TP_SRC: case OFPUTIL_OFPAT_SET_TP_DST: oata = ofputil_put_action(code, b); oata->tp_port = htons(str_to_u32(arg)); break; case OFPUTIL_OFPAT_ENQUEUE: parse_enqueue(b, arg); break; case OFPUTIL_NXAST_RESUBMIT: parse_resubmit(b, arg); break; case OFPUTIL_NXAST_SET_TUNNEL: parse_set_tunnel(b, arg); break; case OFPUTIL_NXAST_SET_QUEUE: ofputil_put_NXAST_SET_QUEUE(b)->queue_id = htonl(str_to_u32(arg)); break; case OFPUTIL_NXAST_POP_QUEUE: ofputil_put_NXAST_POP_QUEUE(b); break; case OFPUTIL_NXAST_REG_MOVE: nxm_parse_reg_move(ofputil_put_NXAST_REG_MOVE(b), arg); break; case OFPUTIL_NXAST_REG_LOAD: nxm_parse_reg_load(ofputil_put_NXAST_REG_LOAD(b), arg); break; case OFPUTIL_NXAST_NOTE: parse_note(b, arg); break; case OFPUTIL_NXAST_SET_TUNNEL64: ofputil_put_NXAST_SET_TUNNEL64(b)->tun_id = htonll(str_to_u64(arg)); break; case OFPUTIL_NXAST_MULTIPATH: multipath_parse(ofputil_put_NXAST_MULTIPATH(b), arg); break; case OFPUTIL_NXAST_AUTOPATH: autopath_parse(ofputil_put_NXAST_AUTOPATH(b), arg); break; case OFPUTIL_NXAST_BUNDLE: bundle_parse(b, arg); break; case OFPUTIL_NXAST_BUNDLE_LOAD: bundle_parse_load(b, arg); break; case OFPUTIL_NXAST_RESUBMIT_TABLE: case OFPUTIL_NXAST_OUTPUT_REG: NOT_REACHED(); case OFPUTIL_NXAST_LEARN: learn_parse(b, arg, flow); break; case OFPUTIL_NXAST_EXIT: ofputil_put_NXAST_EXIT(b); break; } }