memset(match->pad2, '\0', sizeof match->pad2);
}
+enum ofperr
+ofputil_pull_ofp11_match(struct ofpbuf *buf, unsigned int priority,
+ struct cls_rule *rule)
+{
+ struct ofp11_match_header *omh;
+ struct ofp11_match *om;
+
+ if (buf->size < sizeof(struct ofp11_match_header)) {
+ return OFPERR_OFPBMC_BAD_LEN;
+ }
+
+ omh = buf->data;
+ switch (ntohs(omh->type)) {
+ case OFPMT_STANDARD:
+ if (omh->length != htons(sizeof *om) || buf->size < sizeof *om) {
+ return OFPERR_OFPBMC_BAD_LEN;
+ }
+ om = ofpbuf_pull(buf, sizeof *om);
+ return ofputil_cls_rule_from_ofp11_match(om, priority, rule);
+
+ default:
+ return OFPERR_OFPBMC_BAD_TYPE;
+ }
+}
+
/* Converts the ofp11_match in 'match' into a cls_rule in 'rule', with the
* given 'priority'. Returns 0 if successful, otherwise an OFPERR_* value. */
enum ofperr
* 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(int version)
+ofputil_protocol_from_ofp_version(enum ofp_version version)
{
switch (version) {
- case OFP10_VERSION: return OFPUTIL_P_OF10;
- case OFP12_VERSION: return OFPUTIL_P_OF12;
- default: return 0;
+ case OFP10_VERSION:
+ return OFPUTIL_P_OF10;
+ case OFP12_VERSION:
+ return OFPUTIL_P_OF12;
+ case OFP11_VERSION:
+ default:
+ return 0;
}
}
/* Returns the OpenFlow protocol version number (e.g. OFP10_VERSION,
* OFP11_VERSION or OFP12_VERSION) that corresponds to 'protocol'. */
-uint8_t
+enum ofp_version
ofputil_protocol_to_ofp_version(enum ofputil_protocol protocol)
{
switch (protocol) {
ofpbuf_use_const(&b, oh, ntohs(oh->length));
raw = ofpraw_pull_assert(&b);
- if (raw == OFPRAW_OFPT10_FLOW_MOD) {
+ if (raw == OFPRAW_OFPT11_FLOW_MOD) {
/* Standard OpenFlow 1.1 flow_mod. */
- const struct ofp_flow_mod *ofm;
- uint16_t priority;
+ const struct ofp11_flow_mod *ofm;
enum ofperr error;
- /* Get the ofp_flow_mod. */
ofm = ofpbuf_pull(&b, sizeof *ofm);
- /* Set priority based on original wildcards. Normally we'd allow
- * ofputil_cls_rule_from_match() to do this for us, but
- * ofputil_normalize_rule() can put wildcards where the original flow
- * didn't have them. */
- priority = ntohs(ofm->priority);
- if (!(ofm->match.wildcards & htonl(OFPFW10_ALL))) {
- priority = UINT16_MAX;
+ error = ofputil_pull_ofp11_match(&b, ntohs(ofm->priority), &fm->cr);
+ if (error) {
+ return error;
}
- /* Translate the rule. */
- ofputil_cls_rule_from_ofp10_match(&ofm->match, priority, &fm->cr);
- ofputil_normalize_rule(&fm->cr);
-
- /* Now get the actions. */
- error = ofpacts_pull_openflow10(&b, b.size, ofpacts);
+ error = ofpacts_pull_openflow11_instructions(&b, b.size, ofpacts);
if (error) {
return error;
}
/* Translate the message. */
- command = ntohs(ofm->command);
- fm->cookie = htonll(0);
- fm->cookie_mask = htonll(0);
- fm->new_cookie = ofm->cookie;
+ if (ofm->command == OFPFC_ADD) {
+ fm->cookie = htonll(0);
+ fm->cookie_mask = htonll(0);
+ fm->new_cookie = ofm->cookie;
+ } else {
+ /* XXX */
+ fm->cookie = ofm->cookie;
+ fm->cookie_mask = ofm->cookie_mask;
+ fm->new_cookie = htonll(UINT64_MAX);
+ }
+ fm->command = ofm->command;
+ fm->table_id = ofm->table_id;
fm->idle_timeout = ntohs(ofm->idle_timeout);
fm->hard_timeout = ntohs(ofm->hard_timeout);
fm->buffer_id = ntohl(ofm->buffer_id);
- fm->out_port = ntohs(ofm->out_port);
- fm->flags = ntohs(ofm->flags);
- } else if (raw == OFPRAW_NXT_FLOW_MOD) {
- /* Nicira extended flow_mod. */
- const struct nx_flow_mod *nfm;
- enum ofperr error;
-
- /* Dissect the message. */
- nfm = ofpbuf_pull(&b, sizeof *nfm);
- error = nx_pull_match(&b, ntohs(nfm->match_len), ntohs(nfm->priority),
- &fm->cr, &fm->cookie, &fm->cookie_mask);
+ error = ofputil_port_from_ofp11(ofm->out_port, &fm->out_port);
if (error) {
return error;
}
- error = ofpacts_pull_openflow10(&b, b.size, ofpacts);
- if (error) {
- return error;
+ if (ofm->out_group != htonl(OFPG_ANY)) {
+ return OFPERR_NXFMFC_GROUPS_NOT_SUPPORTED;
}
-
- /* Translate the message. */
- command = ntohs(nfm->command);
- if ((command & 0xff) == OFPFC_ADD && fm->cookie_mask) {
- /* Flow additions may only set a new cookie, not match an
- * existing cookie. */
- return OFPERR_NXBRC_NXM_INVALID;
- }
- fm->new_cookie = nfm->cookie;
- fm->idle_timeout = ntohs(nfm->idle_timeout);
- fm->hard_timeout = ntohs(nfm->hard_timeout);
- fm->buffer_id = ntohl(nfm->buffer_id);
- fm->out_port = ntohs(nfm->out_port);
- fm->flags = ntohs(nfm->flags);
+ fm->flags = ntohs(ofm->flags);
} else {
- NOT_REACHED();
+ if (raw == OFPRAW_OFPT10_FLOW_MOD) {
+ /* Standard OpenFlow 1.0 flow_mod. */
+ const struct ofp10_flow_mod *ofm;
+ uint16_t priority;
+ enum ofperr error;
+
+ /* Get the ofp10_flow_mod. */
+ ofm = ofpbuf_pull(&b, sizeof *ofm);
+
+ /* Set priority based on original wildcards. Normally we'd allow
+ * ofputil_cls_rule_from_match() to do this for us, but
+ * ofputil_normalize_rule() can put wildcards where the original
+ * flow didn't have them. */
+ priority = ntohs(ofm->priority);
+ if (!(ofm->match.wildcards & htonl(OFPFW10_ALL))) {
+ priority = UINT16_MAX;
+ }
+
+ /* Translate the rule. */
+ ofputil_cls_rule_from_ofp10_match(&ofm->match, priority, &fm->cr);
+ ofputil_normalize_rule(&fm->cr);
+
+ /* Now get the actions. */
+ error = ofpacts_pull_openflow10(&b, b.size, ofpacts);
+ if (error) {
+ return error;
+ }
+
+ /* Translate the message. */
+ command = ntohs(ofm->command);
+ fm->cookie = htonll(0);
+ fm->cookie_mask = htonll(0);
+ fm->new_cookie = ofm->cookie;
+ fm->idle_timeout = ntohs(ofm->idle_timeout);
+ fm->hard_timeout = ntohs(ofm->hard_timeout);
+ fm->buffer_id = ntohl(ofm->buffer_id);
+ fm->out_port = ntohs(ofm->out_port);
+ fm->flags = ntohs(ofm->flags);
+ } else if (raw == OFPRAW_NXT_FLOW_MOD) {
+ /* Nicira extended flow_mod. */
+ const struct nx_flow_mod *nfm;
+ enum ofperr error;
+
+ /* Dissect the message. */
+ nfm = ofpbuf_pull(&b, sizeof *nfm);
+ error = nx_pull_match(&b, ntohs(nfm->match_len), ntohs(nfm->priority),
+ &fm->cr, &fm->cookie, &fm->cookie_mask);
+ if (error) {
+ return error;
+ }
+ error = ofpacts_pull_openflow10(&b, b.size, ofpacts);
+ if (error) {
+ return error;
+ }
+
+ /* Translate the message. */
+ command = ntohs(nfm->command);
+ if ((command & 0xff) == OFPFC_ADD && fm->cookie_mask) {
+ /* Flow additions may only set a new cookie, not match an
+ * existing cookie. */
+ return OFPERR_NXBRC_NXM_INVALID;
+ }
+ fm->new_cookie = nfm->cookie;
+ fm->idle_timeout = ntohs(nfm->idle_timeout);
+ fm->hard_timeout = ntohs(nfm->hard_timeout);
+ fm->buffer_id = ntohl(nfm->buffer_id);
+ fm->out_port = ntohs(nfm->out_port);
+ fm->flags = ntohs(nfm->flags);
+ } else {
+ NOT_REACHED();
+ }
+
+ if (protocol & OFPUTIL_P_TID) {
+ fm->command = command & 0xff;
+ fm->table_id = command >> 8;
+ } else {
+ fm->command = command;
+ fm->table_id = 0xff;
+ }
}
fm->ofpacts = ofpacts->data;
fm->ofpacts_len = ofpacts->size;
- if (protocol & OFPUTIL_P_TID) {
- fm->command = command & 0xff;
- fm->table_id = command >> 8;
- } else {
- fm->command = command;
- fm->table_id = 0xff;
- }
return 0;
}
ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
enum ofputil_protocol protocol)
{
- struct ofp_flow_mod *ofm;
- struct nx_flow_mod *nfm;
struct ofpbuf *msg;
uint16_t command;
- int match_len;
command = (protocol & OFPUTIL_P_TID
? (fm->command & 0xff) | (fm->table_id << 8)
switch (protocol) {
case OFPUTIL_P_OF10:
- case OFPUTIL_P_OF10_TID:
+ case OFPUTIL_P_OF10_TID: {
+ struct ofp10_flow_mod *ofm;
+
msg = ofpraw_alloc(OFPRAW_OFPT10_FLOW_MOD, OFP10_VERSION,
fm->ofpacts_len);
ofm = ofpbuf_put_zeros(msg, sizeof *ofm);
ofm->out_port = htons(fm->out_port);
ofm->flags = htons(fm->flags);
break;
+ }
case OFPUTIL_P_NXM:
- case OFPUTIL_P_NXM_TID:
+ case OFPUTIL_P_NXM_TID: {
+ struct nx_flow_mod *nfm;
+ int match_len;
+
msg = ofpraw_alloc(OFPRAW_NXT_FLOW_MOD, OFP10_VERSION,
NXM_TYPICAL_LEN + fm->ofpacts_len);
nfm = ofpbuf_put_zeros(msg, sizeof *nfm);
nfm->flags = htons(fm->flags);
nfm->match_len = htons(match_len);
break;
+ }
case OFPUTIL_P_OF12:
default:
static enum ofperr
ofputil_decode_ofpst_flow_request(struct ofputil_flow_stats_request *fsr,
- const struct ofp_flow_stats_request *ofsr,
+ const struct ofp10_flow_stats_request *ofsr,
bool aggregate)
{
fsr->aggregate = aggregate;
switch (protocol) {
case OFPUTIL_P_OF10:
case OFPUTIL_P_OF10_TID: {
- struct ofp_flow_stats_request *ofsr;
+ struct ofp10_flow_stats_request *ofsr;
raw = (fsr->aggregate
? OFPRAW_OFPST_AGGREGATE_REQUEST
if (!msg->size) {
return EOF;
} else if (raw == OFPRAW_OFPST_FLOW_REPLY) {
- const struct ofp_flow_stats *ofs;
+ const struct ofp10_flow_stats *ofs;
size_t length;
ofs = ofpbuf_try_pull(msg, sizeof *ofs);
ofpraw_decode_partial(&raw, reply->data, reply->size);
if (raw == OFPRAW_OFPST_FLOW_REPLY) {
- struct ofp_flow_stats *ofs;
+ struct ofp10_flow_stats *ofs;
ofpbuf_put_uninit(reply, sizeof *ofs);
ofpacts_put_openflow10(fs->ofpacts, fs->ofpacts_len, reply);
}
static size_t
-ofputil_get_phy_port_size(uint8_t ofp_version)
-{
- return ofp_version == OFP10_VERSION ? sizeof(struct ofp10_phy_port)
- : sizeof(struct ofp11_port);
+ofputil_get_phy_port_size(enum ofp_version ofp_version)
+{
+ switch (ofp_version) {
+ case OFP10_VERSION:
+ return sizeof(struct ofp10_phy_port);
+ case OFP11_VERSION:
+ case OFP12_VERSION:
+ return sizeof(struct ofp11_port);
+ default:
+ NOT_REACHED();
+ }
}
static void
}
static void
-ofputil_put_phy_port(uint8_t ofp_version, const struct ofputil_phy_port *pp,
- struct ofpbuf *b)
+ofputil_put_phy_port(enum ofp_version ofp_version,
+ const struct ofputil_phy_port *pp, struct ofpbuf *b)
{
- if (ofp_version == OFP10_VERSION) {
+ switch (ofp_version) {
+ case OFP10_VERSION: {
struct ofp10_phy_port *opp;
if (b->size + sizeof *opp <= UINT16_MAX) {
opp = ofpbuf_put_uninit(b, sizeof *opp);
ofputil_encode_ofp10_phy_port(pp, opp);
}
- } else {
+ break;
+ }
+
+ case OFP11_VERSION:
+ case OFP12_VERSION: {
struct ofp11_port *op;
if (b->size + sizeof *op <= UINT16_MAX) {
op = ofpbuf_put_uninit(b, sizeof *op);
ofputil_encode_ofp11_port(pp, op);
}
+ break;
+ }
+
+ default:
+ NOT_REACHED();
}
}
void
-ofputil_append_port_desc_stats_reply(uint8_t ofp_version,
+ofputil_append_port_desc_stats_reply(enum ofp_version ofp_version,
const struct ofputil_phy_port *pp,
struct list *replies)
{
- if (ofp_version == OFP10_VERSION) {
+ switch (ofp_version) {
+ case OFP10_VERSION: {
struct ofp10_phy_port *opp;
opp = ofpmp_append(replies, sizeof *opp);
ofputil_encode_ofp10_phy_port(pp, opp);
- } else {
+ break;
+ }
+
+ case OFP11_VERSION:
+ case OFP12_VERSION: {
struct ofp11_port *op;
op = ofpmp_append(replies, sizeof *op);
ofputil_encode_ofp11_port(pp, op);
+ break;
+ }
+
+ default:
+ NOT_REACHED();
}
}
\f
/* ofputil_switch_features */
#define OFPC_COMMON (OFPC_FLOW_STATS | OFPC_TABLE_STATS | OFPC_PORT_STATS | \
- OFPC_IP_REASM | OFPC_QUEUE_STATS | OFPC_ARP_MATCH_IP)
+ OFPC_IP_REASM | OFPC_QUEUE_STATS)
BUILD_ASSERT_DECL((int) OFPUTIL_C_FLOW_STATS == OFPC_FLOW_STATS);
BUILD_ASSERT_DECL((int) OFPUTIL_C_TABLE_STATS == OFPC_TABLE_STATS);
BUILD_ASSERT_DECL((int) OFPUTIL_C_PORT_STATS == OFPC_PORT_STATS);
{ 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)
return ofputil_actions;
}
+static uint32_t
+ofputil_capabilities_mask(enum ofp_version ofp_version)
+{
+ /* Handle capabilities whose bit is unique for all Open Flow versions */
+ switch (ofp_version) {
+ case OFP10_VERSION:
+ case OFP11_VERSION:
+ return OFPC_COMMON | OFPC_ARP_MATCH_IP;
+ case OFP12_VERSION:
+ return OFPC_COMMON | OFPC12_PORT_BLOCKED;
+ default:
+ /* Caller needs to check osf->header.version itself */
+ return 0;
+ }
+}
+
/* Decodes an OpenFlow 1.0 or 1.1 "switch_features" structure 'osf' into an
* abstract representation in '*features'. Initializes '*b' to iterate over
* the OpenFlow port structures following 'osf' with later calls to
features->n_buffers = ntohl(osf->n_buffers);
features->n_tables = osf->n_tables;
- features->capabilities = ntohl(osf->capabilities) & OFPC_COMMON;
+ features->capabilities = ntohl(osf->capabilities) &
+ ofputil_capabilities_mask(oh->version);
if (b->size % ofputil_get_phy_port_size(oh->version)) {
return OFPERR_OFPBRC_BAD_LEN;
if (osf->capabilities & htonl(OFPC11_GROUP_STATS)) {
features->capabilities |= OFPUTIL_C_GROUP_STATS;
}
- features->actions = decode_action_bits(osf->actions, of11_action_bits);
+ 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();
+ }
} else {
return OFPERR_OFPBRC_BAD_VERSION;
}
{
struct ofp_switch_features *osf;
struct ofpbuf *b;
- uint8_t version;
+ enum ofp_version version;
+ enum ofpraw raw;
version = ofputil_protocol_to_ofp_version(protocol);
- b = ofpraw_alloc_xid(version == OFP10_VERSION
- ? OFPRAW_OFPT10_FEATURES_REPLY
- : OFPRAW_OFPT11_FEATURES_REPLY,
- version, xid, 0);
+ switch (version) {
+ case OFP10_VERSION:
+ raw = OFPRAW_OFPT10_FEATURES_REPLY;
+ break;
+ case OFP11_VERSION:
+ case OFP12_VERSION:
+ raw = OFPRAW_OFPT11_FEATURES_REPLY;
+ break;
+ default:
+ NOT_REACHED();
+ }
+ b = ofpraw_alloc_xid(raw, version, xid, 0);
osf = ofpbuf_put_zeros(b, sizeof *osf);
osf->datapath_id = htonll(features->datapath_id);
osf->n_buffers = htonl(features->n_buffers);
osf->n_tables = features->n_tables;
osf->capabilities = htonl(features->capabilities & OFPC_COMMON);
- if (version == OFP10_VERSION) {
+ osf->capabilities = htonl(features->capabilities &
+ ofputil_capabilities_mask(version));
+ switch (version) {
+ case OFP10_VERSION:
if (features->capabilities & OFPUTIL_C_STP) {
osf->capabilities |= htonl(OFPC10_STP);
}
osf->actions = encode_action_bits(features->actions, of10_action_bits);
- } else {
+ break;
+ case OFP11_VERSION:
+ case OFP12_VERSION:
if (features->capabilities & OFPUTIL_C_GROUP_STATS) {
osf->capabilities |= htonl(OFPC11_GROUP_STATS);
}
- osf->actions = encode_action_bits(features->actions, of11_action_bits);
+ break;
+ default:
+ NOT_REACHED();
}
return b;
{
struct ofp_port_status *ops;
struct ofpbuf *b;
- uint8_t version;
+ enum ofp_version version;
+ enum ofpraw raw;
version = ofputil_protocol_to_ofp_version(protocol);
- b = ofpraw_alloc_xid(version == OFP10_VERSION
- ? OFPRAW_OFPT10_PORT_STATUS
- : OFPRAW_OFPT11_PORT_STATUS,
- version, htonl(0), 0);
+ switch (version) {
+ case OFP10_VERSION:
+ raw = OFPRAW_OFPT10_PORT_STATUS;
+ break;
+
+ case OFP11_VERSION:
+ case OFP12_VERSION:
+ raw = OFPRAW_OFPT11_PORT_STATUS;
+ break;
+
+ default:
+ NOT_REACHED();
+ }
+
+ b = ofpraw_alloc_xid(raw, version, htonl(0), 0);
ops = ofpbuf_put_zeros(b, sizeof *ops);
ops->reason = ps->reason;
ofputil_put_phy_port(version, &ps->desc, b);
ofputil_encode_port_mod(const struct ofputil_port_mod *pm,
enum ofputil_protocol protocol)
{
- uint8_t ofp_version = ofputil_protocol_to_ofp_version(protocol);
+ enum ofp_version ofp_version = ofputil_protocol_to_ofp_version(protocol);
struct ofpbuf *b;
- if (ofp_version == OFP10_VERSION) {
+ switch (ofp_version) {
+ case OFP10_VERSION: {
struct ofp10_port_mod *opm;
b = ofpraw_alloc(OFPRAW_OFPT10_PORT_MOD, ofp_version, 0);
opm->config = htonl(pm->config & OFPPC10_ALL);
opm->mask = htonl(pm->mask & OFPPC10_ALL);
opm->advertise = netdev_port_features_to_ofp10(pm->advertise);
- } else if (ofp_version == OFP11_VERSION) {
+ break;
+ }
+
+ case OFP11_VERSION: {
struct ofp11_port_mod *opm;
b = ofpraw_alloc(OFPRAW_OFPT11_PORT_MOD, ofp_version, 0);
opm->config = htonl(pm->config & OFPPC11_ALL);
opm->mask = htonl(pm->mask & OFPPC11_ALL);
opm->advertise = netdev_port_features_to_ofp11(pm->advertise);
- } else {
+ break;
+ }
+
+ case OFP12_VERSION:
+ default:
NOT_REACHED();
}
* port and returns 0. If no ports remain to be decoded, returns EOF.
* On an error, returns a positive OFPERR_* value. */
int
-ofputil_pull_phy_port(uint8_t ofp_version, struct ofpbuf *b,
+ofputil_pull_phy_port(enum ofp_version ofp_version, struct ofpbuf *b,
struct ofputil_phy_port *pp)
{
- if (ofp_version == OFP10_VERSION) {
+ switch (ofp_version) {
+ case OFP10_VERSION: {
const struct ofp10_phy_port *opp = ofpbuf_try_pull(b, sizeof *opp);
return opp ? ofputil_decode_ofp10_phy_port(pp, opp) : EOF;
- } else {
+ }
+ case OFP11_VERSION:
+ case OFP12_VERSION: {
const struct ofp11_port *op = ofpbuf_try_pull(b, sizeof *op);
return op ? ofputil_decode_ofp11_port(pp, op) : EOF;
}
+ default:
+ NOT_REACHED();
+ }
}
/* Given a buffer 'b' that contains an array of OpenFlow ports of type