Commit message: ofp-group: Don't assert-fail decoding bad OF1.5 group mod type or command.

When decoding a group mod, the current code validates the group type and
command after the whole group mod has been decoded.  The OF1.5 decoder,
however, tries to use the type and command earlier, when it might still be
invalid.  This caused an assertion failure (via OVS_NOT_REACHED).  This
commit fixes the problem.

ovs-vswitchd does not enable support for OpenFlow 1.5 by default.

Reported-at: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=9249
Signed-off-by: Ben Pfaff <blp@ovn.org>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
CVE: CVE-2018-17204
CWE: CWE-617
Vulnerability description: An issue was discovered in Open vSwitch (OvS) 2.7.x through 2.7.6, affecting parse_group_prop_ntr_selection_method in lib/ofp-util.c. When decoding a group mod, it validates the group type and command after the whole group mod has been decoded. The OF1.5 decoder, however, tries to use the type and command earlier, when it might still be invalid. This causes an assertion failure (via OVS_NOT_REACHED). ovs-vswitchd does not enable support for OpenFlow 1.5 by default.

Project: ovs
File: ofp-util.c

decode_legacy_async_masks(const ovs_be32 masks[2],
                          enum ofputil_async_msg_type oam,
                          enum ofp_version version,
                          struct ofputil_async_cfg *dst)
{
    for (int i = 0; i < 2; i++) {
        bool master = i == 0;
        const struct ofp14_async_prop *ap
            = get_ofp14_async_config_prop_by_oam(oam, master);
        decode_async_mask(masks[i], ap, version, true, dst);
    }
}

Project: ovs
File: ofp-util.c

decode_tlv_table_mappings(struct ofpbuf *msg, unsigned int max_fields,
                             struct ovs_list *mappings)
{
    ovs_list_init(mappings);

    while (msg->size) {
        struct nx_tlv_map *nx_map;
        struct ofputil_tlv_map *map;

        nx_map = ofpbuf_pull(msg, sizeof *nx_map);
        map = xmalloc(sizeof *map);
        ovs_list_push_back(mappings, &map->list_node);

        map->option_class = ntohs(nx_map->option_class);
        map->option_type = nx_map->option_type;

        map->option_len = nx_map->option_len;
        if (map->option_len % 4 || map->option_len > TLV_MAX_OPT_SIZE) {
            VLOG_WARN_RL(&bad_ofmsg_rl,
                         "tlv table option length (%u) is not a valid option size",
                         map->option_len);
            ofputil_uninit_tlv_table(mappings);
            return OFPERR_NXTTMFC_BAD_OPT_LEN;
        }

        map->index = ntohs(nx_map->index);
        if (map->index >= max_fields) {
            VLOG_WARN_RL(&bad_ofmsg_rl,
                         "tlv table field index (%u) is too large (max %u)",
                         map->index, max_fields - 1);
            ofputil_uninit_tlv_table(mappings);
            return OFPERR_NXTTMFC_BAD_FIELD_IDX;
        }
    }

    return 0;
}

Project: ovs
File: ofp-util.c

encode_legacy_async_masks(const struct ofputil_async_cfg *ac,
                          enum ofputil_async_msg_type oam,
                          enum ofp_version version,
                          ovs_be32 masks[2])
{
    for (int i = 0; i < 2; i++) {
        bool master = i == 0;
        const struct ofp14_async_prop *ap
            = get_ofp14_async_config_prop_by_oam(oam, master);
        masks[i] = encode_async_mask(ac, ap, version);
    }
}

Project: ovs
File: ofp-util.c

