void
ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc)
{
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
/* Initialize most of wc. */
flow_wildcards_init_catchall(wc);
/* Most users really don't care about some of the differences between
* protocols. These abbreviations help with that. */
static const struct proto_abbrev proto_abbrevs[] = {
- { OFPUTIL_P_ANY, "any" },
- { OFPUTIL_P_OF10_ANY, "OpenFlow10" },
- { OFPUTIL_P_NXM_ANY, "NXM" },
+ { OFPUTIL_P_ANY, "any" },
+ { OFPUTIL_P_OF10_STD_ANY, "OpenFlow10" },
+ { OFPUTIL_P_OF10_NXM_ANY, "NXM" },
};
#define N_PROTO_ABBREVS ARRAY_SIZE(proto_abbrevs)
enum ofputil_protocol ofputil_flow_dump_protocols[] = {
- OFPUTIL_P_NXM,
- OFPUTIL_P_OF10,
+ OFPUTIL_P_OF12_OXM,
+ OFPUTIL_P_OF10_NXM,
+ OFPUTIL_P_OF10_STD,
};
size_t ofputil_n_flow_dump_protocols = ARRAY_SIZE(ofputil_flow_dump_protocols);
{
switch (version) {
case OFP10_VERSION:
- return OFPUTIL_P_OF10;
+ return OFPUTIL_P_OF10_STD;
case OFP12_VERSION:
- return OFPUTIL_P_OF12;
+ return OFPUTIL_P_OF12_OXM;
case OFP11_VERSION:
default:
return 0;
ofputil_protocol_to_ofp_version(enum ofputil_protocol protocol)
{
switch (protocol) {
- case OFPUTIL_P_OF10:
- case OFPUTIL_P_OF10_TID:
- case OFPUTIL_P_NXM:
- case OFPUTIL_P_NXM_TID:
+ case OFPUTIL_P_OF10_STD:
+ case OFPUTIL_P_OF10_STD_TID:
+ case OFPUTIL_P_OF10_NXM:
+ case OFPUTIL_P_OF10_NXM_TID:
return OFP10_VERSION;
- case OFPUTIL_P_OF12:
+ case OFPUTIL_P_OF12_OXM:
return OFP12_VERSION;
}
ofputil_protocol_set_tid(enum ofputil_protocol protocol, bool enable)
{
switch (protocol) {
- case OFPUTIL_P_OF10:
- case OFPUTIL_P_OF10_TID:
- return enable ? OFPUTIL_P_OF10_TID : OFPUTIL_P_OF10;
+ case OFPUTIL_P_OF10_STD:
+ case OFPUTIL_P_OF10_STD_TID:
+ return enable ? OFPUTIL_P_OF10_STD_TID : OFPUTIL_P_OF10_STD;
- case OFPUTIL_P_NXM:
- case OFPUTIL_P_NXM_TID:
- return enable ? OFPUTIL_P_NXM_TID : OFPUTIL_P_NXM;
+ case OFPUTIL_P_OF10_NXM:
+ case OFPUTIL_P_OF10_NXM_TID:
+ return enable ? OFPUTIL_P_OF10_NXM_TID : OFPUTIL_P_OF10_NXM;
- case OFPUTIL_P_OF12:
- return OFPUTIL_P_OF12;
+ case OFPUTIL_P_OF12_OXM:
+ return OFPUTIL_P_OF12_OXM;
default:
NOT_REACHED();
bool tid = (cur & OFPUTIL_P_TID) != 0;
switch (new_base) {
- case OFPUTIL_P_OF10:
- case OFPUTIL_P_OF10_TID:
- return ofputil_protocol_set_tid(OFPUTIL_P_OF10, tid);
+ case OFPUTIL_P_OF10_STD:
+ case OFPUTIL_P_OF10_STD_TID:
+ return ofputil_protocol_set_tid(OFPUTIL_P_OF10_STD, tid);
- case OFPUTIL_P_NXM:
- case OFPUTIL_P_NXM_TID:
- return ofputil_protocol_set_tid(OFPUTIL_P_NXM, tid);
+ case OFPUTIL_P_OF10_NXM:
+ case OFPUTIL_P_OF10_NXM_TID:
+ return ofputil_protocol_set_tid(OFPUTIL_P_OF10_NXM, tid);
- case OFPUTIL_P_OF12:
- return ofputil_protocol_set_tid(OFPUTIL_P_OF12, tid);
+ case OFPUTIL_P_OF12_OXM:
+ return ofputil_protocol_set_tid(OFPUTIL_P_OF12_OXM, tid);
default:
NOT_REACHED();
/* Use a "switch" statement for single-bit names so that we get a compiler
* warning if we forget any. */
switch (protocol) {
- case OFPUTIL_P_NXM:
+ case OFPUTIL_P_OF10_NXM:
return "NXM-table_id";
- case OFPUTIL_P_NXM_TID:
+ case OFPUTIL_P_OF10_NXM_TID:
return "NXM+table_id";
- case OFPUTIL_P_OF10:
+ case OFPUTIL_P_OF10_STD:
return "OpenFlow10-table_id";
- case OFPUTIL_P_OF10_TID:
+ case OFPUTIL_P_OF10_STD_TID:
return "OpenFlow10+table_id";
- case OFPUTIL_P_OF12:
- return NULL;
+ case OFPUTIL_P_OF12_OXM:
+ return "OXM";
}
/* Check abbreviations. */
return protocols;
}
-static enum ofp_version
+static int
ofputil_version_from_string(const char *s)
{
if (!strcasecmp(s, "OpenFlow10")) {
if (!strcasecmp(s, "OpenFlow12")) {
return OFP12_VERSION;
}
- VLOG_FATAL("Unknown OpenFlow version: \"%s\"", s);
+ return 0;
}
static bool
while (s[i]) {
size_t j;
- enum ofp_version version;
+ int version;
char *key;
if (is_delimiter(s[i])) {
}
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;
}
+uint32_t
+ofputil_versions_from_strings(char ** const s, size_t count)
+{
+ uint32_t bitmap = 0;
+
+ while (count--) {
+ int version = ofputil_version_from_string(s[count]);
+ if (!version) {
+ VLOG_WARN("Unknown OpenFlow version: \"%s\"", s[count]);
+ } else {
+ bitmap |= 1u << version;
+ }
+ }
+
+ return bitmap;
+}
+
const char *
ofputil_version_to_string(enum ofp_version ofp_version)
{
return true;
}
+static bool
+tun_parms_fully_wildcarded(const struct flow_wildcards *wc)
+{
+ return (!wc->masks.tunnel.ip_src &&
+ !wc->masks.tunnel.ip_dst &&
+ !wc->masks.tunnel.ip_ttl &&
+ !wc->masks.tunnel.ip_tos &&
+ !wc->masks.tunnel.flags);
+}
+
/* Returns a bit-mask of ofputil_protocols that can be used for sending 'match'
* to a switch (e.g. to add or remove a flow). Only NXM can handle tunnel IDs,
* registers, or fixing the Ethernet multicast bit. Otherwise, it's better to
{
const struct flow_wildcards *wc = &match->wc;
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
- /* NXM and OF1.1+ supports bitwise matching on ethernet addresses. */
+ /* tunnel params other than tun_id can't be sent in a flow_mod */
+ if (!tun_parms_fully_wildcarded(wc)) {
+ 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_P_NXM_ANY;
+ return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
}
if (!eth_mask_is_exact(wc->masks.dl_dst)
&& !eth_addr_is_zero(wc->masks.dl_dst)) {
- return OFPUTIL_P_NXM_ANY;
+ return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
}
- /* NXM and OF1.1+ support matching metadata. */
+ /* NXM, OXM, and OF1.1+ support matching metadata. */
if (wc->masks.metadata != htonll(0)) {
- return OFPUTIL_P_NXM_ANY;
+ return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
}
- /* Only NXM supports matching ARP hardware addresses. */
+ /* NXM and OXM support matching ARP hardware addresses. */
if (!eth_addr_is_zero(wc->masks.arp_sha) ||
!eth_addr_is_zero(wc->masks.arp_tha)) {
- return OFPUTIL_P_NXM_ANY;
+ return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
}
- /* Only NXM supports matching IPv6 traffic. */
+ /* NXM and OXM support matching IPv6 traffic. */
if (match->flow.dl_type == htons(ETH_TYPE_IPV6)) {
- return OFPUTIL_P_NXM_ANY;
+ return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
}
- /* Only NXM supports matching registers. */
+ /* NXM and OXM support matching registers. */
if (!regs_fully_wildcarded(wc)) {
- return OFPUTIL_P_NXM_ANY;
+ return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
}
- /* Only NXM supports matching tun_id. */
+ /* NXM and OXM support matching tun_id. */
if (wc->masks.tunnel.tun_id != htonll(0)) {
- return OFPUTIL_P_NXM_ANY;
+ return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
}
- /* Only NXM supports matching fragments. */
+ /* NXM and OXM support matching fragments. */
if (wc->masks.nw_frag) {
- return OFPUTIL_P_NXM_ANY;
+ return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
}
- /* Only NXM supports matching IPv6 flow label. */
+ /* NXM and OXM support matching IPv6 flow label. */
if (wc->masks.ipv6_label) {
- return OFPUTIL_P_NXM_ANY;
+ return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
}
- /* Only NXM supports matching IP ECN bits. */
+ /* NXM and OXM support matching IP ECN bits. */
if (wc->masks.nw_tos & IP_ECN_MASK) {
- return OFPUTIL_P_NXM_ANY;
+ return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
}
- /* Only NXM supports matching IP TTL/hop limit. */
+ /* NXM and OXM support matching IP TTL/hop limit. */
if (wc->masks.nw_ttl) {
- return OFPUTIL_P_NXM_ANY;
+ return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
}
- /* Only NXM supports non-CIDR IPv4 address masks. */
+ /* NXM and OXM support non-CIDR IPv4 address masks. */
if (!ip_is_cidr(wc->masks.nw_src) || !ip_is_cidr(wc->masks.nw_dst)) {
- return OFPUTIL_P_NXM_ANY;
+ return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
}
- /* Only NXM supports bitwise matching on transport port. */
+ /* NXM and OXM support bitwise matching on transport port. */
if ((wc->masks.tp_src && wc->masks.tp_src != htons(UINT16_MAX)) ||
(wc->masks.tp_dst && wc->masks.tp_dst != htons(UINT16_MAX))) {
- return OFPUTIL_P_NXM_ANY;
+ return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
}
/* Other formats can express this rule. */
static bool
ofputil_decode_hello_bitmap(const struct ofp_hello_elem_header *oheh,
- uint32_t *allowed_versions)
+ uint32_t *allowed_versionsp)
{
uint16_t bitmap_len = ntohs(oheh->length) - sizeof *oheh;
const ovs_be32 *bitmap = (const ovs_be32 *) (oheh + 1);
+ uint32_t allowed_versions;
if (!bitmap_len || bitmap_len % sizeof *bitmap) {
return false;
* should have no effect on session negotiation until Open vSwtich supports
* wire-protocol versions greater than 31.
*/
- *allowed_versions = ntohl(bitmap[0]);
+ allowed_versions = ntohl(bitmap[0]);
- if (*allowed_versions & 1) {
+ if (allowed_versions & 1) {
/* There's no OpenFlow version 0. */
VLOG_WARN_RL(&bad_ofmsg_rl, "peer claims to support invalid OpenFlow "
"version 0x00");
- *allowed_versions &= ~1u;
+ allowed_versions &= ~1u;
}
- if (!*allowed_versions) {
+ if (!allowed_versions) {
VLOG_WARN_RL(&bad_ofmsg_rl, "peer does not support any OpenFlow "
"version (between 0x01 and 0x1f)");
return false;
}
+ *allowed_versionsp = allowed_versions;
return true;
}
struct ofp_hello_elem_header *oheh;
uint16_t map_len;
- map_len = sizeof(uint32_t) / CHAR_BIT;
+ map_len = sizeof allowed_versions;
oheh = ofpbuf_put_zeros(msg, ROUND_UP(map_len + sizeof *oheh, 8));
oheh->type = htons(OFPHET_VERSIONBITMAP);
oheh->length = htons(map_len + sizeof *oheh);
*(ovs_be32 *)(oheh + 1) = htonl(allowed_versions);
+
+ ofpmsg_update_length(msg);
}
return msg;
* connection if the switch processes the returned message correctly. (If
* '*next != want' then the caller will have to iterate.)
*
- * If 'current == want', returns NULL and stores 'current' in '*next'. */
+ * If 'current == want', or if it is not possible to transition from 'current'
+ * to 'want' (because, for example, 'current' and 'want' use different OpenFlow
+ * protocol versions), returns NULL and stores 'current' in '*next'. */
struct ofpbuf *
ofputil_encode_set_protocol(enum ofputil_protocol current,
enum ofputil_protocol want,
enum ofputil_protocol *next)
{
+ enum ofp_version cur_version, want_version;
enum ofputil_protocol cur_base, want_base;
bool cur_tid, want_tid;
+ cur_version = ofputil_protocol_to_ofp_version(current);
+ want_version = ofputil_protocol_to_ofp_version(want);
+ if (cur_version != want_version) {
+ *next = current;
+ return NULL;
+ }
+
cur_base = ofputil_protocol_to_base(current);
want_base = ofputil_protocol_to_base(want);
if (cur_base != want_base) {
*next = ofputil_protocol_set_base(current, want_base);
switch (want_base) {
- case OFPUTIL_P_NXM:
+ case OFPUTIL_P_OF10_NXM:
return ofputil_encode_nx_set_flow_format(NXFF_NXM);
- case OFPUTIL_P_OF10:
+ case OFPUTIL_P_OF10_STD:
return ofputil_encode_nx_set_flow_format(NXFF_OPENFLOW10);
- case OFPUTIL_P_OF12:
- return ofputil_encode_nx_set_flow_format(NXFF_OPENFLOW12);
+ case OFPUTIL_P_OF12_OXM:
+ /* There's only one OpenFlow 1.2 protocol and we already verified
+ * above that we're not trying to change versions. */
+ NOT_REACHED();
- case OFPUTIL_P_OF10_TID:
- case OFPUTIL_P_NXM_TID:
+ case OFPUTIL_P_OF10_STD_TID:
+ case OFPUTIL_P_OF10_NXM_TID:
NOT_REACHED();
}
}
{
switch (flow_format) {
case NXFF_OPENFLOW10:
- return OFPUTIL_P_OF10;
+ return OFPUTIL_P_OF10_STD;
case NXFF_NXM:
- return OFPUTIL_P_NXM;
-
- case NXFF_OPENFLOW12:
- return OFPUTIL_P_OF12;
+ return OFPUTIL_P_OF10_NXM;
default:
return 0;
return "openflow10";
case NXFF_NXM:
return "nxm";
- case NXFF_OPENFLOW12:
- return "openflow12";
default:
NOT_REACHED();
}
struct ofpbuf *msg;
switch (protocol) {
- case OFPUTIL_P_OF12: {
+ case OFPUTIL_P_OF12_OXM: {
struct ofp11_flow_mod *ofm;
msg = ofpraw_alloc(OFPRAW_OFPT11_FLOW_MOD, OFP12_VERSION,
break;
}
- case OFPUTIL_P_OF10:
- case OFPUTIL_P_OF10_TID: {
+ case OFPUTIL_P_OF10_STD:
+ case OFPUTIL_P_OF10_STD_TID: {
struct ofp10_flow_mod *ofm;
msg = ofpraw_alloc(OFPRAW_OFPT10_FLOW_MOD, OFP10_VERSION,
break;
}
- case OFPUTIL_P_NXM:
- case OFPUTIL_P_NXM_TID: {
+ case OFPUTIL_P_OF10_NXM:
+ case OFPUTIL_P_OF10_NXM_TID: {
struct nx_flow_mod *nfm;
int match_len;
usable_protocols &= OFPUTIL_P_TID;
}
- /* Matching of the cookie is only supported through NXM. */
+ /* Matching of the cookie is only supported through NXM or OF1.1+. */
if (fm->cookie_mask != htonll(0)) {
- usable_protocols &= OFPUTIL_P_NXM_ANY;
+ usable_protocols &= OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
}
}
- assert(usable_protocols);
return usable_protocols;
}
enum ofpraw raw;
switch (protocol) {
- case OFPUTIL_P_OF12: {
+ case OFPUTIL_P_OF12_OXM: {
struct ofp11_flow_stats_request *ofsr;
raw = (fsr->aggregate
break;
}
- case OFPUTIL_P_OF10:
- case OFPUTIL_P_OF10_TID: {
+ case OFPUTIL_P_OF10_STD:
+ case OFPUTIL_P_OF10_STD_TID: {
struct ofp10_flow_stats_request *ofsr;
raw = (fsr->aggregate
break;
}
- case OFPUTIL_P_NXM:
- case OFPUTIL_P_NXM_TID: {
+ case OFPUTIL_P_OF10_NXM:
+ case OFPUTIL_P_OF10_NXM_TID: {
struct nx_flow_stats_request *nfsr;
int match_len;
usable_protocols = ofputil_usable_protocols(&fsr->match);
if (fsr->cookie_mask != htonll(0)) {
- usable_protocols &= OFPUTIL_P_NXM_ANY;
+ usable_protocols &= OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
}
return usable_protocols;
}
struct ofpbuf *msg;
switch (protocol) {
- case OFPUTIL_P_OF12: {
+ case OFPUTIL_P_OF12_OXM: {
struct ofp12_flow_removed *ofr;
msg = ofpraw_alloc_xid(OFPRAW_OFPT11_FLOW_REMOVED,
break;
}
- case OFPUTIL_P_OF10:
- case OFPUTIL_P_OF10_TID: {
+ case OFPUTIL_P_OF10_STD:
+ case OFPUTIL_P_OF10_STD_TID: {
struct ofp_flow_removed *ofr;
msg = ofpraw_alloc_xid(OFPRAW_OFPT10_FLOW_REMOVED, OFP10_VERSION,
break;
}
- case OFPUTIL_P_NXM:
- case OFPUTIL_P_NXM_TID: {
+ case OFPUTIL_P_OF10_NXM:
+ case OFPUTIL_P_OF10_NXM_TID: {
struct nx_flow_removed *nfr;
int match_len;
struct ofpbuf *packet;
/* Add OFPT_PACKET_IN. */
- if (protocol == OFPUTIL_P_OF12) {
+ if (protocol == OFPUTIL_P_OF12_OXM) {
struct ofp12_packet_in *opi;
struct match match;
OFPUTIL_NAMED_PORT(ALL) \
OFPUTIL_NAMED_PORT(CONTROLLER) \
OFPUTIL_NAMED_PORT(LOCAL) \
+ OFPUTIL_NAMED_PORT(ANY)
+
+/* For backwards compatibility, so that "none" is recognized as OFPP_ANY */
+#define OFPUTIL_NAMED_PORTS_WITH_NONE \
+ OFPUTIL_NAMED_PORTS \
OFPUTIL_NAMED_PORT(NONE)
/* Stores the port number represented by 's' into '*portp'. 's' may be an
};
static const struct pair pairs[] = {
#define OFPUTIL_NAMED_PORT(NAME) {#NAME, OFPP_##NAME},
- OFPUTIL_NAMED_PORTS
+ OFPUTIL_NAMED_PORTS_WITH_NONE
#undef OFPUTIL_NAMED_PORT
};
const struct pair *p;
}
case OFP10_VERSION: {
- const struct ofp10_queue_stats_request *qsr11 = ofpmsg_body(request);
- oqsr->queue_id = ntohl(qsr11->queue_id);
- oqsr->port_no = ntohs(qsr11->port_no);
+ const struct ofp10_queue_stats_request *qsr10 = ofpmsg_body(request);
+ oqsr->queue_id = ntohl(qsr10->queue_id);
+ oqsr->port_no = ntohs(qsr10->port_no);
+ /* OF 1.0 uses OFPP_ALL for OFPP_ANY */
+ if (oqsr->port_no == OFPP_ALL) {
+ oqsr->port_no = OFPP_ANY;
+ }
return 0;
}
struct ofp10_queue_stats_request *req;
request = ofpraw_alloc(OFPRAW_OFPST10_QUEUE_REQUEST, ofp_version, 0);
req = ofpbuf_put_zeros(request, sizeof *req);
- req->port_no = htons(oqsr->port_no);
+ /* OpenFlow 1.0 needs OFPP_ALL instead of OFPP_ANY */
+ req->port_no = htons(oqsr->port_no == OFPP_ANY
+ ? OFPP_ALL : oqsr->port_no);
req->queue_id = htonl(oqsr->queue_id);
break;
}