DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH] examples/flow-distributor: rename to server_node_efd
@ 2017-01-24  9:06 Pablo de Lara
  2017-01-30 16:25 ` Thomas Monjalon
  0 siblings, 1 reply; 2+ messages in thread
From: Pablo de Lara @ 2017-01-24  9:06 UTC (permalink / raw)
  To: dev; +Cc: Pablo de Lara

To avoid confusion with distributor app, this commit
renames the flow-distributor sample app to server_node_efd,
since it shows how to use the EFD library and it is based
on a server/nodes model.

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
 MAINTAINERS                                       |    4 +-
 doc/api/examples.dox                              |    8 +-
 doc/guides/sample_app_ug/flow_distributor.rst     |  494 --------
 doc/guides/sample_app_ug/img/flow_distributor.svg | 1254 ---------------------
 doc/guides/sample_app_ug/img/server_node_efd.svg  | 1254 +++++++++++++++++++++
 doc/guides/sample_app_ug/index.rst                |    4 +-
 doc/guides/sample_app_ug/server_node_efd.rst      |  494 ++++++++
 examples/flow_distributor/Makefile                |   44 -
 examples/flow_distributor/distributor/Makefile    |   57 -
 examples/flow_distributor/distributor/args.c      |  200 ----
 examples/flow_distributor/distributor/args.h      |   39 -
 examples/flow_distributor/distributor/init.c      |  371 ------
 examples/flow_distributor/distributor/init.h      |   76 --
 examples/flow_distributor/distributor/main.c      |  362 ------
 examples/flow_distributor/node/Makefile           |   48 -
 examples/flow_distributor/node/node.c             |  417 -------
 examples/flow_distributor/shared/common.h         |   99 --
 examples/server_node_efd/Makefile                 |   44 +
 examples/server_node_efd/node/Makefile            |   48 +
 examples/server_node_efd/node/node.c              |  417 +++++++
 examples/server_node_efd/server/Makefile          |   57 +
 examples/server_node_efd/server/args.c            |  200 ++++
 examples/server_node_efd/server/args.h            |   39 +
 examples/server_node_efd/server/init.c            |  371 ++++++
 examples/server_node_efd/server/init.h            |   76 ++
 examples/server_node_efd/server/main.c            |  362 ++++++
 examples/server_node_efd/shared/common.h          |   99 ++
 27 files changed, 3470 insertions(+), 3468 deletions(-)
 delete mode 100644 doc/guides/sample_app_ug/flow_distributor.rst
 delete mode 100644 doc/guides/sample_app_ug/img/flow_distributor.svg
 create mode 100644 doc/guides/sample_app_ug/img/server_node_efd.svg
 create mode 100644 doc/guides/sample_app_ug/server_node_efd.rst
 delete mode 100644 examples/flow_distributor/Makefile
 delete mode 100644 examples/flow_distributor/distributor/Makefile
 delete mode 100644 examples/flow_distributor/distributor/args.c
 delete mode 100644 examples/flow_distributor/distributor/args.h
 delete mode 100644 examples/flow_distributor/distributor/init.c
 delete mode 100644 examples/flow_distributor/distributor/init.h
 delete mode 100644 examples/flow_distributor/distributor/main.c
 delete mode 100644 examples/flow_distributor/node/Makefile
 delete mode 100644 examples/flow_distributor/node/node.c
 delete mode 100644 examples/flow_distributor/shared/common.h
 create mode 100644 examples/server_node_efd/Makefile
 create mode 100644 examples/server_node_efd/node/Makefile
 create mode 100644 examples/server_node_efd/node/node.c
 create mode 100644 examples/server_node_efd/server/Makefile
 create mode 100644 examples/server_node_efd/server/args.c
 create mode 100644 examples/server_node_efd/server/args.h
 create mode 100644 examples/server_node_efd/server/init.c
 create mode 100644 examples/server_node_efd/server/init.h
 create mode 100644 examples/server_node_efd/server/main.c
 create mode 100644 examples/server_node_efd/shared/common.h

diff --git a/MAINTAINERS b/MAINTAINERS
index f071138..cfbec21 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -551,8 +551,8 @@ M: Pablo de Lara Guarch <pablo.de.lara.guarch@intel.com>
 F: lib/librte_efd/
 F: doc/guides/prog_guide/efd_lib.rst
 F: app/test/test_efd*
-F: examples/flow_distributor/
-F: doc/guides/sample_app_ug/flow_distributor.rst
+F: examples/server_node_efd/
+F: doc/guides/sample_app_ug/server_node_efd.rst
 
 Hashes
 M: Bruce Richardson <bruce.richardson@intel.com>
diff --git a/doc/api/examples.dox b/doc/api/examples.dox
index c13e574..9a48f5f 100644
--- a/doc/api/examples.dox
+++ b/doc/api/examples.dox
@@ -52,10 +52,6 @@
 @example load_balancer/init.c
 @example load_balancer/main.c
 @example load_balancer/runtime.c
-@example flow_distributor/distributor/args.c
-@example flow_distributor/distributor/init.c
-@example flow_distributor/distributor/main.c
-@example flow_distributor/node/node.c
 @example multi_process/client_server_mp/mp_client/client.c
 @example multi_process/client_server_mp/mp_server/args.c
 @example multi_process/client_server_mp/mp_server/init.c
@@ -94,6 +90,10 @@
 @example quota_watermark/qw/init.c
 @example quota_watermark/qw/main.c
 @example rxtx_callbacks/main.c
+@example server_node_efd/server/args.c
+@example server_node_efd/server/init.c
+@example server_node_efd/server/main.c
+@example server_node_efd/node/node.c
 @example skeleton/basicfwd.c
 @example tep_termination/main.c
 @example tep_termination/vxlan.c
diff --git a/doc/guides/sample_app_ug/flow_distributor.rst b/doc/guides/sample_app_ug/flow_distributor.rst
deleted file mode 100644
index a12df76..0000000
--- a/doc/guides/sample_app_ug/flow_distributor.rst
+++ /dev/null
@@ -1,494 +0,0 @@
-..  BSD LICENSE
-    Copyright(c) 2016-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.
-
-Flow Distributor Sample Application
-===================================
-
-This sample application demonstrates the use of EFD library as a flow-level
-load balancer, for more information about the EFD Library please refer to the
-DPDK programmer's guide.
-
-This sample application is a variant of the
-:ref:`client-server sample application <multi_process_app>`
-where a specific target node is specified for every and each flow
-(not in a round-robin fashion as the original load balancing sample application).
-
-Overview
---------
-
-The architecture of the EFD flow-based load balancer sample application is
-presented in the following figure.
-
-.. _figure_efd_sample_app_overview:
-
-.. figure:: img/flow_distributor.*
-
-   Using EFD as a Flow-Level Load Balancer
-
-As shown in :numref:`figure_efd_sample_app_overview`,
-the sample application consists of a front-end node (distributor)
-using the EFD library to create a load-balancing table for flows,
-for each flow a target backend worker node is specified. The EFD table does not
-store the flow key (unlike a regular hash table), and hence, it can
-individually load-balance millions of flows (number of targets * maximum number
-of flows fit in a flow table per target) while still fitting in CPU cache.
-
-It should be noted that although they are referred to as nodes, the frontend
-distributor and worker nodes are processes running on the same platform.
-
-Front-end Distributor
-~~~~~~~~~~~~~~~~~~~~~
-
-Upon initializing, the frontend distributor node (process) creates a flow
-distributor table (based on the EFD library) which is populated with flow
-information and its intended target node.
-
-The sample application assigns a specific target node_id (process) for each of
-the IP destination addresses as follows:
-
-.. code-block:: c
-
-    node_id = i % num_nodes; /* Target node id is generated */
-    ip_dst = rte_cpu_to_be_32(i); /* Specific ip destination address is
-                                     assigned to this target node */
-
-then the pair of <key,target> is inserted into the flow distribution table.
-
-The main loop of the the distributor node receives a burst of packets, then for
-each packet, a flow key (IP destination address) is extracted. The flow
-distributor table is looked up and the target node id is returned.  Packets are
-then enqueued to the specified target node id.
-
-It should be noted that flow distributor table is not a membership test table.
-I.e. if the key has already been inserted the target node id will be correct,
-but for new keys the flow distributor table will return a value (which can be
-valid).
-
-Backend Worker Nodes
-~~~~~~~~~~~~~~~~~~~~
-
-Upon initializing, the worker node (process) creates a flow table (a regular
-hash table that stores the key default size 1M flows) which is populated with
-only the flow information that is serviced at this node. This flow key is
-essential to point out new keys that have not been inserted before.
-
-The worker node's main loop is simply receiving packets then doing a hash table
-lookup. If a match occurs then statistics are updated for flows serviced by
-this node. If no match is found in the local hash table then this indicates
-that this is a new flow, which is dropped.
-
-
-Compiling the Application
--------------------------
-
-The sequence of steps used to build the application is:
-
-#.  Export the required environment variables:
-
-    .. code-block:: console
-
-        export RTE_SDK=/path/to/rte_sdk
-        export RTE_TARGET=x86_64-native-linuxapp-gcc
-
-#.  Build the application executable file:
-
-    .. code-block:: console
-
-        cd ${RTE_SDK}/examples/flow_distributor/
-        make
-
-    For more details on how to build the DPDK libraries and sample
-    applications,
-    please refer to the *DPDK Getting Started Guide.*
-
-
-Running the Application
------------------------
-
-The application has two binaries to be run: the front-end distributor
-and the back-end node.
-
-The frontend distributor (distributor) has the following command line options::
-
-    ./distributor [EAL options] -- -p PORTMASK -n NUM_NODES -f NUM_FLOWS
-
-Where,
-
-* ``-p PORTMASK:`` Hexadecimal bitmask of ports to configure
-* ``-n NUM_NODES:`` Number of back-end nodes that will be used
-* ``-f NUM_FLOWS:`` Number of flows to be added in the EFD table (1 million, by default)
-
-The back-end node (node) has the following command line options::
-
-    ./node [EAL options] -- -n NODE_ID
-
-Where,
-
-* ``-n NODE_ID:`` Node ID, which cannot be equal or higher than NUM_MODES
-
-
-First, the distributor app must be launched, with the number of nodes that will be run.
-Once it has been started, the node instances can be run, with different NODE_ID.
-These instances have to be run as secondary processes, with ``--proc-type=secondary``
-in the EAL options, which will attach to the primary process memory, and therefore,
-they can access the queues created by the primary process to distribute packets.
-
-To successfully run the application, the command line used to start the
-application has to be in sync with the traffic flows configured on the traffic
-generator side.
-
-For examples of application command lines and traffic generator flows, please
-refer to the DPDK Test Report. For more details on how to set up and run the
-sample applications provided with DPDK package, please refer to the
-:ref:`DPDK Getting Started Guide for Linux <linux_gsg>` and
-:ref:`DPDK Getting Started Guide for FreeBSD <freebsd_gsg>`.
-
-
-Explanation
------------
-
-As described in previous sections, there are two processes in this example.
-
-The first process, the front-end distributor, creates and populates the EFD table,
-which is used to distribute packets to nodes, which the number of flows
-specified in the command line (1 million, by default).
-
-
-.. code-block:: c
-
-    static void
-    create_flow_distributor_table(void)
-    {
-        uint8_t socket_id = rte_socket_id();
-
-        /* create table */
-        efd_table = rte_efd_create("flow table", num_flows * 2, sizeof(uint32_t),
-                        1 << socket_id, socket_id);
-
-        if (efd_table == NULL)
-            rte_exit(EXIT_FAILURE, "Problem creating the flow table\n");
-    }
-
-    static void
-    populate_flow_distributor_table(void)
-    {
-        unsigned int i;
-        int32_t ret;
-        uint32_t ip_dst;
-        uint8_t socket_id = rte_socket_id();
-        uint64_t node_id;
-
-        /* Add flows in table */
-        for (i = 0; i < num_flows; i++) {
-            node_id = i % num_nodes;
-
-            ip_dst = rte_cpu_to_be_32(i);
-            ret = rte_efd_update(efd_table, socket_id,
-                            (void *)&ip_dst, (efd_value_t)node_id);
-            if (ret < 0)
-                rte_exit(EXIT_FAILURE, "Unable to add entry %u in "
-                                    "flow distributor table\n", i);
-        }
-
-        printf("EFD table: Adding 0x%x keys\n", num_flows);
-    }
-
-After initialization, packets are received from the enabled ports, and the IPv4
-address from the packets is used as a key to look up in the EFD table,
-which tells the node where the packet has to be distributed.
-
-.. code-block:: c
-
-    static void
-    process_packets(uint32_t port_num __rte_unused, struct rte_mbuf *pkts[],
-            uint16_t rx_count, unsigned int socket_id)
-    {
-        uint16_t i;
-        uint8_t node;
-        efd_value_t data[EFD_BURST_MAX];
-        const void *key_ptrs[EFD_BURST_MAX];
-
-        struct ipv4_hdr *ipv4_hdr;
-        uint32_t ipv4_dst_ip[EFD_BURST_MAX];
-
-        for (i = 0; i < rx_count; i++) {
-            /* Handle IPv4 header.*/
-            ipv4_hdr = rte_pktmbuf_mtod_offset(pkts[i], struct ipv4_hdr *,
-                    sizeof(struct ether_hdr));
-            ipv4_dst_ip[i] = ipv4_hdr->dst_addr;
-            key_ptrs[i] = (void *)&ipv4_dst_ip[i];
-        }
-
-        rte_efd_lookup_bulk(efd_table, socket_id, rx_count,
-                    (const void **) key_ptrs, data);
-        for (i = 0; i < rx_count; i++) {
-            node = (uint8_t) ((uintptr_t)data[i]);
-
-            if (node >= num_nodes) {
-                /*
-                 * Node is out of range, which means that
-                 * flow has not been inserted
-                 */
-                flow_dist_stats.drop++;
-                rte_pktmbuf_free(pkts[i]);
-            } else {
-                flow_dist_stats.distributed++;
-                enqueue_rx_packet(node, pkts[i]);
-            }
-        }
-
-        for (i = 0; i < num_nodes; i++)
-            flush_rx_queue(i);
-    }
-
-The burst of packets received is enqueued in temporary buffers (per node),
-and enqueued in the shared ring between the distributor and the node.
-After this, a new burst of packets is received and this process is
-repeated infinitely.
-
-.. code-block:: c
-
-    static void
-    flush_rx_queue(uint16_t node)
-    {
-        uint16_t j;
-        struct node *cl;
-
-        if (cl_rx_buf[node].count == 0)
-            return;
-
-        cl = &nodes[node];
-        if (rte_ring_enqueue_bulk(cl->rx_q, (void **)cl_rx_buf[node].buffer,
-                cl_rx_buf[node].count) != 0){
-            for (j = 0; j < cl_rx_buf[node].count; j++)
-                rte_pktmbuf_free(cl_rx_buf[node].buffer[j]);
-            cl->stats.rx_drop += cl_rx_buf[node].count;
-        } else
-            cl->stats.rx += cl_rx_buf[node].count;
-
-        cl_rx_buf[node].count = 0;
-    }
-
-The second process, the back-end node, receives the packets from the shared
-ring with the distributor and send them out, if they belong to the node.
-
-At initialization, it attaches to the distributor process memory, to have
-access to the shared ring, parameters and statistics.
-
-.. code-block:: c
-
-    rx_ring = rte_ring_lookup(get_rx_queue_name(node_id));
-    if (rx_ring == NULL)
-        rte_exit(EXIT_FAILURE, "Cannot get RX ring - "
-                "is distributor process running?\n");
-
-    mp = rte_mempool_lookup(PKTMBUF_POOL_NAME);
-    if (mp == NULL)
-        rte_exit(EXIT_FAILURE, "Cannot get mempool for mbufs\n");
-
-    mz = rte_memzone_lookup(MZ_SHARED_INFO);
-    if (mz == NULL)
-        rte_exit(EXIT_FAILURE, "Cannot get port info structure\n");
-    info = mz->addr;
-    tx_stats = &(info->tx_stats[node_id]);
-    filter_stats = &(info->filter_stats[node_id]);
-
-Then, the hash table that contains the flows that will be handled
-by the node is created and populated.
-
-.. code-block:: c
-
-    static struct rte_hash *
-    create_hash_table(const struct shared_info *info)
-    {
-        uint32_t num_flows_node = info->num_flows / info->num_nodes;
-        char name[RTE_HASH_NAMESIZE];
-        struct rte_hash *h;
-
-        /* create table */
-        struct rte_hash_parameters hash_params = {
-            .entries = num_flows_node * 2, /* table load = 50% */
-            .key_len = sizeof(uint32_t), /* Store IPv4 dest IP address */
-            .socket_id = rte_socket_id(),
-            .hash_func_init_val = 0,
-        };
-
-        snprintf(name, sizeof(name), "hash_table_%d", node_id);
-        hash_params.name = name;
-        h = rte_hash_create(&hash_params);
-
-        if (h == NULL)
-            rte_exit(EXIT_FAILURE,
-                    "Problem creating the hash table for node %d\n",
-                    node_id);
-        return h;
-    }
-
-    static void
-    populate_hash_table(const struct rte_hash *h, const struct shared_info *info)
-    {
-        unsigned int i;
-        int32_t ret;
-        uint32_t ip_dst;
-        uint32_t num_flows_node = 0;
-        uint64_t target_node;
-
-        /* Add flows in table */
-        for (i = 0; i < info->num_flows; i++) {
-            target_node = i % info->num_nodes;
-            if (target_node != node_id)
-                continue;
-
-            ip_dst = rte_cpu_to_be_32(i);
-
-            ret = rte_hash_add_key(h, (void *) &ip_dst);
-            if (ret < 0)
-                rte_exit(EXIT_FAILURE, "Unable to add entry %u "
-                        "in hash table\n", i);
-            else
-                num_flows_node++;
-
-        }
-
-        printf("Hash table: Adding 0x%x keys\n", num_flows_node);
-    }
-
-After initialization, packets are dequeued from the shared ring
-(from the distributor) and, like in the distributor process,
-the IPv4 address from the packets is used as a key to look up in the hash table.
-If there is a hit, packet is stored in a buffer, to be eventually transmitted
-in one of the enabled ports. If key is not there, packet is dropped, since the
-flow is not handled by the node.
-
-.. code-block:: c
-
-    static inline void
-    handle_packets(struct rte_hash *h, struct rte_mbuf **bufs, uint16_t num_packets)
-    {
-        struct ipv4_hdr *ipv4_hdr;
-        uint32_t ipv4_dst_ip[PKT_READ_SIZE];
-        const void *key_ptrs[PKT_READ_SIZE];
-        unsigned int i;
-        int32_t positions[PKT_READ_SIZE] = {0};
-
-        for (i = 0; i < num_packets; i++) {
-            /* Handle IPv4 header.*/
-            ipv4_hdr = rte_pktmbuf_mtod_offset(bufs[i], struct ipv4_hdr *,
-                    sizeof(struct ether_hdr));
-            ipv4_dst_ip[i] = ipv4_hdr->dst_addr;
-            key_ptrs[i] = &ipv4_dst_ip[i];
-        }
-        /* Check if packets belongs to any flows handled by this node */
-        rte_hash_lookup_bulk(h, key_ptrs, num_packets, positions);
-
-        for (i = 0; i < num_packets; i++) {
-            if (likely(positions[i] >= 0)) {
-                filter_stats->passed++;
-                transmit_packet(bufs[i]);
-            } else {
-                filter_stats->drop++;
-                /* Drop packet, as flow is not handled by this node */
-                rte_pktmbuf_free(bufs[i]);
-            }
-        }
-    }
-
-Finally, note that both processes updates statistics, such as transmitted, received
-and dropped packets, which are shown and refreshed by the distributor app.
-
-.. code-block:: c
-
-    static void
-    do_stats_display(void)
-    {
-        unsigned int i, j;
-        const char clr[] = {27, '[', '2', 'J', '\0'};
-        const char topLeft[] = {27, '[', '1', ';', '1', 'H', '\0'};
-        uint64_t port_tx[RTE_MAX_ETHPORTS], port_tx_drop[RTE_MAX_ETHPORTS];
-        uint64_t node_tx[MAX_NODES], node_tx_drop[MAX_NODES];
-
-        /* to get TX stats, we need to do some summing calculations */
-        memset(port_tx, 0, sizeof(port_tx));
-        memset(port_tx_drop, 0, sizeof(port_tx_drop));
-        memset(node_tx, 0, sizeof(node_tx));
-        memset(node_tx_drop, 0, sizeof(node_tx_drop));
-
-        for (i = 0; i < num_nodes; i++) {
-            const struct tx_stats *tx = &info->tx_stats[i];
-
-            for (j = 0; j < info->num_ports; j++) {
-                const uint64_t tx_val = tx->tx[info->id[j]];
-                const uint64_t drop_val = tx->tx_drop[info->id[j]];
-
-                port_tx[j] += tx_val;
-                port_tx_drop[j] += drop_val;
-                node_tx[i] += tx_val;
-                node_tx_drop[i] += drop_val;
-            }
-        }
-
-        /* Clear screen and move to top left */
-        printf("%s%s", clr, topLeft);
-
-        printf("PORTS\n");
-        printf("-----\n");
-        for (i = 0; i < info->num_ports; i++)
-            printf("Port %u: '%s'\t", (unsigned int)info->id[i],
-                    get_printable_mac_addr(info->id[i]));
-        printf("\n\n");
-        for (i = 0; i < info->num_ports; i++) {
-            printf("Port %u - rx: %9"PRIu64"\t"
-                    "tx: %9"PRIu64"\n",
-                    (unsigned int)info->id[i], info->rx_stats.rx[i],
-                    port_tx[i]);
-        }
-
-        printf("\nFLOW DISTRIBUTOR\n");
-        printf("-----\n");
-        printf("distributed: %9"PRIu64", drop: %9"PRIu64"\n",
-                flow_dist_stats.distributed, flow_dist_stats.drop);
-
-        printf("\nNODES\n");
-        printf("-------\n");
-        for (i = 0; i < num_nodes; i++) {
-            const unsigned long long rx = nodes[i].stats.rx;
-            const unsigned long long rx_drop = nodes[i].stats.rx_drop;
-            const struct filter_stats *filter = &info->filter_stats[i];
-
-            printf("Node %2u - rx: %9llu, rx_drop: %9llu\n"
-                    "            tx: %9"PRIu64", tx_drop: %9"PRIu64"\n"
-                    "            filter_passed: %9"PRIu64", "
-                    "filter_drop: %9"PRIu64"\n",
-                    i, rx, rx_drop, node_tx[i], node_tx_drop[i],
-                    filter->passed, filter->drop);
-        }
-
-        printf("\n");
-    }
diff --git a/doc/guides/sample_app_ug/img/flow_distributor.svg b/doc/guides/sample_app_ug/img/flow_distributor.svg
deleted file mode 100644
index 9aee30b..0000000
--- a/doc/guides/sample_app_ug/img/flow_distributor.svg
+++ /dev/null
@@ -1,1254 +0,0 @@
-<?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 efd_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"
-		xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="8.2496in" height="5.89673in"
-		viewBox="0 0 593.971 424.565" xml:space="preserve" color-interpolation-filters="sRGB" class="st27">
-	<v:documentProperties v:langID="1033" v:viewMarkup="false">
-		<v:userDefs>
-			<v:ud v:nameU="msvSubprocessMaster" v:prompt="" v:val="VT4(Rectangle)"/>
-			<v:ud v:nameU="msvNoAutoConnect" v:val="VT0(1):26"/>
-		</v:userDefs>
-	</v:documentProperties>
-
-	<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:0.833336em}
-		.st5 {fill:#feffff;font-family:Calibri;font-size:0.75em}
-		.st6 {fill:none;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.22}
-		.st7 {fill:none;stroke:#2e75b5;stroke-width:2.25}
-		.st8 {fill:#305497;stroke:#2e75b5;stroke-width:1}
-		.st9 {fill:#feffff;font-family:Calibri;font-size:0.833336em;font-weight:bold}
-		.st10 {fill:#5b9bd5;fill-opacity:0.22;filter:url(#filter_2)}
-		.st11 {fill:#5b9bd5}
-		.st12 {stroke:#c7c8c8;stroke-width:0.25}
-		.st13 {fill:#acccea;stroke:#c7c8c8;stroke-width:0.25}
-		.st14 {fill:#feffff;font-family:Calibri;font-size:1.00001em;font-weight:bold}
-		.st15 {fill:#ed7d31;stroke:#c7c8c8;stroke-width:0.25}
-		.st16 {fill:#deebf6;stroke:#c7c8c8;stroke-width:0.25}
-		.st17 {marker-end:url(#mrkr5-212);stroke:#ff0000;stroke-linecap:round;stroke-linejoin:round;stroke-width:1}
-		.st18 {fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-opacity:1;stroke-width:0.28409090909091}
-		.st19 {fill:none;stroke:#2e75b5;stroke-width:1}
-		.st20 {fill:#5b9bd5;font-family:Calibri;font-size:1.00001em}
-		.st21 {fill:none;stroke:none;stroke-width:0.25}
-		.st22 {font-size:1em}
-		.st23 {fill:#ffffff}
-		.st24 {stroke:#5b9bd5;stroke-dasharray:1.5,3;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5}
-		.st25 {marker-end:url(#mrkr5-444);stroke:#5b9bd5;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5}
-		.st26 {fill:#5b9bd5;fill-opacity:1;stroke:#5b9bd5;stroke-opacity:1;stroke-width:0.37313432835821}
-		.st27 {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-212" class="st18" 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>
-		<marker id="mrkr5-444" class="st26" v:arrowType="5" v:arrowSize="2" v:setback="4.69" refX="-4.69" orient="auto"
-				markerUnits="strokeWidth" overflow="visible">
-			<use xlink:href="#lend5" transform="scale(-2.68,-2.68) "/>
-		</marker>
-	</defs>
-	<defs id="Filters">
-		<filter id="filter_2">
-			<feGaussianBlur stdDeviation="2"/>
-		</filter>
-	</defs>
-	<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
-		<v:userDefs>
-			<v:ud v:nameU="msvThemeOrder" v:val="VT0(0):26"/>
-		</v:userDefs>
-		<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(319.501,-335.688)">
-			<title>Rectangle.58</title>
-			<desc>Key 1</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
-			<g id="shadow3-2" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-			<text x="4.74" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key 1</text>		</g>
-		<g id="shape4-7" v:mID="4" v:groupContext="shape" transform="translate(353.251,-335.688)">
-			<title>Rectangle.59</title>
-			<desc>Action 1</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
-			<g id="shadow4-8" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-			<text x="4.62" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action 1</text>		</g>
-		<g id="shape5-13" v:mID="5" v:groupContext="shape" transform="translate(400.501,-335.688)">
-			<title>Rectangle.60</title>
-			<desc>Key 2</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
-			<g id="shadow5-14" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-			<text x="4.74" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key 2</text>		</g>
-		<g id="shape6-19" v:mID="6" v:groupContext="shape" transform="translate(434.251,-335.688)">
-			<title>Rectangle.61</title>
-			<desc>Action 2</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
-			<g id="shadow6-20" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-			<text x="4.62" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action 2</text>		</g>
-		<g id="shape7-25" v:mID="7" v:groupContext="shape" transform="translate(481.501,-335.688)">
-			<title>Rectangle.62</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow7-26" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-		</g>
-		<g id="shape8-30" v:mID="8" v:groupContext="shape" transform="translate(515.251,-335.688)">
-			<title>Rectangle.63</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow8-31" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-		</g>
-		<g id="shape9-35" v:mID="9" v:groupContext="shape" transform="translate(319.501,-313.188)">
-			<title>Rectangle.64</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow9-36" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-		</g>
-		<g id="shape10-40" v:mID="10" v:groupContext="shape" transform="translate(353.251,-313.188)">
-			<title>Rectangle.65</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow10-41" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-		</g>
-		<g id="shape11-45" v:mID="11" v:groupContext="shape" transform="translate(400.501,-313.188)">
-			<title>Rectangle.66</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow11-46" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-		</g>
-		<g id="shape12-50" v:mID="12" v:groupContext="shape" transform="translate(434.251,-313.188)">
-			<title>Rectangle.67</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow12-51" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-		</g>
-		<g id="shape13-55" v:mID="13" v:groupContext="shape" transform="translate(481.501,-313.188)">
-			<title>Rectangle.68</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow13-56" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-		</g>
-		<g id="shape14-60" v:mID="14" v:groupContext="shape" transform="translate(515.251,-313.188)">
-			<title>Rectangle.69</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow14-61" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-		</g>
-		<g id="shape15-65" v:mID="15" v:groupContext="shape" transform="translate(319.501,-277.188)">
-			<title>Rectangle.70</title>
-			<desc>Key x</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
-			<g id="shadow15-66" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-			<text x="5.11" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key x</text>		</g>
-		<g id="shape16-71" v:mID="16" v:groupContext="shape" transform="translate(353.251,-277.188)">
-			<title>Rectangle.71</title>
-			<desc>Action x</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
-			<g id="shadow16-72" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-			<text x="4.99" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action x</text>		</g>
-		<g id="shape17-77" v:mID="17" v:groupContext="shape" transform="translate(400.501,-277.188)">
-			<title>Rectangle.72</title>
-			<desc>Key y</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
-			<g id="shadow17-78" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-			<text x="5.01" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key y</text>		</g>
-		<g id="shape18-83" v:mID="18" v:groupContext="shape" transform="translate(434.251,-277.188)">
-			<title>Rectangle.73</title>
-			<desc>Action y</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
-			<g id="shadow18-84" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-			<text x="4.89" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action y</text>		</g>
-		<g id="shape19-89" v:mID="19" v:groupContext="shape" transform="translate(481.501,-277.188)">
-			<title>Rectangle.74</title>
-			<desc>Key z</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
-			<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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-			<text x="5.3" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key z</text>		</g>
-		<g id="shape20-95" v:mID="20" v:groupContext="shape" transform="translate(515.251,-277.188)">
-			<title>Rectangle.75</title>
-			<desc>Action z</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
-			<g id="shadow20-96" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-			<text x="5.18" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action z</text>		</g>
-		<g id="shape21-101" v:mID="21" v:groupContext="shape" transform="translate(319.501,-240.687)">
-			<title>Rectangle.76</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow21-102" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-		</g>
-		<g id="shape22-106" v:mID="22" v:groupContext="shape" transform="translate(353.251,-240.687)">
-			<title>Rectangle.77</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow22-107" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-		</g>
-		<g id="shape23-111" v:mID="23" v:groupContext="shape" transform="translate(400.501,-240.687)">
-			<title>Rectangle.78</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow23-112" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-		</g>
-		<g id="shape24-116" v:mID="24" v:groupContext="shape" transform="translate(434.251,-240.687)">
-			<title>Rectangle.79</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow24-117" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-		</g>
-		<g id="shape25-121" v:mID="25" v:groupContext="shape" transform="translate(481.501,-240.687)">
-			<title>Rectangle.80</title>
-			<desc>Key N</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
-			<g id="shadow25-122" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-			<text x="5.21" y="418.26" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key N</text>		</g>
-		<g id="shape26-127" v:mID="26" v:groupContext="shape" transform="translate(515.251,-240.687)">
-			<title>Rectangle.81</title>
-			<desc>Action N</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
-			<g id="shadow26-128" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-			<text x="5.67" y="418.26" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action N</text>		</g>
-		<g id="shape27-133" v:mID="27" v:groupContext="shape" transform="translate(317.251,-231.687)">
-			<title>Rectangle.82</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow27-134" 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="st1">
-				<rect x="0" y="289.065" width="245.25" height="135.5" class="st6"/>
-			</g>
-			<rect x="0" y="289.065" width="245.25" height="135.5" class="st7"/>
-		</g>
-		<g id="shape28-138" v:mID="28" v:groupContext="shape" transform="translate(328.501,-362.688)">
-			<title>Sheet.28</title>
-			<desc>Local Table for N Specific Flows Serviced at Node 1</desc>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="110.423" cy="418.94" width="220.85" height="11.25"/>
-			<rect x="0" y="413.315" width="220.846" height="11.25" class="st8"/>
-			<text x="5.77" y="421.94" class="st9" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Local Table for N Specific Flows Serviced at Node 1</text>		</g>
-		<g id="group34-141" transform="translate(66.0294,-165.569)" v:mID="34" v:groupContext="group">
-			<v:custProps>
-				<v:cp v:nameU="AssetNumber" v:lbl="Asset Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="SerialNumber" v:lbl="Serial Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Location" v:lbl="Location" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Building" v:lbl="Building" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Room" v:lbl="Room" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Manufacturer" v:lbl="Manufacturer" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="ProductNumber" v:lbl="Product Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="PartNumber" v:lbl="Part Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="ProductDescription" v:lbl="Product Description" v:prompt="" v:type="0" v:format=""
-						v:sortKey="Equipment" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="NetworkName" v:lbl="Network Name" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="IPAddress" v:lbl="IP Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="SubnetMask" v:lbl="Subnet Mask" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="AdminInterface" v:lbl="Administrative Interface" v:prompt="" v:type="0" v:format=""
-						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="NumberofPorts" v:lbl="Number of Ports" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="CommunityString" v:lbl="Community String" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="NetworkDescription" v:lbl="Network Description" v:prompt="" v:type="0" v:format=""
-						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="MACAddress" v:lbl="MAC Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
-						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Equipment)"/>
-				<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
-						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Device)"/>
-				<v:cp v:nameU="SubShapeType" v:lbl="SubShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
-						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Load balancer)"/>
-			</v:custProps>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
-				<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
-				<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
-				<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
-			</v:userDefs>
-			<title>Load balancer</title>
-			<g id="shape35-142" v:mID="35" v:groupContext="shape" transform="translate(0,-7.33146)">
-				<title>Sheet.35</title>
-				<g id="shadow35-143" 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="st1">
-					<path d="M54 367.23 L18 367.23 L0 377.86 L0 424.56 L72 424.56 L72 377.86 L54 367.23 Z" class="st10"/>
-					<path d="M0 377.86 L72 377.86" class="st6"/>
-					<path d="M54 367.23 L18 367.23 L0 377.86 L0 424.56 L72 424.56 L72 377.86 L54 367.23" class="st6"/>
-				</g>
-				<path d="M54 367.23 L18 367.23 L0 377.86 L0 424.56 L72 424.56 L72 377.86 L54 367.23 Z" class="st11"/>
-				<path d="M0 377.86 L72 377.86" class="st12"/>
-				<path d="M54 367.23 L18 367.23 L0 377.86 L0 424.56 L72 424.56 L72 377.86 L54 367.23" class="st12"/>
-			</g>
-			<g id="shape36-152" v:mID="36" v:groupContext="shape" transform="translate(8.03054,-12.9324)">
-				<title>Sheet.36</title>
-				<g id="shadow36-153" 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="st1">
-					<path d="M45.34 421.81 L41.2 422.66 L44.12 424.56 L49.68 423.16 L48.75 417.51 L45.8 415.59 L46.69 419.68 L36.97
-								 413.34 L35.6 415.45 L45.34 421.81 ZM50.83 405.36 L39.2 405.36 L39.2 407.88 L50.8 407.88 L47.82 410.83
-								 L51.34 410.83 L55.21 406.61 L51.32 402.39 L47.83 402.39 L50.83 405.36 ZM46.49 392.01 L36.75 398.37
-								 L38.13 400.48 L47.84 394.14 L46.96 398.23 L49.91 396.31 L50.84 390.66 L45.28 389.26 L42.36 391.16
-								 L46.49 392.01 ZM27.71 397.16 C22.66 397.16 18.58 401.25 18.58 406.29 C18.58 411.33 22.66 415.42
-								 27.71 415.42 C32.75 415.42 36.84 411.33 36.84 406.29 C36.84 401.25 32.75 397.16 27.71 397.16 ZM27.71
-								 400.04 C31.15 400.04 33.96 402.84 33.96 406.29 C33.96 409.74 31.15 412.54 27.71 412.54 C24.26 412.54
-								 21.46 409.74 21.46 406.29 C21.46 402.84 24.26 400.04 27.71 400.04 ZM11.64 405.04 L0 405.04 L0 407.56
-								 L11.6 407.56 L8.62 410.51 L12.14 410.51 L16.01 406.29 L12.12 402.07 L8.64 402.07 L11.64 405.04 Z"
-							class="st2"/>
-				</g>
-				<path d="M45.34 421.81 L41.2 422.66 L44.12 424.56 L49.68 423.16 L48.75 417.51 L45.8 415.59 L46.69 419.68 L36.97 413.34
-							 L35.6 415.45 L45.34 421.81 ZM50.83 405.36 L39.2 405.36 L39.2 407.88 L50.8 407.88 L47.82 410.83 L51.34
-							 410.83 L55.21 406.61 L51.32 402.39 L47.83 402.39 L50.83 405.36 ZM46.49 392.01 L36.75 398.37 L38.13 400.48
-							 L47.84 394.14 L46.96 398.23 L49.91 396.31 L50.84 390.66 L45.28 389.26 L42.36 391.16 L46.49 392.01 ZM27.71
-							 397.16 C22.66 397.16 18.58 401.25 18.58 406.29 C18.58 411.33 22.66 415.42 27.71 415.42 C32.75 415.42
-							 36.84 411.33 36.84 406.29 C36.84 401.25 32.75 397.16 27.71 397.16 ZM27.71 400.04 C31.15 400.04 33.96
-							 402.84 33.96 406.29 C33.96 409.74 31.15 412.54 27.71 412.54 C24.26 412.54 21.46 409.74 21.46 406.29
-							 C21.46 402.84 24.26 400.04 27.71 400.04 ZM11.64 405.04 L0 405.04 L0 407.56 L11.6 407.56 L8.62 410.51
-							 L12.14 410.51 L16.01 406.29 L12.12 402.07 L8.64 402.07 L11.64 405.04 Z" class="st13"/>
-			</g>
-		</g>
-		<g id="shape37-157" v:mID="37" v:groupContext="shape" transform="translate(21.0294,-45.4375)">
-			<title>Rectangle</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow37-158" 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="st1">
-				<rect x="0" y="336.433" width="135" height="88.1315" class="st2"/>
-			</g>
-			<rect x="0" y="336.433" width="135" height="88.1315" class="st3"/>
-		</g>
-		<g id="shape38-162" v:mID="38" v:groupContext="shape" transform="translate(34.693,-126.438)">
-			<title>Sheet.38</title>
-			<desc>EFD Table</desc>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="49.3364" cy="415.565" width="98.68" height="18"/>
-			<rect x="0" y="406.565" width="98.6728" height="18" class="st8"/>
-			<text x="24.87" y="419.17" class="st14" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>EFD Table</text>		</g>
-		<g id="shape39-165" v:mID="39" v:groupContext="shape" transform="translate(30.0294,-99.4375)">
-			<title>Rectangle.39</title>
-			<desc>Group_id</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="26.9182" cy="415.565" width="53.84" height="18"/>
-			<g id="shadow39-166" 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="st1">
-				<rect x="0" y="406.565" width="53.8364" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="53.8364" height="18" class="st15"/>
-			<text x="7.87" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Group_id</text>		</g>
-		<g id="shape40-171" v:mID="40" v:groupContext="shape" transform="translate(93.193,-99.4375)">
-			<title>Rectangle.40</title>
-			<desc>Hash index</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="26.9182" cy="415.565" width="53.84" height="18"/>
-			<g id="shadow40-172" 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="st1">
-				<rect x="0" y="406.565" width="53.8364" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="53.8364" height="18" class="st15"/>
-			<text x="4.64" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Hash index</text>		</g>
-		<g id="shape41-177" v:mID="41" v:groupContext="shape" transform="translate(30.193,-82.4275)">
-			<title>Rectangle.41</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow41-178" 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="st1">
-				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
-			</g>
-			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
-		</g>
-		<g id="shape42-182" v:mID="42" v:groupContext="shape" transform="translate(30.193,-66.8125)">
-			<title>Rectangle.42</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow42-183" 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="st1">
-				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
-			</g>
-			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
-		</g>
-		<g id="shape43-187" v:mID="43" v:groupContext="shape" transform="translate(30.1112,-52.1875)">
-			<title>Rectangle.43</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow43-188" 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="st1">
-				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
-			</g>
-			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
-		</g>
-		<g id="shape44-192" v:mID="44" v:groupContext="shape" transform="translate(93.0294,-81.4375)">
-			<title>Rectangle.44</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow44-193" 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="st1">
-				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
-			</g>
-			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
-		</g>
-		<g id="shape45-197" v:mID="45" v:groupContext="shape" transform="translate(93.193,-66.8125)">
-			<title>Rectangle.45</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow45-198" 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="st1">
-				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
-			</g>
-			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
-		</g>
-		<g id="shape46-202" v:mID="46" v:groupContext="shape" transform="translate(93.193,-52.1875)">
-			<title>Rectangle.46</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow46-203" 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="st1">
-				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
-			</g>
-			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
-		</g>
-		<g id="shape47-207" v:mID="47" v:groupContext="shape" transform="translate(374.924,544.022) rotate(135)">
-			<title>Sheet.47</title>
-			<path d="M-0 417.75 A40.674 18.0151 -156.2 0 0 40.24 422.15 L40.49 421.89" class="st17"/>
-		</g>
-		<g id="shape48-213" v:mID="48" v:groupContext="shape" transform="translate(21.0294,-19)">
-			<title>Sheet.48</title>
-			<desc>Supports X*N Flows</desc>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="67.5" cy="415.565" width="135" height="18"/>
-			<rect x="0" y="406.565" width="135" height="18" class="st19"/>
-			<text x="19.05" y="419.17" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Supports X*N Flows</text>		</g>
-		<g id="shape49-216" v:mID="49" v:groupContext="shape" transform="translate(48.0294,-229.938)">
-			<title>Sheet.49</title>
-			<desc>Frontend Server or Load Balancer</desc>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="54" cy="400.94" width="108" height="47.25"/>
-			<rect x="0" y="377.315" width="108" height="47.25" class="st21"/>
-			<text x="14.56" y="397.34" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Frontend Server<v:newlineChar/><tspan
-						x="13.16" dy="1.2em" class="st22">or Load Balancer </tspan> </text>		</g>
-		<g id="group51-220" transform="translate(223.876,-310.938)" v:mID="51" v:groupContext="group">
-			<v:custProps>
-				<v:cp v:nameU="AssetNumber" v:lbl="Asset Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="SerialNumber" v:lbl="Serial Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Location" v:lbl="Location" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Building" v:lbl="Building" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Room" v:lbl="Room" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Manufacturer" v:lbl="Manufacturer" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="ProductNumber" v:lbl="Product Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="PartNumber" v:lbl="Part Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="ProductDescription" v:lbl="Product Description" v:prompt="" v:type="0" v:format=""
-						v:sortKey="Equipment" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="NetworkName" v:lbl="Network Name" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="IPAddress" v:lbl="IP Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="SubnetMask" v:lbl="Subnet Mask" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="AdminInterface" v:lbl="Administrative Interface" v:prompt="" v:type="0" v:format=""
-						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="NumberofPorts" v:lbl="Number of Ports" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="CommunityString" v:lbl="Community String" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="NetworkDescription" v:lbl="Network Description" v:prompt="" v:type="0" v:format=""
-						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="MACAddress" v:lbl="MAC Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="CPU" v:lbl="CPU" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Memory" v:lbl="Memory" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="OperatingSystem" v:lbl="Operating System" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="HardDriveSize" v:lbl="Hard Drive Capacity" v:prompt="" v:type="0" v:format=""
-						v:sortKey="Workstation" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Department" v:lbl="Department" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
-						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Equipment)"/>
-				<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
-						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Server)"/>
-				<v:cp v:nameU="BelongsTo" v:lbl="Belongs To" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-			</v:custProps>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
-				<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
-				<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
-				<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
-			</v:userDefs>
-			<title>Server</title>
-			<g id="shape52-221" v:mID="52" v:groupContext="shape" transform="translate(13.0183,0)">
-				<title>Sheet.52</title>
-				<g id="shadow52-222" 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="st1">
-					<rect x="0" y="352.565" width="45.9634" height="72" class="st2"/>
-				</g>
-				<rect x="0" y="352.565" width="45.9634" height="72" class="st3"/>
-			</g>
-			<g id="shape53-226" v:mID="53" v:groupContext="shape" transform="translate(47.371,-30.7354)">
-				<title>Sheet.53</title>
-				<g id="shadow53-227" 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="st1">
-					<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st2"/>
-				</g>
-				<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st13"/>
-			</g>
-			<g id="shape54-231" v:mID="54" v:groupContext="shape" transform="translate(30.51,-11.8022)">
-				<title>Sheet.54</title>
-				<v:userDefs>
-					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
-					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
-				</v:userDefs>
-				<g id="shadow54-232" 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="st1">
-					<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31
-								 L-0 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z"
-							class="st10"/>
-				</g>
-				<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31 L-0
-							 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z" class="st23"/>
-			</g>
-		</g>
-		<g id="shape59-239" v:mID="59" v:groupContext="shape" transform="translate(277.876,-373.938)">
-			<title>Sheet.59</title>
-			<path d="M-0 424.56 A111.108 53.2538 42.31 0 1 93.83 421.21 L94.14 421.41" class="st17"/>
-		</g>
-		<g id="shape60-244" v:mID="60" v:groupContext="shape" transform="translate(205.876,-283.938)">
-			<title>Sheet.60</title>
-			<desc>Backend Server 1</desc>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="54" cy="408.124" width="108" height="32.8815"/>
-			<rect x="0" y="391.683" width="108" height="32.8815" class="st21"/>
-			<text x="11.93" y="411.72" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Backend Server 1</text>		</g>
-		<g id="group61-247" transform="translate(223.876,-207.438)" v:mID="61" v:groupContext="group">
-			<v:custProps>
-				<v:cp v:nameU="AssetNumber" v:lbl="Asset Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="SerialNumber" v:lbl="Serial Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Location" v:lbl="Location" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Building" v:lbl="Building" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Room" v:lbl="Room" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Manufacturer" v:lbl="Manufacturer" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="ProductNumber" v:lbl="Product Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="PartNumber" v:lbl="Part Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="ProductDescription" v:lbl="Product Description" v:prompt="" v:type="0" v:format=""
-						v:sortKey="Equipment" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="NetworkName" v:lbl="Network Name" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="IPAddress" v:lbl="IP Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="SubnetMask" v:lbl="Subnet Mask" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="AdminInterface" v:lbl="Administrative Interface" v:prompt="" v:type="0" v:format=""
-						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="NumberofPorts" v:lbl="Number of Ports" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="CommunityString" v:lbl="Community String" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="NetworkDescription" v:lbl="Network Description" v:prompt="" v:type="0" v:format=""
-						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="MACAddress" v:lbl="MAC Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="CPU" v:lbl="CPU" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Memory" v:lbl="Memory" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="OperatingSystem" v:lbl="Operating System" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="HardDriveSize" v:lbl="Hard Drive Capacity" v:prompt="" v:type="0" v:format=""
-						v:sortKey="Workstation" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Department" v:lbl="Department" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
-						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Equipment)"/>
-				<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
-						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Server)"/>
-				<v:cp v:nameU="BelongsTo" v:lbl="Belongs To" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-			</v:custProps>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
-				<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
-				<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
-				<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
-			</v:userDefs>
-			<title>Server.61</title>
-			<g id="shape62-248" v:mID="62" v:groupContext="shape" transform="translate(13.0183,0)">
-				<title>Sheet.62</title>
-				<g id="shadow62-249" 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="st1">
-					<rect x="0" y="352.565" width="45.9634" height="72" class="st2"/>
-				</g>
-				<rect x="0" y="352.565" width="45.9634" height="72" class="st3"/>
-			</g>
-			<g id="shape63-253" v:mID="63" v:groupContext="shape" transform="translate(47.371,-30.7354)">
-				<title>Sheet.63</title>
-				<g id="shadow63-254" 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="st1">
-					<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st2"/>
-				</g>
-				<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st13"/>
-			</g>
-			<g id="shape64-258" v:mID="64" v:groupContext="shape" transform="translate(30.51,-11.8022)">
-				<title>Sheet.64</title>
-				<v:userDefs>
-					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
-					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
-				</v:userDefs>
-				<g id="shadow64-259" 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="st1">
-					<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31
-								 L-0 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z"
-							class="st10"/>
-				</g>
-				<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31 L-0
-							 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z" class="st23"/>
-			</g>
-		</g>
-		<g id="shape65-266" v:mID="65" v:groupContext="shape" transform="translate(205.876,-180.437)">
-			<title>Sheet.65</title>
-			<desc>Backend Server 2</desc>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="54" cy="408.124" width="108" height="32.8815"/>
-			<rect x="0" y="391.683" width="108" height="32.8815" class="st21"/>
-			<text x="11.93" y="411.72" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Backend Server 2</text>		</g>
-		<g id="group66-269" transform="translate(219.029,-58.9375)" v:mID="66" v:groupContext="group">
-			<v:custProps>
-				<v:cp v:nameU="AssetNumber" v:lbl="Asset Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="SerialNumber" v:lbl="Serial Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Location" v:lbl="Location" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Building" v:lbl="Building" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Room" v:lbl="Room" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Manufacturer" v:lbl="Manufacturer" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="ProductNumber" v:lbl="Product Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="PartNumber" v:lbl="Part Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="ProductDescription" v:lbl="Product Description" v:prompt="" v:type="0" v:format=""
-						v:sortKey="Equipment" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="NetworkName" v:lbl="Network Name" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="IPAddress" v:lbl="IP Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="SubnetMask" v:lbl="Subnet Mask" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="AdminInterface" v:lbl="Administrative Interface" v:prompt="" v:type="0" v:format=""
-						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="NumberofPorts" v:lbl="Number of Ports" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="CommunityString" v:lbl="Community String" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="NetworkDescription" v:lbl="Network Description" v:prompt="" v:type="0" v:format=""
-						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="MACAddress" v:lbl="MAC Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="CPU" v:lbl="CPU" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Memory" v:lbl="Memory" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="OperatingSystem" v:lbl="Operating System" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
-						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="HardDriveSize" v:lbl="Hard Drive Capacity" v:prompt="" v:type="0" v:format=""
-						v:sortKey="Workstation" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="Department" v:lbl="Department" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-				<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
-						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Equipment)"/>
-				<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
-						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Server)"/>
-				<v:cp v:nameU="BelongsTo" v:lbl="Belongs To" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
-						v:ask="false" v:langID="1033" v:cal="0"/>
-			</v:custProps>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
-				<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
-				<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
-				<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
-			</v:userDefs>
-			<title>Server.66</title>
-			<g id="shape67-270" v:mID="67" v:groupContext="shape" transform="translate(13.0183,0)">
-				<title>Sheet.67</title>
-				<g id="shadow67-271" 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="st1">
-					<rect x="0" y="352.565" width="45.9634" height="72" class="st2"/>
-				</g>
-				<rect x="0" y="352.565" width="45.9634" height="72" class="st3"/>
-			</g>
-			<g id="shape68-275" v:mID="68" v:groupContext="shape" transform="translate(47.371,-30.7354)">
-				<title>Sheet.68</title>
-				<g id="shadow68-276" 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="st1">
-					<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st2"/>
-				</g>
-				<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st13"/>
-			</g>
-			<g id="shape69-280" v:mID="69" v:groupContext="shape" transform="translate(30.51,-11.8022)">
-				<title>Sheet.69</title>
-				<v:userDefs>
-					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
-					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
-				</v:userDefs>
-				<g id="shadow69-281" 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="st1">
-					<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31
-								 L-0 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z"
-							class="st10"/>
-				</g>
-				<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31 L-0
-							 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z" class="st23"/>
-			</g>
-		</g>
-		<g id="shape70-288" v:mID="70" v:groupContext="shape" transform="translate(201.029,-26.056)">
-			<title>Sheet.70</title>
-			<desc>Backend Server X</desc>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="54" cy="408.124" width="108" height="32.8815"/>
-			<rect x="0" y="391.683" width="108" height="32.8815" class="st21"/>
-			<text x="11.86" y="411.72" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Backend Server X</text>		</g>
-		<g id="shape71-291" v:mID="71" v:groupContext="shape" transform="translate(684.44,239.627) rotate(90)">
-			<title>Sheet.71</title>
-			<path d="M0 424.56 L45 424.56" class="st24"/>
-		</g>
-		<g id="shape72-294" v:mID="72" v:groupContext="shape" transform="translate(6.85967,-22.443) rotate(-38.1076)">
-			<title>Sheet.72</title>
-			<path d="M-0 424.56 A96.1331 44.4001 55.03 0 1 68.24 420.56 L68.51 420.79" class="st17"/>
-		</g>
-		<g id="shape73-299" v:mID="73" v:groupContext="shape" transform="translate(328.501,-135.937)">
-			<title>Rectangle.73</title>
-			<desc>Key 1</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
-			<g id="shadow73-300" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-			<text x="4.74" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key 1</text>		</g>
-		<g id="shape74-305" v:mID="74" v:groupContext="shape" transform="translate(362.251,-135.937)">
-			<title>Rectangle.74</title>
-			<desc>Action 1</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
-			<g id="shadow74-306" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-			<text x="4.62" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action 1</text>		</g>
-		<g id="shape75-311" v:mID="75" v:groupContext="shape" transform="translate(409.501,-135.937)">
-			<title>Rectangle.75</title>
-			<desc>Key 2</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
-			<g id="shadow75-312" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-			<text x="4.74" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key 2</text>		</g>
-		<g id="shape76-317" v:mID="76" v:groupContext="shape" transform="translate(443.251,-135.937)">
-			<title>Rectangle.76</title>
-			<desc>Action 2</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
-			<g id="shadow76-318" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-			<text x="4.62" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action 2</text>		</g>
-		<g id="shape77-323" v:mID="77" v:groupContext="shape" transform="translate(490.501,-135.937)">
-			<title>Rectangle.77</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow77-324" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-		</g>
-		<g id="shape78-328" v:mID="78" v:groupContext="shape" transform="translate(524.251,-135.937)">
-			<title>Rectangle.78</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow78-329" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-		</g>
-		<g id="shape79-333" v:mID="79" v:groupContext="shape" transform="translate(328.501,-113.437)">
-			<title>Rectangle.79</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow79-334" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-		</g>
-		<g id="shape80-338" v:mID="80" v:groupContext="shape" transform="translate(362.251,-113.437)">
-			<title>Rectangle.80</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow80-339" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-		</g>
-		<g id="shape81-343" v:mID="81" v:groupContext="shape" transform="translate(409.501,-113.437)">
-			<title>Rectangle.81</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow81-344" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-		</g>
-		<g id="shape82-348" v:mID="82" v:groupContext="shape" transform="translate(443.251,-113.437)">
-			<title>Rectangle.82</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow82-349" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-		</g>
-		<g id="shape83-353" v:mID="83" v:groupContext="shape" transform="translate(490.501,-113.437)">
-			<title>Rectangle.83</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow83-354" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-		</g>
-		<g id="shape84-358" v:mID="84" v:groupContext="shape" transform="translate(524.251,-113.437)">
-			<title>Rectangle.84</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow84-359" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-		</g>
-		<g id="shape85-363" v:mID="85" v:groupContext="shape" transform="translate(328.501,-77.4375)">
-			<title>Rectangle.85</title>
-			<desc>Key x</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
-			<g id="shadow85-364" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-			<text x="5.11" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key x</text>		</g>
-		<g id="shape86-369" v:mID="86" v:groupContext="shape" transform="translate(362.251,-77.4375)">
-			<title>Rectangle.86</title>
-			<desc>Action x</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
-			<g id="shadow86-370" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-			<text x="4.99" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action x</text>		</g>
-		<g id="shape87-375" v:mID="87" v:groupContext="shape" transform="translate(409.501,-77.4375)">
-			<title>Rectangle.87</title>
-			<desc>Key y</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
-			<g id="shadow87-376" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-			<text x="5.01" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key y</text>		</g>
-		<g id="shape88-381" v:mID="88" v:groupContext="shape" transform="translate(443.251,-77.4375)">
-			<title>Rectangle.88</title>
-			<desc>Action y</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
-			<g id="shadow88-382" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-			<text x="4.89" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action y</text>		</g>
-		<g id="shape89-387" v:mID="89" v:groupContext="shape" transform="translate(490.501,-77.4375)">
-			<title>Rectangle.89</title>
-			<desc>Key z</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
-			<g id="shadow89-388" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-			<text x="5.3" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key z</text>		</g>
-		<g id="shape90-393" v:mID="90" v:groupContext="shape" transform="translate(524.251,-77.4375)">
-			<title>Rectangle.90</title>
-			<desc>Action z</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
-			<g id="shadow90-394" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-			<text x="5.18" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action z</text>		</g>
-		<g id="shape91-399" v:mID="91" v:groupContext="shape" transform="translate(328.501,-40.9375)">
-			<title>Rectangle.91</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow91-400" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-		</g>
-		<g id="shape92-404" v:mID="92" v:groupContext="shape" transform="translate(362.251,-40.9375)">
-			<title>Rectangle.92</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow92-405" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-		</g>
-		<g id="shape93-409" v:mID="93" v:groupContext="shape" transform="translate(409.501,-40.9375)">
-			<title>Rectangle.93</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow93-410" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-		</g>
-		<g id="shape94-414" v:mID="94" v:groupContext="shape" transform="translate(443.251,-40.9375)">
-			<title>Rectangle.94</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow94-415" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-		</g>
-		<g id="shape95-419" v:mID="95" v:groupContext="shape" transform="translate(490.501,-40.9375)">
-			<title>Rectangle.95</title>
-			<desc>Key N</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
-			<g id="shadow95-420" 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="st1">
-				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
-			<text x="5.21" y="418.26" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key N</text>		</g>
-		<g id="shape96-425" v:mID="96" v:groupContext="shape" transform="translate(524.251,-40.9375)">
-			<title>Rectangle.96</title>
-			<desc>Action N</desc>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
-			<g id="shadow96-426" 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="st1">
-				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
-			</g>
-			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
-			<text x="5.67" y="418.26" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action N</text>		</g>
-		<g id="shape97-431" v:mID="97" v:groupContext="shape" transform="translate(326.251,-31.9375)">
-			<title>Rectangle.97</title>
-			<v:userDefs>
-				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
-			</v:userDefs>
-			<g id="shadow97-432" 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="st1">
-				<rect x="0" y="289.065" width="245.25" height="135.5" class="st6"/>
-			</g>
-			<rect x="0" y="289.065" width="245.25" height="135.5" class="st7"/>
-		</g>
-		<g id="shape98-436" v:mID="98" v:groupContext="shape" transform="translate(337.501,-162.938)">
-			<title>Sheet.98</title>
-			<desc>Local Table for N Specific Flows Serviced at Node X</desc>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="110.423" cy="418.94" width="220.85" height="11.25"/>
-			<rect x="0" y="413.315" width="220.846" height="11.25" class="st8"/>
-			<text x="5.55" y="421.94" class="st9" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Local Table for N Specific Flows Serviced at Node X</text>		</g>
-		<g id="shape99-439" v:mID="99" v:groupContext="shape" transform="translate(-204.342,-29.4449) rotate(-53.7462)">
-			<title>Sheet.99</title>
-			<path d="M0 424.56 L160.37 424.56" class="st25"/>
-		</g>
-		<g id="shape100-445" v:mID="100" v:groupContext="shape" transform="translate(-37.6568,-164.882) rotate(-24.444)">
-			<title>Sheet.100</title>
-			<path d="M0 424.56 L101.71 424.56" class="st25"/>
-		</g>
-		<g id="shape101-450" v:mID="101" v:groupContext="shape" transform="translate(464.049,-50.8578) rotate(50.099)">
-			<title>Sheet.101</title>
-			<path d="M0 424.56 L139.8 424.56" class="st25"/>
-		</g>
-		<g id="shape102-455" v:mID="102" v:groupContext="shape" transform="translate(372.376,-207.438)">
-			<title>Sheet.102</title>
-			<desc>Supports N Flows</desc>
-			<v:textBlock v:margins="rect(4,4,4,4)"/>
-			<v:textRect cx="67.5" cy="415.565" width="135" height="18"/>
-			<rect x="0" y="406.565" width="135" height="18" class="st19"/>
-			<text x="25.15" y="419.17" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Supports N Flows</text>		</g>
-	</g>
-</svg>
diff --git a/doc/guides/sample_app_ug/img/server_node_efd.svg b/doc/guides/sample_app_ug/img/server_node_efd.svg
new file mode 100644
index 0000000..9aee30b
--- /dev/null
+++ b/doc/guides/sample_app_ug/img/server_node_efd.svg
@@ -0,0 +1,1254 @@
+<?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 efd_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"
+		xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="8.2496in" height="5.89673in"
+		viewBox="0 0 593.971 424.565" xml:space="preserve" color-interpolation-filters="sRGB" class="st27">
+	<v:documentProperties v:langID="1033" v:viewMarkup="false">
+		<v:userDefs>
+			<v:ud v:nameU="msvSubprocessMaster" v:prompt="" v:val="VT4(Rectangle)"/>
+			<v:ud v:nameU="msvNoAutoConnect" v:val="VT0(1):26"/>
+		</v:userDefs>
+	</v:documentProperties>
+
+	<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:0.833336em}
+		.st5 {fill:#feffff;font-family:Calibri;font-size:0.75em}
+		.st6 {fill:none;filter:url(#filter_2);stroke:#5b9bd5;stroke-opacity:0.22}
+		.st7 {fill:none;stroke:#2e75b5;stroke-width:2.25}
+		.st8 {fill:#305497;stroke:#2e75b5;stroke-width:1}
+		.st9 {fill:#feffff;font-family:Calibri;font-size:0.833336em;font-weight:bold}
+		.st10 {fill:#5b9bd5;fill-opacity:0.22;filter:url(#filter_2)}
+		.st11 {fill:#5b9bd5}
+		.st12 {stroke:#c7c8c8;stroke-width:0.25}
+		.st13 {fill:#acccea;stroke:#c7c8c8;stroke-width:0.25}
+		.st14 {fill:#feffff;font-family:Calibri;font-size:1.00001em;font-weight:bold}
+		.st15 {fill:#ed7d31;stroke:#c7c8c8;stroke-width:0.25}
+		.st16 {fill:#deebf6;stroke:#c7c8c8;stroke-width:0.25}
+		.st17 {marker-end:url(#mrkr5-212);stroke:#ff0000;stroke-linecap:round;stroke-linejoin:round;stroke-width:1}
+		.st18 {fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-opacity:1;stroke-width:0.28409090909091}
+		.st19 {fill:none;stroke:#2e75b5;stroke-width:1}
+		.st20 {fill:#5b9bd5;font-family:Calibri;font-size:1.00001em}
+		.st21 {fill:none;stroke:none;stroke-width:0.25}
+		.st22 {font-size:1em}
+		.st23 {fill:#ffffff}
+		.st24 {stroke:#5b9bd5;stroke-dasharray:1.5,3;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5}
+		.st25 {marker-end:url(#mrkr5-444);stroke:#5b9bd5;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5}
+		.st26 {fill:#5b9bd5;fill-opacity:1;stroke:#5b9bd5;stroke-opacity:1;stroke-width:0.37313432835821}
+		.st27 {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-212" class="st18" 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>
+		<marker id="mrkr5-444" class="st26" v:arrowType="5" v:arrowSize="2" v:setback="4.69" refX="-4.69" orient="auto"
+				markerUnits="strokeWidth" overflow="visible">
+			<use xlink:href="#lend5" transform="scale(-2.68,-2.68) "/>
+		</marker>
+	</defs>
+	<defs id="Filters">
+		<filter id="filter_2">
+			<feGaussianBlur stdDeviation="2"/>
+		</filter>
+	</defs>
+	<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
+		<v:userDefs>
+			<v:ud v:nameU="msvThemeOrder" v:val="VT0(0):26"/>
+		</v:userDefs>
+		<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(319.501,-335.688)">
+			<title>Rectangle.58</title>
+			<desc>Key 1</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow3-2" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="4.74" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key 1</text>		</g>
+		<g id="shape4-7" v:mID="4" v:groupContext="shape" transform="translate(353.251,-335.688)">
+			<title>Rectangle.59</title>
+			<desc>Action 1</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow4-8" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.62" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action 1</text>		</g>
+		<g id="shape5-13" v:mID="5" v:groupContext="shape" transform="translate(400.501,-335.688)">
+			<title>Rectangle.60</title>
+			<desc>Key 2</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow5-14" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="4.74" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key 2</text>		</g>
+		<g id="shape6-19" v:mID="6" v:groupContext="shape" transform="translate(434.251,-335.688)">
+			<title>Rectangle.61</title>
+			<desc>Action 2</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow6-20" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.62" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action 2</text>		</g>
+		<g id="shape7-25" v:mID="7" v:groupContext="shape" transform="translate(481.501,-335.688)">
+			<title>Rectangle.62</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow7-26" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape8-30" v:mID="8" v:groupContext="shape" transform="translate(515.251,-335.688)">
+			<title>Rectangle.63</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow8-31" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape9-35" v:mID="9" v:groupContext="shape" transform="translate(319.501,-313.188)">
+			<title>Rectangle.64</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow9-36" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape10-40" v:mID="10" v:groupContext="shape" transform="translate(353.251,-313.188)">
+			<title>Rectangle.65</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow10-41" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape11-45" v:mID="11" v:groupContext="shape" transform="translate(400.501,-313.188)">
+			<title>Rectangle.66</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow11-46" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape12-50" v:mID="12" v:groupContext="shape" transform="translate(434.251,-313.188)">
+			<title>Rectangle.67</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow12-51" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape13-55" v:mID="13" v:groupContext="shape" transform="translate(481.501,-313.188)">
+			<title>Rectangle.68</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow13-56" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape14-60" v:mID="14" v:groupContext="shape" transform="translate(515.251,-313.188)">
+			<title>Rectangle.69</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow14-61" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape15-65" v:mID="15" v:groupContext="shape" transform="translate(319.501,-277.188)">
+			<title>Rectangle.70</title>
+			<desc>Key x</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow15-66" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.11" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key x</text>		</g>
+		<g id="shape16-71" v:mID="16" v:groupContext="shape" transform="translate(353.251,-277.188)">
+			<title>Rectangle.71</title>
+			<desc>Action x</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow16-72" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.99" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action x</text>		</g>
+		<g id="shape17-77" v:mID="17" v:groupContext="shape" transform="translate(400.501,-277.188)">
+			<title>Rectangle.72</title>
+			<desc>Key y</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow17-78" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.01" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key y</text>		</g>
+		<g id="shape18-83" v:mID="18" v:groupContext="shape" transform="translate(434.251,-277.188)">
+			<title>Rectangle.73</title>
+			<desc>Action y</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow18-84" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.89" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action y</text>		</g>
+		<g id="shape19-89" v:mID="19" v:groupContext="shape" transform="translate(481.501,-277.188)">
+			<title>Rectangle.74</title>
+			<desc>Key z</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.3" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key z</text>		</g>
+		<g id="shape20-95" v:mID="20" v:groupContext="shape" transform="translate(515.251,-277.188)">
+			<title>Rectangle.75</title>
+			<desc>Action z</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow20-96" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="5.18" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action z</text>		</g>
+		<g id="shape21-101" v:mID="21" v:groupContext="shape" transform="translate(319.501,-240.687)">
+			<title>Rectangle.76</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow21-102" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape22-106" v:mID="22" v:groupContext="shape" transform="translate(353.251,-240.687)">
+			<title>Rectangle.77</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow22-107" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape23-111" v:mID="23" v:groupContext="shape" transform="translate(400.501,-240.687)">
+			<title>Rectangle.78</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow23-112" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape24-116" v:mID="24" v:groupContext="shape" transform="translate(434.251,-240.687)">
+			<title>Rectangle.79</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow24-117" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape25-121" v:mID="25" v:groupContext="shape" transform="translate(481.501,-240.687)">
+			<title>Rectangle.80</title>
+			<desc>Key N</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow25-122" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.21" y="418.26" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key N</text>		</g>
+		<g id="shape26-127" v:mID="26" v:groupContext="shape" transform="translate(515.251,-240.687)">
+			<title>Rectangle.81</title>
+			<desc>Action N</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow26-128" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="5.67" y="418.26" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action N</text>		</g>
+		<g id="shape27-133" v:mID="27" v:groupContext="shape" transform="translate(317.251,-231.687)">
+			<title>Rectangle.82</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow27-134" 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="st1">
+				<rect x="0" y="289.065" width="245.25" height="135.5" class="st6"/>
+			</g>
+			<rect x="0" y="289.065" width="245.25" height="135.5" class="st7"/>
+		</g>
+		<g id="shape28-138" v:mID="28" v:groupContext="shape" transform="translate(328.501,-362.688)">
+			<title>Sheet.28</title>
+			<desc>Local Table for N Specific Flows Serviced at Node 1</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="110.423" cy="418.94" width="220.85" height="11.25"/>
+			<rect x="0" y="413.315" width="220.846" height="11.25" class="st8"/>
+			<text x="5.77" y="421.94" class="st9" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Local Table for N Specific Flows Serviced at Node 1</text>		</g>
+		<g id="group34-141" transform="translate(66.0294,-165.569)" v:mID="34" v:groupContext="group">
+			<v:custProps>
+				<v:cp v:nameU="AssetNumber" v:lbl="Asset Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SerialNumber" v:lbl="Serial Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Location" v:lbl="Location" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Building" v:lbl="Building" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Room" v:lbl="Room" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Manufacturer" v:lbl="Manufacturer" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductNumber" v:lbl="Product Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="PartNumber" v:lbl="Part Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductDescription" v:lbl="Product Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Equipment" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkName" v:lbl="Network Name" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="IPAddress" v:lbl="IP Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SubnetMask" v:lbl="Subnet Mask" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="AdminInterface" v:lbl="Administrative Interface" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NumberofPorts" v:lbl="Number of Ports" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="CommunityString" v:lbl="Community String" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkDescription" v:lbl="Network Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="MACAddress" v:lbl="MAC Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Equipment)"/>
+				<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Device)"/>
+				<v:cp v:nameU="SubShapeType" v:lbl="SubShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Load balancer)"/>
+			</v:custProps>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
+				<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
+				<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
+				<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
+			</v:userDefs>
+			<title>Load balancer</title>
+			<g id="shape35-142" v:mID="35" v:groupContext="shape" transform="translate(0,-7.33146)">
+				<title>Sheet.35</title>
+				<g id="shadow35-143" 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="st1">
+					<path d="M54 367.23 L18 367.23 L0 377.86 L0 424.56 L72 424.56 L72 377.86 L54 367.23 Z" class="st10"/>
+					<path d="M0 377.86 L72 377.86" class="st6"/>
+					<path d="M54 367.23 L18 367.23 L0 377.86 L0 424.56 L72 424.56 L72 377.86 L54 367.23" class="st6"/>
+				</g>
+				<path d="M54 367.23 L18 367.23 L0 377.86 L0 424.56 L72 424.56 L72 377.86 L54 367.23 Z" class="st11"/>
+				<path d="M0 377.86 L72 377.86" class="st12"/>
+				<path d="M54 367.23 L18 367.23 L0 377.86 L0 424.56 L72 424.56 L72 377.86 L54 367.23" class="st12"/>
+			</g>
+			<g id="shape36-152" v:mID="36" v:groupContext="shape" transform="translate(8.03054,-12.9324)">
+				<title>Sheet.36</title>
+				<g id="shadow36-153" 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="st1">
+					<path d="M45.34 421.81 L41.2 422.66 L44.12 424.56 L49.68 423.16 L48.75 417.51 L45.8 415.59 L46.69 419.68 L36.97
+								 413.34 L35.6 415.45 L45.34 421.81 ZM50.83 405.36 L39.2 405.36 L39.2 407.88 L50.8 407.88 L47.82 410.83
+								 L51.34 410.83 L55.21 406.61 L51.32 402.39 L47.83 402.39 L50.83 405.36 ZM46.49 392.01 L36.75 398.37
+								 L38.13 400.48 L47.84 394.14 L46.96 398.23 L49.91 396.31 L50.84 390.66 L45.28 389.26 L42.36 391.16
+								 L46.49 392.01 ZM27.71 397.16 C22.66 397.16 18.58 401.25 18.58 406.29 C18.58 411.33 22.66 415.42
+								 27.71 415.42 C32.75 415.42 36.84 411.33 36.84 406.29 C36.84 401.25 32.75 397.16 27.71 397.16 ZM27.71
+								 400.04 C31.15 400.04 33.96 402.84 33.96 406.29 C33.96 409.74 31.15 412.54 27.71 412.54 C24.26 412.54
+								 21.46 409.74 21.46 406.29 C21.46 402.84 24.26 400.04 27.71 400.04 ZM11.64 405.04 L0 405.04 L0 407.56
+								 L11.6 407.56 L8.62 410.51 L12.14 410.51 L16.01 406.29 L12.12 402.07 L8.64 402.07 L11.64 405.04 Z"
+							class="st2"/>
+				</g>
+				<path d="M45.34 421.81 L41.2 422.66 L44.12 424.56 L49.68 423.16 L48.75 417.51 L45.8 415.59 L46.69 419.68 L36.97 413.34
+							 L35.6 415.45 L45.34 421.81 ZM50.83 405.36 L39.2 405.36 L39.2 407.88 L50.8 407.88 L47.82 410.83 L51.34
+							 410.83 L55.21 406.61 L51.32 402.39 L47.83 402.39 L50.83 405.36 ZM46.49 392.01 L36.75 398.37 L38.13 400.48
+							 L47.84 394.14 L46.96 398.23 L49.91 396.31 L50.84 390.66 L45.28 389.26 L42.36 391.16 L46.49 392.01 ZM27.71
+							 397.16 C22.66 397.16 18.58 401.25 18.58 406.29 C18.58 411.33 22.66 415.42 27.71 415.42 C32.75 415.42
+							 36.84 411.33 36.84 406.29 C36.84 401.25 32.75 397.16 27.71 397.16 ZM27.71 400.04 C31.15 400.04 33.96
+							 402.84 33.96 406.29 C33.96 409.74 31.15 412.54 27.71 412.54 C24.26 412.54 21.46 409.74 21.46 406.29
+							 C21.46 402.84 24.26 400.04 27.71 400.04 ZM11.64 405.04 L0 405.04 L0 407.56 L11.6 407.56 L8.62 410.51
+							 L12.14 410.51 L16.01 406.29 L12.12 402.07 L8.64 402.07 L11.64 405.04 Z" class="st13"/>
+			</g>
+		</g>
+		<g id="shape37-157" v:mID="37" v:groupContext="shape" transform="translate(21.0294,-45.4375)">
+			<title>Rectangle</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow37-158" 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="st1">
+				<rect x="0" y="336.433" width="135" height="88.1315" class="st2"/>
+			</g>
+			<rect x="0" y="336.433" width="135" height="88.1315" class="st3"/>
+		</g>
+		<g id="shape38-162" v:mID="38" v:groupContext="shape" transform="translate(34.693,-126.438)">
+			<title>Sheet.38</title>
+			<desc>EFD Table</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="49.3364" cy="415.565" width="98.68" height="18"/>
+			<rect x="0" y="406.565" width="98.6728" height="18" class="st8"/>
+			<text x="24.87" y="419.17" class="st14" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>EFD Table</text>		</g>
+		<g id="shape39-165" v:mID="39" v:groupContext="shape" transform="translate(30.0294,-99.4375)">
+			<title>Rectangle.39</title>
+			<desc>Group_id</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="26.9182" cy="415.565" width="53.84" height="18"/>
+			<g id="shadow39-166" 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="st1">
+				<rect x="0" y="406.565" width="53.8364" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="53.8364" height="18" class="st15"/>
+			<text x="7.87" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Group_id</text>		</g>
+		<g id="shape40-171" v:mID="40" v:groupContext="shape" transform="translate(93.193,-99.4375)">
+			<title>Rectangle.40</title>
+			<desc>Hash index</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="26.9182" cy="415.565" width="53.84" height="18"/>
+			<g id="shadow40-172" 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="st1">
+				<rect x="0" y="406.565" width="53.8364" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="53.8364" height="18" class="st15"/>
+			<text x="4.64" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Hash index</text>		</g>
+		<g id="shape41-177" v:mID="41" v:groupContext="shape" transform="translate(30.193,-82.4275)">
+			<title>Rectangle.41</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow41-178" 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="st1">
+				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
+			</g>
+			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
+		</g>
+		<g id="shape42-182" v:mID="42" v:groupContext="shape" transform="translate(30.193,-66.8125)">
+			<title>Rectangle.42</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow42-183" 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="st1">
+				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
+			</g>
+			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
+		</g>
+		<g id="shape43-187" v:mID="43" v:groupContext="shape" transform="translate(30.1112,-52.1875)">
+			<title>Rectangle.43</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow43-188" 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="st1">
+				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
+			</g>
+			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
+		</g>
+		<g id="shape44-192" v:mID="44" v:groupContext="shape" transform="translate(93.0294,-81.4375)">
+			<title>Rectangle.44</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow44-193" 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="st1">
+				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
+			</g>
+			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
+		</g>
+		<g id="shape45-197" v:mID="45" v:groupContext="shape" transform="translate(93.193,-66.8125)">
+			<title>Rectangle.45</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow45-198" 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="st1">
+				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
+			</g>
+			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
+		</g>
+		<g id="shape46-202" v:mID="46" v:groupContext="shape" transform="translate(93.193,-52.1875)">
+			<title>Rectangle.46</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow46-203" 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="st1">
+				<rect x="0" y="413.315" width="53.8364" height="11.25" class="st2"/>
+			</g>
+			<rect x="0" y="413.315" width="53.8364" height="11.25" class="st16"/>
+		</g>
+		<g id="shape47-207" v:mID="47" v:groupContext="shape" transform="translate(374.924,544.022) rotate(135)">
+			<title>Sheet.47</title>
+			<path d="M-0 417.75 A40.674 18.0151 -156.2 0 0 40.24 422.15 L40.49 421.89" class="st17"/>
+		</g>
+		<g id="shape48-213" v:mID="48" v:groupContext="shape" transform="translate(21.0294,-19)">
+			<title>Sheet.48</title>
+			<desc>Supports X*N Flows</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="67.5" cy="415.565" width="135" height="18"/>
+			<rect x="0" y="406.565" width="135" height="18" class="st19"/>
+			<text x="19.05" y="419.17" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Supports X*N Flows</text>		</g>
+		<g id="shape49-216" v:mID="49" v:groupContext="shape" transform="translate(48.0294,-229.938)">
+			<title>Sheet.49</title>
+			<desc>Frontend Server or Load Balancer</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="54" cy="400.94" width="108" height="47.25"/>
+			<rect x="0" y="377.315" width="108" height="47.25" class="st21"/>
+			<text x="14.56" y="397.34" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Frontend Server<v:newlineChar/><tspan
+						x="13.16" dy="1.2em" class="st22">or Load Balancer </tspan> </text>		</g>
+		<g id="group51-220" transform="translate(223.876,-310.938)" v:mID="51" v:groupContext="group">
+			<v:custProps>
+				<v:cp v:nameU="AssetNumber" v:lbl="Asset Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SerialNumber" v:lbl="Serial Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Location" v:lbl="Location" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Building" v:lbl="Building" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Room" v:lbl="Room" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Manufacturer" v:lbl="Manufacturer" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductNumber" v:lbl="Product Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="PartNumber" v:lbl="Part Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductDescription" v:lbl="Product Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Equipment" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkName" v:lbl="Network Name" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="IPAddress" v:lbl="IP Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SubnetMask" v:lbl="Subnet Mask" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="AdminInterface" v:lbl="Administrative Interface" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NumberofPorts" v:lbl="Number of Ports" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="CommunityString" v:lbl="Community String" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkDescription" v:lbl="Network Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="MACAddress" v:lbl="MAC Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="CPU" v:lbl="CPU" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Memory" v:lbl="Memory" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="OperatingSystem" v:lbl="Operating System" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="HardDriveSize" v:lbl="Hard Drive Capacity" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Workstation" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Department" v:lbl="Department" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Equipment)"/>
+				<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Server)"/>
+				<v:cp v:nameU="BelongsTo" v:lbl="Belongs To" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+			</v:custProps>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
+				<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
+				<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
+				<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
+			</v:userDefs>
+			<title>Server</title>
+			<g id="shape52-221" v:mID="52" v:groupContext="shape" transform="translate(13.0183,0)">
+				<title>Sheet.52</title>
+				<g id="shadow52-222" 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="st1">
+					<rect x="0" y="352.565" width="45.9634" height="72" class="st2"/>
+				</g>
+				<rect x="0" y="352.565" width="45.9634" height="72" class="st3"/>
+			</g>
+			<g id="shape53-226" v:mID="53" v:groupContext="shape" transform="translate(47.371,-30.7354)">
+				<title>Sheet.53</title>
+				<g id="shadow53-227" 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="st1">
+					<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st2"/>
+				</g>
+				<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st13"/>
+			</g>
+			<g id="shape54-231" v:mID="54" v:groupContext="shape" transform="translate(30.51,-11.8022)">
+				<title>Sheet.54</title>
+				<v:userDefs>
+					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
+					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
+				</v:userDefs>
+				<g id="shadow54-232" 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="st1">
+					<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31
+								 L-0 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z"
+							class="st10"/>
+				</g>
+				<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31 L-0
+							 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z" class="st23"/>
+			</g>
+		</g>
+		<g id="shape59-239" v:mID="59" v:groupContext="shape" transform="translate(277.876,-373.938)">
+			<title>Sheet.59</title>
+			<path d="M-0 424.56 A111.108 53.2538 42.31 0 1 93.83 421.21 L94.14 421.41" class="st17"/>
+		</g>
+		<g id="shape60-244" v:mID="60" v:groupContext="shape" transform="translate(205.876,-283.938)">
+			<title>Sheet.60</title>
+			<desc>Backend Server 1</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="54" cy="408.124" width="108" height="32.8815"/>
+			<rect x="0" y="391.683" width="108" height="32.8815" class="st21"/>
+			<text x="11.93" y="411.72" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Backend Server 1</text>		</g>
+		<g id="group61-247" transform="translate(223.876,-207.438)" v:mID="61" v:groupContext="group">
+			<v:custProps>
+				<v:cp v:nameU="AssetNumber" v:lbl="Asset Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SerialNumber" v:lbl="Serial Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Location" v:lbl="Location" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Building" v:lbl="Building" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Room" v:lbl="Room" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Manufacturer" v:lbl="Manufacturer" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductNumber" v:lbl="Product Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="PartNumber" v:lbl="Part Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductDescription" v:lbl="Product Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Equipment" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkName" v:lbl="Network Name" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="IPAddress" v:lbl="IP Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SubnetMask" v:lbl="Subnet Mask" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="AdminInterface" v:lbl="Administrative Interface" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NumberofPorts" v:lbl="Number of Ports" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="CommunityString" v:lbl="Community String" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkDescription" v:lbl="Network Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="MACAddress" v:lbl="MAC Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="CPU" v:lbl="CPU" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Memory" v:lbl="Memory" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="OperatingSystem" v:lbl="Operating System" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="HardDriveSize" v:lbl="Hard Drive Capacity" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Workstation" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Department" v:lbl="Department" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Equipment)"/>
+				<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Server)"/>
+				<v:cp v:nameU="BelongsTo" v:lbl="Belongs To" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+			</v:custProps>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
+				<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
+				<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
+				<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
+			</v:userDefs>
+			<title>Server.61</title>
+			<g id="shape62-248" v:mID="62" v:groupContext="shape" transform="translate(13.0183,0)">
+				<title>Sheet.62</title>
+				<g id="shadow62-249" 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="st1">
+					<rect x="0" y="352.565" width="45.9634" height="72" class="st2"/>
+				</g>
+				<rect x="0" y="352.565" width="45.9634" height="72" class="st3"/>
+			</g>
+			<g id="shape63-253" v:mID="63" v:groupContext="shape" transform="translate(47.371,-30.7354)">
+				<title>Sheet.63</title>
+				<g id="shadow63-254" 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="st1">
+					<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st2"/>
+				</g>
+				<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st13"/>
+			</g>
+			<g id="shape64-258" v:mID="64" v:groupContext="shape" transform="translate(30.51,-11.8022)">
+				<title>Sheet.64</title>
+				<v:userDefs>
+					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
+					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
+				</v:userDefs>
+				<g id="shadow64-259" 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="st1">
+					<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31
+								 L-0 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z"
+							class="st10"/>
+				</g>
+				<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31 L-0
+							 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z" class="st23"/>
+			</g>
+		</g>
+		<g id="shape65-266" v:mID="65" v:groupContext="shape" transform="translate(205.876,-180.437)">
+			<title>Sheet.65</title>
+			<desc>Backend Server 2</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="54" cy="408.124" width="108" height="32.8815"/>
+			<rect x="0" y="391.683" width="108" height="32.8815" class="st21"/>
+			<text x="11.93" y="411.72" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Backend Server 2</text>		</g>
+		<g id="group66-269" transform="translate(219.029,-58.9375)" v:mID="66" v:groupContext="group">
+			<v:custProps>
+				<v:cp v:nameU="AssetNumber" v:lbl="Asset Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SerialNumber" v:lbl="Serial Number" v:prompt="" v:type="0" v:format="" v:sortKey="Asset"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Location" v:lbl="Location" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Building" v:lbl="Building" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Room" v:lbl="Room" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Manufacturer" v:lbl="Manufacturer" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductNumber" v:lbl="Product Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="PartNumber" v:lbl="Part Number" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ProductDescription" v:lbl="Product Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Equipment" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkName" v:lbl="Network Name" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="IPAddress" v:lbl="IP Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="SubnetMask" v:lbl="Subnet Mask" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="AdminInterface" v:lbl="Administrative Interface" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NumberofPorts" v:lbl="Number of Ports" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="CommunityString" v:lbl="Community String" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="NetworkDescription" v:lbl="Network Description" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Network" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="MACAddress" v:lbl="MAC Address" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="CPU" v:lbl="CPU" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Memory" v:lbl="Memory" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="OperatingSystem" v:lbl="Operating System" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
+						v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="HardDriveSize" v:lbl="Hard Drive Capacity" v:prompt="" v:type="0" v:format=""
+						v:sortKey="Workstation" v:invis="false" v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="Department" v:lbl="Department" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+				<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Equipment)"/>
+				<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0" v:val="VT4(Server)"/>
+				<v:cp v:nameU="BelongsTo" v:lbl="Belongs To" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
+						v:ask="false" v:langID="1033" v:cal="0"/>
+			</v:custProps>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
+				<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
+				<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
+				<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
+			</v:userDefs>
+			<title>Server.66</title>
+			<g id="shape67-270" v:mID="67" v:groupContext="shape" transform="translate(13.0183,0)">
+				<title>Sheet.67</title>
+				<g id="shadow67-271" 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="st1">
+					<rect x="0" y="352.565" width="45.9634" height="72" class="st2"/>
+				</g>
+				<rect x="0" y="352.565" width="45.9634" height="72" class="st3"/>
+			</g>
+			<g id="shape68-275" v:mID="68" v:groupContext="shape" transform="translate(47.371,-30.7354)">
+				<title>Sheet.68</title>
+				<g id="shadow68-276" 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="st1">
+					<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st2"/>
+				</g>
+				<ellipse cx="2.77848" cy="421.786" rx="2.77848" ry="2.77848" class="st13"/>
+			</g>
+			<g id="shape69-280" v:mID="69" v:groupContext="shape" transform="translate(30.51,-11.8022)">
+				<title>Sheet.69</title>
+				<v:userDefs>
+					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
+					<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
+				</v:userDefs>
+				<g id="shadow69-281" 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="st1">
+					<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31
+								 L-0 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z"
+							class="st10"/>
+				</g>
+				<path d="M-0 424.56 L22.42 424.56 L22.42 422.76 L-0 422.76 L-0 424.56 ZM-0 419.11 L22.42 419.11 L22.42 417.31 L-0
+							 417.31 L-0 419.11 ZM-0 413.65 L22.42 413.65 L22.42 411.84 L-0 411.84 L-0 413.65 Z" class="st23"/>
+			</g>
+		</g>
+		<g id="shape70-288" v:mID="70" v:groupContext="shape" transform="translate(201.029,-26.056)">
+			<title>Sheet.70</title>
+			<desc>Backend Server X</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="54" cy="408.124" width="108" height="32.8815"/>
+			<rect x="0" y="391.683" width="108" height="32.8815" class="st21"/>
+			<text x="11.86" y="411.72" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Backend Server X</text>		</g>
+		<g id="shape71-291" v:mID="71" v:groupContext="shape" transform="translate(684.44,239.627) rotate(90)">
+			<title>Sheet.71</title>
+			<path d="M0 424.56 L45 424.56" class="st24"/>
+		</g>
+		<g id="shape72-294" v:mID="72" v:groupContext="shape" transform="translate(6.85967,-22.443) rotate(-38.1076)">
+			<title>Sheet.72</title>
+			<path d="M-0 424.56 A96.1331 44.4001 55.03 0 1 68.24 420.56 L68.51 420.79" class="st17"/>
+		</g>
+		<g id="shape73-299" v:mID="73" v:groupContext="shape" transform="translate(328.501,-135.937)">
+			<title>Rectangle.73</title>
+			<desc>Key 1</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow73-300" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="4.74" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key 1</text>		</g>
+		<g id="shape74-305" v:mID="74" v:groupContext="shape" transform="translate(362.251,-135.937)">
+			<title>Rectangle.74</title>
+			<desc>Action 1</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow74-306" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.62" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action 1</text>		</g>
+		<g id="shape75-311" v:mID="75" v:groupContext="shape" transform="translate(409.501,-135.937)">
+			<title>Rectangle.75</title>
+			<desc>Key 2</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow75-312" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="4.74" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key 2</text>		</g>
+		<g id="shape76-317" v:mID="76" v:groupContext="shape" transform="translate(443.251,-135.937)">
+			<title>Rectangle.76</title>
+			<desc>Action 2</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow76-318" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.62" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action 2</text>		</g>
+		<g id="shape77-323" v:mID="77" v:groupContext="shape" transform="translate(490.501,-135.937)">
+			<title>Rectangle.77</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow77-324" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape78-328" v:mID="78" v:groupContext="shape" transform="translate(524.251,-135.937)">
+			<title>Rectangle.78</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow78-329" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape79-333" v:mID="79" v:groupContext="shape" transform="translate(328.501,-113.437)">
+			<title>Rectangle.79</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow79-334" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape80-338" v:mID="80" v:groupContext="shape" transform="translate(362.251,-113.437)">
+			<title>Rectangle.80</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow80-339" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape81-343" v:mID="81" v:groupContext="shape" transform="translate(409.501,-113.437)">
+			<title>Rectangle.81</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow81-344" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape82-348" v:mID="82" v:groupContext="shape" transform="translate(443.251,-113.437)">
+			<title>Rectangle.82</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow82-349" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape83-353" v:mID="83" v:groupContext="shape" transform="translate(490.501,-113.437)">
+			<title>Rectangle.83</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow83-354" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape84-358" v:mID="84" v:groupContext="shape" transform="translate(524.251,-113.437)">
+			<title>Rectangle.84</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow84-359" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape85-363" v:mID="85" v:groupContext="shape" transform="translate(328.501,-77.4375)">
+			<title>Rectangle.85</title>
+			<desc>Key x</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow85-364" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.11" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key x</text>		</g>
+		<g id="shape86-369" v:mID="86" v:groupContext="shape" transform="translate(362.251,-77.4375)">
+			<title>Rectangle.86</title>
+			<desc>Action x</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow86-370" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.99" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action x</text>		</g>
+		<g id="shape87-375" v:mID="87" v:groupContext="shape" transform="translate(409.501,-77.4375)">
+			<title>Rectangle.87</title>
+			<desc>Key y</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow87-376" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.01" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key y</text>		</g>
+		<g id="shape88-381" v:mID="88" v:groupContext="shape" transform="translate(443.251,-77.4375)">
+			<title>Rectangle.88</title>
+			<desc>Action y</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow88-382" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="4.89" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action y</text>		</g>
+		<g id="shape89-387" v:mID="89" v:groupContext="shape" transform="translate(490.501,-77.4375)">
+			<title>Rectangle.89</title>
+			<desc>Key z</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow89-388" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.3" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key z</text>		</g>
+		<g id="shape90-393" v:mID="90" v:groupContext="shape" transform="translate(524.251,-77.4375)">
+			<title>Rectangle.90</title>
+			<desc>Action z</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow90-394" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="5.18" y="418.56" class="st4" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action z</text>		</g>
+		<g id="shape91-399" v:mID="91" v:groupContext="shape" transform="translate(328.501,-40.9375)">
+			<title>Rectangle.91</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow91-400" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape92-404" v:mID="92" v:groupContext="shape" transform="translate(362.251,-40.9375)">
+			<title>Rectangle.92</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow92-405" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape93-409" v:mID="93" v:groupContext="shape" transform="translate(409.501,-40.9375)">
+			<title>Rectangle.93</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow93-410" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+		</g>
+		<g id="shape94-414" v:mID="94" v:groupContext="shape" transform="translate(443.251,-40.9375)">
+			<title>Rectangle.94</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow94-415" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+		</g>
+		<g id="shape95-419" v:mID="95" v:groupContext="shape" transform="translate(490.501,-40.9375)">
+			<title>Rectangle.95</title>
+			<desc>Key N</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="15.75" cy="415.565" width="31.5" height="18"/>
+			<g id="shadow95-420" 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="st1">
+				<rect x="0" y="406.565" width="31.5" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="31.5" height="18" class="st3"/>
+			<text x="5.21" y="418.26" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Key N</text>		</g>
+		<g id="shape96-425" v:mID="96" v:groupContext="shape" transform="translate(524.251,-40.9375)">
+			<title>Rectangle.96</title>
+			<desc>Action N</desc>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="21.375" cy="415.565" width="42.75" height="18"/>
+			<g id="shadow96-426" 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="st1">
+				<rect x="0" y="406.565" width="42.75" height="18" class="st2"/>
+			</g>
+			<rect x="0" y="406.565" width="42.75" height="18" class="st3"/>
+			<text x="5.67" y="418.26" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Action N</text>		</g>
+		<g id="shape97-431" v:mID="97" v:groupContext="shape" transform="translate(326.251,-31.9375)">
+			<title>Rectangle.97</title>
+			<v:userDefs>
+				<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
+			</v:userDefs>
+			<g id="shadow97-432" 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="st1">
+				<rect x="0" y="289.065" width="245.25" height="135.5" class="st6"/>
+			</g>
+			<rect x="0" y="289.065" width="245.25" height="135.5" class="st7"/>
+		</g>
+		<g id="shape98-436" v:mID="98" v:groupContext="shape" transform="translate(337.501,-162.938)">
+			<title>Sheet.98</title>
+			<desc>Local Table for N Specific Flows Serviced at Node X</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="110.423" cy="418.94" width="220.85" height="11.25"/>
+			<rect x="0" y="413.315" width="220.846" height="11.25" class="st8"/>
+			<text x="5.55" y="421.94" class="st9" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Local Table for N Specific Flows Serviced at Node X</text>		</g>
+		<g id="shape99-439" v:mID="99" v:groupContext="shape" transform="translate(-204.342,-29.4449) rotate(-53.7462)">
+			<title>Sheet.99</title>
+			<path d="M0 424.56 L160.37 424.56" class="st25"/>
+		</g>
+		<g id="shape100-445" v:mID="100" v:groupContext="shape" transform="translate(-37.6568,-164.882) rotate(-24.444)">
+			<title>Sheet.100</title>
+			<path d="M0 424.56 L101.71 424.56" class="st25"/>
+		</g>
+		<g id="shape101-450" v:mID="101" v:groupContext="shape" transform="translate(464.049,-50.8578) rotate(50.099)">
+			<title>Sheet.101</title>
+			<path d="M0 424.56 L139.8 424.56" class="st25"/>
+		</g>
+		<g id="shape102-455" v:mID="102" v:groupContext="shape" transform="translate(372.376,-207.438)">
+			<title>Sheet.102</title>
+			<desc>Supports N Flows</desc>
+			<v:textBlock v:margins="rect(4,4,4,4)"/>
+			<v:textRect cx="67.5" cy="415.565" width="135" height="18"/>
+			<rect x="0" y="406.565" width="135" height="18" class="st19"/>
+			<text x="25.15" y="419.17" class="st20" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Supports N Flows</text>		</g>
+	</g>
+</svg>
diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst
index 260f6a5..99ad8ea 100644
--- a/doc/guides/sample_app_ug/index.rst
+++ b/doc/guides/sample_app_ug/index.rst
@@ -57,7 +57,7 @@ Sample Applications User Guides
     l3_forward_virtual
     link_status_intr
     load_balancer
-    flow_distributor
+    server_node_efd
     multi_process
     qos_metering
     qos_scheduler
@@ -133,6 +133,8 @@ Sample Applications User Guides
 
 :numref:`figure_ptpclient_highlevel` :ref:`figure_ptpclient_highlevel`
 
+:numref:`figure_efd_sample_app_overview` :ref:`figure_efd_sample_app_overview`
+
 **Tables**
 
 :numref:`table_qos_metering_1` :ref:`table_qos_metering_1`
diff --git a/doc/guides/sample_app_ug/server_node_efd.rst b/doc/guides/sample_app_ug/server_node_efd.rst
new file mode 100644
index 0000000..9b69cfe
--- /dev/null
+++ b/doc/guides/sample_app_ug/server_node_efd.rst
@@ -0,0 +1,494 @@
+..  BSD LICENSE
+    Copyright(c) 2016-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.
+
+Server-Node EFD Sample Application
+==================================
+
+This sample application demonstrates the use of EFD library as a flow-level
+load balancer, for more information about the EFD Library please refer to the
+DPDK programmer's guide.
+
+This sample application is a variant of the
+:ref:`client-server sample application <multi_process_app>`
+where a specific target node is specified for every and each flow
+(not in a round-robin fashion as the original load balancing sample application).
+
+Overview
+--------
+
+The architecture of the EFD flow-based load balancer sample application is
+presented in the following figure.
+
+.. _figure_efd_sample_app_overview:
+
+.. figure:: img/server_node_efd.*
+
+   Using EFD as a Flow-Level Load Balancer
+
+As shown in :numref:`figure_efd_sample_app_overview`,
+the sample application consists of a front-end node (server)
+using the EFD library to create a load-balancing table for flows,
+for each flow a target backend worker node is specified. The EFD table does not
+store the flow key (unlike a regular hash table), and hence, it can
+individually load-balance millions of flows (number of targets * maximum number
+of flows fit in a flow table per target) while still fitting in CPU cache.
+
+It should be noted that although they are referred to as nodes, the frontend
+server and worker nodes are processes running on the same platform.
+
+Front-end Server
+~~~~~~~~~~~~~~~~
+
+Upon initializing, the frontend server node (process) creates a flow
+distributor table (based on the EFD library) which is populated with flow
+information and its intended target node.
+
+The sample application assigns a specific target node_id (process) for each of
+the IP destination addresses as follows:
+
+.. code-block:: c
+
+    node_id = i % num_nodes; /* Target node id is generated */
+    ip_dst = rte_cpu_to_be_32(i); /* Specific ip destination address is
+                                     assigned to this target node */
+
+then the pair of <key,target> is inserted into the flow distribution table.
+
+The main loop of the server process receives a burst of packets, then for
+each packet, a flow key (IP destination address) is extracted. The flow
+distributor table is looked up and the target node id is returned.  Packets are
+then enqueued to the specified target node id.
+
+It should be noted that flow distributor table is not a membership test table.
+I.e. if the key has already been inserted the target node id will be correct,
+but for new keys the flow distributor table will return a value (which can be
+valid).
+
+Backend Worker Nodes
+~~~~~~~~~~~~~~~~~~~~
+
+Upon initializing, the worker node (process) creates a flow table (a regular
+hash table that stores the key default size 1M flows) which is populated with
+only the flow information that is serviced at this node. This flow key is
+essential to point out new keys that have not been inserted before.
+
+The worker node's main loop is simply receiving packets then doing a hash table
+lookup. If a match occurs then statistics are updated for flows serviced by
+this node. If no match is found in the local hash table then this indicates
+that this is a new flow, which is dropped.
+
+
+Compiling the Application
+-------------------------
+
+The sequence of steps used to build the application is:
+
+#.  Export the required environment variables:
+
+    .. code-block:: console
+
+        export RTE_SDK=/path/to/rte_sdk
+        export RTE_TARGET=x86_64-native-linuxapp-gcc
+
+#.  Build the application executable file:
+
+    .. code-block:: console
+
+        cd ${RTE_SDK}/examples/server_node_efd/
+        make
+
+    For more details on how to build the DPDK libraries and sample
+    applications,
+    please refer to the *DPDK Getting Started Guide.*
+
+
+Running the Application
+-----------------------
+
+The application has two binaries to be run: the front-end server
+and the back-end node.
+
+The frontend server (server) has the following command line options::
+
+    ./server [EAL options] -- -p PORTMASK -n NUM_NODES -f NUM_FLOWS
+
+Where,
+
+* ``-p PORTMASK:`` Hexadecimal bitmask of ports to configure
+* ``-n NUM_NODES:`` Number of back-end nodes that will be used
+* ``-f NUM_FLOWS:`` Number of flows to be added in the EFD table (1 million, by default)
+
+The back-end node (node) has the following command line options::
+
+    ./node [EAL options] -- -n NODE_ID
+
+Where,
+
+* ``-n NODE_ID:`` Node ID, which cannot be equal or higher than NUM_MODES
+
+
+First, the server app must be launched, with the number of nodes that will be run.
+Once it has been started, the node instances can be run, with different NODE_ID.
+These instances have to be run as secondary processes, with ``--proc-type=secondary``
+in the EAL options, which will attach to the primary process memory, and therefore,
+they can access the queues created by the primary process to distribute packets.
+
+To successfully run the application, the command line used to start the
+application has to be in sync with the traffic flows configured on the traffic
+generator side.
+
+For examples of application command lines and traffic generator flows, please
+refer to the DPDK Test Report. For more details on how to set up and run the
+sample applications provided with DPDK package, please refer to the
+:ref:`DPDK Getting Started Guide for Linux <linux_gsg>` and
+:ref:`DPDK Getting Started Guide for FreeBSD <freebsd_gsg>`.
+
+
+Explanation
+-----------
+
+As described in previous sections, there are two processes in this example.
+
+The first process, the front-end server, creates and populates the EFD table,
+which is used to distribute packets to nodes, which the number of flows
+specified in the command line (1 million, by default).
+
+
+.. code-block:: c
+
+    static void
+    create_efd_table(void)
+    {
+        uint8_t socket_id = rte_socket_id();
+
+        /* create table */
+        efd_table = rte_efd_create("flow table", num_flows * 2, sizeof(uint32_t),
+                        1 << socket_id, socket_id);
+
+        if (efd_table == NULL)
+            rte_exit(EXIT_FAILURE, "Problem creating the flow table\n");
+    }
+
+    static void
+    populate_efd_table(void)
+    {
+        unsigned int i;
+        int32_t ret;
+        uint32_t ip_dst;
+        uint8_t socket_id = rte_socket_id();
+        uint64_t node_id;
+
+        /* Add flows in table */
+        for (i = 0; i < num_flows; i++) {
+            node_id = i % num_nodes;
+
+            ip_dst = rte_cpu_to_be_32(i);
+            ret = rte_efd_update(efd_table, socket_id,
+                            (void *)&ip_dst, (efd_value_t)node_id);
+            if (ret < 0)
+                rte_exit(EXIT_FAILURE, "Unable to add entry %u in "
+                                    "EFD table\n", i);
+        }
+
+        printf("EFD table: Adding 0x%x keys\n", num_flows);
+    }
+
+After initialization, packets are received from the enabled ports, and the IPv4
+address from the packets is used as a key to look up in the EFD table,
+which tells the node where the packet has to be distributed.
+
+.. code-block:: c
+
+    static void
+    process_packets(uint32_t port_num __rte_unused, struct rte_mbuf *pkts[],
+            uint16_t rx_count, unsigned int socket_id)
+    {
+        uint16_t i;
+        uint8_t node;
+        efd_value_t data[EFD_BURST_MAX];
+        const void *key_ptrs[EFD_BURST_MAX];
+
+        struct ipv4_hdr *ipv4_hdr;
+        uint32_t ipv4_dst_ip[EFD_BURST_MAX];
+
+        for (i = 0; i < rx_count; i++) {
+            /* Handle IPv4 header.*/
+            ipv4_hdr = rte_pktmbuf_mtod_offset(pkts[i], struct ipv4_hdr *,
+                    sizeof(struct ether_hdr));
+            ipv4_dst_ip[i] = ipv4_hdr->dst_addr;
+            key_ptrs[i] = (void *)&ipv4_dst_ip[i];
+        }
+
+        rte_efd_lookup_bulk(efd_table, socket_id, rx_count,
+                    (const void **) key_ptrs, data);
+        for (i = 0; i < rx_count; i++) {
+            node = (uint8_t) ((uintptr_t)data[i]);
+
+            if (node >= num_nodes) {
+                /*
+                 * Node is out of range, which means that
+                 * flow has not been inserted
+                 */
+                flow_dist_stats.drop++;
+                rte_pktmbuf_free(pkts[i]);
+            } else {
+                flow_dist_stats.distributed++;
+                enqueue_rx_packet(node, pkts[i]);
+            }
+        }
+
+        for (i = 0; i < num_nodes; i++)
+            flush_rx_queue(i);
+    }
+
+The burst of packets received is enqueued in temporary buffers (per node),
+and enqueued in the shared ring between the server and the node.
+After this, a new burst of packets is received and this process is
+repeated infinitely.
+
+.. code-block:: c
+
+    static void
+    flush_rx_queue(uint16_t node)
+    {
+        uint16_t j;
+        struct node *cl;
+
+        if (cl_rx_buf[node].count == 0)
+            return;
+
+        cl = &nodes[node];
+        if (rte_ring_enqueue_bulk(cl->rx_q, (void **)cl_rx_buf[node].buffer,
+                cl_rx_buf[node].count) != 0){
+            for (j = 0; j < cl_rx_buf[node].count; j++)
+                rte_pktmbuf_free(cl_rx_buf[node].buffer[j]);
+            cl->stats.rx_drop += cl_rx_buf[node].count;
+        } else
+            cl->stats.rx += cl_rx_buf[node].count;
+
+        cl_rx_buf[node].count = 0;
+    }
+
+The second process, the back-end node, receives the packets from the shared
+ring with the server and send them out, if they belong to the node.
+
+At initialization, it attaches to the server process memory, to have
+access to the shared ring, parameters and statistics.
+
+.. code-block:: c
+
+    rx_ring = rte_ring_lookup(get_rx_queue_name(node_id));
+    if (rx_ring == NULL)
+        rte_exit(EXIT_FAILURE, "Cannot get RX ring - "
+                "is server process running?\n");
+
+    mp = rte_mempool_lookup(PKTMBUF_POOL_NAME);
+    if (mp == NULL)
+        rte_exit(EXIT_FAILURE, "Cannot get mempool for mbufs\n");
+
+    mz = rte_memzone_lookup(MZ_SHARED_INFO);
+    if (mz == NULL)
+        rte_exit(EXIT_FAILURE, "Cannot get port info structure\n");
+    info = mz->addr;
+    tx_stats = &(info->tx_stats[node_id]);
+    filter_stats = &(info->filter_stats[node_id]);
+
+Then, the hash table that contains the flows that will be handled
+by the node is created and populated.
+
+.. code-block:: c
+
+    static struct rte_hash *
+    create_hash_table(const struct shared_info *info)
+    {
+        uint32_t num_flows_node = info->num_flows / info->num_nodes;
+        char name[RTE_HASH_NAMESIZE];
+        struct rte_hash *h;
+
+        /* create table */
+        struct rte_hash_parameters hash_params = {
+            .entries = num_flows_node * 2, /* table load = 50% */
+            .key_len = sizeof(uint32_t), /* Store IPv4 dest IP address */
+            .socket_id = rte_socket_id(),
+            .hash_func_init_val = 0,
+        };
+
+        snprintf(name, sizeof(name), "hash_table_%d", node_id);
+        hash_params.name = name;
+        h = rte_hash_create(&hash_params);
+
+        if (h == NULL)
+            rte_exit(EXIT_FAILURE,
+                    "Problem creating the hash table for node %d\n",
+                    node_id);
+        return h;
+    }
+
+    static void
+    populate_hash_table(const struct rte_hash *h, const struct shared_info *info)
+    {
+        unsigned int i;
+        int32_t ret;
+        uint32_t ip_dst;
+        uint32_t num_flows_node = 0;
+        uint64_t target_node;
+
+        /* Add flows in table */
+        for (i = 0; i < info->num_flows; i++) {
+            target_node = i % info->num_nodes;
+            if (target_node != node_id)
+                continue;
+
+            ip_dst = rte_cpu_to_be_32(i);
+
+            ret = rte_hash_add_key(h, (void *) &ip_dst);
+            if (ret < 0)
+                rte_exit(EXIT_FAILURE, "Unable to add entry %u "
+                        "in hash table\n", i);
+            else
+                num_flows_node++;
+
+        }
+
+        printf("Hash table: Adding 0x%x keys\n", num_flows_node);
+    }
+
+After initialization, packets are dequeued from the shared ring
+(from the server) and, like in the server process,
+the IPv4 address from the packets is used as a key to look up in the hash table.
+If there is a hit, packet is stored in a buffer, to be eventually transmitted
+in one of the enabled ports. If key is not there, packet is dropped, since the
+flow is not handled by the node.
+
+.. code-block:: c
+
+    static inline void
+    handle_packets(struct rte_hash *h, struct rte_mbuf **bufs, uint16_t num_packets)
+    {
+        struct ipv4_hdr *ipv4_hdr;
+        uint32_t ipv4_dst_ip[PKT_READ_SIZE];
+        const void *key_ptrs[PKT_READ_SIZE];
+        unsigned int i;
+        int32_t positions[PKT_READ_SIZE] = {0};
+
+        for (i = 0; i < num_packets; i++) {
+            /* Handle IPv4 header.*/
+            ipv4_hdr = rte_pktmbuf_mtod_offset(bufs[i], struct ipv4_hdr *,
+                    sizeof(struct ether_hdr));
+            ipv4_dst_ip[i] = ipv4_hdr->dst_addr;
+            key_ptrs[i] = &ipv4_dst_ip[i];
+        }
+        /* Check if packets belongs to any flows handled by this node */
+        rte_hash_lookup_bulk(h, key_ptrs, num_packets, positions);
+
+        for (i = 0; i < num_packets; i++) {
+            if (likely(positions[i] >= 0)) {
+                filter_stats->passed++;
+                transmit_packet(bufs[i]);
+            } else {
+                filter_stats->drop++;
+                /* Drop packet, as flow is not handled by this node */
+                rte_pktmbuf_free(bufs[i]);
+            }
+        }
+    }
+
+Finally, note that both processes updates statistics, such as transmitted, received
+and dropped packets, which are shown and refreshed by the server app.
+
+.. code-block:: c
+
+    static void
+    do_stats_display(void)
+    {
+        unsigned int i, j;
+        const char clr[] = {27, '[', '2', 'J', '\0'};
+        const char topLeft[] = {27, '[', '1', ';', '1', 'H', '\0'};
+        uint64_t port_tx[RTE_MAX_ETHPORTS], port_tx_drop[RTE_MAX_ETHPORTS];
+        uint64_t node_tx[MAX_NODES], node_tx_drop[MAX_NODES];
+
+        /* to get TX stats, we need to do some summing calculations */
+        memset(port_tx, 0, sizeof(port_tx));
+        memset(port_tx_drop, 0, sizeof(port_tx_drop));
+        memset(node_tx, 0, sizeof(node_tx));
+        memset(node_tx_drop, 0, sizeof(node_tx_drop));
+
+        for (i = 0; i < num_nodes; i++) {
+            const struct tx_stats *tx = &info->tx_stats[i];
+
+            for (j = 0; j < info->num_ports; j++) {
+                const uint64_t tx_val = tx->tx[info->id[j]];
+                const uint64_t drop_val = tx->tx_drop[info->id[j]];
+
+                port_tx[j] += tx_val;
+                port_tx_drop[j] += drop_val;
+                node_tx[i] += tx_val;
+                node_tx_drop[i] += drop_val;
+            }
+        }
+
+        /* Clear screen and move to top left */
+        printf("%s%s", clr, topLeft);
+
+        printf("PORTS\n");
+        printf("-----\n");
+        for (i = 0; i < info->num_ports; i++)
+            printf("Port %u: '%s'\t", (unsigned int)info->id[i],
+                    get_printable_mac_addr(info->id[i]));
+        printf("\n\n");
+        for (i = 0; i < info->num_ports; i++) {
+            printf("Port %u - rx: %9"PRIu64"\t"
+                    "tx: %9"PRIu64"\n",
+                    (unsigned int)info->id[i], info->rx_stats.rx[i],
+                    port_tx[i]);
+        }
+
+        printf("\nSERVER\n");
+        printf("-----\n");
+        printf("distributed: %9"PRIu64", drop: %9"PRIu64"\n",
+                flow_dist_stats.distributed, flow_dist_stats.drop);
+
+        printf("\nNODES\n");
+        printf("-------\n");
+        for (i = 0; i < num_nodes; i++) {
+            const unsigned long long rx = nodes[i].stats.rx;
+            const unsigned long long rx_drop = nodes[i].stats.rx_drop;
+            const struct filter_stats *filter = &info->filter_stats[i];
+
+            printf("Node %2u - rx: %9llu, rx_drop: %9llu\n"
+                    "            tx: %9"PRIu64", tx_drop: %9"PRIu64"\n"
+                    "            filter_passed: %9"PRIu64", "
+                    "filter_drop: %9"PRIu64"\n",
+                    i, rx, rx_drop, node_tx[i], node_tx_drop[i],
+                    filter->passed, filter->drop);
+        }
+
+        printf("\n");
+    }
diff --git a/examples/flow_distributor/Makefile b/examples/flow_distributor/Makefile
deleted file mode 100644
index 5bae706..0000000
--- a/examples/flow_distributor/Makefile
+++ /dev/null
@@ -1,44 +0,0 @@
-#   BSD LICENSE
-#
-#   Copyright(c) 2016-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.
-
-ifeq ($(RTE_SDK),)
-$(error "Please define RTE_SDK environment variable")
-endif
-
-# Default target, can be overridden by command line or environment
-RTE_TARGET ?= x86_64-native-linuxapp-gcc
-
-include $(RTE_SDK)/mk/rte.vars.mk
-
-DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += distributor
-DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += node
-
-include $(RTE_SDK)/mk/rte.extsubdir.mk
diff --git a/examples/flow_distributor/distributor/Makefile b/examples/flow_distributor/distributor/Makefile
deleted file mode 100644
index 8714151..0000000
--- a/examples/flow_distributor/distributor/Makefile
+++ /dev/null
@@ -1,57 +0,0 @@
-#   BSD LICENSE
-#
-#   Copyright(c) 2016-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.
-
-ifeq ($(RTE_SDK),)
-$(error "Please define RTE_SDK environment variable")
-endif
-
-# Default target, can be overridden by command line or environment
-RTE_TARGET ?= x86_64-native-linuxapp-gcc
-
-include $(RTE_SDK)/mk/rte.vars.mk
-
-ifneq ($(CONFIG_RTE_EXEC_ENV), "linuxapp")
-$(error This application can only operate in a linuxapp environment, \
-please change the definition of the RTE_TARGET environment variable)
-endif
-
-# binary name
-APP = distributor
-
-# all source are stored in SRCS-y
-SRCS-y := main.c init.c args.c
-
-INC := $(wildcard *.h)
-
-CFLAGS += $(WERROR_FLAGS) -O3
-CFLAGS += -I$(SRCDIR)/../shared
-
-include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/flow_distributor/distributor/args.c b/examples/flow_distributor/distributor/args.c
deleted file mode 100644
index ee29203..0000000
--- a/examples/flow_distributor/distributor/args.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2016-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 <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <getopt.h>
-#include <stdarg.h>
-#include <errno.h>
-
-#include <rte_memory.h>
-#include <rte_string_fns.h>
-
-#include "common.h"
-#include "args.h"
-#include "init.h"
-
-/* 1M flows by default */
-#define DEFAULT_NUM_FLOWS    0x100000
-
-/* global var for number of nodes - extern in header */
-uint8_t num_nodes;
-/* global var for number of flows - extern in header */
-uint32_t num_flows = DEFAULT_NUM_FLOWS;
-
-static const char *progname;
-
-/**
- * Prints out usage information to stdout
- */
-static void
-usage(void)
-{
-	printf("%s [EAL options] -- -p PORTMASK -n NUM_NODES -f NUM_FLOWS\n"
-		" -p PORTMASK: hexadecimal bitmask of ports to use\n"
-		" -n NUM_NODES: number of node processes to use\n"
-		" -f NUM_FLOWS: number of flows to be added in the EFD table\n",
-		progname);
-}
-
-/**
- * The ports to be used by the application are passed in
- * the form of a bitmask. This function parses the bitmask
- * and places the port numbers to be used into the port[]
- * array variable
- */
-static int
-parse_portmask(uint8_t max_ports, const char *portmask)
-{
-	char *end = NULL;
-	unsigned long pm;
-	uint8_t count = 0;
-
-	if (portmask == NULL || *portmask == '\0')
-		return -1;
-
-	/* convert parameter to a number and verify */
-	pm = strtoul(portmask, &end, 16);
-	if (end == NULL || *end != '\0' || pm == 0)
-		return -1;
-
-	/* loop through bits of the mask and mark ports */
-	while (pm != 0) {
-		if (pm & 0x01) { /* bit is set in mask, use port */
-			if (count >= max_ports)
-				printf("WARNING: requested port %u not present"
-				" - ignoring\n", (unsigned int)count);
-			else
-			    info->id[info->num_ports++] = count;
-		}
-		pm = (pm >> 1);
-		count++;
-	}
-
-	return 0;
-}
-
-/**
- * Take the number of nodes parameter passed to the app
- * and convert to a number to store in the num_nodes variable
- */
-static int
-parse_num_nodes(const char *nodes)
-{
-	char *end = NULL;
-	unsigned long temp;
-
-	if (nodes == NULL || *nodes == '\0')
-		return -1;
-
-	temp = strtoul(nodes, &end, 10);
-	if (end == NULL || *end != '\0' || temp == 0)
-		return -1;
-
-	num_nodes = (uint8_t)temp;
-	return 0;
-}
-
-static int
-parse_num_flows(const char *flows)
-{
-	char *end = NULL;
-
-	/* parse hexadecimal string */
-	num_flows = strtoul(flows, &end, 16);
-	if ((flows[0] == '\0') || (end == NULL) || (*end != '\0'))
-		return -1;
-
-	if (num_flows == 0)
-		return -1;
-
-	return 0;
-}
-
-/**
- * The application specific arguments follow the DPDK-specific
- * arguments which are stripped by the DPDK init. This function
- * processes these application arguments, printing usage info
- * on error.
- */
-int
-parse_app_args(uint8_t max_ports, int argc, char *argv[])
-{
-	int option_index, opt;
-	char **argvopt = argv;
-	static struct option lgopts[] = { /* no long options */
-		{NULL, 0, 0, 0 }
-	};
-	progname = argv[0];
-
-	while ((opt = getopt_long(argc, argvopt, "n:f:p:", lgopts,
-			&option_index)) != EOF) {
-		switch (opt) {
-		case 'p':
-			if (parse_portmask(max_ports, optarg) != 0) {
-				usage();
-				return -1;
-			}
-			break;
-		case 'n':
-			if (parse_num_nodes(optarg) != 0) {
-				usage();
-				return -1;
-			}
-			break;
-		case 'f':
-			if (parse_num_flows(optarg) != 0) {
-				usage();
-				return -1;
-			}
-			break;
-		default:
-			printf("ERROR: Unknown option '%c'\n", opt);
-			usage();
-			return -1;
-		}
-	}
-
-	if (info->num_ports == 0 || num_nodes == 0) {
-		usage();
-		return -1;
-	}
-
-	if (info->num_ports % 2 != 0) {
-		printf("ERROR: application requires an even "
-				"number of ports to use\n");
-		return -1;
-	}
-	return 0;
-}
diff --git a/examples/flow_distributor/distributor/args.h b/examples/flow_distributor/distributor/args.h
deleted file mode 100644
index cacf395..0000000
--- a/examples/flow_distributor/distributor/args.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2016-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 _ARGS_H_
-#define _ARGS_H_
-
-int parse_app_args(uint8_t max_ports, int argc, char *argv[]);
-
-#endif /* ifndef _ARGS_H_ */
diff --git a/examples/flow_distributor/distributor/init.c b/examples/flow_distributor/distributor/init.c
deleted file mode 100644
index 3b0aa85..0000000
--- a/examples/flow_distributor/distributor/init.c
+++ /dev/null
@@ -1,371 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2016-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 <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/queue.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <inttypes.h>
-
-#include <rte_common.h>
-#include <rte_memory.h>
-#include <rte_memzone.h>
-#include <rte_eal.h>
-#include <rte_byteorder.h>
-#include <rte_atomic.h>
-#include <rte_launch.h>
-#include <rte_per_lcore.h>
-#include <rte_lcore.h>
-#include <rte_branch_prediction.h>
-#include <rte_debug.h>
-#include <rte_ring.h>
-#include <rte_log.h>
-#include <rte_mempool.h>
-#include <rte_memcpy.h>
-#include <rte_mbuf.h>
-#include <rte_interrupts.h>
-#include <rte_pci.h>
-#include <rte_ether.h>
-#include <rte_ethdev.h>
-#include <rte_malloc.h>
-#include <rte_string_fns.h>
-#include <rte_cycles.h>
-#include <rte_efd.h>
-#include <rte_hash.h>
-
-#include "common.h"
-#include "args.h"
-#include "init.h"
-
-#define MBUFS_PER_NODE 1536
-#define MBUFS_PER_PORT 1536
-#define MBUF_CACHE_SIZE 512
-
-#define RTE_MP_RX_DESC_DEFAULT 512
-#define RTE_MP_TX_DESC_DEFAULT 512
-#define NODE_QUEUE_RINGSIZE 128
-
-#define NO_FLAGS 0
-
-/* The mbuf pool for packet rx */
-struct rte_mempool *pktmbuf_pool;
-
-/* array of info/queues for nodes */
-struct node *nodes;
-
-/* Flow distributor table */
-struct rte_efd_table *efd_table;
-
-/* Shared info between distributor and nodes */
-struct shared_info *info;
-
-/**
- * Initialise the mbuf pool for packet reception for the NIC, and any other
- * buffer pools needed by the app - currently none.
- */
-static int
-init_mbuf_pools(void)
-{
-	const unsigned int num_mbufs = (num_nodes * MBUFS_PER_NODE) +
-			(info->num_ports * MBUFS_PER_PORT);
-
-	/*
-	 * Don't pass single-producer/single-consumer flags to mbuf create as it
-	 * seems faster to use a cache instead
-	 */
-	printf("Creating mbuf pool '%s' [%u mbufs] ...\n",
-			PKTMBUF_POOL_NAME, num_mbufs);
-	pktmbuf_pool = rte_pktmbuf_pool_create(PKTMBUF_POOL_NAME, num_mbufs,
-		MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
-
-	return pktmbuf_pool == NULL; /* 0  on success */
-}
-
-/**
- * Initialise an individual port:
- * - configure number of rx and tx rings
- * - set up each rx ring, to pull from the main mbuf pool
- * - set up each tx ring
- * - start the port and report its status to stdout
- */
-static int
-init_port(uint8_t port_num)
-{
-	/* for port configuration all features are off by default */
-	const struct rte_eth_conf port_conf = {
-		.rxmode = {
-			.mq_mode = ETH_MQ_RX_RSS
-		}
-	};
-	const uint16_t rx_rings = 1, tx_rings = num_nodes;
-	const uint16_t rx_ring_size = RTE_MP_RX_DESC_DEFAULT;
-	const uint16_t tx_ring_size = RTE_MP_TX_DESC_DEFAULT;
-
-	uint16_t q;
-	int retval;
-
-	printf("Port %u init ... ", (unsigned int)port_num);
-	fflush(stdout);
-
-	/*
-	 * Standard DPDK port initialisation - config port, then set up
-	 * rx and tx rings.
-	 */
-	retval = rte_eth_dev_configure(port_num, rx_rings, tx_rings, &port_conf);
-	if (retval != 0)
-		return retval;
-
-	for (q = 0; q < rx_rings; q++) {
-		retval = rte_eth_rx_queue_setup(port_num, q, rx_ring_size,
-				rte_eth_dev_socket_id(port_num),
-				NULL, pktmbuf_pool);
-		if (retval < 0)
-			return retval;
-	}
-
-	for (q = 0; q < tx_rings; q++) {
-		retval = rte_eth_tx_queue_setup(port_num, q, tx_ring_size,
-				rte_eth_dev_socket_id(port_num),
-				NULL);
-		if (retval < 0)
-			return retval;
-	}
-
-	rte_eth_promiscuous_enable(port_num);
-
-	retval = rte_eth_dev_start(port_num);
-	if (retval < 0)
-		return retval;
-
-	printf("done:\n");
-
-	return 0;
-}
-
-/**
- * Set up the DPDK rings which will be used to pass packets, via
- * pointers, between the multi-process distributor and node processes.
- * Each node needs one RX queue.
- */
-static int
-init_shm_rings(void)
-{
-	unsigned int i;
-	unsigned int socket_id;
-	const char *q_name;
-	const unsigned int ringsize = NODE_QUEUE_RINGSIZE;
-
-	nodes = rte_malloc("node details",
-		sizeof(*nodes) * num_nodes, 0);
-	if (nodes == NULL)
-		rte_exit(EXIT_FAILURE, "Cannot allocate memory for "
-				"node program details\n");
-
-	for (i = 0; i < num_nodes; i++) {
-		/* Create an RX queue for each node */
-		socket_id = rte_socket_id();
-		q_name = get_rx_queue_name(i);
-		nodes[i].rx_q = rte_ring_create(q_name,
-				ringsize, socket_id,
-				RING_F_SP_ENQ | RING_F_SC_DEQ);
-		if (nodes[i].rx_q == NULL)
-			rte_exit(EXIT_FAILURE, "Cannot create rx ring queue "
-					"for node %u\n", i);
-	}
-	return 0;
-}
-
-/*
- * Create flow distributor table which will contain all the flows
- * that will be distributed among the nodes
- */
-static void
-create_flow_distributor_table(void)
-{
-	uint8_t socket_id = rte_socket_id();
-
-	/* create table */
-	efd_table = rte_efd_create("flow table", num_flows * 2, sizeof(uint32_t),
-			1 << socket_id,	socket_id);
-
-	if (efd_table == NULL)
-		rte_exit(EXIT_FAILURE, "Problem creating the flow table\n");
-}
-
-static void
-populate_flow_distributor_table(void)
-{
-	unsigned int i;
-	int32_t ret;
-	uint32_t ip_dst;
-	uint8_t socket_id = rte_socket_id();
-	uint64_t node_id;
-
-	/* Add flows in table */
-	for (i = 0; i < num_flows; i++) {
-		node_id = i % num_nodes;
-
-		ip_dst = rte_cpu_to_be_32(i);
-		ret = rte_efd_update(efd_table, socket_id,
-				(void *)&ip_dst, (efd_value_t)node_id);
-		if (ret < 0)
-			rte_exit(EXIT_FAILURE, "Unable to add entry %u in "
-					"flow distributor table\n", i);
-	}
-
-	printf("EFD table: Adding 0x%x keys\n", num_flows);
-}
-
-/* Check the link status of all ports in up to 9s, and print them finally */
-static void
-check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
-{
-#define CHECK_INTERVAL 100 /* 100ms */
-#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
-	uint8_t portid, count, all_ports_up, print_flag = 0;
-	struct rte_eth_link link;
-
-	printf("\nChecking link status");
-	fflush(stdout);
-	for (count = 0; count <= MAX_CHECK_TIME; count++) {
-		all_ports_up = 1;
-		for (portid = 0; portid < port_num; portid++) {
-			if ((port_mask & (1 << info->id[portid])) == 0)
-				continue;
-			memset(&link, 0, sizeof(link));
-			rte_eth_link_get_nowait(info->id[portid], &link);
-			/* print link status if flag set */
-			if (print_flag == 1) {
-				if (link.link_status)
-					printf("Port %d Link Up - speed %u "
-						"Mbps - %s\n", info->id[portid],
-						(unsigned int)link.link_speed,
-				(link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
-					("full-duplex") : ("half-duplex\n"));
-				else
-					printf("Port %d Link Down\n",
-						(uint8_t)info->id[portid]);
-				continue;
-			}
-			/* clear all_ports_up flag if any link down */
-			if (link.link_status == ETH_LINK_DOWN) {
-				all_ports_up = 0;
-				break;
-			}
-		}
-		/* after finally printing all link status, get out */
-		if (print_flag == 1)
-			break;
-
-		if (all_ports_up == 0) {
-			printf(".");
-			fflush(stdout);
-			rte_delay_ms(CHECK_INTERVAL);
-		}
-
-		/* set the print_flag if all ports up or timeout */
-		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
-			print_flag = 1;
-			printf("done\n");
-		}
-	}
-}
-
-/**
- * Main init function for the multi-process distributor app,
- * calls subfunctions to do each stage of the initialisation.
- */
-int
-init(int argc, char *argv[])
-{
-	int retval;
-	const struct rte_memzone *mz;
-	uint8_t i, total_ports;
-
-	/* init EAL, parsing EAL args */
-	retval = rte_eal_init(argc, argv);
-	if (retval < 0)
-		return -1;
-	argc -= retval;
-	argv += retval;
-
-	/* get total number of ports */
-	total_ports = rte_eth_dev_count();
-
-	/* set up array for port data */
-	mz = rte_memzone_reserve(MZ_SHARED_INFO, sizeof(*info),
-				rte_socket_id(), NO_FLAGS);
-	if (mz == NULL)
-		rte_exit(EXIT_FAILURE, "Cannot reserve memory zone "
-				"for port information\n");
-	memset(mz->addr, 0, sizeof(*info));
-	info = mz->addr;
-
-	/* parse additional, application arguments */
-	retval = parse_app_args(total_ports, argc, argv);
-	if (retval != 0)
-		return -1;
-
-	/* initialise mbuf pools */
-	retval = init_mbuf_pools();
-	if (retval != 0)
-		rte_exit(EXIT_FAILURE, "Cannot create needed mbuf pools\n");
-
-	/* now initialise the ports we will use */
-	for (i = 0; i < info->num_ports; i++) {
-		retval = init_port(info->id[i]);
-		if (retval != 0)
-			rte_exit(EXIT_FAILURE, "Cannot initialise port %u\n",
-					(unsigned int) i);
-	}
-
-	check_all_ports_link_status(info->num_ports, (~0x0));
-
-	/* initialise the node queues/rings for inter-eu comms */
-	init_shm_rings();
-
-	/* Create the flow distributor table */
-	create_flow_distributor_table();
-
-	/* Populate the flow distributor table */
-	populate_flow_distributor_table();
-
-	/* Share the total number of nodes */
-	info->num_nodes = num_nodes;
-
-	/* Share the total number of flows */
-	info->num_flows = num_flows;
-	return 0;
-}
diff --git a/examples/flow_distributor/distributor/init.h b/examples/flow_distributor/distributor/init.h
deleted file mode 100644
index d11aacf..0000000
--- a/examples/flow_distributor/distributor/init.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2016-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 _INIT_H_
-#define _INIT_H_
-
-/*
- * #include <rte_ring.h>
- * #include "args.h"
- */
-
-/*
- * Define a node structure with all needed info, including
- * stats from the nodes.
- */
-struct node {
-	struct rte_ring *rx_q;
-	unsigned int node_id;
-	/* these stats hold how many packets the node will actually receive,
-	 * and how many packets were dropped because the node's queue was full.
-	 * The port-info stats, in contrast, record how many packets were received
-	 * or transmitted on an actual NIC port.
-	 */
-	struct {
-		uint64_t rx;
-		uint64_t rx_drop;
-	} stats;
-};
-
-extern struct rte_efd_table *efd_table;
-extern struct node *nodes;
-
-/*
- * shared information between distributor and nodes: number of clients,
- * port numbers, rx and tx stats etc.
- */
-extern struct shared_info *info;
-
-extern struct rte_mempool *pktmbuf_pool;
-extern uint8_t num_nodes;
-extern unsigned int num_sockets;
-extern uint32_t num_flows;
-
-int init(int argc, char *argv[]);
-
-#endif /* ifndef _INIT_H_ */
diff --git a/examples/flow_distributor/distributor/main.c b/examples/flow_distributor/distributor/main.c
deleted file mode 100644
index f97f003..0000000
--- a/examples/flow_distributor/distributor/main.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2016-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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <stdarg.h>
-#include <inttypes.h>
-#include <inttypes.h>
-#include <sys/queue.h>
-#include <errno.h>
-#include <netinet/ip.h>
-
-#include <rte_common.h>
-#include <rte_memory.h>
-#include <rte_memzone.h>
-#include <rte_eal.h>
-#include <rte_byteorder.h>
-#include <rte_launch.h>
-#include <rte_per_lcore.h>
-#include <rte_lcore.h>
-#include <rte_branch_prediction.h>
-#include <rte_atomic.h>
-#include <rte_ring.h>
-#include <rte_log.h>
-#include <rte_debug.h>
-#include <rte_mempool.h>
-#include <rte_memcpy.h>
-#include <rte_mbuf.h>
-#include <rte_ether.h>
-#include <rte_interrupts.h>
-#include <rte_pci.h>
-#include <rte_ethdev.h>
-#include <rte_byteorder.h>
-#include <rte_malloc.h>
-#include <rte_string_fns.h>
-#include <rte_efd.h>
-#include <rte_ip.h>
-
-#include "common.h"
-#include "args.h"
-#include "init.h"
-
-/*
- * When doing reads from the NIC or the node queues,
- * use this batch size
- */
-#define PACKET_READ_SIZE 32
-
-/*
- * Local buffers to put packets in, used to send packets in bursts to the
- * nodes
- */
-struct node_rx_buf {
-	struct rte_mbuf *buffer[PACKET_READ_SIZE];
-	uint16_t count;
-};
-
-struct flow_distributor_stats {
-	uint64_t distributed;
-	uint64_t drop;
-} flow_dist_stats;
-
-/* One buffer per node rx queue - dynamically allocate array */
-static struct node_rx_buf *cl_rx_buf;
-
-static const char *
-get_printable_mac_addr(uint8_t port)
-{
-	static const char err_address[] = "00:00:00:00:00:00";
-	static char addresses[RTE_MAX_ETHPORTS][sizeof(err_address)];
-	struct ether_addr mac;
-
-	if (unlikely(port >= RTE_MAX_ETHPORTS))
-		return err_address;
-	if (unlikely(addresses[port][0] == '\0')) {
-		rte_eth_macaddr_get(port, &mac);
-		snprintf(addresses[port], sizeof(addresses[port]),
-				"%02x:%02x:%02x:%02x:%02x:%02x\n",
-				mac.addr_bytes[0], mac.addr_bytes[1],
-				mac.addr_bytes[2], mac.addr_bytes[3],
-				mac.addr_bytes[4], mac.addr_bytes[5]);
-	}
-	return addresses[port];
-}
-
-/*
- * This function displays the recorded statistics for each port
- * and for each node. It uses ANSI terminal codes to clear
- * screen when called. It is called from a single non-master
- * thread in the distributor process, when the process is run with more
- * than one lcore enabled.
- */
-static void
-do_stats_display(void)
-{
-	unsigned int i, j;
-	const char clr[] = {27, '[', '2', 'J', '\0'};
-	const char topLeft[] = {27, '[', '1', ';', '1', 'H', '\0'};
-	uint64_t port_tx[RTE_MAX_ETHPORTS], port_tx_drop[RTE_MAX_ETHPORTS];
-	uint64_t node_tx[MAX_NODES], node_tx_drop[MAX_NODES];
-
-	/* to get TX stats, we need to do some summing calculations */
-	memset(port_tx, 0, sizeof(port_tx));
-	memset(port_tx_drop, 0, sizeof(port_tx_drop));
-	memset(node_tx, 0, sizeof(node_tx));
-	memset(node_tx_drop, 0, sizeof(node_tx_drop));
-
-	for (i = 0; i < num_nodes; i++) {
-		const struct tx_stats *tx = &info->tx_stats[i];
-
-		for (j = 0; j < info->num_ports; j++) {
-			const uint64_t tx_val = tx->tx[info->id[j]];
-			const uint64_t drop_val = tx->tx_drop[info->id[j]];
-
-			port_tx[j] += tx_val;
-			port_tx_drop[j] += drop_val;
-			node_tx[i] += tx_val;
-			node_tx_drop[i] += drop_val;
-		}
-	}
-
-	/* Clear screen and move to top left */
-	printf("%s%s", clr, topLeft);
-
-	printf("PORTS\n");
-	printf("-----\n");
-	for (i = 0; i < info->num_ports; i++)
-		printf("Port %u: '%s'\t", (unsigned int)info->id[i],
-				get_printable_mac_addr(info->id[i]));
-	printf("\n\n");
-	for (i = 0; i < info->num_ports; i++) {
-		printf("Port %u - rx: %9"PRIu64"\t"
-				"tx: %9"PRIu64"\n",
-				(unsigned int)info->id[i], info->rx_stats.rx[i],
-				port_tx[i]);
-	}
-
-	printf("\nFLOW DISTRIBUTOR\n");
-	printf("-----\n");
-	printf("distributed: %9"PRIu64", drop: %9"PRIu64"\n",
-			flow_dist_stats.distributed, flow_dist_stats.drop);
-
-	printf("\nNODES\n");
-	printf("-------\n");
-	for (i = 0; i < num_nodes; i++) {
-		const unsigned long long rx = nodes[i].stats.rx;
-		const unsigned long long rx_drop = nodes[i].stats.rx_drop;
-		const struct filter_stats *filter = &info->filter_stats[i];
-
-		printf("Node %2u - rx: %9llu, rx_drop: %9llu\n"
-				"            tx: %9"PRIu64", tx_drop: %9"PRIu64"\n"
-				"            filter_passed: %9"PRIu64", "
-				"filter_drop: %9"PRIu64"\n",
-				i, rx, rx_drop, node_tx[i], node_tx_drop[i],
-				filter->passed, filter->drop);
-	}
-
-	printf("\n");
-}
-
-/*
- * The function called from each non-master lcore used by the process.
- * The test_and_set function is used to randomly pick a single lcore on which
- * the code to display the statistics will run. Otherwise, the code just
- * repeatedly sleeps.
- */
-static int
-sleep_lcore(__attribute__((unused)) void *dummy)
-{
-	/* Used to pick a display thread - static, so zero-initialised */
-	static rte_atomic32_t display_stats;
-
-	/* Only one core should display stats */
-	if (rte_atomic32_test_and_set(&display_stats)) {
-		const unsigned int sleeptime = 1;
-
-		printf("Core %u displaying statistics\n", rte_lcore_id());
-
-		/* Longer initial pause so above printf is seen */
-		sleep(sleeptime * 3);
-
-		/* Loop forever: sleep always returns 0 or <= param */
-		while (sleep(sleeptime) <= sleeptime)
-			do_stats_display();
-	}
-	return 0;
-}
-
-/*
- * Function to set all the node statistic values to zero.
- * Called at program startup.
- */
-static void
-clear_stats(void)
-{
-	unsigned int i;
-
-	for (i = 0; i < num_nodes; i++)
-		nodes[i].stats.rx = nodes[i].stats.rx_drop = 0;
-}
-
-/*
- * send a burst of traffic to a node, assuming there are packets
- * available to be sent to this node
- */
-static void
-flush_rx_queue(uint16_t node)
-{
-	uint16_t j;
-	struct node *cl;
-
-	if (cl_rx_buf[node].count == 0)
-		return;
-
-	cl = &nodes[node];
-	if (rte_ring_enqueue_bulk(cl->rx_q, (void **)cl_rx_buf[node].buffer,
-			cl_rx_buf[node].count) != 0){
-		for (j = 0; j < cl_rx_buf[node].count; j++)
-			rte_pktmbuf_free(cl_rx_buf[node].buffer[j]);
-		cl->stats.rx_drop += cl_rx_buf[node].count;
-	} else
-		cl->stats.rx += cl_rx_buf[node].count;
-
-	cl_rx_buf[node].count = 0;
-}
-
-/*
- * marks a packet down to be sent to a particular node process
- */
-static inline void
-enqueue_rx_packet(uint8_t node, struct rte_mbuf *buf)
-{
-	cl_rx_buf[node].buffer[cl_rx_buf[node].count++] = buf;
-}
-
-/*
- * This function takes a group of packets and routes them
- * individually to the node process. Very simply round-robins the packets
- * without checking any of the packet contents.
- */
-static void
-process_packets(uint32_t port_num __rte_unused, struct rte_mbuf *pkts[],
-		uint16_t rx_count, unsigned int socket_id)
-{
-	uint16_t i;
-	uint8_t node;
-	efd_value_t data[RTE_EFD_BURST_MAX];
-	const void *key_ptrs[RTE_EFD_BURST_MAX];
-
-	struct ipv4_hdr *ipv4_hdr;
-	uint32_t ipv4_dst_ip[RTE_EFD_BURST_MAX];
-
-	for (i = 0; i < rx_count; i++) {
-		/* Handle IPv4 header.*/
-		ipv4_hdr = rte_pktmbuf_mtod_offset(pkts[i], struct ipv4_hdr *,
-				sizeof(struct ether_hdr));
-		ipv4_dst_ip[i] = ipv4_hdr->dst_addr;
-		key_ptrs[i] = (void *)&ipv4_dst_ip[i];
-	}
-
-	rte_efd_lookup_bulk(efd_table, socket_id, rx_count,
-				(const void **) key_ptrs, data);
-	for (i = 0; i < rx_count; i++) {
-		node = (uint8_t) ((uintptr_t)data[i]);
-
-		if (node >= num_nodes) {
-			/*
-			 * Node is out of range, which means that
-			 * flow has not been inserted
-			 */
-			flow_dist_stats.drop++;
-			rte_pktmbuf_free(pkts[i]);
-		} else {
-			flow_dist_stats.distributed++;
-			enqueue_rx_packet(node, pkts[i]);
-		}
-	}
-
-	for (i = 0; i < num_nodes; i++)
-		flush_rx_queue(i);
-}
-
-/*
- * Function called by the master lcore of the DPDK process.
- */
-static void
-do_packet_forwarding(void)
-{
-	unsigned int port_num = 0; /* indexes the port[] array */
-	unsigned int socket_id = rte_socket_id();
-
-	for (;;) {
-		struct rte_mbuf *buf[PACKET_READ_SIZE];
-		uint16_t rx_count;
-
-		/* read a port */
-		rx_count = rte_eth_rx_burst(info->id[port_num], 0,
-				buf, PACKET_READ_SIZE);
-		info->rx_stats.rx[port_num] += rx_count;
-
-		/* Now process the NIC packets read */
-		if (likely(rx_count > 0))
-			process_packets(port_num, buf, rx_count, socket_id);
-
-		/* move to next port */
-		if (++port_num == info->num_ports)
-			port_num = 0;
-	}
-}
-
-int
-main(int argc, char *argv[])
-{
-	/* initialise the system */
-	if (init(argc, argv) < 0)
-		return -1;
-	RTE_LOG(INFO, APP, "Finished Process Init.\n");
-
-	cl_rx_buf = calloc(num_nodes, sizeof(cl_rx_buf[0]));
-
-	/* clear statistics */
-	clear_stats();
-
-	/* put all other cores to sleep bar master */
-	rte_eal_mp_remote_launch(sleep_lcore, NULL, SKIP_MASTER);
-
-	do_packet_forwarding();
-	return 0;
-}
diff --git a/examples/flow_distributor/node/Makefile b/examples/flow_distributor/node/Makefile
deleted file mode 100644
index 8cf7b65..0000000
--- a/examples/flow_distributor/node/Makefile
+++ /dev/null
@@ -1,48 +0,0 @@
-#   BSD LICENSE
-#
-#   Copyright(c) 2016-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.
-
-ifeq ($(RTE_SDK),)
-$(error "Please define RTE_SDK environment variable")
-endif
-
-# Default target, can be overridden by command line or environment
-include $(RTE_SDK)/mk/rte.vars.mk
-
-# binary name
-APP = node
-
-# all source are stored in SRCS-y
-SRCS-y := node.c
-
-CFLAGS += $(WERROR_FLAGS) -O3
-CFLAGS += -I$(SRCDIR)/../shared
-
-include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/flow_distributor/node/node.c b/examples/flow_distributor/node/node.c
deleted file mode 100644
index 1f1e7e7..0000000
--- a/examples/flow_distributor/node/node.c
+++ /dev/null
@@ -1,417 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2016-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 <stdint.h>
-#include <stdio.h>
-#include <inttypes.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <sys/queue.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <string.h>
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-#include <rte_memory.h>
-#include <rte_memzone.h>
-#include <rte_eal.h>
-#include <rte_atomic.h>
-#include <rte_branch_prediction.h>
-#include <rte_log.h>
-#include <rte_per_lcore.h>
-#include <rte_launch.h>
-#include <rte_lcore.h>
-#include <rte_ring.h>
-#include <rte_launch.h>
-#include <rte_lcore.h>
-#include <rte_debug.h>
-#include <rte_mempool.h>
-#include <rte_mbuf.h>
-#include <rte_interrupts.h>
-#include <rte_pci.h>
-#include <rte_ether.h>
-#include <rte_ethdev.h>
-#include <rte_string_fns.h>
-#include <rte_ip.h>
-
-#include "common.h"
-
-/* Number of packets to attempt to read from queue */
-#define PKT_READ_SIZE  ((uint16_t)32)
-
-/*
- * Our node id number - tells us which rx queue to read, and NIC TX
- * queue to write to.
- */
-static uint8_t node_id;
-
-#define MBQ_CAPACITY 32
-
-/* maps input ports to output ports for packets */
-static uint8_t output_ports[RTE_MAX_ETHPORTS];
-
-/* buffers up a set of packet that are ready to send */
-struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];
-
-/* shared data from distributor. We update statistics here */
-static struct tx_stats *tx_stats;
-
-static struct filter_stats *filter_stats;
-
-/*
- * print a usage message
- */
-static void
-usage(const char *progname)
-{
-	printf("Usage: %s [EAL args] -- -n <node_id>\n\n", progname);
-}
-
-/*
- * Convert the node id number from a string to an int.
- */
-static int
-parse_node_num(const char *node)
-{
-	char *end = NULL;
-	unsigned long temp;
-
-	if (node == NULL || *node == '\0')
-		return -1;
-
-	temp = strtoul(node, &end, 10);
-	if (end == NULL || *end != '\0')
-		return -1;
-
-	node_id = (uint8_t)temp;
-	return 0;
-}
-
-/*
- * Parse the application arguments to the node app.
- */
-static int
-parse_app_args(int argc, char *argv[])
-{
-	int option_index, opt;
-	char **argvopt = argv;
-	const char *progname = NULL;
-	static struct option lgopts[] = { /* no long options */
-		{NULL, 0, 0, 0 }
-	};
-	progname = argv[0];
-
-	while ((opt = getopt_long(argc, argvopt, "n:", lgopts,
-		&option_index)) != EOF) {
-		switch (opt) {
-		case 'n':
-			if (parse_node_num(optarg) != 0) {
-				usage(progname);
-				return -1;
-			}
-			break;
-		default:
-			usage(progname);
-			return -1;
-		}
-	}
-	return 0;
-}
-
-/*
- * Tx buffer error callback
- */
-static void
-flush_tx_error_callback(struct rte_mbuf **unsent, uint16_t count,
-		void *userdata) {
-	int i;
-	uint8_t port_id = (uintptr_t)userdata;
-
-	tx_stats->tx_drop[port_id] += count;
-
-	/* free the mbufs which failed from transmit */
-	for (i = 0; i < count; i++)
-		rte_pktmbuf_free(unsent[i]);
-
-}
-
-static void
-configure_tx_buffer(uint8_t port_id, uint16_t size)
-{
-	int ret;
-
-	/* Initialize TX buffers */
-	tx_buffer[port_id] = rte_zmalloc_socket("tx_buffer",
-			RTE_ETH_TX_BUFFER_SIZE(size), 0,
-			rte_eth_dev_socket_id(port_id));
-	if (tx_buffer[port_id] == NULL)
-		rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx "
-				"on port %u\n", (unsigned int) port_id);
-
-	rte_eth_tx_buffer_init(tx_buffer[port_id], size);
-
-	ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[port_id],
-			flush_tx_error_callback, (void *)(intptr_t)port_id);
-	if (ret < 0)
-		rte_exit(EXIT_FAILURE, "Cannot set error callback for "
-			"tx buffer on port %u\n", (unsigned int) port_id);
-}
-
-/*
- * set up output ports so that all traffic on port gets sent out
- * its paired port. Index using actual port numbers since that is
- * what comes in the mbuf structure.
- */
-static void
-configure_output_ports(const struct shared_info *info)
-{
-	int i;
-
-	if (info->num_ports > RTE_MAX_ETHPORTS)
-		rte_exit(EXIT_FAILURE, "Too many ethernet ports. "
-				"RTE_MAX_ETHPORTS = %u\n",
-				(unsigned int)RTE_MAX_ETHPORTS);
-	for (i = 0; i < info->num_ports - 1; i += 2) {
-		uint8_t p1 = info->id[i];
-		uint8_t p2 = info->id[i+1];
-
-		output_ports[p1] = p2;
-		output_ports[p2] = p1;
-
-		configure_tx_buffer(p1, MBQ_CAPACITY);
-		configure_tx_buffer(p2, MBQ_CAPACITY);
-
-	}
-}
-
-/*
- * Create the hash table that will contain the flows that
- * the node will handle, which will be used to decide if packet
- * is transmitted or dropped.
- */
-static struct rte_hash *
-create_hash_table(const struct shared_info *info)
-{
-	uint32_t num_flows_node = info->num_flows / info->num_nodes;
-	char name[RTE_HASH_NAMESIZE];
-	struct rte_hash *h;
-
-	/* create table */
-	struct rte_hash_parameters hash_params = {
-		.entries = num_flows_node * 2, /* table load = 50% */
-		.key_len = sizeof(uint32_t), /* Store IPv4 dest IP address */
-		.socket_id = rte_socket_id(),
-		.hash_func_init_val = 0,
-	};
-
-	snprintf(name, sizeof(name), "hash_table_%d", node_id);
-	hash_params.name = name;
-	h = rte_hash_create(&hash_params);
-
-	if (h == NULL)
-		rte_exit(EXIT_FAILURE,
-				"Problem creating the hash table for node %d\n",
-				node_id);
-	return h;
-}
-
-static void
-populate_hash_table(const struct rte_hash *h, const struct shared_info *info)
-{
-	unsigned int i;
-	int32_t ret;
-	uint32_t ip_dst;
-	uint32_t num_flows_node = 0;
-	uint64_t target_node;
-
-	/* Add flows in table */
-	for (i = 0; i < info->num_flows; i++) {
-		target_node = i % info->num_nodes;
-		if (target_node != node_id)
-			continue;
-
-		ip_dst = rte_cpu_to_be_32(i);
-
-		ret = rte_hash_add_key(h, (void *) &ip_dst);
-		if (ret < 0)
-			rte_exit(EXIT_FAILURE, "Unable to add entry %u "
-					"in hash table\n", i);
-		else
-			num_flows_node++;
-
-	}
-
-	printf("Hash table: Adding 0x%x keys\n", num_flows_node);
-}
-
-/*
- * This function performs routing of packets
- * Just sends each input packet out an output port based solely on the input
- * port it arrived on.
- */
-static inline void
-transmit_packet(struct rte_mbuf *buf)
-{
-	int sent;
-	const uint8_t in_port = buf->port;
-	const uint8_t out_port = output_ports[in_port];
-	struct rte_eth_dev_tx_buffer *buffer = tx_buffer[out_port];
-
-	sent = rte_eth_tx_buffer(out_port, node_id, buffer, buf);
-	if (sent)
-		tx_stats->tx[out_port] += sent;
-
-}
-
-static inline void
-handle_packets(struct rte_hash *h, struct rte_mbuf **bufs, uint16_t num_packets)
-{
-	struct ipv4_hdr *ipv4_hdr;
-	uint32_t ipv4_dst_ip[PKT_READ_SIZE];
-	const void *key_ptrs[PKT_READ_SIZE];
-	unsigned int i;
-	int32_t positions[PKT_READ_SIZE] = {0};
-
-	for (i = 0; i < num_packets; i++) {
-		/* Handle IPv4 header.*/
-		ipv4_hdr = rte_pktmbuf_mtod_offset(bufs[i], struct ipv4_hdr *,
-				sizeof(struct ether_hdr));
-		ipv4_dst_ip[i] = ipv4_hdr->dst_addr;
-		key_ptrs[i] = &ipv4_dst_ip[i];
-	}
-	/* Check if packets belongs to any flows handled by this node */
-	rte_hash_lookup_bulk(h, key_ptrs, num_packets, positions);
-
-	for (i = 0; i < num_packets; i++) {
-		if (likely(positions[i] >= 0)) {
-			filter_stats->passed++;
-			transmit_packet(bufs[i]);
-		} else {
-			filter_stats->drop++;
-			/* Drop packet, as flow is not handled by this node */
-			rte_pktmbuf_free(bufs[i]);
-		}
-	}
-}
-
-/*
- * Application main function - loops through
- * receiving and processing packets. Never returns
- */
-int
-main(int argc, char *argv[])
-{
-	const struct rte_memzone *mz;
-	struct rte_ring *rx_ring;
-	struct rte_hash *h;
-	struct rte_mempool *mp;
-	struct shared_info *info;
-	int need_flush = 0; /* indicates whether we have unsent packets */
-	int retval;
-	void *pkts[PKT_READ_SIZE];
-	uint16_t sent;
-
-	retval = rte_eal_init(argc, argv);
-	if (retval  < 0)
-		return -1;
-	argc -= retval;
-	argv += retval;
-
-	if (parse_app_args(argc, argv) < 0)
-		rte_exit(EXIT_FAILURE, "Invalid command-line arguments\n");
-
-	if (rte_eth_dev_count() == 0)
-		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
-
-	rx_ring = rte_ring_lookup(get_rx_queue_name(node_id));
-	if (rx_ring == NULL)
-		rte_exit(EXIT_FAILURE, "Cannot get RX ring - "
-				"is distributor process running?\n");
-
-	mp = rte_mempool_lookup(PKTMBUF_POOL_NAME);
-	if (mp == NULL)
-		rte_exit(EXIT_FAILURE, "Cannot get mempool for mbufs\n");
-
-	mz = rte_memzone_lookup(MZ_SHARED_INFO);
-	if (mz == NULL)
-		rte_exit(EXIT_FAILURE, "Cannot get port info structure\n");
-	info = mz->addr;
-	tx_stats = &(info->tx_stats[node_id]);
-	filter_stats = &(info->filter_stats[node_id]);
-
-	configure_output_ports(info);
-
-	h = create_hash_table(info);
-
-	populate_hash_table(h, info);
-
-	RTE_LOG(INFO, APP, "Finished Process Init.\n");
-
-	printf("\nNode process %d handling packets\n", node_id);
-	printf("[Press Ctrl-C to quit ...]\n");
-
-	for (;;) {
-		uint16_t  rx_pkts = PKT_READ_SIZE;
-		uint8_t port;
-
-		/*
-		 * Try dequeuing max possible packets first, if that fails,
-		 * get the most we can. Loop body should only execute once,
-		 * maximum
-		 */
-		while (rx_pkts > 0 &&
-				unlikely(rte_ring_dequeue_bulk(rx_ring, pkts,
-					rx_pkts) != 0))
-			rx_pkts = (uint16_t)RTE_MIN(rte_ring_count(rx_ring),
-					PKT_READ_SIZE);
-
-		if (unlikely(rx_pkts == 0)) {
-			if (need_flush)
-				for (port = 0; port < info->num_ports; port++) {
-					sent = rte_eth_tx_buffer_flush(
-							info->id[port],
-							node_id,
-							tx_buffer[port]);
-					if (unlikely(sent))
-						tx_stats->tx[port] += sent;
-				}
-			need_flush = 0;
-			continue;
-		}
-
-		handle_packets(h, (struct rte_mbuf **)pkts, rx_pkts);
-
-		need_flush = 1;
-	}
-}
diff --git a/examples/flow_distributor/shared/common.h b/examples/flow_distributor/shared/common.h
deleted file mode 100644
index 5dcffd6..0000000
--- a/examples/flow_distributor/shared/common.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2016-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 _COMMON_H_
-#define _COMMON_H_
-
-#include <rte_hash_crc.h>
-#include <rte_hash.h>
-
-#define MAX_NODES             16
-/*
- * Shared port info, including statistics information for display by distributor.
- * Structure will be put in a memzone.
- * - All port id values share one cache line as this data will be read-only
- * during operation.
- * - All rx statistic values share cache lines, as this data is written only
- * by the distributor process. (rare reads by stats display)
- * - The tx statistics have values for all ports per cache line, but the stats
- * themselves are written by the nodes, so we have a distinct set, on different
- * cache lines for each node to use.
- */
-struct rx_stats {
-	uint64_t rx[RTE_MAX_ETHPORTS];
-} __rte_cache_aligned;
-
-struct tx_stats {
-	uint64_t tx[RTE_MAX_ETHPORTS];
-	uint64_t tx_drop[RTE_MAX_ETHPORTS];
-} __rte_cache_aligned;
-
-struct filter_stats {
-	uint64_t drop;
-	uint64_t passed;
-} __rte_cache_aligned;
-
-struct shared_info {
-	uint8_t num_nodes;
-	uint8_t num_ports;
-	uint32_t num_flows;
-	uint8_t id[RTE_MAX_ETHPORTS];
-	struct rx_stats rx_stats;
-	struct tx_stats tx_stats[MAX_NODES];
-	struct filter_stats filter_stats[MAX_NODES];
-};
-
-/* define common names for structures shared between distributor and node */
-#define MP_NODE_RXQ_NAME "MProc_Node_%u_RX"
-#define PKTMBUF_POOL_NAME "MProc_pktmbuf_pool"
-#define MZ_SHARED_INFO "MProc_shared_info"
-
-/*
- * Given the rx queue name template above, get the queue name
- */
-static inline const char *
-get_rx_queue_name(unsigned int id)
-{
-	/*
-	 * Buffer for return value. Size calculated by %u being replaced
-	 * by maximum 3 digits (plus an extra byte for safety)
-	 */
-	static char buffer[sizeof(MP_NODE_RXQ_NAME) + 2];
-
-	snprintf(buffer, sizeof(buffer) - 1, MP_NODE_RXQ_NAME, id);
-	return buffer;
-}
-
-#define RTE_LOGTYPE_APP RTE_LOGTYPE_USER1
-
-#endif
diff --git a/examples/server_node_efd/Makefile b/examples/server_node_efd/Makefile
new file mode 100644
index 0000000..6977ef9
--- /dev/null
+++ b/examples/server_node_efd/Makefile
@@ -0,0 +1,44 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016-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.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overridden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += server
+DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += node
+
+include $(RTE_SDK)/mk/rte.extsubdir.mk
diff --git a/examples/server_node_efd/node/Makefile b/examples/server_node_efd/node/Makefile
new file mode 100644
index 0000000..8cf7b65
--- /dev/null
+++ b/examples/server_node_efd/node/Makefile
@@ -0,0 +1,48 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016-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.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overridden by command line or environment
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = node
+
+# all source are stored in SRCS-y
+SRCS-y := node.c
+
+CFLAGS += $(WERROR_FLAGS) -O3
+CFLAGS += -I$(SRCDIR)/../shared
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/server_node_efd/node/node.c b/examples/server_node_efd/node/node.c
new file mode 100644
index 0000000..a6c0c70
--- /dev/null
+++ b/examples/server_node_efd/node/node.c
@@ -0,0 +1,417 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016-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 <stdint.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/queue.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_eal.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_log.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_lcore.h>
+#include <rte_ring.h>
+#include <rte_launch.h>
+#include <rte_lcore.h>
+#include <rte_debug.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_string_fns.h>
+#include <rte_ip.h>
+
+#include "common.h"
+
+/* Number of packets to attempt to read from queue */
+#define PKT_READ_SIZE  ((uint16_t)32)
+
+/*
+ * Our node id number - tells us which rx queue to read, and NIC TX
+ * queue to write to.
+ */
+static uint8_t node_id;
+
+#define MBQ_CAPACITY 32
+
+/* maps input ports to output ports for packets */
+static uint8_t output_ports[RTE_MAX_ETHPORTS];
+
+/* buffers up a set of packet that are ready to send */
+struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];
+
+/* shared data from server. We update statistics here */
+static struct tx_stats *tx_stats;
+
+static struct filter_stats *filter_stats;
+
+/*
+ * print a usage message
+ */
+static void
+usage(const char *progname)
+{
+	printf("Usage: %s [EAL args] -- -n <node_id>\n\n", progname);
+}
+
+/*
+ * Convert the node id number from a string to an int.
+ */
+static int
+parse_node_num(const char *node)
+{
+	char *end = NULL;
+	unsigned long temp;
+
+	if (node == NULL || *node == '\0')
+		return -1;
+
+	temp = strtoul(node, &end, 10);
+	if (end == NULL || *end != '\0')
+		return -1;
+
+	node_id = (uint8_t)temp;
+	return 0;
+}
+
+/*
+ * Parse the application arguments to the node app.
+ */
+static int
+parse_app_args(int argc, char *argv[])
+{
+	int option_index, opt;
+	char **argvopt = argv;
+	const char *progname = NULL;
+	static struct option lgopts[] = { /* no long options */
+		{NULL, 0, 0, 0 }
+	};
+	progname = argv[0];
+
+	while ((opt = getopt_long(argc, argvopt, "n:", lgopts,
+		&option_index)) != EOF) {
+		switch (opt) {
+		case 'n':
+			if (parse_node_num(optarg) != 0) {
+				usage(progname);
+				return -1;
+			}
+			break;
+		default:
+			usage(progname);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Tx buffer error callback
+ */
+static void
+flush_tx_error_callback(struct rte_mbuf **unsent, uint16_t count,
+		void *userdata) {
+	int i;
+	uint8_t port_id = (uintptr_t)userdata;
+
+	tx_stats->tx_drop[port_id] += count;
+
+	/* free the mbufs which failed from transmit */
+	for (i = 0; i < count; i++)
+		rte_pktmbuf_free(unsent[i]);
+
+}
+
+static void
+configure_tx_buffer(uint8_t port_id, uint16_t size)
+{
+	int ret;
+
+	/* Initialize TX buffers */
+	tx_buffer[port_id] = rte_zmalloc_socket("tx_buffer",
+			RTE_ETH_TX_BUFFER_SIZE(size), 0,
+			rte_eth_dev_socket_id(port_id));
+	if (tx_buffer[port_id] == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx "
+				"on port %u\n", (unsigned int) port_id);
+
+	rte_eth_tx_buffer_init(tx_buffer[port_id], size);
+
+	ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[port_id],
+			flush_tx_error_callback, (void *)(intptr_t)port_id);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Cannot set error callback for "
+			"tx buffer on port %u\n", (unsigned int) port_id);
+}
+
+/*
+ * set up output ports so that all traffic on port gets sent out
+ * its paired port. Index using actual port numbers since that is
+ * what comes in the mbuf structure.
+ */
+static void
+configure_output_ports(const struct shared_info *info)
+{
+	int i;
+
+	if (info->num_ports > RTE_MAX_ETHPORTS)
+		rte_exit(EXIT_FAILURE, "Too many ethernet ports. "
+				"RTE_MAX_ETHPORTS = %u\n",
+				(unsigned int)RTE_MAX_ETHPORTS);
+	for (i = 0; i < info->num_ports - 1; i += 2) {
+		uint8_t p1 = info->id[i];
+		uint8_t p2 = info->id[i+1];
+
+		output_ports[p1] = p2;
+		output_ports[p2] = p1;
+
+		configure_tx_buffer(p1, MBQ_CAPACITY);
+		configure_tx_buffer(p2, MBQ_CAPACITY);
+
+	}
+}
+
+/*
+ * Create the hash table that will contain the flows that
+ * the node will handle, which will be used to decide if packet
+ * is transmitted or dropped.
+ */
+static struct rte_hash *
+create_hash_table(const struct shared_info *info)
+{
+	uint32_t num_flows_node = info->num_flows / info->num_nodes;
+	char name[RTE_HASH_NAMESIZE];
+	struct rte_hash *h;
+
+	/* create table */
+	struct rte_hash_parameters hash_params = {
+		.entries = num_flows_node * 2, /* table load = 50% */
+		.key_len = sizeof(uint32_t), /* Store IPv4 dest IP address */
+		.socket_id = rte_socket_id(),
+		.hash_func_init_val = 0,
+	};
+
+	snprintf(name, sizeof(name), "hash_table_%d", node_id);
+	hash_params.name = name;
+	h = rte_hash_create(&hash_params);
+
+	if (h == NULL)
+		rte_exit(EXIT_FAILURE,
+				"Problem creating the hash table for node %d\n",
+				node_id);
+	return h;
+}
+
+static void
+populate_hash_table(const struct rte_hash *h, const struct shared_info *info)
+{
+	unsigned int i;
+	int32_t ret;
+	uint32_t ip_dst;
+	uint32_t num_flows_node = 0;
+	uint64_t target_node;
+
+	/* Add flows in table */
+	for (i = 0; i < info->num_flows; i++) {
+		target_node = i % info->num_nodes;
+		if (target_node != node_id)
+			continue;
+
+		ip_dst = rte_cpu_to_be_32(i);
+
+		ret = rte_hash_add_key(h, (void *) &ip_dst);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "Unable to add entry %u "
+					"in hash table\n", i);
+		else
+			num_flows_node++;
+
+	}
+
+	printf("Hash table: Adding 0x%x keys\n", num_flows_node);
+}
+
+/*
+ * This function performs routing of packets
+ * Just sends each input packet out an output port based solely on the input
+ * port it arrived on.
+ */
+static inline void
+transmit_packet(struct rte_mbuf *buf)
+{
+	int sent;
+	const uint8_t in_port = buf->port;
+	const uint8_t out_port = output_ports[in_port];
+	struct rte_eth_dev_tx_buffer *buffer = tx_buffer[out_port];
+
+	sent = rte_eth_tx_buffer(out_port, node_id, buffer, buf);
+	if (sent)
+		tx_stats->tx[out_port] += sent;
+
+}
+
+static inline void
+handle_packets(struct rte_hash *h, struct rte_mbuf **bufs, uint16_t num_packets)
+{
+	struct ipv4_hdr *ipv4_hdr;
+	uint32_t ipv4_dst_ip[PKT_READ_SIZE];
+	const void *key_ptrs[PKT_READ_SIZE];
+	unsigned int i;
+	int32_t positions[PKT_READ_SIZE] = {0};
+
+	for (i = 0; i < num_packets; i++) {
+		/* Handle IPv4 header.*/
+		ipv4_hdr = rte_pktmbuf_mtod_offset(bufs[i], struct ipv4_hdr *,
+				sizeof(struct ether_hdr));
+		ipv4_dst_ip[i] = ipv4_hdr->dst_addr;
+		key_ptrs[i] = &ipv4_dst_ip[i];
+	}
+	/* Check if packets belongs to any flows handled by this node */
+	rte_hash_lookup_bulk(h, key_ptrs, num_packets, positions);
+
+	for (i = 0; i < num_packets; i++) {
+		if (likely(positions[i] >= 0)) {
+			filter_stats->passed++;
+			transmit_packet(bufs[i]);
+		} else {
+			filter_stats->drop++;
+			/* Drop packet, as flow is not handled by this node */
+			rte_pktmbuf_free(bufs[i]);
+		}
+	}
+}
+
+/*
+ * Application main function - loops through
+ * receiving and processing packets. Never returns
+ */
+int
+main(int argc, char *argv[])
+{
+	const struct rte_memzone *mz;
+	struct rte_ring *rx_ring;
+	struct rte_hash *h;
+	struct rte_mempool *mp;
+	struct shared_info *info;
+	int need_flush = 0; /* indicates whether we have unsent packets */
+	int retval;
+	void *pkts[PKT_READ_SIZE];
+	uint16_t sent;
+
+	retval = rte_eal_init(argc, argv);
+	if (retval  < 0)
+		return -1;
+	argc -= retval;
+	argv += retval;
+
+	if (parse_app_args(argc, argv) < 0)
+		rte_exit(EXIT_FAILURE, "Invalid command-line arguments\n");
+
+	if (rte_eth_dev_count() == 0)
+		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+	rx_ring = rte_ring_lookup(get_rx_queue_name(node_id));
+	if (rx_ring == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot get RX ring - "
+				"is server process running?\n");
+
+	mp = rte_mempool_lookup(PKTMBUF_POOL_NAME);
+	if (mp == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot get mempool for mbufs\n");
+
+	mz = rte_memzone_lookup(MZ_SHARED_INFO);
+	if (mz == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot get port info structure\n");
+	info = mz->addr;
+	tx_stats = &(info->tx_stats[node_id]);
+	filter_stats = &(info->filter_stats[node_id]);
+
+	configure_output_ports(info);
+
+	h = create_hash_table(info);
+
+	populate_hash_table(h, info);
+
+	RTE_LOG(INFO, APP, "Finished Process Init.\n");
+
+	printf("\nNode process %d handling packets\n", node_id);
+	printf("[Press Ctrl-C to quit ...]\n");
+
+	for (;;) {
+		uint16_t  rx_pkts = PKT_READ_SIZE;
+		uint8_t port;
+
+		/*
+		 * Try dequeuing max possible packets first, if that fails,
+		 * get the most we can. Loop body should only execute once,
+		 * maximum
+		 */
+		while (rx_pkts > 0 &&
+				unlikely(rte_ring_dequeue_bulk(rx_ring, pkts,
+					rx_pkts) != 0))
+			rx_pkts = (uint16_t)RTE_MIN(rte_ring_count(rx_ring),
+					PKT_READ_SIZE);
+
+		if (unlikely(rx_pkts == 0)) {
+			if (need_flush)
+				for (port = 0; port < info->num_ports; port++) {
+					sent = rte_eth_tx_buffer_flush(
+							info->id[port],
+							node_id,
+							tx_buffer[port]);
+					if (unlikely(sent))
+						tx_stats->tx[port] += sent;
+				}
+			need_flush = 0;
+			continue;
+		}
+
+		handle_packets(h, (struct rte_mbuf **)pkts, rx_pkts);
+
+		need_flush = 1;
+	}
+}
diff --git a/examples/server_node_efd/server/Makefile b/examples/server_node_efd/server/Makefile
new file mode 100644
index 0000000..a2f2f36
--- /dev/null
+++ b/examples/server_node_efd/server/Makefile
@@ -0,0 +1,57 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016-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.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overridden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV), "linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = server
+
+# all source are stored in SRCS-y
+SRCS-y := main.c init.c args.c
+
+INC := $(wildcard *.h)
+
+CFLAGS += $(WERROR_FLAGS) -O3
+CFLAGS += -I$(SRCDIR)/../shared
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/server_node_efd/server/args.c b/examples/server_node_efd/server/args.c
new file mode 100644
index 0000000..ee29203
--- /dev/null
+++ b/examples/server_node_efd/server/args.c
@@ -0,0 +1,200 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016-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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#include <rte_memory.h>
+#include <rte_string_fns.h>
+
+#include "common.h"
+#include "args.h"
+#include "init.h"
+
+/* 1M flows by default */
+#define DEFAULT_NUM_FLOWS    0x100000
+
+/* global var for number of nodes - extern in header */
+uint8_t num_nodes;
+/* global var for number of flows - extern in header */
+uint32_t num_flows = DEFAULT_NUM_FLOWS;
+
+static const char *progname;
+
+/**
+ * Prints out usage information to stdout
+ */
+static void
+usage(void)
+{
+	printf("%s [EAL options] -- -p PORTMASK -n NUM_NODES -f NUM_FLOWS\n"
+		" -p PORTMASK: hexadecimal bitmask of ports to use\n"
+		" -n NUM_NODES: number of node processes to use\n"
+		" -f NUM_FLOWS: number of flows to be added in the EFD table\n",
+		progname);
+}
+
+/**
+ * The ports to be used by the application are passed in
+ * the form of a bitmask. This function parses the bitmask
+ * and places the port numbers to be used into the port[]
+ * array variable
+ */
+static int
+parse_portmask(uint8_t max_ports, const char *portmask)
+{
+	char *end = NULL;
+	unsigned long pm;
+	uint8_t count = 0;
+
+	if (portmask == NULL || *portmask == '\0')
+		return -1;
+
+	/* convert parameter to a number and verify */
+	pm = strtoul(portmask, &end, 16);
+	if (end == NULL || *end != '\0' || pm == 0)
+		return -1;
+
+	/* loop through bits of the mask and mark ports */
+	while (pm != 0) {
+		if (pm & 0x01) { /* bit is set in mask, use port */
+			if (count >= max_ports)
+				printf("WARNING: requested port %u not present"
+				" - ignoring\n", (unsigned int)count);
+			else
+			    info->id[info->num_ports++] = count;
+		}
+		pm = (pm >> 1);
+		count++;
+	}
+
+	return 0;
+}
+
+/**
+ * Take the number of nodes parameter passed to the app
+ * and convert to a number to store in the num_nodes variable
+ */
+static int
+parse_num_nodes(const char *nodes)
+{
+	char *end = NULL;
+	unsigned long temp;
+
+	if (nodes == NULL || *nodes == '\0')
+		return -1;
+
+	temp = strtoul(nodes, &end, 10);
+	if (end == NULL || *end != '\0' || temp == 0)
+		return -1;
+
+	num_nodes = (uint8_t)temp;
+	return 0;
+}
+
+static int
+parse_num_flows(const char *flows)
+{
+	char *end = NULL;
+
+	/* parse hexadecimal string */
+	num_flows = strtoul(flows, &end, 16);
+	if ((flows[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+
+	if (num_flows == 0)
+		return -1;
+
+	return 0;
+}
+
+/**
+ * The application specific arguments follow the DPDK-specific
+ * arguments which are stripped by the DPDK init. This function
+ * processes these application arguments, printing usage info
+ * on error.
+ */
+int
+parse_app_args(uint8_t max_ports, int argc, char *argv[])
+{
+	int option_index, opt;
+	char **argvopt = argv;
+	static struct option lgopts[] = { /* no long options */
+		{NULL, 0, 0, 0 }
+	};
+	progname = argv[0];
+
+	while ((opt = getopt_long(argc, argvopt, "n:f:p:", lgopts,
+			&option_index)) != EOF) {
+		switch (opt) {
+		case 'p':
+			if (parse_portmask(max_ports, optarg) != 0) {
+				usage();
+				return -1;
+			}
+			break;
+		case 'n':
+			if (parse_num_nodes(optarg) != 0) {
+				usage();
+				return -1;
+			}
+			break;
+		case 'f':
+			if (parse_num_flows(optarg) != 0) {
+				usage();
+				return -1;
+			}
+			break;
+		default:
+			printf("ERROR: Unknown option '%c'\n", opt);
+			usage();
+			return -1;
+		}
+	}
+
+	if (info->num_ports == 0 || num_nodes == 0) {
+		usage();
+		return -1;
+	}
+
+	if (info->num_ports % 2 != 0) {
+		printf("ERROR: application requires an even "
+				"number of ports to use\n");
+		return -1;
+	}
+	return 0;
+}
diff --git a/examples/server_node_efd/server/args.h b/examples/server_node_efd/server/args.h
new file mode 100644
index 0000000..cacf395
--- /dev/null
+++ b/examples/server_node_efd/server/args.h
@@ -0,0 +1,39 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016-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 _ARGS_H_
+#define _ARGS_H_
+
+int parse_app_args(uint8_t max_ports, int argc, char *argv[]);
+
+#endif /* ifndef _ARGS_H_ */
diff --git a/examples/server_node_efd/server/init.c b/examples/server_node_efd/server/init.c
new file mode 100644
index 0000000..82457b4
--- /dev/null
+++ b/examples/server_node_efd/server/init.c
@@ -0,0 +1,371 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016-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 <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <inttypes.h>
+
+#include <rte_common.h>
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_eal.h>
+#include <rte_byteorder.h>
+#include <rte_atomic.h>
+#include <rte_launch.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_debug.h>
+#include <rte_ring.h>
+#include <rte_log.h>
+#include <rte_mempool.h>
+#include <rte_memcpy.h>
+#include <rte_mbuf.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_string_fns.h>
+#include <rte_cycles.h>
+#include <rte_efd.h>
+#include <rte_hash.h>
+
+#include "common.h"
+#include "args.h"
+#include "init.h"
+
+#define MBUFS_PER_NODE 1536
+#define MBUFS_PER_PORT 1536
+#define MBUF_CACHE_SIZE 512
+
+#define RTE_MP_RX_DESC_DEFAULT 512
+#define RTE_MP_TX_DESC_DEFAULT 512
+#define NODE_QUEUE_RINGSIZE 128
+
+#define NO_FLAGS 0
+
+/* The mbuf pool for packet rx */
+struct rte_mempool *pktmbuf_pool;
+
+/* array of info/queues for nodes */
+struct node *nodes;
+
+/* EFD table */
+struct rte_efd_table *efd_table;
+
+/* Shared info between server and nodes */
+struct shared_info *info;
+
+/**
+ * Initialise the mbuf pool for packet reception for the NIC, and any other
+ * buffer pools needed by the app - currently none.
+ */
+static int
+init_mbuf_pools(void)
+{
+	const unsigned int num_mbufs = (num_nodes * MBUFS_PER_NODE) +
+			(info->num_ports * MBUFS_PER_PORT);
+
+	/*
+	 * Don't pass single-producer/single-consumer flags to mbuf create as it
+	 * seems faster to use a cache instead
+	 */
+	printf("Creating mbuf pool '%s' [%u mbufs] ...\n",
+			PKTMBUF_POOL_NAME, num_mbufs);
+	pktmbuf_pool = rte_pktmbuf_pool_create(PKTMBUF_POOL_NAME, num_mbufs,
+		MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
+
+	return pktmbuf_pool == NULL; /* 0  on success */
+}
+
+/**
+ * Initialise an individual port:
+ * - configure number of rx and tx rings
+ * - set up each rx ring, to pull from the main mbuf pool
+ * - set up each tx ring
+ * - start the port and report its status to stdout
+ */
+static int
+init_port(uint8_t port_num)
+{
+	/* for port configuration all features are off by default */
+	const struct rte_eth_conf port_conf = {
+		.rxmode = {
+			.mq_mode = ETH_MQ_RX_RSS
+		}
+	};
+	const uint16_t rx_rings = 1, tx_rings = num_nodes;
+	const uint16_t rx_ring_size = RTE_MP_RX_DESC_DEFAULT;
+	const uint16_t tx_ring_size = RTE_MP_TX_DESC_DEFAULT;
+
+	uint16_t q;
+	int retval;
+
+	printf("Port %u init ... ", (unsigned int)port_num);
+	fflush(stdout);
+
+	/*
+	 * Standard DPDK port initialisation - config port, then set up
+	 * rx and tx rings.
+	 */
+	retval = rte_eth_dev_configure(port_num, rx_rings, tx_rings, &port_conf);
+	if (retval != 0)
+		return retval;
+
+	for (q = 0; q < rx_rings; q++) {
+		retval = rte_eth_rx_queue_setup(port_num, q, rx_ring_size,
+				rte_eth_dev_socket_id(port_num),
+				NULL, pktmbuf_pool);
+		if (retval < 0)
+			return retval;
+	}
+
+	for (q = 0; q < tx_rings; q++) {
+		retval = rte_eth_tx_queue_setup(port_num, q, tx_ring_size,
+				rte_eth_dev_socket_id(port_num),
+				NULL);
+		if (retval < 0)
+			return retval;
+	}
+
+	rte_eth_promiscuous_enable(port_num);
+
+	retval = rte_eth_dev_start(port_num);
+	if (retval < 0)
+		return retval;
+
+	printf("done:\n");
+
+	return 0;
+}
+
+/**
+ * Set up the DPDK rings which will be used to pass packets, via
+ * pointers, between the multi-process server and node processes.
+ * Each node needs one RX queue.
+ */
+static int
+init_shm_rings(void)
+{
+	unsigned int i;
+	unsigned int socket_id;
+	const char *q_name;
+	const unsigned int ringsize = NODE_QUEUE_RINGSIZE;
+
+	nodes = rte_malloc("node details",
+		sizeof(*nodes) * num_nodes, 0);
+	if (nodes == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot allocate memory for "
+				"node program details\n");
+
+	for (i = 0; i < num_nodes; i++) {
+		/* Create an RX queue for each node */
+		socket_id = rte_socket_id();
+		q_name = get_rx_queue_name(i);
+		nodes[i].rx_q = rte_ring_create(q_name,
+				ringsize, socket_id,
+				RING_F_SP_ENQ | RING_F_SC_DEQ);
+		if (nodes[i].rx_q == NULL)
+			rte_exit(EXIT_FAILURE, "Cannot create rx ring queue "
+					"for node %u\n", i);
+	}
+	return 0;
+}
+
+/*
+ * Create EFD table which will contain all the flows
+ * that will be distributed among the nodes
+ */
+static void
+create_efd_table(void)
+{
+	uint8_t socket_id = rte_socket_id();
+
+	/* create table */
+	efd_table = rte_efd_create("flow table", num_flows * 2, sizeof(uint32_t),
+			1 << socket_id,	socket_id);
+
+	if (efd_table == NULL)
+		rte_exit(EXIT_FAILURE, "Problem creating the flow table\n");
+}
+
+static void
+populate_efd_table(void)
+{
+	unsigned int i;
+	int32_t ret;
+	uint32_t ip_dst;
+	uint8_t socket_id = rte_socket_id();
+	uint64_t node_id;
+
+	/* Add flows in table */
+	for (i = 0; i < num_flows; i++) {
+		node_id = i % num_nodes;
+
+		ip_dst = rte_cpu_to_be_32(i);
+		ret = rte_efd_update(efd_table, socket_id,
+				(void *)&ip_dst, (efd_value_t)node_id);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "Unable to add entry %u in "
+					"EFD table\n", i);
+	}
+
+	printf("EFD table: Adding 0x%x keys\n", num_flows);
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+	uint8_t portid, count, all_ports_up, print_flag = 0;
+	struct rte_eth_link link;
+
+	printf("\nChecking link status");
+	fflush(stdout);
+	for (count = 0; count <= MAX_CHECK_TIME; count++) {
+		all_ports_up = 1;
+		for (portid = 0; portid < port_num; portid++) {
+			if ((port_mask & (1 << info->id[portid])) == 0)
+				continue;
+			memset(&link, 0, sizeof(link));
+			rte_eth_link_get_nowait(info->id[portid], &link);
+			/* print link status if flag set */
+			if (print_flag == 1) {
+				if (link.link_status)
+					printf("Port %d Link Up - speed %u "
+						"Mbps - %s\n", info->id[portid],
+						(unsigned int)link.link_speed,
+				(link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
+					("full-duplex") : ("half-duplex\n"));
+				else
+					printf("Port %d Link Down\n",
+						(uint8_t)info->id[portid]);
+				continue;
+			}
+			/* clear all_ports_up flag if any link down */
+			if (link.link_status == ETH_LINK_DOWN) {
+				all_ports_up = 0;
+				break;
+			}
+		}
+		/* after finally printing all link status, get out */
+		if (print_flag == 1)
+			break;
+
+		if (all_ports_up == 0) {
+			printf(".");
+			fflush(stdout);
+			rte_delay_ms(CHECK_INTERVAL);
+		}
+
+		/* set the print_flag if all ports up or timeout */
+		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+			print_flag = 1;
+			printf("done\n");
+		}
+	}
+}
+
+/**
+ * Main init function for the multi-process server app,
+ * calls subfunctions to do each stage of the initialisation.
+ */
+int
+init(int argc, char *argv[])
+{
+	int retval;
+	const struct rte_memzone *mz;
+	uint8_t i, total_ports;
+
+	/* init EAL, parsing EAL args */
+	retval = rte_eal_init(argc, argv);
+	if (retval < 0)
+		return -1;
+	argc -= retval;
+	argv += retval;
+
+	/* get total number of ports */
+	total_ports = rte_eth_dev_count();
+
+	/* set up array for port data */
+	mz = rte_memzone_reserve(MZ_SHARED_INFO, sizeof(*info),
+				rte_socket_id(), NO_FLAGS);
+	if (mz == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot reserve memory zone "
+				"for port information\n");
+	memset(mz->addr, 0, sizeof(*info));
+	info = mz->addr;
+
+	/* parse additional, application arguments */
+	retval = parse_app_args(total_ports, argc, argv);
+	if (retval != 0)
+		return -1;
+
+	/* initialise mbuf pools */
+	retval = init_mbuf_pools();
+	if (retval != 0)
+		rte_exit(EXIT_FAILURE, "Cannot create needed mbuf pools\n");
+
+	/* now initialise the ports we will use */
+	for (i = 0; i < info->num_ports; i++) {
+		retval = init_port(info->id[i]);
+		if (retval != 0)
+			rte_exit(EXIT_FAILURE, "Cannot initialise port %u\n",
+					(unsigned int) i);
+	}
+
+	check_all_ports_link_status(info->num_ports, (~0x0));
+
+	/* initialise the node queues/rings for inter-eu comms */
+	init_shm_rings();
+
+	/* Create the EFD table */
+	create_efd_table();
+
+	/* Populate the EFD table */
+	populate_efd_table();
+
+	/* Share the total number of nodes */
+	info->num_nodes = num_nodes;
+
+	/* Share the total number of flows */
+	info->num_flows = num_flows;
+	return 0;
+}
diff --git a/examples/server_node_efd/server/init.h b/examples/server_node_efd/server/init.h
new file mode 100644
index 0000000..8dc5885
--- /dev/null
+++ b/examples/server_node_efd/server/init.h
@@ -0,0 +1,76 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016-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 _INIT_H_
+#define _INIT_H_
+
+/*
+ * #include <rte_ring.h>
+ * #include "args.h"
+ */
+
+/*
+ * Define a node structure with all needed info, including
+ * stats from the nodes.
+ */
+struct node {
+	struct rte_ring *rx_q;
+	unsigned int node_id;
+	/* these stats hold how many packets the node will actually receive,
+	 * and how many packets were dropped because the node's queue was full.
+	 * The port-info stats, in contrast, record how many packets were received
+	 * or transmitted on an actual NIC port.
+	 */
+	struct {
+		uint64_t rx;
+		uint64_t rx_drop;
+	} stats;
+};
+
+extern struct rte_efd_table *efd_table;
+extern struct node *nodes;
+
+/*
+ * shared information between server and nodes: number of nodes,
+ * port numbers, rx and tx stats etc.
+ */
+extern struct shared_info *info;
+
+extern struct rte_mempool *pktmbuf_pool;
+extern uint8_t num_nodes;
+extern unsigned int num_sockets;
+extern uint32_t num_flows;
+
+int init(int argc, char *argv[]);
+
+#endif /* ifndef _INIT_H_ */
diff --git a/examples/server_node_efd/server/main.c b/examples/server_node_efd/server/main.c
new file mode 100644
index 0000000..1a54d1b
--- /dev/null
+++ b/examples/server_node_efd/server/main.c
@@ -0,0 +1,362 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016-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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <inttypes.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <netinet/ip.h>
+
+#include <rte_common.h>
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_eal.h>
+#include <rte_byteorder.h>
+#include <rte_launch.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_atomic.h>
+#include <rte_ring.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_mempool.h>
+#include <rte_memcpy.h>
+#include <rte_mbuf.h>
+#include <rte_ether.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_ethdev.h>
+#include <rte_byteorder.h>
+#include <rte_malloc.h>
+#include <rte_string_fns.h>
+#include <rte_efd.h>
+#include <rte_ip.h>
+
+#include "common.h"
+#include "args.h"
+#include "init.h"
+
+/*
+ * When doing reads from the NIC or the node queues,
+ * use this batch size
+ */
+#define PACKET_READ_SIZE 32
+
+/*
+ * Local buffers to put packets in, used to send packets in bursts to the
+ * nodes
+ */
+struct node_rx_buf {
+	struct rte_mbuf *buffer[PACKET_READ_SIZE];
+	uint16_t count;
+};
+
+struct efd_stats {
+	uint64_t distributed;
+	uint64_t drop;
+} flow_dist_stats;
+
+/* One buffer per node rx queue - dynamically allocate array */
+static struct node_rx_buf *cl_rx_buf;
+
+static const char *
+get_printable_mac_addr(uint8_t port)
+{
+	static const char err_address[] = "00:00:00:00:00:00";
+	static char addresses[RTE_MAX_ETHPORTS][sizeof(err_address)];
+	struct ether_addr mac;
+
+	if (unlikely(port >= RTE_MAX_ETHPORTS))
+		return err_address;
+	if (unlikely(addresses[port][0] == '\0')) {
+		rte_eth_macaddr_get(port, &mac);
+		snprintf(addresses[port], sizeof(addresses[port]),
+				"%02x:%02x:%02x:%02x:%02x:%02x\n",
+				mac.addr_bytes[0], mac.addr_bytes[1],
+				mac.addr_bytes[2], mac.addr_bytes[3],
+				mac.addr_bytes[4], mac.addr_bytes[5]);
+	}
+	return addresses[port];
+}
+
+/*
+ * This function displays the recorded statistics for each port
+ * and for each node. It uses ANSI terminal codes to clear
+ * screen when called. It is called from a single non-master
+ * thread in the server process, when the process is run with more
+ * than one lcore enabled.
+ */
+static void
+do_stats_display(void)
+{
+	unsigned int i, j;
+	const char clr[] = {27, '[', '2', 'J', '\0'};
+	const char topLeft[] = {27, '[', '1', ';', '1', 'H', '\0'};
+	uint64_t port_tx[RTE_MAX_ETHPORTS], port_tx_drop[RTE_MAX_ETHPORTS];
+	uint64_t node_tx[MAX_NODES], node_tx_drop[MAX_NODES];
+
+	/* to get TX stats, we need to do some summing calculations */
+	memset(port_tx, 0, sizeof(port_tx));
+	memset(port_tx_drop, 0, sizeof(port_tx_drop));
+	memset(node_tx, 0, sizeof(node_tx));
+	memset(node_tx_drop, 0, sizeof(node_tx_drop));
+
+	for (i = 0; i < num_nodes; i++) {
+		const struct tx_stats *tx = &info->tx_stats[i];
+
+		for (j = 0; j < info->num_ports; j++) {
+			const uint64_t tx_val = tx->tx[info->id[j]];
+			const uint64_t drop_val = tx->tx_drop[info->id[j]];
+
+			port_tx[j] += tx_val;
+			port_tx_drop[j] += drop_val;
+			node_tx[i] += tx_val;
+			node_tx_drop[i] += drop_val;
+		}
+	}
+
+	/* Clear screen and move to top left */
+	printf("%s%s", clr, topLeft);
+
+	printf("PORTS\n");
+	printf("-----\n");
+	for (i = 0; i < info->num_ports; i++)
+		printf("Port %u: '%s'\t", (unsigned int)info->id[i],
+				get_printable_mac_addr(info->id[i]));
+	printf("\n\n");
+	for (i = 0; i < info->num_ports; i++) {
+		printf("Port %u - rx: %9"PRIu64"\t"
+				"tx: %9"PRIu64"\n",
+				(unsigned int)info->id[i], info->rx_stats.rx[i],
+				port_tx[i]);
+	}
+
+	printf("\nSERVER\n");
+	printf("-----\n");
+	printf("distributed: %9"PRIu64", drop: %9"PRIu64"\n",
+			flow_dist_stats.distributed, flow_dist_stats.drop);
+
+	printf("\nNODES\n");
+	printf("-------\n");
+	for (i = 0; i < num_nodes; i++) {
+		const unsigned long long rx = nodes[i].stats.rx;
+		const unsigned long long rx_drop = nodes[i].stats.rx_drop;
+		const struct filter_stats *filter = &info->filter_stats[i];
+
+		printf("Node %2u - rx: %9llu, rx_drop: %9llu\n"
+				"            tx: %9"PRIu64", tx_drop: %9"PRIu64"\n"
+				"            filter_passed: %9"PRIu64", "
+				"filter_drop: %9"PRIu64"\n",
+				i, rx, rx_drop, node_tx[i], node_tx_drop[i],
+				filter->passed, filter->drop);
+	}
+
+	printf("\n");
+}
+
+/*
+ * The function called from each non-master lcore used by the process.
+ * The test_and_set function is used to randomly pick a single lcore on which
+ * the code to display the statistics will run. Otherwise, the code just
+ * repeatedly sleeps.
+ */
+static int
+sleep_lcore(__attribute__((unused)) void *dummy)
+{
+	/* Used to pick a display thread - static, so zero-initialised */
+	static rte_atomic32_t display_stats;
+
+	/* Only one core should display stats */
+	if (rte_atomic32_test_and_set(&display_stats)) {
+		const unsigned int sleeptime = 1;
+
+		printf("Core %u displaying statistics\n", rte_lcore_id());
+
+		/* Longer initial pause so above printf is seen */
+		sleep(sleeptime * 3);
+
+		/* Loop forever: sleep always returns 0 or <= param */
+		while (sleep(sleeptime) <= sleeptime)
+			do_stats_display();
+	}
+	return 0;
+}
+
+/*
+ * Function to set all the node statistic values to zero.
+ * Called at program startup.
+ */
+static void
+clear_stats(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < num_nodes; i++)
+		nodes[i].stats.rx = nodes[i].stats.rx_drop = 0;
+}
+
+/*
+ * send a burst of traffic to a node, assuming there are packets
+ * available to be sent to this node
+ */
+static void
+flush_rx_queue(uint16_t node)
+{
+	uint16_t j;
+	struct node *cl;
+
+	if (cl_rx_buf[node].count == 0)
+		return;
+
+	cl = &nodes[node];
+	if (rte_ring_enqueue_bulk(cl->rx_q, (void **)cl_rx_buf[node].buffer,
+			cl_rx_buf[node].count) != 0){
+		for (j = 0; j < cl_rx_buf[node].count; j++)
+			rte_pktmbuf_free(cl_rx_buf[node].buffer[j]);
+		cl->stats.rx_drop += cl_rx_buf[node].count;
+	} else
+		cl->stats.rx += cl_rx_buf[node].count;
+
+	cl_rx_buf[node].count = 0;
+}
+
+/*
+ * marks a packet down to be sent to a particular node process
+ */
+static inline void
+enqueue_rx_packet(uint8_t node, struct rte_mbuf *buf)
+{
+	cl_rx_buf[node].buffer[cl_rx_buf[node].count++] = buf;
+}
+
+/*
+ * This function takes a group of packets and routes them
+ * individually to the node process. Very simply round-robins the packets
+ * without checking any of the packet contents.
+ */
+static void
+process_packets(uint32_t port_num __rte_unused, struct rte_mbuf *pkts[],
+		uint16_t rx_count, unsigned int socket_id)
+{
+	uint16_t i;
+	uint8_t node;
+	efd_value_t data[RTE_EFD_BURST_MAX];
+	const void *key_ptrs[RTE_EFD_BURST_MAX];
+
+	struct ipv4_hdr *ipv4_hdr;
+	uint32_t ipv4_dst_ip[RTE_EFD_BURST_MAX];
+
+	for (i = 0; i < rx_count; i++) {
+		/* Handle IPv4 header.*/
+		ipv4_hdr = rte_pktmbuf_mtod_offset(pkts[i], struct ipv4_hdr *,
+				sizeof(struct ether_hdr));
+		ipv4_dst_ip[i] = ipv4_hdr->dst_addr;
+		key_ptrs[i] = (void *)&ipv4_dst_ip[i];
+	}
+
+	rte_efd_lookup_bulk(efd_table, socket_id, rx_count,
+				(const void **) key_ptrs, data);
+	for (i = 0; i < rx_count; i++) {
+		node = (uint8_t) ((uintptr_t)data[i]);
+
+		if (node >= num_nodes) {
+			/*
+			 * Node is out of range, which means that
+			 * flow has not been inserted
+			 */
+			flow_dist_stats.drop++;
+			rte_pktmbuf_free(pkts[i]);
+		} else {
+			flow_dist_stats.distributed++;
+			enqueue_rx_packet(node, pkts[i]);
+		}
+	}
+
+	for (i = 0; i < num_nodes; i++)
+		flush_rx_queue(i);
+}
+
+/*
+ * Function called by the master lcore of the DPDK process.
+ */
+static void
+do_packet_forwarding(void)
+{
+	unsigned int port_num = 0; /* indexes the port[] array */
+	unsigned int socket_id = rte_socket_id();
+
+	for (;;) {
+		struct rte_mbuf *buf[PACKET_READ_SIZE];
+		uint16_t rx_count;
+
+		/* read a port */
+		rx_count = rte_eth_rx_burst(info->id[port_num], 0,
+				buf, PACKET_READ_SIZE);
+		info->rx_stats.rx[port_num] += rx_count;
+
+		/* Now process the NIC packets read */
+		if (likely(rx_count > 0))
+			process_packets(port_num, buf, rx_count, socket_id);
+
+		/* move to next port */
+		if (++port_num == info->num_ports)
+			port_num = 0;
+	}
+}
+
+int
+main(int argc, char *argv[])
+{
+	/* initialise the system */
+	if (init(argc, argv) < 0)
+		return -1;
+	RTE_LOG(INFO, APP, "Finished Process Init.\n");
+
+	cl_rx_buf = calloc(num_nodes, sizeof(cl_rx_buf[0]));
+
+	/* clear statistics */
+	clear_stats();
+
+	/* put all other cores to sleep bar master */
+	rte_eal_mp_remote_launch(sleep_lcore, NULL, SKIP_MASTER);
+
+	do_packet_forwarding();
+	return 0;
+}
diff --git a/examples/server_node_efd/shared/common.h b/examples/server_node_efd/shared/common.h
new file mode 100644
index 0000000..8a13479
--- /dev/null
+++ b/examples/server_node_efd/shared/common.h
@@ -0,0 +1,99 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016-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 _COMMON_H_
+#define _COMMON_H_
+
+#include <rte_hash_crc.h>
+#include <rte_hash.h>
+
+#define MAX_NODES             16
+/*
+ * Shared port info, including statistics information for display by server.
+ * Structure will be put in a memzone.
+ * - All port id values share one cache line as this data will be read-only
+ * during operation.
+ * - All rx statistic values share cache lines, as this data is written only
+ * by the server process. (rare reads by stats display)
+ * - The tx statistics have values for all ports per cache line, but the stats
+ * themselves are written by the nodes, so we have a distinct set, on different
+ * cache lines for each node to use.
+ */
+struct rx_stats {
+	uint64_t rx[RTE_MAX_ETHPORTS];
+} __rte_cache_aligned;
+
+struct tx_stats {
+	uint64_t tx[RTE_MAX_ETHPORTS];
+	uint64_t tx_drop[RTE_MAX_ETHPORTS];
+} __rte_cache_aligned;
+
+struct filter_stats {
+	uint64_t drop;
+	uint64_t passed;
+} __rte_cache_aligned;
+
+struct shared_info {
+	uint8_t num_nodes;
+	uint8_t num_ports;
+	uint32_t num_flows;
+	uint8_t id[RTE_MAX_ETHPORTS];
+	struct rx_stats rx_stats;
+	struct tx_stats tx_stats[MAX_NODES];
+	struct filter_stats filter_stats[MAX_NODES];
+};
+
+/* define common names for structures shared between server and node */
+#define MP_NODE_RXQ_NAME "MProc_Node_%u_RX"
+#define PKTMBUF_POOL_NAME "MProc_pktmbuf_pool"
+#define MZ_SHARED_INFO "MProc_shared_info"
+
+/*
+ * Given the rx queue name template above, get the queue name
+ */
+static inline const char *
+get_rx_queue_name(unsigned int id)
+{
+	/*
+	 * Buffer for return value. Size calculated by %u being replaced
+	 * by maximum 3 digits (plus an extra byte for safety)
+	 */
+	static char buffer[sizeof(MP_NODE_RXQ_NAME) + 2];
+
+	snprintf(buffer, sizeof(buffer) - 1, MP_NODE_RXQ_NAME, id);
+	return buffer;
+}
+
+#define RTE_LOGTYPE_APP RTE_LOGTYPE_USER1
+
+#endif
-- 
2.7.4

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [dpdk-dev] [PATCH] examples/flow-distributor: rename to server_node_efd
  2017-01-24  9:06 [dpdk-dev] [PATCH] examples/flow-distributor: rename to server_node_efd Pablo de Lara
@ 2017-01-30 16:25 ` Thomas Monjalon
  0 siblings, 0 replies; 2+ messages in thread
From: Thomas Monjalon @ 2017-01-30 16:25 UTC (permalink / raw)
  To: Pablo de Lara; +Cc: dev

2017-01-24 09:06, Pablo de Lara:
> To avoid confusion with distributor app, this commit
> renames the flow-distributor sample app to server_node_efd,
> since it shows how to use the EFD library and it is based
> on a server/nodes model.
> 
> Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>

Are you sure of the name? :)

Applied with a fix:

--- a/examples/Makefile
+++ b/examples/Makefile
-DIRS-$(CONFIG_RTE_LIBRTE_EFD) += flow_distributor
+DIRS-$(CONFIG_RTE_LIBRTE_EFD) += server_node_efd

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2017-01-30 16:25 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-24  9:06 [dpdk-dev] [PATCH] examples/flow-distributor: rename to server_node_efd Pablo de Lara
2017-01-30 16:25 ` Thomas Monjalon

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).