* [dpdk-dev] [RFC] Add Membership Library
@ 2017-05-27 1:34 Yipeng Wang
2017-05-27 1:34 ` Yipeng Wang
2017-05-27 9:42 ` Vincent Jardin
0 siblings, 2 replies; 7+ messages in thread
From: Yipeng Wang @ 2017-05-27 1:34 UTC (permalink / raw)
To: yipeng1.wang; +Cc: dev, sameh.gobriel, ren.wang, charlie.tai
A proposal for a new DPDK library that is called “Membership Library”. It
provides an API for DPDK applications to insert a new member, delete an existing
member, or query the existence of a member in a given set, or a group of sets.
For the case of a group of sets the library will return not only whether the
element has been inserted before in one of the sets but also which set it
belongs to.
The Membership Library is an extension and generalization of a traditional
filter (for example Bloom Filter) structure that has multiple usages in a wide
variety of workloads and applications. In general, the Membership Library is a
data structure that provides a “set-summary” and responds to set-membership
queries whether a certain member belongs to a set(s). There are two advantages
of using such a set-summary rather than operating on a “full-blown” complete
list of elements: firstly it has a much smaller storage requirement than storing
the whole list of elements themselves, and secondly checking an element
membership (or other operations) in this set-summary is much faster than
checking it for the original full-blown complete list of elements.
A membership test for an element will return the set this element belongs to or
null (meaning not found) with very high probability of accuracy. Set-summary is
a fundamental data aggregation component that can be used in many network
(and other) applications. It is a crucial structure to address performance and
scalability issues of diverse network applications including overlay networks,
wild card flow classification, web-caches, load balancing, connection tracking,
data-centric networks, flow table summaries, network statistics and traffic
monitoring.
Our Proof of Concept (PoC) using membership library to optimize flow lookup for
Open vSwitch (OvS) shows a speed up of about 3X.
Signed-off-by: Yipeng Wang<Yipeng1.wang@intel.com>
Signed-off-by: Sameh Gobriel<sameh.gobriel@intel.com>
Signed-off-by: Charlie Tai<charlie.tai@intel.com>
Signed-off-by: Ren Wang<ren.wang@intel.com>
Yipeng Wang (1):
Add Membership Library
MAINTAINERS | 7 +
config/defconfig_x86_64-native-linuxapp-gcc | 3 +
doc/guides/prog_guide/img/memship_i1.svg | 1269 ++++++++++++++++++++++
doc/guides/prog_guide/img/memship_i2.svg | 36 +
doc/guides/prog_guide/img/memship_i3.svg | 148 +++
doc/guides/prog_guide/img/memship_i4.svg | 428 ++++++++
doc/guides/prog_guide/img/memship_i5.svg | 123 +++
doc/guides/prog_guide/img/memship_i6.svg | 233 ++++
doc/guides/prog_guide/img/memship_i7.svg | 277 +++++
doc/guides/prog_guide/index.rst | 14 +
doc/guides/prog_guide/membership_lib.rst | 421 +++++++
lib/Makefile | 3 +-
lib/librte_eal/common/eal_common_log.c | 1 +
lib/librte_eal/common/include/rte_log.h | 1 +
lib/librte_membership/Makefile | 48 +
lib/librte_membership/rte_membership.c | 378 +++++++
lib/librte_membership/rte_membership.h | 321 ++++++
lib/librte_membership/rte_membership_bf.c | 254 +++++
lib/librte_membership/rte_membership_bf.h | 99 ++
lib/librte_membership/rte_membership_cache.c | 345 ++++++
lib/librte_membership/rte_membership_cache.h | 95 ++
lib/librte_membership/rte_membership_ht.c | 471 ++++++++
lib/librte_membership/rte_membership_ht.h | 98 ++
lib/librte_membership/rte_membership_vbf.c | 391 +++++++
lib/librte_membership/rte_membership_vbf.h | 85 ++
lib/librte_membership/rte_membership_version.map | 15 +
mk/rte.app.mk | 1 +
test/test/Makefile | 2 +
test/test/test_membership.c | 459 ++++++++
29 files changed, 6025 insertions(+), 1 deletion(-)
create mode 100644 doc/guides/prog_guide/img/memship_i1.svg
create mode 100644 doc/guides/prog_guide/img/memship_i2.svg
create mode 100644 doc/guides/prog_guide/img/memship_i3.svg
create mode 100644 doc/guides/prog_guide/img/memship_i4.svg
create mode 100644 doc/guides/prog_guide/img/memship_i5.svg
create mode 100644 doc/guides/prog_guide/img/memship_i6.svg
create mode 100644 doc/guides/prog_guide/img/memship_i7.svg
create mode 100644 doc/guides/prog_guide/membership_lib.rst
create mode 100644 lib/librte_membership/Makefile
create mode 100644 lib/librte_membership/rte_membership.c
create mode 100644 lib/librte_membership/rte_membership.h
create mode 100644 lib/librte_membership/rte_membership_bf.c
create mode 100644 lib/librte_membership/rte_membership_bf.h
create mode 100644 lib/librte_membership/rte_membership_cache.c
create mode 100644 lib/librte_membership/rte_membership_cache.h
create mode 100644 lib/librte_membership/rte_membership_ht.c
create mode 100644 lib/librte_membership/rte_membership_ht.h
create mode 100644 lib/librte_membership/rte_membership_vbf.c
create mode 100644 lib/librte_membership/rte_membership_vbf.h
create mode 100644 lib/librte_membership/rte_membership_version.map
create mode 100644 test/test/test_membership.c
--
1.9.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [dpdk-dev] [RFC] Add Membership Library
2017-05-27 1:34 [dpdk-dev] [RFC] Add Membership Library Yipeng Wang
@ 2017-05-27 1:34 ` Yipeng Wang
2017-05-27 9:42 ` Vincent Jardin
1 sibling, 0 replies; 7+ messages in thread
From: Yipeng Wang @ 2017-05-27 1:34 UTC (permalink / raw)
To: yipeng1.wang; +Cc: dev, sameh.gobriel, ren.wang, charlie.tai
A proposal for a new DPDK library that is called “Membership Library”. It
provides an API for DPDK applications to insert a new member, delete an existing
member, or query the existence of a member in a given set, or a group of sets.
For the case of a group of sets the library will return not only whether the
element has been inserted before in one of the sets but also which set it
belongs to.
The Membership Library is an extension and generalization of a traditional
filter (for example Bloom Filter) structure that has multiple usages in a wide
variety of workloads and applications. In general, the Membership Library is a
data structure that provides a “set-summary” and responds to set-membership
queries whether a certain member belongs to a set(s). There are two advantages
of using such a set-summary rather than operating on a “full-blown” complete
list of elements: firstly it has a much smaller storage requirement than storing
the whole list of elements themselves, and secondly checking an element
membership (or other operations) in this set-summary is much faster than
checking it for the original full-blown complete list of elements.
A membership test for an element will return the set this element belongs to or
null (meaning not found) with very high probability of accuracy. Set-summary is
a fundamental data aggregation component that can be used in many network
(and other) applications. It is a crucial structure to address performance and
scalability issues of diverse network applications including overlay networks,
wild card flow classification, web-caches, load balancing, connection tracking,
data-centric networks, flow table summaries, network statistics and traffic
monitoring.
Our Proof of Concept (PoC) using membership library to optimize flow lookup for
Open vSwitch (OvS) shows a speed up of about 3X.
---
MAINTAINERS | 7 +
config/defconfig_x86_64-native-linuxapp-gcc | 3 +
doc/guides/prog_guide/img/memship_i1.svg | 1269 ++++++++++++++++++++++
doc/guides/prog_guide/img/memship_i2.svg | 36 +
doc/guides/prog_guide/img/memship_i3.svg | 148 +++
doc/guides/prog_guide/img/memship_i4.svg | 428 ++++++++
doc/guides/prog_guide/img/memship_i5.svg | 123 +++
doc/guides/prog_guide/img/memship_i6.svg | 233 ++++
doc/guides/prog_guide/img/memship_i7.svg | 277 +++++
doc/guides/prog_guide/index.rst | 14 +
doc/guides/prog_guide/membership_lib.rst | 424 ++++++++
lib/Makefile | 3 +-
lib/librte_eal/common/eal_common_log.c | 1 +
lib/librte_eal/common/include/rte_log.h | 1 +
lib/librte_membership/Makefile | 48 +
lib/librte_membership/rte_membership.c | 378 +++++++
lib/librte_membership/rte_membership.h | 321 ++++++
lib/librte_membership/rte_membership_bf.c | 254 +++++
lib/librte_membership/rte_membership_bf.h | 99 ++
lib/librte_membership/rte_membership_cache.c | 345 ++++++
lib/librte_membership/rte_membership_cache.h | 95 ++
lib/librte_membership/rte_membership_ht.c | 471 ++++++++
lib/librte_membership/rte_membership_ht.h | 98 ++
lib/librte_membership/rte_membership_vbf.c | 391 +++++++
lib/librte_membership/rte_membership_vbf.h | 85 ++
lib/librte_membership/rte_membership_version.map | 15 +
mk/rte.app.mk | 1 +
test/test/Makefile | 2 +
test/test/test_membership.c | 459 ++++++++
29 files changed, 6028 insertions(+), 1 deletion(-)
create mode 100644 doc/guides/prog_guide/img/memship_i1.svg
create mode 100644 doc/guides/prog_guide/img/memship_i2.svg
create mode 100644 doc/guides/prog_guide/img/memship_i3.svg
create mode 100644 doc/guides/prog_guide/img/memship_i4.svg
create mode 100644 doc/guides/prog_guide/img/memship_i5.svg
create mode 100644 doc/guides/prog_guide/img/memship_i6.svg
create mode 100644 doc/guides/prog_guide/img/memship_i7.svg
create mode 100644 doc/guides/prog_guide/membership_lib.rst
create mode 100644 lib/librte_membership/Makefile
create mode 100644 lib/librte_membership/rte_membership.c
create mode 100644 lib/librte_membership/rte_membership.h
create mode 100644 lib/librte_membership/rte_membership_bf.c
create mode 100644 lib/librte_membership/rte_membership_bf.h
create mode 100644 lib/librte_membership/rte_membership_cache.c
create mode 100644 lib/librte_membership/rte_membership_cache.h
create mode 100644 lib/librte_membership/rte_membership_ht.c
create mode 100644 lib/librte_membership/rte_membership_ht.h
create mode 100644 lib/librte_membership/rte_membership_vbf.c
create mode 100644 lib/librte_membership/rte_membership_vbf.h
create mode 100644 lib/librte_membership/rte_membership_version.map
create mode 100644 test/test/test_membership.c
diff --git a/MAINTAINERS b/MAINTAINERS
index afb4cab..fc9e937 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -696,6 +696,13 @@ F: test/test/test_meter.c
F: examples/qos_meter/
F: doc/guides/sample_app_ug/qos_metering.rst
+MEMBERSHIP
+M: Yipeng Wang <yipeng1.wang@intel.com>
+M: Sameh Gobriel <sameh.gobriel@intel.com>
+F: lib/librte_membership/
+F: doc/guides/prog_guide/membership.rst
+F: test/test/test_membership*
+
Other libraries
---------------
diff --git a/config/defconfig_x86_64-native-linuxapp-gcc b/config/defconfig_x86_64-native-linuxapp-gcc
index e69a37e..0a218d5 100644
--- a/config/defconfig_x86_64-native-linuxapp-gcc
+++ b/config/defconfig_x86_64-native-linuxapp-gcc
@@ -41,3 +41,6 @@ CONFIG_RTE_ARCH_64=y
CONFIG_RTE_TOOLCHAIN="gcc"
CONFIG_RTE_TOOLCHAIN_GCC=y
+
+
+CONFIG_RTE_LIBRTE_MEMBERSHIP=y
diff --git a/doc/guides/prog_guide/img/memship_i1.svg b/doc/guides/prog_guide/img/memship_i1.svg
new file mode 100644
index 0000000..6f011ae
--- /dev/null
+++ b/doc/guides/prog_guide/img/memship_i1.svg
@@ -0,0 +1,1269 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by Microsoft Visio, SVG Export memship_i1.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
+ width="7.18709in" height="4.75757in" viewBox="0 0 517.471 342.545" xml:space="preserve" color-interpolation-filters="sRGB"
+ class="st56">
+ <style type="text/css">
+ <![CDATA[
+ .st1 {visibility:visible}
+ .st2 {fill:none;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.22}
+ .st3 {fill:#5b9bd5;filter:url(#filter_2);font-family:Calibri;font-size:0.75em;opacity:0.219608}
+ .st4 {font-size:1em}
+ .st5 {fill:none;stroke:#41719c;stroke-width:3}
+ .st6 {fill:#5b9bd5;font-family:Calibri;font-size:0.75em}
+ .st7 {fill:#5b9bd5;fill-opacity:0.22;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.22}
+ .st8 {fill:#5b9bd5;stroke:#c7c8c8;stroke-width:0.25}
+ .st9 {fill:none;stroke:none;stroke-width:0.25}
+ .st10 {fill:#ffffff;font-family:Calibri;font-size:0.499992em;font-weight:bold}
+ .st11 {fill:#ffffff;font-family:Calibri;font-size:0.75em;font-weight:bold}
+ .st12 {marker-end:url(#mrkr5-74);stroke:#5b9bd5;stroke-linecap:round;stroke-linejoin:round;stroke-width:1}
+ .st13 {fill:#5b9bd5;fill-opacity:1;stroke:#5b9bd5;stroke-opacity:1;stroke-width:0.28409090909091}
+ .st14 {fill:#5b9bd5;font-family:Calibri;font-size:0.666664em}
+ .st15 {stroke:#5b9bd5;stroke-linecap:round;stroke-linejoin:round;stroke-width:1}
+ .st16 {fill:#feffff;font-family:Calibri;font-size:0.499992em}
+ .st17 {fill:#deebf6;stroke:#c7c8c8;stroke-width:0.25}
+ .st18 {fill:#000000;font-family:Calibri;font-size:0.499992em}
+ .st19 {marker-end:url(#mrkr5-200);stroke:#ff0000;stroke-linecap:round;stroke-linejoin:round;stroke-width:1}
+ .st20 {fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-opacity:1;stroke-width:0.28409090909091}
+ .st21 {fill:#ff0000;font-family:Calibri;font-size:0.666664em}
+ .st22 {fill:#5b9bd5;fill-opacity:0.22;filter:url(#filter_2)}
+ .st23 {fill:#ffffff}
+ .st24 {stroke:#0070c0;stroke-width:0.25}
+ .st25 {fill:#5b9bd5;stroke:#0070c0;stroke-width:0.25}
+ .st26 {fill:#5b9bd5;stroke:#ffffff;stroke-width:0.25}
+ .st27 {fill:#5b9bd5}
+ .st28 {stroke:#c7c8c8;stroke-width:0.25}
+ .st29 {fill:#acccea;stroke:#c7c8c8;stroke-width:0.25}
+ .st30 {fill:#5b9bd5;fill-opacity:0.22;filter:url(#filter_2);stroke:none;stroke-linecap:butt}
+ .st31 {fill:#000000;fill-opacity:0;stroke:none;stroke-linecap:butt;stroke-width:0.75}
+ .st32 {fill:url(#grad0-350);stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+ .st33 {fill:url(#grad0-354);stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+ .st34 {fill:url(#grad10-358);stroke:#308dda;stroke-linecap:butt;stroke-width:0.130208}
+ .st35 {fill:url(#grad7-366);stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+ .st36 {fill:url(#grad3-376);stroke:#000000;stroke-linecap:butt;stroke-width:0.130208}
+ .st37 {fill:url(#grad1-383);stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+ .st38 {fill:url(#grad3-396);stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+ .st39 {fill:none}
+ .st40 {stroke:#308dda;stroke-linecap:butt;stroke-width:0.130208}
+ .st41 {stroke:#ffffff;stroke-linecap:butt;stroke-width:0.130208}
+ .st42 {fill:url(#grad0-424);stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+ .st43 {fill:url(#grad7-437);stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+ .st44 {fill:none;stroke:#c8c8c8;stroke-width:0.75}
+ .st45 {fill:#9a9a9a;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.0833333}
+ .st46 {fill:url(#grad5-456);stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.0833333}
+ .st47 {fill:url(#grad5-460);stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.0833333}
+ .st48 {stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.25}
+ .st49 {fill:url(#grad10-471);stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.0833333}
+ .st50 {stroke:#c8c8c8;stroke-width:0.75}
+ .st51 {stroke:#4f87bb;stroke-width:0.75}
+ .st52 {fill:#5b9bd5;fill-opacity:0.25;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.25}
+ .st53 {fill:#4f87bb;stroke:#40709c;stroke-width:0.75}
+ .st54 {fill:none;stroke:#0070c0;stroke-width:2.25}
+ .st55 {fill:#595959;font-family:Arial;font-size:0.666664em}
+ .st56 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+ ]]>
+ </style>
+
+ <defs id="Patterns_And_Gradients">
+ <linearGradient id="grad0-350" x1="0" y1="0" x2="1" y2="0" gradientTransform="rotate(270 0.5 0.5)">
+ <stop offset="0" stop-color="#97c2e6" stop-opacity="1"/>
+ <stop offset="1" stop-color="#4274a2" stop-opacity="1"/>
+ </linearGradient>
+ <linearGradient id="grad0-354" x1="0" y1="0" x2="1" y2="0" gradientTransform="rotate(0 0.5 0.5)">
+ <stop offset="0" stop-color="#5491d3" stop-opacity="1"/>
+ <stop offset="1" stop-color="#246ba6" stop-opacity="1"/>
+ </linearGradient>
+ <pattern id="grad10-358" x="0" y="0" width="1" height="1" patternContentUnits="objectBoundingBox">
+ <path d="M 0.5 0.5 L 0 0 L 0 1 z" style="fill:url(#grad0-359)"/>
+ <path d="M 0.5 0.5 L 1 0 L 1 1 z" style="fill:url(#grad0-360)"/>
+ <path d="M 0.5 0.5 L 0 0 L 1 0 z" style="fill:url(#grad0-361)"/>
+ <path d="M 0.5 0.5 L 0 1 L 1 1 z" style="fill:url(#grad0-362)"/>
+ </pattern>
+ <linearGradient id="grad0-359" x1="0" y1="0" x2="1" y2="0" gradientTransform="rotate(180 0.5 0.5)">
+ <stop offset="0" stop-color="#569bd3" stop-opacity="1"/>
+ <stop offset="1" stop-color="#aed0ec" stop-opacity="1"/>
+ </linearGradient>
+ <linearGradient id="grad0-360" x1="0" y1="0" x2="1" y2="0" gradientTransform="rotate(360 0.5 0.5)">
+ <stop offset="0" stop-color="#569bd3" stop-opacity="1"/>
+ <stop offset="1" stop-color="#aed0ec" stop-opacity="1"/>
+ </linearGradient>
+ <linearGradient id="grad0-361" x1="0" y1="0" x2="1" y2="0" gradientTransform="rotate(270 0.5 0.5)">
+ <stop offset="0" stop-color="#569bd3" stop-opacity="1"/>
+ <stop offset="1" stop-color="#aed0ec" stop-opacity="1"/>
+ </linearGradient>
+ <linearGradient id="grad0-362" x1="0" y1="0" x2="1" y2="0" gradientTransform="rotate(90 0.5 0.5)">
+ <stop offset="0" stop-color="#569bd3" stop-opacity="1"/>
+ <stop offset="1" stop-color="#aed0ec" stop-opacity="1"/>
+ </linearGradient>
+ <radialGradient id="grad7-366" cx="0" cy="0" r="1.4">
+ <stop offset="0" stop-color="#c0dff1" stop-opacity="1"/>
+ <stop offset="1" stop-color="#246ba6" stop-opacity="1"/>
+ </radialGradient>
+ <radialGradient id="grad3-376" cx="0.5" cy="0.5" r="0.73">
+ <stop offset="0" stop-color="#c8e5c8" stop-opacity="1"/>
+ <stop offset="1" stop-color="#19bf19" stop-opacity="1"/>
+ </radialGradient>
+ <radialGradient id="grad1-383" cx="1" cy="1" r="1.4">
+ <stop offset="0" stop-color="#5599d7" stop-opacity="1"/>
+ <stop offset="1" stop-color="#b9daf2" stop-opacity="1"/>
+ </radialGradient>
+ <radialGradient id="grad3-396" cx="0.5" cy="0.5" r="0.73">
+ <stop offset="0" stop-color="#5599d7" stop-opacity="1"/>
+ <stop offset="1" stop-color="#214383" stop-opacity="1"/>
+ </radialGradient>
+ <linearGradient id="grad0-424" x1="0" y1="0" x2="1" y2="0" gradientTransform="rotate(270 0.5 0.5)">
+ <stop offset="0" stop-color="#97c2e6" stop-opacity="1"/>
+ <stop offset="1" stop-color="#6ba4dc" stop-opacity="1"/>
+ </linearGradient>
+ <radialGradient id="grad7-437" cx="0" cy="0" r="1.4">
+ <stop offset="0" stop-color="#89bee9" stop-opacity="1"/>
+ <stop offset="1" stop-color="#b9daf2" stop-opacity="1"/>
+ </radialGradient>
+ <radialGradient id="grad5-456" cx="0.5" cy="1" r="1.1">
+ <stop offset="0" stop-color="#000000" stop-opacity="1"/>
+ <stop offset="1" stop-color="#ffffff" stop-opacity="1"/>
+ </radialGradient>
+ <radialGradient id="grad5-460" cx="0.5" cy="1" r="1.1">
+ <stop offset="0" stop-color="#ffffff" stop-opacity="1"/>
+ <stop offset="1" stop-color="#9a9a9a" stop-opacity="1"/>
+ </radialGradient>
+ <pattern id="grad10-471" x="0" y="0" width="1" height="1" patternContentUnits="objectBoundingBox">
+ <path d="M 0.5 0.5 L 0 0 L 0 1 z" style="fill:url(#grad0-472)"/>
+ <path d="M 0.5 0.5 L 1 0 L 1 1 z" style="fill:url(#grad0-473)"/>
+ <path d="M 0.5 0.5 L 0 0 L 1 0 z" style="fill:url(#grad0-474)"/>
+ <path d="M 0.5 0.5 L 0 1 L 1 1 z" style="fill:url(#grad0-475)"/>
+ </pattern>
+ <linearGradient id="grad0-472" x1="0" y1="0" x2="1" y2="0" gradientTransform="rotate(180 0.5 0.5)">
+ <stop offset="0" stop-color="#ffffff" stop-opacity="1"/>
+ <stop offset="1" stop-color="#ffcc00" stop-opacity="1"/>
+ </linearGradient>
+ <linearGradient id="grad0-473" x1="0" y1="0" x2="1" y2="0" gradientTransform="rotate(360 0.5 0.5)">
+ <stop offset="0" stop-color="#ffffff" stop-opacity="1"/>
+ <stop offset="1" stop-color="#ffcc00" stop-opacity="1"/>
+ </linearGradient>
+ <linearGradient id="grad0-474" x1="0" y1="0" x2="1" y2="0" gradientTransform="rotate(270 0.5 0.5)">
+ <stop offset="0" stop-color="#ffffff" stop-opacity="1"/>
+ <stop offset="1" stop-color="#ffcc00" stop-opacity="1"/>
+ </linearGradient>
+ <linearGradient id="grad0-475" x1="0" y1="0" x2="1" y2="0" gradientTransform="rotate(90 0.5 0.5)">
+ <stop offset="0" stop-color="#ffffff" stop-opacity="1"/>
+ <stop offset="1" stop-color="#ffcc00" stop-opacity="1"/>
+ </linearGradient>
+ </defs>
+ <defs id="Markers">
+ <g id="lend5">
+ <path d="M 2 1 L 0 0 L 1.98117 -0.993387 C 1.67173 -0.364515 1.67301 0.372641 1.98465 1.00043 " style="stroke:none"/>
+ </g>
+ <marker id="mrkr5-74" class="st13" refX="-6.16" orient="auto" markerUnits="strokeWidth" overflow="visible">
+ <use xlink:href="#lend5" transform="scale(-3.52,-3.52) "/>
+ </marker>
+ <marker id="mrkr5-200" class="st20" refX="-5.8" orient="auto" markerUnits="strokeWidth" overflow="visible">
+ <use xlink:href="#lend5" transform="scale(-3.52,-3.52) "/>
+ </marker>
+ </defs>
+ <defs id="Filters">
+ <filter id="filter_2">
+ <feGaussianBlur stdDeviation="2"/>
+ </filter>
+ </defs>
+ <g>
+ <title>Page-1</title>
+ <g id="group165-1" transform="translate(21.7794,-24.0978)">
+ <title>Sheet.165</title>
+ <g id="group1-2" transform="translate(308.647,-25.7109)">
+ <title>Sheet.1</title>
+ <g id="shape2-3" transform="translate(13.6117,-58.9839)">
+ <title>Circle</title>
+ <desc>List 1 matching Criteria 1</desc>
+ <g id="shadow2-4" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M0 315.32 A27.2233 27.2233 0 1 1 54.45 315.32 A27.2233 27.2233 0 1 1 0 315.32 Z" class="st2"/>
+ <text x="17.73" y="307.22" class="st3">List 1 <tspan x="10.18" dy="1.2em" class="st4">matching </tspan><tspan
+ x="10.42" dy="1.2em" class="st4">Criteria </tspan>1</text> </g>
+ <path d="M0 315.32 A27.2233 27.2233 0 1 1 54.45 315.32 A27.2233 27.2233 0 1 1 0 315.32 Z" class="st5"/>
+ <text x="17.73" y="307.22" class="st6">List 1 <tspan x="10.18" dy="1.2em" class="st4">matching </tspan><tspan
+ x="10.42" dy="1.2em" class="st4">Criteria </tspan>1</text> </g>
+ <g id="shape3-15" transform="translate(58.9839,-58.9839)">
+ <title>Circle.23</title>
+ <desc>List 2</desc>
+ <g id="shadow3-16" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M0 315.32 A27.2233 27.2233 0 1 1 54.45 315.32 A27.2233 27.2233 0 1 1 0 315.32 Z" class="st2"/>
+ <text x="17.73" y="318.02" class="st3">List 2</text> </g>
+ <path d="M0 315.32 A27.2233 27.2233 0 1 1 54.45 315.32 A27.2233 27.2233 0 1 1 0 315.32 Z" class="st5"/>
+ <text x="17.73" y="318.02" class="st6">List 2</text> </g>
+ <g id="shape4-23">
+ <title>Circle.24</title>
+ <desc>List 1 matching Criteria 1</desc>
+ <g id="shadow4-24" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M0 315.32 A27.2233 27.2233 0 1 1 54.45 315.32 A27.2233 27.2233 0 1 1 0 315.32 Z" class="st2"/>
+ <text x="17.73" y="307.22" class="st3">List 1 <tspan x="10.18" dy="1.2em" class="st4">matching </tspan><tspan
+ x="10.42" dy="1.2em" class="st4">Criteria </tspan>1</text> </g>
+ <path d="M0 315.32 A27.2233 27.2233 0 1 1 54.45 315.32 A27.2233 27.2233 0 1 1 0 315.32 Z" class="st5"/>
+ <text x="17.73" y="307.22" class="st6">List 1 <tspan x="10.18" dy="1.2em" class="st4">matching </tspan><tspan
+ x="10.42" dy="1.2em" class="st4">Criteria </tspan>1</text> </g>
+ <g id="group5-35" transform="translate(50.7413,-4.53722)">
+ <title>Sheet.5</title>
+ <g id="shape6-36" transform="translate(344.2,300.5) rotate(90)">
+ <title>Triangle</title>
+ <g id="shadow6-37" transform="matrix(1,0,0,1,1.97279,-0.345598)" class="st1">
+ <path d="M42.04 342.55 L21.02 318.64 L0 342.55 L42.04 342.55 Z" class="st7"/>
+ </g>
+ <path d="M42.04 342.55 L21.02 318.64 L0 342.55 L42.04 342.55 Z" class="st8"/>
+ </g>
+ <g id="shape7-41" transform="translate(-0.884982,-14.7157)">
+ <title>Sheet.7</title>
+ <desc>Set Summary</desc>
+ <rect x="0" y="329.932" width="25.8535" height="12.6135" class="st9"/>
+ <text x="8.96" y="330.84" class="st10">Set <tspan x="5.02" dy="1.2em" class="st4">Summ</tspan><tspan
+ x="8.96" dy="1.2em" class="st4">ary</tspan></text> </g>
+ </g>
+ <g id="shape8-46" transform="translate(72.5955,0)">
+ <title>Circle.29</title>
+ <desc>List 2 matching Criteria 2</desc>
+ <g id="shadow8-47" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M0 315.32 A27.2233 27.2233 0 1 1 54.45 315.32 A27.2233 27.2233 0 1 1 0 315.32 Z" class="st2"/>
+ <text x="17.73" y="307.22" class="st3">List 2 <tspan x="10.18" dy="1.2em" class="st4">matching </tspan><tspan
+ x="10.42" dy="1.2em" class="st4">Criteria </tspan>2</text> </g>
+ <path d="M0 315.32 A27.2233 27.2233 0 1 1 54.45 315.32 A27.2233 27.2233 0 1 1 0 315.32 Z" class="st5"/>
+ <text x="17.73" y="307.22" class="st6">List 2 <tspan x="10.18" dy="1.2em" class="st4">matching </tspan><tspan
+ x="10.42" dy="1.2em" class="st4">Criteria </tspan>2</text> </g>
+ </g>
+ <g id="group9-58" transform="translate(31.6515,-49.9094)">
+ <title>Sheet.9</title>
+ <g id="group10-59" transform="translate(99.5691,0)">
+ <title>Sheet.10</title>
+ <g id="shape11-60" transform="translate(346.175,275.999) rotate(90)">
+ <title>Triangle</title>
+ <g id="shadow11-61" transform="matrix(1,0,0,1,1.97279,-0.345598)" class="st1">
+ <path d="M66.55 342.55 L33.27 290.12 L0 342.55 L66.55 342.55 Z" class="st7"/>
+ </g>
+ <path d="M66.55 342.55 L33.27 290.12 L0 342.55 L66.55 342.55 Z" class="st8"/>
+ </g>
+ <g id="shape12-65" transform="translate(355.063,285.074) rotate(90)">
+ <title>Sheet.12</title>
+ <desc>Set Summary</desc>
+ <rect x="0" y="322.581" width="48.397" height="19.9638" class="st9"/>
+ <text x="18.25" y="329.86" class="st11">Set <tspan x="6.38" dy="1.2em" class="st4">Summary</tspan></text> </g>
+ </g>
+ <g id="shape13-69" transform="translate(57.5835,-54.4467)">
+ <title>Sheet.13</title>
+ <path d="M0 342.55 L38.9 342.55" class="st12"/>
+ </g>
+ <g id="shape14-75" transform="translate(13.4863,-47.4928)">
+ <title>Sheet.14</title>
+ <desc>Flow Key</desc>
+ <rect x="0" y="324.396" width="50.6656" height="18.1489" class="st9"/>
+ <text x="10.83" y="335.87" class="st14">Flow Key</text> </g>
+ <g id="shape15-78" transform="translate(5.02911,1.60865) rotate(-26.0815)">
+ <title>Sheet.15</title>
+ <path d="M0 342.55 L39.25 342.55" class="st12"/>
+ </g>
+ <g id="shape16-83" transform="translate(155.629,-33.273)">
+ <title>Sheet.16</title>
+ <path d="M0 342.55 L38.34 342.55" class="st12"/>
+ </g>
+ <g id="shape17-88" transform="translate(304.141,0.595416) rotate(25.6934)">
+ <title>Sheet.17</title>
+ <path d="M0 342.55 L42.68 342.55" class="st12"/>
+ </g>
+ <g id="shape18-93" transform="translate(102.642,654.842) rotate(180)">
+ <title>Sheet.18</title>
+ <path d="M0 342.55 L30.14 342.55" class="st12"/>
+ </g>
+ <g id="shape19-98" transform="translate(-11.5184,-24.9928)">
+ <title>Sheet.19</title>
+ <desc>New Flow = New Assignment</desc>
+ <rect x="0" y="324.396" width="102.087" height="18.1489" class="st9"/>
+ <text x="23.75" y="331.07" class="st14">New Flow = New <tspan x="32.07" dy="1.2em" class="st4">Assignment</tspan></text> </g>
+ <g id="shape20-102" transform="translate(102.844,679.041) rotate(180)">
+ <title>Sheet.20</title>
+ <path d="M0 342.55 L30.14 342.55" class="st12"/>
+ </g>
+ <g id="shape21-107" transform="translate(-13.7684,-0.0938726)">
+ <title>Sheet.21</title>
+ <desc>Old Flow = forward to specific thread</desc>
+ <rect x="0" y="324.396" width="102.087" height="18.1489" class="st9"/>
+ <text x="15.6" y="331.07" class="st14">Old Flow = forward to <tspan x="27.2" dy="1.2em" class="st4">specific thread</tspan></text> </g>
+ <g id="shape22-111" transform="translate(541.496,275.999) rotate(90)">
+ <title>Sheet.22</title>
+ <path d="M0 335.81 C2.14 344.21 5.09 343.6 7.56 340.31 C10.62 336.25 12.94 328.1 18.15 335.81" class="st15"/>
+ </g>
+ <g id="shape23-114" transform="translate(541.496,300.198) rotate(90)">
+ <title>Sheet.23</title>
+ <path d="M0 335.81 C2.14 344.21 5.09 343.6 7.56 340.31 C10.62 336.25 12.94 328.1 18.15 335.81" class="st15"/>
+ </g>
+ <g id="shape24-117" transform="translate(541.496,324.396) rotate(90)">
+ <title>Sheet.24</title>
+ <path d="M0 335.81 C2.14 344.21 5.09 343.6 7.56 340.31 C10.62 336.25 12.94 328.1 18.15 335.81" class="st15"/>
+ </g>
+ </g>
+ <g id="group25-120" transform="translate(285.961,-178.628)">
+ <title>Sheet.25</title>
+ <g id="shape26-121" transform="translate(51.2583,-51.2583)">
+ <title>Circle</title>
+ <g id="shadow26-122" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M0 333.23 A9.3197 9.3197 0 0 1 18.64 333.23 A9.3197 9.3197 0 0 1 0 333.23 Z" class="st7"/>
+ </g>
+ <path d="M0 333.23 A9.3197 9.3197 0 0 1 18.64 333.23 A9.3197 9.3197 0 0 1 0 333.23 Z" class="st8"/>
+ </g>
+ <g id="shape27-126" transform="translate(107.177,-55.9182)">
+ <title>Circle.156</title>
+ <g id="shadow27-127" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M0 333.23 A9.3197 9.3197 0 0 1 18.64 333.23 A9.3197 9.3197 0 0 1 0 333.23 Z" class="st7"/>
+ </g>
+ <path d="M0 333.23 A9.3197 9.3197 0 0 1 18.64 333.23 A9.3197 9.3197 0 0 1 0 333.23 Z" class="st8"/>
+ </g>
+ <g id="shape28-131" transform="translate(79.2174,-83.8773)">
+ <title>Circle.157</title>
+ <g id="shadow28-132" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M0 333.23 A9.3197 9.3197 0 0 1 18.64 333.23 A9.3197 9.3197 0 0 1 0 333.23 Z" class="st7"/>
+ </g>
+ <path d="M0 333.23 A9.3197 9.3197 0 0 1 18.64 333.23 A9.3197 9.3197 0 0 1 0 333.23 Z" class="st8"/>
+ </g>
+ <g id="shape29-136" transform="translate(153.775,-51.2583)">
+ <title>Circle.158</title>
+ <g id="shadow29-137" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M0 333.23 A9.3197 9.3197 0 0 1 18.64 333.23 A9.3197 9.3197 0 0 1 0 333.23 Z" class="st7"/>
+ </g>
+ <path d="M0 333.23 A9.3197 9.3197 0 0 1 18.64 333.23 A9.3197 9.3197 0 0 1 0 333.23 Z" class="st8"/>
+ </g>
+ <g id="shape30-141" transform="translate(93.197,-18.6394)">
+ <title>Circle.159</title>
+ <g id="shadow30-142" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M0 333.23 A9.3197 9.3197 0 0 1 18.64 333.23 A9.3197 9.3197 0 0 1 0 333.23 Z" class="st7"/>
+ </g>
+ <path d="M0 333.23 A9.3197 9.3197 0 0 1 18.64 333.23 A9.3197 9.3197 0 0 1 0 333.23 Z" class="st8"/>
+ </g>
+ <g id="shape31-146" transform="translate(27.4102,-57.9329) rotate(-7.12502)">
+ <title>Sheet.31</title>
+ <path d="M0 342.55 L31.41 342.55" class="st12"/>
+ </g>
+ <g id="shape32-151" transform="translate(182.13,-60.5772) rotate(9.46232)">
+ <title>Sheet.32</title>
+ <path d="M0 342.55 L22.18 342.55" class="st12"/>
+ </g>
+ <g id="shape33-156" transform="translate(47.8843,595.237) rotate(-160.346)">
+ <title>Sheet.33</title>
+ <path d="M0 342.55 L63.11 342.55" class="st12"/>
+ </g>
+ <g id="shape34-161" transform="translate(292.945,525.785) rotate(141.977)">
+ <title>Sheet.34</title>
+ <path d="M0 342.55 L20.97 342.55" class="st12"/>
+ </g>
+ <g id="shape35-166" transform="translate(-95.8971,591.793) rotate(-145.945)">
+ <title>Sheet.35</title>
+ <path d="M0 342.55 L28.55 342.55" class="st12"/>
+ </g>
+ <g id="shape36-171" transform="translate(37.2788,2.27374E-013)">
+ <title>Rectangle.167</title>
+ <desc>SUM</desc>
+ <g id="shadow36-172" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="328.566" width="21.7305" height="13.9795" class="st7"/>
+ </g>
+ <rect x="0" y="328.566" width="21.7305" height="13.9795" class="st8"/>
+ <text x="5" y="337.36" class="st16">SUM</text> </g>
+ <g id="shape37-177" transform="translate(55.9182,2.27374E-013)">
+ <title>Rectangle.168</title>
+ <desc>Packet</desc>
+ <g id="shadow37-178" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="328.566" width="46.5985" height="13.9795" class="st7"/>
+ </g>
+ <rect x="0" y="328.566" width="46.5985" height="13.9795" class="st17"/>
+ <text x="15.18" y="337.36" class="st18">Packet</text> </g>
+ <g id="shape38-183" transform="translate(-1.65867E-013,-32.6189)">
+ <title>Rectangle.169</title>
+ <desc>SUM</desc>
+ <g id="shadow38-184" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="328.566" width="20.7593" height="13.9795" class="st7"/>
+ </g>
+ <rect x="0" y="328.566" width="20.7593" height="13.9795" class="st8"/>
+ <text x="4.51" y="337.36" class="st16">SUM</text> </g>
+ <g id="shape39-189" transform="translate(18.6394,-32.6189)">
+ <title>Rectangle.170</title>
+ <desc>Packet</desc>
+ <g id="shadow39-190" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="328.566" width="46.5985" height="13.9795" class="st7"/>
+ </g>
+ <rect x="0" y="328.566" width="46.5985" height="13.9795" class="st17"/>
+ <text x="15.18" y="337.36" class="st18">Packet</text> </g>
+ <g id="shape40-195" transform="translate(197.019,626.053) rotate(161.565)">
+ <title>Sheet.40</title>
+ <path d="M0 328.31 A55.7483 27.2427 -124.2 0 0 42.37 334.19 L42.47 333.85" class="st19"/>
+ </g>
+ <g id="shape41-201" transform="translate(154.607,584.177) rotate(161.121)">
+ <title>Sheet.41</title>
+ <path d="M0 319.39 A80.5593 29.9756 -101.99 0 0 41.7 325.37 L41.79 325.02" class="st19"/>
+ </g>
+ <g id="shape42-206" transform="translate(3.02481,-66.7025)">
+ <title>Sheet.42</title>
+ <desc>Encode ID</desc>
+ <rect x="0" y="328.566" width="38.9138" height="13.9795" class="st9"/>
+ <text x="7.51" y="333.16" class="st21">Encode <tspan x="15.99" dy="1.2em" class="st4">ID</tspan></text> </g>
+ </g>
+ <g id="group43-210" transform="translate(12.0993,-165.858)">
+ <title>Sheet.43</title>
+ <g id="group44-211" transform="translate(7.21495,-75.757)">
+ <title>User</title>
+ <g id="shape45-212" transform="translate(13.3353,-1.13687E-013)">
+ <title>Sheet.45</title>
+ <g id="shadow45-213" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M20.77 325.42 A2.63551 2.63601 -180 1 0 15.5 325.42 A2.63551 2.63601 -180 1 0 20.77 325.42 ZM20.96
+ 328.77 L15.25 328.77 C14.84 328.77 14.46 328.91 14.16 329.14 C13.95 329.31 13.78 329.52
+ 13.66 329.76 C13.54 330 13.47 330.27 13.47 330.55 L13.47 337.32 L15.03 337.32 L15.03 342.55
+ L21.12 342.55 L21.12 337.32 L22.74 337.32 L22.74 330.55 C22.74 330.14 22.6 329.76 22.36
+ 329.46 C22.2 329.25 21.99 329.08 21.75 328.96 C21.51 328.84 21.24 328.77 20.96 328.77 Z"
+ class="st22"/>
+ <path d="M20.77 325.42 A2.63551 2.63601 -180 1 0 15.5 325.42 A2.63551 2.63601 -180 1 0 20.77 325.42"
+ class="st2"/>
+ <path d="M20.96 328.77 L15.25 328.77 C14.84 328.77 14.46 328.91 14.16 329.14 C13.95 329.31 13.78 329.52
+ 13.66 329.76 C13.54 330 13.47 330.27 13.47 330.55 L13.47 337.32 L15.03 337.32 L15.03 342.55
+ L21.12 342.55 L21.12 337.32 L22.74 337.32 L22.74 330.55 C22.74 330.14 22.6 329.76 22.36
+ 329.46 C22.2 329.25 21.99 329.08 21.75 328.96 C21.51 328.84 21.24 328.77 20.96 328.77"
+ class="st2"/>
+ <path d="M18.1 342.55 L18.1 338.37" class="st2"/>
+ <path d="M15.03 337.32 L15.03 333.71" class="st2"/>
+ <path d="M21.12 337.32 L21.12 333.71" class="st2"/>
+ <path d="M0 337.32 L13.47 337.32" class="st2"/>
+ </g>
+ <path d="M20.77 325.42 A2.63551 2.63601 -180 1 0 15.5 325.42 A2.63551 2.63601 -180 1 0 20.77 325.42 ZM20.96
+ 328.77 L15.25 328.77 C14.84 328.77 14.46 328.91 14.16 329.14 C13.95 329.31 13.78 329.52 13.66
+ 329.76 C13.54 330 13.47 330.27 13.47 330.55 L13.47 337.32 L15.03 337.32 L15.03 342.55 L21.12
+ 342.55 L21.12 337.32 L22.74 337.32 L22.74 330.55 C22.74 330.14 22.6 329.76 22.36 329.46 C22.2
+ 329.25 21.99 329.08 21.75 328.96 C21.51 328.84 21.24 328.77 20.96 328.77 Z" class="st23"/>
+ <path d="M20.77 325.42 A2.63551 2.63601 -180 1 0 15.5 325.42 A2.63551 2.63601 -180 1 0 20.77 325.42"
+ class="st24"/>
+ <path d="M20.96 328.77 L15.25 328.77 C14.84 328.77 14.46 328.91 14.16 329.14 C13.95 329.31 13.78 329.52 13.66
+ 329.76 C13.54 330 13.47 330.27 13.47 330.55 L13.47 337.32 L15.03 337.32 L15.03 342.55 L21.12
+ 342.55 L21.12 337.32 L22.74 337.32 L22.74 330.55 C22.74 330.14 22.6 329.76 22.36 329.46 C22.2
+ 329.25 21.99 329.08 21.75 328.96 C21.51 328.84 21.24 328.77 20.96 328.77" class="st24"/>
+ <path d="M18.1 342.55 L18.1 338.37" class="st24"/>
+ <path d="M15.03 337.32 L15.03 333.71" class="st24"/>
+ <path d="M21.12 337.32 L21.12 333.71" class="st24"/>
+ <path d="M0 337.32 L13.47 337.32" class="st24"/>
+ </g>
+ <g id="shape46-230" transform="translate(0,-8.39743)">
+ <title>Sheet.46</title>
+ <g id="shadow46-231" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M21.09 325.52 C21.09 325.13 20.96 324.79 20.74 324.51 C20.59 324.32 20.4 324.16 20.19 324.06
+ C19.97 323.95 19.72 323.89 19.46 323.89 L3.55 323.89 C3.16 323.89 2.82 324.02 2.54 324.23
+ C2.35 324.38 2.19 324.57 2.09 324.79 C1.98 325.01 1.92 325.25 1.92 325.52 L1.92 336.04 L21.09
+ 336.04 L21.09 325.52 ZM21.18 337.33 L1.77 337.33 L0 340.51 L0 342.55 L23.06 342.55 L23.06
+ 340.51 L21.18 337.33 Z" class="st7"/>
+ </g>
+ <path d="M21.09 325.52 C21.09 325.13 20.96 324.79 20.74 324.51 C20.59 324.32 20.4 324.16 20.19 324.06 C19.97
+ 323.95 19.72 323.89 19.46 323.89 L3.55 323.89 C3.16 323.89 2.82 324.02 2.54 324.23 C2.35 324.38
+ 2.19 324.57 2.09 324.79 C1.98 325.01 1.92 325.25 1.92 325.52 L1.92 336.04 L21.09 336.04 L21.09
+ 325.52 ZM21.18 337.33 L1.77 337.33 L0 340.51 L0 342.55 L23.06 342.55 L23.06 340.51 L21.18 337.33
+ Z" class="st25"/>
+ </g>
+ <g id="shape47-235" transform="translate(3.19243,-16.175)">
+ <title>Sheet.47</title>
+ <path d="M16.62 342.55 L16.62 333.29 C16.62 333.23 16.61 333.18 16.58 333.13 C16.55 333.07 16.5 333.02 16.44
+ 332.98 C16.39 332.95 16.33 332.94 16.27 332.94 L0.35 332.94 C0.29 332.94 0.24 332.95 0.19 332.98
+ C0.13 333.01 0.08 333.07 0.04 333.12 C0.02 333.17 0 333.23 0 333.29 L0 342.55 L16.62 342.55
+ Z" class="st26"/>
+ </g>
+ <g id="shape48-237" transform="translate(1.97942,-10.81)">
+ <title>Sheet.48</title>
+ <path d="M0.96 340.83 L0 342.55 L19.06 342.55 L18.1 340.83 L0.96 340.83 Z" class="st23"/>
+ </g>
+ </g>
+ <g id="group49-240" transform="translate(7.21495,-47.1858)">
+ <title>User.7</title>
+ <g id="shape50-241" transform="translate(13.3353,-1.13687E-013)">
+ <title>Sheet.50</title>
+ <g id="shadow50-242" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M20.77 325.42 A2.63551 2.63601 -180 1 0 15.5 325.42 A2.63551 2.63601 -180 1 0 20.77 325.42 ZM20.96
+ 328.77 L15.25 328.77 C14.84 328.77 14.46 328.91 14.16 329.14 C13.95 329.31 13.78 329.52
+ 13.66 329.76 C13.54 330 13.47 330.27 13.47 330.55 L13.47 337.32 L15.03 337.32 L15.03 342.55
+ L21.12 342.55 L21.12 337.32 L22.74 337.32 L22.74 330.55 C22.74 330.14 22.6 329.76 22.36
+ 329.46 C22.2 329.25 21.99 329.08 21.75 328.96 C21.51 328.84 21.24 328.77 20.96 328.77 Z"
+ class="st22"/>
+ <path d="M20.77 325.42 A2.63551 2.63601 -180 1 0 15.5 325.42 A2.63551 2.63601 -180 1 0 20.77 325.42"
+ class="st2"/>
+ <path d="M20.96 328.77 L15.25 328.77 C14.84 328.77 14.46 328.91 14.16 329.14 C13.95 329.31 13.78 329.52
+ 13.66 329.76 C13.54 330 13.47 330.27 13.47 330.55 L13.47 337.32 L15.03 337.32 L15.03 342.55
+ L21.12 342.55 L21.12 337.32 L22.74 337.32 L22.74 330.55 C22.74 330.14 22.6 329.76 22.36
+ 329.46 C22.2 329.25 21.99 329.08 21.75 328.96 C21.51 328.84 21.24 328.77 20.96 328.77"
+ class="st2"/>
+ <path d="M18.1 342.55 L18.1 338.37" class="st2"/>
+ <path d="M15.03 337.32 L15.03 333.71" class="st2"/>
+ <path d="M21.12 337.32 L21.12 333.71" class="st2"/>
+ <path d="M0 337.32 L13.47 337.32" class="st2"/>
+ </g>
+ <path d="M20.77 325.42 A2.63551 2.63601 -180 1 0 15.5 325.42 A2.63551 2.63601 -180 1 0 20.77 325.42 ZM20.96
+ 328.77 L15.25 328.77 C14.84 328.77 14.46 328.91 14.16 329.14 C13.95 329.31 13.78 329.52 13.66
+ 329.76 C13.54 330 13.47 330.27 13.47 330.55 L13.47 337.32 L15.03 337.32 L15.03 342.55 L21.12
+ 342.55 L21.12 337.32 L22.74 337.32 L22.74 330.55 C22.74 330.14 22.6 329.76 22.36 329.46 C22.2
+ 329.25 21.99 329.08 21.75 328.96 C21.51 328.84 21.24 328.77 20.96 328.77 Z" class="st23"/>
+ <path d="M20.77 325.42 A2.63551 2.63601 -180 1 0 15.5 325.42 A2.63551 2.63601 -180 1 0 20.77 325.42"
+ class="st24"/>
+ <path d="M20.96 328.77 L15.25 328.77 C14.84 328.77 14.46 328.91 14.16 329.14 C13.95 329.31 13.78 329.52 13.66
+ 329.76 C13.54 330 13.47 330.27 13.47 330.55 L13.47 337.32 L15.03 337.32 L15.03 342.55 L21.12
+ 342.55 L21.12 337.32 L22.74 337.32 L22.74 330.55 C22.74 330.14 22.6 329.76 22.36 329.46 C22.2
+ 329.25 21.99 329.08 21.75 328.96 C21.51 328.84 21.24 328.77 20.96 328.77" class="st24"/>
+ <path d="M18.1 342.55 L18.1 338.37" class="st24"/>
+ <path d="M15.03 337.32 L15.03 333.71" class="st24"/>
+ <path d="M21.12 337.32 L21.12 333.71" class="st24"/>
+ <path d="M0 337.32 L13.47 337.32" class="st24"/>
+ </g>
+ <g id="shape51-259" transform="translate(0,-8.39743)">
+ <title>Sheet.51</title>
+ <g id="shadow51-260" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M21.09 325.52 C21.09 325.13 20.96 324.79 20.74 324.51 C20.59 324.32 20.4 324.16 20.19 324.06
+ C19.97 323.95 19.72 323.89 19.46 323.89 L3.55 323.89 C3.16 323.89 2.82 324.02 2.54 324.23
+ C2.35 324.38 2.19 324.57 2.09 324.79 C1.98 325.01 1.92 325.25 1.92 325.52 L1.92 336.04 L21.09
+ 336.04 L21.09 325.52 ZM21.18 337.33 L1.77 337.33 L0 340.51 L0 342.55 L23.06 342.55 L23.06
+ 340.51 L21.18 337.33 Z" class="st7"/>
+ </g>
+ <path d="M21.09 325.52 C21.09 325.13 20.96 324.79 20.74 324.51 C20.59 324.32 20.4 324.16 20.19 324.06 C19.97
+ 323.95 19.72 323.89 19.46 323.89 L3.55 323.89 C3.16 323.89 2.82 324.02 2.54 324.23 C2.35 324.38
+ 2.19 324.57 2.09 324.79 C1.98 325.01 1.92 325.25 1.92 325.52 L1.92 336.04 L21.09 336.04 L21.09
+ 325.52 ZM21.18 337.33 L1.77 337.33 L0 340.51 L0 342.55 L23.06 342.55 L23.06 340.51 L21.18 337.33
+ Z" class="st25"/>
+ </g>
+ <g id="shape52-264" transform="translate(3.19243,-16.175)">
+ <title>Sheet.52</title>
+ <path d="M16.62 342.55 L16.62 333.29 C16.62 333.23 16.61 333.18 16.58 333.13 C16.55 333.07 16.5 333.02 16.44
+ 332.98 C16.39 332.95 16.33 332.94 16.27 332.94 L0.35 332.94 C0.29 332.94 0.24 332.95 0.19 332.98
+ C0.13 333.01 0.08 333.07 0.04 333.12 C0.02 333.17 0 333.23 0 333.29 L0 342.55 L16.62 342.55
+ Z" class="st26"/>
+ </g>
+ <g id="shape53-266" transform="translate(1.97942,-10.81)">
+ <title>Sheet.53</title>
+ <path d="M0.96 340.83 L0 342.55 L19.06 342.55 L18.1 340.83 L0.96 340.83 Z" class="st23"/>
+ </g>
+ </g>
+ <g id="group54-269" transform="translate(7.21495,-18.6146)">
+ <title>User.12</title>
+ <g id="shape55-270" transform="translate(13.3353,-1.13687E-013)">
+ <title>Sheet.55</title>
+ <g id="shadow55-271" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M20.77 325.42 A2.63551 2.63601 -180 1 0 15.5 325.42 A2.63551 2.63601 -180 1 0 20.77 325.42 ZM20.96
+ 328.77 L15.25 328.77 C14.84 328.77 14.46 328.91 14.16 329.14 C13.95 329.31 13.78 329.52
+ 13.66 329.76 C13.54 330 13.47 330.27 13.47 330.55 L13.47 337.32 L15.03 337.32 L15.03 342.55
+ L21.12 342.55 L21.12 337.32 L22.74 337.32 L22.74 330.55 C22.74 330.14 22.6 329.76 22.36
+ 329.46 C22.2 329.25 21.99 329.08 21.75 328.96 C21.51 328.84 21.24 328.77 20.96 328.77 Z"
+ class="st22"/>
+ <path d="M20.77 325.42 A2.63551 2.63601 -180 1 0 15.5 325.42 A2.63551 2.63601 -180 1 0 20.77 325.42"
+ class="st2"/>
+ <path d="M20.96 328.77 L15.25 328.77 C14.84 328.77 14.46 328.91 14.16 329.14 C13.95 329.31 13.78 329.52
+ 13.66 329.76 C13.54 330 13.47 330.27 13.47 330.55 L13.47 337.32 L15.03 337.32 L15.03 342.55
+ L21.12 342.55 L21.12 337.32 L22.74 337.32 L22.74 330.55 C22.74 330.14 22.6 329.76 22.36
+ 329.46 C22.2 329.25 21.99 329.08 21.75 328.96 C21.51 328.84 21.24 328.77 20.96 328.77"
+ class="st2"/>
+ <path d="M18.1 342.55 L18.1 338.37" class="st2"/>
+ <path d="M15.03 337.32 L15.03 333.71" class="st2"/>
+ <path d="M21.12 337.32 L21.12 333.71" class="st2"/>
+ <path d="M0 337.32 L13.47 337.32" class="st2"/>
+ </g>
+ <path d="M20.77 325.42 A2.63551 2.63601 -180 1 0 15.5 325.42 A2.63551 2.63601 -180 1 0 20.77 325.42 ZM20.96
+ 328.77 L15.25 328.77 C14.84 328.77 14.46 328.91 14.16 329.14 C13.95 329.31 13.78 329.52 13.66
+ 329.76 C13.54 330 13.47 330.27 13.47 330.55 L13.47 337.32 L15.03 337.32 L15.03 342.55 L21.12
+ 342.55 L21.12 337.32 L22.74 337.32 L22.74 330.55 C22.74 330.14 22.6 329.76 22.36 329.46 C22.2
+ 329.25 21.99 329.08 21.75 328.96 C21.51 328.84 21.24 328.77 20.96 328.77 Z" class="st23"/>
+ <path d="M20.77 325.42 A2.63551 2.63601 -180 1 0 15.5 325.42 A2.63551 2.63601 -180 1 0 20.77 325.42"
+ class="st24"/>
+ <path d="M20.96 328.77 L15.25 328.77 C14.84 328.77 14.46 328.91 14.16 329.14 C13.95 329.31 13.78 329.52 13.66
+ 329.76 C13.54 330 13.47 330.27 13.47 330.55 L13.47 337.32 L15.03 337.32 L15.03 342.55 L21.12
+ 342.55 L21.12 337.32 L22.74 337.32 L22.74 330.55 C22.74 330.14 22.6 329.76 22.36 329.46 C22.2
+ 329.25 21.99 329.08 21.75 328.96 C21.51 328.84 21.24 328.77 20.96 328.77" class="st24"/>
+ <path d="M18.1 342.55 L18.1 338.37" class="st24"/>
+ <path d="M15.03 337.32 L15.03 333.71" class="st24"/>
+ <path d="M21.12 337.32 L21.12 333.71" class="st24"/>
+ <path d="M0 337.32 L13.47 337.32" class="st24"/>
+ </g>
+ <g id="shape56-288" transform="translate(0,-8.39743)">
+ <title>Sheet.56</title>
+ <g id="shadow56-289" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M21.09 325.52 C21.09 325.13 20.96 324.79 20.74 324.51 C20.59 324.32 20.4 324.16 20.19 324.06
+ C19.97 323.95 19.72 323.89 19.46 323.89 L3.55 323.89 C3.16 323.89 2.82 324.02 2.54 324.23
+ C2.35 324.38 2.19 324.57 2.09 324.79 C1.98 325.01 1.92 325.25 1.92 325.52 L1.92 336.04 L21.09
+ 336.04 L21.09 325.52 ZM21.18 337.33 L1.77 337.33 L0 340.51 L0 342.55 L23.06 342.55 L23.06
+ 340.51 L21.18 337.33 Z" class="st7"/>
+ </g>
+ <path d="M21.09 325.52 C21.09 325.13 20.96 324.79 20.74 324.51 C20.59 324.32 20.4 324.16 20.19 324.06 C19.97
+ 323.95 19.72 323.89 19.46 323.89 L3.55 323.89 C3.16 323.89 2.82 324.02 2.54 324.23 C2.35 324.38
+ 2.19 324.57 2.09 324.79 C1.98 325.01 1.92 325.25 1.92 325.52 L1.92 336.04 L21.09 336.04 L21.09
+ 325.52 ZM21.18 337.33 L1.77 337.33 L0 340.51 L0 342.55 L23.06 342.55 L23.06 340.51 L21.18 337.33
+ Z" class="st25"/>
+ </g>
+ <g id="shape57-293" transform="translate(3.19243,-16.175)">
+ <title>Sheet.57</title>
+ <path d="M16.62 342.55 L16.62 333.29 C16.62 333.23 16.61 333.18 16.58 333.13 C16.55 333.07 16.5 333.02 16.44
+ 332.98 C16.39 332.95 16.33 332.94 16.27 332.94 L0.35 332.94 C0.29 332.94 0.24 332.95 0.19 332.98
+ C0.13 333.01 0.08 333.07 0.04 333.12 C0.02 333.17 0 333.23 0 333.29 L0 342.55 L16.62 342.55
+ Z" class="st26"/>
+ </g>
+ <g id="shape58-295" transform="translate(1.97942,-10.81)">
+ <title>Sheet.58</title>
+ <path d="M0.96 340.83 L0 342.55 L19.06 342.55 L18.1 340.83 L0.96 340.83 Z" class="st23"/>
+ </g>
+ </g>
+ <g id="group59-298" transform="translate(171.161,-45.6707)">
+ <title>Data Center</title>
+ <g id="shape60-299">
+ <title>Sheet.60</title>
+ <g id="shadow60-300" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <ellipse cx="37.8785" cy="331.299" rx="37.8785" ry="11.246" class="st7"/>
+ </g>
+ <ellipse cx="37.8785" cy="331.299" rx="37.8785" ry="11.246" class="st8"/>
+ </g>
+ <g id="shape61-304" transform="translate(6.86487,-7.30475)">
+ <title>Sheet.61</title>
+ <g id="shadow61-305" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M54.1 311.79 L43.28 311.79 L43.28 342.55 L62.03 342.55 L62.03 311.79 L54.1 311.79 ZM43.28 332.44
+ L43.28 311.79 L51.21 311.79 L51.21 301.69 L32.33 301.69 L32.33 311.79 L40.39 311.79 L40.39
+ 332.44 L43.28 332.44 ZM40.39 301.69 L40.39 293.03 L21.64 293.03 L21.64 301.69 L29.57 301.69
+ L29.57 311.79 L32.46 311.79 L32.46 301.69 L40.39 301.69 ZM32.46 311.79 L21.64 311.79 L21.64
+ 342.55 L40.39 342.55 L40.39 311.79 L32.46 311.79 ZM10.82 311.79 L0 311.79 L0 342.55 L18.75
+ 342.55 L18.75 311.79 L10.82 311.79 ZM21.64 311.79 L29.57 311.79 L29.57 301.69 L10.82 301.69
+ L10.82 311.79 L18.75 311.79 L18.75 332.44 L21.64 332.44 L21.64 311.79 Z" class="st7"/>
+ </g>
+ <path d="M54.1 311.79 L43.28 311.79 L43.28 342.55 L62.03 342.55 L62.03 311.79 L54.1 311.79 ZM43.28 332.44
+ L43.28 311.79 L51.21 311.79 L51.21 301.69 L32.33 301.69 L32.33 311.79 L40.39 311.79 L40.39 332.44
+ L43.28 332.44 ZM40.39 301.69 L40.39 293.03 L21.64 293.03 L21.64 301.69 L29.57 301.69 L29.57
+ 311.79 L32.46 311.79 L32.46 301.69 L40.39 301.69 ZM32.46 311.79 L21.64 311.79 L21.64 342.55
+ L40.39 342.55 L40.39 311.79 L32.46 311.79 ZM10.82 311.79 L0 311.79 L0 342.55 L18.75 342.55 L18.75
+ 311.79 L10.82 311.79 ZM21.64 311.79 L29.57 311.79 L29.57 301.69 L10.82 301.69 L10.82 311.79
+ L18.75 311.79 L18.75 332.44 L21.64 332.44 L21.64 311.79 Z" class="st8"/>
+ </g>
+ <g id="shape62-309" transform="translate(20.0835,-20.5174)">
+ <title>Sheet.62</title>
+ <g id="shadow62-310" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M45.36 341.36 A1.13296 1.18615 -180 1 0 43.09 341.36 A1.13296 1.18615 -180 1 0 45.36 341.36
+ ZM23.46 341.36 A1.13296 1.18615 -180 1 0 21.2 341.36 A1.13296 1.18615 -180 1 0 23.46 341.36
+ ZM2.27 341.36 A1.13296 1.18615 -180 1 0 0 341.36 A1.13296 1.18615 -180 1 0 2.27 341.36 Z"
+ class="st22"/>
+ </g>
+ <path d="M45.36 341.36 A1.13296 1.18615 -180 1 0 43.09 341.36 A1.13296 1.18615 -180 1 0 45.36 341.36 ZM23.46
+ 341.36 A1.13296 1.18615 -180 1 0 21.2 341.36 A1.13296 1.18615 -180 1 0 23.46 341.36 ZM2.27 341.36
+ A1.13296 1.18615 -180 1 0 0 341.36 A1.13296 1.18615 -180 1 0 2.27 341.36 Z" class="st27"/>
+ </g>
+ <g id="shape63-317" transform="translate(14.2717,-12.5134)">
+ <title>Sheet.63</title>
+ <g id="shadow63-318" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M43.09 342.55 L51.17 342.55 L51.17 341.74 L43.09 341.74 L43.09 342.55 ZM43.09 340.12 L51.17
+ 340.12 L51.17 339.32 L43.09 339.32 L43.09 340.12 ZM43.09 337.69 L51.17 337.69 L51.17 336.89
+ L43.09 336.89 L43.09 337.69 ZM21.2 342.55 L29.27 342.55 L29.27 341.74 L21.2 341.74 L21.2
+ 342.55 ZM21.2 340.12 L29.27 340.12 L29.27 339.32 L21.2 339.32 L21.2 340.12 ZM21.2 337.69
+ L29.27 337.69 L29.27 336.89 L21.2 336.89 L21.2 337.69 ZM-0 342.55 L8.08 342.55 L8.08 341.74
+ L-0 341.74 L-0 342.55 ZM-0 340.12 L8.08 340.12 L8.08 339.32 L-0 339.32 L-0 340.12 ZM-0 337.69
+ L8.08 337.69 L8.08 336.89 L-0 336.89 L-0 337.69 Z" class="st22"/>
+ </g>
+ <path d="M43.09 342.55 L51.17 342.55 L51.17 341.74 L43.09 341.74 L43.09 342.55 ZM43.09 340.12 L51.17 340.12
+ L51.17 339.32 L43.09 339.32 L43.09 340.12 ZM43.09 337.69 L51.17 337.69 L51.17 336.89 L43.09
+ 336.89 L43.09 337.69 ZM21.2 342.55 L29.27 342.55 L29.27 341.74 L21.2 341.74 L21.2 342.55 ZM21.2
+ 340.12 L29.27 340.12 L29.27 339.32 L21.2 339.32 L21.2 340.12 ZM21.2 337.69 L29.27 337.69 L29.27
+ 336.89 L21.2 336.89 L21.2 337.69 ZM-0 342.55 L8.08 342.55 L8.08 341.74 L-0 341.74 L-0 342.55
+ ZM-0 340.12 L8.08 340.12 L8.08 339.32 L-0 339.32 L-0 340.12 ZM-0 337.69 L8.08 337.69 L8.08 336.89
+ L-0 336.89 L-0 337.69 Z" class="st23"/>
+ </g>
+ </g>
+ <g id="group64-325" transform="translate(59.5234,-47.1858)">
+ <title>Load balancer</title>
+ <g id="shape65-326" transform="translate(0,-1.653)">
+ <title>Sheet.65</title>
+ <g id="shadow65-327" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M12.18 329.62 L4.06 329.62 L0 332.02 L0 342.55 L16.23 342.55 L16.23 332.02 L12.18 329.62 Z"
+ class="st22"/>
+ <path d="M0 332.02 L16.23 332.02" class="st2"/>
+ <path d="M12.18 329.62 L4.06 329.62 L0 332.02 L0 342.55 L16.23 342.55 L16.23 332.02 L12.18 329.62"
+ class="st2"/>
+ </g>
+ <path d="M12.18 329.62 L4.06 329.62 L0 332.02 L0 342.55 L16.23 342.55 L16.23 332.02 L12.18 329.62 Z"
+ class="st27"/>
+ <path d="M0 332.02 L16.23 332.02" class="st28"/>
+ <path d="M12.18 329.62 L4.06 329.62 L0 332.02 L0 342.55 L16.23 342.55 L16.23 332.02 L12.18 329.62"
+ class="st28"/>
+ </g>
+ <g id="shape66-336" transform="translate(1.81062,-2.91583)">
+ <title>Sheet.66</title>
+ <g id="shadow66-337" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M10.22 341.92 L9.29 342.12 L9.95 342.55 L11.2 342.23 L10.99 340.96 L10.33 340.52 L10.53 341.44
+ L8.34 340.01 L8.03 340.49 L10.22 341.92 ZM11.46 338.22 L8.84 338.22 L8.84 338.78 L11.45
+ 338.78 L10.78 339.45 L11.57 339.45 L12.45 338.5 L11.57 337.55 L10.78 337.55 L11.46 338.22
+ ZM10.48 335.2 L8.29 336.64 L8.6 337.12 L10.79 335.68 L10.59 336.61 L11.25 336.17 L11.46
+ 334.9 L10.21 334.58 L9.55 335.01 L10.48 335.2 ZM6.25 336.37 C5.11 336.37 4.19 337.29 4.19
+ 338.43 C4.19 339.56 5.11 340.48 6.25 340.48 C7.38 340.48 8.31 339.56 8.31 338.43 C8.31 337.29
+ 7.38 336.37 6.25 336.37 ZM6.25 337.02 C7.02 337.02 7.66 337.65 7.66 338.43 C7.66 339.2 7.02
+ 339.83 6.25 339.83 C5.47 339.83 4.84 339.2 4.84 338.43 C4.84 337.65 5.47 337.02 6.25 337.02
+ ZM2.62 338.14 L0 338.14 L0 338.71 L2.62 338.71 L1.94 339.38 L2.74 339.38 L3.61 338.43 L2.73
+ 337.47 L1.95 337.47 L2.62 338.14 Z" class="st7"/>
+ </g>
+ <path d="M10.22 341.92 L9.29 342.12 L9.95 342.55 L11.2 342.23 L10.99 340.96 L10.33 340.52 L10.53 341.44 L8.34
+ 340.01 L8.03 340.49 L10.22 341.92 ZM11.46 338.22 L8.84 338.22 L8.84 338.78 L11.45 338.78 L10.78
+ 339.45 L11.57 339.45 L12.45 338.5 L11.57 337.55 L10.78 337.55 L11.46 338.22 ZM10.48 335.2 L8.29
+ 336.64 L8.6 337.12 L10.79 335.68 L10.59 336.61 L11.25 336.17 L11.46 334.9 L10.21 334.58 L9.55
+ 335.01 L10.48 335.2 ZM6.25 336.37 C5.11 336.37 4.19 337.29 4.19 338.43 C4.19 339.56 5.11 340.48
+ 6.25 340.48 C7.38 340.48 8.31 339.56 8.31 338.43 C8.31 337.29 7.38 336.37 6.25 336.37 ZM6.25
+ 337.02 C7.02 337.02 7.66 337.65 7.66 338.43 C7.66 339.2 7.02 339.83 6.25 339.83 C5.47 339.83
+ 4.84 339.2 4.84 338.43 C4.84 337.65 5.47 337.02 6.25 337.02 ZM2.62 338.14 L0 338.14 L0 338.71
+ L2.62 338.71 L1.94 339.38 L2.74 339.38 L3.61 338.43 L2.73 337.47 L1.95 337.47 L2.62 338.14 Z"
+ class="st29"/>
+ </g>
+ </g>
+ <g id="group67-341" transform="translate(104.617,-86.5795)">
+ <title>Directory server</title>
+ <g id="shape68-342" transform="translate(0,-0.451005)">
+ <title>Sheet.68</title>
+ <g id="shadow68-343" transform="matrix(1,0,0,1,0.3456,1.9728)" class="st1">
+ <path d="M0.47 329.86 L0.47 331.94 L1.46 332.57 L3.33 331.52 L15.43 338.57 L15.43 340.61 L16.42 341.24
+ L18.24 340.22 L22.24 342.55 L22.24 339.27 L36.07 331.28 L36.07 321.27 L19.64 311.85 L3.16
+ 321.13 L3.16 321.5 L0 319.68 L0 329.58 L0.47 329.86 Z" class="st30"/>
+ </g>
+ <path d="M0.47 329.86 L0.47 331.94 L1.46 332.57 L3.33 331.52 L15.43 338.57 L15.43 340.61 L16.42 341.24 L18.24
+ 340.22 L22.24 342.55 L22.24 339.27 L36.07 331.28 L36.07 321.27 L19.64 311.85 L3.16 321.13 L3.16
+ 321.5 L0 319.68 L0 329.58 L0.47 329.86 Z" class="st31"/>
+ </g>
+ <g id="shape69-347" transform="translate(3.1636,-11.8063)">
+ <title>Sheet.69</title>
+ <path d="M16.48 323.24 L32.91 332.66 L16.31 342.55 L0 333.26 L0 332.52 L16.48 323.24 Z" class="st32"/>
+ </g>
+ <g id="shape70-351" transform="translate(19.06,-3.68954)">
+ <title>Sheet.70</title>
+ <path d="M17.01 324.55 L0 334.19 L3.18 342.55 L17.01 334.56 L17.01 324.55 Z" class="st33"/>
+ </g>
+ <g id="shape71-355" transform="translate(0,-0.415652)">
+ <title>Sheet.71</title>
+ <path d="M22.24 342.55 L0 329.58 L0 319.68 L22.24 332.43 L22.24 342.55 Z" class="st34"/>
+ </g>
+ <g id="shape72-363" transform="translate(0.82443,-19.8334)">
+ <title>Sheet.72</title>
+ <path d="M1.13 341.58 a0.653986 0.653986 -180 0 0 -0.73971 -0.492434 a0.656072 0.656072 -180 0 0 -0.253101
+ 0.865731 a0.653066 0.653066 -180 0 0 0.740769 0.491375 a0.655459 0.655459 -180 0 0 0.252042
+ -0.864672 Z" class="st35"/>
+ </g>
+ <g id="shape73-367" transform="translate(3.62283,-15.1638)">
+ <title>Sheet.73</title>
+ <path d="M3.22 339.78 A1.86495 1.86495 -180 0 0 1.11 338.38 A1.8709 1.8709 -180 0 0 0.38 340.85 A1.86532
+ 1.86532 -180 0 0 2.5 342.25 A1.87264 1.87264 -180 0 0 3.22 339.78 Z" class="st35"/>
+ </g>
+ <g id="shape74-370" transform="translate(3.62283,-10.4867)">
+ <title>Sheet.74</title>
+ <path d="M3.22 339.78 A1.86495 1.86495 -180 0 0 1.11 338.38 A1.8709 1.8709 -180 0 0 0.38 340.85 A1.86532
+ 1.86532 -180 0 0 2.5 342.25 A1.87264 1.87264 -180 0 0 3.22 339.78 Z" class="st35"/>
+ </g>
+ <g id="shape75-373" transform="translate(4.52404,-16.3668)">
+ <title>Sheet.75</title>
+ <path d="M1.61 341.16 a0.931952 0.931952 -180 0 0 -1.05741 -0.702645 a0.935408 0.935408 -180 0 0 -0.361118
+ 1.23585 a0.932139 0.932139 -180 0 0 1.05794 0.702645 a0.935822 0.935822 -180 0 0 0.360589 -1.23585
+ Z" class="st36"/>
+ </g>
+ <g id="shape76-377" transform="translate(4.52404,-11.6897)">
+ <title>Sheet.76</title>
+ <path d="M1.61 341.16 a0.931952 0.931952 -180 0 0 -1.05741 -0.702645 a0.935875 0.935875 -180 0 0 -0.361118
+ 1.23585 a0.932139 0.932139 -180 0 0 1.05794 0.702645 a0.935822 0.935822 -180 0 0 0.360589 -1.23585
+ Z" class="st36"/>
+ </g>
+ <g id="shape77-380" transform="translate(7.78787,-8.83469)">
+ <title>Sheet.77</title>
+ <path d="M0 341.57 L0.05 333.6 L1.83 334.57 L1.78 342.55 L0 341.57 Z" class="st37"/>
+ </g>
+ <g id="shape78-384" transform="translate(10.204,-7.4008)">
+ <title>Sheet.78</title>
+ <path d="M0 341.57 L0.05 333.6 L1.83 334.57 L1.78 342.55 L0 341.57 Z" class="st37"/>
+ </g>
+ <g id="shape79-387" transform="translate(12.6196,-5.96639)">
+ <title>Sheet.79</title>
+ <path d="M0 341.57 L0.05 333.6 L1.83 334.57 L1.78 342.55 L0 341.57 Z" class="st37"/>
+ </g>
+ <g id="shape80-390" transform="translate(15.0357,-4.53251)">
+ <title>Sheet.80</title>
+ <path d="M0 341.57 L0.05 333.6 L1.83 334.57 L1.78 342.55 L0 341.57 Z" class="st37"/>
+ </g>
+ <g id="shape81-393" transform="translate(8.24006,-10.0631)">
+ <title>Sheet.81</title>
+ <path d="M0.85 342.24 a0.388199 0.388199 0 0 1 -0.425188 0.308698 a0.638045 0.638045 0 0 1 -0.424658 -0.573447
+ L0 336.5 a0.387575 0.387575 0 0 1 0.424658 -0.308698 a0.637725 0.637725 0 0 1 0.425188 0.573447
+ L0.85 342.24 Z" class="st38"/>
+ </g>
+ <g id="shape82-397" transform="translate(10.6556,-8.62924)">
+ <title>Sheet.82</title>
+ <path d="M0.85 342.24 a0.388199 0.388199 0 0 1 -0.425188 0.308698 a0.638045 0.638045 0 0 1 -0.424658 -0.573447
+ L0 336.5 a0.387575 0.387575 0 0 1 0.424658 -0.308698 a0.637725 0.637725 0 0 1 0.425188 0.573447
+ L0.85 342.24 Z" class="st38"/>
+ </g>
+ <g id="shape83-400" transform="translate(13.0717,-7.19483)">
+ <title>Sheet.83</title>
+ <path d="M0.85 342.24 a0.388199 0.388199 0 0 1 -0.425188 0.308698 a0.638045 0.638045 0 0 1 -0.424658 -0.573447
+ L0 336.5 a0.387575 0.387575 0 0 1 0.424658 -0.308698 a0.637725 0.637725 0 0 1 0.425188 0.573447
+ L0.85 342.24 Z" class="st38"/>
+ </g>
+ <g id="shape84-403" transform="translate(15.4873,-5.76095)">
+ <title>Sheet.84</title>
+ <path d="M0.85 342.24 a0.388502 0.388502 0 0 1 -0.425717 0.308698 a0.638367 0.638367 0 0 1 -0.424129 -0.573447
+ L0 336.5 a0.387272 0.387272 0 0 1 0.424129 -0.308698 a0.638235 0.638235 0 0 1 0.425717 0.573447
+ L0.85 342.24 Z" class="st38"/>
+ </g>
+ <g id="shape85-406" transform="translate(7.78787,-9.81214)">
+ <title>Sheet.85</title>
+ <path d="M0 342.55 L0.05 334.57 L1.83 335.55 L0 342.55 Z" class="st39"/>
+ <path d="M0 342.55 L0.05 334.57 L1.83 335.55" class="st40"/>
+ </g>
+ <g id="shape86-409" transform="translate(10.204,-8.37826)">
+ <title>Sheet.86</title>
+ <path d="M0 342.55 L0.05 334.57 L1.83 335.55 L0 342.55 Z" class="st39"/>
+ <path d="M0 342.55 L0.05 334.57 L1.83 335.55" class="st40"/>
+ </g>
+ <g id="shape87-412" transform="translate(12.6196,-6.94385)">
+ <title>Sheet.87</title>
+ <path d="M0 342.55 L0.05 334.57 L1.83 335.55 L0 342.55 Z" class="st39"/>
+ <path d="M0 342.55 L0.05 334.57 L1.83 335.55" class="st40"/>
+ </g>
+ <g id="shape88-415" transform="translate(15.0357,-5.50996)">
+ <title>Sheet.88</title>
+ <path d="M0 342.55 L0.05 334.57 L1.83 335.55 L0 342.55 Z" class="st39"/>
+ <path d="M0 342.55 L0.05 334.57 L1.83 335.55" class="st40"/>
+ </g>
+ <g id="shape89-418" transform="translate(7.78787,-4.53251)">
+ <title>Sheet.89</title>
+ <path d="M9.08 334.57 L9.03 342.55 L7.25 341.57 L9.08 334.57 ZM6.66 333.14 L6.61 341.11 L4.83 340.13 L6.66
+ 333.14 ZM4.25 331.7 L4.2 339.68 L2.42 338.7 L4.25 331.7 ZM1.83 330.27 L1.78 338.24 L0 337.27
+ L1.83 330.27 Z" class="st39"/>
+ <path d="M9.08 334.57 L9.03 342.55 L7.25 341.57M6.66 333.14 L6.61 341.11 L4.83 340.13M4.25 331.7 L4.2 339.68
+ L2.42 338.7M1.83 330.27 L1.78 338.24 L0 337.27" class="st41"/>
+ </g>
+ <g id="shape90-421" transform="translate(2.22125,-11.8454)">
+ <title>Sheet.90</title>
+ <path d="M0 341.85 L0.63 341.42 L1.42 341.78 L0.03 342.55 L0 341.85 Z" class="st42"/>
+ </g>
+ <g id="shape91-425" transform="translate(17.1796,-3.17487)">
+ <title>Sheet.91</title>
+ <path d="M0 341.85 L0.63 341.42 L1.42 341.78 L0.03 342.55 L0 341.85 Z" class="st42"/>
+ </g>
+ <g id="shape92-428" transform="translate(1.46036,-10.3893)">
+ <title>Sheet.92</title>
+ <path d="M2.12 341.35 L0 342.55 L0 333.54 L2.12 332.29 L2.12 333.41 L0.79 334.15 L0.79 341.09 L2.18 340.33
+ L2.12 341.35 Z" class="st33"/>
+ </g>
+ <g id="shape93-431" transform="translate(16.4187,-1.71875)">
+ <title>Sheet.93</title>
+ <path d="M2.12 341.35 L0 342.55 L0 333.54 L2.12 332.29 L2.12 333.41 L0.79 334.15 L0.79 341.09 L2.18 340.33
+ L2.12 341.35 Z" class="st33"/>
+ </g>
+ <g id="shape94-434" transform="translate(0.467548,-10.3893)">
+ <title>Sheet.94</title>
+ <path d="M0.99 333.54 L3.11 332.29 L2.12 331.66 L0 332.91 L0 341.92 L0.99 342.55 L0.99 333.54 Z"
+ class="st43"/>
+ </g>
+ <g id="shape95-438" transform="translate(15.4259,-1.71875)">
+ <title>Sheet.95</title>
+ <path d="M0.99 333.54 L3.11 332.29 L2.12 331.66 L0 332.91 L0 341.92 L0.99 342.55 L0.99 333.54 Z"
+ class="st43"/>
+ </g>
+ <g id="shape96-441" transform="translate(0.467548,-1.71928)">
+ <title>Sheet.96</title>
+ <path d="M17.34 339.96 L16.75 340.37 L16.75 334.15 L18.07 333.41 L18.07 332.29 L17.08 331.66 L14.96 332.91
+ L14.96 341.92 L15.95 342.55 L18.07 341.35 L18.14 340.33 L17.34 339.96 ZM2.38 331.29 L1.79 331.7
+ L1.79 325.48 L3.11 324.74 L3.11 323.62 L2.12 322.99 L0 324.24 L0 333.25 L0.99 333.87 L3.11 332.68
+ L3.18 331.66 L2.38 331.29 Z" class="st44"/>
+ </g>
+ <g id="shape97-443" transform="translate(19.9526,-8.71396)">
+ <title>Sheet.97</title>
+ <path d="M1.13 341.58 a0.653986 0.653986 -180 0 0 -0.73971 -0.492434 a0.656072 0.656072 -180 0 0 -0.253101
+ 0.865731 a0.653066 0.653066 -180 0 0 0.740769 0.491375 a0.655459 0.655459 -180 0 0 0.252042
+ -0.864672 Z" class="st35"/>
+ </g>
+ <g id="shape98-446" transform="translate(19.9526,-2.35997)">
+ <title>Sheet.98</title>
+ <path d="M1.13 341.58 a0.653986 0.653986 -180 0 0 -0.73971 -0.492434 a0.656072 0.656072 -180 0 0 -0.253101
+ 0.865731 a0.653066 0.653066 -180 0 0 0.740769 0.491375 a0.655459 0.655459 -180 0 0 0.252042
+ -0.864672 Z" class="st35"/>
+ </g>
+ <g id="shape99-449" transform="translate(0,-0.415652)">
+ <title>Sheet.99</title>
+ <path d="M36.07 331.28 L36.07 321.27 L19.64 311.85 L3.16 321.13 L3.16 321.52 L0 319.68 L0 329.58 L0.47 329.86
+ L0.47 331.94 L1.46 332.57 L3.33 331.52 L15.43 338.57 L15.43 340.61 L16.42 341.24 L18.24 340.22
+ L22.24 342.55 L22.24 339.27 L36.07 331.28 Z" class="st44"/>
+ </g>
+ <g id="shape100-451" transform="translate(27.8077,-2.86477)">
+ <title>Sheet.100</title>
+ <path d="M0.29 342.55 L6.62 338.89 A1.82805 1.82805 0 0 1 6.62 336.9 L0.29 340.55 A1.82805 1.82805 -180 0
+ 0 0.29 342.55 Z" class="st45"/>
+ </g>
+ <g id="shape101-453" transform="translate(23.5035,-4.85627)">
+ <title>Sheet.101</title>
+ <path d="M4.6 342.55 L10.92 338.89 L6.32 336.24 L0 339.89 L4.6 342.55 Z" class="st46"/>
+ </g>
+ <g id="shape102-457" transform="translate(23.3588,-2.86477)">
+ <title>Sheet.102</title>
+ <path d="M0.14 339.89 L4.74 342.55 A1.82805 1.82805 0 0 1 4.74 340.55 L0.14 337.9 A3.49826 3.49826 -180 0
+ 0 0.14 339.89 Z" class="st47"/>
+ </g>
+ <g id="shape103-461" transform="translate(25.8933,-5.98478)">
+ <title>Sheet.103</title>
+ <path d="M2.87 342.55 L0 340.89" class="st48"/>
+ <path d="M0.94 340.34 L3.82 342" class="st48"/>
+ <path d="M1.88 339.8 L4.76 341.46" class="st48"/>
+ <path d="M2.82 339.26 L5.7 340.92" class="st48"/>
+ <path d="M3.76 338.71 L6.64 340.37" class="st48"/>
+ </g>
+ <g id="shape104-468" transform="translate(23.5035,-7.51159)">
+ <title>Sheet.104</title>
+ <path d="M5.13 341.17 L11.45 337.52 A11.9345 11.9345 0 0 1 6.32 338.89 L0 342.55 A11.9345 11.9345 -180 0
+ 0 5.13 341.17 Z" class="st49"/>
+ </g>
+ <g id="shape105-476" transform="translate(30.2106,-4.74563)">
+ <title>Sheet.105</title>
+ <path d="M0.98 341.98 L0 342.55" class="st48"/>
+ <path d="M1.26 341.48 L2.24 340.92" class="st48"/>
+ <path d="M2.53 340.42 L3.51 339.86" class="st48"/>
+ </g>
+ <g id="shape106-481" transform="translate(23.3588,-2.86477)">
+ <title>Sheet.106</title>
+ <path d="M0.14 339.89 L4.74 342.55 L11.07 338.89 A1.82805 1.82805 0 0 1 11.07 336.9 L7.85 335.04 L11.6 332.87
+ A11.9345 11.9345 0 0 1 6.47 334.25 L0.14 337.9 A3.49826 3.49826 -180 0 0 0.14 339.89"
+ class="st50"/>
+ </g>
+ </g>
+ <g id="group107-484" transform="translate(104.617,-33.8201)">
+ <title>Directory server.104</title>
+ <g id="shape108-485" transform="translate(0,-0.451005)">
+ <title>Sheet.108</title>
+ <g id="shadow108-486" transform="matrix(1,0,0,1,0.3456,1.9728)" class="st1">
+ <path d="M0.47 329.86 L0.47 331.94 L1.46 332.57 L3.33 331.52 L15.43 338.57 L15.43 340.61 L16.42 341.24
+ L18.24 340.22 L22.24 342.55 L22.24 339.27 L36.07 331.28 L36.07 321.27 L19.64 311.85 L3.16
+ 321.13 L3.16 321.5 L0 319.68 L0 329.58 L0.47 329.86 Z" class="st30"/>
+ </g>
+ <path d="M0.47 329.86 L0.47 331.94 L1.46 332.57 L3.33 331.52 L15.43 338.57 L15.43 340.61 L16.42 341.24 L18.24
+ 340.22 L22.24 342.55 L22.24 339.27 L36.07 331.28 L36.07 321.27 L19.64 311.85 L3.16 321.13 L3.16
+ 321.5 L0 319.68 L0 329.58 L0.47 329.86 Z" class="st31"/>
+ </g>
+ <g id="shape109-490" transform="translate(3.1636,-11.8063)">
+ <title>Sheet.109</title>
+ <path d="M16.48 323.24 L32.91 332.66 L16.31 342.55 L0 333.26 L0 332.52 L16.48 323.24 Z" class="st32"/>
+ </g>
+ <g id="shape110-493" transform="translate(19.06,-3.68954)">
+ <title>Sheet.110</title>
+ <path d="M17.01 324.55 L0 334.19 L3.18 342.55 L17.01 334.56 L17.01 324.55 Z" class="st33"/>
+ </g>
+ <g id="shape111-496" transform="translate(0,-0.415652)">
+ <title>Sheet.111</title>
+ <path d="M22.24 342.55 L0 329.58 L0 319.68 L22.24 332.43 L22.24 342.55 Z" class="st34"/>
+ </g>
+ <g id="shape112-499" transform="translate(0.82443,-19.8334)">
+ <title>Sheet.112</title>
+ <path d="M1.13 341.58 a0.653986 0.653986 -180 0 0 -0.73971 -0.492434 a0.656072 0.656072 -180 0 0 -0.253101
+ 0.865731 a0.653066 0.653066 -180 0 0 0.740769 0.491375 a0.655459 0.655459 -180 0 0 0.252042
+ -0.864672 Z" class="st35"/>
+ </g>
+ <g id="shape113-502" transform="translate(3.62283,-15.1638)">
+ <title>Sheet.113</title>
+ <path d="M3.22 339.78 A1.86495 1.86495 -180 0 0 1.11 338.38 A1.8709 1.8709 -180 0 0 0.38 340.85 A1.86532
+ 1.86532 -180 0 0 2.5 342.25 A1.87264 1.87264 -180 0 0 3.22 339.78 Z" class="st35"/>
+ </g>
+ <g id="shape114-505" transform="translate(3.62283,-10.4867)">
+ <title>Sheet.114</title>
+ <path d="M3.22 339.78 A1.86495 1.86495 -180 0 0 1.11 338.38 A1.8709 1.8709 -180 0 0 0.38 340.85 A1.86532
+ 1.86532 -180 0 0 2.5 342.25 A1.87264 1.87264 -180 0 0 3.22 339.78 Z" class="st35"/>
+ </g>
+ <g id="shape115-508" transform="translate(4.52404,-16.3668)">
+ <title>Sheet.115</title>
+ <path d="M1.61 341.16 a0.931952 0.931952 -180 0 0 -1.05741 -0.702645 a0.935408 0.935408 -180 0 0 -0.361118
+ 1.23585 a0.932139 0.932139 -180 0 0 1.05794 0.702645 a0.935822 0.935822 -180 0 0 0.360589 -1.23585
+ Z" class="st36"/>
+ </g>
+ <g id="shape116-511" transform="translate(4.52404,-11.6897)">
+ <title>Sheet.116</title>
+ <path d="M1.61 341.16 a0.931952 0.931952 -180 0 0 -1.05741 -0.702645 a0.935875 0.935875 -180 0 0 -0.361118
+ 1.23585 a0.932139 0.932139 -180 0 0 1.05794 0.702645 a0.935822 0.935822 -180 0 0 0.360589 -1.23585
+ Z" class="st36"/>
+ </g>
+ <g id="shape117-514" transform="translate(7.78787,-8.83469)">
+ <title>Sheet.117</title>
+ <path d="M0 341.57 L0.05 333.6 L1.83 334.57 L1.78 342.55 L0 341.57 Z" class="st37"/>
+ </g>
+ <g id="shape118-517" transform="translate(10.204,-7.4008)">
+ <title>Sheet.118</title>
+ <path d="M0 341.57 L0.05 333.6 L1.83 334.57 L1.78 342.55 L0 341.57 Z" class="st37"/>
+ </g>
+ <g id="shape119-520" transform="translate(12.6196,-5.96639)">
+ <title>Sheet.119</title>
+ <path d="M0 341.57 L0.05 333.6 L1.83 334.57 L1.78 342.55 L0 341.57 Z" class="st37"/>
+ </g>
+ <g id="shape120-523" transform="translate(15.0357,-4.53251)">
+ <title>Sheet.120</title>
+ <path d="M0 341.57 L0.05 333.6 L1.83 334.57 L1.78 342.55 L0 341.57 Z" class="st37"/>
+ </g>
+ <g id="shape121-526" transform="translate(8.24006,-10.0631)">
+ <title>Sheet.121</title>
+ <path d="M0.85 342.24 a0.388199 0.388199 0 0 1 -0.425188 0.308698 a0.638045 0.638045 0 0 1 -0.424658 -0.573447
+ L0 336.5 a0.387575 0.387575 0 0 1 0.424658 -0.308698 a0.637725 0.637725 0 0 1 0.425188 0.573447
+ L0.85 342.24 Z" class="st38"/>
+ </g>
+ <g id="shape122-529" transform="translate(10.6556,-8.62924)">
+ <title>Sheet.122</title>
+ <path d="M0.85 342.24 a0.388199 0.388199 0 0 1 -0.425188 0.308698 a0.638045 0.638045 0 0 1 -0.424658 -0.573447
+ L0 336.5 a0.387575 0.387575 0 0 1 0.424658 -0.308698 a0.637725 0.637725 0 0 1 0.425188 0.573447
+ L0.85 342.24 Z" class="st38"/>
+ </g>
+ <g id="shape123-532" transform="translate(13.0717,-7.19483)">
+ <title>Sheet.123</title>
+ <path d="M0.85 342.24 a0.388199 0.388199 0 0 1 -0.425188 0.308698 a0.638045 0.638045 0 0 1 -0.424658 -0.573447
+ L0 336.5 a0.387575 0.387575 0 0 1 0.424658 -0.308698 a0.637725 0.637725 0 0 1 0.425188 0.573447
+ L0.85 342.24 Z" class="st38"/>
+ </g>
+ <g id="shape124-535" transform="translate(15.4873,-5.76095)">
+ <title>Sheet.124</title>
+ <path d="M0.85 342.24 a0.388502 0.388502 0 0 1 -0.425717 0.308698 a0.638367 0.638367 0 0 1 -0.424129 -0.573447
+ L0 336.5 a0.387272 0.387272 0 0 1 0.424129 -0.308698 a0.638235 0.638235 0 0 1 0.425717 0.573447
+ L0.85 342.24 Z" class="st38"/>
+ </g>
+ <g id="shape125-538" transform="translate(7.78787,-9.81214)">
+ <title>Sheet.125</title>
+ <path d="M0 342.55 L0.05 334.57 L1.83 335.55 L0 342.55 Z" class="st39"/>
+ <path d="M0 342.55 L0.05 334.57 L1.83 335.55" class="st40"/>
+ </g>
+ <g id="shape126-541" transform="translate(10.204,-8.37826)">
+ <title>Sheet.126</title>
+ <path d="M0 342.55 L0.05 334.57 L1.83 335.55 L0 342.55 Z" class="st39"/>
+ <path d="M0 342.55 L0.05 334.57 L1.83 335.55" class="st40"/>
+ </g>
+ <g id="shape127-544" transform="translate(12.6196,-6.94385)">
+ <title>Sheet.127</title>
+ <path d="M0 342.55 L0.05 334.57 L1.83 335.55 L0 342.55 Z" class="st39"/>
+ <path d="M0 342.55 L0.05 334.57 L1.83 335.55" class="st40"/>
+ </g>
+ <g id="shape128-547" transform="translate(15.0357,-5.50996)">
+ <title>Sheet.128</title>
+ <path d="M0 342.55 L0.05 334.57 L1.83 335.55 L0 342.55 Z" class="st39"/>
+ <path d="M0 342.55 L0.05 334.57 L1.83 335.55" class="st40"/>
+ </g>
+ <g id="shape129-550" transform="translate(7.78787,-4.53251)">
+ <title>Sheet.129</title>
+ <path d="M9.08 334.57 L9.03 342.55 L7.25 341.57 L9.08 334.57 ZM6.66 333.14 L6.61 341.11 L4.83 340.13 L6.66
+ 333.14 ZM4.25 331.7 L4.2 339.68 L2.42 338.7 L4.25 331.7 ZM1.83 330.27 L1.78 338.24 L0 337.27
+ L1.83 330.27 Z" class="st39"/>
+ <path d="M9.08 334.57 L9.03 342.55 L7.25 341.57M6.66 333.14 L6.61 341.11 L4.83 340.13M4.25 331.7 L4.2 339.68
+ L2.42 338.7M1.83 330.27 L1.78 338.24 L0 337.27" class="st41"/>
+ </g>
+ <g id="shape130-553" transform="translate(2.22125,-11.8454)">
+ <title>Sheet.130</title>
+ <path d="M0 341.85 L0.63 341.42 L1.42 341.78 L0.03 342.55 L0 341.85 Z" class="st42"/>
+ </g>
+ <g id="shape131-556" transform="translate(17.1796,-3.17487)">
+ <title>Sheet.131</title>
+ <path d="M0 341.85 L0.63 341.42 L1.42 341.78 L0.03 342.55 L0 341.85 Z" class="st42"/>
+ </g>
+ <g id="shape132-559" transform="translate(1.46036,-10.3893)">
+ <title>Sheet.132</title>
+ <path d="M2.12 341.35 L0 342.55 L0 333.54 L2.12 332.29 L2.12 333.41 L0.79 334.15 L0.79 341.09 L2.18 340.33
+ L2.12 341.35 Z" class="st33"/>
+ </g>
+ <g id="shape133-562" transform="translate(16.4187,-1.71875)">
+ <title>Sheet.133</title>
+ <path d="M2.12 341.35 L0 342.55 L0 333.54 L2.12 332.29 L2.12 333.41 L0.79 334.15 L0.79 341.09 L2.18 340.33
+ L2.12 341.35 Z" class="st33"/>
+ </g>
+ <g id="shape134-565" transform="translate(0.467548,-10.3893)">
+ <title>Sheet.134</title>
+ <path d="M0.99 333.54 L3.11 332.29 L2.12 331.66 L0 332.91 L0 341.92 L0.99 342.55 L0.99 333.54 Z"
+ class="st43"/>
+ </g>
+ <g id="shape135-568" transform="translate(15.4259,-1.71875)">
+ <title>Sheet.135</title>
+ <path d="M0.99 333.54 L3.11 332.29 L2.12 331.66 L0 332.91 L0 341.92 L0.99 342.55 L0.99 333.54 Z"
+ class="st43"/>
+ </g>
+ <g id="shape136-571" transform="translate(0.467548,-1.71928)">
+ <title>Sheet.136</title>
+ <path d="M17.34 339.96 L16.75 340.37 L16.75 334.15 L18.07 333.41 L18.07 332.29 L17.08 331.66 L14.96 332.91
+ L14.96 341.92 L15.95 342.55 L18.07 341.35 L18.14 340.33 L17.34 339.96 ZM2.38 331.29 L1.79 331.7
+ L1.79 325.48 L3.11 324.74 L3.11 323.62 L2.12 322.99 L0 324.24 L0 333.25 L0.99 333.87 L3.11 332.68
+ L3.18 331.66 L2.38 331.29 Z" class="st44"/>
+ </g>
+ <g id="shape137-573" transform="translate(19.9526,-8.71396)">
+ <title>Sheet.137</title>
+ <path d="M1.13 341.58 a0.653986 0.653986 -180 0 0 -0.73971 -0.492434 a0.656072 0.656072 -180 0 0 -0.253101
+ 0.865731 a0.653066 0.653066 -180 0 0 0.740769 0.491375 a0.655459 0.655459 -180 0 0 0.252042
+ -0.864672 Z" class="st35"/>
+ </g>
+ <g id="shape138-576" transform="translate(19.9526,-2.35997)">
+ <title>Sheet.138</title>
+ <path d="M1.13 341.58 a0.653986 0.653986 -180 0 0 -0.73971 -0.492434 a0.656072 0.656072 -180 0 0 -0.253101
+ 0.865731 a0.653066 0.653066 -180 0 0 0.740769 0.491375 a0.655459 0.655459 -180 0 0 0.252042
+ -0.864672 Z" class="st35"/>
+ </g>
+ <g id="shape139-579" transform="translate(0,-0.415652)">
+ <title>Sheet.139</title>
+ <path d="M36.07 331.28 L36.07 321.27 L19.64 311.85 L3.16 321.13 L3.16 321.52 L0 319.68 L0 329.58 L0.47 329.86
+ L0.47 331.94 L1.46 332.57 L3.33 331.52 L15.43 338.57 L15.43 340.61 L16.42 341.24 L18.24 340.22
+ L22.24 342.55 L22.24 339.27 L36.07 331.28 Z" class="st44"/>
+ </g>
+ <g id="shape140-581" transform="translate(27.8077,-2.86477)">
+ <title>Sheet.140</title>
+ <path d="M0.29 342.55 L6.62 338.89 A1.82805 1.82805 0 0 1 6.62 336.9 L0.29 340.55 A1.82805 1.82805 -180 0
+ 0 0.29 342.55 Z" class="st45"/>
+ </g>
+ <g id="shape141-583" transform="translate(23.5035,-4.85627)">
+ <title>Sheet.141</title>
+ <path d="M4.6 342.55 L10.92 338.89 L6.32 336.24 L0 339.89 L4.6 342.55 Z" class="st46"/>
+ </g>
+ <g id="shape142-586" transform="translate(23.3588,-2.86477)">
+ <title>Sheet.142</title>
+ <path d="M0.14 339.89 L4.74 342.55 A1.82805 1.82805 0 0 1 4.74 340.55 L0.14 337.9 A3.49826 3.49826 -180 0
+ 0 0.14 339.89 Z" class="st47"/>
+ </g>
+ <g id="shape143-589" transform="translate(25.8933,-5.98478)">
+ <title>Sheet.143</title>
+ <path d="M2.87 342.55 L0 340.89" class="st48"/>
+ <path d="M0.94 340.34 L3.82 342" class="st48"/>
+ <path d="M1.88 339.8 L4.76 341.46" class="st48"/>
+ <path d="M2.82 339.26 L5.7 340.92" class="st48"/>
+ <path d="M3.76 338.71 L6.64 340.37" class="st48"/>
+ </g>
+ <g id="shape144-596" transform="translate(23.5035,-7.51159)">
+ <title>Sheet.144</title>
+ <path d="M5.13 341.17 L11.45 337.52 A11.9345 11.9345 0 0 1 6.32 338.89 L0 342.55 A11.9345 11.9345 -180 0
+ 0 5.13 341.17 Z" class="st49"/>
+ </g>
+ <g id="shape145-599" transform="translate(30.2106,-4.74563)">
+ <title>Sheet.145</title>
+ <path d="M0.98 341.98 L0 342.55" class="st48"/>
+ <path d="M1.26 341.48 L2.24 340.92" class="st48"/>
+ <path d="M2.53 340.42 L3.51 339.86" class="st48"/>
+ </g>
+ <g id="shape146-604" transform="translate(23.3588,-2.86477)">
+ <title>Sheet.146</title>
+ <path d="M0.14 339.89 L4.74 342.55 L11.07 338.89 A1.82805 1.82805 0 0 1 11.07 336.9 L7.85 335.04 L11.6 332.87
+ A11.9345 11.9345 0 0 1 6.47 334.25 L0.14 337.9 A3.49826 3.49826 -180 0 0 0.14 339.89"
+ class="st50"/>
+ </g>
+ </g>
+ <g id="shape147-607" transform="translate(427.321,214.49) rotate(90)">
+ <title>Cloud</title>
+ <path d="M5.37 311.54 A8.61618 10.0654 0 0 1 9.5 292.2 A17.4727 20.4114 0 0 1 34.86 275.89 A20.0634 23.4379 0
+ 0 1 56.58 272.26 A12.5816 14.6977 0 0 1 75.21 271.05 A14.3244 16.7336 0 0 1 97.98 277.09 A10.2423
+ 11.9646 0 0 1 106.25 294.02 A12.6864 14.8197 0 0 1 95.9 318.19 A16.0049 18.6962 0 0 1 73.14 330.27
+ A18.8712 22.0444 0 0 1 42.1 335.11 A23.9217 27.9441 0 0 1 15.2 330.27 A9.43759 11.0249 0 0 1 5.37
+ 311.54 Z" class="st39"/>
+ <path d="M5.37 311.54 A8.61618 10.0654 0 0 1 9.5 292.2 A17.4727 20.4114 0 0 1 34.86 275.89 A20.0634 23.4379 0
+ 0 1 56.58 272.26 A12.5816 14.6977 0 0 1 75.21 271.05 A14.3244 16.7336 0 0 1 97.98 277.09 A10.2423
+ 11.9646 0 0 1 106.25 294.02 A12.6864 14.8197 0 0 1 95.9 318.19 A16.0049 18.6962 0 0 1 73.14 330.27
+ A18.8712 22.0444 0 0 1 42.1 335.11 A23.9217 27.9441 0 0 1 15.2 330.27 A9.43759 11.0249 0 0 1 5.37
+ 311.54" class="st51"/>
+ <path d="M11.05 312.14 A8.59237 10.0375 0 0 1 5.37 311.54" class="st51"/>
+ <path d="M40.54 332.09 A8.62978 10.0812 -180 0 0 42.1 335.11" class="st51"/>
+ <path d="M73.92 326.65 A6.96633 8.13801 0 0 1 73.14 330.27" class="st51"/>
+ <path d="M89.7 308.52 A7.30994 8.5394 0 0 1 95.9 318.19" class="st51"/>
+ <path d="M103.15 297.64 A6.67364 7.79609 -180 0 0 106.25 294.02" class="st51"/>
+ <path d="M37.96 278.3 A10.2914 12.0219 -180 0 0 34.86 275.89" class="st51"/>
+ </g>
+ <g id="shape148-616" transform="translate(110.222,-64.9346)">
+ <title>Triangle</title>
+ <desc>Set Summary</desc>
+ <g id="shadow148-617" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M31.4 342.55 L14.67 324.26 L0 342.55 L31.4 342.55 Z" class="st7"/>
+ </g>
+ <path d="M31.4 342.55 L14.67 324.26 L0 342.55 L31.4 342.55 Z" class="st8"/>
+ <text x="11.82" y="334.65" class="st16">Set <tspan x="4.11" dy="1.2em" class="st4">Summary</tspan></text> </g>
+ <g id="shape149-623" transform="translate(292.639,20.8827) rotate(45)">
+ <title>Sheet.149</title>
+ <path d="M0 342.55 L14.71 342.55" class="st12"/>
+ </g>
+ <g id="shape150-628" transform="translate(43.2897,-54.1122)">
+ <title>Sheet.150</title>
+ <path d="M0 342.55 L10.07 342.55" class="st12"/>
+ </g>
+ <g id="shape151-633" transform="translate(-112.261,8.34531) rotate(-28.1394)">
+ <title>Sheet.151</title>
+ <path d="M0 342.55 L18 342.55" class="st12"/>
+ </g>
+ <g id="shape152-638">
+ <title>Sheet.152</title>
+ <desc>Clients</desc>
+ <rect x="0" y="331.723" width="64.9346" height="10.8224" class="st9"/>
+ <text x="21.5" y="339.53" class="st14">Clients</text> </g>
+ <g id="shape153-641" transform="translate(83.578,-9.58078)">
+ <title>Sheet.153</title>
+ <desc>Distributed Cache</desc>
+ <rect x="0" y="331.723" width="84.1355" height="10.8224" class="st9"/>
+ <text x="13.1" y="339.53" class="st14">Distributed Cache</text> </g>
+ <g id="shape154-644" transform="translate(181.983,-18.6146)">
+ <title>Sheet.154</title>
+ <desc>Web Servers</desc>
+ <rect x="0" y="331.723" width="64.9346" height="10.8224" class="st9"/>
+ <text x="11.93" y="339.53" class="st14">Web Servers</text> </g>
+ <g id="shape155-647" transform="translate(96.6068,630.978) rotate(180)">
+ <title>Simple Arrow</title>
+ <g id="shadow155-648" transform="matrix(1,0,0,1,-0.345598,-1.97279)" class="st1">
+ <path d="M0 342.55 L12 330.55 L12 336.55 L16.23 336.55 L16.23 342.55 L16.23 348.54 L12 348.54 L12 354.54
+ L0 342.55 Z" class="st52"/>
+ </g>
+ <path d="M0 342.55 L12 330.55 L12 336.55 L16.23 336.55 L16.23 342.55 L16.23 348.54 L12 348.54 L12 354.54 L0 342.55
+ Z" class="st53"/>
+ </g>
+ <g id="shape156-652" transform="translate(173.159,625.567) rotate(180)">
+ <title>Simple Arrow.153</title>
+ <g id="shadow156-653" transform="matrix(1,0,0,1,-0.345598,-1.97279)" class="st1">
+ <path d="M0 342.55 L12 330.55 L12 336.55 L16.23 336.55 L16.23 342.55 L16.23 348.54 L12 348.54 L12 354.54
+ L0 342.55 Z" class="st52"/>
+ </g>
+ <path d="M0 342.55 L12 330.55 L12 336.55 L16.23 336.55 L16.23 342.55 L16.23 348.54 L12 348.54 L12 354.54 L0 342.55
+ Z" class="st53"/>
+ </g>
+ </g>
+ <g id="shape157-657" transform="translate(0,-149.475)">
+ <title>Rectangle</title>
+ <g id="shadow157-658" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="193.823" width="271.116" height="148.722" class="st2"/>
+ </g>
+ <rect x="0" y="193.823" width="271.116" height="148.722" class="st54"/>
+ </g>
+ <g id="shape158-662" transform="translate(271.116,-149.475)">
+ <title>Rectangle.158</title>
+ <g id="shadow158-663" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="193.823" width="202.104" height="148.722" class="st2"/>
+ </g>
+ <rect x="0" y="193.823" width="202.104" height="148.722" class="st54"/>
+ </g>
+ <g id="shape159-667">
+ <title>Rectangle.159</title>
+ <g id="shadow159-668" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="193.823" width="271.116" height="148.722" class="st2"/>
+ </g>
+ <rect x="0" y="193.823" width="271.116" height="148.722" class="st54"/>
+ </g>
+ <g id="shape160-672" transform="translate(271.116,0)">
+ <title>Rectangle.160</title>
+ <g id="shadow160-673" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="193.823" width="202.104" height="148.722" class="st2"/>
+ </g>
+ <rect x="0" y="193.823" width="202.104" height="148.722" class="st54"/>
+ </g>
+ <g id="shape161-677" transform="translate(83.578,-151.241)">
+ <title>Sheet.161</title>
+ <desc>(a) Distributed Web Cache</desc>
+ <g id="shadow161-678" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="325.066" width="108.709" height="17.4792" class="st7"/>
+ </g>
+ <rect x="0" y="325.066" width="108.709" height="17.4792" class="st8"/>
+ <text x="4" y="336.81" class="st55">(a) Distributed Web Cache</text> </g>
+ <g id="shape162-683" transform="translate(319.513,-151.241)">
+ <title>Sheet.162</title>
+ <desc>(b) Detecting Routing Loops</desc>
+ <g id="shadow162-684" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="325.066" width="108.709" height="17.4792" class="st7"/>
+ </g>
+ <rect x="0" y="325.066" width="108.709" height="17.4792" class="st8"/>
+ <text x="4" y="336.81" class="st55">(b) Detecting Routing Loops</text> </g>
+ <g id="shape163-689" transform="translate(77.5283,-3.35965)">
+ <title>Sheet.163</title>
+ <desc>(c) In-order Workload Scheduler</desc>
+ <g id="shadow163-690" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="325.066" width="127.042" height="17.4792" class="st7"/>
+ </g>
+ <rect x="0" y="325.066" width="127.042" height="17.4792" class="st8"/>
+ <text x="4" y="336.81" class="st55">(c) In-order Workload Scheduler</text> </g>
+ <g id="shape164-695" transform="translate(307.414,-3.35965)">
+ <title>Sheet.164</title>
+ <desc>(d) Database Semi-join Operations</desc>
+ <g id="shadow164-696" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="325.066" width="132.451" height="17.4792" class="st7"/>
+ </g>
+ <rect x="0" y="325.066" width="132.451" height="17.4792" class="st8"/>
+ <text x="4" y="336.81" class="st55">(d) Database Semi-join Operations</text> </g>
+ </g>
+ </g>
+</svg>
diff --git a/doc/guides/prog_guide/img/memship_i2.svg b/doc/guides/prog_guide/img/memship_i2.svg
new file mode 100644
index 0000000..ef71303
--- /dev/null
+++ b/doc/guides/prog_guide/img/memship_i2.svg
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by Microsoft Visio, SVG Export memship_i2.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
+ xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="4.38194in" height="1.25694in"
+ viewBox="0 0 315.5 90.5" xml:space="preserve" color-interpolation-filters="sRGB" class="st6">
+ <v:documentProperties v:langID="1033" v:viewMarkup="false"/>
+
+ <style type="text/css">
+ <![CDATA[
+ .st1 {fill:none;stroke:none;stroke-width:0.25}
+ .st2 {fill:#5b9bd5;font-family:Calibri;font-size:1.16666em}
+ .st3 {baseline-shift:32.4943%;font-size:0.649886em}
+ .st4 {font-size:1em}
+ .st5 {font-family:Cambria Math;font-size:1em}
+ .st6 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+ ]]>
+ </style>
+
+ <g v:mID="0" v:index="1" v:groupContext="foregroundPage">
+ <title>Page-1</title>
+ <v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
+ <g id="shape3-1" v:mID="3" v:groupContext="shape" transform="translate(0.25,-0.25)">
+ <title>Sheet.3</title>
+ <desc>False Positive Probability = (1-(1-1/m)kn)k ≃ (1-ekn/m)k</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="157.5" cy="45.5" width="315" height="90"/>
+ <rect x="0" y="0.5" width="315" height="90" class="st1"/>
+ <text x="8.28" y="49.82" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>False Positive Probability = (1-(1-1/m)<tspan
+ dy="-0.234em" class="st3" v:baseFontSize="14">kn</tspan><tspan dy="0.152em" class="st4">)</tspan><tspan
+ dy="-0.234em" class="st3" v:baseFontSize="14">k</tspan><tspan dy="0.152em" class="st4"> </tspan><tspan
+ class="st5">≃</tspan> (1-e<tspan dy="-0.234em" class="st3" v:baseFontSize="14">kn</tspan><tspan class="st3"
+ v:baseFontSize="14">/</tspan><tspan class="st3" v:baseFontSize="14">m</tspan><tspan dy="0.152em"
+ class="st4">)</tspan><tspan dy="-0.234em" class="st3" v:baseFontSize="14">k</tspan></text> </g>
+ </g>
+</svg>
diff --git a/doc/guides/prog_guide/img/memship_i3.svg b/doc/guides/prog_guide/img/memship_i3.svg
new file mode 100644
index 0000000..f13decb
--- /dev/null
+++ b/doc/guides/prog_guide/img/memship_i3.svg
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by Microsoft Visio, SVG Export memship_i3.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
+ width="4.71875in" height="2.84375in" viewBox="0 0 339.75 204.75" xml:space="preserve" color-interpolation-filters="sRGB"
+ class="st14">
+ <style type="text/css">
+ <![CDATA[
+ .st1 {visibility:visible}
+ .st2 {fill:#5b9bd5;fill-opacity:0.22;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.22}
+ .st3 {fill:#5b9bd5;stroke:#c7c8c8;stroke-width:0.25}
+ .st4 {marker-end:url(#mrkr5-32);stroke:#5b9bd5;stroke-linecap:round;stroke-linejoin:round;stroke-width:1}
+ .st5 {fill:#5b9bd5;fill-opacity:1;stroke:#5b9bd5;stroke-opacity:1;stroke-width:0.28409090909091}
+ .st6 {fill:#feffff;font-family:Calibri;font-size:0.833336em}
+ .st7 {font-size:1em}
+ .st8 {fill:#deebf6;stroke:#c7c8c8;stroke-width:0.25}
+ .st9 {fill:#000000;font-family:Calibri;font-size:0.833336em}
+ .st10 {marker-end:url(#mrkr5-84);stroke:#ff0000;stroke-linecap:round;stroke-linejoin:round;stroke-width:1}
+ .st11 {fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-opacity:1;stroke-width:0.28409090909091}
+ .st12 {fill:none;stroke:none;stroke-width:0.25}
+ .st13 {fill:#ff0000;font-family:Calibri;font-size:1.00001em}
+ .st14 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+ ]]>
+ </style>
+
+ <defs id="Markers">
+ <g id="lend5">
+ <path d="M 2 1 L 0 0 L 1.98117 -0.993387 C 1.67173 -0.364515 1.67301 0.372641 1.98465 1.00043 " style="stroke:none"/>
+ </g>
+ <marker id="mrkr5-32" class="st5" refX="-6.16" orient="auto" markerUnits="strokeWidth" overflow="visible">
+ <use xlink:href="#lend5" transform="scale(-3.52,-3.52) "/>
+ </marker>
+ <marker id="mrkr5-84" class="st11" refX="-5.8" orient="auto" markerUnits="strokeWidth" overflow="visible">
+ <use xlink:href="#lend5" transform="scale(-3.52,-3.52) "/>
+ </marker>
+ </defs>
+ <defs id="Filters">
+ <filter id="filter_2">
+ <feGaussianBlur stdDeviation="2"/>
+ </filter>
+ </defs>
+ <g>
+ <title>Page-1</title>
+ <g id="group174-1" transform="translate(3.0294,-5.3478)">
+ <title>Sheet.174</title>
+ <g id="shape155-2" transform="translate(99,-99)">
+ <title>Circle</title>
+ <g id="shadow155-3" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M0 186.75 A18 18 0 0 1 36 186.75 A18 18 0 1 1 0 186.75 Z" class="st2"/>
+ </g>
+ <path d="M0 186.75 A18 18 0 0 1 36 186.75 A18 18 0 1 1 0 186.75 Z" class="st3"/>
+ </g>
+ <g id="shape156-7" transform="translate(207,-108)">
+ <title>Circle.156</title>
+ <g id="shadow156-8" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M0 186.75 A18 18 0 0 1 36 186.75 A18 18 0 1 1 0 186.75 Z" class="st2"/>
+ </g>
+ <path d="M0 186.75 A18 18 0 0 1 36 186.75 A18 18 0 1 1 0 186.75 Z" class="st3"/>
+ </g>
+ <g id="shape157-12" transform="translate(153,-162)">
+ <title>Circle.157</title>
+ <g id="shadow157-13" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M0 186.75 A18 18 0 0 1 36 186.75 A18 18 0 1 1 0 186.75 Z" class="st2"/>
+ </g>
+ <path d="M0 186.75 A18 18 0 0 1 36 186.75 A18 18 0 1 1 0 186.75 Z" class="st3"/>
+ </g>
+ <g id="shape158-17" transform="translate(297,-99)">
+ <title>Circle.158</title>
+ <g id="shadow158-18" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M0 186.75 A18 18 0 0 1 36 186.75 A18 18 0 1 1 0 186.75 Z" class="st2"/>
+ </g>
+ <path d="M0 186.75 A18 18 0 0 1 36 186.75 A18 18 0 1 1 0 186.75 Z" class="st3"/>
+ </g>
+ <g id="shape159-22" transform="translate(180,-36)">
+ <title>Circle.159</title>
+ <g id="shadow159-23" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <path d="M0 186.75 A18 18 0 0 1 36 186.75 A18 18 0 1 1 0 186.75 Z" class="st2"/>
+ </g>
+ <path d="M0 186.75 A18 18 0 0 1 36 186.75 A18 18 0 1 1 0 186.75 Z" class="st3"/>
+ </g>
+ <g id="shape160-27" transform="translate(109.604,-115.419) rotate(-7.12502)">
+ <title>Sheet.160</title>
+ <path d="M0 204.75 L66.4 204.75" class="st4"/>
+ </g>
+ <g id="shape161-33" transform="translate(276.661,-123.214) rotate(9.46232)">
+ <title>Sheet.161</title>
+ <path d="M0 204.75 L48.58 204.75" class="st4"/>
+ </g>
+ <g id="shape162-38" transform="translate(246.135,262.572) rotate(-160.346)">
+ <title>Sheet.162</title>
+ <path d="M0 204.75 L127.63 204.75" class="st4"/>
+ </g>
+ <g id="shape163-43" transform="translate(284.391,198.775) rotate(141.977)">
+ <title>Sheet.163</title>
+ <path d="M0 204.75 L46.23 204.75" class="st4"/>
+ </g>
+ <g id="shape164-48" transform="translate(70.6118,307.655) rotate(-145.945)">
+ <title>Sheet.164</title>
+ <path d="M0 204.75 L60.88 204.75" class="st4"/>
+ </g>
+ <g id="shape167-53" transform="translate(72,0)">
+ <title>Rectangle.167</title>
+ <desc>BF of IDs</desc>
+ <g id="shadow167-54" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="177.75" width="36" height="27" class="st2"/>
+ </g>
+ <rect x="0" y="177.75" width="36" height="27" class="st3"/>
+ <text x="7.69" y="188.25" class="st6">BF of <tspan x="11.71" dy="1.2em" class="st7">IDs</tspan></text> </g>
+ <g id="shape168-60" transform="translate(108,0)">
+ <title>Rectangle.168</title>
+ <desc>Packet</desc>
+ <g id="shadow168-61" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="177.75" width="90" height="27" class="st2"/>
+ </g>
+ <rect x="0" y="177.75" width="90" height="27" class="st8"/>
+ <text x="31.47" y="194.25" class="st9">Packet</text> </g>
+ <g id="shape169-66" transform="translate(0,-63)">
+ <title>Rectangle.169</title>
+ <desc>BF of IDs</desc>
+ <g id="shadow169-67" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="177.75" width="36" height="27" class="st2"/>
+ </g>
+ <rect x="0" y="177.75" width="36" height="27" class="st3"/>
+ <text x="7.69" y="188.25" class="st6">BF of <tspan x="11.71" dy="1.2em" class="st7">IDs</tspan></text> </g>
+ <g id="shape170-73" transform="translate(36,-63)">
+ <title>Rectangle.170</title>
+ <desc>Packet</desc>
+ <g id="shadow170-74" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="177.75" width="90" height="27" class="st2"/>
+ </g>
+ <rect x="0" y="177.75" width="90" height="27" class="st8"/>
+ <text x="31.47" y="194.25" class="st9">Packet</text> </g>
+ <g id="shape171-79" transform="translate(240.248,331.493) rotate(161.565)">
+ <title>Sheet.171</title>
+ <path d="M-0 190.52 A81.3416 36.0611 -153.48 0 0 82.31 195.86 L82.49 195.55" class="st10"/>
+ </g>
+ <g id="shape172-85" transform="translate(156.426,260.029) rotate(161.565)">
+ <title>Sheet.172</title>
+ <path d="M-0 181.6 A88.1422 54.1439 -124.1 0 0 82.68 187.13 L82.83 186.81" class="st10"/>
+ </g>
+ <g id="shape173-90" transform="translate(18,-121.5)">
+ <title>Sheet.173</title>
+ <desc>Encode ID</desc>
+ <rect x="0" y="177.75" width="63" height="27" class="st12"/>
+ <text x="7.02" y="194.85" class="st13">Encode ID</text> </g>
+ </g>
+ </g>
+</svg>
diff --git a/doc/guides/prog_guide/img/memship_i4.svg b/doc/guides/prog_guide/img/memship_i4.svg
new file mode 100644
index 0000000..24eaf01
--- /dev/null
+++ b/doc/guides/prog_guide/img/memship_i4.svg
@@ -0,0 +1,428 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by Microsoft Visio, SVG Export memship_i4.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
+ xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="7.4375in" height="2.92253in"
+ viewBox="0 0 535.5 210.422" xml:space="preserve" color-interpolation-filters="sRGB" class="st18">
+ <v:documentProperties v:langID="1033" v:viewMarkup="false"/>
+
+ <style type="text/css">
+ <![CDATA[
+ .st1 {fill:none;stroke:#ff0000;stroke-width:0.25}
+ .st2 {fill:#5b9bd5;font-family:Calibri;font-size:1.00001em}
+ .st3 {marker-end:url(#mrkr5-10);stroke:#ff0000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.25}
+ .st4 {fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-opacity:1;stroke-width:0.47169811320755}
+ .st5 {visibility:visible}
+ .st6 {fill:#5b9bd5;fill-opacity:0.22;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.22}
+ .st7 {fill:#5b9bd5;stroke:#c7c8c8;stroke-width:0.25}
+ .st8 {fill:none;stroke:none;stroke-width:0.25}
+ .st9 {fill:#5b9bd5;font-family:Calibri;font-size:1.16666em}
+ .st10 {stroke:#5b9bd5;stroke-dasharray:1.5,3;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5}
+ .st11 {fill:#5b9bd5;fill-opacity:0.25;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.25}
+ .st12 {fill:#4f87bb;stroke:#40709c;stroke-width:0.75}
+ .st13 {fill:#ffffff;font-family:Calibri;font-size:1.00001em;font-weight:bold}
+ .st14 {fill:#000000;font-family:Calibri;font-size:1.00001em}
+ .st15 {font-size:1em}
+ .st16 {marker-end:url(#mrkr5-187);stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:1}
+ .st17 {fill:#000000;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:0.28409090909091}
+ .st18 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+ ]]>
+ </style>
+
+ <defs id="Markers">
+ <g id="lend5">
+ <path d="M 2 1 L 0 0 L 1.98117 -0.993387 C 1.67173 -0.364515 1.67301 0.372641 1.98465 1.00043 " style="stroke:none"/>
+ </g>
+ <marker id="mrkr5-10" class="st4" v:arrowType="5" v:arrowSize="2" v:setback="3.71" refX="-3.71" orient="auto"
+ markerUnits="strokeWidth" overflow="visible">
+ <use xlink:href="#lend5" transform="scale(-2.12,-2.12) "/>
+ </marker>
+ <marker id="mrkr5-187" class="st17" v:arrowType="5" v:arrowSize="2" v:setback="5.8" refX="-5.8" orient="auto"
+ markerUnits="strokeWidth" overflow="visible">
+ <use xlink:href="#lend5" transform="scale(-3.52,-3.52) "/>
+ </marker>
+ </defs>
+ <defs id="Filters">
+ <filter id="filter_2">
+ <feGaussianBlur stdDeviation="2"/>
+ </filter>
+ </defs>
+ <g v:mID="0" v:index="1" v:groupContext="foregroundPage">
+ <title>Page-1</title>
+ <v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
+ <g id="group47-1" transform="translate(3.0294,-0.25)" v:mID="47" v:groupContext="group">
+ <title>Sheet.47</title>
+ <g id="shape1-2" v:mID="1" v:groupContext="shape" transform="translate(177.75,-191.922)">
+ <title>Sheet.1</title>
+ <desc>Element</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="54" cy="201.422" width="108" height="18"/>
+ <rect x="0" y="192.422" width="108" height="18" class="st1"/>
+ <text x="33.77" y="205.02" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Element</text> </g>
+ <g id="shape2-5" v:mID="2" v:groupContext="shape" transform="translate(442.172,18.5) rotate(90)">
+ <title>Sheet.2</title>
+ <path d="M0 210.42 L18.65 210.42" class="st3"/>
+ </g>
+ <g id="shape3-11" v:mID="3" v:groupContext="shape" transform="translate(0,-67.0469)">
+ <title>Rectangle.54</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow3-12" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape4-16" v:mID="4" v:groupContext="shape" transform="translate(27,-67.0469)">
+ <title>Rectangle.55</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow4-17" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape5-21" v:mID="5" v:groupContext="shape" transform="translate(54,-67.0469)">
+ <title>Rectangle.56</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow5-22" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape6-26" v:mID="6" v:groupContext="shape" transform="translate(0,-53.5469)">
+ <title>Rectangle.57</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow6-27" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape7-31" v:mID="7" v:groupContext="shape" transform="translate(27,-53.5469)">
+ <title>Rectangle.58</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow7-32" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape8-36" v:mID="8" v:groupContext="shape" transform="translate(54,-53.5469)">
+ <title>Rectangle.59</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow8-37" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape9-41" v:mID="9" v:groupContext="shape" transform="translate(5.625,-72.6719)">
+ <title>Sheet.9</title>
+ <desc>BF-1</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="36" cy="196.922" width="72" height="27"/>
+ <rect x="0" y="183.422" width="72" height="27" class="st8"/>
+ <text x="23.29" y="201.12" class="st9" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>BF-1</text> </g>
+ <g id="shape10-44" v:mID="10" v:groupContext="shape" transform="translate(128.25,-65.0781)">
+ <title>Rectangle.74</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow10-45" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape11-49" v:mID="11" v:groupContext="shape" transform="translate(155.25,-65.0781)">
+ <title>Rectangle.75</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow11-50" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape12-54" v:mID="12" v:groupContext="shape" transform="translate(182.25,-65.0781)">
+ <title>Rectangle.76</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow12-55" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape13-59" v:mID="13" v:groupContext="shape" transform="translate(128.25,-51.5781)">
+ <title>Rectangle.77</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow13-60" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape14-64" v:mID="14" v:groupContext="shape" transform="translate(155.25,-51.5781)">
+ <title>Rectangle.78</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow14-65" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape15-69" v:mID="15" v:groupContext="shape" transform="translate(182.25,-51.5781)">
+ <title>Rectangle.79</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow15-70" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape16-74" v:mID="16" v:groupContext="shape" transform="translate(301.5,-65.0781)">
+ <title>Rectangle.81</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow16-75" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape17-79" v:mID="17" v:groupContext="shape" transform="translate(328.5,-65.0781)">
+ <title>Rectangle.82</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow17-80" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape18-84" v:mID="18" v:groupContext="shape" transform="translate(355.5,-65.0781)">
+ <title>Rectangle.83</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow18-85" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape19-89" v:mID="19" v:groupContext="shape" transform="translate(301.5,-51.5781)">
+ <title>Rectangle.84</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow19-90" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape20-94" v:mID="20" v:groupContext="shape" transform="translate(328.5,-51.5781)">
+ <title>Rectangle.85</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow20-95" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape21-99" v:mID="21" v:groupContext="shape" transform="translate(355.5,-51.5781)">
+ <title>Rectangle.86</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow21-100" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape22-104" v:mID="22" v:groupContext="shape" transform="translate(447.75,-65.6406)">
+ <title>Rectangle.88</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow22-105" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape23-109" v:mID="23" v:groupContext="shape" transform="translate(474.75,-65.6406)">
+ <title>Rectangle.89</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow23-110" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape24-114" v:mID="24" v:groupContext="shape" transform="translate(501.75,-65.6406)">
+ <title>Rectangle.90</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow24-115" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape25-119" v:mID="25" v:groupContext="shape" transform="translate(447.75,-52.1406)">
+ <title>Rectangle.91</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow25-120" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape26-124" v:mID="26" v:groupContext="shape" transform="translate(474.75,-52.1406)">
+ <title>Rectangle.92</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow26-125" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape27-129" v:mID="27" v:groupContext="shape" transform="translate(501.75,-52.1406)">
+ <title>Rectangle.93</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow27-130" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279" v:shadowType="1"
+ transform="matrix(1,0,0,1,0.345598,1.97279)" class="st5">
+ <rect x="0" y="196.922" width="27" height="13.5" class="st6"/>
+ </g>
+ <rect x="0" y="196.922" width="27" height="13.5" class="st7"/>
+ </g>
+ <g id="shape28-134" v:mID="28" v:groupContext="shape" transform="translate(213.75,-63.9531)">
+ <title>Sheet.28</title>
+ <path d="M0 210.42 L83.25 210.42" class="st10"/>
+ </g>
+ <g id="shape29-137" v:mID="29" v:groupContext="shape" transform="translate(387,-63.9531)">
+ <title>Sheet.29</title>
+ <path d="M0 210.42 L54 210.42" class="st10"/>
+ </g>
+ <g id="group31-140" transform="translate(184.5,-113.172)" v:mID="31" v:groupContext="group">
+ <title>Sheet.31</title>
+ <g id="shape32-141" v:mID="32" v:groupContext="shape" transform="translate(210.422,158.672) rotate(90)">
+ <title>Block Arrow</title>
+ <v:userDefs>
+ <v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
+ </v:userDefs>
+ <g id="shadow32-142" v:groupContext="shadow" v:shadowOffsetX="0.345598" v:shadowOffsetY="-1.97279"
+ v:shadowType="1" transform="matrix(1,0,0,1,1.97279,-0.345598)" class="st5">
+ <path d="M0 210.42 L25.87 210.42 L51.75 163.17 L25.87 115.92 L0 115.92 L0 210.42 Z" class="st11"/>
+ </g>
+ <path d="M0 210.42 L25.87 210.42 L51.75 163.17 L25.87 115.92 L0 115.92 L0 210.42 Z" class="st12"/>
+ </g>
+ <g id="shape33-146" v:mID="33" v:groupContext="shape" transform="translate(2.25,-24.3529)">
+ <title>Sheet.33</title>
+ <desc>h1, h2 .. hk</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="45" cy="201.29" width="90" height="18.2647"/>
+ <rect x="0" y="192.157" width="90" height="18.2647" class="st8"/>
+ <text x="17.56" y="204.89" class="st13" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>h1, h2 .. hk</text> </g>
+ </g>
+ <g id="shape34-149" v:mID="34" v:groupContext="shape" transform="translate(300.24,259.242) rotate(152.323)">
+ <title>Sheet.34</title>
+ <path d="M0 210.42 L128.85 210.42" class="st3"/>
+ </g>
+ <g id="shape35-154" v:mID="35" v:groupContext="shape" transform="translate(418.903,108.413) rotate(99.7172)">
+ <title>Sheet.35</title>
+ <path d="M0 210.42 L58.31 210.42" class="st3"/>
+ </g>
+ <g id="shape36-159" v:mID="36" v:groupContext="shape" transform="translate(397.416,-68.4157) rotate(45)">
+ <title>Sheet.36</title>
+ <path d="M0 210.42 L79.16 210.42" class="st3"/>
+ </g>
+ <g id="shape37-164" v:mID="37" v:groupContext="shape" transform="translate(316.517,-127.658) rotate(15.6155)">
+ <title>Sheet.37</title>
+ <path d="M0 210.42 L200.75 210.42" class="st3"/>
+ </g>
+ <g id="shape38-169" v:mID="38" v:groupContext="shape" transform="translate(132.75,-75.2588)">
+ <title>Sheet.38</title>
+ <desc>BF-2</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="36" cy="196.922" width="72" height="27"/>
+ <rect x="0" y="183.422" width="72" height="27" class="st8"/>
+ <text x="23.29" y="201.12" class="st9" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>BF-2</text> </g>
+ <g id="shape39-172" v:mID="39" v:groupContext="shape" transform="translate(303.75,-70.7588)">
+ <title>Sheet.39</title>
+ <desc>BF-X</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="36" cy="196.922" width="72" height="27"/>
+ <rect x="0" y="183.422" width="72" height="27" class="st8"/>
+ <text x="23.2" y="201.12" class="st9" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>BF-X</text> </g>
+ <g id="shape40-175" v:mID="40" v:groupContext="shape" transform="translate(447.75,-75.2588)">
+ <title>Sheet.40</title>
+ <desc>BF-L</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="36" cy="196.922" width="72" height="27"/>
+ <rect x="0" y="183.422" width="72" height="27" class="st8"/>
+ <text x="23.89" y="201.12" class="st9" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>BF-L</text> </g>
+ <g id="shape41-178" v:mID="41" v:groupContext="shape" transform="translate(300.375,-117)">
+ <title>Sheet.41</title>
+ <desc>Hashing for lookup/Insertion into a vector of BFs happens once</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="90" cy="187.922" width="180" height="45"/>
+ <rect x="0" y="165.422" width="180" height="45" class="st8"/>
+ <text x="4.6" y="184.32" class="st14" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Hashing for lookup/Insertion into a <tspan
+ x="23.06" dy="1.2em" class="st15">vector of BFs happens once</tspan></text> </g>
+ <g id="shape44-182" v:mID="44" v:groupContext="shape" transform="translate(250.649,-151.536) rotate(-3.74012)">
+ <title>Sheet.44</title>
+ <path d="M-0 210.42 A93.4958 45.6256 42.23 0 1 79.38 207.08 L79.68 207.28" class="st16"/>
+ </g>
+ <g id="shape45-188" v:mID="45" v:groupContext="shape" transform="translate(30.375,0)">
+ <title>Sheet.45</title>
+ <desc>Lookup/Insertion is done in the series of BFs, one by one but...</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="216" cy="187.922" width="432" height="45"/>
+ <rect x="0" y="165.422" width="432" height="45" class="st8"/>
+ <text x="9.93" y="191.52" class="st14" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Lookup/Insertion is done in the series of BFs, one by one but can be optimized on IA </text> </g>
+ <g id="shape46-191" v:mID="46" v:groupContext="shape" transform="translate(118.984,-44.3256) rotate(17.0249)">
+ <title>Sheet.46</title>
+ <path d="M-0 210.42 A88.2185 43.0621 47.63 0 1 70.31 206.81 L70.6 207.02" class="st16"/>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/doc/guides/prog_guide/img/memship_i5.svg b/doc/guides/prog_guide/img/memship_i5.svg
new file mode 100644
index 0000000..4dc9ee2
--- /dev/null
+++ b/doc/guides/prog_guide/img/memship_i5.svg
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by Microsoft Visio, SVG Export memship_i5.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
+ width="4.80481in" height="2.14896in" viewBox="0 0 345.946 154.725" xml:space="preserve" color-interpolation-filters="sRGB"
+ class="st14">
+ <style type="text/css">
+ <![CDATA[
+ .st1 {visibility:visible}
+ .st2 {fill:#5b9bd5;fill-opacity:0.22;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.22}
+ .st3 {fill:#5b9bd5;stroke:#c7c8c8;stroke-width:0.25}
+ .st4 {fill:none;stroke:none;stroke-width:0.25}
+ .st5 {fill:#ffffff;font-family:Calibri;font-size:1.16666em;font-weight:bold}
+ .st6 {marker-end:url(#mrkr5-16);stroke:#5b9bd5;stroke-linecap:round;stroke-linejoin:round;stroke-width:1}
+ .st7 {fill:#5b9bd5;fill-opacity:1;stroke:#5b9bd5;stroke-opacity:1;stroke-width:0.28409090909091}
+ .st8 {fill:#5b9bd5;font-family:Calibri;font-size:1.00001em}
+ .st9 {font-size:1em}
+ .st10 {stroke:#5b9bd5;stroke-linecap:round;stroke-linejoin:round;stroke-width:1}
+ .st11 {marker-end:url(#mrkr5-66);stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
+ .st12 {fill:#000000;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:0.22935779816514}
+ .st13 {fill:#000000;font-family:Calibri;font-size:1.00001em}
+ .st14 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+ ]]>
+ </style>
+
+ <defs id="Markers">
+ <g id="lend5">
+ <path d="M 2 1 L 0 0 L 1.98117 -0.993387 C 1.67173 -0.364515 1.67301 0.372641 1.98465 1.00043 " style="stroke:none"/>
+ </g>
+ <marker id="mrkr5-16" class="st7" refX="-6.16" orient="auto" markerUnits="strokeWidth" overflow="visible">
+ <use xlink:href="#lend5" transform="scale(-3.52,-3.52) "/>
+ </marker>
+ <marker id="mrkr5-66" class="st12" refX="-7.15" orient="auto" markerUnits="strokeWidth" overflow="visible">
+ <use xlink:href="#lend5" transform="scale(-4.36,-4.36) "/>
+ </marker>
+ </defs>
+ <defs id="Filters">
+ <filter id="filter_2">
+ <feGaussianBlur stdDeviation="2"/>
+ </filter>
+ </defs>
+ <g>
+ <title>Page-1</title>
+ <g id="group16-1" transform="translate(18.25,-32.9751)">
+ <title>Sheet.16</title>
+ <g id="group1-2" transform="translate(147.3,0)">
+ <title>Sheet.1</title>
+ <g id="shape2-3" transform="translate(160.125,55.7251) rotate(90)">
+ <title>Triangle</title>
+ <g id="shadow2-4" transform="matrix(1,0,0,1,1.97279,-0.345598)" class="st1">
+ <path d="M99 154.73 L49.5 76.73 L0 154.73 L99 154.73 Z" class="st2"/>
+ </g>
+ <path d="M99 154.73 L49.5 76.73 L0 154.73 L99 154.73 Z" class="st3"/>
+ </g>
+ <g id="shape3-8" transform="translate(0,-34.65)">
+ <title>Sheet.3</title>
+ <desc>vBF</desc>
+ <rect x="0" y="125.025" width="72" height="29.7" class="st4"/>
+ <text x="25.55" y="144.08" class="st5">vBF </text> </g>
+ </g>
+ <g id="shape4-11" transform="translate(85.6667,-81)">
+ <title>Sheet.4</title>
+ <path d="M0 154.73 L60.87 154.73" class="st6"/>
+ </g>
+ <g id="shape5-17" transform="translate(70.3125,-76.5)">
+ <title>Sheet.5</title>
+ <desc>Flow Key</desc>
+ <rect x="0" y="127.725" width="75.375" height="27" class="st4"/>
+ <text x="15.93" y="144.83" class="st8">Flow Key</text> </g>
+ <g id="shape6-20" transform="translate(163.417,-34.105) rotate(-25.776)">
+ <title>Sheet.6</title>
+ <path d="M0 154.73 L62.14 154.73" class="st6"/>
+ </g>
+ <g id="shape7-25" transform="translate(230.7,-49.5)">
+ <title>Sheet.7</title>
+ <path d="M0 154.73 L60.87 154.73" class="st6"/>
+ </g>
+ <g id="shape8-30" transform="translate(297.099,-34.5285) rotate(25.413)">
+ <title>Sheet.8</title>
+ <path d="M0 154.73 L67.24 154.73" class="st6"/>
+ </g>
+ <g id="shape9-35" transform="translate(152.7,264.45) rotate(180)">
+ <title>Sheet.9</title>
+ <path d="M0 154.73 L47.84 154.73" class="st6"/>
+ </g>
+ <g id="shape10-40" transform="translate(1.125,-45)">
+ <title>Sheet.10</title>
+ <desc>New Flow = New Assignment</desc>
+ <rect x="0" y="127.725" width="151.875" height="27" class="st4"/>
+ <text x="5.18" y="144.83" class="st8">New Flow = New Assignment</text> </g>
+ <g id="shape11-43" transform="translate(153,300.45) rotate(180)">
+ <title>Sheet.11</title>
+ <path d="M0 154.73 L47.84 154.73" class="st6"/>
+ </g>
+ <g id="shape12-48" transform="translate(0,-9)">
+ <title>Sheet.12</title>
+ <desc>Old Flow = forward to specific thread</desc>
+ <rect x="0" y="127.725" width="151.875" height="27" class="st4"/>
+ <text x="22.77" y="137.63" class="st8">Old Flow = forward to <tspan x="40.17" dy="1.2em" class="st9">specific thread</tspan></text> </g>
+ <g id="shape13-52" transform="translate(453.988,55.7251) rotate(90)">
+ <title>Sheet.13</title>
+ <path d="M0 147.99 C3.18 156.39 7.57 155.78 11.25 152.49 C15.79 148.43 19.26 140.28 27 147.99" class="st10"/>
+ </g>
+ <g id="shape14-55" transform="translate(453.988,91.7251) rotate(90)">
+ <title>Sheet.14</title>
+ <path d="M0 147.99 C3.18 156.39 7.57 155.78 11.25 152.49 C15.79 148.43 19.26 140.28 27 147.99" class="st10"/>
+ </g>
+ <g id="shape15-58" transform="translate(453.988,127.725) rotate(90)">
+ <title>Sheet.15</title>
+ <path d="M0 147.99 C3.18 156.39 7.57 155.78 11.25 152.49 C15.79 148.43 19.26 140.28 27 147.99" class="st10"/>
+ </g>
+ </g>
+ <g id="shape17-61" transform="translate(322.234,-34.6851) rotate(44.5185)">
+ <title>Sheet.17</title>
+ <path d="M-0 154.73 A35.1884 19.2595 167.75 0 1 42.43 151.77 L42.74 151.96" class="st11"/>
+ </g>
+ <g id="shape18-67" transform="translate(186.188,-18.9001)">
+ <title>Sheet.18</title>
+ <desc>A BF corresponding to each worker thread</desc>
+ <rect x="0" y="127.725" width="118.125" height="27" class="st4"/>
+ <text x="5.14" y="137.63" class="st13">A BF corresponding to <tspan x="11.19" dy="1.2em" class="st9">each worker thread</tspan></text> </g>
+ </g>
+</svg>
diff --git a/doc/guides/prog_guide/img/memship_i6.svg b/doc/guides/prog_guide/img/memship_i6.svg
new file mode 100644
index 0000000..1d05ffc
--- /dev/null
+++ b/doc/guides/prog_guide/img/memship_i6.svg
@@ -0,0 +1,233 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by Microsoft Visio, SVG Export memship_i6.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
+ width="8.56597in" height="3.47009in" viewBox="0 0 616.75 249.847" xml:space="preserve" color-interpolation-filters="sRGB"
+ class="st16">
+ <style type="text/css">
+ <![CDATA[
+ .st1 {visibility:visible}
+ .st2 {fill:#5b9bd5;fill-opacity:0.22;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.22}
+ .st3 {fill:#5b9bd5;stroke:#c7c8c8;stroke-width:0.25}
+ .st4 {fill:#feffff;font-family:Calibri;font-size:1.00001em;font-weight:bold}
+ .st5 {font-size:1em}
+ .st6 {fill:#70ad47;fill-opacity:0.5;stroke:#00b050;stroke-width:1.5}
+ .st7 {fill:none;stroke:none;stroke-width:0.25}
+ .st8 {fill:#00b050;font-family:Calibri;font-size:1.00001em}
+ .st9 {fill:none;stroke:#ff0000;stroke-width:0.25}
+ .st10 {fill:#5b9bd5;font-family:Calibri;font-size:0.833336em}
+ .st11 {marker-end:url(#mrkr5-33);stroke:#ff0000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.25}
+ .st12 {fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-opacity:1;stroke-width:0.47169811320755}
+ .st13 {fill:#5b9bd5;font-family:Calibri;font-size:1.00001em}
+ .st14 {fill:#92d050;stroke:#c7c8c8;stroke-width:0.25}
+ .st15 {fill:#5b9bd5;font-family:Calibri;font-size:1.5em;font-weight:bold}
+ .st16 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+ ]]>
+ </style>
+
+ <defs id="Markers">
+ <g id="lend5">
+ <path d="M 2 1 L 0 0 L 1.98117 -0.993387 C 1.67173 -0.364515 1.67301 0.372641 1.98465 1.00043 " style="stroke:none"/>
+ </g>
+ <marker id="mrkr5-33" class="st12" refX="-3.71" orient="auto" markerUnits="strokeWidth" overflow="visible">
+ <use xlink:href="#lend5" transform="scale(-2.12,-2.12) "/>
+ </marker>
+ </defs>
+ <defs id="Filters">
+ <filter id="filter_2">
+ <feGaussianBlur stdDeviation="2"/>
+ </filter>
+ </defs>
+ <g>
+ <title>Page-1</title>
+ <g id="group123-1" transform="translate(3.0294,-5.3478)">
+ <title>Sheet.123</title>
+ <g id="group121-2">
+ <title>Sheet.121</title>
+ <g id="shape49-3" transform="translate(449.422,-57.9401)">
+ <title>Rectangle.2</title>
+ <g id="shadow49-4" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="208.396" width="99.4817" height="41.4507" class="st2"/>
+ </g>
+ <rect x="0" y="208.396" width="99.4817" height="41.4507" class="st3"/>
+ </g>
+ <g id="shape50-8" transform="translate(295.177,-16.6936)">
+ <title>Rectangle.4</title>
+ <g id="shadow50-9" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="166.945" width="99.4817" height="82.9014" class="st2"/>
+ </g>
+ <rect x="0" y="166.945" width="99.4817" height="82.9014" class="st3"/>
+ </g>
+ <g id="shape52-13" transform="translate(6.07514E-013,-29.0155)">
+ <title>Rectangle.10</title>
+ <desc>Signatures for target 1</desc>
+ <g id="shadow52-14" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="179.38" width="99.4817" height="70.4662" class="st2"/>
+ </g>
+ <rect x="0" y="179.38" width="99.4817" height="70.4662" class="st3"/>
+ <text x="14.94" y="211.01" class="st4">Signatures for <tspan x="30.22" dy="1.2em" class="st5">target </tspan>1</text> </g>
+ <g id="shape53-20" transform="translate(286.887,-24.9837)">
+ <title>Sheet.53</title>
+ <rect x="0" y="237.411" width="116.062" height="12.4352" class="st6"/>
+ </g>
+ <g id="shape54-22" transform="translate(227.102,-26.6257)">
+ <title>Sheet.54</title>
+ <desc>Match 1</desc>
+ <rect x="0" y="237.411" width="66.3211" height="12.4352" class="st7"/>
+ <text x="13.06" y="247.23" class="st8">Match 1</text> </g>
+ <g id="shape55-25" transform="translate(215.225,-227.669)">
+ <title>Sheet.55</title>
+ <desc>Packet Payload</desc>
+ <rect x="0" y="233.266" width="99.4817" height="16.5803" class="st9"/>
+ <text x="19.04" y="244.56" class="st10">Packet Payload</text> </g>
+ <g id="shape56-28" transform="translate(514.813,22.1781) rotate(90)">
+ <title>Sheet.56</title>
+ <path d="M0 249.85 L16.52 249.85" class="st11"/>
+ </g>
+ <g id="shape96-34" transform="translate(6.07514E-013,-101.124)">
+ <title>Sheet.96</title>
+ <desc>Attack Signature Length 1</desc>
+ <rect x="0" y="224.976" width="99.4817" height="24.8704" class="st7"/>
+ <text x="9.53" y="233.81" class="st13">Attack Signature <tspan x="28.7" dy="1.2em" class="st5">Length </tspan>1</text> </g>
+ <g id="group114-38" transform="translate(227.979,-150.865)">
+ <title>Sheet.114</title>
+ <g id="group106-39" transform="translate(0,-24.8704)">
+ <title>Sheet.106</title>
+ <g id="shape100-40" transform="translate(3.65707E-013,-12.4352)">
+ <title>Rectangle.100</title>
+ <g id="shadow100-41" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st2"/>
+ </g>
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st3"/>
+ </g>
+ <g id="shape101-45" transform="translate(24.8704,-12.4352)">
+ <title>Rectangle.101</title>
+ <g id="shadow101-46" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st2"/>
+ </g>
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st3"/>
+ </g>
+ <g id="shape102-50" transform="translate(49.7409,-12.4352)">
+ <title>Rectangle.102</title>
+ <g id="shadow102-51" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st2"/>
+ </g>
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st3"/>
+ </g>
+ <g id="shape103-55">
+ <title>Rectangle.103</title>
+ <g id="shadow103-56" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st2"/>
+ </g>
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st3"/>
+ </g>
+ <g id="shape104-60" transform="translate(24.8704,1.42109E-013)">
+ <title>Rectangle.104</title>
+ <g id="shadow104-61" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st2"/>
+ </g>
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st3"/>
+ </g>
+ <g id="shape105-65" transform="translate(49.7409,1.42109E-013)">
+ <title>Rectangle.105</title>
+ <g id="shadow105-66" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st2"/>
+ </g>
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st3"/>
+ </g>
+ </g>
+ <g id="group107-70">
+ <title>Sheet.107</title>
+ <g id="shape108-71" transform="translate(3.65707E-013,-12.4352)">
+ <title>Rectangle.100</title>
+ <g id="shadow108-72" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st2"/>
+ </g>
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st3"/>
+ </g>
+ <g id="shape109-76" transform="translate(24.8704,-12.4352)">
+ <title>Rectangle.101</title>
+ <g id="shadow109-77" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st2"/>
+ </g>
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st3"/>
+ </g>
+ <g id="shape110-81" transform="translate(49.7409,-12.4352)">
+ <title>Rectangle.102</title>
+ <g id="shadow110-82" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st2"/>
+ </g>
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st3"/>
+ </g>
+ <g id="shape111-86">
+ <title>Rectangle.103</title>
+ <g id="shadow111-87" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st2"/>
+ </g>
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st14"/>
+ </g>
+ <g id="shape112-91" transform="translate(24.8704,1.42109E-013)">
+ <title>Rectangle.104</title>
+ <g id="shadow112-92" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st2"/>
+ </g>
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st3"/>
+ </g>
+ <g id="shape113-96" transform="translate(49.7409,1.42109E-013)">
+ <title>Rectangle.105</title>
+ <g id="shadow113-97" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st2"/>
+ </g>
+ <rect x="0" y="237.411" width="24.8704" height="12.4352" class="st14"/>
+ </g>
+ </g>
+ </g>
+ <g id="shape89-101" transform="translate(373.169,-144.96) rotate(19.406)">
+ <title>Sheet.89</title>
+ <path d="M0 249.85 L185.02 249.85" class="st11"/>
+ </g>
+ <g id="shape115-106" transform="translate(116.062,-1.22213E-012)">
+ <title>Rectangle.115</title>
+ <desc>Signatures for target 2</desc>
+ <g id="shadow115-107" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="150.365" width="99.4817" height="99.4817" class="st2"/>
+ </g>
+ <rect x="0" y="150.365" width="99.4817" height="99.4817" class="st3"/>
+ <text x="14.94" y="196.51" class="st4">Signatures for <tspan x="30.22" dy="1.2em" class="st5">target </tspan>2</text> </g>
+ <g id="shape116-113" transform="translate(116.062,-101.124)">
+ <title>Sheet.116</title>
+ <desc>Attack Signature Length 2</desc>
+ <rect x="0" y="224.976" width="99.4817" height="24.8704" class="st7"/>
+ <text x="9.53" y="233.81" class="st13">Attack Signature <tspan x="28.7" dy="1.2em" class="st5">Length </tspan>2</text> </g>
+ <g id="shape117-117" transform="translate(290.155,-101.124)">
+ <title>Sheet.117</title>
+ <desc>Attack Signature Length X</desc>
+ <rect x="0" y="224.976" width="99.4817" height="24.8704" class="st7"/>
+ <text x="9.53" y="233.81" class="st13">Attack Signature <tspan x="28.62" dy="1.2em" class="st5">Length X</tspan></text> </g>
+ <g id="shape118-121" transform="translate(447.668,-102.857)">
+ <title>Sheet.118</title>
+ <desc>Attack Signature Length L</desc>
+ <rect x="0" y="224.976" width="99.4817" height="24.8704" class="st7"/>
+ <text x="9.53" y="233.81" class="st13">Attack Signature <tspan x="29.22" dy="1.2em" class="st5">Length L</tspan></text> </g>
+ <g id="shape119-125" transform="translate(439.378,-65.7997)">
+ <title>Sheet.119</title>
+ <rect x="0" y="237.411" width="116.062" height="12.4352" class="st6"/>
+ </g>
+ <g id="shape120-127" transform="translate(547.149,-63.8181)">
+ <title>Sheet.120</title>
+ <desc>Match 2</desc>
+ <rect x="0" y="237.411" width="66.3211" height="12.4352" class="st7"/>
+ <text x="13.06" y="247.23" class="st8">Match 2</text> </g>
+ <g id="shape85-130" transform="translate(441.66,-55.3013) rotate(53.6564)">
+ <title>Sheet.85</title>
+ <path d="M0 249.85 L150.51 249.85" class="st11"/>
+ </g>
+ </g>
+ <g id="shape122-135" transform="translate(175.448,-169.167)">
+ <title>Sheet.122</title>
+ <desc>HTSS</desc>
+ <rect x="0" y="224.976" width="53.8859" height="24.8704" class="st7"/>
+ <text x="8.3" y="242.81" class="st15">HTSS</text> </g>
+ </g>
+ </g>
+</svg>
diff --git a/doc/guides/prog_guide/img/memship_i7.svg b/doc/guides/prog_guide/img/memship_i7.svg
new file mode 100644
index 0000000..231b309
--- /dev/null
+++ b/doc/guides/prog_guide/img/memship_i7.svg
@@ -0,0 +1,277 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by Microsoft Visio, SVG Export memship_i7.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
+ width="8.125in" height="3.92442in" viewBox="0 0 585 282.559" xml:space="preserve" color-interpolation-filters="sRGB"
+ class="st22">
+ <style type="text/css">
+ <![CDATA[
+ .st1 {visibility:visible}
+ .st2 {fill:#5b9bd5;fill-opacity:0.22;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.22}
+ .st3 {fill:#5b9bd5;stroke:#c7c8c8;stroke-width:0.25}
+ .st4 {fill:#feffff;font-family:Calibri;font-size:1.00001em;font-weight:bold}
+ .st5 {font-size:1em}
+ .st6 {fill:#70ad47;fill-opacity:0.5;stroke:#00b050;stroke-width:1.5}
+ .st7 {fill:none;stroke:none;stroke-width:0.25}
+ .st8 {fill:#00b050;font-family:Calibri;font-size:1.00001em}
+ .st9 {fill:none;stroke:#00b050;stroke-width:2.25}
+ .st10 {fill:#5b9bd5;font-family:Calibri;font-size:0.833336em}
+ .st11 {fill:#5b9bd5;font-family:Calibri;font-size:1.00001em}
+ .st12 {fill:#a8d08d;stroke:#c7c8c8;stroke-width:0.25}
+ .st13 {marker-end:url(#mrkr5-99);stroke:#ff0000;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.25}
+ .st14 {fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-opacity:1;stroke-width:0.47169811320755}
+ .st15 {marker-end:url(#mrkr5-112);stroke:#92d050;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.25}
+ .st16 {fill:#92d050;fill-opacity:1;stroke:#92d050;stroke-opacity:1;stroke-width:0.47169811320755}
+ .st17 {fill:#00b050;font-family:Calibri;font-size:0.833336em;font-weight:bold}
+ .st18 {fill:none;stroke:#ff0000;stroke-width:2.25}
+ .st19 {fill:#ff0000;font-family:Calibri;font-size:0.833336em;font-weight:bold}
+ .st20 {marker-end:url(#mrkr5-140);stroke:#ff0000;stroke-linecap:round;stroke-linejoin:round;stroke-width:1}
+ .st21 {fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-opacity:1;stroke-width:0.28409090909091}
+ .st22 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+ ]]>
+ </style>
+
+ <defs id="Markers">
+ <g id="lend5">
+ <path d="M 2 1 L 0 0 L 1.98117 -0.993387 C 1.67173 -0.364515 1.67301 0.372641 1.98465 1.00043 " style="stroke:none"/>
+ </g>
+ <marker id="mrkr5-99" class="st14" refX="-3.71" orient="auto" markerUnits="strokeWidth" overflow="visible">
+ <use xlink:href="#lend5" transform="scale(-2.12,-2.12) "/>
+ </marker>
+ <marker id="mrkr5-112" class="st16" refX="-3.71" orient="auto" markerUnits="strokeWidth" overflow="visible">
+ <use xlink:href="#lend5" transform="scale(-2.12,-2.12) "/>
+ </marker>
+ <marker id="mrkr5-140" class="st21" refX="-5.8" orient="auto" markerUnits="strokeWidth" overflow="visible">
+ <use xlink:href="#lend5" transform="scale(-3.52,-3.52) "/>
+ </marker>
+ </defs>
+ <defs id="Filters">
+ <filter id="filter_2">
+ <feGaussianBlur stdDeviation="2"/>
+ </filter>
+ </defs>
+ <g>
+ <title>Page-1</title>
+ <g id="group135-1" transform="translate(3.0294,-11.6966)">
+ <title>Sheet.135</title>
+ <g id="group121-2" transform="translate(0,-21.3235)">
+ <title>Sheet.121</title>
+ <g id="shape49-3" transform="translate(426.345,-54.965)">
+ <title>Rectangle.2</title>
+ <g id="shadow49-4" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="243.236" width="94.3736" height="39.3223" class="st2"/>
+ </g>
+ <rect x="0" y="243.236" width="94.3736" height="39.3223" class="st3"/>
+ </g>
+ <g id="shape50-8" transform="translate(280.021,-15.8364)">
+ <title>Rectangle.4</title>
+ <g id="shadow50-9" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="203.914" width="94.3736" height="78.6447" class="st2"/>
+ </g>
+ <rect x="0" y="203.914" width="94.3736" height="78.6447" class="st3"/>
+ </g>
+ <g id="shape52-13" transform="translate(5.83533E-013,-27.5256)">
+ <title>Rectangle.10</title>
+ <desc>Flow Keys Matching Mask 1</desc>
+ <g id="shadow52-14" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="215.711" width="94.3736" height="66.848" class="st2"/>
+ </g>
+ <rect x="0" y="215.711" width="94.3736" height="66.848" class="st3"/>
+ <text x="22.37" y="245.53" class="st4">Flow Keys <tspan x="4.4" dy="1.2em" class="st5">Matching Mask </tspan>1</text> </g>
+ <g id="shape53-20" transform="translate(272.156,-23.7009)">
+ <title>Sheet.53</title>
+ <rect x="0" y="270.762" width="110.103" height="11.7967" class="st6"/>
+ </g>
+ <g id="shape54-22" transform="translate(220.205,-25.2586)">
+ <title>Sheet.54</title>
+ <desc>Match</desc>
+ <rect x="0" y="270.762" width="62.9157" height="11.7967" class="st7"/>
+ <text x="15.75" y="280.26" class="st8">Match</text> </g>
+ <g id="shape55-25" transform="translate(228.07,-215.978)">
+ <title>Sheet.55</title>
+ <desc>Flow ID1</desc>
+ <rect x="0" y="266.83" width="47.4888" height="15.7289" class="st9"/>
+ <text x="6.09" y="277.69" class="st10">Flow ID1</text> </g>
+ <g id="shape96-28" transform="translate(5.83533E-013,-95.9313)">
+ <title>Sheet.96</title>
+ <desc>Flow Mask 1</desc>
+ <rect x="0" y="274.694" width="94.3736" height="7.86447" class="st7"/>
+ <text x="16.77" y="282.23" class="st11">Flow Mask 1</text> </g>
+ <g id="group114-31" transform="translate(216.273,-143.118)">
+ <title>Sheet.114</title>
+ <g id="group106-32" transform="translate(0,-23.5934)">
+ <title>Sheet.106</title>
+ <g id="shape100-33" transform="translate(3.53717E-013,-11.7967)">
+ <title>Rectangle.100</title>
+ <g id="shadow100-34" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st2"/>
+ </g>
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st3"/>
+ </g>
+ <g id="shape101-38" transform="translate(23.5934,-11.7967)">
+ <title>Rectangle.101</title>
+ <g id="shadow101-39" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st2"/>
+ </g>
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st3"/>
+ </g>
+ <g id="shape102-43" transform="translate(47.1868,-11.7967)">
+ <title>Rectangle.102</title>
+ <g id="shadow102-44" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st2"/>
+ </g>
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st3"/>
+ </g>
+ <g id="shape103-48">
+ <title>Rectangle.103</title>
+ <g id="shadow103-49" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st2"/>
+ </g>
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st3"/>
+ </g>
+ <g id="shape104-53" transform="translate(23.5934,1.13687E-013)">
+ <title>Rectangle.104</title>
+ <g id="shadow104-54" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st2"/>
+ </g>
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st3"/>
+ </g>
+ <g id="shape105-58" transform="translate(47.1868,1.13687E-013)">
+ <title>Rectangle.105</title>
+ <g id="shadow105-59" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st2"/>
+ </g>
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st3"/>
+ </g>
+ </g>
+ <g id="group107-63">
+ <title>Sheet.107</title>
+ <g id="shape108-64" transform="translate(3.53717E-013,-11.7967)">
+ <title>Rectangle.100</title>
+ <g id="shadow108-65" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st2"/>
+ </g>
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st3"/>
+ </g>
+ <g id="shape109-69" transform="translate(23.5934,-11.7967)">
+ <title>Rectangle.101</title>
+ <g id="shadow109-70" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st2"/>
+ </g>
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st3"/>
+ </g>
+ <g id="shape110-74" transform="translate(47.1868,-11.7967)">
+ <title>Rectangle.102</title>
+ <g id="shadow110-75" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st2"/>
+ </g>
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st12"/>
+ </g>
+ <g id="shape111-79">
+ <title>Rectangle.103</title>
+ <g id="shadow111-80" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st2"/>
+ </g>
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st3"/>
+ </g>
+ <g id="shape112-84" transform="translate(23.5934,1.13687E-013)">
+ <title>Rectangle.104</title>
+ <g id="shadow112-85" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st2"/>
+ </g>
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st3"/>
+ </g>
+ <g id="shape113-89" transform="translate(47.1868,1.13687E-013)">
+ <title>Rectangle.105</title>
+ <g id="shadow113-90" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st2"/>
+ </g>
+ <rect x="0" y="270.762" width="23.5934" height="11.7967" class="st3"/>
+ </g>
+ </g>
+ </g>
+ <g id="shape89-94" transform="translate(361.211,343.085) rotate(146.31)">
+ <title>Sheet.89</title>
+ <path d="M0 282.56 L133.43 282.56" class="st13"/>
+ </g>
+ <g id="shape115-100" transform="translate(110.103,-1.13687E-012)">
+ <title>Rectangle.115</title>
+ <desc>Flow Keys Matching Mask 2</desc>
+ <g id="shadow115-101" transform="matrix(1,0,0,1,0.345598,1.97279)" class="st1">
+ <rect x="0" y="188.185" width="94.3736" height="94.3736" class="st2"/>
+ </g>
+ <rect x="0" y="188.185" width="94.3736" height="94.3736" class="st3"/>
+ <text x="22.37" y="231.77" class="st4">Flow Keys <tspan x="4.4" dy="1.2em" class="st5">Matching Mask </tspan>2</text> </g>
+ <g id="shape85-107" transform="translate(554.606,79.2847) rotate(81.3573)">
+ <title>Sheet.85</title>
+ <path d="M0 282.56 L124.72 282.56" class="st15"/>
+ </g>
+ <g id="shape56-113" transform="translate(505.594,-56.7279) rotate(64.1257)">
+ <title>Sheet.56</title>
+ <path d="M0 282.56 L46.41 282.56" class="st15"/>
+ </g>
+ </g>
+ <g id="shape122-118" transform="translate(290.985,-176.238)">
+ <title>Sheet.122</title>
+ <desc>HTSS with False Negative (Cache)</desc>
+ <rect x="0" y="258.965" width="94.3736" height="23.5934" class="st7"/>
+ <text x="9.13" y="267.16" class="st11">HTSS with False <tspan x="5.8" dy="1.2em" class="st5">Negative </tspan>(Cache)</text> </g>
+ <g id="shape123-122" transform="translate(232.985,-247.019)">
+ <title>Sheet.123</title>
+ <desc>Active</desc>
+ <rect x="0" y="258.965" width="42.2715" height="23.5934" class="st7"/>
+ <text x="8.17" y="273.76" class="st17">Active</text> </g>
+ <g id="shape124-125" transform="translate(227.919,-121.187)">
+ <title>Sheet.124</title>
+ <desc>Target for Flow ID 1</desc>
+ <rect x="0" y="258.965" width="63.0667" height="23.5934" class="st9"/>
+ <text x="11.41" y="267.76" class="st10">Target for <tspan x="12.75" dy="1.2em" class="st5">Flow ID </tspan>1</text> </g>
+ <g id="shape125-129" transform="translate(117.816,-215.561)">
+ <title>Sheet.125</title>
+ <desc>Flow ID2</desc>
+ <rect x="0" y="266.83" width="47.4888" height="15.7289" class="st18"/>
+ <text x="6.09" y="277.69" class="st10">Flow ID2</text> </g>
+ <g id="shape126-132" transform="translate(133.696,-227.357)">
+ <title>Sheet.126</title>
+ <desc>New/Inactive</desc>
+ <rect x="0" y="258.965" width="70.7802" height="23.5934" class="st7"/>
+ <text x="7.28" y="273.76" class="st19">New/Inactive</text> </g>
+ <g id="shape127-135" transform="translate(201.302,-201.959) rotate(14.0795)">
+ <title>Sheet.127</title>
+ <path d="M0 277.29 A34.2894 18 -180 0 0 42.82 279.69 L43.15 279.55" class="st20"/>
+ </g>
+ <g id="shape128-141" transform="translate(186.231,-191.967)">
+ <title>Sheet.128</title>
+ <desc>Miss</desc>
+ <rect x="0" y="258.965" width="36.4911" height="23.5934" class="st7"/>
+ <text x="7.05" y="274.36" class="st11">Miss</text> </g>
+ <g id="shape129-144" transform="translate(110.103,-117.255)">
+ <title>Sheet.129</title>
+ <desc>Flow Mask 2</desc>
+ <rect x="0" y="274.694" width="94.3736" height="7.86447" class="st7"/>
+ <text x="16.77" y="282.23" class="st11">Flow Mask 2</text> </g>
+ <g id="shape130-147" transform="translate(126.037,-5.6568) rotate(18.2325)">
+ <title>Sheet.130</title>
+ <path d="M0 252.02 A62.209 104.269 -180 0 0 84.65 257.2 L84.84 256.9" class="st20"/>
+ </g>
+ <g id="shape131-152" transform="translate(143.013,8.06313) rotate(-3.24734)">
+ <title>Sheet.131</title>
+ <path d="M0 252.02 A98.1706 104.269 -180 0 0 134.48 256.37 L134.73 256.12" class="st20"/>
+ </g>
+ <g id="shape132-157" transform="translate(284.267,10.4726) rotate(-16.7388)">
+ <title>Sheet.132</title>
+ <path d="M-0 252.02 A96.5426 104.269 -180 0 0 132.21 256.41 L132.46 256.15" class="st20"/>
+ </g>
+ <g id="shape133-162" transform="translate(283.121,-117.255)">
+ <title>Sheet.133</title>
+ <desc>Flow Mask X</desc>
+ <rect x="0" y="274.694" width="94.3736" height="7.86447" class="st7"/>
+ <text x="16.69" y="282.23" class="st11">Flow Mask X</text> </g>
+ <g id="shape134-165" transform="translate(424.681,-117.255)">
+ <title>Sheet.134</title>
+ <desc>Flow Mask L</desc>
+ <rect x="0" y="274.694" width="94.3736" height="7.86447" class="st7"/>
+ <text x="17.29" y="282.23" class="st11">Flow Mask L</text> </g>
+ </g>
+ </g>
+</svg>
diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst
index ef5a02a..096cc93 100644
--- a/doc/guides/prog_guide/index.rst
+++ b/doc/guides/prog_guide/index.rst
@@ -48,6 +48,7 @@ Programmer's Guide
timer_lib
hash_lib
efd_lib
+ membership_lib
lpm_lib
lpm6_lib
packet_distrib_lib
@@ -187,6 +188,19 @@ Programmer's Guide
:numref:`figure_efd11` :ref:`figure_efd11`
+:numref:`figure_membership1` :ref:`figure_membership1`
+
+:numref:`figure_membership2` :ref:`figure_membership2`
+
+:numref:`figure_membership3` :ref:`figure_membership3`
+
+:numref:`figure_membership4` :ref:`figure_membership4`
+
+:numref:`figure_membership5` :ref:`figure_membership5`
+
+:numref:`figure_membership6` :ref:`figure_membership6`
+
+:numref:`figure_membership7` :ref:`figure_membership7`
**Tables**
diff --git a/doc/guides/prog_guide/membership_lib.rst b/doc/guides/prog_guide/membership_lib.rst
new file mode 100644
index 0000000..fb11249
--- /dev/null
+++ b/doc/guides/prog_guide/membership_lib.rst
@@ -0,0 +1,424 @@
+.. BSD LICENSE
+ Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Membership Library
+=======================
+
+Introduction
+------------
+The DPDK Membership Library provides an API for DPDK applications to insert a
+new member, delete an existing member, or query the existence of a member in a
+given set, or a group of sets. For the case of a group of sets the library
+will return not only whether the element has been inserted before in one of
+the sets but also which set it belongs to. The Membership Library is an
+extension and generalization of a traditional filter structure (for example
+Bloom Filter [Memship-bloom]) that has multiple usages in a wide variety of
+workloads and applications. In general, the Membership Library is a data
+structure that provides a “set-summary” on whether a member belongs to a set,
+and as discussed in details later, there are two advantages of using such a
+set-summary rather than operating on a “full-blown” complete list of elements:
+first, it has a much smaller storage requirement than storing the whole list of
+elements themselves, and secondly checking an element membership (or other
+operations) in this set-summary is much faster than checking it for the
+original full-blown complete list of elements.
+
+We use the term “Set-Summary” in this guide to refer to the space-efficient,
+probabilistic membership data structure that is provided by the library. A
+membership test for an element will return the set this element belongs to or
+null (meaning not found) with very high probability of accuracy. Set-summary
+is a fundamental data aggregation component that can be used in many network
+(and other) applications. It is a crucial structure to address performance and
+scalability issues of diverse network applications including overlay networks,
+data-centric networks, flow table summaries, network statistics and
+traffic monitoring. A set-summary is useful for applications who need to
+include a list of elements while a complete list requires too much space
+and/or too much processing cost. In these situations, the set-summary works as
+a lossy hash-based representation of a set of members. It can dramatically
+reduce space requirement and significantly improve the performance of set
+membership queries at the cost of introducing a very small membership test error
+probability.
+
+.. _figure_membership1:
+.. figure:: img/memship_i1.*
+
+ Example Usages of Membership Library
+
+We believe that there are various usages for a Membership Library in a very
+large set of applications and workloads. Interested readers can refer to
+[Memship-survey] for a survey of possible networking usages. The above figure
+provide a small set of examples of using the Membership Library. Sub-figure(a)
+depicts a distributed web cache architecture where a collection of proxies
+attempt to share their web caches (cached from a set of backend web servers) to
+provide faster responses to clients, and the proxies uses the Membership
+Library to share summaries of what webpages they are caching. With the
+Membership Library, a proxy receiving an \http request will inquire the
+set-summary to find its location and quickly determine whether to retrieve the
+requested webpage from a nearby proxy or from a backend web server.
+Sub-figure(b) depicts another example for using the Membership Library to
+prevent routing loops which is typically done using slow TTL countdown and
+dropping packets when TTL expires. As shown in Sub-figure(b), an embedded
+set-summary in the packet header itself can be used to summarize the set of
+nodes a packet has gone through, and each node upon receiving a packet can check
+whether its id is a member of the set of visited nodes, and if it is then a
+routing loop is detected. Sub-Figure(c) presents another usage of Membership
+Library to load balance flows to worker threads with in-order guarantee where a
+set-summary is used to query if a packet belongs to an existing flow or a new
+flow. Packets belonging to a new flow are forwarded to the current least loaded
+worker thread, while those belonging to an existing flow are forwarded to the
+pre-assigned thread to guarantee in-order processing. Sub-figure(d) highlights
+yet another usage example in the database domain where a set-summary is used to
+determine joins between sets instead of creating a join by comparing each
+element of a set against the other elements in a different set, a join is done
+on the summaries since they can efficiently encode members of a given set.
+
+We are including a configurable Membership Library in DPDK to cover set
+membership functionality for both a single set and multi-set scenarios. The
+library is optimized to support the customer network applications which require
+membership checking functionality. In this guide, we will cover few set-summary
+schemes including Bloom Filter, vector of Bloom Filters, abd Hash-Table based
+set-summary schemes with and without false negative probability, followed by
+a brief discussion of the Membership Library API.
+
+Bloom Filter
+---------------
+
+The Bloom Filter (BF) [Memship-bloom] is a well-known space-efficient
+probabilistic data structure that answers set membership queries (test whether
+an element is a member of a set) with some probability of false positives and
+zero false negatives; a query for an element returns either it is "possibly in
+a set" (with very high probability) or "definitely not in a set".
+
+The BF is a method for representing a set of n elements (for example flow keys
+in network applications domain) to support membership queries. The idea of BF is
+to allocate a bit-vector v with m bits, which are initially all set to 0. Then
+it chooses k independent hash functions h1, h2, … hk with hash values range from
+1 to m to perform hashing calculations on each element. Every time when an
+element X being inserted into the set, the bits at positions h1(X), h2(X), …
+hk(X) in v are set to 1 (any particular bit might be set to 1 multiple times
+for multiple different inserted elements). Given a query for any element Y, the
+bits at positions h1(Y), h2(Y), ... hk(Y) are checked. If any of them is 0,
+then Y is definitely not in the set. Otherwise there is a high probability that
+Y is a member of the set with certain false positive probability. As shown in
+the next equation, the false positive probability can be made arbitrarily small
+by changing the number of hash functions (k) and the vector length (m).
+
+.. _figure_membership2:
+.. figure:: img/memship_i2.*
+
+ Bloom Filter False Positive Probability
+
+Without BF, an accurate membership testing could involve a costly hash table
+lookup and full element comparison. The advantage of using a BF is to simplify
+the membership test into a series of hash calculations and memory accesses for a
+small bit-vector, which can be easily optimized. Hence the lookup throughput
+(set membership test) can be significantly faster than a normal hash table
+lookup with element comparison.
+
+.. _figure_membership3:
+.. figure:: img/memship_i3.*
+
+ Detecting Routing Loops Using BF
+
+By design, BF is used for applications that need only one set, and the
+membership of elements is checked against its set-summary. The example discussed
+in the above figure is one example of potential applications that uses only one
+set to capture the node IDs that have been visited so far by the packet. Each
+node will then check this embedded BF in the packet header for its own id, and
+if the BF indicates that the current node is definitely not in the set then a
+loop-free route is guaranteed.
+
+
+Vector of Bloom Filters
+--------------------------
+
+.. _figure_membership4:
+.. figure:: img/memship_i4.*
+
+ Vector Bloom Filter (vBF) Overview
+
+Vector Bloom Filter (vBF) is another scheme supported by the Membership Library
+to support more than one set. The membership test is conducted on all of the
+set-summaries concurrently to determine which set(s) it belongs to or none of
+them. The basic idea of vBF is shown in the above figure where an element is
+used to address multiple bloom filters concurrently and the bloom filter
+index(es) with a hit is returned.
+
+.. _figure_membership5:
+.. figure:: img/memship_i5.*
+
+ vBF for Flow Scheduling to Worker Thread
+
+As previously mentioned, there are many usages of such structure. vBF is used
+for applications that needs to check membership against multiple sets
+simultaneously. The example discussed in the above figure uses a set to capture
+all flows being assigned for processing at a given worker thread. Upon receiving
+a packet the vBF is used to figure quickly if this packet belongs to a new flow
+so as to be forwarded to the current least loaded worker thread, or otherwise it
+should be queued for an existing thread to guarantee in-order processing (i.e.
+the property of vBF to indicate right away that a given flow is a new one or
+not is critical to minimize response time latency).
+
+It should be noted that vBF can be implemented using a set of single bloom
+filters with sequential lookup of each BF. However, being able to concurrently
+search all set-summaries is a big throughput advantage and the implementation
+can typically be fully optimized across different CPU architectures. For
+example, on IA prefetching and vector instructions (AVX) can be used for
+optimizations.
+
+
+Hash-Table based Set-Summaries
+---------------------------------
+
+Hash-table based set-summary (HTSS) is another scheme in the membership library.
+Cuckoo filter [Memship-cfilter] is an example of hash-table based set summary.
+HTSS can be easily extended to support multi-set membership testing like what
+vBF does. Meanwhile, HTSS can easily outperform vBF when the number of sets is
+large, since HTSS uses a single hash table for membership testing while vBF
+requires testing a series of Bloom Filters each corresponding to one set.
+
+.. _figure_membership6:
+.. figure:: img/memship_i6.*
+
+ Using HTSS for Attack Signature Matching
+
+As shown in the above figure, attack signature matching where each set
+represents a certain signature length (for correctness of this example, an
+attack signature should not be a subset of another one) in the payload is a good
+example for using HTSS with 0% false negative (i.e., when an element returns not
+found, it has a 100% certainty that it is not a member of any set). The packet
+inspection application benefits from knowing right away that the current payload
+does not match any attack signatures in the database to establish its
+legitimacy, otherwise a deep inspenction of the packet is needed.
+
+HTSS employs a similar but simpler data structure to a traditional hash table,
+and the major difference is that HTSS stores only the signatures but not the
+full keys/elements which can significantly reduce the footprint of the table.
+Along with the signature, HTSS also stores a value to indicate the target set.
+When looking up for an element, the element is hashed and the HTSS is addressed
+to retrieve the signature stored. If the signature matches then the value is
+retrieved corresponding to the index of the target set which the element belongs
+to. Because signatures can collide, HTSS can still has false positive
+probability similar to vBF. Furthermore, if elements are allowed to be
+overwritten or evicted when the hash table becomes full, it will also have a
+false negative probability. We discuss this case in the next section.
+
+Set-Summaries with False Negative Probability
+-----------------------------------------------
+
+As previously discussed, traditional set-summaries (e.g. Bloom Filters ) do not
+have a false negative probability, i.e., it is 100% certain when an element
+returns “not to be present” for a given set. However, the Membership Library
+also supports a set-summary probabilistic data structure based on HTSS which
+allows for false negative probability.
+
+
+In HTSS, when the hash table becomes full, keys/elements will fail to be added
+into the table and the hash table has to be resized to accommodate for these new
+elements, which can be expensive. However, if we allow new elements to overwrite
+or evict existing elements (as a cache typically does), then the resulting
+set-summary will begin to have false negative probability. This is because the
+element that was evicted from the set-summary may still be present in the target
+set. For subsequent inquiries the set-summary will falsely report the element
+not being in the set, hence having a false negative probability.
+
+The major usage of HTSS with false negative is to use it as a cache for
+distributing elements to different target sets. By allowing HTSS to evict old
+elements, the set-summary can keep track of the most recent elements
+(i.e. active) as a cache typically does. Old inactive elements (infrequently
+used elements) will automatically and eventually get evicted from the
+set-summary. It should be noted that given an element the lookup can always fall
+back to a sequential search of the sets if the set-summary fails to correctly
+report its existence.
+
+.. _figure_membership7:
+.. figure:: img/memship_i7.*
+
+ Using HTSS with False Negatives for Wild Card Classification
+
+HTSS with false negative (i.e. a cache) has also its wide set of applications.
+For example Wild card flow classification (e.g. ACL rules) highlighted in the
+above figure is an example of such application. In that case each target set
+represents a sub-table with rules defined by a certain flow mask. The flow masks
+are non-overlapping, and for flows matching more than one rule only the highest
+priority one is inserted in the corresponding sub-table (interested readers can
+refer to the Open vSwitch (OvS) design of Mega Flow Cache (MFC) [Memship-OvS]
+for further details) Typically the rules will have a large number of distinct
+unique masks and hence, a large number of target sets each corresponding to one
+mask. Because the active set of flows varies widely based on the network
+traffic, HTSS with false negative will act as a cache for <flowid, target ACL
+sub-table> pair for the current active set of flows. When a miss occurs (as
+shown in red in the above figure) the sub-tables will be searched sequentially
+one by one for a possible match, and when found the flow key and target
+sub-table will be inserted in the set-summary (i.e. cache insertion) so
+subsequent packets from the same flow don’t incur the overhead of the
+sequential search of sub-tables.
+
+Library API Overview
+--------------------
+The design goal of the Membership Library API is to be as generic as possible to
+support all the different types of set-summaries we discussed in previous
+sections and beyond. Fundamentally, the APIs need to include query, creation,
+insertion, deletion, and lookup. Other functions like retrieving a set-summary
+by name and destroying a certain set-summary, etc. are also needed but are very
+common, straightforward, and similar to other libraries in DPDK.
+
+Set-summary Type Query
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+*void rte\_ms\_type\_query(enum rte\_ms\_setsum\_type\*\* types)*
+
+This function intends to serve as a convenient tool to query which set-summary
+types are supported in the current version of DPDK. Since the implementations of
+the set-summaries can vary, initial versions of the Membership Library may only
+support a subset of the set-summaries we discussed previously. Programmers could
+use this API to decide which type is available to use in the current version of DPDK.
+
+Set-summary Create
+~~~~~~~~~~~~~~~~~~~~~
+
+*rte\_membership\_create(const struct rte\_membership\_parameters \*params)*
+
+This function is used to create a set-summary structure, the input parameters
+are those needed to initialize the set-summary, while the function returns the
+pointer to the created set-summary or NULL if the creation failed.
+
+Tha input argument parameters used when creating the set-summary are, *name*
+which is the name of the created set-summary, *type* which is one of the types
+supported by the library (BF, vBF, Cache or Hash Table set-summary), *num\_keys*
+which is the maximum total number of elements/keys in the set-summary structure,
+*key\_len* is the length of the element/key. *prim\_hash\_seed* and
+*sec\_hash\_seed* are the seeds of the primary and secondary hash functions,
+while *socket\_id* is the NUMA socket ID for the memory used to create the
+set-summary. The other two parameters that are
+relevant to only the BF and vBF types are *num\_target* which is the number of
+targets (i.e. number of set-summaries), and *false\_pos\_rate* which is the
+maximum allowable false positive probability by the application (in case of BF
+and vBF the two arguments num\_keys and false\_pos\_rate will used to determine
+the number of hash functions and the bit-vector size to gurantee that the actual
+false positive rate is lower than the maximum allowed).
+
+Set-summary Element Insertion
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+*rte\_membership\_add(const void *setsum, const void *key, MEMBERSHIP\_TARGET\_TYPE target\_id)*
+
+This function insert an element/key in a set-summary structure, if it fails an
+error is returned. For success the returned value is defferent based on the
+set-summary mode to provide extra information for the users. For both BF and vBF
+modes, a return value of 0 means a successful insert. For HTSS mode, the return
+value in case of success is the index of the inserted entry in the hash bucket.
+For cache mode, in case of successful insert the return value is 0 if the insert
+does not cause an eviction out of the cache (i.e. no overwriting happensto an
+existing entry) and the value of 1 is returned if an existing entry is evicted
+out of the cache.
+
+The input arguements for the function are *setsum* which is the pointer to the
+set-summary structure, *key* which is a pointer to the element/key that needs to
+be added to the set-summary, and, *target\_id* which is the target id associated
+with the key that needs to be added (for the case of BF mode the target id
+should be no larger than 1).
+
+
+Set-summary Element Lookup
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+*rte\_membership\_lookup(const void \*setsum, const void \*key, MEMBERSHIP\_TARGET\_TYPE \*target\_id)*
+
+This function looks up a single key/element in the set-summary structure. It
+returns as soon the first match is found (no further matching of subsequent
+targets, for example for the vBF mode, is performed) the return value is 1 if a
+match is found and 0 otherwise. The arguments for the function are *setsum*
+which is pointer of a set-summary structure, *key* which is a pointer to the
+element/key that needs to be looked up, *target\_id* which is used to return the
+first target set id where the key has matched, if any.
+
+*rte\_membership\_lookup\_bulk(const void \*setsum, const void \*\*keys, uint32\_t num\_keys, MEMBERSHIP\_TARGET\_TYPE \*target\_ids)*
+
+This function looks up a bulk of keys/elements elements simultaneously in the
+set-summary structure, each key lookup returns as soon as the first match is found. The
+return value is the number of keys that find a match. The arguments of the
+function are *setsum* which is a pointer to the set-summary structure, *keys* is
+a pointer to a bulk of keys that are to be looked up, *num\_keys* is the number
+of keys that will are to be looked up, *target\_ids* are the return target set
+ids for the first match found for each of the input keys.
+
+*rte\_membership\_lookup\_multi(const void \*setsum, const void \*key, MEMBERSHIP\_TARGET\_TYPE \*target\_id)*
+
+This function looks up a single key/element in the set-summary structure. It
+returns ALL the matches (possibly more than one) found for this key when it
+is matched against all target sets (This lookup function can be used with the
+vBF and HT modes of set summaries). The return value is the number of matches
+that was found for this key (for both BF and Cache modes the return value
+should be at most 1). The arguments for the function are *setsum*
+which is pointer of a set-summary structure, *key* which is a pointer to the
+element/key that needs to be looked up, *target\_id* which is used to return all
+target set ids where the key has matched, if any.
+
+*rte\_membership\_lookup\_multi\_bulk(const void \*setsum, const void \*\*keys, uint32\_t num\_keys, uint32\_t max\_match\_per\_key, uint32\_t \*match\_count, MEMBERSHIP\_TARGET\_TYPE \*target\_ids)*
+
+This function looks up a bulk of keys/elements elements simultaneously in the
+set-summary structure, each key lookup returns ALL the matches (possibly more
+than one) found for this key when it is matched against all target sets (This
+lookup function can be used with the vBF and HT modes of set summaries). The
+return value is the number of keys that find one or more matches in the
+set-summary structure. The arguments of the
+function are *setsum* which is a pointer to the set-summary structure, *keys* is
+a pointer to a bulk of keys that are to be looked up, *num\_keys* is the number
+of keys that will are to be looked up, *max\_match\_per\_key* is the possible
+max number of matches for each key, *match\_count* which is the returned number
+of matches for all the keys, and *target\_ids* are the return target set
+ids for the first match found for each of the input keys.
+
+
+Set-summary Element Delete [1]_
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+*rte\_membership\_delete(void \*setsum, const void \*key, MEMBERSHIP\_TARGET\_TYPE target\_id)*
+
+This function deletes an element/key from a set-summary structure, if it fails
+an error is returned. The input arguements for the function are *setsum* which
+is the pointer to the set-summary structure, *key* which is a pointer to the
+element/key that needs to be deleted from the set-summary, and, *target\_id*
+which is used with the vBF and HT set-summary types to delete the key from
+certain target ids.
+
+.. [1] Traditional bloom filter does not support proactive deletion. Proactive deletion may require additional implementation and performance overhead.
+
+References
+-----------
+
+[Memship-bloom] B H Bloom, "Space/Time Trade-offs in Hash Coding with Allowable Errors," Communications of the ACM, 1970.
+
+[Memship-survey] A Broder and M Mitzenmacher, "Network Applications of Bloom Filters: A Survey," in Internet Mathematics, 2005.
+
+[Memship-cfilter] B Fan, D G Andersen and M Kaminsky, "Cuckoo Filter: Practically Better Than Bloom," in Conference on emerging Networking Experiments and Technologies, 2014.
+
+[Memship-OvS] B Pfaff, "The Design and Implementation of Open vSwitch," in NSDI, 2015.
\ No newline at end of file
diff --git a/lib/Makefile b/lib/Makefile
index 07e1fd0..be1ee2d 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -30,7 +30,6 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
include $(RTE_SDK)/mk/rte.vars.mk
-
DIRS-y += librte_compat
DIRS-$(CONFIG_RTE_LIBRTE_EAL) += librte_eal
DIRS-$(CONFIG_RTE_LIBRTE_RING) += librte_ring
@@ -106,6 +105,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
DEPDIRS-librte_reorder := librte_eal librte_mempool librte_mbuf
DIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += librte_pdump
DEPDIRS-librte_pdump := librte_eal librte_mempool librte_mbuf librte_ether
+DIRS-$(CONFIG_RTE_LIBRTE_MEMBERSHIP) += librte_membership
+DEPDIRS-librte_membership := librte_eal librte_mempool librte_hash librte_sched
ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
diff --git a/lib/librte_eal/common/eal_common_log.c b/lib/librte_eal/common/eal_common_log.c
index ddf65b7..3e712c2 100644
--- a/lib/librte_eal/common/eal_common_log.c
+++ b/lib/librte_eal/common/eal_common_log.c
@@ -270,6 +270,7 @@ struct logtype {
{RTE_LOGTYPE_CRYPTODEV, "cryptodev"},
{RTE_LOGTYPE_EFD, "efd"},
{RTE_LOGTYPE_EVENTDEV, "eventdev"},
+ {RTE_LOGTYPE_MEMBERSHIP, "membership"},
{RTE_LOGTYPE_USER1, "user1"},
{RTE_LOGTYPE_USER2, "user2"},
{RTE_LOGTYPE_USER3, "user3"},
diff --git a/lib/librte_eal/common/include/rte_log.h b/lib/librte_eal/common/include/rte_log.h
index 3419138..a323411 100644
--- a/lib/librte_eal/common/include/rte_log.h
+++ b/lib/librte_eal/common/include/rte_log.h
@@ -87,6 +87,7 @@ struct rte_logs {
#define RTE_LOGTYPE_CRYPTODEV 17 /**< Log related to cryptodev. */
#define RTE_LOGTYPE_EFD 18 /**< Log related to EFD. */
#define RTE_LOGTYPE_EVENTDEV 19 /**< Log related to eventdev. */
+#define RTE_LOGTYPE_MEMBERSHIP 20/**< Log related to membership. */
/* these log types can be used in an application */
#define RTE_LOGTYPE_USER1 24 /**< User-defined log type 1. */
diff --git a/lib/librte_membership/Makefile b/lib/librte_membership/Makefile
new file mode 100644
index 0000000..0228378
--- /dev/null
+++ b/lib/librte_membership/Makefile
@@ -0,0 +1,48 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# library name
+LIB = librte_membership.a
+
+CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
+
+EXPORT_MAP := rte_membership_version.map
+
+LIBABIVER := 2
+
+# all source are stored in SRCS-y
+SRCS-$(CONFIG_RTE_LIBRTE_MEMBERSHIP) += rte_membership.c rte_membership_ht.c rte_membership_cache.c rte_membership_bf.c rte_membership_vbf.c
+# install includes
+SYMLINK-$(CONFIG_RTE_LIBRTE_MEMBERSHIP)-include := rte_membership.h
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_membership/rte_membership.c b/lib/librte_membership/rte_membership.c
new file mode 100644
index 0000000..b1e01c6
--- /dev/null
+++ b/lib/librte_membership/rte_membership.c
@@ -0,0 +1,378 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "rte_membership.h"
+#include "rte_membership_ht.h"
+#include "rte_membership_cache.h"
+#include "rte_membership_vbf.h"
+#include "rte_membership_bf.h"
+
+
+
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_malloc.h>
+#include <rte_eal.h>
+#include <rte_eal_memconfig.h>
+#include <rte_errno.h>
+
+TAILQ_HEAD(rte_membership_list, rte_tailq_entry);
+static struct rte_tailq_elem rte_membership_tailq = {
+ .name = "RTE_MEMBERSHIP",
+};
+EAL_REGISTER_TAILQ(rte_membership_tailq)
+
+void
+rte_membership_free(void *ss)
+{
+ struct rte_membership_setsum *setsum = ss;
+ if (setsum == NULL)
+ return;
+ switch (setsum->type) {
+ case SETSUM_TYPE_HT:
+ rte_membership_free_ht(setsum);
+ break;
+ case SETSUM_TYPE_CACHE:
+ rte_membership_free_cache(setsum);
+ break;
+ case SETSUM_TYPE_BF:
+ rte_membership_free_bf(setsum);
+ break;
+ case SETSUM_TYPE_VBF:
+ rte_membership_free_vbf(setsum);
+ break;
+ default:
+ break;
+ }
+ rte_free(setsum);
+}
+
+
+void *
+rte_membership_create(const struct rte_membership_parameters *params)
+{
+ struct rte_tailq_entry *te;
+ struct rte_membership_list *membership_list = NULL;
+ struct rte_membership_setsum *setsum = NULL;
+ int ret;
+
+ if (params == NULL) {
+ return NULL;
+ }
+
+ membership_list = RTE_TAILQ_CAST(rte_membership_tailq.head,
+ rte_membership_list);
+
+ rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
+
+ TAILQ_FOREACH(te, membership_list, next) {
+ setsum = (struct rte_membership_setsum *) te->data;
+ if (strncmp(params->name, setsum->name, RTE_MEMBERSHIP_NAMESIZE) == 0)
+ break;
+ }
+ setsum = NULL;
+ if (te != NULL) {
+ rte_errno = EEXIST;
+ te = NULL;
+ goto error_unlock_exit;
+ }
+
+ te = rte_zmalloc("MEMBERSHIP_TAILQ_ENTRY", sizeof(*te), 0);
+ if (te == NULL){
+ RTE_LOG(ERR, MEMBERSHIP, "tailq entry allocation failed\n");
+ goto error_unlock_exit;
+ }
+
+
+
+ /* Create a new setsum structure */
+ setsum = (struct rte_membership_setsum *) rte_zmalloc_socket(params->name,
+ sizeof(struct rte_membership_setsum),
+ RTE_CACHE_LINE_SIZE,
+ params->socket_id);
+
+ if (setsum == NULL) {
+ RTE_LOG(ERR, MEMBERSHIP, "Create setsummary failed\n");
+ goto error_unlock_exit;
+ }
+
+ setsum->type = params->type;
+ setsum->socket_id = params->socket_id;
+ setsum->key_len = params->key_len;
+ setsum->num_target = params->num_target;
+ setsum->num_keys = params->num_keys;
+ setsum->name = params->name;
+ setsum->false_postive_rate = params->false_postive_rate;
+ setsum->prim_hash_seed = params->prim_hash_seed;
+ setsum->sec_hash_seed = params->sec_hash_seed;
+
+ switch (setsum->type) {
+ case SETSUM_TYPE_HT:
+ ret = rte_membership_create_ht(setsum);
+ break;
+ case SETSUM_TYPE_CACHE:
+ ret = rte_membership_create_cache(setsum);
+ break;
+ case SETSUM_TYPE_BF:
+ ret = rte_membership_create_bf(setsum);
+ break;
+ case SETSUM_TYPE_VBF:
+ ret = rte_membership_create_vbf(setsum);
+ break;
+ default:
+ goto error_unlock_exit;
+ }
+ if (ret < 0)
+ goto error_unlock_exit;
+
+ RTE_LOG(DEBUG, EFD, "Creating an setsummary table with mode %u\n",
+ setsum->type);
+
+ te->data = (void *)setsum;
+ TAILQ_INSERT_TAIL(membership_list, te, next);
+ rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
+ return setsum;
+
+error_unlock_exit:
+ rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
+ rte_membership_free(setsum);
+ return NULL;
+}
+
+
+int
+rte_membership_add(const void *ss, const void *key,
+ MEMBERSHIP_TARGET_TYPE target_id)
+{
+
+ const struct rte_membership_setsum *setsum = ss;
+
+ if (setsum == NULL || key == NULL)
+ return -EINVAL;
+ int ret = 0;
+ switch (setsum->type) {
+ case SETSUM_TYPE_HT:
+ ret = rte_membership_add_ht(setsum, key, target_id);
+ break;
+ case SETSUM_TYPE_CACHE:
+ ret = rte_membership_add_cache(setsum, key, target_id);
+ break;
+ case SETSUM_TYPE_BF:
+ ret = rte_membership_add_bf(setsum, key, target_id);
+ break;
+ case SETSUM_TYPE_VBF:
+ ret = rte_membership_add_vbf(setsum, key, target_id);
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+
+int
+rte_membership_lookup(const void *ss, const void *key,
+ MEMBERSHIP_TARGET_TYPE *target_id)
+{
+ const struct rte_membership_setsum *setsum = ss;
+ if (setsum == NULL || key == NULL || target_id == NULL)
+ return -EINVAL;
+
+ int ret = 0;
+ switch (setsum->type) {
+ case SETSUM_TYPE_HT:
+ ret = rte_membership_lookup_ht(setsum, key, target_id);
+ break;
+ case SETSUM_TYPE_CACHE:
+ ret = rte_membership_lookup_cache(setsum, key, target_id);
+ break;
+ case SETSUM_TYPE_BF:
+ ret = rte_membership_lookup_bf(setsum, key, target_id);
+ break;
+ case SETSUM_TYPE_VBF:
+ ret = rte_membership_lookup_vbf(setsum, key, target_id);
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+
+int
+rte_membership_lookup_bulk(const void *ss, const void **keys, uint32_t num_keys,
+ MEMBERSHIP_TARGET_TYPE *target_ids)
+{
+ const struct rte_membership_setsum *setsum = ss;
+ if (setsum == NULL || keys == NULL || target_ids == NULL)
+ return -EINVAL;
+
+ int ret = 0;
+ switch (setsum->type) {
+ case SETSUM_TYPE_HT:
+ ret = rte_membership_lookup_bulk_ht(setsum, keys, num_keys,
+ target_ids);
+ break;
+ case SETSUM_TYPE_CACHE:
+ ret = rte_membership_lookup_bulk_cache(setsum, keys, num_keys,
+ target_ids);
+ break;
+ case SETSUM_TYPE_BF:
+ ret = rte_membership_lookup_bulk_bf(setsum, keys, num_keys,
+ target_ids);
+ break;
+ case SETSUM_TYPE_VBF:
+ ret = rte_membership_lookup_bulk_vbf(setsum, keys, num_keys,
+ target_ids);
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+int
+rte_membership_lookup_multi(const void *ss, const void *key,
+ MEMBERSHIP_TARGET_TYPE *target_id)
+{
+ const struct rte_membership_setsum *setsum = ss;
+ if (setsum == NULL || key == NULL || target_id == NULL)
+ return -EINVAL;
+ int ret=0;
+ switch (setsum->type) {
+ case SETSUM_TYPE_HT:
+ ret = rte_membership_lookup_multi_ht(setsum, key, target_id);
+ break;
+ case SETSUM_TYPE_CACHE:
+ ret = rte_membership_lookup_multi_cache(setsum, key, target_id);
+ break;
+ case SETSUM_TYPE_BF:
+ ret = rte_membership_lookup_multi_bf(setsum, key, target_id);
+ break;
+ case SETSUM_TYPE_VBF:
+ ret = rte_membership_lookup_multi_vbf(setsum, key, target_id);
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+
+int
+rte_membership_lookup_multi_bulk(const void *ss, const void **keys,
+ uint32_t num_keys, uint32_t max_match_per_key, uint32_t *match_count,
+ MEMBERSHIP_TARGET_TYPE *target_ids)
+{
+ const struct rte_membership_setsum *setsum = ss;
+ if (setsum == NULL || keys == NULL || target_ids == NULL ||
+ match_count == NULL)
+ return -EINVAL;
+ int ret = 0;
+ switch (setsum->type) {
+ case SETSUM_TYPE_HT:
+ ret = rte_membership_lookup_multi_bulk_ht(setsum, keys, num_keys,
+ max_match_per_key, match_count, target_ids);
+ break;
+ case SETSUM_TYPE_CACHE:
+ ret = rte_membership_lookup_multi_bulk_cache(setsum, keys, num_keys,
+ max_match_per_key, match_count, target_ids);
+ break;
+ case SETSUM_TYPE_BF:
+ ret = rte_membership_lookup_multi_bulk_bf(setsum, keys, num_keys,
+ max_match_per_key, match_count, target_ids);
+ break;
+ case SETSUM_TYPE_VBF:
+ ret = rte_membership_lookup_multi_bulk_vbf(setsum, keys, num_keys,
+ max_match_per_key, match_count, target_ids);
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+
+int
+rte_membership_delete(void *ss, const void *key,
+ MEMBERSHIP_TARGET_TYPE target_id)
+{
+ struct rte_membership_setsum *setsum = ss;
+ if (setsum == NULL || key == NULL)
+ return -EINVAL;
+ int ret = 0;
+ switch (setsum->type) {
+ case SETSUM_TYPE_HT:
+ ret = rte_membership_delete_ht(setsum, key, target_id);
+ break;
+ case SETSUM_TYPE_CACHE:
+ ret = rte_membership_delete_cache(setsum, key, target_id);
+ break;
+ case SETSUM_TYPE_BF:
+ case SETSUM_TYPE_VBF:
+ default:
+ return -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+
+void
+rte_membership_reset(const void *ss)
+{
+ const struct rte_membership_setsum *setsum = ss;
+ if (setsum == NULL)
+ return;
+ switch (setsum->type) {
+ case SETSUM_TYPE_HT:
+ rte_membership_reset_ht(setsum);
+ break;
+ case SETSUM_TYPE_CACHE:
+ rte_membership_reset_cache(setsum);
+ break;
+ case SETSUM_TYPE_BF:
+ rte_membership_reset_bf(setsum);
+ break;
+ case SETSUM_TYPE_VBF:
+ rte_membership_reset_vbf(setsum);
+ break;
+ default:
+ break;
+ }
+}
\ No newline at end of file
diff --git a/lib/librte_membership/rte_membership.h b/lib/librte_membership/rte_membership.h
new file mode 100644
index 0000000..abe2c12
--- /dev/null
+++ b/lib/librte_membership/rte_membership.h
@@ -0,0 +1,321 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+
+/**
+ * @file
+ * RTE Membership Library
+ *
+ * The membership library provides structures serving as set summaries of sets.
+ * There are in total four modes are provided: bloom filter (BF), vector bloom
+ * filter (vBF), cache, and hash table-based (HT) modes.
+ *
+ * Each of the mode has different behaviors but they all can be used to test keys
+ * for their memberships of one or more sets. Detailed behavior of each mode
+ * please refer to the API document.
+ */
+
+
+
+#ifndef _RTE_MEMBERSHIP_H_
+#define _RTE_MEMBERSHIP_H_
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <stdio.h>
+#include <stdint.h>
+#include <rte_jhash.h>
+
+/* The maximum set count is 2^16-1 (we reserve 0 for invalid target) */
+typedef uint16_t MEMBERSHIP_TARGET_TYPE;
+/* Invalid or empty set ID uses 0 */
+#define RTE_MEMBERSHIP_NO_MATCH 0
+#define RTE_MEMBERSHIP_LOOKUP_BULK_MAX 16
+#define MEMBERSHIP_MAX_PUSHES 100
+
+#define MEMBERSHIP_BUCKET_ENTRIES 16
+
+
+
+/* Maximum number of characters in setsum name. */
+#define RTE_MEMBERSHIP_NAMESIZE 32
+
+/* This bit is used to choose which bucket to replace entry */
+#define MEMBERSHIP_EVICT_CHOOSE (1 << MEMBERSHIP_BUCKET_ENTRIES)
+
+#define MEMBERSHIP_PRIM_HASH(key, key_len, seed) \
+ (uint32_t)(rte_jhash(key, key_len, seed))
+
+#define MEMBERSHIP_SEC_HASH(key, key_len, seed) \
+ (uint32_t)(rte_jhash(key, key_len, seed))
+
+
+typedef uint16_t SIG_TYPE; /* signature size is 16 bit */
+#define SIG_BITMASK 0xffff /* signature mask, 16 bit */
+
+struct rte_membership_setsum;
+struct rte_membership_parameters;
+
+
+/* All different types of set summaries */
+enum rte_membership_setsum_type {
+ SETSUM_TYPE_HT = 0,
+ SETSUM_TYPE_CACHE,
+ SETSUM_TYPE_BF,
+ SETSUM_TYPE_VBF
+};
+
+
+
+struct rte_membership_setsum {
+ enum rte_membership_setsum_type type;
+ const char *name;
+ uint32_t key_len;
+ /* cache is only relevant to HT based set summary */
+ uint32_t num_keys;
+ /* num_target and false_postive_rate only relevant to BF based set summary */
+ uint32_t num_target;
+ float false_postive_rate;
+
+ uint32_t prim_hash_seed;
+ uint32_t sec_hash_seed;
+
+ int socket_id;
+
+ void *ss;
+};
+
+
+/**
+ * Parameters used when creating the set summary table.
+ */
+struct rte_membership_parameters {
+ const char *name; /* Name of the hash. */
+ enum rte_membership_setsum_type type;
+ uint32_t num_keys; /* Total hash table entries. */
+ uint32_t key_len; /* Length of hash key. */
+
+ /* num_target and false_postive_rate only relevant with BF based set summary */
+ uint32_t num_target;
+ float false_postive_rate;
+
+ uint32_t prim_hash_seed;
+ uint32_t sec_hash_seed;
+
+ int socket_id; /* NUMA Socket ID for memory. */
+};
+
+
+
+/**
+ * Create setsummary (SS) table
+ *
+ * @param params
+ * parameters to initialize the setsummary.
+ * @return
+ * return the pointer to the setsummary.
+ * return value is NULL if the creation failed.
+ */
+
+void *
+rte_membership_create(const struct rte_membership_parameters *params);
+
+
+
+/**
+ * Lookup key in setsummary (SS) table
+ * Single key lookup and return as soon as the first match found
+ * @param setsum
+ * pointer of a setsummary table
+ * @param key
+ * pointer of the key that needs to lookup
+ * @param target_id
+ * returned target set id.
+ * @return
+ * return 1 for found a match and 0 for not found a match
+ */
+
+int
+rte_membership_lookup(const void *setsum,
+ const void *key, MEMBERSHIP_TARGET_TYPE *target_id);
+
+
+/**
+ * lookup bulk of keys in setsummary (SS) table
+ * Each key lookup returns as soon as the first match found
+ * @param setsum
+ * Pointer of a setsummary table
+ * @param keys
+ * Pointer of bulk of keys that to be lookup
+ * @param num_keys
+ * Number of keys that will be lookup
+ * @param target_ids
+ * Return target ids for all the keys to the array.
+ * User should preallocate array that can contain the maximum possible number
+ * of matches.
+ * @return
+ * The number of keys that find a match.
+ */
+
+
+int
+rte_membership_lookup_bulk(const void *setsum,
+ const void **keys, uint32_t num_keys, MEMBERSHIP_TARGET_TYPE *target_ids);
+
+
+
+
+/**
+ * Lookup a key in setsummary (SS) table for multiple matches
+ * The key lookup will find all matched entries (multiple match)
+ * This is for VBF and HT modes of setsummaries.
+ * @param setsum
+ * pointer of a setsummary struct
+ * @param key
+ * The key that to be lookup
+ * @param target_id
+ * returned target ids for all the matches of the key
+ * @return
+ * The number of matches that found for the key.
+ * For BF and Cache mode, the number should be at most 1
+ */
+
+int
+rte_membership_lookup_multi(const void *setsum,
+ const void *key, MEMBERSHIP_TARGET_TYPE *target_id);
+
+
+
+
+/**
+ * Lookup a bulk of keys in setsummary (SS) table for multiple matches
+ * Each key lookup will find all matched entries (multiple match)
+ * This is for VBF and HT type of setsummaries.
+ * @param setsum
+ * pointer of a setsummary struct
+ * @param keys
+ * The keys that to be lookup
+ * @param num_keys
+ * The number of keys that will be lookup
+ * @param max_match_per_key
+ * The possible max number of matches for each key.
+ * @param match_count
+ * The number of match for all the keys.
+ * @param target_ids
+ * Return target ids for all the matches of all keys
+ * @return
+ * The number of keys that find one or more matches in the table.
+ */
+
+int
+rte_membership_lookup_multi_bulk(const void *setsum,
+ const void **keys, uint32_t num_keys, uint32_t max_match_per_key,
+ uint32_t *match_count,
+ MEMBERSHIP_TARGET_TYPE *target_ids);
+
+/**
+ * Insert key to setsummary (SS) table
+ *
+ * @param setsum
+ * pointer of a setsummary table
+ * @param key
+ * the key that needs to be added
+ * @param target_id
+ * The target id associated with the key that needs to be added.
+ * Note that for BF mode the target id should no larger than 1.
+ * @return
+ * Return error code if fail.
+ * For success we return different value for different mode for providing
+ * extra information for the users.
+ * Return 0 for BF. Return 0 for Cache mode if the add does not cause
+ * eviction, return 1 otherwise. Return the index of the inserted entry of the
+ * bucket for HT mode. Return 0 for vBF mode.
+ */
+
+int
+rte_membership_add(const void *setsum, const void *key,
+ MEMBERSHIP_TARGET_TYPE target_id);
+
+
+/**
+ * De-allocate all memory used by set summary table
+ * @param setsum
+ * Pointer to the set summary
+ */
+void
+rte_membership_free(void *setsum);
+
+
+
+/**
+ * Reset the setsummary tables. E.g. reset bits to be 0 in BF,
+ * reset target_id in each entry to be no_match
+ * @param setsum
+ * Pointer to the set summary
+ */
+void
+rte_membership_reset(const void *setsum);
+
+
+
+
+/**
+ * Detele items from the set summary
+ * @param setsum
+ * Pointer to the set summary.
+ * @param key
+ * The key to be deleted.
+ * @param target_id
+ * For HT or VBF type of setsummary, we pass this argument to only delete
+ * keys with certain target_id.
+ * @return
+ * If no entry found to delete, an error code could be returned.
+ */
+
+int
+rte_membership_delete(void *setsum, const void *key,
+ MEMBERSHIP_TARGET_TYPE target_id);
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_MEMBERSHIP_H_ */
\ No newline at end of file
diff --git a/lib/librte_membership/rte_membership_bf.c b/lib/librte_membership/rte_membership_bf.c
new file mode 100644
index 0000000..bf3de11
--- /dev/null
+++ b/lib/librte_membership/rte_membership_bf.c
@@ -0,0 +1,254 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) 2012, Jyri J. Virkki
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+ *Some of the code is modified from Jyri's libbloom library
+ *(https://github.com/jvirkki/libbloom) which is under BSD license
+ */
+
+#include "rte_membership.h"
+#include "rte_membership_bf.h"
+#include <math.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+
+#include <rte_bitmap.h>
+#include <rte_malloc.h>
+#include <rte_memory.h>
+
+
+
+struct rte_membership_bf *
+__membership_create_bf(const struct rte_membership_setsum *ss)
+{
+
+ struct rte_membership_bf *bloom;
+ double num;
+ double denom = 0.480453013918201; /* ln(2)^2 */
+ double dentries;
+ uint32_t bmp_mem_size;
+
+
+ if (ss->num_keys < 1 || ss->false_postive_rate == 0) {
+ return NULL;
+ }
+ bloom = rte_zmalloc_socket(NULL, sizeof(struct rte_membership_bf),
+ RTE_CACHE_LINE_SIZE, ss->socket_id);
+ if (bloom == NULL) {
+ RTE_LOG(ERR, EAL, "Bitmap init error\n");
+ return NULL;
+ }
+ bloom->entries = ss->num_keys;
+ bloom->error = ss->false_postive_rate;
+ num = log(bloom->error);
+
+ bloom->bpe = -(num / denom);
+
+ dentries = (double)(bloom->entries);
+ bloom->bits = rte_align32pow2((int)(dentries * bloom->bpe));
+ bloom->bucket_bitmask = bloom->bits - 1;
+
+ bloom->num_hashes = (int)ceil(0.693147180559945 * bloom->bpe); /* ln(2) */
+
+ bmp_mem_size = rte_bitmap_get_memory_footprint(bloom->bits);
+
+ bloom->bmp_array = rte_zmalloc(NULL, bmp_mem_size, RTE_CACHE_LINE_SIZE);
+ if (bloom->bmp_array == NULL) {
+ rte_free(bloom);
+ return NULL;
+ }
+
+ bloom->bmp = rte_bitmap_init(bloom->bits, bloom->bmp_array, bmp_mem_size);
+ if (bloom->bmp == NULL) {
+ RTE_LOG(ERR, EAL, "Bitmap init error\n");
+ rte_free(bloom->bmp_array);
+ rte_free(bloom);
+ return NULL;
+ }
+ return bloom;
+}
+
+
+
+int
+rte_membership_create_bf(struct rte_membership_setsum *setsum)
+{
+ struct rte_membership_bf *bloom =
+ __membership_create_bf((const struct rte_membership_setsum *)setsum);
+
+ if(bloom != NULL)
+ setsum->ss = bloom;
+ else
+ return -ENOMEM;
+ return 0;
+}
+
+
+int
+rte_membership_lookup_bf(const struct rte_membership_setsum *setsum,
+ const void *key, MEMBERSHIP_TARGET_TYPE *target_id)
+{
+ struct rte_membership_bf *bloom = setsum->ss;
+ uint32_t key_len = setsum->key_len;
+ uint32_t prim_hash_seed = setsum->prim_hash_seed;
+ uint32_t sec_hash_seed = setsum->sec_hash_seed;
+ uint32_t a = MEMBERSHIP_PRIM_HASH(key, key_len, prim_hash_seed);
+ uint32_t b = MEMBERSHIP_SEC_HASH(key, key_len, sec_hash_seed);
+ uint32_t x;
+ uint32_t i;
+
+ struct rte_bitmap *bmp = bloom->bmp;
+
+ for (i = 0; i < bloom->num_hashes; i++) {
+ x = (a + i*b) & bloom->bucket_bitmask;
+ if (rte_bitmap_get(bmp, x) == 0) {
+ return 0;
+ }
+ }
+ *target_id = 1;
+ return 1;
+}
+
+
+int
+rte_membership_lookup_multi_bf(const struct rte_membership_setsum *setsum,
+ const void *key, MEMBERSHIP_TARGET_TYPE *target_id)
+{
+ int ret = rte_membership_lookup_bf(setsum, key, target_id);
+ return ret;
+}
+
+
+int
+rte_membership_lookup_bulk_bf(const struct rte_membership_setsum* setsum,
+ const void** keys, uint32_t num_keys, MEMBERSHIP_TARGET_TYPE* target_id)
+{
+ struct rte_membership_bf* bloom = setsum->ss;
+ uint32_t key_len = setsum->key_len;
+ uint32_t prim_hash_seed = setsum->prim_hash_seed;
+ uint32_t sec_hash_seed = setsum->sec_hash_seed;
+
+ uint32_t i, j;
+ uint32_t x, a, b;
+ int ret = 0;
+ struct rte_bitmap *bmp = bloom->bmp;
+ for (i = 0; i < num_keys; i++) {
+ a = MEMBERSHIP_PRIM_HASH(keys[i], key_len, prim_hash_seed);
+ b = MEMBERSHIP_SEC_HASH(keys[i], key_len, sec_hash_seed);
+ for (j = 0; j < bloom->num_hashes; j++) {
+ x = (a + j * b) & bloom->bucket_bitmask;
+ if (rte_bitmap_get(bmp, x) == 0) {
+ target_id[i] = RTE_MEMBERSHIP_NO_MATCH;
+ break;
+ }
+ }
+ if (j == bloom->num_hashes) {
+ target_id[i] = 1;
+ ret++;
+ }
+ }
+ return ret;
+}
+
+int
+rte_membership_lookup_multi_bulk_bf(const struct rte_membership_setsum *setsum,
+ const void **keys, uint32_t num_keys, uint32_t match_per_key,
+ uint32_t *match_count, MEMBERSHIP_TARGET_TYPE *target_ids)
+{
+
+ int ret;
+ uint32_t i;
+ MEMBERSHIP_TARGET_TYPE target_id[num_keys];
+ ret = rte_membership_lookup_bulk_bf(setsum, keys, num_keys, target_id);
+ for (i = 0; i < num_keys; i++) {
+ if (target_id[i] != RTE_MEMBERSHIP_NO_MATCH) {
+ match_count[i] = 1;
+ target_ids[i*match_per_key]= target_id[i];
+ }
+ else {
+ match_count[i] = 0;
+ }
+ }
+ return ret;
+}
+
+int
+rte_membership_add_bf(const struct rte_membership_setsum *setsum,
+ const void *key, MEMBERSHIP_TARGET_TYPE target_id)
+{
+ /* bloomfilter only allows 1 bit target, hit or not since only 1 set */
+ if (target_id > 1)
+ return -EINVAL;
+ struct rte_membership_bf *bloom = setsum->ss;
+ uint32_t key_len = setsum->key_len;
+ uint32_t prim_hash_seed = setsum->prim_hash_seed;
+ uint32_t sec_hash_seed = setsum->sec_hash_seed;
+ uint32_t a = MEMBERSHIP_PRIM_HASH(key, key_len, prim_hash_seed);
+ uint32_t b = MEMBERSHIP_SEC_HASH(key, key_len, sec_hash_seed);
+ uint32_t x;
+ uint32_t i;
+
+ struct rte_bitmap *bmp = bloom->bmp;
+
+ for (i = 0; i < bloom->num_hashes; i++) {
+ x = (a + i * b) & bloom->bucket_bitmask;
+ rte_bitmap_set(bmp, x);
+ }
+ return 0;
+}
+
+
+void
+rte_membership_free_bf(struct rte_membership_setsum *setsum)
+{
+ struct rte_membership_bf *bloom = setsum->ss;
+ if (bloom != NULL) {
+ rte_free(bloom->bmp_array);
+ rte_free(bloom);
+ }
+}
+
+
+void
+rte_membership_reset_bf(const struct rte_membership_setsum *setsum)
+{
+ struct rte_membership_bf *bloom = setsum->ss;
+ if (bloom != NULL) {
+ rte_bitmap_reset(bloom->bmp_array);
+ }
+
+}
\ No newline at end of file
diff --git a/lib/librte_membership/rte_membership_bf.h b/lib/librte_membership/rte_membership_bf.h
new file mode 100644
index 0000000..fdafd0d
--- /dev/null
+++ b/lib/librte_membership/rte_membership_bf.h
@@ -0,0 +1,99 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_MEMBERSHIP_BF_H_
+#define _RTE_MEMBERSHIP_BF_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_bitmap.h>
+
+struct rte_membership_bf
+{
+ int entries; /* number of entries expected to store in filter */
+ double error; /* expected false positive rate */
+ double bpe; /* theoretical bit per entry */
+ unsigned bits; /* actual number of bits allocated (rounded to 2pow) */
+ unsigned num_hashes; /* number of hash functions needed (optimal) */
+
+ unsigned bucket_bitmask;
+
+ void *bmp_array; /* memory chunk holding bmp */
+ struct rte_bitmap *bmp;
+};
+
+
+struct rte_membership_bf *
+__membership_create_bf(const struct rte_membership_setsum *ss);
+
+int
+rte_membership_create_bf(struct rte_membership_setsum *ss);
+
+int
+rte_membership_lookup_bf(const struct rte_membership_setsum *setsum,
+ const void *key, MEMBERSHIP_TARGET_TYPE* target_id);
+
+int
+rte_membership_lookup_multi_bf(const struct rte_membership_setsum *setsum,
+ const void *key, MEMBERSHIP_TARGET_TYPE *target_id);
+
+
+int
+rte_membership_lookup_bulk_bf(const struct rte_membership_setsum *setsum,
+ const void **key, uint32_t num_keys, MEMBERSHIP_TARGET_TYPE *target_id);
+
+
+int
+rte_membership_lookup_multi_bulk_bf(const struct rte_membership_setsum *setsum,
+ const void **keys, uint32_t num_keys, uint32_t match_per_key,
+ uint32_t *match_count,
+ MEMBERSHIP_TARGET_TYPE *target_ids);
+
+int
+rte_membership_add_bf(const struct rte_membership_setsum *setsum,
+ const void *key, MEMBERSHIP_TARGET_TYPE target_id);
+
+
+void
+rte_membership_free_bf(struct rte_membership_setsum *ss);
+
+
+void
+rte_membership_reset_bf(const struct rte_membership_setsum *setsum);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _RTE_MEMBERSHIP_BF_H_ */
diff --git a/lib/librte_membership/rte_membership_cache.c b/lib/librte_membership/rte_membership_cache.c
new file mode 100644
index 0000000..f048bca
--- /dev/null
+++ b/lib/librte_membership/rte_membership_cache.c
@@ -0,0 +1,345 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "rte_membership.h"
+#include "rte_membership_cache.h"
+
+#include <rte_errno.h>
+#include <rte_malloc.h>
+#include <rte_prefetch.h>
+#include <rte_random.h>
+
+
+/* The bucket struct for cuckoo distributor*/
+struct membership_cache_bucket {
+ SIG_TYPE sigs[MEMBERSHIP_BUCKET_ENTRIES]; /*2-byte signature*/
+ MEMBERSHIP_TARGET_TYPE targets[MEMBERSHIP_BUCKET_ENTRIES];/*2-byte target*/
+} __attribute__ ((packed));
+
+
+struct membership_cache_ss {
+ struct membership_cache_bucket* buckets; /*buckets array*/
+ uint32_t bucket_cnt;
+ uint32_t bucket_mask;
+};
+
+
+
+int
+rte_membership_create_cache(struct rte_membership_setsum *ss){
+ uint32_t i, j;
+ const uint32_t num_buckets = rte_align32pow2(ss->num_keys) /
+ MEMBERSHIP_BUCKET_ENTRIES;
+ struct membership_cache_ss* t;
+
+ t = (struct membership_cache_ss *)rte_zmalloc_socket(NULL,
+ sizeof(struct membership_cache_ss),
+ RTE_CACHE_LINE_SIZE, ss->socket_id);
+
+
+ struct membership_cache_bucket* buckets = rte_zmalloc_socket(NULL,
+ num_buckets * sizeof(struct membership_cache_bucket),
+ RTE_CACHE_LINE_SIZE, ss->socket_id);
+
+ t->buckets = buckets;
+ t->bucket_cnt=num_buckets;
+ t->bucket_mask = num_buckets - 1;
+ ss->ss = t;
+
+ for( i=0; i<num_buckets; i++){
+ for( j=0; j<MEMBERSHIP_BUCKET_ENTRIES; j++){
+ buckets[i].targets[j]=RTE_MEMBERSHIP_NO_MATCH;
+ }
+ }
+ return 0;
+}
+
+
+int
+rte_membership_lookup_cache(const struct rte_membership_setsum *setsum,
+ const void *key, MEMBERSHIP_TARGET_TYPE *target_id)
+{
+
+ int32_t i;
+ struct membership_cache_ss* ht = setsum->ss;
+ uint32_t prim_hash_seed = setsum->prim_hash_seed;
+ uint32_t sec_hash_seed = setsum->sec_hash_seed;
+ uint32_t bucket_mask = ht->bucket_mask;
+ struct membership_cache_bucket* buckets = ht->buckets;
+ uint32_t key_len = setsum->key_len;
+
+
+ SIG_TYPE tmp_sig = MEMBERSHIP_PRIM_HASH(key, key_len, prim_hash_seed) &
+ SIG_BITMASK;
+
+ uint32_t hash_val = MEMBERSHIP_SEC_HASH(key, key_len, sec_hash_seed);
+ uint32_t prim_bucket = hash_val & bucket_mask;
+ uint32_t sec_bucket = (hash_val >> 16) & bucket_mask;
+
+
+ for (i = 0; i < MEMBERSHIP_BUCKET_ENTRIES; i++) {
+ if(tmp_sig == buckets[prim_bucket].sigs[i] &&
+ buckets[prim_bucket].targets[i] != RTE_MEMBERSHIP_NO_MATCH) {
+ *target_id = buckets[prim_bucket].targets[i];
+ return 1;
+ }
+ }
+ for (i = 0; i < MEMBERSHIP_BUCKET_ENTRIES; i++) {
+ if(tmp_sig == buckets[sec_bucket].sigs[i] &&
+ buckets[sec_bucket].targets[i] != RTE_MEMBERSHIP_NO_MATCH) {
+ *target_id = buckets[sec_bucket].targets[i];
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+rte_membership_lookup_multi_cache(const struct rte_membership_setsum* setsum,
+ const void* key, MEMBERSHIP_TARGET_TYPE* target_id)
+{
+
+ int ret = rte_membership_lookup_cache(setsum, key, target_id);
+ return ret;
+}
+
+
+
+
+int
+rte_membership_lookup_bulk_cache(const struct rte_membership_setsum *setsum,
+ const void **keys, uint32_t num_keys, MEMBERSHIP_TARGET_TYPE *target_id)
+{
+ uint32_t i,j;
+ int ret = 0;
+ struct membership_cache_ss* ht = setsum->ss;
+ uint32_t prim_hash_seed = setsum->prim_hash_seed;
+ uint32_t sec_hash_seed = setsum->sec_hash_seed;
+ uint32_t bucket_mask = ht->bucket_mask;
+ struct membership_cache_bucket* buckets = ht->buckets;
+ uint32_t key_len = setsum->key_len;
+
+ SIG_TYPE tmp_sig[RTE_MEMBERSHIP_LOOKUP_BULK_MAX];
+ const struct membership_cache_bucket*
+ prim_buckets[RTE_MEMBERSHIP_LOOKUP_BULK_MAX];
+ const struct membership_cache_bucket*
+ sec_buckets[RTE_MEMBERSHIP_LOOKUP_BULK_MAX];
+
+ for( i=0; i<num_keys; i++){
+ tmp_sig[i] = MEMBERSHIP_PRIM_HASH(keys[i], key_len, prim_hash_seed) &
+ SIG_BITMASK;
+ uint32_t hash_val = MEMBERSHIP_SEC_HASH(keys[i], key_len, sec_hash_seed);
+ uint32_t prim_bucket = hash_val & bucket_mask;
+ uint32_t sec_bucket = (hash_val >> 16) & bucket_mask;
+ prim_buckets[i] = &buckets[prim_bucket];
+ sec_buckets[i] = &buckets[sec_bucket];
+ rte_prefetch0(prim_buckets[i]);
+ rte_prefetch0(sec_buckets[i]);
+ }
+
+
+ for (i = 0; i < num_keys; i++ ) {
+ for (j = 0; j < MEMBERSHIP_BUCKET_ENTRIES; j++) {
+ if(tmp_sig[i] == prim_buckets[i]->sigs[j] &&
+ prim_buckets[i]->targets[j] != RTE_MEMBERSHIP_NO_MATCH) {
+ target_id[i] = prim_buckets[i]->targets[j];
+ ret++;
+ break;
+ }
+ }
+
+ if (j == MEMBERSHIP_BUCKET_ENTRIES) {
+ for (j = 0; j < MEMBERSHIP_BUCKET_ENTRIES; j++) {
+ if(tmp_sig[i] == sec_buckets[i]->sigs[j] &&
+ sec_buckets[i]->targets[j] != RTE_MEMBERSHIP_NO_MATCH) {
+ target_id[i] = sec_buckets[i]->targets[j];
+ ret++;
+ break;
+ }
+ }
+ }
+ if (j == MEMBERSHIP_BUCKET_ENTRIES) {
+ target_id[i] = RTE_MEMBERSHIP_NO_MATCH;
+ }
+ }
+ return ret;
+}
+
+
+int
+rte_membership_lookup_multi_bulk_cache(const struct rte_membership_setsum *setsum,
+ const void **keys, uint32_t num_keys, uint32_t match_per_key,
+ uint32_t *match_count, MEMBERSHIP_TARGET_TYPE *target_ids)
+{
+ int ret;
+ uint32_t i;
+ MEMBERSHIP_TARGET_TYPE target_id[num_keys];
+ ret = rte_membership_lookup_bulk_cache(setsum, keys, num_keys, target_id);
+ for (i = 0; i < num_keys; i++) {
+ if (target_id[i] != RTE_MEMBERSHIP_NO_MATCH) {
+ match_count[i] = 1;
+ target_ids[i*match_per_key] = target_id[i];
+ }
+ else {
+ match_count[i] = 0;
+ }
+ }
+ return ret;
+}
+
+
+
+int
+rte_membership_add_cache(const struct rte_membership_setsum *setsum,
+ const void *key, MEMBERSHIP_TARGET_TYPE target_id)
+{
+ int i;
+ struct membership_cache_ss* ht = setsum->ss;
+ uint32_t prim_hash_seed = setsum->prim_hash_seed;
+ uint32_t sec_hash_seed = setsum->sec_hash_seed;
+ uint32_t bucket_mask = ht->bucket_mask;
+ struct membership_cache_bucket* buckets = ht->buckets;
+ uint32_t key_len = setsum->key_len;
+
+ SIG_TYPE tmp_sig = MEMBERSHIP_PRIM_HASH(key, key_len, prim_hash_seed) &
+ SIG_BITMASK;
+
+ uint32_t hash_val = MEMBERSHIP_SEC_HASH(key, key_len, sec_hash_seed);
+ uint32_t prim_bucket = hash_val & bucket_mask;
+ uint32_t sec_bucket = (hash_val >> 16) & bucket_mask;
+
+ /* Check if the signature already in the two buckets */
+
+ for (i = 0; i < MEMBERSHIP_BUCKET_ENTRIES; i++) {
+ if (buckets[prim_bucket].sigs[i] == tmp_sig) {
+ buckets[prim_bucket].targets[i] = target_id;
+ return 0;
+ }
+ if (buckets[sec_bucket].sigs[i] == tmp_sig) {
+ buckets[sec_bucket].targets[i] = target_id;
+ return 0;
+ }
+ }
+
+
+ /* If not then insert into one slot (prefer empty slot) */
+ for (i = 0; i < MEMBERSHIP_BUCKET_ENTRIES; i++) {
+ if(buckets[prim_bucket].targets[i] == RTE_MEMBERSHIP_NO_MATCH){
+ buckets[prim_bucket].sigs[i] = tmp_sig;
+ buckets[prim_bucket].targets[i] = target_id;
+ return 0;
+ }
+ }
+
+ /* Primary location full */
+
+ for (i = 0; i < MEMBERSHIP_BUCKET_ENTRIES; i++) {
+ if(buckets[sec_bucket].targets[i] == RTE_MEMBERSHIP_NO_MATCH){
+ buckets[sec_bucket].sigs[i] = tmp_sig;
+ buckets[sec_bucket].targets[i] = target_id;
+ return 0;
+ }
+ }
+
+ /* Then we should evict someone. */
+ /* currently it is a random eviction policy */
+
+ uint64_t random = rte_rand();
+ uint32_t evict_idx = random & (MEMBERSHIP_BUCKET_ENTRIES-1);
+ uint32_t bucket_choose = prim_bucket;
+
+ if (random & MEMBERSHIP_EVICT_CHOOSE) {
+ bucket_choose = sec_bucket;
+ }
+
+ buckets[bucket_choose].sigs[evict_idx] = tmp_sig;
+ buckets[bucket_choose].targets[evict_idx] = target_id;
+ return 1;
+}
+
+
+void
+rte_membership_free_cache(struct rte_membership_setsum* setsum){
+ rte_free(setsum->ss);
+}
+
+
+int
+rte_membership_delete_cache(struct rte_membership_setsum* setsum,
+ const void* key, MEMBERSHIP_TARGET_TYPE target_id)
+{
+ (void)target_id;
+ int i;
+ struct membership_cache_ss* ht = setsum->ss;
+ uint32_t prim_hash_seed = setsum->prim_hash_seed;
+ uint32_t sec_hash_seed = setsum->sec_hash_seed;
+ uint32_t bucket_mask = ht->bucket_mask;
+ struct membership_cache_bucket* buckets = ht->buckets;
+ uint32_t key_len = setsum->key_len;
+
+ SIG_TYPE tmp_sig = MEMBERSHIP_PRIM_HASH(key, key_len, prim_hash_seed) &
+ SIG_BITMASK;
+
+
+ uint32_t hash_val = MEMBERSHIP_SEC_HASH(key, key_len, sec_hash_seed);
+ uint32_t prim_bucket = hash_val & bucket_mask;
+ uint32_t sec_bucket = (prim_bucket ^ tmp_sig) & bucket_mask;
+
+ for (i = 0; i < MEMBERSHIP_BUCKET_ENTRIES; i++) {
+ if(tmp_sig == buckets[prim_bucket].sigs[i]) {
+ buckets[prim_bucket].targets[i] = RTE_MEMBERSHIP_NO_MATCH;
+ return 0;
+ }
+ }
+
+ for (i = 0; i < MEMBERSHIP_BUCKET_ENTRIES; i++) {
+ if (tmp_sig == buckets[sec_bucket].sigs[i]) {
+ buckets[sec_bucket].targets[i] = RTE_MEMBERSHIP_NO_MATCH;
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+void
+rte_membership_reset_cache(const struct rte_membership_setsum *setsum)
+{
+ uint32_t i, j;
+ struct membership_cache_ss* ht = setsum->ss;
+ /* FIXME: low efficient */
+ for (i=0; i<ht->bucket_cnt; i++) {
+ for (j=0; j<MEMBERSHIP_BUCKET_ENTRIES; j++) {
+ ht->buckets[i].targets[j]=RTE_MEMBERSHIP_NO_MATCH;
+ }
+ }
+}
\ No newline at end of file
diff --git a/lib/librte_membership/rte_membership_cache.h b/lib/librte_membership/rte_membership_cache.h
new file mode 100644
index 0000000..8e262ff
--- /dev/null
+++ b/lib/librte_membership/rte_membership_cache.h
@@ -0,0 +1,95 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_MEMBERSHIP_CACHE_H_
+#define _RTE_MEMBERSHIP_CACHE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int
+rte_membership_create_cache(struct rte_membership_setsum* ss);
+
+
+int
+rte_membership_lookup_cache(const struct rte_membership_setsum* setsum,
+ const void* key, MEMBERSHIP_TARGET_TYPE* target_id);
+
+
+int
+rte_membership_lookup_multi_cache(const struct rte_membership_setsum* setsum,
+ const void* key, MEMBERSHIP_TARGET_TYPE* target_id);
+
+
+int
+rte_membership_lookup_bulk_cache(const struct rte_membership_setsum *setsum,
+ const void **keys, uint32_t num_keys,
+ MEMBERSHIP_TARGET_TYPE* target_ids);
+
+
+
+int
+rte_membership_lookup_multi_bulk_cache(const struct rte_membership_setsum* setsum,
+ const void **keys, uint32_t num_keys, uint32_t match_per_key,
+ uint32_t *match_count, MEMBERSHIP_TARGET_TYPE *target_ids);
+
+
+
+int
+rte_membership_add_cache(const struct rte_membership_setsum* setsum,
+ const void* key, MEMBERSHIP_TARGET_TYPE target_id);
+
+void
+rte_membership_free_cache(struct rte_membership_setsum* setsum);
+
+
+
+
+int
+rte_membership_delete_cache(struct rte_membership_setsum* ss, const void* key,
+ MEMBERSHIP_TARGET_TYPE target_id);
+
+
+
+void
+rte_membership_reset_cache(const struct rte_membership_setsum *setsum);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _RTE_MEMBERSHIP_CACHE_H_ */
diff --git a/lib/librte_membership/rte_membership_ht.c b/lib/librte_membership/rte_membership_ht.c
new file mode 100644
index 0000000..980374f
--- /dev/null
+++ b/lib/librte_membership/rte_membership_ht.c
@@ -0,0 +1,471 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "rte_membership.h"
+#include "rte_membership_ht.h"
+
+#include <rte_errno.h>
+#include <rte_malloc.h>
+#include <rte_prefetch.h>
+
+
+/* The bucket struct for ht setsum */
+struct membership_ht_bucket {
+ SIG_TYPE sigs[MEMBERSHIP_BUCKET_ENTRIES]; /* 2-byte signature */
+ uint8_t flags[MEMBERSHIP_BUCKET_ENTRIES];
+ MEMBERSHIP_TARGET_TYPE targets[MEMBERSHIP_BUCKET_ENTRIES];/* 2-byte target */
+} __attribute__ ((packed));
+
+
+struct membership_ht_ss {
+ struct membership_ht_bucket* buckets; /* buckets array */
+ uint32_t bucket_cnt;
+ uint32_t bucket_mask;
+
+};
+
+
+int
+rte_membership_create_ht(struct rte_membership_setsum *ss){
+ uint32_t i, j;
+ const uint32_t num_buckets = rte_align32pow2(ss->num_keys) /
+ MEMBERSHIP_BUCKET_ENTRIES;
+ struct membership_ht_ss *t;
+
+ t = (struct membership_ht_ss *)rte_zmalloc_socket(NULL,
+ sizeof(struct membership_ht_ss),
+ RTE_CACHE_LINE_SIZE, ss->socket_id);
+
+
+ struct membership_ht_bucket* buckets = rte_zmalloc_socket(NULL,
+ num_buckets * sizeof(struct membership_ht_bucket),
+ RTE_CACHE_LINE_SIZE, ss->socket_id);
+
+ t->buckets = buckets;
+ t->bucket_cnt = num_buckets;
+ t->bucket_mask = num_buckets - 1;
+
+ ss->ss = t;
+
+ for (i=0; i<num_buckets; i++) {
+ for (j=0; j<MEMBERSHIP_BUCKET_ENTRIES; j++) {
+ buckets[i].targets[j]=RTE_MEMBERSHIP_NO_MATCH;
+ }
+ }
+ return 0;
+}
+
+
+int
+rte_membership_lookup_multi_ht(const struct rte_membership_setsum* setsum,
+ const void* key, MEMBERSHIP_TARGET_TYPE* target_id)
+{
+
+ int32_t i;
+ int ret = 0;
+ struct membership_ht_ss* ht = setsum->ss;
+ uint32_t prim_hash_seed = setsum->prim_hash_seed;
+ uint32_t sec_hash_seed = setsum->sec_hash_seed;
+ uint32_t bucket_mask = ht->bucket_mask;
+ struct membership_ht_bucket* buckets = ht->buckets;
+ uint32_t key_len = setsum->key_len;
+
+
+ SIG_TYPE tmp_sig = MEMBERSHIP_PRIM_HASH(key, key_len, prim_hash_seed) &
+ SIG_BITMASK;
+
+ uint32_t hash_val = MEMBERSHIP_SEC_HASH(key, key_len, sec_hash_seed);
+ uint32_t prim_bucket = hash_val & bucket_mask;
+ uint32_t sec_bucket = (prim_bucket ^ tmp_sig) & bucket_mask;
+
+ for (i = 0; i < MEMBERSHIP_BUCKET_ENTRIES; i++) {
+ if (tmp_sig == buckets[prim_bucket].sigs[i] &&
+ buckets[prim_bucket].targets[i] != RTE_MEMBERSHIP_NO_MATCH) {
+ target_id[ret] = buckets[prim_bucket].targets[i];
+ ret++;
+ }
+ }
+
+ for (i = 0; i < MEMBERSHIP_BUCKET_ENTRIES; i++) {
+ if (tmp_sig == buckets[sec_bucket].sigs[i] &&
+ buckets[sec_bucket].targets[i] != RTE_MEMBERSHIP_NO_MATCH) {
+ target_id[ret] = buckets[sec_bucket].targets[i];
+ ret++;
+ }
+ }
+ return ret;
+}
+
+int
+rte_membership_lookup_multi_bulk_ht(const struct rte_membership_setsum *setsum,
+ const void **keys, uint32_t num_keys, uint32_t match_per_key,
+ uint32_t *match_count,
+ MEMBERSHIP_TARGET_TYPE *target_ids)
+{
+ uint32_t i,j;
+ int ret = 0;
+ struct membership_ht_ss *ht = setsum->ss;
+ uint32_t prim_hash_seed = setsum->prim_hash_seed;
+ uint32_t sec_hash_seed = setsum->sec_hash_seed;
+ uint32_t bucket_mask = ht->bucket_mask;
+ struct membership_ht_bucket* buckets = ht->buckets;
+ uint32_t key_len = setsum->key_len;
+
+ SIG_TYPE tmp_sig[RTE_MEMBERSHIP_LOOKUP_BULK_MAX] = {0};
+ const struct membership_ht_bucket*
+ prim_buckets[RTE_MEMBERSHIP_LOOKUP_BULK_MAX] = {0};
+ const struct membership_ht_bucket*
+ sec_buckets[RTE_MEMBERSHIP_LOOKUP_BULK_MAX] = {0};
+
+ for (i=0; i<num_keys; i++) {
+ tmp_sig[i] = MEMBERSHIP_PRIM_HASH(keys[i], key_len, prim_hash_seed) &
+ SIG_BITMASK;
+ uint32_t hash_val = MEMBERSHIP_SEC_HASH(keys[i], key_len, sec_hash_seed);
+ uint32_t prim_bucket = hash_val & bucket_mask;
+ uint32_t sec_bucket = (prim_bucket ^ tmp_sig[i]) & bucket_mask;
+ prim_buckets[i] = &buckets[prim_bucket];
+ sec_buckets[i] = &buckets[sec_bucket];
+ rte_prefetch0(prim_buckets[i]);
+ rte_prefetch0(sec_buckets[i]);
+ }
+
+ for (j = 0; j < num_keys; j++) {
+ uint32_t match_cnt = 0;
+ for (i = 0; i < MEMBERSHIP_BUCKET_ENTRIES; i++){
+ if(tmp_sig[j] == prim_buckets[j]->sigs[i] &&
+ prim_buckets[j]->targets[i] != RTE_MEMBERSHIP_NO_MATCH){
+ if (match_cnt >= match_per_key)
+ break;
+ target_ids[j*match_per_key+match_cnt] = prim_buckets[j]->targets[i];
+ match_cnt++;
+ }
+ }
+ for (i = 0; i < MEMBERSHIP_BUCKET_ENTRIES; i++) {
+ if (tmp_sig[j] == sec_buckets[j]->sigs[i] &&
+ sec_buckets[j]->targets[i] != RTE_MEMBERSHIP_NO_MATCH) {
+ if (match_cnt >= match_per_key)
+ break;
+ target_ids[j*match_per_key+match_cnt] = sec_buckets[j]->targets[i];
+ match_cnt++;
+ }
+ }
+ match_count[j] = match_cnt;
+ if (match_cnt != 0)
+ ret++;
+ }
+ return ret;
+}
+
+int
+rte_membership_lookup_ht(const struct rte_membership_setsum *setsum,
+ const void *key, MEMBERSHIP_TARGET_TYPE *target_id)
+{
+
+ int32_t i;
+ struct membership_ht_ss* ht = setsum->ss;
+ uint32_t prim_hash_seed = setsum->prim_hash_seed;
+ uint32_t sec_hash_seed = setsum->sec_hash_seed;
+ uint32_t bucket_mask = ht->bucket_mask;
+ struct membership_ht_bucket* buckets = ht->buckets;
+ uint32_t key_len = setsum->key_len;
+
+
+ SIG_TYPE tmp_sig = MEMBERSHIP_PRIM_HASH(key, key_len, prim_hash_seed) &
+ SIG_BITMASK;
+
+ uint32_t hash_val = MEMBERSHIP_SEC_HASH(key, key_len, sec_hash_seed);
+ uint32_t prim_bucket = hash_val & bucket_mask;
+ uint32_t sec_bucket = (prim_bucket ^ tmp_sig) & bucket_mask;
+
+ for (i = 0; i < MEMBERSHIP_BUCKET_ENTRIES; i++) {
+ if (tmp_sig == buckets[prim_bucket].sigs[i] &&
+ buckets[prim_bucket].targets[i] != RTE_MEMBERSHIP_NO_MATCH) {
+ *target_id = buckets[prim_bucket].targets[i];
+ return 1;
+ }
+ }
+ for (i = 0; i < MEMBERSHIP_BUCKET_ENTRIES; i++) {
+ if (tmp_sig == buckets[sec_bucket].sigs[i] &&
+ buckets[sec_bucket].targets[i] != RTE_MEMBERSHIP_NO_MATCH) {
+ *target_id = buckets[sec_bucket].targets[i];
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+rte_membership_lookup_bulk_ht(const struct rte_membership_setsum *setsum,
+ const void **keys, uint32_t num_keys, MEMBERSHIP_TARGET_TYPE *target_id)
+{
+ uint32_t i,j;
+ int ret = 0;
+ struct membership_ht_ss* ht = setsum->ss;
+ uint32_t prim_hash_seed = setsum->prim_hash_seed;
+ uint32_t sec_hash_seed = setsum->sec_hash_seed;
+ uint32_t bucket_mask = ht->bucket_mask;
+ struct membership_ht_bucket* buckets = ht->buckets;
+ uint32_t key_len = setsum->key_len;
+
+ SIG_TYPE tmp_sig[RTE_MEMBERSHIP_LOOKUP_BULK_MAX] = {0};
+ const struct membership_ht_bucket*
+ prim_buckets[RTE_MEMBERSHIP_LOOKUP_BULK_MAX] = {0};
+ const struct membership_ht_bucket*
+ sec_buckets[RTE_MEMBERSHIP_LOOKUP_BULK_MAX] = {0};
+
+ for (i = 0; i < num_keys; i++) {
+ tmp_sig[i] = MEMBERSHIP_PRIM_HASH(keys[i], key_len, prim_hash_seed) &
+ SIG_BITMASK;
+ uint32_t hash_val = MEMBERSHIP_SEC_HASH(keys[i], key_len, sec_hash_seed);
+ uint32_t prim_bucket = hash_val & bucket_mask;
+ uint32_t sec_bucket = (prim_bucket ^ tmp_sig[i]) & bucket_mask;
+ prim_buckets[i] = &buckets[prim_bucket];
+ sec_buckets[i] = &buckets[sec_bucket];
+ rte_prefetch0(prim_buckets[i]);
+ rte_prefetch0(sec_buckets[i]);
+ }
+
+ for (i = 0; i < num_keys; i++) {
+ for (j = 0; j < MEMBERSHIP_BUCKET_ENTRIES; j++) {
+ if(tmp_sig[i] == prim_buckets[i]->sigs[j] &&
+ prim_buckets[i]->targets[j] != RTE_MEMBERSHIP_NO_MATCH) {
+ target_id[i] = prim_buckets[i]->targets[j];
+ ret++;
+ break;
+ }
+ }
+
+ if (j == MEMBERSHIP_BUCKET_ENTRIES) {
+ for (j = 0; j < MEMBERSHIP_BUCKET_ENTRIES; j++) {
+ if(tmp_sig[i] == sec_buckets[i]->sigs[j] &&
+ sec_buckets[i]->targets[j] != RTE_MEMBERSHIP_NO_MATCH) {
+ target_id[i]= sec_buckets[i]->targets[j];
+ ret++;
+ break;
+ }
+ }
+ }
+
+ if (j == MEMBERSHIP_BUCKET_ENTRIES) {
+ target_id[i] = RTE_MEMBERSHIP_NO_MATCH;
+ }
+ }
+ return ret;
+}
+
+
+
+/* Search for an entry that can be pushed to its alternative location */
+static inline int
+make_space_bucket(const struct rte_membership_setsum *setsum, uint32_t bkt_num)
+{
+ static unsigned int nr_pushes;
+ unsigned i, j;
+ int ret;
+ uint32_t next_bucket_idx;
+ struct membership_ht_ss* ht = setsum->ss;
+ struct membership_ht_bucket *next_bkt[MEMBERSHIP_BUCKET_ENTRIES];
+ struct membership_ht_bucket *bkt = &ht->buckets[bkt_num];
+
+ /*
+ * Push existing item (search for bucket with space in
+ * alternative locations) to its alternative location
+ */
+ for (i = 0; i < MEMBERSHIP_BUCKET_ENTRIES; i++) {
+ /* Search for space in alternative locations */
+ next_bucket_idx = (bkt->sigs[i] ^ bkt_num) & ht->bucket_mask;
+ next_bkt[i] = &ht->buckets[next_bucket_idx];
+ for (j = 0; j < MEMBERSHIP_BUCKET_ENTRIES; j++) {
+ if (next_bkt[i]->targets[j] == RTE_MEMBERSHIP_NO_MATCH)
+ break;
+ }
+
+ if (j != MEMBERSHIP_BUCKET_ENTRIES)
+ break;
+ }
+
+ /* Alternative location has spare room (end of recursive function) */
+ if (i != MEMBERSHIP_BUCKET_ENTRIES) {
+ next_bkt[i]->sigs[j] = bkt->sigs[i];
+ next_bkt[i]->targets[j] = bkt->targets[i];
+ return i;
+ }
+
+ /* Pick entry that has not been pushed yet */
+ for (i = 0; i < MEMBERSHIP_BUCKET_ENTRIES; i++)
+ if (bkt->flags[i] == 0)
+ break;
+
+ /* All entries have been pushed, so entry cannot be added */
+ if (i == MEMBERSHIP_BUCKET_ENTRIES || nr_pushes > MEMBERSHIP_MAX_PUSHES)
+ return -ENOSPC;
+
+ /* Set flag to indicate that this entry is going to be pushed */
+ bkt->flags[i] = 1;
+
+ nr_pushes++;
+ /* Need room in alternative bucket to insert the pushed entry */
+ ret = make_space_bucket(setsum, next_bucket_idx);
+ /*
+ * After recursive function.
+ * Clear flags and insert the pushed entry
+ * in its alternative location if successful,
+ * or return error
+ */
+ bkt->flags[i] = 0;
+ nr_pushes = 0;
+ if (ret >= 0) {
+ next_bkt[i]->sigs[ret] = bkt->sigs[i];
+ next_bkt[i]->targets[ret] = bkt->targets[i];
+ return i;
+ } else
+ return ret;
+}
+
+
+
+int
+rte_membership_add_ht(const struct rte_membership_setsum* setsum,
+ const void* key, MEMBERSHIP_TARGET_TYPE target_id)
+{
+ int i;
+ int ret;
+ struct membership_ht_ss* ht = setsum->ss;
+ uint32_t prim_hash_seed = setsum->prim_hash_seed;
+ uint32_t sec_hash_seed = setsum->sec_hash_seed;
+ uint32_t bucket_mask = ht->bucket_mask;
+ struct membership_ht_bucket* buckets = ht->buckets;
+ uint32_t key_len = setsum->key_len;
+
+ SIG_TYPE tmp_sig = MEMBERSHIP_PRIM_HASH(key, key_len, prim_hash_seed) &
+ SIG_BITMASK;
+
+
+ uint32_t hash_val = MEMBERSHIP_SEC_HASH(key, key_len, sec_hash_seed);
+ uint32_t prim_bucket = hash_val & bucket_mask;
+ uint32_t sec_bucket = (prim_bucket ^ tmp_sig) & bucket_mask;
+
+
+ /* If not full then insert into one slot*/
+ for (i = 0; i < MEMBERSHIP_BUCKET_ENTRIES; i++) {
+ if (buckets[prim_bucket].targets[i] == RTE_MEMBERSHIP_NO_MATCH) {
+ buckets[prim_bucket].sigs[i] = tmp_sig;
+ buckets[prim_bucket].targets[i] = target_id;
+ ret = i;
+ return ret;
+ }
+ }
+
+ for (i = 0; i < MEMBERSHIP_BUCKET_ENTRIES; i++) {
+ if(buckets[sec_bucket].targets[i] == RTE_MEMBERSHIP_NO_MATCH){
+ buckets[sec_bucket].sigs[i] = tmp_sig;
+ buckets[sec_bucket].targets[i] = target_id;
+ ret = i;
+ return ret;
+ }
+ }
+
+
+ /* random pick prim or sec for recursive displacement */
+
+ uint32_t select_bucket = (hash_val>>31) ? prim_bucket : sec_bucket;
+ ret = make_space_bucket (setsum, select_bucket);
+
+ if (ret >= 0) {
+ buckets[select_bucket].sigs[ret] = tmp_sig;
+ buckets[select_bucket].targets[ret] = target_id;
+ return ret;
+ }
+ return ret;
+}
+
+
+void
+rte_membership_free_ht(struct rte_membership_setsum *setsum)
+{
+ rte_free(setsum->ss);
+}
+
+
+int
+rte_membership_delete_ht(struct rte_membership_setsum *setsum, const void *key,
+ MEMBERSHIP_TARGET_TYPE target_id)
+{
+ int i;
+ struct membership_ht_ss *ht = setsum->ss;
+ uint32_t prim_hash_seed = setsum->prim_hash_seed;
+ uint32_t sec_hash_seed = setsum->sec_hash_seed;
+ uint32_t bucket_mask = ht->bucket_mask;
+ struct membership_ht_bucket *buckets = ht->buckets;
+ uint32_t key_len = setsum->key_len;
+
+ SIG_TYPE tmp_sig = MEMBERSHIP_PRIM_HASH(key, key_len, prim_hash_seed) &
+ SIG_BITMASK;
+
+
+ uint32_t hash_val = MEMBERSHIP_SEC_HASH(key, key_len, sec_hash_seed);
+ uint32_t prim_bucket = hash_val & bucket_mask;
+ uint32_t sec_bucket = (prim_bucket ^ tmp_sig) & bucket_mask;
+
+ for (i = 0; i < MEMBERSHIP_BUCKET_ENTRIES; i++) {
+ if (tmp_sig == buckets[prim_bucket].sigs[i] &&
+ target_id == buckets[prim_bucket].targets[i]){
+ buckets[prim_bucket].targets[i] = RTE_MEMBERSHIP_NO_MATCH;
+ return 0;
+ }
+ }
+
+ for (i = 0; i < MEMBERSHIP_BUCKET_ENTRIES; i++){
+ if(tmp_sig == buckets[sec_bucket].sigs[i] &&
+ target_id == buckets[sec_bucket].targets[i]){
+ buckets[prim_bucket].targets[i] = RTE_MEMBERSHIP_NO_MATCH;
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+
+void
+rte_membership_reset_ht(const struct rte_membership_setsum *setsum)
+{
+ uint32_t i, j;
+ struct membership_ht_ss *ht = setsum->ss;
+ /* FIXME: inefficient*/
+ for (i = 0; i < ht->bucket_cnt; i++) {
+ for (j = 0; j < MEMBERSHIP_BUCKET_ENTRIES; j++){
+ ht->buckets[i].targets[j] = RTE_MEMBERSHIP_NO_MATCH;
+ }
+ }
+}
+
diff --git a/lib/librte_membership/rte_membership_ht.h b/lib/librte_membership/rte_membership_ht.h
new file mode 100644
index 0000000..5a69470
--- /dev/null
+++ b/lib/librte_membership/rte_membership_ht.h
@@ -0,0 +1,98 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_MEMBERSHIP_HT_H_
+#define _RTE_MEMBERSHIP_HT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int
+rte_membership_create_ht(struct rte_membership_setsum *ss);
+
+
+int
+rte_membership_lookup_ht(const struct rte_membership_setsum *setsum,
+ const void *key, MEMBERSHIP_TARGET_TYPE *target_id);
+
+
+
+int
+rte_membership_lookup_bulk_ht(const struct rte_membership_setsum *setsum,
+ const void **keys, uint32_t num_keys, MEMBERSHIP_TARGET_TYPE *target_ids);
+
+
+
+
+int
+rte_membership_lookup_multi_ht(const struct rte_membership_setsum *setsum,
+ const void *key, MEMBERSHIP_TARGET_TYPE *target_id);
+
+
+
+int
+rte_membership_lookup_multi_bulk_ht(const struct rte_membership_setsum *setsum,
+ const void **keys, uint32_t num_keys, uint32_t match_per_key,
+ uint32_t *match_count,
+ MEMBERSHIP_TARGET_TYPE *target_ids);
+
+
+
+
+int
+rte_membership_add_ht(const struct rte_membership_setsum *setsum,
+ const void *key, MEMBERSHIP_TARGET_TYPE target_id);
+
+void
+rte_membership_free_ht(struct rte_membership_setsum *setsum);
+
+
+
+
+int
+rte_membership_delete_ht(struct rte_membership_setsum *ss, const void *key,
+ MEMBERSHIP_TARGET_TYPE target_id);
+
+
+void
+rte_membership_reset_ht(const struct rte_membership_setsum *setsum);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+#endif /* _RTE_MEMBERSHIP_HT_H_ */
diff --git a/lib/librte_membership/rte_membership_vbf.c b/lib/librte_membership/rte_membership_vbf.c
new file mode 100644
index 0000000..dd8cf6c
--- /dev/null
+++ b/lib/librte_membership/rte_membership_vbf.c
@@ -0,0 +1,391 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "rte_membership.h"
+#include "rte_membership_bf.h"
+#include "rte_membership_vbf.h"
+
+#include <rte_bitmap.h>
+#include <rte_malloc.h>
+#include <rte_memory.h>
+#include <rte_hash_crc.h>
+#include <rte_errno.h>
+
+
+/*
+ * vBF currently implemented as a linked list of BFs
+ */
+
+int
+__membership_push(const struct rte_membership_setsum *setsum,
+ struct rte_membership_bf *bf, MEMBERSHIP_TARGET_TYPE target_id);
+
+
+struct rte_membership_vbf_node
+{
+ struct rte_membership_bf *bf;
+ MEMBERSHIP_TARGET_TYPE target_id;
+ struct rte_membership_vbf_node *next;
+};
+
+struct rte_membership_vbf
+{
+ struct rte_membership_vbf_node *root;
+};
+
+
+int
+__membership_push(const struct rte_membership_setsum *setsum,
+ struct rte_membership_bf *bf, MEMBERSHIP_TARGET_TYPE target_id)
+{
+ struct rte_membership_vbf *vbf = setsum->ss;
+ struct rte_membership_vbf_node *current = vbf->root;
+
+ struct rte_membership_vbf_node *new_node;
+ new_node = rte_zmalloc_socket(NULL, sizeof(struct rte_membership_vbf_node),
+ RTE_CACHE_LINE_SIZE, setsum->socket_id);
+ if (new_node == NULL) {
+ return -ENOMEM;
+ }
+
+ new_node->bf = bf;
+ new_node->target_id = target_id;
+ new_node->next = NULL;
+
+
+ if (current != NULL) {
+ while(current->next != NULL){
+ current = current->next;
+ }
+ current->next = new_node;
+ }
+ else {
+ vbf->root = new_node;
+ }
+
+ return 0;
+}
+
+
+
+int
+rte_membership_create_vbf(struct rte_membership_setsum *setsum)
+{
+ int i;
+ int num_target = setsum->num_target;
+ struct rte_membership_vbf *vbf =
+ rte_zmalloc_socket(NULL, sizeof(struct rte_membership_vbf),
+ RTE_CACHE_LINE_SIZE, setsum->socket_id);
+ if(vbf == NULL)
+ return -ENOMEM;
+
+ vbf->root = NULL;
+ setsum->ss = vbf;
+ for (i = 1; i < num_target+1; i++) {
+ struct rte_membership_bf *bloom =
+ __membership_create_bf((const struct rte_membership_setsum *)setsum);
+
+ if (bloom == NULL) {
+ rte_membership_free_vbf(setsum);
+ return -ENOMEM;
+ }
+ if (__membership_push((const struct rte_membership_setsum *)setsum,
+ bloom, i) < 0) {
+ rte_membership_free_vbf(setsum);
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+
+int
+rte_membership_lookup_vbf(const struct rte_membership_setsum *setsum,
+ const void *key, MEMBERSHIP_TARGET_TYPE *target_id)
+{
+ uint32_t key_len = setsum->key_len;
+ uint32_t prim_hash_seed = setsum->prim_hash_seed;
+ uint32_t sec_hash_seed = setsum->sec_hash_seed;
+ uint32_t a = MEMBERSHIP_PRIM_HASH(key, key_len, prim_hash_seed);
+ uint32_t b = MEMBERSHIP_SEC_HASH(key, key_len, sec_hash_seed);
+
+ struct rte_membership_vbf* vbf = setsum->ss;
+ struct rte_membership_vbf_node* current = vbf->root;
+
+ while (current != NULL) {
+ struct rte_membership_bf* bloom = current->bf;
+ uint32_t x;
+ uint32_t i;
+
+ struct rte_bitmap *bmp = bloom->bmp;
+
+ for (i = 0; i < bloom->num_hashes; i++) {
+ x = (a + i*b) & bloom->bucket_bitmask;
+ if (rte_bitmap_get(bmp, x) == 0) {
+ current = current->next;
+ break;
+ }
+ }
+ if(i == bloom->num_hashes){
+ *target_id = current->target_id;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+int
+rte_membership_lookup_bulk_vbf(const struct rte_membership_setsum *setsum,
+ const void **keys, uint32_t num_keys, MEMBERSHIP_TARGET_TYPE *target_ids)
+{
+ uint32_t i;
+ int ret = 0;
+ uint32_t key_len = setsum->key_len;
+ uint32_t prim_hash_seed = setsum->prim_hash_seed;
+ uint32_t sec_hash_seed = setsum->sec_hash_seed;
+
+ struct rte_membership_vbf* vbf = setsum->ss;
+
+ for (i = 0; i < num_keys; i++) {
+ uint32_t a = MEMBERSHIP_PRIM_HASH(keys[i], key_len, prim_hash_seed);
+ uint32_t b = MEMBERSHIP_SEC_HASH(keys[i], key_len, sec_hash_seed);
+ struct rte_membership_vbf_node* current = vbf->root;
+ while (current != NULL) {
+ struct rte_membership_bf* bloom = current->bf;
+ uint32_t x;
+ uint32_t j;
+
+ struct rte_bitmap *bmp = bloom->bmp;
+
+ for (j = 0; j < bloom->num_hashes; j++) {
+ x = (a + j*b) & bloom->bucket_bitmask;
+ if (rte_bitmap_get(bmp, x) == 0) {
+ current = current->next;
+ break;
+ }
+ }
+ if (j == bloom->num_hashes) {
+ target_ids[i] = current->target_id;
+ ret++;
+ break;
+ }
+ }
+ if (current == NULL)
+ target_ids[i] = RTE_MEMBERSHIP_NO_MATCH;
+ }
+ return ret;
+}
+
+
+
+
+int
+rte_membership_lookup_multi_vbf(const struct rte_membership_setsum *setsum,
+ const void *key, MEMBERSHIP_TARGET_TYPE *target_id)
+{
+ int ret = 0;
+ uint32_t key_len = setsum->key_len;
+ uint32_t prim_hash_seed = setsum->prim_hash_seed;
+ uint32_t sec_hash_seed = setsum->sec_hash_seed;
+ uint32_t a = MEMBERSHIP_PRIM_HASH(key, key_len, prim_hash_seed);
+ uint32_t b = MEMBERSHIP_SEC_HASH(key, key_len, sec_hash_seed);
+
+ struct rte_membership_vbf* vbf = setsum->ss;
+ struct rte_membership_vbf_node* current = vbf->root;
+
+ while (current != NULL) {
+ struct rte_membership_bf* bloom = current->bf;
+ uint32_t x;
+ uint32_t i;
+
+ struct rte_bitmap *bmp = bloom->bmp;
+
+ for (i = 0; i < bloom->num_hashes; i++) {
+ x = (a + i*b) & bloom->bucket_bitmask;
+ if (rte_bitmap_get(bmp, x) == 0) {
+ current = current->next;
+ break;
+ }
+ }
+ if(i == bloom->num_hashes){
+ target_id[ret] = current->target_id;
+ ret++;
+ current = current->next;
+ }
+ }
+ return ret;
+}
+
+
+
+int
+rte_membership_lookup_multi_bulk_vbf(const struct rte_membership_setsum *setsum,
+ const void **keys, uint32_t num_keys, uint32_t match_per_key,
+ uint32_t *match_count,
+ MEMBERSHIP_TARGET_TYPE *target_ids)
+{
+ uint32_t j;
+ int ret = 0;
+ uint32_t key_len = setsum->key_len;
+ uint32_t prim_hash_seed = setsum->prim_hash_seed;
+ uint32_t sec_hash_seed = setsum->sec_hash_seed;
+ struct rte_membership_vbf* vbf = setsum->ss;
+
+ for (j = 0; j < num_keys; j++) {
+ uint32_t match_cnt=0;
+ uint32_t a = MEMBERSHIP_PRIM_HASH(keys[j], key_len, prim_hash_seed);
+ uint32_t b = MEMBERSHIP_SEC_HASH(keys[j], key_len, sec_hash_seed);
+ struct rte_membership_vbf_node* current = vbf->root;
+ while (current != NULL) {
+ struct rte_membership_bf* bloom = current->bf;
+ uint32_t x;
+ uint32_t i;
+
+ struct rte_bitmap *bmp = bloom->bmp;
+
+ for (i = 0; i < bloom->num_hashes; i++) {
+ x = (a + i * b) & bloom->bucket_bitmask;
+ if (rte_bitmap_get(bmp, x) == 0) {
+ current = current->next;
+ break;
+ }
+ }
+ if (i == bloom->num_hashes) {
+ if (match_cnt >= match_per_key)
+ break;
+ target_ids[j*match_per_key+match_cnt] = current->target_id;
+ match_cnt++;
+ current = current->next;
+ }
+ }
+ match_count[j] = match_cnt;
+ if (match_cnt != 0)
+ ret++;
+ }
+ return ret;
+}
+
+
+
+int
+rte_membership_add_vbf(const struct rte_membership_setsum *setsum,
+ const void *key, MEMBERSHIP_TARGET_TYPE target_id)
+{
+
+ uint32_t key_len = setsum->key_len;
+ uint32_t prim_hash_seed = setsum->prim_hash_seed;
+ uint32_t sec_hash_seed = setsum->sec_hash_seed;
+ uint32_t a = MEMBERSHIP_PRIM_HASH(key, key_len, prim_hash_seed);
+ uint32_t b = MEMBERSHIP_SEC_HASH(key, key_len, sec_hash_seed);
+ struct rte_membership_vbf* vbf = setsum->ss;
+ struct rte_membership_vbf_node* current = vbf->root;
+ uint32_t x;
+ uint32_t i;
+
+ while (current != NULL) {
+ if (current->target_id != target_id) {
+ current = current->next;
+ continue;
+ }
+
+ struct rte_membership_bf *bloom = current->bf;
+
+ struct rte_bitmap *bmp = bloom->bmp;
+
+ for (i = 0; i < bloom->num_hashes; i++) {
+ x = (a + i * b) & bloom->bucket_bitmask;
+ rte_bitmap_set(bmp, x);
+ }
+ return 0;
+ }
+
+ /* Here means there is no BF matches the target. So we add a new BF */
+
+ struct rte_membership_bf *bloom = __membership_create_bf(setsum);
+
+ if(bloom == NULL) {
+ return -ENOMEM;
+ }
+
+ struct rte_bitmap *bmp = bloom->bmp;
+
+ for (i = 0; i < bloom->num_hashes; i++) {
+ x = (a + i * b) & bloom->bucket_bitmask;
+ rte_bitmap_set(bmp, x);
+ }
+
+ if (__membership_push(setsum, bloom, i) < 0) {
+ rte_free(bloom->bmp_array);
+ rte_free(bloom);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+
+void
+rte_membership_free_vbf(struct rte_membership_setsum *setsum)
+{
+ struct rte_membership_vbf* vbf = setsum->ss;
+ if (vbf != NULL) {
+ struct rte_membership_vbf_node* current = vbf->root;
+ struct rte_membership_vbf_node* next;
+ while (current != NULL) {
+ next = current->next;
+ if(current->bf != NULL){
+ rte_free(current->bf->bmp_array);
+ rte_free(current->bf);
+ }
+ rte_free(current);
+ current = next;
+ }
+ }
+}
+
+
+
+
+void
+rte_membership_reset_vbf(const struct rte_membership_setsum *setsum)
+{
+
+ struct rte_membership_vbf *vbf = setsum->ss;
+ struct rte_membership_vbf_node *current = vbf->root;
+
+ while (current != NULL) {
+ if (current->bf != NULL)
+ rte_bitmap_reset(current->bf->bmp_array);
+ current = current->next;
+ }
+}
\ No newline at end of file
diff --git a/lib/librte_membership/rte_membership_vbf.h b/lib/librte_membership/rte_membership_vbf.h
new file mode 100644
index 0000000..4cc06ac
--- /dev/null
+++ b/lib/librte_membership/rte_membership_vbf.h
@@ -0,0 +1,85 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_MEMBERSHIP_VBF_H_
+#define _RTE_MEMBERSHIP_VBF_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int
+rte_membership_create_vbf(struct rte_membership_setsum *ss);
+
+
+int
+rte_membership_lookup_vbf(const struct rte_membership_setsum *setsum,
+ const void *key, MEMBERSHIP_TARGET_TYPE *target_id);
+
+
+int
+rte_membership_lookup_bulk_vbf(const struct rte_membership_setsum *setsum,
+ const void **keys, uint32_t num_keys, MEMBERSHIP_TARGET_TYPE *target_ids);
+
+
+int
+rte_membership_lookup_multi_vbf(const struct rte_membership_setsum *setsum,
+ const void *key, MEMBERSHIP_TARGET_TYPE *target_id);
+
+
+int
+rte_membership_lookup_multi_bulk_vbf(const struct rte_membership_setsum *setsum,
+ const void **keys, uint32_t num_keys, uint32_t match_per_key,
+ uint32_t *match_count,
+ MEMBERSHIP_TARGET_TYPE *target_ids);
+
+
+
+int
+rte_membership_add_vbf(const struct rte_membership_setsum *setsum,
+ const void *key, MEMBERSHIP_TARGET_TYPE target_id);
+
+
+void
+rte_membership_free_vbf(struct rte_membership_setsum *ss);
+
+
+void
+rte_membership_reset_vbf(const struct rte_membership_setsum *setsum);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_MEMBERSHIP_VBF_H_ */
diff --git a/lib/librte_membership/rte_membership_version.map b/lib/librte_membership/rte_membership_version.map
new file mode 100644
index 0000000..d10f8a2
--- /dev/null
+++ b/lib/librte_membership/rte_membership_version.map
@@ -0,0 +1,15 @@
+DPDK_17.08 {
+ global:
+
+ rte_membership_create;
+ rte_membership_lookup;
+ rte_membership_lookup_bulk;
+ rte_membership_lookup_multi;
+ rte_membership_lookup_multi_bulk;
+ rte_membership_add;
+ rte_membership_free;
+ rte_membership_reset;
+ rte_membership_delete;
+
+ local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index bcaf1b3..58218fe 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -85,6 +85,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CFGFILE) += -lrte_cfgfile
_LDLIBS-y += --whole-archive
_LDLIBS-$(CONFIG_RTE_LIBRTE_HASH) += -lrte_hash
+_LDLIBS-$(CONFIG_RTE_LIBRTE_MEMBERSHIP) += -lrte_membership
_LDLIBS-$(CONFIG_RTE_LIBRTE_VHOST) += -lrte_vhost
_LDLIBS-$(CONFIG_RTE_LIBRTE_KVARGS) += -lrte_kvargs
_LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF) += -lrte_mbuf
diff --git a/test/test/Makefile b/test/test/Makefile
index ee240be..2dd0a90 100644
--- a/test/test/Makefile
+++ b/test/test/Makefile
@@ -123,6 +123,8 @@ SRCS-y += test_logs.c
SRCS-y += test_memcpy.c
SRCS-y += test_memcpy_perf.c
+
+SRCS-$(CONFIG_RTE_LIBRTE_MEMBERSHIP) += test_membership.c
SRCS-$(CONFIG_RTE_LIBRTE_EFD) += test_efd.c
SRCS-$(CONFIG_RTE_LIBRTE_EFD) += test_efd_perf.c
diff --git a/test/test/test_membership.c b/test/test/test_membership.c
new file mode 100644
index 0000000..f2ccd15
--- /dev/null
+++ b/test/test/test_membership.c
@@ -0,0 +1,459 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <rte_memcpy.h>
+#include <rte_malloc.h>
+#include <rte_membership.h>
+#include <rte_byteorder.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ip.h>
+
+
+#include "test.h"
+
+void *setsum_ht;
+void *setsum_cache;
+void *setsum_bf;
+void *setsum_vbf;
+
+#define KEY 0xffff
+#define KEY1 0xfffe
+#define TARGET 31
+
+#define ITERATIONS 3
+#define MAX_KEYSIZE 4
+
+static struct rte_membership_parameters params = {
+ .name = "test_membership_ht",
+ .type = SETSUM_TYPE_HT,
+ .num_keys = 1 << 16, /* Total hash table entries. */
+ .key_len = 4, /* Length of hash key. */
+
+ /*num_target and false_postive_rate only relevent with BF based set summary*/
+ .num_target = 32,
+ .false_postive_rate = 0.03,
+ .prim_hash_seed = 1,
+ .sec_hash_seed = 11,
+ .socket_id = 0 /* NUMA Socket ID for memory. */
+ };
+
+
+#define RETURN_IF_ERROR(cond, str, ...) do { \
+ if (cond) { \
+ printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
+ return -1; \
+ } \
+} while(0)
+
+static int test_membership_create(void)
+{
+
+
+ setsum_ht = rte_membership_create(¶ms);
+
+ params.name = "test_membership_cache";
+ params.type = SETSUM_TYPE_CACHE;
+
+ setsum_cache = rte_membership_create(¶ms);
+
+ params.name = "test_membership_bf";
+ params.type = SETSUM_TYPE_BF;
+
+ setsum_bf = rte_membership_create(¶ms);
+
+ params.name = "test_membership_vbf";
+ params.type = SETSUM_TYPE_VBF;
+
+ setsum_vbf = rte_membership_create(¶ms);
+
+ if(setsum_ht==NULL || setsum_cache == NULL || setsum_bf == NULL ||
+ setsum_vbf == NULL) {
+ printf("Creation of setsums fail\n");
+ return -1;
+ }
+ printf("Creation of setsums success\n");
+ return 0;
+}
+
+static int test_membership_insert(void)
+{
+ int ret_ht, ret_cache, ret_bf, ret_vbf;
+ uint32_t key=KEY;
+ uint32_t target_bf = 1;
+ ret_ht = rte_membership_add(setsum_ht, &key, TARGET);
+ ret_cache = rte_membership_add(setsum_cache, &key, TARGET);
+ ret_bf = rte_membership_add(setsum_bf, &key, target_bf);
+ ret_vbf = rte_membership_add(setsum_vbf, &key, TARGET);
+ printf("%d, %d, %d, %d\n", ret_ht, ret_cache, ret_bf, ret_vbf);
+ RETURN_IF_ERROR(ret_ht < 0 || ret_cache < 0 || ret_bf < 0 || ret_vbf < 0,
+ "insert error");
+
+ printf("insert key %d with target %d success\n", key, TARGET);
+ return 0;
+}
+
+static int test_membership_lookup(void)
+{
+ int ret_ht, ret_cache, ret_bf, ret_vbf;
+ uint16_t target_ht, target_cache, target_bf, target_vbf;
+ MEMBERSHIP_TARGET_TYPE target_ids_ht[8] = {0};
+ MEMBERSHIP_TARGET_TYPE target_ids_cache[8] = {0};
+ MEMBERSHIP_TARGET_TYPE target_ids_bf[8] = {0};
+ MEMBERSHIP_TARGET_TYPE target_ids_vbf[8] = {0};
+ uint32_t key = KEY;
+ uint32_t key1 = KEY1;
+ uint32_t *key_array[8];
+ uint32_t num_key_ht = 2;
+ uint32_t num_key_cache = 2;
+ uint32_t num_key_bf = 2;
+
+ /* single lookup test */
+ ret_ht = rte_membership_lookup(setsum_ht, &key, &target_ht);
+ ret_cache = rte_membership_lookup(setsum_cache, &key, &target_cache);
+ ret_bf = rte_membership_lookup(setsum_bf, &key, &target_bf);
+ ret_vbf = rte_membership_lookup(setsum_vbf, &key, &target_vbf);
+ if(ret_ht < 0 || ret_cache < 0 || ret_bf < 0 || ret_vbf < 0){
+ printf("lookup ret:%d, %d, %d, %d\n", ret_ht, ret_cache, ret_bf, ret_vbf);
+ return -1;
+ }
+ printf("lookup get target:%d, %d, %d, %d\n", target_ht, target_cache,
+ target_bf, target_vbf);
+ printf("lookup single key success\n");
+
+ /* bulk lookup test */
+ key_array[0] = &key1;
+ key_array[1] = &key;
+
+ ret_ht = rte_membership_lookup_bulk(setsum_ht, (const void**)(key_array),
+ num_key_ht, target_ids_ht);
+
+ ret_cache = rte_membership_lookup_bulk(setsum_cache, (const void**)(key_array),
+ num_key_cache,target_ids_cache);
+
+ ret_bf = rte_membership_lookup_bulk(setsum_bf, (const void**)(key_array),
+ num_key_bf, target_ids_bf);
+
+ ret_vbf = rte_membership_lookup_bulk(setsum_vbf, (const void**)(key_array),
+ num_key_bf, target_ids_vbf);
+
+ RETURN_IF_ERROR((target_ids_ht[0] != target_ids_cache[0]) ||
+ (target_ids_ht[1] != target_ids_cache[1]), "bulk lookup error");
+ printf("bulk lookup target 0:%d, %d, %d, %d\n", target_ids_ht[0],
+ target_ids_cache[0], target_ids_bf[0], target_ids_vbf[0]);
+
+ printf("bulk lookup target 1:%d, %d, %d, %d\n", target_ids_ht[1],
+ target_ids_cache[1], target_ids_bf[1], target_ids_vbf[1]);
+
+ RETURN_IF_ERROR((ret_ht != ret_cache || ret_ht != ret_bf || ret_ht != ret_vbf),
+ "bulk lookup error");
+
+ return 0;
+}
+
+
+static int test_membership_delete(void)
+{
+ int ret_ht, ret_cache, ret_bf, ret_vbf;
+ uint32_t key = KEY;
+ uint16_t target_ht, target_cache, target_bf, target_vbf;
+ ret_ht = rte_membership_delete(setsum_ht, &key, TARGET);
+ ret_cache = rte_membership_delete(setsum_cache, &key, TARGET);
+ ret_bf = rte_membership_delete(setsum_bf, &key, TARGET);
+ ret_vbf = rte_membership_delete(setsum_vbf, &key, TARGET);
+ RETURN_IF_ERROR(ret_ht < 0 || ret_cache < 0 || ret_bf > 0 || ret_vbf > 0,
+ "bulk lookup error");
+
+ ret_ht = rte_membership_lookup(setsum_ht, &key, &target_ht);
+ ret_cache = rte_membership_lookup(setsum_cache, &key, &target_cache);
+ ret_bf = rte_membership_lookup(setsum_bf, &key, &target_bf);
+ ret_vbf = rte_membership_lookup(setsum_vbf, &key, &target_vbf);
+ printf("lookup delete target:%d, %d, %d, %d\n", target_ht, target_cache,
+ target_bf, target_vbf);
+ printf("lookup delete ret:%d, %d, %d, %d\n", ret_ht, ret_cache,
+ ret_bf, ret_vbf);
+ return 0;
+}
+
+
+static int test_membership_multimatch(void)
+{
+ int ret_ht, ret_vbf, ret_cache, ret_bf;
+ MEMBERSHIP_TARGET_TYPE target_ids_ht[32] = {0};
+ MEMBERSHIP_TARGET_TYPE target_ids_vbf[32] = {0};
+ MEMBERSHIP_TARGET_TYPE target_ids_bf[32] = {0};
+ MEMBERSHIP_TARGET_TYPE target_ids_cache[32] = {0};
+
+ MEMBERSHIP_TARGET_TYPE target_ids_ht_m[2][32] = {{0}};
+ MEMBERSHIP_TARGET_TYPE target_ids_vbf_m[2][32] = {{0}};
+ MEMBERSHIP_TARGET_TYPE target_ids_bf_m[2][32] = {{0}};
+ MEMBERSHIP_TARGET_TYPE target_ids_cache_m[2][32] = {{0}};
+ uint32_t key = KEY;
+ uint32_t key1 = KEY1;
+ uint32_t* key_array[8];
+ uint32_t match_count_ht[8];
+ uint32_t match_count_vbf[8];
+ uint32_t match_count_cache[8];
+ uint32_t match_count_bf[8];
+
+ uint32_t num_key_ht = 2;
+ uint32_t num_key_vbf = 2;
+ uint32_t num_key_cache = 2;
+ uint32_t num_key_bf = 2;
+
+ uint32_t i, j;
+ /* same key at most inserted 2*entry_per_bucket times for HT mode */
+ for (i = 1; i < 33; i++) {
+ ret_ht = rte_membership_add(setsum_ht, &key, i);
+ ret_ht = rte_membership_add(setsum_ht, &key1, i);
+ ret_vbf = rte_membership_add(setsum_vbf, &key, i);
+ ret_vbf = rte_membership_add(setsum_vbf, &key1, i);
+
+ /* for cache and bf mode, they do not support multimatch
+ * the mutimatch should works like single match
+ */
+ ret_cache = rte_membership_add(setsum_cache, &key, i);
+ ret_cache = rte_membership_add(setsum_cache, &key1, i);
+ ret_bf = rte_membership_add(setsum_bf, &key, 1);
+ ret_bf = rte_membership_add(setsum_bf, &key1, 1);
+
+ RETURN_IF_ERROR(ret_ht < 0 || ret_vbf < 0 || ret_cache < 0 ||
+ ret_bf < 0, "insert error");
+ }
+
+ /* single multimatch test */
+ ret_vbf = rte_membership_lookup_multi(setsum_vbf, &key, target_ids_vbf);
+ ret_ht = rte_membership_lookup_multi(setsum_ht, &key, target_ids_ht);
+ ret_bf = rte_membership_lookup_multi(setsum_bf, &key, target_ids_bf);
+ ret_cache = rte_membership_lookup_multi(setsum_cache, &key, target_ids_cache);
+ RETURN_IF_ERROR(ret_ht < 0 || ret_vbf < 0 || ret_cache < 0 ||
+ ret_bf < 0, "lookup_multi error");
+
+ for (i=0; i < (uint32_t)ret_ht; i++) {
+ printf("%d,", target_ids_ht[i]);
+ RETURN_IF_ERROR(target_ids_ht[i] != target_ids_vbf[i],
+ "singl multimatch lookup error");
+ }
+ printf("\n");
+
+ /* bulk multimatch test */
+ key_array[0] = &key;
+ key_array[1] = &key1;
+ ret_vbf = rte_membership_lookup_multi_bulk(setsum_vbf,
+ (const void **)key_array, num_key_ht, 32, match_count_vbf,
+ (MEMBERSHIP_TARGET_TYPE *)target_ids_vbf_m);
+
+ ret_ht = rte_membership_lookup_multi_bulk(setsum_ht,
+ (const void **)key_array, num_key_vbf, 32, match_count_ht,
+ (MEMBERSHIP_TARGET_TYPE *)target_ids_ht_m);
+
+ ret_cache = rte_membership_lookup_multi_bulk(setsum_cache,
+ (const void **)key_array, num_key_cache, 32, match_count_cache,
+ (MEMBERSHIP_TARGET_TYPE *)target_ids_cache_m);
+
+ ret_bf = rte_membership_lookup_multi_bulk(setsum_bf,
+ (const void **)key_array, num_key_bf, 32, match_count_bf,
+ (MEMBERSHIP_TARGET_TYPE *)target_ids_bf_m);
+
+
+ for (i = 0; i < num_key_ht; i++) {
+ printf("ht match count %d %d\n", match_count_ht[0], match_count_ht[1]);
+ printf("vbf match count %d %d\n", match_count_vbf[0], match_count_vbf[1]);
+ printf("cache match count %d %d\n", match_count_cache[0], match_count_cache[1]);
+ printf("bf match count %d %d\n", match_count_bf[0], match_count_bf[1]);
+ }
+
+
+ for (i = 0; i < num_key_ht; i++) {
+ printf("target for key %d: ", i);
+ printf("ht:");
+ for (j = 0; j < match_count_ht[i]; j++) {
+ printf("%d,", target_ids_ht_m[i][j]);
+ }
+ printf("vbf:");
+ for (j = 0; j < match_count_vbf[i]; j++) {
+ printf("%d,", target_ids_vbf_m[i][j]);
+ }
+ printf("cache:");
+ for (j = 0; j < match_count_cache[i]; j++) {
+ printf("%d,", target_ids_cache_m[i][j]);
+ }
+ printf("bf:");
+ for (j = 0; j < match_count_bf[i]; j++) {
+ printf("%d,", target_ids_bf_m[i][j]);
+ }
+ printf("\n");
+ }
+ return 0;
+}
+
+
+
+
+static int test_membership_loadfactor(void)
+{
+ uint8_t simple_key[MAX_KEYSIZE];
+ unsigned i, j;
+ unsigned added_keys, average_keys_added = 0;
+ int ret;
+
+ rte_membership_reset(setsum_ht);
+ rte_membership_reset(setsum_cache);
+
+
+ /* test HT mode */
+ for (j = 0; j < ITERATIONS; j++) {
+ ret = 0;
+ /* Add random entries until key cannot be added */
+ for (added_keys = 0; ret >= 0; added_keys++) {
+ for (i = 0; i < params.key_len; i++)
+ simple_key[i] = rte_rand() % 255;
+ uint16_t target = rte_rand() % ((1 << 16) - 1);
+ ret = rte_membership_add(setsum_ht, simple_key, target);
+ }
+ if (ret != -ENOSPC) {
+ printf("Unexpected error when adding keys\n");
+ return -1;
+ }
+
+ average_keys_added += added_keys;
+
+ /* Reset the table */
+ rte_membership_reset(setsum_ht);
+
+ /* Print a dot to show progress on operations */
+ printf(".");
+ fflush(stdout);
+ }
+
+ average_keys_added /= ITERATIONS;
+
+ printf("\nAverage table utilization for HT mode = %.2f%% (%u/%u)\n",
+ ((double) average_keys_added / params.num_keys * 100),
+ average_keys_added, params.num_keys);
+
+
+
+ /* test cache mode */
+ added_keys = average_keys_added = 0;
+ for (j = 0; j < ITERATIONS; j++) {
+ ret = 0;
+ /* Add random entries until key cannot be added */
+ for (added_keys = 0; ret == 0; added_keys++) {
+ for (i = 0; i < params.key_len; i++)
+ simple_key[i] = rte_rand() % 255;
+ uint16_t target = rte_rand() % ((1 << 16) - 1);
+ ret = rte_membership_add(setsum_cache, simple_key, target);
+ }
+ if (ret != 1) {
+ printf("Unexpected error when adding keys\n");
+ return -1;
+ }
+
+ average_keys_added += added_keys;
+
+ /* Reset the table */
+ rte_membership_reset(setsum_cache);
+
+ /* Print a dot to show progress on operations */
+ printf(".");
+ fflush(stdout);
+ }
+
+ average_keys_added /= ITERATIONS;
+
+ printf("\nAverage table utilization for cache mode = %.2f%% (%u/%u)\n",
+ ((double) average_keys_added / params.num_keys * 100),
+ average_keys_added, params.num_keys);
+ return 0;
+}
+
+
+
+
+
+
+static int
+test_membership(void)
+{
+
+ /* Simple tests for initial debug usage */
+ if (test_membership_create() < 0) {
+ rte_membership_free(setsum_ht);
+ rte_membership_free(setsum_cache);
+ rte_membership_free(setsum_bf);
+ rte_membership_free(setsum_vbf);
+ return -1;
+ }
+ if (test_membership_insert() < 0) {
+ rte_membership_free(setsum_ht);
+ rte_membership_free(setsum_cache);
+ rte_membership_free(setsum_bf);
+ rte_membership_free(setsum_vbf);
+ return -1;
+ }
+ if (test_membership_lookup() < 0) {
+ rte_membership_free(setsum_ht);
+ rte_membership_free(setsum_cache);
+ rte_membership_free(setsum_bf);
+ rte_membership_free(setsum_vbf);
+ return -1;
+ }
+ if (test_membership_delete() < 0) {
+ rte_membership_free(setsum_ht);
+ rte_membership_free(setsum_cache);
+ rte_membership_free(setsum_bf);
+ rte_membership_free(setsum_vbf);
+ return -1;
+ }
+ if (test_membership_multimatch() < 0) {
+ rte_membership_free(setsum_ht);
+ rte_membership_free(setsum_cache);
+ rte_membership_free(setsum_bf);
+ rte_membership_free(setsum_vbf);
+ return -1;
+ }
+
+
+ if (test_membership_loadfactor() < 0) {
+ rte_membership_free(setsum_ht);
+ rte_membership_free(setsum_cache);
+ }
+ /* more complex test */
+ /* FIXME: to be implemented */
+
+ return 0;
+}
+
+REGISTER_TEST_COMMAND(membership_autotest, test_membership);
--
1.9.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [dpdk-dev] [RFC] Add Membership Library
2017-05-27 1:34 [dpdk-dev] [RFC] Add Membership Library Yipeng Wang
2017-05-27 1:34 ` Yipeng Wang
@ 2017-05-27 9:42 ` Vincent Jardin
2017-06-01 1:03 ` Wang, Yipeng1
1 sibling, 1 reply; 7+ messages in thread
From: Vincent Jardin @ 2017-05-27 9:42 UTC (permalink / raw)
To: Yipeng Wang; +Cc: dev, sameh.gobriel, ren.wang, charlie.tai
Why duplicating Jyri's libbloom - https://github.com/jvirkki/libbloom - for
this DPDK capability? Why not showing that you can contribute to libbloom
and make it linkable with the DPDK?
There are so many duplicated code...
Thank you,
Vincent
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [dpdk-dev] [RFC] Add Membership Library
2017-05-27 9:42 ` Vincent Jardin
@ 2017-06-01 1:03 ` Wang, Yipeng1
2017-06-01 23:48 ` Vincent Jardin
2017-06-02 20:51 ` Stephen Hemminger
0 siblings, 2 replies; 7+ messages in thread
From: Wang, Yipeng1 @ 2017-06-01 1:03 UTC (permalink / raw)
To: Vincent Jardin; +Cc: dev, Gobriel, Sameh, Wang, Ren, Tai, Charlie
Hi Vincent,
Thanks for the comments and some quick responses below:
- DPDK Bloom Filter is derived from the libbloom (as shown by the included BSD license), but optimized for performance with various DPDK goodness such as rte_zmalloc, rte_bitmap, rte_jhash, etc. It doesn't seem appropriate to bring those DPDK specific features into libbloom, which is designed for more generic environments.
- DPDK Bloom Filter is just one very basic mode among other more sophisticated ones in the DPDK Membership Library, which supports a different set of APIs (e.g., bulk lookup, multi-match, etc.) than those supported in libbloom.
- It may make sense to bring some generic (i.e., non DPDK specific) improvements back to libbloom once identified.
Thanks
Yipeng
> -----Original Message-----
> From: Vincent Jardin [mailto:vincent.jardin@6wind.com]
> Sent: Saturday, May 27, 2017 2:42 AM
> To: Wang, Yipeng1 <yipeng1.wang@intel.com>
> Cc: dev@dpdk.org; Gobriel, Sameh <sameh.gobriel@intel.com>; Wang, Ren
> <ren.wang@intel.com>; Tai, Charlie <charlie.tai@intel.com>
> Subject: Re: [dpdk-dev] [RFC] Add Membership Library
>
> Why duplicating Jyri's libbloom - https://github.com/jvirkki/libbloom - for this
> DPDK capability? Why not showing that you can contribute to libbloom and
> make it linkable with the DPDK?
>
> There are so many duplicated code...
>
> Thank you,
> Vincent
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [dpdk-dev] [RFC] Add Membership Library
2017-06-01 1:03 ` Wang, Yipeng1
@ 2017-06-01 23:48 ` Vincent Jardin
2017-07-17 21:04 ` Vincent JARDIN
2017-06-02 20:51 ` Stephen Hemminger
1 sibling, 1 reply; 7+ messages in thread
From: Vincent Jardin @ 2017-06-01 23:48 UTC (permalink / raw)
To: Wang, Yipeng1; +Cc: dev, Gobriel, Sameh, Wang, Ren, Tai, Charlie
Le 1 juin 2017 03:03:39 "Wang, Yipeng1" <yipeng1.wang@intel.com> a écrit :
> Hi Vincent,
>
> Thanks for the comments and some quick responses below:
>
> - DPDK Bloom Filter is derived from the libbloom (as shown by the included
> BSD license), but optimized for performance with various DPDK goodness such
> as rte_zmalloc, rte_bitmap, rte_jhash, etc. It doesn't seem appropriate to
> bring those DPDK specific features into libbloom, which is designed for
> more generic environments.
Did you try and ask to the original author?
> - DPDK Bloom Filter is just one very basic mode among other more
> sophisticated ones in the DPDK Membership Library, which supports a
> different set of APIs (e.g., bulk lookup, multi-match, etc.) than those
> supported in libbloom.
How does it justify forking the code?
> - It may make sense to bring some generic (i.e., non DPDK specific)
> improvements back to libbloom once identified.
So let's start first with contributions to libbloom, please.
>
> Thanks
> Yipeng
>
>> -----Original Message-----
>> From: Vincent Jardin [mailto:vincent.jardin@6wind.com]
>> Sent: Saturday, May 27, 2017 2:42 AM
>> To: Wang, Yipeng1 <yipeng1.wang@intel.com>
>> Cc: dev@dpdk.org; Gobriel, Sameh <sameh.gobriel@intel.com>; Wang, Ren
>> <ren.wang@intel.com>; Tai, Charlie <charlie.tai@intel.com>
>> Subject: Re: [dpdk-dev] [RFC] Add Membership Library
>>
>> Why duplicating Jyri's libbloom - https://github.com/jvirkki/libbloom - for
>> this
>> DPDK capability? Why not showing that you can contribute to libbloom and
>> make it linkable with the DPDK?
>>
>> There are so many duplicated code...
>>
>> Thank you,
>> Vincent
>>
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [dpdk-dev] [RFC] Add Membership Library
2017-06-01 1:03 ` Wang, Yipeng1
2017-06-01 23:48 ` Vincent Jardin
@ 2017-06-02 20:51 ` Stephen Hemminger
1 sibling, 0 replies; 7+ messages in thread
From: Stephen Hemminger @ 2017-06-02 20:51 UTC (permalink / raw)
To: Wang, Yipeng1
Cc: Vincent Jardin, dev, Gobriel, Sameh, Wang, Ren, Tai, Charlie
On Thu, 1 Jun 2017 01:03:36 +0000
"Wang, Yipeng1" <yipeng1.wang@intel.com> wrote:
> Hi Vincent,
>
> Thanks for the comments and some quick responses below:
>
> - DPDK Bloom Filter is derived from the libbloom (as shown by the included BSD license), but optimized for performance with various DPDK goodness such as rte_zmalloc, rte_bitmap, rte_jhash, etc. It doesn't seem appropriate to bring those DPDK specific features into libbloom, which is designed for more generic environments.
> - DPDK Bloom Filter is just one very basic mode among other more sophisticated ones in the DPDK Membership Library, which supports a different set of APIs (e.g., bulk lookup, multi-match, etc.) than those supported in libbloom.
> - It may make sense to bring some generic (i.e., non DPDK specific) improvements back to libbloom once identified.
>
> Thanks
> Yipeng
>
> > -----Original Message-----
> > From: Vincent Jardin [mailto:vincent.jardin@6wind.com]
> > Sent: Saturday, May 27, 2017 2:42 AM
> > To: Wang, Yipeng1 <yipeng1.wang@intel.com>
> > Cc: dev@dpdk.org; Gobriel, Sameh <sameh.gobriel@intel.com>; Wang, Ren
> > <ren.wang@intel.com>; Tai, Charlie <charlie.tai@intel.com>
> > Subject: Re: [dpdk-dev] [RFC] Add Membership Library
> >
> > Why duplicating Jyri's libbloom - https://github.com/jvirkki/libbloom - for this
> > DPDK capability? Why not showing that you can contribute to libbloom and
> > make it linkable with the DPDK?
> >
> > There are so many duplicated code...
> >
> > Thank you,
> > Vincent
> >
>
Note: rte_zmalloc is really no faster in my experience than regular malloc. And under
memory pressure rte_malloc is worse than malloc.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [dpdk-dev] [RFC] Add Membership Library
2017-06-01 23:48 ` Vincent Jardin
@ 2017-07-17 21:04 ` Vincent JARDIN
0 siblings, 0 replies; 7+ messages in thread
From: Vincent JARDIN @ 2017-07-17 21:04 UTC (permalink / raw)
To: Wang, Yipeng1; +Cc: dev, Gobriel, Sameh, Wang, Ren, Tai, Charlie
Hi,
So, I understand from a call we had today that you'll send an update of
this series with:
- rte_membership for DPDK because it uses CRC+hash+rte_malloc+few EALs,
- calls to the lib bloom filter (to avoid forking code),
- using builtin/vectorized gcc instead of asm AVX code to keep it
readable code.
we'll be interested in this update. You are welcomed.
best regards,
Vincent
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2017-07-17 21:04 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-27 1:34 [dpdk-dev] [RFC] Add Membership Library Yipeng Wang
2017-05-27 1:34 ` Yipeng Wang
2017-05-27 9:42 ` Vincent Jardin
2017-06-01 1:03 ` Wang, Yipeng1
2017-06-01 23:48 ` Vincent Jardin
2017-07-17 21:04 ` Vincent JARDIN
2017-06-02 20:51 ` Stephen Hemminger
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).