diff --git a/build-aux/extract-ofp-actions b/build-aux/extract-ofp-actions index 2d1dbe70973..057bd269140 100755 --- a/build-aux/extract-ofp-actions +++ b/build-aux/extract-ofp-actions @@ -21,7 +21,8 @@ version_reverse_map = dict((v, k) for (k, v) in version_map.items()) # Map from vendor name to the length of the action header. vendor_map = {"OF": (0x00000000, 4), "ONF": (0x4f4e4600, 10), - "NX": (0x00002320, 10)} + "NX": (0x00002320, 10), + "OPK": (0x0000AA02, 10)} # Basic types used in action arguments. types = {} diff --git a/include/openflow/openflow-common.h b/include/openflow/openflow-common.h index 584f20ec179..a40ea2a5e26 100644 --- a/include/openflow/openflow-common.h +++ b/include/openflow/openflow-common.h @@ -110,6 +110,7 @@ enum ofp_version { #define NX_VENDOR_ID 0x00002320 /* Nicira. */ #define ONF_VENDOR_ID 0x4f4e4600 /* Open Networking Foundation. */ #define INTEL_VENDOR_ID 0x0000AA01 /* Intel */ +#define OPK_VENDOR_ID 0x0000AA02 /* Open Kilda */ #define OFP_MAX_TABLE_NAME_LEN 32 #define OFP_MAX_PORT_NAME_LEN 16 diff --git a/include/openvswitch/ofp-actions.h b/include/openvswitch/ofp-actions.h index 41bcb55d205..3e6a7e75f54 100644 --- a/include/openvswitch/ofp-actions.h +++ b/include/openvswitch/ofp-actions.h @@ -84,6 +84,7 @@ struct vl_mff_map; OFPACT(SET_L4_SRC_PORT, ofpact_l4_port, ofpact, "mod_tp_src") \ OFPACT(SET_L4_DST_PORT, ofpact_l4_port, ofpact, "mod_tp_dst") \ OFPACT(REG_MOVE, ofpact_reg_move, ofpact, "move") \ + OFPACT(SWAP_FIELD, ofpact_swap_field, ofpact, "swap") \ OFPACT(STACK_PUSH, ofpact_stack, ofpact, "push") \ OFPACT(STACK_POP, ofpact_stack, ofpact, "pop") \ OFPACT(DEC_TTL, ofpact_cnt_ids, cnt_ids, "dec_ttl") \ @@ -527,6 +528,14 @@ struct ofpact_reg_move { ); }; +struct ofpact_swap_field { + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + struct mf_subfield src; + struct mf_subfield dst; + ); +}; + /* OFPACT_STACK_PUSH, OFPACT_STACK_POP. * * Used for NXAST_STACK_PUSH and NXAST_STACK_POP. */ diff --git a/lib/nx-match.c b/lib/nx-match.c index 440f5f7630c..07026c9d614 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -1810,6 +1810,33 @@ nxm_parse_reg_move(struct ofpact_reg_move *move, const char *s) } return NULL; } + +char * OVS_WARN_UNUSED_RESULT +nxm_parse_swap_field(struct ofpact_swap_field *swap, const char *s) +{ + const char *full_s = s; + char *error; + + error = mf_parse_subfield__(&swap->src, &s); + if (error) { + return error; + } + if (strncmp(s, "->", 2)) { + return xasprintf("%s: missing `->' following source", full_s); + } + s += 2; + error = mf_parse_subfield(&swap->dst, s); + if (error) { + return error; + } + + if (swap->src.n_bits != swap->dst.n_bits) { + return xasprintf("%s: source field is %d bits wide but destination is " + "%d bits wide", full_s, + swap->src.n_bits, swap->dst.n_bits); + } + return NULL; +} /* nxm_format_reg_move(). */ @@ -1822,6 +1849,15 @@ nxm_format_reg_move(const struct ofpact_reg_move *move, struct ds *s) mf_format_subfield(&move->dst, s); } +void +nxm_format_swap_field(const struct ofpact_swap_field *swap, struct ds *s) +{ + ds_put_format(s, "%sswap:%s", colors.special, colors.end); + mf_format_subfield(&swap->src, s); + ds_put_format(s, "%s->%s", colors.special, colors.end); + mf_format_subfield(&swap->dst, s); +} + enum ofperr nxm_reg_move_check(const struct ofpact_reg_move *move, @@ -1839,6 +1875,19 @@ nxm_reg_move_check(const struct ofpact_reg_move *move, /* nxm_execute_reg_move(). */ +enum ofperr nxm_swap_field_check(const struct ofpact_swap_field *swap, + const struct match *match) +{ + enum ofperr error; + + error = mf_check_src(&swap->src, match); + if (error) { + return error; + } + + return mf_check_dst(&swap->dst, match); +} + void nxm_reg_load(const struct mf_subfield *dst, uint64_t src_data, struct flow *flow, struct flow_wildcards *wc) diff --git a/lib/nx-match.h b/lib/nx-match.h index 3120ac0a0d5..ed510e4743e 100644 --- a/lib/nx-match.h +++ b/lib/nx-match.h @@ -29,6 +29,7 @@ struct ds; struct match; struct ofpact_reg_move; +struct ofpact_swap_field; struct ofpact_reg_load; struct ofpact_stack; struct ofpbuf; @@ -118,11 +119,19 @@ void nx_format_field_name(enum mf_field_id, enum ofp_version, struct ds *); char *nxm_parse_reg_move(struct ofpact_reg_move *, const char *) OVS_WARN_UNUSED_RESULT; +char *nxm_parse_swap_field(struct ofpact_swap_field *, const char *) +OVS_WARN_UNUSED_RESULT; + void nxm_format_reg_move(const struct ofpact_reg_move *, struct ds *); +void nxm_format_swap_field(const struct ofpact_swap_field *, struct ds *); + enum ofperr nxm_reg_move_check(const struct ofpact_reg_move *, const struct match *); +enum ofperr nxm_swap_field_check(const struct ofpact_swap_field *, + const struct match *); + void nxm_reg_load(const struct mf_subfield *, uint64_t src_data, struct flow *, struct flow_wildcards *); diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index 6fb3da50745..413be2edfbf 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -262,6 +262,12 @@ enum ofp_raw_action_type { /* OF1.5+(29): uint32_t. */ OFPAT_RAW15_METER, +/* ## ------------------------- ## */ +/* ## Open Kilda extension actions. ## */ +/* ## ------------------------- ## */ + /* OPK1.3-1.4(3201): struct opk_action_swap_field, ... VLMFF */ + OPK_RAW13_SWAP_FIELD, + /* ## ------------------------- ## */ /* ## Nicira extension actions. ## */ /* ## ------------------------- ## */ @@ -470,6 +476,7 @@ ofpact_next_flattened(const struct ofpact *ofpact) case OFPACT_SET_L4_SRC_PORT: case OFPACT_SET_L4_DST_PORT: case OFPACT_REG_MOVE: + case OFPACT_SWAP_FIELD: case OFPACT_STACK_PUSH: case OFPACT_STACK_POP: case OFPACT_DEC_TTL: @@ -2458,6 +2465,26 @@ struct onf_action_copy_field { * The "pad3" member is the beginning of the above. */ uint8_t pad3[4]; /* Not used. */ }; + +/* Action structure for OpenFlow 1.3 extension copy-field action.. */ +struct opk_action_swap_field { + ovs_be16 type; /* OFPAT_EXPERIMENTER. */ + ovs_be16 len; /* Length is padded to 64 bits. */ + ovs_be32 experimenter; /* OPK_VENDOR_ID. */ + ovs_be16 exp_type; /* 3201. */ + uint8_t pad[2]; /* Not used. */ + ovs_be16 n_bits; /* Number of bits to copy. */ + ovs_be16 src_offset; /* Starting bit offset in source. */ + ovs_be16 dst_offset; /* Starting bit offset in destination. */ + uint8_t pad2[2]; /* Not used. */ + /* Followed by: + * - OXM header for source field. + * - OXM header for destination field. + * - Padding with 0-bytes (either 0 or 4 of them) to a multiple of 8 bytes. + * The "pad3" member is the beginning of the above. */ + uint8_t pad3[4]; /* Not used. */ +}; + OFP_ASSERT(sizeof(struct onf_action_copy_field) == 24); /* Action structure for NXAST_REG_MOVE. @@ -2607,6 +2634,42 @@ decode_copy_field__(ovs_be16 src_offset, ovs_be16 dst_offset, ovs_be16 n_bits, return nxm_reg_move_check(move, NULL); } +static enum ofperr +decode_swap_field__(ovs_be16 src_offset, ovs_be16 dst_offset, ovs_be16 n_bits, + const void *action, ovs_be16 action_len, size_t oxm_offset, + const struct vl_mff_map *vl_mff_map, + uint64_t *tlv_bitmap, struct ofpbuf *ofpacts) +{ + struct ofpact_swap_field *swap = ofpact_put_SWAP_FIELD(ofpacts); + enum ofperr error; + + swap->ofpact.raw = ONFACT_RAW13_COPY_FIELD; + swap->src.ofs = ntohs(src_offset); + swap->src.n_bits = ntohs(n_bits); + swap->dst.ofs = ntohs(dst_offset); + swap->dst.n_bits = ntohs(n_bits); + + struct ofpbuf b = ofpbuf_const_initializer(action, ntohs(action_len)); + ofpbuf_pull(&b, oxm_offset); + + error = mf_vl_mff_nx_pull_header(&b, vl_mff_map, &swap->src.field, NULL, + tlv_bitmap); + if (error) { + return error; + } + error = mf_vl_mff_nx_pull_header(&b, vl_mff_map, &swap->dst.field, NULL, + tlv_bitmap); + if (error) { + return error; + } + + if (!is_all_zeros(b.data, b.size)) { + return OFPERR_NXBRC_MUST_BE_ZERO; + } + + return nxm_swap_field_check(swap, NULL); +} + static enum ofperr decode_OFPAT_RAW15_COPY_FIELD(const struct ofp15_action_copy_field *oacf, enum ofp_version ofp_version OVS_UNUSED, @@ -2619,6 +2682,18 @@ decode_OFPAT_RAW15_COPY_FIELD(const struct ofp15_action_copy_field *oacf, tlv_bitmap, ofpacts); } +static enum ofperr +decode_OPK_RAW13_SWAP_FIELD(const struct opk_action_swap_field *oasf, + enum ofp_version ofp_version OVS_UNUSED, + const struct vl_mff_map *vl_mff_map, + uint64_t *tlv_bitmap, struct ofpbuf *ofpacts) +{ + return decode_swap_field__(oasf->src_offset, oasf->dst_offset, + oasf->n_bits, oasf, oasf->len, + OBJECT_OFFSETOF(oasf, pad3), vl_mff_map, + tlv_bitmap, ofpacts); +} + static enum ofperr decode_ONFACT_RAW13_COPY_FIELD(const struct onf_action_copy_field *oacf, enum ofp_version ofp_version OVS_UNUSED, @@ -2707,6 +2782,24 @@ encode_REG_MOVE(const struct ofpact_reg_move *move, pad_ofpat(out, start_ofs); } +static void +encode_SWAP_FIELD(const struct ofpact_swap_field *swap, + enum ofp_version ofp_version, struct ofpbuf *out) +{ + size_t start_ofs = out->size; + + struct opk_action_swap_field *swap_action = put_OPK13_SWAP_FIELD(out); + swap_action->n_bits = htons(swap->dst.n_bits); + swap_action->src_offset = htons(swap->src.ofs); + swap_action->dst_offset = htons(swap->dst.ofs); + out->size = out->size - sizeof swap_action->pad3; + nx_put_mff_header(out, swap->src.field, ofp_version, false); + nx_put_mff_header(out, swap->dst.field, ofp_version, false); + + pad_ofpat(out, start_ofs); +} + + static char * OVS_WARN_UNUSED_RESULT parse_REG_MOVE(const char *arg, const struct ofpact_parse_params *pp) { @@ -2727,6 +2820,28 @@ check_REG_MOVE(const struct ofpact_reg_move *a, { return nxm_reg_move_check(a, cp->match); } + +static char * OVS_WARN_UNUSED_RESULT +parse_SWAP_FIELD(const char *arg, const struct ofpact_parse_params *pp) +{ + struct ofpact_swap_field *swap = ofpact_put_SWAP_FIELD(pp->ofpacts); + return nxm_parse_swap_field(swap, arg); +} + + +static void +format_SWAP_FIELD(const struct ofpact_swap_field *a, + const struct ofpact_format_params *fp) +{ + nxm_format_swap_field(a, fp->s); +} + +static enum ofperr +check_SWAP_FIELD(const struct ofpact_swap_field *a, + const struct ofpact_check_params *cp) +{ + return nxm_swap_field_check(a, cp->match); +} /* Action structure for OFPAT12_SET_FIELD. */ struct ofp12_action_set_field { @@ -7940,6 +8055,7 @@ action_set_classify(const struct ofpact *a) case OFPACT_SET_FIELD: case OFPACT_REG_MOVE: + case OFPACT_SWAP_FIELD: case OFPACT_SET_ETH_DST: case OFPACT_SET_ETH_SRC: case OFPACT_SET_IP_DSCP: @@ -8157,6 +8273,7 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type, case OFPACT_SET_L4_SRC_PORT: case OFPACT_SET_L4_DST_PORT: case OFPACT_REG_MOVE: + case OFPACT_SWAP_FIELD: case OFPACT_SET_FIELD: case OFPACT_STACK_PUSH: case OFPACT_STACK_POP: @@ -8648,6 +8765,10 @@ ofpact_get_mf_dst(const struct ofpact *ofpact) orm = CONTAINER_OF(ofpact, struct ofpact_reg_move, ofpact); return orm->dst.field; + } else if (ofpact->type == OFPACT_SWAP_FIELD) { + const struct ofpact_swap_field *orm; + orm = CONTAINER_OF(ofpact, struct ofpact_swap_field, ofpact); + return orm->dst.field; } return NULL; @@ -9062,6 +9183,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port) case OFPACT_SET_L4_SRC_PORT: case OFPACT_SET_L4_DST_PORT: case OFPACT_REG_MOVE: + case OFPACT_SWAP_FIELD: case OFPACT_SET_FIELD: case OFPACT_STACK_PUSH: case OFPACT_STACK_POP: @@ -9598,7 +9720,8 @@ ofpact_decode_raw(enum ofp_version ofp_version, if (oah->type == htons(OFPAT_VENDOR)) { /* Get vendor. */ hdrs.vendor = ntohl(oah->vendor); - if (hdrs.vendor == NX_VENDOR_ID || hdrs.vendor == ONF_VENDOR_ID) { + if (hdrs.vendor == NX_VENDOR_ID || hdrs.vendor == ONF_VENDOR_ID + || hdrs.vendor == OPK_VENDOR_ID) { /* Get extension subtype. */ const struct ext_action_header *nah; @@ -9725,7 +9848,8 @@ ofpact_put_raw(struct ofpbuf *buf, enum ofp_version ofp_version, break; case NX_VENDOR_ID: - case ONF_VENDOR_ID: { + case ONF_VENDOR_ID: + case OPK_VENDOR_ID: { struct ext_action_header *nah = (struct ext_action_header *) oah; nah->subtype = htons(hdrs->type); break; diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 7108c8a3013..0154619919f 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -5685,6 +5685,7 @@ reversible_actions(const struct ofpact *ofpacts, size_t ofpacts_len) case OFPACT_PUSH_MPLS: case OFPACT_PUSH_VLAN: case OFPACT_REG_MOVE: + case OFPACT_SWAP_FIELD: case OFPACT_RESUBMIT: case OFPACT_SAMPLE: case OFPACT_SET_ETH_DST: @@ -6022,6 +6023,7 @@ freeze_unroll_actions(const struct ofpact *a, const struct ofpact *end, case OFPACT_NAT: case OFPACT_CHECK_PKT_LARGER: case OFPACT_DELETE_FIELD: + case OFPACT_SWAP_FIELD: /* These may not generate PACKET INs. */ break; @@ -6649,6 +6651,7 @@ recirc_for_mpls(const struct ofpact *a, struct xlate_ctx *ctx) case OFPACT_SET_L4_SRC_PORT: case OFPACT_SET_L4_DST_PORT: case OFPACT_REG_MOVE: + case OFPACT_SWAP_FIELD: case OFPACT_STACK_PUSH: case OFPACT_STACK_POP: case OFPACT_DEC_TTL: @@ -6699,6 +6702,14 @@ xlate_ofpact_reg_move(struct xlate_ctx *ctx, const struct ofpact_reg_move *a) xlate_report_subfield(ctx, &a->dst); } +static void +xlate_ofpact_swap_field(struct xlate_ctx *ctx, const struct ofpact_swap_field *a) +{ + mf_subfield_swap(&a->src, &a->dst, &ctx->xin->flow, ctx->wc); + xlate_report_subfield(ctx, &a->dst); +} + + static void xlate_ofpact_stack_pop(struct xlate_ctx *ctx, const struct ofpact_stack *a) { @@ -6943,6 +6954,9 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, case OFPACT_REG_MOVE: xlate_ofpact_reg_move(ctx, ofpact_get_REG_MOVE(a)); break; + case OFPACT_SWAP_FIELD: + xlate_ofpact_swap_field(ctx, ofpact_get_SWAP_FIELD(a)); + break; case OFPACT_SET_FIELD: set_field = ofpact_get_SET_FIELD(a);