\f
/* Converting OpenFlow 1.0 to ofpacts. */
+union ofp_action {
+ ovs_be16 type;
+ struct ofp_action_header header;
+ struct ofp_action_vendor_header vendor;
+ struct ofp10_action_output output10;
+ struct ofp_action_vlan_vid vlan_vid;
+ struct ofp_action_vlan_pcp vlan_pcp;
+ struct ofp_action_nw_addr nw_addr;
+ struct ofp_action_nw_tos nw_tos;
+ struct ofp_action_tp_port tp_port;
+};
+OFP_ASSERT(sizeof(union ofp_action) == 8);
+
static enum ofperr
output_from_openflow10(const struct ofp10_action_output *oao,
struct ofpbuf *out)
return 0;
}
+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)
{
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;
}
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;
}
struct ofpact *a;
size_t start = out->size;
- error = ofpacts_from_openflow(in, n_in, out, ofpact_from_openflow11);
+ error = ofpacts_from_openflow11(in, n_in, out);
if (error) {
return error;
}
return 0;
}
+\f
+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);
+}
\f
/* OpenFlow 1.1 instructions. */
*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.
* 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)
{
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;
}
struct ofpact_nest *on;
const union ofp_action *actions;
size_t n_actions;
- size_t start = ofpacts->size;
+ size_t start;
+ ofpact_pad(ofpacts);
+ start = ofpacts->size;
on = ofpact_put(ofpacts, OFPACT_WRITE_ACTIONS,
offsetof(struct ofpact_nest, actions));
get_actions_from_instruction(insts[OVSINST_OFPIT11_WRITE_ACTIONS],
if (error) {
goto exit;
}
+ on = ofpbuf_at_assert(ofpacts, start, sizeof *on);
on->ofpact.len = ofpacts->size - start;
}
if (insts[OVSINST_OFPIT11_WRITE_METADATA]) {