2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 01:51:26 +00:00

hash: Add symmetric L3/L4 hash functions for multipath, bundle hashing.

Signed-off-by: Jeroen van Bemmel <jvb127@gmail.com>
[blp@nicira.com made code style fixes, expanded documentation]
Signed-off-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
Jeroen van Bemmel 2015-07-06 12:58:24 -05:00 committed by Ben Pfaff
parent c4270b1377
commit 4249b5470e
8 changed files with 132 additions and 6 deletions

View File

@ -86,6 +86,7 @@ Jason Kölker jason@koelker.net
Jasper Capel jasper@capel.tv
Jean Tourrilhes jt@hpl.hp.com
Jeremy Stribling strib@nicira.com
Jeroen van Bemmel jvb127@gmail.com
Jesse Gross jesse@nicira.com
Jing Ai jinga@google.com
Joe Perches joe@perches.com

1
NEWS
View File

@ -11,6 +11,7 @@ Post-v2.4.0
* OpenFlow 1.4+ OFPMP_TABLE_DESC is now implemented.
- Support for matching and generating options with Geneve tunnels.
- Support Multicast Listener Discovery (MLDv1 and MLDv2).
- Add 'symmetric_l3l4' and 'symmetric_l3l4+udp' hash functions.
v2.4.0 - xx xxx xxxx

View File

