+
+/* Verifies that the 'ofpacts_len' bytes of actions in 'ofpacts' are
+ * in the appropriate order as defined by the OpenFlow spec. */
+enum ofperr
+ofpacts_verify(const struct ofpact ofpacts[], size_t ofpacts_len)
+{
+ const struct ofpact *a;
+ enum ovs_instruction_type inst;
+
+ inst = OVSINST_OFPIT11_APPLY_ACTIONS;
+ OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
+ enum ovs_instruction_type next;
+
+ if (a->type == OFPACT_CLEAR_ACTIONS) {
+ next = OVSINST_OFPIT11_CLEAR_ACTIONS;
+ } else if (a->type == OFPACT_WRITE_METADATA) {
+ next = OVSINST_OFPIT11_WRITE_METADATA;
+ } else if (a->type == OFPACT_GOTO_TABLE) {
+ next = OVSINST_OFPIT11_GOTO_TABLE;
+ } else {
+ next = OVSINST_OFPIT11_APPLY_ACTIONS;
+ }
+
+ if (inst != OVSINST_OFPIT11_APPLY_ACTIONS && next <= inst) {
+ const char *name = ofpact_instruction_name_from_type(inst);
+ const char *next_name = ofpact_instruction_name_from_type(next);
+
+ if (next == inst) {
+ VLOG_WARN("duplicate %s instruction not allowed, for OpenFlow "
+ "1.1+ compatibility", name);
+ } else {
+ VLOG_WARN("invalid instruction ordering: %s must appear "
+ "before %s, for OpenFlow 1.1+ compatibility",
+ next_name, name);
+ }
+ return OFPERR_OFPBAC_UNSUPPORTED_ORDER;
+ }
+
+ inst = next;
+ }
+
+ return 0;
+}