Skip to content

Commit

Permalink
bfd: Make the tp_dst masking megaflow-friendly.
Browse files Browse the repository at this point in the history
When there are tunnel ports with BFD enabled, all UDP flows will have
dst port as match condition in datapath, which causes unnecessarily
high flow miss for all UDP traffic, and results in latency increase.

This patch solves the problem by masking tp_dst only for a single
bit that is enough to tell the mismatch when it is not BFD traffic.

Reported-at: https://mail.openvswitch.org/pipermail/ovs-discuss/2018-September/047360.html
Signed-off-by: Han Zhou <hzhou8@ebay.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
  • Loading branch information
hzhou8 authored and blp committed Oct 3, 2018
1 parent ea43b02 commit 2ccd0d2
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 12 deletions.
23 changes: 11 additions & 12 deletions lib/bfd.c
Expand Up @@ -672,19 +672,18 @@ bfd_should_process_flow(const struct bfd *bfd_, const struct flow *flow,

if (flow->dl_type == htons(ETH_TYPE_IP)) {
memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
if (flow->nw_proto == IPPROTO_UDP && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst);
if (flow->tp_dst == htons(BFD_DEST_PORT)) {
bool check_tnl_key;

atomic_read_relaxed(&bfd->check_tnl_key, &check_tnl_key);
if (check_tnl_key) {
memset(&wc->masks.tunnel.tun_id, 0xff,
sizeof wc->masks.tunnel.tun_id);
return flow->tunnel.tun_id == htonll(0);
}
return true;
if (flow->nw_proto == IPPROTO_UDP
&& !(flow->nw_frag & FLOW_NW_FRAG_LATER)
&& tp_dst_equals(flow, BFD_DEST_PORT, wc)) {
bool check_tnl_key;

atomic_read_relaxed(&bfd->check_tnl_key, &check_tnl_key);
if (check_tnl_key) {
memset(&wc->masks.tunnel.tun_id, 0xff,
sizeof wc->masks.tunnel.tun_id);
return flow->tunnel.tun_id == htonll(0);
}
return true;
}
}
return false;
Expand Down
22 changes: 22 additions & 0 deletions lib/flow.h
Expand Up @@ -1188,4 +1188,26 @@ static inline bool is_stp(const struct flow *flow)
&& eth_addr_equals(flow->dl_dst, eth_addr_stp));
}

/* Returns true if flow->tp_dst equals 'port'. If 'wc' is nonnull, sets
* appropriate bits in wc->masks.tp_dst to account for the test.
*
* The caller must already have ensured that 'flow' is a protocol for which
* tp_dst is relevant. */
static inline bool tp_dst_equals(const struct flow *flow, uint16_t port,
struct flow_wildcards *wc)
{
uint16_t diff = port ^ ntohs(flow->tp_dst);
if (wc) {
if (diff) {
/* Set mask for the most significant mismatching bit. */
int ofs = raw_clz64((uint64_t) diff << 48); /* range [0,15] */
wc->masks.tp_dst |= htons(0x8000 >> ofs);
} else {
/* Must match all bits. */
wc->masks.tp_dst = OVS_BE16_MAX;
}
}
return !diff;
}

#endif /* flow.h */

0 comments on commit 2ccd0d2

Please sign in to comment.