/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
static const struct proto_abbrev proto_abbrevs[] = {
{ OFPUTIL_P_ANY, "any" },
{ OFPUTIL_P_OF10_STD_ANY, "OpenFlow10" },
- { OFPUTIL_P_OF10_NXM_ANY, "NXM" },
+ { OFPUTIL_P_OF10_NXM_ANY, "NXM" },
+ { OFPUTIL_P_ANY_OXM, "OXM" },
};
#define N_PROTO_ABBREVS ARRAY_SIZE(proto_abbrevs)
};
size_t ofputil_n_flow_dump_protocols = ARRAY_SIZE(ofputil_flow_dump_protocols);
-/* Returns the ofputil_protocol that is initially in effect on an OpenFlow
- * connection that has negotiated the given 'version'. 'version' should
- * normally be an 8-bit OpenFlow version identifier (e.g. 0x01 for OpenFlow
- * 1.0, 0x02 for OpenFlow 1.1). Returns 0 if 'version' is not supported or
- * outside the valid range. */
+/* Returns the set of ofputil_protocols that are supported with the given
+ * OpenFlow 'version'. 'version' should normally be an 8-bit OpenFlow version
+ * identifier (e.g. 0x01 for OpenFlow 1.0, 0x02 for OpenFlow 1.1). Returns 0
+ * if 'version' is not supported or outside the valid range. */
enum ofputil_protocol
-ofputil_protocol_from_ofp_version(enum ofp_version version)
+ofputil_protocols_from_ofp_version(enum ofp_version version)
{
switch (version) {
case OFP10_VERSION:
- return OFPUTIL_P_OF10_STD;
+ return OFPUTIL_P_OF10_STD_ANY | OFPUTIL_P_OF10_NXM_ANY;
case OFP12_VERSION:
return OFPUTIL_P_OF12_OXM;
case OFP13_VERSION:
}
}
+/* Returns the ofputil_protocol that is initially in effect on an OpenFlow
+ * connection that has negotiated the given 'version'. 'version' should
+ * normally be an 8-bit OpenFlow version identifier (e.g. 0x01 for OpenFlow
+ * 1.0, 0x02 for OpenFlow 1.1). Returns 0 if 'version' is not supported or
+ * outside the valid range. */
+enum ofputil_protocol
+ofputil_protocol_from_ofp_version(enum ofp_version version)
+{
+ return rightmost_1bit(ofputil_protocols_from_ofp_version(version));
+}
+
/* Returns the OpenFlow protocol version number (e.g. OFP10_VERSION,
* etc.) that corresponds to 'protocol'. */
enum ofp_version
NOT_REACHED();
}
+/* Returns a bitmap of OpenFlow versions that are supported by at
+ * least one of the 'protocols'. */
+uint32_t
+ofputil_protocols_to_version_bitmap(enum ofputil_protocol protocols)
+{
+ uint32_t bitmap = 0;
+
+ for (; protocols; protocols = zero_rightmost_1bit(protocols)) {
+ enum ofputil_protocol protocol = rightmost_1bit(protocols);
+
+ bitmap |= 1u << ofputil_protocol_to_ofp_version(protocol);
+ }
+
+ return bitmap;
+}
+
+/* Returns the set of protocols that are supported on top of the
+ * OpenFlow versions included in 'bitmap'. */
+enum ofputil_protocol
+ofputil_protocols_from_version_bitmap(uint32_t bitmap)
+{
+ enum ofputil_protocol protocols = 0;
+
+ for (; bitmap; bitmap = zero_rightmost_1bit(bitmap)) {
+ enum ofp_version version = rightmost_1bit_idx(bitmap);
+
+ protocols |= ofputil_protocols_from_ofp_version(version);
+ }
+
+ return protocols;
+}
+
/* Returns true if 'protocol' is a single OFPUTIL_P_* value, false
* otherwise. */
bool
return "OpenFlow10+table_id";
case OFPUTIL_P_OF12_OXM:
- return "OXM";
+ return "OXM-OpenFlow12";
case OFPUTIL_P_OF13_OXM:
- return "OpenFlow13";
+ return "OXM-OpenFlow13";
}
/* Check abbreviations. */
{
struct ds s;
- assert(!(protocols & ~OFPUTIL_P_ANY));
+ ovs_assert(!(protocols & ~OFPUTIL_P_ANY));
if (protocols == 0) {
return xstrdup("none");
}
return OFPUTIL_P_NONE;
}
+ /* skb_mark and skb_priority can't be sent in a flow_mod */
+ if (wc->masks.skb_mark || wc->masks.skb_priority) {
+ return OFPUTIL_P_NONE;
+ }
+
/* NXM, OXM, and OF1.1 support bitwise matching on ethernet addresses. */
if (!eth_mask_is_exact(wc->masks.dl_src)
&& !eth_addr_is_zero(wc->masks.dl_src)) {
return ofputil_make_flow_mod_table_id(want_tid);
}
- assert(current == want);
+ ovs_assert(current == want);
*next = current;
return NULL;
struct nx_set_flow_format *sff;
struct ofpbuf *msg;
- assert(ofputil_nx_flow_format_is_valid(nxff));
+ ovs_assert(ofputil_nx_flow_format_is_valid(nxff));
msg = ofpraw_alloc(OFPRAW_NXT_SET_FLOW_FORMAT, OFP10_VERSION, 0);
sff = ofpbuf_put_zeros(msg, sizeof *sff);
if (fm->flags & OFPFF10_EMERG) {
/* We do not support the OpenFlow 1.0 emergency flow cache, which
* is not required in OpenFlow 1.0.1 and removed from OpenFlow 1.1.
- * There is no good error code, so just state that the flow table
- * is full.
- * Moreover, OFPFF10_EMERG overlaps with OFPFF12_RESET_COUNTS,
- * so this check must be here */
- return OFPERR_OFPFMFC_TABLE_FULL;
+ *
+ * OpenFlow 1.0 specifies the error code to use when idle_timeout
+ * or hard_timeout is nonzero. Otherwise, there is no good error
+ * code, so just state that the flow table is full. */
+ return (fm->hard_timeout || fm->idle_timeout
+ ? OFPERR_OFPFMFC_BAD_EMERG_TIMEOUT
+ : OFPERR_OFPFMFC_TABLE_FULL);
}
if (protocol & OFPUTIL_P_TID) {
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;
+ const struct ofp10_flow_removed *ofr;
ofr = ofpbuf_pull(&b, sizeof *ofr);
case OFPUTIL_P_OF10_STD:
case OFPUTIL_P_OF10_STD_TID: {
- struct ofp_flow_removed *ofr;
+ struct ofp10_flow_removed *ofr;
msg = ofpraw_alloc_xid(OFPRAW_OFPT10_FLOW_REMOVED, OFP10_VERSION,
htonl(0), 0);
ofputil_decode_packet_in_finish(pin, &match, &b);
} else if (raw == OFPRAW_OFPT10_PACKET_IN) {
- const struct ofp_packet_in *opi;
+ const struct ofp10_packet_in *opi;
- opi = ofpbuf_pull(&b, offsetof(struct ofp_packet_in, data));
+ opi = ofpbuf_pull(&b, offsetof(struct ofp10_packet_in, data));
pin->packet = opi->data;
pin->packet_len = b.size;
opi->cookie = pin->cookie;
}
} else if (packet_in_format == NXPIF_OPENFLOW10) {
- struct ofp_packet_in *opi;
+ struct ofp10_packet_in *opi;
packet = ofpraw_alloc_xid(OFPRAW_OFPT10_PACKET_IN, OFP10_VERSION,
htonl(0), send_len);
- opi = ofpbuf_put_zeros(packet, offsetof(struct ofp_packet_in, data));
+ opi = ofpbuf_put_zeros(packet, offsetof(struct ofp10_packet_in, data));
opi->total_len = htons(pin->total_len);
opi->in_port = htons(pin->fmd.in_port);
opi->reason = pin->reason;
}
} else if (raw == OFPRAW_OFPT10_PACKET_OUT) {
enum ofperr error;
- const struct ofp_packet_out *opo = ofpbuf_pull(&b, sizeof *opo);
+ const struct ofp10_packet_out *opo = ofpbuf_pull(&b, sizeof *opo);
po->buffer_id = ntohl(opo->buffer_id);
po->in_port = ntohs(opo->in_port);
{
const struct ofp_header *oh = b->data;
- ofputil_put_phy_port(oh->version, pp, b);
+ if (oh->version < OFP13_VERSION) {
+ ofputil_put_phy_port(oh->version, pp, b);
+ }
}
\f
/* ofputil_port_status */
ps->reason = ops->reason;
retval = ofputil_pull_phy_port(oh->version, &b, &ps->desc);
- assert(retval != EOF);
+ ovs_assert(retval != EOF);
return retval;
}
return b;
}
\f
+/* ofputil_role_request */
+
+/* Decodes the OpenFlow "role request" or "role reply" message in '*oh' into
+ * an abstract form in '*rr'. Returns 0 if successful, otherwise an
+ * OFPERR_* value. */
+enum ofperr
+ofputil_decode_role_message(const struct ofp_header *oh,
+ struct ofputil_role_request *rr)
+{
+ const struct ofp12_role_request *orr = ofpmsg_body(oh);
+ uint32_t role = ntohl(orr->role);
+ struct ofpbuf b;
+ enum ofpraw raw;
+
+ memset(rr, 0, sizeof *rr);
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ raw = ofpraw_pull_assert(&b);
+
+ if (raw == OFPRAW_OFPT12_ROLE_REQUEST
+ || raw == OFPRAW_OFPT12_ROLE_REPLY) {
+
+ if (raw == OFPRAW_OFPT12_ROLE_REQUEST) {
+ if (role == OFPCR12_ROLE_NOCHANGE) {
+ rr->request_current_role_only = true;
+ return 0;
+ }
+ if (role == OFPCR12_ROLE_MASTER || role == OFPCR12_ROLE_SLAVE) {
+ rr->generation_id = ntohll(orr->generation_id);
+ rr->have_generation_id = true;
+ }
+ }
+
+ /* Map to enum nx_role */
+ role -= 1; /* OFPCR12_ROLE_MASTER -> NX_ROLE_MASTER etc. */
+ } else if (raw != OFPRAW_NXT_ROLE_REQUEST
+ && raw != OFPRAW_NXT_ROLE_REPLY) {
+ return OFPERR_OFPBRC_BAD_TYPE;
+ }
+
+ if (role != NX_ROLE_OTHER && role != NX_ROLE_MASTER
+ && role != NX_ROLE_SLAVE) {
+ return OFPERR_OFPRRFC_BAD_ROLE;
+ }
+
+ rr->role = role;
+ return 0;
+}
+
+/* Returns an encoded form of a role reply suitable for the "request" in a
+ * buffer owned by the caller. */
+struct ofpbuf *
+ofputil_encode_role_reply(const struct ofp_header *request,
+ enum nx_role role)
+{
+ struct ofp12_role_request *reply;
+ struct ofpbuf *buf;
+ size_t reply_size;
+
+ struct ofpbuf b;
+ enum ofpraw raw;
+
+ ofpbuf_use_const(&b, request, ntohs(request->length));
+ raw = ofpraw_pull_assert(&b);
+ if (raw == OFPRAW_OFPT12_ROLE_REQUEST) {
+ reply_size = sizeof (struct ofp12_role_request);
+ raw = OFPRAW_OFPT12_ROLE_REPLY;
+ }
+ else if (raw == OFPRAW_NXT_ROLE_REQUEST) {
+ reply_size = sizeof (struct nx_role_request);
+ raw = OFPRAW_NXT_ROLE_REPLY;
+ } else {
+ NOT_REACHED();
+ }
+
+ buf = ofpraw_alloc_reply(raw, request, 0);
+ reply = ofpbuf_put_zeros(buf, reply_size);
+
+ if (raw == OFPRAW_OFPT12_ROLE_REPLY) {
+ /* Map to OpenFlow enum ofp12_controller_role */
+ role += 1; /* NX_ROLE_MASTER -> OFPCR12_ROLE_MASTER etc. */
+ /*
+ * OpenFlow specification does not specify use of generation_id field
+ * on reply messages. Intuitively, it would seem a good idea to return
+ * the current value. However, the current value is undefined
+ * initially, and there is no way to insert an undefined value in the
+ * message. Therefore we leave the generation_id zeroed on reply
+ * messages.
+ *
+ * A request for clarification has been filed with the Open Networking
+ * Foundation as EXT-272.
+ */
+ }
+ reply->role = htonl(role);
+
+ return buf;
+}
+\f
/* Table stats. */
static void
struct ofpbuf *buf)
{
struct wc_map {
- enum ofp_flow_wildcards wc10;
+ enum ofp10_flow_wildcards wc10;
enum oxm12_ofb_match_fields mf12;
};
struct ofp10_table_stats *out;
const struct wc_map *p;
- out = ofpbuf_put_uninit(buf, sizeof *out);
+ out = ofpbuf_put_zeros(buf, sizeof *out);
out->table_id = in->table_id;
- strcpy(out->name, in->name);
+ ovs_strlcpy(out->name, in->name, sizeof out->name);
out->wildcards = 0;
for (p = wc_map; p < &wc_map[ARRAY_SIZE(wc_map)]; p++) {
if (in->wildcards & htonll(1ULL << p->mf12)) {
{
struct ofp11_table_stats *out;
- out = ofpbuf_put_uninit(buf, sizeof *out);
+ out = ofpbuf_put_zeros(buf, sizeof *out);
out->table_id = in->table_id;
- strcpy(out->name, in->name);
+ ovs_strlcpy(out->name, in->name, sizeof out->name);
out->wildcards = oxm12_to_ofp11_flow_match_fields(in->wildcards);
out->match = oxm12_to_ofp11_flow_match_fields(in->match);
out->instructions = in->instructions;
VLOG_WARN_RL(&bad_ofmsg_rl,
"NXST_FLOW_MONITOR reply has bad event %"PRIu16,
ntohs(nfuh->event));
- return OFPERR_OFPET_BAD_REQUEST;
+ return OFPERR_NXBRC_FM_BAD_EVENT;
}
bad_len:
switch (ofp_version) {
case OFP10_VERSION: {
- struct ofp_packet_out *opo;
+ struct ofp10_packet_out *opo;
size_t actions_ofs;
msg = ofpraw_alloc(OFPRAW_OFPT10_PACKET_OUT, OFP10_VERSION, size);
return true;
} else if (port32 < OFPP11_MAX) {
VLOG_WARN("port %u is outside the supported range 0 through "
- "%"PRIx16"or 0x%x through 0x%"PRIx32, port32,
+ "%"PRIx16" or 0x%x through 0x%"PRIx32, port32,
UINT16_MAX, (unsigned int) OFPP11_MAX, UINT32_MAX);
return false;
} else {