X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fofp-util.c;h=c49b07988cca4903ce10b259eedd266e3ef1d5a1;hb=d4da3acc2a788d1c1b78c0bea6399660c7851f4a;hp=1125b83fc17752de195b11ee6479136da958fb45;hpb=685a51a5b89750cead1b2934c2079d2bb9c52a4a;p=openvswitch diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 1125b83f..c49b0798 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -19,6 +19,7 @@ #include #include #include +#include "autopath.h" #include "byte-order.h" #include "classifier.h" #include "dynamic-string.h" @@ -29,6 +30,7 @@ #include "ofpbuf.h" #include "packets.h" #include "random.h" +#include "unaligned.h" #include "type-props.h" #include "vlog.h" @@ -398,14 +400,6 @@ ofputil_decode_vendor(const struct ofp_header *oh, const struct ofputil_msg_type **typep) { static const struct ofputil_msg_type nxt_messages[] = { - { OFPUTIL_NXT_STATUS_REQUEST, - NXT_STATUS_REQUEST, "NXT_STATUS_REQUEST", - sizeof(struct nicira_header), 1 }, - - { OFPUTIL_NXT_STATUS_REPLY, - NXT_STATUS_REPLY, "NXT_STATUS_REPLY", - sizeof(struct nicira_header), 1 }, - { OFPUTIL_NXT_TUN_ID_FROM_COOKIE, NXT_TUN_ID_FROM_COOKIE, "NXT_TUN_ID_FROM_COOKIE", sizeof(struct nxt_tun_id_cookie), 0 }, @@ -856,7 +850,8 @@ is_nxm_required(const struct cls_rule *rule, bool cookie_support, ovs_be64 cookie) { const struct flow_wildcards *wc = &rule->wc; - ovs_be32 cookie_hi; + uint32_t cookie_hi; + uint64_t tun_id; /* Only NXM supports separately wildcards the Ethernet multicast bit. */ if (!(wc->wildcards & FWW_DL_DST) != !(wc->wildcards & FWW_ETH_MCAST)) { @@ -885,11 +880,21 @@ is_nxm_required(const struct cls_rule *rule, bool cookie_support, break; case CONSTANT_HTONLL(UINT64_MAX): - /* Only NXM supports matching tunnel ID, unless there is a cookie and - * the top 32 bits of the cookie are the desired tunnel ID value. */ - cookie_hi = htonl(ntohll(cookie) >> 32); - if (!cookie_support - || (cookie_hi && cookie_hi != ntohll(rule->flow.tun_id))) { + /* Only NXM supports tunnel ID matching without a cookie. */ + if (!cookie_support) { + return true; + } + + /* Only NXM supports 64-bit tunnel IDs. */ + tun_id = ntohll(rule->flow.tun_id); + if (tun_id > UINT32_MAX) { + return true; + } + + /* Only NXM supports a cookie whose top 32 bits conflict with the + * tunnel ID. */ + cookie_hi = ntohll(cookie) >> 32; + if (cookie_hi && cookie_hi != tun_id) { return true; } break; @@ -1146,7 +1151,7 @@ ofputil_decode_nxst_flow_request(struct flow_stats_request *fsr, } /* Converts an OFPST_FLOW, OFPST_AGGREGATE, NXST_FLOW, or NXST_AGGREGATE - * message 'oh', received when the current flow format was 'flow_format', into + * request 'oh', received when the current flow format was 'flow_format', into * an abstract flow_stats_request in 'fsr'. Returns 0 if successful, otherwise * an OpenFlow error code. * @@ -1186,7 +1191,7 @@ ofputil_decode_flow_stats_request(struct flow_stats_request *fsr, } /* Converts abstract flow_stats_request 'fsr' into an OFPST_FLOW, - * OFPST_AGGREGATE, NXST_FLOW, or NXST_AGGREGATE message 'oh' according to + * OFPST_AGGREGATE, NXST_FLOW, or NXST_AGGREGATE request 'oh' according to * 'flow_format', and returns the message. */ struct ofpbuf * ofputil_encode_flow_stats_request(const struct flow_stats_request *fsr, @@ -1228,6 +1233,117 @@ ofputil_encode_flow_stats_request(const struct flow_stats_request *fsr, return msg; } +/* Converts an OFPST_FLOW or NXST_FLOW reply in 'msg' into an abstract + * ofputil_flow_stats in 'fs'. For OFPST_FLOW messages, 'flow_format' should + * be the current flow format at the time when the request corresponding to the + * reply in 'msg' was sent. Otherwise 'flow_format' is ignored. + * + * Multiple OFPST_FLOW or NXST_FLOW replies can be packed into a single + * OpenFlow message. Calling this function multiple times for a single 'msg' + * iterates through the replies. The caller must initially leave 'msg''s layer + * pointers null and not modify them between calls. + * + * Returns 0 if successful, EOF if no replies were left in this 'msg', + * otherwise a positive errno value. */ +int +ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, + struct ofpbuf *msg, + enum nx_flow_format flow_format) +{ + const struct ofputil_msg_type *type; + int code; + + ofputil_decode_msg_type(msg->l2 ? msg->l2 : msg->data, &type); + code = ofputil_msg_type_code(type); + if (!msg->l2) { + msg->l2 = msg->data; + if (code == OFPUTIL_OFPST_FLOW_REPLY) { + ofpbuf_pull(msg, sizeof(struct ofp_stats_reply)); + } else if (code == OFPUTIL_NXST_FLOW_REPLY) { + ofpbuf_pull(msg, sizeof(struct nicira_stats_msg)); + } else { + NOT_REACHED(); + } + } + + if (!msg->size) { + return EOF; + } else if (code == OFPUTIL_OFPST_FLOW_REPLY) { + const struct ofp_flow_stats *ofs; + size_t length; + + 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_actions(msg, length - sizeof *ofs, + &fs->actions, &fs->n_actions)) { + return EINVAL; + } + + fs->cookie = get_32aligned_be64(&ofs->cookie); + ofputil_cls_rule_from_match(&ofs->match, ntohs(ofs->priority), + flow_format, fs->cookie, &fs->rule); + 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->packet_count = ntohll(get_32aligned_be64(&ofs->packet_count)); + fs->byte_count = ntohll(get_32aligned_be64(&ofs->byte_count)); + } else if (code == OFPUTIL_NXST_FLOW_REPLY) { + const struct nx_flow_stats *nfs; + size_t match_len, length; + + nfs = ofpbuf_try_pull(msg, sizeof *nfs); + if (!nfs) { + VLOG_WARN_RL(&bad_ofmsg_rl, "NXST_FLOW reply has %zu leftover " + "bytes at end", msg->size); + return EINVAL; + } + + length = ntohs(nfs->length); + match_len = ntohs(nfs->match_len); + if (length < sizeof *nfs + ROUND_UP(match_len, 8)) { + VLOG_WARN_RL(&bad_ofmsg_rl, "NXST_FLOW reply with match_len=%zu " + "claims invalid length %zu", match_len, length); + return EINVAL; + } + if (nx_pull_match(msg, match_len, ntohs(nfs->priority), &fs->rule)) { + return EINVAL; + } + + if (ofputil_pull_actions(msg, + length - sizeof *nfs - ROUND_UP(match_len, 8), + &fs->actions, &fs->n_actions)) { + return EINVAL; + } + + fs->cookie = nfs->cookie; + fs->table_id = nfs->table_id; + fs->duration_sec = ntohl(nfs->duration_sec); + fs->duration_nsec = ntohl(nfs->duration_nsec); + fs->idle_timeout = ntohs(nfs->idle_timeout); + fs->hard_timeout = ntohs(nfs->hard_timeout); + fs->packet_count = ntohll(nfs->packet_count); + fs->byte_count = ntohll(nfs->byte_count); + } else { + NOT_REACHED(); + } + + return 0; +} + /* Converts an OFPT_FLOW_REMOVED or NXT_FLOW_REMOVED message 'oh', received * when the current flow format was 'flow_format', into an abstract * ofputil_flow_removed in 'fr'. Returns 0 if successful, otherwise an @@ -1290,6 +1406,97 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr, return 0; } +/* Converts abstract ofputil_flow_removed 'fr' into an OFPT_FLOW_REMOVED or + * NXT_FLOW_REMOVED message 'oh' according to 'flow_format', and returns the + * message. */ +struct ofpbuf * +ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr, + enum nx_flow_format flow_format) +{ + struct ofpbuf *msg; + + if (flow_format == NXFF_OPENFLOW10 + || flow_format == NXFF_TUN_ID_FROM_COOKIE) { + struct ofp_flow_removed *ofr; + + ofr = make_openflow_xid(sizeof *ofr, OFPT_FLOW_REMOVED, htonl(0), + &msg); + ofputil_cls_rule_to_match(&fr->rule, flow_format, &ofr->match, + fr->cookie, &ofr->cookie); + ofr->priority = htons(fr->rule.priority); + ofr->reason = fr->reason; + ofr->duration_sec = htonl(fr->duration_sec); + ofr->duration_nsec = htonl(fr->duration_nsec); + ofr->idle_timeout = htons(fr->idle_timeout); + ofr->packet_count = htonll(fr->packet_count); + ofr->byte_count = htonll(fr->byte_count); + } else if (flow_format == NXFF_NXM) { + struct nx_flow_removed *nfr; + int match_len; + + make_nxmsg_xid(sizeof *nfr, NXT_FLOW_REMOVED, htonl(0), &msg); + match_len = nx_put_match(msg, &fr->rule); + + nfr = msg->data; + nfr->cookie = fr->cookie; + nfr->priority = htons(fr->rule.priority); + nfr->reason = fr->reason; + nfr->duration_sec = htonl(fr->duration_sec); + nfr->duration_nsec = htonl(fr->duration_nsec); + nfr->idle_timeout = htons(fr->idle_timeout); + nfr->match_len = htons(match_len); + nfr->packet_count = htonll(fr->packet_count); + nfr->byte_count = htonll(fr->byte_count); + } else { + NOT_REACHED(); + } + + return msg; +} + +/* Converts abstract ofputil_packet_in 'pin' into an OFPT_PACKET_IN message + * and returns the message. + * + * If 'rw_packet' is NULL, the caller takes ownership of the newly allocated + * returned ofpbuf. + * + * If 'rw_packet' is nonnull, then it must contain the same data as + * pin->packet. 'rw_packet' is allowed to be the same ofpbuf as pin->packet. + * It is modified in-place into an OFPT_PACKET_IN message according to 'pin', + * and then ofputil_encode_packet_in() returns 'rw_packet'. If 'rw_packet' has + * enough headroom to insert a "struct ofp_packet_in", this is more efficient + * than ofputil_encode_packet_in() because it does not copy the packet + * payload. */ +struct ofpbuf * +ofputil_encode_packet_in(const struct ofputil_packet_in *pin, + struct ofpbuf *rw_packet) +{ + int total_len = pin->packet->size; + struct ofp_packet_in *opi; + + if (rw_packet) { + if (pin->send_len < rw_packet->size) { + rw_packet->size = pin->send_len; + } + } else { + rw_packet = ofpbuf_clone_data_with_headroom( + pin->packet->data, MIN(pin->send_len, pin->packet->size), + offsetof(struct ofp_packet_in, data)); + } + + /* Add OFPT_PACKET_IN. */ + opi = ofpbuf_push_zeros(rw_packet, offsetof(struct ofp_packet_in, data)); + opi->header.version = OFP_VERSION; + opi->header.type = OFPT_PACKET_IN; + opi->total_len = htons(total_len); + opi->in_port = htons(pin->in_port); + opi->reason = pin->reason; + opi->buffer_id = htonl(pin->buffer_id); + update_openflow_length(rw_packet); + + return rw_packet; +} + /* Returns a string representing the message type of 'type'. The string is the * enumeration constant for the type, e.g. "OFPT_HELLO". For statistics * messages, the constant is followed by "request" or "reply", @@ -1657,49 +1864,17 @@ make_echo_reply(const struct ofp_header *rq) return out; } -const struct ofp_flow_stats * -flow_stats_first(struct flow_stats_iterator *iter, - const struct ofp_stats_reply *osr) -{ - iter->pos = osr->body; - iter->end = osr->body + (ntohs(osr->header.length) - - offsetof(struct ofp_stats_reply, body)); - return flow_stats_next(iter); -} - -const struct ofp_flow_stats * -flow_stats_next(struct flow_stats_iterator *iter) +/* Converts the members of 'opp' from host to network byte order. */ +void +hton_ofp_phy_port(struct ofp_phy_port *opp) { - ptrdiff_t bytes_left = iter->end - iter->pos; - const struct ofp_flow_stats *fs; - size_t length; - - if (bytes_left < sizeof *fs) { - if (bytes_left != 0) { - VLOG_WARN_RL(&bad_ofmsg_rl, - "%td leftover bytes in flow stats reply", bytes_left); - } - return NULL; - } - - fs = (const void *) iter->pos; - length = ntohs(fs->length); - if (length < sizeof *fs) { - VLOG_WARN_RL(&bad_ofmsg_rl, "flow stats length %zu is shorter than " - "min %zu", length, sizeof *fs); - return NULL; - } else if (length > bytes_left) { - VLOG_WARN_RL(&bad_ofmsg_rl, "flow stats length %zu but only %td " - "bytes left", length, bytes_left); - return NULL; - } else if ((length - sizeof *fs) % sizeof fs->actions[0]) { - VLOG_WARN_RL(&bad_ofmsg_rl, "flow stats length %zu has %zu bytes " - "left over in final action", length, - (length - sizeof *fs) % sizeof fs->actions[0]); - return NULL; - } - iter->pos += length; - return fs; + opp->port_no = htons(opp->port_no); + opp->config = htonl(opp->config); + opp->state = htonl(opp->state); + opp->curr = htonl(opp->curr); + opp->advertised = htonl(opp->advertised); + opp->supported = htonl(opp->supported); + opp->peer = htonl(opp->peer); } static int @@ -1840,6 +2015,14 @@ check_nicira_action(const union ofp_action *a, unsigned int len, } return multipath_check((const struct nx_action_multipath *) a); + case NXAST_AUTOPATH: + error = check_nx_action_exact_len( + nah, len, sizeof(struct nx_action_autopath)); + if (error) { + return error; + } + return autopath_check((const struct nx_action_autopath *) a); + case NXAST_SNAT__OBSOLETE: default: VLOG_WARN_RL(&bad_ofmsg_rl,