ofputil_append_flow_monitor_request(
    const struct ofputil_flow_monitor_request *rq, struct ofpbuf *msg)
{
    struct nx_flow_monitor_request *nfmr;
    size_t start_ofs;
    int match_len;

    if (!msg->size) {
        ofpraw_put(OFPRAW_NXST_FLOW_MONITOR_REQUEST, OFP10_VERSION, msg);
    }

    start_ofs = msg->size;
    ofpbuf_put_zeros(msg, sizeof *nfmr);
    match_len = nx_put_match(msg, &rq->match, htonll(0), htonll(0));

    nfmr = ofpbuf_at_assert(msg, start_ofs, sizeof *nfmr);
    nfmr->id = htonl(rq->id);
    nfmr->flags = htons(rq->flags);
    nfmr->out_port = htons(ofp_to_u16(rq->out_port));
    nfmr->match_len = htons(match_len);
    nfmr->table_id = rq->table_id;
}

Project: ovs
File: ofp-util.c

ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
                                struct ovs_list *replies,
                                const struct tun_table *tun_table)
{
    struct ofputil_flow_stats *fs_ = CONST_CAST(struct ofputil_flow_stats *,
                                                fs);
    const struct tun_table *orig_tun_table;
    struct ofpbuf *reply = ofpbuf_from_list(ovs_list_back(replies));
    size_t start_ofs = reply->size;
    enum ofp_version version = ofpmp_version(replies);
    enum ofpraw raw = ofpmp_decode_raw(replies);

    orig_tun_table = fs->match.flow.tunnel.metadata.tab;
    fs_->match.flow.tunnel.metadata.tab = tun_table;

    if (raw == OFPRAW_OFPST11_FLOW_REPLY || raw == OFPRAW_OFPST13_FLOW_REPLY) {
        struct ofp11_flow_stats *ofs;

        ofpbuf_put_uninit(reply, sizeof *ofs);
        oxm_put_match(reply, &fs->match, version);
        ofpacts_put_openflow_instructions(fs->ofpacts, fs->ofpacts_len, reply,
                                          version);

        ofs = ofpbuf_at_assert(reply, start_ofs, sizeof *ofs);
        ofs->length = htons(reply->size - start_ofs);
        ofs->table_id = fs->table_id;
        ofs->pad = 0;
        ofs->duration_sec = htonl(fs->duration_sec);
        ofs->duration_nsec = htonl(fs->duration_nsec);
        ofs->priority = htons(fs->priority);
        ofs->idle_timeout = htons(fs->idle_timeout);
        ofs->hard_timeout = htons(fs->hard_timeout);
        if (version >= OFP14_VERSION) {
            ofs->importance = htons(fs->importance);
        } else {
            ofs->importance = 0;
        }
        if (raw == OFPRAW_OFPST13_FLOW_REPLY) {
            ofs->flags = ofputil_encode_flow_mod_flags(fs->flags, version);
        } else {
            ofs->flags = 0;
        }
        memset(ofs->pad2, 0, sizeof ofs->pad2);
        ofs->cookie = fs->cookie;
        ofs->packet_count = htonll(unknown_to_zero(fs->packet_count));
        ofs->byte_count = htonll(unknown_to_zero(fs->byte_count));
    } else if (raw == OFPRAW_OFPST10_FLOW_REPLY) {
        struct ofp10_flow_stats *ofs;

        ofpbuf_put_uninit(reply, sizeof *ofs);
        ofpacts_put_openflow_actions(fs->ofpacts, fs->ofpacts_len, reply,
                                     version);
        ofs = ofpbuf_at_assert(reply, start_ofs, sizeof *ofs);
        ofs->length = htons(reply->size - start_ofs);
        ofs->table_id = fs->table_id;
        ofs->pad = 0;
        ofputil_match_to_ofp10_match(&fs->match, &ofs->match);
        ofs->duration_sec = htonl(fs->duration_sec);
        ofs->duration_nsec = htonl(fs->duration_nsec);
        ofs->priority = htons(fs->priority);
        ofs->idle_timeout = htons(fs->idle_timeout);
        ofs->hard_timeout = htons(fs->hard_timeout);
        memset(ofs->pad2, 0, sizeof ofs->pad2);
        put_32aligned_be64(&ofs->cookie, fs->cookie);
        put_32aligned_be64(&ofs->packet_count,
                           htonll(unknown_to_zero(fs->packet_count)));
        put_32aligned_be64(&ofs->byte_count,
                           htonll(unknown_to_zero(fs->byte_count)));
    } else if (raw == OFPRAW_NXST_FLOW_REPLY) {
        struct nx_flow_stats *nfs;
        int match_len;

        ofpbuf_put_uninit(reply, sizeof *nfs);
        match_len = nx_put_match(reply, &fs->match, 0, 0);
        ofpacts_put_openflow_actions(fs->ofpacts, fs->ofpacts_len, reply,
                                     version);
        nfs = ofpbuf_at_assert(reply, start_ofs, sizeof *nfs);
        nfs->length = htons(reply->size - start_ofs);
        nfs->table_id = fs->table_id;
        nfs->pad = 0;
        nfs->duration_sec = htonl(fs->duration_sec);
        nfs->duration_nsec = htonl(fs->duration_nsec);
        nfs->priority = htons(fs->priority);
        nfs->idle_timeout = htons(fs->idle_timeout);
        nfs->hard_timeout = htons(fs->hard_timeout);
        nfs->idle_age = htons(fs->idle_age < 0 ? 0
                              : fs->idle_age < UINT16_MAX ? fs->idle_age + 1
                              : UINT16_MAX);
        nfs->hard_age = htons(fs->hard_age < 0 ? 0
                              : fs->hard_age < UINT16_MAX ? fs->hard_age + 1
                              : UINT16_MAX);
        nfs->match_len = htons(match_len);
        nfs->cookie = fs->cookie;
        nfs->packet_count = htonll(fs->packet_count);
        nfs->byte_count = htonll(fs->byte_count);
    } else {
        OVS_NOT_REACHED();
    }

    ofpmp_postappend(replies, start_ofs);
    fs_->match.flow.tunnel.metadata.tab = orig_tun_table;
}

Project: ovs
File: ofp-util.c

ofputil_bucket_clone_data(const struct ofputil_bucket *bucket)
{
    struct ofputil_bucket *new;

    new = xmemdup(bucket, sizeof *bucket);
    new->ofpacts = xmemdup(bucket->ofpacts, bucket->ofpacts_len);

    return new;
}

Project: ovs
File: ofp-util.c

ofputil_bucket_list_front(const struct ovs_list *buckets)
{
    static struct ofputil_bucket *bucket;

    ASSIGN_CONTAINER(bucket, ovs_list_front(buckets), list_node);

    return bucket;
}

Project: ovs
File: ofp-util.c

ofputil_capabilities_mask(enum ofp_version ofp_version)
{
    /* Handle capabilities whose bit is unique for all OpenFlow versions */
    switch (ofp_version) {
    case OFP10_VERSION:
    case OFP11_VERSION:
        return OFPC_COMMON | OFPC_ARP_MATCH_IP;
    case OFP12_VERSION:
    case OFP13_VERSION:
        return OFPC_COMMON | OFPC12_PORT_BLOCKED;
    case OFP14_VERSION:
    case OFP15_VERSION:
    case OFP16_VERSION:
        return OFPC_COMMON | OFPC12_PORT_BLOCKED | OFPC14_BUNDLES
            | OFPC14_FLOW_MONITORING;
    default:
        /* Caller needs to check osf->header.version itself */
        return 0;
    }
}

Project: ovs
File: ofp-util.c

