diff options
Diffstat (limited to 'lib/ofp-actions.c')
-rw-r--r-- | lib/ofp-actions.c | 91 |
1 files changed, 79 insertions, 12 deletions
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index 79b04333..c00c0367 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -251,6 +251,22 @@ sample_from_openflow(const struct nx_action_sample *nas, } static enum ofperr +push_mpls_from_openflow(ovs_be16 ethertype, enum ofpact_mpls_position position, + struct ofpbuf *out) +{ + struct ofpact_push_mpls *oam; + + if (!eth_type_mpls(ethertype)) { + return OFPERR_OFPBAC_BAD_ARGUMENT; + } + oam = ofpact_put_PUSH_MPLS(out); + oam->ethertype = ethertype; + oam->position = position; + + return 0; +} + +static enum ofperr decode_nxast_action(const union ofp_action *a, enum ofputil_action_code *code) { const struct nx_action_header *nah = (const struct nx_action_header *) a; @@ -443,10 +459,8 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code, case OFPUTIL_NXAST_PUSH_MPLS: { struct nx_action_push_mpls *nxapm = (struct nx_action_push_mpls *)a; - if (!eth_type_mpls(nxapm->ethertype)) { - return OFPERR_OFPBAC_BAD_ARGUMENT; - } - ofpact_put_PUSH_MPLS(out)->ethertype = nxapm->ethertype; + error = push_mpls_from_openflow(nxapm->ethertype, + OFPACT_MPLS_AFTER_VLAN, out); break; } @@ -857,10 +871,8 @@ ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out) case OFPUTIL_OFPAT11_PUSH_MPLS: { struct ofp11_action_push *oap = (struct ofp11_action_push *)a; - if (!eth_type_mpls(oap->ethertype)) { - return OFPERR_OFPBAC_BAD_ARGUMENT; - } - ofpact_put_PUSH_MPLS(out)->ethertype = oap->ethertype; + error = push_mpls_from_openflow(oap->ethertype, + OFPACT_MPLS_AFTER_VLAN, out); break; } @@ -1121,6 +1133,35 @@ ofpacts_from_openflow11_for_action_set(const union ofp_action *in, } +static enum ofperr +ofpact_from_openflow13(const union ofp_action *a, struct ofpbuf *out) +{ + enum ofputil_action_code code; + enum ofperr error; + + error = decode_openflow11_action(a, &code); + if (error) { + return error; + } + + if (code == OFPUTIL_OFPAT11_PUSH_MPLS) { + struct ofp11_action_push *oap = (struct ofp11_action_push *)a; + error = push_mpls_from_openflow(oap->ethertype, + OFPACT_MPLS_BEFORE_VLAN, out); + } else { + error = ofpact_from_openflow11(a, out); + } + + return error; +} + +static enum ofperr +ofpacts_from_openflow13(const union ofp_action *in, size_t n_in, + struct ofpbuf *out) +{ + return ofpacts_from_openflow(in, n_in, out, ofpact_from_openflow13); +} + /* OpenFlow 1.1 instructions. */ #define DEFINE_INST(ENUM, STRUCT, EXTENSIBLE, NAME) \ @@ -1327,11 +1368,14 @@ get_actions_from_instruction(const struct ofp11_instruction *inst, *n_actions = (ntohs(inst->len) - sizeof *inst) / OFP11_INSTRUCTION_ALIGN; } -/* Attempts to convert 'actions_len' bytes of OpenFlow 1.1 actions from the +/* Attempts to convert 'actions_len' bytes of OpenFlow actions from the * front of 'openflow' into ofpacts. On success, replaces any existing content * in 'ofpacts' by the converted ofpacts; on failure, clears 'ofpacts'. * Returns 0 if successful, otherwise an OpenFlow error. * + * Actions are processed according to their OpenFlow version which + * is provided in the 'version' parameter. + * * In most places in OpenFlow 1.1 and 1.2, actions appear encapsulated in * instructions, so you should call ofpacts_pull_openflow11_instructions() * instead of this function. @@ -1343,15 +1387,27 @@ get_actions_from_instruction(const struct ofp11_instruction *inst, * valid in a specific context. */ enum ofperr ofpacts_pull_openflow11_actions(struct ofpbuf *openflow, + enum ofp_version version, unsigned int actions_len, struct ofpbuf *ofpacts) { - return ofpacts_pull_actions(openflow, actions_len, ofpacts, - ofpacts_from_openflow11); + switch (version) { + case OFP10_VERSION: + case OFP11_VERSION: + case OFP12_VERSION: + return ofpacts_pull_actions(openflow, actions_len, ofpacts, + ofpacts_from_openflow11); + case OFP13_VERSION: + return ofpacts_pull_actions(openflow, actions_len, ofpacts, + ofpacts_from_openflow13); + default: + NOT_REACHED(); + } } enum ofperr ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow, + enum ofp_version version, unsigned int instructions_len, struct ofpbuf *ofpacts) { @@ -1402,7 +1458,18 @@ ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow, get_actions_from_instruction(insts[OVSINST_OFPIT11_APPLY_ACTIONS], &actions, &n_actions); - error = ofpacts_from_openflow11(actions, n_actions, ofpacts); + switch (version) { + case OFP10_VERSION: + case OFP11_VERSION: + case OFP12_VERSION: + error = ofpacts_from_openflow11(actions, n_actions, ofpacts); + break; + case OFP13_VERSION: + error = ofpacts_from_openflow13(actions, n_actions, ofpacts); + break; + default: + NOT_REACHED(); + } if (error) { goto exit; } |