ofproto: Inline actions in struct rule_actions.
[sliver-openvswitch.git] / ofproto / connmgr.c
index a58e785..9a5167d 100644 (file)
@@ -1410,6 +1410,65 @@ ofconn_receives_async_msg(const struct ofconn *ofconn,
     return true;
 }
 
+/* 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) {
+            enum ofproto_table_config config;
+
+            config = ofproto_table_get_config(ofconn->connmgr->ofproto,
+                                              pin->up.table_id);
+            if (config == OFPROTO_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.
+ *
+ * This function returns false to indicate that a packet_in message
+ * for a "table-miss" should be sent to at least one controller.
+ * That is there is at least one controller with controller_id 0
+ * which connected using an OpenFlow version earlier than OpenFlow1.3.
+ *
+ * False otherwise.
+ *
+ * This logic assumes that "table-miss" packet_in messages
+ * are always sent to controller_id 0. */
+bool
+connmgr_wants_packet_in_on_miss(struct connmgr *mgr)
+{
+    struct ofconn *ofconn;
+
+    LIST_FOR_EACH (ofconn, node, &mgr->all_conns) {
+        enum ofputil_protocol protocol = ofconn_get_protocol(ofconn);
+
+        if (ofconn->controller_id == 0 &&
+            (protocol == OFPUTIL_P_NONE ||
+             ofputil_protocol_to_ofp_version(protocol) < OFP13_VERSION)) {
+            return true;
+        }
+    }
+    return false;
+}
+
 /* Returns a human-readable name for an OpenFlow connection between 'mgr' and
  * 'target', suitable for use in log messages for identifying the connection.
  *
@@ -1456,9 +1515,11 @@ 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'. */
+ * controllers managed by 'mgr'.  For messages caused by a controller
+ * OFPT_PORT_MOD, specify 'source' as the controller connection that sent the
+ * request; otherwise, specify 'source' as NULL. */
 void
-connmgr_send_port_status(struct connmgr *mgr,
+connmgr_send_port_status(struct connmgr *mgr, struct ofconn *source,
                          const struct ofputil_phy_port *pp, uint8_t reason)
 {
     /* XXX Should limit the number of queued port status change messages. */
@@ -1471,6 +1532,30 @@ connmgr_send_port_status(struct connmgr *mgr,
         if (ofconn_receives_async_msg(ofconn, OAM_PORT_STATUS, reason)) {
             struct ofpbuf *msg;
 
+            /* Before 1.5, OpenFlow specified that OFPT_PORT_MOD should not
+             * generate OFPT_PORT_STATUS messages.  That requirement was a
+             * relic of how OpenFlow originally supported a single controller,
+             * so that one could expect the controller to already know the
+             * changes it had made.
+             *
+             * EXT-338 changes OpenFlow 1.5 OFPT_PORT_MOD to send
+             * OFPT_PORT_STATUS messages to every controller.  This is
+             * obviously more useful in the multi-controller case.  We could
+             * always implement it that way in OVS, but that would risk
+             * confusing controllers that are intended for single-controller
+             * use only.  (Imagine a controller that generates an OFPT_PORT_MOD
+             * in response to any OFPT_PORT_STATUS!)
+             *
+             * So this compromises: for OpenFlow 1.4 and earlier, it generates
+             * OFPT_PORT_STATUS for OFPT_PORT_MOD, but not back to the
+             * originating controller.  In a single-controller environment, in
+             * particular, this means that it will never generate
+             * OFPT_PORT_STATUS for OFPT_PORT_MOD at all. */
+            if (ofconn == source
+                && rconn_get_version(ofconn->rconn) < OFP15_VERSION) {
+                continue;
+            }
+
             msg = ofputil_encode_port_status(&ps, ofconn_get_protocol(ofconn));
             ofconn_send(ofconn, msg, NULL);
         }
@@ -1508,7 +1593,8 @@ connmgr_send_flow_removed(struct connmgr *mgr,
 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) {
+    if (pin->miss_type == OFPROTO_PACKET_IN_MISS_FLOW
+        && pin->up.reason == OFPR_ACTION) {
         enum ofputil_protocol protocol = ofconn_get_protocol(ofconn);
 
         if (protocol != OFPUTIL_P_NONE
@@ -1532,7 +1618,8 @@ connmgr_send_packet_in(struct connmgr *mgr,
     LIST_FOR_EACH (ofconn, node, &mgr->all_conns) {
         enum ofp_packet_in_reason reason = wire_reason(ofconn, pin);
 
-        if (ofconn_receives_async_msg(ofconn, OAM_PACKET_IN, reason)
+        if (ofconn_wants_packet_in_on_miss(ofconn, pin)
+            && ofconn_receives_async_msg(ofconn, OAM_PACKET_IN, pin->up.reason)
             && ofconn->controller_id == pin->controller_id) {
             schedule_packet_in(ofconn, *pin, reason);
         }
@@ -1796,7 +1883,8 @@ connmgr_flushed(struct connmgr *mgr)
         ofpact_pad(&ofpacts);
 
         match_init_catchall(&match);
-        ofproto_add_flow(mgr->ofproto, &match, 0, ofpacts.data, ofpacts.size);
+        ofproto_add_flow(mgr->ofproto, &match, 0, ofpbuf_data(&ofpacts),
+                                                  ofpbuf_size(&ofpacts));
 
         ofpbuf_uninit(&ofpacts);
     }
@@ -2017,8 +2105,9 @@ ofmonitor_report(struct connmgr *mgr, struct rule *rule,
                 ovs_mutex_unlock(&rule->mutex);
 
                 if (flags & NXFMF_ACTIONS) {
-                    fu.ofpacts = rule->actions->ofpacts;
-                    fu.ofpacts_len = rule->actions->ofpacts_len;
+                    const struct rule_actions *actions = rule_get_actions(rule);
+                    fu.ofpacts = actions->ofpacts;
+                    fu.ofpacts_len = actions->ofpacts_len;
                 } else {
                     fu.ofpacts = NULL;
                     fu.ofpacts_len = 0;