Skip to content

Commit 34a6935

Browse files
authored
[meta] Use custom hash in SaiObjectCollection (sonic-net#709)
Currently unordered_map with std::string key is used, but since sai_serialize_object_meta_key is expensive, it make sense to keep original meta_key as key and write custom hash function. For 100k routes, metadata speeds up 3x when using custom hash.
1 parent c847733 commit 34a6935

10 files changed

+452
-205
lines changed

meta/Makefile.am

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ libsaimetadata_la_SOURCES = \
8484
SaiObject.cpp \
8585
SaiObjectCollection.cpp \
8686
PortRelatedSet.cpp \
87+
MetaKeyHasher.cpp \
8788
Meta.cpp
8889

8990

meta/Meta.cpp

+119-129
Large diffs are not rendered by default.

meta/Meta.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ namespace saimeta
411411
_In_ sai_object_id_t oid) const;
412412

413413
bool objectExists(
414-
_In_ const std::string& mk) const;
414+
_In_ const sai_object_meta_key_t& mk) const;
415415

416416
private: // port helpers
417417

meta/MetaKeyHasher.cpp

+210
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
#include "MetaKeyHasher.h"
2+
#include "sai_serialize.h"
3+
4+
#include "swss/logger.h"
5+
6+
#include <cstring>
7+
8+
using namespace saimeta;
9+
10+
static bool operator==(
11+
_In_ const sai_fdb_entry_t& a,
12+
_In_ const sai_fdb_entry_t& b)
13+
{
14+
SWSS_LOG_ENTER();
15+
16+
return a.switch_id == b.switch_id &&
17+
a.bv_id == b.bv_id &&
18+
memcmp(a.mac_address, b.mac_address, sizeof(a.mac_address)) == 0;
19+
}
20+
21+
static bool operator==(
22+
_In_ const sai_route_entry_t& a,
23+
_In_ const sai_route_entry_t& b)
24+
{
25+
// SWSS_LOG_ENTER(); // disabled for performance reasons
26+
27+
bool part = a.switch_id == b.switch_id &&
28+
a.vr_id == b.vr_id &&
29+
a.destination.addr_family == b.destination.addr_family;
30+
31+
if (a.destination.addr_family == SAI_IP_ADDR_FAMILY_IPV4)
32+
{
33+
return part &&
34+
a.destination.addr.ip4 == b.destination.addr.ip4 &&
35+
a.destination.mask.ip4 == b.destination.mask.ip4;
36+
}
37+
38+
if (a.destination.addr_family == SAI_IP_ADDR_FAMILY_IPV6)
39+
{
40+
return part &&
41+
memcmp(a.destination.addr.ip6, b.destination.addr.ip6, sizeof(b.destination.addr.ip6)) == 0 &&
42+
memcmp(a.destination.mask.ip6, b.destination.mask.ip6, sizeof(b.destination.mask.ip6)) == 0;
43+
}
44+
45+
return part;
46+
}
47+
48+
static bool operator==(
49+
_In_ const sai_neighbor_entry_t& a,
50+
_In_ const sai_neighbor_entry_t& b)
51+
{
52+
SWSS_LOG_ENTER();
53+
54+
bool part = a.switch_id == b.switch_id &&
55+
a.rif_id == b.rif_id &&
56+
a.ip_address.addr_family == b.ip_address.addr_family;
57+
58+
if (a.ip_address.addr_family == SAI_IP_ADDR_FAMILY_IPV4)
59+
return part && a.ip_address.addr.ip4 == b.ip_address.addr.ip4;
60+
61+
if (a.ip_address.addr_family == SAI_IP_ADDR_FAMILY_IPV6)
62+
return part && memcmp(a.ip_address.addr.ip6, b.ip_address.addr.ip6, sizeof(b.ip_address.addr.ip6)) == 0;
63+
64+
return part;
65+
}
66+
67+
static bool operator==(
68+
_In_ const sai_nat_entry_t& a,
69+
_In_ const sai_nat_entry_t& b)
70+
{
71+
SWSS_LOG_ENTER();
72+
73+
// we can't use mem compare, since some fields will be padded and they
74+
// could contain garbage
75+
76+
return a.switch_id == b.switch_id &&
77+
a.vr_id == b.vr_id &&
78+
a.nat_type == b.nat_type &&
79+
a.data.key.src_ip == b.data.key.src_ip &&
80+
a.data.key.dst_ip == b.data.key.dst_ip &&
81+
a.data.key.proto == b.data.key.proto &&
82+
a.data.key.l4_src_port == b.data.key.l4_src_port &&
83+
a.data.key.l4_dst_port == b.data.key.l4_dst_port &&
84+
a.data.mask.src_ip == b.data.mask.src_ip &&
85+
a.data.mask.dst_ip == b.data.mask.dst_ip &&
86+
a.data.mask.proto == b.data.mask.proto &&
87+
a.data.mask.l4_src_port == b.data.mask.l4_src_port &&
88+
a.data.mask.l4_dst_port == b.data.mask.l4_dst_port;
89+
}
90+
91+
bool MetaKeyHasher::operator()(
92+
_In_ const sai_object_meta_key_t& a,
93+
_In_ const sai_object_meta_key_t& b) const
94+
{
95+
// SWSS_LOG_ENTER(); // disabled for performance reasons
96+
97+
if (a.objecttype != b.objecttype)
98+
return false;
99+
100+
auto meta = sai_metadata_get_object_type_info(a.objecttype);
101+
102+
if (meta && meta->isobjectid)
103+
return a.objectkey.key.object_id == b.objectkey.key.object_id;
104+
105+
if (a.objecttype == SAI_OBJECT_TYPE_ROUTE_ENTRY)
106+
return a.objectkey.key.route_entry == b.objectkey.key.route_entry;
107+
108+
if (a.objecttype == SAI_OBJECT_TYPE_NEIGHBOR_ENTRY)
109+
return a.objectkey.key.neighbor_entry == b.objectkey.key.neighbor_entry;
110+
111+
if (a.objecttype == SAI_OBJECT_TYPE_FDB_ENTRY)
112+
return a.objectkey.key.fdb_entry == b.objectkey.key.fdb_entry;
113+
114+
if (a.objecttype == SAI_OBJECT_TYPE_NAT_ENTRY)
115+
return a.objectkey.key.nat_entry == b.objectkey.key.nat_entry;
116+
117+
SWSS_LOG_THROW("not implemented: %s",
118+
sai_serialize_object_meta_key(a).c_str());
119+
}
120+
121+
static_assert(sizeof(std::size_t) >= sizeof(uint32_t), "size_t must be at least 32 bits");
122+
123+
static inline std::size_t sai_get_hash(
124+
_In_ const sai_route_entry_t& re)
125+
{
126+
// SWSS_LOG_ENTER(); // disabled for performance reasons
127+
128+
if (re.destination.addr_family == SAI_IP_ADDR_FAMILY_IPV4)
129+
{
130+
return re.destination.addr.ip4;
131+
}
132+
133+
if (re.destination.addr_family == SAI_IP_ADDR_FAMILY_IPV6)
134+
{
135+
const uint32_t* ip6 = (const uint32_t*)re.destination.addr.ip6;
136+
137+
return ip6[0] ^ ip6[1] ^ ip6[2] ^ ip6[3];
138+
}
139+
140+
return re.destination.addr_family;
141+
}
142+
143+
static inline std::size_t sai_get_hash(
144+
_In_ const sai_neighbor_entry_t& ne)
145+
{
146+
SWSS_LOG_ENTER();
147+
148+
if (ne.ip_address.addr_family == SAI_IP_ADDR_FAMILY_IPV4)
149+
{
150+
return ne.ip_address.addr.ip4;
151+
}
152+
153+
if (ne.ip_address.addr_family == SAI_IP_ADDR_FAMILY_IPV6)
154+
{
155+
const uint32_t* ip6 = (const uint32_t*)ne.ip_address.addr.ip6;
156+
157+
return ip6[0] ^ ip6[1] ^ ip6[2] ^ ip6[3];
158+
}
159+
160+
return ne.ip_address.addr_family;
161+
}
162+
163+
static inline std::size_t sai_get_hash(
164+
_In_ const sai_fdb_entry_t& fe)
165+
{
166+
SWSS_LOG_ENTER();
167+
168+
return *(const uint32_t*)(&fe.mac_address[2]);
169+
}
170+
171+
static inline std::size_t sai_get_hash(
172+
_In_ const sai_nat_entry_t& ne)
173+
{
174+
SWSS_LOG_ENTER();
175+
176+
// TODO revisit - may depend on nat_type
177+
178+
return ne.data.key.src_ip ^ ne.data.key.dst_ip;
179+
}
180+
181+
std::size_t MetaKeyHasher::operator()(
182+
_In_ const sai_object_meta_key_t& k) const
183+
{
184+
// SWSS_LOG_ENTER(); // disabled for performance reasons
185+
186+
auto meta = sai_metadata_get_object_type_info(k.objecttype);
187+
188+
if (meta && meta->isobjectid)
189+
{
190+
return k.objectkey.key.object_id;
191+
}
192+
193+
switch (k.objecttype)
194+
{
195+
case SAI_OBJECT_TYPE_ROUTE_ENTRY:
196+
return sai_get_hash(k.objectkey.key.route_entry);
197+
198+
case SAI_OBJECT_TYPE_NEIGHBOR_ENTRY:
199+
return sai_get_hash(k.objectkey.key.neighbor_entry);
200+
201+
case SAI_OBJECT_TYPE_FDB_ENTRY:
202+
return sai_get_hash(k.objectkey.key.fdb_entry);
203+
204+
case SAI_OBJECT_TYPE_NAT_ENTRY:
205+
return sai_get_hash(k.objectkey.key.nat_entry);
206+
207+
default:
208+
SWSS_LOG_THROW("not handled: %s", sai_serialize_object_type(k.objecttype).c_str());
209+
}
210+
}

