X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fofp-actions.c;h=170e796fabb4f8b02d187ad4d7a8db63deea7925;hb=a32f0904a7ed4b9cdc05165920d33cfe45349933;hp=0d1a2acdda193ce7b32d647a1c8575487ef123fd;hpb=7bcb1506ee2de6a460db35404e642f21d8219b5f;p=openvswitch diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index 0d1a2acd..170e796f 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -135,6 +135,23 @@ controller_from_openflow(const struct nx_action_controller *nac, oc->reason = nac->reason; } +static enum ofperr +metadata_from_nxast(const struct nx_action_write_metadata *nawm, + struct ofpbuf *out) +{ + struct ofpact_metadata *om; + + if (!is_all_zeros(nawm->zeros, sizeof nawm->zeros)) { + return OFPERR_NXBRC_MUST_BE_ZERO; + } + + om = ofpact_put_WRITE_METADATA(out); + om->metadata = nawm->metadata; + om->mask = nawm->mask; + + return 0; +} + static void note_from_openflow(const struct nx_action_note *nan, struct ofpbuf *out) { @@ -276,6 +293,7 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code, const struct nx_action_set_queue *nasq; const struct nx_action_note *nan; const struct nx_action_set_tunnel64 *nast64; + const struct nx_action_write_metadata *nawm; struct ofpact_tunnel *tunnel; enum ofperr error = 0; @@ -297,6 +315,11 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code, tunnel->tun_id = ntohl(nast->tun_id); break; + case OFPUTIL_NXAST_WRITE_METADATA: + nawm = (const struct nx_action_write_metadata *) a; + error = metadata_from_nxast(nawm, out); + break; + case OFPUTIL_NXAST_SET_QUEUE: nasq = (const struct nx_action_set_queue *) a; ofpact_put_SET_QUEUE(out)->queue_id = ntohl(nasq->queue_id); @@ -567,6 +590,12 @@ ofpacts_pull_actions(struct ofpbuf *openflow, unsigned int actions_len, } error = translate(actions, actions_len / OFP_ACTION_ALIGN, ofpacts); + if (error) { + ofpbuf_clear(ofpacts); + return error; + } + + error = ofpacts_verify(ofpacts->data, ofpacts->size); if (error) { ofpbuf_clear(ofpacts); } @@ -685,6 +714,19 @@ ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out) ofpact_put_SET_VLAN_PCP(out)->vlan_pcp = a->vlan_pcp.vlan_pcp; break; + case OFPUTIL_OFPAT11_PUSH_VLAN: + if (((const struct ofp11_action_push *)a)->ethertype != + htons(ETH_TYPE_VLAN_8021Q)) { + /* TODO:XXX 802.1AD(QinQ) isn't supported at the moment */ + return OFPERR_OFPET_BAD_ACTION; + } + ofpact_put_PUSH_VLAN(out); + break; + + case OFPUTIL_OFPAT11_POP_VLAN: + ofpact_put_STRIP_VLAN(out); + break; + case OFPUTIL_OFPAT11_SET_DL_SRC: memcpy(ofpact_put_SET_ETH_SRC(out)->mac, ((const struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN); @@ -968,7 +1010,17 @@ ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow, ofpact_put_CLEAR_ACTIONS(ofpacts); } /* TODO:XXX Write-Actions */ - /* TODO:XXX Write-Metadata */ + if (insts[OVSINST_OFPIT11_WRITE_METADATA]) { + const struct ofp11_instruction_write_metadata *oiwm; + struct ofpact_metadata *om; + + oiwm = (const struct ofp11_instruction_write_metadata *) + insts[OVSINST_OFPIT11_WRITE_METADATA]; + + om = ofpact_put_WRITE_METADATA(ofpacts); + om->metadata = oiwm->metadata; + om->mask = oiwm->metadata_mask; + } if (insts[OVSINST_OFPIT11_GOTO_TABLE]) { const struct ofp11_instruction_goto_table *oigt; struct ofpact_goto_table *ogt; @@ -979,12 +1031,12 @@ ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow, ogt->table_id = oigt->table_id; } - if (insts[OVSINST_OFPIT11_WRITE_METADATA] || - insts[OVSINST_OFPIT11_WRITE_ACTIONS]) { + if (insts[OVSINST_OFPIT11_WRITE_ACTIONS]) { error = OFPERR_OFPBIC_UNSUP_INST; goto exit; } + error = ofpacts_verify(ofpacts->data, ofpacts->size); exit: if (error) { ofpbuf_clear(ofpacts); @@ -1022,6 +1074,7 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports) case OFPACT_SET_VLAN_VID: case OFPACT_SET_VLAN_PCP: case OFPACT_STRIP_VLAN: + case OFPACT_PUSH_VLAN: case OFPACT_SET_ETH_SRC: case OFPACT_SET_ETH_DST: case OFPACT_SET_IPV4_SRC: @@ -1059,6 +1112,7 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports) return 0; case OFPACT_CLEAR_ACTIONS: + case OFPACT_WRITE_METADATA: case OFPACT_GOTO_TABLE: return 0; @@ -1085,6 +1139,35 @@ ofpacts_check(const struct ofpact ofpacts[], size_t ofpacts_len, return 0; } + +/* Verifies that the 'ofpacts_len' bytes of actions in 'ofpacts' are + * in the appropriate order as defined by the OpenFlow spec. */ +enum ofperr +ofpacts_verify(const struct ofpact ofpacts[], size_t ofpacts_len) +{ + const struct ofpact *a; + const struct ofpact_metadata *om = NULL; + + OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { + if (om) { + if (a->type == OFPACT_WRITE_METADATA) { + VLOG_WARN("duplicate write_metadata instruction specified"); + /* should be OFPERR_OFPET_BAD_ACTION? */ + return OFPERR_OFPBAC_UNSUPPORTED_ORDER; + } else { + VLOG_WARN("write_metadata instruction must be specified after " + "other instructions/actions"); + return OFPERR_OFPBAC_UNSUPPORTED_ORDER; + } + } + + if (a->type == OFPACT_WRITE_METADATA) { + om = (const struct ofpact_metadata *) a; + } + } + + return 0; +} /* Converting ofpacts to Nicira OpenFlow extensions. */ @@ -1130,6 +1213,17 @@ ofpact_set_tunnel_to_nxast(const struct ofpact_tunnel *tunnel, } } +static void +ofpact_write_metadata_to_nxast(const struct ofpact_metadata *om, + struct ofpbuf *out) +{ + struct nx_action_write_metadata *nawm; + + nawm = ofputil_put_NXAST_WRITE_METADATA(out); + nawm->metadata = om->metadata; + nawm->mask = om->mask; +} + static void ofpact_note_to_nxast(const struct ofpact_note *note, struct ofpbuf *out) { @@ -1228,6 +1322,10 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out) ofpact_set_tunnel_to_nxast(ofpact_get_SET_TUNNEL(a), out); break; + case OFPACT_WRITE_METADATA: + ofpact_write_metadata_to_nxast(ofpact_get_WRITE_METADATA(a), out); + break; + case OFPACT_SET_QUEUE: ofputil_put_NXAST_SET_QUEUE(out)->queue_id = htonl(ofpact_get_SET_QUEUE(a)->queue_id); @@ -1270,6 +1368,7 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out) case OFPACT_SET_VLAN_VID: case OFPACT_SET_VLAN_PCP: case OFPACT_STRIP_VLAN: + case OFPACT_PUSH_VLAN: case OFPACT_SET_ETH_SRC: case OFPACT_SET_ETH_DST: case OFPACT_SET_IPV4_SRC: @@ -1368,6 +1467,7 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out) = htons(ofpact_get_SET_L4_DST_PORT(a)->port); break; + case OFPACT_PUSH_VLAN: case OFPACT_CLEAR_ACTIONS: case OFPACT_GOTO_TABLE: /* TODO:XXX */ @@ -1380,6 +1480,7 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out) case OFPACT_REG_LOAD: case OFPACT_DEC_TTL: case OFPACT_SET_TUNNEL: + case OFPACT_WRITE_METADATA: case OFPACT_SET_QUEUE: case OFPACT_POP_QUEUE: case OFPACT_FIN_TIMEOUT: @@ -1421,6 +1522,19 @@ ofpact_output_to_openflow11(const struct ofpact_output *output, 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) { @@ -1443,7 +1557,13 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out) break; case OFPACT_STRIP_VLAN: - /* XXX */ + 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: @@ -1482,11 +1602,11 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out) break; case OFPACT_DEC_TTL: - if (a->compat == OFPUTIL_OFPAT11_DEC_NW_TTL) { - ofputil_put_OFPAT11_DEC_NW_TTL(out); - } else { - ofpact_to_nxast(a, out); - } + 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: @@ -1553,7 +1673,7 @@ ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[], OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { /* TODO:XXX Write-Actions */ - /* TODO:XXX Write-Metadata */ + if (a->type == OFPACT_CLEAR_ACTIONS) { instruction_put_OFPIT11_CLEAR_ACTIONS(openflow); } else if (a->type == OFPACT_GOTO_TABLE) { @@ -1562,6 +1682,14 @@ ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[], 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; @@ -1601,6 +1729,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port) case OFPACT_SET_VLAN_VID: case OFPACT_SET_VLAN_PCP: case OFPACT_STRIP_VLAN: + case OFPACT_PUSH_VLAN: case OFPACT_SET_ETH_SRC: case OFPACT_SET_ETH_DST: case OFPACT_SET_IPV4_SRC: @@ -1612,6 +1741,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port) case OFPACT_REG_LOAD: case OFPACT_DEC_TTL: case OFPACT_SET_TUNNEL: + case OFPACT_WRITE_METADATA: case OFPACT_SET_QUEUE: case OFPACT_POP_QUEUE: case OFPACT_FIN_TIMEOUT: @@ -1711,6 +1841,7 @@ ofpact_format(const struct ofpact *a, struct ds *s) const struct ofpact_resubmit *resubmit; const struct ofpact_autopath *autopath; const struct ofpact_controller *controller; + const struct ofpact_metadata *metadata; const struct ofpact_tunnel *tunnel; uint16_t port; @@ -1782,6 +1913,11 @@ ofpact_format(const struct ofpact *a, struct ds *s) ds_put_cstr(s, "strip_vlan"); break; + case OFPACT_PUSH_VLAN: + /* TODO:XXX 802.1AD case*/ + ds_put_format(s, "push_vlan:%#"PRIx16, ETH_TYPE_VLAN_8021Q); + break; + case OFPACT_SET_ETH_SRC: ds_put_format(s, "mod_dl_src:"ETH_ADDR_FMT, ETH_ADDR_ARGS(ofpact_get_SET_ETH_SRC(a)->mac)); @@ -1896,6 +2032,17 @@ ofpact_format(const struct ofpact *a, struct ds *s) OVSINST_OFPIT11_CLEAR_ACTIONS)); break; + case OFPACT_WRITE_METADATA: + metadata = ofpact_get_WRITE_METADATA(a); + ds_put_format(s, "%s:%#"PRIx64, + ofpact_instruction_name_from_type( + OVSINST_OFPIT11_WRITE_METADATA), + ntohll(metadata->metadata)); + if (metadata->mask != htonll(UINT64_MAX)) { + ds_put_format(s, "/%#"PRIx64, ntohll(metadata->mask)); + } + break; + case OFPACT_GOTO_TABLE: ds_put_format(s, "%s:%"PRIu8, ofpact_instruction_name_from_type( @@ -1923,7 +2070,6 @@ ofpacts_format(const struct ofpact *ofpacts, size_t ofpacts_len, } /* TODO:XXX write-actions */ - /* TODO:XXX write-metadata */ ofpact_format(a, string); } }