ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
const struct ofp_header *oh,
enum ofputil_protocol protocol,
- struct ofpbuf *ofpacts)
+ struct ofpbuf *ofpacts,
+ ofp_port_t max_port, uint8_t max_table)
{
ovs_be16 raw_flags;
enum ofperr error;
}
fm->modify_cookie = false;
fm->command = ofm->command;
+
+ /* Get table ID.
+ *
+ * OF1.1 entirely forbids table_id == 255.
+ * OF1.2+ allows table_id == 255 only for deletes. */
fm->table_id = ofm->table_id;
+ if (fm->table_id == 255
+ && (oh->version == OFP11_VERSION
+ || (ofm->command != OFPFC_DELETE &&
+ ofm->command != OFPFC_DELETE_STRICT))) {
+ return OFPERR_OFPFMFC_BAD_TABLE_ID;
+ }
+
fm->idle_timeout = ntohs(ofm->idle_timeout);
fm->hard_timeout = ntohs(ofm->hard_timeout);
fm->buffer_id = ntohl(ofm->buffer_id);
: OFPERR_OFPFMFC_TABLE_FULL);
}
- return 0;
+ return ofpacts_check(fm->ofpacts, fm->ofpacts_len, &fm->match.flow,
+ oh->version > OFP10_VERSION, max_port,
+ fm->table_id, max_table);
}
static enum ofperr
ofm->cookie = fm->cookie;
}
ofm->cookie_mask = fm->cookie_mask;
- ofm->table_id = fm->table_id;
+ if (fm->table_id != 255
+ || (protocol != OFPUTIL_P_OF11_STD
+ && (fm->command == OFPFC_DELETE ||
+ fm->command == OFPFC_DELETE_STRICT))) {
+ ofm->table_id = fm->table_id;
+ } else {
+ ofm->table_id = 0;
+ }
ofm->command = fm->command;
ofm->idle_timeout = htons(fm->idle_timeout);
ofm->hard_timeout = htons(fm->hard_timeout);