This is intended as a usable demonstration of how the NTR selection method extension might may be used.
NTR selection method Signed-off-by: Simon Horman <simon.hor...@netronome.com> --- v3 * Update new check in parse_group_prop_nmx_selection_method() to allow decoding hash selection method * Use fixed array for fields_array rather than constructing a list * Use NTR instead of NMX as Netronome extension prefix v2 * Use list of struct field_array of TLVs rather than OF1.1 match for fields field of NTR selection method property --- lib/nx-match.c | 2 +- lib/nx-match.h | 3 +++ lib/ofp-util.c | 13 +++++-------- ofproto/ofproto-dpif-xlate.c | 45 ++++++++++++++++++++++++++++++++++++++++++++ ofproto/ofproto-dpif.c | 12 ++++++++++++ ofproto/ofproto-dpif.h | 2 ++ tests/ofproto-dpif.at | 20 ++++++++++++++++++++ 7 files changed, 88 insertions(+), 9 deletions(-) diff --git a/lib/nx-match.c b/lib/nx-match.c index fc14de3..df2d976 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -414,7 +414,7 @@ nx_pull_header(struct ofpbuf *b, const struct mf_field **field, bool *masked) return error; } -static enum ofperr +enum ofperr nx_pull_match_entry(struct ofpbuf *b, bool allow_cookie, const struct mf_field **field, union mf_value *value, union mf_value *mask) diff --git a/lib/nx-match.h b/lib/nx-match.h index 6bd473a..3767fdf 100644 --- a/lib/nx-match.h +++ b/lib/nx-match.h @@ -70,6 +70,9 @@ enum ofperr nx_pull_entry(struct ofpbuf *, const struct mf_field **, union mf_value *value, union mf_value *mask); enum ofperr nx_pull_header(struct ofpbuf *, const struct mf_field **, bool *masked); +enum ofperr nx_pull_match_entry(struct ofpbuf *b, bool allow_cookie, + const struct mf_field **field, + union mf_value *value, union mf_value *mask); void nx_put_entry(struct ofpbuf *, enum mf_field_id, enum ofp_version, const union mf_value *value, const union mf_value *mask); void nx_put_header(struct ofpbuf *, enum mf_field_id, enum ofp_version, diff --git a/lib/ofp-util.c b/lib/ofp-util.c index b9099b6..433d807 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -7823,14 +7823,11 @@ parse_group_prop_ntr_selection_method(struct ofpbuf *payload, return OFPERR_OFPBPC_BAD_VALUE; } - /* Only allow selection method property if the selection_method field - * matches a suported method. As no methods are currently supported - * this check is a no-op that always fails. As selection methods are - * added they should be checked against the selection_method field - * here. */ - log_property(false, "ntr selection method '%s' is not supported", - prop->selection_method); - return OFPERR_OFPBPC_BAD_VALUE; + if (strcmp("hash", prop->selection_method)) { + log_property(false, "ntr selection method '%s' is not supported", + prop->selection_method); + return OFPERR_OFPBPC_BAD_VALUE; + } strcpy(gp->selection_method, prop->selection_method); gp->selection_method_param = ntohll(prop->selection_method_param); diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 1a3d34c..63b7393 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -35,6 +35,7 @@ #include "dpif.h" #include "dynamic-string.h" #include "in-band.h" +#include "jhash.h" #include "lacp.h" #include "learn.h" #include "list.h" @@ -3088,6 +3089,48 @@ xlate_default_select_group(struct xlate_ctx *ctx, struct group_dpif *group) } } +static void +xlate_hash_fields_select_group(struct xlate_ctx *ctx, struct group_dpif *group) +{ + struct flow_wildcards *wc = &ctx->xout->wc; + uint64_t selection_method_param; + struct ofputil_bucket *bucket; + const struct field_array *fields; + struct flow flow; + uint32_t basis; + int i; + + fields = group_dpif_get_fields(group); + flow = ctx->xin->flow; + + for (i = 0; i < MFF_N_IDS; i++) { + if (bitmap_is_set(fields->used.bm, i)) { + int j; + union mf_value value; + const struct mf_field *mf = mf_from_id(i); + + mf_get_value(mf, &flow, &value); + /* This seems inefficient but so is apply_mask() */ + for (j = 0; j < mf->n_bytes; j++) { + ((uint8_t *) &value)[j] &= ((uint8_t *) &fields->value[i])[j]; + } + mf_set_flow_value(mf, &value, &flow); + + mf_mask_field(mf, &wc->masks); + } + } + + selection_method_param = group_dpif_get_selection_method_param(group); + + basis = (uint32_t)(selection_method_param & 0xffffffff); + basis = jhash_bytes(&flow, sizeof flow, basis); + bucket = group_best_live_bucket(ctx, group, basis); + if (bucket) { + xlate_group_bucket(ctx, bucket); + xlate_group_stats(ctx, group, bucket); + } +} + static bool xlate_select_group(struct xlate_ctx *ctx, struct group_dpif *group) { @@ -3095,6 +3138,8 @@ xlate_select_group(struct xlate_ctx *ctx, struct group_dpif *group) if (selection_method[0] == '\0') { xlate_default_select_group(ctx, group); + } else if (!strcasecmp("hash", selection_method)) { + xlate_hash_fields_select_group(ctx, group); } else { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 4d2333f..7218d3d 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -4256,6 +4256,18 @@ group_dpif_get_selection_method(const struct group_dpif *group) { return group->up.selection_method; } + +uint64_t +group_dpif_get_selection_method_param(const struct group_dpif *group) +{ + return group->up.selection_method_param; +} + +const struct field_array * +group_dpif_get_fields(const struct group_dpif *group) +{ + return &group->up.fields; +} /* Sends 'packet' out 'ofport'. * May modify 'packet'. diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h index fd099a2..19c91f0 100644 --- a/ofproto/ofproto-dpif.h +++ b/ofproto/ofproto-dpif.h @@ -138,6 +138,8 @@ void group_dpif_get_buckets(const struct group_dpif *group, const struct ovs_list **buckets); enum ofp11_group_type group_dpif_get_type(const struct group_dpif *group); const char *group_dpif_get_selection_method(const struct group_dpif *group); +uint64_t group_dpif_get_selection_method_param(const struct group_dpif *group); +const struct field_array *group_dpif_get_fields(const struct group_dpif *group); bool ofproto_has_vlan_splinters(const struct ofproto_dpif *); ofp_port_t vsp_realdev_to_vlandev(const struct ofproto_dpif *, diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index 4932fcc..fe65856 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -403,6 +403,26 @@ AT_CHECK([tail -1 stdout], [0], OVS_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([ofproto-dpif - select group with hash selection method]) +OVS_VSWITCHD_START +ADD_OF_PORTS([br0], [1], [10], [11]) +AT_CHECK([ovs-ofctl -O OpenFlow15 add-group br0 'group_id=1234,type=select,selection_method=hash,fields=eth_dst=ff:ff:ff:ff:ff:ff,bucket=output:10,bucket=output:11']) +AT_CHECK([ovs-ofctl -O OpenFlow15 add-flow br0 'ip actions=write_actions(group:1234)']) + +# Try a bunch of different flows and make sure that they get distributed +# at least somewhat. +for d in 0 1 2 3 4 5 6 7 8 9 a b c d e f; do + AT_CHECK([ovs-appctl ofproto/trace br0 "in_port=1,dl_src=50:54:00:00:00:07,dl_dst=50:54:00:00:00:0$d,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,icmp_type=8,icmp_code=0"], [0], [stdout]) + tail -1 stdout >> results +done +sort results | uniq -c +AT_CHECK([sort results | uniq], [0], + [Datapath actions: 10 +Datapath actions: 11 +]) +OVS_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([ofproto-dpif - fast failover group]) OVS_VSWITCHD_START ADD_OF_PORTS([br0], [1], [10], [11]) -- 2.1.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev