{
size_t orig_size = ofpacts->size;
struct ofpact_tunnel *tunnel;
+ struct ofpact_vlan_vid *vlan_vid;
+ struct ofpact_vlan_pcp *vlan_pcp;
char *error = NULL;
uint16_t ethertype = 0;
uint16_t vid = 0;
- uint8_t tos = 0;
+ uint8_t tos = 0, ecn, ttl;
uint8_t pcp = 0;
switch (code) {
if (vid & ~VLAN_VID_MASK) {
return xasprintf("%s: not a valid VLAN VID", arg);
}
- ofpact_put_SET_VLAN_VID(ofpacts)->vlan_vid = vid;
+ vlan_vid = ofpact_put_SET_VLAN_VID(ofpacts);
+ vlan_vid->vlan_vid = vid;
+ vlan_vid->ofpact.compat = code;
+ vlan_vid->push_vlan_if_needed = code == OFPUTIL_OFPAT10_SET_VLAN_VID;
break;
case OFPUTIL_OFPAT10_SET_VLAN_PCP:
if (pcp & ~7) {
return xasprintf("%s: not a valid VLAN PCP", arg);
}
- ofpact_put_SET_VLAN_PCP(ofpacts)->vlan_pcp = pcp;
+ vlan_pcp = ofpact_put_SET_VLAN_PCP(ofpacts);
+ vlan_pcp->vlan_pcp = pcp;
+ vlan_pcp->ofpact.compat = code;
+ vlan_pcp->push_vlan_if_needed = code == OFPUTIL_OFPAT10_SET_VLAN_PCP;
break;
case OFPUTIL_OFPAT12_SET_FIELD:
case OFPUTIL_OFPAT10_STRIP_VLAN:
case OFPUTIL_OFPAT11_POP_VLAN:
- ofpact_put_STRIP_VLAN(ofpacts);
+ ofpact_put_STRIP_VLAN(ofpacts)->ofpact.compat = code;
break;
case OFPUTIL_OFPAT11_PUSH_VLAN:
if (tos & ~IP_DSCP_MASK) {
return xasprintf("%s: not a valid TOS", arg);
}
- ofpact_put_SET_IPV4_DSCP(ofpacts)->dscp = tos;
+ ofpact_put_SET_IP_DSCP(ofpacts)->dscp = tos;
+ break;
+
+ case OFPUTIL_OFPAT11_SET_NW_ECN:
+ error = str_to_u8(arg, "ECN", &ecn);
+ if (error) {
+ return error;
+ }
+
+ if (ecn & ~IP_ECN_MASK) {
+ return xasprintf("%s: not a valid ECN", arg);
+ }
+ ofpact_put_SET_IP_ECN(ofpacts)->ecn = ecn;
+ break;
+
+ case OFPUTIL_OFPAT11_SET_NW_TTL:
+ error = str_to_u8(arg, "TTL", &ttl);
+ if (error) {
+ return error;
+ }
+
+ ofpact_put_SET_IP_TTL(ofpacts)->ttl = ttl;
break;
case OFPUTIL_OFPAT11_DEC_NW_TTL:
static char * WARN_UNUSED_RESULT
parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,
- enum ofputil_protocol *usable_protocols)
+ enum ofputil_protocol *usable_protocols,
+ bool enforce_consistency)
{
enum {
F_OUT_PORT = 1 << 0,
enum ofperr err;
err = ofpacts_check(ofpacts.data, ofpacts.size, &fm->match.flow,
- OFPP_MAX, 0);
+ OFPP_MAX, 0, true);
if (err) {
- error = xasprintf("actions are invalid with specified match "
- "(%s)", ofperr_to_string(err));
+ if (!enforce_consistency &&
+ err == OFPERR_OFPBAC_MATCH_INCONSISTENT) {
+ /* Allow inconsistent actions to be used with OF 1.0. */
+ *usable_protocols &= OFPUTIL_P_OF10_ANY;
+ /* Try again, allowing for inconsistency.
+ * XXX: As a side effect, logging may be duplicated. */
+ err = ofpacts_check(ofpacts.data, ofpacts.size,
+ &fm->match.flow, OFPP_MAX, 0, false);
+ }
+ if (err) {
+ error = xasprintf("actions are invalid with specified match "
+ "(%s)", ofperr_to_string(err));
+ }
}
}
if (error) {
* error. The caller is responsible for freeing the returned string. */
char * WARN_UNUSED_RESULT
parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
- enum ofputil_protocol *usable_protocols)
+ enum ofputil_protocol *usable_protocols,
+ bool enforce_consistency)
{
char *string = xstrdup(str_);
char *error;
- error = parse_ofp_str__(fm, command, string, usable_protocols);
+ error = parse_ofp_str__(fm, command, string, usable_protocols,
+ enforce_consistency);
if (error) {
fm->ofpacts = NULL;
fm->ofpacts_len = 0;
char * WARN_UNUSED_RESULT
parse_ofp_flow_mod_str(struct ofputil_flow_mod *fm, const char *string,
uint16_t command,
- enum ofputil_protocol *usable_protocols)
+ enum ofputil_protocol *usable_protocols,
+ bool enforce_consistency)
{
- char *error = parse_ofp_str(fm, command, string, usable_protocols);
+ char *error = parse_ofp_str(fm, command, string, usable_protocols,
+ enforce_consistency);
if (!error) {
/* Normalize a copy of the match. This ensures that non-normalized
* flows get logged but doesn't affect what gets sent to the switch, so
char * WARN_UNUSED_RESULT
parse_ofp_flow_mod_file(const char *file_name, uint16_t command,
struct ofputil_flow_mod **fms, size_t *n_fms,
- enum ofputil_protocol *usable_protocols)
+ enum ofputil_protocol *usable_protocols,
+ bool enforce_consistency)
{
size_t allocated_fms;
int line_number;
*fms = x2nrealloc(*fms, &allocated_fms, sizeof **fms);
}
error = parse_ofp_flow_mod_str(&(*fms)[*n_fms], ds_cstr(&s), command,
- &usable);
+ &usable, enforce_consistency);
if (error) {
size_t i;
char * WARN_UNUSED_RESULT
parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *fsr,
bool aggregate, const char *string,
- enum ofputil_protocol *usable_protocols)
+ enum ofputil_protocol *usable_protocols,
+ bool enforce_consistency)
{
struct ofputil_flow_mod fm;
char *error;
- error = parse_ofp_str(&fm, -1, string, usable_protocols);
+ error = parse_ofp_str(&fm, -1, string, usable_protocols,
+ enforce_consistency);
if (error) {
return error;
}