This commit implements a new dp_hash algorithm OVS_HASH_L4_SYMMETRIC in the netdev datapath. It will be used as default hash algorithm for the dp_hash-based select groups in a subsequent commit to maintain compatibility with the symmetry property of the current default hash selection method.
A new dpif_backer_support field 'max_hash_alg' is introduced to reflect the highest hash algorithm a datapath supports in the dp_hash action. Signed-off-by: Jan Scheurich <jan.scheur...@ericsson.com> Signed-off-by: Nitin Katiyar <nitin.kati...@ericsson.com> Co-authored-by: Nitin Katiyar <nitin.kati...@ericsson.com> --- datapath/linux/compat/include/linux/openvswitch.h | 4 ++ lib/flow.c | 43 +++++++++++++++++++++- lib/flow.h | 1 + lib/odp-execute.c | 23 ++++++++++-- ofproto/ofproto-dpif-xlate.c | 7 +++- ofproto/ofproto-dpif.c | 45 +++++++++++++++++++++++ ofproto/ofproto-dpif.h | 5 ++- 7 files changed, 121 insertions(+), 7 deletions(-) diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h index 6f4fa01..5c1e238 100644 --- a/datapath/linux/compat/include/linux/openvswitch.h +++ b/datapath/linux/compat/include/linux/openvswitch.h @@ -724,6 +724,10 @@ struct ovs_action_push_vlan { */ enum ovs_hash_alg { OVS_HASH_ALG_L4, +#ifndef __KERNEL__ + OVS_HASH_ALG_SYM_L4, +#endif + __OVS_HASH_MAX }; /* diff --git a/lib/flow.c b/lib/flow.c index 136f060..75ca456 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -2124,6 +2124,45 @@ flow_hash_symmetric_l4(const struct flow *flow, uint32_t basis) return jhash_bytes(&fields, sizeof fields, basis); } +/* Symmetrically Hashes non-IP 'flow' based on its L2 headers. */ +uint32_t +flow_hash_symmetric_l2(const struct flow *flow, uint32_t basis) +{ + union { + struct { + ovs_be16 eth_type; + ovs_be16 vlan_tci; + struct eth_addr eth_addr; + ovs_be16 pad; + }; + uint32_t word[3]; + } fields; + + uint32_t hash = basis; + int i; + + if (flow->packet_type != htonl(PT_ETH)) { + /* Cannot hash non-Ethernet flows */ + return 0; + } + + for (i = 0; i < ARRAY_SIZE(fields.eth_addr.be16); i++) { + fields.eth_addr.be16[i] = + flow->dl_src.be16[i] ^ flow->dl_dst.be16[i]; + } + fields.vlan_tci = 0; + for (i = 0; i < FLOW_MAX_VLAN_HEADERS; i++) { + fields.vlan_tci ^= flow->vlans[i].tci & htons(VLAN_VID_MASK); + } + fields.eth_type = flow->dl_type; + fields.pad = 0; + + hash = hash_add(hash, fields.word[0]); + hash = hash_add(hash, fields.word[1]); + hash = hash_add(hash, fields.word[2]); + return hash_finish(hash, basis); +} + /* Hashes 'flow' based on its L3 through L4 protocol information */ uint32_t flow_hash_symmetric_l3l4(const struct flow *flow, uint32_t basis, @@ -2144,8 +2183,8 @@ flow_hash_symmetric_l3l4(const struct flow *flow, uint32_t basis, hash = hash_add64(hash, a[i] ^ b[i]); } } else { - /* Cannot hash non-IP flows */ - return 0; + /* Revert to hashing L2 headers */ + return flow_hash_symmetric_l2(flow, basis); } hash = hash_add(hash, flow->nw_proto); diff --git a/lib/flow.h b/lib/flow.h index 7a9e7d0..9de94b2 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -236,6 +236,7 @@ hash_odp_port(odp_port_t odp_port) uint32_t flow_hash_5tuple(const struct flow *flow, uint32_t basis); uint32_t flow_hash_symmetric_l4(const struct flow *flow, uint32_t basis); +uint32_t flow_hash_symmetric_l2(const struct flow *flow, uint32_t basis); uint32_t flow_hash_symmetric_l3l4(const struct flow *flow, uint32_t basis, bool inc_udp_ports ); diff --git a/lib/odp-execute.c b/lib/odp-execute.c index c5080ea..5831d1f 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -730,14 +730,16 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal, } switch ((enum ovs_action_attr) type) { + case OVS_ACTION_ATTR_HASH: { const struct ovs_action_hash *hash_act = nl_attr_get(a); - /* Calculate a hash value directly. This might not match the + /* Calculate a hash value directly. This might not match the * value computed by the datapath, but it is much less expensive, * and the current use case (bonding) does not require a strict * match to work properly. */ - if (hash_act->hash_alg == OVS_HASH_ALG_L4) { + switch (hash_act->hash_alg) { + case OVS_HASH_ALG_L4: { struct flow flow; uint32_t hash; @@ -753,7 +755,22 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal, } packet->md.dp_hash = hash; } - } else { + break; + } + case OVS_HASH_ALG_SYM_L4: { + struct flow flow; + uint32_t hash; + + DP_PACKET_BATCH_FOR_EACH (i, packet, batch) { + flow_extract(packet, &flow); + hash = flow_hash_symmetric_l3l4(&flow, + hash_act->hash_basis, + false); + packet->md.dp_hash = hash; + } + break; + } + default: /* Assert on unknown hash algorithm. */ OVS_NOT_REACHED(); } diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index c7c9df5..9f7fca7 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -4005,10 +4005,15 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, struct ovs_action_hash *act_hash; /* Hash action. */ + enum ovs_hash_alg hash_alg = xr->hash_alg; + if (hash_alg > ctx->xbridge->support.max_hash_alg) { + /* Algorithm supported by all datapaths. */ + hash_alg = OVS_HASH_ALG_L4; + } act_hash = nl_msg_put_unspec_uninit(ctx->odp_actions, OVS_ACTION_ATTR_HASH, sizeof *act_hash); - act_hash->hash_alg = xr->hash_alg; + act_hash->hash_alg = hash_alg; act_hash->hash_basis = xr->hash_basis; /* Recirc action. */ diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 1ed82d0..7162811 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -1291,6 +1291,50 @@ check_ct_clear(struct dpif_backer *backer) return supported; } +/* Probe the highest dp_hash algorithm supported by the datapath. */ +static size_t +check_max_dp_hash_alg(struct dpif_backer *backer) +{ + struct odputil_keybuf keybuf; + struct ofpbuf key; + struct flow flow; + struct ovs_action_hash *hash; + int max_alg = 0; + + struct odp_flow_key_parms odp_parms = { + .flow = &flow, + .probe = true, + }; + + memset(&flow, 0, sizeof flow); + ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); + odp_flow_key_from_flow(&odp_parms, &key); + + /* All datapaths support algortithm 0 (OVS_HASH_ALG_L4). */ + for (int alg = 1; alg < __OVS_HASH_MAX; alg++) { + struct ofpbuf actions; + bool ok; + + ofpbuf_init(&actions, 300); + hash = nl_msg_put_unspec_uninit(&actions, + OVS_ACTION_ATTR_HASH, sizeof *hash); + hash->hash_basis = 0; + hash->hash_alg = alg; + ok = dpif_probe_feature(backer->dpif, "Max dp_hash algorithm", &key, + &actions, NULL); + ofpbuf_uninit(&actions); + if (ok) { + max_alg = alg; + } else { + break; + } + } + + VLOG_INFO("%s: Max dp_hash algorithm probed to be %d", + dpif_name(backer->dpif), max_alg); + return max_alg; +} + #define CHECK_FEATURE__(NAME, SUPPORT, FIELD, VALUE, ETHTYPE) \ static bool \ check_##NAME(struct dpif_backer *backer) \ @@ -1353,6 +1397,7 @@ check_support(struct dpif_backer *backer) backer->rt_support.sample_nesting = check_max_sample_nesting(backer); backer->rt_support.ct_eventmask = check_ct_eventmask(backer); backer->rt_support.ct_clear = check_ct_clear(backer); + backer->rt_support.max_hash_alg = check_max_dp_hash_alg(backer); /* Flow fields. */ backer->rt_support.odp.ct_state = check_ct_state(backer); diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h index 47bf7f9..d654947 100644 --- a/ofproto/ofproto-dpif.h +++ b/ofproto/ofproto-dpif.h @@ -175,7 +175,10 @@ struct group_dpif *group_dpif_lookup(struct ofproto_dpif *, DPIF_SUPPORT_FIELD(bool, ct_eventmask, "Conntrack eventmask") \ \ /* True if the datapath supports OVS_ACTION_ATTR_CT_CLEAR action. */ \ - DPIF_SUPPORT_FIELD(bool, ct_clear, "Conntrack clear") + DPIF_SUPPORT_FIELD(bool, ct_clear, "Conntrack clear") \ + \ + /* Highest supported dp_hash algorithm. */ \ + DPIF_SUPPORT_FIELD(size_t, max_hash_alg, "Max dp_hash algorithm") /* Stores the various features which the corresponding backer supports. */ struct dpif_backer_support { -- 1.9.1 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev