X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fofp-util.c;h=ce9bb74d1caa2a6750c7a2ee2ee8099fcda22663;hb=960c02bd4d5e9711e8e13592f6715bb974031f21;hp=8a2f3fdaf91a680899ab010bfc9404ec34d437db;hpb=1b58552471d1149033cbb6b85d2a5d567f8f8e0e;p=sliver-openvswitch.git diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 8a2f3fdaf..ce9bb74d1 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -267,23 +267,36 @@ ofputil_cls_rule_to_ofp10_match(const struct cls_rule *rule, enum ofperr ofputil_pull_ofp11_match(struct ofpbuf *buf, unsigned int priority, - struct cls_rule *rule) + struct cls_rule *rule, uint16_t *padded_match_len) { - struct ofp11_match_header *omh; - struct ofp11_match *om; + struct ofp11_match_header *omh = buf->data; + uint16_t match_len; - if (buf->size < sizeof(struct ofp11_match_header)) { + if (buf->size < sizeof *omh) { return OFPERR_OFPBMC_BAD_LEN; } - omh = buf->data; + match_len = ntohs(omh->length); + switch (ntohs(omh->type)) { - case OFPMT_STANDARD: - if (omh->length != htons(sizeof *om) || buf->size < sizeof *om) { + case OFPMT_STANDARD: { + struct ofp11_match *om; + + if (match_len != sizeof *om || buf->size < sizeof *om) { return OFPERR_OFPBMC_BAD_LEN; } om = ofpbuf_pull(buf, sizeof *om); + if (padded_match_len) { + *padded_match_len = match_len; + } return ofputil_cls_rule_from_ofp11_match(om, priority, rule); + } + + case OFPMT_OXM: + if (padded_match_len) { + *padded_match_len = ROUND_UP(match_len, 8); + } + return oxm_pull_match(buf, priority, rule); default: return OFPERR_OFPBMC_BAD_TYPE; @@ -1137,7 +1150,8 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, ofm = ofpbuf_pull(&b, sizeof *ofm); - error = ofputil_pull_ofp11_match(&b, ntohs(ofm->priority), &fm->cr); + error = ofputil_pull_ofp11_match(&b, ntohs(ofm->priority), &fm->cr, + NULL); if (error) { return error; } @@ -1259,6 +1273,15 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, return 0; } +static ovs_be16 +ofputil_tid_command(const struct ofputil_flow_mod *fm, + enum ofputil_protocol protocol) +{ + return htons(protocol & OFPUTIL_P_TID + ? (fm->command & 0xff) | (fm->table_id << 8) + : fm->command); +} + /* Converts 'fm' into an OFPT_FLOW_MOD or NXT_FLOW_MOD message according to * 'protocol' and returns the message. */ struct ofpbuf * @@ -1266,13 +1289,30 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm, enum ofputil_protocol protocol) { struct ofpbuf *msg; - uint16_t command; - - command = (protocol & OFPUTIL_P_TID - ? (fm->command & 0xff) | (fm->table_id << 8) - : fm->command); switch (protocol) { + case OFPUTIL_P_OF12: { + struct ofp11_flow_mod *ofm; + + msg = ofpraw_alloc(OFPRAW_OFPT11_FLOW_MOD, OFP12_VERSION, + NXM_TYPICAL_LEN + fm->ofpacts_len); + ofm = ofpbuf_put_zeros(msg, sizeof *ofm); + ofm->cookie = fm->new_cookie; + ofm->cookie_mask = fm->cookie_mask; + ofm->table_id = fm->table_id; + ofm->command = fm->command; + ofm->idle_timeout = htons(fm->idle_timeout); + ofm->hard_timeout = htons(fm->hard_timeout); + ofm->priority = htons(fm->cr.priority); + ofm->buffer_id = htonl(fm->buffer_id); + ofm->out_port = ofputil_port_to_ofp11(fm->out_port); + ofm->out_group = htonl(OFPG11_ANY); + ofm->flags = htons(fm->flags); + oxm_put_match(msg, &fm->cr); + ofpacts_put_openflow11_instructions(fm->ofpacts, fm->ofpacts_len, msg); + break; + } + case OFPUTIL_P_OF10: case OFPUTIL_P_OF10_TID: { struct ofp10_flow_mod *ofm; @@ -1282,13 +1322,14 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm, ofm = ofpbuf_put_zeros(msg, sizeof *ofm); ofputil_cls_rule_to_ofp10_match(&fm->cr, &ofm->match); ofm->cookie = fm->new_cookie; - ofm->command = htons(command); + ofm->command = ofputil_tid_command(fm, protocol); ofm->idle_timeout = htons(fm->idle_timeout); ofm->hard_timeout = htons(fm->hard_timeout); ofm->priority = htons(fm->cr.priority); ofm->buffer_id = htonl(fm->buffer_id); ofm->out_port = htons(fm->out_port); ofm->flags = htons(fm->flags); + ofpacts_put_openflow10(fm->ofpacts, fm->ofpacts_len, msg); break; } @@ -1300,10 +1341,9 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm, msg = ofpraw_alloc(OFPRAW_NXT_FLOW_MOD, OFP10_VERSION, NXM_TYPICAL_LEN + fm->ofpacts_len); nfm = ofpbuf_put_zeros(msg, sizeof *nfm); - nfm->command = htons(command); + nfm->command = ofputil_tid_command(fm, protocol); nfm->cookie = fm->new_cookie; - match_len = nx_put_match(msg, false, &fm->cr, - fm->cookie, fm->cookie_mask); + match_len = nx_put_match(msg, &fm->cr, fm->cookie, fm->cookie_mask); nfm = msg->l3; nfm->idle_timeout = htons(fm->idle_timeout); nfm->hard_timeout = htons(fm->hard_timeout); @@ -1312,17 +1352,14 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm, nfm->out_port = htons(fm->out_port); nfm->flags = htons(fm->flags); nfm->match_len = htons(match_len); + ofpacts_put_openflow10(fm->ofpacts, fm->ofpacts_len, msg); break; } - case OFPUTIL_P_OF12: default: NOT_REACHED(); } - if (fm->ofpacts) { - ofpacts_put_openflow10(fm->ofpacts, fm->ofpacts_len, msg); - } ofpmsg_update_length(msg); return msg; } @@ -1359,9 +1396,9 @@ ofputil_flow_mod_usable_protocols(const struct ofputil_flow_mod *fms, } static enum ofperr -ofputil_decode_ofpst_flow_request(struct ofputil_flow_stats_request *fsr, - const struct ofp10_flow_stats_request *ofsr, - bool aggregate) +ofputil_decode_ofpst10_flow_request(struct ofputil_flow_stats_request *fsr, + const struct ofp10_flow_stats_request *ofsr, + bool aggregate) { fsr->aggregate = aggregate; ofputil_cls_rule_from_ofp10_match(&ofsr->match, 0, &fsr->match); @@ -1372,6 +1409,33 @@ ofputil_decode_ofpst_flow_request(struct ofputil_flow_stats_request *fsr, return 0; } +static enum ofperr +ofputil_decode_ofpst11_flow_request(struct ofputil_flow_stats_request *fsr, + struct ofpbuf *b, bool aggregate) +{ + const struct ofp11_flow_stats_request *ofsr; + enum ofperr error; + + ofsr = ofpbuf_pull(b, sizeof *ofsr); + fsr->aggregate = aggregate; + fsr->table_id = ofsr->table_id; + error = ofputil_port_from_ofp11(ofsr->out_port, &fsr->out_port); + if (error) { + return error; + } + if (ofsr->out_group != htonl(OFPG11_ANY)) { + return OFPERR_NXFMFC_GROUPS_NOT_SUPPORTED; + } + fsr->cookie = ofsr->cookie; + fsr->cookie_mask = ofsr->cookie_mask; + error = ofputil_pull_ofp11_match(b, 0, &fsr->match, NULL); + if (error) { + return error; + } + + return 0; +} + static enum ofperr ofputil_decode_nxst_flow_request(struct ofputil_flow_stats_request *fsr, struct ofpbuf *b, bool aggregate) @@ -1409,11 +1473,17 @@ ofputil_decode_flow_stats_request(struct ofputil_flow_stats_request *fsr, ofpbuf_use_const(&b, oh, ntohs(oh->length)); raw = ofpraw_pull_assert(&b); switch ((int) raw) { - case OFPRAW_OFPST_FLOW_REQUEST: - return ofputil_decode_ofpst_flow_request(fsr, b.data, false); + case OFPRAW_OFPST10_FLOW_REQUEST: + return ofputil_decode_ofpst10_flow_request(fsr, b.data, false); + + case OFPRAW_OFPST10_AGGREGATE_REQUEST: + return ofputil_decode_ofpst10_flow_request(fsr, b.data, true); - case OFPRAW_OFPST_AGGREGATE_REQUEST: - return ofputil_decode_ofpst_flow_request(fsr, b.data, true); + case OFPRAW_OFPST11_FLOW_REQUEST: + return ofputil_decode_ofpst11_flow_request(fsr, &b, false); + + case OFPRAW_OFPST11_AGGREGATE_REQUEST: + return ofputil_decode_ofpst11_flow_request(fsr, &b, true); case OFPRAW_NXST_FLOW_REQUEST: return ofputil_decode_nxst_flow_request(fsr, &b, false); @@ -1438,13 +1508,30 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr, enum ofpraw raw; switch (protocol) { + case OFPUTIL_P_OF12: { + struct ofp11_flow_stats_request *ofsr; + + raw = (fsr->aggregate + ? OFPRAW_OFPST11_AGGREGATE_REQUEST + : OFPRAW_OFPST11_FLOW_REQUEST); + msg = ofpraw_alloc(raw, OFP12_VERSION, NXM_TYPICAL_LEN); + ofsr = ofpbuf_put_zeros(msg, sizeof *ofsr); + ofsr->table_id = fsr->table_id; + ofsr->out_port = ofputil_port_to_ofp11(fsr->out_port); + ofsr->out_group = htonl(OFPG11_ANY); + ofsr->cookie = fsr->cookie; + ofsr->cookie_mask = fsr->cookie_mask; + oxm_put_match(msg, &fsr->match); + break; + } + case OFPUTIL_P_OF10: case OFPUTIL_P_OF10_TID: { struct ofp10_flow_stats_request *ofsr; raw = (fsr->aggregate - ? OFPRAW_OFPST_AGGREGATE_REQUEST - : OFPRAW_OFPST_FLOW_REQUEST); + ? OFPRAW_OFPST10_AGGREGATE_REQUEST + : OFPRAW_OFPST10_FLOW_REQUEST); msg = ofpraw_alloc(raw, OFP10_VERSION, 0); ofsr = ofpbuf_put_zeros(msg, sizeof *ofsr); ofputil_cls_rule_to_ofp10_match(&fsr->match, &ofsr->match); @@ -1461,9 +1548,9 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr, raw = (fsr->aggregate ? OFPRAW_NXST_AGGREGATE_REQUEST : OFPRAW_NXST_FLOW_REQUEST); - msg = ofpraw_alloc(raw, OFP10_VERSION, 0); + msg = ofpraw_alloc(raw, OFP10_VERSION, NXM_TYPICAL_LEN); ofpbuf_put_zeros(msg, sizeof *nfsr); - match_len = nx_put_match(msg, false, &fsr->match, + match_len = nx_put_match(msg, &fsr->match, fsr->cookie, fsr->cookie_mask); nfsr = msg->l3; @@ -1473,7 +1560,6 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr, break; } - case OFPUTIL_P_OF12: default: NOT_REACHED(); } @@ -1536,7 +1622,48 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, if (!msg->size) { return EOF; - } else if (raw == OFPRAW_OFPST_FLOW_REPLY) { + } else if (raw == OFPRAW_OFPST11_FLOW_REPLY) { + const struct ofp11_flow_stats *ofs; + size_t length; + uint16_t padded_match_len; + + ofs = ofpbuf_try_pull(msg, sizeof *ofs); + if (!ofs) { + VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply has %zu leftover " + "bytes at end", msg->size); + return EINVAL; + } + + length = ntohs(ofs->length); + if (length < sizeof *ofs) { + VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply claims invalid " + "length %zu", length); + return EINVAL; + } + + if (ofputil_pull_ofp11_match(msg, ntohs(ofs->priority), &fs->rule, + &padded_match_len)) { + VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply bad match"); + return EINVAL; + } + + if (ofpacts_pull_openflow11_instructions(msg, length - sizeof *ofs - + padded_match_len, ofpacts)) { + VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply bad instructions"); + return EINVAL; + } + + fs->table_id = ofs->table_id; + fs->duration_sec = ntohl(ofs->duration_sec); + fs->duration_nsec = ntohl(ofs->duration_nsec); + fs->idle_timeout = ntohs(ofs->idle_timeout); + fs->hard_timeout = ntohs(ofs->hard_timeout); + fs->idle_age = -1; + fs->hard_age = -1; + fs->cookie = ofs->cookie; + fs->packet_count = ntohll(ofs->packet_count); + fs->byte_count = ntohll(ofs->byte_count); + } else if (raw == OFPRAW_OFPST10_FLOW_REPLY) { const struct ofp10_flow_stats *ofs; size_t length; @@ -1648,7 +1775,28 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs, enum ofpraw raw; ofpraw_decode_partial(&raw, reply->data, reply->size); - if (raw == OFPRAW_OFPST_FLOW_REPLY) { + if (raw == OFPRAW_OFPST11_FLOW_REPLY) { + struct ofp11_flow_stats *ofs; + + ofpbuf_put_uninit(reply, sizeof *ofs); + oxm_put_match(reply, &fs->rule); + ofpacts_put_openflow11_instructions(fs->ofpacts, fs->ofpacts_len, + reply); + + 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->rule.priority); + ofs->idle_timeout = htons(fs->idle_timeout); + ofs->hard_timeout = htons(fs->hard_timeout); + 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); @@ -1675,7 +1823,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs, int match_len; ofpbuf_put_uninit(reply, sizeof *nfs); - match_len = nx_put_match(reply, false, &fs->rule, 0, 0); + match_len = nx_put_match(reply, &fs->rule, 0, 0); ofpacts_put_openflow10(fs->ofpacts, fs->ofpacts_len, reply); nfs = ofpbuf_at_assert(reply, start_ofs, sizeof *nfs); @@ -1718,7 +1866,7 @@ ofputil_encode_aggregate_stats_reply( enum ofpraw raw; ofpraw_decode(&raw, request); - if (raw == OFPRAW_OFPST_AGGREGATE_REQUEST) { + if (raw == OFPRAW_OFPST10_AGGREGATE_REQUEST) { packet_count = unknown_to_zero(stats->packet_count); byte_count = unknown_to_zero(stats->byte_count); } else { @@ -1765,7 +1913,28 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr, ofpbuf_use_const(&b, oh, ntohs(oh->length)); raw = ofpraw_pull_assert(&b); - if (raw == OFPRAW_OFPT10_FLOW_REMOVED) { + if (raw == OFPRAW_OFPT11_FLOW_REMOVED) { + const struct ofp12_flow_removed *ofr; + enum ofperr error; + + ofr = ofpbuf_pull(&b, sizeof *ofr); + + error = ofputil_pull_ofp11_match(&b, ntohs(ofr->priority), + &fr->rule, NULL); + if (error) { + return error; + } + + fr->cookie = ofr->cookie; + fr->reason = ofr->reason; + /* XXX: ofr->table_id is ignored */ + fr->duration_sec = ntohl(ofr->duration_sec); + fr->duration_nsec = ntohl(ofr->duration_nsec); + fr->idle_timeout = ntohs(ofr->idle_timeout); + fr->hard_timeout = ntohs(ofr->hard_timeout); + fr->packet_count = ntohll(ofr->packet_count); + fr->byte_count = ntohll(ofr->byte_count); + } else if (raw == OFPRAW_OFPT10_FLOW_REMOVED) { const struct ofp_flow_removed *ofr; ofr = ofpbuf_pull(&b, sizeof *ofr); @@ -1777,6 +1946,7 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr, fr->duration_sec = ntohl(ofr->duration_sec); fr->duration_nsec = ntohl(ofr->duration_nsec); fr->idle_timeout = ntohs(ofr->idle_timeout); + fr->hard_timeout = 0; fr->packet_count = ntohll(ofr->packet_count); fr->byte_count = ntohll(ofr->byte_count); } else if (raw == OFPRAW_NXT_FLOW_REMOVED) { @@ -1798,6 +1968,7 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr, fr->duration_sec = ntohl(nfr->duration_sec); fr->duration_nsec = ntohl(nfr->duration_nsec); fr->idle_timeout = ntohs(nfr->idle_timeout); + fr->hard_timeout = 0; fr->packet_count = ntohll(nfr->packet_count); fr->byte_count = ntohll(nfr->byte_count); } else { @@ -1817,6 +1988,27 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr, struct ofpbuf *msg; switch (protocol) { + case OFPUTIL_P_OF12: { + struct ofp12_flow_removed *ofr; + + msg = ofpraw_alloc_xid(OFPRAW_OFPT11_FLOW_REMOVED, + ofputil_protocol_to_ofp_version(protocol), + htonl(0), NXM_TYPICAL_LEN); + ofr = ofpbuf_put_zeros(msg, sizeof *ofr); + ofr->cookie = fr->cookie; + ofr->priority = htons(fr->rule.priority); + ofr->reason = fr->reason; + ofr->table_id = 0; + ofr->duration_sec = htonl(fr->duration_sec); + ofr->duration_nsec = htonl(fr->duration_nsec); + ofr->idle_timeout = htons(fr->idle_timeout); + ofr->hard_timeout = htons(fr->hard_timeout); + ofr->packet_count = htonll(fr->packet_count); + ofr->byte_count = htonll(fr->byte_count); + oxm_put_match(msg, &fr->rule); + break; + } + case OFPUTIL_P_OF10: case OFPUTIL_P_OF10_TID: { struct ofp_flow_removed *ofr; @@ -1844,7 +2036,7 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr, msg = ofpraw_alloc_xid(OFPRAW_NXT_FLOW_REMOVED, OFP10_VERSION, htonl(0), NXM_TYPICAL_LEN); nfr = ofpbuf_put_zeros(msg, sizeof *nfr); - match_len = nx_put_match(msg, false, &fr->rule, 0, 0); + match_len = nx_put_match(msg, &fr->rule, 0, 0); nfr = msg->l3; nfr->cookie = fr->cookie; @@ -1859,7 +2051,6 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr, break; } - case OFPUTIL_P_OF12: default: NOT_REACHED(); } @@ -1867,6 +2058,20 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr, return msg; } +static void +ofputil_decode_packet_in_finish(struct ofputil_packet_in *pin, + struct cls_rule *rule, + struct ofpbuf *b) +{ + pin->packet = b->data; + pin->packet_len = b->size; + + pin->fmd.in_port = rule->flow.in_port; + pin->fmd.tun_id = rule->flow.tun_id; + pin->fmd.metadata = rule->flow.metadata; + memcpy(pin->fmd.regs, rule->flow.regs, sizeof pin->fmd.regs); +} + enum ofperr ofputil_decode_packet_in(struct ofputil_packet_in *pin, const struct ofp_header *oh) @@ -1878,7 +2083,29 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin, ofpbuf_use_const(&b, oh, ntohs(oh->length)); raw = ofpraw_pull_assert(&b); - if (raw == OFPRAW_OFPT10_PACKET_IN) { + if (raw == OFPRAW_OFPT12_PACKET_IN) { + const struct ofp12_packet_in *opi; + struct cls_rule rule; + int error; + + opi = ofpbuf_pull(&b, sizeof *opi); + error = oxm_pull_match_loose(&b, 0, &rule); + if (error) { + return error; + } + + if (!ofpbuf_try_pull(&b, 2)) { + return OFPERR_OFPBRC_BAD_LEN; + } + + pin->reason = opi->reason; + pin->table_id = opi->table_id; + + pin->buffer_id = ntohl(opi->buffer_id); + pin->total_len = ntohs(opi->total_len); + + ofputil_decode_packet_in_finish(pin, &rule, &b); + } else if (raw == OFPRAW_OFPT10_PACKET_IN) { const struct ofp_packet_in *opi; opi = ofpbuf_pull(&b, offsetof(struct ofp_packet_in, data)); @@ -1906,26 +2133,14 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin, return OFPERR_OFPBRC_BAD_LEN; } - pin->packet = b.data; - pin->packet_len = b.size; pin->reason = npi->reason; pin->table_id = npi->table_id; pin->cookie = npi->cookie; - pin->fmd.in_port = rule.flow.in_port; - - pin->fmd.tun_id = rule.flow.tun_id; - pin->fmd.tun_id_mask = rule.wc.tun_id_mask; - - pin->fmd.metadata = rule.flow.metadata; - pin->fmd.metadata_mask = rule.wc.metadata_mask; - - memcpy(pin->fmd.regs, rule.flow.regs, sizeof pin->fmd.regs); - memcpy(pin->fmd.reg_masks, rule.wc.reg_masks, - sizeof pin->fmd.reg_masks); - pin->buffer_id = ntohl(npi->buffer_id); pin->total_len = ntohs(npi->total_len); + + ofputil_decode_packet_in_finish(pin, &rule, &b); } else { NOT_REACHED(); } @@ -1933,17 +2148,61 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin, return 0; } +static void +ofputil_packet_in_to_rule(const struct ofputil_packet_in *pin, + struct cls_rule *rule) +{ + int i; + + cls_rule_init_catchall(rule, 0); + if (pin->fmd.tun_id != htonll(0)) { + cls_rule_set_tun_id(rule, pin->fmd.tun_id); + } + if (pin->fmd.metadata != htonll(0)) { + cls_rule_set_metadata(rule, pin->fmd.metadata); + } + + for (i = 0; i < FLOW_N_REGS; i++) { + if (pin->fmd.regs[i]) { + cls_rule_set_reg(rule, i, pin->fmd.regs[i]); + } + } + + cls_rule_set_in_port(rule, pin->fmd.in_port); +} + /* Converts abstract ofputil_packet_in 'pin' into a PACKET_IN message * in the format specified by 'packet_in_format'. */ struct ofpbuf * ofputil_encode_packet_in(const struct ofputil_packet_in *pin, + enum ofputil_protocol protocol, enum nx_packet_in_format packet_in_format) { size_t send_len = MIN(pin->send_len, pin->packet_len); struct ofpbuf *packet; /* Add OFPT_PACKET_IN. */ - if (packet_in_format == NXPIF_OPENFLOW10) { + if (protocol == OFPUTIL_P_OF12) { + struct ofp12_packet_in *opi; + struct cls_rule rule; + + ofputil_packet_in_to_rule(pin, &rule); + + /* The final argument is just an estimate of the space required. */ + packet = ofpraw_alloc_xid(OFPRAW_OFPT12_PACKET_IN, OFP12_VERSION, + htonl(0), (sizeof(struct flow_metadata) * 2 + + 2 + send_len)); + ofpbuf_put_zeros(packet, sizeof *opi); + oxm_put_match(packet, &rule); + ofpbuf_put_zeros(packet, 2); + ofpbuf_put(packet, pin->packet, send_len); + + opi = packet->l3; + opi->buffer_id = htonl(pin->buffer_id); + opi->total_len = htons(pin->total_len); + opi->reason = pin->reason; + opi->table_id = pin->table_id; + } else if (packet_in_format == NXPIF_OPENFLOW10) { struct ofp_packet_in *opi; packet = ofpraw_alloc_xid(OFPRAW_OFPT10_PACKET_IN, OFP10_VERSION, @@ -1959,28 +2218,15 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin, struct nx_packet_in *npi; struct cls_rule rule; size_t match_len; - size_t i; - - cls_rule_init_catchall(&rule, 0); - cls_rule_set_tun_id_masked(&rule, pin->fmd.tun_id, - pin->fmd.tun_id_mask); - cls_rule_set_metadata_masked(&rule, pin->fmd.metadata, - pin->fmd.metadata_mask); - - for (i = 0; i < FLOW_N_REGS; i++) { - cls_rule_set_reg_masked(&rule, i, pin->fmd.regs[i], - pin->fmd.reg_masks[i]); - } - - cls_rule_set_in_port(&rule, pin->fmd.in_port); + ofputil_packet_in_to_rule(pin, &rule); /* The final argument is just an estimate of the space required. */ packet = ofpraw_alloc_xid(OFPRAW_NXT_PACKET_IN, OFP10_VERSION, htonl(0), (sizeof(struct flow_metadata) * 2 + 2 + send_len)); ofpbuf_put_zeros(packet, sizeof *npi); - match_len = nx_put_match(packet, false, &rule, 0, 0); + match_len = nx_put_match(packet, &rule, 0, 0); ofpbuf_put_zeros(packet, 2); ofpbuf_put(packet, pin->packet, send_len); @@ -2047,29 +2293,54 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po, const struct ofp_header *oh, struct ofpbuf *ofpacts) { - const struct ofp_packet_out *opo; - enum ofperr error; + enum ofperr bad_in_port_err; enum ofpraw raw; struct ofpbuf b; ofpbuf_use_const(&b, oh, ntohs(oh->length)); raw = ofpraw_pull_assert(&b); - assert(raw == OFPRAW_OFPT10_PACKET_OUT); - opo = ofpbuf_pull(&b, sizeof *opo); - po->buffer_id = ntohl(opo->buffer_id); - po->in_port = ntohs(opo->in_port); + if (raw == OFPRAW_OFPT11_PACKET_OUT) { + enum ofperr error; + const struct ofp11_packet_out *opo = ofpbuf_pull(&b, sizeof *opo); + + po->buffer_id = ntohl(opo->buffer_id); + error = ofputil_port_from_ofp11(opo->in_port, &po->in_port); + if (error) { + return error; + } + + error = ofpacts_pull_openflow11_actions(&b, ntohs(opo->actions_len), + ofpacts); + if (error) { + return error; + } + + bad_in_port_err = OFPERR_OFPBMC_BAD_VALUE; + } else if (raw == OFPRAW_OFPT10_PACKET_OUT) { + enum ofperr error; + const struct ofp_packet_out *opo = ofpbuf_pull(&b, sizeof *opo); + + po->buffer_id = ntohl(opo->buffer_id); + po->in_port = ntohs(opo->in_port); + + error = ofpacts_pull_openflow10(&b, ntohs(opo->actions_len), ofpacts); + if (error) { + return error; + } + + bad_in_port_err = OFPERR_NXBRC_BAD_IN_PORT; + } else { + NOT_REACHED(); + } + if (po->in_port >= OFPP_MAX && po->in_port != OFPP_LOCAL && po->in_port != OFPP_NONE && po->in_port != OFPP_CONTROLLER) { VLOG_WARN_RL(&bad_ofmsg_rl, "packet-out has bad input port %#"PRIx16, po->in_port); - return OFPERR_NXBRC_BAD_IN_PORT; + return bad_in_port_err; } - error = ofpacts_pull_openflow10(&b, ntohs(opo->actions_len), ofpacts); - if (error) { - return error; - } po->ofpacts = ofpacts->data; po->ofpacts_len = ofpacts->size; @@ -2341,52 +2612,6 @@ static const struct ofputil_action_bit_translation of10_action_bits[] = { { 0, 0 }, }; -static const struct ofputil_action_bit_translation of11_action_bits[] = { - { OFPUTIL_A_OUTPUT, OFPAT11_OUTPUT }, - { OFPUTIL_A_SET_VLAN_VID, OFPAT11_SET_VLAN_VID }, - { OFPUTIL_A_SET_VLAN_PCP, OFPAT11_SET_VLAN_PCP }, - { OFPUTIL_A_SET_DL_SRC, OFPAT11_SET_DL_SRC }, - { OFPUTIL_A_SET_DL_DST, OFPAT11_SET_DL_DST }, - { OFPUTIL_A_SET_NW_SRC, OFPAT11_SET_NW_SRC }, - { OFPUTIL_A_SET_NW_DST, OFPAT11_SET_NW_DST }, - { OFPUTIL_A_SET_NW_TOS, OFPAT11_SET_NW_TOS }, - { OFPUTIL_A_SET_NW_ECN, OFPAT11_SET_NW_ECN }, - { OFPUTIL_A_SET_TP_SRC, OFPAT11_SET_TP_SRC }, - { OFPUTIL_A_SET_TP_DST, OFPAT11_SET_TP_DST }, - { OFPUTIL_A_COPY_TTL_OUT, OFPAT11_COPY_TTL_OUT }, - { OFPUTIL_A_COPY_TTL_IN, OFPAT11_COPY_TTL_IN }, - { OFPUTIL_A_SET_MPLS_LABEL, OFPAT11_SET_MPLS_LABEL }, - { OFPUTIL_A_SET_MPLS_TC, OFPAT11_SET_MPLS_TC }, - { OFPUTIL_A_SET_MPLS_TTL, OFPAT11_SET_MPLS_TTL }, - { OFPUTIL_A_DEC_MPLS_TTL, OFPAT11_DEC_MPLS_TTL }, - { OFPUTIL_A_PUSH_VLAN, OFPAT11_PUSH_VLAN }, - { OFPUTIL_A_POP_VLAN, OFPAT11_POP_VLAN }, - { OFPUTIL_A_PUSH_MPLS, OFPAT11_PUSH_MPLS }, - { OFPUTIL_A_POP_MPLS, OFPAT11_POP_MPLS }, - { OFPUTIL_A_SET_QUEUE, OFPAT11_SET_QUEUE }, - { OFPUTIL_A_GROUP, OFPAT11_GROUP }, - { OFPUTIL_A_SET_NW_TTL, OFPAT11_SET_NW_TTL }, - { OFPUTIL_A_DEC_NW_TTL, OFPAT11_DEC_NW_TTL }, - { 0, 0 }, -}; - -static const struct ofputil_action_bit_translation of12_action_bits[] = { - { OFPUTIL_A_OUTPUT, OFPAT12_OUTPUT }, - { OFPUTIL_A_COPY_TTL_OUT, OFPAT12_COPY_TTL_OUT }, - { OFPUTIL_A_COPY_TTL_IN, OFPAT12_COPY_TTL_IN }, - { OFPUTIL_A_SET_MPLS_TTL, OFPAT12_SET_MPLS_TTL }, - { OFPUTIL_A_DEC_MPLS_TTL, OFPAT12_DEC_MPLS_TTL }, - { OFPUTIL_A_PUSH_VLAN, OFPAT12_PUSH_VLAN }, - { OFPUTIL_A_POP_VLAN, OFPAT12_POP_VLAN }, - { OFPUTIL_A_PUSH_MPLS, OFPAT12_PUSH_MPLS }, - { OFPUTIL_A_POP_MPLS, OFPAT12_POP_MPLS }, - { OFPUTIL_A_SET_QUEUE, OFPAT12_SET_QUEUE }, - { OFPUTIL_A_GROUP, OFPAT12_GROUP }, - { OFPUTIL_A_SET_NW_TTL, OFPAT12_SET_NW_TTL }, - { OFPUTIL_A_DEC_NW_TTL, OFPAT12_DEC_NW_TTL }, - { 0, 0 }, -}; - static enum ofputil_action_bitmap decode_action_bits(ovs_be32 of_actions, const struct ofputil_action_bit_translation *x) @@ -2455,19 +2680,7 @@ ofputil_decode_switch_features(const struct ofp_header *oh, if (osf->capabilities & htonl(OFPC11_GROUP_STATS)) { features->capabilities |= OFPUTIL_C_GROUP_STATS; } - switch ((enum ofp_version)oh->version) { - case OFP11_VERSION: - features->actions = decode_action_bits(htonl(UINT32_MAX), - of11_action_bits); - break; - case OFP12_VERSION: - features->actions = decode_action_bits(htonl(UINT32_MAX), - of12_action_bits); - break; - case OFP10_VERSION: - default: - NOT_REACHED(); - } + features->actions = 0; } else { return OFPERR_OFPBRC_BAD_VERSION; } @@ -2718,12 +2931,13 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm, break; } - case OFP11_VERSION: { + case OFP11_VERSION: + case OFP12_VERSION: { struct ofp11_port_mod *opm; b = ofpraw_alloc(OFPRAW_OFPT11_PORT_MOD, ofp_version, 0); opm = ofpbuf_put_zeros(b, sizeof *opm); - opm->port_no = htonl(pm->port_no); + opm->port_no = ofputil_port_to_ofp11(pm->port_no); memcpy(opm->hw_addr, pm->hw_addr, ETH_ADDR_LEN); opm->config = htonl(pm->config & OFPPC11_ALL); opm->mask = htonl(pm->mask & OFPPC11_ALL); @@ -2731,7 +2945,6 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm, break; } - case OFP12_VERSION: default: NOT_REACHED(); } @@ -2810,7 +3023,7 @@ ofputil_append_flow_monitor_request( start_ofs = msg->size; ofpbuf_put_zeros(msg, sizeof *nfmr); - match_len = nx_put_match(msg, false, &rq->match, htonll(0), htonll(0)); + 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); @@ -2978,8 +3191,7 @@ ofputil_append_flow_update(const struct ofputil_flow_update *update, int match_len; ofpbuf_put_zeros(msg, sizeof *nfuf); - match_len = nx_put_match(msg, false, update->match, - htonll(0), htonll(0)); + match_len = nx_put_match(msg, update->match, htonll(0), htonll(0)); ofpacts_put_openflow10(update->ofpacts, update->ofpacts_len, msg); nfuf = ofpbuf_at_assert(msg, start_ofs, sizeof *nfuf); @@ -3000,10 +3212,10 @@ ofputil_append_flow_update(const struct ofputil_flow_update *update, } struct ofpbuf * -ofputil_encode_packet_out(const struct ofputil_packet_out *po) +ofputil_encode_packet_out(const struct ofputil_packet_out *po, + enum ofputil_protocol protocol) { - struct ofp_packet_out *opo; - size_t actions_ofs; + enum ofp_version ofp_version = ofputil_protocol_to_ofp_version(protocol); struct ofpbuf *msg; size_t size; @@ -3012,15 +3224,42 @@ ofputil_encode_packet_out(const struct ofputil_packet_out *po) size += po->packet_len; } - msg = ofpraw_alloc(OFPRAW_OFPT10_PACKET_OUT, OFP10_VERSION, size); - ofpbuf_put_zeros(msg, sizeof *opo); - actions_ofs = msg->size; - ofpacts_put_openflow10(po->ofpacts, po->ofpacts_len, msg); + switch (ofp_version) { + case OFP10_VERSION: { + struct ofp_packet_out *opo; + size_t actions_ofs; + + msg = ofpraw_alloc(OFPRAW_OFPT10_PACKET_OUT, OFP10_VERSION, size); + ofpbuf_put_zeros(msg, sizeof *opo); + actions_ofs = msg->size; + ofpacts_put_openflow10(po->ofpacts, po->ofpacts_len, msg); + + opo = msg->l3; + opo->buffer_id = htonl(po->buffer_id); + opo->in_port = htons(po->in_port); + opo->actions_len = htons(msg->size - actions_ofs); + break; + } + + case OFP11_VERSION: + case OFP12_VERSION: { + struct ofp11_packet_out *opo; + size_t len; - opo = msg->l3; - opo->buffer_id = htonl(po->buffer_id); - opo->in_port = htons(po->in_port); - opo->actions_len = htons(msg->size - actions_ofs); + msg = ofpraw_alloc(OFPRAW_OFPT11_PACKET_OUT, ofp_version, size); + ofpbuf_put_zeros(msg, sizeof *opo); + len = ofpacts_put_openflow11_actions(po->ofpacts, po->ofpacts_len, msg); + + opo = msg->l3; + opo->buffer_id = htonl(po->buffer_id); + opo->in_port = ofputil_port_to_ofp11(po->in_port); + opo->actions_len = htons(len); + break; + } + + default: + NOT_REACHED(); + } if (po->buffer_id == UINT32_MAX) { ofpbuf_put(msg, po->packet, po->packet_len); @@ -3033,9 +3272,9 @@ ofputil_encode_packet_out(const struct ofputil_packet_out *po) /* Creates and returns an OFPT_ECHO_REQUEST message with an empty payload. */ struct ofpbuf * -make_echo_request(void) +make_echo_request(enum ofp_version ofp_version) { - return ofpraw_alloc_xid(OFPRAW_OFPT_ECHO_REQUEST, OFP10_VERSION, + return ofpraw_alloc_xid(OFPRAW_OFPT_ECHO_REQUEST, ofp_version, htonl(0), 0); } @@ -3056,9 +3295,25 @@ make_echo_reply(const struct ofp_header *rq) } struct ofpbuf * -ofputil_encode_barrier_request(void) +ofputil_encode_barrier_request(enum ofp_version ofp_version) { - return ofpraw_alloc(OFPRAW_OFPT10_BARRIER_REQUEST, OFP10_VERSION, 0); + enum ofpraw type; + + switch (ofp_version) { + case OFP12_VERSION: + case OFP11_VERSION: + type = OFPRAW_OFPT11_BARRIER_REQUEST; + break; + + case OFP10_VERSION: + type = OFPRAW_OFPT10_BARRIER_REQUEST; + break; + + default: + NOT_REACHED(); + } + + return ofpraw_alloc(type, ofp_version, 0); } const char * @@ -3332,23 +3587,8 @@ ofputil_put_action(enum ofputil_action_code code, struct ofpbuf *buf) } #include "ofp-util.def" -/* "Normalizes" the wildcards in 'rule'. That means: - * - * 1. If the type of level N is known, then only the valid fields for that - * level may be specified. For example, ARP does not have a TOS field, - * so nw_tos must be wildcarded if 'rule' specifies an ARP flow. - * Similarly, IPv4 does not have any IPv6 addresses, so ipv6_src and - * ipv6_dst (and other fields) must be wildcarded if 'rule' specifies an - * IPv4 flow. - * - * 2. If the type of level N is not known (or not understood by Open - * vSwitch), then no fields at all for that level may be specified. For - * example, Open vSwitch does not understand SCTP, an L4 protocol, so the - * L4 fields tp_src and tp_dst must be wildcarded if 'rule' specifies an - * SCTP flow. - */ -void -ofputil_normalize_rule(struct cls_rule *rule) +static void +ofputil_normalize_rule__(struct cls_rule *rule, bool may_log) { enum { MAY_NW_ADDR = 1 << 0, /* nw_src, nw_dst */ @@ -3422,7 +3662,7 @@ ofputil_normalize_rule(struct cls_rule *rule) /* Log any changes. */ if (!flow_wildcards_equal(&wc, &rule->wc)) { - bool log = !VLOG_DROP_INFO(&bad_ofmsg_rl); + bool log = may_log && !VLOG_DROP_INFO(&bad_ofmsg_rl); char *pre = log ? cls_rule_to_string(rule) : NULL; rule->wc = wc; @@ -3439,6 +3679,39 @@ ofputil_normalize_rule(struct cls_rule *rule) } } +/* "Normalizes" the wildcards in 'rule'. That means: + * + * 1. If the type of level N is known, then only the valid fields for that + * level may be specified. For example, ARP does not have a TOS field, + * so nw_tos must be wildcarded if 'rule' specifies an ARP flow. + * Similarly, IPv4 does not have any IPv6 addresses, so ipv6_src and + * ipv6_dst (and other fields) must be wildcarded if 'rule' specifies an + * IPv4 flow. + * + * 2. If the type of level N is not known (or not understood by Open + * vSwitch), then no fields at all for that level may be specified. For + * example, Open vSwitch does not understand SCTP, an L4 protocol, so the + * L4 fields tp_src and tp_dst must be wildcarded if 'rule' specifies an + * SCTP flow. + * + * If this function changes 'rule', it logs a rate-limited informational + * message. */ +void +ofputil_normalize_rule(struct cls_rule *rule) +{ + ofputil_normalize_rule__(rule, true); +} + +/* Same as ofputil_normalize_rule() without the logging. Thus, this function + * is suitable for a program's internal use, whereas ofputil_normalize_rule() + * sense for use on flows received from elsewhere (so that a bug in the program + * that sent them can be reported and corrected). */ +void +ofputil_normalize_rule_quiet(struct cls_rule *rule) +{ + ofputil_normalize_rule__(rule, false); +} + /* Parses a key or a key-value pair from '*stringp'. * * On success: Stores the key into '*keyp'. Stores the value, if present, into