\f
/* Sending asynchronous messages. */
-static void schedule_packet_in(struct ofconn *, struct ofproto_packet_in);
+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'. */
}
}
+/* 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)
+{
+ if (pin->generated_by_table_miss && pin->up.reason == OFPR_ACTION) {
+ enum ofputil_protocol protocol = ofconn_get_protocol(ofconn);
+ enum ofp_version version = ofputil_protocol_to_ofp_version(protocol);
+
+ if (version >= OFP13_VERSION) {
+ return OFPR_NO_MATCH;
+ }
+ }
+ 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) {
- if (ofconn_receives_async_msg(ofconn, OAM_PACKET_IN, pin->up.reason)
+ enum ofp_packet_in_reason reason = wire_reason(ofconn, pin);
+
+ if (ofconn_receives_async_msg(ofconn, OAM_PACKET_IN, reason)
&& ofconn->controller_id == pin->controller_id) {
- schedule_packet_in(ofconn, *pin);
+ schedule_packet_in(ofconn, *pin, reason);
}
}
}
/* 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)
+schedule_packet_in(struct ofconn *ofconn, struct ofproto_packet_in pin,
+ enum ofp_packet_in_reason wire_reason)
{
struct connmgr *mgr = ofconn->connmgr;
uint16_t controller_max_len;
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 {
struct rule_actions *rule_get_actions__(const struct rule *rule)
OVS_REQUIRES(rule->mutex);
+/* Returns true if 'rule' is an OpenFlow 1.3 "table-miss" rule, false
+ * otherwise.
+ *
+ * ("Table-miss" rules are special because a packet_in generated through one
+ * uses OFPR_NO_MATCH as its reason, whereas packet_ins generated by any other
+ * rule use OFPR_ACTION.) */
+static inline bool
+rule_is_table_miss(const struct rule *rule)
+{
+ return rule->cr.priority == 0 && cls_rule_is_catchall(&rule->cr);
+}
+
/* A set of actions within a "struct rule".
*
*