#include "ofpbuf.h"
#include "packets.h"
#include "random.h"
-
-#define THIS_MODULE VLM_ofp_util
#include "vlog.h"
+#include "xtoxll.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. */
/* 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 *
uint32_t buffer_id, uint16_t out_port,
uint16_t idle_timeout)
{
- struct ofp_action_output *oao;
- struct ofpbuf *buffer = make_add_flow(flow, buffer_id, idle_timeout,
- sizeof *oao);
- oao = ofpbuf_put_zeros(buffer, sizeof *oao);
- oao->type = htons(OFPAT_OUTPUT);
- oao->len = htons(sizeof *oao);
- oao->port = htons(out_port);
- return buffer;
+ if (out_port != OFPP_NONE) {
+ struct ofp_action_output *oao;
+ struct ofpbuf *buffer;
+
+ buffer = make_add_flow(flow, buffer_id, idle_timeout, sizeof *oao);
+ oao = ofpbuf_put_zeros(buffer, sizeof *oao);
+ oao->type = htons(OFPAT_OUTPUT);
+ oao->len = htons(sizeof *oao);
+ oao->port = htons(out_port);
+ return buffer;
+ } else {
+ return make_add_flow(flow, buffer_id, idle_timeout, 0);
+ }
}
struct ofpbuf *
make_buffered_packet_out(uint32_t buffer_id,
uint16_t in_port, uint16_t out_port)
{
- struct ofp_action_output action;
- action.type = htons(OFPAT_OUTPUT);
- action.len = htons(sizeof action);
- action.port = htons(out_port);
- return make_packet_out(NULL, buffer_id, in_port,
- (struct ofp_action_header *) &action, 1);
+ if (out_port != OFPP_NONE) {
+ struct ofp_action_output action;
+ action.type = htons(OFPAT_OUTPUT);
+ action.len = htons(sizeof action);
+ action.port = htons(out_port);
+ return make_packet_out(NULL, buffer_id, in_port,
+ (struct ofp_action_header *) &action, 1);
+ } else {
+ return make_packet_out(NULL, buffer_id, in_port, NULL, 0);
+ }
}
/* Creates and returns an OFPT_ECHO_REQUEST message with an empty payload. */
}
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);
return 0;
}
+/* Checks that 'port' is a valid output port for the OFPAT_OUTPUT action, given
+ * that the switch will never have more than 'max_ports' ports. Returns 0 if
+ * 'port' is valid, otherwise an ofp_mkerr() return code. */
static int
-check_action_port(int port, int max_ports)
+check_output_port(uint16_t port, int max_ports)
{
switch (port) {
case OFPP_IN_PORT:
return 0;
default:
- if (port >= 0 && port < max_ports) {
+ if (port < max_ports) {
return 0;
}
VLOG_WARN_RL(&bad_ofmsg_rl, "unknown output port %x", port);
}
}
+/* Checks that 'action' is a valid OFPAT_ENQUEUE action, given that the switch
+ * will never have more than 'max_ports' ports. Returns 0 if 'port' is valid,
+ * otherwise an ofp_mkerr() return code. */
+static int
+check_enqueue_action(const union ofp_action *a, unsigned int len,
+ int max_ports)
+{
+ const struct ofp_action_enqueue *oae;
+ uint16_t port;
+ int error;
+
+ error = check_action_exact_len(a, len, 16);
+ if (error) {
+ return error;
+ }
+
+ oae = (const struct ofp_action_enqueue *) a;
+ port = ntohs(oae->port);
+ if (port < max_ports || port == OFPP_IN_PORT) {
+ return 0;
+ }
+ VLOG_WARN_RL(&bad_ofmsg_rl, "unknown enqueue port %x", port);
+ return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT);
+}
+
static int
check_nicira_action(const union ofp_action *a, unsigned int len)
{
switch (ntohs(nah->subtype)) {
case NXAST_RESUBMIT:
case NXAST_SET_TUNNEL:
+ case NXAST_DROP_SPOOFED_ARP:
return check_action_exact_len(a, len, 16);
default:
return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR_TYPE);
switch (ntohs(a->type)) {
case OFPAT_OUTPUT:
- error = check_action_port(ntohs(a->output.port), max_ports);
- return error ? error : check_action_exact_len(a, len, 8);
+ error = check_action_exact_len(a, len, 8);
+ if (error) {
+ return error;
+ }
+ return check_output_port(ntohs(a->output.port), max_ports);
case OFPAT_SET_VLAN_VID:
case OFPAT_SET_VLAN_PCP:
? check_nicira_action(a, len)
: ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR));
+ case OFPAT_ENQUEUE:
+ return check_enqueue_action(a, len, max_ports);
+
default:
VLOG_WARN_RL(&bad_ofmsg_rl, "unknown action type %"PRIu16,
ntohs(a->type));
return 0;
}
+/* Returns true if 'action' outputs to 'port' (which must be in network byte
+ * order), false otherwise. */
+bool
+action_outputs_to_port(const union ofp_action *action, uint16_t port)
+{
+ switch (ntohs(action->type)) {
+ case OFPAT_OUTPUT:
+ return action->output.port == port;
+ case OFPAT_ENQUEUE:
+ return ((const struct ofp_action_enqueue *) action)->port == port;
+ default:
+ return false;
+ }
+}
+
/* The set of actions must either come from a trusted source or have been
* previously validated with validate_actions(). */
const union ofp_action *
/* Can't sensibly match on network or transport headers if the
* data link type is unknown. */
wc |= OFPFW_NW | OFPFW_TP;
- m->nw_src = m->nw_dst = m->nw_proto = 0;
+ m->nw_src = m->nw_dst = m->nw_proto = m->nw_tos = 0;
m->tp_src = m->tp_dst = 0;
} else if (m->dl_type == htons(ETH_TYPE_IP)) {
if (wc & OFPFW_NW_PROTO) {
if (wc & OFPFW_NW_DST_MASK) {
m->nw_dst &= flow_nw_bits_to_mask(wc, OFPFW_NW_DST_SHIFT);
}
+ if (wc & OFPFW_NW_TOS) {
+ m->nw_tos = 0;
+ } else {
+ m->nw_tos &= IP_DSCP_MASK;
+ }
} else if (m->dl_type == htons(ETH_TYPE_ARP)) {
if (wc & OFPFW_NW_PROTO) {
m->nw_proto = 0;
if (wc & OFPFW_NW_DST_MASK) {
m->nw_dst &= flow_nw_bits_to_mask(wc, OFPFW_NW_DST_SHIFT);
}
- m->tp_src = m->tp_dst = 0;
+ m->tp_src = m->tp_dst = m->nw_tos = 0;
} else {
/* Network and transport layer fields will always be extracted as
* zeros, so we can do an exact-match on those values. */
wc &= ~(OFPFW_NW | OFPFW_TP);
- m->nw_proto = m->nw_src = m->nw_dst = 0;
+ m->nw_proto = m->nw_src = m->nw_dst = m->nw_tos = 0;
m->tp_src = m->tp_dst = 0;
}
if (wc & OFPFW_DL_SRC) {
m->wildcards = htonl(wc);
}
+/* Returns a string that describes 'match' in a very literal way, without
+ * interpreting its contents except in a very basic fashion. The returned
+ * string is intended to be fixed-length, so that it is easy to see differences
+ * between two such strings if one is put above another. This is useful for
+ * describing changes made by normalize_match().
+ *
+ * The caller must free the returned string (with free()). */
+char *
+ofp_match_to_literal_string(const struct ofp_match *match)
+{
+ return xasprintf("wildcards=%#10"PRIx32" "
+ " in_port=%5"PRId16" "
+ " dl_src="ETH_ADDR_FMT" "
+ " dl_dst="ETH_ADDR_FMT" "
+ " dl_vlan=%5"PRId16" "
+ " dl_vlan_pcp=%3"PRId8" "
+ " dl_type=%#6"PRIx16" "
+ " nw_tos=%#4"PRIx8" "
+ " nw_proto=%#4"PRIx16" "
+ " nw_src=%#10"PRIx32" "
+ " nw_dst=%#10"PRIx32" "
+ " tp_src=%5"PRId16" "
+ " tp_dst=%5"PRId16,
+ ntohl(match->wildcards),
+ ntohs(match->in_port),
+ ETH_ADDR_ARGS(match->dl_src),
+ ETH_ADDR_ARGS(match->dl_dst),
+ ntohs(match->dl_vlan),
+ match->dl_vlan_pcp,
+ ntohs(match->dl_type),
+ match->nw_tos,
+ match->nw_proto,
+ ntohl(match->nw_src),
+ ntohl(match->nw_dst),
+ ntohs(match->tp_src),
+ ntohs(match->tp_dst));
+}