ofproto: Move ofpacts_check() calls from ofproto-dpif to ofproto.
[sliver-openvswitch.git] / ofproto / ofproto.c
index f614096..d773c91 100644 (file)
@@ -390,6 +390,7 @@ ofproto_create(const char *datapath_name, const char *datapath_type,
     ofproto->frag_handling = OFPC_FRAG_NORMAL;
     hmap_init(&ofproto->ports);
     shash_init(&ofproto->port_by_name);
+    ofproto->max_ports = OFPP_MAX;
     ofproto->tables = NULL;
     ofproto->n_tables = 0;
     ofproto->connmgr = connmgr_create(ofproto, datapath_name, datapath_name);
@@ -422,6 +423,9 @@ ofproto_create(const char *datapath_name, const char *datapath_type,
     return 0;
 }
 
+/* Must be called (only) by an ofproto implementation in its constructor
+ * function.  See the large comment on 'construct' in struct ofproto_class for
+ * details. */
 void
 ofproto_init_tables(struct ofproto *ofproto, int n_tables)
 {
@@ -437,6 +441,24 @@ ofproto_init_tables(struct ofproto *ofproto, int n_tables)
     }
 }
 
+/* To be optionally called (only) by an ofproto implementation in its
+ * constructor function.  See the large comment on 'construct' in struct
+ * ofproto_class for details.
+ *
+ * Sets the maximum number of ports to 'max_ports'.  The ofproto generic layer
+ * will then ensure that actions passed into the ofproto implementation will
+ * not refer to OpenFlow ports numbered 'max_ports' or higher.  If this
+ * function is not called, there will be no such restriction.
+ *
+ * Reserved ports numbered OFPP_MAX and higher are special and not subject to
+ * the 'max_ports' restriction. */
+void
+ofproto_init_max_ports(struct ofproto *ofproto, uint16_t max_ports)
+{
+    assert(max_ports <= OFPP_MAX);
+    ofproto->max_ports = max_ports;
+}
+
 uint64_t
 ofproto_get_datapath_id(const struct ofproto *ofproto)
 {
@@ -2103,6 +2125,10 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh)
     if (error) {
         goto exit_free_ofpacts;
     }
+    if (po.in_port >= p->max_ports && po.in_port < OFPP_MAX) {
+        error = OFPERR_NXBRC_BAD_IN_PORT;
+        goto exit_free_ofpacts;
+    }
 
     /* Get payload. */
     if (po.buffer_id != UINT32_MAX) {
@@ -2115,10 +2141,13 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh)
         ofpbuf_use_const(payload, po.packet, po.packet_len);
     }
 
-    /* Send out packet. */
+    /* Verify actions against packet, then send packet if successful. */
     flow_extract(payload, 0, 0, po.in_port, &flow);
-    error = p->ofproto_class->packet_out(p, payload, &flow,
-                                         po.ofpacts, po.ofpacts_len);
+    error = ofpacts_check(po.ofpacts, po.ofpacts_len, &flow, p->max_ports);
+    if (!error) {
+        error = p->ofproto_class->packet_out(p, payload, &flow,
+                                             po.ofpacts, po.ofpacts_len);
+    }
     ofpbuf_delete(payload);
 
 exit_free_ofpacts:
