#include "ofp-print.h"
#include <inttypes.h>
#include <stdlib.h>
+#include "byte-order.h"
#include "ofp-util.h"
#include "ofpbuf.h"
#include "packets.h"
#include "random.h"
-#include "xtoxll.h"
-
-#define THIS_MODULE VLM_ofp_util
#include "vlog.h"
+VLOG_DEFINE_THIS_MODULE(ofp_util);
+
/* Rate limit for OpenFlow message parse errors. These always indicate a bug
* in the peer and so there's not much point in showing a lot of them. */
static struct vlog_rate_limit bad_ofmsg_rl = VLOG_RATE_LIMIT_INIT(1, 5);
/* Updates the 'length' field of the OpenFlow message in 'buffer' to
* 'buffer->size'. */
void
-update_openflow_length(struct ofpbuf *buffer)
+update_openflow_length(struct ofpbuf *buffer)
{
struct ofp_header *oh = ofpbuf_at_assert(buffer, 0, sizeof *oh);
- oh->length = htons(buffer->size);
+ oh->length = htons(buffer->size);
}
struct ofpbuf *
-make_flow_mod(uint16_t command, const flow_t *flow, size_t actions_len)
+make_flow_mod(uint16_t command, const struct flow *flow, size_t actions_len)
{
struct ofp_flow_mod *ofm;
size_t size = sizeof *ofm + actions_len;
}
struct ofpbuf *
-make_add_flow(const flow_t *flow, uint32_t buffer_id,
+make_add_flow(const struct flow *flow, uint32_t buffer_id,
uint16_t idle_timeout, size_t actions_len)
{
struct ofpbuf *out = make_flow_mod(OFPFC_ADD, flow, actions_len);
}
struct ofpbuf *
-make_del_flow(const flow_t *flow)
+make_del_flow(const struct flow *flow)
{
struct ofpbuf *out = make_flow_mod(OFPFC_DELETE_STRICT, flow, 0);
struct ofp_flow_mod *ofm = out->data;
}
struct ofpbuf *
-make_add_simple_flow(const flow_t *flow,
+make_add_simple_flow(const struct flow *flow,
uint32_t buffer_id, uint16_t out_port,
uint16_t idle_timeout)
{
}
static int
-check_message_type(uint8_t got_type, uint8_t want_type)
+check_message_type(uint8_t got_type, uint8_t want_type)
{
if (got_type != want_type) {
char *want_type_name = ofp_message_type_to_string(want_type);
switch (ntohs(nah->subtype)) {
case NXAST_RESUBMIT:
case NXAST_SET_TUNNEL:
+ case NXAST_DROP_SPOOFED_ARP:
+ case NXAST_SET_QUEUE:
+ case NXAST_POP_QUEUE:
return check_action_exact_len(a, len, 16);
default:
return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR_TYPE);
return check_output_port(ntohs(a->output.port), max_ports);
case OFPAT_SET_VLAN_VID:
+ error = check_action_exact_len(a, len, 8);
+ if (error) {
+ return error;
+ }
+ if (a->vlan_vid.vlan_vid & ~htons(0xfff)) {
+ return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
+ }
+ return 0;
+
case OFPAT_SET_VLAN_PCP:
+ error = check_action_exact_len(a, len, 8);
+ if (error) {
+ return error;
+ }
+ if (a->vlan_vid.vlan_vid & ~7) {
+ return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
+ }
+ return 0;
+
case OFPAT_STRIP_VLAN:
case OFPAT_SET_NW_SRC:
case OFPAT_SET_NW_DST:
validate_actions(const union ofp_action *actions, size_t n_actions,
int max_ports)
{
- const union ofp_action *a;
+ size_t i;
- for (a = actions; a < &actions[n_actions]; ) {
+ for (i = 0; i < n_actions; ) {
+ const union ofp_action *a = &actions[i];
unsigned int len = ntohs(a->header.len);
unsigned int n_slots = len / ACTION_ALIGNMENT;
unsigned int slots_left = &actions[n_actions] - a;
if (error) {
return error;
}
- a += n_slots;
+ i += n_slots;
}
return 0;
}
const union ofp_action *
actions_next(struct actions_iterator *iter)
{
- if (iter->pos < iter->end) {
+ if (iter->pos != iter->end) {
const union ofp_action *a = iter->pos;
unsigned int len = ntohs(a->header.len);
iter->pos += len / ACTION_ALIGNMENT;
void
normalize_match(struct ofp_match *m)
{
- enum { OFPFW_NW = OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK | OFPFW_NW_PROTO };
+ enum { OFPFW_NW = (OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK | OFPFW_NW_PROTO
+ | OFPFW_NW_TOS) };
enum { OFPFW_TP = OFPFW_TP_SRC | OFPFW_TP_DST };
uint32_t wc;
ntohs(match->tp_src),
ntohs(match->tp_dst));
}
+
+static uint32_t
+vendor_code_to_id(uint8_t code)
+{
+ switch (code) {
+#define OFPUTIL_VENDOR(NAME, VENDOR_ID) case NAME: return VENDOR_ID;
+ default:
+ return UINT32_MAX;
+ }
+}
+
+/* Creates and returns an OpenFlow message of type OFPT_ERROR with the error
+ * information taken from 'error', whose encoding must be as described in the
+ * large comment in ofp-util.h. If 'oh' is nonnull, then the error will use
+ * oh->xid as its transaction ID, and it will include up to the first 64 bytes
+ * of 'oh'.
+ *
+ * Returns NULL if 'error' is not an OpenFlow error code. */
+struct ofpbuf *
+make_ofp_error_msg(int error, const struct ofp_header *oh)
+{
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+
+ struct ofpbuf *buf;
+ const void *data;
+ size_t len;
+ uint8_t vendor;
+ uint16_t type;
+ uint16_t code;
+ uint32_t xid;
+
+ if (!is_ofp_error(error)) {
+ /* We format 'error' with strerror() here since it seems likely to be
+ * a system errno value. */
+ VLOG_WARN_RL(&rl, "invalid OpenFlow error code %d (%s)",
+ error, strerror(error));
+ return NULL;
+ }
+
+ if (oh) {
+ xid = oh->xid;
+ data = oh;
+ len = ntohs(oh->length);
+ if (len > 64) {
+ len = 64;
+ }
+ } else {
+ xid = 0;
+ data = NULL;
+ len = 0;
+ }
+
+ vendor = get_ofp_err_vendor(error);
+ type = get_ofp_err_type(error);
+ code = get_ofp_err_code(error);
+ if (vendor == OFPUTIL_VENDOR_OPENFLOW) {
+ struct ofp_error_msg *oem;
+
+ oem = make_openflow_xid(len + sizeof *oem, OFPT_ERROR, xid, &buf);
+ oem->type = htons(type);
+ oem->code = htons(code);
+ } else {
+ struct ofp_error_msg *oem;
+ struct nx_vendor_error *ove;
+ uint32_t vendor_id;
+
+ vendor_id = vendor_code_to_id(vendor);
+ if (vendor_id == UINT32_MAX) {
+ VLOG_WARN_RL(&rl, "error %x contains invalid vendor code %d",
+ error, vendor);
+ return NULL;
+ }
+
+ oem = make_openflow_xid(len + sizeof *oem + sizeof *ove,
+ OFPT_ERROR, xid, &buf);
+ oem->type = htons(NXET_VENDOR);
+ oem->code = htons(NXVC_VENDOR_ERROR);
+
+ ove = ofpbuf_put_uninit(buf, sizeof *ove);
+ ove->vendor = htonl(vendor_id);
+ ove->type = htons(type);
+ ove->code = htons(code);
+ }
+
+ if (len) {
+ ofpbuf_put(buf, data, len);
+ }
+
+ return buf;
+}