Skip to content

Commit

Permalink
hash: Add symmetric L3/L4 hash functions for multipath, bundle hashing.
Browse files Browse the repository at this point in the history
Signed-off-by: Jeroen van Bemmel <[email protected]>
[[email protected] made code style fixes, expanded documentation]
Signed-off-by: Ben Pfaff <[email protected]>
  • Loading branch information
jbemmel authored and blp committed Jul 8, 2015
1 parent c4270b1 commit 4249b54
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 6 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ Jason Kölker [email protected]
Jasper Capel [email protected]
Jean Tourrilhes [email protected]
Jeremy Stribling [email protected]
Jeroen van Bemmel [email protected]
Jesse Gross [email protected]
Jing Ai [email protected]
Joe Perches [email protected]
Expand Down
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
23 changes: 22 additions & 1 deletion include/openflow/nicira-ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions lib/bundle.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
71 changes: 70 additions & 1 deletion lib/flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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();
}
Expand All @@ -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();
Expand All @@ -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>";
}
}
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions lib/flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Expand Down
4 changes: 4 additions & 0 deletions lib/multipath.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
32 changes: 28 additions & 4 deletions utilities/ovs-ofctl.8.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down

0 comments on commit 4249b54

Please sign in to comment.