Include NMX selection method experimenter group property in in group mod request and group desc reply.
NMX selection method Signed-off-by: Simon Horman <simon.hor...@netronome.com> --- lib/nx-match.c | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++---- lib/nx-match.h | 2 + lib/ofp-util.c | 31 ++++++++ ofproto/ofproto.c | 7 ++ 4 files changed, 241 insertions(+), 13 deletions(-) diff --git a/lib/nx-match.c b/lib/nx-match.c index 6b1d9d8..29055ca 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -699,6 +699,13 @@ nxm_put_64m(struct ofpbuf *b, enum mf_field_id field, enum ofp_version version, } static void +nxm_put_64(struct ofpbuf *b, enum mf_field_id field, enum ofp_version version, + ovs_be64 value) +{ + nxm_put_unmasked(b, field, version, &value, sizeof value); +} + +static void nxm_put_eth_masked(struct ofpbuf *b, enum mf_field_id field, enum ofp_version version, const uint8_t value[ETH_ADDR_LEN], @@ -708,25 +715,48 @@ nxm_put_eth_masked(struct ofpbuf *b, } static void -nxm_put_ipv6(struct ofpbuf *b, - enum mf_field_id field, enum ofp_version version, - const struct in6_addr *value, const struct in6_addr *mask) +nxm_put_eth(struct ofpbuf *b, enum mf_field_id field, enum ofp_version version, + const uint8_t value[ETH_ADDR_LEN]) +{ + nxm_put_unmasked(b, field, version, value, ETH_ADDR_LEN); +} + +static void +nxm_put_ipv6_masked(struct ofpbuf *b, + enum mf_field_id field, enum ofp_version version, + const struct in6_addr *value, const struct in6_addr *mask) { nxm_put(b, field, version, value->s6_addr, mask->s6_addr, sizeof value->s6_addr); } static void -nxm_put_frag(struct ofpbuf *b, const struct match *match, +nxm_put_ipv6(struct ofpbuf *b, + enum mf_field_id field, enum ofp_version version, + const struct in6_addr *value) +{ + nxm_put_unmasked(b, field, version, value->s6_addr, sizeof value->s6_addr); +} + +static void +nxm_put_frag_masked(struct ofpbuf *b, uint8_t value, uint8_t mask, enum ofp_version version) { - uint8_t nw_frag = match->flow.nw_frag & FLOW_NW_FRAG_MASK; - uint8_t nw_frag_mask = match->wc.masks.nw_frag & FLOW_NW_FRAG_MASK; + uint8_t nw_frag = value & FLOW_NW_FRAG_MASK; + uint8_t nw_frag_mask = mask & FLOW_NW_FRAG_MASK; nxm_put_8m(b, MFF_IP_FRAG, version, nw_frag, nw_frag_mask == FLOW_NW_FRAG_MASK ? UINT8_MAX : nw_frag_mask); } +static void +nxm_put_frag(struct ofpbuf *b, uint8_t value, enum ofp_version version) +{ + uint8_t nw_frag = value & FLOW_NW_FRAG_MASK; + + nxm_put_8(b, MFF_IP_FRAG, version, nw_frag); +} + /* Appends to 'b' a set of OXM or NXM matches for the IPv4 or IPv6 fields in * 'match'. */ static void @@ -740,13 +770,13 @@ nxm_put_ip(struct ofpbuf *b, const struct match *match, enum ofp_version oxm) nxm_put_32m(b, MFF_IPV4_DST, oxm, flow->nw_dst, match->wc.masks.nw_dst); } else { - nxm_put_ipv6(b, MFF_IPV6_SRC, oxm, - &flow->ipv6_src, &match->wc.masks.ipv6_src); - nxm_put_ipv6(b, MFF_IPV6_DST, oxm, - &flow->ipv6_dst, &match->wc.masks.ipv6_dst); + nxm_put_ipv6_masked(b, MFF_IPV6_SRC, oxm, + &flow->ipv6_src, &match->wc.masks.ipv6_src); + nxm_put_ipv6_masked(b, MFF_IPV6_DST, oxm, + &flow->ipv6_dst, &match->wc.masks.ipv6_dst); } - nxm_put_frag(b, match, oxm); + nxm_put_frag_masked(b, flow->nw_frag, match->wc.masks.nw_frag, oxm); if (match->wc.masks.nw_tos & IP_DSCP_MASK) { if (oxm) { @@ -810,8 +840,9 @@ nxm_put_ip(struct ofpbuf *b, const struct match *match, enum ofp_version oxm) } if (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT) || flow->tp_src == htons(ND_NEIGHBOR_ADVERT)) { - nxm_put_ipv6(b, MFF_ND_TARGET, oxm, - &flow->nd_target, &match->wc.masks.nd_target); + nxm_put_ipv6_masked(b, MFF_ND_TARGET, oxm, + &flow->nd_target, + &match->wc.masks.nd_target); if (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT)) { nxm_put_eth_masked(b, MFF_ND_SLL, oxm, flow->arp_sha, match->wc.masks.arp_sha); @@ -991,6 +1022,130 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match, return match_len; } +/* Appends to 'b' the nx_match format that expresses the tlv with + * 'id' in 'flow'. */ +static void +nx_put_tlv(struct ofpbuf *b, enum ofp_version oxm, + const struct flow *flow, int id) +{ + const struct mf_field *mf; + union mf_value value; + + mf = mf_from_id(id); + mf_get_value(mf, flow, &value); + + if (id == MFF_IP_FRAG) { + nxm_put_frag(b, value.u8, oxm); + } else { + switch(mf->n_bytes) { + case 1: + nxm_put_8(b, id, oxm, value.u8); + break; + case 2: + nxm_put_16(b, id, oxm, value.be16); + break; + case 4: + nxm_put_32(b, id, oxm, value.be32); + break; + case ETH_ADDR_LEN: + nxm_put_eth(b, id, oxm, value.mac); + break; + case 8: + nxm_put_64(b, id, oxm, value.be64); + break; + case 16: + nxm_put_ipv6(b, id, oxm, &value.ipv6); + break; + } + } +} + +/* Appends to 'b' the nx_match format that expresses 'flow'. + * + * Only 'flow' fields whose corresponding bit is set in bm are added to 'b'. + * All fields are added without any mask. + * + * Specify 'oxm' as 0 to express the match in NXM format; otherwise, specify + * 'oxm' as the OpenFlow version number for the OXM format to use. + * + * This function can cause 'b''s data to be reallocated. + * + * Returns the number of bytes appended to 'b', excluding padding. */ +static int +nx_put_raw_bm(struct ofpbuf *b, enum ofp_version oxm, + const struct flow *flow, const struct mf_bitmap *bm) +{ + const size_t start_len = ofpbuf_size(b); + int match_len; + int i; + struct mf_bitmap done = MF_BITMAP_INITIALIZER; + + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28); + + for (i = 0; i < MFF_N_IDS; i++) { + int id = i; + + if (!bitmap_is_set(bm->bm, id)) { + continue; + } + + if (oxm) { + if (id == MFF_VLAN_TCI) { + /* The MFF_VLAN_TCI NXM TLV covers the MFF_VLAN_VID + * and MFF_VLAN_PCP OXM TLVs. Handle the the latter directly + * and translate the id for the former. */ + if (flow->vlan_tci & htons(VLAN_VID_MASK | VLAN_CFI)) { + nx_put_tlv(b, oxm, flow, MFF_VLAN_PCP); + } + bitmap_set1(done.bm, MFF_VLAN_PCP); + id = MFF_VLAN_VID; + } else if (id == IP_DSCP_MASK) { + /* The MFF_IP_DSCP_MASK NXM TLV covers the + * MFF_IP_DSCP_SHIFTED OXM TLV. Translate the id accordingly. */ + id = MFF_IP_DSCP_SHIFTED; + } + } else { + if (id == MFF_VLAN_VID || id == MFF_VLAN_PCP) { + /* The MFF_VLAN_TCI NXM TLV covers the MFF_VLAN_VID + * and MFF_VLAN_PCP OXM TLVs. ranslate the id accordingly. */ + id = MFF_VLAN_TCI; + } else if (id == MFF_IP_DSCP_SHIFTED) { + /* The MFF_IP_DSCP_MASK_SHIFTED NXM TLV covers the + * MFF_IP_DSCP OXM TLV. Translate the id accordingly. */ + id = MFF_IP_DSCP; + } + } + + if (oxm < OFP15_VERSION) { + if (id >= MFF_XREG0 && id < MFF_XREG0 + FLOW_N_XREGS) { + id = (id - MFF_XREG0) * 2 + MFF_REG0; + /* non-extended register corresponding to low word of + * extended register */ + nx_put_tlv(b, oxm, flow, id); + /* non-extended register corresponding to high word of + * extended register */ + id++; + } + } else { + if (id >= MFF_REG0 && id < MFF_REG0 + FLOW_N_REGS) { + /* extended register corresponding to two non-extended + * registers */ + id = (id - MFF_REG0) / 2 + MFF_XREG0; + } + } + + if (bitmap_is_set(done.bm, id)) { + continue; + } + bitmap_set1(done.bm, id); + + nx_put_tlv(b, oxm, flow, id); + } + + match_len = ofpbuf_size(b) - start_len; + return match_len; +} + /* Appends to 'b' the nx_match format that expresses 'match', plus enough zero * bytes to pad the nx_match out to a multiple of 8. For Flow Mod and Flow * Stats Requests messages, a 'cookie' and 'cookie_mask' may be supplied. @@ -1043,6 +1198,39 @@ oxm_put_match(struct ofpbuf *b, const struct match *match, return match_len; } +/* Appends to 'b' an struct ofp11_match_header followed by the OXM format that + * expresses 'flow', plus enough zero bytes to pad the data appended out to a + * multiple of 8. + * + * Only 'flow' fields whose corresponding bit is set in bm are added to 'b'. + * All fields are added without any mask. + * + * OXM differs slightly among versions of OpenFlow. Specify the OpenFlow + * version in use as 'version'. + * + * This function can cause 'b''s data to be reallocated. + * + * Returns the number of bytes appended to 'b', excluding the padding. Never + * returns zero. */ +int +oxm_put_match_bm(struct ofpbuf *b, const struct flow *flow, + const struct mf_bitmap *bm, enum ofp_version version) +{ + int match_len; + struct ofp11_match_header *omh; + size_t start_len = ofpbuf_size(b); + + ofpbuf_put_uninit(b, sizeof *omh); + match_len = (nx_put_raw_bm(b, version, flow, bm) + sizeof *omh); + ofpbuf_put_zeros(b, PAD_SIZE(match_len, 8)); + + omh = ofpbuf_at(b, start_len, sizeof *omh); + omh->type = htons(OFPMT_OXM); + omh->length = htons(match_len); + + return match_len; +} + static void nx_put_header__(struct ofpbuf *b, uint64_t header, bool masked) { diff --git a/lib/nx-match.h b/lib/nx-match.h index ecc1aae..f89a2cc 100644 --- a/lib/nx-match.h +++ b/lib/nx-match.h @@ -59,6 +59,8 @@ enum ofperr oxm_pull_mask(struct ofpbuf *, struct match *, struct mf_bitmap *); int nx_put_match(struct ofpbuf *, const struct match *, ovs_be64 cookie, ovs_be64 cookie_mask); int oxm_put_match(struct ofpbuf *, const struct match *, enum ofp_version); +int oxm_put_match_bm(struct ofpbuf *, const struct flow *, + const struct mf_bitmap *, enum ofp_version version); /* Decoding and encoding OXM/NXM headers (just a field ID) or entries (a field * ID followed by a value and possibly a mask). */ diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 4a78d81..9f301bc 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -7438,6 +7438,26 @@ ofputil_put_ofp15_bucket(const struct ofputil_bucket *bucket, } static void +ofputil_put_group_prop_nmx_selection_method(enum ofp_version ofp_version, + const struct ofputil_group_props *gp, + struct ofpbuf *openflow) +{ + struct nmx_group_prop_selection_method *prop; + size_t start; + + start = ofpbuf_size(openflow); + ofpbuf_put_zeros(openflow, sizeof *prop); + oxm_put_match_bm(openflow, &gp->fields.flow, &gp->fields.bm, ofp_version); + prop = ofpbuf_at_assert(openflow, start, sizeof *prop); + prop->type = htons(OFPGPT15_EXPERIMENTER); + prop->experimenter = htonl(NMX_VENDOR_ID); + prop->exp_type = htonl(NMXT_SELECTION_METHOD); + strcpy(prop->selection_method, gp->selection_method); + prop->selection_method_param = htonll(gp->selection_method_param); + end_property(openflow, start); +} + +static void ofputil_append_ofp11_group_desc_reply(const struct ofputil_group_desc *gds, struct list *buckets, struct list *replies, @@ -7485,6 +7505,12 @@ ofputil_append_ofp15_group_desc_reply(const struct ofputil_group_desc *gds, ogds->group_id = htonl(gds->group_id); ogds->bucket_list_len = htons(ofpbuf_size(reply) - start_buckets); + /* Add group properties */ + if (gds->props.selection_method[0]) { + ofputil_put_group_prop_nmx_selection_method(version, &gds->props, + reply); + } + ofpmp_postappend(replies, start_ogds); } @@ -8132,6 +8158,11 @@ ofputil_encode_ofp15_group_mod(enum ofp_version ofp_version, ogm->command_bucket_id = htonl(gm->command_bucket_id); ogm->bucket_list_len = htons(ofpbuf_size(b) - start_ogm - sizeof *ogm); + /* Add group properties */ + if (gm->props.selection_method[0]) { + ofputil_put_group_prop_nmx_selection_method(ofp_version, &gm->props, b); + } + id_pool_destroy(bucket_ids); return b; } diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 99dd4e6..c6828a2 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -5668,6 +5668,13 @@ append_group_desc(struct ofgroup *group, struct list *replies) gds.group_id = group->group_id; gds.type = group->type; + + memcpy(gds.props.selection_method, group->selection_method, + NMX_MAX_SELECTION_METHOD_LEN); + gds.props.selection_method_param = group->selection_method_param; + miniflow_expand(&group->fields.flow, &gds.props.fields.flow); + gds.props.fields.bm = group->fields.bm; + ofputil_append_group_desc_reply(&gds, &group->buckets, replies); } -- 2.1.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev