/*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
struct ofputil_msg_type {
enum ofputil_msg_code code; /* OFPUTIL_*. */
+ uint8_t ofp_version; /* An OpenFlow version or 0 for "any". */
uint32_t value; /* OFPT_*, OFPST_*, NXT_*, or NXST_*. */
const char *name; /* e.g. "OFPT_FLOW_REMOVED". */
unsigned int min_size; /* Minimum total message size in bytes. */
/* Represents a malformed OpenFlow message. */
static const struct ofputil_msg_type ofputil_invalid_type = {
- OFPUTIL_MSG_INVALID, 0, "OFPUTIL_MSG_INVALID", 0, 0
+ OFPUTIL_MSG_INVALID, 0, 0, "OFPUTIL_MSG_INVALID", 0, 0
};
struct ofputil_msg_category {
static int
ofputil_lookup_openflow_message(const struct ofputil_msg_category *cat,
- uint32_t value,
+ uint8_t version, uint32_t value,
const struct ofputil_msg_type **typep)
{
const struct ofputil_msg_type *type;
for (type = cat->types; type < &cat->types[cat->n_types]; type++) {
- if (type->value == value) {
+ if (type->value == value
+ && (!type->ofp_version || version == type->ofp_version)) {
*typep = type;
return 0;
}
const struct ofputil_msg_type **typep)
{
static const struct ofputil_msg_type nxt_messages[] = {
- { OFPUTIL_NXT_ROLE_REQUEST,
+ { OFPUTIL_NXT_ROLE_REQUEST, OFP10_VERSION,
NXT_ROLE_REQUEST, "NXT_ROLE_REQUEST",
sizeof(struct nx_role_request), 0 },
- { OFPUTIL_NXT_ROLE_REPLY,
+ { OFPUTIL_NXT_ROLE_REPLY, OFP10_VERSION,
NXT_ROLE_REPLY, "NXT_ROLE_REPLY",
sizeof(struct nx_role_request), 0 },
- { OFPUTIL_NXT_SET_FLOW_FORMAT,
+ { OFPUTIL_NXT_SET_FLOW_FORMAT, OFP10_VERSION,
NXT_SET_FLOW_FORMAT, "NXT_SET_FLOW_FORMAT",
- sizeof(struct nxt_set_flow_format), 0 },
+ sizeof(struct nx_set_flow_format), 0 },
- { OFPUTIL_NXT_FLOW_MOD,
+ { OFPUTIL_NXT_SET_PACKET_IN_FORMAT, OFP10_VERSION,
+ NXT_SET_PACKET_IN_FORMAT, "NXT_SET_PACKET_IN_FORMAT",
+ sizeof(struct nx_set_packet_in_format), 0 },
+
+ { OFPUTIL_NXT_PACKET_IN, OFP10_VERSION,
+ NXT_PACKET_IN, "NXT_PACKET_IN",
+ sizeof(struct nx_packet_in), 1 },
+
+ { OFPUTIL_NXT_FLOW_MOD, OFP10_VERSION,
NXT_FLOW_MOD, "NXT_FLOW_MOD",
sizeof(struct nx_flow_mod), 8 },
- { OFPUTIL_NXT_FLOW_REMOVED,
+ { OFPUTIL_NXT_FLOW_REMOVED, OFP10_VERSION,
NXT_FLOW_REMOVED, "NXT_FLOW_REMOVED",
sizeof(struct nx_flow_removed), 8 },
- { OFPUTIL_NXT_FLOW_MOD_TABLE_ID,
+ { OFPUTIL_NXT_FLOW_MOD_TABLE_ID, OFP10_VERSION,
NXT_FLOW_MOD_TABLE_ID, "NXT_FLOW_MOD_TABLE_ID",
- sizeof(struct nxt_flow_mod_table_id), 0 },
+ sizeof(struct nx_flow_mod_table_id), 0 },
};
static const struct ofputil_msg_category nxt_category = {
}
nh = (const struct nicira_header *) oh;
- return ofputil_lookup_openflow_message(&nxt_category, ntohl(nh->subtype),
- typep);
+ return ofputil_lookup_openflow_message(&nxt_category, oh->version,
+ ntohl(nh->subtype), typep);
}
static int
const struct ofputil_msg_type **typep)
{
static const struct ofputil_msg_type nxst_requests[] = {
- { OFPUTIL_NXST_FLOW_REQUEST,
+ { OFPUTIL_NXST_FLOW_REQUEST, OFP10_VERSION,
NXST_FLOW, "NXST_FLOW request",
sizeof(struct nx_flow_stats_request), 8 },
- { OFPUTIL_NXST_AGGREGATE_REQUEST,
+ { OFPUTIL_NXST_AGGREGATE_REQUEST, OFP10_VERSION,
NXST_AGGREGATE, "NXST_AGGREGATE request",
sizeof(struct nx_aggregate_stats_request), 8 },
};
}
nsm = (struct nicira_stats_msg *) oh;
- return ofputil_lookup_openflow_message(&nxst_request_category,
+ return ofputil_lookup_openflow_message(&nxst_request_category, oh->version,
ntohl(nsm->subtype), typep);
}
const struct ofputil_msg_type **typep)
{
static const struct ofputil_msg_type nxst_replies[] = {
- { OFPUTIL_NXST_FLOW_REPLY,
+ { OFPUTIL_NXST_FLOW_REPLY, OFP10_VERSION,
NXST_FLOW, "NXST_FLOW reply",
sizeof(struct nicira_stats_msg), 8 },
- { OFPUTIL_NXST_AGGREGATE_REPLY,
+ { OFPUTIL_NXST_AGGREGATE_REPLY, OFP10_VERSION,
NXST_AGGREGATE, "NXST_AGGREGATE reply",
sizeof(struct nx_aggregate_stats_reply), 0 },
};
}
nsm = (struct nicira_stats_msg *) oh;
- return ofputil_lookup_openflow_message(&nxst_reply_category,
+ return ofputil_lookup_openflow_message(&nxst_reply_category, oh->version,
ntohl(nsm->subtype), typep);
}
const struct ofputil_msg_type **typep)
{
static const struct ofputil_msg_type ofpst_requests[] = {
- { OFPUTIL_OFPST_DESC_REQUEST,
+ { OFPUTIL_OFPST_DESC_REQUEST, OFP10_VERSION,
OFPST_DESC, "OFPST_DESC request",
sizeof(struct ofp_stats_msg), 0 },
- { OFPUTIL_OFPST_FLOW_REQUEST,
+ { OFPUTIL_OFPST_FLOW_REQUEST, OFP10_VERSION,
OFPST_FLOW, "OFPST_FLOW request",
sizeof(struct ofp_flow_stats_request), 0 },
- { OFPUTIL_OFPST_AGGREGATE_REQUEST,
+ { OFPUTIL_OFPST_AGGREGATE_REQUEST, OFP10_VERSION,
OFPST_AGGREGATE, "OFPST_AGGREGATE request",
sizeof(struct ofp_flow_stats_request), 0 },
- { OFPUTIL_OFPST_TABLE_REQUEST,
+ { OFPUTIL_OFPST_TABLE_REQUEST, OFP10_VERSION,
OFPST_TABLE, "OFPST_TABLE request",
sizeof(struct ofp_stats_msg), 0 },
- { OFPUTIL_OFPST_PORT_REQUEST,
+ { OFPUTIL_OFPST_PORT_REQUEST, OFP10_VERSION,
OFPST_PORT, "OFPST_PORT request",
sizeof(struct ofp_port_stats_request), 0 },
- { OFPUTIL_OFPST_QUEUE_REQUEST,
+ { OFPUTIL_OFPST_QUEUE_REQUEST, OFP10_VERSION,
OFPST_QUEUE, "OFPST_QUEUE request",
sizeof(struct ofp_queue_stats_request), 0 },
- { 0,
+ { 0, 0,
OFPST_VENDOR, "OFPST_VENDOR request",
sizeof(struct ofp_vendor_stats_msg), 1 },
};
}
error = ofputil_lookup_openflow_message(&ofpst_request_category,
- ntohs(request->type), typep);
+ oh->version, ntohs(request->type),
+ typep);
if (!error && request->type == htons(OFPST_VENDOR)) {
error = ofputil_decode_nxst_request(oh, length, typep);
}
const struct ofputil_msg_type **typep)
{
static const struct ofputil_msg_type ofpst_replies[] = {
- { OFPUTIL_OFPST_DESC_REPLY,
+ { OFPUTIL_OFPST_DESC_REPLY, OFP10_VERSION,
OFPST_DESC, "OFPST_DESC reply",
sizeof(struct ofp_desc_stats), 0 },
- { OFPUTIL_OFPST_FLOW_REPLY,
+ { OFPUTIL_OFPST_FLOW_REPLY, OFP10_VERSION,
OFPST_FLOW, "OFPST_FLOW reply",
sizeof(struct ofp_stats_msg), 1 },
- { OFPUTIL_OFPST_AGGREGATE_REPLY,
+ { OFPUTIL_OFPST_AGGREGATE_REPLY, OFP10_VERSION,
OFPST_AGGREGATE, "OFPST_AGGREGATE reply",
sizeof(struct ofp_aggregate_stats_reply), 0 },
- { OFPUTIL_OFPST_TABLE_REPLY,
+ { OFPUTIL_OFPST_TABLE_REPLY, OFP10_VERSION,
OFPST_TABLE, "OFPST_TABLE reply",
sizeof(struct ofp_stats_msg), sizeof(struct ofp_table_stats) },
- { OFPUTIL_OFPST_PORT_REPLY,
+ { OFPUTIL_OFPST_PORT_REPLY, OFP10_VERSION,
OFPST_PORT, "OFPST_PORT reply",
sizeof(struct ofp_stats_msg), sizeof(struct ofp_port_stats) },
- { OFPUTIL_OFPST_QUEUE_REPLY,
+ { OFPUTIL_OFPST_QUEUE_REPLY, OFP10_VERSION,
OFPST_QUEUE, "OFPST_QUEUE reply",
sizeof(struct ofp_stats_msg), sizeof(struct ofp_queue_stats) },
- { 0,
+ { 0, 0,
OFPST_VENDOR, "OFPST_VENDOR reply",
sizeof(struct ofp_vendor_stats_msg), 1 },
};
return error;
}
- error = ofputil_lookup_openflow_message(&ofpst_reply_category,
+ error = ofputil_lookup_openflow_message(&ofpst_reply_category, oh->version,
ntohs(reply->type), typep);
if (!error && reply->type == htons(OFPST_VENDOR)) {
error = ofputil_decode_nxst_reply(oh, length, typep);
const struct ofputil_msg_type **typep)
{
static const struct ofputil_msg_type ofpt_messages[] = {
- { OFPUTIL_OFPT_HELLO,
+ { OFPUTIL_OFPT_HELLO, OFP10_VERSION,
OFPT_HELLO, "OFPT_HELLO",
sizeof(struct ofp_hello), 1 },
- { OFPUTIL_OFPT_ERROR,
+ { OFPUTIL_OFPT_ERROR, OFP10_VERSION,
OFPT_ERROR, "OFPT_ERROR",
sizeof(struct ofp_error_msg), 1 },
- { OFPUTIL_OFPT_ECHO_REQUEST,
+ { OFPUTIL_OFPT_ECHO_REQUEST, OFP10_VERSION,
OFPT_ECHO_REQUEST, "OFPT_ECHO_REQUEST",
sizeof(struct ofp_header), 1 },
- { OFPUTIL_OFPT_ECHO_REPLY,
+ { OFPUTIL_OFPT_ECHO_REPLY, OFP10_VERSION,
OFPT_ECHO_REPLY, "OFPT_ECHO_REPLY",
sizeof(struct ofp_header), 1 },
- { OFPUTIL_OFPT_FEATURES_REQUEST,
+ { OFPUTIL_OFPT_FEATURES_REQUEST, OFP10_VERSION,
OFPT_FEATURES_REQUEST, "OFPT_FEATURES_REQUEST",
sizeof(struct ofp_header), 0 },
- { OFPUTIL_OFPT_FEATURES_REPLY,
+ { OFPUTIL_OFPT_FEATURES_REPLY, OFP10_VERSION,
OFPT_FEATURES_REPLY, "OFPT_FEATURES_REPLY",
sizeof(struct ofp_switch_features), sizeof(struct ofp_phy_port) },
- { OFPUTIL_OFPT_GET_CONFIG_REQUEST,
+ { OFPUTIL_OFPT_GET_CONFIG_REQUEST, OFP10_VERSION,
OFPT_GET_CONFIG_REQUEST, "OFPT_GET_CONFIG_REQUEST",
sizeof(struct ofp_header), 0 },
- { OFPUTIL_OFPT_GET_CONFIG_REPLY,
+ { OFPUTIL_OFPT_GET_CONFIG_REPLY, OFP10_VERSION,
OFPT_GET_CONFIG_REPLY, "OFPT_GET_CONFIG_REPLY",
sizeof(struct ofp_switch_config), 0 },
- { OFPUTIL_OFPT_SET_CONFIG,
+ { OFPUTIL_OFPT_SET_CONFIG, OFP10_VERSION,
OFPT_SET_CONFIG, "OFPT_SET_CONFIG",
sizeof(struct ofp_switch_config), 0 },
- { OFPUTIL_OFPT_PACKET_IN,
+ { OFPUTIL_OFPT_PACKET_IN, OFP10_VERSION,
OFPT_PACKET_IN, "OFPT_PACKET_IN",
offsetof(struct ofp_packet_in, data), 1 },
- { OFPUTIL_OFPT_FLOW_REMOVED,
+ { OFPUTIL_OFPT_FLOW_REMOVED, OFP10_VERSION,
OFPT_FLOW_REMOVED, "OFPT_FLOW_REMOVED",
sizeof(struct ofp_flow_removed), 0 },
- { OFPUTIL_OFPT_PORT_STATUS,
+ { OFPUTIL_OFPT_PORT_STATUS, OFP10_VERSION,
OFPT_PORT_STATUS, "OFPT_PORT_STATUS",
sizeof(struct ofp_port_status), 0 },
- { OFPUTIL_OFPT_PACKET_OUT,
+ { OFPUTIL_OFPT_PACKET_OUT, OFP10_VERSION,
OFPT_PACKET_OUT, "OFPT_PACKET_OUT",
sizeof(struct ofp_packet_out), 1 },
- { OFPUTIL_OFPT_FLOW_MOD,
+ { OFPUTIL_OFPT_FLOW_MOD, OFP10_VERSION,
OFPT_FLOW_MOD, "OFPT_FLOW_MOD",
sizeof(struct ofp_flow_mod), 1 },
- { OFPUTIL_OFPT_PORT_MOD,
+ { OFPUTIL_OFPT_PORT_MOD, OFP10_VERSION,
OFPT_PORT_MOD, "OFPT_PORT_MOD",
sizeof(struct ofp_port_mod), 0 },
- { 0,
+ { 0, OFP10_VERSION,
OFPT_STATS_REQUEST, "OFPT_STATS_REQUEST",
sizeof(struct ofp_stats_msg), 1 },
- { 0,
+ { 0, OFP10_VERSION,
OFPT_STATS_REPLY, "OFPT_STATS_REPLY",
sizeof(struct ofp_stats_msg), 1 },
- { OFPUTIL_OFPT_BARRIER_REQUEST,
+ { OFPUTIL_OFPT_BARRIER_REQUEST, OFP10_VERSION,
OFPT_BARRIER_REQUEST, "OFPT_BARRIER_REQUEST",
sizeof(struct ofp_header), 0 },
- { OFPUTIL_OFPT_BARRIER_REPLY,
+ { OFPUTIL_OFPT_BARRIER_REPLY, OFP10_VERSION,
OFPT_BARRIER_REPLY, "OFPT_BARRIER_REPLY",
sizeof(struct ofp_header), 0 },
- { 0,
+ { 0, 0,
OFPT_VENDOR, "OFPT_VENDOR",
sizeof(struct ofp_vendor_header), 1 },
};
int error;
- error = ofputil_lookup_openflow_message(&ofpt_category, oh->type, typep);
+ error = ofputil_lookup_openflow_message(&ofpt_category, oh->version,
+ oh->type, typep);
if (!error) {
switch (oh->type) {
case OFPT_VENDOR:
: -1);
}
+bool
+ofputil_packet_in_format_is_valid(enum nx_packet_in_format packet_in_format)
+{
+ switch (packet_in_format) {
+ case NXPIF_OPENFLOW10:
+ case NXPIF_NXM:
+ return true;
+ }
+
+ return false;
+}
+
+const char *
+ofputil_packet_in_format_to_string(enum nx_packet_in_format packet_in_format)
+{
+ switch (packet_in_format) {
+ case NXPIF_OPENFLOW10:
+ return "openflow10";
+ case NXPIF_NXM:
+ return "nxm";
+ default:
+ NOT_REACHED();
+ }
+}
+
+int
+ofputil_packet_in_format_from_string(const char *s)
+{
+ return (!strcmp(s, "openflow10") ? NXPIF_OPENFLOW10
+ : !strcmp(s, "nxm") ? NXPIF_NXM
+ : -1);
+}
+
static bool
regs_fully_wildcarded(const struct flow_wildcards *wc)
{
struct ofpbuf *
ofputil_make_set_flow_format(enum nx_flow_format flow_format)
{
- struct nxt_set_flow_format *sff;
+ struct nx_set_flow_format *sff;
struct ofpbuf *msg;
sff = make_nxmsg(sizeof *sff, NXT_SET_FLOW_FORMAT, &msg);
return msg;
}
+struct ofpbuf *
+ofputil_make_set_packet_in_format(enum nx_packet_in_format packet_in_format)
+{
+ struct nx_set_packet_in_format *spif;
+ struct ofpbuf *msg;
+
+ spif = make_nxmsg(sizeof *spif, NXT_SET_PACKET_IN_FORMAT, &msg);
+ spif->format = htonl(packet_in_format);
+
+ return msg;
+}
+
/* Returns an OpenFlow message that can be used to turn the flow_mod_table_id
* extension on or off (according to 'flow_mod_table_id'). */
struct ofpbuf *
ofputil_make_flow_mod_table_id(bool flow_mod_table_id)
{
- struct nxt_flow_mod_table_id *nfmti;
+ struct nx_flow_mod_table_id *nfmti;
struct ofpbuf *msg;
nfmti = make_nxmsg(sizeof *nfmti, NXT_FLOW_MOD_TABLE_ID, &msg);
pin->packet_len = ntohs(opi->header.length)
- offsetof(struct ofp_packet_in, data);
- pin->in_port = ntohs(opi->in_port);
+ pin->fmd.in_port = ntohs(opi->in_port);
pin->reason = opi->reason;
pin->buffer_id = ntohl(opi->buffer_id);
pin->total_len = ntohs(opi->total_len);
+ } else if (code == OFPUTIL_NXT_PACKET_IN) {
+ const struct nx_packet_in *npi;
+ struct cls_rule rule;
+ struct ofpbuf b;
+ int error;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+
+ npi = ofpbuf_pull(&b, sizeof *npi);
+ error = nx_pull_match_loose(&b, ntohs(npi->match_len), 0, &rule, NULL,
+ NULL);
+ if (error) {
+ return error;
+ }
+
+ if (!ofpbuf_try_pull(&b, 2)) {
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
+ }
+
+ pin->packet = b.data;
+ pin->packet_len = b.size;
+ pin->reason = npi->reason;
+ pin->table_id = npi->table_id;
+ pin->cookie = npi->cookie;
+
+ pin->fmd.in_port = rule.flow.in_port;
+
+ pin->fmd.tun_id = rule.flow.tun_id;
+ pin->fmd.tun_id_mask = rule.wc.tun_id_mask;
+
+ memcpy(pin->fmd.regs, rule.flow.regs, sizeof pin->fmd.regs);
+ memcpy(pin->fmd.reg_masks, rule.wc.reg_masks,
+ sizeof pin->fmd.reg_masks);
+
+ pin->buffer_id = ntohl(npi->buffer_id);
+ pin->total_len = ntohs(npi->total_len);
} else {
NOT_REACHED();
}
return 0;
}
-/* Converts abstract ofputil_packet_in 'pin' into an OFPT_PACKET_IN message
- * and returns the message. */
+/* Converts abstract ofputil_packet_in 'pin' into a PACKET_IN message
+ * in the format specified by 'packet_in_format'. */
struct ofpbuf *
-ofputil_encode_packet_in(const struct ofputil_packet_in *pin)
+ofputil_encode_packet_in(const struct ofputil_packet_in *pin,
+ enum nx_packet_in_format packet_in_format)
{
- struct ofp_packet_in opi;
- struct ofpbuf *rw_packet;
-
- rw_packet = ofpbuf_clone_data_with_headroom(
- pin->packet, MIN(pin->send_len, pin->packet_len),
- offsetof(struct ofp_packet_in, data));
+ size_t send_len = MIN(pin->send_len, pin->packet_len);
+ struct ofpbuf *packet;
/* Add OFPT_PACKET_IN. */
- memset(&opi, 0, sizeof opi);
- opi.header.version = OFP_VERSION;
- opi.header.type = OFPT_PACKET_IN;
- opi.total_len = htons(pin->packet_len);
- opi.in_port = htons(pin->in_port);
- opi.reason = pin->reason;
- opi.buffer_id = htonl(pin->buffer_id);
- ofpbuf_push(rw_packet, &opi, offsetof(struct ofp_packet_in, data));
- update_openflow_length(rw_packet);
-
- return rw_packet;
+ if (packet_in_format == NXPIF_OPENFLOW10) {
+ size_t header_len = offsetof(struct ofp_packet_in, data);
+ struct ofp_packet_in *opi;
+
+ packet = ofpbuf_new(send_len + header_len);
+ opi = ofpbuf_put_zeros(packet, header_len);
+ opi->header.version = OFP_VERSION;
+ opi->header.type = OFPT_PACKET_IN;
+ opi->total_len = htons(pin->total_len);
+ opi->in_port = htons(pin->fmd.in_port);
+ opi->reason = pin->reason;
+ opi->buffer_id = htonl(pin->buffer_id);
+
+ ofpbuf_put(packet, pin->packet, send_len);
+ } else if (packet_in_format == NXPIF_NXM) {
+ struct nx_packet_in *npi;
+ struct cls_rule rule;
+ size_t match_len;
+ size_t i;
+
+ /* Estimate of required PACKET_IN length includes the NPI header, space
+ * for the match (2 times sizeof the metadata seems like enough), 2
+ * bytes for padding, and the packet length. */
+ packet = ofpbuf_new(sizeof *npi + sizeof(struct flow_metadata) * 2
+ + 2 + send_len);
+
+ cls_rule_init_catchall(&rule, 0);
+ cls_rule_set_tun_id_masked(&rule, pin->fmd.tun_id,
+ pin->fmd.tun_id_mask);
+
+ for (i = 0; i < FLOW_N_REGS; i++) {
+ cls_rule_set_reg_masked(&rule, i, pin->fmd.regs[i],
+ pin->fmd.reg_masks[i]);
+ }
+
+ cls_rule_set_in_port(&rule, pin->fmd.in_port);
+
+ ofpbuf_put_zeros(packet, sizeof *npi);
+ match_len = nx_put_match(packet, &rule, 0, 0);
+ ofpbuf_put_zeros(packet, 2);
+ ofpbuf_put(packet, pin->packet, send_len);
+
+ npi = packet->data;
+ npi->nxh.header.version = OFP_VERSION;
+ npi->nxh.header.type = OFPT_VENDOR;
+ npi->nxh.vendor = htonl(NX_VENDOR_ID);
+ npi->nxh.subtype = htonl(NXT_PACKET_IN);
+
+ npi->buffer_id = htonl(pin->buffer_id);
+ npi->total_len = htons(pin->total_len);
+ npi->reason = pin->reason;
+ npi->table_id = pin->table_id;
+ npi->cookie = pin->cookie;
+ npi->match_len = htons(match_len);
+ } else {
+ NOT_REACHED();
+ }
+ update_openflow_length(packet);
+
+ return packet;
}
/* Returns a string representing the message type of 'type'. The string is the