ofproto: Use ofproto_check_ofpacts() from modify_flows__().
[sliver-openvswitch.git] / ofproto / ofproto.c
index f67e1fb..91a39ef 100644 (file)
@@ -451,7 +451,7 @@ ofproto_enumerate_names(const char *type, struct sset *names)
 {
     const struct ofproto_class *class = ofproto_class_find__(type);
     return class ? class->enumerate_names(type, names) : EAFNOSUPPORT;
- }
+}
 
 int
 ofproto_create(const char *datapath_name, const char *datapath_type,
@@ -2823,13 +2823,15 @@ reject_slave_controller(struct ofconn *ofconn)
 static enum ofperr
 ofproto_check_ofpacts(struct ofproto *ofproto,
                       const struct ofpact ofpacts[], size_t ofpacts_len,
-                      struct flow *flow, uint8_t table_id)
+                      struct flow *flow, uint8_t table_id,
+                      const struct ofp_header *oh)
 {
     enum ofperr error;
     uint32_t mid;
 
     error = ofpacts_check(ofpacts, ofpacts_len, flow,
-                          u16_to_ofp(ofproto->max_ports), table_id);
+                          u16_to_ofp(ofproto->max_ports), table_id,
+                          oh && oh->version > OFP10_VERSION);
     if (error) {
         return error;
     }
@@ -2887,7 +2889,7 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh)
     /* Verify actions against packet, then send packet if successful. */
     in_port_.ofp_port = po.in_port;
     flow_extract(payload, 0, 0, NULL, &in_port_, &flow);
-    error = ofproto_check_ofpacts(p, po.ofpacts, po.ofpacts_len, &flow, 0);
+    error = ofproto_check_ofpacts(p, po.ofpacts, po.ofpacts_len, &flow, 0, oh);
     if (!error) {
         error = p->ofproto_class->packet_out(p, payload, &flow,
                                              po.ofpacts, po.ofpacts_len);
@@ -3937,7 +3939,7 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
 
     /* Verify actions. */
     error = ofproto_check_ofpacts(ofproto, fm->ofpacts, fm->ofpacts_len,
-                                  &fm->match.flow, table_id);
+                                  &fm->match.flow, table_id, request);
     if (error) {
         cls_rule_destroy(&cr);
         return error;
@@ -4041,6 +4043,19 @@ modify_flows__(struct ofproto *ofproto, struct ofconn *ofconn,
     enum ofperr error;
     size_t i;
 
+    /* Verify actions before we start to modify any rules, to avoid partial
+     * flow table modifications. */
+    for (i = 0; i < rules->n; i++) {
+        struct rule *rule = rules->rules[i];
+
+        error = ofproto_check_ofpacts(ofproto, fm->ofpacts, fm->ofpacts_len,
+                                      &fm->match.flow, rule->table_id,
+                                      request);
+        if (error) {
+            return error;
+        }
+    }
+
     type = fm->command == OFPFC_ADD ? OFOPERATION_REPLACE : OFOPERATION_MODIFY;
     group = ofopgroup_create(ofproto, ofconn, request, fm->buffer_id);
     error = OFPERR_OFPBRC_EPERM;
@@ -4059,13 +4074,6 @@ modify_flows__(struct ofproto *ofproto, struct ofconn *ofconn,
             continue;
         }
 
-        /* Verify actions. */
-        error = ofpacts_check(fm->ofpacts, fm->ofpacts_len, &fm->match.flow,
-                              u16_to_ofp(ofproto->max_ports), rule->table_id);
-        if (error) {
-            return error;
-        }
-
         actions_changed = !ofpacts_equal(fm->ofpacts, fm->ofpacts_len,
                                          rule->actions->ofpacts,
                                          rule->actions->ofpacts_len);
@@ -5672,6 +5680,13 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
     if (error) {
         return error;
     }
+    if (oh->version >= OFP13_VERSION && ofpmsg_is_stat_request(oh)
+        && ofpmp_more(oh)) {
+        /* We have no buffer implementation for multipart requests.
+         * Report overflow for requests which consists of multiple
+         * messages. */
+        return OFPERR_OFPBRC_MULTIPART_BUFFER_OVERFLOW;
+    }
 
     switch (type) {
         /* OpenFlow requests. */
@@ -5785,7 +5800,7 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
         /* FIXME: Change the following once they are implemented: */
     case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:
     case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
-        return OFPERR_OFPBRC_BAD_TYPE;
+        /* fallthrough */
 
     case OFPTYPE_HELLO:
     case OFPTYPE_ERROR:
@@ -5816,7 +5831,11 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
     case OFPTYPE_METER_FEATURES_STATS_REPLY:
     case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
     default:
-        return OFPERR_OFPBRC_BAD_TYPE;
+        if (ofpmsg_is_stat_request(oh)) {
+            return OFPERR_OFPBRC_BAD_STAT;
+        } else {
+            return OFPERR_OFPBRC_BAD_TYPE;
+        }
     }
 }