@ -109,7 +109,28 @@ enum nx_hash_fields {
* - NXM_OF_IP_SRC / NXM_OF_IP_DST
* - NXM_OF_TCP_SRC / NXM_OF_TCP_DST
*/
NX_HASH_FIELDS_SYMMETRIC_L4
NX_HASH_FIELDS_SYMMETRIC_L4,
/* L3+L4 only, including the following fields:
*
* - NXM_OF_IP_PROTO
* - NXM_OF_IP_SRC / NXM_OF_IP_DST
* - NXM_OF_SCTP_SRC / NXM_OF_SCTP_DST
* - NXM_OF_TCP_SRC / NXM_OF_TCP_DST
*/
NX_HASH_FIELDS_SYMMETRIC_L3L4,
/* L3+L4 only with UDP ports, including the following fields:
*
* - NXM_OF_IP_PROTO
* - NXM_OF_IP_SRC / NXM_OF_IP_DST
* - NXM_OF_SCTP_SRC / NXM_OF_SCTP_DST
* - NXM_OF_TCP_SRC / NXM_OF_TCP_DST
* - NXM_OF_UDP_SRC / NXM_OF_UDP_DST
*/
NX_HASH_FIELDS_SYMMETRIC_L3L4_UDP
};
/* This command enables or disables an Open vSwitch extension that allows a

View File

@ -186,6 +186,10 @@ bundle_parse__(const char *s, char **save_ptr,
bundle->fields = NX_HASH_FIELDS_ETH_SRC;
} else if (!strcasecmp(fields, "symmetric_l4")) {
bundle->fields = NX_HASH_FIELDS_SYMMETRIC_L4;
} else if (!strcasecmp(fields, "symmetric_l3l4")) {
bundle->fields = NX_HASH_FIELDS_SYMMETRIC_L3L4;
} else if (!strcasecmp(fields, "symmetric_l3l4+udp")) {
bundle->fields = NX_HASH_FIELDS_SYMMETRIC_L3L4_UDP;
} else {
return xasprintf("%s: unknown fields `%s'", s, fields);
}

View File

@ -1347,6 +1347,40 @@ flow_hash_symmetric_l4(const struct flow *flow, uint32_t basis)
return jhash_bytes(&fields, sizeof fields, basis);
}
/* Hashes 'flow' based on its L3 through L4 protocol information */
uint32_t
flow_hash_symmetric_l3l4(const struct flow *flow, uint32_t basis,
bool inc_udp_ports)
{
uint32_t hash = basis;
/* UDP source and destination port are also taken into account. */
if (flow->dl_type == htons(ETH_TYPE_IP)) {
hash = hash_add(hash,
(OVS_FORCE uint32_t) (flow->nw_src ^ flow->nw_dst));
} else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
/* IPv6 addresses are 64-bit aligned inside struct flow. */
const uint64_t *a = ALIGNED_CAST(uint64_t *, flow->ipv6_src.s6_addr);
const uint64_t *b = ALIGNED_CAST(uint64_t *, flow->ipv6_dst.s6_addr);
for (int i = 0; i < 4; i++) {
hash = hash_add64(hash, a[i] ^ b[i]);
}
} else {
/* Cannot hash non-IP flows */
return 0;
}
hash = hash_add(hash, flow->nw_proto);
if (flow->nw_proto == IPPROTO_TCP || flow->nw_proto == IPPROTO_SCTP ||
(inc_udp_ports && flow->nw_proto == IPPROTO_UDP)) {
hash = hash_add(hash,
(OVS_FORCE uint16_t) (flow->tp_src ^ flow->tp_dst));
}
return hash_finish(hash, basis);
}
/* Initialize a flow with random fields that matter for nx_hash_fields. */
void
flow_random_hash_fields(struct flow *flow)
@ -1414,6 +1448,30 @@ flow_mask_hash_fields(const struct flow *flow, struct flow_wildcards *wc,
wc->masks.vlan_tci |= htons(VLAN_VID_MASK | VLAN_CFI);
break;
case NX_HASH_FIELDS_SYMMETRIC_L3L4_UDP:
if (is_ip_any(flow) && flow->nw_proto == IPPROTO_UDP) {
memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst);
}
/* no break */
case NX_HASH_FIELDS_SYMMETRIC_L3L4:
if (flow->dl_type == htons(ETH_TYPE_IP)) {
memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst);
} else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
memset(&wc->masks.ipv6_src, 0xff, sizeof wc->masks.ipv6_src);
memset(&wc->masks.ipv6_dst, 0xff, sizeof wc->masks.ipv6_dst);
} else {
break; /* non-IP flow */
}
memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
if (flow->nw_proto == IPPROTO_TCP || flow->nw_proto == IPPROTO_SCTP) {
memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst);
}
break;
default:
OVS_NOT_REACHED();
}
@ -1431,6 +1489,13 @@ flow_hash_fields(const struct flow *flow, enum nx_hash_fields fields,
case NX_HASH_FIELDS_SYMMETRIC_L4:
return flow_hash_symmetric_l4(flow, basis);
case NX_HASH_FIELDS_SYMMETRIC_L3L4:
return flow_hash_symmetric_l3l4(flow, basis, false);
case NX_HASH_FIELDS_SYMMETRIC_L3L4_UDP:
return flow_hash_symmetric_l3l4(flow, basis, true);
}
OVS_NOT_REACHED();
@ -1443,6 +1508,8 @@ flow_hash_fields_to_str(enum nx_hash_fields fields)
switch (fields) {
case NX_HASH_FIELDS_ETH_SRC: return "eth_src";
case NX_HASH_FIELDS_SYMMETRIC_L4: return "symmetric_l4";
case NX_HASH_FIELDS_SYMMETRIC_L3L4: return "symmetric_l3l4";
case NX_HASH_FIELDS_SYMMETRIC_L3L4_UDP: return "symmetric_l3l4+udp";
default: return "<unknown>";
}
}
@ -1452,7 +1519,9 @@ bool
flow_hash_fields_valid(enum nx_hash_fields fields)
{
return fields == NX_HASH_FIELDS_ETH_SRC
|| fields == NX_HASH_FIELDS_SYMMETRIC_L4;
|| fields == NX_HASH_FIELDS_SYMMETRIC_L4
|| fields == NX_HASH_FIELDS_SYMMETRIC_L3L4
|| fields == NX_HASH_FIELDS_SYMMETRIC_L3L4_UDP;
}
/* Returns a hash value for the bits of 'flow' that are active based on

View File

@ -341,6 +341,8 @@ bool flow_wildcards_equal(const struct flow_wildcards *,
const struct flow_wildcards *);
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_l3l4(const struct flow *flow, uint32_t basis,
bool inc_udp_ports );
/* Initialize a flow with random fields that matter for nx_hash_fields. */
void flow_random_hash_fields(struct flow *);