ofputil_decode_port_stats(struct ofputil_port_stats *ps, struct ofpbuf *msg)
{
    enum ofperr error;
    enum ofpraw raw;

    memset(&(ps->stats), 0xFF, sizeof (ps->stats));

    error = (msg->header ? ofpraw_decode(&raw, msg->header)
             : ofpraw_pull(&raw, msg));
    if (error) {
        return error;
    }

    if (!msg->size) {
        return EOF;
    } else if (raw == OFPRAW_OFPST14_PORT_REPLY) {
        return ofputil_pull_ofp14_port_stats(ps, msg);
    } else if (raw == OFPRAW_OFPST13_PORT_REPLY) {
        const struct ofp13_port_stats *ps13;
        ps13 = ofpbuf_try_pull(msg, sizeof *ps13);
        if (!ps13) {
            goto bad_len;
        }
        return ofputil_port_stats_from_ofp13(ps, ps13);
    } else if (raw == OFPRAW_OFPST11_PORT_REPLY) {
        const struct ofp11_port_stats *ps11;

        ps11 = ofpbuf_try_pull(msg, sizeof *ps11);
        if (!ps11) {
            goto bad_len;
        }
        return ofputil_port_stats_from_ofp11(ps, ps11);
    } else if (raw == OFPRAW_OFPST10_PORT_REPLY) {
        const struct ofp10_port_stats *ps10;

        ps10 = ofpbuf_try_pull(msg, sizeof *ps10);
        if (!ps10) {
            goto bad_len;
        }
        return ofputil_port_stats_from_ofp10(ps, ps10);
    } else {
        OVS_NOT_REACHED();
    }

 bad_len:
    VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_PORT reply has %"PRIu32" leftover "
                 "bytes at end", msg->size);
    return OFPERR_OFPBRC_BAD_LEN;
}

Project: ovs
File: ofp-util.c

ofputil_encode_group_features_request(enum ofp_version ofp_version)
{
    struct ofpbuf *request = NULL;

    switch (ofp_version) {
    case OFP10_VERSION:
    case OFP11_VERSION:
        ovs_fatal(0, "dump-group-features needs OpenFlow 1.2 or later "
                     "(\'-O OpenFlow12\')");
    case OFP12_VERSION:
    case OFP13_VERSION:
    case OFP14_VERSION:
    case OFP15_VERSION:
    case OFP16_VERSION:
        request = ofpraw_alloc(OFPRAW_OFPST12_GROUP_FEATURES_REQUEST,
                               ofp_version, 0);
        break;
    default:
        OVS_NOT_REACHED();
    }

    return request;
}

Project: ovs
File: ofp-util.c

ofputil_encode_requestforward(const struct ofputil_requestforward *rf,
                              enum ofputil_protocol protocol)
{
    enum ofp_version ofp_version = ofputil_protocol_to_ofp_version(protocol);
    struct ofpbuf *inner;

    switch (rf->reason) {
    case OFPRFR_GROUP_MOD:
        inner = ofputil_encode_group_mod(ofp_version, rf->group_mod);
        break;

    case OFPRFR_METER_MOD:
        inner = ofputil_encode_meter_mod(ofp_version, rf->meter_mod);
        break;

    case OFPRFR_N_REASONS:
    default:
        OVS_NOT_REACHED();
    }

    struct ofp_header *inner_oh = inner->data;
    inner_oh->xid = rf->xid;
    inner_oh->length = htons(inner->size);

    struct ofpbuf *outer = ofpraw_alloc_xid(OFPRAW_OFPT14_REQUESTFORWARD,
                                            ofp_version, htonl(0),
                                            inner->size);
    ofpbuf_put(outer, inner->data, inner->size);
    ofpbuf_delete(inner);

    return outer;
}

Project: ovs
File: ofp-util.c

ofputil_encode_role_status(const struct ofputil_role_status *status,
                           enum ofputil_protocol protocol)
{
    enum ofp_version version;

    version = ofputil_protocol_to_ofp_version(protocol);
    if (version >= OFP14_VERSION) {
        struct ofp14_role_status *rstatus;
        struct ofpbuf *buf;

        buf = ofpraw_alloc_xid(OFPRAW_OFPT14_ROLE_STATUS, version, htonl(0),
                               0);
        rstatus = ofpbuf_put_zeros(buf, sizeof *rstatus);
        rstatus->role = htonl(status->role);
        rstatus->reason = status->reason;
        rstatus->generation_id = htonll(status->generation_id);

        return buf;
    } else {
        return NULL;
    }
}

