summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorHan Zhou <hzhou8@ebay.com>2018-10-03 15:11:20 -0700
committerBen Pfaff <blp@ovn.org>2018-10-03 15:12:11 -0700
commit2ccd0d2f0b63052408b5500e22c5254e8374e996 (patch)
treec3036056fa16e5c72c0f24efe8c7ff93ddcbaab6 /lib
parentea43b024a8a03f6648d0e06589137a4fbfea9f5a (diff)
downloadopenvswitch-2ccd0d2f0b63052408b5500e22c5254e8374e996.tar.gz
bfd: Make the tp_dst masking megaflow-friendly.
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>
Diffstat (limited to 'lib')
-rw-r--r--lib/bfd.c23
-rw-r--r--lib/flow.h22
2 files changed, 33 insertions, 12 deletions
diff --git a/lib/bfd.c b/lib/bfd.c
index 530826240..cc8c6857a 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -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;
diff --git a/lib/flow.h b/lib/flow.h
index 1f6c1d6ae..902ab1bad 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -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 */