/* Why is this packet being sent to the controller? */
enum ofp_packet_in_reason {
+ /* Standard reasons. */
OFPR_NO_MATCH, /* No matching flow. */
OFPR_ACTION, /* Action explicitly output to controller. */
OFPR_INVALID_TTL, /* Packet has invalid TTL. */
(OFPR10_BITS | \
(1u << OFPR_ACTION_SET) | (1u << OFPR_GROUP) | (1u << OFPR_PACKET_OUT))
+ /* Nonstandard reason--not exposed via OpenFlow. */
+ OFPR_EXPLICIT_MISS,
+ OFPR_IMPLICIT_MISS,
+
OFPR_N_REASONS
};
process_packet_in(struct lswitch *sw, const struct ofp_header *oh)
{
struct ofputil_packet_in pi;
+ size_t total_len;
+ uint32_t buffer_id;
uint32_t queue_id;
ofp_port_t out_port;
struct dp_packet pkt;
struct flow flow;
- error = ofputil_decode_packet_in(&pi, oh);
+ error = ofputil_decode_packet_in(oh, &pi, &total_len, &buffer_id);
if (error) {
VLOG_WARN_RL(&rl, "failed to decode packet-in: %s",
ofperr_to_string(error));
return;
}
- /* Extract flow data from 'opi' into 'flow'. */
- dp_packet_use_const(&pkt, pi.packet, pi.packet_len);
+ /* Extract flow data from 'pi' into 'flow'. */
+ dp_packet_use_const(&pkt, pi.packet, pi.len);
flow_extract(&pkt, &flow);
flow.in_port.ofp_port = pi.flow_metadata.flow.in_port.ofp_port;
flow.tunnel.tun_id = pi.flow_metadata.flow.tunnel.tun_id;
}
/* Prepare packet_out in case we need one. */
- po.buffer_id = pi.buffer_id;
- if (po.buffer_id == UINT32_MAX) {
+ po.buffer_id = buffer_id;
+ if (buffer_id == UINT32_MAX) {
po.packet = dp_packet_data(&pkt);
po.packet_len = dp_packet_size(&pkt);
} else {
.table_id = 0xff,
.command = OFPFC_ADD,
.idle_timeout = sw->max_idle,
- .buffer_id = pi.buffer_id,
+ .buffer_id = buffer_id,
.out_port = OFPP_NONE,
.ofpacts = ofpacts.data,
.ofpacts_len = ofpacts.size,
queue_tx(sw, buffer);
/* If the switch didn't buffer the packet, we need to send a copy. */
- if (pi.buffer_id == UINT32_MAX && out_port != OFPP_NONE) {
+ if (buffer_id == UINT32_MAX && out_port != OFPP_NONE) {
queue_tx(sw, ofputil_encode_packet_out(&po, sw->protocol));
}
} else {
/* We don't know that MAC, or we don't set up flows. Send along the
* packet without setting up a flow. */
- if (pi.buffer_id != UINT32_MAX || out_port != OFPP_NONE) {
+ if (buffer_id != UINT32_MAX || out_port != OFPP_NONE) {
queue_tx(sw, ofputil_encode_packet_out(&po, sw->protocol));
}
}
{
char reasonbuf[OFPUTIL_PACKET_IN_REASON_BUFSIZE];
struct ofputil_packet_in pin;
+ uint32_t buffer_id;
+ size_t total_len;
int error;
- error = ofputil_decode_packet_in(&pin, oh);
+ error = ofputil_decode_packet_in(oh, &pin, &total_len, &buffer_id);
if (error) {
ofp_print_error(string, error);
return;
ds_put_format(string, " cookie=0x%"PRIx64, ntohll(pin.cookie));
}
- ds_put_format(string, " total_len=%"PRIuSIZE" ", pin.total_len);
+ ds_put_format(string, " total_len=%"PRIuSIZE" ", total_len);
match_format(&pin.flow_metadata, string, OFP_DEFAULT_PRIORITY);
ds_put_format(string, " (via %s)",
- ofputil_packet_in_reason_to_string(pin.reason, reasonbuf,
+ ofputil_packet_in_reason_to_string(pin.reason,
+ reasonbuf,
sizeof reasonbuf));
- ds_put_format(string, " data_len=%"PRIuSIZE, pin.packet_len);
- if (pin.buffer_id == UINT32_MAX) {
+ ds_put_format(string, " data_len=%"PRIuSIZE, pin.len);
+ if (buffer_id == UINT32_MAX) {
ds_put_format(string, " (unbuffered)");
- if (pin.total_len != pin.packet_len) {
+ if (total_len != pin.len) {
ds_put_format(string, " (***total_len != data_len***)");
}
} else {
- ds_put_format(string, " buffer=0x%08"PRIx32, pin.buffer_id);
- if (pin.total_len < pin.packet_len) {
+ ds_put_format(string, " buffer=0x%08"PRIx32, buffer_id);
+ if (total_len < pin.len) {
ds_put_format(string, " (***total_len < data_len***)");
}
}
ds_put_char(string, '\n');
if (verbosity > 0) {
- char *packet = ofp_packet_to_string(pin.packet, pin.packet_len);
+ char *packet = ofp_packet_to_string(pin.packet, pin.len);
ds_put_cstr(string, packet);
free(packet);
}
if (verbosity > 2) {
- ds_put_hex_dump(string, pin.packet, pin.packet_len, 0, false);
+ ds_put_hex_dump(string, pin.packet, pin.len, 0, false);
}
}
reason = ofp_async_config_reason_to_string(
j, type, reasonbuf, sizeof reasonbuf);
- ds_put_format(string, " %s", reason);
+ if (reason[0]) {
+ ds_put_format(string, " %s", reason);
+ }
}
}
if (!role) {
#include "ofpbuf.h"
#include "openflow/netronome-ext.h"
#include "packets.h"
+#include "pktbuf.h"
#include "random.h"
#include "tun-metadata.h"
#include "unaligned.h"
return msg;
}
+/* Decodes the packet-in message starting at 'oh' into '*pin'. Populates
+ * 'pin->packet' and 'pin->len' with the part of the packet actually included
+ * in the message, and '*total_len' with the original length of the packet
+ * (which is larger than 'packet->len' if only part of the packet was
+ * included). Stores the packet's buffer ID in '*buffer_id' (UINT32_MAX if it
+ * was not buffered).
+ *
+ * Returns 0 if successful, otherwise an OpenFlow error code. */
enum ofperr
-ofputil_decode_packet_in(struct ofputil_packet_in *pin,
- const struct ofp_header *oh)
+ofputil_decode_packet_in(const struct ofp_header *oh,
+ struct ofputil_packet_in *pin,
+ size_t *total_len, uint32_t *buffer_id)
{
enum ofpraw raw;
struct ofpbuf b;
pin->reason = opi->reason;
pin->table_id = opi->table_id;
- pin->buffer_id = ntohl(opi->buffer_id);
- pin->total_len = ntohs(opi->total_len);
-
+ *buffer_id = ntohl(opi->buffer_id);
+ *total_len = ntohs(opi->total_len);
if (cookie) {
pin->cookie = *cookie;
}
pin->packet = b.data;
- pin->packet_len = b.size;
+ pin->len = b.size;
} else if (raw == OFPRAW_OFPT10_PACKET_IN) {
const struct ofp10_packet_in *opi;
opi = ofpbuf_pull(&b, offsetof(struct ofp10_packet_in, data));
pin->packet = opi->data;
- pin->packet_len = b.size;
+ pin->len = b.size;
match_init_catchall(&pin->flow_metadata);
- match_set_in_port(&pin->flow_metadata, u16_to_ofp(ntohs(opi->in_port)));
+ match_set_in_port(&pin->flow_metadata,
+ u16_to_ofp(ntohs(opi->in_port)));
pin->reason = opi->reason;
- pin->buffer_id = ntohl(opi->buffer_id);
- pin->total_len = ntohs(opi->total_len);
+ *buffer_id = ntohl(opi->buffer_id);
+ *total_len = ntohs(opi->total_len);
} else if (raw == OFPRAW_OFPT11_PACKET_IN) {
const struct ofp11_packet_in *opi;
ofp_port_t in_port;
opi = ofpbuf_pull(&b, sizeof *opi);
pin->packet = b.data;
- pin->packet_len = b.size;
+ pin->len = b.size;
- pin->buffer_id = ntohl(opi->buffer_id);
+ *buffer_id = ntohl(opi->buffer_id);
error = ofputil_port_from_ofp11(opi->in_port, &in_port);
if (error) {
return error;
}
match_init_catchall(&pin->flow_metadata);
match_set_in_port(&pin->flow_metadata, in_port);
- pin->total_len = ntohs(opi->total_len);
+ *total_len = ntohs(opi->total_len);
pin->reason = opi->reason;
pin->table_id = opi->table_id;
} else if (raw == OFPRAW_NXT_PACKET_IN) {
pin->table_id = npi->table_id;
pin->cookie = npi->cookie;
- pin->buffer_id = ntohl(npi->buffer_id);
- pin->total_len = ntohs(npi->total_len);
+ *buffer_id = ntohl(npi->buffer_id);
+ *total_len = ntohs(npi->total_len);
pin->packet = b.data;
- pin->packet_len = b.size;
+ pin->len = b.size;
} else {
OVS_NOT_REACHED();
}
return 0;
}
+static int
+encode_packet_in_reason(enum ofp_packet_in_reason reason,
+ enum ofp_version version)
+{
+ switch (reason) {
+ case OFPR_NO_MATCH:
+ case OFPR_ACTION:
+ case OFPR_INVALID_TTL:
+ return reason;
+
+ case OFPR_ACTION_SET:
+ case OFPR_GROUP:
+ case OFPR_PACKET_OUT:
+ return version < OFP14_VERSION ? OFPR_ACTION : reason;
+
+ case OFPR_EXPLICIT_MISS:
+ return version < OFP13_VERSION ? OFPR_ACTION : OFPR_NO_MATCH;
+
+ case OFPR_IMPLICIT_MISS:
+ return OFPR_NO_MATCH;
+
+ case OFPR_N_REASONS:
+ default:
+ OVS_NOT_REACHED();
+ }
+}
+
static struct ofpbuf *
-ofputil_encode_ofp10_packet_in(const struct ofputil_packet_in *pin)
+ofputil_encode_ofp10_packet_in(const struct ofputil_packet_in *pin,
+ uint32_t buffer_id)
{
struct ofp10_packet_in *opi;
- struct ofpbuf *packet;
+ struct ofpbuf *msg;
- packet = ofpraw_alloc_xid(OFPRAW_OFPT10_PACKET_IN, OFP10_VERSION,
- htonl(0), pin->packet_len);
- opi = ofpbuf_put_zeros(packet, offsetof(struct ofp10_packet_in, data));
- opi->total_len = htons(pin->total_len);
+ msg = ofpraw_alloc_xid(OFPRAW_OFPT10_PACKET_IN, OFP10_VERSION,
+ htonl(0), pin->len);
+ opi = ofpbuf_put_zeros(msg, offsetof(struct ofp10_packet_in, data));
+ opi->total_len = htons(pin->len);
opi->in_port = htons(ofp_to_u16(pin->flow_metadata.flow.in_port.ofp_port));
- opi->reason = pin->reason;
- opi->buffer_id = htonl(pin->buffer_id);
-
- ofpbuf_put(packet, pin->packet, pin->packet_len);
+ opi->reason = encode_packet_in_reason(pin->reason, OFP10_VERSION);
+ opi->buffer_id = htonl(buffer_id);
- return packet;
+ return msg;
}
static struct ofpbuf *
-ofputil_encode_nx_packet_in(const struct ofputil_packet_in *pin)
+ofputil_encode_nx_packet_in(const struct ofputil_packet_in *pin,
+ uint32_t buffer_id)
{
struct nx_packet_in *npi;
- struct ofpbuf *packet;
+ struct ofpbuf *msg;
size_t match_len;
/* The final argument is just an estimate of the space required. */
- packet = ofpraw_alloc_xid(OFPRAW_NXT_PACKET_IN, OFP10_VERSION,
- htonl(0), NXM_TYPICAL_LEN + 2 + pin->packet_len);
- ofpbuf_put_zeros(packet, sizeof *npi);
- match_len = nx_put_match(packet, &pin->flow_metadata, 0, 0);
- ofpbuf_put_zeros(packet, 2);
- ofpbuf_put(packet, pin->packet, pin->packet_len);
-
- npi = packet->msg;
- npi->buffer_id = htonl(pin->buffer_id);
- npi->total_len = htons(pin->total_len);
- npi->reason = pin->reason;
+ msg = ofpraw_alloc_xid(OFPRAW_NXT_PACKET_IN, OFP10_VERSION,
+ htonl(0), NXM_TYPICAL_LEN + 2 + pin->len);
+ ofpbuf_put_zeros(msg, sizeof *npi);
+ match_len = nx_put_match(msg, &pin->flow_metadata, 0, 0);
+ ofpbuf_put_zeros(msg, 2);
+
+ npi = msg->msg;
+ npi->buffer_id = htonl(buffer_id);
+ npi->total_len = htons(pin->len);
+ npi->reason = encode_packet_in_reason(pin->reason, OFP10_VERSION);
npi->table_id = pin->table_id;
npi->cookie = pin->cookie;
npi->match_len = htons(match_len);
- return packet;
+ return msg;
}
static struct ofpbuf *
-ofputil_encode_ofp11_packet_in(const struct ofputil_packet_in *pin)
+ofputil_encode_ofp11_packet_in(const struct ofputil_packet_in *pin,
+ uint32_t buffer_id)
{
struct ofp11_packet_in *opi;
- struct ofpbuf *packet;
+ struct ofpbuf *msg;
- packet = ofpraw_alloc_xid(OFPRAW_OFPT11_PACKET_IN, OFP11_VERSION,
- htonl(0), pin->packet_len);
- opi = ofpbuf_put_zeros(packet, sizeof *opi);
- opi->buffer_id = htonl(pin->buffer_id);
- opi->in_port = ofputil_port_to_ofp11(pin->flow_metadata.flow.in_port.ofp_port);
+ msg = ofpraw_alloc_xid(OFPRAW_OFPT11_PACKET_IN, OFP11_VERSION,
+ htonl(0), pin->len);
+ opi = ofpbuf_put_zeros(msg, sizeof *opi);
+ opi->buffer_id = htonl(buffer_id);
+ opi->in_port = ofputil_port_to_ofp11(
+ pin->flow_metadata.flow.in_port.ofp_port);
opi->in_phy_port = opi->in_port;
- opi->total_len = htons(pin->total_len);
- opi->reason = pin->reason;
+ opi->total_len = htons(pin->len);
+ opi->reason = encode_packet_in_reason(pin->reason, OFP11_VERSION);
opi->table_id = pin->table_id;
- ofpbuf_put(packet, pin->packet, pin->packet_len);
-
- return packet;
+ return msg;
}
static struct ofpbuf *
ofputil_encode_ofp12_packet_in(const struct ofputil_packet_in *pin,
- enum ofputil_protocol protocol)
+ enum ofp_version version,
+ uint32_t buffer_id)
{
- enum ofp_version version = ofputil_protocol_to_ofp_version(protocol);
enum ofpraw raw = (version >= OFP13_VERSION
? OFPRAW_OFPT13_PACKET_IN
: OFPRAW_OFPT12_PACKET_IN);
/* The final argument is just an estimate of the space required. */
msg = ofpraw_alloc_xid(raw, version,
- htonl(0), NXM_TYPICAL_LEN + 2 + pin->packet_len);
+ htonl(0), NXM_TYPICAL_LEN + 2 + pin->len);
struct ofp12_packet_in *opi = ofpbuf_put_zeros(msg, sizeof *opi);
- opi->buffer_id = htonl(pin->buffer_id);
- opi->total_len = htons(pin->total_len);
- opi->reason = pin->reason;
+ opi->buffer_id = htonl(buffer_id);
+ opi->total_len = htons(pin->len);
+ opi->reason = encode_packet_in_reason(pin->reason, version);
opi->table_id = pin->table_id;
+
if (version >= OFP13_VERSION) {
ovs_be64 cookie = pin->cookie;
ofpbuf_put(msg, &cookie, sizeof cookie);
oxm_put_match(msg, &pin->flow_metadata, version);
ofpbuf_put_zeros(msg, 2);
- ofpbuf_put(msg, pin->packet, pin->packet_len);
return msg;
}
-/* Converts abstract ofputil_packet_in 'pin' into a PACKET_IN message
- * in the format specified by 'packet_in_format'. */
+/* Converts abstract ofputil_packet_in 'pin' into a PACKET_IN message for
+ * 'protocol', using the packet-in format specified by 'packet_in_format'.
+ *
+ * If 'pkt_buf' is nonnull and 'max_len' allows the packet to be buffered, this
+ * function will attempt to obtain a buffer ID from 'pktbuf' and truncate the
+ * packet to 'max_len' bytes. Otherwise, or if 'pktbuf' doesn't have a free
+ * buffer, it will send the whole packet without buffering. */
struct ofpbuf *
ofputil_encode_packet_in(const struct ofputil_packet_in *pin,
enum ofputil_protocol protocol,
- enum nx_packet_in_format packet_in_format)
+ enum nx_packet_in_format packet_in_format,
+ uint16_t max_len, struct pktbuf *pktbuf)
{
- struct ofpbuf *packet;
+ enum ofp_version version = ofputil_protocol_to_ofp_version(protocol);
+
+ /* Get buffer ID. */
+ ofp_port_t in_port = pin->flow_metadata.flow.in_port.ofp_port;
+ uint32_t buffer_id = (max_len != OFPCML12_NO_BUFFER && pktbuf
+ ? pktbuf_save(pktbuf, pin->packet,
+ pin->len, in_port)
+ : UINT32_MAX);
+ struct ofpbuf *msg;
switch (protocol) {
case OFPUTIL_P_OF10_STD:
case OFPUTIL_P_OF10_STD_TID:
case OFPUTIL_P_OF10_NXM:
case OFPUTIL_P_OF10_NXM_TID:
- packet = (packet_in_format == NXPIF_NXM
- ? ofputil_encode_nx_packet_in(pin)
- : ofputil_encode_ofp10_packet_in(pin));
+ msg = (packet_in_format == NXPIF_NXM
+ ? ofputil_encode_nx_packet_in(pin, buffer_id)
+ : ofputil_encode_ofp10_packet_in(pin, buffer_id));
break;
case OFPUTIL_P_OF11_STD:
- packet = ofputil_encode_ofp11_packet_in(pin);
+ msg = ofputil_encode_ofp11_packet_in(pin, buffer_id);
break;
case OFPUTIL_P_OF12_OXM:
case OFPUTIL_P_OF13_OXM:
case OFPUTIL_P_OF14_OXM:
case OFPUTIL_P_OF15_OXM:
- packet = ofputil_encode_ofp12_packet_in(pin, protocol);
+ msg = ofputil_encode_ofp12_packet_in(pin, version, buffer_id);
break;
default:
OVS_NOT_REACHED();
}
- ofpmsg_update_length(packet);
- return packet;
+ /* Append some of the packet:
+ *
+ * - If not buffered, the whole thing.
+ *
+ * - Otherwise, no more than 'max_len' bytes. */
+ ofpbuf_put(msg, pin->packet,
+ (buffer_id == UINT32_MAX
+ ? pin->len
+ : MIN(max_len, pin->len)));
+
+ ofpmsg_update_length(msg);
+ return msg;
}
/* Returns a string form of 'reason'. The return value is either a statically
return "group";
case OFPR_PACKET_OUT:
return "packet_out";
+ case OFPR_EXPLICIT_MISS:
+ case OFPR_IMPLICIT_MISS:
+ return "";
case OFPR_N_REASONS:
default:
}
}
+ if (ap->oam == OAM_PACKET_IN) {
+ if (mask & (1u << OFPR_NO_MATCH)) {
+ mask |= 1u << OFPR_EXPLICIT_MISS;
+ if (version < OFP13_VERSION) {
+ mask |= 1u << OFPR_IMPLICIT_MISS;
+ }
+ }
+ }
+
uint32_t *array = ap->master ? dst->master : dst->slave;
array[ap->oam] = mask;
return 0;
struct ofputil_async_cfg
ofputil_async_cfg_default(enum ofp_version version)
{
+ /* We enable all of the OF1.4 reasons regardless of 'version' because the
+ * reasons added in OF1.4 just are just refinements of the OFPR_ACTION
+ * introduced in OF1.0, breaking it into more specific categories. When we
+ * encode these for earlier OpenFlow versions, we translate them into
+ * OFPR_ACTION. */
+ uint32_t pin = OFPR14_BITS & ~(1u << OFPR_INVALID_TTL);
+ pin |= 1u << OFPR_EXPLICIT_MISS;
+ if (version <= OFP12_VERSION) {
+ pin |= 1u << OFPR_IMPLICIT_MISS;
+ }
+
return (struct ofputil_async_cfg) {
- .master[OAM_PACKET_IN]
- = ((version >= OFP14_VERSION ? OFPR14_BITS : OFPR10_BITS)
- & ~(1u << OFPR_INVALID_TTL)),
+ .master[OAM_PACKET_IN] = pin,
.master[OAM_FLOW_REMOVED]
= (version >= OFP14_VERSION ? OFPRR14_BITS : OFPRR10_BITS),
struct ofpbuf;
union ofp_action;
struct ofpact_set_field;
+struct pktbuf;
/* Port numbers. */
enum ofperr ofputil_port_from_ofp11(ovs_be32 ofp11_port,
struct ofpbuf *ofputil_encode_flow_removed(const struct ofputil_flow_removed *,
enum ofputil_protocol);
-/* Abstract packet-in message. */
+/* Abstract packet-in message.
+ *
+ * This omits the 'total_len' and 'buffer_id' fields, which we handle
+ * differently for encoding and decoding.*/
struct ofputil_packet_in {
/* Packet data and metadata.
*
- * To save bandwidth, in some cases a switch may send only the first
- * several bytes of a packet, indicated by 'packet_len < total_len'. When
- * the full packet is included, 'packet_len == total_len'. */
- const void *packet;
- size_t packet_len; /* Number of bytes in 'packet'. */
- size_t total_len; /* Size of packet, pre-truncation. */
- struct match flow_metadata;
-
- /* Identifies a buffer in the switch that contains the full packet, to
- * allow the controller to reference it later without having to send the
- * entire packet back to the switch.
+ * On encoding, the full packet should be supplied, but depending on its
+ * other parameters ofputil_encode_packet_in() might send only the first
+ * part of the packet.
*
- * UINT32_MAX indicates that the packet is not buffered in the switch. A
- * switch should only use UINT32_MAX when it sends the entire packet. */
- uint32_t buffer_id;
+ * On decoding, the 'len' bytes in 'packet' might only be the first part of
+ * the original packet. ofputil_decode_packet_in() reports the full
+ * original length of the packet using its 'total_len' output parameter. */
+ const void *packet; /* The packet. */
+ size_t len; /* Length of 'packet' in bytes. */
+
+ /* Input port and other metadata for packet. */
+ struct match flow_metadata;
/* Reason that the packet-in is being sent. */
enum ofp_packet_in_reason reason; /* One of OFPR_*. */
ovs_be64 cookie; /* Flow's cookie. */
};
-enum ofperr ofputil_decode_packet_in(struct ofputil_packet_in *,
- const struct ofp_header *);
struct ofpbuf *ofputil_encode_packet_in(const struct ofputil_packet_in *,
enum ofputil_protocol protocol,
- enum nx_packet_in_format);
+ enum nx_packet_in_format,
+ uint16_t max_len, struct pktbuf *);
+
+enum ofperr ofputil_decode_packet_in(const struct ofp_header *,
+ struct ofputil_packet_in *,
+ size_t *total_len, uint32_t *buffer_id);
enum { OFPUTIL_PACKET_IN_REASON_BUFSIZE = INT_STRLEN(int) + 1 };
const char *ofputil_packet_in_reason_to_string(enum ofp_packet_in_reason,
return (masks[type] & (1u << reason)) != 0;
}
-/* The default "table-miss" behaviour for OpenFlow1.3+ is to drop the
- * packet rather than to send the packet to the controller.
- *
- * This function returns false to indicate the packet should be dropped if
- * the controller action was the result of the default table-miss behaviour
- * and the controller is using OpenFlow1.3+.
- *
- * Otherwise true is returned to indicate the packet should be forwarded to
- * the controller */
-static bool
-ofconn_wants_packet_in_on_miss(struct ofconn *ofconn,
- const struct ofproto_packet_in *pin)
-{
- if (pin->miss_type == OFPROTO_PACKET_IN_MISS_WITHOUT_FLOW) {
- enum ofputil_protocol protocol = ofconn_get_protocol(ofconn);
-
- if (protocol != OFPUTIL_P_NONE
- && ofputil_protocol_to_ofp_version(protocol) >= OFP13_VERSION
- && (ofproto_table_get_miss_config(ofconn->connmgr->ofproto,
- pin->up.table_id)
- == OFPUTIL_TABLE_MISS_DEFAULT)) {
- return false;
- }
- }
- return true;
-}
-
/* The default "table-miss" behaviour for OpenFlow1.3+ is to drop the
* packet rather than to send the packet to the controller.
*
\f
/* Sending asynchronous messages. */
-static void schedule_packet_in(struct ofconn *, struct ofproto_packet_in,
- enum ofp_packet_in_reason wire_reason);
-
/* Sends an OFPT_PORT_STATUS message with 'opp' and 'reason' to appropriate
* controllers managed by 'mgr'. For messages caused by a controller
* OFPT_PORT_MOD, specify 'source' as the controller connection that sent the
}
}
-/* Normally a send-to-controller action uses reason OFPR_ACTION. However, in
- * OpenFlow 1.3 and later, packet_ins generated by a send-to-controller action
- * in a "table-miss" flow (one with priority 0 and completely wildcarded) are
- * sent as OFPR_NO_MATCH. This function returns the reason that should
- * actually be sent on 'ofconn' for 'pin'. */
-static enum ofp_packet_in_reason
-wire_reason(struct ofconn *ofconn, const struct ofproto_packet_in *pin)
-{
- enum ofputil_protocol protocol = ofconn_get_protocol(ofconn);
-
- if (pin->miss_type == OFPROTO_PACKET_IN_MISS_FLOW
- && pin->up.reason == OFPR_ACTION
- && protocol != OFPUTIL_P_NONE
- && ofputil_protocol_to_ofp_version(protocol) >= OFP13_VERSION) {
- return OFPR_NO_MATCH;
- }
-
- switch (pin->up.reason) {
- case OFPR_ACTION_SET:
- case OFPR_GROUP:
- case OFPR_PACKET_OUT:
- if (!(protocol & OFPUTIL_P_OF14_UP)) {
- /* Only supported in OF1.4+ */
- return OFPR_ACTION;
- }
- /* Fall through. */
- case OFPR_NO_MATCH:
- case OFPR_ACTION:
- case OFPR_INVALID_TTL:
- case OFPR_N_REASONS:
- default:
- return pin->up.reason;
- }
-}
-
/* Given 'pin', sends an OFPT_PACKET_IN message to each OpenFlow controller as
* necessary according to their individual configurations.
*
struct ofconn *ofconn;
LIST_FOR_EACH (ofconn, node, &mgr->all_conns) {
- enum ofp_packet_in_reason reason = wire_reason(ofconn, pin);
-
- if (ofconn_wants_packet_in_on_miss(ofconn, pin)
- && ofconn_receives_async_msg(ofconn, OAM_PACKET_IN, reason)
- && ofconn->controller_id == pin->controller_id) {
- schedule_packet_in(ofconn, *pin, reason);
+ enum ofputil_protocol protocol = ofconn_get_protocol(ofconn);
+ if (protocol == OFPUTIL_P_NONE || !rconn_is_connected(ofconn->rconn)
+ || ofconn->controller_id != pin->controller_id
+ || !ofconn_receives_async_msg(ofconn, OAM_PACKET_IN,
+ pin->up.reason)) {
+ continue;
}
+
+ struct ofpbuf *msg = ofputil_encode_packet_in(
+ &pin->up, protocol, ofconn->packet_in_format,
+ pin->max_len >= 0 ? pin->max_len : ofconn->miss_send_len,
+ ofconn->pktbuf);
+
+ struct ovs_list txq;
+ bool is_miss = (pin->up.reason == OFPR_NO_MATCH ||
+ pin->up.reason == OFPR_EXPLICIT_MISS ||
+ pin->up.reason == OFPR_IMPLICIT_MISS);
+ pinsched_send(ofconn->schedulers[is_miss],
+ pin->up.flow_metadata.flow.in_port.ofp_port, msg, &txq);
+ do_send_packet_ins(ofconn, &txq);
}
}
}
}
}
-
-/* Takes 'pin', composes an OpenFlow packet-in message from it, and passes it
- * to 'ofconn''s packet scheduler for sending. */
-static void
-schedule_packet_in(struct ofconn *ofconn, struct ofproto_packet_in pin,
- enum ofp_packet_in_reason wire_reason)
-{
- uint16_t controller_max_len;
- struct ovs_list txq;
-
- pin.up.total_len = pin.up.packet_len;
-
- pin.up.reason = wire_reason;
- if (pin.up.reason == OFPR_ACTION) {
- controller_max_len = pin.send_len; /* max_len */
- } else {
- controller_max_len = ofconn->miss_send_len;
- }
-
- /* Get OpenFlow buffer_id.
- * For OpenFlow 1.2+, OFPCML_NO_BUFFER (== UINT16_MAX) specifies
- * unbuffered. This behaviour doesn't violate prior versions, too. */
- if (controller_max_len == UINT16_MAX) {
- pin.up.buffer_id = UINT32_MAX;
- } else if (!ofconn->pktbuf) {
- pin.up.buffer_id = UINT32_MAX;
- } else {
- pin.up.buffer_id = pktbuf_save(ofconn->pktbuf,
- pin.up.packet, pin.up.packet_len,
- pin.up.flow_metadata.flow.in_port.ofp_port);
- }
-
- /* Figure out how much of the packet to send.
- * If not buffered, send the entire packet. Otherwise, depending on
- * the reason of packet-in, send what requested by the controller. */
- if (pin.up.buffer_id != UINT32_MAX
- && controller_max_len < pin.up.packet_len) {
- pin.up.packet_len = controller_max_len;
- }
-
- /* Make OFPT_PACKET_IN and hand over to packet scheduler. */
- pinsched_send(ofconn->schedulers[pin.up.reason == OFPR_NO_MATCH ? 0 : 1],
- pin.up.flow_metadata.flow.in_port.ofp_port,
- ofputil_encode_packet_in(&pin.up,
- ofconn_get_protocol(ofconn),
- ofconn->packet_in_format),
- &txq);
- do_send_packet_ins(ofconn, &txq);
-}
\f
/* Fail-open settings. */
OFCONN_SERVICE /* A service connection, e.g. "ovs-ofctl". */
};
-enum ofproto_packet_in_miss_type {
- /* Not generated by a flow miss or table-miss flow. */
- OFPROTO_PACKET_IN_NO_MISS,
-
- /* The packet_in was generated directly by a table-miss flow, that is, a
- * flow with priority 0 that wildcards all fields. See OF1.3.3 section
- * 5.4.
- *
- * (Our interpretation of "directly" is "not via groups". Packet_ins
- * generated by table-miss flows via groups use
- * OFPROTO_PACKET_IN_NO_MISS.) */
- OFPROTO_PACKET_IN_MISS_FLOW,
-
- /* The packet-in was generated directly by a table-miss, but not a
- * table-miss flow. That is, it was generated by the OpenFlow 1.0, 1.1, or
- * 1.2 table-miss behavior. */
- OFPROTO_PACKET_IN_MISS_WITHOUT_FLOW,
-};
-
/* A packet_in, with extra members to assist in queuing and routing it. */
struct ofproto_packet_in {
struct ofputil_packet_in up;
struct ovs_list list_node; /* For queuing. */
uint16_t controller_id; /* Controller ID to send to. */
- int send_len; /* Length that the action requested sending. */
- enum ofproto_packet_in_miss_type miss_type;
+ int max_len; /* From action, or -1 if none. */
};
/* Basics. */
/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2015 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2015, 2016 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
static void
send_bogus_packet_ins(struct fail_open *fo)
{
- struct ofproto_packet_in pin;
struct eth_addr mac;
struct dp_packet b;
eth_addr_nicira_random(&mac);
compose_rarp(&b, mac);
- memset(&pin, 0, sizeof pin);
- pin.up.packet = dp_packet_data(&b);
- pin.up.packet_len = dp_packet_size(&b);
- pin.up.reason = OFPR_NO_MATCH;
- match_init_catchall(&pin.up.flow_metadata);
- match_set_in_port(&pin.up.flow_metadata, OFPP_LOCAL);
- pin.send_len = dp_packet_size(&b);
- pin.miss_type = OFPROTO_PACKET_IN_NO_MISS;
+ struct ofproto_packet_in pin = {
+ .up = {
+ .packet = dp_packet_data(&b),
+ .len = dp_packet_size(&b),
+ .flow_metadata = MATCH_CATCHALL_INITIALIZER,
+ .flow_metadata.flow.in_port.ofp_port = OFPP_LOCAL,
+ .flow_metadata.wc.masks.in_port.ofp_port = u16_to_ofp(UINT16_MAX),
+ .reason = OFPR_NO_MATCH,
+ .cookie = OVS_BE64_MAX,
+ },
+ .max_len = UINT16_MAX,
+ };
connmgr_send_packet_in(fo->connmgr, &pin);
dp_packet_uninit(&b);
-/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
odp_execute_actions(NULL, &packet, 1, false,
ctx->odp_actions->data, ctx->odp_actions->size, NULL);
- pin = xmalloc(sizeof *pin);
- pin->up.packet_len = dp_packet_size(packet);
- pin->up.packet = dp_packet_steal_data(packet);
- pin->up.reason = reason;
- pin->up.table_id = ctx->table_id;
- pin->up.cookie = ctx->rule_cookie;
+ /* A packet sent by an action in a table-miss rule is considered an
+ * explicit table miss. OpenFlow before 1.3 doesn't have that concept so
+ * it will get translated back to OFPR_ACTION for those versions. */
+ if (reason == OFPR_ACTION
+ && ctx->rule && rule_dpif_is_table_miss(ctx->rule)) {
+ reason = OFPR_EXPLICIT_MISS;
+ }
+
+ size_t packet_len = dp_packet_size(packet);
+ pin = xmalloc(sizeof *pin);
+ *pin = (struct ofproto_packet_in) {
+ .controller_id = controller_id,
+ .up = {
+ .packet = dp_packet_steal_data(packet),
+ .len = packet_len,
+ .reason = reason,
+ .table_id = ctx->table_id,
+ .cookie = ctx->rule_cookie,
+ },
+ .max_len = len,
+ };
flow_get_metadata(&ctx->xin->flow, &pin->up.flow_metadata);
- pin->controller_id = controller_id;
- pin->send_len = len;
- /* If a rule is a table-miss rule then this is
- * a table-miss handled by a table-miss rule.
- *
- * Else, if rule is internal and has a controller action,
- * the later being implied by the rule being processed here,
- * then this is a table-miss handled without a table-miss rule.
- *
- * Otherwise this is not a table-miss. */
- pin->miss_type = OFPROTO_PACKET_IN_NO_MISS;
- if (ctx->rule) {
- if (rule_dpif_is_table_miss(ctx->rule)) {
- pin->miss_type = OFPROTO_PACKET_IN_MISS_FLOW;
- } else if (rule_dpif_is_internal(ctx->rule)) {
- pin->miss_type = OFPROTO_PACKET_IN_MISS_WITHOUT_FLOW;
- }
- }
ofproto_dpif_send_packet_in(ctx->xbridge->ofproto, pin);
dp_packet_delete(packet);
}
controller = ofpact_put_CONTROLLER(&ofpacts);
controller->max_len = UINT16_MAX;
controller->controller_id = 0;
- controller->reason = OFPR_NO_MATCH;
+ controller->reason = OFPR_IMPLICIT_MISS;
error = add_internal_miss_flow(ofproto, id++, &ofpacts,
&ofproto->miss_rule);
/* Get payload. */
if (po.buffer_id != UINT32_MAX) {
error = ofconn_pktbuf_retrieve(ofconn, po.buffer_id, &payload, NULL);
- if (error || !payload) {
+ if (error) {
goto exit_free_ofpacts;
}
} else {
const struct ofp_header *msg)
{
struct ofputil_packet_in pin;
+ uint32_t buffer_id;
+ size_t total_len;
- if (ofputil_decode_packet_in(&pin, msg) != 0) {
+ if (ofputil_decode_packet_in(msg, &pin, &total_len, &buffer_id) != 0) {
return;
}
if (pin.reason != OFPR_ACTION) {