Project: ovs
File: ofp-util.c

ofputil_encode_table_mod(const struct ofputil_table_mod *tm,
                        enum ofputil_protocol protocol)
{
    enum ofp_version ofp_version = ofputil_protocol_to_ofp_version(protocol);
    struct ofpbuf *b;

    switch (ofp_version) {
    case OFP10_VERSION: {
        ovs_fatal(0, "table mod needs OpenFlow 1.1 or later "
                     "(\'-O OpenFlow11\')");
        break;
    }
    case OFP11_VERSION:
    case OFP12_VERSION:
    case OFP13_VERSION: {
        struct ofp11_table_mod *otm;

        b = ofpraw_alloc(OFPRAW_OFPT11_TABLE_MOD, ofp_version, 0);
        otm = ofpbuf_put_zeros(b, sizeof *otm);
        otm->table_id = tm->table_id;
        otm->config = ofputil_encode_table_config(tm->miss, tm->eviction,
                                                  tm->vacancy, ofp_version);
        break;
    }
    case OFP14_VERSION:
    case OFP15_VERSION:
    case OFP16_VERSION: {
        struct ofp14_table_mod *otm;

        b = ofpraw_alloc(OFPRAW_OFPT14_TABLE_MOD, ofp_version, 0);
        otm = ofpbuf_put_zeros(b, sizeof *otm);
        otm->table_id = tm->table_id;
        otm->config = ofputil_encode_table_config(tm->miss, tm->eviction,
                                                  tm->vacancy, ofp_version);

        if (tm->eviction_flags != UINT32_MAX) {
            ofpprop_put_u32(b, OFPTMPT14_EVICTION, tm->eviction_flags);
        }
        if (tm->vacancy == OFPUTIL_TABLE_VACANCY_ON) {
            struct ofp14_table_mod_prop_vacancy *otv;

            otv = ofpprop_put_zeros(b, OFPTMPT14_VACANCY, sizeof *otv);
            otv->vacancy_down = tm->table_vacancy.vacancy_down;
            otv->vacancy_up = tm->table_vacancy.vacancy_up;
        }
        break;
    }
    default:
        OVS_NOT_REACHED();
    }

    return b;
}

Project: ovs
File: ofp-util.c

ofputil_group_stats_to_ofp13(const struct ofputil_group_stats *gs,
                             struct ofp13_group_stats *gs13, size_t length,
                             struct ofp11_bucket_counter bucket_cnts[])
{
    ofputil_group_stats_to_ofp11(gs, &gs13->gs, length, bucket_cnts);
    gs13->duration_sec = htonl(gs->duration_sec);
    gs13->duration_nsec = htonl(gs->duration_nsec);

}

Project: ovs
File: ofp-util.c

ofputil_match_to_ofp11_match(const struct match *match,
                             struct ofp11_match *ofmatch)
{
    uint32_t wc = 0;

    memset(ofmatch, 0, sizeof *ofmatch);
    ofmatch->omh.type = htons(OFPMT_STANDARD);
    ofmatch->omh.length = htons(OFPMT11_STANDARD_LENGTH);

    if (!match->wc.masks.in_port.ofp_port) {
        wc |= OFPFW11_IN_PORT;
    } else {
        ofmatch->in_port = ofputil_port_to_ofp11(match->flow.in_port.ofp_port);
    }

    ofmatch->dl_src = match->flow.dl_src;
    ofmatch->dl_src_mask = eth_addr_invert(match->wc.masks.dl_src);
    ofmatch->dl_dst = match->flow.dl_dst;
    ofmatch->dl_dst_mask = eth_addr_invert(match->wc.masks.dl_dst);

