+/* Converting ofpacts to OpenFlow 1.1. */
+
+static void
+ofpact_output_to_openflow11(const struct ofpact_output *output,
+ struct ofpbuf *out)
+{
+ struct ofp11_action_output *oao;
+
+ oao = ofputil_put_OFPAT11_OUTPUT(out);
+ oao->port = ofputil_port_to_ofp11(output->port);
+ oao->max_len = htons(output->max_len);
+}
+
+static void
+ofpact_dec_ttl_to_openflow11(const struct ofpact_cnt_ids *dec_ttl,
+ struct ofpbuf *out)
+{
+ if (dec_ttl->n_controllers == 1 && dec_ttl->cnt_ids[0] == 0
+ && (!dec_ttl->ofpact.compat ||
+ dec_ttl->ofpact.compat == OFPUTIL_OFPAT11_DEC_NW_TTL)) {
+ ofputil_put_OFPAT11_DEC_NW_TTL(out);
+ } else {
+ ofpact_dec_ttl_to_nxast(dec_ttl, out);
+ }
+}
+
+static void
+ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
+{
+ switch (a->type) {
+ case OFPACT_OUTPUT:
+ return ofpact_output_to_openflow11(ofpact_get_OUTPUT(a), out);
+
+ case OFPACT_ENQUEUE:
+ /* XXX */
+ break;
+
+ case OFPACT_SET_VLAN_VID:
+ ofputil_put_OFPAT11_SET_VLAN_VID(out)->vlan_vid
+ = htons(ofpact_get_SET_VLAN_VID(a)->vlan_vid);
+ break;
+
+ case OFPACT_SET_VLAN_PCP:
+ ofputil_put_OFPAT11_SET_VLAN_PCP(out)->vlan_pcp
+ = ofpact_get_SET_VLAN_PCP(a)->vlan_pcp;
+ break;
+
+ case OFPACT_STRIP_VLAN:
+ ofputil_put_OFPAT11_POP_VLAN(out);
+ break;
+
+ case OFPACT_PUSH_VLAN:
+ /* TODO:XXX ETH_TYPE_VLAN_8021AD case */
+ ofputil_put_OFPAT11_PUSH_VLAN(out)->ethertype =
+ htons(ETH_TYPE_VLAN_8021Q);
+ break;
+
+ case OFPACT_SET_ETH_SRC:
+ memcpy(ofputil_put_OFPAT11_SET_DL_SRC(out)->dl_addr,
+ ofpact_get_SET_ETH_SRC(a)->mac, ETH_ADDR_LEN);
+ break;
+
+ case OFPACT_SET_ETH_DST:
+ memcpy(ofputil_put_OFPAT11_SET_DL_DST(out)->dl_addr,
+ ofpact_get_SET_ETH_DST(a)->mac, ETH_ADDR_LEN);
+ break;
+
+ case OFPACT_SET_IPV4_SRC:
+ ofputil_put_OFPAT11_SET_NW_SRC(out)->nw_addr
+ = ofpact_get_SET_IPV4_SRC(a)->ipv4;
+ break;
+
+ case OFPACT_SET_IPV4_DST:
+ ofputil_put_OFPAT11_SET_NW_DST(out)->nw_addr
+ = ofpact_get_SET_IPV4_DST(a)->ipv4;
+ break;
+
+ case OFPACT_SET_IPV4_DSCP:
+ ofputil_put_OFPAT11_SET_NW_TOS(out)->nw_tos
+ = ofpact_get_SET_IPV4_DSCP(a)->dscp;
+ break;
+
+ case OFPACT_SET_L4_SRC_PORT:
+ ofputil_put_OFPAT11_SET_TP_SRC(out)->tp_port
+ = htons(ofpact_get_SET_L4_SRC_PORT(a)->port);
+ break;
+
+ case OFPACT_SET_L4_DST_PORT:
+ ofputil_put_OFPAT11_SET_TP_DST(out)->tp_port
+ = htons(ofpact_get_SET_L4_DST_PORT(a)->port);
+ break;
+
+ case OFPACT_DEC_TTL:
+ ofpact_dec_ttl_to_openflow11(ofpact_get_DEC_TTL(a), out);
+ break;
+
+ case OFPACT_WRITE_METADATA:
+ /* OpenFlow 1.1 uses OFPIT_WRITE_METADATA to express this action. */
+ break;
+
+ case OFPACT_CLEAR_ACTIONS:
+ case OFPACT_GOTO_TABLE:
+ NOT_REACHED();
+
+ case OFPACT_CONTROLLER:
+ case OFPACT_OUTPUT_REG:
+ case OFPACT_BUNDLE:
+ case OFPACT_REG_MOVE:
+ case OFPACT_REG_LOAD:
+ case OFPACT_SET_TUNNEL:
+ case OFPACT_SET_QUEUE:
+ case OFPACT_POP_QUEUE:
+ case OFPACT_FIN_TIMEOUT:
+ case OFPACT_RESUBMIT:
+ case OFPACT_LEARN:
+ case OFPACT_MULTIPATH:
+ case OFPACT_AUTOPATH:
+ case OFPACT_NOTE:
+ case OFPACT_EXIT:
+ ofpact_to_nxast(a, out);
+ break;
+ }
+}
+
+/* Converts the ofpacts in 'ofpacts' (terminated by OFPACT_END) into OpenFlow
+ * 1.1 actions in 'openflow', appending the actions to any existing data in
+ * 'openflow'. */
+size_t
+ofpacts_put_openflow11_actions(const struct ofpact ofpacts[],
+ size_t ofpacts_len, struct ofpbuf *openflow)
+{
+ const struct ofpact *a;
+ size_t start_size = openflow->size;
+
+ OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
+ ofpact_to_openflow11(a, openflow);
+ }
+
+ return openflow->size - start_size;
+}
+
+static void
+ofpacts_update_instruction_actions(struct ofpbuf *openflow, size_t ofs)
+{
+ struct ofp11_instruction_actions *oia;
+
+ /* Update the instruction's length (or, if it's empty, delete it). */
+ oia = ofpbuf_at_assert(openflow, ofs, sizeof *oia);
+ if (openflow->size > ofs + sizeof *oia) {
+ oia->len = htons(openflow->size - ofs);
+ } else {
+ openflow->size = ofs;
+ }
+}
+
+void
+ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
+ size_t ofpacts_len,
+ struct ofpbuf *openflow)
+{
+ const struct ofpact *a;
+
+ OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
+ /* TODO:XXX Write-Actions */
+
+ if (a->type == OFPACT_CLEAR_ACTIONS) {
+ instruction_put_OFPIT11_CLEAR_ACTIONS(openflow);
+ } else if (a->type == OFPACT_GOTO_TABLE) {
+ struct ofp11_instruction_goto_table *oigt;
+
+ oigt = instruction_put_OFPIT11_GOTO_TABLE(openflow);
+ oigt->table_id = ofpact_get_GOTO_TABLE(a)->table_id;
+ memset(oigt->pad, 0, sizeof oigt->pad);
+ } else if (a->type == OFPACT_WRITE_METADATA) {
+ const struct ofpact_metadata *om;
+ struct ofp11_instruction_write_metadata *oiwm;
+
+ om = ofpact_get_WRITE_METADATA(a);
+ oiwm = instruction_put_OFPIT11_WRITE_METADATA(openflow);
+ oiwm->metadata = om->metadata;
+ oiwm->metadata_mask = om->mask;
+ } else if (!ofpact_is_instruction(a)) {
+ /* Apply-actions */
+ const size_t ofs = openflow->size;
+ const size_t ofpacts_len_left =
+ (uint8_t*)ofpact_end(ofpacts, ofpacts_len) - (uint8_t*)a;
+ const struct ofpact *action;
+ const struct ofpact *processed = a;
+
+ instruction_put_OFPIT11_APPLY_ACTIONS(openflow);
+ OFPACT_FOR_EACH(action, a, ofpacts_len_left) {
+ if (ofpact_is_instruction(action)) {
+ break;
+ }
+ ofpact_to_openflow11(action, openflow);
+ processed = action;
+ }
+ ofpacts_update_instruction_actions(openflow, ofs);
+ a = processed;
+ }
+ }
+}
+\f