2
0
mirror of https://github.com/openvswitch/ovs synced 2025-10-17 14:28:02 +00:00

Initial OpenFlow 1.3 support

Initial OpenFlow 1.3 support with new include/openflow/openflow-1.3.h.
Most of the messages that differ from 1.2 are implemented. OFPT_SET_ASYNC
is implemented via NX_SET_ASYNC_CONFIG, other new message types are yet to
be implemented. Stats replies that add duration fields are implemented at
encode/decode level only. Test cases for implemented features are included.
Remaining FIXME:s should not cause runtime aborts. Make check comes out
clean.

Signed-off-by: Jarno Rajahalme <jarno.rajahalme@nsn.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
Jarno Rajahalme
2012-11-27 17:44:22 +02:00
committed by Ben Pfaff
parent 6ed3b860fe
commit 2e1ae2005e
27 changed files with 1414 additions and 149 deletions

View File

@@ -588,6 +588,7 @@ static const struct proto_abbrev proto_abbrevs[] = {
#define N_PROTO_ABBREVS ARRAY_SIZE(proto_abbrevs)
enum ofputil_protocol ofputil_flow_dump_protocols[] = {
OFPUTIL_P_OF13_OXM,
OFPUTIL_P_OF12_OXM,
OFPUTIL_P_OF10_NXM,
OFPUTIL_P_OF10_STD,
@@ -607,6 +608,8 @@ ofputil_protocol_from_ofp_version(enum ofp_version version)
return OFPUTIL_P_OF10_STD;
case OFP12_VERSION:
return OFPUTIL_P_OF12_OXM;
case OFP13_VERSION:
return OFPUTIL_P_OF13_OXM;
case OFP11_VERSION:
default:
return 0;
@@ -614,7 +617,7 @@ ofputil_protocol_from_ofp_version(enum ofp_version version)
}
/* Returns the OpenFlow protocol version number (e.g. OFP10_VERSION,
* OFP11_VERSION or OFP12_VERSION) that corresponds to 'protocol'. */
* etc.) that corresponds to 'protocol'. */
enum ofp_version
ofputil_protocol_to_ofp_version(enum ofputil_protocol protocol)
{
@@ -626,6 +629,8 @@ ofputil_protocol_to_ofp_version(enum ofputil_protocol protocol)
return OFP10_VERSION;
case OFPUTIL_P_OF12_OXM:
return OFP12_VERSION;
case OFPUTIL_P_OF13_OXM:
return OFP13_VERSION;
}
NOT_REACHED();
@@ -664,6 +669,9 @@ ofputil_protocol_set_tid(enum ofputil_protocol protocol, bool enable)
case OFPUTIL_P_OF12_OXM:
return OFPUTIL_P_OF12_OXM;
case OFPUTIL_P_OF13_OXM:
return OFPUTIL_P_OF13_OXM;
default:
NOT_REACHED();
}
@@ -698,6 +706,9 @@ ofputil_protocol_set_base(enum ofputil_protocol cur,
case OFPUTIL_P_OF12_OXM:
return ofputil_protocol_set_tid(OFPUTIL_P_OF12_OXM, tid);
case OFPUTIL_P_OF13_OXM:
return ofputil_protocol_set_tid(OFPUTIL_P_OF13_OXM, tid);
default:
NOT_REACHED();
}
@@ -728,6 +739,9 @@ ofputil_protocol_to_string(enum ofputil_protocol protocol)
case OFPUTIL_P_OF12_OXM:
return "OXM";
case OFPUTIL_P_OF13_OXM:
return "OpenFlow13";
}
/* Check abbreviations. */
@@ -860,6 +874,9 @@ ofputil_version_from_string(const char *s)
if (!strcasecmp(s, "OpenFlow12")) {
return OFP12_VERSION;
}
if (!strcasecmp(s, "OpenFlow13")) {
return OFP13_VERSION;
}
return 0;
}
@@ -928,6 +945,8 @@ ofputil_version_to_string(enum ofp_version ofp_version)
return "OpenFlow11";
case OFP12_VERSION:
return "OpenFlow12";
case OFP13_VERSION:
return "OpenFlow13";
default:
NOT_REACHED();
}
@@ -1008,68 +1027,81 @@ ofputil_usable_protocols(const struct match *match)
/* 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_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
if (!eth_mask_is_exact(wc->masks.dl_dst)
&& !eth_addr_is_zero(wc->masks.dl_dst)) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM, OXM, and OF1.1+ support matching metadata. */
if (wc->masks.metadata != htonll(0)) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* 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_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM and OXM support matching IPv6 traffic. */
if (match->flow.dl_type == htons(ETH_TYPE_IPV6)) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM and OXM support matching registers. */
if (!regs_fully_wildcarded(wc)) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM and OXM support matching tun_id. */
if (wc->masks.tunnel.tun_id != htonll(0)) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM and OXM support matching fragments. */
if (wc->masks.nw_frag) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM and OXM support matching IPv6 flow label. */
if (wc->masks.ipv6_label) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM and OXM support matching IP ECN bits. */
if (wc->masks.nw_tos & IP_ECN_MASK) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* NXM and OXM support matching IP TTL/hop limit. */
if (wc->masks.nw_ttl) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* 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_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* 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_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
/* Other formats can express this rule. */
@@ -1269,8 +1301,9 @@ ofputil_encode_set_protocol(enum ofputil_protocol current,
return ofputil_encode_nx_set_flow_format(NXFF_OPENFLOW10);
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. */
case OFPUTIL_P_OF13_OXM:
/* There are only one of each OpenFlow 1.2+ protocols and we already
* verified above that we're not trying to change versions. */
NOT_REACHED();
case OFPUTIL_P_OF10_STD_TID:
@@ -1511,6 +1544,16 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
NOT_REACHED();
}
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;
}
if (protocol & OFPUTIL_P_TID) {
fm->command = command & 0xff;
fm->table_id = command >> 8;
@@ -1544,10 +1587,12 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
struct ofpbuf *msg;
switch (protocol) {
case OFPUTIL_P_OF12_OXM: {
case OFPUTIL_P_OF12_OXM:
case OFPUTIL_P_OF13_OXM: {
struct ofp11_flow_mod *ofm;
msg = ofpraw_alloc(OFPRAW_OFPT11_FLOW_MOD, OFP12_VERSION,
msg = ofpraw_alloc(OFPRAW_OFPT11_FLOW_MOD,
ofputil_protocol_to_ofp_version(protocol),
NXM_TYPICAL_LEN + fm->ofpacts_len);
ofm = ofpbuf_put_zeros(msg, sizeof *ofm);
if (fm->command == OFPFC_ADD) {
@@ -1644,7 +1689,8 @@ ofputil_flow_mod_usable_protocols(const struct ofputil_flow_mod *fms,
/* Matching of the cookie is only supported through NXM or OF1.1+. */
if (fm->cookie_mask != htonll(0)) {
usable_protocols &= OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
usable_protocols &= OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
}
@@ -1764,13 +1810,15 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
enum ofpraw raw;
switch (protocol) {
case OFPUTIL_P_OF12_OXM: {
case OFPUTIL_P_OF12_OXM:
case OFPUTIL_P_OF13_OXM: {
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);
msg = ofpraw_alloc(raw, ofputil_protocol_to_ofp_version(protocol),
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);
@@ -1835,7 +1883,8 @@ ofputil_flow_stats_request_usable_protocols(
usable_protocols = ofputil_usable_protocols(&fsr->match);
if (fsr->cookie_mask != htonll(0)) {
usable_protocols &= OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM;
usable_protocols &= OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
return usable_protocols;
}
@@ -1878,7 +1927,8 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
if (!msg->size) {
return EOF;
} else if (raw == OFPRAW_OFPST11_FLOW_REPLY) {
} else if (raw == OFPRAW_OFPST11_FLOW_REPLY
|| raw == OFPRAW_OFPST13_FLOW_REPLY) {
const struct ofp11_flow_stats *ofs;
size_t length;
uint16_t padded_match_len;
@@ -1914,6 +1964,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
fs->duration_nsec = ntohl(ofs->duration_nsec);
fs->idle_timeout = ntohs(ofs->idle_timeout);
fs->hard_timeout = ntohs(ofs->hard_timeout);
fs->flags = (raw == OFPRAW_OFPST13_FLOW_REPLY) ? ntohs(ofs->flags) : 0;
fs->idle_age = -1;
fs->hard_age = -1;
fs->cookie = ofs->cookie;
@@ -1953,6 +2004,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
fs->hard_age = -1;
fs->packet_count = ntohll(get_32aligned_be64(&ofs->packet_count));
fs->byte_count = ntohll(get_32aligned_be64(&ofs->byte_count));
fs->flags = 0;
} else if (raw == OFPRAW_NXST_FLOW_REPLY) {
const struct nx_flow_stats *nfs;
size_t match_len, actions_len, length;
@@ -1999,6 +2051,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
}
fs->packet_count = ntohll(nfs->packet_count);
fs->byte_count = ntohll(nfs->byte_count);
fs->flags = 0;
} else {
NOT_REACHED();
}
@@ -2031,7 +2084,7 @@ 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_OFPST11_FLOW_REPLY) {
if (raw == OFPRAW_OFPST11_FLOW_REPLY || raw == OFPRAW_OFPST13_FLOW_REPLY) {
struct ofp11_flow_stats *ofs;
ofpbuf_put_uninit(reply, sizeof *ofs);
@@ -2048,6 +2101,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
ofs->priority = htons(fs->priority);
ofs->idle_timeout = htons(fs->idle_timeout);
ofs->hard_timeout = htons(fs->hard_timeout);
ofs->flags = (raw == OFPRAW_OFPST13_FLOW_REPLY) ? htons(fs->flags) : 0;
memset(ofs->pad2, 0, sizeof ofs->pad2);
ofs->cookie = fs->cookie;
ofs->packet_count = htonll(unknown_to_zero(fs->packet_count));
@@ -2247,7 +2301,8 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
struct ofpbuf *msg;
switch (protocol) {
case OFPUTIL_P_OF12_OXM: {
case OFPUTIL_P_OF12_OXM:
case OFPUTIL_P_OF13_OXM: {
struct ofp12_flow_removed *ofr;
msg = ofpraw_alloc_xid(OFPRAW_OFPT11_FLOW_REMOVED,
@@ -2341,12 +2396,19 @@ 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_OFPT12_PACKET_IN) {
const struct ofp12_packet_in *opi;
if (raw == OFPRAW_OFPT13_PACKET_IN || raw == OFPRAW_OFPT12_PACKET_IN) {
const struct ofp13_packet_in *opi;
struct match match;
int error;
size_t packet_in_size;
opi = ofpbuf_pull(&b, sizeof *opi);
if (raw == OFPRAW_OFPT12_PACKET_IN) {
packet_in_size = sizeof (struct ofp12_packet_in);
} else {
packet_in_size = sizeof (struct ofp13_packet_in);
}
opi = ofpbuf_pull(&b, packet_in_size);
error = oxm_pull_match_loose(&b, &match);
if (error) {
return error;
@@ -2356,11 +2418,14 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin,
return OFPERR_OFPBRC_BAD_LEN;
}
pin->reason = opi->reason;
pin->table_id = opi->table_id;
pin->reason = opi->pi.reason;
pin->table_id = opi->pi.table_id;
pin->buffer_id = ntohl(opi->pi.buffer_id);
pin->total_len = ntohs(opi->pi.total_len);
pin->buffer_id = ntohl(opi->buffer_id);
pin->total_len = ntohs(opi->total_len);
if (raw == OFPRAW_OFPT13_PACKET_IN) {
pin->cookie = opi->cookie;
}
ofputil_decode_packet_in_finish(pin, &match, &b);
} else if (raw == OFPRAW_OFPT10_PACKET_IN) {
@@ -2440,27 +2505,43 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin,
struct ofpbuf *packet;
/* Add OFPT_PACKET_IN. */
if (protocol == OFPUTIL_P_OF12_OXM) {
struct ofp12_packet_in *opi;
if (protocol == OFPUTIL_P_OF13_OXM || protocol == OFPUTIL_P_OF12_OXM) {
struct ofp13_packet_in *opi;
struct match match;
enum ofpraw packet_in_raw;
enum ofp_version packet_in_version;
size_t packet_in_size;
if (protocol == OFPUTIL_P_OF12_OXM) {
packet_in_raw = OFPRAW_OFPT12_PACKET_IN;
packet_in_version = OFP12_VERSION;
packet_in_size = sizeof (struct ofp12_packet_in);
} else {
packet_in_raw = OFPRAW_OFPT13_PACKET_IN;
packet_in_version = OFP13_VERSION;
packet_in_size = sizeof (struct ofp13_packet_in);
}
ofputil_packet_in_to_match(pin, &match);
/* The final argument is just an estimate of the space required. */
packet = ofpraw_alloc_xid(OFPRAW_OFPT12_PACKET_IN, OFP12_VERSION,
packet = ofpraw_alloc_xid(packet_in_raw, packet_in_version,
htonl(0), (sizeof(struct flow_metadata) * 2
+ 2 + send_len));
ofpbuf_put_zeros(packet, sizeof *opi);
ofpbuf_put_zeros(packet, packet_in_size);
oxm_put_match(packet, &match);
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) {
opi->pi.buffer_id = htonl(pin->buffer_id);
opi->pi.total_len = htons(pin->total_len);
opi->pi.reason = pin->reason;
opi->pi.table_id = pin->table_id;
if (protocol == OFPUTIL_P_OF13_OXM) {
opi->cookie = pin->cookie;
}
} else if (packet_in_format == NXPIF_OPENFLOW10) {
struct ofp_packet_in *opi;
packet = ofpraw_alloc_xid(OFPRAW_OFPT10_PACKET_IN, OFP10_VERSION,
@@ -2729,6 +2810,7 @@ ofputil_get_phy_port_size(enum ofp_version ofp_version)
return sizeof(struct ofp10_phy_port);
case OFP11_VERSION:
case OFP12_VERSION:
case OFP13_VERSION:
return sizeof(struct ofp11_port);
default:
NOT_REACHED();
@@ -2791,7 +2873,8 @@ ofputil_put_phy_port(enum ofp_version ofp_version,
}
case OFP11_VERSION:
case OFP12_VERSION: {
case OFP12_VERSION:
case OFP13_VERSION: {
struct ofp11_port *op;
if (b->size + sizeof *op <= UINT16_MAX) {
op = ofpbuf_put_uninit(b, sizeof *op);
@@ -2820,7 +2903,8 @@ ofputil_append_port_desc_stats_reply(enum ofp_version ofp_version,
}
case OFP11_VERSION:
case OFP12_VERSION: {
case OFP12_VERSION:
case OFP13_VERSION: {
struct ofp11_port *op;
op = ofpmp_append(replies, sizeof *op);
@@ -2889,6 +2973,7 @@ ofputil_capabilities_mask(enum ofp_version ofp_version)
case OFP11_VERSION:
return OFPC_COMMON | OFPC_ARP_MATCH_IP;
case OFP12_VERSION:
case OFP13_VERSION:
return OFPC_COMMON | OFPC12_PORT_BLOCKED;
default:
/* Caller needs to check osf->header.version itself */
@@ -2916,6 +3001,7 @@ ofputil_decode_switch_features(const struct ofp_header *oh,
features->datapath_id = ntohll(osf->datapath_id);
features->n_buffers = ntohl(osf->n_buffers);
features->n_tables = osf->n_tables;
features->auxiliary_id = 0;
features->capabilities = ntohl(osf->capabilities) &
ofputil_capabilities_mask(oh->version);
@@ -2929,11 +3015,15 @@ ofputil_decode_switch_features(const struct ofp_header *oh,
features->capabilities |= OFPUTIL_C_STP;
}
features->actions = decode_action_bits(osf->actions, of10_action_bits);
} else if (raw == OFPRAW_OFPT11_FEATURES_REPLY) {
} else if (raw == OFPRAW_OFPT11_FEATURES_REPLY
|| raw == OFPRAW_OFPT13_FEATURES_REPLY) {
if (osf->capabilities & htonl(OFPC11_GROUP_STATS)) {
features->capabilities |= OFPUTIL_C_GROUP_STATS;
}
features->actions = 0;
if (raw == OFPRAW_OFPT13_FEATURES_REPLY) {
features->auxiliary_id = osf->auxiliary_id;
}
} else {
return OFPERR_OFPBRC_BAD_VERSION;
}
@@ -3010,6 +3100,9 @@ ofputil_encode_switch_features(const struct ofputil_switch_features *features,
case OFP12_VERSION:
raw = OFPRAW_OFPT11_FEATURES_REPLY;
break;
case OFP13_VERSION:
raw = OFPRAW_OFPT13_FEATURES_REPLY;
break;
default:
NOT_REACHED();
}
@@ -3029,6 +3122,9 @@ ofputil_encode_switch_features(const struct ofputil_switch_features *features,
}
osf->actions = encode_action_bits(features->actions, of10_action_bits);
break;
case OFP13_VERSION:
osf->auxiliary_id = features->auxiliary_id;
/* fall through */
case OFP11_VERSION:
case OFP12_VERSION:
if (features->capabilities & OFPUTIL_C_GROUP_STATS) {
@@ -3102,6 +3198,7 @@ ofputil_encode_port_status(const struct ofputil_port_status *ps,
case OFP11_VERSION:
case OFP12_VERSION:
case OFP13_VERSION:
raw = OFPRAW_OFPT11_PORT_STATUS;
break;
@@ -3185,7 +3282,8 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm,
}
case OFP11_VERSION:
case OFP12_VERSION: {
case OFP12_VERSION:
case OFP13_VERSION: {
struct ofp11_port_mod *opm;
b = ofpraw_alloc(OFPRAW_OFPT11_PORT_MOD, ofp_version, 0);
@@ -3309,6 +3407,22 @@ ofputil_put_ofp11_table_stats(const struct ofp12_table_stats *in,
out->matched_count = in->matched_count;
}
static void
ofputil_put_ofp13_table_stats(const struct ofp12_table_stats *in,
struct ofpbuf *buf)
{
struct ofp13_table_stats *out;
/* OF 1.3 splits table features off the ofp_table_stats,
* so there is not much here. */
out = ofpbuf_put_uninit(buf, sizeof *out);
out->table_id = in->table_id;
out->active_count = in->active_count;
out->lookup_count = in->lookup_count;
out->matched_count = in->matched_count;
}
struct ofpbuf *
ofputil_encode_table_stats_reply(const struct ofp12_table_stats stats[], int n,
const struct ofp_header *request)
@@ -3335,6 +3449,12 @@ ofputil_encode_table_stats_reply(const struct ofp12_table_stats stats[], int n,
ofpbuf_put(reply, stats, n * sizeof *stats);
break;
case OFP13_VERSION:
for (i = 0; i < n; i++) {
ofputil_put_ofp13_table_stats(&stats[i], reply);
}
break;
default:
NOT_REACHED();
}
@@ -3631,7 +3751,8 @@ ofputil_encode_packet_out(const struct ofputil_packet_out *po,
}
case OFP11_VERSION:
case OFP12_VERSION: {
case OFP12_VERSION:
case OFP13_VERSION: {
struct ofp11_packet_out *opo;
size_t len;
@@ -3689,6 +3810,7 @@ ofputil_encode_barrier_request(enum ofp_version ofp_version)
enum ofpraw type;
switch (ofp_version) {
case OFP13_VERSION:
case OFP12_VERSION:
case OFP11_VERSION:
type = OFPRAW_OFPT11_BARRIER_REQUEST;
@@ -3920,7 +4042,8 @@ ofputil_pull_phy_port(enum ofp_version ofp_version, struct ofpbuf *b,
return opp ? ofputil_decode_ofp10_phy_port(pp, opp) : EOF;
}
case OFP11_VERSION:
case OFP12_VERSION: {
case OFP12_VERSION:
case OFP13_VERSION: {
const struct ofp11_port *op = ofpbuf_try_pull(b, sizeof *op);
return op ? ofputil_decode_ofp11_port(pp, op) : EOF;
}
@@ -4219,7 +4342,7 @@ ofputil_parse_key_value(char **stringp, char **keyp, char **valuep)
}
/* Encode a dump ports request for 'port', the encoded message
* will be fore Open Flow version 'ofp_version'. Returns message
* will be for Open Flow version 'ofp_version'. Returns message
* as a struct ofpbuf. Returns encoded message on success, NULL on error */
struct ofpbuf *
ofputil_encode_dump_ports_request(enum ofp_version ofp_version, int16_t port)
@@ -4235,7 +4358,8 @@ ofputil_encode_dump_ports_request(enum ofp_version ofp_version, int16_t port)
break;
}
case OFP11_VERSION:
case OFP12_VERSION: {
case OFP12_VERSION:
case OFP13_VERSION: {
struct ofp11_port_stats_request *req;
request = ofpraw_alloc(OFPRAW_OFPST11_PORT_REQUEST, ofp_version, 0);
req = ofpbuf_put_zeros(request, sizeof *req);
@@ -4289,6 +4413,19 @@ ofputil_port_stats_to_ofp11(const struct ofputil_port_stats *ops,
ps11->collisions = htonll(ops->stats.collisions);
}
static void
ofputil_port_stats_to_ofp13(const struct ofputil_port_stats *ops,
struct ofp13_port_stats *ps13)
{
ofputil_port_stats_to_ofp11(ops, &ps13->ps);
/* OF 1.3 adds duration fields */
/* FIXME: Need to implement port alive duration (sec + nsec) */
ps13->duration_sec = htonl(~0);
ps13->duration_nsec = htonl(~0);
}
/* Encode a ports stat for 'ops' and append it to 'replies'. */
void
ofputil_append_port_stat(struct list *replies,
@@ -4298,6 +4435,11 @@ ofputil_append_port_stat(struct list *replies,
struct ofp_header *oh = msg->data;
switch ((enum ofp_version)oh->version) {
case OFP13_VERSION: {
struct ofp13_port_stats *reply = ofpmp_append(replies, sizeof *reply);
ofputil_port_stats_to_ofp13(ops, reply);
break;
}
case OFP12_VERSION:
case OFP11_VERSION: {
struct ofp11_port_stats *reply = ofpmp_append(replies, sizeof *reply);
@@ -4368,6 +4510,21 @@ ofputil_port_stats_from_ofp11(struct ofputil_port_stats *ops,
return 0;
}
static enum ofperr
ofputil_port_stats_from_ofp13(struct ofputil_port_stats *ops,
const struct ofp13_port_stats *ps13)
{
enum ofperr error =
ofputil_port_stats_from_ofp11(ops, &ps13->ps);
if (!error) {
/* FIXME: Get ps13->duration_sec and ps13->duration_nsec,
* Add to netdev_stats? */
}
return error;
}
/* Returns the number of port stats elements in OFPTYPE_PORT_STATS_REPLY
* message 'oh'. */
size_t
@@ -4408,14 +4565,20 @@ ofputil_decode_port_stats(struct ofputil_port_stats *ps, struct ofpbuf *msg)
if (!msg->size) {
return EOF;
} 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) {
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_PORT reply has %zu leftover "
"bytes at end", msg->size);
return OFPERR_OFPBRC_BAD_LEN;
goto bad_len;
}
return ofputil_port_stats_from_ofp11(ps, ps11);
} else if (raw == OFPRAW_OFPST10_PORT_REPLY) {
@@ -4423,15 +4586,17 @@ ofputil_decode_port_stats(struct ofputil_port_stats *ps, struct ofpbuf *msg)
ps10 = ofpbuf_try_pull(msg, sizeof *ps10);
if (!ps10) {
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_PORT reply has %zu leftover "
"bytes at end", msg->size);
return OFPERR_OFPBRC_BAD_LEN;
goto bad_len;
}
return ofputil_port_stats_from_ofp10(ps, ps10);
} else {
NOT_REACHED();
}
bad_len:
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_PORT reply has %zu leftover "
"bytes at end", msg->size);
return OFPERR_OFPBRC_BAD_LEN;
}
/* Parse a port status request message into a 16 bit OpenFlow 1.0
@@ -4442,6 +4607,7 @@ ofputil_decode_port_stats_request(const struct ofp_header *request,
uint16_t *ofp10_port)
{
switch ((enum ofp_version)request->version) {
case OFP13_VERSION:
case OFP12_VERSION:
case OFP11_VERSION: {
const struct ofp11_port_stats_request *psr11 = ofpmsg_body(request);
@@ -4466,6 +4632,7 @@ ofputil_decode_queue_stats_request(const struct ofp_header *request,
struct ofputil_queue_stats_request *oqsr)
{
switch ((enum ofp_version)request->version) {
case OFP13_VERSION:
case OFP12_VERSION:
case OFP11_VERSION: {
const struct ofp11_queue_stats_request *qsr11 = ofpmsg_body(request);
@@ -4500,7 +4667,8 @@ ofputil_encode_queue_stats_request(enum ofp_version ofp_version,
switch (ofp_version) {
case OFP11_VERSION:
case OFP12_VERSION: {
case OFP12_VERSION:
case OFP13_VERSION: {
struct ofp11_queue_stats_request *req;
request = ofpraw_alloc(OFPRAW_OFPST11_QUEUE_REQUEST, ofp_version, 0);
req = ofpbuf_put_zeros(request, sizeof *req);
@@ -4572,6 +4740,20 @@ ofputil_queue_stats_from_ofp11(struct ofputil_queue_stats *oqs,
return 0;
}
static enum ofperr
ofputil_queue_stats_from_ofp13(struct ofputil_queue_stats *oqs,
const struct ofp13_queue_stats *qs13)
{
enum ofperr error
= ofputil_queue_stats_from_ofp11(oqs, &qs13->qs);
if (!error) {
/* FIXME: Get qs13->duration_sec and qs13->duration_nsec,
* Add to netdev_queue_stats? */
}
return error;
}
/* Converts an OFPST_QUEUE_STATS reply in 'msg' into an abstract
* ofputil_queue_stats in 'qs'.
*
@@ -4597,14 +4779,20 @@ ofputil_decode_queue_stats(struct ofputil_queue_stats *qs, struct ofpbuf *msg)
if (!msg->size) {
return EOF;
} else if (raw == OFPRAW_OFPST13_QUEUE_REPLY) {
const struct ofp13_queue_stats *qs13;
qs13 = ofpbuf_try_pull(msg, sizeof *qs13);
if (!qs13) {
goto bad_len;
}
return ofputil_queue_stats_from_ofp13(qs, qs13);
} else if (raw == OFPRAW_OFPST11_QUEUE_REPLY) {
const struct ofp11_queue_stats *qs11;
qs11 = ofpbuf_try_pull(msg, sizeof *qs11);
if (!qs11) {
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_QUEUE reply has %zu leftover "
"bytes at end", msg->size);
return OFPERR_OFPBRC_BAD_LEN;
goto bad_len;
}
return ofputil_queue_stats_from_ofp11(qs, qs11);
} else if (raw == OFPRAW_OFPST10_QUEUE_REPLY) {
@@ -4612,14 +4800,17 @@ ofputil_decode_queue_stats(struct ofputil_queue_stats *qs, struct ofpbuf *msg)
qs10 = ofpbuf_try_pull(msg, sizeof *qs10);
if (!qs10) {
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_QUEUE reply has %zu leftover "
"bytes at end", msg->size);
return OFPERR_OFPBRC_BAD_LEN;
goto bad_len;
}
return ofputil_queue_stats_from_ofp10(qs, qs10);
} else {
NOT_REACHED();
}
bad_len:
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_QUEUE reply has %zu leftover "
"bytes at end", msg->size);
return OFPERR_OFPBRC_BAD_LEN;
}
static void
@@ -4645,6 +4836,17 @@ ofputil_queue_stats_to_ofp11(const struct ofputil_queue_stats *oqs,
qs11->tx_errors = htonll(oqs->stats.tx_errors);
}
static void
ofputil_queue_stats_to_ofp13(const struct ofputil_queue_stats *oqs,
struct ofp13_queue_stats *qs13)
{
ofputil_queue_stats_to_ofp11(oqs, &qs13->qs);
/* OF 1.3 adds duration fields */
/* FIXME: Need to implement queue alive duration (sec + nsec) */
qs13->duration_sec = htonl(~0);
qs13->duration_nsec = htonl(~0);
}
/* Encode a queue stat for 'oqs' and append it to 'replies'. */
void
ofputil_append_queue_stat(struct list *replies,
@@ -4654,15 +4856,21 @@ ofputil_append_queue_stat(struct list *replies,
struct ofp_header *oh = msg->data;
switch ((enum ofp_version)oh->version) {
case OFP13_VERSION: {
struct ofp13_queue_stats *reply = ofpmp_append(replies, sizeof *reply);
ofputil_queue_stats_to_ofp13(oqs, reply);
break;
}
case OFP12_VERSION:
case OFP11_VERSION: {
struct ofp11_queue_stats *reply = ofpmp_append(replies, sizeof *reply);;
struct ofp11_queue_stats *reply = ofpmp_append(replies, sizeof *reply);
ofputil_queue_stats_to_ofp11(oqs, reply);
break;
}
case OFP10_VERSION: {
struct ofp10_queue_stats *reply = ofpmp_append(replies, sizeof *reply);;
struct ofp10_queue_stats *reply = ofpmp_append(replies, sizeof *reply);
ofputil_queue_stats_to_ofp10(oqs, reply);
break;
}