    if (match->wc.masks.vlan_tci == htons(0)) {
        wc |= OFPFW11_DL_VLAN | OFPFW11_DL_VLAN_PCP;
    } else if (match->wc.masks.vlan_tci & htons(VLAN_CFI)
               && !(match->flow.vlan_tci & htons(VLAN_CFI))) {
        ofmatch->dl_vlan = htons(OFPVID11_NONE);
        wc |= OFPFW11_DL_VLAN_PCP;
    } else {
        if (!(match->wc.masks.vlan_tci & htons(VLAN_VID_MASK))) {
            ofmatch->dl_vlan = htons(OFPVID11_ANY);
        } else {
            ofmatch->dl_vlan = htons(vlan_tci_to_vid(match->flow.vlan_tci));
        }

        if (!(match->wc.masks.vlan_tci & htons(VLAN_PCP_MASK))) {
            wc |= OFPFW11_DL_VLAN_PCP;
        } else {
            ofmatch->dl_vlan_pcp = vlan_tci_to_pcp(match->flow.vlan_tci);
        }
    }

    if (!match->wc.masks.dl_type) {
        wc |= OFPFW11_DL_TYPE;
    } else {
        ofmatch->dl_type = ofputil_dl_type_to_openflow(match->flow.dl_type);
    }

    if (!(match->wc.masks.nw_tos & IP_DSCP_MASK)) {
        wc |= OFPFW11_NW_TOS;
    } else {
        ofmatch->nw_tos = match->flow.nw_tos & IP_DSCP_MASK;
    }

    if (!match->wc.masks.nw_proto) {
        wc |= OFPFW11_NW_PROTO;
    } else {
        ofmatch->nw_proto = match->flow.nw_proto;
    }

    ofmatch->nw_src = match->flow.nw_src;
    ofmatch->nw_src_mask = ~match->wc.masks.nw_src;
    ofmatch->nw_dst = match->flow.nw_dst;
    ofmatch->nw_dst_mask = ~match->wc.masks.nw_dst;

    if (!match->wc.masks.tp_src) {
        wc |= OFPFW11_TP_SRC;
    } else {
        ofmatch->tp_src = match->flow.tp_src;
    }

    if (!match->wc.masks.tp_dst) {
        wc |= OFPFW11_TP_DST;
    } else {
        ofmatch->tp_dst = match->flow.tp_dst;
    }

    if (!(match->wc.masks.mpls_lse[0] & htonl(MPLS_LABEL_MASK))) {
        wc |= OFPFW11_MPLS_LABEL;
    } else {
        ofmatch->mpls_label = htonl(mpls_lse_to_label(
                                        match->flow.mpls_lse[0]));
    }

    if (!(match->wc.masks.mpls_lse[0] & htonl(MPLS_TC_MASK))) {
        wc |= OFPFW11_MPLS_TC;
    } else {
        ofmatch->mpls_tc = mpls_lse_to_tc(match->flow.mpls_lse[0]);
    }

    ofmatch->metadata = match->flow.metadata;
    ofmatch->metadata_mask = ~match->wc.masks.metadata;

    ofmatch->wildcards = htonl(wc);
}

Project: ovs
File: ofp-util.c

ofputil_protocol_to_string(enum ofputil_protocol protocol)
{
    const struct proto_abbrev *p;

    /* Use a "switch" statement for single-bit names so that we get a compiler
     * warning if we forget any. */
    switch (protocol) {
    case OFPUTIL_P_OF10_NXM:
        return "NXM-table_id";

    case OFPUTIL_P_OF10_NXM_TID:
        return "NXM+table_id";

    case OFPUTIL_P_OF10_STD:
        return "OpenFlow10-table_id";

    case OFPUTIL_P_OF10_STD_TID:
        return "OpenFlow10+table_id";

    case OFPUTIL_P_OF11_STD:
        return "OpenFlow11";

    case OFPUTIL_P_OF12_OXM:
        return "OXM-OpenFlow12";

    case OFPUTIL_P_OF13_OXM:
        return "OXM-OpenFlow13";

    case OFPUTIL_P_OF14_OXM:
        return "OXM-OpenFlow14";

    case OFPUTIL_P_OF15_OXM:
        return "OXM-OpenFlow15";

    case OFPUTIL_P_OF16_OXM:
        return "OXM-OpenFlow16";
    }

    /* Check abbreviations. */
    for (p = proto_abbrevs; p < &proto_abbrevs[N_PROTO_ABBREVS]; p++) {
        if (protocol == p->protocol) {
            return p->name;
        }
    }

    return NULL;
}

