예제 #1
0
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;
    }
}
예제 #2
0
파일: learn.c 프로젝트: Altiscale/ovs
/* 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;
}
예제 #3
0
파일: learn.c 프로젝트: yamt/openvswitch
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);
    }
}
예제 #4
0
파일: learn.c 프로젝트: Grim-lock/ovs
/* 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;
}
예제 #5
0
파일: learn.c 프로젝트: exuuwen/study
/* 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;
}
예제 #6
0
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;
    }
}