@@ -2208,7 +2237,7 @@ handle_table_stats_request(struct ofconn *ofconn,
                            const struct ofp_header *request)
 {
     struct ofproto *p = ofconn_get_ofproto(ofconn);
-    struct ofp_table_stats *ots;
+    struct ofp10_table_stats *ots;
     struct ofpbuf *msg;
     size_t i;
 
@@ -2244,7 +2273,7 @@ static void
 append_port_stat(struct ofport *port, struct list *replies)
 {
     struct netdev_stats stats;
-    struct ofp_port_stats *ops;
+    struct ofp10_port_stats *ops;
 
     /* Intentionally ignore return value, since errors will set
      * 'stats' to all-1s, which is correct for OpenFlow, and
@@ -2273,7 +2302,7 @@ handle_port_stats_request(struct ofconn *ofconn,
                           const struct ofp_header *request)
 {
     struct ofproto *p = ofconn_get_ofproto(ofconn);
-    const struct ofp_port_stats_request *psr = ofpmsg_body(request);
+    const struct ofp10_port_stats_request *psr = ofpmsg_body(request);
     struct ofport *port;
     struct list replies;
 
@@ -2298,14 +2327,15 @@ handle_port_desc_stats_request(struct ofconn *ofconn,
                                const struct ofp_header *request)
 {
     struct ofproto *p = ofconn_get_ofproto(ofconn);
+    enum ofp_version version;
     struct ofport *port;
     struct list replies;
 
     ofpmp_init(&replies, request);
 
+    version = ofputil_protocol_to_ofp_version(ofconn_get_protocol(ofconn));
     HMAP_FOR_EACH (port, hmap_node, &p->ports) {
-        ofputil_append_port_desc_stats_reply(ofconn_get_protocol(ofconn),
-                                             &port->pp, &replies);
+        ofputil_append_port_desc_stats_reply(version, &port->pp, &replies);
     }
 
     ofconn_send_replies(ofconn, &replies);
@@ -2593,7 +2623,7 @@ ofproto_get_netflow_ids(const struct ofproto *ofproto,
 /* Checks the fault status of CFM for 'ofp_port' within 'ofproto'.  Returns a
  * bitmask of 'cfm_fault_reason's to indicate a CFM fault (generally
  * indicating a connectivity problem).  Returns zero if CFM is not faulted,
- * and -1 if CFM is not enabled on 'port'. */
+ * and -1 if CFM is not enabled on 'ofp_port'. */
 int
 ofproto_port_get_cfm_fault(const struct ofproto *ofproto, uint16_t ofp_port)
 {
@@ -2603,6 +2633,19 @@ ofproto_port_get_cfm_fault(const struct ofproto *ofproto, uint16_t ofp_port)
             : -1);
 }
 
+/* Checks the operational status reported by the remote CFM endpoint of
+ * 'ofp_port'  Returns 1 if operationally up, 0 if operationally down, and -1
+ * if CFM is not enabled on 'ofp_port' or does not support operational status.
+ */
+int
+ofproto_port_get_cfm_opup(const struct ofproto *ofproto, uint16_t ofp_port)
+{
+    struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
+    return (ofport && ofproto->ofproto_class->get_cfm_opup
+            ? ofproto->ofproto_class->get_cfm_opup(ofport)
+            : -1);
+}
+
 /* Gets the MPIDs of the remote maintenance points broadcasting to 'ofp_port'
  * within 'ofproto'.  Populates 'rmps' with an array of MPIDs owned by
  * 'ofproto', and 'n_rmps' with the number of MPIDs in 'rmps'.  Returns a
@@ -2705,7 +2748,7 @@ static void
 put_queue_stats(struct queue_stats_cbdata *cbdata, uint32_t queue_id,
                 const struct netdev_queue_stats *stats)
 {
-    struct ofp_queue_stats *reply;
+    struct ofp10_queue_stats *reply;
 
     reply = ofpmp_append(&cbdata->replies, sizeof *reply);
     reply->port_no = htons(cbdata->ofport->pp.port_no);
@@ -2751,7 +2794,7 @@ handle_queue_stats_request(struct ofconn *ofconn,
                            const struct ofp_header *rq)
 {
     struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
-    const struct ofp_queue_stats_request *qsr = ofpmsg_body(rq);
+    const struct ofp10_queue_stats_request *qsr = ofpmsg_body(rq);
     struct queue_stats_cbdata cbdata;
     unsigned int port_no;
     struct ofport *port;
@@ -3141,6 +3184,7 @@ ofproto_rule_send_removed(struct rule *rule, uint8_t reason)
     calc_flow_duration__(rule->created, time_msec(),
                          &fr.duration_sec, &fr.duration_nsec);
     fr.idle_timeout = rule->idle_timeout;
+    fr.hard_timeout = rule->hard_timeout;
     rule->ofproto->ofproto_class->rule_get_stats(rule, &fr.packet_count,
                                                  &fr.byte_count);
 
@@ -3209,14 +3253,19 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh)
         goto exit_free_ofpacts;
     }
 
+    if (fm.flags & OFPFF10_EMERG) {
     /* We do not support the OpenFlow 1.0 emergency flow cache, which is not
      * required in OpenFlow 1.0.1 and removed from OpenFlow 1.1. */
-    if (fm.flags & OFPFF_EMERG) {
         /* We do not support the emergency flow cache.  It will hopefully get
          * dropped from OpenFlow in the near future.  There is no good error
          * code, so just state that the flow table is full. */
         error = OFPERR_OFPFMFC_ALL_TABLES_FULL;
-    } else {
+    }
+    if (!error) {
+        error = ofpacts_check(fm.ofpacts, fm.ofpacts_len,
+                              &fm.cr.flow, ofproto->max_ports);
+    }
+    if (!error) {
         error = handle_flow_mod__(ofconn_get_ofproto(ofconn), ofconn, &fm, oh);
     }
     if (error) {
@@ -3454,7 +3503,7 @@ ofproto_compose_flow_refresh_update(const struct rule *rule,
     fu.hard_timeout = rule->hard_timeout;
     fu.table_id = rule->table_id;
     fu.cookie = rule->flow_cookie;
-    fu.match = (struct cls_rule *) &rule->cr;
+    fu.match = CONST_CAST(struct cls_rule *, &rule->cr);
     if (!(flags & NXFMF_ACTIONS)) {
         fu.ofpacts = NULL;
         fu.ofpacts_len = 0;