Project: ovs
File: ofp-util.c

ofputil_pull_ofp11_group_mod(struct ofpbuf *msg, enum ofp_version ofp_version,
                             struct ofputil_group_mod *gm)
{
    const struct ofp11_group_mod *ogm;
    enum ofperr error;

    ogm = ofpbuf_pull(msg, sizeof *ogm);
    gm->command = ntohs(ogm->command);
    gm->type = ogm->type;
    gm->group_id = ntohl(ogm->group_id);
    gm->command_bucket_id = OFPG15_BUCKET_ALL;

    error = ofputil_pull_ofp11_buckets(msg, msg->size, ofp_version,
                                       &gm->buckets);

    /* OF1.3.5+ prescribes an error when an OFPGC_DELETE includes buckets. */
    if (!error
        && ofp_version >= OFP13_VERSION
        && gm->command == OFPGC11_DELETE
        && !ovs_list_is_empty(&gm->buckets)) {
        error = OFPERR_OFPGMFC_INVALID_GROUP;
        ofputil_bucket_list_destroy(&gm->buckets);
    }

    return error;
}

Project: ovs
File: ofp-util.c

ofputil_start_queue_get_config_reply(const struct ofp_header *request,
                                     struct ovs_list *replies)
{
    struct ofpbuf *reply;
    enum ofperr error;
    ofp_port_t port;
    uint32_t queue;

    error = ofputil_decode_queue_get_config_request(request, &port, &queue);
    ovs_assert(!error);

    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);
}

Project: ovs
File: ofp-util.c

ofputil_uninit_tlv_table(struct ovs_list *mappings)
{
    struct ofputil_tlv_map *map;

    LIST_FOR_EACH_POP (map, list_node, mappings) {
        free(map);
    }
}

Project: ovs
File: ofp-util.c

ofputil_versions_from_string(const char *s)
{
    size_t i = 0;
    uint32_t bitmap = 0;

    while (s[i]) {
        size_t j;
        int version;
        char *key;

        if (is_delimiter(s[i])) {
            i++;
            continue;
        }
        j = 0;
        while (s[i + j] && !is_delimiter(s[i + j])) {
            j++;
        }
        key = xmemdup0(s + i, j);
        version = ofputil_version_from_string(key);
        if (!version) {
            VLOG_FATAL("Unknown OpenFlow version: \"%s\"", key);
        }
        free(key);
        bitmap |= 1u << version;
        i += j;
    }

    return bitmap;
}

Project: ovs
File: ofp-util.c

parse_actions_property(struct ofpbuf *property, enum ofp_version version,
                       struct ofpbuf *ofpacts)
{
    if (!ofpbuf_try_pull(property, ROUND_UP(ofpbuf_headersize(property), 8))) {
        VLOG_WARN_RL(&bad_ofmsg_rl, "actions property has bad length %"PRIu32,
                     property->size);
        return OFPERR_OFPBPC_BAD_LEN;
    }

    return ofpacts_pull_openflow_actions(property, property->size,
                                         version, NULL, NULL, ofpacts);
}

Project: ovs
File: ofp-util.c

pull_table_feature_property(struct ofpbuf *msg, struct ofpbuf *payload,
                            uint64_t *typep)
{
    enum ofperr error;

    error = ofpprop_pull(msg, payload, typep);
    if (payload && !error) {
        ofpbuf_pull(payload, (char *)payload->msg - (char *)payload->header);
    }
    return error;
}