View File

@ -162,6 +162,10 @@ multipath_parse__(struct ofpact_multipath *mp, const char *s_, char *s)
mp->fields = NX_HASH_FIELDS_ETH_SRC;
} else if (!strcasecmp(fields, "symmetric_l4")) {
mp->fields = NX_HASH_FIELDS_SYMMETRIC_L4;
} else if (!strcasecmp(fields, "symmetric_l3l4")) {
mp->fields = NX_HASH_FIELDS_SYMMETRIC_L3L4;
} else if (!strcasecmp(fields, "symmetric_l3l4+udp")) {
mp->fields = NX_HASH_FIELDS_SYMMETRIC_L3L4_UDP;
} else {
return xasprintf("%s: unknown fields `%s'", s_, fields);
}

View File

@ -1619,8 +1619,32 @@ numbered 0 through \fIn_links\fR minus 1, and stores the link into
\fIdst\fB[\fIstart\fB..\fIend\fB]\fR, which must be an NXM field as
described above.
.IP
Currently, \fIfields\fR must be either \fBeth_src\fR or
\fBsymmetric_l4\fR and \fIalgorithm\fR must be one of \fBmodulo_n\fR,
\fIfields\fR must be one of the following:
.RS
.IP \fBeth_src\fR
Hashes Ethernet source address only.
.IP \fBsymmetric_l4\fR
Hashes Ethernet source, destination, and type, VLAN ID, IPv4/IPv6
source, destination, and protocol, and TCP or SCTP (but not UDP)
ports. The hash is computed so that pairs of corresponding flows in
each direction hash to the same value, in environments where L2 paths
are the same in each direction. UDP ports are not included in the
hash to support protocols such as VXLAN that use asymmetric ports in
each direction.
.IP \fBsymmetric_l3l4\fR
Hashes IPv4/IPv6 source, destination, and protocol, and TCP or SCTP
(but not UDP) ports. Like \fBsymmetric_l4\fR, this is a symmetric
hash, but by excluding L2 headers it is more effective in environments
with asymmetric L2 paths (e.g. paths involving VRRP IP addresses on a
router). Not an effective hash function for protocols other than IPv4
and IPv6, which hash to a constant zero.
.IP \fBsymmetric_l3l4+udp\fR
Like \fBsymmetric_l3l4+udp\fR, but UDP ports are included in the hash.
This is a more effective hash when asymmetric UDP protocols such as
VXLAN are not a consideration.
.RE
.IP
\fIalgorithm\fR must be one of \fBmodulo_n\fR,
\fBhash_threshold\fR, \fBhrw\fR, and \fBiter_hash\fR. Only
the \fBiter_hash\fR algorithm uses \fIarg\fR.
.IP
@ -1633,8 +1657,8 @@ slaves represented as \fIslave_type\fR. Currently the only supported
\fIslave_type\fR is \fBofport\fR. Thus, each \fIs1\fR through \fIsN\fR should
be an OpenFlow port number. Outputs to the selected slave.
.IP
Currently, \fIfields\fR must be either \fBeth_src\fR or \fBsymmetric_l4\fR and
\fIalgorithm\fR must be one of \fBhrw\fR and \fBactive_backup\fR.
Currently, \fIfields\fR must be either \fBeth_src\fR, \fBsymmetric_l4\fR, \fBsymmetric_l3l4\fR, or \fBsymmetric_l3l4+udp\fR,
and \fIalgorithm\fR must be one of \fBhrw\fR and \fBactive_backup\fR.
.IP
Example: \fBbundle(eth_src,0,hrw,ofport,slaves:4,8)\fR uses an Ethernet source
hash with basis 0, to select between OpenFlow ports 4 and 8 using the Highest