X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=lib%2Fofp-actions.c;h=eef3389bb72c82d1b4357614239add76f2c84691;hb=f08e39dd023ff27c32166b76d6906fbf20f78991;hp=7d9ee585ab7c76c788b03302357578fe64137018;hpb=bad8a439942c517d660720bdf2f113493081c336;p=cascardo%2Fovs.git diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index 7d9ee585a..eef3389bb 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,7 @@ #include "ofpbuf.h" #include "unaligned.h" #include "util.h" -#include "vlog.h" +#include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(ofp_actions); @@ -218,6 +218,8 @@ enum ofp_raw_action_type { /* OF1.5+(28): struct ofp15_action_copy_field, ... */ OFPAT_RAW15_COPY_FIELD, + /* ONF1.3-1.4(3200): struct onf_action_copy_field, ... */ + ONFACT_RAW13_COPY_FIELD, /* NX1.0-1.4(6): struct nx_action_reg_move, ... */ NXAST_RAW_REG_MOVE, @@ -279,6 +281,9 @@ enum ofp_raw_action_type { /* NX1.0+(29): struct nx_action_sample. */ NXAST_RAW_SAMPLE, + + /* NX1.0+(34): struct nx_action_conjunction. */ + NXAST_RAW_CONJUNCTION, }; /* OpenFlow actions are always a multiple of 8 bytes in length. */ @@ -326,7 +331,7 @@ static enum ofperr ofpact_pull_raw(struct ofpbuf *, enum ofp_version, static void *ofpact_put_raw(struct ofpbuf *, enum ofp_version, enum ofp_raw_action_type, uint64_t arg); -static char *WARN_UNUSED_RESULT ofpacts_parse( +static char *OVS_WARN_UNUSED_RESULT ofpacts_parse( char *str, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols, bool allow_instructions); @@ -409,7 +414,7 @@ encode_OUTPUT(const struct ofpact_output *output, } } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_OUTPUT(const char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -464,7 +469,7 @@ encode_GROUP(const struct ofpact_group *group, } } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_GROUP(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -527,7 +532,7 @@ encode_CONTROLLER(const struct ofpact_controller *controller, nac->reason = controller->reason; } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_CONTROLLER(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -656,7 +661,7 @@ encode_ENQUEUE(const struct ofpact_enqueue *enqueue, } } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_ENQUEUE(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -776,7 +781,7 @@ decode_NXAST_RAW_OUTPUT_REG2(const struct nx_action_output_reg2 *naor, if (error) { return error; } - if (!is_all_zeros(ofpbuf_data(&b), ofpbuf_size(&b))) { + if (!is_all_zeros(b.data, b.size)) { return OFPERR_NXBRC_MUST_BE_ZERO; } @@ -794,15 +799,15 @@ encode_OUTPUT_REG(const struct ofpact_output_reg *output_reg, if (output_reg->ofpact.raw == NXAST_RAW_OUTPUT_REG2 || !mf_nxm_header(output_reg->src.field->id)) { struct nx_action_output_reg2 *naor = put_NXAST_OUTPUT_REG2(out); - size_t size = ofpbuf_size(out); + size_t size = out->size; naor->ofs_nbits = nxm_encode_ofs_nbits(output_reg->src.ofs, output_reg->src.n_bits); naor->max_len = htons(output_reg->max_len); - ofpbuf_set_size(out, size - sizeof naor->pad); + out->size = size - sizeof naor->pad; nx_put_header(out, output_reg->src.field->id, 0, false); - ofpbuf_set_size(out, size); + out->size = size; } else { struct nx_action_output_reg *naor = put_NXAST_OUTPUT_REG(out); @@ -813,7 +818,7 @@ encode_OUTPUT_REG(const struct ofpact_output_reg *output_reg, } } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_OUTPUT_REG(const char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -964,7 +969,7 @@ decode_bundle(bool load, const struct nx_action_bundle *nab, ofpbuf_put(ofpacts, &ofp_port, sizeof ofp_port); } - bundle = ofpacts->frame; + bundle = ofpacts->header; ofpact_update_len(ofpacts, &bundle->ofpact); if (!error) { @@ -1017,14 +1022,14 @@ encode_BUNDLE(const struct ofpact_bundle *bundle, } } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_BUNDLE(const char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { return bundle_parse(arg, ofpacts); } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_bundle_load(const char *arg, struct ofpbuf *ofpacts) { return bundle_parse_load(arg, ofpacts); @@ -1087,7 +1092,7 @@ encode_SET_VLAN_VID(const struct ofpact_vlan_vid *vlan_vid, } } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_set_vlan_vid(char *arg, struct ofpbuf *ofpacts, bool push_vlan_if_needed) { struct ofpact_vlan_vid *vlan_vid; @@ -1108,7 +1113,7 @@ parse_set_vlan_vid(char *arg, struct ofpbuf *ofpacts, bool push_vlan_if_needed) return NULL; } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_SET_VLAN_VID(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -1173,7 +1178,7 @@ encode_SET_VLAN_PCP(const struct ofpact_vlan_pcp *vlan_pcp, } } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_set_vlan_pcp(char *arg, struct ofpbuf *ofpacts, bool push_vlan_if_needed) { struct ofpact_vlan_pcp *vlan_pcp; @@ -1194,7 +1199,7 @@ parse_set_vlan_pcp(char *arg, struct ofpbuf *ofpacts, bool push_vlan_if_needed) return NULL; } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_SET_VLAN_PCP(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -1236,7 +1241,7 @@ encode_STRIP_VLAN(const struct ofpact_null *null OVS_UNUSED, } } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_STRIP_VLAN(char *arg OVS_UNUSED, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -1244,7 +1249,7 @@ parse_STRIP_VLAN(char *arg OVS_UNUSED, struct ofpbuf *ofpacts, return NULL; } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_pop_vlan(struct ofpbuf *ofpacts) { ofpact_put_STRIP_VLAN(ofpacts)->ofpact.raw = OFPAT_RAW11_POP_VLAN; @@ -1285,7 +1290,7 @@ encode_PUSH_VLAN(const struct ofpact_null *null OVS_UNUSED, } } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_PUSH_VLAN(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -1376,14 +1381,14 @@ encode_SET_ETH_DST(const struct ofpact_mac *mac, } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_SET_ETH_SRC(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { return str_to_mac(arg, ofpact_put_SET_ETH_SRC(ofpacts)->mac); } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_SET_ETH_DST(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -1448,14 +1453,14 @@ encode_SET_IPV4_DST(const struct ofpact_ipv4 *ipv4, out); } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_SET_IPV4_SRC(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { return str_to_ip(arg, &ofpact_put_SET_IPV4_SRC(ofpacts)->ipv4); } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_SET_IPV4_DST(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -1499,7 +1504,7 @@ encode_SET_IP_DSCP(const struct ofpact_dscp *dscp, } } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_SET_IP_DSCP(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -1551,7 +1556,7 @@ encode_SET_IP_ECN(const struct ofpact_ecn *ip_ecn, } } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_SET_IP_ECN(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -1596,7 +1601,7 @@ encode_SET_IP_TTL(const struct ofpact_ip_ttl *ttl, } } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_SET_IP_TTL(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -1675,7 +1680,7 @@ encode_SET_L4_DST_PORT(const struct ofpact_l4_port *l4_port, encode_SET_L4_port(l4_port, ofp_version, OFPAT_RAW_SET_TP_DST, field, out); } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_SET_L4_SRC_PORT(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -1683,7 +1688,7 @@ parse_SET_L4_SRC_PORT(char *arg, struct ofpbuf *ofpacts, &ofpact_put_SET_L4_SRC_PORT(ofpacts)->port); } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_SET_L4_DST_PORT(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -1710,16 +1715,36 @@ struct ofp15_action_copy_field { 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. */ - ovs_be16 oxm_id_len; /* Length of oxm_ids. */ + uint8_t pad[2]; /* Followed by: * - OXM header for source field. * - OXM header for destination field. * - Padding with 0-bytes to a multiple of 8 bytes. - * The "pad" member is the beginning of the above. */ - uint8_t pad[4]; + * The "pad2" member is the beginning of the above. */ + uint8_t pad2[4]; }; OFP_ASSERT(sizeof(struct ofp15_action_copy_field) == 16); +/* Action structure for OpenFlow 1.3 extension copy-field action.. */ +struct onf_action_copy_field { + ovs_be16 type; /* OFPAT_EXPERIMENTER. */ + ovs_be16 len; /* Length is padded to 64 bits. */ + ovs_be32 experimenter; /* ONF_VENDOR_ID. */ + ovs_be16 exp_type; /* 3200. */ + 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. * * Copies src[src_ofs:src_ofs+n_bits] to dst[dst_ofs:dst_ofs+n_bits], where @@ -1828,23 +1853,23 @@ struct nx_action_reg_move { OFP_ASSERT(sizeof(struct nx_action_reg_move) == 16); static enum ofperr -decode_OFPAT_RAW15_COPY_FIELD(const struct ofp15_action_copy_field *oacf, - struct ofpbuf *ofpacts) +decode_copy_field__(ovs_be16 src_offset, ovs_be16 dst_offset, ovs_be16 n_bits, + const void *action, ovs_be16 action_len, size_t oxm_offset, + struct ofpbuf *ofpacts) { struct ofpact_reg_move *move; enum ofperr error; - size_t orig_size; struct ofpbuf b; move = ofpact_put_REG_MOVE(ofpacts); - move->src.ofs = ntohs(oacf->src_offset); - move->src.n_bits = ntohs(oacf->n_bits); - move->dst.ofs = ntohs(oacf->dst_offset); - move->dst.n_bits = ntohs(oacf->n_bits); - - ofpbuf_use_const(&b, oacf, ntohs(oacf->len)); - ofpbuf_pull(&b, offsetof(struct ofp15_action_copy_field, pad)); - orig_size = ofpbuf_size(&b); + move->ofpact.raw = ONFACT_RAW13_COPY_FIELD; + move->src.ofs = ntohs(src_offset); + move->src.n_bits = ntohs(n_bits); + move->dst.ofs = ntohs(dst_offset); + move->dst.n_bits = ntohs(n_bits); + + ofpbuf_use_const(&b, action, ntohs(action_len)); + ofpbuf_pull(&b, oxm_offset); error = nx_pull_header(&b, &move->src.field, NULL); if (error) { return error; @@ -1853,17 +1878,32 @@ decode_OFPAT_RAW15_COPY_FIELD(const struct ofp15_action_copy_field *oacf, if (error) { return error; } - if (orig_size - ofpbuf_size(&b) != ntohs(oacf->oxm_id_len)) { - return OFPERR_OFPBAC_BAD_LEN; - } - if (!is_all_zeros(ofpbuf_data(&b), ofpbuf_size(&b))) { + if (!is_all_zeros(b.data, b.size)) { return OFPERR_NXBRC_MUST_BE_ZERO; } return nxm_reg_move_check(move, NULL); } +static enum ofperr +decode_OFPAT_RAW15_COPY_FIELD(const struct ofp15_action_copy_field *oacf, + struct ofpbuf *ofpacts) +{ + return decode_copy_field__(oacf->src_offset, oacf->dst_offset, + oacf->n_bits, oacf, oacf->len, + OBJECT_OFFSETOF(oacf, pad2), ofpacts); +} + +static enum ofperr +decode_ONFACT_RAW13_COPY_FIELD(const struct onf_action_copy_field *oacf, + struct ofpbuf *ofpacts) +{ + return decode_copy_field__(oacf->src_offset, oacf->dst_offset, + oacf->n_bits, oacf, oacf->len, + OBJECT_OFFSETOF(oacf, pad3), ofpacts); +} + static enum ofperr decode_NXAST_RAW_REG_MOVE(const struct nx_action_reg_move *narm, struct ofpbuf *ofpacts) @@ -1873,6 +1913,7 @@ decode_NXAST_RAW_REG_MOVE(const struct nx_action_reg_move *narm, struct ofpbuf b; move = ofpact_put_REG_MOVE(ofpacts); + move->ofpact.raw = NXAST_RAW_REG_MOVE; move->src.ofs = ntohs(narm->src_ofs); move->src.n_bits = ntohs(narm->n_bits); move->dst.ofs = ntohs(narm->dst_ofs); @@ -1888,7 +1929,7 @@ decode_NXAST_RAW_REG_MOVE(const struct nx_action_reg_move *narm, if (error) { return error; } - if (!is_all_zeros(ofpbuf_data(&b), ofpbuf_size(&b))) { + if (!is_all_zeros(b.data, b.size)) { return OFPERR_NXBRC_MUST_BE_ZERO; } @@ -1899,14 +1940,28 @@ static void encode_REG_MOVE(const struct ofpact_reg_move *move, enum ofp_version ofp_version, struct ofpbuf *out) { - size_t start_ofs = ofpbuf_size(out); + /* For OpenFlow 1.3, the choice of ONFACT_RAW13_COPY_FIELD versus + * NXAST_RAW_REG_MOVE is somewhat difficult. Neither one is guaranteed to + * be supported by every OpenFlow 1.3 implementation. It would be ideal to + * probe for support. Until we have that ability, we currently prefer + * NXAST_RAW_REG_MOVE for backward compatibility with older Open vSwitch + * versions. */ + size_t start_ofs = out->size; if (ofp_version >= OFP15_VERSION) { struct ofp15_action_copy_field *copy = put_OFPAT15_COPY_FIELD(out); copy->n_bits = htons(move->dst.n_bits); copy->src_offset = htons(move->src.ofs); copy->dst_offset = htons(move->dst.ofs); - copy->oxm_id_len = htons(8); - ofpbuf_set_size(out, ofpbuf_size(out) - sizeof copy->pad); + out->size = out->size - sizeof copy->pad2; + nx_put_header(out, move->src.field->id, ofp_version, false); + nx_put_header(out, move->dst.field->id, ofp_version, false); + } else if (ofp_version == OFP13_VERSION + && move->ofpact.raw == ONFACT_RAW13_COPY_FIELD) { + struct onf_action_copy_field *copy = put_ONFACT13_COPY_FIELD(out); + copy->n_bits = htons(move->dst.n_bits); + copy->src_offset = htons(move->src.ofs); + copy->dst_offset = htons(move->dst.ofs); + out->size = out->size - sizeof copy->pad3; nx_put_header(out, move->src.field->id, ofp_version, false); nx_put_header(out, move->dst.field->id, ofp_version, false); } else { @@ -1920,7 +1975,7 @@ encode_REG_MOVE(const struct ofpact_reg_move *move, pad_ofpat(out, start_ofs); } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_REG_MOVE(const char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -2049,7 +2104,7 @@ decode_ofpat_set_field(const struct ofp12_action_set_field *oasf, memset(&sf->mask, 0xff, sf->field->n_bytes); } - if (!is_all_zeros(ofpbuf_data(&b), ofpbuf_size(&b))) { + if (!is_all_zeros(b.data, b.size)) { return OFPERR_OFPBAC_BAD_SET_ARGUMENT; } @@ -2066,7 +2121,7 @@ decode_ofpat_set_field(const struct ofp12_action_set_field *oasf, return OFPERR_OFPBAC_BAD_SET_ARGUMENT; } - /* The value must be valid for match. The OpenFlow 1.5 draft also says, + /* The value must be valid for match. OpenFlow 1.5 also says, * "In an OXM_OF_VLAN_VID set-field action, the OFPVID_PRESENT bit must be * a 1-bit in oxm_value and in oxm_mask." */ if (!mf_is_value_valid(sf->field, &sf->value) @@ -2150,7 +2205,7 @@ decode_NXAST_RAW_REG_LOAD2(const struct nx_action_reg_load2 *narl, if (error) { return error; } - if (!is_all_zeros(ofpbuf_data(&b), ofpbuf_size(&b))) { + if (!is_all_zeros(b.data, b.size)) { return OFPERR_OFPBAC_BAD_SET_ARGUMENT; } @@ -2168,13 +2223,13 @@ ofpact_put_set_field(struct ofpbuf *openflow, enum ofp_version ofp_version, { struct ofp12_action_set_field *oasf OVS_UNUSED; int n_bytes = mf_from_id(field)->n_bytes; - size_t start_ofs = ofpbuf_size(openflow); + size_t start_ofs = openflow->size; union mf_value value; value.be64 = htonll(value_ << (8 * (8 - n_bytes))); oasf = put_OFPAT12_SET_FIELD(openflow); - ofpbuf_set_size(openflow, ofpbuf_size(openflow) - sizeof oasf->pad); + openflow->size = openflow->size - sizeof oasf->pad; nx_put_entry(openflow, field, ofp_version, &value, NULL); pad_ofpat(openflow, start_ofs); } @@ -2183,16 +2238,17 @@ static bool next_load_segment(const struct ofpact_set_field *sf, struct mf_subfield *dst, uint64_t *value) { - int w = sf->field->n_bytes; + int n_bits = sf->field->n_bits; + int n_bytes = sf->field->n_bytes; int start = dst->ofs + dst->n_bits; - if (start < 8 * w) { + if (start < n_bits) { dst->field = sf->field; - dst->ofs = bitwise_scan(&sf->mask, w, 1, start, 8 * w); - if (dst->ofs < 8 * w) { - dst->n_bits = bitwise_scan(&sf->mask, w, 0, dst->ofs + 1, - MIN(dst->ofs + 64, 8 * w)) - dst->ofs; - *value = bitwise_get(&sf->value, w, dst->ofs, dst->n_bits); + dst->ofs = bitwise_scan(&sf->mask, n_bytes, 1, start, n_bits); + if (dst->ofs < n_bits) { + dst->n_bits = bitwise_scan(&sf->mask, n_bytes, 0, dst->ofs + 1, + MIN(dst->ofs + 64, n_bits)) - dst->ofs; + *value = bitwise_get(&sf->value, n_bytes, dst->ofs, dst->n_bits); return true; } } @@ -2210,10 +2266,10 @@ set_field_to_nxast(const struct ofpact_set_field *sf, struct ofpbuf *openflow) if (sf->ofpact.raw == NXAST_RAW_REG_LOAD2 || !mf_nxm_header(sf->field->id)) { struct nx_action_reg_load2 *narl OVS_UNUSED; - size_t start_ofs = ofpbuf_size(openflow); + size_t start_ofs = openflow->size; narl = put_NXAST_REG_LOAD2(openflow); - ofpbuf_set_size(openflow, ofpbuf_size(openflow) - sizeof narl->pad); + openflow->size = openflow->size - sizeof narl->pad; nx_put_entry(openflow, sf->field->id, 0, &sf->value, &sf->mask); pad_ofpat(openflow, start_ofs); } else { @@ -2356,10 +2412,10 @@ set_field_to_set_field(const struct ofpact_set_field *sf, enum ofp_version ofp_version, struct ofpbuf *out) { struct ofp12_action_set_field *oasf OVS_UNUSED; - size_t start_ofs = ofpbuf_size(out); + size_t start_ofs = out->size; oasf = put_OFPAT12_SET_FIELD(out); - ofpbuf_set_size(out, ofpbuf_size(out) - sizeof oasf->pad); + out->size = out->size - sizeof oasf->pad; nx_put_entry(out, sf->field->id, ofp_version, &sf->value, &sf->mask); pad_ofpat(out, start_ofs); } @@ -2396,7 +2452,7 @@ encode_SET_FIELD(const struct ofpact_set_field *sf, * * Returns NULL if successful, otherwise a malloc()'d string describing the * error. The caller is responsible for freeing the returned string. */ -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT set_field_parse__(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols) { @@ -2444,7 +2500,7 @@ set_field_parse__(char *arg, struct ofpbuf *ofpacts, * * Returns NULL if successful, otherwise a malloc()'d string describing the * error. The caller is responsible for freeing the returned string. */ -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_SET_FIELD(const char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols) { @@ -2454,7 +2510,7 @@ parse_SET_FIELD(const char *arg, struct ofpbuf *ofpacts, return error; } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_reg_load(char *arg, struct ofpbuf *ofpacts) { struct ofpact_set_field *sf = ofpact_put_reg_load(ofpacts); @@ -2553,9 +2609,9 @@ decode_stack_action(const struct nx_action_stack *nasp, if (error) { return error; } - stack_action->subfield.n_bits = ntohs(*(const ovs_be16 *) ofpbuf_data(&b)); + stack_action->subfield.n_bits = ntohs(*(const ovs_be16 *) b.data); ofpbuf_pull(&b, 2); - if (!is_all_zeros(ofpbuf_data(&b), ofpbuf_size(&b))) { + if (!is_all_zeros(b.data, b.size)) { return OFPERR_NXBRC_MUST_BE_ZERO; } @@ -2610,14 +2666,14 @@ encode_STACK_POP(const struct ofpact_stack *stack, encode_STACK_op(stack, put_NXAST_STACK_POP(out)); } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_STACK_PUSH(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { return nxm_parse_stack_action(ofpact_put_STACK_PUSH(ofpacts), arg); } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_STACK_POP(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -2673,7 +2729,7 @@ decode_OFPAT_RAW_DEC_NW_TTL(struct ofpbuf *out) ids = ofpact_put_DEC_TTL(out); ids->n_controllers = 1; ofpbuf_put(out, &id, sizeof id); - ids = out->frame; + ids = out->header; ofpact_update_len(out, &ids->ofpact); return error; } @@ -2707,7 +2763,7 @@ decode_NXAST_RAW_DEC_TTL_CNT_IDS(const struct nx_action_cnt_ids *nac_ids, for (i = 0; i < ids->n_controllers; i++) { uint16_t id = ntohs(((ovs_be16 *)(nac_ids + 1))[i]); ofpbuf_put(out, &id, sizeof id); - ids = out->frame; + ids = out->header; } ofpact_update_len(out, &ids->ofpact); @@ -2747,12 +2803,12 @@ parse_noargs_dec_ttl(struct ofpbuf *ofpacts) ofpact_put_DEC_TTL(ofpacts); ofpbuf_put(ofpacts, &id, sizeof id); - ids = ofpacts->frame; + ids = ofpacts->header; ids->n_controllers++; ofpact_update_len(ofpacts, &ids->ofpact); } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_DEC_TTL(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -2769,7 +2825,7 @@ parse_DEC_TTL(char *arg, struct ofpbuf *ofpacts, uint16_t id = atoi(cntr); ofpbuf_put(ofpacts, &id, sizeof id); - ids = ofpacts->frame; + ids = ofpacts->header; ids->n_controllers++; } if (!ids->n_controllers) { @@ -2821,7 +2877,7 @@ encode_SET_MPLS_LABEL(const struct ofpact_mpls_label *label, } } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_SET_MPLS_LABEL(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -2860,7 +2916,7 @@ encode_SET_MPLS_TC(const struct ofpact_mpls_tc *tc, } } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_SET_MPLS_TC(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -2901,7 +2957,7 @@ encode_SET_MPLS_TTL(const struct ofpact_mpls_ttl *ttl, * * Returns NULL if successful, otherwise a malloc()'d string describing the * error. The caller is responsible for freeing the returned string. */ -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_SET_MPLS_TTL(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -2937,7 +2993,7 @@ encode_DEC_MPLS_TTL(const struct ofpact_null *null OVS_UNUSED, put_OFPAT_DEC_MPLS_TTL(out, ofp_version); } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_DEC_MPLS_TTL(char *arg OVS_UNUSED, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -2974,7 +3030,7 @@ encode_PUSH_MPLS(const struct ofpact_push_mpls *push_mpls, put_OFPAT_PUSH_MPLS(out, ofp_version, push_mpls->ethertype); } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_PUSH_MPLS(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -3010,7 +3066,7 @@ encode_POP_MPLS(const struct ofpact_pop_mpls *pop_mpls, put_OFPAT_POP_MPLS(out, ofp_version, pop_mpls->ethertype); } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_POP_MPLS(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -3068,7 +3124,7 @@ encode_SET_TUNNEL(const struct ofpact_tunnel *tunnel, } } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_set_tunnel(char *arg, struct ofpbuf *ofpacts, enum ofp_raw_action_type raw) { @@ -3079,7 +3135,7 @@ parse_set_tunnel(char *arg, struct ofpbuf *ofpacts, return str_to_u64(arg, &tunnel->tun_id); } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_SET_TUNNEL(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -3111,7 +3167,7 @@ encode_SET_QUEUE(const struct ofpact_queue *queue, put_OFPAT_SET_QUEUE(out, ofp_version, queue->queue_id); } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_SET_QUEUE(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -3140,7 +3196,7 @@ encode_POP_QUEUE(const struct ofpact_null *null OVS_UNUSED, put_NXAST_POP_QUEUE(out); } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_POP_QUEUE(const char *arg OVS_UNUSED, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -3210,7 +3266,7 @@ encode_FIN_TIMEOUT(const struct ofpact_fin_timeout *fin_timeout, naft->fin_hard_timeout = htons(fin_timeout->fin_hard_timeout); } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_FIN_TIMEOUT(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -3352,7 +3408,7 @@ encode_RESUBMIT(const struct ofpact_resubmit *resubmit, } } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_RESUBMIT(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -3604,7 +3660,24 @@ format_RESUBMIT(const struct ofpact_resubmit *a, struct ds *s) * address. This is not usually the intent in MAC learning; instead, we want * the MAC learn entry to expire when no traffic has been sent *from* the * learned address. Use a hard timeout for that. - */ + * + * + * Visibility of Changes + * --------------------- + * + * Prior to Open vSwitch 2.4, any changes made by a "learn" action in a given + * flow translation are visible to flow table lookups made later in the flow + * translation. This means that, in the example above, a MAC learned by the + * learn action in table 0 would be found in table 1 (if the packet being + * processed had the same source and destination MAC address). + * + * In Open vSwitch 2.4 and later, changes to a flow table (whether to add or + * modify a flow) by a "learn" action are visible only for later flow + * translations, not for later lookups within the same flow translation. In + * the MAC learning example, a MAC learned by the learn action in table 0 would + * not be found in table 1 if the flow translation would resubmit to table 1 + * after the processing of the learn action, meaning that if this MAC had not + * been learned before then the packet would be flooded. */ struct nx_action_learn { ovs_be16 type; /* OFPAT_VENDOR. */ ovs_be16 len; /* At least 24. */ @@ -3716,7 +3789,7 @@ decode_NXAST_RAW_LEARN(const struct nx_action_learn *nal, } spec = ofpbuf_put_zeros(ofpacts, sizeof *spec); - learn = ofpacts->frame; + learn = ofpacts->header; learn->n_specs++; spec->src_type = header & NX_LEARN_SRC_MASK; @@ -3797,7 +3870,7 @@ encode_LEARN(const struct ofpact_learn *learn, struct nx_action_learn *nal; size_t start_ofs; - start_ofs = ofpbuf_size(out); + start_ofs = out->size; nal = put_NXAST_LEARN(out); nal->idle_timeout = htons(learn->idle_timeout); nal->hard_timeout = htons(learn->hard_timeout); @@ -3832,7 +3905,7 @@ encode_LEARN(const struct ofpact_learn *learn, pad_ofpat(out, start_ofs); } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_LEARN(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -3845,6 +3918,89 @@ format_LEARN(const struct ofpact_learn *a, struct ds *s) learn_format(a, s); } +/* Action structure for NXAST_CONJUNCTION. */ +struct nx_action_conjunction { + ovs_be16 type; /* OFPAT_VENDOR. */ + ovs_be16 len; /* At least 16. */ + ovs_be32 vendor; /* NX_VENDOR_ID. */ + ovs_be16 subtype; /* See enum ofp_raw_action_type. */ + uint8_t clause; + uint8_t n_clauses; + ovs_be32 id; +}; +OFP_ASSERT(sizeof(struct nx_action_conjunction) == 16); + +static void +add_conjunction(struct ofpbuf *out, + uint32_t id, uint8_t clause, uint8_t n_clauses) +{ + struct ofpact_conjunction *oc; + + oc = ofpact_put_CONJUNCTION(out); + oc->id = id; + oc->clause = clause; + oc->n_clauses = n_clauses; +} + +static enum ofperr +decode_NXAST_RAW_CONJUNCTION(const struct nx_action_conjunction *nac, + struct ofpbuf *out) +{ + if (nac->n_clauses < 2 || nac->n_clauses > 64 + || nac->clause >= nac->n_clauses) { + return OFPERR_NXBAC_BAD_CONJUNCTION; + } else { + add_conjunction(out, ntohl(nac->id), nac->clause, nac->n_clauses); + return 0; + } +} + +static void +encode_CONJUNCTION(const struct ofpact_conjunction *oc, + enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) +{ + struct nx_action_conjunction *nac = put_NXAST_CONJUNCTION(out); + nac->clause = oc->clause; + nac->n_clauses = oc->n_clauses; + nac->id = htonl(oc->id); +} + +static void +format_CONJUNCTION(const struct ofpact_conjunction *oc, struct ds *s) +{ + ds_put_format(s, "conjunction(%"PRIu32",%"PRIu8"/%"PRIu8")", + oc->id, oc->clause + 1, oc->n_clauses); +} + +static char * OVS_WARN_UNUSED_RESULT +parse_CONJUNCTION(const char *arg, struct ofpbuf *ofpacts, + enum ofputil_protocol *usable_protocols OVS_UNUSED) +{ + uint8_t n_clauses; + uint8_t clause; + uint32_t id; + int n; + + if (!ovs_scan(arg, "%"SCNi32" , %"SCNu8" / %"SCNu8" %n", + &id, &clause, &n_clauses, &n) || n != strlen(arg)) { + return xstrdup("\"conjunction\" syntax is \"conjunction(id,i/n)\""); + } + + if (n_clauses < 2) { + return xstrdup("conjunction must have at least 2 clauses"); + } else if (n_clauses > 64) { + return xstrdup("conjunction must have at most 64 clauses"); + } else if (clause < 1) { + return xstrdup("clause index must be positive"); + } else if (clause > n_clauses) { + return xstrdup("clause index must be less than or equal to " + "number of clauses"); + } + + add_conjunction(ofpacts, id, clause - 1, n_clauses); + return NULL; +} + /* Action structure for NXAST_MULTIPATH. * * This action performs the following steps in sequence: @@ -3952,7 +4108,7 @@ encode_MULTIPATH(const struct ofpact_multipath *mp, nam->dst = htonl(mf_nxm_header(mp->dst.field->id)); } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_MULTIPATH(const char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -4002,26 +4158,26 @@ static void encode_NOTE(const struct ofpact_note *note, enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) { - size_t start_ofs = ofpbuf_size(out); + size_t start_ofs = out->size; struct nx_action_note *nan; unsigned int remainder; unsigned int len; put_NXAST_NOTE(out); - ofpbuf_set_size(out, ofpbuf_size(out) - sizeof nan->note); + out->size = out->size - sizeof nan->note; ofpbuf_put(out, note->data, note->length); - len = ofpbuf_size(out) - start_ofs; + len = out->size - start_ofs; remainder = len % OFP_ACTION_ALIGN; if (remainder) { ofpbuf_put_zeros(out, OFP_ACTION_ALIGN - remainder); } nan = ofpbuf_at(out, start_ofs, sizeof *nan); - nan->len = htons(ofpbuf_size(out) - start_ofs); + nan->len = htons(out->size - start_ofs); } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_NOTE(const char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -4045,7 +4201,7 @@ parse_NOTE(const char *arg, struct ofpbuf *ofpacts, } ofpbuf_put(ofpacts, &byte, 1); - note = ofpacts->frame; + note = ofpacts->header; note->length++; arg += 2; @@ -4084,7 +4240,7 @@ encode_EXIT(const struct ofpact_null *null OVS_UNUSED, put_NXAST_EXIT(out); } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_EXIT(char *arg OVS_UNUSED, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -4098,6 +4254,31 @@ format_EXIT(const struct ofpact_null *a OVS_UNUSED, struct ds *s) ds_put_cstr(s, "exit"); } +/* Unroll xlate action. */ + +static void +encode_UNROLL_XLATE(const struct ofpact_unroll_xlate *unroll OVS_UNUSED, + enum ofp_version ofp_version OVS_UNUSED, + struct ofpbuf *out OVS_UNUSED) +{ + OVS_NOT_REACHED(); +} + +static char * OVS_WARN_UNUSED_RESULT +parse_UNROLL_XLATE(char *arg OVS_UNUSED, struct ofpbuf *ofpacts OVS_UNUSED, + enum ofputil_protocol *usable_protocols OVS_UNUSED) +{ + OVS_NOT_REACHED(); + return NULL; +} + +static void +format_UNROLL_XLATE(const struct ofpact_unroll_xlate *a OVS_UNUSED, + struct ds *s) +{ + ds_put_cstr(s, "unroll_xlate"); +} + /* Action structure for NXAST_SAMPLE. * * Samples matching packets with the given probability and sends them @@ -4159,7 +4340,7 @@ encode_SAMPLE(const struct ofpact_sample *sample, * * Returns NULL if successful, otherwise a malloc()'d string describing the * error. The caller is responsible for freeing the returned string. */ -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_SAMPLE(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -4214,7 +4395,7 @@ encode_METER(const struct ofpact_meter *meter, } } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_METER(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols) { @@ -4240,7 +4421,7 @@ encode_CLEAR_ACTIONS(const struct ofpact_null *null OVS_UNUSED, } } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_CLEAR_ACTIONS(char *arg OVS_UNUSED, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -4261,7 +4442,7 @@ encode_WRITE_ACTIONS(const struct ofpact_nest *actions, enum ofp_version ofp_version, struct ofpbuf *out) { if (ofp_version > OFP10_VERSION) { - const size_t ofs = ofpbuf_size(out); + const size_t ofs = out->size; instruction_put_OFPIT11_WRITE_ACTIONS(out); ofpacts_put_openflow_actions(actions->actions, @@ -4271,7 +4452,7 @@ encode_WRITE_ACTIONS(const struct ofpact_nest *actions, } } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_WRITE_ACTIONS(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols) { @@ -4281,7 +4462,7 @@ parse_WRITE_ACTIONS(char *arg, struct ofpbuf *ofpacts, /* Pull off existing actions or instructions. */ ofpact_pad(ofpacts); - ofs = ofpbuf_size(ofpacts); + ofs = ofpacts->size; ofpbuf_pull(ofpacts, ofs); /* Add a Write-Actions instruction and then pull it off. */ @@ -4299,7 +4480,7 @@ parse_WRITE_ACTIONS(char *arg, struct ofpbuf *ofpacts, /* Put the Write-Actions back on and update its length. */ on = ofpbuf_push_uninit(ofpacts, sizeof *on); - on->ofpact.len = ofpbuf_size(ofpacts); + on->ofpact.len = ofpacts->size; /* Put any previous actions or instructions back on. */ ofpbuf_push_uninit(ofpacts, ofs); @@ -4365,7 +4546,7 @@ encode_WRITE_METADATA(const struct ofpact_metadata *metadata, } } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_WRITE_METADATA(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols) { @@ -4420,7 +4601,7 @@ encode_GOTO_TABLE(const struct ofpact_goto_table *goto_table, } } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT parse_GOTO_TABLE(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols OVS_UNUSED) { @@ -4461,8 +4642,8 @@ ofpacts_decode(const void *actions, size_t actions_len, struct ofpbuf openflow; ofpbuf_use_const(&openflow, actions, actions_len); - while (ofpbuf_size(&openflow)) { - const struct ofp_action_header *action = ofpbuf_data(&openflow); + while (openflow.size) { + const struct ofp_action_header *action = openflow.data; enum ofp_raw_action_type raw; enum ofperr error; uint64_t arg; @@ -4504,7 +4685,7 @@ ofpacts_pull_openflow_actions__(struct ofpbuf *openflow, if (actions == NULL) { VLOG_WARN_RL(&rl, "OpenFlow message actions length %u exceeds " "remaining message length (%"PRIu32")", - actions_len, ofpbuf_size(openflow)); + actions_len, openflow->size); return OFPERR_OFPBRC_BAD_LEN; } @@ -4514,7 +4695,7 @@ ofpacts_pull_openflow_actions__(struct ofpbuf *openflow, return error; } - error = ofpacts_verify(ofpbuf_data(ofpacts), ofpbuf_size(ofpacts), + error = ofpacts_verify(ofpacts->data, ofpacts->size, allowed_ovsinsts); if (error) { ofpbuf_clear(ofpacts); @@ -4587,10 +4768,12 @@ ofpact_is_set_or_move_action(const struct ofpact *a) case OFPACT_DEC_TTL: case OFPACT_ENQUEUE: case OFPACT_EXIT: + case OFPACT_UNROLL_XLATE: case OFPACT_FIN_TIMEOUT: case OFPACT_GOTO_TABLE: case OFPACT_GROUP: case OFPACT_LEARN: + case OFPACT_CONJUNCTION: case OFPACT_METER: case OFPACT_MULTIPATH: case OFPACT_NOTE: @@ -4655,8 +4838,10 @@ ofpact_is_allowed_in_actions_set(const struct ofpact *a) case OFPACT_CONTROLLER: case OFPACT_ENQUEUE: case OFPACT_EXIT: + case OFPACT_UNROLL_XLATE: case OFPACT_FIN_TIMEOUT: case OFPACT_LEARN: + case OFPACT_CONJUNCTION: case OFPACT_MULTIPATH: case OFPACT_NOTE: case OFPACT_OUTPUT_REG: @@ -4695,7 +4880,7 @@ ofpacts_copy_last(struct ofpbuf *out, const struct ofpbuf *in, const struct ofpact *a; target = NULL; - OFPACT_FOR_EACH (a, ofpbuf_data(in), ofpbuf_size(in)) { + OFPACT_FOR_EACH (a, in->data, in->size) { if (a->type == filter) { target = a; } @@ -4714,7 +4899,7 @@ ofpacts_copy_all(struct ofpbuf *out, const struct ofpbuf *in, { const struct ofpact *a; - OFPACT_FOR_EACH (a, ofpbuf_data(in), ofpbuf_size(in)) { + OFPACT_FOR_EACH (a, in->data, in->size) { if (filter(a)) { ofpact_copy(out, a); } @@ -4727,7 +4912,7 @@ ofpacts_copy_all(struct ofpbuf *out, const struct ofpbuf *in, * "Action Set" and "Action List" terms used in OpenFlow 1.1+.) * * In general this involves appending the last instance of each action that is - * adimissible in the action set in the order described in the OpenFlow + * admissible in the action set in the order described in the OpenFlow * specification. * * Exceptions: @@ -4773,7 +4958,7 @@ ofpacts_decode_for_action_set(const struct ofp_action_header *in, { enum ofperr error; struct ofpact *a; - size_t start = ofpbuf_size(out); + size_t start = out->size; error = ofpacts_decode(in, n_in, version, out); @@ -4781,7 +4966,7 @@ ofpacts_decode_for_action_set(const struct ofp_action_header *in, return error; } - OFPACT_FOR_EACH (a, ofpact_end(ofpbuf_data(out), start), ofpbuf_size(out) - start) { + OFPACT_FOR_EACH (a, ofpact_end(out->data, start), out->size - start) { if (!ofpact_is_allowed_in_actions_set(a)) { VLOG_WARN_RL(&rl, "disallowed action in action set"); return OFPERR_OFPBAC_BAD_TYPE; @@ -4872,9 +5057,11 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type) case OFPACT_FIN_TIMEOUT: case OFPACT_RESUBMIT: case OFPACT_LEARN: + case OFPACT_CONJUNCTION: case OFPACT_MULTIPATH: case OFPACT_NOTE: case OFPACT_EXIT: + case OFPACT_UNROLL_XLATE: case OFPACT_SAMPLE: default: return OVSINST_OFPIT11_APPLY_ACTIONS; @@ -5092,7 +5279,7 @@ ofpacts_pull_openflow_instructions(struct ofpbuf *openflow, if (instructions == NULL) { VLOG_WARN_RL(&rl, "OpenFlow message instructions length %u exceeds " "remaining message length (%"PRIu32")", - instructions_len, ofpbuf_size(openflow)); + instructions_len, openflow->size); error = OFPERR_OFPBIC_BAD_LEN; goto exit; } @@ -5137,9 +5324,9 @@ ofpacts_pull_openflow_instructions(struct ofpbuf *openflow, size_t start; ofpact_pad(ofpacts); - start = ofpbuf_size(ofpacts); - on = ofpact_put(ofpacts, OFPACT_WRITE_ACTIONS, - offsetof(struct ofpact_nest, actions)); + start = ofpacts->size; + ofpact_put(ofpacts, OFPACT_WRITE_ACTIONS, + offsetof(struct ofpact_nest, actions)); get_actions_from_instruction(insts[OVSINST_OFPIT11_WRITE_ACTIONS], &actions, &actions_len); error = ofpacts_decode_for_action_set(actions, actions_len, @@ -5148,7 +5335,7 @@ ofpacts_pull_openflow_instructions(struct ofpbuf *openflow, goto exit; } on = ofpbuf_at_assert(ofpacts, start, sizeof *on); - on->ofpact.len = ofpbuf_size(ofpacts) - start; + on->ofpact.len = ofpacts->size - start; } if (insts[OVSINST_OFPIT11_WRITE_METADATA]) { const struct ofp11_instruction_write_metadata *oiwm; @@ -5171,7 +5358,7 @@ ofpacts_pull_openflow_instructions(struct ofpbuf *openflow, ogt->table_id = oigt->table_id; } - error = ofpacts_verify(ofpbuf_data(ofpacts), ofpbuf_size(ofpacts), + error = ofpacts_verify(ofpacts->data, ofpacts->size, (1u << N_OVS_INSTRUCTIONS) - 1); exit: if (error) { @@ -5189,10 +5376,10 @@ ofpacts_update_instruction_actions(struct ofpbuf *openflow, size_t ofs) struct ofp11_instruction_actions *oia; oia = ofpbuf_at_assert(openflow, ofs, sizeof *oia); - if (ofpbuf_size(openflow) > ofs + sizeof *oia) { - oia->len = htons(ofpbuf_size(openflow) - ofs); + if (openflow->size > ofs + sizeof *oia) { + oia->len = htons(openflow->size - ofs); } else { - ofpbuf_set_size(openflow, ofs); + openflow->size = ofs; } } @@ -5333,19 +5520,8 @@ ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a, return 0; case OFPACT_SET_L4_SRC_PORT: - if (!is_ip_any(flow) || - (flow->nw_proto != IPPROTO_TCP && flow->nw_proto != IPPROTO_UDP - && flow->nw_proto != IPPROTO_SCTP)) { - inconsistent_match(usable_protocols); - } - /* Note on which transport protocol the port numbers are set. - * This allows this set action to be converted to an OF1.2 set field - * action. */ - ofpact_get_SET_L4_SRC_PORT(a)->flow_ip_proto = flow->nw_proto; - return 0; - case OFPACT_SET_L4_DST_PORT: - if (!is_ip_any(flow) || + if (!is_ip_any(flow) || (flow->nw_frag & FLOW_NW_FRAG_LATER) || (flow->nw_proto != IPPROTO_TCP && flow->nw_proto != IPPROTO_UDP && flow->nw_proto != IPPROTO_SCTP)) { inconsistent_match(usable_protocols); @@ -5353,7 +5529,11 @@ ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a, /* Note on which transport protocol the port numbers are set. * This allows this set action to be converted to an OF1.2 set field * action. */ - ofpact_get_SET_L4_DST_PORT(a)->flow_ip_proto = flow->nw_proto; + if (a->type == OFPACT_SET_L4_SRC_PORT) { + ofpact_get_SET_L4_SRC_PORT(a)->flow_ip_proto = flow->nw_proto; + } else { + ofpact_get_SET_L4_DST_PORT(a)->flow_ip_proto = flow->nw_proto; + } return 0; case OFPACT_REG_MOVE: @@ -5409,6 +5589,9 @@ ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a, case OFPACT_LEARN: return learn_check(ofpact_get_LEARN(a), flow); + case OFPACT_CONJUNCTION: + return 0; + case OFPACT_MULTIPATH: return multipath_check(ofpact_get_MULTIPATH(a), flow); @@ -5469,6 +5652,11 @@ ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a, case OFPACT_GROUP: return 0; + case OFPACT_UNROLL_XLATE: + /* UNROLL is an internal action that should never be seen via + * OpenFlow. */ + return OFPERR_OFPBAC_BAD_TYPE; + default: OVS_NOT_REACHED(); } @@ -5530,8 +5718,12 @@ ofpacts_check_consistency(struct ofpact ofpacts[], size_t ofpacts_len, : 0); } -/* Verifies that the 'ofpacts_len' bytes of actions in 'ofpacts' are - * in the appropriate order as defined by the OpenFlow spec. */ +/* Verifies that the 'ofpacts_len' bytes of actions in 'ofpacts' are in the + * appropriate order as defined by the OpenFlow spec and as required by Open + * vSwitch. + * + * 'allowed_ovsinsts' is a bitmap of OVSINST_* values, in which 1-bits indicate + * instructions that are allowed within 'ofpacts[]'. */ static enum ofperr ofpacts_verify(const struct ofpact ofpacts[], size_t ofpacts_len, uint32_t allowed_ovsinsts) @@ -5543,6 +5735,19 @@ ofpacts_verify(const struct ofpact ofpacts[], size_t ofpacts_len, OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { enum ovs_instruction_type next; + if (a->type == OFPACT_CONJUNCTION) { + OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { + if (a->type != OFPACT_CONJUNCTION && a->type != OFPACT_NOTE) { + VLOG_WARN("\"conjunction\" actions may be used along with " + "\"note\" but not any other kind of action " + "(such as the \"%s\" action used here)", + ofpact_name(a->type)); + return OFPERR_NXBAC_BAD_CONJUNCTION; + } + } + return 0; + } + next = ovs_instruction_type_from_ofpact_type(a->type); if (a > ofpacts && (inst == OVSINST_OFPIT11_APPLY_ACTIONS @@ -5601,12 +5806,12 @@ ofpacts_put_openflow_actions(const struct ofpact ofpacts[], size_t ofpacts_len, enum ofp_version ofp_version) { const struct ofpact *a; - size_t start_size = ofpbuf_size(openflow); + size_t start_size = openflow->size; OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { encode_ofpact(a, ofp_version, openflow); } - return ofpbuf_size(openflow) - start_size; + return openflow->size - start_size; } static enum ovs_instruction_type @@ -5634,7 +5839,7 @@ ofpacts_put_openflow_instructions(const struct ofpact ofpacts[], a = ofpacts; while (a < end) { if (ofpact_is_apply_actions(a)) { - size_t ofs = ofpbuf_size(openflow); + size_t ofs = openflow->size; instruction_put_OFPIT11_APPLY_ACTIONS(openflow); do { @@ -5841,9 +6046,11 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port) case OFPACT_FIN_TIMEOUT: case OFPACT_RESUBMIT: case OFPACT_LEARN: + case OFPACT_CONJUNCTION: case OFPACT_MULTIPATH: case OFPACT_NOTE: case OFPACT_EXIT: + case OFPACT_UNROLL_XLATE: case OFPACT_PUSH_MPLS: case OFPACT_POP_MPLS: case OFPACT_SAMPLE: @@ -5970,7 +6177,8 @@ ofpact_put(struct ofpbuf *ofpacts, enum ofpact_type type, size_t len) struct ofpact *ofpact; ofpact_pad(ofpacts); - ofpact = ofpacts->frame = ofpbuf_put_uninit(ofpacts, len); + ofpacts->header = ofpbuf_put_uninit(ofpacts, len); + ofpact = ofpacts->header; ofpact_init(ofpact, type, len); return ofpact; } @@ -5993,7 +6201,7 @@ ofpact_init(struct ofpact *ofpact, enum ofpact_type type, size_t len) void ofpact_update_len(struct ofpbuf *ofpacts, struct ofpact *ofpact) { - ovs_assert(ofpact == ofpacts->frame); + ovs_assert(ofpact == ofpacts->header); ofpact->len = (char *) ofpbuf_tail(ofpacts) - (char *) ofpact; } @@ -6010,7 +6218,7 @@ ofpact_update_len(struct ofpbuf *ofpacts, struct ofpact *ofpact) void ofpact_pad(struct ofpbuf *ofpacts) { - unsigned int pad = PAD_SIZE(ofpbuf_size(ofpacts), OFPACT_ALIGNTO); + unsigned int pad = PAD_SIZE(ofpacts->size, OFPACT_ALIGNTO); if (pad) { ofpbuf_put_zeros(ofpacts, pad); } @@ -6019,7 +6227,7 @@ ofpact_pad(struct ofpbuf *ofpacts) -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT ofpact_parse(enum ofpact_type type, char *value, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols) { @@ -6052,7 +6260,7 @@ ofpact_type_from_name(const char *name, enum ofpact_type *type) * * Returns NULL if successful, otherwise a malloc()'d string describing the * error. The caller is responsible for freeing the returned string. */ -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT ofpacts_parse__(char *str, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols, bool allow_instructions) @@ -6121,12 +6329,12 @@ ofpacts_parse__(char *str, struct ofpbuf *ofpacts, } ofpact_pad(ofpacts); - if (drop && ofpbuf_size(ofpacts)) { + if (drop && ofpacts->size) { return xstrdup("\"drop\" must not be accompanied by any other action " "or instruction"); } - retval = ofpacts_verify(ofpbuf_data(ofpacts), ofpbuf_size(ofpacts), + retval = ofpacts_verify(ofpacts->data, ofpacts->size, (allow_instructions ? (1u << N_OVS_INSTRUCTIONS) - 1 : 1u << OVSINST_OFPIT11_APPLY_ACTIONS)); @@ -6137,20 +6345,20 @@ ofpacts_parse__(char *str, struct ofpbuf *ofpacts, return NULL; } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT ofpacts_parse(char *str, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols, bool allow_instructions) { - uint32_t orig_size = ofpbuf_size(ofpacts); + uint32_t orig_size = ofpacts->size; char *error = ofpacts_parse__(str, ofpacts, usable_protocols, allow_instructions); if (error) { - ofpbuf_set_size(ofpacts, orig_size); + ofpacts->size = orig_size; } return error; } -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT ofpacts_parse_copy(const char *s_, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols, bool allow_instructions) @@ -6171,7 +6379,7 @@ ofpacts_parse_copy(const char *s_, struct ofpbuf *ofpacts, * * Returns NULL if successful, otherwise a malloc()'d string describing the * error. The caller is responsible for freeing the returned string. */ -char * WARN_UNUSED_RESULT +char * OVS_WARN_UNUSED_RESULT ofpacts_parse_actions(const char *s, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols) { @@ -6183,7 +6391,7 @@ ofpacts_parse_actions(const char *s, struct ofpbuf *ofpacts, * * Returns NULL if successful, otherwise a malloc()'d string describing the * error. The caller is responsible for freeing the returned string. */ -char * WARN_UNUSED_RESULT +char * OVS_WARN_UNUSED_RESULT ofpacts_parse_instructions(const char *s, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols) { @@ -6265,15 +6473,20 @@ struct ofp_action_header { }; OFP_ASSERT(sizeof(struct ofp_action_header) == 8); -/* Header for Nicira-defined actions. */ -struct nx_action_header { +/* Header for Nicira-defined actions and for ONF vendor extensions. + * + * This cannot be used as an entirely generic vendor extension action header, + * because OpenFlow does not specify the location or size of the action + * subtype; it just happens that ONF extensions and Nicira extensions share + * this format. */ +struct ext_action_header { ovs_be16 type; /* OFPAT_VENDOR. */ ovs_be16 len; /* At least 16. */ - ovs_be32 vendor; /* NX_VENDOR_ID. */ + ovs_be32 vendor; /* NX_VENDOR_ID or ONF_VENDOR_ID. */ ovs_be16 subtype; /* See enum ofp_raw_action_type. */ uint8_t pad[6]; }; -OFP_ASSERT(sizeof(struct nx_action_header) == 16); +OFP_ASSERT(sizeof(struct ext_action_header) == 16); static bool ofpact_hdrs_equal(const struct ofpact_hdrs *a, @@ -6351,11 +6564,11 @@ 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) { - /* Get Nicira action type. */ - const struct nx_action_header *nah; + if (hdrs.vendor == NX_VENDOR_ID || hdrs.vendor == ONF_VENDOR_ID) { + /* Get extension subtype. */ + const struct ext_action_header *nah; - nah = ALIGNED_CAST(const struct nx_action_header *, oah); + nah = ALIGNED_CAST(const struct ext_action_header *, oah); if (length < sizeof *nah) { return OFPERR_OFPBAC_BAD_LEN; } @@ -6388,13 +6601,13 @@ static enum ofperr ofpact_pull_raw(struct ofpbuf *buf, enum ofp_version ofp_version, enum ofp_raw_action_type *raw, uint64_t *arg) { - const struct ofp_action_header *oah = ofpbuf_data(buf); + const struct ofp_action_header *oah = buf->data; const struct ofpact_raw_instance *action; unsigned int length; enum ofperr error; *raw = *arg = 0; - error = ofpact_decode_raw(ofp_version, oah, ofpbuf_size(buf), &action); + error = ofpact_decode_raw(ofp_version, oah, buf->size, &action); if (error) { return error; } @@ -6406,6 +6619,11 @@ ofpact_pull_raw(struct ofpbuf *buf, enum ofp_version ofp_version, } length = ntohs(oah->len); + if (length > buf->size) { + VLOG_WARN_RL(&rl, "OpenFlow action %s length %u exceeds action buffer " + "length %"PRIu32, action->name, length, buf->size); + return OFPERR_OFPBAC_BAD_LEN; + } if (length < action->min_length || length > action->max_length) { VLOG_WARN_RL(&rl, "OpenFlow action %s length %u not in valid range " "[%hu,%hu]", action->name, length, @@ -6469,8 +6687,9 @@ ofpact_put_raw(struct ofpbuf *buf, enum ofp_version ofp_version, case 0: break; - case NX_VENDOR_ID: { - struct nx_action_header *nah = (struct nx_action_header *) oah; + case NX_VENDOR_ID: + case ONF_VENDOR_ID: { + struct ext_action_header *nah = (struct ext_action_header *) oah; nah->subtype = htons(hdrs->type); break; } @@ -6499,9 +6718,9 @@ pad_ofpat(struct ofpbuf *openflow, size_t start_ofs) { struct ofp_action_header *oah; - ofpbuf_put_zeros(openflow, PAD_SIZE(ofpbuf_size(openflow) - start_ofs, 8)); + ofpbuf_put_zeros(openflow, PAD_SIZE(openflow->size - start_ofs, 8)); oah = ofpbuf_at_assert(openflow, start_ofs, sizeof *oah); - oah->len = htons(ofpbuf_size(openflow) - start_ofs); + oah->len = htons(openflow->size - start_ofs); }