meta/MetaKeyHasher.h

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#pragma once
2+
3+
extern "C" {
4+
#include "saimetadata.h"
5+
}
6+
7+
#include <string>
8+
9+
namespace saimeta
10+
{
11+
struct MetaKeyHasher
12+
{
13+
std::size_t operator()(
14+
_In_ const sai_object_meta_key_t& k) const;
15+
16+
bool operator()(
17+
_In_ const sai_object_meta_key_t& a,
18+
_In_ const sai_object_meta_key_t& b) const;
19+
};
20+
}

meta/SaiObject.cpp

+1-8
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ SaiObject::SaiObject(
1212
{
1313
SWSS_LOG_ENTER();
1414

15-
m_strMetaKey = sai_serialize_object_meta_key(metaKey);
15+
// empty
1616
}
1717

1818
sai_object_type_t SaiObject::getObjectType() const
@@ -30,13 +30,6 @@ bool SaiObject::hasAttr(
3030
return m_attrs.find(id) != m_attrs.end();
3131
}
3232

33-
const std::string SaiObject::getStrMetaKey() const
34-
{
35-
SWSS_LOG_ENTER();
36-
37-
return m_strMetaKey;
38-
}
39-
4033
const sai_object_meta_key_t& SaiObject::getMetaKey() const
4134
{
4235
SWSS_LOG_ENTER();

meta/SaiObject.h

-4
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ namespace saimeta
2929
bool hasAttr(
3030
_In_ sai_attr_id_t id) const;
3131

32-
const std::string getStrMetaKey() const;
33-
3432
const sai_object_meta_key_t& getMetaKey() const;
3533

3634
void setAttr(
@@ -49,8 +47,6 @@ namespace saimeta
4947

5048
sai_object_meta_key_t m_metaKey;
5149

52-
std::string m_strMetaKey;
53-
5450
std::unordered_map<sai_attr_id_t, std::shared_ptr<SaiAttrWrapper>> m_attrs;
5551
};
5652
}

0 commit comments

Comments
 (0)